getsuperpower
Advanced tools
+7
-3
| { | ||
| "name": "getsuperpower", | ||
| "version": "0.3.0", | ||
| "version": "0.3.1", | ||
| "type": "module", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/0xroylee/getsuperpower" | ||
| }, | ||
| "bin": { | ||
@@ -18,6 +22,6 @@ "getsuperpower": "dist/cli.js" | ||
| "build": "bun build --target=bun --outfile=dist/cli.js src/cli.ts", | ||
| "test": "bun test", | ||
| "test": "bun test tests", | ||
| "ci:test": "find tests -maxdepth 1 -name '*.test.ts' ! -name '*.e2e.test.ts' -print0 | xargs -0 bun test", | ||
| "ci:check": "biome check . && bun run typecheck && bun run ci:test", | ||
| "coverage": "bun test --coverage --coverage-reporter=lcov --coverage-dir=coverage && bun scripts/check-coverage.ts 90 coverage/lcov.info", | ||
| "coverage": "bun test tests --coverage --coverage-reporter=lcov --coverage-dir=coverage && bun scripts/check-coverage.ts 90 coverage/lcov.info", | ||
| "coverage:check": "bun scripts/check-coverage.ts 90 coverage/lcov.info", | ||
@@ -24,0 +28,0 @@ "deps:check-recency": "bun scripts/check-package-recency.ts", |
+11
-49
@@ -19,2 +19,9 @@ <img src="/assets/getsupwerpower.jpg" alt="GetSuperpower" width="640" /> | ||
| Install from a public git repository: | ||
| ```bash | ||
| npx getsuperpower install https://github.com/acme/release-review.git | ||
| npx getsuperpower install 'https://github.com/acme/workflows.git#examples/release-review' | ||
| ``` | ||
| List installed GetSuperpowers: | ||
@@ -32,33 +39,4 @@ | ||
| ```mermaid | ||
| flowchart LR | ||
| Install["getsuperpower install"] | ||
| Manifest["workflow.json<br/>what to install"] | ||
| Entry["entry skill<br/>what users call"] | ||
| Skills["sub-skills<br/>what the agent uses"] | ||
| Agent["Claude / Codex / opencode / Cursor / GitHub Copilot"] | ||
| Result["workflow result"] | ||
| <img src="assets/diagrams/getsuperpower-how-it-works.svg" alt="GetSuperpower workflow diagram" width="720" /> | ||
| Install --> Manifest | ||
| Manifest --> Entry | ||
| Manifest --> Skills | ||
| Entry --> Agent | ||
| Skills --> Agent | ||
| Agent --> Result | ||
| classDef command fill:#dbeafe,stroke:#2563eb,color:#172554; | ||
| classDef manifest fill:#dcfce7,stroke:#16a34a,color:#052e16; | ||
| classDef entry fill:#f3e8ff,stroke:#9333ea,color:#3b0764; | ||
| classDef skills fill:#ffedd5,stroke:#f97316,color:#431407; | ||
| classDef agent fill:#fef9c3,stroke:#ca8a04,color:#422006; | ||
| classDef result fill:#e0f2fe,stroke:#0284c7,color:#082f49; | ||
| class Install command; | ||
| class Manifest manifest; | ||
| class Entry entry; | ||
| class Skills skills; | ||
| class Agent agent; | ||
| class Result result; | ||
| ``` | ||
| `workflow.json` installs the skill tree. The entry skill runs it. Sub-skills are the steps the agent follows. | ||
@@ -68,22 +46,4 @@ | ||
| ```mermaid | ||
| sequenceDiagram | ||
| autonumber | ||
| actor User as User | ||
| participant CLI as GetSuperpower CLI | ||
| participant Workflow as workflow json | ||
| participant Skills as entry skill and sub skills | ||
| participant State as workflow records | ||
| participant Agent as AI agent | ||
| <img src="assets/diagrams/getsuperpower-install-sequence.svg" alt="GetSuperpower install and run sequence diagram" width="920" /> | ||
| User->>CLI: install or clone a GetSuperpower | ||
| CLI->>Workflow: read workflow.json skills and steps | ||
| CLI->>Skills: install required skills | ||
| CLI->>State: save .getsuperpower/workflows record | ||
| User->>Agent: call the entry skill | ||
| Agent->>Workflow: follow the skill tree | ||
| Agent->>Skills: use sub-skills in order | ||
| Agent-->>User: return the workflow result | ||
| ``` | ||
| ## Try A Callable Workflow | ||
@@ -176,2 +136,3 @@ | ||
| | `npx getsuperpower clone product-dev` | Same as install; deploy a GetSuperpower by name or source. | | ||
| | `npx getsuperpower install https://github.com/acme/release-review.git` | Install a GetSuperpower from a public git repo. | | ||
| | `npx getsuperpower deps <source>` | Show required skills before install or clone. | | ||
@@ -207,2 +168,3 @@ | `npx getsuperpower list` | Show installed GetSuperpowers. | | ||
| bun run check | ||
| bun scripts/smoke-public-git-install.ts | ||
| ``` | ||
@@ -209,0 +171,0 @@ |
+1
-1
@@ -17,3 +17,3 @@ #!/usr/bin/env bun | ||
| const CLI_VERSION = "0.3.0"; | ||
| const CLI_VERSION = "0.3.1"; | ||
@@ -20,0 +20,0 @@ interface CommanderVersionInternals { |
+70
-37
@@ -16,2 +16,3 @@ import { homedir } from "node:os"; | ||
| loadWorkflowBundle, | ||
| type WorkflowGitCommandRunner, | ||
| } from "./runtimes/ponytrail"; | ||
@@ -81,2 +82,3 @@ | ||
| installExternalSkillDependency?: GetSuperpowerExternalSkillDependencyInstaller; | ||
| workflowGitCommandRunner?: WorkflowGitCommandRunner; | ||
| } | ||
@@ -101,3 +103,3 @@ | ||
| .description("Compatibility alias for GetSuperpower authoring."); | ||
| configureAuthorCommands(bundleCommand, options.rootDir); | ||
| configureAuthorCommands(bundleCommand, options); | ||
@@ -117,9 +119,12 @@ const workflowCommand = program | ||
| ): void { | ||
| configureAuthorCommands(command, options.rootDir); | ||
| configureAuthorCommands(command, options); | ||
| configureInstallCommand(command, options); | ||
| configureListCommand(command, options.rootDir); | ||
| configureDependencyCommand(command, options.rootDir); | ||
| configureDependencyCommand(command, options); | ||
| } | ||
| function configureAuthorCommands(command: Command, rootDir: string): void { | ||
| function configureAuthorCommands( | ||
| command: Command, | ||
| options: ConfigureGetSuperpowerCommandOptions, | ||
| ): void { | ||
| command | ||
@@ -129,6 +134,6 @@ .command("init") | ||
| .argument("<name>", "GetSuperpower name") | ||
| .option("--dir <dir>", "directory that will contain the GetSuperpower", rootDir) | ||
| .option("--dir <dir>", "directory that will contain the GetSuperpower", options.rootDir) | ||
| .action(async (name: string, commandOptions: { dir: string }) => { | ||
| const scaffold = await createWorkflowBundleScaffold({ | ||
| rootDir: resolvePath(rootDir, commandOptions.dir), | ||
| rootDir: resolvePath(options.rootDir, commandOptions.dir), | ||
| name, | ||
@@ -147,7 +152,15 @@ }); | ||
| .action(async (path: string) => { | ||
| const bundle = await loadWorkflowBundle(path, { cwd: rootDir }); | ||
| console.log(`GetSuperpower valid: ${bundle.manifest.name}@${bundle.manifest.version}`); | ||
| console.log(`${pc.dim("Steps:")} ${bundle.manifest.steps.length}`); | ||
| console.log(`${pc.dim("Skills:")} ${bundle.manifest.skills.length}`); | ||
| const bundle = await loadWorkflowBundle(path, { | ||
| cwd: options.rootDir, | ||
| ...(options.workflowGitCommandRunner | ||
| ? { runGitCommand: options.workflowGitCommandRunner } | ||
| : {}), | ||
| }); | ||
| try { | ||
| console.log(`GetSuperpower valid: ${bundle.manifest.name}@${bundle.manifest.version}`); | ||
| console.log(`${pc.dim("Steps:")} ${bundle.manifest.steps.length}`); | ||
| console.log(`${pc.dim("Skills:")} ${bundle.manifest.skills.length}`); | ||
| } finally { | ||
| await bundle.cleanup?.(); | ||
| } | ||
| }); | ||
@@ -198,3 +211,8 @@ } | ||
| const targetDir = resolvePath(options.rootDir, commandOptions.dir); | ||
| const bundle = await loadWorkflowBundle(source, { cwd: options.rootDir }); | ||
| const bundle = await loadWorkflowBundle(source, { | ||
| cwd: options.rootDir, | ||
| ...(options.workflowGitCommandRunner | ||
| ? { runGitCommand: options.workflowGitCommandRunner } | ||
| : {}), | ||
| }); | ||
| const installAgents = parseSkillInstallAgents(commandOptions.agents); | ||
@@ -204,23 +222,27 @@ const homeDir = resolveHomePath(commandOptions.home); | ||
| for (const skillSource of getWorkflowSkillInstallSources(bundle)) { | ||
| const skillResult = await installGetSuperpowerSkillDependency({ | ||
| rootDir: targetDir, | ||
| source: skillSource, | ||
| homeDir, | ||
| agents: installAgents, | ||
| installSkill: options.installSkill, | ||
| installExternalSkillDependency: | ||
| options.installExternalSkillDependency ?? installExternalSkillDependencyWithSkillsCli, | ||
| installedExternalPackages, | ||
| }); | ||
| try { | ||
| for (const skillSource of getWorkflowSkillInstallSources(bundle)) { | ||
| const skillResult = await installGetSuperpowerSkillDependency({ | ||
| rootDir: targetDir, | ||
| source: skillSource, | ||
| homeDir, | ||
| agents: installAgents, | ||
| installSkill: options.installSkill, | ||
| installExternalSkillDependency: | ||
| options.installExternalSkillDependency ?? installExternalSkillDependencyWithSkillsCli, | ||
| installedExternalPackages, | ||
| }); | ||
| options.printSkillInstallResult(skillResult.skillInstall, "install", { | ||
| showPostSkillChangeWelcome: false, | ||
| }); | ||
| } | ||
| options.printSkillInstallResult(skillResult.skillInstall, "install", { | ||
| showPostSkillChangeWelcome: false, | ||
| }); | ||
| } | ||
| const install = await installWorkflowBundle({ rootDir: targetDir, bundle }); | ||
| const install = await installWorkflowBundle({ rootDir: targetDir, bundle }); | ||
| console.log(`GetSuperpower installed: ${install.workflow.name}`); | ||
| console.log(`${pc.dim("GetSuperpower file:")} ${install.path}`); | ||
| console.log(`GetSuperpower installed: ${install.workflow.name}`); | ||
| console.log(`${pc.dim("GetSuperpower file:")} ${install.path}`); | ||
| } finally { | ||
| await bundle.cleanup?.(); | ||
| } | ||
| } | ||
@@ -389,3 +411,6 @@ | ||
| function configureDependencyCommand(command: Command, rootDir: string): void { | ||
| function configureDependencyCommand( | ||
| command: Command, | ||
| options: ConfigureGetSuperpowerCommandOptions, | ||
| ): void { | ||
| command | ||
@@ -397,8 +422,16 @@ .command("deps") | ||
| .action(async (source: string) => { | ||
| const bundle = await loadWorkflowBundle(source, { cwd: rootDir }); | ||
| console.log(`GetSuperpower dependencies: ${bundle.manifest.name}`); | ||
| for (const skill of bundle.manifest.skills) { | ||
| const optional = skill.optional ? " (optional)" : ""; | ||
| console.log(`- ${skill.source}${optional}`); | ||
| const bundle = await loadWorkflowBundle(source, { | ||
| cwd: options.rootDir, | ||
| ...(options.workflowGitCommandRunner | ||
| ? { runGitCommand: options.workflowGitCommandRunner } | ||
| : {}), | ||
| }); | ||
| try { | ||
| console.log(`GetSuperpower dependencies: ${bundle.manifest.name}`); | ||
| for (const skill of bundle.manifest.skills) { | ||
| const optional = skill.optional ? " (optional)" : ""; | ||
| console.log(`- ${skill.source}${optional}`); | ||
| } | ||
| } finally { | ||
| await bundle.cleanup?.(); | ||
| } | ||
@@ -405,0 +438,0 @@ }); |
| import { existsSync } from "node:fs"; | ||
| import { mkdir, readdir, readFile, writeFile } from "node:fs/promises"; | ||
| import { mkdir, mkdtemp, readdir, readFile, rm, writeFile } from "node:fs/promises"; | ||
| import { tmpdir } from "node:os"; | ||
| import { dirname, isAbsolute, join, resolve } from "node:path"; | ||
@@ -57,2 +58,31 @@ import { z } from "zod"; | ||
| export interface WorkflowGitCommand { | ||
| executable: string; | ||
| args: string[]; | ||
| cwd: string; | ||
| env: Record<string, string | undefined>; | ||
| } | ||
| export interface WorkflowGitCommandResult { | ||
| stdout: string; | ||
| stderr: string; | ||
| exitCode: number; | ||
| } | ||
| export type WorkflowGitCommandRunner = ( | ||
| command: WorkflowGitCommand, | ||
| ) => Promise<WorkflowGitCommandResult>; | ||
| export type WorkflowBundleSource = | ||
| | { | ||
| kind: "bundled" | "local"; | ||
| path: string; | ||
| } | ||
| | { | ||
| kind: "git"; | ||
| url: string; | ||
| commit?: string; | ||
| subdirectory?: string; | ||
| }; | ||
| export interface WorkflowBundle { | ||
@@ -62,3 +92,4 @@ manifest: WorkflowBundleManifest; | ||
| manifestPath: string; | ||
| bundled: boolean; | ||
| source: WorkflowBundleSource; | ||
| cleanup?: () => Promise<void>; | ||
| } | ||
@@ -74,6 +105,3 @@ | ||
| export interface InstalledWorkflowBundle extends WorkflowBundleManifest { | ||
| source: { | ||
| kind: "bundled" | "local"; | ||
| path: string; | ||
| }; | ||
| source: WorkflowBundleSource; | ||
| } | ||
@@ -88,18 +116,40 @@ | ||
| source: string, | ||
| options: { cwd?: string } = {}, | ||
| options: { | ||
| cwd?: string; | ||
| runGitCommand?: WorkflowGitCommandRunner; | ||
| tempDir?: string; | ||
| } = {}, | ||
| ): Promise<WorkflowBundle> { | ||
| const sourceDir = resolveWorkflowBundleSource(source, options.cwd ?? process.cwd()); | ||
| const manifestPath = sourceDir.endsWith(workflowFileName) | ||
| ? sourceDir | ||
| : join(sourceDir, workflowFileName); | ||
| const manifestDir = sourceDir.endsWith(workflowFileName) ? dirname(sourceDir) : sourceDir; | ||
| const rawManifest = await readFile(manifestPath, "utf8"); | ||
| const manifest = WorkflowBundleManifestSchema.parse(JSON.parse(rawManifest)); | ||
| const resolvedSource = await resolveWorkflowBundleSource(source, { | ||
| cwd: options.cwd ?? process.cwd(), | ||
| ...(options.runGitCommand ? { runGitCommand: options.runGitCommand } : {}), | ||
| ...(options.tempDir ? { tempDir: options.tempDir } : {}), | ||
| }); | ||
| const manifestPath = resolvedSource.sourceDir.endsWith(workflowFileName) | ||
| ? resolvedSource.sourceDir | ||
| : join(resolvedSource.sourceDir, workflowFileName); | ||
| const manifestDir = resolvedSource.sourceDir.endsWith(workflowFileName) | ||
| ? dirname(resolvedSource.sourceDir) | ||
| : resolvedSource.sourceDir; | ||
| return { | ||
| manifest, | ||
| sourceDir: manifestDir, | ||
| manifestPath, | ||
| bundled: isBundledWorkflowSource(source), | ||
| }; | ||
| try { | ||
| const rawManifest = await readFile(manifestPath, "utf8"); | ||
| const manifest = WorkflowBundleManifestSchema.parse(JSON.parse(rawManifest)); | ||
| return { | ||
| manifest, | ||
| sourceDir: manifestDir, | ||
| manifestPath, | ||
| source: resolvedSource.source, | ||
| ...(resolvedSource.cleanup ? { cleanup: resolvedSource.cleanup } : {}), | ||
| }; | ||
| } catch (error) { | ||
| await resolvedSource.cleanup?.(); | ||
| if (resolvedSource.source.kind === "git" && isMissingFileError(error)) { | ||
| throw new Error( | ||
| `No GetSuperpower workflow manifest was found at ${manifestPath} from public git source: ${resolvedSource.source.url}`, | ||
| ); | ||
| } | ||
| throw error; | ||
| } | ||
| } | ||
@@ -192,6 +242,3 @@ | ||
| ...bundle.manifest, | ||
| source: { | ||
| kind: bundle.bundled ? "bundled" : "local", | ||
| path: bundle.sourceDir, | ||
| }, | ||
| source: bundle.source, | ||
| }; | ||
@@ -281,8 +328,28 @@ } | ||
| function resolveWorkflowBundleSource(source: string, cwd: string): string { | ||
| interface ResolvedWorkflowBundleSource { | ||
| sourceDir: string; | ||
| source: WorkflowBundleSource; | ||
| cleanup?: () => Promise<void>; | ||
| } | ||
| async function resolveWorkflowBundleSource( | ||
| source: string, | ||
| options: { | ||
| cwd: string; | ||
| runGitCommand?: WorkflowGitCommandRunner; | ||
| tempDir?: string; | ||
| }, | ||
| ): Promise<ResolvedWorkflowBundleSource> { | ||
| const gitSource = parseGitWorkflowSource(source); | ||
| if (gitSource) { | ||
| return cloneGitWorkflowSource(gitSource, options); | ||
| } | ||
| if (isLocalWorkflowSource(source)) { | ||
| return isAbsolute(source) ? source : resolve(cwd, source); | ||
| const sourceDir = isAbsolute(source) ? source : resolve(options.cwd, source); | ||
| return { sourceDir, source: { kind: "local", path: sourceDir } }; | ||
| } | ||
| return join(findBundledWorkflowsDir(), source); | ||
| const sourceDir = join(findBundledWorkflowsDir(), source); | ||
| return { sourceDir, source: { kind: "bundled", path: sourceDir } }; | ||
| } | ||
@@ -302,6 +369,153 @@ | ||
| function isBundledWorkflowSource(source: string): boolean { | ||
| return !isLocalWorkflowSource(source); | ||
| interface GitWorkflowSource { | ||
| cloneUrl: string; | ||
| url: string; | ||
| subdirectory?: string; | ||
| } | ||
| function parseGitWorkflowSource(source: string): GitWorkflowSource | null { | ||
| let url: URL; | ||
| try { | ||
| url = new URL(source); | ||
| } catch { | ||
| return null; | ||
| } | ||
| if (url.protocol !== "https:" && url.protocol !== "file:") { | ||
| return null; | ||
| } | ||
| const subdirectory = parseGitWorkflowSubdirectory(url.hash); | ||
| url.hash = ""; | ||
| return { | ||
| cloneUrl: url.toString(), | ||
| url: source, | ||
| ...(subdirectory ? { subdirectory } : {}), | ||
| }; | ||
| } | ||
| function parseGitWorkflowSubdirectory(hash: string): string | undefined { | ||
| if (!hash) { | ||
| return undefined; | ||
| } | ||
| const rawHash = decodeURIComponent(hash.slice(1)); | ||
| const params = new URLSearchParams(rawHash); | ||
| const candidate = params.get("path") ?? (rawHash.includes("=") ? undefined : rawHash); | ||
| if (!candidate) { | ||
| return undefined; | ||
| } | ||
| const normalized = candidate | ||
| .split("/") | ||
| .filter((part) => part.length > 0 && part !== ".") | ||
| .join("/"); | ||
| if (!normalized) { | ||
| return undefined; | ||
| } | ||
| if ( | ||
| normalized === ".." || | ||
| normalized.startsWith("../") || | ||
| normalized.includes("/../") || | ||
| isAbsolute(normalized) | ||
| ) { | ||
| throw new Error(`Unsupported public git workflow subdirectory: ${candidate}`); | ||
| } | ||
| return normalized; | ||
| } | ||
| async function cloneGitWorkflowSource( | ||
| source: GitWorkflowSource, | ||
| options: { | ||
| cwd: string; | ||
| runGitCommand?: WorkflowGitCommandRunner; | ||
| tempDir?: string; | ||
| }, | ||
| ): Promise<ResolvedWorkflowBundleSource> { | ||
| const tempRoot = await mkdtemp(join(options.tempDir ?? tmpdir(), "getsuperpower-git-")); | ||
| const checkoutDir = join(tempRoot, "checkout"); | ||
| const cleanup = () => rm(tempRoot, { recursive: true, force: true }); | ||
| try { | ||
| await runRequiredGitCommand( | ||
| { | ||
| executable: "git", | ||
| args: ["clone", "--depth", "1", source.cloneUrl, checkoutDir], | ||
| cwd: options.cwd, | ||
| env: process.env, | ||
| }, | ||
| options.runGitCommand, | ||
| `Public git workflow source could not be fetched: ${source.url}`, | ||
| ); | ||
| const commitResult = await runOptionalGitCommand( | ||
| { | ||
| executable: "git", | ||
| args: ["rev-parse", "HEAD"], | ||
| cwd: checkoutDir, | ||
| env: process.env, | ||
| }, | ||
| options.runGitCommand, | ||
| ); | ||
| const commit = commitResult.exitCode === 0 ? commitResult.stdout.trim() : undefined; | ||
| const sourceDir = source.subdirectory ? join(checkoutDir, source.subdirectory) : checkoutDir; | ||
| return { | ||
| sourceDir, | ||
| source: { | ||
| kind: "git", | ||
| url: source.url, | ||
| ...(commit ? { commit } : {}), | ||
| ...(source.subdirectory ? { subdirectory: source.subdirectory } : {}), | ||
| }, | ||
| cleanup, | ||
| }; | ||
| } catch (error) { | ||
| await cleanup(); | ||
| throw error; | ||
| } | ||
| } | ||
| async function runRequiredGitCommand( | ||
| command: WorkflowGitCommand, | ||
| runGitCommand: WorkflowGitCommandRunner | undefined, | ||
| failureMessage: string, | ||
| ): Promise<WorkflowGitCommandResult> { | ||
| const result = await runOptionalGitCommand(command, runGitCommand); | ||
| if (result.exitCode !== 0) { | ||
| const detail = [result.stderr.trim(), result.stdout.trim()].filter(Boolean).join("\n"); | ||
| throw new Error(detail ? `${failureMessage}\n${detail}` : failureMessage); | ||
| } | ||
| return result; | ||
| } | ||
| async function runOptionalGitCommand( | ||
| command: WorkflowGitCommand, | ||
| runGitCommand: WorkflowGitCommandRunner | undefined, | ||
| ): Promise<WorkflowGitCommandResult> { | ||
| if (runGitCommand) { | ||
| return runGitCommand(command); | ||
| } | ||
| const subprocess = Bun.spawn([command.executable, ...command.args], { | ||
| cwd: command.cwd, | ||
| stdout: "pipe", | ||
| stderr: "pipe", | ||
| env: command.env, | ||
| }); | ||
| const [stdout, stderr, exitCode] = await Promise.all([ | ||
| new Response(subprocess.stdout).text(), | ||
| new Response(subprocess.stderr).text(), | ||
| subprocess.exited, | ||
| ]); | ||
| return { stdout, stderr, exitCode }; | ||
| } | ||
| function isMissingFileError(error: unknown): boolean { | ||
| return (error as NodeJS.ErrnoException).code === "ENOENT"; | ||
| } | ||
| function findBundledWorkflowsDir(): string { | ||
@@ -308,0 +522,0 @@ const currentDir = dirname(new URL(import.meta.url).pathname); |
Sorry, the diff of this file is too big to display
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 2 instances
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
AI-detected potential malware
Supply chain riskAI has identified this package as malware. This is a strong signal that the package may be malicious.
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
819721
1.29%21112
1.74%0
-100%170
-18.27%28
16.67%