runcastle 0.2.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +47 -0
  2. package/bin/runcastle.js +5609 -0
  3. package/drizzle/0000_amused_bruce_banner.sql +74 -0
  4. package/drizzle/0001_mapped_feature_flag.sql +1 -0
  5. package/drizzle/0002_waypoints.sql +14 -0
  6. package/drizzle/0003_project_closed_at.sql +1 -0
  7. package/drizzle/0004_events_project_id.sql +28 -0
  8. package/drizzle/0005_project_setting_overrides.sql +2 -0
  9. package/drizzle/meta/0000_snapshot.json +466 -0
  10. package/drizzle/meta/0001_snapshot.json +474 -0
  11. package/drizzle/meta/0002_snapshot.json +568 -0
  12. package/drizzle/meta/0003_snapshot.json +575 -0
  13. package/drizzle/meta/0004_snapshot.json +582 -0
  14. package/drizzle/meta/0005_snapshot.json +596 -0
  15. package/drizzle/meta/_journal.json +48 -0
  16. package/hook-client.ts +67 -0
  17. package/index.js +5453 -0
  18. package/package.json +24 -30
  19. package/pty-host.cjs +186 -0
  20. package/sandcastle-template/Containerfile +33 -0
  21. package/sandcastle-template/Dockerfile +33 -0
  22. package/skills/burner/implement-ticket.md +42 -0
  23. package/skills/burner/research-waypoint.md +45 -0
  24. package/skills/packs/README.md +50 -0
  25. package/skills/packs/runcastle/.claude-plugin/plugin.json +6 -0
  26. package/skills/packs/runcastle/skills/converge/SKILL.md +51 -0
  27. package/skills/packs/runcastle/skills/ideate/SKILL.md +81 -0
  28. package/skills/packs/runcastle/skills/qa/SKILL.md +30 -0
  29. package/skills/packs/runcastle/skills/spec/SKILL.md +43 -0
  30. package/skills/packs/runcastle/skills/tickets/SKILL.md +52 -0
  31. package/skills/packs/runcastle/skills/waypoint/SKILL.md +54 -0
  32. package/web/assets/index-CKZ5Z7vc.css +1 -0
  33. package/web/assets/index-YBuT7tTz.js +108 -0
  34. package/web/index.html +13 -0
  35. package/dist/add-DD7G73HH.js +0 -315
  36. package/dist/add-DD7G73HH.js.map +0 -1
  37. package/dist/chunk-44KDPUYJ.js +0 -49
  38. package/dist/chunk-44KDPUYJ.js.map +0 -1
  39. package/dist/chunk-5VPKMXSV.js +0 -190
  40. package/dist/chunk-5VPKMXSV.js.map +0 -1
  41. package/dist/chunk-6CWCR5SO.js +0 -24
  42. package/dist/chunk-6CWCR5SO.js.map +0 -1
  43. package/dist/chunk-7CHGGMP7.js +0 -73
  44. package/dist/chunk-7CHGGMP7.js.map +0 -1
  45. package/dist/chunk-AHRTPV2C.js +0 -1082
  46. package/dist/chunk-AHRTPV2C.js.map +0 -1
  47. package/dist/chunk-GU4LRYYH.js +0 -41
  48. package/dist/chunk-GU4LRYYH.js.map +0 -1
  49. package/dist/chunk-LP5MV76P.js +0 -33
  50. package/dist/chunk-LP5MV76P.js.map +0 -1
  51. package/dist/chunk-OJ356IMJ.js +0 -136
  52. package/dist/chunk-OJ356IMJ.js.map +0 -1
  53. package/dist/chunk-PRNBOQHW.js +0 -32
  54. package/dist/chunk-PRNBOQHW.js.map +0 -1
  55. package/dist/chunk-QTC5Y3LU.js +0 -146
  56. package/dist/chunk-QTC5Y3LU.js.map +0 -1
  57. package/dist/chunk-SNUH2UT6.js +0 -95
  58. package/dist/chunk-SNUH2UT6.js.map +0 -1
  59. package/dist/chunk-UG25BZUN.js +0 -59
  60. package/dist/chunk-UG25BZUN.js.map +0 -1
  61. package/dist/chunk-VWAIXSB6.js +0 -78
  62. package/dist/chunk-VWAIXSB6.js.map +0 -1
  63. package/dist/index.js +0 -99
  64. package/dist/index.js.map +0 -1
  65. package/dist/info-3PW6A6JA.js +0 -80
  66. package/dist/info-3PW6A6JA.js.map +0 -1
  67. package/dist/init-MOJNLWXK.js +0 -212
  68. package/dist/init-MOJNLWXK.js.map +0 -1
  69. package/dist/logout-YPGZ6BB6.js +0 -27
  70. package/dist/logout-YPGZ6BB6.js.map +0 -1
  71. package/dist/publish-W37Y6TO6.js +0 -211
  72. package/dist/publish-W37Y6TO6.js.map +0 -1
  73. package/dist/run-M4XXNPGD.js +0 -291
  74. package/dist/run-M4XXNPGD.js.map +0 -1
  75. package/dist/search-2KNAXPM5.js +0 -55
  76. package/dist/search-2KNAXPM5.js.map +0 -1
  77. package/dist/update-UCT4K6IQ.js +0 -125
  78. package/dist/update-UCT4K6IQ.js.map +0 -1
  79. package/dist/validate-GFDSEVPV.js +0 -12
  80. package/dist/validate-GFDSEVPV.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../schema/dist/index.js"],"sourcesContent":["// src/constants.ts\nvar PRODUCT_NAME = \"runcastle\";\nvar DEFAULT_REGISTRY_URL = \"https://runcastle.dev\";\nvar SCHEMA_VERSION = 1;\nvar SCHEMA_ID = `${DEFAULT_REGISTRY_URL}/schema/v1.json`;\nvar PAYLOAD_DIR = \".sandcastle\";\nvar DEFAULT_ENTRYPOINT = `${PAYLOAD_DIR}/main.ts`;\nvar SANDCASTLE_PACKAGE_NAME = \"@ai-hero/sandcastle\";\nvar MAX_PACKAGE_SIZE_BYTES = 2 * 1024 * 1024;\nvar MAX_FILE_COUNT = 100;\nvar MAX_FILE_SIZE_BYTES = 512 * 1024;\nvar MAX_DESCRIPTION_LENGTH = 280;\nvar MAX_TAGS = 8;\nvar MIN_README_LENGTH = 300;\nvar SLUG_REGEX = /^[a-z0-9-]{3,64}$/;\nvar ENV_NAME_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/;\nvar ALLOWED_EXTENSIONS = [\n \".ts\",\n \".mts\",\n \".md\",\n \".json\",\n \".yaml\",\n \".yml\",\n \".gitignore\",\n \".env.example\",\n \".sh\"\n];\nvar ALLOWED_FILENAMES = [\n \"Dockerfile\",\n \"Containerfile\",\n \".gitignore\",\n \".env.example\"\n];\nvar WINDOWS_RESERVED_NAMES = /* @__PURE__ */ new Set([\n \"CON\",\n \"PRN\",\n \"AUX\",\n \"NUL\",\n ...Array.from({ length: 9 }, (_, i) => `COM${i + 1}`),\n ...Array.from({ length: 9 }, (_, i) => `LPT${i + 1}`)\n]);\nvar SANDBOX_PROVIDERS = [\n \"docker\",\n \"podman\",\n \"vercel\",\n \"custom\"\n];\nvar AGENT_PROVIDERS = [\n \"claude-code\",\n \"codex\",\n \"pi\",\n \"opencode\",\n \"cursor\",\n \"copilot\"\n];\nvar AGENT_FACTORY_NAMES = [\n \"claudeCode\",\n \"codex\",\n \"pi\",\n \"opencode\"\n];\nvar FACTORY_TO_PROVIDER = {\n claudeCode: \"claude-code\",\n codex: \"codex\",\n pi: \"pi\",\n opencode: \"opencode\"\n};\nvar ALLOWED_IMPORT_ROOTS = [\n SANDCASTLE_PACKAGE_NAME,\n \"zod\"\n];\nvar ErrorCode = {\n E_SCHEMA_INVALID: \"E_SCHEMA_INVALID\",\n E_MISSING_FILE: \"E_MISSING_FILE\",\n E_UNLISTED_FILE: \"E_UNLISTED_FILE\",\n E_UNSAFE_PATH: \"E_UNSAFE_PATH\",\n E_ENV_FILE_PRESENT: \"E_ENV_FILE_PRESENT\",\n E_SECRET_DETECTED: \"E_SECRET_DETECTED\",\n E_ENV_MISMATCH: \"E_ENV_MISMATCH\",\n E_HOOKS_MISMATCH: \"E_HOOKS_MISMATCH\",\n E_HOOKS_NOT_STATIC: \"E_HOOKS_NOT_STATIC\",\n E_FORBIDDEN_IMPORT: \"E_FORBIDDEN_IMPORT\",\n E_UNDECLARED_SHELL_EXPANSION: \"E_UNDECLARED_SHELL_EXPANSION\",\n E_PACKAGE_TOO_LARGE: \"E_PACKAGE_TOO_LARGE\",\n E_TOO_MANY_FILES: \"E_TOO_MANY_FILES\",\n E_FILE_TOO_LARGE: \"E_FILE_TOO_LARGE\",\n E_BINARY_FILE: \"E_BINARY_FILE\",\n E_FORBIDDEN_EXTENSION: \"E_FORBIDDEN_EXTENSION\"\n};\nvar WarningCode = {\n W_VERSION_RANGE_STALE: \"W_VERSION_RANGE_STALE\",\n W_NO_TOPOLOGY: \"W_NO_TOPOLOGY\",\n W_SHORT_README: \"W_SHORT_README\",\n W_NAMESPACE_UNSAFE_PATHS: \"W_NAMESPACE_UNSAFE_PATHS\"\n};\nvar COMMON_SPDX_LICENSE_IDS = [\n \"MIT\",\n \"Apache-2.0\",\n \"BSD-2-Clause\",\n \"BSD-3-Clause\",\n \"ISC\",\n \"MPL-2.0\",\n \"GPL-2.0-only\",\n \"GPL-2.0-or-later\",\n \"GPL-3.0-only\",\n \"GPL-3.0-or-later\",\n \"LGPL-2.1-only\",\n \"LGPL-3.0-only\",\n \"AGPL-3.0-only\",\n \"AGPL-3.0-or-later\",\n \"Unlicense\",\n \"CC0-1.0\",\n \"0BSD\"\n];\nfunction isKnownSpdxLicense(id) {\n return COMMON_SPDX_LICENSE_IDS.includes(id);\n}\n\n// src/manifest.ts\nimport { z } from \"zod\";\nimport semver from \"semver\";\nvar semverString = z.string().refine((v) => semver.valid(v, { loose: false }) !== null, {\n message: \"must be a strict semver version (e.g. 1.2.3)\"\n});\nvar semverRange = z.string().refine((v) => semver.validRange(v, { loose: false }) !== null, {\n message: \"must be a valid semver range (e.g. >=0.12.0 <0.13.0)\"\n});\nvar AgentSchema = z.object({\n role: z.string().min(1).describe(\"The agent's role name as used in the orchestration code (e.g. planner, implementer, reviewer).\"),\n provider: z.enum(AGENT_PROVIDERS).describe(\"Agent factory / provider used for this role.\"),\n model: z.string().min(1).describe(\"Model identifier passed to the provider (e.g. claude-opus-4-8).\"),\n parallel: z.boolean().optional().describe(\"Whether this role fans out into parallel instances.\")\n});\nvar SandcastleCompatSchema = z.object({\n packageName: z.string().min(1).default(SANDCASTLE_PACKAGE_NAME).describe(\"The orchestration package. Defaults to @ai-hero/sandcastle.\"),\n versionRange: semverRange.describe(\n \"Semver range of Sandcastle versions the workflow is tested against (e.g. >=0.12.0 <0.13.0).\"\n ),\n entrypoint: z.string().min(1).default(DEFAULT_ENTRYPOINT).describe(\"Path to the orchestration entrypoint that calls run(). Defaults to .sandcastle/main.ts.\")\n});\nvar EnvVarSchema = z.object({\n name: z.string().regex(ENV_NAME_REGEX, \"invalid environment variable name\").describe(\"Environment variable name (shell-safe identifier).\"),\n required: z.boolean().describe(\"Whether the workflow fails without this variable set.\"),\n description: z.string().optional().describe(\"What the variable is for \\u2014 shown to installers.\")\n});\nvar DisclosuresSchema = z.object({\n hostHooks: z.array(z.string()).default([]).describe(\"Every host.* hook command run on the consumer's machine, verbatim as string literals.\"),\n sandboxHooks: z.array(z.string()).default([]).describe(\"Every sandbox.* hook command run inside the sandbox, verbatim as string literals.\"),\n networkAccess: z.string().optional().describe(\"Free-text note describing what the workflow accesses over the network.\"),\n usesShellExpansion: z.boolean().default(false).describe(\"Whether any prompt file contains !`command` shell-expansion blocks.\")\n});\nvar TopologyNodeSchema = z.object({\n id: z.string().min(1).describe(\"Unique node identifier, referenced by edges.\"),\n role: z.string().min(1).nullable().describe(\"The agent role this node represents, or null for non-agent nodes (e.g. a git step).\"),\n label: z.string().min(1).describe(\"Display label rendered in the diagram.\"),\n kind: z.string().min(1).optional().describe('Optional node flavor (e.g. \"git\") \\u2014 non-agent nodes get a muted rendering.'),\n fanOut: z.boolean().optional().describe(\"Marks a node that fans out into parallel instances \\u2014 rendered as a stacked card.\")\n});\nvar TopologyEdgeSchema = z.object({\n from: z.string().min(1).describe(\"Source node id.\"),\n to: z.string().min(1).describe(\"Target node id.\"),\n label: z.string().optional().describe(\"Optional edge label (e.g. a condition).\"),\n loop: z.boolean().optional().describe(\"Marks a feedback edge (e.g. reviewer sending work back) \\u2014 rendered dashed.\")\n});\nvar TopologySchema = z.object({\n nodes: z.array(TopologyNodeSchema).describe(\"Graph nodes \\u2014 one per agent role or auxiliary step.\"),\n edges: z.array(TopologyEdgeSchema).describe(\"Directed edges between node ids.\")\n});\nvar ManifestSchema = z.object({\n $schema: z.string().optional().describe(\"Optional JSON Schema URL so editors provide autocomplete and inline validation.\"),\n schemaVersion: z.literal(SCHEMA_VERSION).describe(\"Manifest format version. Always 1 for now.\"),\n // Identity\n name: z.string().min(1).max(120).describe(\"Human-readable display name shown on cards and the detail page.\"),\n slug: z.string().regex(SLUG_REGEX, \"slug must match [a-z0-9-]{3,64}\").describe(\"URL-safe identifier [a-z0-9-]{3,64}, unique per author; forms the install handle author/slug.\"),\n version: semverString.describe(\n \"Strict semver (e.g. 1.2.0). Versions are immutable \\u2014 republishing a version is rejected with 409.\"\n ),\n description: z.string().min(1).max(MAX_DESCRIPTION_LENGTH).describe(`One-paragraph summary (max ${MAX_DESCRIPTION_LENGTH} chars) shown on cards and in search.`),\n license: z.string().min(1).describe(\"SPDX license identifier for the package contents (e.g. MIT).\"),\n tags: z.array(z.string().min(1)).max(MAX_TAGS).default([]).describe(`Up to ${MAX_TAGS} tags from an open vocabulary, used for browse filters and search.`),\n // Compatibility\n sandcastle: SandcastleCompatSchema.describe(\n \"Compatibility block describing the Sandcastle runtime the workflow targets.\"\n ),\n // Declared runtime metadata\n agents: z.array(AgentSchema).default([]).describe(\"The agents the workflow orchestrates \\u2014 declared metadata cross-checked against the entrypoint.\"),\n sandboxProviders: z.array(z.enum(SANDBOX_PROVIDERS)).default([]).describe(\"Sandbox environments the workflow supports (subset of docker | podman | vercel | custom).\"),\n // Environment\n env: z.array(EnvVarSchema).default([]).describe(\"Environment variables the user must provide; cross-checked against .env.example.\"),\n // Disclosures\n disclosures: DisclosuresSchema.describe(\n \"The declared side-effect surface (hooks, network, shell expansion). Mismatches with detected behavior block publish.\"\n ),\n // Topology (optional — absence produces a warning)\n topology: TopologySchema.optional().describe(\n \"The node/edge graph describing the orchestration shape. Optional \\u2014 drives the site diagram, cards, and OG images.\"\n ),\n // Files to install\n files: z.array(z.string().min(1)).min(1).max(MAX_FILE_COUNT).describe(\"Exhaustive list of files the package installs, relative to the package root (all under .sandcastle/).\"),\n // Optional metadata\n repositoryDirectory: z.string().optional().describe(\"Directory within the repository containing the package, when it isn't at the repo root.\"),\n // http(s) only — package content is hostile input (§8.6); a javascript: URL\n // here would become a live link on the workflow page.\n homepage: z.string().url().refine((u) => /^https?:\\/\\//i.test(u), {\n message: \"homepage must be an http(s) URL\"\n }).optional().describe(\"Optional project homepage URL (http(s) only).\"),\n postInstallNotes: z.string().optional().describe(\"Plain text printed by the CLI after a successful install (printed, never executed).\")\n});\nfunction parseManifest(value) {\n const result = ManifestSchema.safeParse(value);\n if (result.success) return { ok: true, manifest: result.data };\n return { ok: false, error: result.error };\n}\n\n// src/json-schema.ts\nimport { z as z2 } from \"zod\";\nfunction manifestJsonSchema() {\n const schema = z2.toJSONSchema(ManifestSchema, {\n io: \"input\",\n target: \"draft-2020-12\",\n unrepresentable: \"any\"\n });\n schema.$id = SCHEMA_ID;\n schema.title = \"Runcastle workflow.json\";\n schema.description = \"Manifest for a Runcastle workflow package (Sandcastle orchestration).\";\n return schema;\n}\nvar MANIFEST_JSON_SCHEMA = manifestJsonSchema();\n\n// src/validate.ts\nimport semver2 from \"semver\";\n\n// src/secrets.ts\nvar SECRET_RULES = [\n {\n id: \"anthropic-api-key\",\n description: \"Anthropic API key (sk-ant-)\",\n pattern: /sk-ant-[A-Za-z0-9_-]{16,}/g\n },\n {\n id: \"openai-project-key\",\n description: \"OpenAI project key (sk-proj-)\",\n pattern: /sk-proj-[A-Za-z0-9_-]{16,}/g\n },\n {\n id: \"openai-api-key\",\n description: \"OpenAI API key (sk-)\",\n // Classic sk- keys: sk- followed by >=20 base62 chars, not preceded by a\n // word char and not one of the more specific sk-ant-/sk-proj- prefixes.\n pattern: /(?<![A-Za-z0-9_-])sk-(?!ant-|proj-)[A-Za-z0-9]{20,}/g\n },\n {\n id: \"github-pat-classic\",\n description: \"GitHub personal access token (ghp_)\",\n pattern: /ghp_[A-Za-z0-9]{36,}/g\n },\n {\n id: \"github-pat-fine-grained\",\n description: \"GitHub fine-grained PAT (github_pat_)\",\n pattern: /github_pat_[A-Za-z0-9_]{22,}/g\n },\n {\n id: \"github-oauth-token\",\n description: \"GitHub OAuth token (gho_)\",\n pattern: /gho_[A-Za-z0-9]{36,}/g\n },\n {\n id: \"aws-access-key-id\",\n description: \"AWS access key id (AKIA/ASIA)\",\n pattern: /\\b(?:AKIA|ASIA)[0-9A-Z]{16}\\b/g\n },\n {\n id: \"aws-secret-access-key\",\n description: \"AWS secret access key (contextual)\",\n // Require an aws-secret context word near a 40-char base64 secret to keep\n // false positives on arbitrary hashes/blobs low.\n pattern: /aws.{0,20}?(?:secret|sak).{0,20}?['\"]?([A-Za-z0-9/+=]{40})['\"]?/gis\n },\n {\n id: \"private-key-block\",\n description: \"PEM PRIVATE KEY block\",\n pattern: /-----BEGIN(?: [A-Z0-9]+)* PRIVATE KEY-----/g\n }\n];\nfunction scanForSecrets(content) {\n const findings = [];\n for (const rule of SECRET_RULES) {\n rule.pattern.lastIndex = 0;\n let m;\n while ((m = rule.pattern.exec(content)) !== null) {\n findings.push({\n ruleId: rule.id,\n description: rule.description,\n match: m[0],\n index: m.index\n });\n if (m.index === rule.pattern.lastIndex) rule.pattern.lastIndex++;\n }\n }\n return findings;\n}\nfunction hasSecret(content) {\n return scanForSecrets(content).length > 0;\n}\n\n// src/analyzers/hooks.ts\nimport {\n Node,\n SyntaxKind,\n VariableDeclarationKind\n} from \"ts-morph\";\n\n// src/analyzers/project.ts\nimport { Project } from \"ts-morph\";\nfunction createSourceFile(content) {\n const project = new Project({\n useInMemoryFileSystem: true,\n skipAddingFilesFromTsConfig: true,\n skipFileDependencyResolution: true,\n skipLoadingLibFiles: true,\n compilerOptions: {\n allowJs: true\n }\n });\n return project.createSourceFile(\"entrypoint.mts\", content, {\n overwrite: true\n });\n}\n\n// src/analyzers/hooks.ts\nfunction readStringLiteral(node) {\n if (!node) return void 0;\n if (Node.isStringLiteral(node) || Node.isNoSubstitutionTemplateLiteral(node)) {\n return node.getLiteralText();\n }\n return void 0;\n}\nfunction extractCommand(entry, out, reasons) {\n if (!Node.isObjectLiteralExpression(entry)) {\n reasons.push(\"hook entry is not an object literal\");\n return;\n }\n const commandProp = entry.getProperty(\"command\");\n if (!commandProp || !Node.isPropertyAssignment(commandProp)) {\n reasons.push(\"hook entry has no static `command` property\");\n return;\n }\n const value = readStringLiteral(commandProp.getInitializer());\n if (value === void 0) {\n reasons.push(\"hook `command` is not a string literal\");\n return;\n }\n out.push(value);\n}\nfunction extractGroup(groupValue, out, reasons) {\n if (!groupValue) return;\n if (!Node.isObjectLiteralExpression(groupValue)) {\n reasons.push(\"hook group is not an object literal\");\n return;\n }\n for (const prop of groupValue.getProperties()) {\n if (!Node.isPropertyAssignment(prop)) {\n reasons.push(\"hook event is not a static property\");\n continue;\n }\n const arr = prop.getInitializer();\n if (!arr || !Node.isArrayLiteralExpression(arr)) {\n reasons.push(\"hook event value is not an array literal\");\n continue;\n }\n for (const el of arr.getElements()) {\n if (Node.isSpreadElement(el)) {\n reasons.push(\"hook array uses a spread element\");\n continue;\n }\n extractCommand(el, out, reasons);\n }\n }\n}\nfunction extractHooksObject(hooksObject, hostOut, sandboxOut, reasons) {\n const host = hooksObject.getProperty(\"host\");\n if (host) {\n if (Node.isPropertyAssignment(host)) {\n extractGroup(host.getInitializer(), hostOut, reasons);\n } else {\n reasons.push(\"`host` hooks are not a static property\");\n }\n }\n const sandbox = hooksObject.getProperty(\"sandbox\");\n if (sandbox) {\n if (Node.isPropertyAssignment(sandbox)) {\n extractGroup(sandbox.getInitializer(), sandboxOut, reasons);\n } else {\n reasons.push(\"`sandbox` hooks are not a static property\");\n }\n }\n}\nfunction resolveObjectLiteral(node, source) {\n let current = node;\n while (current && (Node.isAsExpression(current) || Node.isSatisfiesExpression(current) || Node.isParenthesizedExpression(current))) {\n current = current.getExpression();\n }\n if (!current) return void 0;\n if (Node.isObjectLiteralExpression(current)) return current;\n if (Node.isIdentifier(current)) {\n const name = current.getText();\n for (const stmt of source.getVariableStatements()) {\n if (stmt.getDeclarationKind() !== VariableDeclarationKind.Const) continue;\n for (const decl of stmt.getDeclarations()) {\n if (decl.getName() !== name) continue;\n const init = decl.getInitializer();\n if (!init) return void 0;\n let unwrapped = init;\n while (Node.isAsExpression(unwrapped) || Node.isSatisfiesExpression(unwrapped) || Node.isParenthesizedExpression(unwrapped)) {\n unwrapped = unwrapped.getExpression();\n }\n return Node.isObjectLiteralExpression(unwrapped) ? unwrapped : void 0;\n }\n }\n }\n return void 0;\n}\nfunction extractHooks(entrypointContent) {\n const source = createSourceFile(entrypointContent);\n const hostCommands = [];\n const sandboxCommands = [];\n const dynamicReasons = [];\n const objects = source.getDescendantsOfKind(\n SyntaxKind.ObjectLiteralExpression\n );\n for (const obj of objects) {\n const hooksProp = obj.getProperty(\"hooks\");\n if (!hooksProp) continue;\n let value;\n if (Node.isPropertyAssignment(hooksProp)) {\n value = hooksProp.getInitializer();\n } else if (Node.isShorthandPropertyAssignment(hooksProp)) {\n value = hooksProp.getNameNode();\n } else {\n dynamicReasons.push(\"`hooks` is not a static property assignment\");\n continue;\n }\n const literal2 = value ? resolveObjectLiteral(value, source) : void 0;\n if (!literal2) {\n dynamicReasons.push(\n \"`hooks` value is not an object literal (or a same-file `const` object literal)\"\n );\n continue;\n }\n extractHooksObject(literal2, hostCommands, sandboxCommands, dynamicReasons);\n }\n return {\n static: dynamicReasons.length === 0,\n hostCommands,\n sandboxCommands,\n dynamicReasons\n };\n}\n\n// src/analyzers/imports.ts\nimport { Node as Node2, SyntaxKind as SyntaxKind2 } from \"ts-morph\";\nfunction isAllowedImport(specifier) {\n if (specifier.startsWith(\"node:\")) return true;\n for (const root of ALLOWED_IMPORT_ROOTS) {\n if (specifier === root || specifier.startsWith(`${root}/`)) return true;\n }\n return false;\n}\nfunction analyzeImports(entrypointContent) {\n const source = createSourceFile(entrypointContent);\n const specifiers = [];\n for (const decl of source.getImportDeclarations()) {\n specifiers.push(decl.getModuleSpecifierValue());\n }\n for (const decl of source.getExportDeclarations()) {\n const value = decl.getModuleSpecifierValue();\n if (value) specifiers.push(value);\n }\n for (const call of source.getDescendantsOfKind(SyntaxKind2.CallExpression)) {\n const expr = call.getExpression();\n const isRequire = Node2.isIdentifier(expr) && expr.getText() === \"require\";\n const isDynamicImport = expr.getKind() === SyntaxKind2.ImportKeyword;\n if (!isRequire && !isDynamicImport) continue;\n const arg = call.getArguments()[0];\n if (arg && (Node2.isStringLiteral(arg) || Node2.isNoSubstitutionTemplateLiteral(arg))) {\n specifiers.push(arg.getLiteralText());\n }\n }\n return specifiers.map((specifier) => ({\n specifier,\n allowed: isAllowedImport(specifier)\n }));\n}\nfunction forbiddenImports(entrypointContent) {\n const seen = /* @__PURE__ */ new Set();\n const out = [];\n for (const ref of analyzeImports(entrypointContent)) {\n if (!ref.allowed && !seen.has(ref.specifier)) {\n seen.add(ref.specifier);\n out.push(ref.specifier);\n }\n }\n return out;\n}\n\n// src/analyzers/prompts.ts\nvar SHELL_EXPANSION_RE = /!`([^`]+)`/g;\nfunction detectShellExpansions(content) {\n const out = [];\n SHELL_EXPANSION_RE.lastIndex = 0;\n let m;\n while ((m = SHELL_EXPANSION_RE.exec(content)) !== null) {\n out.push({ command: m[1] ?? \"\", index: m.index });\n }\n return out;\n}\nfunction hasShellExpansion(content) {\n SHELL_EXPANSION_RE.lastIndex = 0;\n return SHELL_EXPANSION_RE.test(content);\n}\n\n// src/analyzers/namespace.ts\nimport { Node as Node3, SyntaxKind as SyntaxKind3 } from \"ts-morph\";\nfunction literal(node) {\n if (!node) return void 0;\n if (Node3.isStringLiteral(node) || Node3.isNoSubstitutionTemplateLiteral(node)) {\n return node.getLiteralText();\n }\n return void 0;\n}\nfunction findNamespaceUnsafePaths(entrypointContent) {\n const source = createSourceFile(entrypointContent);\n const out = [];\n const prefix = `${PAYLOAD_DIR}/`;\n for (const prop of source.getDescendantsOfKind(\n SyntaxKind3.PropertyAssignment\n )) {\n if (prop.getName() !== \"promptFile\") continue;\n const value = literal(prop.getInitializer());\n if (value === void 0) continue;\n const normalized = value.replace(/^\\.\\//, \"\");\n if (normalized.startsWith(prefix)) {\n out.push({ path: value });\n }\n }\n return out;\n}\n\n// src/validate.ts\nfunction normalizePath(p) {\n return p.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\").replace(/\\/{2,}/g, \"/\").replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n}\nfunction basename(p) {\n const norm = normalizePath(p);\n const idx = norm.lastIndexOf(\"/\");\n return idx === -1 ? norm : norm.slice(idx + 1);\n}\nvar PURE_EXTENSIONS = ALLOWED_EXTENSIONS.filter(\n (e) => !ALLOWED_FILENAMES.includes(e)\n);\nfunction extensionAllowed(path) {\n const base = basename(path);\n if (ALLOWED_FILENAMES.includes(base)) return true;\n return PURE_EXTENSIONS.some((ext) => base.endsWith(ext));\n}\nvar PAYLOAD_PREFIX = `${PAYLOAD_DIR}/`;\nfunction inPayload(path) {\n return path === PAYLOAD_DIR || path.startsWith(PAYLOAD_PREFIX);\n}\nfunction unsafePathReason(raw) {\n if (typeof raw !== \"string\" || raw.trim() === \"\") return \"path is empty\";\n for (let i = 0; i < raw.length; i++) {\n const code = raw.charCodeAt(i);\n if (code < 32 || code === 127) return \"path contains control characters\";\n }\n if (raw.includes(\"\\\\\")) return \"path contains a backslash\";\n if (raw.includes(\":\")) {\n return \"path contains a colon (drive letter or NTFS alternate data stream)\";\n }\n if (raw.startsWith(\"/\")) return \"path is absolute\";\n const norm = normalizePath(raw);\n if (norm === \"\") return \"path is empty\";\n for (const seg of norm.split(\"/\")) {\n if (seg === \"..\") return \"path contains a '..' traversal segment\";\n const stem = seg.split(\".\")[0].toUpperCase();\n if (WINDOWS_RESERVED_NAMES.has(stem)) {\n return `path uses the Windows reserved name \"${seg}\"`;\n }\n }\n if (!inPayload(norm)) {\n return `path must live under ${PAYLOAD_DIR}/`;\n }\n return null;\n}\nvar utf8Decoder = new TextDecoder(\"utf-8\", { fatal: false });\nfunction decodeFile(file) {\n if (typeof file.content === \"string\") {\n return {\n text: file.content,\n isBinary: file.content.includes(\"\\0\")\n };\n }\n const bytes = file.content;\n for (let i = 0; i < bytes.length; i++) {\n if (bytes[i] === 0) return { text: null, isBinary: true };\n }\n const text = utf8Decoder.decode(bytes);\n const isBinary = text.includes(\"\\uFFFD\");\n return { text: isBinary ? null : text, isBinary };\n}\nfunction parseEnvExampleKeys(content) {\n const keys = /* @__PURE__ */ new Set();\n for (const rawLine of content.split(/\\r?\\n/)) {\n const line = rawLine.trim();\n if (!line || line.startsWith(\"#\")) continue;\n const m = /^(?:export\\s+)?([A-Za-z_][A-Za-z0-9_]*)\\s*=/.exec(line);\n if (m?.[1]) keys.add(m[1]);\n }\n return keys;\n}\nvar Report = class {\n errors = [];\n warnings = [];\n error(code, message, file) {\n this.errors.push({ code, message, ...file ? { file } : {} });\n }\n warn(code, message, file) {\n this.warnings.push({ code, message, ...file ? { file } : {} });\n }\n};\nfunction validatePackage(pkg, options = {}) {\n const report = new Report();\n const files = /* @__PURE__ */ new Map();\n for (const [rawPath, file] of pkg.files) {\n files.set(normalizePath(rawPath), file);\n }\n const decoded = /* @__PURE__ */ new Map();\n const textOf = (path) => {\n if (!decoded.has(path)) {\n const f = files.get(path);\n decoded.set(path, f ? decodeFile(f) : { text: null, isBinary: false });\n }\n return decoded.get(path).text;\n };\n runStructuralChecks(files, decoded, report);\n const manifestFile = files.get(\"workflow.json\");\n if (!manifestFile) {\n report.error(\n ErrorCode.E_MISSING_FILE,\n \"workflow.json is required at the package root\",\n \"workflow.json\"\n );\n return finalize(report);\n }\n const manifestText = textOf(\"workflow.json\");\n let manifest;\n if (manifestText === null) {\n report.error(\n ErrorCode.E_SCHEMA_INVALID,\n \"workflow.json is not readable UTF-8 text\",\n \"workflow.json\"\n );\n } else {\n let json;\n try {\n json = JSON.parse(manifestText);\n } catch (e) {\n report.error(\n ErrorCode.E_SCHEMA_INVALID,\n `workflow.json is not valid JSON: ${e.message}`,\n \"workflow.json\"\n );\n }\n if (json !== void 0) {\n const parsed = parseManifest(json);\n if (parsed.ok) {\n manifest = parsed.manifest;\n } else {\n for (const issue of parsed.error.issues) {\n const path = issue.path.join(\".\");\n report.error(\n ErrorCode.E_SCHEMA_INVALID,\n `${path ? `${path}: ` : \"\"}${issue.message}`,\n \"workflow.json\"\n );\n }\n }\n }\n }\n const readmeText = textOf(\"README.md\");\n if (readmeText === null && !files.has(\"README.md\")) {\n report.error(\n ErrorCode.E_MISSING_FILE,\n \"README.md is required at the package root\",\n \"README.md\"\n );\n } else if (readmeText !== null && readmeText.trim().length < MIN_README_LENGTH) {\n report.warn(\n WarningCode.W_SHORT_README,\n `README is shorter than ${MIN_README_LENGTH} characters`,\n \"README.md\"\n );\n }\n if (manifest) {\n runManifestChecks(manifest, files, textOf, report, options);\n }\n return finalize(report);\n}\nfunction finalize(report) {\n return {\n ok: report.errors.length === 0,\n errors: report.errors,\n warnings: report.warnings\n };\n}\nfunction isRealEnvFile(path) {\n const base = basename(path);\n return base === \".env\" || base.startsWith(\".env.\") && base !== \".env.example\";\n}\nfunction runStructuralChecks(files, decoded, report) {\n if (files.size > MAX_FILE_COUNT) {\n report.error(\n ErrorCode.E_TOO_MANY_FILES,\n `package has ${files.size} files (max ${MAX_FILE_COUNT})`\n );\n }\n let totalBytes = 0;\n for (const [path, file] of files) {\n totalBytes += file.sizeBytes;\n if (isRealEnvFile(path)) {\n report.error(\n ErrorCode.E_ENV_FILE_PRESENT,\n \"a real .env file must not be included in the package\",\n path\n );\n continue;\n }\n if (file.sizeBytes > MAX_FILE_SIZE_BYTES) {\n report.error(\n ErrorCode.E_FILE_TOO_LARGE,\n `file is ${file.sizeBytes} bytes (max ${MAX_FILE_SIZE_BYTES})`,\n path\n );\n }\n if (!decoded.has(path)) decoded.set(path, decodeFile(file));\n const dec = decoded.get(path);\n if (dec.isBinary) {\n report.error(\n ErrorCode.E_BINARY_FILE,\n \"binary files are not allowed; text files only\",\n path\n );\n }\n if (!extensionAllowed(path)) {\n report.error(\n ErrorCode.E_FORBIDDEN_EXTENSION,\n `file extension is not on the allowlist (${basename(path)})`,\n path\n );\n }\n if (!dec.isBinary && dec.text !== null) {\n const findings = scanForSecrets(dec.text);\n if (findings.length > 0) {\n const rules = [...new Set(findings.map((f) => f.description))].join(\", \");\n report.error(\n ErrorCode.E_SECRET_DETECTED,\n `possible secret detected (${rules})`,\n path\n );\n }\n }\n }\n if (totalBytes > MAX_PACKAGE_SIZE_BYTES) {\n report.error(\n ErrorCode.E_PACKAGE_TOO_LARGE,\n `package is ${totalBytes} bytes (max ${MAX_PACKAGE_SIZE_BYTES})`\n );\n }\n}\nfunction runManifestChecks(manifest, files, textOf, report, options) {\n checkSafePaths(manifest, report);\n const listed = new Set(manifest.files.map(normalizePath));\n for (const path of listed) {\n if (!files.has(path)) {\n report.error(\n ErrorCode.E_MISSING_FILE,\n \"file listed in manifest.files is missing from the package\",\n path\n );\n }\n }\n for (const path of files.keys()) {\n if (inPayload(path) && !listed.has(path) && !isRealEnvFile(path)) {\n report.error(\n ErrorCode.E_UNLISTED_FILE,\n \"package file under .sandcastle/ is not listed in manifest.files\",\n path\n );\n }\n }\n const entrypoint = normalizePath(\n manifest.sandcastle.entrypoint || DEFAULT_ENTRYPOINT\n );\n const entrypointText = files.has(entrypoint) ? textOf(entrypoint) : null;\n if (!files.has(entrypoint)) {\n report.error(\n ErrorCode.E_MISSING_FILE,\n \"the manifest entrypoint is missing from the package\",\n entrypoint\n );\n }\n checkEnvConsistency(manifest, files, textOf, report);\n if (entrypointText !== null) {\n checkHooks(manifest, entrypoint, entrypointText, report);\n checkImports(entrypoint, entrypointText, report);\n checkNamespaceSafety(entrypoint, entrypointText, report);\n }\n checkShellExpansion(manifest, files, textOf, report);\n if (!manifest.topology) {\n report.warn(WarningCode.W_NO_TOPOLOGY, \"workflow declares no topology\");\n }\n if (options.latestSandcastleVersion) {\n const latest = options.latestSandcastleVersion;\n const range = manifest.sandcastle.versionRange;\n if (semver2.validRange(range) && semver2.valid(latest)) {\n if (!semver2.satisfies(latest, range)) {\n report.warn(\n WarningCode.W_VERSION_RANGE_STALE,\n `sandcastle.versionRange \"${range}\" does not include the latest known Sandcastle release (${latest})`\n );\n }\n }\n }\n}\nfunction checkSafePaths(manifest, report) {\n for (const raw of manifest.files) {\n const reason = unsafePathReason(raw);\n if (reason) {\n report.error(\n ErrorCode.E_UNSAFE_PATH,\n `unsafe install path in manifest.files \\u2014 ${reason}`,\n typeof raw === \"string\" ? raw : void 0\n );\n }\n }\n const entrypoint = manifest.sandcastle.entrypoint || DEFAULT_ENTRYPOINT;\n const entryReason = unsafePathReason(entrypoint);\n if (entryReason) {\n report.error(\n ErrorCode.E_UNSAFE_PATH,\n `unsafe sandcastle.entrypoint \\u2014 ${entryReason}`,\n entrypoint\n );\n }\n}\nfunction checkEnvConsistency(manifest, files, textOf, report) {\n const envExamplePath = `${PAYLOAD_DIR}/.env.example`;\n const exampleText = files.has(envExamplePath) ? textOf(envExamplePath) : null;\n const exampleKeys = exampleText ? parseEnvExampleKeys(exampleText) : /* @__PURE__ */ new Set();\n const manifestKeys = new Set(manifest.env.map((e) => e.name));\n if (exampleKeys.size === 0 && manifestKeys.size === 0) return;\n const missingFromManifest = [...exampleKeys].filter((k) => !manifestKeys.has(k));\n const missingFromExample = [...manifestKeys].filter((k) => !exampleKeys.has(k));\n if (missingFromManifest.length > 0 || missingFromExample.length > 0) {\n const parts = [];\n if (missingFromManifest.length > 0) {\n parts.push(\n `in .env.example but not manifest.env: ${missingFromManifest.join(\", \")}`\n );\n }\n if (missingFromExample.length > 0) {\n parts.push(\n `in manifest.env but not .env.example: ${missingFromExample.join(\", \")}`\n );\n }\n report.error(\n ErrorCode.E_ENV_MISMATCH,\n `env vars inconsistent \\u2014 ${parts.join(\"; \")}`,\n envExamplePath\n );\n }\n}\nfunction checkHooks(manifest, entrypoint, entrypointText, report) {\n const extraction = extractHooks(entrypointText);\n if (!extraction.static) {\n report.error(\n ErrorCode.E_HOOKS_NOT_STATIC,\n `hooks must be statically analyzable: ${[...new Set(extraction.dynamicReasons)].join(\"; \")}`,\n entrypoint\n );\n return;\n }\n const detectedHost = new Set(extraction.hostCommands);\n const detectedSandbox = new Set(extraction.sandboxCommands);\n const declaredHost = new Set(manifest.disclosures.hostHooks);\n const declaredSandbox = new Set(manifest.disclosures.sandboxHooks);\n const hostMismatch = !setsEqual(detectedHost, declaredHost);\n const sandboxMismatch = !setsEqual(detectedSandbox, declaredSandbox);\n if (hostMismatch || sandboxMismatch) {\n const details = [];\n if (hostMismatch) {\n details.push(\n `host hooks \\u2014 declared [${[...declaredHost].join(\", \")}] vs detected [${[...detectedHost].join(\", \")}]`\n );\n }\n if (sandboxMismatch) {\n details.push(\n `sandbox hooks \\u2014 declared [${[...declaredSandbox].join(\", \")}] vs detected [${[...detectedSandbox].join(\", \")}]`\n );\n }\n report.error(\n ErrorCode.E_HOOKS_MISMATCH,\n `disclosures.*Hooks do not match the entrypoint: ${details.join(\"; \")}`,\n entrypoint\n );\n }\n}\nfunction checkImports(entrypoint, entrypointText, report) {\n for (const specifier of forbiddenImports(entrypointText)) {\n report.error(\n ErrorCode.E_FORBIDDEN_IMPORT,\n `entrypoint imports \"${specifier}\" \\u2014 only @ai-hero/sandcastle, zod, and node:* builtins are allowed`,\n entrypoint\n );\n }\n}\nfunction checkNamespaceSafety(entrypoint, entrypointText, report) {\n const unsafe = findNamespaceUnsafePaths(entrypointText);\n if (unsafe.length > 0) {\n const paths = unsafe.map((u) => u.path).join(\", \");\n report.warn(\n WarningCode.W_NAMESPACE_UNSAFE_PATHS,\n `promptFile paths anchored to ${PAYLOAD_DIR}/ may break under a namespaced install: ${paths}`,\n entrypoint\n );\n }\n}\nfunction checkShellExpansion(manifest, files, textOf, report) {\n if (manifest.disclosures.usesShellExpansion) return;\n for (const path of files.keys()) {\n if (!inPayload(path) || !path.endsWith(\".md\")) continue;\n const text = textOf(path);\n if (text === null) continue;\n const blocks = detectShellExpansions(text);\n if (blocks.length > 0) {\n report.error(\n ErrorCode.E_UNDECLARED_SHELL_EXPANSION,\n \"prompt file contains !`command` shell expansion but disclosures.usesShellExpansion is false\",\n path\n );\n }\n }\n}\nfunction setsEqual(a, b) {\n if (a.size !== b.size) return false;\n for (const v of a) if (!b.has(v)) return false;\n return true;\n}\nfunction packageFromRecord(record) {\n const encoder = new TextEncoder();\n const files = /* @__PURE__ */ new Map();\n for (const [path, content] of Object.entries(record)) {\n const sizeBytes = typeof content === \"string\" ? encoder.encode(content).length : content.length;\n files.set(normalizePath(path), { content, sizeBytes });\n }\n return { files };\n}\n\n// src/analyzers/agents.ts\nimport { Node as Node4, SyntaxKind as SyntaxKind4 } from \"ts-morph\";\nvar FACTORY_SET = new Set(AGENT_FACTORY_NAMES);\nfunction readStatic(node) {\n if (!node) return void 0;\n if (Node4.isStringLiteral(node) || Node4.isNoSubstitutionTemplateLiteral(node)) {\n return node.getLiteralText();\n }\n if (Node4.isNumericLiteral(node)) return Number(node.getLiteralText());\n if (node.getKind() === SyntaxKind4.TrueKeyword) return true;\n if (node.getKind() === SyntaxKind4.FalseKeyword) return false;\n if (node.getKind() === SyntaxKind4.NullKeyword) return null;\n return void 0;\n}\nfunction readOptions(node) {\n const out = {};\n if (!node || !Node4.isObjectLiteralExpression(node)) return out;\n for (const prop of node.getProperties()) {\n if (!Node4.isPropertyAssignment(prop)) continue;\n const value = readStatic(prop.getInitializer());\n if (value !== void 0) out[prop.getName()] = value;\n }\n return out;\n}\nfunction detectAgents(entrypointContent) {\n const source = createSourceFile(entrypointContent);\n const out = [];\n for (const call of source.getDescendantsOfKind(SyntaxKind4.CallExpression)) {\n const expr = call.getExpression();\n if (!Node4.isIdentifier(expr)) continue;\n const name = expr.getText();\n if (!FACTORY_SET.has(name)) continue;\n const factory = name;\n const args = call.getArguments();\n const model = readStatic(args[0]);\n const options = readOptions(args[1]);\n out.push({\n factory,\n provider: FACTORY_TO_PROVIDER[factory],\n ...typeof model === \"string\" ? { model } : {},\n options\n });\n }\n return out;\n}\n\n// src/api.ts\nimport { z as z3 } from \"zod\";\nvar ErrorEnvelopeSchema = z3.object({\n error: z3.object({\n code: z3.string(),\n message: z3.string()\n })\n});\nvar RepoRefSchema = z3.string().regex(/^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+$/, \"expected owner/name\");\nvar CommitShaSchema = z3.string().regex(/^[0-9a-f]{40}$|^[0-9a-f]{64}$/, \"expected a git commit SHA\");\nvar DirectorySchema = z3.string().max(256, \"directory must be at most 256 characters\").regex(\n /^[A-Za-z0-9._/-]+$/,\n \"directory may only contain A-Za-z0-9._/- (no backslash, colon, or whitespace)\"\n).refine((d) => !d.startsWith(\"/\"), { message: \"directory must be relative\" }).refine((d) => !d.split(\"/\").includes(\"..\"), {\n message: \"directory must not contain a '..' traversal segment\"\n});\nvar FileChecksumSchema = z3.object({\n path: z3.string().min(1),\n sha256: z3.string().regex(/^[0-9a-f]{64}$/, \"expected a sha256 hex digest\"),\n sizeBytes: z3.number().int().nonnegative(),\n /** URL to fetch the cached content (registry cache endpoint). */\n downloadUrl: z3.string().optional()\n});\nvar FileListingSchema = z3.array(FileChecksumSchema);\nvar PublishRequestSchema = z3.object({\n manifest: ManifestSchema,\n repo: RepoRefSchema,\n directory: DirectorySchema.optional(),\n commitSha: CommitShaSchema\n});\nvar VersionRecordSchema = z3.object({\n version: z3.string(),\n commitSha: CommitShaSchema,\n manifest: ManifestSchema,\n publishedAt: z3.string()\n});\nvar WorkflowStatsSchema = z3.object({\n downloads: z3.number().int().nonnegative(),\n stars: z3.number().int().nonnegative()\n});\nvar WorkflowRecordSchema = z3.object({\n author: z3.string(),\n slug: z3.string(),\n repo: RepoRefSchema,\n directory: z3.string().optional(),\n version: z3.string(),\n commitSha: CommitShaSchema,\n manifest: ManifestSchema,\n files: FileListingSchema,\n stats: WorkflowStatsSchema,\n unlisted: z3.boolean().default(false),\n publishedAt: z3.string(),\n versions: z3.array(z3.string()).default([])\n});\nvar BrowseSortSchema = z3.enum([\"downloads\", \"newest\", \"name\"]);\nvar BrowseQuerySchema = z3.object({\n q: z3.string().optional(),\n tags: z3.union([z3.string(), z3.array(z3.string())]).transform(\n (v) => Array.isArray(v) ? v : v.split(\",\").map((s) => s.trim()).filter(Boolean)\n ).optional(),\n agentProvider: z3.enum(AGENT_PROVIDERS).optional(),\n sandboxProvider: z3.enum(SANDBOX_PROVIDERS).optional(),\n sort: BrowseSortSchema.default(\"downloads\"),\n page: z3.coerce.number().int().positive().default(1)\n});\nvar AgentBadgeSchema = z3.object({\n role: z3.string(),\n provider: z3.enum(AGENT_PROVIDERS),\n model: z3.string()\n});\nvar WorkflowCardSchema = z3.object({\n author: z3.string(),\n slug: z3.string(),\n name: z3.string(),\n description: z3.string(),\n tags: z3.array(z3.string()),\n agents: z3.array(AgentBadgeSchema),\n sandboxProviders: z3.array(z3.enum(SANDBOX_PROVIDERS)),\n downloads: z3.number().int().nonnegative(),\n stars: z3.number().int().nonnegative(),\n hasTopology: z3.boolean(),\n version: z3.string()\n});\nvar BrowseResponseSchema = z3.object({\n items: z3.array(WorkflowCardSchema),\n page: z3.number().int().positive(),\n pageSize: z3.number().int().positive(),\n total: z3.number().int().nonnegative()\n});\nvar DownloadPingSchema = z3.object({\n /** Random anonymous install id (no PII). */\n anonInstallId: z3.string().min(1)\n});\nvar ReportReasonSchema = z3.enum([\n \"malware\",\n \"secret-leak\",\n \"spam\",\n \"policy-violation\",\n \"other\"\n]);\nvar ReportRequestSchema = z3.object({\n reason: ReportReasonSchema,\n details: z3.string().max(2e3).optional()\n});\nvar SandcastleVersionsSchema = z3.object({\n latest: z3.string(),\n distTags: z3.record(z3.string(), z3.string()),\n refreshedAt: z3.string()\n});\nfunction errorEnvelope(code, message) {\n return { error: { code, message } };\n}\nexport {\n AGENT_FACTORY_NAMES,\n AGENT_PROVIDERS,\n ALLOWED_EXTENSIONS,\n ALLOWED_FILENAMES,\n ALLOWED_IMPORT_ROOTS,\n AgentBadgeSchema,\n AgentSchema,\n BrowseQuerySchema,\n BrowseResponseSchema,\n BrowseSortSchema,\n COMMON_SPDX_LICENSE_IDS,\n CommitShaSchema,\n DEFAULT_ENTRYPOINT,\n DEFAULT_REGISTRY_URL,\n DirectorySchema,\n DisclosuresSchema,\n DownloadPingSchema,\n ENV_NAME_REGEX,\n EnvVarSchema,\n ErrorCode,\n ErrorEnvelopeSchema,\n FACTORY_TO_PROVIDER,\n FileChecksumSchema,\n FileListingSchema,\n MANIFEST_JSON_SCHEMA,\n MAX_DESCRIPTION_LENGTH,\n MAX_FILE_COUNT,\n MAX_FILE_SIZE_BYTES,\n MAX_PACKAGE_SIZE_BYTES,\n MAX_TAGS,\n MIN_README_LENGTH,\n ManifestSchema,\n PAYLOAD_DIR,\n PRODUCT_NAME,\n PublishRequestSchema,\n RepoRefSchema,\n ReportReasonSchema,\n ReportRequestSchema,\n SANDBOX_PROVIDERS,\n SANDCASTLE_PACKAGE_NAME,\n SCHEMA_ID,\n SCHEMA_VERSION,\n SECRET_RULES,\n SLUG_REGEX,\n SandcastleCompatSchema,\n SandcastleVersionsSchema,\n TopologyEdgeSchema,\n TopologyNodeSchema,\n TopologySchema,\n VersionRecordSchema,\n WarningCode,\n WorkflowCardSchema,\n WorkflowRecordSchema,\n WorkflowStatsSchema,\n analyzeImports,\n createSourceFile,\n detectAgents,\n detectShellExpansions,\n errorEnvelope,\n extractHooks,\n findNamespaceUnsafePaths,\n forbiddenImports,\n hasSecret,\n hasShellExpansion,\n isAllowedImport,\n isKnownSpdxLicense,\n manifestJsonSchema,\n normalizePath,\n packageFromRecord,\n parseManifest,\n scanForSecrets,\n unsafePathReason,\n validatePackage\n};\n"],"mappings":"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","names":[]}
