@rallycry/conveyor-agent 10.13.54 → 10.13.56

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.
@@ -9,7 +9,7 @@ import {
9
9
  readAgentVersion,
10
10
  redactToken,
11
11
  reportBootMilestone
12
- } from "./chunk-KCB7CSWJ.js";
12
+ } from "./chunk-7765OQU5.js";
13
13
  import {
14
14
  workbenchPort
15
15
  } from "./chunk-4VUQ2NPF.js";
@@ -42,9 +42,14 @@ function parseGitPlan(raw) {
42
42
  throw new Error("bundle missing field: gitPlan");
43
43
  }
44
44
  const obj = raw;
45
+ const provider = obj.provider === "forgejo" ? "forgejo" : "github";
46
+ const repoOwner = requireString(obj, "repoOwner");
47
+ const repoName = requireString(obj, "repoName");
45
48
  const plan = {
46
- repoOwner: requireString(obj, "repoOwner"),
47
- repoName: requireString(obj, "repoName"),
49
+ provider,
50
+ cloneUrl: typeof obj.cloneUrl === "string" ? obj.cloneUrl : `https://github.com/${repoOwner}/${repoName}.git`,
51
+ repoOwner,
52
+ repoName,
48
53
  branch: requireString(obj, "branch"),
49
54
  baseBranch: requireString(obj, "baseBranch")
50
55
  };
@@ -57,9 +62,17 @@ function parseBundle(text) {
57
62
  const raw = JSON.parse(text);
58
63
  const envVarsRaw = raw.envVars;
59
64
  const envVars = envVarsRaw !== null && envVarsRaw !== void 0 && typeof envVarsRaw === "object" ? envVarsRaw : {};
65
+ const githubToken = typeof raw.githubToken === "string" ? raw.githubToken : void 0;
66
+ const credentialRaw = raw.gitCredential;
67
+ const gitCredential = typeof credentialRaw === "object" && credentialRaw !== null ? {
68
+ username: requireString(credentialRaw, "username"),
69
+ secret: requireString(credentialRaw, "secret")
70
+ } : { username: "x-access-token", secret: githubToken ?? "" };
71
+ if (!gitCredential.secret) throw new Error("bundle missing field: gitCredential");
60
72
  const typed = {
61
73
  sessionJwt: requireString(raw, "sessionJwt"),
62
- githubToken: requireString(raw, "githubToken"),
74
+ ...githubToken ? { githubToken } : {},
75
+ gitCredential,
63
76
  anthropicKey: requireString(raw, "anthropicKey"),
64
77
  gcpToken: requireString(raw, "gcpToken"),
65
78
  envVars,
@@ -117,8 +130,14 @@ function buildChildEnv(opts) {
117
130
  if (v) child[k] = v;
118
131
  };
119
132
  setIf("CONVEYOR_TASK_TOKEN", bundle.sessionJwt);
120
- setIf("CONVEYOR_GITHUB_TOKEN", bundle.githubToken);
121
- setIf("GH_TOKEN", bundle.githubToken);
133
+ setIf("CONVEYOR_GIT_PROVIDER", bundle.gitPlan.provider);
134
+ setIf("CONVEYOR_GIT_CLONE_URL", bundle.gitPlan.cloneUrl);
135
+ setIf("CONVEYOR_GIT_USERNAME", bundle.gitCredential.username);
136
+ setIf("CONVEYOR_GIT_SECRET", bundle.gitCredential.secret);
137
+ if (bundle.gitPlan.provider === "github") {
138
+ setIf("CONVEYOR_GITHUB_TOKEN", bundle.githubToken ?? bundle.gitCredential.secret);
139
+ setIf("GH_TOKEN", bundle.githubToken ?? bundle.gitCredential.secret);
140
+ }
122
141
  setIf("ANTHROPIC_API_KEY", bundle.anthropicKey);
123
142
  setIf("CLOUDSDK_AUTH_ACCESS_TOKEN", bundle.gcpToken);
124
143
  setIf("REPO_OWNER", bundle.gitPlan.repoOwner);
@@ -920,7 +939,7 @@ function parseReferenceRepos(refsJson) {
920
939
  async function runPreReadyBinds(workspace, bundle, git, log) {
921
940
  const graphifyEnv = computeGraphifyEnv(process.env, bundle.gitPlan.repoName, isDir2);
922
941
  bindGraphifyBundle(workspace, graphifyEnv, log);
923
- await ensureGrimoireSubmodule(workspace, bundle.githubToken, git, log);
942
+ await ensureGrimoireSubmodule(workspace, bundle.githubToken ?? "", git, log);
924
943
  linkGrimoireSkills(workspace, log);
925
944
  await neutralizeGrimoirePointer(workspace, git, log);
926
945
  }
@@ -1297,4 +1316,4 @@ export {
1297
1316
  runBoot,
1298
1317
  workbenchBootSteps
1299
1318
  };
1300
- //# sourceMappingURL=boot-6X5ZZG3B.js.map
1319
+ //# sourceMappingURL=boot-RW7SNO6X.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/boot/index.ts","../src/boot/bundle.ts","../src/boot/graphify.ts","../src/boot/logger.ts","../src/boot/types.ts","../src/boot/pipeline.ts","../src/boot/poll.ts","../src/boot/exec.ts","../src/boot/supervisor.ts","../src/boot/crash-report.ts","../src/boot/user-home.ts","../src/boot/sshd.ts","../src/boot/workspace-extras.ts","../src/boot/workbench-boot-deps.ts","../src/boot/workbench-boot.ts"],"sourcesContent":["/* oxlint-disable import/max-dependencies -- boot composition module: it wires the Task 1-8 pieces (poll/unpack/supervisor/user-home/workbench) into the two role pipelines; splitting the wiring would scatter the boot sequence */\n/**\n * `conveyor-agent boot` — the vnext pod boot entry. Composes the tested Task\n * 1-8 pieces into two role pipelines (agent / workbench) and the legacy-launch\n * tombstone predicate the CLI guards on. The pod runs the BAKED agent — there\n * is no runtime self-update (removed after it caused the 2026-07-19 eviction\n * outage); a new agent version ships via publish → auto-rebake.\n *\n * The bash entrypoint (runtime/entrypoint.sh) is retired: a split-only pod\n * runs `conveyor-agent boot` in each container, keyed by CONVEYOR_CONTAINER_ROLE.\n * Every network/spawn/fs seam is injected via `BootDeps` (production defaults in\n * `defaultBootDeps`) so the dispatch tests run offline.\n */\nimport { spawn } from \"node:child_process\";\nimport { statSync } from \"node:fs\";\nimport { hostname as osHostname } from \"node:os\";\nimport { readAgentVersion } from \"../runner/session-runner-helpers.js\";\nimport { workbenchPort } from \"../workbench/mode.js\";\nimport { DEFAULT_WORKBENCH_PORT } from \"../workbench/protocol.js\";\nimport { buildChildEnv, decodeJwtClaims } from \"./bundle.js\";\nimport { computeGraphifyEnv } from \"./graphify.js\";\nimport { createBootLogger } from \"./logger.js\";\nimport { runPipeline } from \"./pipeline.js\";\nimport { pollBootstrapBundle } from \"./poll.js\";\nimport { defaultExec, type ExecDeps } from \"./exec.js\";\nimport { superviseRunner } from \"./supervisor.js\";\nimport type { BootContext, BootLogger, BootRole, BootStep } from \"./types.js\";\nimport { reclaimHomeOwnership, wireUserHome } from \"./user-home.js\";\nimport { runWorkbenchBoot } from \"./workbench-boot.js\";\nimport { defaultWorkbenchBootDeps, type WorkbenchBootDeps } from \"./workbench-boot-deps.js\";\n\nconst HOME_DIR = \"/home/conveyor\";\nconst USER_HOME_MOUNT = \"/mnt/conveyor-users\";\n\n// Leaf module so cli.ts's guard doesn't eagerly load the whole boot graph.\nexport { isLegacyEntrypointLaunch, TOMBSTONE_MESSAGE } from \"./tombstone.js\";\n\n/** The single injectable seam bundle — network (fetch/poll), spawn, exec, and\n * identity — so dispatch/pipeline composition runs without side effects. */\nexport interface BootDeps {\n fetchFn: typeof fetch;\n sleepFn: (ms: number) => Promise<void>;\n spawnFn: typeof spawn;\n exec: ExecDeps[\"exec\"];\n dirExists: (path: string) => boolean;\n hostname: string;\n log: BootLogger;\n}\n\nexport function defaultBootDeps(): BootDeps {\n return {\n fetchFn: fetch,\n sleepFn: (ms) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms);\n }),\n spawnFn: spawn,\n exec: defaultExec,\n dirExists: (path) => {\n try {\n return statSync(path).isDirectory();\n } catch {\n return false;\n }\n },\n hostname: osHostname(),\n log: createBootLogger(),\n };\n}\n\nfunction errMsg(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/** Resolves when `signal` aborts (or is already aborted); never rejects. */\nfunction whenAborted(signal: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n if (signal.aborted) {\n resolve();\n return;\n }\n signal.addEventListener(\"abort\", () => resolve(), { once: true });\n });\n}\n\n/**\n * The agent container's boot: poll bootstrap → unpack the bundle into the\n * runner's child env (with graphify env merged) → reclaim home ownership\n * (best-effort) → wire the persistent user-home. superviseRunner runs after\n * the pipeline — it IS the container's foreground process, not a step. Each\n * post-poll step no-ops when the bundle is absent (SIGTERM aborted standby).\n */\nexport function agentBootSteps(\n deps: BootDeps = defaultBootDeps(),\n signal: AbortSignal = new AbortController().signal,\n): BootStep[] {\n // Started alongside the bootstrap poll (it only touches local fs ownership,\n // ~0.7s of chown) so the two overlap; the reclaimHome step awaits it. Runs\n // even when standby is SIGTERM-aborted — a chown of home is harmless.\n let reclaim: Promise<void> | undefined;\n return [\n {\n name: \"pollBootstrap\",\n critical: true,\n run: async (ctx) => {\n reclaim = reclaimHomeOwnership(HOME_DIR, deps.exec, ctx.log).catch(() => undefined);\n const bundle = await pollBootstrapBundle(ctx.apiUrl, ctx.bootstrapToken, {\n fetchFn: deps.fetchFn,\n sleepFn: deps.sleepFn,\n log: ctx.log,\n signal,\n });\n if (bundle) ctx.bundle = bundle;\n },\n },\n {\n name: \"unpackBundle\",\n critical: true,\n run: (ctx) => {\n if (ctx.bundle) {\n const claims = decodeJwtClaims(ctx.bundle.sessionJwt);\n ctx.claims = claims;\n const childEnv = buildChildEnv({\n base: process.env,\n bundle: ctx.bundle,\n claims,\n hostname: ctx.hostname,\n log: ctx.log,\n });\n const graphifyEnv = computeGraphifyEnv(\n process.env,\n ctx.bundle.gitPlan.repoName,\n deps.dirExists,\n );\n ctx.childEnv = { ...childEnv, ...graphifyEnv };\n }\n return Promise.resolve();\n },\n },\n {\n name: \"reclaimHome\",\n critical: false,\n run: async (ctx) => {\n if (!ctx.bundle) return;\n // Already in flight since the poll started — this step is just the\n // barrier so wireUserHome never runs on unreclaimed ownership.\n await (reclaim ?? reclaimHomeOwnership(HOME_DIR, deps.exec, ctx.log));\n },\n },\n {\n name: \"wireUserHome\",\n critical: true,\n run: (ctx) => {\n if (ctx.bundle) {\n wireUserHome({\n home: HOME_DIR,\n userHomeMount: USER_HOME_MOUNT,\n userId: ctx.childEnv?.CONVEYOR_USER_ID,\n projectId: ctx.childEnv?.CONVEYOR_PROJECT_ID ?? ctx.childEnv?.PROJECT_ID,\n sharedDir: process.env.CONVEYOR_SHARED_DIR,\n log: ctx.log,\n });\n }\n return Promise.resolve();\n },\n },\n ];\n}\n\n/**\n * Declarative manifest of the workbench container's critical boot path\n * (poll → unpack → startDaemon), pinned by boot-dispatch.test.ts. The PRODUCTION\n * executor is `runWorkbenchBoot` (Task 7): it runs these three critical\n * operations AND the post-listen deferred jobs (ensure /workspaces/repo, git\n * prep, user-home, sshd, reclaim) that a flat pipeline cannot express. This\n * function documents the contract those three steps must honor; the run bodies\n * delegate to the same deps seam so it stays a faithful (if partial) executor.\n */\nexport function workbenchBootSteps(\n deps: WorkbenchBootDeps = defaultWorkbenchBootDeps(),\n): BootStep[] {\n return [\n {\n name: \"pollBootstrap\",\n critical: true,\n run: async (ctx) => {\n const bundle = await deps.pollBundle(ctx);\n if (bundle) ctx.bundle = bundle;\n },\n },\n {\n name: \"unpackBundle\",\n critical: true,\n run: (ctx) => {\n if (ctx.bundle) ctx.childEnv = deps.unpack(ctx, ctx.bundle);\n return Promise.resolve();\n },\n },\n {\n name: \"startDaemon\",\n critical: true,\n run: async (ctx) => {\n await deps.startDaemon({\n port: workbenchPort() ?? DEFAULT_WORKBENCH_PORT,\n token: ctx.bootstrapToken,\n version: readAgentVersion() ?? \"unknown\",\n // The manifest has no GitPrepJob, so it must never claim readiness —\n // \"pending\" is the safe answer if anyone ever executes these steps\n // directly instead of via runWorkbenchBoot (which serves live state).\n getGitStatus: () => ({ t: \"gitStatus\", state: \"pending\" }),\n });\n },\n },\n ];\n}\n\nasync function runAgentRole(\n ctx: BootContext,\n deps: BootDeps,\n signal: AbortSignal,\n): Promise<number> {\n try {\n await runPipeline(agentBootSteps(deps, signal), ctx);\n } catch (err) {\n // A critical step (incl. the poll's 401 BootstrapUnauthorizedError, wrapped\n // by runPipeline) — the pipeline already logged FATAL. Pod identity invalid.\n ctx.log.error(`[boot] agent boot failed: ${errMsg(err)}`);\n return 1;\n }\n if (signal.aborted || !ctx.bundle) {\n ctx.log.info(\"[boot] SIGTERM during standby — exiting.\");\n return 0;\n }\n // The pod runs whatever agent version was BAKED into the image — there is no\n // runtime self-update. A new agent ships via publish → auto-rebake → new\n // pods; a booting pod never downloads or version-checks the agent (the old\n // npm-preflight self-update caused the 2026-07-19 ephemeral-eviction outage\n // and is gone).\n // The agent container's /workspaces/repo is a dead overlay (entrypoint.sh:907)\n // — every workspace op is proxied to the workbench daemon; run from ~.\n process.chdir(HOME_DIR);\n // superviseRunner owns LAUNCH_MARKER (touched post-bind, before first spawn)\n // and the SIGTERM drain once the runner is live.\n return superviseRunner({\n childEnv: ctx.childEnv ?? {},\n cwd: HOME_DIR,\n apiUrl: ctx.apiUrl,\n bootstrapToken: ctx.bootstrapToken,\n log: ctx.log,\n spawnFn: deps.spawnFn,\n signal,\n });\n}\n\nasync function runWorkbenchRole(\n ctx: BootContext,\n deps: BootDeps,\n signal: AbortSignal,\n): Promise<number> {\n // The daemon runs the BAKED agent — no runtime self-update (see runAgentRole).\n // runWorkbenchBoot parks forever on success; the race resolves only when the\n // signal aborts (SIGTERM), which is our clean exit. Its internal poll gets the\n // same signal so a standby SIGTERM aborts the in-flight fetch too.\n try {\n await Promise.race([\n runWorkbenchBoot(ctx, {\n pollBundle: (workbenchCtx) =>\n pollBootstrapBundle(workbenchCtx.apiUrl, workbenchCtx.bootstrapToken, {\n fetchFn: deps.fetchFn,\n sleepFn: deps.sleepFn,\n log: workbenchCtx.log,\n signal,\n }),\n }),\n whenAborted(signal),\n ]);\n } catch (err) {\n ctx.log.error(`[boot] workbench boot failed: ${errMsg(err)}`);\n return 1;\n }\n // ctx.bundle distinguishes a serving workbench from one still in standby —\n // pod-death forensics reads this line.\n ctx.log.info(\n ctx.bundle\n ? \"[boot] SIGTERM — workbench shutting down.\"\n : \"[boot] SIGTERM during standby — exiting.\",\n );\n return 0;\n}\n\n/**\n * The `conveyor-agent boot` process. Resolves the pod exit code (cli.ts does\n * `process.exit(await runBoot(...))`).\n *\n * - `--preflight-update` → NO-OP (exit 0). There is no runtime self-update any\n * more: the pod runs the baked agent. Kept as an inert accepted flag only so\n * an OLD baked shim that still invokes it can't fail the boot.\n * - else: CONVEYOR_CONTAINER_ROLE selects the pipeline (fatal-loud on anything\n * but agent/workbench — vnext pods are split-only), after asserting the two\n * required identity env vars are present.\n */\nexport async function runBoot(argv: string[], deps: BootDeps = defaultBootDeps()): Promise<number> {\n const { log } = deps;\n\n if (argv.includes(\"--preflight-update\")) {\n log.info(\"[boot] --preflight-update is a no-op (baked agent, no runtime self-update)\");\n return 0;\n }\n\n const role = process.env.CONVEYOR_CONTAINER_ROLE;\n if (role !== \"agent\" && role !== \"workbench\") {\n log.error(\"[boot] FATAL missing/invalid CONVEYOR_CONTAINER_ROLE — vnext pods are split-only\");\n return 1;\n }\n\n const apiUrl = process.env.CONVEYOR_API_URL;\n const bootstrapToken = process.env.POD_BOOTSTRAP_TOKEN;\n if (!apiUrl || !bootstrapToken) {\n // Mirrors entrypoint.sh:161-162 — no identity, nothing to poll for.\n log.error(\"[boot] FATAL missing required env: CONVEYOR_API_URL + POD_BOOTSTRAP_TOKEN\");\n return 1;\n }\n\n // One controller drives every abort path: standby poll (resolves null →\n // exit 0), the workbench park race, and the live runner drain.\n const controller = new AbortController();\n const abort = (): void => controller.abort();\n process.on(\"SIGTERM\", abort);\n process.on(\"SIGINT\", abort);\n\n const ctx: BootContext = {\n role: role as BootRole,\n apiUrl,\n bootstrapToken,\n hostname: deps.hostname,\n log,\n };\n\n const code = await (role === \"workbench\"\n ? runWorkbenchRole(ctx, deps, controller.signal)\n : runAgentRole(ctx, deps, controller.signal));\n // Settle any concurrent work still in flight (e.g. the workbench's poll\n // promise if the role returned via SIGTERM before it settled) — nothing may\n // outlive the role's verdict.\n controller.abort();\n return code;\n}\n","import type { BootstrapBundle, GitPlan } from \"../setup/bootstrap-bundle-types.js\";\nimport type { BootLogger, SessionClaims } from \"./types.js\";\n\n/**\n * Ports entrypoint.sh:222-344 (bundle field extraction, JWT claim decode,\n * mode mapping, env injection + denylist).\n *\n * DELIBERATE DEVIATION from the bash on empty values: the literal entrypoint\n * exported most credential/identity fields UNCONDITIONALLY — `export\n * FOO=$(... | jq -r '.f // empty')` yields an empty-string-PRESENT variable\n * when the field is missing (jq's `// empty` only empties the substitution,\n * the `export` still happens). That covered CONVEYOR_TASK_TOKEN,\n * CONVEYOR_GITHUB_TOKEN/GH_TOKEN, ANTHROPIC_API_KEY,\n * CLOUDSDK_AUTH_ACCESS_TOKEN, REPO_OWNER/REPO_NAME/BRANCH,\n * CONVEYOR_SESSION_ID, and CONVEYOR_WORKSPACE_ID; only CONVEYOR_TASK_ID and\n * CONVEYOR_PROJECT_ID were truly absent-on-empty in bash too (guarded\n * export / explicit unset). vnext instead omits ANY empty-valued key\n * uniformly (`setIf` in buildChildEnv): absent is the safer contract —\n * presence-keyed consumers (gh, anthropic tooling) misread an empty-present\n * GH_TOKEN/ANTHROPIC_API_KEY as \"credentials configured\" — and every known\n * in-repo consumer checks truthiness, so the change is otherwise inert.\n *\n * `parseBundle` throws on a genuinely missing/wrong-type required field (so\n * boot fails loud instead of shipping \"null\" into a git URL or env var) and\n * normalizes `envVars: null` to `{}`. Unknown top-level keys are preserved\n * on the returned object — the bundle wire contract can grow fields this\n * package doesn't know about yet.\n */\nfunction requireString(source: Record<string, unknown>, field: string): string {\n const value = source[field];\n if (typeof value !== \"string\") {\n throw new Error(`bundle missing field: ${field}`);\n }\n return value;\n}\n\nfunction parseGitPlan(raw: unknown): GitPlan {\n if (typeof raw !== \"object\" || raw === null) {\n throw new Error(\"bundle missing field: gitPlan\");\n }\n const obj = raw as Record<string, unknown>;\n const provider = obj.provider === \"forgejo\" ? \"forgejo\" : \"github\";\n const repoOwner = requireString(obj, \"repoOwner\");\n const repoName = requireString(obj, \"repoName\");\n const plan: GitPlan = {\n provider,\n cloneUrl:\n typeof obj.cloneUrl === \"string\"\n ? obj.cloneUrl\n : `https://github.com/${repoOwner}/${repoName}.git`,\n repoOwner,\n repoName,\n branch: requireString(obj, \"branch\"),\n baseBranch: requireString(obj, \"baseBranch\"),\n };\n if (typeof obj.checkoutRef === \"string\") {\n plan.checkoutRef = obj.checkoutRef;\n }\n return plan;\n}\n\nexport function parseBundle(text: string): BootstrapBundle {\n const raw = JSON.parse(text) as Record<string, unknown>;\n const envVarsRaw = raw.envVars;\n const envVars: Record<string, string> =\n envVarsRaw !== null && envVarsRaw !== undefined && typeof envVarsRaw === \"object\"\n ? (envVarsRaw as Record<string, string>)\n : {};\n const githubToken = typeof raw.githubToken === \"string\" ? raw.githubToken : undefined;\n const credentialRaw = raw.gitCredential;\n const gitCredential =\n typeof credentialRaw === \"object\" && credentialRaw !== null\n ? {\n username: requireString(credentialRaw as Record<string, unknown>, \"username\"),\n secret: requireString(credentialRaw as Record<string, unknown>, \"secret\"),\n }\n : { username: \"x-access-token\", secret: githubToken ?? \"\" };\n if (!gitCredential.secret) throw new Error(\"bundle missing field: gitCredential\");\n const typed = {\n sessionJwt: requireString(raw, \"sessionJwt\"),\n ...(githubToken ? { githubToken } : {}),\n gitCredential,\n anthropicKey: requireString(raw, \"anthropicKey\"),\n gcpToken: requireString(raw, \"gcpToken\"),\n envVars,\n gitPlan: parseGitPlan(raw.gitPlan),\n };\n return { ...raw, ...typed } as BootstrapBundle;\n}\n\n/**\n * Decodes the non-secret session identity claims out of the task JWT's\n * middle segment — base64url alphabet (`-`/`_`), padding restored before\n * decode. Ports the inline `node -e` one-liner at entrypoint.sh:236. Any\n * failure (too few segments, invalid base64, non-JSON payload) yields `{}`\n * rather than throwing: an unreadable JWT degrades to \"no claims\", it never\n * aborts boot — the bootstrap poll step already validated the token against\n * the API before this runs.\n */\nexport function decodeJwtClaims(jwt: string): SessionClaims {\n try {\n const segment = jwt.split(\".\")[1] ?? \"\";\n const normalized = segment.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = normalized + \"=\".repeat((4 - (normalized.length % 4)) % 4);\n const json = Buffer.from(padded, \"base64\").toString(\"utf8\");\n const parsed: unknown = JSON.parse(json);\n if (typeof parsed !== \"object\" || parsed === null) {\n return {};\n }\n return parsed as SessionClaims;\n } catch {\n return {};\n }\n}\n\n// Mode mapping, comments carried from entrypoint.sh:261-287. Order is load-bearing —\n// a wrong mapping here crash-looped pods every 10s (agent CLI exits \"Invalid\n// CONVEYOR_MODE\"). Do not reorder without re-reading the history in that range.\nexport function resolveModeEnv(claims: SessionClaims): Record<string, string> {\n // Review sessions are keyed on the session MODE claim, not role; the runner\n // mode is spelled \"code-review\" — bare \"review\" crash-loops the CLI.\n if (claims.mode === \"review\") return { CONVEYOR_MODE: \"code-review\" };\n if (claims.mode === \"pack\") return { CONVEYOR_MODE: \"pack\" };\n // adhoc is also task-less with a projectId — it must win over the pm branch.\n if (claims.mode === \"adhoc\") return { CONVEYOR_MODE: \"adhoc\" };\n if (!claims.taskId && claims.projectId) return { CONVEYOR_MODE: \"pm\" };\n return {};\n}\n\n// A bundle key that isn't a valid shell/env identifier would make `export`\n// eval arbitrary content in the old bash world; the vnext child-env object\n// has no such injection risk, but we keep the same validation so a garbage\n// key can never silently shadow something unexpected. A handful of names\n// would hijack the boot itself (PATH swaps every binary below; LD_PRELOAD\n// injects code into them) — denylisted regardless of validity.\nexport const ENV_KEY_DENYLIST: ReadonlySet<string> = new Set([\n \"PATH\",\n \"HOME\",\n \"LD_PRELOAD\",\n \"SHELL\",\n]);\nconst IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nexport interface BuildChildEnvOptions {\n base: NodeJS.ProcessEnv;\n bundle: BootstrapBundle;\n claims: SessionClaims;\n hostname: string;\n log: BootLogger;\n /** default \"/workspaces/repo\" */\n workspaceDir?: string;\n}\n\nexport function buildChildEnv(opts: BuildChildEnvOptions): Record<string, string> {\n const { base, bundle, claims, hostname, log } = opts;\n const child: Record<string, string> = {};\n for (const [k, v] of Object.entries(base)) {\n if (typeof v === \"string\") child[k] = v;\n }\n for (const [key, value] of Object.entries(bundle.envVars ?? {})) {\n if (!IDENTIFIER_RE.test(key)) {\n log.warn(`[boot] WARN skipping invalid env key from bundle: '${key}'`);\n continue;\n }\n if (ENV_KEY_DENYLIST.has(key)) {\n log.warn(`[boot] WARN skipping denylisted env key from bundle: '${key}'`);\n continue;\n }\n child[key] = value;\n }\n const setIf = (k: string, v: string | undefined): void => {\n if (v) child[k] = v;\n };\n setIf(\"CONVEYOR_TASK_TOKEN\", bundle.sessionJwt);\n setIf(\"CONVEYOR_GIT_PROVIDER\", bundle.gitPlan.provider);\n setIf(\"CONVEYOR_GIT_CLONE_URL\", bundle.gitPlan.cloneUrl);\n setIf(\"CONVEYOR_GIT_USERNAME\", bundle.gitCredential.username);\n setIf(\"CONVEYOR_GIT_SECRET\", bundle.gitCredential.secret);\n if (bundle.gitPlan.provider === \"github\") {\n setIf(\"CONVEYOR_GITHUB_TOKEN\", bundle.githubToken ?? bundle.gitCredential.secret);\n setIf(\"GH_TOKEN\", bundle.githubToken ?? bundle.gitCredential.secret);\n }\n setIf(\"ANTHROPIC_API_KEY\", bundle.anthropicKey);\n setIf(\"CLOUDSDK_AUTH_ACCESS_TOKEN\", bundle.gcpToken);\n setIf(\"REPO_OWNER\", bundle.gitPlan.repoOwner);\n setIf(\"REPO_NAME\", bundle.gitPlan.repoName);\n setIf(\"BRANCH\", bundle.gitPlan.branch);\n // CONVEYOR_TASK_ID is absent (never empty) for task-less sessions.\n setIf(\"CONVEYOR_TASK_ID\", claims.taskId);\n setIf(\"CONVEYOR_PROJECT_ID\", claims.projectId);\n setIf(\"CONVEYOR_SESSION_ID\", claims.sessionId);\n setIf(\"CONVEYOR_WORKSPACE_ID\", claims.workspaceId);\n Object.assign(child, resolveModeEnv(claims));\n child.CLAUDESPACE_NAME = hostname;\n child.CONVEYOR_WORKSPACE = opts.workspaceDir ?? \"/workspaces/repo\";\n child.CONVEYOR_BOOT_VNEXT = \"1\";\n // POD_BOOTSTRAP_TOKEN and CONVEYOR_API_URL are never touched here — they pass\n // through unchanged from `base` (copied above). POD_BOOTSTRAP_TOKEN is the\n // credential-refresh key: the agent re-polls with it to swap in a fresh\n // githubToken/sessionJwt in place (entrypoint.sh:338-340).\n return child;\n}\n","/**\n * Port of entrypoint.sh:494-519 (`configure_graphify_env`). A locally\n * published graph lives in the shared GCS-FUSE user-home bucket at a fixed\n * mount point, under `users/_shared/graphify/<repo>/latest` — this computes\n * the env var contract the rest of boot (and the agent process) consumes,\n * without touching the filesystem itself (that's `dirExists`, injected so\n * this stays pure/testable).\n */\nconst USER_HOME_MOUNT = \"/mnt/conveyor-users\";\n\nexport interface GraphifyEnvInput {\n CONVEYOR_GRAPHIFY_DISABLE?: string;\n CONVEYOR_GRAPHIFY_SLUG?: string;\n CONVEYOR_GRAPHIFY_SHARED_ROOT?: string;\n CONVEYOR_GRAPHIFY_DIR?: string;\n CONVEYOR_GRAPHIFY_GRAPH?: string;\n}\n\nexport function computeGraphifyEnv(\n env: GraphifyEnvInput,\n repoName: string | undefined,\n dirExists: (p: string) => boolean,\n): Record<string, string> {\n if (env.CONVEYOR_GRAPHIFY_DISABLE === \"1\") {\n return {};\n }\n\n const slug = env.CONVEYOR_GRAPHIFY_SLUG || repoName;\n if (!slug) {\n return {};\n }\n\n const primaryRoot = `${USER_HOME_MOUNT}/users/_shared/graphify`;\n const legacyRoot = `${USER_HOME_MOUNT}/_shared/graphify`;\n let sharedRoot = env.CONVEYOR_GRAPHIFY_SHARED_ROOT;\n if (!sharedRoot) {\n // Primary root wins whenever it exists (or legacy doesn't) — legacy is\n // only chosen when primary is missing AND legacy is actually present.\n sharedRoot = dirExists(primaryRoot) || !dirExists(legacyRoot) ? primaryRoot : legacyRoot;\n }\n\n const dir = env.CONVEYOR_GRAPHIFY_DIR || `${sharedRoot}/${slug}/latest`;\n const graph = env.CONVEYOR_GRAPHIFY_GRAPH || `${dir}/graph.json`;\n\n return {\n CONVEYOR_GRAPHIFY_SLUG: slug,\n CONVEYOR_GRAPHIFY_SHARED_ROOT: sharedRoot,\n CONVEYOR_GRAPHIFY_DIR: dir,\n CONVEYOR_GRAPHIFY_GRAPH: graph,\n };\n}\n","import { appendFileSync } from \"node:fs\";\nimport type { BootLogger } from \"./types.js\";\n\nexport const BOOTSTRAP_LOG_PATH = \"/tmp/claudespace-bootstrap.log\";\n\nexport function createBootLogger(filePath: string | undefined = BOOTSTRAP_LOG_PATH): BootLogger {\n const emit = (line: string): void => {\n process.stdout.write(`${line}\\n`);\n if (filePath) {\n try {\n appendFileSync(filePath, `${line}\\n`);\n } catch {\n // The file sink is best-effort; stdout is the durable channel (kubectl logs).\n }\n }\n };\n return { info: emit, warn: emit, error: emit };\n}\n","import type { BootstrapBundle } from \"../setup/bootstrap-bundle-types.js\";\n\nexport type BootRole = \"agent\" | \"workbench\";\n\nexport interface BootLogger {\n info(msg: string): void;\n warn(msg: string): void;\n error(msg: string): void;\n}\n\nexport interface SessionClaims {\n taskId?: string;\n projectId?: string;\n sessionId?: string;\n workspaceId?: string;\n mode?: string;\n}\n\nexport interface BootContext {\n role: BootRole;\n apiUrl: string;\n bootstrapToken: string;\n hostname: string;\n log: BootLogger;\n /** Filled by the poll step. */\n bundle?: BootstrapBundle;\n /** Filled by the unpack step. */\n claims?: SessionClaims;\n /** Filled by the unpack step — the env handed to children (runner/daemon jobs). */\n childEnv?: Record<string, string>;\n}\n\nexport interface BootStep {\n name: string;\n /** true → a throw aborts boot (fatal-loud). false → degrade-and-continue (warn). */\n critical: boolean;\n run(ctx: BootContext): Promise<void>;\n}\n\nexport class BootFatalError extends Error {\n constructor(\n public readonly step: string,\n message: string,\n options?: { cause?: unknown },\n ) {\n super(`[boot] FATAL step=${step}: ${message}`, options);\n this.name = \"BootFatalError\";\n }\n}\n","import { BootFatalError, type BootContext, type BootStep } from \"./types.js\";\n\nexport async function runPipeline(steps: BootStep[], ctx: BootContext): Promise<void> {\n const t0 = Date.now();\n const timings: string[] = [];\n for (const step of steps) {\n const s0 = Date.now();\n try {\n await step.run(ctx);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (step.critical) {\n ctx.log.error(`[boot] FATAL step=${step.name}: ${msg}`);\n throw err instanceof BootFatalError\n ? err\n : new BootFatalError(step.name, msg, { cause: err });\n }\n ctx.log.warn(`[boot] WARN step=${step.name} degraded: ${msg}`);\n }\n const ms = Date.now() - s0;\n timings.push(`${step.name}:${ms}`);\n ctx.log.info(`[boot] step=${step.name} ms=${ms}`);\n }\n ctx.log.info(\n `[boot] timeline role=${ctx.role} total=${Date.now() - t0} steps=${timings.join(\",\")}`,\n );\n}\n","import type { BootstrapBundle } from \"../setup/bootstrap-bundle-types.js\";\nimport { parseBundle } from \"./bundle.js\";\nimport type { BootLogger } from \"./types.js\";\n\n/**\n * Ports the standby poll loop (entrypoint.sh:186-220): poll\n * `GET ${apiUrl}/api/v3/pods/bootstrap` until the reconciler binds this pod\n * (200 + bundle body) or the bootstrap token is rejected (401, fatal). 204\n * (still unbound) and any network error both retry after `pollIntervalMs`.\n *\n * DELIBERATELY NOT `setup/bootstrap-poll.ts` (`pollUntilBound`) — that\n * helper has deadline/throw semantics for a different caller. Boot instead\n * needs abort support (SIGTERM during standby → clean exit) and periodic\n * progress logging, so it gets its own poll loop.\n */\nexport class BootstrapUnauthorizedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"BootstrapUnauthorizedError\";\n }\n}\n\nexport interface PollDeps {\n fetchFn: typeof fetch;\n sleepFn: (ms: number) => Promise<void>;\n log: BootLogger;\n /** Aborted (e.g. SIGTERM during standby) → resolves null; caller exits 0. */\n signal?: AbortSignal;\n /** default 2000 */\n pollIntervalMs?: number;\n}\n\nconst PROGRESS_LOG_EVERY = 30;\nconst DEFAULT_POLL_INTERVAL_MS = 2_000;\n\n/**\n * Resolves after `ms` via `sleepFn`, or immediately when `signal` aborts —\n * whichever comes first. Without the race, a SIGTERM landing mid-sleep would\n * ride out the full poll interval before the loop-top abort check could run.\n * The abort listener is removed on normal completion so repeated polls don't\n * accumulate listeners on a long-lived signal.\n */\nfunction sleepUnlessAborted(\n sleepFn: (ms: number) => Promise<void>,\n ms: number,\n signal?: AbortSignal,\n): Promise<void> {\n if (!signal) return sleepFn(ms);\n if (signal.aborted) return Promise.resolve();\n return new Promise<void>((resolve) => {\n const onAbort = (): void => {\n resolve();\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n void sleepFn(ms).then(() => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve();\n });\n });\n}\n\n/**\n * Resolves the parsed bundle once bound, or `null` if `deps.signal` is\n * aborted first. Never logs the response body — it carries credentials.\n */\nexport async function pollBootstrapBundle(\n apiUrl: string,\n token: string,\n deps: PollDeps,\n): Promise<BootstrapBundle | null> {\n const interval = deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n let pollCount = 0;\n\n while (true) {\n if (deps.signal?.aborted) return null;\n\n let res: Response | undefined;\n try {\n // The signal is threaded into fetch so a SIGTERM during shutdown can\n // abort a hung request instead of blocking past the grace period.\n res = await deps.fetchFn(`${apiUrl}/api/v3/pods/bootstrap`, {\n headers: { Authorization: `Bearer ${token}` },\n signal: deps.signal,\n });\n } catch {\n // An abort mid-fetch surfaces here as an AbortError rejection —\n // that's shutdown, not a network failure; bail out immediately.\n if (deps.signal?.aborted) return null;\n // Network error — treat the same as a still-unbound (204) poll and retry.\n res = undefined;\n }\n\n if (res?.status === 200) {\n return parseBundle(await res.text());\n }\n if (res?.status === 401) {\n throw new BootstrapUnauthorizedError(\"bootstrap token rejected (401) — pod identity invalid\");\n }\n\n pollCount++;\n if (pollCount % PROGRESS_LOG_EVERY === 0) {\n deps.log.info(`[boot] Still waiting for bind (poll #${pollCount})...`);\n }\n await sleepUnlessAborted(deps.sleepFn, interval, deps.signal);\n }\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport type { BootLogger } from \"./types.js\";\n\n/**\n * The injectable exec seam shared across the boot steps (home reclaim, sshd,\n * user-home wiring). Formerly lived in a `self-update` module alongside an npm\n * preflight; the runtime self-update is gone (the pod runs the baked agent —\n * see boot/index.ts), so this is now purely the exec plumbing.\n */\nexport interface ExecDeps {\n exec(cmd: string, args: string[], opts: { timeoutMs: number }): Promise<{ stdout: string }>;\n log: BootLogger;\n}\n\nconst execFileAsync = promisify(execFile);\n\nexport function defaultExec(\n cmd: string,\n args: string[],\n opts: { timeoutMs: number },\n): Promise<{ stdout: string }> {\n return execFileAsync(cmd, args, { timeout: opts.timeoutMs });\n}\n","import { spawn as spawnChildProcess, type ChildProcess } from \"node:child_process\";\nimport { appendFileSync, statSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { reportAgentCrash } from \"./crash-report.js\";\nimport type { BootLogger } from \"./types.js\";\n\n/**\n * Ports the supervised launch loop (entrypoint.sh:901-978): spawn\n * `conveyor-agent`, restart it on a nonzero exit up to `AGENT_CRASH_MAX`\n * times with a backoff between attempts, and report every crash to the API.\n * A clean exit (0) or an aborted (SIGTERM) supervision both return without\n * further restarts.\n *\n * Liveness contract: this supervisor writes the markers\n * `apps/api/.../dockerfiles/liveness.sh` reads — `LAUNCH_MARKER`\n * (/tmp/conveyor-agent-launching) once supervision starts (post-bind, before\n * the first spawn), arming the probe, and `RESTARTING_MARKER` touched before\n * each restart backoff so the probe stays green across backoff sleeps.\n * (Same names the late-era bash entrypoint used, so one liveness.sh serves\n * both worlds during the rollout window.)\n */\n// Mirrors bootstrap-route.ts:35.\nexport const AGENT_CRASH_MAX = 3;\nexport const AGENT_LOG_PATH = \"/tmp/claudespace-agent.log\";\n// Cap the agent log so a long-lived, chatty pod can't fill the 10Gi ephemeral\n// disk and get evicted. Rotation is a single truncate-on-overflow (no rolling\n// N files): pod stdout already tees the full stream, so the file is only a\n// same-pod convenience tail, not the archive.\nexport const AGENT_LOG_MAX_BYTES = 16 * 1024 * 1024;\n\nconst LAUNCH_MARKER_NAME = \"conveyor-agent-launching\";\nconst RESTARTING_MARKER_NAME = \"conveyor-agent-restarting\";\nexport const LAUNCH_MARKER = `/tmp/${LAUNCH_MARKER_NAME}`;\nexport const RESTARTING_MARKER = `/tmp/${RESTARTING_MARKER_NAME}`;\n\nconst DEFAULT_CRASH_BACKOFF_MS = 10_000;\n// Under the pod's 60s terminationGracePeriodSeconds.\nconst DEFAULT_DRAIN_TIMEOUT_MS = 45_000;\nconst DEFAULT_MARKER_DIR = \"/tmp\";\n\nexport interface SuperviseOptions {\n childEnv: Record<string, string>;\n cwd: string;\n apiUrl: string;\n bootstrapToken: string;\n log: BootLogger;\n /** Injected in tests to substitute a fake binary for `conveyor-agent`. */\n spawnFn?: typeof spawnChildProcess;\n reportFn?: typeof reportAgentCrash;\n crashBackoffMs?: number;\n drainTimeoutMs?: number;\n /** default \"/tmp\"; tests point this at a tmpdir. */\n markerDir?: string;\n /**\n * Test-visible SIGTERM stand-in. Production wiring (`process.on(\"SIGTERM\",\n * () => controller.abort())`) happens in Task 9 — this module only reacts\n * to the signal, it never installs the process listener itself.\n */\n signal?: AbortSignal;\n}\n\n/** Touch (create-or-refresh) a liveness marker. Best-effort — a marker-dir\n * permission problem must never take down agent supervision. */\nfunction touchMarker(path: string, log: BootLogger): void {\n try {\n writeFileSync(path, \"\");\n } catch (err) {\n log.warn(\n `[boot] WARN failed to write liveness marker ${path}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n}\n\n/**\n * Build a size-bounded appender for the agent log. Tracks the running file size\n * (seeded from any pre-existing file so a restart doesn't forget prior growth)\n * and, once the next chunk would cross `maxBytes`, truncates the file and starts\n * fresh with that chunk rather than growing without bound. Best-effort\n * throughout (`report_agent_crash`-style `|| true`): a full disk or permission\n * error must never kill supervision.\n */\nexport function createLogAppender(path: string, maxBytes: number): (chunk: Buffer) => void {\n let size = 0;\n try {\n size = statSync(path).size;\n } catch {\n size = 0;\n }\n return (chunk: Buffer): void => {\n try {\n if (size + chunk.length > maxBytes) {\n // Rotate by truncation — drop the old log and start over with this\n // chunk (pod stdout still carries the full stream).\n writeFileSync(path, chunk);\n size = chunk.length;\n } else {\n appendFileSync(path, chunk);\n size += chunk.length;\n }\n } catch {\n // Best-effort log file — see doc comment above.\n }\n };\n}\n\n/**\n * Tees the child's stdout/stderr to our own stdout (so pod logs still show\n * it) and appends to the size-bounded agent log via `appendLog`. Chunks are\n * written as they arrive — no ordering guarantee is claimed or needed beyond\n * \"as they arrive\".\n */\nfunction teeChildOutput(child: ChildProcess, appendLog: (chunk: Buffer) => void): void {\n const onData = (chunk: Buffer): void => {\n process.stdout.write(chunk);\n appendLog(chunk);\n };\n child.stdout?.on(\"data\", onData);\n child.stderr?.on(\"data\", onData);\n}\n\nfunction spawnAgent(spawnFn: typeof spawnChildProcess, opts: SuperviseOptions): ChildProcess {\n // argv `[]`, PATH-resolved (no shell) so a preflight npm-install update\n // lands on the next spawn without any code here caring about it.\n return spawnFn(\"conveyor-agent\", [], {\n cwd: opts.cwd,\n env: opts.childEnv,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n}\n\n/** Resolves the child's exit code. A signal-kill (code null) counts as\n * nonzero — the only caller that kills the child itself (drain) already\n * short-circuits before this matters for restart bookkeeping. */\nfunction waitForExit(child: ChildProcess): Promise<number> {\n return new Promise((resolve) => {\n child.once(\"exit\", (code, signal) => {\n resolve(code ?? (signal ? 1 : 0));\n });\n child.once(\"error\", () => resolve(1));\n });\n}\n\n/** Never resolves unless `signal` fires (or is already aborted). */\nfunction whenAborted(signal: AbortSignal | undefined): Promise<void> {\n return new Promise((resolve) => {\n if (!signal) return;\n if (signal.aborted) {\n resolve();\n return;\n }\n signal.addEventListener(\"abort\", () => resolve(), { once: true });\n });\n}\n\n/**\n * Sleeps `ms`, resolving early if `signal` aborts — mirrors poll.ts's\n * module-private `sleepUnlessAborted` so a SIGTERM landing mid-backoff\n * doesn't ride out the full `crashBackoffMs` before draining can start.\n */\nfunction sleepUnlessAborted(ms: number, signal?: AbortSignal): Promise<void> {\n if (!signal) {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n }\n if (signal.aborted) return Promise.resolve();\n return new Promise((resolve) => {\n const onAbort = (): void => {\n clearTimeout(timer);\n resolve();\n };\n const timer = setTimeout(() => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\n/**\n * Forward SIGTERM to the child, wait up to `drainTimeoutMs` for it to exit\n * on its own, then SIGKILL. Always resolves 0 — draining is a clean\n * shutdown from the supervisor's point of view regardless of the child's\n * final exit code.\n */\nasync function drainChild(\n child: ChildProcess,\n exitPromise: Promise<number>,\n drainTimeoutMs: number,\n log: BootLogger,\n): Promise<number> {\n log.info(\"[boot] SIGTERM received, draining agent...\");\n child.kill(\"SIGTERM\");\n\n const TIMED_OUT = Symbol(\"drain-timeout\");\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<typeof TIMED_OUT>((resolve) => {\n timer = setTimeout(() => resolve(TIMED_OUT), drainTimeoutMs);\n });\n const winner = await Promise.race([exitPromise, timeout]);\n if (timer) clearTimeout(timer);\n\n if (winner === TIMED_OUT) {\n log.warn(`[boot] agent did not exit within drainTimeoutMs=${drainTimeoutMs}ms — SIGKILL`);\n child.kill(\"SIGKILL\");\n await exitPromise;\n }\n return 0;\n}\n\nexport async function superviseRunner(opts: SuperviseOptions): Promise<number> {\n const spawnFn = opts.spawnFn ?? spawnChildProcess;\n const reportFn = opts.reportFn ?? reportAgentCrash;\n const crashBackoffMs = opts.crashBackoffMs ?? DEFAULT_CRASH_BACKOFF_MS;\n const drainTimeoutMs = opts.drainTimeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS;\n const markerDir = opts.markerDir ?? DEFAULT_MARKER_DIR;\n const launchMarkerPath = join(markerDir, LAUNCH_MARKER_NAME);\n const restartingMarkerPath = join(markerDir, RESTARTING_MARKER_NAME);\n\n // Supervision starting (post-bind) arms the liveness probe — see the\n // liveness-contract doc comment above.\n touchMarker(launchMarkerPath, opts.log);\n\n // One size-bounded appender shared across every restart so the cap tracks the\n // whole supervision lifetime, not a single spawn.\n const appendLog = createLogAppender(AGENT_LOG_PATH, AGENT_LOG_MAX_BYTES);\n\n let attempt = 0;\n while (true) {\n attempt++;\n opts.log.info(\"[boot] Launching agent...\");\n const child = spawnAgent(spawnFn, opts);\n teeChildOutput(child, appendLog);\n const exitPromise = waitForExit(child);\n\n const winner = await Promise.race([\n exitPromise.then((code) => ({ type: \"exit\" as const, code })),\n whenAborted(opts.signal).then(() => ({ type: \"abort\" as const })),\n ]);\n\n if (winner.type === \"abort\") {\n return await drainChild(child, exitPromise, drainTimeoutMs, opts.log);\n }\n\n const exitCode = winner.code;\n if (exitCode === 0) {\n opts.log.info(\"[boot] agent exited cleanly (code 0), shutting down pod.\");\n return 0;\n }\n\n if (attempt >= AGENT_CRASH_MAX) {\n opts.log.error(\n `[boot] agent crashed (code ${exitCode}) — attempt cap ${AGENT_CRASH_MAX} reached, giving up.`,\n );\n await reportFn(opts.apiUrl, opts.bootstrapToken, { exitCode, attempt, final: true });\n return 1;\n }\n\n touchMarker(restartingMarkerPath, opts.log);\n await reportFn(opts.apiUrl, opts.bootstrapToken, { exitCode, attempt, final: false });\n opts.log.warn(\n `[boot] agent crashed (code ${exitCode}), retrying in ${crashBackoffMs}ms (attempt ${attempt}/${AGENT_CRASH_MAX})...`,\n );\n await sleepUnlessAborted(crashBackoffMs, opts.signal);\n if (opts.signal?.aborted) {\n // Aborted during backoff — no child is running; draining means \"stop\n // trying to restart\", nothing to SIGTERM/await here.\n return 0;\n }\n }\n}\n","/**\n * Ports `report_agent_crash` (entrypoint.sh:936-943): the pod-side crash\n * supervisor's best-effort POST to the API so the crash gets posted to the\n * task's activity log (which also keeps the pod alive through recovery) and,\n * on the final attempt, a durable notification. Payload contract matches\n * `bootstrap-route.ts`'s `parseCrashReport`: `{ exitCode, attempt, final }`.\n *\n * Best-effort, mirrors the bash `|| true`: a failed or slow report must never\n * block the supervisor's restart loop, so every path swallows errors and this\n * never throws.\n */\nconst CRASH_REPORT_TIMEOUT_MS = 10_000;\n\nexport interface CrashReport {\n exitCode: number;\n attempt: number;\n final: boolean;\n}\n\nexport async function reportAgentCrash(\n apiUrl: string,\n bootstrapToken: string,\n report: CrashReport,\n fetchFn: typeof fetch = fetch,\n): Promise<void> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), CRASH_REPORT_TIMEOUT_MS);\n try {\n await fetchFn(`${apiUrl}/api/v3/pods/agent-crash`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: `Bearer ${bootstrapToken}`,\n },\n body: JSON.stringify(report),\n signal: controller.signal,\n });\n } catch {\n // Best-effort — never let a network failure or timeout block the retry loop.\n } finally {\n clearTimeout(timer);\n }\n}\n","import {\n chmodSync,\n copyFileSync,\n existsSync,\n lstatSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n rmSync,\n statSync,\n symlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { ExecDeps } from \"./exec.js\";\nimport type { BootLogger } from \"./types.js\";\n\n/**\n * Ports entrypoint.sh:120-143 (`reclaim_home_ownership`), 346-379\n * (`seed_claude_json`), and 381-487 (mount wiring / pod-local ~/.claude.json /\n * credential symlink / opencode links / no-mount fallback).\n *\n * `.claude/rules/claude-session-persistence.md` invariant carried verbatim:\n * ~/.claude.json is pod-local and NEVER symlinked into the mount — the CLI\n * rewrites it wholesale at startup/during runs, and a burst of concurrent pods\n * for the same user+project racing one shared file produces last-writer-wins\n * lost updates (root cause of a live TUI startup-dialog park and a poisoned\n * customApiKeyResponses write bricking every future pod). ~/.claude itself IS\n * symlinked into the mount when present — it holds the shared, append-mostly\n * transcript/plan/memory state --resume depends on.\n */\n\n// ── seed_claude_json ────────────────────────────────────────────────────────\n\nexport const SEED_GATES: Record<string, unknown> = {\n hasCompletedOnboarding: true,\n bypassPermissionsModeAccepted: true,\n projects: {\n \"/workspaces/repo\": { hasTrustDialogAccepted: true },\n },\n};\n\n// Fable is entitlement-gated in the CLI's /model picker via\n// additionalModelOptionsCache, normally populated by a bootstrap fetch the\n// pods' synthesized credentials don't satisfy — without this row the picker\n// never offers Fable in a pod. The literal value is entitlement-load-bearing;\n// it mirrors FABLE_MODEL (\"claude-fable-5\") in packages/shared/src/constants/\n// models.ts plus the CLI's \"[1m]\" 1M-context variant suffix.\nexport const SEED_FABLE_OPTION: {\n value: \"claude-fable-5[1m]\";\n label: \"Fable\";\n description: string;\n} = {\n value: \"claude-fable-5[1m]\",\n label: \"Fable\",\n description: \"Fable 5 - most capable for your hardest and longest-running tasks\",\n};\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction deepMerge(\n target: Record<string, unknown>,\n patch: Record<string, unknown>,\n): Record<string, unknown> {\n const out = { ...target };\n for (const [k, v] of Object.entries(patch)) {\n const cur = out[k];\n out[k] = isPlainObject(cur) && isPlainObject(v) ? deepMerge(cur, v) : v;\n }\n return out;\n}\n\nfunction hasFableEntry(cache: unknown[]): boolean {\n return cache.some((entry) => {\n if (!isPlainObject(entry)) return false;\n const value = entry.value;\n return typeof value === \"string\" && value.toLowerCase().includes(\"fable\");\n });\n}\n\n/**\n * Pre-answer every interactive first-run gate the CLI shows on a fresh (or\n * partially initialized) config — the onboarding wizard, the\n * bypass-permissions warning, and the folder-trust dialog for the repo\n * workspace — plus append the Fable model-picker entitlement row. Merge via\n * deep-merge, never clobber: CLI-owned keys (cache keys, firstStartTime,\n * other projects' trust entries) survive. A missing or corrupt file becomes a\n * fresh seed (Claude Code treats a 0-byte/unparseable file as fatal, so\n * replacing is a repair, not data loss). Theme only seeds fresh configs — a\n * user-picked theme is never overridden. Never throws: seeding must not kill\n * boot under a single bad stat/write.\n */\nexport function seedClaudeJson(targetPath: string): void {\n try {\n let config: Record<string, unknown> | null = null;\n try {\n const parsed: unknown = JSON.parse(readFileSync(targetPath, \"utf8\"));\n if (isPlainObject(parsed)) config = parsed;\n } catch {\n // Missing or corrupt → fresh seed (repair), not a throw.\n }\n let merged = config ? deepMerge(config, SEED_GATES) : { ...SEED_GATES, theme: \"dark\" };\n const cache = Array.isArray(merged.additionalModelOptionsCache)\n ? merged.additionalModelOptionsCache\n : [];\n if (!hasFableEntry(cache)) {\n merged = { ...merged, additionalModelOptionsCache: [...cache, SEED_FABLE_OPTION] };\n }\n writeFileSync(targetPath, JSON.stringify(merged));\n } catch {\n // Seeding must never kill boot.\n }\n}\n\n// ── wire_user_home ──────────────────────────────────────────────────────────\n\nexport interface WireUserHomeOptions {\n /** \"/home/conveyor\" in prod, a tmpdir in tests. */\n home: string;\n /** \"/mnt/conveyor-users\" — the GCS FUSE CSI mount point. */\n userHomeMount: string;\n userId?: string;\n projectId?: string;\n /** CONVEYOR_SHARED_DIR — always set in split pods. */\n sharedDir?: string;\n /** Pre-created agent log-redirect dir; overridable for tests. */\n scratchDir?: string;\n log: BootLogger;\n}\n\nfunction isDir(path: string): boolean {\n try {\n return statSync(path).isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction isRegularFile(path: string): boolean {\n try {\n return lstatSync(path).isFile();\n } catch {\n return false;\n }\n}\n\nfunction safely(log: BootLogger, label: string, fn: () => void): void {\n try {\n fn();\n } catch (err) {\n log.warn(`[boot] WARN ${label} failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\n/** `ln -sfn target link` semantics: replace whatever is at `link`, creating\n * its parent dir first. */\nfunction relink(target: string, link: string): void {\n mkdirSync(dirname(link), { recursive: true });\n rmSync(link, { recursive: true, force: true });\n symlinkSync(target, link);\n}\n\ninterface CredentialWireOptions {\n home: string;\n root: string;\n sharedDir?: string;\n log: BootLogger;\n}\n\n/**\n * Pod-local ~/.claude/.credentials.json: concurrent pods under different keys\n * clobbering one shared file cross-wired usage attribution between accounts\n * (seen live). The shared dir keeps a SYMLINK to an absolute pod-local path,\n * which resolves per-pod; racing pods all write the identical symlink value,\n * so the symlink itself cannot lose data. A pre-existing REGULAR (non-symlink)\n * shared file is legacy — carry its contents into the pod-local target first\n * so auth survives the cutover.\n */\nfunction wireCredentials(opts: CredentialWireOptions): void {\n const { home, root, sharedDir, log } = opts;\n const shared = join(root, \".claude\", \".credentials.json\");\n const podLocal = sharedDir\n ? join(sharedDir, \"claude-credentials.pod.json\")\n : join(home, \".claude-credentials.pod.json\");\n safely(log, \"carry legacy shared credentials\", () => {\n if (isRegularFile(shared)) copyFileSync(shared, podLocal);\n });\n safely(log, \"repoint credentials symlink\", () => relink(podLocal, shared));\n safely(log, \"chmod pod-local credentials\", () => chmodSync(podLocal, 0o600));\n}\n\n/**\n * The agent's memory dir, project-scoped and shared across users.\n *\n * Memory used to be keyed (userId, projectId). The 2026-07-27 fleet audit found\n * 6 such silos holding 67 memories with ZERO topics in common: the same pod-env\n * lessons (chromium `executablePath`, review-guide anchors, which gates OOM)\n * were discovered the hard way and written down independently in each silo,\n * because a memory written by one user's pod is invisible to the next. Project\n * scope is the right boundary — memories are project-technical facts, it\n * matches the ACL boundary, and it mirrors the `users/_shared/graphify`\n * convention already living on this mount.\n *\n * One-file-per-memory keeps concurrent pods collision-free; migration never\n * overwrites an existing shared file, so a stale per-user copy cannot clobber\n * what another pod already published.\n */\nconst AGENT_MEMORY_PROJECT_DIR = \"-workspaces-repo\";\n\nfunction migrateMemories(from: string, to: string, log: BootLogger): void {\n let entries: string[];\n try {\n entries = readdirSync(from);\n } catch {\n return;\n }\n for (const entry of entries) {\n const target = join(to, entry);\n if (existsSync(target)) continue;\n safely(log, `migrate memory ${entry}`, () => copyFileSync(join(from, entry), target));\n }\n}\n\nfunction wireSharedMemory(\n root: string,\n userHomeMount: string,\n projectId: string,\n log: BootLogger,\n): void {\n const shared = join(userHomeMount, \"users\", \"_shared\", \"memory\", projectId);\n const link = join(root, \".claude\", \"projects\", AGENT_MEMORY_PROJECT_DIR, \"memory\");\n safely(log, \"mkdir shared memory dir\", () => mkdirSync(shared, { recursive: true }));\n // Only migrate a REAL directory — on the second boot `link` is already the\n // symlink we created, and copying it onto itself would be a no-op at best.\n safely(log, \"migrate per-user memories\", () => {\n if (existsSync(link) && !lstatSync(link).isSymbolicLink()) migrateMemories(link, shared, log);\n });\n safely(log, \"wire shared memory symlink\", () => relink(shared, link));\n}\n\ninterface MountedWireOptions {\n home: string;\n userHomeMount: string;\n userId: string;\n projectId: string;\n sharedDir?: string;\n log: BootLogger;\n}\n\nfunction wireMountedUserHome(opts: MountedWireOptions): void {\n const { home, userHomeMount, userId, projectId, sharedDir, log } = opts;\n const root = join(userHomeMount, \"users\", userId, projectId);\n safely(log, \"mkdir user-home root\", () => {\n mkdirSync(join(root, \".claude\"), { recursive: true });\n mkdirSync(join(root, \".config\", \"claude\"), { recursive: true });\n });\n safely(log, \"wire ~/.claude symlink\", () => relink(join(root, \".claude\"), join(home, \".claude\")));\n safely(log, \"wire ~/.config/claude symlink\", () =>\n relink(join(root, \".config\", \"claude\"), join(home, \".config\", \"claude\")),\n );\n safely(log, \"seed pod-local ~/.claude.json\", () => {\n rmSync(join(home, \".claude.json\"), { recursive: true, force: true });\n seedClaudeJson(join(home, \".claude.json\"));\n });\n wireSharedMemory(root, userHomeMount, projectId, log);\n wireCredentials({ home, root, sharedDir, log });\n safely(log, \"mkdir opencode root\", () => {\n mkdirSync(join(root, \".local\", \"share\", \"opencode\"), { recursive: true });\n mkdirSync(join(root, \".config\", \"opencode\"), { recursive: true });\n });\n safely(log, \"wire opencode data symlink\", () =>\n relink(join(root, \".local\", \"share\", \"opencode\"), join(home, \".local\", \"share\", \"opencode\")),\n );\n safely(log, \"wire opencode config symlink\", () =>\n relink(join(root, \".config\", \"opencode\"), join(home, \".config\", \"opencode\")),\n );\n}\n\ninterface NoMountWireOptions {\n home: string;\n sharedDir?: string;\n log: BootLogger;\n}\n\nfunction wireNoMountUserHome(opts: NoMountWireOptions): void {\n const { home, sharedDir, log } = opts;\n // No persistent home — the CLI reads the pod-local config; seed it there so\n // non-FUSE pods get the same first-run gate suppression as the mounted path.\n safely(log, \"seed pod-local ~/.claude.json (no mount)\", () =>\n seedClaudeJson(join(home, \".claude.json\")),\n );\n if (sharedDir) {\n // Split-mode pods without a persistent user-home: ~/.claude must still\n // cross the container boundary (claude writes transcripts in the\n // workbench; the agent's tailer reads them), so it lives on the shared\n // emptyDir.\n safely(log, \"wire ~/.claude to shared emptyDir\", () => {\n const target = join(sharedDir, \"claude-home\", \".claude\");\n mkdirSync(target, { recursive: true });\n relink(target, join(home, \".claude\"));\n });\n }\n}\n\n/**\n * When the pod has the GCS FUSE user-home mount present with a resolvable\n * userId+projectId, symlink ~/.claude, ~/.config/claude, and the opencode\n * dirs into the user's persistent subdir, seed a pod-local ~/.claude.json,\n * and repoint the shared credentials file to a pod-local symlink target.\n * Otherwise fall back to a pod-local-only seed (plus a shared-emptyDir\n * ~/.claude symlink for split pods). Every sub-step degrades independently —\n * one failure never aborts the rest.\n */\nexport function wireUserHome(opts: WireUserHomeOptions): void {\n const { home, userHomeMount, userId, projectId, sharedDir, log } = opts;\n // Agents habitually redirect gate logs into /tmp/claude-cmd despite docs\n // saying it doesn't exist (55 sessions hit the ENOENT in the 2026-07-27\n // fleet audit) — pre-create it so the redirect just works.\n safely(log, \"mkdir agent scratch dir\", () =>\n mkdirSync(opts.scratchDir ?? \"/tmp/claude-cmd\", { recursive: true }),\n );\n if (userId && projectId && isDir(userHomeMount)) {\n wireMountedUserHome({ home, userHomeMount, userId, projectId, sharedDir, log });\n } else {\n wireNoMountUserHome({ home, sharedDir, log });\n }\n}\n\n// ── reclaim_home_ownership ──────────────────────────────────────────────────\n\nconst RECLAIM_FIND_TIMEOUT_MS = 10_000;\n\n/**\n * Bake steps that run as root while ENV HOME points at the pod home can leave\n * root-owned entries under ~/.config / ~/.local (a uv install receipt once\n * bricked every pod boot fleet-wide). Reclaims them so a baked ownership slip\n * can't EACCES the entrypoint. CONDITIONAL, not a recursive chown: a\n * `find … ! -user conveyor` walk is stat-only when the tree is already clean\n * (the common case), so it triggers no overlayfs copy-up — an unconditional\n * `chown -R` here once cost ~16s of I/O-bound copy-up on every boot even when\n * nothing was root-owned.\n */\nexport async function reclaimHomeOwnership(\n home: string,\n exec: ExecDeps[\"exec\"],\n log: BootLogger,\n): Promise<void> {\n for (const dir of [join(home, \".config\"), join(home, \".local\")]) {\n if (!isDir(dir)) continue;\n try {\n await exec(\n \"sudo\",\n [\n \"-n\",\n \"find\",\n dir,\n \"!\",\n \"-user\",\n \"conveyor\",\n \"-exec\",\n \"chown\",\n \"conveyor:conveyor\",\n \"{}\",\n \"+\",\n ],\n { timeoutMs: RECLAIM_FIND_TIMEOUT_MS },\n );\n } catch (err) {\n log.warn(\n `[boot] WARN reclaim_home_ownership failed for ${dir}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n}\n","import { chmodSync, closeSync, copyFileSync, existsSync, mkdirSync, openSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { ExecDeps } from \"./exec.js\";\nimport type { BootLogger } from \"./types.js\";\n\n// Persistent authorized_keys copy on the shared emptyDir (mounted in both\n// containers, survives workbench restarts for the pod's life). installWorkspaceSshKey\n// (apps/api .../workspace-ssh-key.ts) writes it there; we re-hydrate the live\n// ~/.ssh/authorized_keys from it on every workbench start so a key installed before\n// an OOM restart survives. Kept in sync with SHARED_MOUNT_DEFAULT there.\nfunction persistedAuthorizedKeys(): string {\n return join(\n process.env.CONVEYOR_SHARED_DIR || \"/var/run/conveyor-workbench\",\n \"ssh\",\n \"authorized_keys\",\n );\n}\n\n/**\n * Ports `start_workspace_sshd` (entrypoint.sh:12-31). Warn-only end to end —\n * SSH attach is a convenience surface; its absence must never degrade boot.\n *\n * Binds all interfaces deliberately: the preview-router tunnels in from\n * outside the pod to the pod IP. Access is gated by the attach token + SSH\n * public-key auth, not by network reachability (no public ingress).\n */\nexport async function startWorkspaceSshd(\n exec: ExecDeps[\"exec\"],\n log: BootLogger,\n port: string = process.env.CONVEYOR_WORKSPACE_SSH_PORT || \"2222\",\n home = \"/home/conveyor\",\n): Promise<void> {\n try {\n const sshDir = join(home, \".ssh\");\n mkdirSync(sshDir, { recursive: true });\n chmodSync(sshDir, 0o700);\n const authorizedKeys = join(sshDir, \"authorized_keys\");\n const persisted = persistedAuthorizedKeys();\n if (existsSync(persisted)) {\n // Restore keys installed before a workbench restart wiped /home/conveyor.\n copyFileSync(persisted, authorizedKeys);\n } else if (!existsSync(authorizedKeys)) {\n closeSync(openSync(authorizedKeys, \"a\"));\n }\n chmodSync(authorizedKeys, 0o600);\n } catch (err) {\n log.warn(\n `[boot] WARN: workspace SSHD key setup failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n return;\n }\n if (!existsSync(\"/usr/sbin/sshd\")) {\n log.warn(\"[boot] WARN: workspace SSHD unavailable\");\n return;\n }\n try {\n await exec(\"sudo\", [\"mkdir\", \"-p\", \"/run/sshd\"], { timeoutMs: 10_000 });\n await exec(\"sudo\", [\"/usr/sbin/sshd\", \"-o\", \"ListenAddress=0.0.0.0\", \"-o\", `Port=${port}`], {\n timeoutMs: 10_000,\n });\n log.info(`[boot] Workspace SSHD listening on 0.0.0.0:${port}`);\n } catch {\n log.warn(\"[boot] WARN: workspace SSHD failed to start\");\n }\n}\n","import {\n appendFileSync,\n existsSync,\n lstatSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n readlinkSync,\n rmSync,\n statSync,\n symlinkSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { BootstrapBundle } from \"../setup/bootstrap-bundle-types.js\";\nimport { redactToken, type GitFn } from \"./git-prep.js\";\nimport { computeGraphifyEnv } from \"./graphify.js\";\nimport type { BootLogger } from \"./types.js\";\n\n/**\n * Ports the best-effort workspace extras that ride the git-ready gate:\n * - `bind_graphify_bundle` (entrypoint.sh:521-562)\n * - `ensure_grimoire_submodule` + `link_grimoire_skills` (entrypoint.sh:576-621)\n * - the reference-repos clone block (entrypoint.sh:793-827)\n *\n * Ordering invariant (mark_git_ready, entrypoint.sh:623-628): graphify bind +\n * grimoire submodule + skill links run BEFORE the ready flip (Claude must not\n * spawn before skills exist — fleet-wide 2026-07-10 incident); reference\n * repos run AFTER ready (supplementary context must never block Claude).\n * GitPrepJob's onReady/afterReady hooks carry that split.\n *\n * Every helper is best-effort: always returns cleanly, never fails the gate.\n */\n\nfunction errText(err: unknown): string {\n return redactToken(err instanceof Error ? err.message : String(err));\n}\n\nfunction isDir(path: string): boolean {\n try {\n return statSync(path).isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction isSymlink(path: string): boolean {\n try {\n return lstatSync(path).isSymbolicLink();\n } catch {\n return false;\n }\n}\n\nconst GRAPHIFY_BUNDLE_FILES = [\n \"graph.json\",\n \"GRAPH_REPORT.md\",\n \"manifest.json\",\n \".graphify_analysis.json\",\n \".graphify_labels.json\",\n \"publish-manifest.json\",\n \"cost.json\",\n];\n\n/** Symlink the shared graphify bundle into <workspace>/graphify-out.\n * `graphifyEnv` is computeGraphifyEnv's output — empty (disabled/no slug)\n * makes this a no-op. */\nexport function bindGraphifyBundle(\n workspace: string,\n graphifyEnv: Record<string, string>,\n log: BootLogger,\n): void {\n const slug = graphifyEnv.CONVEYOR_GRAPHIFY_SLUG;\n const sourceDir = graphifyEnv.CONVEYOR_GRAPHIFY_DIR;\n const graphFile = graphifyEnv.CONVEYOR_GRAPHIFY_GRAPH;\n if (!slug || !sourceDir || !graphFile) return;\n if (!existsSync(graphFile)) {\n log.info(`[boot] Graphify bundle not found for '${slug}' at ${sourceDir}`);\n return;\n }\n const targetDir = join(workspace, \"graphify-out\");\n try {\n mkdirSync(targetDir, { recursive: true });\n } catch {\n log.warn(`[boot] WARN: unable to create graphify-out at ${targetDir}`);\n return;\n }\n for (const rel of GRAPHIFY_BUNDLE_FILES) {\n const source = join(sourceDir, rel);\n const target = join(targetDir, rel);\n if (!existsSync(source)) continue;\n // -e || -L in bash: never clobber an existing entry, including a broken\n // symlink (existsSync follows links, hence the extra lstat check).\n if (existsSync(target) || isSymlink(target)) continue;\n try {\n symlinkSync(source, target);\n } catch {\n /* best-effort, bash `|| true` */\n }\n }\n log.info(`[boot] Bound graphify bundle '${slug}' into ${targetDir}`);\n}\n\n/** Materialize the .claude/grimoire submodule when the repo declares it and\n * the bake didn't populate it. Always returns cleanly. */\nexport async function ensureGrimoireSubmodule(\n workspace: string,\n githubToken: string,\n git: GitFn,\n log: BootLogger,\n): Promise<void> {\n try {\n if (!existsSync(join(workspace, \".gitmodules\"))) return;\n let paths = \"\";\n try {\n ({ stdout: paths } = await git(\n [\"config\", \"--file\", \".gitmodules\", \"--get-regexp\", String.raw`submodule\\..*\\.path`],\n { cwd: workspace, timeoutMs: 10_000 },\n ));\n } catch {\n // No submodule entries (config exits nonzero on no match).\n return;\n }\n if (!paths.split(\"\\n\").some((line) => line.trim().endsWith(\".claude/grimoire\"))) return;\n // Already materialized (pod-image bake ran conveyor-prebake successfully).\n if (isDir(join(workspace, \".claude\", \"grimoire\", \"skills\"))) return;\n if (!githubToken) {\n log.warn(\"[boot] WARN: grimoire submodule absent and no token to fetch it\");\n return;\n }\n // insteadOf injects the installation token for the submodule's https URL\n // the same way syncTaskBranchToRepo authenticates the main repo remote.\n try {\n await git(\n [\n \"-c\",\n `url.https://x-access-token:${githubToken}@github.com/.insteadOf=https://github.com/`,\n \"submodule\",\n \"update\",\n \"--init\",\n \".claude/grimoire\",\n ],\n { cwd: workspace, timeoutMs: 300_000 },\n );\n log.info(\"[boot] Initialized grimoire submodule\");\n } catch (err) {\n log.warn(\n `[boot] WARN: grimoire submodule init failed (baked pods may lack rc-* skills): ${errText(err)}`,\n );\n }\n } catch (err) {\n log.warn(`[boot] WARN: grimoire submodule check failed: ${errText(err)}`);\n }\n}\n\n/** Register pod-local skill symlinks in .git/info/exclude so `git add -A`\n * (create_pull_request, WIP flush) can never sweep them into a commit.\n * Repo .gitignore only covers `rc-*`; grimoire skills without that prefix\n * (e.g. conveyor-plan) leaked into real PRs — 2026-07-27 fleet audit. */\nfunction excludeLinkedSkills(workspace: string, names: string[], log: BootLogger): void {\n if (names.length === 0) return;\n const infoDir = join(workspace, \".git\", \"info\");\n // A worktree checkout has a .git FILE — skip rather than misplace the exclude.\n if (!isDir(join(workspace, \".git\"))) return;\n try {\n mkdirSync(infoDir, { recursive: true });\n const excludePath = join(infoDir, \"exclude\");\n const existing = existsSync(excludePath) ? readFileSync(excludePath, \"utf8\") : \"\";\n const missing = names\n .map((name) => `.claude/skills/${name}`)\n .filter((line) => !existing.split(\"\\n\").includes(line));\n if (missing.length === 0) return;\n const prefix = existing.length > 0 && !existing.endsWith(\"\\n\") ? \"\\n\" : \"\";\n appendFileSync(excludePath, `${prefix}${missing.join(\"\\n\")}\\n`);\n } catch (err) {\n log.warn(`[boot] WARN: unable to exclude grimoire skill links: ${errText(err)}`);\n }\n}\n\nfunction symlinkTargetsGrimoire(path: string): boolean {\n try {\n return readlinkSync(path).includes(join(\"grimoire\", \"skills\"));\n } catch {\n return false;\n }\n}\n\n/** Link grimoire skills into the repo's project skill dir (pod-local; each\n * link is registered in .git/info/exclude so it can never be committed).\n * Never clobbers a real (repo-tracked) skill dir or a symlink owned by\n * something else (e.g. @rallycry/conveyor-skills links into node_modules). */\nexport function linkGrimoireSkills(workspace: string, log: BootLogger): void {\n const sourceDir = join(workspace, \".claude\", \"grimoire\", \"skills\");\n const targetDir = join(workspace, \".claude\", \"skills\");\n if (!isDir(sourceDir)) return;\n try {\n mkdirSync(targetDir, { recursive: true });\n } catch {\n log.warn(`[boot] WARN: unable to create ${targetDir}; skipping grimoire skill links`);\n return;\n }\n const linkedNames: string[] = [];\n let names: string[] = [];\n try {\n names = readdirSync(sourceDir);\n } catch {\n return;\n }\n for (const name of names) {\n if (!isDir(join(sourceDir, name))) continue;\n const target = join(targetDir, name);\n // bash: [ -e ] && [ ! -L ] — a broken symlink is replaceable, a real dir is not.\n if (existsSync(target) && !isSymlink(target)) {\n log.warn(`[boot] WARN: ${target} exists and is not a symlink; skipping`);\n continue;\n }\n // A repo-owned symlink (e.g. a committed link into node_modules/@rallycry/\n // conveyor-skills) is TRACKED content — rewriting it to point at grimoire\n // would surface as a modification that `git add -A` sweeps into commits.\n // Only grimoire-owned links (broken or not) are ours to refresh.\n if (isSymlink(target) && !symlinkTargetsGrimoire(target)) continue;\n try {\n // ln -sfn: replace an existing symlink in place.\n rmSync(target, { force: true });\n symlinkSync(join(\"..\", \"grimoire\", \"skills\", name), target);\n linkedNames.push(name);\n } catch {\n /* best-effort */\n }\n }\n excludeLinkedSkills(workspace, linkedNames, log);\n log.info(`[boot] Linked ${linkedNames.length} grimoire skills into ${targetDir}`);\n}\n\n/** Mark the grimoire submodule gitlink assume-unchanged so pointer drift after\n * a pod resume never shows as `M .claude/grimoire` nor gets committed by the\n * `git add -A` paths (create_pull_request, WIP flush). Agents hand-ran this in\n * 8 sessions of the 2026-07-27 fleet audit; in-pod submodule fetches fail\n * (no credentials on the submodule remote), so the pointer is noise here. */\nexport async function neutralizeGrimoirePointer(\n workspace: string,\n git: GitFn,\n log: BootLogger,\n): Promise<void> {\n if (!existsSync(join(workspace, \".claude\", \"grimoire\"))) return;\n try {\n await git([\"update-index\", \"--assume-unchanged\", \".claude/grimoire\"], {\n cwd: workspace,\n timeoutMs: 10_000,\n });\n log.info(\"[boot] Marked .claude/grimoire assume-unchanged (submodule pointer drift is noise)\");\n } catch (err) {\n // Path not in the index (repo without the submodule) or index lock — noise either way.\n log.warn(`[boot] WARN: grimoire assume-unchanged failed: ${errText(err)}`);\n }\n}\n\ninterface ReferenceRepo {\n slug: string;\n owner: string;\n name: string;\n branch: string;\n token: string;\n}\n\nfunction parseReferenceRepos(refsJson: string): ReferenceRepo[] {\n let parsed: unknown;\n try {\n parsed = JSON.parse(refsJson);\n } catch {\n // bash parity: jq parse errors were sent to /dev/null.\n return [];\n }\n if (!Array.isArray(parsed)) return [];\n const refs: ReferenceRepo[] = [];\n for (const entry of parsed) {\n if (typeof entry !== \"object\" || entry === null) continue;\n const raw = entry as Record<string, unknown>;\n const str = (key: string): string => (typeof raw[key] === \"string\" ? (raw[key] as string) : \"\");\n const ref: ReferenceRepo = {\n slug: str(\"slug\"),\n owner: str(\"owner\"),\n name: str(\"name\"),\n branch: str(\"branch\") || \"main\",\n token: str(\"token\"),\n };\n if (ref.token && ref.slug && ref.owner && ref.name) refs.push(ref);\n }\n return refs;\n}\n\n/**\n * GitPrepJob.onReady production composition — the three pre-ready binds in\n * the pinned mark_git_ready order (graphify bind, grimoire submodule, skill\n * links). Best-effort like its parts; a throw here is downgraded to a warn by\n * GitPrepJob anyway.\n */\nexport async function runPreReadyBinds(\n workspace: string,\n bundle: BootstrapBundle,\n git: GitFn,\n log: BootLogger,\n): Promise<void> {\n const graphifyEnv = computeGraphifyEnv(process.env, bundle.gitPlan.repoName, isDir);\n bindGraphifyBundle(workspace, graphifyEnv, log);\n await ensureGrimoireSubmodule(workspace, bundle.githubToken ?? \"\", git, log);\n linkGrimoireSkills(workspace, log);\n await neutralizeGrimoirePointer(workspace, git, log);\n}\n\n/**\n * Shallow-clone reference repos (from REFERENCE_REPOS_JSON in bundle.envVars)\n * as read-only context. Runs strictly AFTER the ready flip. Failures are\n * non-fatal — the task proceeds even when a reference project's GitHub App is\n * uninstalled or its token mint failed.\n */\nexport async function cloneReferenceRepos(\n refsJson: string | undefined,\n git: GitFn,\n log: BootLogger,\n referencesDir = \"/workspaces/references\",\n): Promise<void> {\n if (!refsJson) return;\n const refs = parseReferenceRepos(refsJson);\n if (refs.length === 0) return;\n try {\n mkdirSync(referencesDir, { recursive: true });\n } catch {\n return;\n }\n for (const ref of refs) {\n const dest = join(referencesDir, ref.slug);\n if (existsSync(join(dest, \".git\"))) continue;\n try {\n await git(\n [\n \"clone\",\n \"--depth\",\n \"1\",\n \"--single-branch\",\n \"--branch\",\n ref.branch,\n `https://x-access-token:${ref.token}@github.com/${ref.owner}/${ref.name}.git`,\n dest,\n ],\n { timeoutMs: 600_000 },\n );\n // Strip the token from the cloned remote so it never surfaces via\n // `git remote -v` when the agent inspects the reference repo.\n try {\n await git(\n [\"remote\", \"set-url\", \"origin\", `https://github.com/${ref.owner}/${ref.name}.git`],\n { cwd: dest, timeoutMs: 10_000 },\n );\n } catch {\n /* best-effort */\n }\n log.info(`[boot] cloned reference ${ref.slug} (${ref.owner}/${ref.name}@${ref.branch})`);\n } catch {\n log.warn(`[boot] WARN: reference clone failed: ${ref.slug}`);\n }\n }\n}\n","import type { BootstrapBundle } from \"../setup/bootstrap-bundle-types.js\";\nimport {\n startWorkbenchServer,\n type WorkbenchServerHandle,\n type WorkbenchServerOptions,\n} from \"../workbench/server.js\";\nimport { buildChildEnv, decodeJwtClaims } from \"./bundle.js\";\nimport { defaultGit, ensureDir, type GitPrepDeps } from \"./git-prep.js\";\nimport { pollBootstrapBundle } from \"./poll.js\";\nimport { defaultExec } from \"./exec.js\";\nimport { startWorkspaceSshd } from \"./sshd.js\";\nimport type { BootContext } from \"./types.js\";\nimport { reclaimHomeOwnership, wireUserHome } from \"./user-home.js\";\nimport { cloneReferenceRepos, runPreReadyBinds } from \"./workspace-extras.js\";\n\n/**\n * The injectable step surface of `runWorkbenchBoot` (workbench-boot.ts) plus\n * its production defaults — split out so tests exercise the boot sequencing\n * without network, sockets, or real git, and so the composition module stays\n * within the dependency budget.\n */\nexport interface WorkbenchBootDeps {\n /** Task 4 poll — throws BootstrapUnauthorizedError on 401 (fatal), resolves\n * null when aborted (SIGTERM during standby). */\n pollBundle(ctx: BootContext): Promise<BootstrapBundle | null>;\n /** Task 3 unpack — claims decode + child env. */\n unpack(ctx: BootContext, bundle: BootstrapBundle): Record<string, string>;\n startDaemon(opts: WorkbenchServerOptions): Promise<WorkbenchServerHandle>;\n gitPrepDeps(ctx: BootContext, bundle: BootstrapBundle): GitPrepDeps;\n /** GitPrepJob.onReady — graphify bind + grimoire submodule + skill links. */\n bindsBeforeReady(ctx: BootContext, bundle: BootstrapBundle): Promise<void>;\n /** GitPrepJob.afterReady — reference repos, never blocking Claude. */\n cloneReferences(ctx: BootContext, bundle: BootstrapBundle): Promise<void>;\n /** mkdir -p /workspaces/repo before git prep — the daemon serves shell cwd\n * from it, and the no-git-plan prep path never creates it (bash did so\n * unconditionally, entrypoint.sh:848). */\n ensureWorkspaceDir(ctx: BootContext): void;\n wireHome(ctx: BootContext): void;\n startSshd(ctx: BootContext): Promise<void>;\n reclaimOwnership(ctx: BootContext): Promise<void>;\n /** Daemon lifetime — resolves never; SIGTERM → exit is Task 9's wiring. */\n park(ctx: BootContext): Promise<never>;\n}\n\nconst WORKSPACE_DIR = \"/workspaces/repo\";\nconst HOME_DIR = \"/home/conveyor\";\nconst USER_HOME_MOUNT = \"/mnt/conveyor-users\";\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport function defaultWorkbenchBootDeps(): WorkbenchBootDeps {\n return {\n pollBundle: (ctx) =>\n pollBootstrapBundle(ctx.apiUrl, ctx.bootstrapToken, {\n fetchFn: fetch,\n sleepFn: sleep,\n log: ctx.log,\n }),\n unpack: (ctx, bundle) => {\n const claims = decodeJwtClaims(bundle.sessionJwt);\n ctx.claims = claims;\n return buildChildEnv({\n base: process.env,\n bundle,\n claims,\n hostname: ctx.hostname,\n log: ctx.log,\n });\n },\n startDaemon: (opts) => startWorkbenchServer(opts),\n gitPrepDeps: (ctx, bundle) => ({\n git: defaultGit,\n bundle,\n podImage: process.env.CONVEYOR_POD_IMAGE === \"1\",\n log: ctx.log,\n }),\n bindsBeforeReady: (ctx, bundle) => runPreReadyBinds(WORKSPACE_DIR, bundle, defaultGit, ctx.log),\n cloneReferences: (ctx, bundle) =>\n cloneReferenceRepos(bundle.envVars?.REFERENCE_REPOS_JSON, defaultGit, ctx.log),\n ensureWorkspaceDir: (ctx) => {\n ensureDir(WORKSPACE_DIR);\n ctx.log.info(`[boot] ensured workspace dir ${WORKSPACE_DIR}`);\n },\n wireHome: (ctx) => {\n // Same id sources as the bash (entrypoint.sh:342-343, 388): userId from\n // the pod env / bundle envVars, projectId from the claim with a pod-env\n // fallback — all merged into childEnv by the unpack step.\n wireUserHome({\n home: HOME_DIR,\n userHomeMount: USER_HOME_MOUNT,\n userId: ctx.childEnv?.CONVEYOR_USER_ID,\n projectId: ctx.childEnv?.CONVEYOR_PROJECT_ID ?? ctx.childEnv?.PROJECT_ID,\n sharedDir: process.env.CONVEYOR_SHARED_DIR,\n log: ctx.log,\n });\n },\n startSshd: (ctx) => startWorkspaceSshd(defaultExec, ctx.log),\n reclaimOwnership: (ctx) => reclaimHomeOwnership(HOME_DIR, defaultExec, ctx.log),\n park: () =>\n new Promise<never>(() => {\n /* parked for the daemon's lifetime */\n }),\n };\n}\n","import { readAgentVersion } from \"../runner/session-runner-helpers.js\";\nimport { reportBootMilestone } from \"../setup/boot-milestone.js\";\nimport { oomWatchdogOptionsFromEnv } from \"../workbench/oom-watchdog.js\";\nimport { workbenchPort } from \"../workbench/mode.js\";\nimport { DEFAULT_WORKBENCH_PORT, type GitStatusFrame } from \"../workbench/protocol.js\";\nimport { GitPrepJob, type GitPrepState } from \"./git-prep.js\";\nimport type { BootContext } from \"./types.js\";\nimport { defaultWorkbenchBootDeps, type WorkbenchBootDeps } from \"./workbench-boot-deps.js\";\n\n/**\n * The workbench container's vnext boot: acquire the bundle, start the daemon\n * (whose listen socket IS the pod's startupProbe), then run everything else —\n * git prep, user-home wiring, sshd, ownership reclaim — strictly after the\n * probe can pass. Replaces the bash entrypoint's workbench tail\n * (entrypoint.sh:835-899): the marker files become the GitPrepJob state\n * served over the daemon's `gitStatus` op.\n *\n * Task 9 composes this through runPipeline; every step is injectable via the\n * deps object (`workbench-boot-deps.ts` carries the production defaults) so\n * tests run without network, sockets, or real git.\n */\n\nexport type { WorkbenchBootDeps } from \"./workbench-boot-deps.js\";\n\nexport function toGitStatusFrame(state: GitPrepState): GitStatusFrame {\n return state.state === \"failed\"\n ? { t: \"gitStatus\", state: \"failed\", reason: state.reason }\n : { t: \"gitStatus\", state: state.state };\n}\n\nfunction warnErr(ctx: BootContext, label: string): (err: unknown) => void {\n return (err) => {\n ctx.log.warn(\n `[boot] WARN ${label} failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n };\n}\n\nexport async function runWorkbenchBoot(\n ctx: BootContext,\n overrides: Partial<WorkbenchBootDeps> = {},\n): Promise<never> {\n const deps: WorkbenchBootDeps = { ...defaultWorkbenchBootDeps(), ...overrides };\n // ── CRITICAL PATH ──────────────────────────────────────────────────────\n // The daemon's listen socket is the pod's startupProbe — it gates both the\n // agent container start and Provisioning→Running. Nothing may run before\n // it besides bundle acquisition and env unpack.\n //\n // The poll's 401 (BootstrapUnauthorizedError) propagates — fatal-loud.\n const bundle = await deps.pollBundle(ctx);\n if (!bundle) {\n // Aborted during standby (SIGTERM). Task 9's signal wiring owns process\n // exit; parking preserves the Promise<never> contract meanwhile.\n ctx.log.info(\"[boot] standby poll aborted — parking for shutdown\");\n return deps.park(ctx);\n }\n ctx.bundle = bundle;\n ctx.childEnv = deps.unpack(ctx, bundle);\n const job = new GitPrepJob(deps.gitPrepDeps(ctx, bundle), {\n // Order pinned by the old entrypoint-grimoire test: binds BEFORE the\n // ready flip (Claude must not spawn before skills exist), references after.\n onReady: () => {\n // Must still return this promise — GitPrepJob awaits onReady() before\n // flipping status to \"ready\" (the daemon's gitStatus gate), so binds\n // completing before the ready flip is preserved. The milestone report\n // is fire-and-forget and never delays that flip.\n const binds = deps.bindsBeforeReady(ctx, bundle);\n void reportBootMilestone({ key: \"repo_synced\" });\n return binds;\n },\n afterReady: () => deps.cloneReferences(ctx, bundle),\n });\n await deps.startDaemon({\n port: workbenchPort() ?? DEFAULT_WORKBENCH_PORT,\n token: ctx.bootstrapToken,\n version: readAgentVersion() ?? \"unknown\",\n getGitStatus: () => toGitStatusFrame(job.status),\n oomWatchdog: oomWatchdogOptionsFromEnv(ctx.log),\n });\n ctx.log.info(\"[boot] step=startDaemon listen socket up (startupProbe gate open)\");\n void reportBootMilestone({ key: \"workbench_ready\" });\n\n // ── DEFERRED (post-listen) ─────────────────────────────────────────────\n // Everything below runs after the probe can pass; each degrades alone.\n // Ensure the repo cwd exists BEFORE the git prep job — the no-git-plan path\n // returns ready without creating it, and the daemon serves shell cwd from here.\n try {\n deps.ensureWorkspaceDir(ctx);\n } catch (err) {\n warnErr(ctx, \"ensureWorkspaceDir\")(err);\n }\n job.start();\n try {\n deps.wireHome(ctx);\n } catch (err) {\n warnErr(ctx, \"wireUserHome\")(err);\n }\n void deps.startSshd(ctx).catch(warnErr(ctx, \"startWorkspaceSshd\"));\n void deps.reclaimOwnership(ctx).catch(warnErr(ctx, \"reclaimHomeOwnership\"));\n return deps.park(ctx);\n}\n"],"mappings":"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","names":["statSync","appendFileSync","appendFileSync","sleepUnlessAborted","statSync","writeFileSync","join","chmodSync","copyFileSync","existsSync","mkdirSync","join","appendFileSync","existsSync","lstatSync","mkdirSync","readdirSync","readFileSync","rmSync","statSync","symlinkSync","join","isDir","statSync","lstatSync","existsSync","join","mkdirSync","symlinkSync","readFileSync","appendFileSync","readdirSync","rmSync","USER_HOME_MOUNT","HOME_DIR","USER_HOME_MOUNT","statSync","whenAborted"]}
@@ -40,17 +40,55 @@ function readAgentVersion() {
40
40
  return null;
41
41
  }
42
42
 
43
+ // src/boot/git-credential.ts
44
+ import { createHash } from "crypto";
45
+ import { chmodSync, mkdirSync, renameSync, writeFileSync } from "fs";
46
+ import { dirname as dirname2, join as join2 } from "path";
47
+ function credentialDir(cwd) {
48
+ return join2(dirname2(cwd), ".conveyor-git-credentials");
49
+ }
50
+ function gitCredentialFile(cwd) {
51
+ const key = createHash("sha256").update(cwd).digest("hex").slice(0, 16);
52
+ return join2(credentialDir(cwd), `${key}.store`);
53
+ }
54
+ function gitCredentialHelper(cwd) {
55
+ return `store --file=${gitCredentialFile(cwd)}`;
56
+ }
57
+ function writeGitCredential(cwd, cloneUrl, credential) {
58
+ const cleanUrl = new URL(cloneUrl);
59
+ if (!/^https?:$/.test(cleanUrl.protocol) || cleanUrl.username || cleanUrl.password) {
60
+ throw new Error("Git clone URL must be a credential-free HTTP(S) URL");
61
+ }
62
+ if (!credential.username || !credential.secret) {
63
+ throw new Error("Git credential username and secret are required");
64
+ }
65
+ const dir = credentialDir(cwd);
66
+ mkdirSync(dir, { recursive: true, mode: 448 });
67
+ chmodSync(dir, 448);
68
+ cleanUrl.username = credential.username;
69
+ cleanUrl.password = credential.secret;
70
+ cleanUrl.pathname = "/";
71
+ cleanUrl.search = "";
72
+ cleanUrl.hash = "";
73
+ const target = gitCredentialFile(cwd);
74
+ const temporary = `${target}.${process.pid}.tmp`;
75
+ writeFileSync(temporary, `${cleanUrl.toString()}
76
+ `, { encoding: "utf8", mode: 384 });
77
+ chmodSync(temporary, 384);
78
+ renameSync(temporary, target);
79
+ }
80
+
43
81
  // src/boot/git-prep.ts
44
82
  import { execFile } from "child_process";
45
- import { existsSync, mkdirSync } from "fs";
46
- import { join as join2 } from "path";
83
+ import { existsSync, mkdirSync as mkdirSync2 } from "fs";
84
+ import { join as join3 } from "path";
47
85
  import { promisify } from "util";
48
86
  var QUICK_GIT_TIMEOUT_MS = 6e4;
49
87
  var FETCH_TIMEOUT_MS = 3e5;
50
88
  var CLONE_TIMEOUT_MS = 6e5;
51
89
  var execFileAsync = promisify(execFile);
52
90
  function ensureDir(dir) {
53
- mkdirSync(dir, { recursive: true });
91
+ mkdirSync2(dir, { recursive: true });
54
92
  }
55
93
  function defaultGit(args, opts = {}) {
56
94
  return execFileAsync("git", args, {
@@ -77,6 +115,8 @@ async function syncTaskBranchToRepo(deps, paths) {
77
115
  log.error(`[boot] ERROR: remote set-url failed: ${errText(err)}`);
78
116
  return { state: "failed", reason: "remote set-url failed" };
79
117
  }
118
+ const credentialFailure = await persistCredentialHelper(deps, paths);
119
+ if (credentialFailure) return credentialFailure;
80
120
  try {
81
121
  await git(["fetch", "origin", `+refs/heads/${baseBranch}:refs/remotes/origin/${baseBranch}`], {
82
122
  cwd: paths.repoDir,
@@ -96,6 +136,18 @@ async function syncTaskBranchToRepo(deps, paths) {
96
136
  log.info(`[boot] Repo remote ready; agent will checkout ${branch}`);
97
137
  return { state: "ready" };
98
138
  }
139
+ async function persistCredentialHelper(deps, paths) {
140
+ try {
141
+ await deps.git(["config", "--local", "credential.helper", paths.credentialHelper], {
142
+ cwd: paths.repoDir,
143
+ timeoutMs: QUICK_GIT_TIMEOUT_MS
144
+ });
145
+ return null;
146
+ } catch (err) {
147
+ deps.log.error(`[boot] ERROR: credential helper config failed: ${errText(err)}`);
148
+ return { state: "failed", reason: "credential helper config failed" };
149
+ }
150
+ }
99
151
  async function clonePostAssignment(deps, paths) {
100
152
  const { git, log } = deps;
101
153
  const { branch, baseBranch, checkoutRef } = deps.bundle.gitPlan;
@@ -104,6 +156,8 @@ async function clonePostAssignment(deps, paths) {
104
156
  try {
105
157
  await git(
106
158
  [
159
+ "-c",
160
+ `credential.helper=${paths.credentialHelper}`,
107
161
  "clone",
108
162
  "--depth",
109
163
  "1",
@@ -119,6 +173,8 @@ async function clonePostAssignment(deps, paths) {
119
173
  log.error(`[boot] ERROR: post-assignment clone failed: ${errText(err)}`);
120
174
  return { state: "failed", reason: "post-assignment clone failed" };
121
175
  }
176
+ const credentialFailure = await persistCredentialHelper(deps, paths);
177
+ if (credentialFailure) return credentialFailure;
122
178
  try {
123
179
  await git(["fetch", "origin", `+${checkoutRef}:refs/remotes/origin/pr-checkout`], {
124
180
  cwd: paths.repoDir,
@@ -140,10 +196,19 @@ async function clonePostAssignment(deps, paths) {
140
196
  return { state: "ready" };
141
197
  }
142
198
  try {
143
- await git(["clone", "--single-branch", "--branch", baseBranch, paths.remoteUrl, "repo"], {
144
- cwd: paths.workspacesDir,
145
- timeoutMs: CLONE_TIMEOUT_MS
146
- });
199
+ await git(
200
+ [
201
+ "-c",
202
+ `credential.helper=${paths.credentialHelper}`,
203
+ "clone",
204
+ "--single-branch",
205
+ "--branch",
206
+ baseBranch,
207
+ paths.remoteUrl,
208
+ "repo"
209
+ ],
210
+ { cwd: paths.workspacesDir, timeoutMs: CLONE_TIMEOUT_MS }
211
+ );
147
212
  } catch (err) {
148
213
  log.error(
149
214
  `[boot] ERROR: post-assignment clone of base '${baseBranch}' failed: ${errText(err)}`
@@ -155,30 +220,32 @@ async function clonePostAssignment(deps, paths) {
155
220
  async function prepareWorkspaceGit(deps) {
156
221
  const { bundle, log } = deps;
157
222
  const workspacesDir = deps.workspacesDir ?? "/workspaces";
158
- const repoDir = join2(workspacesDir, "repo");
159
- const { repoOwner, repoName, branch } = bundle.gitPlan;
160
- const token = bundle.githubToken;
223
+ const repoDir = join3(workspacesDir, "repo");
224
+ const { branch, cloneUrl, repoOwner, repoName } = bundle.gitPlan;
225
+ const credential = bundle.gitCredential;
161
226
  const paths = {
162
227
  workspacesDir,
163
228
  repoDir,
164
- remoteUrl: `https://x-access-token:${token}@github.com/${repoOwner}/${repoName}.git`
229
+ remoteUrl: cloneUrl,
230
+ credentialHelper: gitCredentialHelper(repoDir)
165
231
  };
166
232
  try {
167
- if (existsSync(join2(repoDir, ".git")) && token) {
233
+ if (!cloneUrl || !repoOwner || !repoName || !branch || !credential.username || !credential.secret) {
234
+ log.info("[boot] No git plan to prepare \u2014 marking git ready.");
235
+ return { state: "ready" };
236
+ }
237
+ writeGitCredential(repoDir, cloneUrl, credential);
238
+ if (existsSync(join3(repoDir, ".git"))) {
168
239
  log.info(
169
240
  deps.podImage ? `[boot] Pod image \u2014 updating repo to latest (branch=${branch})...` : `[boot] Repo present (non-pod-image) \u2014 updating repo to latest (branch=${branch})...`
170
241
  );
171
242
  return await syncTaskBranchToRepo(deps, paths);
172
243
  }
173
- if (token && repoOwner && repoName && branch) {
174
- try {
175
- mkdirSync(workspacesDir, { recursive: true });
176
- } catch {
177
- }
178
- return await clonePostAssignment(deps, paths);
244
+ try {
245
+ mkdirSync2(workspacesDir, { recursive: true });
246
+ } catch {
179
247
  }
180
- log.info("[boot] No git plan to prepare \u2014 marking git ready.");
181
- return { state: "ready" };
248
+ return await clonePostAssignment(deps, paths);
182
249
  } catch (err) {
183
250
  log.error(`[boot] ERROR: git prep failed unexpectedly: ${errText(err)}`);
184
251
  return { state: "failed", reason: "git prep failed unexpectedly" };
@@ -279,6 +346,8 @@ async function reportBootMilestone(opts) {
279
346
  }
280
347
 
281
348
  export {
349
+ gitCredentialHelper,
350
+ writeGitCredential,
282
351
  mapChatHistory,
283
352
  readAgentVersion,
284
353
  FETCH_TIMEOUT_MS,
@@ -292,4 +361,4 @@ export {
292
361
  registerBootMilestoneSocketFallback,
293
362
  reportBootMilestone
294
363
  };
295
- //# sourceMappingURL=chunk-KCB7CSWJ.js.map
364
+ //# sourceMappingURL=chunk-7765OQU5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runner/session-runner-helpers.ts","../src/boot/git-credential.ts","../src/boot/git-prep.ts","../src/setup/boot-milestone.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { ChatMessage, TaskContextDTO } from \"@project/shared\";\n\nexport function mapChatHistory(\n messages: TaskContextDTO[\"chatHistory\"] | undefined | null,\n): ChatMessage[] {\n if (!messages) return [];\n return messages.map((m) => ({\n id: m.id,\n role: (m.role ?? \"user\") as \"user\" | \"assistant\" | \"system\",\n content: m.content ?? \"\",\n userId: m.userId,\n userName: m.user?.name ?? undefined,\n createdAt: m.createdAt,\n ...(m.source ? { source: m.source } : {}),\n ...(m.files && m.files.length > 0\n ? {\n files: m.files.map((f) => ({\n fileId: f.id,\n fileName: f.fileName,\n mimeType: f.mimeType,\n fileSize: f.fileSize,\n downloadUrl: f.downloadUrl ?? \"\",\n content: f.content,\n contentEncoding: f.contentEncoding,\n })),\n }\n : {}),\n }));\n}\n\n/** Read this agent's version from its bundled package.json. */\nexport function readAgentVersion(): string | null {\n try {\n const here = dirname(fileURLToPath(import.meta.url));\n // Walk up: dist/runner/session-runner.js → dist/ → package.json\n for (const rel of [\"../package.json\", \"../../package.json\"]) {\n try {\n const pkg = JSON.parse(readFileSync(join(here, rel), \"utf-8\")) as { version?: string };\n if (pkg.version) return pkg.version;\n } catch {\n /* try next candidate */\n }\n }\n } catch {\n /* ignore */\n }\n return null;\n}\n","import { createHash } from \"node:crypto\";\nimport { chmodSync, mkdirSync, renameSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { GitCredential } from \"@project/shared\";\n\nfunction credentialDir(cwd: string): string {\n return join(dirname(cwd), \".conveyor-git-credentials\");\n}\n\nexport function gitCredentialFile(cwd: string): string {\n const key = createHash(\"sha256\").update(cwd).digest(\"hex\").slice(0, 16);\n return join(credentialDir(cwd), `${key}.store`);\n}\n\nexport function gitCredentialHelper(cwd: string): string {\n return `store --file=${gitCredentialFile(cwd)}`;\n}\n\n/** Persist a pod-lifetime credential outside the repository with owner-only permissions. */\nexport function writeGitCredential(cwd: string, cloneUrl: string, credential: GitCredential): void {\n const cleanUrl = new URL(cloneUrl);\n if (!/^https?:$/.test(cleanUrl.protocol) || cleanUrl.username || cleanUrl.password) {\n throw new Error(\"Git clone URL must be a credential-free HTTP(S) URL\");\n }\n if (!credential.username || !credential.secret) {\n throw new Error(\"Git credential username and secret are required\");\n }\n\n const dir = credentialDir(cwd);\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n chmodSync(dir, 0o700);\n\n cleanUrl.username = credential.username;\n cleanUrl.password = credential.secret;\n cleanUrl.pathname = \"/\";\n cleanUrl.search = \"\";\n cleanUrl.hash = \"\";\n\n const target = gitCredentialFile(cwd);\n const temporary = `${target}.${process.pid}.tmp`;\n writeFileSync(temporary, `${cleanUrl.toString()}\\n`, { encoding: \"utf8\", mode: 0o600 });\n chmodSync(temporary, 0o600);\n renameSync(temporary, target);\n}\n","import { execFile } from \"node:child_process\";\nimport { existsSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport type { BootstrapBundle } from \"../setup/bootstrap-bundle-types.js\";\nimport type { BootLogger } from \"./types.js\";\nimport { gitCredentialHelper, writeGitCredential } from \"./git-credential.js\";\n\n/**\n * Ports `prepare_workspace_git` + `sync_task_branch_to_repo` +\n * `reset_tracked_repo_changes_before_assignment_checkout`\n * (entrypoint.sh:623-829) and the workbench bounded retry loop\n * (entrypoint.sh:877-893). The bash signalled via marker files on the shared\n * emptyDir; vnext replaces the markers with daemon-owned state — `GitPrepJob`\n * holds it and the workbench daemon serves it over the `gitStatus` op.\n *\n * Contract carried from the old entrypoint-git-prep.test.ts (verbatim — the\n * agent side depends on it):\n * - `syncTaskBranchToRepo` NEVER touches BRANCH/CHECKOUT_REF and does NO\n * merge. It refreshes the origin remote with the fresh installation token,\n * warms `origin/<base>` (warn-only on failure — the ref may already be\n * present from the bake), and resets tracked changes. The agent's\n * `ensureOnTaskBranch` owns the authoritative checkout.\n * - Clone paths: with checkoutRef → depth-1 base clone, fetch the ref to\n * refs/remotes/origin/pr-checkout, `checkout -f -B <branch>` onto it.\n * Without → clone the BASE branch at FULL depth (a naive `--branch <task>`\n * dies when the task branch was never pushed; `--depth 1` caused the\n * \"refusing to merge unrelated histories\" incident), then sync.\n * - No git plan (empty token/owner/name/branch) → immediate ready.\n *\n * Every fallible git call is guarded — `prepareWorkspaceGit` NEVER throws\n * (the bash equivalent: every error path wrote the failed marker instead of\n * exiting the backgrounded subshell). Reasons stay the short bash marker\n * strings; redacted detail goes to the log.\n */\n\nexport type GitPrepState =\n | { state: \"pending\" }\n | { state: \"ready\" }\n | { state: \"failed\"; reason: string };\n\n/** Async git runner — always `execFile` with a timeout, never execSync (a\n * sync child freezes the event loop; see runner/git-utils.ts history). */\nexport type GitFn = (\n args: string[],\n opts?: { cwd?: string; timeoutMs?: number },\n) => Promise<{ stdout: string }>;\n\nexport interface GitPrepDeps {\n git: GitFn;\n bundle: BootstrapBundle;\n /** env CONVEYOR_POD_IMAGE === \"1\" — log-line fidelity only; behavior matches. */\n podImage: boolean;\n /** default \"/workspaces\" */\n workspacesDir?: string;\n log: BootLogger;\n}\n\nconst QUICK_GIT_TIMEOUT_MS = 60_000;\n// FETCH/CLONE timeouts are exported so setup/git-ready.ts can DERIVE its gate\n// deadline from the daemon's actual retry envelope instead of hand-picking a\n// number that silently drifts when these change.\nexport const FETCH_TIMEOUT_MS = 300_000;\nexport const CLONE_TIMEOUT_MS = 600_000;\n\nconst execFileAsync = promisify(execFile);\n\n/** `mkdir -p`. Shared with the workbench boot's `ensureWorkspaceDir` default so\n * its deps aggregator reuses this module rather than pulling in node:fs. */\nexport function ensureDir(dir: string): void {\n mkdirSync(dir, { recursive: true });\n}\n\n/** Production GitFn. */\nexport function defaultGit(\n args: string[],\n opts: { cwd?: string; timeoutMs?: number } = {},\n): Promise<{ stdout: string }> {\n return execFileAsync(\"git\", args, {\n cwd: opts.cwd,\n timeout: opts.timeoutMs ?? QUICK_GIT_TIMEOUT_MS,\n maxBuffer: 10 * 1024 * 1024,\n });\n}\n\n/** Remote URLs embed the installation token; execFile error messages embed\n * the command line. Redact before ANY log/reason sink. */\nexport function redactToken(text: string): string {\n return text.replace(/x-access-token:[^@]*@/g, \"x-access-token:***@\");\n}\n\nfunction errText(err: unknown): string {\n return redactToken(err instanceof Error ? err.message : String(err));\n}\n\ninterface PrepPaths {\n workspacesDir: string;\n repoDir: string;\n remoteUrl: string;\n credentialHelper: string;\n}\n\n/** Refresh the remote token + warm origin/<base> + reset tracked changes.\n * Deliberately no BRANCH/CHECKOUT_REF handling — see module doc. */\nasync function syncTaskBranchToRepo(deps: GitPrepDeps, paths: PrepPaths): Promise<GitPrepState> {\n const { git, log } = deps;\n const { branch, baseBranch } = deps.bundle.gitPlan;\n try {\n await git([\"remote\", \"set-url\", \"origin\", paths.remoteUrl], {\n cwd: paths.repoDir,\n timeoutMs: QUICK_GIT_TIMEOUT_MS,\n });\n } catch (err) {\n log.error(`[boot] ERROR: remote set-url failed: ${errText(err)}`);\n return { state: \"failed\", reason: \"remote set-url failed\" };\n }\n const credentialFailure = await persistCredentialHelper(deps, paths);\n if (credentialFailure) return credentialFailure;\n // Warm origin/<base> so the agent's checkout/fetch is a fast-forward.\n // Warn-only: a stale-but-present origin/<base> from the bake still works.\n try {\n await git([\"fetch\", \"origin\", `+refs/heads/${baseBranch}:refs/remotes/origin/${baseBranch}`], {\n cwd: paths.repoDir,\n timeoutMs: FETCH_TIMEOUT_MS,\n });\n } catch (err) {\n log.warn(`[boot] WARN: fetch origin/${baseBranch} failed: ${errText(err)}`);\n }\n // The baked/pooled repo is not user-owned until this gate succeeds: reset\n // stale tracked image dirt so the agent's checkout isn't blocked. No\n // `git clean` — untracked prebake artifacts may be intentional.\n try {\n await git([\"reset\", \"--hard\", \"HEAD\"], { cwd: paths.repoDir, timeoutMs: QUICK_GIT_TIMEOUT_MS });\n } catch (err) {\n log.error(\n `[boot] ERROR: failed to clean tracked repo changes before checkout: ${errText(err)}`,\n );\n return { state: \"failed\", reason: \"pre-checkout reset failed\" };\n }\n log.info(`[boot] Repo remote ready; agent will checkout ${branch}`);\n return { state: \"ready\" };\n}\n\n/**\n * `git -c credential.helper=… clone` scopes the setting to that ONE invocation;\n * it is NOT written into the new repo's config (only `git clone --config` does\n * that). The remote URL is credential-free by design now, so without this the\n * cloned repo has no way to authenticate and every later fetch/push — the\n * agent's `ensureOnTaskBranch`, the WIP snapshot flush — fails.\n */\nasync function persistCredentialHelper(\n deps: GitPrepDeps,\n paths: PrepPaths,\n): Promise<GitPrepState | null> {\n try {\n await deps.git([\"config\", \"--local\", \"credential.helper\", paths.credentialHelper], {\n cwd: paths.repoDir,\n timeoutMs: QUICK_GIT_TIMEOUT_MS,\n });\n return null;\n } catch (err) {\n deps.log.error(`[boot] ERROR: credential helper config failed: ${errText(err)}`);\n return { state: \"failed\", reason: \"credential helper config failed\" };\n }\n}\n\nasync function clonePostAssignment(deps: GitPrepDeps, paths: PrepPaths): Promise<GitPrepState> {\n const { git, log } = deps;\n const { branch, baseBranch, checkoutRef } = deps.bundle.gitPlan;\n log.info(\"[boot] Cloning repo post-assignment (pre-clone was missing)...\");\n if (checkoutRef) {\n try {\n await git(\n [\n \"-c\",\n `credential.helper=${paths.credentialHelper}`,\n \"clone\",\n \"--depth\",\n \"1\",\n \"--single-branch\",\n \"--branch\",\n baseBranch,\n paths.remoteUrl,\n \"repo\",\n ],\n { cwd: paths.workspacesDir, timeoutMs: CLONE_TIMEOUT_MS },\n );\n } catch (err) {\n log.error(`[boot] ERROR: post-assignment clone failed: ${errText(err)}`);\n return { state: \"failed\", reason: \"post-assignment clone failed\" };\n }\n // Before the very next fetch — it authenticates against origin too.\n const credentialFailure = await persistCredentialHelper(deps, paths);\n if (credentialFailure) return credentialFailure;\n try {\n await git([\"fetch\", \"origin\", `+${checkoutRef}:refs/remotes/origin/pr-checkout`], {\n cwd: paths.repoDir,\n timeoutMs: FETCH_TIMEOUT_MS,\n });\n } catch (err) {\n log.error(`[boot] ERROR: post-assignment fetch of ${checkoutRef} failed: ${errText(err)}`);\n return { state: \"failed\", reason: `post-assignment fetch of ${checkoutRef} failed` };\n }\n // -f: an untracked bake artifact can collide with a path the target ref\n // tracks; the repo is not user-owned yet, so forcing is safe.\n try {\n await git([\"checkout\", \"-f\", \"-B\", branch, \"refs/remotes/origin/pr-checkout\"], {\n cwd: paths.repoDir,\n timeoutMs: QUICK_GIT_TIMEOUT_MS,\n });\n } catch (err) {\n log.error(`[boot] ERROR: post-assignment checkout of ${checkoutRef} failed: ${errText(err)}`);\n return { state: \"failed\", reason: `post-assignment checkout of ${checkoutRef} failed` };\n }\n return { state: \"ready\" };\n }\n // FULL depth base-branch clone — see module doc for both incidents.\n try {\n await git(\n [\n \"-c\",\n `credential.helper=${paths.credentialHelper}`,\n \"clone\",\n \"--single-branch\",\n \"--branch\",\n baseBranch,\n paths.remoteUrl,\n \"repo\",\n ],\n { cwd: paths.workspacesDir, timeoutMs: CLONE_TIMEOUT_MS },\n );\n } catch (err) {\n log.error(\n `[boot] ERROR: post-assignment clone of base '${baseBranch}' failed: ${errText(err)}`,\n );\n return { state: \"failed\", reason: \"post-assignment clone failed\" };\n }\n return syncTaskBranchToRepo(deps, paths);\n}\n\n/** ONE preparation attempt. Never throws. */\nexport async function prepareWorkspaceGit(deps: GitPrepDeps): Promise<GitPrepState> {\n const { bundle, log } = deps;\n const workspacesDir = deps.workspacesDir ?? \"/workspaces\";\n const repoDir = join(workspacesDir, \"repo\");\n const { branch, cloneUrl, repoOwner, repoName } = bundle.gitPlan;\n const credential = bundle.gitCredential;\n const paths: PrepPaths = {\n workspacesDir,\n repoDir,\n remoteUrl: cloneUrl,\n credentialHelper: gitCredentialHelper(repoDir),\n };\n try {\n if (\n !cloneUrl ||\n !repoOwner ||\n !repoName ||\n !branch ||\n !credential.username ||\n !credential.secret\n ) {\n log.info(\"[boot] No git plan to prepare — marking git ready.\");\n return { state: \"ready\" };\n }\n writeGitCredential(repoDir, cloneUrl, credential);\n if (existsSync(join(repoDir, \".git\"))) {\n // Do NOT silently fall through to the image snapshot on failure — a\n // stale image repo has bitten us before (old scripts, wrong deps) and is\n // brutal to diagnose from pod logs. Fail loud via the returned state.\n log.info(\n deps.podImage\n ? `[boot] Pod image — updating repo to latest (branch=${branch})...`\n : `[boot] Repo present (non-pod-image) — updating repo to latest (branch=${branch})...`,\n );\n return await syncTaskBranchToRepo(deps, paths);\n }\n try {\n mkdirSync(workspacesDir, { recursive: true });\n } catch {\n /* clone below surfaces the real failure */\n }\n return await clonePostAssignment(deps, paths);\n } catch (err) {\n // Belt-and-braces: nothing above should throw, but this function's\n // contract is \"never throws\" (the bash never `exit`ed the subshell).\n log.error(`[boot] ERROR: git prep failed unexpectedly: ${errText(err)}`);\n return { state: \"failed\", reason: \"git prep failed unexpectedly\" };\n }\n}\n\n// Brief-mandated attempt count: 3 total. Not a literal match for the bash\n// workbench retry loop (entrypoint.sh:883) — bash did 1 initial attempt + 3\n// retries = 4 attempts total; the TS port intentionally caps at 3.\nexport const GIT_PREP_MAX_RETRIES = 3;\n/** Exported for setup/git-ready.ts's derived gate deadline (see above). */\nexport const DEFAULT_RETRY_DELAY_MS = 10_000;\n\nexport interface GitPrepJobExtras {\n /** Awaited BEFORE status flips ready — graphify bind + grimoire submodule +\n * skill links. Claude must not spawn before skills exist. */\n onReady: () => Promise<void>;\n /** Runs AFTER ready — reference-repo clones must never block Claude. */\n afterReady: () => Promise<void>;\n /** default 10s (the bash loop's poll cadence); tests shrink it. */\n retryDelayMs?: number;\n}\n\n/**\n * Daemon-owned replacement for the marker files + workbench retry loop: up to\n * `GIT_PREP_MAX_RETRIES` `prepareWorkspaceGit` attempts, then give up leaving\n * `status` failed (the agent surfaces it). While a retry is still possible the\n * status stays `pending`, never transiently `failed` — the agent's gitStatus\n * gate treats `failed` as fatal, and the bash marker dance had exactly this\n * race (agent glimpses the failed marker before the retry loop clears it).\n */\nexport class GitPrepJob {\n private current: GitPrepState = { state: \"pending\" };\n private started = false;\n\n constructor(\n private readonly deps: GitPrepDeps,\n private readonly extras: GitPrepJobExtras,\n ) {}\n\n get status(): GitPrepState {\n return this.current;\n }\n\n /** Kick off the background attempts. Idempotent. */\n start(): void {\n if (this.started) return;\n this.started = true;\n void this.run();\n }\n\n private async run(): Promise<void> {\n const { log } = this.deps;\n const retryDelayMs = this.extras.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;\n for (let attempt = 1; attempt <= GIT_PREP_MAX_RETRIES; attempt++) {\n const result = await prepareWorkspaceGit(this.deps);\n if (result.state === \"ready\") {\n // Binds gate readiness but are best-effort — a graphify/grimoire\n // failure must never fail the git gate itself.\n try {\n await this.extras.onReady();\n } catch (err) {\n log.warn(`[boot] WARN: pre-ready binds failed: ${errText(err)}`);\n }\n this.current = { state: \"ready\" };\n try {\n await this.extras.afterReady();\n } catch (err) {\n log.warn(`[boot] WARN: post-ready work failed: ${errText(err)}`);\n }\n return;\n }\n if (attempt >= GIT_PREP_MAX_RETRIES) {\n log.error(\n `[boot] workbench git prep failed ${GIT_PREP_MAX_RETRIES} times — giving up (agent surfaces the failure).`,\n );\n this.current = result;\n return;\n }\n log.warn(\n `[boot] workbench git prep failed — retrying (attempt ${attempt}/${GIT_PREP_MAX_RETRIES})...`,\n );\n await new Promise<void>((resolve) => {\n setTimeout(resolve, retryDelayMs);\n });\n }\n }\n}\n","/**\n * Pod-side bootstrap-milestone reporter. The pod alone observes when the\n * workspace git is up to date, when its sidecars are ready, and when the\n * start command has launched; it reports those milestones to the API over the\n * same bootstrap-token channel the bundle poll and crash reporter use\n * (`POST /api/v3/pods/boot-milestone`). The API\n * records them on `Workspace.bootTimeline`, which drives the agent-tab progress\n * meter. Server-owned milestones (pod_created/pod_scheduled/containers_ready/\n * agent_connected/app_serving) are never reported from here — the API enforces\n * the allow-list.\n *\n * Fire-and-forget: a failed or slow report must never delay start, so\n * every path swallows errors and the whole thing no-ops off-pod (GitHub\n * Codespaces / local), where the bootstrap token is absent.\n */\nimport type { BootStepKey } from \"@project/shared\";\n\nconst REPORT_TIMEOUT_MS = 5_000;\n\n/** The steps a pod may report. Mirrors the API's `POD_REPORTABLE_BOOT_STEPS`. */\nexport type PodReportableBootStep = Extract<\n BootStepKey,\n | \"workbench_ready\"\n | \"repo_synced\"\n | \"sidecars_ready\"\n | \"branch_ready\"\n | \"agent_live\"\n | \"start_command_launched\"\n>;\n\nexport interface ReportBootMilestoneOptions {\n key: PodReportableBootStep;\n /** Defaults to `process.env`. Injected for tests. */\n env?: NodeJS.ProcessEnv;\n /** Injected for tests; defaults to global fetch. */\n fetchFn?: typeof fetch;\n timeoutMs?: number;\n}\n\n/**\n * Off-pod fallback sender (GitHub Codespaces): no bootstrap token exists\n * there, but once the agent socket is up its authenticated channel can carry\n * the same milestones. Registered by SessionRunner after connect; milestones\n * fired before registration are dropped — on the codespace step list those\n * early keys aren't rendered anyway.\n */\nlet socketFallback: ((key: PodReportableBootStep) => void) | null = null;\n\nexport function registerBootMilestoneSocketFallback(\n fn: ((key: PodReportableBootStep) => void) | null,\n): void {\n socketFallback = fn;\n}\n\n/**\n * Best-effort POST of a boot milestone. Resolves to `true` when the API\n * acknowledged (HTTP 2xx), `false` otherwise — including the off-pod paths.\n * Never throws. Off-pod (no bootstrap token), the registered socket fallback\n * carries the milestone instead of the HTTP route.\n */\nexport async function reportBootMilestone(opts: ReportBootMilestoneOptions): Promise<boolean> {\n const env = opts.env ?? process.env;\n const apiUrl = env.CONVEYOR_API_URL;\n const token = env.POD_BOOTSTRAP_TOKEN;\n // Only claudespace v3 pods carry both — elsewhere the socket fallback (when\n // registered) feeds the meter instead.\n if (!apiUrl || !token) {\n try {\n socketFallback?.(opts.key);\n } catch {\n // fire-and-forget contract\n }\n return false;\n }\n\n const fetchFn = opts.fetchFn ?? fetch;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), opts.timeoutMs ?? REPORT_TIMEOUT_MS);\n try {\n const res = await fetchFn(`${apiUrl.replace(/\\/$/, \"\")}/api/v3/pods/boot-milestone`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ key: opts.key }),\n signal: controller.signal,\n });\n return res.ok;\n } catch {\n return false;\n } finally {\n clearTimeout(timer);\n }\n}\n"],"mappings":"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","names":["dirname","join","mkdirSync","join","mkdirSync","join"]}