@@ -1,41 +0,0 @@
1
- import {
2
- LOCKFILE_NAME
3
- } from "./chunk-LP5MV76P.js";
4
- import {
5
- PAYLOAD_DIR
6
- } from "./chunk-AHRTPV2C.js";
7
-
8
- // src/lib/lockfile.ts
9
- import fsp from "fs/promises";
10
- import path from "path";
11
- function lockPath(projectRoot) {
12
- return path.join(projectRoot, PAYLOAD_DIR, LOCKFILE_NAME);
13
- }
14
- async function readLockfile(projectRoot) {
15
- try {
16
- const raw = await fsp.readFile(lockPath(projectRoot), "utf8");
17
- const parsed = JSON.parse(raw);
18
- if (parsed && Array.isArray(parsed.installs)) {
19
- return { lockfileVersion: 1, installs: parsed.installs };
20
- }
21
- } catch {
22
- }
23
- return { lockfileVersion: 1, installs: [] };
24
- }
25
- async function writeLockEntry(projectRoot, entry) {
26
- const lock = await readLockfile(projectRoot);
27
- const idx = lock.installs.findIndex((i) => i.dir === entry.dir);
28
- if (idx >= 0) lock.installs[idx] = entry;
29
- else lock.installs.push(entry);
30
- lock.installs.sort((a, b) => a.dir.localeCompare(b.dir));
31
- const file = lockPath(projectRoot);
32
- await fsp.mkdir(path.dirname(file), { recursive: true });
33
- await fsp.writeFile(file, `${JSON.stringify(lock, null, 2)}
34
- `, "utf8");
35
- }
36
-
37
- export {
38
- readLockfile,
39
- writeLockEntry
40
- };
41
- //# sourceMappingURL=chunk-GU4LRYYH.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/lockfile.ts"],"sourcesContent":["// The install lockfile (spec §5.4.6): `.sandcastle/runcastle.lock.json`. Records\n// what was installed so `runcastle update` can diff cleanly. Supports multiple\n// installs (namespaced) keyed by their install directory.\n\nimport fsp from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { PAYLOAD_DIR, LOCKFILE_NAME } from \"./config.js\";\n\nexport interface LockEntry {\n /** \"author/slug\" for registry installs, or \"github:owner/repo[/dir]\" for github: installs. */\n source: string;\n slug: string;\n author?: string;\n version: string;\n sha: string;\n registry?: string;\n /** Install directory relative to project root (e.g. \".sandcastle\" or \".sandcastle/<slug>\"). */\n dir: string;\n /** Installed target path (relative to project root) → sha256 of the written bytes. */\n files: Record<string, string>;\n installedAt: string;\n /** Entrypoint target path (relative to project root) — lets `run` skip guessing. */\n entrypoint?: string;\n /** Names of env vars the manifest declares as required. */\n requiredEnv?: string[];\n /** Sandbox providers the manifest declares (e.g. [\"docker\", \"podman\"]). */\n sandboxProviders?: string[];\n}\n\nexport interface Lockfile {\n lockfileVersion: 1;\n installs: LockEntry[];\n}\n\nfunction lockPath(projectRoot: string): string {\n return path.join(projectRoot, PAYLOAD_DIR, LOCKFILE_NAME);\n}\n\nexport async function readLockfile(projectRoot: string): Promise<Lockfile> {\n try {\n const raw = await fsp.readFile(lockPath(projectRoot), \"utf8\");\n const parsed = JSON.parse(raw) as Partial<Lockfile>;\n if (parsed && Array.isArray(parsed.installs)) {\n return { lockfileVersion: 1, installs: parsed.installs };\n }\n } catch {\n /* absent or unreadable → empty */\n }\n return { lockfileVersion: 1, installs: [] };\n}\n\n/** Upsert an install entry (keyed by install `dir`) and persist. */\nexport async function writeLockEntry(projectRoot: string, entry: LockEntry): Promise<void> {\n const lock = await readLockfile(projectRoot);\n const idx = lock.installs.findIndex((i) => i.dir === entry.dir);\n if (idx >= 0) lock.installs[idx] = entry;\n else lock.installs.push(entry);\n lock.installs.sort((a, b) => a.dir.localeCompare(b.dir));\n const file = lockPath(projectRoot);\n await fsp.mkdir(path.dirname(file), { recursive: true });\n await fsp.writeFile(file, `${JSON.stringify(lock, null, 2)}\\n`, \"utf8\");\n}\n"],"mappings":";;;;;;;;AAIA,OAAO,SAAS;AAChB,OAAO,UAAU;AA6BjB,SAAS,SAAS,aAA6B;AAC7C,SAAO,KAAK,KAAK,aAAa,aAAa,aAAa;AAC1D;AAEA,eAAsB,aAAa,aAAwC;AACzE,MAAI;AACF,UAAM,MAAM,MAAM,IAAI,SAAS,SAAS,WAAW,GAAG,MAAM;AAC5D,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,UAAU,MAAM,QAAQ,OAAO,QAAQ,GAAG;AAC5C,aAAO,EAAE,iBAAiB,GAAG,UAAU,OAAO,SAAS;AAAA,IACzD;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO,EAAE,iBAAiB,GAAG,UAAU,CAAC,EAAE;AAC5C;AAGA,eAAsB,eAAe,aAAqB,OAAiC;AACzF,QAAM,OAAO,MAAM,aAAa,WAAW;AAC3C,QAAM,MAAM,KAAK,SAAS,UAAU,CAAC,MAAM,EAAE,QAAQ,MAAM,GAAG;AAC9D,MAAI,OAAO,EAAG,MAAK,SAAS,GAAG,IAAI;AAAA,MAC9B,MAAK,SAAS,KAAK,KAAK;AAC7B,OAAK,SAAS,KAAK,CAAC,GAAG,MAAM,EAAE,IAAI,cAAc,EAAE,GAAG,CAAC;AACvD,QAAM,OAAO,SAAS,WAAW;AACjC,QAAM,IAAI,MAAM,KAAK,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AACvD,QAAM,IAAI,UAAU,MAAM,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,GAAM,MAAM;AACxE;","names":[]}
@@ -1,33 +0,0 @@
1
- import {
2
- DEFAULT_REGISTRY_URL,
3
- PRODUCT_NAME
4
- } from "./chunk-AHRTPV2C.js";
5
-
6
- // src/lib/config.ts
7
- import os from "os";
8
- import path from "path";
9
- var LOCKFILE_NAME = "runcastle.lock.json";
10
- var USER_AGENT = `${PRODUCT_NAME}-cli`;
11
- var GITHUB_CLIENT_ID = process.env.CASTELLAN_GITHUB_CLIENT_ID ?? "Iv1.castellan-placeholder";
12
- function configDir() {
13
- const xdg = process.env.XDG_CONFIG_HOME;
14
- const base = xdg && xdg.trim() ? xdg : path.join(os.homedir(), ".config");
15
- return path.join(base, PRODUCT_NAME);
16
- }
17
- function authFilePath() {
18
- return path.join(configDir(), "auth.json");
19
- }
20
- function resolveRegistry(flag) {
21
- const url = flag ?? process.env.CASTELLAN_REGISTRY ?? DEFAULT_REGISTRY_URL;
22
- return url.replace(/\/+$/, "");
23
- }
24
-
25
- export {
26
- LOCKFILE_NAME,
27
- USER_AGENT,
28
- GITHUB_CLIENT_ID,
29
- configDir,
30
- authFilePath,
31
- resolveRegistry
32
- };
33
- //# sourceMappingURL=chunk-LP5MV76P.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/config.ts"],"sourcesContent":["// CLI-local constants and paths. The product name and default registry come from\n// the schema package (single source of truth); everything here is CLI-specific.\n\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { DEFAULT_REGISTRY_URL, PAYLOAD_DIR, PRODUCT_NAME } from \"@castellan/schema\";\n\nexport { DEFAULT_REGISTRY_URL, PAYLOAD_DIR, PRODUCT_NAME };\n\n/** The lockfile name written under `.sandcastle/` (spec §5.4.6). */\nexport const LOCKFILE_NAME = \"runcastle.lock.json\";\n\n/** User-Agent sent on every registry / GitHub request. */\nexport const USER_AGENT = `${PRODUCT_NAME}-cli`;\n\n/**\n * GitHub OAuth app client id for the device flow (spec §5.3). No real app exists\n * in this build; override via env for local/CI testing. The device flow prints\n * the verification URL and code regardless, so a placeholder is harmless offline.\n */\nexport const GITHUB_CLIENT_ID =\n process.env.CASTELLAN_GITHUB_CLIENT_ID ?? \"Iv1.castellan-placeholder\";\n\n/**\n * Resolve the config directory: `$XDG_CONFIG_HOME/castellan` when set, else\n * `~/.config/castellan` on every platform (spec §5.3 — on Windows we still write\n * under the home `.config` dir, just without chmod).\n */\nexport function configDir(): string {\n const xdg = process.env.XDG_CONFIG_HOME;\n const base = xdg && xdg.trim() ? xdg : path.join(os.homedir(), \".config\");\n return path.join(base, PRODUCT_NAME);\n}\n\n/** Absolute path to the cached auth token file. */\nexport function authFilePath(): string {\n return path.join(configDir(), \"auth.json\");\n}\n\n/** Resolve the registry base URL: flag > env > default. */\nexport function resolveRegistry(flag?: string): string {\n const url = flag ?? process.env.CASTELLAN_REGISTRY ?? DEFAULT_REGISTRY_URL;\n return url.replace(/\\/+$/, \"\");\n}\n"],"mappings":";;;;;;AAGA,OAAO,QAAQ;AACf,OAAO,UAAU;AAMV,IAAM,gBAAgB;AAGtB,IAAM,aAAa,GAAG,YAAY;AAOlC,IAAM,mBACX,QAAQ,IAAI,8BAA8B;AAOrC,SAAS,YAAoB;AAClC,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,OAAO,OAAO,IAAI,KAAK,IAAI,MAAM,KAAK,KAAK,GAAG,QAAQ,GAAG,SAAS;AACxE,SAAO,KAAK,KAAK,MAAM,YAAY;AACrC;AAGO,SAAS,eAAuB;AACrC,SAAO,KAAK,KAAK,UAAU,GAAG,WAAW;AAC3C;AAGO,SAAS,gBAAgB,MAAuB;AACrD,QAAM,MAAM,QAAQ,QAAQ,IAAI,sBAAsB;AACtD,SAAO,IAAI,QAAQ,QAAQ,EAAE;AAC/B;","names":[]}
@@ -1,136 +0,0 @@
1
- import {
2
- doFetch,
3
- getFetch
4
- } from "./chunk-5VPKMXSV.js";
5
- import {
6
- USER_AGENT
7
- } from "./chunk-LP5MV76P.js";
8
- import {
9
- CliError
10
- } from "./chunk-6CWCR5SO.js";
11
-
12
- // src/lib/github.ts
13
- var GH_DEVICE_CODE_URL = "https://github.com/login/device/code";
14
- var GH_ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
15
- var GH_API = "https://api.github.com";
16
- var GH_RAW = "https://raw.githubusercontent.com";
17
- var OAUTH_SCOPES = "read:user read:org";
18
- var RealGitHubClient = class {
19
- fetchImpl;
20
- /** Injectable sleep so polling is instant in tests. */
21
- sleep;
22
- constructor(opts = {}) {
23
- this.fetchImpl = getFetch(opts.fetchImpl);
24
- this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
25
- }
26
- async requestDeviceCode(clientId) {
27
- const res = await doFetch(this.fetchImpl, GH_DEVICE_CODE_URL, {
28
- method: "POST",
29
- headers: { accept: "application/json", "content-type": "application/json", "user-agent": USER_AGENT },
30
- body: JSON.stringify({ client_id: clientId, scope: OAUTH_SCOPES })
31
- });
32
- if (!res.ok) {
33
- throw new CliError(`GitHub device-code request failed (HTTP ${res.status}): ${GH_DEVICE_CODE_URL}`, {
34
- code: "E_OAUTH"
35
- });
36
- }
37
- const j = await res.json();
38
- if (!j["device_code"] || !j["user_code"]) {
39
- throw new CliError(`GitHub device-code response was malformed: ${GH_DEVICE_CODE_URL}`, {
40
- code: "E_OAUTH",
41
- details: [typeof j["error_description"] === "string" ? j["error_description"] : ""]
42
- });
43
- }
44
- return {
45
- deviceCode: String(j["device_code"]),
46
- userCode: String(j["user_code"]),
47
- verificationUri: String(j["verification_uri"] ?? "https://github.com/login/device"),
48
- intervalSeconds: Number(j["interval"] ?? 5),
49
- expiresInSeconds: Number(j["expires_in"] ?? 900)
50
- };
51
- }
52
- async pollForToken(clientId, grant) {
53
- const deadline = Date.now() + grant.expiresInSeconds * 1e3;
54
- let intervalMs = Math.max(grant.intervalSeconds, 1) * 1e3;
55
- while (Date.now() < deadline) {
56
- await this.sleep(intervalMs);
57
- const res = await doFetch(this.fetchImpl, GH_ACCESS_TOKEN_URL, {
58
- method: "POST",
59
- headers: { accept: "application/json", "content-type": "application/json", "user-agent": USER_AGENT },
60
- body: JSON.stringify({
61
- client_id: clientId,
62
- device_code: grant.deviceCode,
63
- grant_type: "urn:ietf:params:oauth:grant-type:device_code"
64
- })
65
- });
66
- const j = await res.json().catch(() => ({}));
67
- if (typeof j["access_token"] === "string") return j["access_token"];
68
- const err = j["error"];
69
- if (err === "authorization_pending") continue;
70
- if (err === "slow_down") {
71
- intervalMs += 5e3;
72
- continue;
73
- }
74
- if (err === "expired_token" || err === "access_denied") {
75
- throw new CliError(
76
- `GitHub authorization ${err === "access_denied" ? "was denied" : "expired"}; run the command again`,
77
- { code: "E_OAUTH" }
78
- );
79
- }
80
- if (err) {
81
- throw new CliError(`GitHub authorization failed: ${String(err)}`, { code: "E_OAUTH" });
82
- }
83
- }
84
- throw new CliError("GitHub authorization timed out; run the command again", { code: "E_OAUTH" });
85
- }
86
- async getViewerLogin(token) {
87
- const url = `${GH_API}/user`;
88
- const res = await doFetch(this.fetchImpl, url, { headers: this.apiHeaders(token) });
89
- if (!res.ok) throw new CliError(`could not read GitHub user (HTTP ${res.status}): ${url}`, { code: "E_OAUTH" });
90
- const j = await res.json();
91
- return j.login ?? "unknown";
92
- }
93
- async commitExists(owner, repo, sha, token) {
94
- const url = `${GH_API}/repos/${owner}/${repo}/commits/${sha}`;
95
- const res = await doFetch(this.fetchImpl, url, { headers: this.apiHeaders(token) });
96
- if (res.status === 404 || res.status === 422) return false;
97
- if (!res.ok) {
98
- throw new CliError(`could not verify commit on GitHub (HTTP ${res.status}): ${url}`, { code: "E_GITHUB" });
99
- }
100
- return true;
101
- }
102
- async resolveRef(owner, repo, ref, token) {
103
- const url = `${GH_API}/repos/${owner}/${repo}/commits/${encodeURIComponent(ref)}`;
104
- const res = await doFetch(this.fetchImpl, url, { headers: this.apiHeaders(token) });
105
- if (res.status === 404 || res.status === 422) {
106
- throw new CliError(`ref "${ref}" not found on ${owner}/${repo}: ${url}`, { code: "E_NOT_FOUND" });
107
- }
108
- if (!res.ok) throw new CliError(`could not resolve ref on GitHub (HTTP ${res.status}): ${url}`, { code: "E_GITHUB" });
109
- const j = await res.json();
110
- if (!j.sha) throw new CliError(`GitHub returned no SHA for ref "${ref}": ${url}`, { code: "E_GITHUB" });
111
- return j.sha;
112
- }
113
- async fetchRawFile(owner, repo, sha, filePath) {
114
- const segs = filePath.split("/").map(encodeURIComponent).join("/");
115
- const url = `${GH_RAW}/${owner}/${repo}/${sha}/${segs}`;
116
- const res = await doFetch(this.fetchImpl, url, { headers: { "user-agent": USER_AGENT } });
117
- if (!res.ok) {
118
- throw new CliError(`could not fetch file from GitHub (HTTP ${res.status}): ${url}`, { code: "E_DOWNLOAD" });
119
- }
120
- return new Uint8Array(await res.arrayBuffer());
121
- }
122
- apiHeaders(token) {
123
- const h = {
124
- accept: "application/vnd.github+json",
125
- "user-agent": USER_AGENT,
126
- "x-github-api-version": "2022-11-28"
127
- };
128
- if (token) h["authorization"] = `Bearer ${token}`;
129
- return h;
130
- }
131
- };
132
-
133
- export {
134
- RealGitHubClient
135
- };
136
- //# sourceMappingURL=chunk-OJ356IMJ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/github.ts"],"sourcesContent":["// GitHub client (spec §5.3 device flow, §5.4.2 raw fallback, §5.3.4 SHA check).\n// Behind an interface so tests fake all network I/O. The concrete implementation\n// talks to github.com (device flow), api.github.com (commit lookup, user), and\n// raw.githubusercontent.com (file fallback).\n\nimport { CliError } from \"./errors.js\";\nimport { doFetch, getFetch, type FetchLike } from \"./http.js\";\nimport { USER_AGENT } from \"./config.js\";\n\nexport interface DeviceCodeGrant {\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n intervalSeconds: number;\n expiresInSeconds: number;\n}\n\nexport interface GitHubClient {\n /** Begin device flow: returns the code + URL to show the user. */\n requestDeviceCode(clientId: string): Promise<DeviceCodeGrant>;\n /** Poll until the user authorizes (or the grant expires). Returns a token. */\n pollForToken(clientId: string, grant: DeviceCodeGrant): Promise<string>;\n /** The authenticated user's login (for the confirmation line). */\n getViewerLogin(token: string): Promise<string>;\n /** True when `sha` exists on `owner/repo` (spec §5.3.4). */\n commitExists(owner: string, repo: string, sha: string, token?: string): Promise<boolean>;\n /** Fetch a raw file at a pinned SHA from raw.githubusercontent.com. */\n fetchRawFile(owner: string, repo: string, sha: string, filePath: string): Promise<Uint8Array>;\n /** Resolve a ref (branch/tag/sha/HEAD-ish) to a full commit SHA. */\n resolveRef(owner: string, repo: string, ref: string, token?: string): Promise<string>;\n}\n\nconst GH_DEVICE_CODE_URL = \"https://github.com/login/device/code\";\nconst GH_ACCESS_TOKEN_URL = \"https://github.com/login/oauth/access_token\";\nconst GH_API = \"https://api.github.com\";\nconst GH_RAW = \"https://raw.githubusercontent.com\";\n\n/**\n * OAuth scopes (spec §8.5, §8 / M4): the MINIMUM that lets the registry confirm\n * repo ownership without any write capability. `read:user` identifies the\n * publisher; `read:org` permits org membership/permission checks for org-owned\n * repos. We deliberately drop `public_repo` — it grants WRITE to public repos,\n * which publish never needs (ownership of a public repo is confirmed via the\n * unauthenticated/`read`-level repo endpoint). See docs/adr/0001.\n */\nexport const OAUTH_SCOPES = \"read:user read:org\";\n\nexport class RealGitHubClient implements GitHubClient {\n private readonly fetchImpl: FetchLike;\n /** Injectable sleep so polling is instant in tests. */\n private readonly sleep: (ms: number) => Promise<void>;\n\n constructor(opts: { fetchImpl?: FetchLike; sleep?: (ms: number) => Promise<void> } = {}) {\n this.fetchImpl = getFetch(opts.fetchImpl);\n this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));\n }\n\n async requestDeviceCode(clientId: string): Promise<DeviceCodeGrant> {\n const res = await doFetch(this.fetchImpl, GH_DEVICE_CODE_URL, {\n method: \"POST\",\n headers: { accept: \"application/json\", \"content-type\": \"application/json\", \"user-agent\": USER_AGENT },\n body: JSON.stringify({ client_id: clientId, scope: OAUTH_SCOPES }),\n });\n if (!res.ok) {\n throw new CliError(`GitHub device-code request failed (HTTP ${res.status}): ${GH_DEVICE_CODE_URL}`, {\n code: \"E_OAUTH\",\n });\n }\n const j = (await res.json()) as Record<string, unknown>;\n if (!j[\"device_code\"] || !j[\"user_code\"]) {\n throw new CliError(`GitHub device-code response was malformed: ${GH_DEVICE_CODE_URL}`, {\n code: \"E_OAUTH\",\n details: [typeof j[\"error_description\"] === \"string\" ? (j[\"error_description\"] as string) : \"\"],\n });\n }\n return {\n deviceCode: String(j[\"device_code\"]),\n userCode: String(j[\"user_code\"]),\n verificationUri: String(j[\"verification_uri\"] ?? \"https://github.com/login/device\"),\n intervalSeconds: Number(j[\"interval\"] ?? 5),\n expiresInSeconds: Number(j[\"expires_in\"] ?? 900),\n };\n }\n\n async pollForToken(clientId: string, grant: DeviceCodeGrant): Promise<string> {\n const deadline = Date.now() + grant.expiresInSeconds * 1000;\n let intervalMs = Math.max(grant.intervalSeconds, 1) * 1000;\n while (Date.now() < deadline) {\n await this.sleep(intervalMs);\n const res = await doFetch(this.fetchImpl, GH_ACCESS_TOKEN_URL, {\n method: \"POST\",\n headers: { accept: \"application/json\", \"content-type\": \"application/json\", \"user-agent\": USER_AGENT },\n body: JSON.stringify({\n client_id: clientId,\n device_code: grant.deviceCode,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }),\n });\n const j = (await res.json().catch(() => ({}))) as Record<string, unknown>;\n if (typeof j[\"access_token\"] === \"string\") return j[\"access_token\"] as string;\n const err = j[\"error\"];\n if (err === \"authorization_pending\") continue;\n if (err === \"slow_down\") {\n intervalMs += 5000;\n continue;\n }\n if (err === \"expired_token\" || err === \"access_denied\") {\n throw new CliError(\n `GitHub authorization ${err === \"access_denied\" ? \"was denied\" : \"expired\"}; run the command again`,\n { code: \"E_OAUTH\" },\n );\n }\n if (err) {\n throw new CliError(`GitHub authorization failed: ${String(err)}`, { code: \"E_OAUTH\" });\n }\n }\n throw new CliError(\"GitHub authorization timed out; run the command again\", { code: \"E_OAUTH\" });\n }\n\n async getViewerLogin(token: string): Promise<string> {\n const url = `${GH_API}/user`;\n const res = await doFetch(this.fetchImpl, url, { headers: this.apiHeaders(token) });\n if (!res.ok) throw new CliError(`could not read GitHub user (HTTP ${res.status}): ${url}`, { code: \"E_OAUTH\" });\n const j = (await res.json()) as { login?: string };\n return j.login ?? \"unknown\";\n }\n\n async commitExists(owner: string, repo: string, sha: string, token?: string): Promise<boolean> {\n const url = `${GH_API}/repos/${owner}/${repo}/commits/${sha}`;\n const res = await doFetch(this.fetchImpl, url, { headers: this.apiHeaders(token) });\n if (res.status === 404 || res.status === 422) return false;\n if (!res.ok) {\n throw new CliError(`could not verify commit on GitHub (HTTP ${res.status}): ${url}`, { code: \"E_GITHUB\" });\n }\n return true;\n }\n\n async resolveRef(owner: string, repo: string, ref: string, token?: string): Promise<string> {\n const url = `${GH_API}/repos/${owner}/${repo}/commits/${encodeURIComponent(ref)}`;\n const res = await doFetch(this.fetchImpl, url, { headers: this.apiHeaders(token) });\n if (res.status === 404 || res.status === 422) {\n throw new CliError(`ref \"${ref}\" not found on ${owner}/${repo}: ${url}`, { code: \"E_NOT_FOUND\" });\n }\n if (!res.ok) throw new CliError(`could not resolve ref on GitHub (HTTP ${res.status}): ${url}`, { code: \"E_GITHUB\" });\n const j = (await res.json()) as { sha?: string };\n if (!j.sha) throw new CliError(`GitHub returned no SHA for ref \"${ref}\": ${url}`, { code: \"E_GITHUB\" });\n return j.sha;\n }\n\n async fetchRawFile(owner: string, repo: string, sha: string, filePath: string): Promise<Uint8Array> {\n const segs = filePath.split(\"/\").map(encodeURIComponent).join(\"/\");\n const url = `${GH_RAW}/${owner}/${repo}/${sha}/${segs}`;\n const res = await doFetch(this.fetchImpl, url, { headers: { \"user-agent\": USER_AGENT } });\n if (!res.ok) {\n throw new CliError(`could not fetch file from GitHub (HTTP ${res.status}): ${url}`, { code: \"E_DOWNLOAD\" });\n }\n return new Uint8Array(await res.arrayBuffer());\n }\n\n private apiHeaders(token?: string): Record<string, string> {\n const h: Record<string, string> = {\n accept: \"application/vnd.github+json\",\n \"user-agent\": USER_AGENT,\n \"x-github-api-version\": \"2022-11-28\",\n };\n if (token) h[\"authorization\"] = `Bearer ${token}`;\n return h;\n }\n}\n"],"mappings":";;;;;;;;;;;;AAgCA,IAAM,qBAAqB;AAC3B,IAAM,sBAAsB;AAC5B,IAAM,SAAS;AACf,IAAM,SAAS;AAUR,IAAM,eAAe;AAErB,IAAM,mBAAN,MAA+C;AAAA,EACnC;AAAA;AAAA,EAEA;AAAA,EAEjB,YAAY,OAAyE,CAAC,GAAG;AACvF,SAAK,YAAY,SAAS,KAAK,SAAS;AACxC,SAAK,QAAQ,KAAK,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAAA,EAC1E;AAAA,EAEA,MAAM,kBAAkB,UAA4C;AAClE,UAAM,MAAM,MAAM,QAAQ,KAAK,WAAW,oBAAoB;AAAA,MAC5D,QAAQ;AAAA,MACR,SAAS,EAAE,QAAQ,oBAAoB,gBAAgB,oBAAoB,cAAc,WAAW;AAAA,MACpG,MAAM,KAAK,UAAU,EAAE,WAAW,UAAU,OAAO,aAAa,CAAC;AAAA,IACnE,CAAC;AACD,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,IAAI,SAAS,2CAA2C,IAAI,MAAM,MAAM,kBAAkB,IAAI;AAAA,QAClG,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AACA,UAAM,IAAK,MAAM,IAAI,KAAK;AAC1B,QAAI,CAAC,EAAE,aAAa,KAAK,CAAC,EAAE,WAAW,GAAG;AACxC,YAAM,IAAI,SAAS,8CAA8C,kBAAkB,IAAI;AAAA,QACrF,MAAM;AAAA,QACN,SAAS,CAAC,OAAO,EAAE,mBAAmB,MAAM,WAAY,EAAE,mBAAmB,IAAe,EAAE;AAAA,MAChG,CAAC;AAAA,IACH;AACA,WAAO;AAAA,MACL,YAAY,OAAO,EAAE,aAAa,CAAC;AAAA,MACnC,UAAU,OAAO,EAAE,WAAW,CAAC;AAAA,MAC/B,iBAAiB,OAAO,EAAE,kBAAkB,KAAK,iCAAiC;AAAA,MAClF,iBAAiB,OAAO,EAAE,UAAU,KAAK,CAAC;AAAA,MAC1C,kBAAkB,OAAO,EAAE,YAAY,KAAK,GAAG;AAAA,IACjD;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,UAAkB,OAAyC;AAC5E,UAAM,WAAW,KAAK,IAAI,IAAI,MAAM,mBAAmB;AACvD,QAAI,aAAa,KAAK,IAAI,MAAM,iBAAiB,CAAC,IAAI;AACtD,WAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,YAAM,KAAK,MAAM,UAAU;AAC3B,YAAM,MAAM,MAAM,QAAQ,KAAK,WAAW,qBAAqB;AAAA,QAC7D,QAAQ;AAAA,QACR,SAAS,EAAE,QAAQ,oBAAoB,gBAAgB,oBAAoB,cAAc,WAAW;AAAA,QACpG,MAAM,KAAK,UAAU;AAAA,UACnB,WAAW;AAAA,UACX,aAAa,MAAM;AAAA,UACnB,YAAY;AAAA,QACd,CAAC;AAAA,MACH,CAAC;AACD,YAAM,IAAK,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC5C,UAAI,OAAO,EAAE,cAAc,MAAM,SAAU,QAAO,EAAE,cAAc;AAClE,YAAM,MAAM,EAAE,OAAO;AACrB,UAAI,QAAQ,wBAAyB;AACrC,UAAI,QAAQ,aAAa;AACvB,sBAAc;AACd;AAAA,MACF;AACA,UAAI,QAAQ,mBAAmB,QAAQ,iBAAiB;AACtD,cAAM,IAAI;AAAA,UACR,wBAAwB,QAAQ,kBAAkB,eAAe,SAAS;AAAA,UAC1E,EAAE,MAAM,UAAU;AAAA,QACpB;AAAA,MACF;AACA,UAAI,KAAK;AACP,cAAM,IAAI,SAAS,gCAAgC,OAAO,GAAG,CAAC,IAAI,EAAE,MAAM,UAAU,CAAC;AAAA,MACvF;AAAA,IACF;AACA,UAAM,IAAI,SAAS,yDAAyD,EAAE,MAAM,UAAU,CAAC;AAAA,EACjG;AAAA,EAEA,MAAM,eAAe,OAAgC;AACnD,UAAM,MAAM,GAAG,MAAM;AACrB,UAAM,MAAM,MAAM,QAAQ,KAAK,WAAW,KAAK,EAAE,SAAS,KAAK,WAAW,KAAK,EAAE,CAAC;AAClF,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,SAAS,oCAAoC,IAAI,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,UAAU,CAAC;AAC9G,UAAM,IAAK,MAAM,IAAI,KAAK;AAC1B,WAAO,EAAE,SAAS;AAAA,EACpB;AAAA,EAEA,MAAM,aAAa,OAAe,MAAc,KAAa,OAAkC;AAC7F,UAAM,MAAM,GAAG,MAAM,UAAU,KAAK,IAAI,IAAI,YAAY,GAAG;AAC3D,UAAM,MAAM,MAAM,QAAQ,KAAK,WAAW,KAAK,EAAE,SAAS,KAAK,WAAW,KAAK,EAAE,CAAC;AAClF,QAAI,IAAI,WAAW,OAAO,IAAI,WAAW,IAAK,QAAO;AACrD,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,IAAI,SAAS,2CAA2C,IAAI,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,WAAW,CAAC;AAAA,IAC3G;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAW,OAAe,MAAc,KAAa,OAAiC;AAC1F,UAAM,MAAM,GAAG,MAAM,UAAU,KAAK,IAAI,IAAI,YAAY,mBAAmB,GAAG,CAAC;AAC/E,UAAM,MAAM,MAAM,QAAQ,KAAK,WAAW,KAAK,EAAE,SAAS,KAAK,WAAW,KAAK,EAAE,CAAC;AAClF,QAAI,IAAI,WAAW,OAAO,IAAI,WAAW,KAAK;AAC5C,YAAM,IAAI,SAAS,QAAQ,GAAG,kBAAkB,KAAK,IAAI,IAAI,KAAK,GAAG,IAAI,EAAE,MAAM,cAAc,CAAC;AAAA,IAClG;AACA,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,SAAS,yCAAyC,IAAI,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,WAAW,CAAC;AACpH,UAAM,IAAK,MAAM,IAAI,KAAK;AAC1B,QAAI,CAAC,EAAE,IAAK,OAAM,IAAI,SAAS,mCAAmC,GAAG,MAAM,GAAG,IAAI,EAAE,MAAM,WAAW,CAAC;AACtG,WAAO,EAAE;AAAA,EACX;AAAA,EAEA,MAAM,aAAa,OAAe,MAAc,KAAa,UAAuC;AAClG,UAAM,OAAO,SAAS,MAAM,GAAG,EAAE,IAAI,kBAAkB,EAAE,KAAK,GAAG;AACjE,UAAM,MAAM,GAAG,MAAM,IAAI,KAAK,IAAI,IAAI,IAAI,GAAG,IAAI,IAAI;AACrD,UAAM,MAAM,MAAM,QAAQ,KAAK,WAAW,KAAK,EAAE,SAAS,EAAE,cAAc,WAAW,EAAE,CAAC;AACxF,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,IAAI,SAAS,0CAA0C,IAAI,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,aAAa,CAAC;AAAA,IAC5G;AACA,WAAO,IAAI,WAAW,MAAM,IAAI,YAAY,CAAC;AAAA,EAC/C;AAAA,EAEQ,WAAW,OAAwC;AACzD,UAAM,IAA4B;AAAA,MAChC,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,wBAAwB;AAAA,IAC1B;AACA,QAAI,MAAO,GAAE,eAAe,IAAI,UAAU,KAAK;AAC/C,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -1,32 +0,0 @@
1
- // src/lib/output.ts
2
- import pc from "picocolors";
3
- var jsonMode = false;
4
- function setJsonMode(on) {
5
- jsonMode = on;
6
- }
7
- function isJsonMode() {
8
- return jsonMode;
9
- }
10
- function log(line = "") {
11
- if (jsonMode) return;
12
- process.stdout.write(`${line}
13
- `);
14
- }
15
- function logErr(line = "") {
16
- process.stderr.write(`${line}
17
- `);
18
- }
19
- function emitJson(value) {
20
- process.stdout.write(`${JSON.stringify(value, null, 2)}
21
- `);
22
- }
23
-
24
- export {
25
- pc,
26
- setJsonMode,
27
- isJsonMode,
28
- log,
29
- logErr,
30
- emitJson
31
- };
32
- //# sourceMappingURL=chunk-PRNBOQHW.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/output.ts"],"sourcesContent":["// Output helpers. A single module owns stdout/stderr writing and the global\n// `--json` mode so commands stay declarative. Color is delegated to picocolors,\n// which already honors NO_COLOR / FORCE_COLOR (important: the preview is a\n// security surface and is snapshot-tested with color disabled).\n\nimport pc from \"picocolors\";\n\nlet jsonMode = false;\n\nexport function setJsonMode(on: boolean): void {\n jsonMode = on;\n}\n\nexport function isJsonMode(): boolean {\n return jsonMode;\n}\n\n/** Human-readable line to stdout (suppressed in --json mode). */\nexport function log(line = \"\"): void {\n if (jsonMode) return;\n process.stdout.write(`${line}\\n`);\n}\n\n/** Diagnostic line to stderr (always shown; safe alongside --json stdout). */\nexport function logErr(line = \"\"): void {\n process.stderr.write(`${line}\\n`);\n}\n\n/** Emit a machine-readable JSON payload to stdout (only in --json mode paths). */\nexport function emitJson(value: unknown): void {\n process.stdout.write(`${JSON.stringify(value, null, 2)}\\n`);\n}\n\nexport { pc };\n"],"mappings":";AAKA,OAAO,QAAQ;AAEf,IAAI,WAAW;AAER,SAAS,YAAY,IAAmB;AAC7C,aAAW;AACb;AAEO,SAAS,aAAsB;AACpC,SAAO;AACT;AAGO,SAAS,IAAI,OAAO,IAAU;AACnC,MAAI,SAAU;AACd,UAAQ,OAAO,MAAM,GAAG,IAAI;AAAA,CAAI;AAClC;AAGO,SAAS,OAAO,OAAO,IAAU;AACtC,UAAQ,OAAO,MAAM,GAAG,IAAI;AAAA,CAAI;AAClC;AAGO,SAAS,SAAS,OAAsB;AAC7C,UAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,CAAI;AAC5D;","names":[]}
@@ -1,146 +0,0 @@
1
- import {
2
- PAYLOAD_DIR
3
- } from "./chunk-AHRTPV2C.js";
4
- import {
5
- CliError
6
- } from "./chunk-6CWCR5SO.js";
7
-
8
- // src/lib/checksum.ts
9
- import { createHash } from "crypto";
10
- function sha256Hex(bytes) {
11
- return createHash("sha256").update(bytes).digest("hex");
12
- }
13
-
14
- // src/lib/installer.ts
15
- import fsp from "fs/promises";
16
- import fs from "fs";
17
- import path from "path";
18
- import { createTwoFilesPatch } from "diff";
19
- function resolveInsideRoot(projectRoot, target) {
20
- const root = path.resolve(projectRoot);
21
- const abs = path.resolve(root, ...target.split("/"));
22
- const prefix = root.endsWith(path.sep) ? root : root + path.sep;
23
- if (abs !== root && !abs.startsWith(prefix)) {
24
- throw new CliError(
25
- `refusing to write outside the project: "${target}" resolves to ${abs} (possible path-traversal in the workflow manifest)`,
26
- { code: "E_UNSAFE_PATH" }
27
- );
28
- }
29
- return abs;
30
- }
31
- function mapTarget(packagePath, installDir) {
32
- const payloadPrefix = `${PAYLOAD_DIR}/`;
33
- if (installDir === PAYLOAD_DIR) return packagePath;
34
- if (packagePath === PAYLOAD_DIR) return installDir;
35
- if (packagePath.startsWith(payloadPrefix)) {
36
- return `${installDir}/${packagePath.slice(payloadPrefix.length)}`;
37
- }
38
- return packagePath;
39
- }
40
- function readExisting(projectRoot, target) {
41
- const abs = path.join(projectRoot, ...target.split("/"));
42
- try {
43
- if (!fs.existsSync(abs)) return null;
44
- return new Uint8Array(fs.readFileSync(abs));
45
- } catch {
46
- return null;
47
- }
48
- }
49
- function bytesEqual(a, b) {
50
- if (a.length !== b.length) return false;
51
- for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
52
- return true;
53
- }
54
- function planInstall(projectRoot, files, installDir) {
55
- return files.map((f) => {
56
- const target = mapTarget(f.path, installDir);
57
- const existing = readExisting(projectRoot, target);
58
- let action = "create";
59
- if (existing) action = bytesEqual(existing, f.bytes) ? "identical" : "overwrite";
60
- return {
61
- packagePath: f.path,
62
- target,
63
- bytes: f.bytes,
64
- sha256: f.sha256 ?? sha256Hex(f.bytes),
65
- action
66
- };
67
- });
68
- }
69
- function hasConflicts(plan) {
70
- return plan.some((p) => p.action === "overwrite");
71
- }
72
- function toPreviewPlan(plan) {
73
- return plan.map((p) => ({ target: p.target, action: p.action }));
74
- }
75
- var decoder = new TextDecoder("utf-8", { fatal: false });
76
- function renderDiff(projectRoot, planned) {
77
- const existing = readExisting(projectRoot, planned.target);
78
- const oldText = existing ? decoder.decode(existing) : "";
79
- const newText = decoder.decode(planned.bytes);
80
- return createTwoFilesPatch(
81
- `a/${planned.target}`,
82
- `b/${planned.target}`,
83
- oldText,
84
- newText,
85
- "current",
86
- "incoming"
87
- );
88
- }
89
- async function writePlan(projectRoot, plan) {
90
- const targets = plan.filter((p) => p.action !== "identical").map((p) => ({ p, abs: resolveInsideRoot(projectRoot, p.target) }));
91
- for (const { p, abs } of targets) {
92
- await fsp.mkdir(path.dirname(abs), { recursive: true });
93
- await fsp.writeFile(abs, p.bytes);
94
- }
95
- }
96
- async function ensurePayloadGitignore(projectRoot, installDir) {
97
- const abs = resolveInsideRoot(projectRoot, `${installDir}/.gitignore`);
98
- if (fs.existsSync(abs)) return;
99
- await fsp.mkdir(path.dirname(abs), { recursive: true });
100
- await fsp.writeFile(abs, "# added by runcastle: never commit secrets or run artifacts\n.env\nlogs/\nworktrees/\n", "utf8");
101
- }
102
- function postInstallNotes(manifest, installDir, detected) {
103
- const out = [];
104
- const envTarget = `${installDir}/.env`;
105
- const runArg = installDir === PAYLOAD_DIR ? "" : ` ${installDir}`;
106
- let step = 1;
107
- if (detected && !detected.version && !detected.range) {
108
- out.push(`${step++}. Install the runtime: npm install -D @ai-hero/sandcastle tsx`);
109
- out.push(` ${"(runcastle run offers to do this for you)"}`);
110
- }
111
- const requiredEnv = manifest.env.filter((e) => e.required).map((e) => e.name);
112
- if (requiredEnv.length > 0) {
113
- out.push(`${step++}. Copy ${envTarget}.example to ${envTarget} and set: ${requiredEnv.join(", ")}`);
114
- out.push(` (runcastle run creates the copy and tells you exactly what's missing)`);
115
- } else {
116
- out.push(`${step++}. Review ${envTarget}.example for any env vars you need to set.`);
117
- }
118
- const providers = manifest.sandboxProviders.length > 0 ? manifest.sandboxProviders : ["docker"];
119
- if (providers.includes("docker") || providers.includes("podman")) {
120
- out.push(`${step++}. Run it: npx runcastle run${runArg}`);
121
- out.push(` (checks your setup, builds the sandbox image on first run, then executes)`);
122
- } else if (providers.includes("vercel")) {
123
- out.push(`${step++}. This workflow targets the Vercel sandbox \u2014 see the Sandcastle docs for setup.`);
124
- } else {
125
- out.push(`${step++}. This workflow uses a custom sandbox \u2014 see its README.`);
126
- }
127
- if (manifest.postInstallNotes) {
128
- out.push("");
129
- out.push(`Author notes: ${manifest.postInstallNotes}`);
130
- }
131
- return out;
132
- }
133
-
134
- export {
135
- sha256Hex,
136
- resolveInsideRoot,
137
- mapTarget,
138
- planInstall,
139
- hasConflicts,
140
- toPreviewPlan,
141
- renderDiff,
142
- writePlan,
143
- ensurePayloadGitignore,
144
- postInstallNotes
145
- };
146
- //# sourceMappingURL=chunk-QTC5Y3LU.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/checksum.ts","../src/lib/installer.ts"],"sourcesContent":["// SHA-256 checksums. The tamper-evidence anchor (spec §8.2): the CLI verifies\n// every downloaded file against the registry's publish-time checksum, regardless\n// of where the bytes came from.\n\nimport { createHash } from \"node:crypto\";\n\n/** Lowercase hex SHA-256 of raw bytes. */\nexport function sha256Hex(bytes: Uint8Array): string {\n return createHash(\"sha256\").update(bytes).digest(\"hex\");\n}\n","// Shared install mechanics for `add` (registry and github: modes): map package\n// paths to install targets (with namespacing), compute the create/overwrite plan,\n// render per-file diffs, write bytes byte-for-byte, and generate post-install\n// notes. Never executes anything (spec §8.1).\n\nimport fsp from \"node:fs/promises\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createTwoFilesPatch } from \"diff\";\nimport type { Manifest } from \"@castellan/schema\";\nimport { PAYLOAD_DIR } from \"./config.js\";\nimport { CliError } from \"./errors.js\";\nimport { sha256Hex } from \"./checksum.js\";\nimport type { FileAction, PreviewFilePlanEntry } from \"./preview.js\";\n\nexport interface PlannedFile {\n /** Package-relative source path (e.g. \".sandcastle/main.ts\"). */\n packagePath: string;\n /** Target path relative to project root (post-namespacing). */\n target: string;\n bytes: Uint8Array;\n sha256: string;\n action: FileAction;\n}\n\n/**\n * Resolve a project-relative target to an absolute path and assert it stays\n * inside `projectRoot` (defense-in-depth against a malicious manifest whose\n * `files`/entrypoint escape the payload dir — §8 / C1). Aborts the whole\n * install if the resolved path would land outside the project.\n */\nexport function resolveInsideRoot(projectRoot: string, target: string): string {\n const root = path.resolve(projectRoot);\n const abs = path.resolve(root, ...target.split(\"/\"));\n const prefix = root.endsWith(path.sep) ? root : root + path.sep;\n if (abs !== root && !abs.startsWith(prefix)) {\n throw new CliError(\n `refusing to write outside the project: \"${target}\" resolves to ${abs} (possible path-traversal in the workflow manifest)`,\n { code: \"E_UNSAFE_PATH\" },\n );\n }\n return abs;\n}\n\n/** Map a package-relative path into the chosen install directory. */\nexport function mapTarget(packagePath: string, installDir: string): string {\n const payloadPrefix = `${PAYLOAD_DIR}/`;\n if (installDir === PAYLOAD_DIR) return packagePath;\n if (packagePath === PAYLOAD_DIR) return installDir;\n if (packagePath.startsWith(payloadPrefix)) {\n return `${installDir}/${packagePath.slice(payloadPrefix.length)}`;\n }\n return packagePath;\n}\n\nfunction readExisting(projectRoot: string, target: string): Uint8Array | null {\n const abs = path.join(projectRoot, ...target.split(\"/\"));\n try {\n if (!fs.existsSync(abs)) return null;\n return new Uint8Array(fs.readFileSync(abs));\n } catch {\n return null;\n }\n}\n\nfunction bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n\n/** Build the full install plan, resolving each file's action against disk. */\nexport function planInstall(\n projectRoot: string,\n files: { path: string; bytes: Uint8Array; sha256?: string }[],\n installDir: string,\n): PlannedFile[] {\n return files.map((f) => {\n const target = mapTarget(f.path, installDir);\n const existing = readExisting(projectRoot, target);\n let action: FileAction = \"create\";\n if (existing) action = bytesEqual(existing, f.bytes) ? \"identical\" : \"overwrite\";\n return {\n packagePath: f.path,\n target,\n bytes: f.bytes,\n sha256: f.sha256 ?? sha256Hex(f.bytes),\n action,\n };\n });\n}\n\n/** True when any planned file would overwrite a differing existing file. */\nexport function hasConflicts(plan: PlannedFile[]): boolean {\n return plan.some((p) => p.action === \"overwrite\");\n}\n\nexport function toPreviewPlan(plan: PlannedFile[]): PreviewFilePlanEntry[] {\n return plan.map((p) => ({ target: p.target, action: p.action }));\n}\n\nconst decoder = new TextDecoder(\"utf-8\", { fatal: false });\n\n/** A unified diff between the existing file and the incoming bytes (text only). */\nexport function renderDiff(projectRoot: string, planned: PlannedFile): string {\n const existing = readExisting(projectRoot, planned.target);\n const oldText = existing ? decoder.decode(existing) : \"\";\n const newText = decoder.decode(planned.bytes);\n return createTwoFilesPatch(\n `a/${planned.target}`,\n `b/${planned.target}`,\n oldText,\n newText,\n \"current\",\n \"incoming\",\n );\n}\n\n/** Write every planned file byte-for-byte, creating parent directories. */\nexport async function writePlan(projectRoot: string, plan: PlannedFile[]): Promise<void> {\n // Assert containment for EVERY target before writing a single byte, so a\n // traversal entry aborts the whole install atomically (§8 / C1).\n const targets = plan\n .filter((p) => p.action !== \"identical\")\n .map((p) => ({ p, abs: resolveInsideRoot(projectRoot, p.target) }));\n for (const { p, abs } of targets) {\n await fsp.mkdir(path.dirname(abs), { recursive: true });\n await fsp.writeFile(abs, p.bytes);\n }\n}\n\n/**\n * Ensure the install dir has a .gitignore covering secrets and run artifacts.\n * `sandcastle init` writes one; installed payloads usually don't ship one, and\n * without it the user's `.env` (holding a real token) is one `git add -A` away\n * from being committed. Never overwrites an author-provided file.\n */\nexport async function ensurePayloadGitignore(projectRoot: string, installDir: string): Promise<void> {\n const abs = resolveInsideRoot(projectRoot, `${installDir}/.gitignore`);\n if (fs.existsSync(abs)) return;\n await fsp.mkdir(path.dirname(abs), { recursive: true });\n await fsp.writeFile(abs, \"# added by runcastle: never commit secrets or run artifacts\\n.env\\nlogs/\\nworktrees/\\n\", \"utf8\");\n}\n\n/**\n * Generate the post-install output (spec §5.4.5). The happy path is exactly two\n * steps — fill in .env, then `runcastle run` (which installs the runtime,\n * builds the image, and executes). The runtime-install hint appears only when\n * sandcastle isn't already a dependency of the project.\n */\nexport function postInstallNotes(\n manifest: Manifest,\n installDir: string,\n detected?: { version?: string; range?: string },\n): string[] {\n const out: string[] = [];\n const envTarget = `${installDir}/.env`;\n const runArg = installDir === PAYLOAD_DIR ? \"\" : ` ${installDir}`;\n let step = 1;\n\n if (detected && !detected.version && !detected.range) {\n out.push(`${step++}. Install the runtime: npm install -D @ai-hero/sandcastle tsx`);\n out.push(` ${\"(runcastle run offers to do this for you)\"}`);\n }\n\n const requiredEnv = manifest.env.filter((e) => e.required).map((e) => e.name);\n if (requiredEnv.length > 0) {\n out.push(`${step++}. Copy ${envTarget}.example to ${envTarget} and set: ${requiredEnv.join(\", \")}`);\n out.push(` (runcastle run creates the copy and tells you exactly what's missing)`);\n } else {\n out.push(`${step++}. Review ${envTarget}.example for any env vars you need to set.`);\n }\n\n const providers = manifest.sandboxProviders.length > 0 ? manifest.sandboxProviders : [\"docker\"];\n if (providers.includes(\"docker\") || providers.includes(\"podman\")) {\n out.push(`${step++}. Run it: npx runcastle run${runArg}`);\n out.push(` (checks your setup, builds the sandbox image on first run, then executes)`);\n } else if (providers.includes(\"vercel\")) {\n out.push(`${step++}. This workflow targets the Vercel sandbox — see the Sandcastle docs for setup.`);\n } else {\n out.push(`${step++}. This workflow uses a custom sandbox — see its README.`);\n }\n\n if (manifest.postInstallNotes) {\n out.push(\"\");\n out.push(`Author notes: ${manifest.postInstallNotes}`);\n }\n return out;\n}\n"],"mappings":"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","names":[]}