@schoolai/shipyard 3.7.0 → 3.8.0-rc.20260529.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{auth-SS7LV5XK.js → auth-EXHO3AG5.js} +4 -4
- package/dist/capability-detector-worker.js +142 -0
- package/dist/capability-detector-worker.js.map +1 -0
- package/dist/{chunk-DKMDBOFU.js → chunk-2CNIEBKO.js} +21 -11
- package/dist/chunk-2CNIEBKO.js.map +1 -0
- package/dist/chunk-422NIGWV.js +6963 -0
- package/dist/chunk-422NIGWV.js.map +1 -0
- package/dist/chunk-4T2OQAVL.js +51 -0
- package/dist/chunk-4T2OQAVL.js.map +1 -0
- package/dist/chunk-5ER6ZHA2.js +46 -0
- package/dist/chunk-5ER6ZHA2.js.map +1 -0
- package/dist/chunk-7LSEE26O.js +24227 -0
- package/dist/chunk-7LSEE26O.js.map +1 -0
- package/dist/{chunk-7AHRFPAL.js → chunk-7YOU7MBN.js} +183 -17
- package/dist/chunk-7YOU7MBN.js.map +1 -0
- package/dist/chunk-CMGJGK6R.js +382 -0
- package/dist/chunk-CMGJGK6R.js.map +1 -0
- package/dist/{chunk-VPMN47TL.js → chunk-CNR7O5YH.js} +1 -2
- package/dist/{chunk-2J3WSIAF.js → chunk-EF2DAODF.js} +18 -3
- package/dist/chunk-EF2DAODF.js.map +1 -0
- package/dist/chunk-HQ43PHOH.js +1203 -0
- package/dist/chunk-HQ43PHOH.js.map +1 -0
- package/dist/chunk-KITSAHTX.js +134 -0
- package/dist/chunk-KITSAHTX.js.map +1 -0
- package/dist/{chunk-LW2MS4T5.js → chunk-LMJFHKRD.js} +15 -12
- package/dist/chunk-LMJFHKRD.js.map +1 -0
- package/dist/{chunk-SNYEQHUK.js → chunk-NACJENDW.js} +14 -21
- package/dist/chunk-NACJENDW.js.map +1 -0
- package/dist/{chunk-IISLTKYY.js → chunk-TU63KZFW.js} +2 -2
- package/dist/chunk-TX6DK4PK.js +186 -0
- package/dist/chunk-TX6DK4PK.js.map +1 -0
- package/dist/chunk-UQVXWOPT.js +48 -0
- package/dist/chunk-UQVXWOPT.js.map +1 -0
- package/dist/{chunk-3MNPDCO5.js → chunk-WBB4XHLH.js} +139 -140
- package/dist/chunk-WBB4XHLH.js.map +1 -0
- package/dist/chunk-X3MULCV5.js +11 -0
- package/dist/chunk-X3MULCV5.js.map +1 -0
- package/dist/chunk-YZ3Z3ZYI.js +787 -0
- package/dist/chunk-YZ3Z3ZYI.js.map +1 -0
- package/dist/{chunk-2UN5AR7V.js → chunk-ZAOPND5G.js} +2 -2
- package/dist/chunk-ZFKJAYAN.js +542 -0
- package/dist/chunk-ZFKJAYAN.js.map +1 -0
- package/dist/cursor-hook-shim.js +316 -0
- package/dist/cursor-hook-shim.js.map +1 -0
- package/dist/cursor-runner.js +358 -0
- package/dist/cursor-runner.js.map +1 -0
- package/dist/electron-utility.js +111 -0
- package/dist/electron-utility.js.map +1 -0
- package/dist/git-pool-V73Q53NX.js +18 -0
- package/dist/{git-repo-VRT57DGC.js → git-repo-TN3VZXQV.js} +9 -6
- package/dist/index.js +12 -12
- package/dist/index.js.map +1 -1
- package/dist/{logger-GQCSLSZH.js → logger-QHPTO22N.js} +4 -4
- package/dist/login-Q7SZI7JJ.js +20 -0
- package/dist/{logout-VUNCW5B2.js → logout-O4AVMO5S.js} +6 -6
- package/dist/mcp-servers-F64M5T4I.js +24 -0
- package/dist/{roi-Y3MX5UW4.js → roi-EYDLPOCS.js} +5 -5
- package/dist/rss-worker.js +159 -0
- package/dist/rss-worker.js.map +1 -0
- package/dist/{serve-O53FNK64.js → serve-GMRVBGVV.js} +89872 -103000
- package/dist/{serve-O53FNK64.js.map → serve-GMRVBGVV.js.map} +1 -1
- package/dist/skills-ZHEPSBHW.js +11 -0
- package/dist/{start-IDFDHRD6.js → start-4UCUZPIV.js} +229 -27
- package/dist/start-4UCUZPIV.js.map +1 -0
- package/dist/vault-crypto-BKDOA65F.js +13 -0
- package/dist/vault-crypto-BKDOA65F.js.map +1 -0
- package/dist/worker.js +6 -3
- package/dist/worker.js.map +1 -1
- package/package.json +17 -10
- package/dist/chunk-2J3WSIAF.js.map +0 -1
- package/dist/chunk-3MNPDCO5.js.map +0 -1
- package/dist/chunk-66OBOZ3X.js +0 -79
- package/dist/chunk-66OBOZ3X.js.map +0 -1
- package/dist/chunk-7AHRFPAL.js.map +0 -1
- package/dist/chunk-DKMDBOFU.js.map +0 -1
- package/dist/chunk-L2WQMPWS.js +0 -666
- package/dist/chunk-L2WQMPWS.js.map +0 -1
- package/dist/chunk-LW2MS4T5.js.map +0 -1
- package/dist/chunk-PI77CUEP.js +0 -49
- package/dist/chunk-PI77CUEP.js.map +0 -1
- package/dist/chunk-RXI4637N.js +0 -395
- package/dist/chunk-RXI4637N.js.map +0 -1
- package/dist/chunk-SNYEQHUK.js.map +0 -1
- package/dist/chunk-VBPHGPBR.js +0 -126
- package/dist/chunk-VBPHGPBR.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/login-L4BBPUYO.js +0 -20
- package/dist/mcp-servers-MXS5VAWI.js +0 -18
- package/dist/shell-V36EX2IJ.js +0 -27
- package/dist/skills-GPGRNV4R.js +0 -9
- package/dist/start-IDFDHRD6.js.map +0 -1
- package/dist/worker.d.ts +0 -49
- /package/dist/{auth-SS7LV5XK.js.map → auth-EXHO3AG5.js.map} +0 -0
- /package/dist/{chunk-VPMN47TL.js.map → chunk-CNR7O5YH.js.map} +0 -0
- /package/dist/{chunk-IISLTKYY.js.map → chunk-TU63KZFW.js.map} +0 -0
- /package/dist/{chunk-2UN5AR7V.js.map → chunk-ZAOPND5G.js.map} +0 -0
- /package/dist/{git-repo-VRT57DGC.js.map → git-pool-V73Q53NX.js.map} +0 -0
- /package/dist/{logger-GQCSLSZH.js.map → git-repo-TN3VZXQV.js.map} +0 -0
- /package/dist/{login-L4BBPUYO.js.map → logger-QHPTO22N.js.map} +0 -0
- /package/dist/{mcp-servers-MXS5VAWI.js.map → login-Q7SZI7JJ.js.map} +0 -0
- /package/dist/{logout-VUNCW5B2.js.map → logout-O4AVMO5S.js.map} +0 -0
- /package/dist/{shell-V36EX2IJ.js.map → mcp-servers-F64M5T4I.js.map} +0 -0
- /package/dist/{roi-Y3MX5UW4.js.map → roi-EYDLPOCS.js.map} +0 -0
- /package/dist/{skills-GPGRNV4R.js.map → skills-ZHEPSBHW.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/observability/bootstrap-phase.ts","../src/shared/capabilities/effort-probe.ts","../src/shared/capabilities/claude-binary.ts","../src/shared/capabilities/env-methods.ts","../src/shared/capabilities/auth.ts","../src/shared/capabilities/model-capabilities.ts","../src/services/session/message-classifiers.ts","../src/services/session/profiles/claude-code-profile.ts","../src/services/session/profiles/codex-profile.ts","../src/shared/capabilities/codex-auth-detect.ts","../src/services/billing/codex-cost-estimator.ts","../src/services/session/codex-auth.ts","../src/services/session/codex-content-builder.ts","../src/services/session/codex-subagent-result-synthesizer.ts","../src/services/session/codex-item-translator.ts","../src/services/session/profiles/codex-model-catalog.ts","../src/services/session/profiles/cursor-profile.ts","../src/shared/capabilities/cursor-auth-detect.ts","../src/services/session/cursor-auth.ts","../src/services/session/cursor-error-mapper.ts","../src/services/session/profiles/cursor-model-catalog.ts","../src/services/session/profiles/profile-registry.ts","../src/shared/capabilities/index.ts","../src/shared/observability/watchdog-context.ts","../src/shared/capabilities/agent-providers-cache.ts","../src/shared/capabilities/claude-version-cache.ts","../src/shared/capabilities/agents.ts","../src/shared/capabilities/common-dirs.ts","../src/shared/capabilities/detector-timeout.ts","../src/shared/capabilities/env-mismatch.ts","../src/shared/capabilities/graphite-detect.ts","../src/shared/capabilities/marketplace.ts","../src/shared/capabilities/models.ts","../src/shared/capabilities/runtime/auth-adapters.ts","../src/shared/capabilities/git-pr-search.ts","../src/shared/capabilities/git-pr.ts","../src/shared/capabilities/git-ci.ts","../src/shared/capabilities/git-diff.ts","../src/shared/capabilities/refresh-helpers.ts","../src/shared/mcp/token-store.ts"],"sourcesContent":["import type { MetricsCapture } from '../../services/metrics/metrics-collector.js';\nimport { logger } from '../logger.js';\n\n/**\n * Generic auto-instrumentation primitive for daemon startup phases.\n *\n * Wrap any async startup step with `bootstrapPhase(name, () => ...)` and the\n * primitive emits a `bootstrap_phase_start` log on entry, a\n * `bootstrap_phase_end` log on exit, and forwards a `bootstrap_phase` event\n * to the metrics collector. Every wrapped phase contributes one entry to the\n * accumulator; `emitStartupComplete()` flushes the accumulator as a single\n * `startup_complete` log so a daemon-log scan tells you the boot timeline in\n * one place.\n *\n * Why a primitive instead of hardcoded emits at each boundary: the silent\n * `try/catch` in `agents.ts` swallowed the timeout that produced the 2026-05-13\n * 40-second hang with zero log output. Every future startup step that needs\n * timing/outcome metrics gets them for free by being wrapped — there is no\n * \"I forgot to emit\" failure mode.\n *\n * Errors propagate. The primitive logs + emits the `error` outcome and then\n * re-throws so callers preserve their own error-handling semantics.\n */\nexport interface BootstrapPhaseEntry {\n name: string;\n durationMs: number;\n outcome: 'success' | 'error' | 'worker_killed';\n error?: string;\n}\n\n/**\n * Late-bindable sink for the metrics worker. The `MetricsCollector` is\n * constructed several phases into boot (after auth + pid acquisition), so\n * earlier phases would have nowhere to emit. They still produce a log and\n * still land in the accumulator — only the wire emit is conditional.\n */\nlet metricsSink: MetricsCapture | null = null;\nconst accumulator: BootstrapPhaseEntry[] = [];\n\ninterface InFlightPhase {\n name: string;\n start: number;\n}\n\n/**\n * Module-scoped registry of phases currently mid-flight. When a parent abort\n * fires (outer worker terminated externally), `logInFlightPhasesAsKilled`\n * emits `bootstrap_phase_end` with `worker_killed` for every phase that\n * started but never logged `_end`. Without this, the most common production\n * failure mode — outer worker timeout killing the worker mid-phase — leaves\n * zero log evidence of which phase was stuck.\n */\nconst inFlightPhases = new Set<InFlightPhase>();\n/**\n * Mutable so tests resetting module state via `_resetBootstrapPhaseStateForTests`\n * see `totalMs` measured from the start of THEIR simulated boot, not from the\n * original module load.\n */\nlet startupBootStart = performance.now();\nlet startupCompleteEmitted = false;\n\nexport function setBootstrapPhaseMetricsSink(sink: MetricsCapture | null): void {\n metricsSink = sink;\n}\n\n/**\n * Test-only: reset module state so each test starts fresh. Production must\n * never call this — the accumulator is daemon-lifetime by design.\n */\nexport function _resetBootstrapPhaseStateForTests(): void {\n metricsSink = null;\n accumulator.length = 0;\n inFlightPhases.clear();\n startupCompleteEmitted = false;\n startupBootStart = performance.now();\n}\n\n/**\n * Emit `worker_killed` for every phase that started but never ended. Returns\n * the count for tests / callers that want to know.\n */\nexport function logInFlightPhasesAsKilled(): number {\n const now = performance.now();\n const snapshot = [...inFlightPhases];\n inFlightPhases.clear();\n for (const entry of snapshot) {\n const durationMs = now - entry.start;\n accumulator.push({ name: entry.name, durationMs, outcome: 'worker_killed' });\n safeLog('warn', {\n event: 'bootstrap_phase_end',\n phase: entry.name,\n durationMs,\n outcome: 'worker_killed',\n });\n safeEmit('bootstrap_phase', {\n phase: entry.name,\n durationMs,\n outcome: 'worker_killed',\n });\n }\n return snapshot.length;\n}\n\nexport async function bootstrapPhase<T>(name: string, fn: () => Promise<T>): Promise<T> {\n const start = performance.now();\n const tracker: InFlightPhase = { name, start };\n inFlightPhases.add(tracker);\n safeLog('info', { event: 'bootstrap_phase_start', phase: name });\n try {\n const result = await fn();\n /** If killed mid-flight, `logInFlightPhasesAsKilled` already removed us — don't double-log. */\n if (!inFlightPhases.delete(tracker)) return result;\n const durationMs = performance.now() - start;\n const entry: BootstrapPhaseEntry = { name, durationMs, outcome: 'success' };\n accumulator.push(entry);\n safeLog('info', { event: 'bootstrap_phase_end', phase: name, durationMs, outcome: 'success' });\n safeEmit('bootstrap_phase', { phase: name, durationMs, outcome: 'success' });\n return result;\n } catch (error) {\n if (!inFlightPhases.delete(tracker)) throw error;\n const durationMs = performance.now() - start;\n const msg = error instanceof Error ? error.message : String(error);\n const entry: BootstrapPhaseEntry = { name, durationMs, outcome: 'error', error: msg };\n accumulator.push(entry);\n safeLog('warn', {\n event: 'bootstrap_phase_end',\n phase: name,\n durationMs,\n outcome: 'error',\n error: msg,\n });\n safeEmit('bootstrap_phase', {\n phase: name,\n durationMs,\n outcome: 'error',\n error: msg,\n });\n throw error;\n }\n}\n\n/**\n * Flush the accumulated per-phase entries as a single `startup_complete` log.\n * Idempotent — repeated calls are no-ops so multiple boot paths or test\n * harnesses can safely call without producing duplicate aggregates.\n */\nexport function emitStartupComplete(): void {\n if (startupCompleteEmitted) return;\n startupCompleteEmitted = true;\n const totalMs = performance.now() - startupBootStart;\n safeLog('info', {\n event: 'startup_complete',\n totalMs,\n phaseCount: accumulator.length,\n phases: accumulator.map((p) => ({\n name: p.name,\n durationMs: p.durationMs,\n outcome: p.outcome,\n })),\n });\n safeEmit('startup_complete', {\n totalMs,\n phaseCount: accumulator.length,\n phases: accumulator,\n });\n}\n\n/**\n * Snapshot the accumulator. Used by tests and the daemon `startup_complete`\n * emit only — production callers should rely on `emitStartupComplete()`.\n */\nexport function getBootstrapPhaseAccumulator(): readonly BootstrapPhaseEntry[] {\n return accumulator;\n}\n\nfunction safeLog(level: 'info' | 'warn', obj: Record<string, unknown>): void {\n try {\n if (level === 'info') logger.info(obj);\n else logger.warn(obj);\n } catch {\n /** A throw from pino must never abort a startup phase. */\n }\n}\n\nfunction safeEmit(eventType: string, payload: Record<string, unknown>): void {\n const sink = metricsSink;\n if (!sink) return;\n try {\n sink.capture(eventType, payload);\n } catch {\n /** A throw from the metrics buffer must never abort a startup phase. */\n }\n}\n","import { existsSync } from 'node:fs';\nimport { open } from 'node:fs/promises';\nimport { REASONING_EFFORTS, type ReasoningEffort } from '@shipyard/loro-schema';\nimport { logger } from '../logger.js';\nimport { bootstrapPhase } from '../observability/bootstrap-phase.js';\nimport { resolveBundledClaudeBinary } from './claude-binary.js';\n\n/**\n * Probe the SDK-bundled Claude Code CLI to determine which `--effort` values it\n * actually accepts. The installed SDK version may lag behind what Shipyard's\n * capability schema advertises (e.g. SDK 0.2.81 bundles a CLI that rejects\n * `xhigh`). Advertising efforts the CLI rejects produces hard-failing turns,\n * so we narrow the advertised set to the intersection.\n *\n * SDK 0.2.116+ distributes Claude Code as a per-platform native binary\n * (`@anthropic-ai/claude-agent-sdk-${platform}-${arch}`) instead of a bundled\n * `cli.js`. The probe resolves that binary by platform, scans its bytes for\n * the commander effort-option description, and parses the choices out. If the\n * user overrides the spawned binary via `CLAUDE_CODE_PATH`, the advertised\n * set may be stale — `resolveSupportedEffort` in anthropic-adapter.ts\n * provides a second-layer coercion at spawn time to catch that edge case.\n */\n\n/**\n * `xhigh` belongs in the conservative fallback: opus-4-7 advertises it as a\n * core effort tier and the bundled CLI accepts it. Omitting it from the\n * fallback (when binary probing fails) silently strips the most expensive\n * tier from the picker for the entire daemon session.\n */\nconst CONSERVATIVE_FALLBACK: ReadonlySet<ReasoningEffort> = new Set([\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n 'max',\n]);\n\ntype ProbeResult = {\n supported: ReadonlySet<ReasoningEffort>;\n /** `parsed` when the bundled CLI was successfully scanned; `fallback` otherwise. */\n source: 'parsed' | 'fallback';\n};\n\n/**\n * Cached probe result. We use a Promise here so concurrent first-callers\n * deduplicate onto a single chunked-read pass over the ~200MB binary instead\n * of each running their own scan in parallel.\n */\nlet cached: Promise<ReadonlySet<ReasoningEffort>> | null = null;\n/**\n * Synchronous mirror of the resolved value once the probe has completed. Read\n * by sync callers (`resolveSupportedEffort` in anthropic-adapter.ts, called\n * inside the synchronous static `spawn()`) — null until the probe resolves\n * and the spawn-time coercion falls back to \"trust the requested effort\".\n * The eager-warm in `lifecycle.ts` populates this well before any spawn.\n */\nlet cachedSync: ReadonlySet<ReasoningEffort> | null = null;\n\nexport async function getSupportedEfforts(): Promise<ReadonlySet<ReasoningEffort>> {\n if (cached) return cached;\n /**\n * Capture the promise locally before assigning so we can clear the slot\n * on rejection. Without this, a `bootstrapPhase` re-throw (or any future\n * change that lets `probeCli` propagate) would poison `cached` with a\n * permanently-rejected promise — every subsequent caller would observe\n * the same rejection and `cachedSync` would never populate.\n */\n const promise = (async (): Promise<ReadonlySet<ReasoningEffort>> => {\n /**\n * Wrapped so the cold-disk 5-16s read (200MB binary scan) shows up in\n * `startup_complete`. Historically this probe overlapped with the version\n * probe and saturated libuv's I/O thread pool — visibility is the gate to\n * staying on the structural fix that staggers it after signaling.\n */\n const { supported, source } = await bootstrapPhase('effort_probe', () => probeCli());\n cachedSync = supported;\n if (source === 'parsed') {\n /**\n * Exclude meta-values that are never expected in the `--effort` flag set\n * (currently `'none'` — translated to `applyFlagSettings({alwaysThinkingEnabled:false})`\n * at runtime). Otherwise every boot would log a misleading \"CLI doesn't\n * support 'none'\" line, even though nothing is actually missing.\n */\n const dropped = REASONING_EFFORTS.filter((e) => e !== 'none' && !supported.has(e));\n if (dropped.length > 0) {\n logger.info(\n { supported: [...supported], dropped },\n 'bundled Claude Code CLI does not support all reasoning efforts; advertised set narrowed'\n );\n }\n }\n return supported;\n })();\n promise.catch(() => {\n if (cached === promise) cached = null;\n });\n cached = promise;\n return cached;\n}\n\n/**\n * Synchronous accessor for spawn-time call sites that cannot await. Returns\n * the cached probe result if available, or `null` if the probe has not yet\n * resolved. Callers MUST tolerate `null` (no-op coercion path) — see\n * `resolveSupportedEffort` in anthropic-adapter.ts.\n *\n * The eager-warm in `lifecycle.ts:start()` triggers `getSupportedEfforts()`\n * during daemon boot, so by the time any subprocess is spawned the cache\n * has resolved on a healthy machine. The null branch only matters during\n * the first ~hundreds of ms after boot or when the binary cannot be read.\n */\nexport function getSupportedEffortsSync(): ReadonlySet<ReasoningEffort> | null {\n return cachedSync;\n}\n\n/**\n * Pure parse step: extract the supported effort tokens from the CLI's argParser\n * description string. Returns `null` when the description can't be located so\n * the caller can distinguish \"probe succeeded, narrowed to X\" from \"probe\n * failed, fall back conservatively\".\n *\n * The inner char class is permissive (`[^)]+`); unknown tokens are filtered\n * out by `isReasoningEffort` so a new tier introduced in a future CLI is\n * gracefully ignored rather than breaking the outer match.\n */\nexport function parseEffortsFromCliText(cliSource: string): ReadonlySet<ReasoningEffort> | null {\n const match = cliSource.match(/Effort level for the current session \\(([^)]+)\\)/);\n if (!match?.[1]) return null;\n const allowed = new Set<ReasoningEffort>();\n for (const token of match[1].split(',')) {\n const t = token.trim();\n if (isReasoningEffort(t)) allowed.add(t);\n }\n return allowed.size > 0 ? allowed : null;\n}\n\n/**\n * Pure parse step for the array-literal form. SDK 0.3.153 builds the\n * `--effort` help text at runtime (`Effort level for the current session\n * (${BN.join(\", \")})`), so the comma-separated tokens are no longer baked into\n * the description string — `parseEffortsFromCliText` finds only NUL padding\n * there. The effort enum itself, however, is still emitted as a static array\n * literal (`\"low\",\"medium\",\"high\",\"xhigh\",\"max\"`). This parses that slice.\n *\n * `text` starts at the array's first token (the scan needle anchors on\n * `\"low\",\"medium\",\"high\",\"xhigh\"`). We cut at the first `]`/`)` so trailing\n * bytes from an adjacent literal can't leak in, then collect every quoted\n * lowercase token and keep the ones that are real reasoning efforts. Unknown\n * tokens are dropped here; the drift watcher is what alarms on them.\n */\nexport function parseEffortArrayText(text: string): ReadonlySet<ReasoningEffort> | null {\n const terminator = text.search(/[\\])]/);\n const body = terminator === -1 ? text : text.slice(0, terminator);\n const allowed = new Set<ReasoningEffort>();\n for (const match of body.matchAll(/\"([a-z][a-z0-9-]*)\"/g)) {\n const token = match[1];\n if (token !== undefined && isReasoningEffort(token)) allowed.add(token);\n }\n return allowed.size > 0 ? allowed : null;\n}\n\n/**\n * Extract effort tokens from a bundled Claude Code binary using the same\n * primary/fallback path as `probeCli`. Exported for the drift-watcher meta-test\n * so it validates the real parser rather than a duplicate regex.\n */\nexport async function extractEffortTokensFromBinary(\n binaryPath: string\n): Promise<ReadonlySet<ReasoningEffort> | null> {\n const fromArray = await readEffortArrayFromBinary(binaryPath);\n if (fromArray) return fromArray;\n const slice = await readEffortDescriptionFromBinary(binaryPath);\n return slice ? parseEffortsFromCliText(slice) : null;\n}\n\nexport const _testing = {\n reset(): void {\n cached = null;\n cachedSync = null;\n },\n setCached(values: ReadonlySet<ReasoningEffort>): void {\n cachedSync = values;\n cached = Promise.resolve(values);\n },\n};\n\nconst EFFORT_SET: ReadonlySet<string> = new Set(REASONING_EFFORTS);\nfunction isReasoningEffort(value: string): value is ReasoningEffort {\n return EFFORT_SET.has(value);\n}\n\nasync function probeCli(): Promise<ProbeResult> {\n try {\n const binaryPath = resolveBundledClaudeBinary();\n if (!binaryPath || !existsSync(binaryPath)) {\n logger.warn(\n { binaryPath },\n 'bundled Claude Code binary not found; using conservative effort set'\n );\n return { supported: CONSERVATIVE_FALLBACK, source: 'fallback' };\n }\n /**\n * Primary: the static effort-array literal. Present in both the legacy\n * static-string binaries (≤0.2.120) and the runtime-template binaries\n * (0.3.153+), so it's the version-robust signal. Fallback: the commander\n * description string, which only carries tokens on the older binaries.\n */\n const fromArray = await readEffortArrayFromBinary(binaryPath);\n if (fromArray) return { supported: fromArray, source: 'parsed' };\n\n const slice = await readEffortDescriptionFromBinary(binaryPath);\n const fromDescription = slice ? parseEffortsFromCliText(slice) : null;\n if (fromDescription) return { supported: fromDescription, source: 'parsed' };\n\n logger.warn(\n { binaryPath },\n 'could not parse effort tokens from bundled binary (array literal and description both absent); using conservative effort set'\n );\n return { supported: CONSERVATIVE_FALLBACK, source: 'fallback' };\n } catch (err) {\n logger.warn({ err }, 'effort probe failed; using conservative effort set');\n return { supported: CONSERVATIVE_FALLBACK, source: 'fallback' };\n }\n}\n\nconst READ_CHUNK_SIZE = 1024 * 1024;\nconst NEEDLE_BYTES = Buffer.from('Effort level for the current session');\nconst SLICE_TAIL_BYTES = 200;\n\n/**\n * Chunked async scan over the bundled binary (~200MB) for the commander\n * effort-option description string. Reads 1MB at a time and exits as soon as\n * the needle appears in the current window.\n *\n * The previous synchronous `readFileSync(binaryPath)` blocked the event loop\n * for 5-16s on cold disk during daemon boot. The chunked variant returns in\n * sub-second on warm OS page cache and never holds a 200MB buffer, so it\n * stays kind to peak RSS during a daemon restart.\n *\n * To handle a needle that straddles two chunks, we keep the trailing\n * `needle.length - 1` bytes of each chunk and prepend them to the next read.\n */\n/**\n * Extract the effort description starting at `idx` in `window`. When the\n * post-needle tail extends past the window (chunk boundary truncated it),\n * re-read directly at the absolute file offset to capture the full slice.\n */\nasync function extractNeedleSlice(\n fh: Awaited<ReturnType<typeof open>>,\n window: Buffer,\n idx: number,\n windowAbsoluteStart: number\n): Promise<string | null> {\n const end = Math.min(idx + SLICE_TAIL_BYTES, window.length);\n if (end - idx >= NEEDLE_BYTES.length) {\n return window.toString('utf-8', idx, end);\n }\n const absoluteIdx = windowAbsoluteStart + idx;\n const tailLen = SLICE_TAIL_BYTES + NEEDLE_BYTES.length;\n const tailBuf = Buffer.alloc(tailLen);\n const { bytesRead } = await fh.read(tailBuf, 0, tailLen, absoluteIdx);\n if (bytesRead === 0) return null;\n return tailBuf.toString('utf-8', 0, Math.min(tailLen, bytesRead));\n}\n\nasync function readEffortDescriptionFromBinary(binaryPath: string): Promise<string | null> {\n const fh = await open(binaryPath, 'r');\n try {\n const overlap = NEEDLE_BYTES.length - 1;\n const buf = Buffer.alloc(READ_CHUNK_SIZE);\n let carry: Buffer = Buffer.alloc(0);\n let position = 0;\n while (true) {\n const { bytesRead } = await fh.read(buf, 0, READ_CHUNK_SIZE, position);\n if (bytesRead === 0) return null;\n const window =\n carry.length === 0\n ? buf.subarray(0, bytesRead)\n : Buffer.concat([carry, buf.subarray(0, bytesRead)]);\n const idx = window.indexOf(NEEDLE_BYTES);\n if (idx !== -1) {\n return extractNeedleSlice(fh, window, idx, position - carry.length);\n }\n position += bytesRead;\n if (bytesRead < READ_CHUNK_SIZE) return null;\n carry = window.length >= overlap ? window.subarray(window.length - overlap) : window;\n }\n } finally {\n await fh.close();\n }\n}\n\n/**\n * Needle for the static effort-array literal. The minifier emits it with no\n * spaces (`\"low\",\"medium\",\"high\",\"xhigh\"`). Anchoring on the `,\"xhigh\"` suffix\n * disambiguates it from the unrelated `\"low\",\"medium\",\"high\",\"immediate\"`\n * array that also lives in the binary; the trailing slice then picks up `,\"max\"`\n * (and any future appended tier).\n */\nconst EFFORT_ARRAY_NEEDLE = Buffer.from('\"low\",\"medium\",\"high\",\"xhigh\"');\nconst EFFORT_ARRAY_SLICE_LEN = EFFORT_ARRAY_NEEDLE.length + 64;\n\nasync function extractArraySlice(\n fh: Awaited<ReturnType<typeof open>>,\n window: Buffer,\n idx: number,\n windowAbsoluteStart: number\n): Promise<string> {\n const end = Math.min(idx + EFFORT_ARRAY_SLICE_LEN, window.length);\n if (end - idx >= EFFORT_ARRAY_SLICE_LEN) {\n return window.toString('utf-8', idx, end);\n }\n const tailBuf = Buffer.alloc(EFFORT_ARRAY_SLICE_LEN);\n const { bytesRead } = await fh.read(\n tailBuf,\n 0,\n EFFORT_ARRAY_SLICE_LEN,\n windowAbsoluteStart + idx\n );\n return tailBuf.toString('utf-8', 0, bytesRead);\n}\n\n/**\n * Scan one window for every needle occurrence, folding the recognized tokens\n * into `union`. Returns `true` once the union includes `max` (the top tier),\n * which signals the complete effort array has been seen and the caller can stop\n * early.\n */\nasync function foldArrayTokensInWindow(\n fh: Awaited<ReturnType<typeof open>>,\n window: Buffer,\n windowAbsoluteStart: number,\n union: Set<ReasoningEffort>\n): Promise<boolean> {\n let from = 0;\n while (true) {\n const idx = window.indexOf(EFFORT_ARRAY_NEEDLE, from);\n if (idx === -1) return false;\n const slice = await extractArraySlice(fh, window, idx, windowAbsoluteStart);\n const tokens = parseEffortArrayText(slice);\n if (tokens) {\n for (const t of tokens) union.add(t);\n }\n if (union.has('max')) return true;\n from = idx + EFFORT_ARRAY_NEEDLE.length;\n }\n}\n\n/**\n * Full chunked scan for the effort-array literal, unioning the recognized\n * tokens across every occurrence (the binary holds both a 4-token\n * `...,\"xhigh\"` and the full `...,\"xhigh\",\"max\"` array). Early-exits as soon as\n * the union includes `max`. Returns null when the needle never appears, so the\n * caller falls back to the description regex and then the conservative set.\n */\nasync function readEffortArrayFromBinary(\n binaryPath: string\n): Promise<ReadonlySet<ReasoningEffort> | null> {\n const fh = await open(binaryPath, 'r');\n try {\n const overlap = EFFORT_ARRAY_NEEDLE.length - 1;\n const buf = Buffer.alloc(READ_CHUNK_SIZE);\n let carry: Buffer = Buffer.alloc(0);\n let position = 0;\n const union = new Set<ReasoningEffort>();\n while (true) {\n const { bytesRead } = await fh.read(buf, 0, READ_CHUNK_SIZE, position);\n if (bytesRead === 0) break;\n const window =\n carry.length === 0\n ? buf.subarray(0, bytesRead)\n : Buffer.concat([carry, buf.subarray(0, bytesRead)]);\n const complete = await foldArrayTokensInWindow(fh, window, position - carry.length, union);\n if (complete) return union;\n position += bytesRead;\n if (bytesRead < READ_CHUNK_SIZE) break;\n carry = window.length >= overlap ? window.subarray(window.length - overlap) : window;\n }\n return union.size > 0 ? union : null;\n } finally {\n await fh.close();\n }\n}\n","import { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { logger } from '../logger.js';\n\n/**\n * One source of truth for \"where is the Claude Code binary on this machine?\".\n * Subprocess spawns that pass the bare name `'claude'` rely on PATH and\n * silently break when a task's inherited environment loses PATH — which is\n * what happened in the deleted-worktree cascade on 2026-05-13 (see #3034 /\n * #3282 for the analogous fix on the LSP spawn path).\n */\n\n/**\n * Resolve the absolute path of the SDK-bundled Claude Code native binary.\n *\n * SDK 0.2.116+ ships per-platform binaries as optional dependencies:\n * `@anthropic-ai/claude-agent-sdk-${platform}-${arch}/claude`\n * Linux additionally has a musl variant we try first.\n *\n * Returns null when no candidate package is installed (uncommon — would mean\n * a corrupt install).\n */\nexport function resolveBundledClaudeBinary(): string | null {\n const req = createRequire(import.meta.url);\n const sdkMain = req.resolve('@anthropic-ai/claude-agent-sdk');\n const sdkReq = createRequire(sdkMain);\n const ext = process.platform === 'win32' ? '.exe' : '';\n const candidates =\n process.platform === 'linux'\n ? [\n `@anthropic-ai/claude-agent-sdk-linux-${process.arch}-musl`,\n `@anthropic-ai/claude-agent-sdk-linux-${process.arch}`,\n ]\n : [`@anthropic-ai/claude-agent-sdk-${process.platform}-${process.arch}`];\n for (const pkg of candidates) {\n try {\n const resolved = sdkReq.resolve(`${pkg}/claude${ext}`);\n /** Binaries inside an ASAR archive cannot be exec'd — rewrite to the unpacked path that electron-builder places them at via asarUnpack. */\n return resolved.includes('app.asar/')\n ? resolved.replace('app.asar/', 'app.asar.unpacked/')\n : resolved;\n } catch (err) {\n logger.debug({ pkg, err }, 'platform claude binary candidate not resolvable');\n }\n }\n return null;\n}\n\n/**\n * Resolve an absolute path to the Claude Code binary for daemon subprocess\n * spawns. Returns null if nothing resolves — callers should treat that as\n * \"skip the subprocess\" rather than falling back to bare `'claude'`. The\n * bare-name fallback is exactly what produced the ENOENT cluster in the\n * 2026-05-13 deleted-worktree cascade.\n *\n * Resolution order:\n * 1. `CLAUDE_CODE_PATH` env override (if set and points to an existing file)\n * 2. SDK-bundled platform native binary (`existsSync`-gated)\n */\nexport function resolveClaudeBinaryPath(\n log: (e: { event: string; [k: string]: unknown }) => void\n): string | null {\n const envPath = process.env.CLAUDE_CODE_PATH;\n if (envPath && existsSync(envPath)) return envPath;\n const bundled = resolveBundledClaudeBinary();\n if (bundled && existsSync(bundled)) return bundled;\n log({ event: 'claude_binary_unresolved', envPath: envPath ?? null, bundled });\n return null;\n}\n","import type { AnthropicAuthMethod } from '@shipyard/loro-schema';\n\n/**\n * Single source of truth for env-var → auth-method resolution.\n * Precedence must stay in sync between auth detection and env-mismatch\n * classification — use this helper in both places.\n */\nexport interface EnvMethodResolution {\n method: AnthropicAuthMethod;\n envVar: string;\n}\n\nexport function resolveEnvMethod(env: NodeJS.ProcessEnv): EnvMethodResolution | null {\n if (env.CLAUDE_CODE_USE_BEDROCK) return { method: 'bedrock', envVar: 'CLAUDE_CODE_USE_BEDROCK' };\n if (env.CLAUDE_CODE_USE_VERTEX) return { method: 'vertex', envVar: 'CLAUDE_CODE_USE_VERTEX' };\n if (env.CLAUDE_CODE_USE_FOUNDRY) return { method: 'foundry', envVar: 'CLAUDE_CODE_USE_FOUNDRY' };\n if (env.ANTHROPIC_AUTH_TOKEN) return { method: 'gateway', envVar: 'ANTHROPIC_AUTH_TOKEN' };\n if (env.ANTHROPIC_API_KEY) return { method: 'api-key', envVar: 'ANTHROPIC_API_KEY' };\n return null;\n}\n","import type { AnthropicAuthStatus } from '@shipyard/session';\nimport { logger } from '../logger.js';\nimport { resolveEnvMethod } from './env-methods.js';\nimport { AUTH_STATUS_TIMEOUT_MS, run } from './shell.js';\n\n/**\n * Tagged discriminated union for auth detection.\n *\n * - `detected` — confirmed authenticated state (env var or CLI loggedIn: true)\n * - `not-detected` — CLI reports loggedIn: false (explicit logout)\n * - `preserved` — CLI call failed; caller should keep prior state\n */\nexport type AuthDetectionResult =\n | { kind: 'detected'; auth: AnthropicAuthStatus }\n | { kind: 'preserved'; reason: 'spawn-error' | 'timeout' | 'parse-error' }\n | { kind: 'not-detected'; auth: { status: 'unauthenticated'; method: 'none' } };\n\n/**\n * @param methodHint — if the caller knows which login method was used\n * (e.g. from the login request), pass it here. The CLI status output\n * reports `authMethod: \"claude.ai\"` for both subscription and console\n * OAuth, so we need this hint to distinguish them.\n */\nexport async function detectAnthropicAuth(\n methodHint?: AnthropicAuthStatus['method']\n): Promise<AuthDetectionResult> {\n const envResult = detectFromEnvVars();\n if (envResult) return { kind: 'detected', auth: envResult };\n\n let stdout: string;\n try {\n stdout = await run('claude', ['auth', 'status', '--json'], undefined, AUTH_STATUS_TIMEOUT_MS);\n } catch (err) {\n const reason = classifyCliError(err);\n logger.warn(\n { err, reason },\n 'Failed to detect Anthropic auth via claude CLI — preserving last-known status'\n );\n return { kind: 'preserved', reason };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(stdout);\n } catch (err) {\n logger.warn({ err }, 'claude auth status returned invalid JSON — preserving last-known status');\n return { kind: 'preserved', reason: 'parse-error' };\n }\n\n return interpretCliPayload(parsed, methodHint);\n}\n\ninterface CliSpawnError extends Error {\n code?: string;\n signal?: string;\n killed?: boolean;\n}\n\nfunction isCliSpawnError(err: unknown): err is CliSpawnError {\n return err instanceof Error;\n}\n\nfunction classifyCliError(err: unknown): 'timeout' | 'spawn-error' {\n if (!isCliSpawnError(err)) return 'spawn-error';\n if (err.code === 'ETIMEDOUT') return 'timeout';\n if (err.killed === true && err.signal === 'SIGTERM') return 'timeout';\n return 'spawn-error';\n}\n\nfunction interpretCliPayload(\n parsed: unknown,\n methodHint: AnthropicAuthStatus['method'] | undefined\n): AuthDetectionResult {\n if (typeof parsed !== 'object' || parsed === null) {\n return { kind: 'not-detected', auth: { status: 'unauthenticated', method: 'none' } };\n }\n\n const record = toRecord(parsed);\n if (!record.loggedIn) {\n return { kind: 'not-detected', auth: { status: 'unauthenticated', method: 'none' } };\n }\n\n const method = methodHint && methodHint !== 'none' ? methodHint : resolveCliAuthMethod(record);\n const email = typeof record.email === 'string' ? record.email : undefined;\n const auth: AnthropicAuthStatus = {\n status: 'authenticated',\n method,\n email,\n orgName: typeof record.orgName === 'string' ? record.orgName : undefined,\n apiProvider: typeof record.apiProvider === 'string' ? record.apiProvider : undefined,\n subscriptionType:\n typeof record.subscriptionType === 'string'\n ? record.subscriptionType\n : record.subscriptionType === null\n ? null\n : undefined,\n /**\n * Account identifier for collision detection (Step 19). Use email as\n * the primary candidate; fall back to the sub claim from the id_token\n * when email is absent (env-var auth path, console auth, etc.).\n */\n accountId: email ?? (typeof record.sub === 'string' ? record.sub : undefined),\n };\n return { kind: 'detected', auth };\n}\n\nfunction detectFromEnvVars(): AnthropicAuthStatus | null {\n const resolved = resolveEnvMethod(process.env);\n return resolved ? { status: 'authenticated', method: resolved.method } : null;\n}\n\n/**\n * Map the CLI's `authMethod` / `apiProvider` fields to our canonical method enum.\n */\nfunction resolveCliAuthMethod(record: Record<string, unknown>): AnthropicAuthStatus['method'] {\n const authMethod = typeof record.authMethod === 'string' ? record.authMethod : '';\n const apiProvider = typeof record.apiProvider === 'string' ? record.apiProvider : '';\n\n if (authMethod === 'claude.ai') return 'claude-ai';\n if (authMethod.includes('console') || apiProvider === 'console') return 'console';\n if (authMethod.includes('sso') || apiProvider === 'sso') return 'sso';\n\n return 'claude-ai';\n}\n\nfunction toRecord(value: unknown): Record<string, unknown> {\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n return value as never;\n }\n return {};\n}\n","/**\n * Per-model capability predicates and shared thinking constants. Pure\n * model-family facts (no I/O, no SDK coupling) — kept here so multiple spawn\n * paths can share them without one adapter importing from another. Sibling to\n * `effort-probe.ts`.\n */\n\nconst THINKING_CAPABLE_PREFIXES = ['claude-sonnet', 'claude-opus'];\n\n/**\n * Returns true when `thinking: { type: 'adaptive' }` is supported. Haiku does\n * not support adaptive thinking; Sonnet 4.5+ and Opus 4.5+ do. Suffix tags\n * (e.g. `[1m]`) are tolerated since the prefix check is the authoritative\n * gate.\n */\nexport function supportsAdaptiveThinking(model: string): boolean {\n return THINKING_CAPABLE_PREFIXES.some((prefix) => model.startsWith(prefix));\n}\n\n/**\n * User-facing placeholder for `redacted_thinking` blocks (Anthropic's safety\n * filter substitutes this for the original reasoning). One source of truth so\n * copy stays consistent across the SDK, direct-API, and subagent paths.\n */\nexport const REDACTED_THINKING_PLACEHOLDER = '[Reasoning was filtered by Anthropic]';\n","import type {\n SDKMemoryRecallMessage,\n SDKMessage,\n SDKSystemMessage,\n SDKUserMessage,\n} from '@anthropic-ai/claude-agent-sdk';\nimport type { BetaContentBlock } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs';\nimport type { ContentBlock } from '@shipyard/loro-schema';\nimport { AGENT_SYSTEM_CLAUDE_CODE } from '@shipyard/loro-schema';\nimport { z } from 'zod';\n\n/**\n * `BetaUsage` carries optional `service_tier` / `speed` / `inference_geo`\n * fields that the SDK shipped in mid-2026 but older versions omit. Parse\n * via Zod so test mocks and pre-upgrade payloads don't trip on missing\n * fields, and so the runtime narrowing matches what we forward to the\n * UI. `passthrough` keeps the rest of `BetaUsage` reachable to callers\n * holding the original reference.\n */\nconst usageBetaExtensionsSchema = z\n .object({\n service_tier: z.string().nullable().optional(),\n speed: z.string().nullable().optional(),\n inference_geo: z.string().nullable().optional(),\n })\n .passthrough();\n\nimport { REDACTED_THINKING_PLACEHOLDER } from '../../shared/capabilities/model-capabilities.js';\n\nimport type { InitMetadata, SubprocessEvent } from './agent-subprocess.js';\nimport { toRecord } from './sdk-content-builder.js';\n\nexport type AdapterLogger = (entry: { event: string; [key: string]: unknown }) => void;\n\nexport function extractInitMetadata(initMsg: SDKSystemMessage): InitMetadata {\n return {\n tools: initMsg.tools,\n skills: initMsg.skills,\n agents: initMsg.agents ?? [],\n mcpServers: initMsg.mcp_servers,\n model: initMsg.model,\n claudeCodeVersion: initMsg.claude_code_version,\n agentRuntimeVersion: initMsg.claude_code_version,\n agentSystem: AGENT_SYSTEM_CLAUDE_CODE,\n };\n}\n\nexport function classifySystemMessage(\n message: SDKMessage & { type: 'system' }\n): SubprocessEvent | null {\n switch (message.subtype) {\n case 'init':\n return {\n type: 'init_received',\n sessionId: message.session_id,\n metadata: extractInitMetadata(message),\n };\n case 'task_started':\n return {\n type: 'background_agent_started',\n taskId: message.task_id,\n toolUseId: message.tool_use_id ?? '',\n description: message.description,\n agentType: message.task_type,\n prompt: message.prompt,\n };\n case 'task_notification':\n return {\n type: 'background_agent_completed',\n taskId: message.task_id,\n status: message.status,\n summary: message.summary,\n usage: message.usage\n ? {\n totalTokens: message.usage.total_tokens,\n toolUses: message.usage.tool_uses,\n durationMs: message.usage.duration_ms,\n }\n : undefined,\n };\n case 'task_progress':\n return {\n type: 'subagent_progress',\n taskId: message.task_id,\n toolUseId: message.tool_use_id,\n description: message.description,\n summary: message.summary,\n lastToolName: message.last_tool_name,\n usage: message.usage\n ? {\n totalTokens: message.usage.total_tokens,\n toolUses: message.usage.tool_uses,\n durationMs: message.usage.duration_ms,\n }\n : { totalTokens: 0, toolUses: 0, durationMs: 0 },\n };\n case 'compact_boundary': {\n const meta = message.compact_metadata;\n return {\n type: 'compaction_completed',\n preTokens: meta.pre_tokens,\n ...(meta.post_tokens !== undefined ? { postTokens: meta.post_tokens } : {}),\n ...(meta.duration_ms !== undefined ? { durationMs: meta.duration_ms } : {}),\n ...(meta.trigger !== undefined ? { compactionTrigger: meta.trigger } : {}),\n };\n }\n case 'status':\n return message.status === 'compacting' ? { type: 'compaction_started' } : null;\n case 'memory_recall': {\n const recall: SDKMemoryRecallMessage = message;\n return {\n type: 'memory_recall',\n mode: recall.mode,\n memories: recall.memories,\n };\n }\n case 'files_persisted':\n case 'hook_started':\n case 'hook_progress':\n case 'hook_response':\n case 'local_command_output':\n case 'elicitation_complete':\n return null;\n default:\n return null;\n }\n}\n\nexport function extractDeniedToolNames(\n denials: Array<{ tool_name: string }> | undefined\n): string[] | undefined {\n const names = denials?.map((d) => d.tool_name) ?? [];\n return names.length > 0 ? names : undefined;\n}\n\ntype ModelEntry = NonNullable<ReturnType<typeof Object.values<unknown>>>[number] & {\n cacheReadInputTokens?: number;\n cacheCreationInputTokens?: number;\n inputTokens?: number;\n outputTokens?: number;\n contextWindow?: number;\n maxOutputTokens?: number;\n webSearchRequests?: number;\n costUSD?: number;\n};\n\nfunction aggregateModelUsage(\n modelEntries: ModelEntry[],\n fallback: { cacheRead: number; cacheCreation: number; input: number; output: number }\n) {\n if (modelEntries.length === 0)\n return {\n ...fallback,\n maxContext: undefined,\n maxOutput: undefined,\n webSearch: undefined,\n costUsd: undefined,\n };\n const sum = (fn: (m: ModelEntry) => number | undefined) =>\n modelEntries.reduce((acc, m) => acc + (fn(m) ?? 0), 0);\n const maxOf = (fn: (m: ModelEntry) => number | undefined): number | undefined =>\n Math.max(...modelEntries.map((m) => fn(m) ?? 0)) || undefined;\n return {\n cacheRead: sum((m) => m.cacheReadInputTokens),\n cacheCreation: sum((m) => m.cacheCreationInputTokens),\n input: sum((m) => m.inputTokens),\n output: sum((m) => m.outputTokens),\n maxContext: maxOf((m) => m.contextWindow),\n maxOutput: maxOf((m) => m.maxOutputTokens),\n webSearch: sum((m) => m.webSearchRequests) || undefined,\n costUsd: sum((m) => m.costUSD) || undefined,\n };\n}\n\ninterface UsageBetaFields {\n serviceTier: string | null;\n speed: string | null;\n inferenceGeo: string | null;\n}\n\n/**\n * Pure: extract the post-mid-2026 BetaUsage extensions from a usage\n * payload via Zod. Returns nulls when fields are absent (older SDK\n * versions or test mocks). Extracted so `buildSuccessTurnResult`\n * stays under the cognitive-complexity ceiling.\n */\nfunction extractUsageBetaFields(usage: unknown): UsageBetaFields {\n const parsed = usageBetaExtensionsSchema.safeParse(usage);\n if (!parsed.success) return { serviceTier: null, speed: null, inferenceGeo: null };\n return {\n serviceTier: parsed.data.service_tier ?? null,\n speed: parsed.data.speed ?? null,\n inferenceGeo: parsed.data.inference_geo ?? null,\n };\n}\n\n/**\n * Build the success-branch payload of `classifyResultMessage`. Extracted\n * so the parent stays under the 15-complexity ceiling — Biome counts\n * each ternary spread + null guard, and the post-mid-2026 BetaUsage\n * extensions pushed this past the limit.\n */\nfunction buildSuccessTurnResult(\n message: SDKMessage & { type: 'result'; subtype: 'success' },\n permissionDeniedTools: string[] | undefined\n): SubprocessEvent {\n // eslint-disable-next-line no-restricted-syntax -- Object.values returns unknown[]; ModelEntry is a local structural type, not Zod-validated, so we narrow with an intersection cast rather than parse\n const entries = Object.values(message.modelUsage ?? {}) as ModelEntry[];\n const u = message.usage;\n const agg = aggregateModelUsage(entries, {\n cacheRead: u.cache_read_input_tokens,\n cacheCreation: u.cache_creation_input_tokens,\n input: u.input_tokens,\n output: u.output_tokens,\n });\n const { serviceTier, speed, inferenceGeo } = extractUsageBetaFields(u);\n return {\n type: 'turn_complete',\n result: {\n totalCostUsd: message.total_cost_usd,\n durationMs: message.duration_ms,\n durationApiMs: message.duration_api_ms,\n resultText: message.result,\n numTurns: message.num_turns,\n inputTokens: u.input_tokens,\n inputTokensRaw:\n u.input_tokens + (u.cache_read_input_tokens ?? 0) + (u.cache_creation_input_tokens ?? 0),\n outputTokens: agg.output,\n cacheReadInputTokens: u.cache_read_input_tokens ?? 0,\n cacheCreationInputTokens: u.cache_creation_input_tokens ?? 0,\n contextWindow: agg.maxContext,\n maxOutputTokens: agg.maxOutput,\n stopReason: message.stop_reason,\n permissionDeniedTools,\n ...(agg.webSearch !== undefined ? { webSearchRequests: agg.webSearch } : {}),\n ...(agg.costUsd !== undefined ? { costUsd: agg.costUsd } : {}),\n ...(serviceTier !== null ? { serviceTier } : {}),\n ...(speed !== null ? { speed } : {}),\n ...(inferenceGeo !== null ? { inferenceGeo } : {}),\n providerExtras: {\n provider: 'claude-code' as const,\n ...(serviceTier !== null ? { serviceTier } : {}),\n ...(speed !== null ? { speed } : {}),\n ...(inferenceGeo !== null ? { inferenceGeo } : {}),\n ...(agg.webSearch !== undefined ? { webSearchRequests: agg.webSearch } : {}),\n ...(agg.costUsd !== undefined ? { costUsd: agg.costUsd } : {}),\n },\n },\n };\n}\n\nexport function classifyResultMessage(message: SDKMessage & { type: 'result' }): SubprocessEvent {\n const permissionDeniedTools = extractDeniedToolNames(message.permission_denials);\n if (message.subtype === 'success') {\n return buildSuccessTurnResult(message, permissionDeniedTools);\n }\n const errorText =\n message.errors.length > 0 ? message.errors.join('; ') : `SDK error: ${message.subtype}`;\n return {\n type: 'sdk_error',\n error: errorText,\n errorSubtype: message.subtype,\n stopReason: message.stop_reason,\n permissionDeniedTools,\n };\n}\n\nexport function extractParentToolUseId(message: SDKMessage): string | null {\n return 'parent_tool_use_id' in message && typeof message.parent_tool_use_id === 'string'\n ? message.parent_tool_use_id\n : null;\n}\n\nexport function classifyUserMessage(\n message: SDKMessage & { type: 'user' }\n): SubprocessEvent | null {\n const isReplay = 'isReplay' in message && message.isReplay;\n const parentId = extractParentToolUseId(message);\n /**\n * Claude SDK exposes a per-user-message stable id on `message.uuid`.\n * Stamp as a Claude-tagged AgentMessageMark; Codex stamps marks\n * differently in its adapter.\n */\n const uuid = 'uuid' in message && typeof message.uuid === 'string' ? message.uuid : undefined;\n const mark =\n uuid !== undefined ? ({ agentId: AGENT_SYSTEM_CLAUDE_CODE, ref: uuid } as const) : undefined;\n\n if (isReplay) {\n const blocks = convertUserContent(message.message.content);\n if (blocks.length === 0) return null;\n return { type: 'user_message_echo', content: blocks, mark };\n }\n\n const agentResult = parseTaskNotificationXml(message.message.content);\n if (agentResult) return agentResult;\n\n const toolResults = extractToolResults(message.message.content, parentId);\n if (toolResults.length > 0) {\n return { type: 'tool_result_echo', content: toolResults };\n }\n\n if (mark) {\n return { type: 'user_message_echo', content: [], mark };\n }\n return null;\n}\n\nexport function parseTaskNotificationXml(\n content: string | SDKUserMessage['message']['content']\n): SubprocessEvent | null {\n const text = typeof content === 'string' ? content : null;\n if (!text || !text.startsWith('<task-notification>')) return null;\n const taskId = extractXmlTag(text, 'task-id');\n const result = extractXmlTag(text, 'result');\n if (!taskId || !result) return null;\n return { type: 'background_agent_result', taskId, result };\n}\n\nexport function extractXmlTag(xml: string, tag: string): string | null {\n const open = `<${tag}>`;\n const close = `</${tag}>`;\n const start = xml.indexOf(open);\n if (start === -1) return null;\n const end = xml.indexOf(close, start + open.length);\n if (end === -1) return null;\n return xml.slice(start + open.length, end);\n}\n\n/**\n * Classify an SDK message into a SubprocessEvent, or null if the\n * message doesn't need to be forwarded.\n */\nexport function classifyMessage(message: SDKMessage, log?: AdapterLogger): SubprocessEvent | null {\n switch (message.type) {\n case 'system':\n return classifySystemMessage(message);\n case 'result':\n return classifyResultMessage(message);\n case 'assistant': {\n if (message.error === 'authentication_failed') {\n return { type: 'auth_not_logged_in' };\n }\n if (message.error === 'billing_error') {\n return { type: 'billing_error' };\n }\n if (message.error === 'rate_limit') {\n return { type: 'rate_limit_error' };\n }\n const parentId = extractParentToolUseId(message);\n const blocks = convertAssistantContent(message.message.content, parentId);\n if (blocks.length === 0) return null;\n return {\n type: 'assistant_message',\n messageId: String(message.uuid),\n content: blocks,\n };\n }\n case 'tool_progress':\n return {\n type: 'tool_use_started',\n toolUseId: message.tool_use_id,\n toolName: message.tool_name,\n };\n case 'user':\n return classifyUserMessage(message);\n case 'auth_status':\n if (!message.isAuthenticating && message.error) {\n return { type: 'auth_not_logged_in' };\n }\n return null;\n case 'stream_event':\n return classifyStreamEvent(message);\n case 'tool_use_summary':\n return {\n type: 'tool_use_summary',\n summary: message.summary,\n toolUseIds: message.preceding_tool_use_ids,\n };\n case 'rate_limit_event':\n return { type: 'rate_limit', info: message.rate_limit_info };\n case 'prompt_suggestion':\n return null;\n default: {\n const _exhaustive: never = message;\n log?.({ event: 'unhandled_sdk_message_type', message: JSON.stringify(_exhaustive) });\n return null;\n }\n }\n}\n\nexport function classifyStreamEvent(\n message: SDKMessage & { type: 'stream_event' }\n): SubprocessEvent | null {\n const rawEvent = message.event;\n switch (rawEvent.type) {\n case 'content_block_start': {\n const block = rawEvent.content_block;\n const base = {\n type: 'stream_delta' as const,\n event: 'content_block_start' as const,\n index: rawEvent.index,\n blockType: block.type,\n };\n if (block.type === 'tool_use') {\n return { ...base, toolName: block.name, toolUseId: block.id };\n }\n return base;\n }\n case 'content_block_delta': {\n const delta = rawEvent.delta;\n const base = {\n type: 'stream_delta' as const,\n event: 'content_block_delta' as const,\n index: rawEvent.index,\n };\n switch (delta.type) {\n case 'text_delta':\n return { ...base, textDelta: delta.text };\n case 'input_json_delta':\n return { ...base, inputJsonDelta: delta.partial_json };\n case 'thinking_delta':\n return { ...base, textDelta: delta.thinking };\n case 'citations_delta':\n case 'signature_delta':\n case 'compaction_delta':\n return null;\n default: {\n const _exhaustive: never = delta;\n void _exhaustive;\n return null;\n }\n }\n }\n case 'content_block_stop':\n return {\n type: 'stream_delta',\n event: 'content_block_stop',\n index: rawEvent.index,\n };\n case 'message_start': {\n const usage = rawEvent.message?.usage;\n if (usage) {\n return {\n type: 'api_usage_snapshot',\n inputTokens: usage.input_tokens ?? 0,\n cacheReadInputTokens: usage.cache_read_input_tokens ?? 0,\n cacheCreationInputTokens: usage.cache_creation_input_tokens ?? 0,\n };\n }\n return null;\n }\n case 'message_delta':\n case 'message_stop':\n return null;\n default:\n return null;\n }\n}\n\nexport function convertAssistantContent(\n content: BetaContentBlock[],\n parentToolUseId: string | null\n): ContentBlock[] {\n const blocks: ContentBlock[] = [];\n\n for (const block of content) {\n switch (block.type) {\n case 'text':\n blocks.push({ type: 'text', text: block.text });\n break;\n case 'tool_use':\n blocks.push({\n type: 'tool_use',\n toolUseId: block.id,\n toolName: block.name,\n input: toRecord(block.input),\n parentToolUseId,\n });\n break;\n case 'thinking':\n if (block.thinking.length > 0) {\n blocks.push({ type: 'thinking', text: block.thinking });\n }\n break;\n case 'redacted_thinking':\n blocks.push({ type: 'thinking', text: REDACTED_THINKING_PLACEHOLDER });\n break;\n case 'server_tool_use':\n case 'web_search_tool_result':\n case 'web_fetch_tool_result':\n case 'code_execution_tool_result':\n case 'bash_code_execution_tool_result':\n case 'text_editor_code_execution_tool_result':\n case 'tool_search_tool_result':\n case 'mcp_tool_use':\n case 'mcp_tool_result':\n case 'container_upload':\n case 'compaction':\n case 'advisor_tool_result':\n break;\n default: {\n const _exhaustive: never = block;\n void _exhaustive;\n }\n }\n }\n\n return blocks;\n}\n\n/**\n * Extract tool_result blocks from SDK user messages.\n * These are the results of tool execution that the agent consumes internally.\n * We emit them so the browser can pair them with tool_use blocks.\n */\nexport function extractToolResults(\n content: string | SDKUserMessage['message']['content'],\n parentToolUseId: string | null\n): ContentBlock[] {\n if (typeof content === 'string') return [];\n const blocks: ContentBlock[] = [];\n for (const block of content) {\n if (block.type !== 'tool_result') continue;\n const resultContent =\n typeof block.content === 'string'\n ? block.content\n : Array.isArray(block.content)\n ? block.content\n .filter((c): c is { type: 'text'; text: string } => c.type === 'text')\n .map((c) => c.text)\n .join('\\n')\n : '';\n blocks.push({\n type: 'tool_result',\n toolUseId: block.tool_use_id,\n content: resultContent,\n isError: block.is_error ?? false,\n parentToolUseId,\n });\n }\n return blocks;\n}\n\n/**\n * Extract text blocks from SDK user message content.\n * Handles both `string` and `ContentBlockParam[]` forms.\n * Skips tool_result blocks (emitted separately via extractToolResults).\n * SDK image blocks from resumed sessions are dropped — the asset is already on disk.\n */\nexport function convertUserContent(\n content: string | SDKUserMessage['message']['content']\n): ContentBlock[] {\n if (typeof content === 'string') {\n return content.trim() ? [{ type: 'text', text: content }] : [];\n }\n\n const blocks: ContentBlock[] = [];\n for (const block of content) {\n switch (block.type) {\n case 'text':\n if (block.text.trim()) {\n blocks.push({ type: 'text', text: block.text });\n }\n break;\n case 'image':\n break;\n case 'tool_result':\n case 'tool_use':\n case 'document':\n case 'search_result':\n case 'thinking':\n case 'redacted_thinking':\n case 'server_tool_use':\n case 'web_search_tool_result':\n case 'web_fetch_tool_result':\n case 'code_execution_tool_result':\n case 'bash_code_execution_tool_result':\n case 'text_editor_code_execution_tool_result':\n case 'tool_search_tool_result':\n case 'container_upload':\n break;\n default: {\n const _exhaustive: never = block;\n void _exhaustive;\n }\n }\n }\n return blocks;\n}\n","/**\n * Claude Code profile entry — c3 form.\n *\n * c3 status (codex retrofit): every field on `AgentCapabilityProfile<ContentBlock>`\n * is populated, allowing the registry's `RegisteredProfile` type to tighten\n * from `Pick<...> & Partial<...>` to the full profile contract. Behavior is\n * unchanged — every field that has a daemon-side implementation today is\n * bound to the existing function (no physical relocation in this commit).\n * Sub-steps in `.research/codex-implementation-playbook.md` §11 schedule\n * the physical moves; c3 establishes the typed chokepoint so each move can\n * land independently without re-typing the profile shape.\n *\n * What \"bound\" means here:\n * - `spawn.args/envInject/envStrip` mirror the spawn-time options assembled\n * by `buildSpawnOptions` in `../../serve-factory-helpers.ts`. The shipping\n * daemon still calls `buildSpawnOptions` directly; the profile fields\n * describe the same contract so a later flip can route through them.\n * - `contentTranslator` and `eventTranslator` are typed shells that delegate\n * to the existing translator functions in `../message-classifiers.ts`\n * / `../sdk-content-builder.ts`. Profile readers consume the canonical\n * shape; the SDK adapter continues to call the translators directly.\n * - `permissionFlow.callbackHandler` and `planContentSource.extract` are\n * stubs that throw if invoked through the profile — neither callsite has\n * migrated yet. The wire-type strings (`requestMessageType`,\n * `responseMessageType`) and `writePathTemplate` ARE authoritative and\n * safe to read.\n * - `permissionModeMap` IS authoritative — it's a pure function consumed\n * by the Codex profile work in c7+ as the reference for how `auto` vs\n * `acceptEdits` resolve.\n *\n * Anything that reads a profile field today (post-c3) gets the right answer\n * if the field is documented as authoritative below. Stub closures are\n * marked with `Profile field not yet wired through dispatch.` comments —\n * those are unreachable in c3 because no callsite reads them yet.\n */\n\nimport type {\n AgentAuthDetectionResult,\n AgentCapabilityProfile,\n AnthropicAuthMethod,\n ContentBlock,\n RewindTarget,\n PermissionMode as SchemaPermissionMode,\n SpawnContext,\n TaskOverlay,\n} from '@shipyard/loro-schema';\nimport { AnthropicAuthMethodSchema } from '@shipyard/loro-schema';\n\nimport { detectAnthropicAuth } from '../../../shared/capabilities/auth.js';\nimport { getSupportedEfforts } from '../../../shared/capabilities/effort-probe.js';\nimport type { AgentSubprocess } from '../agent-subprocess.js';\nimport { convertAssistantContent } from '../message-classifiers.js';\nimport { toSdkContent } from '../sdk-content-builder.js';\n\n/**\n * The bundled-CLI version Shipyard ships and bills against. Update this\n * in lockstep with the agent SDK bump.\n */\nconst CLAUDE_CODE_BUNDLED_VERSION = '2.1.153';\n\n/**\n * Pure mapper: Shipyard `PermissionMode` → native Claude approval policy.\n *\n * `PermissionMode` from `@shipyard/loro-schema` uses kebab-case\n * (`'accept-edits'`, `'bypass'`); the SDK's NativeApprovalPolicy.claude\n * uses camelCase (`'acceptEdits'`, `'bypassPermissions'`). The translation\n * here mirrors the implicit shape in `anthropic-adapter.toSdkPermissionMode`.\n */\nfunction claudePermissionModeMap(\n mode: SchemaPermissionMode\n): ReturnType<AgentCapabilityProfile['permissionModeMap']> {\n switch (mode) {\n case 'default':\n return { kind: 'claude-code', policy: 'default' };\n case 'accept-edits':\n return { kind: 'claude-code', policy: 'acceptEdits' };\n case 'plan':\n return { kind: 'claude-code', policy: 'plan' };\n case 'bypass':\n return { kind: 'claude-code', policy: 'bypassPermissions' };\n case 'auto':\n return { kind: 'claude-code', policy: 'auto' };\n default: {\n const _exhaustive: never = mode;\n return _exhaustive;\n }\n }\n}\n\n/**\n * Stub used for profile fields whose callsite has not yet migrated to read\n * through the profile (per playbook §11, sub-steps 5/6/8/9/10). Calling one\n * of these in c3 indicates an out-of-order migration — the field exists on\n * the profile contract for future-step typing, but is not yet wired.\n */\nfunction notYetWired(fieldName: string): never {\n throw new Error(\n `claudeCodeProfile.${fieldName}: profile field not yet wired through dispatch in c3 — ` +\n 'callsite still reads directly from the legacy chokepoint. ' +\n 'See .research/codex-implementation-playbook.md §11 for migration order.'\n );\n}\n\n/**\n * Type guard for objects with a string-valued `type` field equal to the\n * expected discriminant. Used by `compactionSource.matcher` closures so\n * the profile contract carries the matcher logic without `as` casts.\n */\nfunction hasTypeField(value: unknown, expected: string): boolean {\n if (typeof value !== 'object' || value === null) return false;\n if (!('type' in value)) return false;\n const record: Record<string, unknown> = value;\n return record.type === expected;\n}\n\nexport const claudeCodeProfile: AgentCapabilityProfile<ContentBlock, AgentSubprocess> = {\n id: 'claude-code',\n displayName: 'Claude Code',\n iconRef: {\n kind: 'svg-component',\n component: 'ClaudeCodeIcon',\n /** Anthropic rust/copper — matches the `ClaudeCodeIcon` SVG fill. */\n color: '#D97757',\n },\n capabilityBadges: [],\n onboardingCopy: {\n emptyStateHeading: 'Spawn Claude Code agents on your machine.',\n installInstructions: 'Claude Code ships bundled with Shipyard — no separate install required.',\n authPromptHelp:\n 'Sign in with your Claude.ai subscription, an Anthropic Console API key, or your enterprise SSO/Bedrock/Vertex/Foundry configuration.',\n capabilityCaveats: [],\n },\n capabilities: {\n canStreamTextDelta: true,\n canStreamReasoningDelta: true,\n canRewindByMessage: true,\n canPlanMode: true,\n canBackgroundExec: true,\n canMidSessionMcpReload: true,\n canCwdHookObserve: true,\n canPersistFullCompactionMetadata: true,\n canSubagent: true,\n canMcpOauth: true,\n windowOccupancyReporting: 'current',\n },\n\n /**\n * Rewind contract — Claude rewinds at spawn time via the SDK's\n * `forkSession + resumeSessionAt` options, both keyed off\n * `AgentMessageMark.ref` (the Claude SDK `message.uuid`). No live-side\n * dispatch — `applyLive` is omitted so the handler falls through to\n * the stop+respawn cycle that translates `resumeAtMessageId` into the\n * SDK spawn options via `buildSpawnOptions`.\n */\n rewind: {\n supports: new Set<RewindTarget['kind']>(['beforeMessage']),\n toSpawnOptions(target: RewindTarget) {\n if (target.kind !== 'beforeMessage') return null;\n return { resumeAtMessageId: target.mark.ref };\n },\n },\n\n /**\n * Spawn contract — mirrors `buildSpawnOptions` in serve-factory-helpers.\n * The shipping daemon continues to call `buildSpawnOptions` directly; this\n * field exists so a later sub-step can flip dispatch through the profile.\n */\n spawn: {\n /**\n * Claude Code is bundled with Shipyard via `@anthropic-ai/claude-agent-sdk`,\n * which ships per-platform native binaries — there is no separate install.\n * Returning a non-null sentinel keeps the binary-installed check positive\n * without committing to a concrete path (the SDK resolves the path\n * internally via `pathToClaudeCodeExecutable` resolution).\n */\n binaryResolver: () => Promise.resolve('bundled-via-sdk'),\n args: () => {\n notYetWired('spawn.args');\n },\n envInject: () => ({}),\n /**\n * Claude honors Shipyard's `NODE_OPTIONS` heap configuration; no env\n * stripping required. Codex profile (c7) populates this with\n * `['NODE_OPTIONS']` because the Rust binary panics on it.\n */\n envStrip: [],\n },\n\n transport: {\n /** Claude's adapter consumes an async iterator from the SDK, not framed JSON-RPC. */\n framing: 'sdk-iterator',\n outboundEncoder: () => {\n notYetWired('transport.outboundEncoder');\n },\n inboundDecoder: () => {\n notYetWired('transport.inboundDecoder');\n },\n correlator: {\n register: () => {\n notYetWired('transport.correlator.register');\n },\n resolve: () => {\n notYetWired('transport.correlator.resolve');\n },\n reject: () => {\n notYetWired('transport.correlator.reject');\n },\n },\n notificationDispatcher: () => {\n notYetWired('transport.notificationDispatcher');\n },\n },\n\n reconnect: {\n /** Claude resumes via the SDK's `resume` option; user_message_echo replays state. */\n kind: 'replay-on-resume',\n },\n\n memoryContract: {\n honorsNodeOptions: true,\n oomSignalsByPlatform: {\n darwin: [6, 9],\n linux: [6, 9],\n },\n },\n\n prewarmable: true,\n\n /**\n * Content translator — typed shells over the existing message-classifiers\n * and sdk-content-builder helpers. Direct callers continue to import the\n * helpers; this binding lets profile-aware callers use the canonical\n * `ContentTranslator<ContentBlock>` interface.\n */\n contentTranslator: {\n toNativeUserInput: (blocks: ContentBlock[]) => toSdkContent(blocks),\n fromNativeAssistantContent: (native) => {\n /**\n * The SDK message classifiers operate over the full assistant SDK\n * message; here we narrow to the `content` array shape. Callers\n * that already hold an SDK message route through `convertAssistantContent`\n * directly. This shim exists to satisfy the profile contract — when\n * the dispatch flip lands, the call site that holds raw content will\n * use this entrypoint.\n */\n if (!Array.isArray(native)) {\n throw new Error(\n 'claudeCodeProfile.contentTranslator.fromNativeAssistantContent: ' +\n 'expected native to be an Anthropic content array. ' +\n 'Direct adapter callers should continue to use convertAssistantContent.'\n );\n }\n /**\n * Reuse the assistant-content path from message-classifiers. The\n * classifier takes (content, parentToolUseId) and returns canonical\n * `ContentBlock[]`. `null` parent is the right default for the\n * top-level assistant message; subagent transcripts carry their own\n * parent and are translated by the subagent backend, not here.\n */\n return convertAssistantContent(native, null);\n },\n },\n\n /**\n * Event translator — Claude's SDK delivers messages as a typed iterator;\n * `message-classifiers.classifyMessage` is the existing chokepoint. The\n * profile exposes a thin closure for symmetry with Codex's notification\n * translator. Not yet read by dispatch in c3.\n */\n eventTranslator: {\n translate: () => {\n notYetWired('eventTranslator.translate');\n },\n synthesizeInit: () => {\n notYetWired('eventTranslator.synthesizeInit');\n },\n },\n\n /**\n * Browser-side `MODEL_META` lived in the model-comparison panel until\n * the Codex profile-snapshot grouping landed; moved verbatim onto the\n * profile so each agent owns its own per-model display metadata and the\n * Codex section renders uniformly. Pricing here is the panel-display\n * pair (`costInputUsd`/`costOutputUsd`), distinct from the structured\n * `pricing` field reserved for `costReporting === 'estimated'` profiles\n * (Codex). Claude continues to report cost directly so the structured\n * `pricing` field is intentionally absent on these entries.\n */\n models: [\n {\n id: 'claude-opus-4-8',\n nativeName: 'claude-opus-4-8',\n displayName: 'Claude Opus 4.8',\n description: 'Most capable, sharper judgement, more honest progress reporting',\n contextWindow: 1_000_000,\n maxOutput: 128_000,\n /**\n * `ultracode` is a synthetic Shipyard tier: `xhigh` effort + the SDK's\n * Dynamic Workflows grant (`Settings.enableWorkflows`). It is NOT a\n * `--effort` token — the bundled CLI's `--effort` flag only accepts\n * low/medium/high/xhigh/max, and the API only ever sees `xhigh`. Because\n * it's synthetic it would be stripped by the binary-probe filter, so\n * `filterEfforts` in capabilities/models.ts exempts it (gated on `xhigh`\n * being probe-supported, since that's what it realizes as). The effort is\n * coerced to `xhigh` and the workflow grant is carried via\n * `enableWorkflows` — see anthropic-adapter.ts. Anthropic recommends\n * starting at `xhigh` (or `ultracode` when the agent should fan out).\n */\n supportedEfforts: ['none', 'low', 'medium', 'high', 'xhigh', 'ultracode', 'max'],\n defaultEffort: 'xhigh',\n tagline: 'Most capable, sharper judgement, more honest progress reporting',\n speedTier: 'slow',\n costInputUsd: 5,\n costOutputUsd: 25,\n /**\n * Fast Mode on Opus 4.8 is gated on Claude Code CLI v2.1.154+. The\n * currently-pinned SDK 0.3.153 bundles CLI v2.1.153, which does NOT\n * route Opus 4.8 Fast Mode at the new $10/M input, $50/M output tier\n * (2× standard / 2.5× speed). Until 0.3.154+ is published, leave the\n * toggle off so users do not see a broken Fast Mode experience.\n *\n * Follow-up: P0 issue tracks re-enabling once SDK 0.3.154+ ships.\n */\n supportsFastMode: false,\n capabilities: {\n reasoning: true,\n adaptiveThinking: true,\n webSearch: true,\n vision: true,\n },\n },\n {\n id: 'claude-opus-4-7',\n nativeName: 'claude-opus-4-7',\n displayName: 'Claude Opus 4.7',\n description: 'Previous-generation Opus, 1M context, adaptive reasoning',\n contextWindow: 1_000_000,\n maxOutput: 128_000,\n /**\n * Default bumped from `high` to `xhigh` per Anthropic's official\n * recommendation: \"Start with `xhigh` for coding and agentic use cases,\n * and use `high` as the minimum for most intelligence-sensitive\n * workloads.\" See\n * https://platform.claude.com/docs/en/build-with-claude/effort#recommended-effort-levels-for-claude-opus-4-7.\n * Opus 4.7 does NOT advertise `ultracode` — that's Opus 4.8 / CLI 2.1.153+ only.\n */\n supportedEfforts: ['none', 'low', 'medium', 'high', 'xhigh', 'max'],\n defaultEffort: 'xhigh',\n tagline: 'Previous-generation Opus, 1M context, adaptive reasoning',\n speedTier: 'slow',\n costInputUsd: 5,\n costOutputUsd: 25,\n supportsFastMode: true,\n /**\n * Anthropic Fast Mode is a beta tier (research preview) for\n * Claude Opus 4.6 and 4.7 only — `$30/M input, $150/M output`,\n * which is 6× standard rates. Source:\n * https://platform.claude.com/docs/en/about-claude/pricing#fast-mode-pricing\n *\n * Cache and data-residency multipliers stack on top of these\n * rates; the chip shows the base Fast rate only.\n */\n fastModePricing: {\n costInputUsd: 30,\n costOutputUsd: 150,\n },\n capabilities: {\n reasoning: true,\n adaptiveThinking: true,\n webSearch: true,\n vision: true,\n },\n },\n {\n id: 'claude-sonnet-4-6',\n nativeName: 'claude-sonnet-4-6',\n displayName: 'Claude Sonnet 4.6',\n description: 'Everyday coding, reviews, quick iterations',\n contextWindow: 1_000_000,\n maxOutput: 64_000,\n supportedEfforts: ['none', 'low', 'medium', 'high', 'max'],\n defaultEffort: 'medium',\n tagline: 'Everyday coding, reviews, quick iterations',\n speedTier: 'fast',\n costInputUsd: 3,\n costOutputUsd: 15,\n capabilities: {\n reasoning: true,\n adaptiveThinking: true,\n webSearch: true,\n vision: true,\n },\n },\n {\n id: 'claude-haiku-4-5-20251001',\n nativeName: 'claude-haiku-4-5-20251001',\n displayName: 'Claude Haiku 4.5',\n description: 'Simple questions, boilerplate, rapid prototyping',\n contextWindow: 200_000,\n maxOutput: 64_000,\n supportedEfforts: [],\n tagline: 'Simple questions, boilerplate, rapid prototyping',\n speedTier: 'fastest',\n costInputUsd: 1,\n costOutputUsd: 5,\n capabilities: {\n reasoning: false,\n adaptiveThinking: false,\n webSearch: true,\n vision: true,\n },\n },\n ],\n\n thinkingDescriptor: {\n shape: 'claude-adaptive',\n defaultDisplay: 'summarized',\n },\n\n permissionFlow: {\n kind: 'callback',\n callbackHandler: () => {\n notYetWired('permissionFlow.callbackHandler');\n },\n requestMessageType: 'permission_request',\n responseMessageType: 'permission_resolved',\n },\n permissionModeMap: claudePermissionModeMap,\n sandboxExtensionFlow: null,\n\n /**\n * Authoritative mirror of the Shipyard-supported Anthropic auth methods.\n * Matches `AnthropicAuthMethod` from shared-enums minus `'none'`. Read\n * by the onboarding/profile-summary surfaces (post-c10).\n */\n authMethods: [\n {\n id: 'claude-ai',\n displayName: 'Claude.ai subscription',\n loginUx: 'oauth-browser',\n storageHint: 'OAuth token stored in macOS Keychain',\n requiresShell: false,\n },\n {\n id: 'console',\n displayName: 'Anthropic Console API key',\n loginUx: 'api-key-paste',\n storageHint: 'API key stored in macOS Keychain or ANTHROPIC_API_KEY env',\n requiresShell: false,\n },\n {\n id: 'api-key',\n displayName: 'ANTHROPIC_API_KEY environment',\n loginUx: 'env-only',\n storageHint: 'Read from ANTHROPIC_API_KEY at process start',\n requiresShell: false,\n },\n {\n id: 'gateway',\n displayName: 'Anthropic Gateway token',\n loginUx: 'env-only',\n storageHint: 'Read from ANTHROPIC_AUTH_TOKEN at process start',\n requiresShell: false,\n },\n {\n id: 'sso',\n displayName: 'Enterprise SSO',\n loginUx: 'oauth-browser',\n storageHint: 'OAuth token from corporate IdP, stored in Keychain',\n requiresShell: false,\n },\n {\n id: 'bedrock',\n displayName: 'AWS Bedrock',\n loginUx: 'env-only',\n storageHint: 'AWS_* credentials from ambient environment',\n requiresShell: false,\n },\n {\n id: 'vertex',\n displayName: 'Google Vertex AI',\n loginUx: 'env-only',\n storageHint: 'GOOGLE_APPLICATION_CREDENTIALS from ambient environment',\n requiresShell: false,\n },\n {\n id: 'foundry',\n displayName: 'Azure Foundry',\n loginUx: 'env-only',\n storageHint: 'AZURE_* credentials from ambient environment',\n requiresShell: false,\n },\n ],\n\n /**\n * Triggering login is currently handled by the `auth-status` channel\n * messages in the daemon — there is no profile-level `triggerLogin`\n * dispatch yet. Stub returns an unreachable error to satisfy the type\n * contract; the legacy auth-status path remains the source of truth.\n */\n triggerLogin: () => {\n notYetWired('triggerLogin');\n },\n\n resolveAuthCredentials: () => Promise.resolve(null),\n\n /**\n * Refresh-time auth probe — bound to the existing `detectAnthropicAuth`\n * helper. The unified `onRefreshAgentProviders` chokepoint reads this\n * via the profile contract; the prior bespoke \"refresh anthropicAuth\n * only\" code path stays intact for boot-time `detectCapabilities` calls\n * where the existing serial ordering matters.\n *\n * The `methodHint` parameter is validated as an `AnthropicAuthMethod`\n * before the call to keep the contract loose-typed; invalid hints flow\n * through as `undefined`, mirroring the underlying detector's default.\n */\n authDetector: (methodHint?: string): Promise<AgentAuthDetectionResult> => {\n const parsed = methodHint ? AnthropicAuthMethodSchema.safeParse(methodHint) : null;\n const validHint: AnthropicAuthMethod | undefined =\n parsed?.success === true ? parsed.data : undefined;\n return detectAnthropicAuth(validHint).then((result): AgentAuthDetectionResult => {\n switch (result.kind) {\n case 'detected':\n return { kind: 'detected', auth: result.auth };\n case 'not-detected':\n return { kind: 'not-detected', auth: result.auth };\n case 'preserved':\n return { kind: 'preserved', reason: result.reason };\n default: {\n const _exhaustive: never = result;\n return _exhaustive;\n }\n }\n });\n },\n\n /**\n * Claude reports cost via SDK `result.total_cost_usd` — authoritative.\n * Codex (c7) computes from tokens × pricing and sets `'estimated'`.\n */\n costReporting: 'reported',\n costEstimator: null,\n tokenUsageFieldMap: {\n /**\n * SDK shape (Anthropic Messages API):\n * { input_tokens, output_tokens,\n * cache_read_input_tokens, cache_creation_input_tokens }\n * Reasoning is NOT broken out — folded into output_tokens. Cache\n * creation IS broken out for prompt-cache cost attribution.\n */\n inputTokens: 'input_tokens',\n cachedInputTokens: 'cache_read_input_tokens',\n outputTokens: 'output_tokens',\n cacheCreationTokens: 'cache_creation_input_tokens',\n },\n rateLimitShape: 'anthropic',\n\n /**\n * Error classification still happens inline in the SDK adapter — the\n * SDK emits `auth_not_logged_in` / `rate_limit` / `billing_error` /\n * `rate_limit_error` events that the agent-session FSM consumes\n * directly. This entrypoint is reserved for future centralization\n * (Codex c7 needs the same shape but parsing JSON-RPC error frames).\n */\n errorMapper: {\n classify: () => {\n notYetWired('errorMapper.classify');\n },\n },\n\n subagentBackend: {\n spawnTool: 'Task',\n /**\n * Claude reports subagent progress via SDK `system` messages with\n * subtype `task_started` / `task_progress` / `task_updated` /\n * `task_notification` — see `subagent-task-filter.ts` for the\n * suppression filter that drops the `local_bash` synthetic.\n */\n progressSource: 'system-message',\n /**\n * The agent receives subagent results as XML injected inline into the\n * next user turn. `parseTaskNotificationXml` (search the daemon)\n * extracts the result envelope.\n */\n resultDelivery: { kind: 'inline-xml-injection' },\n transcriptVisibility: 'inline',\n terminate: () => {\n notYetWired('subagentBackend.terminate');\n },\n parentChildIdShape: 'parentToolUseId',\n },\n\n /**\n * Null because Claude's plan capture rides on `ExitPlanMode` tool\n * interception directly in `plan-handler.ts`, not through the\n * profile-level `extract` contract. Keeping a stubbed entry here would\n * advertise an `extract` function the daemon never calls and invite\n * future callers to assume `planContentSource` is the canonical\n * source for every agent — which it isn't for Claude.\n */\n planContentSource: null,\n\n /**\n * Claude emits `TodoWrite` tool_use blocks; the daemon translates them\n * into TaskOverlay diffs. The translation still lives inline in the\n * harness; this field documents the canonical hook point.\n */\n todoSource: {\n kind: 'tool-event',\n toolOrItemName: 'TodoWrite',\n translateToTaskOverlay: (): TaskOverlay => {\n notYetWired('todoSource.translateToTaskOverlay');\n },\n },\n\n /**\n * Claude exposes `CwdChanged` as an SDK hook installed at spawn time\n * (see `anthropic-adapter.ts` `hooks.CwdChanged`). Profile binding is\n * informational — the hook installation site can read this in a later\n * sub-step but in c3 the inline hook stays put.\n */\n cwdObserver: {\n installHook: () => {\n notYetWired('cwdObserver.installHook');\n },\n },\n\n /**\n * Claude emits BOTH `compaction_started` and `compaction_completed`\n * events from the agent-session FSM — the SDK reports a `compact_boundary`\n * system subtype that the orchestrator translates. The matcher functions\n * are stubbed until the dispatch flip migrates callers.\n */\n compactionSource: {\n startedEvent: {\n eventName: 'compaction_started',\n matcher: (e) => hasTypeField(e, 'compaction_started'),\n },\n completedEvent: {\n eventName: 'compaction_completed',\n matcher: (e) => hasTypeField(e, 'compaction_completed'),\n extractPreTokens: (e) => {\n if (typeof e !== 'object' || e === null || !('preTokens' in e)) return null;\n const record: Record<string, unknown> = e;\n const value = record.preTokens;\n return typeof value === 'number' ? value : null;\n },\n },\n },\n\n /**\n * Tool denylist applies via SDK option `disallowedTools` — wired through\n * `buildSpawnOptions`. Profile binding is informational; the inline path\n * remains authoritative until the dispatch flip.\n */\n toolDenylistApplicator: {\n apply: () => {\n notYetWired('toolDenylistApplicator.apply');\n },\n },\n\n mcpServerRegistration: {\n /**\n * Claude accepts MCP servers via the SDK's `mcpServers` option at\n * spawn time (see `buildSpawnOptions`). Codex (c7) uses\n * `thread-start-config` instead.\n */\n kind: 'sdk-option',\n register: () => {\n notYetWired('mcpServerRegistration.register');\n },\n },\n\n mcpAuthIdioms: {\n /** SDK method names exposed by the bundled Claude Code runtime. */\n authenticateMethod: 'mcpAuthenticate',\n submitCallbackMethod: 'mcpSubmitOAuthCallbackUrl',\n },\n\n skillsMechanism: {\n /** Claude supports a per-spawn skills allowlist via SDK option `skills`. */\n kind: 'sdk-filter',\n /**\n * Narrow the daemon's full `SkillInfo[]` to skill names the Claude\n * runtime can reach.\n *\n * Defaults applied on read (matches the schema doc on `SkillInfoSchema`\n * in `@shipyard/session/schemas.ts`):\n * - `compatibleAgents` defaults to `[sourceAgent ?? 'claude-code']` so\n * a skill with no explicit compat tag still counts as Claude-native.\n * - `bodyResolution` defaults to `'native'` so a skill the detector\n * didn't classify is treated as reachable.\n *\n * Dropping `bodyResolution === 'unreachable'` covers Codex-pathed\n * skills with mirror off (compatibleAgents = ['codex'], resolution =\n * 'unreachable' for Claude). The compat check is the primary gate;\n * the resolution check is belt-and-suspenders for skills whose source\n * tagging is missing but classifier marked them unreachable.\n *\n * `namespace` is present only for plugin-provided skills. The SDK\n * accepts bare skill names or plugin-qualified names (`plugin-foo:qa`);\n * synthetic prefixes such as `claude-code:qa` are rejected.\n */\n filterSkills: (skills, _ctx) => {\n return skills\n .filter((s) => {\n const compat: readonly string[] = s.compatibleAgents ?? [s.sourceAgent ?? 'claude-code'];\n const resolution = s.bodyResolution ?? 'native';\n return compat.includes('claude-code') && resolution !== 'unreachable';\n })\n .map((s) => (s.namespace ? `${s.namespace}:${s.name}` : s.name));\n },\n },\n\n /**\n * System prompt fragments — the assembled prompt continues to live in\n * `../../harness/system-prompt.ts` (one consolidated string). Splitting\n * into named fragments is scheduled for playbook §11 sub-step 3; for c3\n * we surface placeholders so the type compiles. The fragments below are\n * empty strings; the harness's `buildShipyardSystemPrompt()` remains the\n * authoritative assembler.\n *\n * IMPORTANT: do NOT begin splitting the prompt by reading these — they\n * are intentionally empty. The split must preserve byte-for-byte output\n * via a snapshot test, which sub-step 3 will add.\n */\n systemPromptFragments: {\n backgroundExecution: '',\n planMode: '',\n todoGuidance: '',\n toolReferences: {\n subagentSpawn: 'Task',\n shellExec: 'Bash',\n fileEdit: 'Edit',\n todoTool: 'TodoWrite',\n planSubmit: 'ExitPlanMode',\n },\n },\n\n /**\n * Managed-key billing identity — Anthropic's Messages API requires this\n * header prefix to allow subscription users to consume Sonnet/Opus via\n * the direct API.\n */\n cliResumeTemplate: 'cd \"{cwd}\" && claude --resume {sessionId}',\n skillInvocationSigil: '/',\n\n metadata: {\n displayName: 'Claude Code',\n vendor: 'Anthropic',\n cliCommand: 'claude',\n messageSigil: '/',\n postHogProviderId: 'claude',\n /** Claude Code ships bundled with Shipyard — no separate install step. */\n installCommand: null,\n },\n\n probeEfforts: getSupportedEfforts,\n\n billingIdentityHeaders: (_ctx: SpawnContext) => ({\n 'x-anthropic-billing-header': `cc_version=${CLAUDE_CODE_BUNDLED_VERSION}; cc_entrypoint=sdk-ts;`,\n }),\n\n /**\n * Approximate Shipyard system-prompt overhead for Claude Code, in tokens.\n * Used by the cross-agent bridge to subtract overhead from the context\n * window before computing the history budget. Measured against\n * `apps/daemon/src/services/harness/system-prompt.ts` output\n * (~3500 chars / 4 ≈ 875 tokens as of 2026-05-25).\n */\n systemPromptOverheadTokens: 875,\n};\n","/**\n * Codex profile entry — c7 form.\n *\n * Brings up `codexProfile` as the second registered `AgentCapabilityProfile`.\n * Mirrors the c3 Claude retrofit shape: every field on\n * `AgentCapabilityProfile<ContentBlock>` is populated, behavioral closures\n * that still live in legacy chokepoints throw via `notYetWired`, and the\n * declarative fields (capabilities, models, auth methods, permission mode\n * map, etc.) are authoritative and safe to read.\n *\n * What \"bound\" means here:\n * - `spawn.args/envInject/envStrip` describe the Codex `app-server` spawn\n * contract — argv prefix, `NODE_OPTIONS` stripping (Rust binary panics\n * on it), no env injection beyond what `CodexAgentSubprocess.spawn`\n * adds itself (the harness bearer token). c7's serve-factory branch\n * reads through this rather than hardcoding the argv list.\n * - `contentTranslator.toNativeUserInput` delegates to c6's\n * `buildCodexUserInput`. `fromNativeAssistantContent` returns `[]`\n * because Codex's assistant content flows in via `item/started` and\n * `item/completed` thread items, not a bulk content array; the\n * translator's per-frame path (`translateCodexItem`) is the right\n * entry.\n * - `eventTranslator.translate` is bound to `translateCodexItem` for\n * thread-item frames. `synthesizeInit` is stubbed; the Codex\n * subprocess synthesizes its own init event in-flight from the\n * `thread/start` response (see `codex-subprocess.ts` →\n * `#emitInitFromThreadStart`). When the dispatch flip lands, the\n * subprocess will read through this closure.\n * - `permissionFlow.notificationHandler` is stubbed; c9 wires the\n * daemon↔browser approval-response roundtrip. Wire-type strings are\n * authoritative.\n * - `permissionModeMap` IS authoritative — a pure function consumed by\n * spawn-time policy resolution in c9.\n * - `sandboxExtensionFlow` populates `parseDeniedPath` + `bannerCopy`\n * declaratively; `applyExtension` throws until c9 wires the actual\n * thread-restart with extended `additional_directories`.\n * - `errorMapper.classify` delegates to the warning classifier extracted\n * here so the c6 translator and the profile share one implementation.\n *\n * Out of scope for c7 (deferred per playbook §3):\n * - Pre-warm pool integration (`prewarmable = false`).\n * - Skills filter (`skillsMechanism = null`).\n * - Tool denylist applicator (`null` — Codex has no per-thread mechanism).\n * - Subagent termination RPC (stub; Codex protocol does not surface it).\n * - Live model switch + mid-thread MCP reload (stubbed in c6 subprocess).\n *\n * Trust posture: this profile is loaded inside the daemon process. Its\n * spawn fields are read by `serve-factory.ts`'s Codex branch which trusts\n * the daemon-supplied binary path. The harness MCP HTTP server's bearer\n * token is injected by `CodexAgentSubprocess.spawn` from the per-task\n * registration result — this profile does not handle secrets directly.\n */\n\nimport { execFile } from 'node:child_process';\nimport { createRequire } from 'node:module';\nimport { platform } from 'node:os';\nimport { promisify } from 'node:util';\n\nimport type {\n AgentAuthDetectionResult,\n AgentCapabilityProfile,\n CodexAuthMethod,\n ContentBlock,\n MappedError,\n ResolvedAuth,\n RewindTarget,\n SandboxRequestedPaths,\n PermissionMode as SchemaPermissionMode,\n SpawnArgs,\n SpawnContext,\n TaskOverlay,\n} from '@shipyard/loro-schema';\nimport { CODEX_AUTH_METHODS, CodexAuthMethodSchema } from '@shipyard/loro-schema';\n\nimport { detectCodexAuth } from '../../../shared/capabilities/codex-auth-detect.js';\nimport { logger } from '../../../shared/logger.js';\nimport { estimateCodexCost } from '../../billing/codex-cost-estimator.js';\nimport type { AgentSubprocess } from '../agent-subprocess.js';\nimport { resolveCodexCredentials } from '../codex-auth.js';\nimport { buildCodexUserInput } from '../codex-content-builder.js';\nimport {\n createTranslatorCtx,\n type ItemTranslatorLogger,\n type TranslatorCtx,\n translateCodexItem,\n} from '../codex-item-translator.js';\n\nimport { CODEX_MODEL_CATALOG } from './codex-model-catalog.js';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Pinned `@openai/codex` version that ships bundled with the daemon. Must\n * match the exact pin in `apps/daemon/package.json` and\n * `apps/daemon/package-npm.json` per AGENTS.md Invariant #13.\n *\n * Codex is bundled the same way the Claude Agent SDK is bundled: an exact\n * version pin in the daemon `package.json` brings the package into\n * `node_modules` so the daemon can resolve the CLI entry via\n * `require.resolve('@openai/codex/bin/codex.js')` without depending on\n * the user's PATH. The user no longer needs `npm install -g @openai/codex`\n * — see `resolveCodexBinary` in this file for the resolution chain.\n *\n * This in-source mirror is used for diagnostic logging on spawn (so a\n * bundled-version mismatch is visible in daemon logs without inspecting\n * `node_modules`).\n */\nexport const CODEX_BUNDLED_VERSION = '0.133.0';\n\n/**\n * Pure mapper: Shipyard `PermissionMode` → native Codex approval policy.\n *\n * Authoritative for c7. The Codex variants are tagged with `kind:` strings\n * directly on `NativeApprovalPolicy` (the union is closed; adding a new\n * variant breaks the switch in c9's spawn-time resolver).\n *\n * - `'default'` → on-request (per-tool prompt)\n * - `'accept-edits'` → on-request (collapses to default — Codex\n * has no shell-vs-edit primitive split;\n * see plan §\"Known divergences from Claude\")\n * - `'plan'` → collaboration-plan (read-only + plan capture)\n * - `'bypass'` → never (no prompts — destructive; admin-only)\n * - `'auto'` → on-request (guardian subagent wiring deferred;\n * byte-identical to default until then)\n */\nfunction codexPermissionModeMap(\n mode: SchemaPermissionMode\n): ReturnType<AgentCapabilityProfile['permissionModeMap']> {\n switch (mode) {\n case 'default':\n return { kind: 'codex-on-request' };\n case 'accept-edits':\n return { kind: 'codex-on-request' };\n case 'plan':\n return { kind: 'codex-collaboration-plan' };\n case 'bypass':\n return { kind: 'codex-never' };\n case 'auto':\n return { kind: 'codex-on-request' };\n default: {\n const _exhaustive: never = mode;\n return _exhaustive;\n }\n }\n}\n\n/**\n * Last successful binary resolution. Survives transient `execFile` failures\n * (libuv pool exhaustion, signal-killed lookup, kernel hiccups) on the\n * fallback PATH lookup that would otherwise collapse `installedAgents` to\n * `[]` and broadcast \"Codex not installed\" to the UI for the duration of\n * one tick.\n *\n * Matches the `lastKnown` semantics of `agents.ts`'s Claude path:\n * - exit code 1 (`ERR_CHILD_PROCESS_STDIO_MAXBUFFER`-class authoritative\n * \"not found\" from `which`) clears the cache.\n * - Any other failure (timeout, signal, ENOENT spawning `which` itself)\n * keeps the cached path so the next caller sees the prior state.\n *\n * The bundled path (via `require.resolve`) is deterministic — once the\n * daemon is installed with `@openai/codex` as a dep, the resolution is a\n * pure filesystem lookup. Bundled resolution failures are NOT cached: a\n * surprise resolution failure would be a packaging bug, not a transient\n * one, and silently masking it would defeat diagnostics.\n */\nlet lastKnownCodexBinary: string | null = null;\n\n/**\n * Test-only: reset the session memo. Production must not call this — the\n * cache is purely a transient-failure guard.\n */\nexport function _resetCodexBinaryCacheForTests(): void {\n lastKnownCodexBinary = null;\n}\n\n/**\n * Synchronous accessor for the most recent resolved Codex binary path.\n * Returns `null` until the first `resolveCodexBinary()` call lands a\n * result (boot-time `detectCapabilities` always runs it). Used by\n * `serve-factory`'s spawn router (Phase B / PROTOCOL_VERSION 86) to\n * decide `agent_not_installed` rejection without awaiting a fresh\n * `which codex` inside the synchronous `SpawnSubprocessFn`.\n *\n * Test-only setter: `_setCodexBinaryCacheForTests` below. Production\n * writes go exclusively through `resolveCodexBinary()`.\n */\nexport function getCachedCodexBinaryPath(): string | null {\n return lastKnownCodexBinary;\n}\n\n/** Test-only: seed the session memo to a known value. */\nexport function _setCodexBinaryCacheForTests(value: string | null): void {\n lastKnownCodexBinary = value;\n}\n\nfunction isAuthoritativeNotFound(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n if ('killed' in err && err.killed === true) return false;\n if ('signal' in err && typeof err.signal === 'string') return false;\n if (!('code' in err)) return false;\n const code = err.code;\n if (typeof code === 'string') return false;\n return code === 1;\n}\n\n/**\n * Resolve the bundled `@openai/codex` CLI entry point. The package's\n * `bin.codex` is `bin/codex.js`, a Node wrapper that discovers the\n * platform-specific native binary via optionalDependencies\n * (`@openai/codex-${platform}-${arch}`) and exec's it with stdio inherited\n * — preserving the JSON-RPC stdio framing the daemon's `JsonRpcStdioClient`\n * relies on.\n *\n * `bin/codex.js` carries a `#!/usr/bin/env node` shebang and is shipped\n * with the executable bit set, so `spawn(resolvedPath, args)` works\n * directly on macOS + Linux. On Windows, `.js` is not directly executable\n * by `spawn()` without `shell: true`; the PATH fallback (`where codex`)\n * returns the npm-generated `codex.cmd` shim which is spawnable. Users on\n * Windows therefore retain the prior \"system codex on PATH\" experience\n * until we move to native-binary resolution.\n *\n * Returns null when resolution fails so the caller falls back to the PATH\n * lookup. Resolution failure is logged at debug, not warn — in a healthy\n * bundled install this should never happen, but a deliberate downstream\n * stripper (e.g. a minimal docker build that excludes optionalDependencies)\n * is a legitimate non-failure case.\n */\nfunction resolveBundledCodexBinary(): string | null {\n try {\n const req = createRequire(import.meta.url);\n /**\n * `@openai/codex/bin/codex.js` is the package's `bin.codex` entry —\n * verified against `node_modules/@openai/codex/package.json`. Pinning\n * the exact subpath (rather than letting Node's main-export resolution\n * pick a different file) keeps the resolver semantically stable across\n * `@openai/codex` minor versions.\n */\n const resolved = req.resolve('@openai/codex/bin/codex.js');\n return resolved;\n } catch (err) {\n logger.debug(\n { err, codexBundledVersion: CODEX_BUNDLED_VERSION },\n 'codex_bundled_binary_resolve_failed_falling_back_to_path'\n );\n return null;\n }\n}\n\nasync function resolveCodexBinary(): Promise<string | null> {\n /**\n * Bundled path wins. `@openai/codex` is pinned as a daemon dep so the\n * resolver succeeds in any healthy install — Codex is therefore \"always\n * installed\" from the UI's perspective and the install button is no\n * longer reachable. The PATH fallback below stays in place for two\n * cases: (a) Windows, where `.js` isn't spawnable without shell:true and\n * the PATH-side `codex.cmd` shim is the working path; (b) advanced\n * users who deliberately want a different system-wide codex version to\n * win over the bundled one (rare — they can uninstall the bundled dep,\n * but the PATH fallback is the simpler escape hatch).\n */\n const bundled = resolveBundledCodexBinary();\n if (bundled !== null) {\n lastKnownCodexBinary = bundled;\n return bundled;\n }\n\n const lookup = platform() === 'win32' ? 'where' : 'which';\n try {\n const { stdout } = await execFileAsync(lookup, ['codex']);\n const first = stdout.split(/\\r?\\n/).find((line) => line.trim().length > 0);\n const resolved = first ? first.trim() : null;\n lastKnownCodexBinary = resolved;\n return resolved;\n } catch (err) {\n if (isAuthoritativeNotFound(err)) {\n lastKnownCodexBinary = null;\n return null;\n }\n /**\n * Transient failure (timeout, signal-killed lookup, ENOENT on the\n * `which` binary itself). Preserve the prior result so the UI does\n * not flip to \"not installed\" on a single bad tick.\n */\n return lastKnownCodexBinary;\n }\n}\n\n/**\n * Warning classifier — extracted so c6's `translateWarningNotification`\n * and this profile's `errorMapper.classify` share one source. The\n * translator wraps the result back into a `SubprocessEvent`; the profile\n * surfaces it as a canonical `MappedError`.\n */\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null;\n}\n\nexport function classifyCodexWarning(native: unknown): MappedError {\n const message = (() => {\n if (typeof native === 'string') return native;\n if (isRecord(native) && typeof native.message === 'string') {\n return native.message;\n }\n return '';\n })();\n const lower = message.toLowerCase();\n if (/rate.?limit|usage.?limit/.test(lower)) {\n return { canonical: 'rate_limit_error', detail: message };\n }\n if (/auth|log[a-z]*\\s?in|signed.?out|unauthor/.test(lower)) {\n return { canonical: 'auth_not_logged_in' };\n }\n if (/billing|credit|payment/.test(lower)) {\n return { canonical: 'billing_error', detail: message };\n }\n return { canonical: 'sdk_error', detail: message || 'Codex error' };\n}\n\n/**\n * Parse the structured `RequestPermissionProfile` payload out of a Codex\n * `item/permissions/requestApproval` event.\n *\n * The Rust shape (`codex-rs/protocol/src/request_permissions.rs:18`):\n *\n * RequestPermissionProfile {\n * network: Option<{ enabled?: bool }>,\n * file_system: Option<{ read?: string[], write?: string[] }>,\n * }\n *\n * Returns `{ writePaths, readPaths, networkRequested }` when at least\n * one ask is present. Returns null when the payload carries no\n * actionable ask (caller falls through to a generic permission card).\n *\n * Legacy heuristic fallback: pre-spec Shipyard parser looked for a\n * top-level `deniedPath` field. Codex 0.130.0 never emits this shape,\n * but keep the fallback for one version bump in case any downstream\n * tooling still uses it; logs a deprecation when hit so we can confirm\n * before removal.\n */\n/** Filter an unknown array down to its string elements. Defensive. */\nfunction collectStringPaths(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n const out: string[] = [];\n for (const p of value) {\n if (typeof p === 'string') out.push(p);\n }\n return out;\n}\n\n/** Extract write + read path arrays from a `file_system` sub-object. */\nfunction extractFileSystemPaths(fileSystem: unknown): {\n writePaths: string[];\n readPaths: string[];\n} {\n if (!isRecord(fileSystem)) return { writePaths: [], readPaths: [] };\n return {\n writePaths: collectStringPaths(fileSystem.write),\n readPaths: collectStringPaths(fileSystem.read),\n };\n}\n\n/**\n * Pre-real-shape parser fallback: look for a single `deniedPath` at the\n * top level or inside `error.deniedPath`. Returns null when no legacy\n * field is present.\n */\nfunction extractLegacyDeniedPath(event: Record<string, unknown>): string | null {\n if (typeof event.deniedPath === 'string') return event.deniedPath;\n if (isRecord(event.error) && typeof event.error.deniedPath === 'string') {\n return event.error.deniedPath;\n }\n return null;\n}\n\nfunction parseSandboxRequestedPaths(event: unknown): SandboxRequestedPaths | null {\n if (!isRecord(event)) return null;\n\n const { writePaths, readPaths } = extractFileSystemPaths(event.file_system);\n const networkRequested = isRecord(event.network) && event.network.enabled === true;\n\n if (writePaths.length > 0 || readPaths.length > 0 || networkRequested) {\n return { writePaths, readPaths, networkRequested };\n }\n\n /**\n * Legacy fallback — pre-real-shape parser looked at non-canonical\n * fields. Drop this branch once we confirm no callers hit it.\n */\n const legacyDenied = extractLegacyDeniedPath(event);\n if (legacyDenied !== null) {\n codexLog({\n event: 'codex_sandbox_parser_legacy_denied_path',\n reason:\n 'parseSandboxRequestedPaths hit the legacy deniedPath fallback. ' +\n 'Codex 0.130.0+ should emit the structured RequestPermissionProfile ' +\n 'shape. Confirm this branch is unreachable before removing it.',\n });\n return { writePaths: [legacyDenied], readPaths: [], networkRequested: false };\n }\n\n return null;\n}\n\n/**\n * Type-guard: narrow an arbitrary `methodId` string from the profile\n * contract to the Zod-validated `CodexAuthMethod` union. The contract\n * uses `string` so different profiles can carry different method-id\n * vocabularies; here we validate against Codex's own union before\n * dispatching to the resolver.\n */\nfunction isCodexAuthMethod(methodId: string): methodId is CodexAuthMethod {\n for (const known of CODEX_AUTH_METHODS) {\n if (known === methodId) return true;\n }\n return false;\n}\n\n/**\n * Adapt the c8 `resolveCodexCredentials` shape ({ apiKey?, authToken?,\n * source }) into the profile contract's `ResolvedAuth` shape.\n *\n * The credential resolution itself (env vars, `~/.codex/auth.json` with\n * `CODEX_HOME` honoring, fallback ordering) lives in `codex-auth.ts` so\n * the same module powers both this profile binding AND the spawn-time\n * dispatch in serve-factory.\n */\nasync function resolveCodexAuthCredentials(methodId: string): Promise<ResolvedAuth | null> {\n if (!isCodexAuthMethod(methodId)) return null;\n const creds = await resolveCodexCredentials(methodId);\n if (!creds) return null;\n return {\n method: creds.source,\n details: {\n ...(creds.apiKey !== undefined ? { apiKey: creds.apiKey } : {}),\n ...(creds.authToken !== undefined ? { accessToken: creds.authToken } : {}),\n },\n };\n}\n\n/**\n * Build the `SpawnArgs` that invoke `codex login <methodId>` so the\n * caller can shell out to drive the user through OAuth. c7 returned a\n * descriptor; c8 still returns one — the actual subprocess driver\n * lives in `services/credentials/codex-login.ts` and consumes this\n * descriptor via the profile.\n */\nasync function triggerCodexLogin(methodId: string): Promise<SpawnArgs> {\n const binary = (await resolveCodexBinary()) ?? 'codex';\n return {\n binary,\n argv: ['login', methodId],\n };\n}\n\n/**\n * Helper: thread-item / notification matchers. Codex's `thread/compacted`\n * arrives as `{ event: 'thread/compacted', ... }` per the c4 protocol\n * port; the matcher accepts either the bare notification shape or the\n * envelope-wrapped form.\n */\nfunction matchesEventField(value: unknown, expected: string): boolean {\n if (typeof value !== 'object' || value === null) return false;\n if (!('event' in value)) return false;\n const record: Record<string, unknown> = value;\n return record.event === expected;\n}\n\nconst codexLog: ItemTranslatorLogger = () => {\n /** Profile-level translator log is a no-op; the daemon adapter passes its own logger to `translateCodexItem` at call time. */\n};\n\nexport const codexProfile: AgentCapabilityProfile<ContentBlock, AgentSubprocess> = {\n id: 'codex',\n displayName: 'Codex',\n iconRef: {\n kind: 'svg-component',\n component: 'CodexIcon',\n /** OpenAI Codex blue — middle stop of the `CodexIcon` gradient. */\n color: '#7A9DFF',\n },\n capabilityBadges: [],\n onboardingCopy: {\n emptyStateHeading: 'Spawn OpenAI Codex agents on your machine.',\n /**\n * Codex ships bundled with Shipyard (`@openai/codex` is a daemon dep).\n * The install hint is retained as a fallback for users who\n * deliberately want a different system-wide codex version to win over\n * the bundled one, but the UI never surfaces an \"Install Codex\"\n * affordance — login is the only agent-onboarding step.\n */\n installInstructions: 'Codex ships bundled with Shipyard. Sign in to start spawning agents.',\n authPromptHelp:\n 'Sign in with your ChatGPT account, paste an OpenAI API key, ' +\n 'or rely on AWS Bedrock credentials from the ambient environment.',\n capabilityCaveats: [],\n },\n capabilities: {\n canStreamTextDelta: true,\n canStreamReasoningDelta: true,\n canRewindByMessage: false,\n canPlanMode: true,\n canBackgroundExec: false,\n canMidSessionMcpReload: false,\n canCwdHookObserve: false,\n canPersistFullCompactionMetadata: false,\n canSubagent: true,\n canMcpOauth: true,\n windowOccupancyReporting: 'current',\n },\n\n /**\n * Rewind contract — Codex's native rollback primitive is count-based\n * (`client.rollback(threadId, { numTurns })`), invoked on the LIVE\n * subprocess. The respawn path is not used: `toSpawnOptions` always\n * returns null, and `applyLive` performs the rollback against the\n * running thread before returning `{ handled: true }` so the handler\n * skips the stop+respawn cycle.\n *\n * c8 will widen `AgentSubprocess` to expose a `rollback(numTurns)`\n * method; until then `applyLive` is a no-op placeholder that returns\n * `{ handled: false }`, falling through to the stop+respawn path so the\n * profile compiles without an `as any` cast.\n */\n rewind: {\n supports: new Set<RewindTarget['kind']>(['dropLastTurns']),\n toSpawnOptions(_target: RewindTarget) {\n return null;\n },\n async applyLive(subprocess, target) {\n if (target.kind !== 'dropLastTurns') return { handled: false };\n await subprocess.rollback(target.numTurns);\n return { handled: true };\n },\n },\n\n /**\n * Spawn contract — drives `CodexAgentSubprocess.spawn` from the\n * serve-factory Codex branch. `args` returns the argv that follows the\n * binary path; `envInject` injects the per-task `SHIPYARD_TASK_ID` so the\n * harness MCP wiring can build a correctly-scoped `http_headers` entry.\n * The bearer token itself does NOT travel through the profile contract\n * (it's plumbed by `serve-factory.ts` directly into `CodexSubprocessOptions`\n * — see `SECURITY POSTURE` in `harness-http-server.ts`).\n */\n spawn: {\n binaryResolver: () => resolveCodexBinary(),\n /**\n * `codex app-server` (0.130.0+) takes model + cwd at `thread/start` over\n * JSON-RPC, NOT as command-line flags. Passing `--model`, `--cwd`, or\n * `--ignore-user-config` here makes the binary exit with code 2\n * (\"unexpected argument\"). Keep the args minimal and let the\n * `thread/start` payload carry per-thread context.\n */\n args: (_ctx: SpawnContext) => ['app-server'],\n envInject: (ctx: SpawnContext) => ({\n /**\n * `CODEX_HOME` could override `~/.codex/` here. We deliberately do\n * NOT set it: Shipyard's `codex login` flow writes to the user's\n * default config dir, and overriding would hide the user's session.\n */\n\n /**\n * Required for the harness HTTP MCP wiring (`codex-subprocess.ts`\n * `buildHarnessMcpConfig`): the harness's per-task bearer-token\n * authorization rejects calls whose `x-shipyard-task-id` header does\n * not match the taskId the token was minted for. The codex subprocess\n * reads this env to populate the static `http_headers` entry passed\n * to Codex's `mcp_servers.shipyard.http_headers` at `thread/start`,\n * so every MCP request from Codex carries the right task scope.\n * Without this, the harness 401s every Shipyard tool call and the\n * agent's Shipyard tool surface collapses to empty.\n */\n SHIPYARD_TASK_ID: ctx.taskId,\n }),\n /**\n * Codex is a Rust binary — Node's `NODE_OPTIONS` panics it on start.\n * Stripping the var is load-bearing; do not remove without verifying\n * that upstream Codex no longer interprets the var.\n */\n envStrip: ['NODE_OPTIONS'],\n },\n\n /**\n * Codex's `app-server` speaks JSON-RPC 2.0 over line-delimited stdio.\n * The actual transport implementation lives in c4's\n * `JsonRpcStdioClient` (consumed via `CodexAppServerClient`); the\n * profile fields here are stubs that document the contract. When the\n * dispatch flip migrates the subprocess factory to read through these\n * closures, the stubs become the chokepoint.\n */\n transport: {\n framing: 'jsonrpc-line-delimited',\n outboundEncoder: (req: unknown) => `${JSON.stringify(req)}\\n`,\n inboundDecoder: (line: string) => JSON.parse(line),\n correlator: {\n register: (id) => {\n logger.info(\n { event: 'codex_nyi_correlator_register', id },\n 'codex_nyi_correlator_register'\n );\n },\n resolve: (id) => {\n logger.info({ event: 'codex_nyi_correlator_resolve', id }, 'codex_nyi_correlator_resolve');\n },\n reject: (id) => {\n logger.info({ event: 'codex_nyi_correlator_reject', id }, 'codex_nyi_correlator_reject');\n },\n },\n notificationDispatcher: (_msg, _sinks) => {\n logger.info(\n { event: 'codex_nyi_notification_dispatcher' },\n 'codex_nyi_notification_dispatcher'\n );\n },\n },\n\n /**\n * Reconnect: Codex does not replay history on resume — the daemon\n * fetches turns via `thread/turns/list` after reconnect. The profile\n * closure cannot reach the per-task `CodexAppServerClient`; the real\n * implementation lives on `CodexAgentSubprocess.fetchHistory()` and is\n * wired through the conversation layer. This stub exists so the profile\n * shape is satisfied; callers that go through the subprocess directly\n * should use `CodexAgentSubprocess.fetchHistory()` instead.\n */\n reconnect: {\n kind: 'server-history-fetch',\n fetchHistoryRpc: async (threadId) => {\n logger.warn(\n { event: 'codex_fetch_history_via_profile_closure', threadId },\n 'codex_fetch_history_via_profile_closure_should_go_through_subprocess'\n );\n return [];\n },\n },\n\n memoryContract: {\n /** Rust binary — `NODE_OPTIONS` is stripped (see `spawn.envStrip`). */\n honorsNodeOptions: false,\n /** SIGABRT (6) on macOS + linux; SIGKILL (9) on linux only — verified empirically. */\n oomSignalsByPlatform: {\n darwin: [6],\n linux: [6, 9],\n },\n },\n\n /** Codex v1 does not support pre-warming. */\n prewarmable: false,\n\n contentTranslator: {\n toNativeUserInput: (blocks: ContentBlock[]) => buildCodexUserInput(blocks, codexLog),\n /**\n * Codex's assistant content flows through `item/started` +\n * `item/completed` thread-item notifications, not a bulk assistant\n * content array. The canonical entrypoint is the event translator\n * below — this content-side fallback returns `[]` so any caller that\n * accidentally goes through here gets an empty (rather than wrong)\n * result.\n */\n fromNativeAssistantContent: () => [],\n },\n\n /**\n * Event translator — `translate` delegates to c6's `translateCodexItem`\n * via a shim that converts the native frame into the (item, ctx)\n * arguments the function expects. The shim normalizes both bare\n * `ThreadItem` frames and the envelope-wrapped `{ method, params }`\n * notification shape.\n *\n * `synthesizeInit` remains stubbed because the Codex subprocess\n * already synthesizes `init_received` in-flight from the\n * `thread/start` response — see `codex-subprocess.ts#emitInitFromThreadStart`.\n */\n eventTranslator: {\n translate: (native, ctx) => {\n const translatorCtx: TranslatorCtx = createTranslatorCtx({\n taskId: ctx.taskId,\n model: ctx.model,\n });\n /**\n * Accept either a bare `ThreadItem` (already unwrapped from\n * `item.completed.params.item`) or an envelope. We treat anything\n * with a `type` discriminator as a thread item; everything else is\n * dropped (logged at the caller).\n */\n if (!isRecord(native) || typeof native.type !== 'string') return [];\n /**\n * `translateCodexItem` accepts the full `ThreadItem` discriminated union\n * from c6 and handles unknown variants via its `isKnownItem` guard +\n * `generic_item` fallback. We've narrowed `native` to \"object with a\n * string `type` field\"; the translator itself owns the strict variant\n * dispatch, so passing through is the right boundary.\n */\n // eslint-disable-next-line no-restricted-syntax -- translator owns ThreadItem variant dispatch (isKnownItem + generic_item fallback); native is narrowed to {type:string} above\n const threadItem = native as Parameters<typeof translateCodexItem>[0];\n return translateCodexItem(threadItem, translatorCtx, codexLog);\n },\n synthesizeInit: async (_threadStartResponse, _deps) => {\n logger.info({ event: 'codex_nyi_synthesize_init' }, 'codex_nyi_synthesize_init');\n return { type: 'noop' };\n },\n },\n\n models: CODEX_MODEL_CATALOG,\n\n thinkingDescriptor: {\n shape: 'codex-summary',\n defaultDisplay: 'none',\n },\n\n /**\n * Codex permission flow (c9 / PROTOCOL_VERSION 81).\n *\n * Wire-type strings are authoritative: the daemon-side\n * `permission-handler.ts#createCodexPermissionRequest` emits\n * `permission_request_codex` and resolves on `permission_response_codex`.\n *\n * `notificationHandler` is a no-op log here because the actual\n * daemon↔browser roundtrip is wired NOT through this static profile\n * closure but through `CodexAgentSubprocess`'s `onPermissionRequest`\n * constructor option — which is the only place per-task daemon state\n * (the matching `PermissionHandler`) is reachable. The profile field\n * stays for contract uniformity with `claudeCodeProfile.callbackHandler`\n * and so the `PermissionFlow.kind === 'notification-roundtrip'`\n * discriminator remains true.\n *\n * The contract's `Promise<void>` return is also why the real wiring\n * sidesteps this callback: Codex's app-server needs a\n * `PermissionsRequestApprovalResponse` returned synchronously to its\n * pending RPC, which a `void` signature cannot deliver. Promoting the\n * signature would ripple through `claudeCodeProfile`; rather than\n * widen the canonical contract for one provider, we route directly\n * via `onPermissionRequest`.\n */\n permissionFlow: {\n kind: 'notification-roundtrip',\n notificationHandler: async (_req, ctx) => {\n /**\n * Log only — see comment block above. Reaching this path indicates\n * a caller that found `permissionFlow.notificationHandler` and\n * invoked it directly instead of going through\n * `onPermissionRequest`. Surface a diagnostic but do not throw —\n * the caller still gets a resolved promise so the calling site\n * (whatever it is) does not wedge.\n */\n codexLog({\n event: 'codex_permission_flow_legacy_callback_hit',\n taskId: ctx.taskId,\n reason:\n 'Real roundtrip lives on CodexAgentSubprocess.onPermissionRequest; ' +\n 'this profile-level callback is a no-op contract slot.',\n });\n },\n requestMessageType: 'permission_request_codex',\n responseMessageType: 'permission_response_codex',\n },\n permissionModeMap: codexPermissionModeMap,\n\n /**\n * Sandbox extension — Codex emits a sandbox-denied event when the\n * agent tries to read/write a path outside the workspace. We surface\n * a \"Grant + retry / Deny\" banner; on Grant the daemon restarts the\n * thread with the granted path appended to `sandbox.writable_roots`.\n *\n * c9 wires the parse + banner copy. c26 wires the actual thread\n * restart — it does NOT live in this profile-level `applyExtension`\n * closure. Instead, `control-channel-wiring.ts onPermissionResponseCodex`\n * detects the sandbox-extension grant (decision='approved' +\n * scope='session') and dispatches to the per-task outer facade's\n * `restartWithExtendedSandbox(deniedPath)` AFTER the JSON-RPC reply\n * is delivered to Codex. The per-task facade is reachable via\n * `daemon.requestCodexSandboxRestart(taskId, path)`, which serve-factory\n * registers when the inner Codex facade is constructed.\n *\n * This profile-level callback stays as a logged no-op contract slot —\n * same pattern as `permissionFlow.notificationHandler`. Reaching it\n * indicates a caller went through the profile rather than the real\n * wiring; we surface a diagnostic but do not throw so the calling\n * site does not wedge.\n */\n sandboxExtensionFlow: {\n parseRequestedPaths: parseSandboxRequestedPaths,\n applyExtension: async (grant, ctx) => {\n codexLog({\n event: 'codex_sandbox_extension_profile_callback_hit',\n taskId: ctx.taskId,\n writePaths: grant.writePaths,\n readPaths: grant.readPaths,\n networkRequested: grant.networkRequested,\n reason:\n 'Real thread restart lives at apps/daemon/src/services/channels/control-channel-wiring.ts ' +\n 'onPermissionResponseCodex -> daemon.requestCodexSandboxRestart(taskId, grant); ' +\n 'this profile-level callback is a no-op contract slot.',\n });\n /**\n * No throw — `applyExtension` returns `Promise<void>` per the\n * contract. The caller (if any) gets a resolved promise.\n */\n },\n bannerCopy: (grant) => {\n const parts: string[] = [];\n if (grant.writePaths.length > 0) {\n parts.push(`write to ${grant.writePaths.join(', ')}`);\n }\n if (grant.readPaths.length > 0) {\n parts.push(`read from ${grant.readPaths.join(', ')}`);\n }\n if (grant.networkRequested) {\n parts.push('network access');\n }\n const ask = parts.length > 0 ? parts.join(' + ') : 'additional permissions';\n return `Codex needs ${ask}. Grant access to continue?`;\n },\n },\n\n authMethods: [\n {\n id: 'chatgpt',\n displayName: 'ChatGPT',\n loginUx: 'oauth-browser',\n storageHint: '~/.codex/auth.json',\n requiresShell: true,\n },\n {\n id: 'api-key',\n displayName: 'OpenAI API Key',\n loginUx: 'api-key-paste',\n storageHint: '~/.codex/auth.json',\n requiresShell: false,\n },\n {\n id: 'bedrock',\n displayName: 'AWS Bedrock',\n loginUx: 'env-only',\n storageHint: 'AWS_ACCESS_KEY_ID env var',\n requiresShell: false,\n },\n ],\n\n triggerLogin: triggerCodexLogin,\n resolveAuthCredentials: resolveCodexAuthCredentials,\n\n /**\n * Refresh-time auth probe — bound to `detectCodexAuth`. Mirrors the\n * Claude profile binding so the unified `onRefreshAgentProviders`\n * chokepoint can refresh both providers in lockstep without the\n * bespoke \"preserve stale codexAuth\" patch that lived in\n * control-channel-infra-handlers pre-unification.\n */\n authDetector: (methodHint?: string): Promise<AgentAuthDetectionResult> => {\n const parsed = methodHint ? CodexAuthMethodSchema.safeParse(methodHint) : null;\n const validHint: CodexAuthMethod | undefined =\n parsed?.success === true ? parsed.data : undefined;\n return detectCodexAuth(validHint).then((result): AgentAuthDetectionResult => {\n switch (result.kind) {\n case 'detected':\n return { kind: 'detected', auth: result.auth };\n case 'not-detected':\n return { kind: 'not-detected', auth: result.auth };\n case 'preserved':\n return { kind: 'preserved', reason: result.reason };\n default: {\n const _exhaustive: never = result;\n return _exhaustive;\n }\n }\n });\n },\n\n /** Codex does not report dollar cost — daemon estimates from tokens × pricing. */\n costReporting: 'estimated',\n costEstimator: {\n /**\n * Surface c6's `estimateCodexCost` through the canonical interface.\n * The estimator's `EstimatedCodexCost` shape is a superset of\n * `EstimatedCost` (it includes an `'unavailable'` variant); we\n * coerce here so the canonical type stays clean — callers see\n * `amountUsd: 0` and `pricingEffectiveAsOf: '1970-01-01'` when the\n * model is unknown.\n */\n estimate: (tokenUsage, modelId) => {\n const result = estimateCodexCost(\n {\n inputTokens: tokenUsage.inputTokens,\n cachedInputTokens: tokenUsage.cachedInputTokens,\n outputTokens: tokenUsage.outputTokens,\n ...(tokenUsage.reasoningOutputTokens !== undefined\n ? { reasoningOutputTokens: tokenUsage.reasoningOutputTokens }\n : {}),\n },\n modelId,\n () => {}\n );\n return {\n amountUsd: result.amountUsd,\n source: 'estimated',\n modelId: result.modelId,\n pricingEffectiveAsOf: result.pricingEffectiveAsOf,\n };\n },\n },\n tokenUsageFieldMap: {\n /**\n * Native field names on Codex's `thread/tokenUsage/updated`\n * notification. `reasoning_tokens` is informational only — already\n * folded into `output_tokens` for billing (see\n * `codex-cost-estimator.ts` for the invariant + test).\n */\n inputTokens: 'input_tokens',\n cachedInputTokens: 'cached_tokens',\n outputTokens: 'output_tokens',\n reasoningOutputTokens: 'reasoning_tokens',\n },\n rateLimitShape: 'openai',\n errorMapper: {\n classify: classifyCodexWarning,\n },\n\n subagentBackend: {\n /** Codex's `spawn_agent` MCP tool launches a sub-thread. */\n spawnTool: 'spawn_agent',\n /**\n * Progress lands as collab-tool-call updates on the parent thread —\n * the daemon translates Codex's `tool_call_update` notifications into\n * Shipyard's `background_agent_update` control messages.\n */\n progressSource: 'collab-tool-call-update',\n /** `wait` RPC returns the result; the daemon synthesizes <task-notification> XML. */\n resultDelivery: { kind: 'rpc-return-with-synth-xml' },\n transcriptVisibility: 'separate-thread-id',\n terminate: async (subagentId, _ctx) => {\n /**\n * Codex's protocol does not surface a subagent-kill RPC at this\n * revision. The closest behavior — cancelling the parent turn —\n * also cancels every other in-flight tool call, which is the\n * wrong blast radius. Log and no-op until Codex exposes a\n * targeted RPC; the subagent will run to completion and report\n * its result via the normal `wait` path.\n */\n codexLog({\n event: 'codex_subagent_terminate_noop',\n subagentId,\n reason: 'Codex app-server has no targeted subagent-kill RPC at this protocol revision.',\n });\n },\n parentChildIdShape: 'receiver_thread_ids',\n },\n\n /**\n * Plan content — captured by Codex's upstream stream parser from the\n * model's `<proposed_plan>` block and surfaced as a `plan` ThreadItem.\n * The codex-item-translator stashes the text on `TranslatorCtx.lastProposedPlan`,\n * the codex-subprocess reads it at turn-complete-in-plan-mode and emits a\n * `plan_content_ready` SubprocessEvent. Written to the same shared\n * destination as Claude's `ExitPlanMode` capture.\n */\n planContentSource: {\n kind: 'last-agent-message-in-plan-mode',\n triggerCriterion: 'on-turn-complete-in-plan-mode',\n extract: (signal: unknown) => {\n if (typeof signal !== 'object' || signal === null || !('lastProposedPlan' in signal)) {\n return null;\n }\n const record: Record<string, unknown> = signal;\n const value = record.lastProposedPlan;\n if (typeof value !== 'string' || value.length === 0) return null;\n return value;\n },\n writePathTemplate: '~/.shipyard/plans/{taskId}.md',\n },\n\n /**\n * Codex emits an `update_plan` thread item that mirrors the agent's\n * todo list. The translator hook is intentionally stubbed: the harness\n * currently pipes items through directly (the dispatch flip moving\n * translation into the profile is a planned follow-up).\n *\n * Throws to match Claude's symmetric stub at\n * `claude-code-profile.ts:547`. Returning an empty overlay would let\n * Codex silently swallow plan items while Claude throws — the\n * inconsistency masks regressions on whichever consumer wires the\n * path first.\n */\n todoSource: {\n kind: 'thread-item-event',\n toolOrItemName: 'update_plan',\n translateToTaskOverlay: (): TaskOverlay => {\n throw new Error(\n 'codexProfile.todoSource.translateToTaskOverlay: profile field not yet wired through dispatch — ' +\n 'call site still reads directly from the legacy chokepoint.'\n );\n },\n },\n\n /** Codex's daemon-owned cwd model means no observer hook. */\n cwdObserver: null,\n\n /**\n * Codex emits only `thread/compacted` — no start event. The matcher\n * accepts the bare notification or the envelope-wrapped form (see\n * `matchesEventField`). `extractPreTokens` returns null because Codex\n * doesn't report the pre-compaction token count.\n */\n compactionSource: {\n startedEvent: null,\n completedEvent: {\n eventName: 'thread/compacted',\n matcher: (e) => matchesEventField(e, 'thread/compacted'),\n extractPreTokens: () => null,\n },\n },\n\n /** Codex has no per-thread tool denylist mechanism. */\n toolDenylistApplicator: null,\n\n mcpServerRegistration: {\n /** Codex registers MCP servers at `thread/start` config; mid-thread reload is not supported. */\n kind: 'thread-start-config',\n register: (_servers, _ctx) => {\n logger.info(\n { event: 'codex_nyi_mcp_server_registration' },\n 'codex_nyi_mcp_server_registration'\n );\n },\n },\n\n mcpAuthIdioms: {\n authenticateMethod: 'mcp/oauthLogin',\n submitCallbackMethod: 'mcp/oauthLoginCompleted',\n },\n\n /** Codex has no skills filter — capability surface is fixed at compile time. */\n skillsMechanism: null,\n\n /**\n * System prompt fragments — Codex-specific wording is populated in c10\n * once we have empirical data on what Codex needs. For c7 the\n * fragments are placeholders matching the c3 Claude shape; the\n * harness prompt assembler still owns the full string.\n */\n systemPromptFragments: {\n backgroundExecution:\n 'Codex does not support background execution. Long-running shell ' +\n 'commands block the current turn — keep them short or break work ' +\n 'into smaller steps so the user sees progress.',\n planMode:\n 'In plan mode Codex runs read-only — file edits and shell writes ' +\n 'are blocked. Use this turn to research the codebase and propose a ' +\n 'plan in your final message; Shipyard captures that message as the ' +\n 'plan and surfaces it for review. Do not call apply_patch or ' +\n 'destructive shell commands until the user approves and exits plan mode.',\n todoGuidance:\n 'Use the update_plan tool to keep the user-visible task list in ' +\n 'sync with your work. When starting, include any items already ' +\n 'visible in <task-list> using their exact subjects — then add your ' +\n \"own steps below them. Don't paraphrase template items or you'll \" +\n 'create duplicate sidebar entries. Update statuses (pending → ' +\n 'in_progress → completed) as you progress; call update_plan whenever ' +\n 'you start, finish, or reorder a step.',\n toolReferences: {\n subagentSpawn: 'spawn_agent',\n shellExec: 'shell',\n fileEdit: 'apply_patch',\n todoTool: 'update_plan',\n /** Codex captures plans from the last agent message in plan mode — no tool. */\n planSubmit: undefined,\n },\n },\n\n cliResumeTemplate: 'cd \"{cwd}\" && codex resume {sessionId}',\n skillInvocationSigil: '$',\n\n metadata: {\n displayName: 'Codex CLI',\n vendor: 'OpenAI',\n cliCommand: 'codex',\n messageSigil: '$',\n postHogProviderId: 'codex',\n /** `@openai/codex` ships bundled with the daemon — no separate install step. */\n installCommand: null,\n },\n\n /**\n * No Shipyard-controlled billing identity for Codex — OpenAI bills the\n * user's account directly via their API key / ChatGPT session.\n */\n billingIdentityHeaders: () => ({}),\n\n /**\n * Approximate Shipyard system-prompt overhead for Codex, in tokens.\n * Used by the cross-agent bridge to subtract overhead from the context\n * window before computing the history budget. Measured against Codex's\n * system-prompt assembly path (~2500 chars / 4 ≈ 625 tokens as of 2026-05-25).\n */\n systemPromptOverheadTokens: 625,\n};\n","/**\n * Codex auth status detector (PROTOCOL_VERSION 83).\n *\n * Mirrors `auth.ts`'s `detectAnthropicAuth` shape — returns a tagged\n * discriminated result so the caller can distinguish \"detected\" /\n * \"not-detected\" / \"preserved\" (transient IO failure, keep last-known).\n *\n * Method resolution order:\n * - User-selected method (from `preferredAuthMethod['codex']`) is the\n * hint. If absent, we infer from what's present on disk / env.\n * - `chatgpt`: read `~/.codex/auth.json` (honoring `CODEX_HOME`),\n * verify `tokens.access_token`, parse `tokens.id_token` JWT claims\n * to surface the user's email + account.\n * - `api-key`: same file's `OPENAI_API_KEY` field, or the\n * `OPENAI_API_KEY` / `CODEX_API_KEY` env vars. Surfaces an\n * `apiKeyHint` like `sk-***xxxxx` so the settings card can render\n * a meaningful \"logged in\" line without exposing the full key.\n * - `bedrock`: ambient AWS credential chain. Returns `authenticated`\n * when the daemon has enough vars to plausibly succeed; the real\n * verification happens when Codex actually talks to Bedrock.\n *\n * No subprocess shell-out — purely file + env. The Anthropic detector\n * shells out to `claude auth status --json`; the Codex detector skips\n * that because Codex's CLI status path is slower and the file/env path\n * is authoritative for what the daemon will see at spawn time anyway.\n */\nexport { type CodexAuthDetectionResult, detectCodexAuth };\n\nimport { promises as fs } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nimport type { CodexAuthMethod, CodexAuthStatus } from '@shipyard/loro-schema';\n\nimport { logger } from '../logger.js';\n\n/**\n * Tagged result mirroring `AuthDetectionResult` in `auth.ts`.\n *\n * - `detected`: confirmed authenticated state, surface the status.\n * - `not-detected`: nothing found on disk or env for the resolved method.\n * - `preserved`: IO hiccup that doesn't tell us auth state; caller\n * should keep the last-known status to avoid flicker.\n */\ntype CodexAuthDetectionResult =\n | { kind: 'detected'; auth: CodexAuthStatus }\n | { kind: 'not-detected'; auth: { status: 'unauthenticated'; method: 'none' } }\n | { kind: 'preserved'; reason: 'parse-error' | 'fs-error' };\n\ninterface CodexAuthFile {\n /** Codex writes `null` here when in chatgpt-auth-mode; string when api-key mode. */\n OPENAI_API_KEY?: string | null;\n tokens?: {\n access_token?: string;\n refresh_token?: string;\n id_token?: string;\n } | null;\n last_refresh?: string;\n}\n\nfunction codexAuthFilePath(): string {\n const home = process.env.CODEX_HOME?.trim();\n if (home && home.length > 0) return join(home, 'auth.json');\n return join(homedir(), '.codex', 'auth.json');\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isCodexAuthFile(value: unknown): value is CodexAuthFile {\n if (!isPlainObject(value)) return false;\n /**\n * Codex writes `OPENAI_API_KEY: null` in chatgpt-auth-mode files. Treat\n * explicit null as \"absent\" so we don't reject a valid auth.json — the\n * downstream detectChatgpt path checks `tokens.access_token` first and\n * only consults OPENAI_API_KEY as a fallback for the same-file API-key\n * compatibility path.\n */\n if (\n value.OPENAI_API_KEY !== undefined &&\n value.OPENAI_API_KEY !== null &&\n typeof value.OPENAI_API_KEY !== 'string'\n )\n return false;\n const tokens = value.tokens;\n if (tokens !== undefined && tokens !== null) {\n if (!isPlainObject(tokens)) return false;\n if (tokens.access_token !== undefined && typeof tokens.access_token !== 'string') return false;\n if (tokens.id_token !== undefined && typeof tokens.id_token !== 'string') return false;\n }\n return true;\n}\n\n/**\n * Parse the middle (payload) segment of a JWT id_token without\n * verifying the signature. We never use this token for authentication\n * — only for the email/account display in the settings card.\n *\n * Returns null on any parse failure. The OAuth flow runs entirely\n * inside Codex; if the token is malformed the user is already broken in\n * a way Shipyard cannot fix.\n */\nfunction parseIdTokenClaims(idToken: string): Record<string, unknown> | null {\n try {\n const parts = idToken.split('.');\n if (parts.length < 2) return null;\n const payload = parts[1];\n if (!payload) return null;\n /** Base64url → base64. */\n const padded = payload.replace(/-/g, '+').replace(/_/g, '/');\n /** Add `=` padding so atob/Buffer don't reject the truncated form. */\n const pad = padded.length % 4 === 0 ? '' : '='.repeat(4 - (padded.length % 4));\n const json = Buffer.from(padded + pad, 'base64').toString('utf8');\n const parsed = JSON.parse(json);\n if (!isPlainObject(parsed)) return null;\n return parsed;\n } catch {\n return null;\n }\n}\n\n/**\n * Classify a JWT bearer token's freshness from its `exp` claim. Pure\n * function — no IO, no clock-skew tolerance beyond the explicit buffer.\n *\n * Returns:\n * - `'fresh'` — token has a valid `exp` that is strictly in the future\n * by more than `nowOffsetSeconds` (the buffer treats tokens that\n * expire within the next minute as already-stale so a spawn that\n * races the buffer doesn't 401 mid-turn).\n * - `'expired'` — `exp` is present and at-or-before `now + buffer`.\n * - `'unparseable'` — token isn't a JWT, lacks an `exp` numeric claim,\n * or the payload otherwise can't be parsed. Treated as a soft\n * signal: callers fall back to \"trust the file's presence\" because\n * OpenAI may issue tokens without `exp` (it currently does include\n * it, but the protocol is owned by Codex upstream — we don't want\n * to break the path if they change the claim set).\n *\n * The exp check is a pure best-effort: a non-expired classification\n * does NOT prove the token will be accepted by the server (it could be\n * revoked, scope-changed, etc.). An expired classification IS\n * authoritative — the bearer is past its TTL and the server will 401.\n */\nexport type JwtFreshness = 'fresh' | 'expired' | 'unparseable';\n\nexport function classifyJwtFreshness(\n token: string,\n nowSeconds: number,\n nowOffsetSeconds = 60\n): JwtFreshness {\n const claims = parseIdTokenClaims(token);\n if (!claims) return 'unparseable';\n const exp = claims.exp;\n if (typeof exp !== 'number' || !Number.isFinite(exp)) return 'unparseable';\n if (exp <= nowSeconds + nowOffsetSeconds) return 'expired';\n return 'fresh';\n}\n\n/**\n * Extract the user's email + account id from the `tokens.id_token`\n * JWT. The actual field in the JWT payload is `account_id` (the value\n * that lives at `tokens.account_id` in `~/.codex/auth.json`). Some\n * older token issuances used `chatgpt_account_id`; we check both for\n * backwards-compat. Email candidates: `chatgpt_account_email` (org\n * variants) then `email`. Null fields are dropped at the call site.\n */\nfunction extractIdentity(claims: Record<string, unknown>): { email?: string; accountId?: string } {\n const result: { email?: string; accountId?: string } = {};\n const emailCandidates = [claims.chatgpt_account_email, claims.email];\n for (const c of emailCandidates) {\n if (typeof c === 'string' && c.length > 0) {\n result.email = c;\n break;\n }\n }\n const accountCandidates = [claims.account_id, claims.chatgpt_account_id];\n for (const c of accountCandidates) {\n if (typeof c === 'string' && c.length > 0) {\n result.accountId = c;\n break;\n }\n }\n return result;\n}\n\n/**\n * Build a `sk-***xxxxx` style hint for the api-key path. Same shape as\n * `safe_format_key` in `codex-rs/cli/src/login.rs:443`.\n */\nfunction formatApiKeyHint(key: string): string {\n if (key.length <= 13) return '***';\n return `${key.slice(0, 8)}***${key.slice(-5)}`;\n}\n\nasync function readCodexAuthFile(): Promise<\n | { kind: 'ok'; file: CodexAuthFile }\n | { kind: 'missing' }\n | { kind: 'parse-error' }\n | { kind: 'fs-error' }\n> {\n const path = codexAuthFilePath();\n try {\n const raw = await fs.readFile(path, 'utf8');\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return { kind: 'parse-error' };\n }\n if (!isCodexAuthFile(parsed)) return { kind: 'parse-error' };\n return { kind: 'ok', file: parsed };\n } catch (err) {\n if (err && typeof err === 'object' && 'code' in err && err.code === 'ENOENT') {\n return { kind: 'missing' };\n }\n return { kind: 'fs-error' };\n }\n}\n\nfunction detectChatgpt(file: CodexAuthFile, nowSeconds: number): CodexAuthDetectionResult {\n const accessToken = file.tokens?.access_token?.trim();\n if (!accessToken || accessToken.length === 0) {\n return { kind: 'not-detected', auth: { status: 'unauthenticated', method: 'none' } };\n }\n\n /**\n * Passive detection should not duplicate Codex's refresh protocol. If the\n * bearer is expired but a refresh_token exists, keep reporting authenticated\n * and let Codex's AuthManager perform its reload/refresh recovery on use.\n * Without a refresh_token, an expired bearer is authoritative unauth.\n *\n * `unparseable` is treated as a soft signal — fall through to the\n * trust-the-file-presence path so a future change in OpenAI's claim\n * set doesn't silently break detection.\n */\n const freshness = classifyJwtFreshness(accessToken, nowSeconds);\n if (freshness === 'expired' && !file.tokens?.refresh_token?.trim()) {\n return { kind: 'not-detected', auth: { status: 'unauthenticated', method: 'none' } };\n }\n\n const auth: CodexAuthStatus = {\n status: 'authenticated',\n method: 'chatgpt',\n };\n const idToken = file.tokens?.id_token;\n if (idToken && idToken.length > 0) {\n const claims = parseIdTokenClaims(idToken);\n if (claims) {\n const identity = extractIdentity(claims);\n if (identity.email) auth.email = identity.email;\n if (identity.accountId) auth.accountId = identity.accountId;\n }\n }\n return { kind: 'detected', auth };\n}\n\nfunction detectApiKey(): CodexAuthDetectionResult {\n const envKey = process.env.OPENAI_API_KEY?.trim() ?? '';\n const altKey = process.env.CODEX_API_KEY?.trim() ?? '';\n const key = envKey.length > 0 ? envKey : altKey;\n if (key.length > 0) {\n return {\n kind: 'detected',\n auth: {\n status: 'authenticated',\n method: 'api-key',\n apiKeyHint: formatApiKeyHint(key),\n },\n };\n }\n return { kind: 'not-detected', auth: { status: 'unauthenticated', method: 'none' } };\n}\n\nfunction detectBedrock(): CodexAuthDetectionResult {\n const hasProfile = (process.env.AWS_PROFILE ?? '').trim().length > 0;\n const hasKey = (process.env.AWS_ACCESS_KEY_ID ?? '').trim().length > 0;\n const hasSecret = (process.env.AWS_SECRET_ACCESS_KEY ?? '').trim().length > 0;\n const hasRegion =\n (process.env.AWS_REGION ?? '').trim().length > 0 ||\n (process.env.AWS_DEFAULT_REGION ?? '').trim().length > 0;\n const credentialsOk = hasProfile || (hasKey && hasSecret);\n if (credentialsOk && hasRegion) {\n return { kind: 'detected', auth: { status: 'authenticated', method: 'bedrock' } };\n }\n return { kind: 'not-detected', auth: { status: 'unauthenticated', method: 'none' } };\n}\n\n/**\n * Detect Codex auth status.\n *\n * `methodHint` is the user's selected method from\n * `preferredAuthMethod['codex']`. When absent (first-run, user hasn't\n * picked yet), we resolve in priority order:\n * 1. `~/.codex/auth.json` with `tokens.access_token` → `chatgpt`\n * 2. `OPENAI_API_KEY` / `CODEX_API_KEY` env → `api-key`\n * 3. `~/.codex/auth.json` with `OPENAI_API_KEY` field → `chatgpt`\n * with apiKeyHint (fallback for the same-file API key path)\n * 4. AWS_* env → `bedrock` only if both credentials and region present\n *\n * Bedrock is NOT auto-detected without an explicit method hint — the\n * AWS env is too common (anyone with AWS work set up) to assume it\n * means \"I want Codex to use Bedrock\".\n */\nconst NOT_AUTHENTICATED: CodexAuthDetectionResult = {\n kind: 'not-detected',\n auth: { status: 'unauthenticated', method: 'none' },\n};\n\nfunction preservedOrNotDetected(\n file: Awaited<ReturnType<typeof readCodexAuthFile>>\n): CodexAuthDetectionResult | null {\n if (file.kind === 'fs-error') return { kind: 'preserved', reason: 'fs-error' };\n if (file.kind === 'parse-error') return { kind: 'preserved', reason: 'parse-error' };\n return null;\n}\n\nfunction detectApiKeyFromFile(file: {\n OPENAI_API_KEY?: string | null;\n}): CodexAuthDetectionResult | null {\n const fileKey = file.OPENAI_API_KEY?.trim();\n if (!fileKey) return null;\n return {\n kind: 'detected',\n auth: {\n status: 'authenticated',\n method: 'api-key',\n apiKeyHint: formatApiKeyHint(fileKey),\n },\n };\n}\n\nasync function detectCodexAuthWithHint(\n methodHint: CodexAuthMethod,\n nowSeconds: number\n): Promise<CodexAuthDetectionResult> {\n if (methodHint === 'bedrock') return detectBedrock();\n if (methodHint === 'api-key') {\n const envResult = detectApiKey();\n if (envResult.kind === 'detected') return envResult;\n const file = await readCodexAuthFile();\n if (file.kind === 'ok') {\n const fileKey = detectApiKeyFromFile(file.file);\n if (fileKey) return fileKey;\n }\n const preserved = preservedOrNotDetected(file);\n if (preserved) {\n logger.warn(\n { path: codexAuthFilePath(), method: methodHint },\n 'codex auth file issue in hint path — preserving status'\n );\n return preserved;\n }\n return NOT_AUTHENTICATED;\n }\n /** chatgpt path */\n const file = await readCodexAuthFile();\n if (file.kind === 'ok') return detectChatgpt(file.file, nowSeconds);\n const preserved = preservedOrNotDetected(file);\n if (preserved) {\n logger.warn(\n { path: codexAuthFilePath(), method: methodHint },\n 'codex auth file issue in hint path — preserving status'\n );\n return preserved;\n }\n return NOT_AUTHENTICATED;\n}\n\nasync function detectCodexAuth(\n methodHint?: CodexAuthMethod | undefined\n): Promise<CodexAuthDetectionResult> {\n const nowSeconds = Math.floor(Date.now() / 1000);\n if (methodHint && methodHint !== 'none') return detectCodexAuthWithHint(methodHint, nowSeconds);\n\n /**\n * Auto-detect priority: file access_token > env api-key > file api-key.\n * File IO errors (non-ENOENT) do NOT block env-var detection — a user\n * with OPENAI_API_KEY set but a permission-denied auth file is still\n * detected as api-key authenticated.\n */\n const file = await readCodexAuthFile();\n if (file.kind === 'ok') {\n const chatgptResult = detectChatgpt(file.file, nowSeconds);\n if (chatgptResult.kind === 'detected') return chatgptResult;\n }\n const apiKeyResult = detectApiKey();\n if (apiKeyResult.kind === 'detected') return apiKeyResult;\n /** File OPENAI_API_KEY checked last so env wins over file. */\n if (file.kind === 'ok') {\n const fileKeyResult = detectApiKeyFromFile(file.file);\n if (fileKeyResult) return fileKeyResult;\n }\n /** Now handle file errors — after env check so env-api-key is never blocked by IO issues. */\n if (file.kind === 'fs-error') {\n logger.warn(\n { path: codexAuthFilePath() },\n 'Failed to read Codex auth file — preserving status'\n );\n return { kind: 'preserved', reason: 'fs-error' };\n }\n if (file.kind === 'parse-error') {\n logger.warn({ path: codexAuthFilePath() }, 'Codex auth file is malformed — preserving status');\n return { kind: 'preserved', reason: 'parse-error' };\n }\n return NOT_AUTHENTICATED;\n}\n","/**\n * Codex cost estimator.\n *\n * The Codex app-server protocol does NOT report a dollar amount on\n * `turn/completed`. Cost is estimated from token counts × per-model\n * pricing seeded below.\n *\n * Critical invariant — `reasoning_output_tokens` is ALREADY INCLUDED in\n * `output_tokens` per OpenAI billing. The estimator MUST NOT charge for\n * reasoning separately. A regression on this would silently 2-3x the cost\n * displayed on every reasoning turn. The unit test in\n * `codex-cost-estimator.test.ts` pins this.\n *\n * Pricing source: developers.openai.com/codex/pricing (verified 2026-05-17,\n * cross-checked against OpenRouter, DevTk.AI, Apidog). OpenAI has no pricing\n * API — these values must be kept in sync manually.\n *\n * Context-window tiers (gpt-5.5, gpt-5.4 only):\n * ≤272k input tokens → standard rate\n * >272k input tokens → high-context rate (higher per-token price)\n * The cutoff is 272,000 tokens (the full context window for both models).\n * `modelContextWindow` from `thread/tokenUsage/updated` is the authoritative\n * signal; total input token count is the fallback.\n *\n * Priority mode (gpt-5.5 only): when the model slug contains \"priority\" or\n * when `serviceTier === 'priority'` is provided, the premium rate applies.\n * Defaults to standard tier when neither signal is present.\n */\n\nexport interface CodexModelPricing {\n /** $ per million input tokens (uncached). */\n inputUsdPerMtok: number;\n /** $ per million cached-input tokens (prompt-cache hit). */\n cachedInputUsdPerMtok: number;\n /**\n * $ per million output tokens. INCLUDES reasoning_output_tokens — the\n * OpenAI billing line item is a single number that covers visible text\n * AND reasoning. Do NOT add a separate reasoning rate.\n */\n outputUsdPerMtok: number;\n /** ISO date the rates were last verified against the live pricing page. */\n effectiveAsOf: string;\n source: 'official' | 'openai-pricing-page' | 'placeholder';\n}\n\nexport interface EstimatedCodexCost {\n amountUsd: number;\n source: 'estimated' | 'unavailable';\n modelId: string;\n pricingEffectiveAsOf: string;\n}\n\nexport interface CodexTokenUsage {\n inputTokens: number;\n cachedInputTokens: number;\n outputTokens: number;\n /**\n * Codex-reported reasoning tokens. Already folded into `outputTokens`\n * for billing — this field is informational only. The estimator\n * accepts it and intentionally ignores it for the cost calc; we also\n * defensively log if `reasoningOutputTokens > outputTokens` since that\n * would indicate the upstream protocol changed and the assumption no\n * longer holds.\n */\n reasoningOutputTokens?: number;\n /**\n * Model's total context window size in tokens, as reported by the Codex\n * server on `thread/tokenUsage/updated`. Used to select the correct\n * pricing tier for gpt-5.5 and gpt-5.4 (≤272k vs >272k context).\n * When absent, the estimator falls back to total input token count.\n */\n modelContextWindow?: number | null;\n /**\n * OpenAI service tier. When `'priority'`, the gpt-5.5 premium rate\n * applies. Defaults to standard when absent.\n */\n serviceTier?: string;\n}\n\nexport type CostEstimatorLogger = (entry: { event: string; [key: string]: unknown }) => void;\n\n/** Threshold (tokens) that triggers the high-context rate for gpt-5.5 / gpt-5.4. */\nconst HIGH_CONTEXT_THRESHOLD = 272_000;\n\nconst EFFECTIVE_AS_OF = '2026-05-17';\n\n/**\n * Per-model pricing table.\n *\n * gpt-5.5 and gpt-5.4 have context-window-dependent tiers resolved at\n * runtime in `resolvePricing()`. The seed entry for those models stores\n * the standard (≤272k) rate — used for display hints in the model catalog.\n * The high-context and priority rates are in `CODEX_TIERED_PRICING`.\n *\n * gpt-5.3-codex-spark is a research preview billed at $0; it is included so\n * the estimator returns `source: 'estimated'` (not 'unavailable') for it.\n */\nexport const CODEX_PRICING_SEED: Record<string, CodexModelPricing> = {\n /** Standard (≤272k context) rate. High-context rate: see CODEX_TIERED_PRICING. */\n 'gpt-5.5': {\n inputUsdPerMtok: 5.0,\n cachedInputUsdPerMtok: 0.5,\n outputUsdPerMtok: 30.0,\n effectiveAsOf: EFFECTIVE_AS_OF,\n source: 'openai-pricing-page',\n },\n /** Standard (≤272k context) rate. High-context rate: see CODEX_TIERED_PRICING. */\n 'gpt-5.4': {\n inputUsdPerMtok: 2.5,\n cachedInputUsdPerMtok: 0.25,\n outputUsdPerMtok: 15.0,\n effectiveAsOf: EFFECTIVE_AS_OF,\n source: 'openai-pricing-page',\n },\n 'gpt-5.4-mini': {\n inputUsdPerMtok: 0.75,\n cachedInputUsdPerMtok: 0.075,\n outputUsdPerMtok: 4.5,\n effectiveAsOf: EFFECTIVE_AS_OF,\n source: 'openai-pricing-page',\n },\n 'gpt-5.3-codex': {\n inputUsdPerMtok: 1.75,\n cachedInputUsdPerMtok: 0.175,\n outputUsdPerMtok: 14.0,\n effectiveAsOf: EFFECTIVE_AS_OF,\n source: 'openai-pricing-page',\n },\n /** Research preview — billed at $0. */\n 'gpt-5.3-codex-spark': {\n inputUsdPerMtok: 0,\n cachedInputUsdPerMtok: 0,\n outputUsdPerMtok: 0,\n effectiveAsOf: EFFECTIVE_AS_OF,\n source: 'openai-pricing-page',\n },\n /**\n * gpt-5.2: same credit row as gpt-5.3-codex on the Codex pricing page.\n * Dollar rates derived from credits × $0.04 conversion factor.\n */\n 'gpt-5.2': {\n inputUsdPerMtok: 1.75,\n cachedInputUsdPerMtok: 0.175,\n outputUsdPerMtok: 14.0,\n effectiveAsOf: EFFECTIVE_AS_OF,\n source: 'openai-pricing-page',\n },\n /**\n * codex-auto-review: no public pricing available — intentionally omitted\n * so `estimateCodexCost` returns `{ source: 'unavailable' }` for this model.\n * Do NOT add a zero-rate entry here; that would return `source: 'estimated'`\n * with a misleading $0 figure instead of the correct unavailable signal.\n */\n};\n\n/**\n * Tiered rate overrides for models whose pricing depends on context window\n * size or service tier. Consulted by `resolvePricing()` before falling back\n * to `CODEX_PRICING_SEED`.\n */\ninterface TieredRates {\n /** Applied when total input context exceeds HIGH_CONTEXT_THRESHOLD. */\n highContext: CodexModelPricing;\n /** Applied when priority mode is detected (gpt-5.5 only). */\n priority?: CodexModelPricing;\n}\n\nconst CODEX_TIERED_PRICING: Record<string, TieredRates> = {\n 'gpt-5.5': {\n highContext: {\n inputUsdPerMtok: 10.0,\n cachedInputUsdPerMtok: 1.0,\n outputUsdPerMtok: 45.0,\n effectiveAsOf: EFFECTIVE_AS_OF,\n source: 'openai-pricing-page',\n },\n priority: {\n inputUsdPerMtok: 12.5,\n cachedInputUsdPerMtok: 1.25,\n outputUsdPerMtok: 75.0,\n effectiveAsOf: EFFECTIVE_AS_OF,\n source: 'openai-pricing-page',\n },\n },\n 'gpt-5.4': {\n highContext: {\n inputUsdPerMtok: 5.0,\n cachedInputUsdPerMtok: 0.5,\n outputUsdPerMtok: 22.5,\n effectiveAsOf: EFFECTIVE_AS_OF,\n source: 'openai-pricing-page',\n },\n },\n};\n\nconst STALE_THRESHOLD_MS = 30 * 24 * 60 * 60 * 1000;\n\nfunction isStale(effectiveAsOf: string, now: number): boolean {\n const parsedMs = Date.parse(effectiveAsOf);\n if (Number.isNaN(parsedMs)) return true;\n return now - parsedMs > STALE_THRESHOLD_MS;\n}\n\n/**\n * Resolve the correct `CodexModelPricing` for a given model + usage context.\n *\n * Priority order:\n * 1. Priority mode (gpt-5.5 only) — slug contains \"priority\" OR serviceTier === 'priority'\n * 2. High-context tier — modelContextWindow > HIGH_CONTEXT_THRESHOLD,\n * OR (when modelContextWindow is absent) total input tokens > HIGH_CONTEXT_THRESHOLD\n * 3. Standard rate from CODEX_PRICING_SEED\n *\n * Returns undefined when the model is not in the seed table.\n */\nfunction resolvePricing(\n modelId: string,\n usage: Pick<CodexTokenUsage, 'inputTokens' | 'modelContextWindow' | 'serviceTier'>\n): CodexModelPricing | undefined {\n const base = CODEX_PRICING_SEED[modelId];\n if (!base) return undefined;\n\n const tiered = CODEX_TIERED_PRICING[modelId];\n if (!tiered) return base;\n\n const isPriority =\n tiered.priority !== undefined &&\n (modelId.includes('priority') || usage.serviceTier === 'priority');\n if (isPriority && tiered.priority) return tiered.priority;\n\n const contextSignal =\n usage.modelContextWindow !== undefined && usage.modelContextWindow !== null\n ? usage.modelContextWindow\n : usage.inputTokens;\n if (contextSignal > HIGH_CONTEXT_THRESHOLD) return tiered.highContext;\n\n return base;\n}\n\n/**\n * Compute an estimated dollar cost for a Codex turn.\n *\n * Formula:\n * cost = (inputTokens / 1e6) × inputUsdPerMtok\n * + (cachedInputTokens / 1e6) × cachedInputUsdPerMtok\n * + (outputTokens / 1e6) × outputUsdPerMtok\n *\n * `outputTokens` is the OpenAI billing number which already includes\n * reasoning. `reasoningOutputTokens` is logged for diagnostics but does\n * NOT participate in the formula.\n *\n * Returns `{ source: 'unavailable' }` when the model is not in the seed\n * table — callers MUST handle this and not assume a number.\n */\nexport function estimateCodexCost(\n usage: CodexTokenUsage,\n modelId: string,\n log: CostEstimatorLogger,\n /**\n * Codex `serviceTier` from `thread/start` (priority vs standard). The\n * base seeds are standard-tier pricing; when callers know they're on\n * priority tier they can fold the multiplier in by passing it here.\n * Threaded through but the pricing table is the same for now —\n * priority-tier rates need their own seed row before this changes\n * the math. Until then the parameter is a forward-compat placeholder\n * so call sites do not need to be updated again.\n */\n _serviceTier?: string | null\n): EstimatedCodexCost {\n const pricing = resolvePricing(modelId, usage);\n if (!pricing) {\n log({ event: 'codex_pricing_missing', modelId });\n return {\n amountUsd: 0,\n source: 'unavailable',\n modelId,\n pricingEffectiveAsOf: '1970-01-01',\n };\n }\n\n if (isStale(pricing.effectiveAsOf, Date.now())) {\n log({\n event: 'codex_pricing_stale',\n modelId,\n effectiveAsOf: pricing.effectiveAsOf,\n pricingSource: pricing.source,\n });\n }\n\n if (\n usage.reasoningOutputTokens !== undefined &&\n usage.reasoningOutputTokens > usage.outputTokens\n ) {\n /**\n * If this ever fires, the upstream protocol changed and our\n * \"reasoning is folded into output\" invariant no longer holds. Log\n * loudly so the next incident triage sees it; the cost calc itself\n * continues with the documented formula.\n */\n log({\n event: 'codex_reasoning_exceeds_output',\n modelId,\n reasoningOutputTokens: usage.reasoningOutputTokens,\n outputTokens: usage.outputTokens,\n });\n }\n\n const cost =\n (usage.inputTokens / 1_000_000) * pricing.inputUsdPerMtok +\n (usage.cachedInputTokens / 1_000_000) * pricing.cachedInputUsdPerMtok +\n (usage.outputTokens / 1_000_000) * pricing.outputUsdPerMtok;\n\n return {\n amountUsd: cost,\n source: 'estimated',\n modelId,\n pricingEffectiveAsOf: pricing.effectiveAsOf,\n };\n}\n","/**\n * Codex credential resolver.\n *\n * `resolveCodexCredentials(method)` is the daemon-side chokepoint for\n * picking up the credential bag the Codex subprocess needs to talk to\n * OpenAI. Three real methods (`chatgpt`, `api-key`, `bedrock`) plus the\n * `none` sentinel for \"user has not picked yet\".\n *\n * - `chatgpt`: read `~/.codex/auth.json` (honoring `CODEX_HOME` env)\n * and surface the OAuth `tokens.access_token` when it is usable. Shipyard\n * does not refresh ChatGPT OAuth tokens directly; upstream Codex owns the\n * token family, including reload and refresh-token recovery. `OPENAI_API_KEY`\n * from the same file is accepted as a fallback for users whose Codex CLI\n * wrote the API-key path into the same file.\n * - `api-key`: read `OPENAI_API_KEY` then `CODEX_API_KEY` from the\n * process env. Pure env path — no file IO.\n * - `bedrock`: returns null. AWS credential chain is ambient; the\n * Codex subprocess inherits `AWS_*` from `process.env` at spawn\n * time. The null return tells the caller \"no Shipyard-supplied\n * credentials\" — the spawn dispatch trusts the inherited env.\n * - `none`: returns null. Sentinel for unconfigured.\n *\n * No fallback chain across methods: we resolve exactly what the user's\n * `preferredAuthMethod['codex']` setting selects. If the right\n * credentials aren't available, returns null and callers treat Codex\n * credentials as unavailable until the user explicitly starts sign-in.\n */\nexport { type CodexCredentials, resolveCodexCredentials };\n\nimport { promises as fs } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nimport type { CodexAuthMethod } from '@shipyard/loro-schema';\n\nimport { classifyJwtFreshness } from '../../shared/capabilities/codex-auth-detect.js';\n\n/**\n * Resolved Codex credentials.\n *\n * `apiKey` carries an OpenAI API key (for the `api-key` flow, or the\n * fallback path where `~/.codex/auth.json` stores an API key under\n * `OPENAI_API_KEY`). `authToken` carries the ChatGPT OAuth access token\n * for the `chatgpt` flow. The Codex subprocess receives credentials via\n * env injection at spawn time (`OPENAI_API_KEY` for keys; the OAuth\n * token is consumed by `codex` itself from the same file).\n */\ninterface CodexCredentials {\n apiKey?: string;\n authToken?: string;\n source: CodexAuthMethod;\n}\n\ninterface CodexAuthFile {\n /** Codex-written API key path; some users have both this AND `tokens` populated. */\n OPENAI_API_KEY?: string;\n tokens?: {\n access_token?: string;\n refresh_token?: string;\n id_token?: string;\n };\n last_refresh?: string;\n}\n\n/**\n * Buffer (in seconds) before the JWT `exp` at which we treat the token\n * as needing refresh. 5 minutes covers normal daemon-to-spawn latency\n * so a token that expires mid-turn doesn't cause a 401.\n */\nconst REFRESH_BUFFER_SECONDS = 5 * 60;\n\n/**\n * Return the path to `auth.json`. Honors `CODEX_HOME` env override per\n * Codex's documented config-dir contract (`utils/home-dir/src/lib.rs`).\n * Default: `~/.codex/auth.json`.\n */\nfunction codexAuthFilePath(): string {\n const home = process.env.CODEX_HOME?.trim();\n if (home && home.length > 0) return join(home, 'auth.json');\n return join(homedir(), '.codex', 'auth.json');\n}\n\n/**\n * Narrow an unknown JSON parse result to the loose `CodexAuthFile`\n * shape. Only the fields we read are validated — extra keys flow\n * through (the file is owned by the Codex CLI and may grow new fields\n * in future versions; we don't want to reject those).\n */\nfunction isCodexAuthFile(value: unknown): value is CodexAuthFile {\n if (!isPlainObject(value)) return false;\n if (value.OPENAI_API_KEY !== undefined && typeof value.OPENAI_API_KEY !== 'string') return false;\n const tokens = value.tokens;\n if (tokens !== undefined) {\n if (!isPlainObject(tokens)) return false;\n if (tokens.access_token !== undefined && typeof tokens.access_token !== 'string') return false;\n if (tokens.refresh_token !== undefined && typeof tokens.refresh_token !== 'string')\n return false;\n if (tokens.id_token !== undefined && typeof tokens.id_token !== 'string') return false;\n }\n return true;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nasync function readCodexAuthFile(): Promise<CodexAuthFile | null> {\n const path = codexAuthFilePath();\n try {\n const raw = await fs.readFile(path, 'utf8');\n const parsed: unknown = JSON.parse(raw);\n if (!isCodexAuthFile(parsed)) return null;\n return parsed;\n } catch {\n /**\n * Any IO failure (ENOENT, permission denied, malformed JSON) maps\n * to \"not logged in\" — the caller treats null as \"drive the user\n * through `codex login`\". We deliberately do not log here because\n * the chokepoint logs at the boundary; this function stays pure\n * (modulo the fs read it is named for).\n */\n return null;\n }\n}\n\n/**\n * Resolve the chatgpt OAuth access_token from the auth file.\n *\n * If the stored token is expired or within `REFRESH_BUFFER_SECONDS` of expiry,\n * return null instead of refreshing directly. Codex's app-server owns the\n * ChatGPT token refresh protocol and has process-local cache/reload semantics\n * that Shipyard should not duplicate. Falls back to the raw file token if the\n * JWT is unparseable (non-JWT format or missing `exp` claim) so users with\n * tokens that lack an `exp` claim aren't broken.\n */\nasync function resolveChatgptCredentials(file: CodexAuthFile): Promise<CodexCredentials | null> {\n const oauthToken = file.tokens?.access_token?.trim();\n if (oauthToken && oauthToken.length > 0) {\n const nowSeconds = Math.floor(Date.now() / 1000);\n const freshness = classifyJwtFreshness(oauthToken, nowSeconds, REFRESH_BUFFER_SECONDS);\n\n if (freshness === 'expired') {\n return null;\n }\n\n return { authToken: oauthToken, source: 'chatgpt' };\n }\n\n /**\n * Some Codex CLI versions write the OpenAI key path into the same\n * `auth.json` file under `OPENAI_API_KEY` — treat that as a valid\n * `chatgpt` resolution rather than failing back to \"not logged in\"\n * just because the OAuth refresh isn't present.\n */\n const fileKey = file.OPENAI_API_KEY?.trim();\n if (fileKey && fileKey.length > 0) {\n return { apiKey: fileKey, source: 'chatgpt' };\n }\n\n return null;\n}\n\n/**\n * Resolve Codex credentials for the user's chosen auth method.\n *\n * No fallback chain — we use exactly what matches the user's\n * `preferredAuthMethod['codex']` setting. If the right credentials\n * aren't available, returns null (the user needs to log in with that\n * method).\n */\nasync function resolveCodexCredentials(method: CodexAuthMethod): Promise<CodexCredentials | null> {\n switch (method) {\n case 'chatgpt': {\n const file = await readCodexAuthFile();\n if (!file) return null;\n return resolveChatgptCredentials(file);\n }\n\n case 'api-key': {\n const envKey = process.env.OPENAI_API_KEY?.trim();\n if (envKey && envKey.length > 0) return { apiKey: envKey, source: 'api-key' };\n const altKey = process.env.CODEX_API_KEY?.trim();\n if (altKey && altKey.length > 0) return { apiKey: altKey, source: 'api-key' };\n return null;\n }\n\n case 'bedrock':\n /**\n * AWS credential chain is ambient — the Codex subprocess inherits\n * `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / `AWS_SESSION_TOKEN`\n * / `AWS_PROFILE` from `process.env` at spawn time. Returning null\n * here tells the caller \"no Shipyard-supplied credentials\"; the\n * spawn dispatch lets the inherited env carry the credentials\n * through unchanged.\n */\n return null;\n\n case 'none':\n return null;\n\n default:\n method satisfies never;\n return null;\n }\n}\n","/**\n * Codex content builder (codex c6).\n *\n * Converts Shipyard's canonical `ContentBlock[]` (user-input shape) into\n * Codex's native `UserInput[]` accepted by `turn/start.input`.\n *\n * Codex's `UserInput` variants are narrower than Claude's: there is no\n * `tool_use`, `tool_result`, or `thinking` analog (those flow through\n * thread items, not user turn input). The exhaustive switch over\n * `ContentBlockSchema`'s variants is load-bearing — adding a new content\n * block to the schema breaks the build here until a translation is chosen,\n * which prevents silent drops of new block types.\n *\n * Image handling:\n * - Embedded `resource` blocks with an image mime type and an asset path\n * in `_meta` emit `{ type: 'localImage', path }` — Codex reads the\n * file off disk natively (no base64 inlining).\n * - Embedded `resource` blocks with an image mime type but no asset\n * path fall back to `{ type: 'image', url: 'data:<mime>;base64,...' }`.\n * - Text-bearing resources emit text.\n *\n * Feedback blocks (diff/preview/annotation/task) are formatted to text\n * using the same formatters the Claude path uses, so the agent sees the\n * same surface text on either provider.\n */\n\nimport type { ContentBlock, SkillInvocationBlock } from '@shipyard/loro-schema';\nimport { isImageMimeType } from '@shipyard/loro-schema';\nimport type { UserInput } from '@shipyard/session/codex-app-server';\nimport { ASSET_PATH_META_KEY } from '../asset-resolver.js';\n\nimport {\n formatAnnotationFeedback,\n formatDiffReviewFeedback,\n formatPreviewAnnotationFeedback,\n} from './feedback-formatters.js';\nimport { formatTaskFeedback } from './sdk-content-builder.js';\n\nexport type CodexContentBuilderLogger = (entry: { event: string; [key: string]: unknown }) => void;\n\nfunction readAssetPath(meta: Record<string, unknown> | undefined): string | null {\n if (!meta) return null;\n const value = meta[ASSET_PATH_META_KEY];\n return typeof value === 'string' ? value : null;\n}\n\n/**\n * The display token for a skill chip — `$qa` for a bare skill, `$plugin:qa`\n * when a namespace is set to disambiguate a collision. Mirrors the composer's\n * sigil convention (use-submit.ts:extractSkillInvocations).\n */\nfunction skillToken(block: SkillInvocationBlock): string {\n return block.namespace ? `$${block.namespace}:${block.name}` : `$${block.name}`;\n}\n\n/** Escape a string for safe insertion into a regex character class / literal. */\nfunction escapeForRegex(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Build the regex that matches a single skill token at a word boundary,\n * mirroring the composer's pattern in `extractSkillInvocations`. We match\n * the `$` sigil specifically because the rewrite only applies on the Codex\n * wire (Codex uses `$` for skill sigils).\n *\n * The lookbehind/lookahead anchors require whitespace or string boundaries\n * around the token so `foo$qa` or `$qabar` are NOT rewritten.\n */\nfunction buildSkillTokenRegex(token: string): RegExp {\n /** Drop the leading `$` for the regex body; the sigil is matched literally. */\n const body = token.slice(1);\n return new RegExp(`(?<=^|\\\\s)\\\\$${escapeForRegex(body)}(?=\\\\s|$)`, 'g');\n}\n\n/**\n * Pre-scan a message's blocks to compute the text rewrites required by each\n * `skill_invocation` block's `bodyResolution`. Returns a map keyed by the\n * exact token (`$qa` or `$plugin:qa`) to its replacement.\n *\n * Only `bodyResolution === 'pass-in'` with a `path` produces a rewrite —\n * `native` and `mirror` leave the bare sigil in place for Codex's resolver,\n * and `unreachable` skills must remain visible as plain text per spec.\n *\n * Idempotency: callers only invoke this on live submission blocks, never on\n * pre-rewritten text. The token regex requires the bare `$qa` form, so a\n * second pass over `[$qa](skill://...)` would not match (the `$` no longer\n * sits at a word boundary because of the preceding `[`).\n */\nfunction computeSkillRewrites(blocks: ContentBlock[]): Map<string, string> {\n const rewrites = new Map<string, string>();\n for (const block of blocks) {\n if (block.type !== 'skill_invocation') continue;\n if (block.bodyResolution !== 'pass-in') continue;\n if (!block.path) continue;\n const token = skillToken(block);\n /**\n * `skill://` URI: protocol + empty host + absolute path. The three\n * slashes are intentional and matter to Codex's resolver\n * (codex-rs/core-skills/src/injection.rs:258).\n */\n rewrites.set(token, `[${token}](skill://${block.path})`);\n }\n return rewrites;\n}\n\n/**\n * Apply the precomputed rewrites to a single text block's content. Each\n * token is rewritten in place at word boundaries; non-rewriteable tokens\n * are left alone. Pure — no I/O, no logging.\n */\nfunction applySkillRewrites(text: string, rewrites: Map<string, string>): string {\n if (rewrites.size === 0) return text;\n let out = text;\n for (const [token, replacement] of rewrites) {\n out = out.replace(buildSkillTokenRegex(token), replacement);\n }\n return out;\n}\n\nfunction buildResourceUserInput(\n block: Extract<ContentBlock, { type: 'resource' }>,\n log: CodexContentBuilderLogger\n): UserInput[] {\n const resource = block.resource;\n if ('text' in resource) {\n if (resource.text === '') return [];\n return [{ type: 'text', text: resource.text }];\n }\n /** Binary / blob resource. */\n if ('blob' in resource) {\n if (resource.mimeType && isImageMimeType(resource.mimeType)) {\n const assetPath = readAssetPath(resource._meta);\n if (assetPath) {\n return [{ type: 'localImage', path: assetPath }];\n }\n /** No asset path — fall back to a data URL. */\n const dataUrl = `data:${resource.mimeType};base64,${resource.blob}`;\n return [{ type: 'image', url: dataUrl }];\n }\n log({\n event: 'codex_content_skip_binary_resource',\n uri: resource.uri,\n mimeType: resource.mimeType ?? '<none>',\n });\n return [];\n }\n /** Unreachable per the EmbeddedResource schema (text | blob exhaustive). */\n return [];\n}\n\n/** Format a file_attachment block as a text snippet for Codex context injection. */\nfunction formatFileAttachmentForCodex(filename: string, preview: string | undefined): string {\n return preview ? `[File: ${filename}]\\n${preview}` : `[File attached: ${filename}]`;\n}\n\n/**\n * Translate Shipyard `ContentBlock[]` to Codex `UserInput[]`.\n *\n * Returns an empty array when every block is silent-skip (tool_use,\n * tool_result, thinking, compaction_boundary, review_decision, etc.).\n * Callers MUST treat empty-array as \"do not push\" — sending empty user\n * input to `turn/start` will produce a server-side error.\n */\nexport function buildCodexUserInput(\n blocks: ContentBlock[],\n log: CodexContentBuilderLogger\n): UserInput[] {\n const out: UserInput[] = [];\n /**\n * Two-pass: first scan all skill_invocation blocks so we know which text\n * tokens need rewriting. Then emit blocks in original order, rewriting\n * text blocks on the fly. Order-independent — skill block may appear\n * before or after its paired text block in the array.\n */\n const skillRewrites = computeSkillRewrites(blocks);\n\n for (const block of blocks) {\n switch (block.type) {\n case 'text': {\n const rewritten = applySkillRewrites(block.text, skillRewrites);\n if (rewritten !== '') out.push({ type: 'text', text: rewritten });\n break;\n }\n case 'diff_review_feedback':\n out.push({ type: 'text', text: formatDiffReviewFeedback(block.comments) });\n break;\n case 'preview_annotation_feedback':\n out.push({ type: 'text', text: formatPreviewAnnotationFeedback(block.comments) });\n break;\n case 'annotation_feedback':\n out.push({ type: 'text', text: formatAnnotationFeedback(block.annotations) });\n break;\n case 'task_feedback':\n out.push({ type: 'text', text: formatTaskFeedback(block) });\n break;\n case 'resource_link': {\n const desc = block.description ? ` - ${block.description}` : '';\n out.push({ type: 'text', text: `[Resource: ${block.name}${desc}](${block.uri})` });\n break;\n }\n case 'resource':\n out.push(...buildResourceUserInput(block, log));\n break;\n /** Silent-skip: not part of user input on the Codex protocol. */\n case 'tool_use':\n case 'tool_result':\n case 'thinking':\n case 'review_decision':\n case 'review_comment':\n case 'compaction_boundary':\n break;\n /** File attachment — Codex integration is follow-up work; emit preview as text fallback. */\n case 'file_attachment':\n out.push({\n type: 'text',\n text: formatFileAttachmentForCodex(block.filename, block.preview),\n });\n break;\n /**\n * Skill chip — Codex has a native `skill` UserInput type that tells\n * the agent to load the SKILL.md at the given path. Behavior depends\n * on `bodyResolution`:\n *\n * `native` / `mirror` / undefined: emit the skill metadata if a\n * path is known. Codex's resolver loads the body from its own\n * indexed location (or from the mirror symlink).\n * `pass-in`: emit the skill metadata AND let the paired text block\n * rewrite carry the `skill://` URI. The redundant metadata is\n * harmless and matches the existing wire shape.\n * `unreachable`: skip the metadata entirely — Codex would reject a\n * skill ref it can't resolve. The paired text keeps the bare\n * `$qa` sigil so the user sees the unloaded mention rather than\n * a silent drop.\n */\n case 'skill_invocation':\n if (block.bodyResolution === 'unreachable') break;\n if (block.path) {\n out.push({ type: 'skill', name: block.name, path: block.path });\n }\n break;\n default: {\n const _exhaustive: never = block;\n throw new Error(`Unhandled content block: ${JSON.stringify(_exhaustive)}`);\n }\n }\n }\n\n return out;\n}\n","/**\n * Codex subagent result synthesizer (codex c11).\n *\n * Codex returns subagent results via the `wait_agent` mailbox path (see\n * .research/codex-gap-F-subagents.md §6 Q5) — there is no inline XML\n * injection like Claude's `<task-notification>` user turn. To keep\n * downstream code uniform across providers, Shipyard synthesizes the\n * same XML shape from Codex's `CollabAgentSpawnEnd` payload so the\n * existing `parseTaskNotificationXml` parser in\n * `message-classifiers.ts:182` accepts both wire formats unchanged.\n *\n * This module is the canonical home for that synthesis. The c6\n * translator (`codex-item-translator.ts`) previously inlined\n * `buildTaskNotificationXml` + `classifyCodexAgentStatus`; c11 lifts\n * them here so any future caller — direct `CollabAgentSpawnEndEvent`\n * consumer, child-thread fetch path, retry-after-restart replay — uses\n * one source of truth. The translator delegates here for the\n * `collabAgentToolCall` (wait) translation path.\n *\n * Pure module. No I/O, no async work, no external imports beyond\n * canonical Shipyard types.\n *\n * Wire-format reference: .research/codex-implementation-playbook.md §10.\n */\nimport type { SubprocessEvent } from './agent-subprocess.js';\n\n/**\n * Canonical end-state from a Codex subagent run. Maps the relevant\n * subset of `CollabAgentSpawnEndEvent` + `CollabAgentState`. We do not\n * include the full Codex types here so the synthesizer stays callable\n * from sites that have only partial data (translator at item-completed\n * boundary; future direct-event consumer).\n */\nexport interface CodexSubagentResultInput {\n /** Codex `receiver_thread_id` (the child thread). Falls back to tool-call id. */\n subagentThreadId: string;\n /** Native Codex agent status — accepts every variant of `CollabAgentStatusSchema`. */\n codexStatus: CodexAgentStatus;\n /**\n * The subagent's final `agent_message` text (Codex surfaces this as\n * `CollabAgentState.message`). Empty string when the child terminated\n * without producing a final message.\n */\n resultText: string;\n /** Cumulative token usage if available; 0 when Codex does not surface it. */\n totalTokens?: number;\n /** Tool-use count if available; 0 when Codex does not surface it. */\n toolUses?: number;\n /** Duration in ms if available; 0 when not computed. */\n durationMs?: number;\n}\n\n/**\n * Codex's native `CollabAgentStatus` variants — duplicated here so the\n * synthesizer does not depend on the `@shipyard/session/codex-app-server`\n * package (keeps the module callable from contexts where only canonical\n * types are present).\n */\nexport type CodexAgentStatus =\n | 'pendingInit'\n | 'running'\n | 'interrupted'\n | 'completed'\n | 'errored'\n | 'shutdown'\n | 'notFound';\n\n/**\n * Shipyard canonical subagent status (matches\n * `BackgroundAgentStatusSchema` and the `<status>` enum the existing\n * `parseTaskNotificationXml` consumer expects).\n */\nexport type CanonicalSubagentStatus = 'completed' | 'failed' | 'stopped';\n\n/**\n * Map a Codex `CollabAgentStatus` to the canonical Shipyard status the\n * XML envelope advertises. Per gap-F audit §3:\n * - `Completed` → `completed`\n * - `Errored` | `NotFound` → `failed`\n * - `Interrupted` | `Shutdown` | `PendingInit` | `Running` (defensively) → `stopped`\n */\nexport function classifyCodexAgentStatus(\n status: CodexAgentStatus | undefined\n): CanonicalSubagentStatus {\n if (status === 'completed') return 'completed';\n if (status === 'errored' || status === 'notFound') return 'failed';\n return 'stopped';\n}\n\n/**\n * Build the synthetic `<task-notification>` XML payload that Claude's\n * `parseTaskNotificationXml` consumes. Result is a plain string suitable\n * for emitting as a `background_agent_result` SubprocessEvent's `result`\n * field, or for stuffing into a user-turn-style ContentBlock when a\n * future path needs the parent agent to \"see\" the result inline.\n *\n * The XML shape is fixed by the playbook §10. Caller is responsible for\n * trimming/normalizing `resultText` if it contains untrusted HTML — the\n * parser does not interpret it as HTML, only as the inner text of the\n * `<result>` tag.\n */\nexport function buildTaskNotificationXml(args: {\n subagentThreadId: string;\n status: CanonicalSubagentStatus;\n resultText: string;\n totalTokens: number;\n toolUses: number;\n durationMs: number;\n}): string {\n const lines = [\n '<task-notification>',\n ` <task-id>${args.subagentThreadId}</task-id>`,\n ` <status>${args.status}</status>`,\n ' <result>',\n args.resultText.trim(),\n ' </result>',\n ' <usage>',\n ` <total-tokens>${args.totalTokens}</total-tokens>`,\n ` <tool-uses>${args.toolUses}</tool-uses>`,\n ` <duration-ms>${args.durationMs}</duration-ms>`,\n ' </usage>',\n '</task-notification>',\n ];\n return lines.join('\\n');\n}\n\n/**\n * Synthesize the canonical pair of SubprocessEvents Codex would have\n * emitted if its protocol surfaced subagent results inline:\n * 1. `background_agent_completed` — terminal status + summary.\n * 2. `background_agent_result` — `<task-notification>` XML payload\n * that Claude's existing parser will accept.\n *\n * The returned event order matches Claude's emission order so\n * downstream consumers (state machines, store writers, browser\n * subscribers) need no provider-specific branching.\n *\n * Caller is responsible for deciding whether to emit — e.g. only on a\n * `wait` tool whose `status === 'completed'` (the translator handles\n * this gate), or only when a new `CollabAgentSpawnEnd` arrives.\n */\nexport function synthesizeCodexSubagentEvents(input: CodexSubagentResultInput): SubprocessEvent[] {\n const canonical = classifyCodexAgentStatus(input.codexStatus);\n const xml = buildTaskNotificationXml({\n subagentThreadId: input.subagentThreadId,\n status: canonical,\n resultText: input.resultText,\n totalTokens: input.totalTokens ?? 0,\n toolUses: input.toolUses ?? 0,\n durationMs: input.durationMs ?? 0,\n });\n\n return [\n {\n type: 'background_agent_completed',\n taskId: input.subagentThreadId,\n status: canonical,\n summary: input.resultText,\n },\n {\n type: 'background_agent_result',\n taskId: input.subagentThreadId,\n result: xml,\n },\n ];\n}\n","/**\n * Codex item translator (codex c6).\n *\n * Translates Codex `ThreadItem` records (from c4's protocol-types) and\n * loose per-turn notifications into zero-or-more canonical\n * `SubprocessEvent`s the daemon's session state machine consumes.\n *\n * Translator philosophy:\n * - Known `ThreadItem` variants get an explicit case. The `default`\n * branch falls through to the `GenericThreadItem` schema (Codex's\n * own forward-compat envelope) — we log + drop unknown types\n * rather than throwing so a new Codex release does not crash the\n * daemon mid-turn.\n * - `agent_message` (complete) becomes a Shipyard `assistant_message`.\n * Streaming deltas arrive as a separate `AgentMessageDeltaNotification`\n * and are translated by `translateAgentMessageDelta`.\n * - Tool calls (`commandExecution`, `fileChange`, `mcpToolCall`,\n * `dynamicToolCall`, `webSearch`) emit a paired\n * `assistant_message` (with a `tool_use` ContentBlock) + a follow-up\n * `tool_result_echo` (with the matching `tool_result` ContentBlock).\n * The pair matches what the Claude SDK path produces so the\n * browser's `groupContentBlocks` / `ToolCallLine` rendering fires\n * unchanged. `tool_use_started` is still emitted for telemetry\n * hooks; the new pair is what makes the call visible in the UI.\n * - Subagent items (`collabAgentToolCall`) translate via the\n * `spawnAgent` / `wait` tool discriminator into Shipyard's\n * `background_agent_started` / `background_agent_completed` /\n * `background_agent_result` events AND a synthetic `Task`\n * `tool_use` + `tool_result` pair so the subagent card renders.\n * - Plan items (`plan`, `enteredReviewMode`) capture into\n * `ctx.lastProposedPlan` for plan-mode synthesis and emit a\n * synthetic `ExitPlanMode` `tool_use` block so the existing\n * plan-detection pipeline (`PlanHandler.detectPlanEvents`) fires.\n *\n * Translator context (`TranslatorCtx`) is mutated by callers between\n * frames to track per-turn state — the last `<proposed_plan>` content\n * is captured for plan-mode synthesis, the current turn id for cancel,\n * the in-flight tool_use / tool_result emission ledger so we don't\n * double-fire across `item/started` + `item/completed`, etc. The\n * translator itself is pure (returns events; no I/O).\n */\n\nimport type {\n AccountRateLimitsUpdatedNotification,\n AgentMessageDeltaNotification,\n CommandExecutionOutputDeltaNotification,\n ContextCompactedNotification,\n FileChangePatchUpdatedNotification,\n FileUpdateChange,\n GenericThreadItem,\n KnownThreadItem,\n ReasoningSummaryTextDeltaNotification,\n ReasoningTextDeltaNotification,\n ThreadItem,\n WarningNotification,\n} from '@shipyard/session/codex-app-server';\n\nimport type { SubprocessEvent } from './agent-subprocess.js';\nimport {\n type CanonicalSubagentStatus,\n type CodexAgentStatus,\n classifyCodexAgentStatus,\n synthesizeCodexSubagentEvents,\n} from './codex-subagent-result-synthesizer.js';\n\n/**\n * Cap on the persisted Codex shell tool_result body. The live streaming\n * preview (translateCommandExecutionOutputDelta) is intentionally\n * uncapped — only the result that lands in JSONL + the chat UI is\n * truncated, with a marker so the user sees what was dropped.\n *\n * Counted in JS code units; Codex shell output is ASCII-dominant so the\n * distinction from UTF-8 bytes is immaterial in practice.\n */\nconst MAX_OUTPUT_BYTES = 32_000;\n\nexport interface TranslatorCtx {\n /** Active task id. */\n taskId: string;\n /** Active model (from thread/start). */\n model?: string;\n /** Collaboration mode set on `turn/start` (e.g. 'plan'). */\n collaborationMode?: string;\n /**\n * Content of the most recent `<proposed_plan>` block extracted by Codex's\n * upstream stream parser and surfaced as a `plan` ThreadItem. Updated by\n * `translatePlanItem` on each plan-item completion; consumed by the\n * codex-subprocess's `#emitTurnComplete` to fire `plan_content_ready` so\n * the orchestrator can persist the file and attach the bridge. Reset to\n * empty after each emission so a turn without a new plan does not re-emit.\n */\n lastProposedPlan: string;\n /**\n * Item IDs whose `tool_use` `assistant_message` has already been\n * emitted. Codex fires both `item/started` AND `item/completed` for\n * every tool-like item, and our translator runs once per\n * notification. Tracking here lets us emit exactly one `tool_use`\n * block (on the first sighting) and one `tool_result_echo` (on the\n * terminal sighting) regardless of whether the upstream gates by\n * status. The set is per-translator-instance — Codex item IDs are\n * already unique within a thread so cross-turn collisions are not a\n * concern. Reset on thread restart (the subprocess instance is\n * disposed + replaced).\n */\n emittedToolUseItemIds: Set<string>;\n /**\n * Item IDs whose `tool_result_echo` has been emitted. Same purpose\n * as `emittedToolUseItemIds` but for the terminal side of the pair.\n */\n emittedToolResultItemIds: Set<string>;\n /**\n * Tracks the active stream block type so the dispatcher can emit\n * `content_block_stop` / `content_block_start` events on transitions\n * between text and thinking deltas. Without boundary events the\n * browser's stream renderer flushes reasoning text into the agent\n * message block (and vice versa) before the tail-compare correction.\n * Reset by the dispatcher on turn boundaries.\n */\n lastStreamBlockType: 'text' | 'thinking' | null;\n}\n\nexport type ItemTranslatorLogger = (entry: { event: string; [key: string]: unknown }) => void;\n\n/**\n * Build a fresh translator context. Centralized so call sites can't\n * forget to initialize the dedup sets.\n */\nexport function createTranslatorCtx(args: {\n taskId: string;\n model?: string;\n collaborationMode?: string;\n}): TranslatorCtx {\n return {\n taskId: args.taskId,\n model: args.model,\n collaborationMode: args.collaborationMode,\n lastProposedPlan: '',\n emittedToolUseItemIds: new Set(),\n emittedToolResultItemIds: new Set(),\n lastStreamBlockType: null,\n };\n}\n\n/**\n * Translate a streaming `agentMessage` delta into a canonical\n * stream_delta event. Codex deltas are per-chunk text fragments.\n */\nexport function translateAgentMessageDelta(delta: AgentMessageDeltaNotification): SubprocessEvent {\n return {\n type: 'stream_delta',\n event: 'content_block_delta',\n index: 0,\n blockType: 'text',\n textDelta: delta.delta,\n };\n}\n\n/**\n * Translate a streaming `item/reasoning/summaryTextDelta` notification into a\n * canonical thinking-style stream_delta. Codex emits these while a\n * `reasoning` thread item is in flight; the summary is the short\n * human-readable synopsis we surface as the live \"Thinking...\" chunk.\n *\n * `summaryIndex` is dropped: the daemon collapses every summary segment\n * onto the same thinking surface (matches the Claude path which has no\n * multi-summary concept).\n */\nexport function translateReasoningSummaryTextDelta(\n delta: ReasoningSummaryTextDeltaNotification\n): SubprocessEvent {\n return {\n type: 'stream_delta',\n event: 'content_block_delta',\n index: 0,\n blockType: 'thinking',\n textDelta: delta.delta,\n };\n}\n\n/**\n * Translate a streaming `item/reasoning/textDelta` notification into a\n * canonical thinking-style stream_delta. Codex emits these for the raw\n * reasoning content (the full model trace, not the summary).\n */\nexport function translateReasoningTextDelta(\n delta: ReasoningTextDeltaNotification\n): SubprocessEvent {\n return {\n type: 'stream_delta',\n event: 'content_block_delta',\n index: 0,\n blockType: 'thinking',\n textDelta: delta.delta,\n };\n}\n\n/**\n * Translate a streaming `item/commandExecution/outputDelta`\n * notification into a canonical tool-output stream_delta. The\n * `tool_output` blockType lets the browser-facing stream shaper cap\n * noisy stdout before it crosses the data channel; the committed\n * `tool_result_echo` (emitted on `item/completed`) carries the retained\n * `aggregated_output` so refresh still shows useful command output.\n *\n * `itemId` is preserved as `toolUseId` so the stream shaper can cap\n * each command independently. The visible stream is still appended to\n * the single in-flight tail, while each finalized command gets its own\n * `tool_result_echo` keyed by item id.\n */\nexport function translateCommandExecutionOutputDelta(\n delta: CommandExecutionOutputDeltaNotification\n): SubprocessEvent {\n return {\n type: 'stream_delta',\n event: 'content_block_delta',\n index: 0,\n blockType: 'tool_output',\n toolName: 'shell',\n toolUseId: delta.itemId,\n textDelta: delta.delta,\n };\n}\n\n/**\n * Translate a streaming `item/fileChange/patchUpdated` notification\n * into a canonical text-style stream_delta. Codex emits these as the\n * agent revises a not-yet-applied patch; the daemon surfaces a\n * compact human-readable summary so the live tool surface shows\n * progress. The committed `tool_result_echo` (emitted on\n * `item/completed`) carries the full diff payload for refresh.\n */\nexport function translateFileChangePatchUpdated(\n delta: FileChangePatchUpdatedNotification\n): SubprocessEvent {\n const summary = summarizeFileChangePatch(delta.changes);\n return {\n type: 'stream_delta',\n event: 'content_block_delta',\n index: 0,\n blockType: 'text',\n textDelta: summary,\n };\n}\n\n/**\n * Translate a non-turn-scoped warning into a canonical error/auth/rate\n * event. Mirrors the future `profile.errorMapper` contract — c7 will\n * pull this out so the Codex profile can declare it declaratively.\n */\n/**\n * Pure classifier for agent-error free-text. Shared between Codex\n * `warning` notifications and Codex `error` notifications so both\n * paths produce the same canonical SubprocessEvent kinds. The Claude\n * adapter classifies via `assistant.error` discriminators already\n * (`message-classifiers.ts:209`), so this function is Codex-only.\n *\n * Returns one of: `'usage_limit'` (provider quota), `'auth_required'`\n * (unauthorized / signed-out), `'billing_error'` (credit / payment),\n * or `null` to mean \"no classification — caller should fall through to\n * generic sdk_error\".\n */\nexport function classifyCodexErrorText(\n raw: string\n): 'usage_limit' | 'auth_required' | 'billing_error' | null {\n const msg = raw.toLowerCase();\n if (/rate.?limit|usage.?limit|quota/.test(msg)) return 'usage_limit';\n if (\n /\\bunauthor|\\btoken[_.-]?revoked|\\bsigned.?out|\\bnot\\s+(?:logged|signed)\\s+in|\\bauth(?:entication)?\\s+(?:failed|required|expired|\\berror)|\\binvalid\\s+(?:api.?key|token|credential)|\\bsession\\s+(?:expired|invalid)/.test(\n msg\n )\n )\n return 'auth_required';\n if (/billing|credit|payment/.test(msg)) return 'billing_error';\n return null;\n}\n\nexport function translateWarningNotification(warn: WarningNotification): SubprocessEvent {\n const classified = classifyCodexErrorText(warn.message);\n if (classified === 'usage_limit') {\n return {\n type: 'rate_limit',\n info: { status: 'rejected', provider: 'openai' },\n };\n }\n if (classified === 'auth_required') {\n return { type: 'auth_not_logged_in' };\n }\n if (classified === 'billing_error') {\n return { type: 'billing_error' };\n }\n return { type: 'sdk_error', error: warn.message };\n}\n\n/**\n * Translate an `account/rateLimits/updated` notification into a Shipyard\n * `rate_limit` SubprocessEvent.\n *\n * Maps the Codex `RateLimitSnapshot` fields onto the existing\n * provider-agnostic `RateLimitInfo` shape (provider `'openai'`). The\n * browser's rate-limit modal already narrows on `provider` to select which\n * fields to render — Codex fields (`primaryUsedPercent`, `primaryResetsAt`)\n * populate the OpenAI variant.\n *\n * `rateLimitReachedType` drives the `status` discriminator: when the server\n * has flagged a limit-reached condition we emit `'rejected'`; otherwise this\n * is an informational push (`'allowed_warning'`).\n */\nexport function translateAccountRateLimitsUpdated(\n notif: AccountRateLimitsUpdatedNotification\n): SubprocessEvent {\n const { rateLimits } = notif;\n const status =\n rateLimits.rateLimitReachedType !== null && rateLimits.rateLimitReachedType !== undefined\n ? ('rejected' as const)\n : ('allowed_warning' as const);\n const creditsRemainingUsd = parseCreditsBalance(rateLimits.credits?.balance);\n return {\n type: 'rate_limit',\n info: {\n status,\n provider: 'openai',\n ...(rateLimits.primary?.usedPercent !== undefined\n ? { primaryUsedPercent: rateLimits.primary.usedPercent }\n : {}),\n ...(rateLimits.primary?.resetsAt !== null && rateLimits.primary?.resetsAt !== undefined\n ? { primaryResetsAt: rateLimits.primary.resetsAt }\n : {}),\n ...(rateLimits.secondary?.usedPercent !== undefined\n ? { secondaryUsedPercent: rateLimits.secondary.usedPercent }\n : {}),\n ...(rateLimits.secondary?.resetsAt !== null && rateLimits.secondary?.resetsAt !== undefined\n ? { secondaryResetsAt: rateLimits.secondary.resetsAt }\n : {}),\n ...(creditsRemainingUsd !== null ? { creditsRemainingUsd } : {}),\n },\n };\n}\n\n/**\n * Parse the Codex `credits.balance` string (e.g. `\"$5.00\"`, `\"5.00\"`,\n * `\"$1,234.50\"`) into a USD float. Returns `null` for `undefined`,\n * `null`, empty, or unparseable input so the caller can omit the field\n * entirely rather than emit `NaN` on the wire.\n *\n * Locale safety: Codex emits canonical en-US (\"$1,234.50\") today; we\n * strip everything but digits, dot, and minus before parsing so the\n * common case round-trips even if a future build adds whitespace or\n * a different currency prefix.\n */\nfunction parseCreditsBalance(balance: string | null | undefined): number | null {\n if (balance === undefined || balance === null) return null;\n const trimmed = balance.trim();\n if (trimmed === '') return null;\n const numeric = trimmed.replace(/[^0-9.-]/g, '');\n if (numeric === '' || numeric === '-' || numeric === '.') return null;\n const parsed = Number.parseFloat(numeric);\n return Number.isFinite(parsed) ? parsed : null;\n}\n\n/**\n * Translate a non-turn-scoped `error` notification (fires via NotificationSinks.onError).\n *\n * Parallel to `translateWarningNotification`: both run the same\n * `classifyCodexErrorText` classifier so auth errors on EITHER path\n * produce `auth_not_logged_in` and trigger the unauth banner.\n *\n * The `params` shape is `{ error: string | { message: string } }` per\n * Codex's app-server protocol, but we accept `unknown` and fall back\n * gracefully so a malformed notification still emits a recognisable\n * `sdk_error` rather than silently dropping the event.\n */\nexport function translateErrorNotification(params: unknown): SubprocessEvent {\n let message = 'Codex error';\n if (typeof params === 'object' && params !== null && 'error' in params) {\n const errorRecord: { error: unknown } = params;\n if (typeof errorRecord.error === 'string') {\n message = errorRecord.error;\n } else if (isRecord(errorRecord.error) && typeof errorRecord.error.message === 'string') {\n message = errorRecord.error.message;\n }\n }\n const classified = classifyCodexErrorText(message);\n if (classified === 'auth_required') {\n return { type: 'auth_not_logged_in' };\n }\n if (classified === 'usage_limit') {\n return { type: 'rate_limit', info: { status: 'rejected', provider: 'openai' } };\n }\n if (classified === 'billing_error') {\n return { type: 'billing_error' };\n }\n return { type: 'sdk_error', error: message };\n}\n\n/**\n * Translate the `thread/compacted` notification.\n */\nexport function translateContextCompacted(_notif: ContextCompactedNotification): SubprocessEvent {\n /**\n * Codex does NOT report pre-compaction token count on the\n * notification (verified in protocol-types `ContextCompactedNotificationSchema`).\n * Zero-fill keeps the canonical event shape stable; the UI shows a\n * neutral \"Context compacted\" badge.\n */\n return { type: 'compaction_completed', preTokens: 0 };\n}\n\n/**\n * Convenience type guard: is this a known ThreadItem variant?\n *\n * We can't rely on Zod parsing here (the caller already parsed); the\n * union narrowing comes from the schema's `discriminatedUnion` on\n * `type`, so checking for a known literal is sufficient.\n */\nconst KNOWN_ITEM_TYPES: ReadonlySet<string> = new Set<KnownThreadItem['type']>([\n 'userMessage',\n 'hookPrompt',\n 'agentMessage',\n 'plan',\n 'reasoning',\n 'commandExecution',\n 'fileChange',\n 'mcpToolCall',\n 'dynamicToolCall',\n 'collabAgentToolCall',\n 'webSearch',\n 'imageView',\n 'imageGeneration',\n 'enteredReviewMode',\n 'exitedReviewMode',\n 'contextCompaction',\n]);\n\nfunction isKnownItem(item: ThreadItem): item is KnownThreadItem {\n return KNOWN_ITEM_TYPES.has(item.type);\n}\n\ntype CollabItem = Extract<KnownThreadItem, { type: 'collabAgentToolCall' }>;\n\n/**\n * Re-export of the canonical status classifier for tests / call sites\n * that have a `CollabAgentState`-shaped status string. The actual\n * implementation lives in `codex-subagent-result-synthesizer.ts` so\n * that future consumers of `CollabAgentSpawnEndEvent` (e.g. a direct\n * event subscriber, child-thread history replay) share one mapping.\n */\nfunction statusOfFirstAgent(item: CollabItem): CodexAgentStatus | undefined {\n const state = item.receiverThreadIds\n .map((rid) => item.agentsStates[rid])\n .find((s) => s !== undefined);\n return state?.status;\n}\n\n/**\n * Canonical tool name for the synthetic subagent tool_use block.\n * Matches the names `SubagentManager` watches for (`Task` / `Agent`) so\n * the existing subagent tracking + result-injection pipeline fires\n * for Codex spawns without any provider-specific branching.\n */\nconst SUBAGENT_TOOL_NAME = 'Task';\n\n/**\n * Canonical tool name for the synthetic plan tool_use block. Matches\n * Claude's tool — `PlanHandler.detectPlanEvents` keys on this string\n * literal, so emitting it here is what triggers the plan panel.\n */\nconst PLAN_TOOL_NAME = 'ExitPlanMode';\n\nfunction translateSpawnAgent(\n item: CollabItem,\n subagentId: string,\n ctx: TranslatorCtx\n): SubprocessEvent[] {\n if (item.status !== 'inProgress' && item.status !== 'completed') return [];\n /**\n * Both `item/started` (status=inProgress) AND `item/completed`\n * (status=completed) fire for spawnAgent. The Shipyard task layer's\n * `onBackgroundAgentStarted` registers the subagent on the parent\n * task — running it twice double-registers and corrupts the\n * pending-toolUseId queue. Gate by the per-item ledger so the\n * `background_agent_started` + `assistant_message` pair fires\n * exactly once across the lifecycle. The `wait` tool emits the\n * matching `background_agent_completed` later (see `translateWaitAgent`).\n */\n if (ctx.emittedToolUseItemIds.has(item.id)) return [];\n ctx.emittedToolUseItemIds.add(item.id);\n /**\n * Order matters: `assistant_message` MUST come before `background_agent_started`.\n * `SubagentManager.trackAgentToolUse` populates the pending-toolUseId/name queue\n * from the Task tool_use block in the assistant message, and\n * `onBackgroundAgentStarted` drains it. Claude emits them in this order; emitting\n * them reversed leaves the queue empty on the first spawn (fallback to\n * `event.toolUseId` is correct) but poisons it with leftover entries for the\n * second+ spawn, persisting stale toolUseId + agentType onto the next\n * ThreadMetadata and breaking \"Open thread\" in the parent chat.\n */\n return [\n {\n type: 'assistant_message',\n messageId: item.id,\n content: [\n {\n type: 'tool_use',\n toolUseId: item.id,\n toolName: SUBAGENT_TOOL_NAME,\n input: {\n description: item.prompt ?? '',\n prompt: item.prompt ?? '',\n ...(item.model ? { model: item.model } : {}),\n },\n parentToolUseId: null,\n },\n ],\n ...(ctx.model !== undefined ? { model: ctx.model } : {}),\n },\n {\n type: 'background_agent_started',\n taskId: subagentId,\n toolUseId: item.id,\n description: item.prompt ?? '',\n agentType: 'codex',\n prompt: item.prompt ?? undefined,\n },\n ];\n}\n\nfunction translateWaitAgent(\n item: CollabItem,\n subagentId: string,\n ctx: TranslatorCtx\n): SubprocessEvent[] {\n if (item.status !== 'completed') return [];\n const agentState = item.receiverThreadIds\n .map((rid) => item.agentsStates[rid])\n .find((s) => s !== undefined);\n const summary = agentState?.message ?? '';\n\n /**\n * Delegate the XML envelope construction + canonical status mapping\n * to the shared synthesizer (c11). Keeping one source of truth means\n * any future direct `CollabAgentSpawnEndEvent` consumer (subagent\n * subscriber, retry-after-restart replay, etc.) produces a\n * byte-identical `<task-notification>` payload — `parseTaskNotificationXml`\n * cannot drift between callers.\n */\n const events = synthesizeCodexSubagentEvents({\n subagentThreadId: subagentId,\n codexStatus: agentState?.status ?? 'shutdown',\n resultText: summary,\n /** Codex does not surface per-subagent token usage on the tool-call item. */\n totalTokens: 0,\n toolUses: 0,\n durationMs: 0,\n });\n\n /**\n * Pair the subagent result with the `Task` tool_use emitted by\n * `translateSpawnAgent`. `toolUseId` is the wait-item id so the\n * pair anchors on the wait call (each wait call gets a fresh\n * `tool_use`/`tool_result` pair, even when the underlying subagent\n * thread is the same — matching how Claude's repeated `Task` calls\n * each get their own pair in the chat). We piggy-back the\n * synthesizer's XML so `groupContentBlocks` has a non-empty result\n * body, which keeps the `background_agent` card from rendering as\n * \"Unknown\".\n */\n const canonical = classifyCodexAgentStatus(agentState?.status);\n const isError = canonical === 'failed';\n if (!ctx.emittedToolUseItemIds.has(item.id)) {\n ctx.emittedToolUseItemIds.add(item.id);\n events.push({\n type: 'assistant_message',\n messageId: item.id,\n content: [\n {\n type: 'tool_use',\n toolUseId: item.id,\n toolName: SUBAGENT_TOOL_NAME,\n input: {\n description: 'Waiting on subagent',\n subagent_thread_id: subagentId,\n },\n parentToolUseId: null,\n },\n ],\n ...(ctx.model !== undefined ? { model: ctx.model } : {}),\n });\n }\n if (!ctx.emittedToolResultItemIds.has(item.id)) {\n ctx.emittedToolResultItemIds.add(item.id);\n events.push({\n type: 'tool_result_echo',\n content: [\n {\n type: 'tool_result',\n toolUseId: item.id,\n content: summary || `Subagent ${subagentId} ${canonical}`,\n isError,\n parentToolUseId: null,\n },\n ],\n });\n }\n return events;\n}\n\n/**\n * Hook entry point: synthesize result events directly from a\n * `CollabAgentSpawnEnd`-shaped payload (c11). Surfaces the synthesizer\n * to callers that have the event but no full `ThreadItem` (e.g. a\n * future subscriber that listens to `CollabAgentSpawnEndEvent`\n * directly off the Codex client). c11 ships the entry; the caller\n * wiring lands in c12. Pure pass-through to the shared synthesizer.\n */\nexport function translateCollabAgentSpawnEnd(args: {\n subagentThreadId: string;\n codexStatus: CodexAgentStatus;\n resultText: string;\n}): SubprocessEvent[] {\n return synthesizeCodexSubagentEvents({\n subagentThreadId: args.subagentThreadId,\n codexStatus: args.codexStatus,\n resultText: args.resultText,\n totalTokens: 0,\n toolUses: 0,\n durationMs: 0,\n });\n}\n\n/**\n * Re-export of the canonical agent-status classifier so the translator\n * tests + downstream call sites can map a raw Codex agent status to\n * Shipyard's canonical 3-state status without depending directly on\n * the synthesizer module's internals.\n */\nexport { classifyCodexAgentStatus, type CanonicalSubagentStatus, statusOfFirstAgent };\n\nfunction translateCollabAgentToolCall(item: CollabItem, ctx: TranslatorCtx): SubprocessEvent[] {\n /** First receiver is the primary subagent id we surface in canonical events. */\n const subagentId = item.receiverThreadIds[0] ?? item.id;\n if (item.tool === 'spawnAgent') return translateSpawnAgent(item, subagentId, ctx);\n if (item.tool === 'wait') return translateWaitAgent(item, subagentId, ctx);\n /** sendInput / resumeAgent / closeAgent: no canonical event yet. */\n return [];\n}\n\n/**\n * Stringify the `input` payload of a synthetic tool_use block so it\n * renders cleanly in the chat UI's tool-call line. Codex item shapes\n * vary per item type; this is just a passthrough — the keys map to\n * the names the tool-summarizers in\n * `apps/web/src/utils/messages/tool-summarizers.ts` look for.\n */\ntype CommandExecutionItem = Extract<KnownThreadItem, { type: 'commandExecution' }>;\ntype FileChangeItem = Extract<KnownThreadItem, { type: 'fileChange' }>;\ntype McpToolCallItem = Extract<KnownThreadItem, { type: 'mcpToolCall' }>;\ntype DynamicToolCallItem = Extract<KnownThreadItem, { type: 'dynamicToolCall' }>;\ntype WebSearchItem = Extract<KnownThreadItem, { type: 'webSearch' }>;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return isRecord(value) ? value : {};\n}\n\nfunction commandExecutionInput(item: CommandExecutionItem): Record<string, unknown> {\n return {\n command: item.command,\n cwd: item.cwd,\n ...(item.source !== undefined ? { source: item.source } : {}),\n };\n}\n\nfunction commandExecutionResult(item: CommandExecutionItem): {\n content: string;\n isError: boolean;\n} {\n const exit = item.exitCode ?? null;\n const raw = item.aggregatedOutput ?? '';\n const out =\n raw.length > MAX_OUTPUT_BYTES\n ? `${raw.slice(0, MAX_OUTPUT_BYTES)}\\n[truncated ${raw.length - MAX_OUTPUT_BYTES} bytes]`\n : raw;\n const isError = item.status === 'failed' || (exit !== null && exit !== 0);\n const exitLine = exit !== null ? `\\n[exit code: ${exit}]` : '';\n return { content: `${out}${exitLine}`, isError };\n}\n\nfunction extractFileChangeKind(kindRaw: unknown): string {\n if (typeof kindRaw === 'string') return kindRaw;\n if (isRecord(kindRaw) && typeof kindRaw.type === 'string') return kindRaw.type;\n return 'update';\n}\n\nfunction summarizeFileChangePatch(changes: ReadonlyArray<FileUpdateChange>): string {\n if (changes.length === 0) return '(no changes)';\n return changes.map((c) => `${extractFileChangeKind(c.kind)} ${c.path}`).join('\\n');\n}\n\nfunction fileChangeInput(item: FileChangeItem): Record<string, unknown> {\n return {\n changes: item.changes.map((c) => ({ path: c.path, kind: c.kind })),\n };\n}\n\nfunction fileChangeResult(item: FileChangeItem): { content: string; isError: boolean } {\n const summary = summarizeFileChangePatch(item.changes);\n const diff = item.changes.map((c) => c.diff).join('\\n');\n const isError = item.status === 'failed';\n return { content: diff ? `${summary}\\n\\n${diff}` : summary, isError };\n}\n\nfunction mcpToolCallInput(item: McpToolCallItem): Record<string, unknown> {\n return asRecord(item.arguments);\n}\n\nfunction mcpToolCallResult(item: McpToolCallItem): { content: string; isError: boolean } {\n const err = asRecord(item.error);\n if (err.message && typeof err.message === 'string') {\n return { content: err.message, isError: true };\n }\n const result = item.result;\n if (result === null || result === undefined) {\n return { content: '(no result)', isError: item.status === 'failed' };\n }\n /**\n * Codex's `result` is the full MCP `CallToolResult` envelope; the\n * agent sees a structured payload. We stringify for the chat UI —\n * `groupContentBlocks` doesn't try to introspect, and the dedicated\n * MCP server's summarizer (registered via `tool-summarizers.ts`)\n * formats the input separately.\n */\n try {\n return {\n content: typeof result === 'string' ? result : JSON.stringify(result, null, 2),\n isError: item.status === 'failed',\n };\n } catch {\n return { content: String(result), isError: true };\n }\n}\n\nfunction dynamicToolCallInput(item: DynamicToolCallItem): Record<string, unknown> {\n return asRecord(item.arguments);\n}\n\nfunction dynamicToolCallResult(item: DynamicToolCallItem): {\n content: string;\n isError: boolean;\n} {\n const isError =\n item.status === 'failed' ||\n (item.success !== null && item.success !== undefined && !item.success);\n const items = item.contentItems;\n if (!items || items.length === 0) {\n return { content: isError ? '(tool reported failure)' : '(no output)', isError };\n }\n const text = items\n .map((entry) => {\n const rec = asRecord(entry);\n if (rec.type === 'inputText' && typeof rec.text === 'string') return rec.text;\n if (rec.type === 'inputImage' && typeof rec.imageUrl === 'string')\n return `[image] ${rec.imageUrl}`;\n try {\n return JSON.stringify(rec);\n } catch {\n return String(entry);\n }\n })\n .join('\\n');\n return { content: text, isError };\n}\n\nfunction webSearchInput(item: WebSearchItem): Record<string, unknown> {\n const action = asRecord(item.action);\n return {\n query: item.query,\n ...(typeof action.type === 'string' ? { action: action.type } : {}),\n };\n}\n\nfunction webSearchResult(item: WebSearchItem): { content: string; isError: boolean } {\n const action = asRecord(item.action);\n const actionType = typeof action.type === 'string' ? action.type : '';\n if (actionType === 'openPage') {\n const url = typeof action.url === 'string' ? action.url : '';\n return { content: `Opened page: ${url}`, isError: false };\n }\n if (actionType === 'findInPage') {\n const url = typeof action.url === 'string' ? action.url : '';\n const pattern = typeof action.pattern === 'string' ? action.pattern : '';\n return { content: `Searched in ${url} for \"${pattern}\"`, isError: false };\n }\n /** `search` (default) and `other`: surface the query. */\n return { content: `Searched: ${item.query}`, isError: false };\n}\n\n/**\n * Status mapping used to decide whether the translator should treat\n * the current `item` notification as \"start\" (emit tool_use) or\n * \"terminal\" (emit tool_result).\n *\n * Codex statuses are camelCase: `inProgress` / `completed` / `failed`\n * / `declined`. Items without a status field (`webSearch`, `plan`,\n * `reasoning`, `contextCompaction`) gate on the seen-set in ctx\n * instead — the first sighting is the \"start\" and any subsequent\n * sighting with the same id is the \"terminal\" emission.\n */\ntype ItemPhase = 'start' | 'terminal';\n\nfunction commandExecPhase(status: CommandExecutionItem['status']): ItemPhase {\n return status === 'inProgress' ? 'start' : 'terminal';\n}\n\nfunction fileChangePhase(status: FileChangeItem['status']): ItemPhase {\n return status === 'inProgress' ? 'start' : 'terminal';\n}\n\nfunction mcpPhase(status: McpToolCallItem['status']): ItemPhase {\n return status === 'inProgress' ? 'start' : 'terminal';\n}\n\nfunction dynamicPhase(status: DynamicToolCallItem['status']): ItemPhase {\n return status === 'inProgress' ? 'start' : 'terminal';\n}\n\n/**\n * Build the canonical `assistant_message` + optional `tool_result_echo`\n * events for a tool-like item, gated by the per-item ledger so the\n * pair is emitted exactly once across `item/started` + `item/completed`.\n *\n * `tool_use_started` is always emitted on start (matches the legacy\n * behavior) — it's a state-machine ping for telemetry, distinct from\n * the persisted tool_use ContentBlock the UI renders.\n */\nfunction emitToolUseStartedAndUseBlock(args: {\n itemId: string;\n toolName: string;\n input: Record<string, unknown>;\n ctx: TranslatorCtx;\n model: string | undefined;\n}): SubprocessEvent[] {\n const events: SubprocessEvent[] = [\n { type: 'tool_use_started', toolUseId: args.itemId, toolName: args.toolName },\n ];\n if (args.ctx.emittedToolUseItemIds.has(args.itemId)) return events;\n args.ctx.emittedToolUseItemIds.add(args.itemId);\n events.push({\n type: 'assistant_message',\n messageId: args.itemId,\n content: [\n {\n type: 'tool_use',\n toolUseId: args.itemId,\n toolName: args.toolName,\n input: args.input,\n parentToolUseId: null,\n },\n ],\n ...(args.model !== undefined ? { model: args.model } : {}),\n });\n return events;\n}\n\nfunction emitToolResult(args: {\n itemId: string;\n content: string;\n isError: boolean;\n ctx: TranslatorCtx;\n}): SubprocessEvent[] {\n if (args.ctx.emittedToolResultItemIds.has(args.itemId)) return [];\n args.ctx.emittedToolResultItemIds.add(args.itemId);\n return [\n {\n type: 'tool_result_echo',\n content: [\n {\n type: 'tool_result',\n toolUseId: args.itemId,\n content: args.content,\n isError: args.isError,\n parentToolUseId: null,\n },\n ],\n },\n ];\n}\n\n/**\n * Per-type translators. Each returns the SubprocessEvents for one\n * `ThreadItem` variant, given the translator context. Splitting these\n * out keeps `translateCodexItem`'s cognitive complexity below the\n * shared lint threshold while still funneling every dispatch through a\n * single exhaustive switch.\n */\nfunction translateAgentMessageItem(\n item: Extract<KnownThreadItem, { type: 'agentMessage' }>,\n ctx: TranslatorCtx\n): SubprocessEvent[] {\n /**\n * Codex fires `agentMessage` items twice — once on `item/started` (with\n * `text: \"\"`) and again on `item/completed` (with the populated text).\n * Without these gates the daemon writes TWO Message records to JSONL for\n * the same logical assistant turn: one empty, one full. They share the\n * same messageId (Codex item id), so the browser's grouping merges them,\n * but the empty leading record still leaks into the persisted content\n * array and into the wire frame — every refresh sees a duplicate.\n *\n * Two gates:\n * 1. Skip empty text — `item/started` carries no content. Persisting it\n * adds noise without delivering anything the user can see.\n * 2. Per-item dedup ledger — if `item/completed` ever fires twice (e.g.\n * with a single trailing whitespace edit), still emit only once.\n */\n if (item.text === '') return [];\n if (ctx.emittedToolUseItemIds.has(item.id)) return [];\n ctx.emittedToolUseItemIds.add(item.id);\n return [\n {\n type: 'assistant_message',\n messageId: item.id,\n content: [{ type: 'text', text: item.text }],\n ...(ctx.model !== undefined ? { model: ctx.model } : {}),\n },\n ];\n}\n\nfunction translateReasoningItem(\n item: Extract<KnownThreadItem, { type: 'reasoning' }>,\n ctx: TranslatorCtx\n): SubprocessEvent[] {\n /**\n * `reasoning` fires twice — once on `item/started` (empty summary /\n * content) and once on `item/completed` (populated). Live streaming\n * is already handled by `translateReasoningSummaryTextDelta` /\n * `translateReasoningTextDelta`. Here we persist the final\n * concatenated thinking text on completion so refresh / reconnect\n * still shows the reasoning surface. The previous `stream_delta`\n * shape was lost on persist (stream deltas are not written to\n * JSONL); writing the assistant_message with a `thinking` block\n * makes the reasoning durable.\n */\n const summary = item.summary?.join('\\n') ?? '';\n const content = item.content?.join('\\n') ?? '';\n const text = summary || content;\n if (!text) return [];\n if (ctx.emittedToolUseItemIds.has(item.id)) return [];\n ctx.emittedToolUseItemIds.add(item.id);\n return [\n {\n type: 'assistant_message',\n messageId: item.id,\n content: [{ type: 'thinking', text }],\n ...(ctx.model !== undefined ? { model: ctx.model } : {}),\n },\n ];\n}\n\nfunction translateCommandExecutionItem(\n item: CommandExecutionItem,\n ctx: TranslatorCtx\n): SubprocessEvent[] {\n if (commandExecPhase(item.status) === 'start') {\n return emitToolUseStartedAndUseBlock({\n itemId: item.id,\n toolName: 'shell',\n input: commandExecutionInput(item),\n ctx,\n model: ctx.model,\n });\n }\n const { content, isError } = commandExecutionResult(item);\n return emitToolResult({ itemId: item.id, content, isError, ctx });\n}\n\nfunction translateFileChangeItem(item: FileChangeItem, ctx: TranslatorCtx): SubprocessEvent[] {\n if (fileChangePhase(item.status) === 'start') {\n return emitToolUseStartedAndUseBlock({\n itemId: item.id,\n toolName: 'apply_patch',\n input: fileChangeInput(item),\n ctx,\n model: ctx.model,\n });\n }\n const { content, isError } = fileChangeResult(item);\n return emitToolResult({ itemId: item.id, content, isError, ctx });\n}\n\nfunction translateMcpToolCallItem(item: McpToolCallItem, ctx: TranslatorCtx): SubprocessEvent[] {\n const composite = `mcp__${item.server}__${item.tool}`;\n if (mcpPhase(item.status) === 'start') {\n return emitToolUseStartedAndUseBlock({\n itemId: item.id,\n toolName: composite,\n input: mcpToolCallInput(item),\n ctx,\n model: ctx.model,\n });\n }\n const { content, isError } = mcpToolCallResult(item);\n return emitToolResult({ itemId: item.id, content, isError, ctx });\n}\n\nfunction translateDynamicToolCallItem(\n item: DynamicToolCallItem,\n ctx: TranslatorCtx\n): SubprocessEvent[] {\n if (dynamicPhase(item.status) === 'start') {\n return emitToolUseStartedAndUseBlock({\n itemId: item.id,\n toolName: item.tool,\n input: dynamicToolCallInput(item),\n ctx,\n model: ctx.model,\n });\n }\n const { content, isError } = dynamicToolCallResult(item);\n return emitToolResult({ itemId: item.id, content, isError, ctx });\n}\n\nfunction translateWebSearchItem(item: WebSearchItem, ctx: TranslatorCtx): SubprocessEvent[] {\n /**\n * `webSearch` has no status field. Both `item/started` and\n * `item/completed` flow through here; gate by the per-item ledger so\n * the pair fires exactly once. `action` is populated on completion\n * only — when absent we treat this as the start (emit tool_use),\n * when present we treat it as terminal (emit tool_result).\n */\n const hasAction = item.action !== null && item.action !== undefined;\n if (!hasAction) {\n return emitToolUseStartedAndUseBlock({\n itemId: item.id,\n toolName: 'web_search',\n input: webSearchInput(item),\n ctx,\n model: ctx.model,\n });\n }\n const startEvents = ctx.emittedToolUseItemIds.has(item.id)\n ? []\n : emitToolUseStartedAndUseBlock({\n itemId: item.id,\n toolName: 'web_search',\n input: webSearchInput(item),\n ctx,\n model: ctx.model,\n });\n const { content, isError } = webSearchResult(item);\n return [...startEvents, ...emitToolResult({ itemId: item.id, content, isError, ctx })];\n}\n\nfunction translatePlanItem(\n item: Extract<KnownThreadItem, { type: 'plan' }>,\n ctx: TranslatorCtx\n): SubprocessEvent[] {\n /**\n * Plan-mode capture. The plan item carries plan markdown; we stash\n * it in ctx so the plan-handler can resolve \"is the plan ready\" on\n * the next turn-complete in collaborationMode === 'plan'.\n *\n * Emit a synthetic `ExitPlanMode` `tool_use` block so the existing\n * `PlanHandler.detectPlanEvents` pipeline fires (`detectPlanEvents`\n * keys on `toolName === 'ExitPlanMode'`). Plan items don't fire\n * `item/completed` with a separate body — the `text` IS the\n * completed plan — so we emit the pair on first sighting only, no\n * tool_result follow-up. The plan panel shows the markdown body and\n * the user explicitly approves or rejects via the plan-continuation\n * flow; the absence of a tool_result keeps the plan card in\n * \"pending\" state which is exactly what the UI expects until the\n * user decides.\n */\n ctx.lastProposedPlan = item.text;\n if (ctx.emittedToolUseItemIds.has(item.id)) return [];\n ctx.emittedToolUseItemIds.add(item.id);\n return [\n {\n type: 'assistant_message',\n messageId: item.id,\n content: [\n {\n type: 'tool_use',\n toolUseId: item.id,\n toolName: PLAN_TOOL_NAME,\n input: { plan: item.text },\n parentToolUseId: null,\n },\n ],\n ...(ctx.model !== undefined ? { model: ctx.model } : {}),\n },\n ];\n}\n\n/**\n * Translate a single `ThreadItem` (either KnownThreadItem or\n * GenericThreadItem fallthrough) into 0..N SubprocessEvents.\n *\n * Side effect: mutates `ctx.lastProposedPlan` on every complete `plan`\n * item so the codex-subprocess's `#emitTurnComplete` can fire\n * `plan_content_ready` for the orchestrator to persist + bridge. Also\n * mutates the `emittedToolUseItemIds` / `emittedToolResultItemIds`\n * ledgers so `item/started` + `item/completed` for the same item\n * produces exactly one tool_use + tool_result pair.\n */\nexport function translateCodexItem(\n item: ThreadItem,\n ctx: TranslatorCtx,\n log: ItemTranslatorLogger\n): SubprocessEvent[] {\n if (!isKnownItem(item)) {\n const generic: GenericThreadItem = item;\n log({\n event: 'codex_item_unknown_type',\n itemType: generic.type,\n itemId: generic.id ?? '<no-id>',\n });\n return [];\n }\n\n switch (item.type) {\n case 'agentMessage':\n return translateAgentMessageItem(item, ctx);\n case 'reasoning':\n return translateReasoningItem(item, ctx);\n case 'commandExecution':\n return translateCommandExecutionItem(item, ctx);\n case 'fileChange':\n return translateFileChangeItem(item, ctx);\n case 'mcpToolCall':\n return translateMcpToolCallItem(item, ctx);\n case 'dynamicToolCall':\n return translateDynamicToolCallItem(item, ctx);\n case 'webSearch':\n return translateWebSearchItem(item, ctx);\n case 'collabAgentToolCall':\n return translateCollabAgentToolCall(item, ctx);\n case 'plan':\n return translatePlanItem(item, ctx);\n case 'contextCompaction':\n /** Same shape as the notification — defer to a compaction_completed event. */\n return [{ type: 'compaction_completed', preTokens: 0 }];\n case 'imageGeneration':\n case 'imageView':\n case 'enteredReviewMode':\n case 'exitedReviewMode':\n case 'userMessage':\n case 'hookPrompt':\n /**\n * No canonical event yet. `userMessage` echoes are not needed —\n * the daemon produced the user turn locally and writes it\n * synchronously. The review-mode + image items are visualization-\n * only on the Codex side; until Shipyard surfaces them there's\n * nothing actionable to emit.\n */\n return [];\n default: {\n const _exhaustive: never = item;\n log({\n event: 'codex_item_unreachable',\n detail: JSON.stringify(_exhaustive),\n });\n return [];\n }\n }\n}\n","/**\n * Source: ~/repos/codex-src/codex-rs/models-manager/models.json (snapshot 2026-05-12)\n * Pricing reference: https://openai.com/api/pricing/ (Codex / Responses API)\n * Pricing entries below are PLACEHOLDERS — must be verified against the live\n * pricing page before shipping. The staleness-warning guard in\n * codex-cost-estimator.ts will fire on startup if effectiveAsOf is > 30 days\n * old (sentinel '1970-01-01' forces this).\n */\n\n/**\n * Codex model catalog (codex c7-followup).\n *\n * Seeds the `ModelDescriptor[]` list the Codex profile exposes through\n * `profile.models`. The shape mirrors the Claude side once that catalog\n * is moved over from `shared/capabilities/models.ts`.\n *\n * Pricing entries here are PLACEHOLDERS — they reference the same seed\n * values as `codex-cost-estimator.ts` (`CODEX_PRICING_SEED`), which has\n * its own staleness-warning guard. We do NOT duplicate pricing numbers\n * here; the estimator remains the single source of truth for actual\n * cost math. The `pricing` field on the descriptor exists so the browser\n * profile-summary can show a \"$ per Mtok\" hint, but cost is computed\n * daemon-side from the estimator.\n *\n * Supported efforts: models.json `supported_reasoning_levels` lists\n * low/medium/high/xhigh for all 5 models. gap-D-config.md confirms the\n * Codex effort enum is `none|minimal|low|medium|high|xhigh`. We surface\n * all four (none/minimal are omitted — \"Off\" is the UI affordance).\n * Default effort: medium (per models.json `default_reasoning_level`).\n *\n * Context window: 272_000 for all 5 models (per models.json).\n *\n * Excluded: `codex-auto-review` (visibility:\"hide\" — internal model).\n */\n\nimport type { ModelDescriptor } from '@shipyard/loro-schema';\n\nimport { CODEX_PRICING_SEED } from '../../billing/codex-cost-estimator.js';\n\nfunction pricingFor(modelId: string): ModelDescriptor['pricing'] | undefined {\n const seed = CODEX_PRICING_SEED[modelId];\n if (!seed) return undefined;\n /**\n * The estimator's `source` enum is `'openai-pricing-page' | 'placeholder'`;\n * the schema's enum is `'openai-pricing-page' | 'anthropic-pricing-page' |\n * 'inferred-promo'`. Map `placeholder` → `inferred-promo` because the\n * descriptor doesn't have a placeholder variant and `inferred-promo`\n * communicates the same \"verify before relying on this\" intent. The\n * estimator's own staleness-warning is what production should rely on;\n * this descriptor field is informational.\n */\n return {\n inputUsdPerMtok: seed.inputUsdPerMtok,\n cachedInputUsdPerMtok: seed.cachedInputUsdPerMtok,\n outputUsdPerMtok: seed.outputUsdPerMtok,\n effectiveAsOf: seed.effectiveAsOf,\n source: seed.source === 'openai-pricing-page' ? 'openai-pricing-page' : 'inferred-promo',\n };\n}\n\n/**\n * Display-cost helper mirroring `pricingFor`, but flattens to the panel's\n * `costInputUsd` / `costOutputUsd` pair. Returns `undefined` for both when\n * no seed exists so the browser falls through to the legacy FALLBACK_META.\n */\nfunction displayCostFor(modelId: string): { costInputUsd?: number; costOutputUsd?: number } {\n const seed = CODEX_PRICING_SEED[modelId];\n if (!seed) return {};\n return {\n costInputUsd: seed.inputUsdPerMtok,\n costOutputUsd: seed.outputUsdPerMtok,\n };\n}\n\nexport const CODEX_MODEL_CATALOG: ModelDescriptor[] = [\n {\n id: 'gpt-5.5',\n nativeName: 'gpt-5.5',\n displayName: 'GPT-5.5',\n description: 'OpenAI Codex — frontier model for complex coding, research, and real-world work.',\n contextWindow: 272_000,\n supportedEfforts: ['low', 'medium', 'high', 'xhigh'],\n defaultEffort: 'medium',\n pricing: pricingFor('gpt-5.5'),\n tagline: 'Frontier OpenAI Codex — complex coding, research, real-world work',\n speedTier: 'standard',\n ...displayCostFor('gpt-5.5'),\n capabilities: {\n reasoning: true,\n adaptiveThinking: false,\n webSearch: false,\n vision: true,\n },\n },\n {\n id: 'gpt-5.4',\n nativeName: 'gpt-5.4',\n displayName: 'GPT-5.4',\n description: 'OpenAI Codex — GPT-5.4 model.',\n contextWindow: 272_000,\n supportedEfforts: ['low', 'medium', 'high', 'xhigh'],\n defaultEffort: 'medium',\n pricing: pricingFor('gpt-5.4'),\n tagline: 'OpenAI Codex GPT-5.4',\n speedTier: 'standard',\n ...displayCostFor('gpt-5.4'),\n capabilities: {\n reasoning: true,\n adaptiveThinking: false,\n webSearch: false,\n vision: true,\n },\n },\n {\n id: 'gpt-5.4-mini',\n nativeName: 'gpt-5.4-mini',\n displayName: 'GPT-5.4-Mini',\n description: 'OpenAI Codex — smaller / faster GPT-5.4 variant.',\n contextWindow: 272_000,\n supportedEfforts: ['low', 'medium', 'high', 'xhigh'],\n defaultEffort: 'medium',\n pricing: pricingFor('gpt-5.4-mini'),\n tagline: 'OpenAI Codex — smaller, faster GPT-5.4 variant',\n speedTier: 'fast',\n ...displayCostFor('gpt-5.4-mini'),\n capabilities: {\n reasoning: true,\n adaptiveThinking: false,\n webSearch: false,\n vision: true,\n },\n },\n {\n id: 'gpt-5.3-codex',\n nativeName: 'gpt-5.3-codex',\n displayName: 'GPT-5.3-Codex',\n description: 'OpenAI Codex — GPT-5.3 Codex model.',\n contextWindow: 272_000,\n supportedEfforts: ['low', 'medium', 'high', 'xhigh'],\n defaultEffort: 'medium',\n pricing: pricingFor('gpt-5.3-codex'),\n tagline: 'OpenAI Codex GPT-5.3',\n speedTier: 'standard',\n ...displayCostFor('gpt-5.3-codex'),\n capabilities: {\n reasoning: true,\n adaptiveThinking: false,\n webSearch: false,\n vision: true,\n },\n },\n {\n id: 'gpt-5.2',\n nativeName: 'gpt-5.2',\n displayName: 'GPT-5.2',\n description: 'OpenAI Codex — GPT-5.2 model.',\n contextWindow: 272_000,\n supportedEfforts: ['low', 'medium', 'high', 'xhigh'],\n defaultEffort: 'medium',\n pricing: pricingFor('gpt-5.2'),\n tagline: 'OpenAI Codex GPT-5.2',\n speedTier: 'standard',\n ...displayCostFor('gpt-5.2'),\n capabilities: {\n reasoning: true,\n adaptiveThinking: false,\n webSearch: false,\n vision: true,\n },\n },\n];\n","/**\n * Cursor profile — S3 of the cursor-integration-plan-v2 lane.\n *\n * Brings up `cursorProfile` as the third registered `AgentCapabilityProfile`.\n * Mirrors the codex profile shape (c7 form): every field on\n * `AgentCapabilityProfile<ContentBlock, AgentSubprocess>` is populated.\n *\n * What \"bound\" means here:\n * - `spawn.binaryResolver` returns `process.execPath` — the runner is a\n * forked Node child, not a native binary. `args` returns the runner\n * module path so `child_process.fork(execPath, [runnerPath])` works.\n * - Transport closures (`outboundEncoder`, `inboundDecoder`, `correlator`,\n * `notificationDispatcher`) are stub no-ops: the actual IPC is the Node\n * `process.send` channel managed by `cursor-subprocess.ts`. The\n * `framing: 'sdk-iterator'` tag carries the semantics; these closures\n * exist only to satisfy the contract.\n * - `contentTranslator`/`eventTranslator` delegate to the S2 modules.\n * - `permissionFlow.notificationHandler` is a no-op log slot — the real\n * roundtrip is resolved by `PermissionHandler.handleCursorPermissionResponse`\n * after the user responds via the cursor-hook-socket path.\n * - `permissionModeMap` IS authoritative — pure function mapping\n * Shipyard's `PermissionMode` onto Cursor's hook-level allow/deny gate.\n * - `todoSource.translateToTaskOverlay` throws (matches Codex's\n * symmetric stub); the real dispatch lands in S5a via\n * `TaskManager.applyShipyardPlanUpdate`.\n *\n * Auth wiring caveat: `resolveAuthCredentials` and `authDetector` both\n * require a `CursorVaultDeps` (vault + env). The static profile module\n * cannot import the daemon's per-instance `CredentialsVault` directly\n * without a circular dep. We expose a module-level\n * `_setCursorVaultDeps(deps)` hook that S4 (profile registry wiring)\n * calls during boot to inject the live vault. Until injection, both\n * closures fall back to env-only resolution — sufficient for boot-time\n * `detectCapabilities` against `CURSOR_API_KEY` and never silently\n * masks a vault-stored key (env miss falls through to \"not-detected\"\n * and the UI prompts the user to paste).\n *\n * Out of scope for S3 (per v2 plan §5.9 + non-goals):\n * - Live model switch beyond the IPC stub (`set_model` is no-op v1).\n * - Pre-warm pool integration (`prewarmable = false`).\n * - Skills filter (`skillsMechanism = null` — A#23).\n * - Tool denylist applicator (`null` — no per-thread mechanism).\n *\n * Plan mode wiring (R1 spec): hooks.json deny-writes policy + skill-body\n * conditional + createPlan interception in cursor-event-translator.ts.\n * `canPlanMode: true` — synthesized via .cursor/hooks.json preToolUse deny\n * rules since SDK 1.0.13 lacks a native `mode` field. See\n * docs/cursor-implementation-specs/r1-plan-mode.md.\n *\n * Trust posture: this profile is loaded inside the daemon process. The\n * `spawn` fields are read by the serve-factory cursor branch (S4) which\n * trusts the daemon-supplied runner path. The cursor api key is plumbed\n * by `serve-factory.ts` directly into `CursorSubprocessOptions` via the\n * registry-level auth resolution — this profile does not handle secrets\n * inline beyond returning the `ResolvedAuth` envelope.\n */\n\nimport { fileURLToPath } from 'node:url';\n\nimport type {\n AgentAuthDetectionResult,\n AgentCapabilityProfile,\n ContentBlock,\n ResolvedAuth,\n RewindTarget,\n PermissionMode as SchemaPermissionMode,\n SpawnArgs,\n SpawnContext,\n TaskOverlay,\n} from '@shipyard/loro-schema';\nimport { AGENT_SYSTEM_CURSOR } from '@shipyard/loro-schema';\n\nimport { cursorAuthDetect } from '../../../shared/capabilities/cursor-auth-detect.js';\nimport { logger } from '../../../shared/logger.js';\nimport type { AgentSubprocess } from '../agent-subprocess.js';\nimport { type CursorVaultDeps, resolveCursorCredentials } from '../cursor-auth.js';\nimport { buildCursorUserPrompt } from '../cursor-content-builder.js';\nimport { classifyCursorError } from '../cursor-error-mapper.js';\nimport { CURSOR_MODEL_CATALOG } from './cursor-model-catalog.js';\n\n/**\n * Stub used for profile fields whose primary path lives on the subprocess\n * class, not the profile contract. Calling one of these is a programming\n * error — the field exists for contract symmetry with other profiles but\n * has a different chokepoint (e.g., `cursor-subprocess.ts` owns the\n * long-lived translator ctx that production translation requires).\n */\nfunction notYetWired(fieldName: string): never {\n throw new Error(\n `cursorProfile.${fieldName}: profile field not wired — production path lives in cursor-subprocess.ts. ` +\n 'See `cursor-event-translator.ts` for the translator API and `CursorAgentSubprocess` for the ctx owner.'\n );\n}\n\n/**\n * Resolves the absolute path to the compiled runner JS that\n * `child_process.fork` invokes. Mirrors the resolution in\n * `cursor-subprocess.ts` so the spawn args agree with the actual fork site.\n *\n * tsup emits the runner as a sibling of the daemon entry at\n * `dist/cursor-runner.js` (object-form entry config). After bundling this\n * module's code lives in the daemon entry chunk at the dist root, so the\n * runner is a sibling of `import.meta.url`. Match the sibling pattern used\n * by every other bundled-subprocess resolver (`cursor-subprocess.ts`,\n * `detector-runner/runner.ts`, `subprocess-memory.ts`).\n */\nfunction resolveRunnerPath(): string {\n return fileURLToPath(new URL('./cursor-runner.js', import.meta.url));\n}\n\n/**\n * Injected vault dependency. The profile module cannot import the daemon's\n * `CredentialsVault` directly without inverting the dep direction; instead\n * the registry-wiring lane (S4) calls `_setCursorVaultDeps({ vault, env })`\n * during boot. Until then, auth resolution falls back to env-only.\n *\n * Test-only: `_resetCursorVaultDepsForTests()` resets the binding.\n */\nlet cursorVaultDeps: CursorVaultDeps | null = null;\n\n/**\n * Wire the live vault into the static profile module. Called once during\n * daemon boot from the profile-registry init path (S4). Subsequent calls\n * overwrite the binding (test ergonomics — production never calls twice).\n */\nexport function _setCursorVaultDeps(deps: CursorVaultDeps): void {\n cursorVaultDeps = deps;\n}\n\n/** Test-only: clear the injected vault binding. */\nexport function _resetCursorVaultDepsForTests(): void {\n cursorVaultDeps = null;\n}\n\n/**\n * Encrypt and persist an API key to the credentials vault under the\n * canonical `'cursor:api-key'` key. Called by the daemon's\n * `onCursorLoginRequest` handler (S5b) after client-side prefix validation.\n *\n * Returns silently when the vault write function has not yet been injected\n * (boot hasn't finished). The daemon handler should treat this as a vault\n * unavailability error and broadcast a failed status.\n */\nexport async function writeCursorApiKeyToVault(apiKey: string): Promise<void> {\n const deps = cursorVaultDeps;\n if (!deps?.vault.set) {\n throw new Error('cursor vault not yet wired — vault.set unavailable');\n }\n await deps.vault.set('cursor', 'api-key', apiKey);\n}\n\n/**\n * Build the `CursorVaultDeps` actually used for resolution. Falls back to\n * a no-vault stub when `_setCursorVaultDeps` has not been called — env\n * resolution then handles `CURSOR_API_KEY`.\n */\nfunction getEffectiveVaultDeps(): CursorVaultDeps {\n if (cursorVaultDeps !== null) return cursorVaultDeps;\n return {\n vault: {\n /** No-op shim — `null` means \"no vault entry\", env path takes over. */\n get: async () => null,\n },\n env: process.env,\n };\n}\n\n/**\n * Pure mapper: Shipyard `PermissionMode` → native Cursor approval policy.\n *\n * Cursor enforces permissions via `.cursor/hooks.json` files, not a\n * runtime API. The two variants are:\n * - `cursor-hook-allow` → permissive hooks (Shell/Write/Read allowed)\n * - `cursor-hook-deny-writes` → plan-mode hooks (Read allowed; Write/Shell denied)\n *\n * Authoritative for S3. The actual hook-file rewriting is owned by\n * `cursor-skill-writer.ts` and the runner; this map only decides which\n * shape to write.\n *\n * - `'default'` → cursor-hook-allow\n * - `'accept-edits'` → cursor-hook-allow (Cursor has no shell-vs-edit split)\n * - `'plan'` → cursor-hook-deny-writes (research-only)\n * - `'bypass'` → cursor-hook-allow (no destructive variant in v1)\n * - `'auto'` → cursor-hook-allow (guardian wiring deferred)\n */\nfunction cursorPermissionModeMap(\n mode: SchemaPermissionMode\n): ReturnType<AgentCapabilityProfile['permissionModeMap']> {\n switch (mode) {\n case 'default':\n return { kind: 'cursor-hook-allow' };\n case 'accept-edits':\n return { kind: 'cursor-hook-allow' };\n case 'plan':\n return { kind: 'cursor-hook-deny-writes' };\n case 'bypass':\n return { kind: 'cursor-hook-allow' };\n case 'auto':\n return { kind: 'cursor-hook-allow' };\n default: {\n const _exhaustive: never = mode;\n return _exhaustive;\n }\n }\n}\n\n/**\n * Adapt the S2 `resolveCursorCredentials` shape ({ apiKey, source }) into\n * the profile contract's `ResolvedAuth` envelope.\n *\n * Method id is validated against Cursor's single supported method ('api-key').\n * Unknown method ids return null so a registry-level lookup doesn't bind\n * stale credentials to a profile that never advertised them.\n */\nasync function resolveCursorAuthCredentials(methodId: string): Promise<ResolvedAuth | null> {\n if (methodId !== 'api-key') return null;\n const creds = await resolveCursorCredentials(getEffectiveVaultDeps());\n if (!creds) return null;\n return {\n method: 'api-key',\n details: { apiKey: creds.apiKey, source: creds.source },\n };\n}\n\n/**\n * Refresh-time auth probe — delegates to `cursorAuthDetect`. Cursor has\n * only one auth method so the `methodHint` is accepted but ignored.\n */\nfunction cursorAuthDetectorBinding(methodHint?: string): Promise<AgentAuthDetectionResult> {\n return cursorAuthDetect(methodHint, getEffectiveVaultDeps());\n}\n\nexport const cursorProfile: AgentCapabilityProfile<ContentBlock, AgentSubprocess> = {\n id: AGENT_SYSTEM_CURSOR,\n displayName: 'Cursor',\n iconRef: {\n kind: 'svg-component',\n component: 'CursorIcon',\n /** Cursor brand black — revisit when brand assets land. */\n color: '#0F0F0F',\n },\n capabilityBadges: [\n {\n label: 'BYOK',\n tooltip: 'Bring your own Cursor API key',\n variant: 'info',\n },\n ],\n onboardingCopy: {\n emptyStateHeading: 'Spawn Cursor agents on your machine.',\n installInstructions:\n 'Cursor ships bundled with Shipyard. Add a Cursor API key to start spawning agents.',\n authPromptHelp:\n 'Paste your Cursor API key (format: `crsr_…`). Your key never leaves this device — it stays encrypted in the local Shipyard credentials vault. Generate one at https://cursor.com/dashboard/integrations.',\n capabilityCaveats: ['MCP server changes require restarting the Cursor agent.'],\n },\n capabilities: {\n canStreamTextDelta: true,\n canStreamReasoningDelta: true,\n canRewindByMessage: false,\n canPlanMode: true,\n canBackgroundExec: false,\n canMidSessionMcpReload: false,\n canCwdHookObserve: false,\n canPersistFullCompactionMetadata: false,\n canSubagent: true,\n canMcpOauth: false,\n windowOccupancyReporting: 'cumulative-fallback',\n },\n\n /**\n * Rewind contract — Cursor's only native rollback primitive is \"respawn\n * fresh.\" The FSM owns the truncation + UI side; this profile declares\n * `supports: {'fresh'}` and returns null from `toSpawnOptions` so the\n * dispatch falls through to the respawn path. No `applyLive` — there is\n * no live-rollback API in `@cursor/sdk@1.0.13`.\n */\n rewind: {\n supports: new Set<RewindTarget['kind']>(['fresh']),\n toSpawnOptions(_target: RewindTarget) {\n return null;\n },\n },\n\n /**\n * Spawn contract — drives `CursorAgentSubprocess` (Option B: forked\n * Node child running `cursor-runner.js`). `binaryResolver` returns\n * `process.execPath` (the daemon's own Node binary); `args` returns\n * the absolute runner path so `fork(execPath, [runnerPath])` resolves.\n * The runner receives its init payload over the IPC channel, not argv\n * or env — keeping the spawn surface minimal.\n */\n spawn: {\n binaryResolver: () => Promise.resolve(process.execPath),\n args: (_ctx: SpawnContext) => [resolveRunnerPath()],\n envInject: (_ctx: SpawnContext) => ({}),\n envStrip: [],\n },\n\n /**\n * Transport contract — the cursor runner uses the Node IPC channel\n * (`process.send` / `child.on('message', ...)`) rather than stdio\n * line-framing or a JSON-RPC correlator. The contract still requires\n * these slots, so we declare `framing: 'sdk-iterator'` (the closest\n * semantic match) and provide no-op closures. The real IPC code lives\n * in `cursor-subprocess.ts`.\n */\n transport: {\n framing: 'sdk-iterator',\n /** In-process IPC bypass — see cursor-subprocess.ts. */\n outboundEncoder: (req: unknown) => JSON.stringify(req),\n /** In-process IPC bypass — see cursor-subprocess.ts. */\n inboundDecoder: (line: string) => JSON.parse(line),\n /** In-process IPC bypass — Node IPC has no JSON-RPC correlation. */\n correlator: {\n register: () => {},\n resolve: () => {},\n reject: () => {},\n },\n /** In-process IPC bypass — see cursor-subprocess.ts. */\n notificationDispatcher: () => {},\n },\n\n /**\n * Reconnect — Cursor's SDK does not expose a server-side history-fetch\n * RPC; on resume the daemon replays its locally-persisted history\n * (`replay-on-resume`).\n */\n reconnect: {\n kind: 'replay-on-resume',\n },\n\n memoryContract: {\n /** Runner is a Node child — honors NODE_OPTIONS. */\n honorsNodeOptions: true,\n /** Linux/macOS SIGKILL (9) is the canonical OOM signal for forked Node. */\n oomSignalsByPlatform: {\n darwin: [9],\n linux: [9],\n },\n },\n\n /** Cursor v1 does not support pre-warming. */\n prewarmable: false,\n\n contentTranslator: {\n /**\n * Logger no-op at the profile level — call sites that need diagnostic\n * output (the daemon adapter, the runner's per-frame translator) pass\n * their own log sink.\n */\n toNativeUserInput: (blocks: ContentBlock[]) => buildCursorUserPrompt(blocks, () => {}),\n /**\n * Cursor's assistant content flows through the per-frame\n * `translateCursorSdkMessage` path (see `eventTranslator.translate`),\n * not a bulk content array. Return `[]` so any caller that hits this\n * fallback gets an empty (rather than wrong) result.\n */\n fromNativeAssistantContent: () => [],\n },\n\n /**\n * Event translator — unwired by design. The production translation path\n * is `cursor-subprocess.ts`, which owns a long-lived `CursorTranslatorCtx`\n * across the run for text/thinking accumulation, dedup, and plan-mode\n * state. Calling `translateCursorSdkMessage` here with a per-message ctx\n * would silently drop streamed text (buffered, never flushed) and break\n * tool-call dedup. `notYetWired` so any future caller fails fast instead\n * of corrupting state. `synthesizeInit` returns a `noop` because the\n * cursor subprocess synthesizes `init_received` in-flight from the\n * `init_ok` IPC message.\n */\n eventTranslator: {\n translate: () => {\n notYetWired('eventTranslator.translate');\n },\n synthesizeInit: async () => ({ type: 'noop' }),\n },\n\n models: CURSOR_MODEL_CATALOG,\n\n thinkingDescriptor: {\n shape: 'claude-adaptive',\n defaultDisplay: 'auto',\n },\n\n /**\n * Cursor permission flow — wire-type strings are authoritative.\n *\n * The per-tool gating round-trip lives on `CursorAgentSubprocess` via the\n * `.cursor/hooks.json` `preToolUse` hook + the daemon-owned\n * cursor-hook-socket. The SDK spawns `cursor-hook-shim`, which connects\n * to the per-task socket, HMAC-authenticates, and blocks on a reply. The\n * daemon resolves the reply via `PermissionHandler.handleCursorPermissionResponse`\n * after the user clicks Allow/Deny on the existing `permission_request_cursor`\n * card. The shim copies the reply JSON to its stdout for the SDK to\n * consume per its hook contract.\n *\n * `notificationHandler` here is a no-op log slot — the real roundtrip\n * is the socket path described above, NOT this profile-level callback.\n * Same pattern as codex-profile.ts where per-task daemon state lives on\n * the subprocess rather than the profile.\n */\n permissionFlow: {\n kind: 'notification-roundtrip',\n notificationHandler: async (_req, ctx) => {\n logger.info(\n {\n event: 'cursor_permission_flow_legacy_callback_hit',\n taskId: ctx.taskId,\n reason:\n 'Real roundtrip lives on the cursor-hook-socket + ' +\n 'PermissionHandler.createCursorPermissionRequest; ' +\n 'this profile-level callback is a no-op contract slot.',\n },\n 'cursor_permission_flow_legacy_callback_hit'\n );\n },\n requestMessageType: 'permission_request_cursor',\n responseMessageType: 'permission_response_cursor',\n },\n permissionModeMap: cursorPermissionModeMap,\n\n /** Cursor has no sandbox-extension flow (no permission widening protocol). */\n sandboxExtensionFlow: null,\n\n authMethods: [\n {\n id: 'api-key',\n displayName: 'Cursor API key',\n loginUx: 'api-key-paste',\n storageHint: 'Stored encrypted in the Shipyard credentials vault',\n requiresShell: false,\n },\n ],\n\n /**\n * Cursor login is a pure browser-side paste flow — the user pastes a\n * `crsr_…` key into the auth wizard which writes it to the credentials\n * vault. No native binary is invoked. The descriptor returned here\n * exists only to satisfy the contract; callers that hit it should\n * route to the wizard instead.\n */\n triggerLogin: async (_methodId): Promise<SpawnArgs> => {\n return {\n binary: process.execPath,\n argv: [],\n envInject: {},\n };\n },\n\n resolveAuthCredentials: resolveCursorAuthCredentials,\n\n /**\n * Refresh-time auth probe — wired through the module-level vault deps\n * setter (`_setCursorVaultDeps`). When the registry boot lane (S4) has\n * not yet injected the vault, falls back to env-only probing of\n * `CURSOR_API_KEY` which is sufficient for first-boot detection.\n */\n authDetector: cursorAuthDetectorBinding,\n\n /**\n * Cursor reports per-call cost via the SDK — but the SDK surface in\n * 1.0.13 does not expose a stable accessor for cost dollars at the\n * frame level. Set `reported` per v2 plan §5.8; the daemon's billing\n * pipeline reads cost off the runner's `run_complete` payload when\n * present and treats absence as null (no synthetic estimate).\n */\n costReporting: 'reported',\n costEstimator: null,\n tokenUsageFieldMap: {\n /**\n * Cursor SDK uses camelCase field names natively (`inputTokens`,\n * `cachedInputTokens`, `outputTokens`). The wire shape matches our\n * canonical `TokenUsage` 1:1 — no field translation needed at the\n * runner boundary.\n *\n * Cursor does not break out reasoning tokens or cache-creation\n * tokens; the optional fields on `TokenUsageFieldMap` are omitted.\n */\n inputTokens: 'inputTokens',\n cachedInputTokens: 'cachedInputTokens',\n outputTokens: 'outputTokens',\n },\n rateLimitShape: 'cursor',\n errorMapper: {\n classify: classifyCursorError,\n },\n\n subagentBackend: {\n /** Cursor's `task` tool spawns a sub-thread (matches Claude's Task tool). */\n spawnTool: 'task',\n /** Subagent progress lands as system messages on the parent stream. */\n progressSource: 'system-message',\n /** Final result is injected inline via XML wrapper (Claude shape). */\n resultDelivery: { kind: 'inline-xml-injection' },\n transcriptVisibility: 'inline',\n terminate: async (subagentId, _ctx) => {\n /**\n * `@cursor/sdk@1.0.13` exposes no targeted subagent-kill RPC. Log\n * and no-op — the subagent runs to completion and reports via the\n * normal result-delivery path.\n */\n logger.info(\n {\n event: 'cursor_subagent_terminate_noop',\n subagentId,\n reason: 'Cursor SDK has no targeted subagent-kill RPC at v1.0.13.',\n },\n 'cursor_subagent_terminate_noop'\n );\n },\n /** Matches Claude — child events tie back via `parentToolUseId`. */\n parentChildIdShape: 'parentToolUseId',\n },\n\n /**\n * Plan content source — reuses Claude/Codex's\n * `last-agent-message-in-plan-mode` shape so the persisted plan format\n * stays uniform. `extract` reads `lastProposedPlan` from the signal\n * (the translator ctx passed at turn-complete). The primary capture path\n * is `createPlan` tool interception in `cursor-event-translator.ts`;\n * the last-message accumulator is the fallback when the agent skips\n * `createPlan` and writes prose instead.\n */\n planContentSource: {\n kind: 'last-agent-message-in-plan-mode',\n triggerCriterion: 'on-turn-complete-in-plan-mode',\n extract: (signal: unknown): string | null => {\n if (typeof signal !== 'object' || signal === null) return null;\n const value: unknown = Reflect.get(signal, 'lastProposedPlan');\n if (typeof value !== 'string' || value.length === 0) return null;\n return value;\n },\n writePathTemplate: '~/.shipyard/plans/{taskId}.md',\n },\n\n /**\n * Todo source — Cursor emits todo updates via the harness-injected\n * `shipyard_update_plan` MCP tool (defined in S2 / task-server.ts).\n * The translator is intentionally stubbed: the real overlay dispatch\n * lives in S5a (`TaskManager.applyShipyardPlanUpdate`). Throws (not\n * empty-returns) to mirror Codex's symmetric stub at\n * `codex-profile.ts:982` — silent emptiness would let Cursor swallow\n * plan items while Codex throws.\n */\n todoSource: {\n kind: 'tool-event',\n toolOrItemName: 'shipyard_update_plan',\n translateToTaskOverlay: (): TaskOverlay => {\n throw new Error(\n 'cursorProfile.todoSource.translateToTaskOverlay: profile field not yet wired through dispatch — ' +\n 'real translation lives in S5a via TaskManager.applyShipyardPlanUpdate.'\n );\n },\n },\n\n /** Cursor's runner-owned cwd model means no observer hook. */\n cwdObserver: null,\n\n /**\n * Cursor compaction — the SDK emits a `preCompact` hook but the runner\n * does not observe it in v1. `startedEvent: null` because there is no\n * start signal; `completedEvent.matcher` always returns false so\n * nothing is ever counted as a completed compaction via this path.\n * Daemon-side compaction bookkeeping is a no-op for Cursor v1.\n */\n compactionSource: {\n startedEvent: null,\n completedEvent: {\n eventName: 'preCompact',\n matcher: () => false,\n },\n },\n\n /** Cursor has no per-thread tool denylist mechanism. */\n toolDenylistApplicator: null,\n\n mcpServerRegistration: {\n /**\n * Cursor reads MCP servers from the runner's `init` IPC payload —\n * not via an SDK option call at runtime. The closure is a no-op;\n * registration happens in `cursor-subprocess.ts` at spawn time.\n */\n kind: 'sdk-option',\n register: () => {},\n },\n\n /**\n * MCP auth idioms — Cursor 1.0.13 exposes no MCP-auth API\n * (`canMcpOauth: false`). The strings here match Claude's shape for\n * contract uniformity but are never reached at runtime.\n */\n mcpAuthIdioms: {\n authenticateMethod: '',\n submitCallbackMethod: '',\n },\n\n /**\n * Cursor has no SDK skills filter — A#23. Skill files are written via\n * the spawn flow (`cursor-skill-writer.ts`) but the SDK has no\n * `skills` option to narrow the set.\n */\n skillsMechanism: null,\n\n /**\n * System prompt fragments — Cursor-specific wording with tool-name\n * references substituted. `planMode` is injected by the harness prompt\n * builder when the task is in plan mode.\n */\n systemPromptFragments: {\n backgroundExecution:\n 'Cursor does not support background execution. Long-running Shell ' +\n 'commands block the current turn — keep them short or break work into ' +\n 'smaller steps so the user sees progress.',\n planMode:\n 'In plan mode Cursor runs read-only — `write`, `edit`, `delete`, ' +\n '`shell`, and `task` are blocked at the hook layer. Research the ' +\n 'codebase, propose a concrete plan as markdown, and emit it by ' +\n 'calling `createPlan({ plan: \"...\" })`. If you cannot call ' +\n '`createPlan`, put the plan as your final message and Shipyard ' +\n 'captures it from there. Wait for the user to approve before ' +\n 'attempting writes.',\n todoGuidance:\n 'Use the shipyard_update_plan MCP tool to keep the user-visible task ' +\n 'list in sync with your work. When starting, include any items already ' +\n 'visible in <task-list> using their exact subjects — then add your own ' +\n \"steps below them. Don't paraphrase template items or you'll create \" +\n 'duplicate sidebar entries. Update statuses (pending → in_progress → ' +\n 'completed) as you progress; call shipyard_update_plan whenever you ' +\n 'start, finish, or reorder a step. Use the task tool to spawn subagents ' +\n 'for parallel work — that is a separate concern.',\n toolReferences: {\n subagentSpawn: 'task',\n shellExec: 'Shell',\n fileEdit: 'Write',\n todoTool: 'shipyard_update_plan',\n },\n },\n\n cliResumeTemplate: 'cd \"{cwd}\" && cursor-agent --resume {sessionId}',\n /** Frontend recommendation (v2 plan F): share Claude's `/` sigil. */\n skillInvocationSigil: '/',\n\n metadata: {\n displayName: 'Cursor',\n vendor: 'Anysphere',\n cliCommand: 'cursor-agent',\n messageSigil: '/',\n postHogProviderId: 'cursor',\n /** `@cursor/sdk` ships bundled with the daemon — no separate install step. */\n installCommand: null,\n },\n\n /**\n * BYOK — no Shipyard-controlled billing identity for Cursor. The user's\n * Cursor API key is the billing identity; no managed-key headers.\n */\n billingIdentityHeaders: () => ({}),\n\n /**\n * Approximate Shipyard system-prompt overhead for Cursor, in tokens.\n * Used by the cross-agent bridge to subtract overhead from the context\n * window before computing the history budget. Cursor's prompt is shorter\n * than Claude's (~2000 chars / 4 ≈ 500 tokens as of 2026-05-25).\n */\n systemPromptOverheadTokens: 500,\n};\n","/**\n * Cursor auth status detector.\n *\n * Mirrors the `detectCodexAuth` shape — returns an `AgentAuthDetectionResult`\n * discriminated union so the `onRefreshAgentProviders` chokepoint can merge the\n * result into `runtimeAuth['cursor']` without special-casing Cursor.\n *\n * Detection is **presence-only** (no network call):\n * - `detected` — a key exists in vault or env AND passes the `crsr_` prefix check.\n * - `not-detected` — no key found anywhere, or found but fails the prefix check.\n * - `preserved` — vault threw (filesystem error, decryption failure); caller\n * keeps the last-known auth status to avoid flicker.\n *\n * `methodHint` is accepted for API symmetry with the Codex detector but is\n * ignored — Cursor has only one auth method (`api-key`).\n *\n * No subprocess shell-out; no JWT parsing; no clock-skew handling. The probe\n * runs on every capability refresh cycle and must stay fast and offline.\n *\n * ## Vault error semantics\n *\n * `cursorAuthDetect` distinguishes three outcomes from the vault path:\n * - `vault.get()` returns a non-null value → examine the key.\n * - `vault.get()` returns null / empty → miss, try env next.\n * - `vault.get()` throws → `preserved` (IO/decryption failure; don't clear\n * the last-known status and don't try env — an encrypted store that is\n * temporarily unreadable might still be populated).\n *\n * `resolveCursorCredentials` (in cursor-auth.ts) swallows vault errors and\n * falls through to env — the two functions serve different callers. The detect\n * function probes the vault directly before delegating to the shared resolver\n * so it can surface the throw as `preserved` rather than masking it.\n */\nexport { type CursorAuthDetectionResult, cursorAuthDetect };\n\nimport type { AgentAuthDetectionResult } from '@shipyard/loro-schema';\nimport type { CursorVaultDeps } from '../../services/session/cursor-auth.js';\nimport { logger } from '../logger.js';\n\n/**\n * Auth detection result specific to Cursor.\n *\n * Re-exported for callers that want the narrower type. The `auth` payload\n * shape conforms to `CursorAuthStatusSchema` (status, method, apiKeyHint)\n * so the `assignProfileAuth` chokepoint's Zod parse succeeds — without\n * that, the recomputed snapshot ships with `cursorAuth: undefined` and\n * the settings card shows \"Not signed in\" forever.\n */\ntype CursorAuthDetectionResult = AgentAuthDetectionResult;\n\nconst NOT_DETECTED: CursorAuthDetectionResult = {\n kind: 'not-detected',\n auth: { status: 'unauthenticated', method: 'none' },\n};\n\nconst CURSOR_KEY_PREFIX = 'crsr_';\n\nfunction isValidCursorKey(key: string): boolean {\n return key.startsWith(CURSOR_KEY_PREFIX);\n}\n\n/**\n * Build a `crsr_***xxxxx` style hint so the settings card can show\n * \"Signed in as crsr_***abcde\" without exposing the full secret. Same\n * shape as `formatApiKeyHint` in `codex-auth-detect.ts`.\n */\nfunction formatCursorKeyHint(key: string): string {\n if (key.length <= 13) return '***';\n return `${key.slice(0, 8)}***${key.slice(-5)}`;\n}\n\n/**\n * Detect Cursor auth status without a network call.\n *\n * @param _methodHint Ignored. Cursor has only one auth method. Accepted for\n * API symmetry with `detectCodexAuth`.\n * @param deps Vault + env access. Injected to keep the function\n * testable without global state.\n */\nasync function cursorAuthDetect(\n _methodHint: string | undefined,\n deps: CursorVaultDeps\n): Promise<CursorAuthDetectionResult> {\n const env = deps.env ?? process.env;\n\n let vaultResult: string | null;\n try {\n vaultResult = await deps.vault.get('cursor', 'api-key');\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.warn({ error: msg }, 'cursor auth detect — vault read failed, preserving status');\n return { kind: 'preserved', reason: `vault-read-failed: ${msg}` };\n }\n\n if (vaultResult !== null) {\n const trimmed = vaultResult.trim();\n if (trimmed.length > 0) {\n if (isValidCursorKey(trimmed)) {\n return {\n kind: 'detected',\n auth: {\n status: 'authenticated',\n method: 'api-key',\n apiKeyHint: formatCursorKeyHint(trimmed),\n /**\n * Cursor has no real account info. Use the last 4 chars of the\n * API key as a stable proxy for collision detection (Step 19).\n */\n accountId: trimmed.slice(-4),\n },\n };\n }\n /**\n * Key present but wrong format — treat as not-detected (log happens in\n * resolveCursorCredentials; silent here to avoid duplicate warnings).\n */\n return NOT_DETECTED;\n }\n }\n\n const envKey = (env.CURSOR_API_KEY ?? '').trim();\n if (envKey.length > 0 && isValidCursorKey(envKey)) {\n return {\n kind: 'detected',\n auth: {\n status: 'authenticated',\n method: 'api-key',\n apiKeyHint: formatCursorKeyHint(envKey),\n accountId: envKey.slice(-4),\n },\n };\n }\n\n return NOT_DETECTED;\n}\n","/**\n * Cursor credential resolver.\n *\n * `resolveCursorCredentials(deps)` is the daemon-side chokepoint for picking\n * up the API key the Cursor subprocess needs. Cursor supports only one auth\n * method (`api-key`), so the resolver is simpler than the Codex equivalent.\n *\n * Precedence:\n * 1. Shipyard credentials vault (`cursor:api-key` key, AES-256-GCM encrypted\n * at rest). The vault abstraction behind `deps.vault.get` handles\n * decryption — this module never sees the raw `CredentialRecord`.\n * 2. `CURSOR_API_KEY` environment variable.\n *\n * Both paths validate the `crsr_` prefix (Cursor's documented API-key format).\n * An invalid format is treated as absent so a misconfigured key doesn't silently\n * reach the subprocess. Returns null on miss, invalid format, or vault errors.\n *\n * No fallback chain across methods — Cursor has one auth method.\n * No network calls — format check only.\n */\nexport { type CursorCredentials, type CursorVaultDeps, resolveCursorCredentials };\n\nimport type { ResolvedAuth } from '@shipyard/loro-schema';\n\nimport { logger } from '../../shared/logger.js';\n\n/**\n * Resolved Cursor credentials returned to callers.\n *\n * `apiKey` is the raw `crsr_...` key. `source` identifies which path\n * supplied it so callers (and logs) can distinguish vault-stored vs env keys.\n */\ninterface CursorCredentials {\n apiKey: string;\n source: 'vault' | 'env';\n}\n\n/**\n * Dependency interface for vault access.\n *\n * The vault implementation (backed by `CredentialsVaultStore` + AES-256-GCM\n * decryption) is injected by the caller. Unit tests pass a minimal mock.\n *\n * `get(agent, methodId)` returns the decrypted plaintext key, or null when\n * the key is absent. Throws on decryption failure or filesystem error —\n * callers that need the `preserved` distinction (i.e. auth-detect) catch\n * the throw; `resolveCursorCredentials` itself returns null on error.\n */\ninterface CursorVaultDeps {\n vault: {\n get(agent: string, methodId: string): Promise<string | null>;\n /** Write an encrypted plaintext key to the vault. Optional — absent when vault is not yet wired. */\n set?(agent: string, methodId: string, value: string): Promise<void>;\n };\n env?: NodeJS.ProcessEnv;\n}\n\n/** Cursor API keys always start with this prefix. */\nconst CURSOR_KEY_PREFIX = 'crsr_';\n\n/**\n * Validate that `key` is a non-empty string starting with the `crsr_` prefix.\n *\n * A dedicated helper so the prefix check is applied consistently in both the\n * vault path and the env path — a single source of truth for the format rule.\n */\nfunction isValidCursorKey(key: string): boolean {\n return key.startsWith(CURSOR_KEY_PREFIX);\n}\n\n/**\n * Resolve Cursor credentials from the vault then the environment.\n *\n * Returns a `CursorCredentials` bag (suitable for wrapping into `ResolvedAuth`)\n * or null when no valid key is found.\n *\n * On vault read errors the error is swallowed and resolution falls through to\n * the env-var path — the auth-detect layer (`cursorAuthDetect`) handles the\n * `preserved` distinction for capability reporting.\n */\nasync function resolveCursorCredentials(deps: CursorVaultDeps): Promise<CursorCredentials | null> {\n const env = deps.env ?? process.env;\n\n try {\n const vaultKey = await deps.vault.get('cursor', 'api-key');\n if (vaultKey !== null) {\n const trimmed = vaultKey.trim();\n if (trimmed.length > 0) {\n if (!isValidCursorKey(trimmed)) {\n logger.warn(\n { source: 'vault', prefix: trimmed.slice(0, 8) },\n 'cursor vault key does not start with crsr_ — ignoring'\n );\n /** Fall through to env — a bad vault key should not block a valid env key. */\n } else {\n return { apiKey: trimmed, source: 'vault' };\n }\n }\n }\n } catch (err) {\n logger.warn(\n { error: err instanceof Error ? err.message : String(err) },\n 'cursor vault read failed — falling back to env'\n );\n }\n\n const envKey = (env.CURSOR_API_KEY ?? '').trim();\n if (envKey.length > 0) {\n if (!isValidCursorKey(envKey)) {\n logger.warn(\n { source: 'env', prefix: envKey.slice(0, 8) },\n 'CURSOR_API_KEY does not start with crsr_ — ignoring'\n );\n return null;\n }\n return { apiKey: envKey, source: 'env' };\n }\n\n return null;\n}\n\n/**\n * Convenience wrapper: resolves credentials and adapts them to `ResolvedAuth`.\n *\n * Used by `cursor-profile.ts` as the `resolveAuthCredentials` binding. Returns\n * null when no valid key is available.\n */\nasync function resolveCursorResolvedAuth(deps: CursorVaultDeps): Promise<ResolvedAuth | null> {\n const creds = await resolveCursorCredentials(deps);\n if (!creds) return null;\n return {\n method: 'api-key',\n details: { apiKey: creds.apiKey },\n };\n}\n\nexport { resolveCursorResolvedAuth };\n","/**\n * Cursor error mapper.\n *\n * Pure FC/IS module: classifies any thrown value from the Cursor SDK into a\n * canonical `MappedError` the daemon's session FSM can act on.\n *\n * Design invariants:\n * - No I/O. No async. No side effects.\n * - Every `CursorSdkError` subclass gets an explicit case.\n * - Billing detection uses substring matching on `error.code`.\n * - Unknown errors fall through to `sdk_error / unknown`.\n *\n * Billing code substrings matched (case-insensitive):\n * - 'payment_required'\n * - 'billing_'\n * - 'insufficient_credits'\n * - 'subscription_expired'\n * - 'plan_limit'\n *\n * These are conservative patterns chosen to avoid false positives on generic\n * API errors. They should be tightened or expanded once we observe real Cursor\n * billing error codes in production.\n *\n * Error hierarchy (from cursor-sdk-deep-dive §12):\n *\n * CursorSdkError\n * └─ CursorAgentError (backward-compat root)\n * ├─ AuthenticationError (401)\n * ├─ RateLimitError (429)\n * ├─ AgentBusyError (409)\n * ├─ NetworkError (503/504)\n * ├─ UnknownAgentError\n * └─ ConfigurationError (400/404)\n * └─ IntegrationNotConnectedError (helpUrl, provider)\n */\n\nimport type { MappedError } from '@shipyard/loro-schema';\n\n/**\n * Minimal interface matching `CursorSdkError`. We use duck-typing rather\n * than `instanceof` because the SDK is loaded by the forked `cursor-runner`\n * subprocess — the error objects arrive serialised over IPC as plain objects,\n * not live class instances. The runner reconstructs them with their `name`\n * field so we can still discriminate.\n */\ninterface CursorSdkErrorShape {\n name: string;\n message: string;\n isRetryable?: boolean;\n code?: string;\n status?: number;\n cause?: unknown;\n endpoint?: string;\n requestId?: string;\n operation?: string;\n}\n\ninterface IntegrationNotConnectedShape extends CursorSdkErrorShape {\n helpUrl?: string;\n provider?: string;\n}\n\n/**\n * Returns true when the error code substring indicates a billing / payment\n * problem. Intentionally conservative — we prefer false negatives (falls\n * through to `sdk_error`) over false positives (wrong error classification\n * that hides a real auth or rate-limit issue).\n *\n * Matched substrings (case-insensitive):\n * payment_required, billing_, insufficient_credits,\n * subscription_expired, plan_limit\n */\nfunction isBillingCode(code: string | undefined): boolean {\n if (!code) return false;\n const lower = code.toLowerCase();\n return (\n lower.includes('payment_required') ||\n lower.includes('billing_') ||\n lower.includes('insufficient_credits') ||\n lower.includes('subscription_expired') ||\n lower.includes('plan_limit')\n );\n}\n\nfunction isCursorSdkErrorShape(err: unknown): err is CursorSdkErrorShape {\n if (typeof err !== 'object' || err === null) return false;\n // eslint-disable-next-line no-restricted-syntax -- unknown -> Record<string,unknown> for duck-typed SDK error shape; validated by typeof checks immediately after\n const rec = err as Record<string, unknown>;\n return typeof rec.name === 'string' && typeof rec.message === 'string';\n}\n\n/**\n * Classify any thrown value from the Cursor SDK into a canonical `MappedError`.\n *\n * Pure function. No I/O, no async. Safe to call from within synchronous error\n * handlers.\n *\n * Error `name` values (from errors.d.ts class declarations):\n * AuthenticationError, RateLimitError, ConfigurationError,\n * AgentBusyError, IntegrationNotConnectedError, NetworkError,\n * UnknownAgentError, CursorAgentError, CursorSdkError\n */\nexport function classifyCursorError(err: unknown): MappedError {\n if (!isCursorSdkErrorShape(err)) {\n return {\n canonical: 'sdk_error',\n subkind: 'unknown',\n detail: String(err),\n };\n }\n\n const { name, message, code } = err;\n\n /**\n * Billing check runs first — a 402 might surface as AuthenticationError\n * on some paths; we prefer the billing classification.\n */\n if (isBillingCode(code)) {\n return {\n canonical: 'billing_error',\n detail: message,\n };\n }\n\n switch (name) {\n case 'AuthenticationError': {\n return { canonical: 'auth_not_logged_in' };\n }\n\n case 'RateLimitError': {\n /**\n * Attempt to extract a retry-after duration from the error's `cause`\n * or from a `retryAfter` property if the SDK adds one. This is\n * best-effort for v1 — we surface the rate_limit_error canonical even\n * when no retry-after time is available.\n */\n const retryAfterMs = extractRetryAfterMs(err);\n return {\n canonical: 'rate_limit_error',\n detail: message,\n ...(retryAfterMs !== null ? { retryAfterMs } : {}),\n };\n }\n\n case 'AgentBusyError': {\n return {\n canonical: 'sdk_error',\n subkind: 'busy',\n detail: message,\n };\n }\n\n case 'IntegrationNotConnectedError': {\n // eslint-disable-next-line no-restricted-syntax -- IntegrationNotConnectedShape is a local structural extension of CursorSdkErrorShape; duck-typed because errors arrive serialised over IPC\n const integration = err as IntegrationNotConnectedShape;\n const providerInfo = integration.provider ? ` (${integration.provider})` : '';\n const helpLink = integration.helpUrl ? ` — ${integration.helpUrl}` : '';\n return {\n canonical: 'sdk_error',\n subkind: 'integration-missing',\n detail: `${message}${providerInfo}${helpLink}`,\n };\n }\n\n case 'ConfigurationError': {\n return {\n canonical: 'sdk_error',\n subkind: 'config',\n detail: message,\n };\n }\n\n case 'NetworkError': {\n return {\n canonical: 'sdk_error',\n subkind: 'network',\n detail: message,\n };\n }\n\n case 'UnknownAgentError': {\n return {\n canonical: 'sdk_error',\n subkind: 'unknown',\n detail: message,\n };\n }\n\n default: {\n /**\n * Catch-all for `CursorAgentError`, `CursorSdkError`, and any future\n * subclass added after this file was written. We still honour the\n * billing check (done above) so novel error names don't hide payment\n * issues.\n */\n return {\n canonical: 'sdk_error',\n subkind: 'unknown',\n detail: message,\n };\n }\n }\n}\n\n/**\n * Parse a Retry-After header value (string seconds) into milliseconds.\n * Returns null on parse failure.\n */\nfunction parseRetryAfterHeader(value: string): number | null {\n const parsed = Number.parseFloat(value);\n return Number.isFinite(parsed) && parsed > 0 ? parsed * 1000 : null;\n}\n\n/**\n * Probe an HTTP-headers-like object for a Retry-After value.\n * Returns milliseconds or null.\n *\n * Hyphenated header names MUST use bracket notation — dot notation is a\n * syntax error. Biome's `useLiteralKeys` only applies when bracket notation\n * is used for valid identifier keys; hyphenated keys are exempt.\n */\nfunction extractRetryAfterFromHeaders(headers: Record<string, unknown>): number | null {\n const raw =\n headers['retry-after'] ?? headers['Retry-After'] ?? headers['x-ratelimit-reset-after'];\n return typeof raw === 'string' ? parseRetryAfterHeader(raw) : null;\n}\n\n/**\n * Best-effort extraction of a retry-after duration in milliseconds.\n *\n * The Cursor SDK doesn't document a `retryAfter` field on `RateLimitError`\n * in v1.0.13, but the `cause` may carry HTTP response headers with\n * `Retry-After` (seconds). We probe common shapes without throwing.\n */\nfunction extractRetryAfterMs(err: CursorSdkErrorShape): number | null {\n // eslint-disable-next-line no-restricted-syntax -- CursorSdkErrorShape -> Record<string,unknown> to probe optional future fields; all accesses guarded by typeof checks\n const asRecord = err as unknown as Record<string, unknown>;\n\n /** Direct retryAfterMs field (future SDK versions may add this) */\n if (typeof asRecord.retryAfterMs === 'number') {\n return asRecord.retryAfterMs;\n }\n if (typeof asRecord.retryAfter === 'number') {\n return asRecord.retryAfter * 1000;\n }\n\n if (err.cause !== null && err.cause !== undefined && typeof err.cause === 'object') {\n // eslint-disable-next-line no-restricted-syntax -- cause is typed as unknown; narrowed by typeof === \"object\" check above; Record<string,unknown> for headers probe\n const cause = err.cause as Record<string, unknown>;\n if (\n cause.headers !== null &&\n cause.headers !== undefined &&\n typeof cause.headers === 'object'\n ) {\n // eslint-disable-next-line no-restricted-syntax -- headers is typed as object; narrowing to Record<string,unknown> for header value probe\n return extractRetryAfterFromHeaders(cause.headers as Record<string, unknown>);\n }\n }\n\n return null;\n}\n","/**\n * Cursor model catalog.\n *\n * Source: https://cursor.com/docs/models/cursor-composer-2-5\n *\n * Only `composer-2.5` is exposed. Composer 2 is hidden by default in the\n * Cursor pricing table (effectively deprecated for new users), and\n * `composer-latest` is not listed anywhere in the Cursor docs — we\n * previously assumed it was an alias but the official model index does\n * not advertise it, so we drop it rather than ship something users may\n * not be able to invoke.\n *\n * ### Pricing (per million tokens, USD)\n *\n * - Standard: $0.5 in, $2.5 out (draws from the Auto + Composer pool)\n * - Fast Mode: $3 in, $15 out (faster variant, higher cost)\n *\n * `supportsFastMode: true` so the composer renders the Fast toggle.\n * `fastModePricing` carries the Fast Mode rates so the comparison panel\n * can swap the displayed pricing chip when the toggle is on.\n *\n * ### Capabilities\n *\n * - reasoning: false — composer-2.5 has Fast Mode but no reasoning-effort\n * control (verified against `cursor.com/docs/models/cursor-composer-2-5`).\n * `supportedEfforts: []` so the reasoning-effort strip stays hidden.\n * - vision / webSearch: docs don't explicitly confirm or deny — we set\n * `false` rather than guess. Update once verified against\n * `Cursor.models.list()` with a real key.\n *\n * ### contextWindow / maxOutput\n *\n * Cursor's docs don't publish either field. `contextWindow` stays at the\n * v1 best-guess of 200_000 (carried forward from the previous catalog so\n * the schema's required field stays populated). `maxOutput` omitted —\n * the panel falls back to \"—\" rather than rendering a wrong number.\n *\n * Once `Cursor.models.list()` is wired (cursor-sdk-deep-dive.md §12),\n * the open items here get authoritative answers.\n */\n\nimport type { ModelDescriptor } from '@shipyard/loro-schema';\n\nexport const CURSOR_MODEL_CATALOG: ModelDescriptor[] = [\n {\n id: 'composer-2.5',\n nativeName: 'composer-2.5',\n displayName: 'Composer 2.5',\n description: \"Cursor's frontier-level coding model, tuned for tool use and terminal operations\",\n contextWindow: 200_000,\n supportedEfforts: [],\n tagline: \"Cursor's house frontier model — tuned for tool use, file edits, terminal ops\",\n speedTier: 'standard',\n costInputUsd: 0.5,\n costOutputUsd: 2.5,\n supportsFastMode: true,\n fastModePricing: {\n costInputUsd: 3,\n costOutputUsd: 15,\n },\n capabilities: {\n reasoning: false,\n adaptiveThinking: false,\n webSearch: false,\n vision: false,\n },\n },\n];\n","/**\n * Profile registry — daemon-side lookup table mapping `AgentId` to its\n * `AgentCapabilityProfile`. Built in codex c2 as a no-behavior-change\n * dispatch chokepoint. Subsequent commits (c3: Claude retrofit; c7:\n * Codex wiring) fill in the heavy profile fields (translators, spawn\n * args, plan content source, etc.) on top of the entries registered\n * here.\n *\n * The registry is intentionally a simple in-memory map. It does not\n * persist across daemon restarts — every boot rebuilds it from the\n * code-side `claudeCodeProfile` (and, post-c7, `codexProfile`) modules.\n * That keeps the source of truth in source: the daemon and tests can\n * never disagree about which agents exist.\n *\n * Lookup is total: callers must pass a known `AgentId`. Unknown lookups\n * throw — there is no fallback profile because every callsite already\n * narrows on `AgentId` upstream (Zod-validated `ModelProvider`).\n */\n\nimport type { AgentCapabilityProfile, AgentId, ContentBlock } from '@shipyard/loro-schema';\n\nimport type { AgentSubprocess } from '../agent-subprocess.js';\n\nimport { claudeCodeProfile } from './claude-code-profile.js';\nimport { codexProfile } from './codex-profile.js';\nimport { cursorProfile } from './cursor-profile.js';\n\n/**\n * Full profile contract. c3 (Claude retrofit) populates every field on\n * `claudeCodeProfile`; c7 (Codex wiring) brings up `codexProfile`. The\n * earlier `Pick<...> & Partial<...>` shape was a c2 placeholder — now\n * tightened to the full `AgentCapabilityProfile<ContentBlock, AgentSubprocess>`\n * so the compiler enforces that every registered profile supplies every\n * slot.\n *\n * `TBlock` is bound to `ContentBlock` from `@shipyard/loro-schema` —\n * the canonical content-block shape used across the daemon. `TSubprocess`\n * is bound to the daemon-local `AgentSubprocess` so the `rewind.applyLive`\n * closure can take the concrete daemon-side interface without forcing\n * `loro-schema` to import daemon types. Adding a new field to\n * `AgentCapabilityProfile` will force every profile to implement it\n * before the daemon compiles.\n */\nexport type RegisteredProfile = AgentCapabilityProfile<ContentBlock, AgentSubprocess>;\n\nclass ProfileRegistry {\n readonly #profiles = new Map<AgentId, RegisteredProfile>();\n\n register(profile: RegisteredProfile): void {\n if (this.#profiles.has(profile.id)) {\n throw new Error(`Duplicate registration for agent profile ${profile.id}`);\n }\n this.#profiles.set(profile.id, profile);\n }\n\n get(id: AgentId): RegisteredProfile {\n const profile = this.#profiles.get(id);\n if (!profile) {\n throw new Error(\n `No profile registered for agent ${id}. ` +\n 'Did the boot path call registerBuiltInProfiles()?'\n );\n }\n return profile;\n }\n\n has(id: AgentId): boolean {\n return this.#profiles.has(id);\n }\n\n list(): RegisteredProfile[] {\n return Array.from(this.#profiles.values());\n }\n\n /**\n * Locate the profile whose `models` catalog contains the given model id.\n * Returns null when no registered profile claims the id — the spawn\n * router treats this as \"unknown provider\" and refuses to spawn rather\n * than silently routing to Claude (Phase B / PROTOCOL_VERSION 86).\n *\n * Lookup is linear in the number of registered profiles (≤ 2 today).\n * Worth keeping in this file so the registry remains the single\n * source of truth for \"which agent owns which model\".\n */\n findByModelId(modelId: string): RegisteredProfile | null {\n for (const profile of this.#profiles.values()) {\n if (profile.models.some((m) => m.id === modelId)) return profile;\n }\n return null;\n }\n\n reset(): void {\n this.#profiles.clear();\n }\n}\n\n/**\n * Process-singleton. Constructed lazily on first import. Tests that need\n * a clean slate call `profileRegistry.reset()` then re-register.\n *\n * The default-export style is intentional: every callsite imports the\n * same instance, so there's no risk of two registries diverging within\n * the same daemon process.\n */\nexport const profileRegistry = new ProfileRegistry();\n\n/**\n * Registers every built-in profile. Called once at daemon boot before\n * any task starts. Both Claude and Codex profiles are ALWAYS registered\n * — registration is just metadata exposure (the `profile_snapshot`\n * wire message carries `binaryAvailable` so the browser onboarding card\n * can show install-vs-login). Codex ships bundled with the daemon\n * (`@openai/codex` is a daemon dep), so spawn is unconditional once a\n * task's `agentId` resolves to the codex profile.\n *\n * Idempotent: safe to call twice in the same process — second call\n * resets first to keep test-and-prod boot paths symmetric. (The\n * underlying `register()` throws on duplicates; we reset first.)\n */\nexport function registerBuiltInProfiles(): void {\n profileRegistry.reset();\n profileRegistry.register(claudeCodeProfile);\n profileRegistry.register(codexProfile);\n profileRegistry.register(cursorProfile);\n}\n","import { readFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { AnthropicAuthMethod, CodexAuthMethod } from '@shipyard/loro-schema';\nimport {\n type AnthropicAuthStatus,\n type CodexAuthStatus,\n type InstalledAgent,\n type MachineCapabilities,\n PermissionModeSchema,\n} from '@shipyard/session';\nimport { z } from 'zod';\nimport { logger } from '../logger.js';\nimport { bootstrapPhase, logInFlightPhasesAsKilled } from '../observability/bootstrap-phase.js';\nimport { withLabelAsync } from '../observability/watchdog-context.js';\nimport { detectAgentProviders } from './agents.js';\nimport { type AuthDetectionResult, detectAnthropicAuth } from './auth.js';\nimport { detectCodexAuth } from './codex-auth-detect.js';\nimport { detectCommonDirs } from './common-dirs.js';\nimport {\n DEFAULT_DETECTOR_TIMEOUT_MS,\n ENVIRONMENT_DETECTOR_TIMEOUT_MS,\n withDetectorTimeout,\n} from './detector-timeout.js';\nimport { classifyEnvMismatch } from './env-mismatch.js';\nimport { detectEnvironments } from './git-repo.js';\nimport { detectGraphite } from './graphite-detect.js';\nimport { detectMarketplacePlugins } from './marketplace.js';\nimport { detectMCPServers } from './mcp-servers.js';\nimport { detectModels } from './models.js';\nimport { buildRuntimeAuthMapFromSnapshot as buildRuntimeAuthMap } from './runtime/auth-adapters.js';\nimport { CLAUDE_CODE_RUNTIME_ID } from './runtime/catalog.js';\nimport { detectSkills } from './skills.js';\n\nexport { detectAgentProviders } from './agents.js';\nexport { detectAnthropicAuth } from './auth.js';\nexport { detectCodexAuth } from './codex-auth-detect.js';\nexport {\n getConfiguredEnvironments,\n getLatestDeployments,\n getRequiredChecks,\n getWorkflowRuns,\n rerunChecks,\n} from './git-ci.js';\nexport {\n captureTreeSnapshot,\n fetchRemoteBranch,\n findRenames,\n getBranchDiff,\n getBranchFiles,\n getChangedFiles,\n getDefaultBranch,\n getFileAtRef,\n getGitRefExists,\n getMergeBase,\n getSnapshotDiff,\n getSnapshotFiles,\n getStackDiff,\n getStackFiles,\n getStagedDiff,\n getUnstagedDiff,\n} from './git-diff.js';\nexport {\n addAssignees,\n addLabels,\n addReviewers,\n appendShipyardBodyMarker,\n approvePR,\n buildShipyardBodyMarker,\n closePR,\n commentOnPR,\n convertToDraft,\n deduplicatePRs,\n ensureLabel,\n getAssignedReviews,\n getPRByBranch,\n getPRDiff,\n getPRFiles,\n getPRForCurrentBranch,\n getPRReviewComments,\n getUserPRs,\n mapGhPRToPRData,\n markPRReady,\n mergePR,\n removeAssignees,\n removeLabels,\n reopenPR,\n replyToReviewComment,\n requestChanges,\n resolveReviewThread,\n unresolveReviewThread,\n} from './git-pr.js';\nexport {\n detectEnvironments,\n findGitRepos,\n getGitTopLevel,\n getRepoMetadata,\n isAncestor,\n isGhAvailable,\n parseOwnerRepo,\n} from './git-repo.js';\nexport { detectMarketplacePlugins } from './marketplace.js';\nexport { detectMCPServers, redactArgs, redactEnv } from './mcp-servers.js';\nexport { detectModels } from './models.js';\nexport {\n addWorktreeToCache,\n invalidateRepoPaths,\n removeWorktreeFromCache,\n} from './repo-paths-cache.js';\nexport {\n buildRuntimeAuthMapFromSnapshot as buildRuntimeAuthMap,\n PROFILE_AUTH_ADAPTERS,\n type ProfileAuthAdapter,\n snapshotProfileAuth,\n} from './runtime/auth-adapters.js';\nexport { getRuntimeDescriptor } from './runtime/catalog.js';\nexport { detectSkills } from './skills.js';\n\nconst AutoModeConfigSchema = z\n .object({\n cachedGrowthBookFeatures: z\n .object({ tengu_auto_mode_config: z.object({ enabled: z.string() }) })\n .passthrough(),\n })\n .passthrough();\n\nasync function detectAutoModeEnabled(): Promise<boolean> {\n try {\n const claudeConfig = await readFile(join(homedir(), '.claude.json'), 'utf-8');\n const result = AutoModeConfigSchema.safeParse(JSON.parse(claudeConfig));\n return (\n result.success &&\n result.data.cachedGrowthBookFeatures.tengu_auto_mode_config.enabled === 'enabled'\n );\n } catch {\n return false;\n }\n}\n\nconst UNKNOWN_AUTH: AnthropicAuthStatus = { status: 'unknown', method: 'none' };\nconst UNKNOWN_CODEX_AUTH: CodexAuthStatus = { status: 'unknown', method: 'none' };\n\nfunction resolveAnthropicAuth(\n result: Awaited<ReturnType<typeof detectAnthropicAuth>>,\n lastKnown: AnthropicAuthStatus | undefined\n): AnthropicAuthStatus {\n if (result.kind === 'preserved') return lastKnown ?? UNKNOWN_AUTH;\n return result.auth;\n}\n\nfunction resolveCodexAuth(\n result: Awaited<ReturnType<typeof detectCodexAuth>>,\n lastKnown: CodexAuthStatus | undefined\n): CodexAuthStatus {\n if (result.kind === 'preserved') return lastKnown ?? UNKNOWN_CODEX_AUTH;\n return result.auth;\n}\n\n/**\n * Pick the slices `detectCapabilities` consults as `lastKnownCapabilities`\n * fallbacks. Centralized so the 5 call sites all pass the same shape and a\n * future detector addition only needs to land here, not in every caller.\n */\nexport function pickLastKnownCapabilities(\n caps: MachineCapabilities | undefined\n):\n | Pick<\n MachineCapabilities,\n 'models' | 'environments' | 'mcpServers' | 'skills' | 'marketplacePlugins' | 'usesGraphite'\n >\n | undefined {\n if (!caps) return undefined;\n return {\n models: caps.models,\n environments: caps.environments,\n mcpServers: caps.mcpServers,\n skills: caps.skills,\n marketplacePlugins: caps.marketplacePlugins,\n usesGraphite: caps.usesGraphite,\n };\n}\n\nexport async function detectCapabilities(\n tokenStore: import('../mcp/token-store.js').MCPTokenStore | undefined,\n methodHint: AnthropicAuthStatus['method'] | undefined,\n lastKnownAuth: AnthropicAuthStatus | undefined,\n lastKnownAgents?: InstalledAgent[],\n /**\n * Defense in depth — preserve previously-detected slices when their\n * detector hits a transient subprocess/IO failure that would otherwise\n * collapse the slice to `[]`. Each slice is preserved independently.\n * The `lastKnownAgents` arg is kept as a separate param for backwards\n * compatibility with the existing call sites; this object covers the\n * other four detectors (`models`, `environments`, `mcpServers`,\n * `skills`, `marketplacePlugins`).\n */\n lastKnownCapabilities?: Pick<\n MachineCapabilities,\n 'models' | 'environments' | 'mcpServers' | 'skills' | 'marketplacePlugins' | 'usesGraphite'\n >,\n /**\n * Codex auth detection hint (PROTOCOL_VERSION 83). When set, the\n * Codex detector validates the user's chosen method exclusively\n * (no auto-detect fallbacks). Falls back to auto-detect when undefined.\n */\n codexMethodHint?: CodexAuthMethod,\n /**\n * Defense-in-depth fallback for the Codex detector. The detector\n * returns `preserved` on transient FS / parse errors; we keep the\n * prior status in that case so the settings card doesn't flicker\n * between authenticated and unauthenticated during a write window\n * on `~/.codex/auth.json`.\n */\n lastKnownCodexAuth?: CodexAuthStatus,\n /**\n * When this signal aborts mid-detect (worker terminated externally),\n * every in-flight `bootstrapPhase` logs `outcome:'worker_killed'` so the\n * daemon log records which phase was stuck on the next investigation.\n */\n abortSignal?: AbortSignal\n): Promise<MachineCapabilities> {\n return withLabelAsync('detectCapabilities', async () => {\n const onAbort = abortSignal ? () => void logInFlightPhasesAsKilled() : null;\n if (onAbort && abortSignal) {\n if (abortSignal.aborted) onAbort();\n else abortSignal.addEventListener('abort', onAbort, { once: true });\n }\n try {\n return await runDetectCapabilitiesBody({\n tokenStore,\n methodHint,\n lastKnownAuth,\n lastKnownAgents,\n lastKnownCapabilities,\n codexMethodHint,\n lastKnownCodexAuth,\n });\n } finally {\n if (onAbort && abortSignal) abortSignal.removeEventListener('abort', onAbort);\n }\n });\n}\n\ninterface RunDetectCapabilitiesBodyArgs {\n tokenStore: import('../mcp/token-store.js').MCPTokenStore | undefined;\n methodHint: AnthropicAuthStatus['method'] | undefined;\n lastKnownAuth: AnthropicAuthStatus | undefined;\n lastKnownAgents: InstalledAgent[] | undefined;\n lastKnownCapabilities:\n | Pick<\n MachineCapabilities,\n 'models' | 'environments' | 'mcpServers' | 'skills' | 'marketplacePlugins' | 'usesGraphite'\n >\n | undefined;\n codexMethodHint: CodexAuthMethod | undefined;\n lastKnownCodexAuth: CodexAuthStatus | undefined;\n}\n\nasync function runDetectCapabilitiesBody({\n tokenStore,\n methodHint,\n lastKnownAuth,\n lastKnownAgents,\n lastKnownCapabilities,\n codexMethodHint,\n lastKnownCodexAuth,\n}: RunDetectCapabilitiesBodyArgs): Promise<MachineCapabilities> {\n /**\n * Run the agent probe FIRST, serially, before the rest of detect kicks off.\n *\n * Reason: `detectModels` awaits `getSupportedEfforts()` which reads the\n * ~200MB bundled Claude SDK binary in 1MB chunks (5-16s cold disk). That\n * read saturates libuv's I/O thread pool. If `detectAgentProviders` runs\n * concurrently — as it did when both were sibling entries of this same\n * `Promise.all` — the `setTimeout` backing `execFile`'s 5s timeout for\n * `claude --version` fires 10-21s late, and `detectInitialCapabilities`'s\n * one-shot retry doubles it. That was the 2026-05-13 40-second startup\n * hang (#3289).\n *\n * Serializing the agent probe in front of the rest costs the version-probe\n * spawn time (~50ms warm, ~250ms cold) and eliminates the contention\n * entirely. The remaining detectors then run in parallel because they\n * don't touch the same I/O pool dimension.\n */\n /**\n * Every detector is wrapped in `withDetectorTimeout` so one wedged\n * subprocess / hung syscall cannot stall the whole detection pass. On\n * timeout we fall back to `lastKnown*` (where the detector has one) or\n * to a safe empty shape. Detection is now off the boot path entirely\n * (#3360) — capabilities ride a control-channel `capabilities` broadcast\n * — so a partial result here just means the browser sees the prior\n * slice value until the next refresh tick succeeds, not a stalled daemon.\n */\n const installedAgents = await bootstrapPhase('detect_agent_providers', () =>\n withDetectorTimeout({\n name: 'detect_agent_providers',\n run: () => detectAgentProviders(lastKnownAgents),\n fallback: lastKnownAgents ?? [],\n timeoutMs: DEFAULT_DETECTOR_TIMEOUT_MS,\n })\n );\n const [models, environments, authResult, codexAuthResult] = await Promise.all([\n bootstrapPhase('detect_models', () =>\n withDetectorTimeout({\n name: 'detect_models',\n run: () => detectModels(lastKnownCapabilities?.models),\n fallback: lastKnownCapabilities?.models ?? [],\n timeoutMs: DEFAULT_DETECTOR_TIMEOUT_MS,\n })\n ),\n bootstrapPhase('detect_environments', () =>\n withDetectorTimeout({\n name: 'detect_environments',\n run: () => detectEnvironments(lastKnownCapabilities?.environments),\n fallback: lastKnownCapabilities?.environments ?? [],\n timeoutMs: ENVIRONMENT_DETECTOR_TIMEOUT_MS,\n })\n ),\n bootstrapPhase('detect_anthropic_auth', () =>\n withDetectorTimeout<AuthDetectionResult>({\n name: 'detect_anthropic_auth',\n run: () => detectAnthropicAuth(methodHint),\n fallback: { kind: 'preserved', reason: 'timeout' },\n timeoutMs: DEFAULT_DETECTOR_TIMEOUT_MS,\n })\n ),\n bootstrapPhase('detect_codex_auth', () => detectCodexAuth(codexMethodHint)),\n ]);\n\n const [mcpServers, skills, marketplacePlugins, autoModeEnabled, graphite, commonDirs] =\n await Promise.all([\n bootstrapPhase('detect_mcp_servers', () =>\n withDetectorTimeout({\n name: 'detect_mcp_servers',\n run: () =>\n detectMCPServers(\n environments,\n tokenStore,\n (entry) => logger.warn(entry, entry.event),\n lastKnownCapabilities?.mcpServers,\n CLAUDE_CODE_RUNTIME_ID,\n methodHint === 'none' ? undefined : methodHint\n ),\n fallback: lastKnownCapabilities?.mcpServers ?? [],\n timeoutMs: DEFAULT_DETECTOR_TIMEOUT_MS,\n })\n ),\n bootstrapPhase('detect_skills', () =>\n withDetectorTimeout({\n name: 'detect_skills',\n run: () => detectSkills(environments, lastKnownCapabilities?.skills),\n fallback: lastKnownCapabilities?.skills ?? [],\n timeoutMs: DEFAULT_DETECTOR_TIMEOUT_MS,\n })\n ),\n bootstrapPhase('detect_marketplace_plugins', () =>\n withDetectorTimeout({\n name: 'detect_marketplace_plugins',\n run: () => detectMarketplacePlugins(lastKnownCapabilities?.marketplacePlugins),\n fallback: lastKnownCapabilities?.marketplacePlugins ?? [],\n timeoutMs: DEFAULT_DETECTOR_TIMEOUT_MS,\n })\n ),\n bootstrapPhase('detect_auto_mode', () =>\n withDetectorTimeout({\n name: 'detect_auto_mode',\n run: () => detectAutoModeEnabled(),\n fallback: false,\n timeoutMs: DEFAULT_DETECTOR_TIMEOUT_MS,\n })\n ),\n bootstrapPhase('detect_graphite', () =>\n withDetectorTimeout({\n name: 'detect_graphite',\n run: () => detectGraphite(),\n fallback: { usesGraphite: false, signals: [] },\n timeoutMs: DEFAULT_DETECTOR_TIMEOUT_MS,\n })\n ),\n bootstrapPhase('detect_common_dirs', () =>\n withDetectorTimeout({\n name: 'detect_common_dirs',\n run: () => detectCommonDirs(),\n fallback: [],\n timeoutMs: DEFAULT_DETECTOR_TIMEOUT_MS,\n })\n ),\n ]);\n /**\n * Preserve a prior `true` across transient detection failures — the same\n * defense-in-depth pattern the other detectors apply via lastKnownCapabilities.\n * If `detectGraphite` returned false but we previously confirmed the user has\n * Graphite, a transient PATH or file-read hiccup should not hide the banner.\n */\n const resolvedUsesGraphite =\n graphite.usesGraphite || (lastKnownCapabilities?.usesGraphite ?? false);\n const permissionModes = autoModeEnabled\n ? [...PermissionModeSchema.options]\n : PermissionModeSchema.options.filter((m) => m !== 'auto');\n\n let anthropicAuth: AnthropicAuthStatus = resolveAnthropicAuth(authResult, lastKnownAuth);\n\n const preferred: AnthropicAuthMethod | null =\n methodHint && methodHint !== 'none' ? methodHint : null;\n const mismatch = classifyEnvMismatch(preferred, process.env);\n if (mismatch.kind === 'mismatch') {\n anthropicAuth = {\n ...anthropicAuth,\n authMismatch: {\n selected: mismatch.selected,\n envMethod: mismatch.envMethod,\n envVar: mismatch.envVar,\n },\n };\n }\n\n const codexAuth: CodexAuthStatus = resolveCodexAuth(codexAuthResult, lastKnownCodexAuth);\n\n return {\n models,\n environments,\n permissionModes,\n autoModeEnabled,\n homeDir: homedir(),\n commonDirs,\n anthropicAuth,\n codexAuth,\n /**\n * Boot-time snapshot only includes profiles whose detectors are\n * wired here (anthropic + codex). Cursor's auth-detector requires\n * vault injection which happens later in serve-factory; the first\n * `refreshFull('cursor_login')` call lands cursor into the snapshot\n * via the registry-driven `runProfileAwareRefresh` path.\n */\n runtimeAuth: buildRuntimeAuthMap({\n 'claude-code': anthropicAuth,\n codex: codexAuth,\n }),\n mcpServers,\n skills,\n marketplacePlugins,\n installedAgents,\n installedRuntimes: installedAgents,\n /**\n * Reaching here means detection actually ran — flip the gate so the\n * browser banner predicate (\"No agent installed\") becomes authoritative.\n * The stub in serve-factory-helpers.ts:204 returns `false` instead.\n */\n detectionComplete: true,\n usesGraphite: resolvedUsesGraphite,\n };\n}\n","export {\n withLabel,\n withLabelAsync,\n getCurrentWatchdogLabel,\n getPreviousWatchdogLabel,\n getPreviousWatchdogDurationMs,\n _resetWatchdogContextForTests,\n};\n\n/**\n * Lightweight watchdog/attribution context for daemon-side blocking work.\n *\n * Pairs with `EventLoopWatchdog`: when the watchdog detects a stall, it\n * surfaces `currentLabel` (what's running NOW, almost always the thing that\n * caused the stall) and `prevLabel` + `prevDurationMs` (what JUST finished —\n * the actual culprit if the stall is a microtask continuation of completed\n * sync work). Together those give \"stall happened during X, just after Y took\n * Z ms\" without per-call instrumentation in every code path.\n *\n * The context is intentionally module-scoped state, not AsyncLocalStorage:\n * the cost of ALS at the rate we'd label things (every spawn, every git walk)\n * isn't worth the per-async-flow scoping. The watchdog reads single global\n * vars; that's enough for \"what was on the stack when libuv stalled\".\n *\n * `withLabel<T>(name, fn)` and `withLabelAsync<T>(name, fn)` are the public\n * surface. They use try/finally so abnormal exits still restore the prior\n * label.\n */\n\nlet currentLabel: string | null = null;\nlet prevCompletedLabel: string | null = null;\nlet prevCompletedDurationMs = 0;\n\nfunction withLabel<T>(name: string, fn: () => T): T {\n const priorLabel = currentLabel;\n const start = Date.now();\n currentLabel = name;\n try {\n return fn();\n } finally {\n const duration = Date.now() - start;\n prevCompletedLabel = name;\n prevCompletedDurationMs = duration;\n currentLabel = priorLabel;\n }\n}\n\nasync function withLabelAsync<T>(name: string, fn: () => Promise<T>): Promise<T> {\n const priorLabel = currentLabel;\n const start = Date.now();\n currentLabel = name;\n try {\n return await fn();\n } finally {\n const duration = Date.now() - start;\n prevCompletedLabel = name;\n prevCompletedDurationMs = duration;\n currentLabel = priorLabel;\n }\n}\n\nfunction getCurrentWatchdogLabel(): string | null {\n return currentLabel;\n}\n\nfunction getPreviousWatchdogLabel(): string | null {\n return prevCompletedLabel;\n}\n\nfunction getPreviousWatchdogDurationMs(): number {\n return prevCompletedDurationMs;\n}\n\nfunction _resetWatchdogContextForTests(): void {\n currentLabel = null;\n prevCompletedLabel = null;\n prevCompletedDurationMs = 0;\n}\n","import { mkdir, readFile, rename, stat, unlink, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { z } from 'zod';\nimport { getShipyardHome } from '../env.js';\nimport { isEnoent } from '../fs-utils.js';\nimport { logger } from '../logger.js';\n\nconst CacheEntrySchema = z.object({\n binaryPath: z.string(),\n version: z.string().optional(),\n binaryMtimeMs: z.number(),\n cachedAt: z.number(),\n});\n\nconst CacheFileSchema = z.object({\n entries: z.record(z.string(), CacheEntrySchema),\n});\n\nexport type AgentCacheEntry = z.infer<typeof CacheEntrySchema>;\ntype CacheFile = z.infer<typeof CacheFileSchema>;\n\nexport const AGENT_CACHE_TTL_MS = 24 * 60 * 60 * 1000;\n\nfunction cacheFilePath(): string {\n return join(getShipyardHome(), 'data', 'agent-providers-cache.json');\n}\n\nexport async function loadCache(): Promise<Map<string, AgentCacheEntry>> {\n const filePath = cacheFilePath();\n try {\n const raw = await readFile(filePath, 'utf8');\n const parsed: unknown = JSON.parse(raw);\n const result = CacheFileSchema.safeParse(parsed);\n if (!result.success) {\n logger.debug({ path: filePath }, 'agent-providers-cache: malformed, treating as empty');\n return new Map();\n }\n return new Map(Object.entries(result.data.entries));\n } catch (err) {\n if (isEnoent(err)) {\n return new Map();\n }\n logger.debug({ err }, 'agent-providers-cache: read failed, treating as empty');\n return new Map();\n }\n}\n\nexport async function getBinaryMtime(binaryPath: string): Promise<number | null> {\n try {\n const s = await stat(binaryPath);\n return s.mtimeMs;\n } catch {\n return null;\n }\n}\n\nexport function isCacheValid(entry: AgentCacheEntry, currentMtimeMs: number): boolean {\n if (entry.binaryMtimeMs !== currentMtimeMs) return false;\n if (Date.now() - entry.cachedAt >= AGENT_CACHE_TTL_MS) return false;\n return true;\n}\n\nexport async function saveCache(entries: Map<string, AgentCacheEntry>): Promise<void> {\n const filePath = cacheFilePath();\n const tmpPath = `${filePath}.tmp`;\n try {\n await mkdir(dirname(filePath), { recursive: true });\n /**\n * Merge-on-save mirrors environments-cache.ts: re-read disk before writing\n * so concurrent calls don't clobber each other's entries.\n */\n const current = await loadCache();\n for (const [path, entry] of entries) {\n current.set(path, entry);\n }\n const payload: CacheFile = { entries: Object.fromEntries(current) };\n await writeFile(tmpPath, JSON.stringify(payload), 'utf8');\n await rename(tmpPath, filePath);\n } catch (err) {\n logger.debug({ err, filePath }, 'agent-providers-cache: save failed');\n void unlink(tmpPath).catch(() => {});\n }\n}\n","/**\n * On-disk persistence for the session-lifetime `claude-code` version cache.\n *\n * Why this exists: the in-memory `sessionVersionCache` in `agents.ts` short-\n * circuits the `which` + `stat` + JSON-cache pipeline after the first call,\n * but after EVERY daemon restart the slot is empty — so the first call pays\n * the full cost again. On macOS the cold-cache `which claude` + `stat` round\n * trip is ~50-100ms; in pathological cases (the native CLI binary not in OS\n * page cache, antivirus indexing, NFS-mounted home dirs) it can be seconds.\n * Persisting the last-known-good resolution lets boot reuse it immediately,\n * subject to a mtime check against the binary on disk.\n *\n * Single-entry by design — `agent-providers-cache.json` (sibling file) is a\n * `Map<binaryPath, AgentCacheEntry>` keyed for the case where the user\n * switches between multiple `claude` installs. This cache is the \"what did\n * we LAST resolve to\" memo, used to seed `sessionVersionCache` on boot. A\n * single binary path is sufficient because the session cache is also\n * single-entry.\n */\n\nimport { mkdir, readFile, rename, stat, unlink, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { z } from 'zod';\nimport { getShipyardHome } from '../env.js';\nimport { isEnoent } from '../fs-utils.js';\nimport { logger } from '../logger.js';\n\nconst ClaudeVersionCacheSchema = z.object({\n binaryPath: z.string(),\n version: z.string(),\n binaryMtimeMs: z.number(),\n cachedAt: z.number(),\n});\n\nexport type ClaudeVersionCache = z.infer<typeof ClaudeVersionCacheSchema>;\n\nfunction cacheFilePath(): string {\n return join(getShipyardHome(), 'data', 'claude-version-cache.json');\n}\n\n/**\n * Read the persisted cache. Returns null when missing, unreadable, or\n * structurally invalid — callers fall through to the live probe path.\n */\nexport async function loadClaudeVersionCache(): Promise<ClaudeVersionCache | null> {\n const filePath = cacheFilePath();\n let raw: string;\n try {\n raw = await readFile(filePath, 'utf8');\n } catch (err: unknown) {\n if (isEnoent(err)) return null;\n logger.debug({ err, filePath }, 'claude-version-cache: read failed');\n return null;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return null;\n }\n const result = ClaudeVersionCacheSchema.safeParse(parsed);\n if (!result.success) return null;\n return result.data;\n}\n\n/**\n * Validate a loaded entry by stat'ing the binary path. Returns true when\n * the binary still exists at the recorded path AND its mtime matches what\n * we cached. Mtime mismatch ⇒ upgrade ⇒ invalidate.\n */\nexport async function isClaudeVersionCacheFresh(entry: ClaudeVersionCache): Promise<boolean> {\n try {\n const s = await stat(entry.binaryPath);\n return s.mtimeMs === entry.binaryMtimeMs;\n } catch {\n return false;\n }\n}\n\n/**\n * Persist the cache atomically. Best-effort: write failures log at debug\n * and never bubble — the in-memory slot is the source of truth at runtime\n * and a missed write at most costs one extra probe on the next boot.\n */\nexport async function saveClaudeVersionCache(entry: ClaudeVersionCache): Promise<void> {\n const filePath = cacheFilePath();\n const tmpPath = `${filePath}.tmp`;\n try {\n await mkdir(dirname(filePath), { recursive: true });\n await writeFile(tmpPath, JSON.stringify(entry), 'utf8');\n await rename(tmpPath, filePath);\n } catch (err: unknown) {\n logger.debug({ err, filePath }, 'claude-version-cache: save failed');\n void unlink(tmpPath).catch(() => {});\n }\n}\n","import { AGENT_IDS, type AgentId } from '@shipyard/loro-schema';\nimport type { InstalledAgent } from '@shipyard/session';\n\nimport { profileRegistry } from '../../services/session/profiles/profile-registry.js';\nimport { logger } from '../logger.js';\nimport { bootstrapPhase } from '../observability/bootstrap-phase.js';\nimport {\n type AgentCacheEntry,\n getBinaryMtime,\n isCacheValid,\n loadCache,\n saveCache,\n} from './agent-providers-cache.js';\nimport {\n isClaudeVersionCacheFresh,\n loadClaudeVersionCache,\n saveClaudeVersionCache,\n} from './claude-version-cache.js';\nimport { run } from './shell.js';\n\nexport function buildAgent(id: AgentId, name: string, version: string | undefined): InstalledAgent {\n switch (id) {\n case 'claude-code':\n return { id: 'claude-code', providerId: 'anthropic', name: 'Claude Code', version };\n case 'codex':\n return { id: 'codex', providerId: 'openai', name: 'Codex', version };\n case 'cursor':\n return { id: 'cursor', providerId: 'cursor', name: 'Cursor', version };\n default: {\n const _exhaustive: never = id;\n logger.warn({ id, name }, 'agents_unknown_profile_id');\n return _exhaustive;\n }\n }\n}\n\n/**\n * Session-lifetime in-memory cache for the claude-code version probe.\n *\n * `detectAgentProviders` is called from three independent code paths: the\n * initial capability detect at boot, the 30s capability-refresh tick, and\n * the browser-triggered `refresh_agent_providers` control message. In a\n * 10-minute session that's 20+ calls — each one paying for `which claude`,\n * `stat(binaryPath)`, the on-disk JSON cache read, and the `loadCache`\n * pretty-printed JSON parse. The disk cache prevents the `--version` spawn\n * on warm boot, but the surrounding I/O still hits the loop ~20x per\n * session.\n *\n * This memo collapses those calls to one. After the first call populates\n * the slot, every subsequent call returns the cached agents synchronously\n * (in a Promise wrapper) and fires an async revalidation in the background:\n * stat the binary, compare mtime; on mismatch, re-probe and replace the\n * slot. Callers always see a value with sub-millisecond latency on cache\n * hit. The revalidation cannot block the response — that's the whole\n * point of stale-while-revalidate.\n *\n * Wired at the chokepoint (Invariant #6) so every caller benefits without\n * each one wiring its own memo.\n *\n * Claude-specific: the version probe pipeline shells out to `claude --version`\n * which has measurable latency; profiles whose `binaryResolver` returns a\n * non-null path other than Claude's `'bundled-via-sdk'` sentinel are detected\n * via the profile loop and do not participate in this cache. The cache stays\n * Claude-scoped so the existing on-disk persistence file\n * (`claude-version-cache.json`) keeps the same shape.\n */\ninterface SessionVersionCache {\n binaryPath: string;\n binaryMtimeMs: number | null;\n version: string | undefined;\n}\n\nlet sessionClaudeVersionCache: SessionVersionCache | null = null;\nlet inflightClaudeRevalidation: Promise<void> | null = null;\n\n/**\n * Test-only: clear the session-memo so each test starts with a cold cache.\n * Production code MUST NOT call this — the cache is a daemon-lifetime\n * optimization and the only correct way to invalidate it is via the\n * automatic mtime revalidation.\n */\nexport function _resetSessionVersionCacheForTests(): void {\n sessionClaudeVersionCache = null;\n inflightClaudeRevalidation = null;\n}\n\n/**\n * Boot-time hydration of the session cache from disk. The disk file\n * `~/.shipyard/data/claude-version-cache.json` carries the last successful\n * resolution from a prior daemon run. Validated by stat'ing the recorded\n * binary path — a mtime mismatch indicates the user upgraded `claude` since\n * we last cached, so we invalidate and fall through to the live probe.\n *\n * Called fire-and-forget from `serve-factory.ts` near daemon boot so it\n * completes BEFORE the first capability-detect tick. If `detectAgentProviders`\n * happens to be called before this resolves, the worst case is one extra\n * probe — `loadCache()` is async and already cheap.\n *\n * Returns true when the disk cache was loaded into the in-memory slot;\n * false when missing/stale/invalid. Callers can log the outcome.\n */\nexport async function loadAgentProvidersFromDisk(): Promise<boolean> {\n if (sessionClaudeVersionCache !== null) return false;\n const entry = await loadClaudeVersionCache();\n if (!entry) return false;\n const fresh = await isClaudeVersionCacheFresh(entry);\n if (!fresh) {\n logger.info({ binaryPath: entry.binaryPath }, 'claude_code_version_cache_disk_stale');\n return false;\n }\n /**\n * Double-check: another caller may have populated the slot during the\n * stat round-trip (e.g. capability-detect fired in parallel with boot\n * hydration). Don't clobber that — the live probe's value is fresher.\n */\n if (sessionClaudeVersionCache !== null) return false;\n sessionClaudeVersionCache = {\n binaryPath: entry.binaryPath,\n binaryMtimeMs: entry.binaryMtimeMs,\n version: entry.version,\n };\n logger.info(\n { binaryPath: entry.binaryPath, version: entry.version },\n 'claude_code_version_cache_loaded_from_disk'\n );\n return true;\n}\n\n/**\n * Persist the in-memory session cache to disk so subsequent daemon boots\n * can skip the `which` + `stat` + probe pipeline. Best-effort — disk write\n * failures log at debug but never throw. Only called when the in-memory\n * slot was just populated with an authoritative resolution.\n */\nfunction persistSessionVersionCache(cache: SessionVersionCache): void {\n if (!cache.version || cache.binaryMtimeMs == null) return;\n void saveClaudeVersionCache({\n binaryPath: cache.binaryPath,\n version: cache.version,\n binaryMtimeMs: cache.binaryMtimeMs,\n cachedAt: Date.now(),\n }).then(() => {\n logger.info(\n { binaryPath: cache.binaryPath, version: cache.version },\n 'claude_code_version_cache_persisted'\n );\n });\n}\n\n/**\n * `which` / `where.exe` exit code 1 ⇒ binary genuinely not in PATH.\n * Anything else (timeout, kill signal, spawn ENOENT/EACCES/EAGAIN/EMFILE,\n * unexpected exit codes) ⇒ subprocess execution itself failed, the absence\n * of `claude` is not authoritative. The 30s capability-refresh timer\n * (apps/daemon/src/services/serve.ts) calls this on every tick; without the\n * distinction, a single transient subprocess failure overwrites a known-good\n * `installedAgents: [claude-code]` with `[]` and broadcasts \"No agent\n * installed\" to the UI. Confirmed live: ~1% of broadcasts in a heavily-loaded\n * daemon log were the wrong shape (55 / 5418).\n */\nfunction isAuthoritativeNotFound(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n if ('killed' in err && err.killed === true) return false;\n if ('signal' in err && typeof err.signal === 'string') return false;\n if (!('code' in err)) return false;\n const code = err.code;\n if (typeof code === 'string') return false;\n return code === 1;\n}\n\n/**\n * Iterate registered profiles, await each `binaryResolver()`, and build\n * `InstalledAgent` entries for the ones that resolved to a non-null path.\n * Adds Claude version probing as a bonus enrichment (only Claude exposes\n * `--version` cheaply enough for refresh-tick polling); other profiles get\n * a versionless entry so the UI can still render an \"installed\" badge.\n *\n * `lastKnown` is preserved per-profile when transient probe failures occur,\n * matching the prior Claude-only `lastKnown` semantics — a single bad\n * `execFile` tick must not flip the agent row to \"not installed\".\n */\nexport async function detectAgentProviders(\n lastKnown?: InstalledAgent[]\n): Promise<InstalledAgent[]> {\n const lastKnownById = new Map<AgentId, InstalledAgent>();\n for (const agent of lastKnown ?? []) {\n const knownId = AGENT_IDS.find((id) => id === agent.id);\n if (knownId !== undefined) {\n lastKnownById.set(knownId, agent);\n }\n }\n\n const profiles = profileRegistry.list();\n /**\n * If the registry hasn't been populated yet (registerBuiltInProfiles not\n * called — happens in some test fixtures), preserve lastKnown rather than\n * collapse to empty. The boot path calls `registerBuiltInProfiles()` before\n * any caller reaches `detectAgentProviders`, so the empty case here is\n * defensive only.\n */\n if (profiles.length === 0) {\n logger.warn(\n { lastKnownCount: lastKnown?.length ?? 0 },\n 'detect_agent_providers_empty_registry_preserving_last_known'\n );\n return lastKnown ?? [];\n }\n\n const result: InstalledAgent[] = [];\n for (const profile of profiles) {\n const entry = await resolveProfileAgent(profile, lastKnownById);\n if (entry) result.push(entry);\n }\n return result;\n}\n\n/**\n * Resolve a single profile's `InstalledAgent` entry, applying the\n * Claude-specific version-probe path when the profile is `claude-code` and\n * falling back to a versionless entry otherwise. Returns null when the\n * profile is not installed AND no lastKnown fallback applies.\n */\nasync function resolveProfileAgent(\n profile: ReturnType<typeof profileRegistry.list>[number],\n lastKnownById: Map<AgentId, InstalledAgent>\n): Promise<InstalledAgent | null> {\n let binaryPath: string | null;\n try {\n binaryPath = await profile.spawn.binaryResolver();\n } catch (err) {\n /**\n * `binaryResolver` is profile-owned — its only failure mode for our\n * production profiles is transient subprocess error (Codex's\n * `execFile which`). Codex's resolver already swallows + preserves\n * via `lastKnownCodexBinary`; this catch is defensive against future\n * profiles that throw. Preserve the lastKnown entry for that profile\n * so the UI does not flicker.\n */\n logger.warn(\n { err, profileId: profile.id },\n 'agent_provider_binary_resolver_threw_preserving_last_known'\n );\n return lastKnownById.get(profile.id) ?? null;\n }\n if (binaryPath === null) return null;\n if (profile.id === 'claude-code') {\n return resolveClaudeAgent(lastKnownById.get('claude-code'));\n }\n /** Non-Claude profile — `binaryResolver` succeeded; emit a versionless entry. */\n return buildAgent(profile.id, profile.displayName, undefined);\n}\n\n/**\n * Claude version probe with stale-while-revalidate session memo. The\n * `binaryResolver` for Claude returns `'bundled-via-sdk'` (the SDK is\n * always available); for version-reporting we still try to resolve the\n * standalone `claude` CLI via `which claude` so the UI can show a version\n * string. A missing CLI is not authoritative for installation — Claude\n * always counts as installed thanks to the bundled SDK.\n */\nasync function resolveClaudeAgent(\n lastKnown: InstalledAgent | undefined\n): Promise<InstalledAgent | null> {\n if (sessionClaudeVersionCache) {\n const cached = sessionClaudeVersionCache;\n logger.info(\n { binaryPath: cached.binaryPath, version: cached.version ?? null },\n 'claude_code_version_cache_hit'\n );\n if (!inflightClaudeRevalidation) {\n inflightClaudeRevalidation = revalidateClaudeSessionCache(cached).finally(() => {\n inflightClaudeRevalidation = null;\n });\n }\n return buildAgent('claude-code', 'Claude Code', cached.version);\n }\n\n logger.info({}, 'claude_code_version_cache_miss');\n const probed = await probeClaudeUncached(lastKnown);\n if (probed.binaryPath && probed.version) {\n sessionClaudeVersionCache = {\n binaryPath: probed.binaryPath,\n binaryMtimeMs: probed.binaryMtimeMs,\n version: probed.version,\n };\n persistSessionVersionCache(sessionClaudeVersionCache);\n }\n /**\n * Claude is \"installed\" regardless of whether the standalone CLI was\n * found — the SDK is bundled with Shipyard. Versions are best-effort\n * metadata. Always return a Claude entry; only the `version` field\n * tracks the probe outcome.\n */\n return buildAgent('claude-code', 'Claude Code', probed.version);\n}\n\nasync function revalidateClaudeSessionCache(cached: SessionVersionCache): Promise<void> {\n const currentMtimeMs = await getBinaryMtime(cached.binaryPath);\n /**\n * stat() failed entirely — binary may have moved or been uninstalled.\n * Invalidate so the next call re-probes. Don't probe NOW because we\n * already returned the stale value to the caller; the next caller\n * will pay the probe cost.\n */\n if (currentMtimeMs == null) {\n sessionClaudeVersionCache = null;\n return;\n }\n if (currentMtimeMs === cached.binaryMtimeMs) return;\n /**\n * Mtime drifted — binary was upgraded. Re-probe in the background and\n * update the slot. The next caller picks up the new value.\n */\n try {\n const probed = await probeClaudeUncached(undefined);\n if (probed.binaryPath && probed.version) {\n sessionClaudeVersionCache = {\n binaryPath: probed.binaryPath,\n binaryMtimeMs: probed.binaryMtimeMs,\n version: probed.version,\n };\n persistSessionVersionCache(sessionClaudeVersionCache);\n } else {\n sessionClaudeVersionCache = null;\n }\n } catch {\n /** Background revalidation must not throw — log nothing, leave stale cache for next caller. */\n }\n}\n\ninterface UncachedClaudeProbeResult {\n binaryPath: string | null;\n binaryMtimeMs: number | null;\n version: string | undefined;\n}\n\nasync function probeClaudeUncached(\n lastKnown: InstalledAgent | undefined\n): Promise<UncachedClaudeProbeResult> {\n const whichCmd = process.platform === 'win32' ? 'where.exe' : 'which';\n let binaryPath: string;\n try {\n /**\n * `which` (and `where.exe`) can return multiple lines when the binary is\n * resolvable through more than one PATH entry (e.g. brew + manual install,\n * or nvm/asdf shim + system bin). Take the first match — that's what the\n * shell would actually exec.\n */\n binaryPath = (await run(whichCmd, ['claude'])).split(/\\r?\\n/)[0]?.trim() ?? '';\n } catch (err) {\n if (isAuthoritativeNotFound(err)) {\n logger.warn({ err }, 'Claude Code CLI not found');\n return { binaryPath: null, binaryMtimeMs: null, version: undefined };\n }\n logger.warn(\n { err, lastKnownVersion: lastKnown?.version ?? null },\n 'Claude Code CLI detection failed transiently — preserving lastKnown'\n );\n return { binaryPath: null, binaryMtimeMs: null, version: lastKnown?.version };\n }\n if (!binaryPath) return { binaryPath: null, binaryMtimeMs: null, version: undefined };\n\n /**\n * Cache layer (`agent-providers-cache.ts`) catches its own I/O errors:\n * `getBinaryMtime` returns null on stat failure, `loadCache` returns an\n * empty Map on read failure, `saveCache` is fire-and-forget. The version\n * probe inside `detectAndPersist` swallows its own errors. So once `which`\n * succeeded, the rest of this pipeline is total — no second catch needed.\n */\n const currentMtimeMs = await getBinaryMtime(binaryPath);\n if (currentMtimeMs == null) {\n const version = await detectAndPersist(binaryPath, null);\n return { binaryPath, binaryMtimeMs: null, version };\n }\n\n const cache = await loadCache();\n const cached = cache.get(binaryPath);\n if (cached && isCacheValid(cached, currentMtimeMs)) {\n logger.info({ binaryPath, version: cached.version }, 'agent_providers_cache_hit');\n return {\n binaryPath,\n binaryMtimeMs: currentMtimeMs,\n version: cached.version,\n };\n }\n\n const version = await detectAndPersist(binaryPath, currentMtimeMs);\n return { binaryPath, binaryMtimeMs: currentMtimeMs, version };\n}\n\nasync function detectAndPersist(\n binaryPath: string,\n binaryMtimeMs: number | null\n): Promise<string | undefined> {\n logger.info({ binaryPath }, 'Detecting Claude Code CLI');\n let version: string | undefined;\n try {\n /**\n * Wrapped so the silent-swallow pattern that hid the 2026-05-13 40s hang\n * (`bootstrap_phase_end` with `outcome: 'error'` always logs even when\n * the `catch` here drops the rejection). The `version_probe` phase entry\n * lets a future hang be diagnosed by reading the daemon log alone.\n */\n const raw = await bootstrapPhase('version_probe', () => run('claude', ['--version']));\n const match = raw.match(/\\d+\\.\\d+\\.\\d+/);\n if (match) version = match[0];\n } catch (err) {\n /** Best-effort — some builds don't support --version. Outcome is in the bootstrap_phase log. */\n logger.warn({ err, binaryPath }, 'claude_version_probe_failed_or_timed_out');\n }\n logger.info({ binaryPath, version }, 'Agent detection complete');\n\n if (binaryMtimeMs != null && version) {\n const entry: AgentCacheEntry = {\n binaryPath,\n version,\n binaryMtimeMs,\n cachedAt: Date.now(),\n };\n await saveCache(new Map([[binaryPath, entry]]));\n }\n\n return version;\n}\n","import { access } from 'node:fs/promises';\nimport { homedir, platform } from 'node:os';\nimport { join } from 'node:path';\n\nexport interface CommonDir {\n path: string;\n label: string;\n}\n\nexport interface CommonDirsDeps {\n homedir?: () => string;\n platform?: () => NodeJS.Platform;\n fileExists?: (path: string) => Promise<boolean>;\n}\n\ninterface Candidate {\n subdir: string;\n label: string;\n platforms?: ReadonlyArray<NodeJS.Platform>;\n}\n\n/**\n * Cross-platform quick-pick directory candidates. Each entry is probed\n * with `fs.access` — non-existent ones are dropped so users only see dirs\n * they actually have. Order in the array == display order on the picker.\n *\n * `~` (home itself) is intentionally excluded — the picker already renders\n * a dedicated Home button. Hidden dirs (`~/.claude`, `~/.shipyard`) are\n * excluded for noise reasons.\n *\n * `platforms` narrows the candidate to the listed OSes. Omit to include\n * everywhere (relies on the existence check to gate platform-specific\n * folders like `~/repos` that exist on every developer's macOS/Linux\n * machine but rarely on a vanilla Windows install).\n */\nconst CANDIDATES: ReadonlyArray<Candidate> = [\n { subdir: 'Documents', label: '~/Documents' },\n { subdir: 'Desktop', label: '~/Desktop' },\n { subdir: 'Downloads', label: '~/Downloads' },\n { subdir: 'Projects', label: '~/Projects' },\n { subdir: 'repos', label: '~/repos' },\n];\n\nasync function defaultFileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Pure-ish core: given home + a platform + an existence-check, return the\n * subset of CANDIDATES that exist. The async fan-out runs in parallel so a\n * slow disk on one entry doesn't serialize the rest.\n */\nexport async function findCommonDirs(\n home: string,\n currentPlatform: NodeJS.Platform,\n fileExists: (path: string) => Promise<boolean>\n): Promise<CommonDir[]> {\n const candidates = CANDIDATES.filter(\n (c) => !c.platforms || c.platforms.includes(currentPlatform)\n );\n const results = await Promise.all(\n candidates.map(async (c) => {\n const path = join(home, c.subdir);\n const exists = await fileExists(path);\n return exists ? { path, label: c.label } : null;\n })\n );\n return results.filter((r): r is CommonDir => r !== null);\n}\n\nexport async function detectCommonDirs(deps: CommonDirsDeps = {}): Promise<CommonDir[]> {\n const getHomedir = deps.homedir ?? homedir;\n const getPlatform = deps.platform ?? platform;\n const fileExists = deps.fileExists ?? defaultFileExists;\n return findCommonDirs(getHomedir(), getPlatform(), fileExists);\n}\n","import { logger } from '../logger.js';\n\n/**\n * Per-detector timeout wrapper.\n *\n * Wraps a single capability detector so a wedged subprocess or hung syscall\n * inside one detector cannot hang the WHOLE `detectCapabilities` await (and,\n * before #3360, the entire daemon boot). On timeout the wrapper logs\n * `detector_timeout` and returns `fallback` — typically the last-known\n * slice value or an empty equivalent — so the rest of the detection pipeline\n * continues with degraded but non-empty data.\n *\n * Note: a TRUE synchronous JS-thread wedge cannot be recovered by this\n * wrapper because `setTimeout` fires from the event loop. This guard is\n * specifically for the async-hang case (subprocess that never exits, stat\n * call against a hung mount, OAuth token refresh that loops). The boot\n * fix (#3360) keeps detection off the boot path so any wedge — sync or\n * async — no longer prevents the daemon from coming up.\n */\ntype DetectorOutcome<T> =\n | { kind: 'value'; value: T }\n | { kind: 'error'; error: unknown }\n | { kind: 'timeout' };\n\nexport async function withDetectorTimeout<T>(opts: {\n name: string;\n run: () => Promise<T>;\n fallback: T;\n timeoutMs: number;\n}): Promise<T> {\n const { name, run, fallback, timeoutMs } = opts;\n let timer: ReturnType<typeof setTimeout> | null = null;\n const timeoutPromise = new Promise<DetectorOutcome<T>>((resolve) => {\n timer = setTimeout(() => resolve({ kind: 'timeout' }), timeoutMs);\n timer.unref();\n });\n /**\n * Materialize both fulfillment AND rejection of `run()` as a resolved\n * outcome. Without the `.catch`, if `timeoutPromise` wins the race and\n * `run()` later rejects, the rejection becomes an unhandled promise\n * rejection because nothing else is observing it. Capturing it as\n * `{ kind: 'error', error }` keeps the promise observed; if the timeout\n * already won, we just log and discard the rejection.\n */\n const runPromise: Promise<DetectorOutcome<T>> = run().then(\n (value): DetectorOutcome<T> => ({ kind: 'value', value }),\n (error): DetectorOutcome<T> => ({ kind: 'error', error })\n );\n try {\n const winner = await Promise.race([runPromise, timeoutPromise]);\n if (winner.kind === 'timeout') {\n logger.warn({ event: 'detector_timeout', detector: name, timeoutMs });\n void runPromise.then((late) => {\n if (late.kind === 'error') {\n logger.warn({\n event: 'detector_error_after_timeout',\n detector: name,\n timeoutMs,\n error: late.error instanceof Error ? late.error.message : String(late.error),\n });\n }\n });\n return fallback;\n }\n if (winner.kind === 'error') {\n logger.warn({\n event: 'detector_error',\n detector: name,\n error: winner.error instanceof Error ? winner.error.message : String(winner.error),\n });\n return fallback;\n }\n return winner.value;\n } finally {\n if (timer !== null) clearTimeout(timer);\n }\n}\n\n/**\n * Default per-detector timeout. Picked so even the slowest healthy detector\n * (`detect_environments` with a cold `git worktree list` storm across a\n * hundred repos) has headroom, while still bounding a wedged detector to a\n * known recovery window. Detection runs in the background so this only\n * affects when the browser receives the real capabilities, never boot time.\n */\nexport const DEFAULT_DETECTOR_TIMEOUT_MS = 15_000;\n\n/**\n * `detect_environments` can legitimately be much slower than the other\n * detectors on machines with hundreds of repos/worktrees, especially after a\n * cache-shape migration forces one metadata refresh for every path. Detection\n * runs off the boot path, so give this detector enough budget to repair and\n * persist its cache instead of repeatedly falling back to the stale snapshot.\n */\nexport const ENVIRONMENT_DETECTOR_TIMEOUT_MS = 90_000;\n","import type { AnthropicAuthMethod } from '@shipyard/loro-schema';\nimport { resolveEnvMethod } from './env-methods.js';\n\nexport type EnvMismatch =\n | { kind: 'aligned' }\n | {\n kind: 'mismatch';\n selected: AnthropicAuthMethod;\n envMethod: AnthropicAuthMethod;\n envVar: string;\n };\n\n/**\n * Pure function: classify whether the user's preferred auth method conflicts\n * with credentials present in the process environment.\n *\n * A mismatch fires whenever the env-resolved method differs from the user's\n * explicit preference — this catches both \"subscription user with stray API\n * key\" and \"API-key user with stray bedrock env\", because the CLI's env-var\n * precedence will silently route billing to whichever env var wins.\n */\nexport function classifyEnvMismatch(\n preferred: AnthropicAuthMethod | null,\n env: NodeJS.ProcessEnv\n): EnvMismatch {\n if (preferred === null || preferred === 'none') return { kind: 'aligned' };\n const resolved = resolveEnvMethod(env);\n if (!resolved) return { kind: 'aligned' };\n if (resolved.method === preferred) return { kind: 'aligned' };\n return {\n kind: 'mismatch',\n selected: preferred,\n envMethod: resolved.method,\n envVar: resolved.envVar,\n };\n}\n","import { access, readFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { z } from 'zod';\nimport { run, TIMEOUT_MS } from './shell.js';\n\nexport interface GraphiteDetection {\n usesGraphite: boolean;\n signals: Array<'gt-cli' | 'user-config'>;\n}\n\nexport interface GraphiteDetectDeps {\n homedir?: () => string;\n fileExists?: (path: string) => Promise<boolean>;\n readFile?: (path: string) => Promise<string>;\n isCommandAvailable?: (cmd: string) => Promise<boolean>;\n}\n\nasync function defaultFileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function defaultIsCommandAvailable(cmd: string): Promise<boolean> {\n try {\n await run('which', [cmd], undefined, TIMEOUT_MS);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function defaultReadFile(path: string): Promise<string> {\n return readFile(path, 'utf-8');\n}\n\nexport async function detectGraphite(deps: GraphiteDetectDeps = {}): Promise<GraphiteDetection> {\n const getHomedir = deps.homedir ?? homedir;\n const fileExists = deps.fileExists ?? defaultFileExists;\n const readFileFn = deps.readFile ?? defaultReadFile;\n const isCommandAvailable = deps.isCommandAvailable ?? defaultIsCommandAvailable;\n\n const signals: Array<'gt-cli' | 'user-config'> = [];\n\n const [gtAvailable, configSignal] = await Promise.all([\n isCommandAvailable('gt').catch(() => false),\n (async (): Promise<boolean> => {\n try {\n const configPath = join(getHomedir(), '.config', 'graphite', 'user_config');\n if (!(await fileExists(configPath))) return false;\n const raw = await readFileFn(configPath);\n const result = z.object({ authToken: z.string().min(1) }).safeParse(JSON.parse(raw));\n return result.success;\n } catch {\n return false;\n }\n })(),\n ]);\n\n if (gtAvailable) signals.push('gt-cli');\n if (configSignal) signals.push('user-config');\n\n return { usesGraphite: signals.length > 0, signals };\n}\n","import { readdir, readFile, stat } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { MarketplacePluginInfo } from '@shipyard/session';\nimport { z } from 'zod';\n\nimport { logger } from '../logger.js';\n\nconst PluginJsonSchema = z.object({\n name: z.string(),\n description: z.string().optional(),\n version: z.string().optional(),\n author: z.union([z.object({ name: z.string() }), z.string()]).optional(),\n});\n\nconst InstalledPluginsSchema = z.object({\n version: z.number(),\n plugins: z.record(\n z.string(),\n z.array(\n z.object({\n scope: z.string(),\n installPath: z.string(),\n version: z.string(),\n installedAt: z.string(),\n lastUpdated: z.string(),\n })\n )\n ),\n});\n\nconst InstallCountsSchema = z.object({\n counts: z.array(\n z.object({\n plugin: z.string(),\n unique_installs: z.number(),\n })\n ),\n});\n\nconst KnownMarketplacesSchema = z.record(\n z.string(),\n z\n .object({\n installLocation: z.string(),\n })\n .passthrough()\n);\n\nasync function readJsonFile<T>(path: string, schema: z.ZodType<T>): Promise<T | null> {\n try {\n const raw = await readFile(path, 'utf-8');\n const result = schema.safeParse(JSON.parse(raw));\n return result.success ? result.data : null;\n } catch {\n return null;\n }\n}\n\nasync function listSubdirs(dir: string): Promise<string[]> {\n try {\n const entries = await readdir(dir);\n const results: string[] = [];\n for (const entry of entries) {\n if (entry.startsWith('.')) continue;\n const full = join(dir, entry);\n const s = await stat(full).catch(() => null);\n if (s?.isDirectory()) results.push(entry);\n }\n return results;\n } catch {\n return [];\n }\n}\n\nfunction resolveAuthor(author: z.infer<typeof PluginJsonSchema>['author']): string {\n if (!author) return 'Unknown';\n if (typeof author === 'string') return author;\n return author.name;\n}\n\n/**\n * Scan a single marketplace directory for plugins.\n * Reads both `plugins/` (first-party) and `external_plugins/` (third-party).\n */\nasync function scanMarketplace(\n marketplaceName: string,\n marketplacePath: string,\n installedSet: Set<string>,\n enabledMap: Record<string, boolean>,\n installCounts: Map<string, number>\n): Promise<MarketplacePluginInfo[]> {\n const results: MarketplacePluginInfo[] = [];\n\n for (const subdir of ['plugins', 'external_plugins']) {\n const isExternal = subdir === 'external_plugins';\n const dir = join(marketplacePath, subdir);\n const pluginNames = await listSubdirs(dir);\n\n for (const pluginName of pluginNames) {\n const pluginJsonPath = join(dir, pluginName, '.claude-plugin', 'plugin.json');\n const pluginJson = await readJsonFile(pluginJsonPath, PluginJsonSchema);\n if (!pluginJson) continue;\n\n const fullId = `${pluginName}@${marketplaceName}`;\n const installed = installedSet.has(fullId);\n const enabled = enabledMap[fullId] ?? false;\n\n results.push({\n name: pluginName,\n description: pluginJson.description ?? '',\n author: resolveAuthor(pluginJson.author),\n marketplace: marketplaceName,\n installCount: installCounts.get(fullId),\n installed,\n enabled: installed && enabled,\n version: pluginJson.version,\n isExternal,\n });\n }\n }\n\n return results;\n}\n\n/**\n * Detect all plugins available in Claude Code's marketplace directories.\n * Cross-references with installed state, enabled state, and install counts.\n *\n * `lastKnown` preserves the previously-detected list when this function\n * throws (rare — `readJsonFile` swallows errors and returns null — but\n * defense in depth against future regressions). Mirror of the\n * `lastKnownAgents` pattern in `agents.ts`.\n */\nexport async function detectMarketplacePlugins(\n lastKnown?: MarketplacePluginInfo[]\n): Promise<MarketplacePluginInfo[]> {\n try {\n return await detectMarketplacePluginsInner();\n } catch (err) {\n /**\n * Preserve \"always resolves\" contract — inner readers already swallow\n * per-file errors. Never rethrow because the Promise.all in\n * detectCapabilities would tear down the whole refresh for a single\n * slice's failure.\n */\n if (lastKnown && lastKnown.length > 0) {\n logger.warn(\n { err, lastKnownCount: lastKnown.length },\n 'detectMarketplacePlugins threw — preserving lastKnown'\n );\n return lastKnown;\n }\n logger.debug({ err }, 'detectMarketplacePlugins threw with no lastKnown — returning []');\n return [];\n }\n}\n\nasync function detectMarketplacePluginsInner(): Promise<MarketplacePluginInfo[]> {\n const pluginsDir = join(homedir(), '.claude', 'plugins');\n\n const [installedData, installCountsData, knownMarketplaces, enabledPlugins] = await Promise.all([\n readJsonFile(join(pluginsDir, 'installed_plugins.json'), InstalledPluginsSchema),\n readJsonFile(join(pluginsDir, 'install-counts-cache.json'), InstallCountsSchema),\n readJsonFile(join(pluginsDir, 'known_marketplaces.json'), KnownMarketplacesSchema),\n readJsonFile(\n join(homedir(), '.claude', 'settings.json'),\n z\n .object({\n enabledPlugins: z.record(z.string(), z.boolean()).optional(),\n })\n .passthrough()\n ),\n ]);\n\n const installedSet = new Set<string>(installedData ? Object.keys(installedData.plugins) : []);\n\n const enabledMap = enabledPlugins?.enabledPlugins ?? {};\n\n const installCounts = new Map<string, number>();\n if (installCountsData) {\n for (const entry of installCountsData.counts) {\n installCounts.set(entry.plugin, entry.unique_installs);\n }\n }\n\n const allPlugins: MarketplacePluginInfo[] = [];\n\n if (knownMarketplaces) {\n const scanPromises = Object.entries(knownMarketplaces).map(async ([name, meta]) => {\n if (!meta || typeof meta !== 'object') return [];\n const location = meta.installLocation;\n if (typeof location !== 'string') return [];\n return scanMarketplace(name, location, installedSet, enabledMap, installCounts);\n });\n\n const results = await Promise.all(scanPromises);\n for (const plugins of results) {\n allPlugins.push(...plugins);\n }\n }\n\n allPlugins.sort((a, b) => (b.installCount ?? 0) - (a.installCount ?? 0));\n\n logger.debug({ count: allPlugins.length }, 'Detected marketplace plugins');\n return allPlugins;\n}\n","import type { ReasoningEffort } from '@shipyard/loro-schema';\nimport type { ModelInfo } from '@shipyard/session';\nimport { profileRegistry } from '../../services/session/profiles/profile-registry.js';\nimport { logger } from '../logger.js';\n\n/**\n * `lastKnown` preserves a previously-detected model list when all profiles\n * fail their binary checks. Mirror of the `lastKnownAgents` pattern in\n * `agents.ts`.\n */\nexport async function detectModels(lastKnown?: ModelInfo[]): Promise<ModelInfo[]> {\n const results = await Promise.allSettled(\n profileRegistry.list().map((profile) => collectProfileModels(profile))\n );\n\n const models: ModelInfo[] = [];\n for (const result of results) {\n if (result.status === 'fulfilled') {\n models.push(...result.value);\n }\n }\n\n if (models.length === 0 && lastKnown && lastKnown.length > 0) {\n logger.warn(\n { lastKnownCount: lastKnown.length },\n 'detectModels: all profiles failed — preserving lastKnown'\n );\n return lastKnown;\n }\n\n return models;\n}\n\ntype ProfileLike = ReturnType<typeof profileRegistry.list>[number];\n\nasync function collectProfileModels(profile: ProfileLike): Promise<ModelInfo[]> {\n let binaryPath: string | null = null;\n try {\n binaryPath = await profile.spawn.binaryResolver();\n } catch (err) {\n logger.debug({ err, profileId: profile.id }, 'profile binaryResolver failed');\n }\n if (binaryPath === null) return [];\n\n let probedEfforts: ReadonlySet<ReasoningEffort> | null = null;\n if (profile.probeEfforts) {\n try {\n probedEfforts = await profile.probeEfforts();\n } catch (err) {\n logger.warn({ err, profileId: profile.id }, 'probeEfforts failed — using catalog values');\n }\n }\n\n /**\n * The binary probe only sees the literal `--effort` tokens the CLI accepts\n * (`low`..`max`). Two tiers in our catalog are *synthetic* — they never\n * appear in the probed set and must not be filtered against it:\n * - `none` is our thinking-off meta-value (translated to\n * `alwaysThinkingEnabled:false`, never passed as `--effort`).\n * - `ultracode` is a Shipyard picker tier that realizes as `xhigh` + a\n * standing multi-agent grant; it's coerced to `xhigh` at the SDK\n * boundary (`resolveSupportedEffort`), so it's valid exactly when the\n * CLI accepts `xhigh`. Gating on `xhigh` means it disappears correctly\n * if a future CLI ever drops the tier it rides on.\n */\n const filterEfforts = (efforts: ReasoningEffort[]): ReasoningEffort[] => {\n const probed = probedEfforts;\n if (!probed) return efforts;\n return efforts.filter((e) => {\n if (e === 'none') return true;\n if (e === 'ultracode') return probed.has('xhigh');\n return probed.has(e);\n });\n };\n\n /**\n * Effort intensity ordering. When the catalog's desired default is not in\n * the probed/supported set (e.g. xhigh requested but the bundled CLI\n * doesn't expose it), walk DOWN from the desired tier to the next-lower\n * available effort. The previous \"last element wins\" fallback could jump\n * from xhigh to max, which is semantically worse: max is unconstrained\n * tokens, not \"next step down.\" `'none'` is excluded because it's our\n * meta-value for thinking-off, not an effort intensity. `'ultracode'`\n * sits at the xhigh level (it's the CLI-side multi-agent wrapper around\n * xhigh) so we treat it as xhigh-intensity for fallback purposes.\n */\n const INTENSITY_ORDER: readonly ReasoningEffort[] = [\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n 'ultracode',\n 'max',\n ];\n const pickDefault = (desired: ReasoningEffort, efforts: ReasoningEffort[]): ReasoningEffort => {\n if (efforts.includes(desired)) return desired;\n const desiredIdx = INTENSITY_ORDER.indexOf(desired);\n if (desiredIdx >= 0) {\n for (let i = desiredIdx - 1; i >= 0; i--) {\n const candidate = INTENSITY_ORDER[i];\n if (candidate !== undefined && efforts.includes(candidate)) return candidate;\n }\n }\n const concrete = efforts.filter((e) => e !== 'none');\n return concrete[concrete.length - 1] ?? 'low';\n };\n\n return profile.models.map((m) => {\n const efforts = filterEfforts(m.supportedEfforts);\n const firstEffort = efforts[0];\n const reasoning =\n firstEffort !== undefined\n ? {\n efforts,\n defaultEffort: m.defaultEffort ? pickDefault(m.defaultEffort, efforts) : firstEffort,\n }\n : undefined;\n return {\n id: m.id,\n name: m.displayName,\n provider: profile.id,\n description: m.description,\n reasoning,\n ...(m.supportsFastMode === true ? { supportsFastMode: true as const } : {}),\n };\n });\n}\n","/**\n * Per-profile auth adapter registry.\n *\n * Single source of truth for \"how do I turn a profile's auth payload into\n * the canonical `RuntimeAuthStatus` wire shape, and into the per-profile\n * `daemon.capabilities` slot?\" The capability refresh chokepoint\n * (`runProfileAwareRefresh`), the boot-time `detectCapabilities` pass,\n * and the post-login refreshes inside `control-channel-wiring.ts` all\n * iterate this table instead of hardcoding `if profileId === codex` /\n * `if anthropic && codex && cursor` branches.\n *\n * **Adding a fourth agent profile:** register the profile in\n * `profileRegistry`, then add a single row here — narrower (Zod parse\n * against the profile-specific status schema), runtime mapper (project\n * onto `RuntimeAuthStatus`), and `capabilitySlot` (which `daemon.capabilities`\n * field the per-profile snapshot writes to) — and add its id to the\n * `PROFILE_IDS` array below. The iteration loops everywhere else pick\n * it up automatically.\n *\n * Why this lives in `shared/capabilities/runtime/` and not on each\n * profile module: the daemon owns the wire-mapping concern (the wire\n * `RuntimeAuthStatus` shape is daemon↔browser, not agent-internal).\n * Profile modules stay focused on agent SDK adaptation; the runtime\n * layer owns the wire format.\n *\n * @see runProfileAwareRefresh in control-channel-infra-handlers.ts —\n * the capability-refresh path that drives this table on every\n * `refreshFull('cursor_login')` etc.\n */\n\nimport {\n AGENT_SYSTEM_CLAUDE_CODE,\n AGENT_SYSTEM_CODEX,\n AGENT_SYSTEM_CURSOR,\n type AgentId,\n} from '@shipyard/loro-schema';\nimport {\n type AnthropicAuthStatus,\n AnthropicAuthStatusSchema,\n type CodexAuthStatus,\n CodexAuthStatusSchema,\n type CursorAuthStatus,\n CursorAuthStatusSchema,\n type RuntimeAuthStatus,\n} from '@shipyard/session';\n\nimport { CLAUDE_CODE_RUNTIME_ID, CODEX_RUNTIME_ID, CURSOR_RUNTIME_ID } from './catalog.js';\n\nexport interface ProfileAuthAdapter {\n /** Zod-parse the `authDetector`'s `auth: unknown` payload. Returns `null` on schema mismatch. */\n narrow: (value: unknown) => unknown | null;\n /**\n * Project an arbitrary detector payload onto the canonical wire shape.\n * Narrows internally so the iteration sites never need a type assertion;\n * returns `null` when the payload can't be parsed against the\n * profile-specific Zod schema.\n */\n toRuntimeAuthStatus: (value: unknown) => RuntimeAuthStatus | null;\n /** Per-profile slot name on `CapabilitiesPayload` / `MachineCapabilities`. */\n capabilitySlot: 'anthropicAuth' | 'codexAuth' | 'cursorAuth';\n /** Canonical runtime ID used as the `runtimeAuth` map key. */\n runtimeId: string;\n}\n\nexport function narrowAnthropicAuth(value: unknown): AnthropicAuthStatus | null {\n const parsed = AnthropicAuthStatusSchema.safeParse(value);\n return parsed.success ? parsed.data : null;\n}\n\nexport function narrowCodexAuth(value: unknown): CodexAuthStatus | null {\n const parsed = CodexAuthStatusSchema.safeParse(value);\n return parsed.success ? parsed.data : null;\n}\n\nexport function narrowCursorAuth(value: unknown): CursorAuthStatus | null {\n const parsed = CursorAuthStatusSchema.safeParse(value);\n return parsed.success ? parsed.data : null;\n}\n\nfunction anthropicAuthToRuntimeAuthStatus(status: AnthropicAuthStatus): RuntimeAuthStatus {\n return {\n runtimeId: CLAUDE_CODE_RUNTIME_ID,\n providerId: 'anthropic',\n status: status.status,\n method: status.method,\n email: status.email,\n orgName: status.orgName,\n subscriptionType: status.subscriptionType,\n apiProvider: status.apiProvider,\n authMismatch: status.authMismatch\n ? {\n selected: status.authMismatch.selected,\n envMethod: status.authMismatch.envMethod,\n envVar: status.authMismatch.envVar,\n }\n : undefined,\n };\n}\n\nfunction codexAuthToRuntimeAuthStatus(status: CodexAuthStatus): RuntimeAuthStatus {\n return {\n runtimeId: CODEX_RUNTIME_ID,\n providerId: 'openai',\n status: status.status,\n method: status.method,\n email: status.email,\n };\n}\n\nfunction cursorAuthToRuntimeAuthStatus(status: CursorAuthStatus): RuntimeAuthStatus {\n return {\n runtimeId: CURSOR_RUNTIME_ID,\n providerId: 'cursor',\n status: status.status,\n method: status.method,\n email: status.email,\n apiKeyHint: status.apiKeyHint,\n };\n}\n\n/**\n * Canonical iteration order over registered profiles. Sites that need\n * to walk the profile registry use this array so `Object.keys(...)` cast\n * to `AgentId[]` never appears at the call site. Adding a fourth profile\n * means appending its id here once.\n */\nexport const PROFILE_IDS: readonly AgentId[] = [\n AGENT_SYSTEM_CLAUDE_CODE,\n AGENT_SYSTEM_CODEX,\n AGENT_SYSTEM_CURSOR,\n];\n\n/**\n * Registry of per-profile auth adapters. Iterated by every site that\n * needs to (a) narrow an `unknown` auth payload from a detector, (b)\n * project profile-specific status onto wire shape, or (c) decide which\n * per-profile slot on `CapabilitiesPayload` receives the new status.\n *\n * Adding a fourth profile is mechanical: register the profile, add a\n * row here. No edits to the iteration sites.\n */\nexport const PROFILE_AUTH_ADAPTERS: Record<AgentId, ProfileAuthAdapter> = {\n [AGENT_SYSTEM_CLAUDE_CODE]: {\n narrow: narrowAnthropicAuth,\n toRuntimeAuthStatus: (value) => {\n const narrowed = narrowAnthropicAuth(value);\n return narrowed ? anthropicAuthToRuntimeAuthStatus(narrowed) : null;\n },\n capabilitySlot: 'anthropicAuth',\n runtimeId: CLAUDE_CODE_RUNTIME_ID,\n },\n [AGENT_SYSTEM_CODEX]: {\n narrow: narrowCodexAuth,\n toRuntimeAuthStatus: (value) => {\n const narrowed = narrowCodexAuth(value);\n return narrowed ? codexAuthToRuntimeAuthStatus(narrowed) : null;\n },\n capabilitySlot: 'codexAuth',\n runtimeId: CODEX_RUNTIME_ID,\n },\n [AGENT_SYSTEM_CURSOR]: {\n narrow: narrowCursorAuth,\n toRuntimeAuthStatus: (value) => {\n const narrowed = narrowCursorAuth(value);\n return narrowed ? cursorAuthToRuntimeAuthStatus(narrowed) : null;\n },\n capabilitySlot: 'cursorAuth',\n runtimeId: CURSOR_RUNTIME_ID,\n },\n};\n\n/**\n * Read every profile's slot off a `CapabilitiesPayload`-shaped object\n * into the canonical `Partial<Record<AgentId, unknown>>` snapshot. Pass\n * `override` to substitute a freshly-detected status for one profile\n * without losing the others.\n *\n * Iterates `PROFILE_IDS` so adding a fourth profile picks up its\n * `capabilitySlot` automatically. Callers in `control-channel-wiring.ts`\n * use this to keep `runtimeAuth` consistent across every per-profile\n * login/logout handler without hardcoding the other agents' slots.\n */\nexport function snapshotProfileAuth(\n capabilities: Record<string, unknown> | undefined,\n override?: Partial<Record<AgentId, unknown>>\n): Partial<Record<AgentId, unknown>> {\n const out: Partial<Record<AgentId, unknown>> = {};\n for (const profileId of PROFILE_IDS) {\n const adapter = PROFILE_AUTH_ADAPTERS[profileId];\n const overridden = override?.[profileId];\n if (overridden !== undefined) {\n out[profileId] = overridden;\n continue;\n }\n const slotValue = capabilities?.[adapter.capabilitySlot];\n if (slotValue !== undefined && slotValue !== null) {\n out[profileId] = slotValue;\n }\n }\n return out;\n}\n\n/**\n * Build the canonical `runtimeAuth` map from a profile-keyed snapshot.\n *\n * Iterates `PROFILE_IDS` so the call site never has to know which\n * profiles exist — it passes everything it has, and the adapters decide\n * what lands in the wire map.\n */\nexport function buildRuntimeAuthMapFromSnapshot(\n snapshot: Partial<Record<AgentId, unknown>>\n): Record<string, RuntimeAuthStatus> {\n const out: Record<string, RuntimeAuthStatus> = {};\n for (const profileId of PROFILE_IDS) {\n const adapter = PROFILE_AUTH_ADAPTERS[profileId];\n const status = snapshot[profileId];\n if (status === undefined || status === null) continue;\n const mapped = adapter.toRuntimeAuthStatus(status);\n if (mapped !== null) out[adapter.runtimeId] = mapped;\n }\n return out;\n}\n","import { z } from 'zod';\nimport { runWithTimeout } from './shell.js';\n\n/**\n * Fields supported by `gh search prs --json`. The set of accepted fields is\n * narrower than `gh pr view --json`: ref names, head repository, review\n * decision, line/file deltas, comment authors, and review requests are NOT\n * available here. Requesting any unsupported field causes gh to exit with\n * \"Unknown JSON field\". The richer fields are populated by the per-PR\n * enrichment step in `searchPrs` via `gh pr view`.\n */\nconst SEARCH_PR_JSON_FIELDS =\n 'number,title,url,state,isDraft,author,labels,updatedAt,createdAt,assignees,repository,commentsCount';\n\n/**\n * Fields fetched per-PR via `gh pr view --json` to enrich the partial search\n * result. These are the fields that `gh search prs` does not expose but the\n * downstream consumers (worktree creation, post-filter evaluation, browser\n * autocomplete) require.\n */\nconst PR_VIEW_JSON_FIELDS =\n 'baseRefName,headRefName,headRepository,isCrossRepository,reviewDecision,additions,deletions,changedFiles,comments,reviewRequests';\n\n/**\n * Concurrency cap for the per-PR enrichment fan-out. Bounded to avoid hitting\n * gh CLI rate limits or spawning hundreds of subprocesses on a large search\n * result. 8 is conservative enough for typical PR-review section sizes (low\n * tens) while still amortizing latency.\n */\nconst ENRICHMENT_CONCURRENCY = 8;\n\n/** Per-call timeout (ms) for both the search call and each enrichment call. */\nconst GH_CALL_TIMEOUT_MS = 30_000;\n\nconst GH_SEARCH_STATE_MAP: Record<string, string> = {\n OPEN: 'open',\n CLOSED: 'closed',\n MERGED: 'merged',\n};\n\nconst PRSummarySchema = z.object({\n number: z.number(),\n title: z.string(),\n /** Lowercased state: open | closed | merged | draft */\n state: z.string(),\n isDraft: z.boolean(),\n url: z.string(),\n /** Login string (author.login extracted from the raw object) */\n author: z.string(),\n baseRefName: z.string(),\n headRefName: z.string(),\n /** Short repo name (headRepository.name extracted from the gh pr view response) */\n headRepository: z.string(),\n /**\n * True when the PR's head ref lives on a fork repository, not on the\n * same repository as the base. Used to gate worktree dispatch — fork\n * branches aren't reachable via the user's `origin` remote.\n */\n isCrossRepository: z.boolean(),\n updatedAt: z.union([z.string(), z.number()]),\n createdAt: z.union([z.string(), z.number()]),\n reviewDecision: z.string().nullable(),\n labels: z.array(z.object({ name: z.string(), color: z.string() })),\n additions: z.number(),\n deletions: z.number(),\n changedFiles: z.number(),\n /** Comment count */\n comments: z.number(),\n assignees: z.array(z.object({ login: z.string() })),\n reviewRequests: z.array(z.object({ login: z.string() })),\n});\n\nexport type PRSummary = z.infer<typeof PRSummarySchema>;\n\n/**\n * Shape of an item in the `gh search prs --json` response. Limited to the\n * fields gh search supports — see SEARCH_PR_JSON_FIELDS.\n */\nconst RawSearchPRSchema = z\n .object({\n number: z.number().optional(),\n title: z.string().optional(),\n url: z.string().optional(),\n state: z.string().optional(),\n isDraft: z.boolean().optional(),\n author: z.object({ login: z.string() }).passthrough().optional(),\n updatedAt: z.string().optional(),\n createdAt: z.string().optional(),\n labels: z.array(z.object({ name: z.string(), color: z.string() }).passthrough()).optional(),\n assignees: z.array(z.object({ login: z.string() }).passthrough()).optional(),\n repository: z\n .object({ name: z.string().optional(), nameWithOwner: z.string().optional() })\n .passthrough()\n .optional(),\n commentsCount: z.number().optional(),\n })\n .passthrough();\n\ntype RawSearchPR = z.infer<typeof RawSearchPRSchema>;\n\n/**\n * `gh pr view --json reviewRequests` emits a tagged union of User vs Team\n * variants (see gh-cli api/export_pr.go ~L141). Only User has `login`; Team\n * has `name`+`slug` and no `login`. Bot/Mannequin variants are silently dropped\n * by gh's export switch, so we won't see them in practice. Earlier versions of\n * this schema declared `login: z.string()` unconditionally, which caused Zod\n * to reject any PR with a team review request and dropped the whole PR from\n * the reviews sidebar (#3122).\n */\nconst RawReviewRequestSchema = z.discriminatedUnion('__typename', [\n z.object({ __typename: z.literal('User'), login: z.string() }).passthrough(),\n z.object({ __typename: z.literal('Team'), slug: z.string() }).passthrough(),\n]);\n\n/**\n * Shape of the `gh pr view --json` response for the enrichment fields.\n * `headRepository` from `gh pr view` is `{ id, name, nameWithOwner }` — the\n * `name` field is the short repo name expected by PRSummary consumers.\n */\nconst RawViewPRSchema = z\n .object({\n baseRefName: z.string().optional(),\n headRefName: z.string().optional(),\n headRepository: z.object({ name: z.string().optional() }).passthrough().nullable().optional(),\n isCrossRepository: z.boolean().optional(),\n reviewDecision: z.string().nullable().optional(),\n additions: z.number().optional(),\n deletions: z.number().optional(),\n changedFiles: z.number().optional(),\n comments: z.union([z.number(), z.array(z.unknown())]).optional(),\n reviewRequests: z.array(RawReviewRequestSchema).optional(),\n })\n .passthrough();\n\ntype RawViewPR = z.infer<typeof RawViewPRSchema>;\n\n/** Combined shape after merging search + view responses for a single PR. */\ninterface MergedPR {\n search: RawSearchPR;\n view: RawViewPR | null;\n}\n\nfunction resolveSearchState(raw: RawSearchPR): string {\n const isDraft = raw.isDraft === true;\n if (isDraft) return 'draft';\n const ghState = typeof raw.state === 'string' ? raw.state.toUpperCase() : '';\n return GH_SEARCH_STATE_MAP[ghState] ?? 'open';\n}\n\nfunction mapSearchLabel(l: { name: string; color: string }): { name: string; color: string } {\n return {\n name: typeof l.name === 'string' ? l.name : '',\n color: typeof l.color === 'string' && l.color !== '' ? `#${l.color}` : '',\n };\n}\n\nfunction resolveCommentCount(merged: MergedPR): number {\n const c = merged.view?.comments;\n if (typeof c === 'number') return c;\n if (Array.isArray(c)) return c.length;\n /** Fall back to the search-only commentsCount when the view call failed. */\n return merged.search.commentsCount ?? 0;\n}\n\nfunction extractMergedScalars(merged: MergedPR) {\n const { search, view } = merged;\n return {\n number: search.number ?? 0,\n title: search.title ?? '',\n url: search.url ?? '',\n author: search.author?.login ?? '',\n baseRefName: view?.baseRefName ?? '',\n headRefName: view?.headRefName ?? '',\n headRepository: view?.headRepository?.name ?? '',\n isCrossRepository: view?.isCrossRepository ?? false,\n updatedAt: search.updatedAt ?? '',\n createdAt: search.createdAt ?? '',\n reviewDecision: view?.reviewDecision ?? null,\n additions: view?.additions ?? 0,\n deletions: view?.deletions ?? 0,\n changedFiles: view?.changedFiles ?? 0,\n };\n}\n\nfunction mapMergedPR(merged: MergedPR): PRSummary {\n const { search, view } = merged;\n return {\n ...extractMergedScalars(merged),\n state: resolveSearchState(search),\n isDraft: search.isDraft === true,\n labels: (search.labels ?? []).map(mapSearchLabel),\n comments: resolveCommentCount(merged),\n assignees: (search.assignees ?? []).map((a) => ({ login: a.login })),\n reviewRequests: (view?.reviewRequests ?? []).flatMap((r) =>\n r.__typename === 'User' ? [{ login: r.login }] : []\n ),\n };\n}\n\n/**\n * Run `fn` over `items` with at most `concurrency` calls in flight at once.\n * Order of results matches order of inputs. Inlined to avoid pulling in a\n * dependency for a single use site.\n */\nasync function parallelMap<T, R>(\n items: T[],\n concurrency: number,\n fn: (item: T, index: number) => Promise<R>\n): Promise<R[]> {\n const results = new Array<R>(items.length);\n let nextIndex = 0;\n\n const workers = Array.from(\n { length: Math.min(concurrency, items.length) },\n async (): Promise<void> => {\n while (true) {\n const i = nextIndex++;\n if (i >= items.length) return;\n const item = items[i];\n if (item === undefined) return;\n results[i] = await fn(item, i);\n }\n }\n );\n\n await Promise.all(workers);\n return results;\n}\n\n/**\n * Fetch enrichment fields for a single PR via `gh pr view`. Returns null on\n * any failure so the search result is preserved with default-valued enrichment\n * fields rather than dropping the whole batch.\n */\ntype EnrichResult = { ok: true; data: RawViewPR } | { ok: false; error: string };\n\nasync function enrichPr(url: string, cwd: string): Promise<EnrichResult> {\n try {\n const stdout = await runWithTimeout(\n 'gh',\n ['pr', 'view', url, '--json', PR_VIEW_JSON_FIELDS],\n cwd,\n GH_CALL_TIMEOUT_MS\n );\n const parsed = RawViewPRSchema.safeParse(JSON.parse(stdout));\n if (!parsed.success) {\n return { ok: false, error: `parse failed: ${parsed.error.message.slice(0, 200)}` };\n }\n return { ok: true, data: parsed.data };\n } catch (err: unknown) {\n return { ok: false, error: err instanceof Error ? err.message.slice(0, 300) : String(err) };\n }\n}\n\n/**\n * Search PRs via `gh search prs` and enrich each result with `gh pr view` to\n * populate fields not exposed by gh's search endpoint (ref names, head\n * repository, review decision, line/file deltas, review requests).\n *\n * Returns a typed PRSummary array. On any gh failure (network, auth, parse\n * error) of the search itself, returns []. Per-PR enrichment failures fall\n * through with default values so a single bad PR does not drop the batch.\n */\nexport interface EnrichFailure {\n url: string;\n error: string;\n}\n\nexport async function searchPrs(\n args: string[],\n cwd: string,\n onEnrichFailure?: (failures: EnrichFailure[], total: number) => void\n): Promise<PRSummary[]> {\n let stdout: string;\n try {\n stdout = await runWithTimeout(\n 'gh',\n ['search', 'prs', ...args, '--json', SEARCH_PR_JSON_FIELDS],\n cwd,\n GH_CALL_TIMEOUT_MS\n );\n } catch {\n return [];\n }\n\n const rawArray = z.array(RawSearchPRSchema).safeParse(JSON.parse(stdout));\n if (!rawArray.success) return [];\n\n const enrichInputs = rawArray.data\n .map((search) => ({ search, url: search.url ?? '' }))\n .filter((entry): entry is { search: RawSearchPR; url: string } => entry.url !== '');\n\n const enrichedResults = await parallelMap(enrichInputs, ENRICHMENT_CONCURRENCY, (entry) =>\n enrichPr(entry.url, cwd)\n );\n\n const failures: EnrichFailure[] = [];\n for (let i = 0; i < enrichInputs.length; i++) {\n const result = enrichedResults[i];\n if (result && !result.ok) {\n const entry = enrichInputs[i];\n if (entry) failures.push({ url: entry.url, error: result.error });\n }\n }\n if (failures.length > 0) onEnrichFailure?.(failures, enrichInputs.length);\n\n return enrichInputs.map((entry, i) => {\n const result = enrichedResults[i];\n const view = result?.ok ? result.data : null;\n return mapMergedPR({ search: entry.search, view });\n });\n}\n\nfunction isValidTimestampStr(value: string): boolean {\n if (!value) return false;\n return !Number.isNaN(Date.parse(value));\n}\n\n/**\n * Poll `GET /notifications` with an optional `If-Modified-Since` header.\n * Returns `{ updated: false }` for 304 responses and\n * `{ updated: true, lastModified }` for 200 responses.\n * On gh failure, returns `{ updated: false, lastModified: null }` so the\n * caller skips the full section refetch rather than crashing.\n */\nexport async function notificationsSince(\n timestamp: string | null,\n cwd: string\n): Promise<{ updated: boolean; lastModified: string | null }> {\n const ghArgs = ['api', '/notifications', '--include'];\n if (timestamp !== null && isValidTimestampStr(timestamp)) {\n ghArgs.push('-H', `If-Modified-Since: ${timestamp}`);\n }\n try {\n const stdout = await runWithTimeout('gh', ghArgs, cwd, 15_000);\n const lines = stdout.split('\\n');\n const statusLine = lines[0] ?? '';\n const updated = !statusLine.includes(' 304');\n let lastModified: string | null = null;\n for (const line of lines) {\n if (/^last-modified:/i.test(line)) {\n lastModified = line.split(/:\\s+(.+)/)[1]?.trim() ?? null;\n break;\n }\n }\n return { updated, lastModified };\n } catch {\n return { updated: false, lastModified: null };\n }\n}\n\n/**\n * Returns the parsed output of `gh status --json`, or null if `gh status`\n * does not support --json or fails for any reason.\n */\nexport async function ghStatus(cwd: string): Promise<unknown> {\n try {\n const stdout = await runWithTimeout('gh', ['status', '--json'], cwd, 10_000);\n return JSON.parse(stdout);\n } catch {\n return null;\n }\n}\n\nexport const _testing = {\n SEARCH_PR_JSON_FIELDS,\n PR_VIEW_JSON_FIELDS,\n ENRICHMENT_CONCURRENCY,\n};\n","import { createOneShotPool, type ExecFileLike, type OneShotPool } from '@shipyard/local-runtime';\nimport type { CICheck, PRComment, PRData, PRReviewer, PRState } from '@shipyard/loro-schema';\nimport { z } from 'zod';\nimport { BUFFER_OVERFLOW_MSG, isMaxBufferError, runWithTimeout, truncateDiff } from './shell.js';\n\n/**\n * Shared OneShotPool for `gh` CLI calls. Provides two wins:\n *\n * 1. TTL cache — a second call with the same args+cwd within 60s returns the\n * cached result without spawning, matching the 30s poll interval.\n * 2. Coalescing — concurrent calls with identical args share one subprocess.\n *\n * Covers the high-frequency read paths: `getPRForCurrentBranch`,\n * `getAssignedReviews`, `getUserPRs`, `getPRByBranch`. One-off writes\n * (approve, merge, comment, label) intentionally stay on `runWithTimeout`\n * because their args vary per call and caching would mask real mutations.\n */\nlet ghPool: OneShotPool = createOneShotPool({ ttlMs: 60_000 });\n\nexport type { PRSummary } from './git-pr-search.js';\nexport { ghStatus, notificationsSince, searchPrs } from './git-pr-search.js';\n\nconst GH_PR_JSON_FIELDS =\n 'number,title,state,author,url,baseRefName,headRefName,headRefOid,body,isDraft,additions,deletions,changedFiles,createdAt,updatedAt,mergedAt,mergeCommit,mergeStateStatus,autoMergeRequest,statusCheckRollup,reviews,reviewRequests,comments,labels,assignees,reviewDecision,mergeable';\n\nconst GH_STATE_MAP: Record<string, PRState> = {\n OPEN: 'open',\n CLOSED: 'closed',\n MERGED: 'merged',\n};\n\nconst GhPRResponseSchema = z\n .object({\n number: z.number().optional(),\n title: z.string().optional(),\n state: z.string().optional(),\n author: z.object({ login: z.string() }).passthrough().optional(),\n url: z.string().optional(),\n baseRefName: z.string().optional(),\n headRefName: z.string().optional(),\n body: z.string().optional(),\n isDraft: z.boolean().optional(),\n additions: z.number().optional(),\n deletions: z.number().optional(),\n changedFiles: z.number().optional(),\n createdAt: z.string().optional(),\n updatedAt: z.string().optional(),\n statusCheckRollup: z.array(z.record(z.string(), z.unknown())).optional(),\n reviews: z\n .union([\n z.array(z.record(z.string(), z.unknown())),\n z.object({ nodes: z.array(z.record(z.string(), z.unknown())) }).passthrough(),\n ])\n .optional(),\n comments: z\n .union([\n z.array(z.record(z.string(), z.unknown())),\n z.object({ nodes: z.array(z.record(z.string(), z.unknown())) }).passthrough(),\n ])\n .optional(),\n })\n .passthrough();\n\nconst GhPRListResponseSchema = z.array(GhPRResponseSchema);\n\nexport function parseTimestamp(value: unknown): number | null {\n if (typeof value === 'string') {\n if (value.startsWith('0001-')) return null;\n const parsed = new Date(value).getTime();\n if (!Number.isNaN(parsed)) return parsed;\n }\n if (typeof value === 'number') return value;\n return null;\n}\n\n// eslint-disable-next-line no-restricted-syntax -- gh CLI output needs runtime field access\nfunction field(obj: unknown, key: string): unknown {\n if (typeof obj === 'object' && obj !== null && key in obj) {\n return (obj as never)[key];\n }\n return undefined;\n}\n\n/** Narrow unknown to Record<string, unknown>, defaulting to empty object */\nfunction toRecord(value: unknown): Record<string, unknown> {\n if (typeof value === 'object' && value !== null) return value as never;\n return {};\n}\n\nfunction extractOid(value: unknown): string | null {\n if (typeof value === 'object' && value !== null && 'oid' in value) {\n const rec = toRecord(value);\n return typeof rec.oid === 'string' ? rec.oid : null;\n }\n return null;\n}\n\nfunction extractLogin(obj: unknown): string {\n const login = field(obj, 'login');\n return typeof login === 'string' ? login : '';\n}\n\nfunction extractStringField(obj: unknown, f: string): string | null {\n const val = field(obj, f);\n return typeof val === 'string' ? val : null;\n}\n\nfunction extractArrayOrNodes(value: unknown): unknown[] {\n if (Array.isArray(value)) return value;\n const nodes = field(value, 'nodes');\n if (Array.isArray(nodes)) return nodes;\n return [];\n}\n\nfunction mapCheckStatus(check: Record<string, unknown>): CICheck['status'] {\n const state = typeof check.state === 'string' ? check.state.toLowerCase() : '';\n const conclusion = typeof check.conclusion === 'string' ? check.conclusion.toLowerCase() : '';\n\n if (conclusion === 'success') return 'success';\n if (conclusion === 'failure' || conclusion === 'timed_out' || conclusion === 'action_required')\n return 'failure';\n if (conclusion === 'neutral') return 'neutral';\n if (conclusion === 'skipped') return 'skipped';\n if (conclusion === 'cancelled') return 'cancelled';\n\n if (state === 'success') return 'success';\n if (state === 'failure' || state === 'error') return 'failure';\n if (state === 'pending' || state === 'queued' || state === 'in_progress') return 'pending';\n\n return 'pending';\n}\n\nfunction mapReviewState(value: unknown): PRReviewer['state'] {\n if (typeof value !== 'string') return 'pending';\n const upper = value.toUpperCase();\n if (upper === 'APPROVED') return 'approved';\n if (upper === 'CHANGES_REQUESTED') return 'changes_requested';\n if (upper === 'COMMENTED') return 'commented';\n if (upper === 'DISMISSED') return 'dismissed';\n return 'pending';\n}\n\n// eslint-disable-next-line no-restricted-syntax -- gh CLI output items are untyped\nfunction mapGhCheck(c: Record<string, unknown>): CICheck {\n const name = typeof c.name === 'string' ? c.name : typeof c.context === 'string' ? c.context : '';\n const url =\n typeof c.targetUrl === 'string'\n ? c.targetUrl\n : typeof c.detailsUrl === 'string'\n ? c.detailsUrl\n : null;\n return {\n name,\n status: mapCheckStatus(c),\n conclusion: typeof c.conclusion === 'string' ? c.conclusion.toLowerCase() : null,\n url,\n startedAt: parseTimestamp(c.startedAt),\n completedAt: parseTimestamp(c.completedAt),\n };\n}\n\n// eslint-disable-next-line no-restricted-syntax -- gh CLI output items are untyped\nfunction mapGhReviewer(r: Record<string, unknown>): PRReviewer {\n return {\n login: extractLogin(r.author),\n state: mapReviewState(r.state),\n avatarUrl: extractStringField(r.author, 'avatarUrl'),\n submittedAt: parseTimestamp(r.submittedAt),\n };\n}\n\n/**\n * Legacy mapper for embedded `gh pr view --json comments` output. The\n * embedded payload drops anchoring fields (commit_id, in_reply_to_id,\n * etc.) so the new fields default to null/false. Use `getPRReviewComments`\n * for fully-anchored review-comment ingest; this mapper exists only for\n * the existing `mapGhPRToPRData` path which builds the PR-panel summary.\n */\n// eslint-disable-next-line no-restricted-syntax -- gh CLI output items are untyped\nfunction mapGhComment(c: Record<string, unknown>): PRComment {\n const author = extractLogin(c.author);\n return {\n id: typeof c.id === 'string' ? c.id : String(c.id ?? ''),\n author,\n body: typeof c.body === 'string' ? c.body : '',\n createdAt: parseTimestamp(c.createdAt) ?? 0,\n updatedAt: typeof c.updatedAt === 'string' ? parseTimestamp(c.updatedAt) : null,\n path: typeof c.path === 'string' ? c.path : null,\n line: typeof c.line === 'number' ? c.line : null,\n side: typeof c.side === 'string' ? c.side : null,\n isReviewComment: c.pullRequestReview !== undefined && c.pullRequestReview !== null,\n commitId: null,\n diffHunk: null,\n inReplyToId: null,\n pullRequestReviewId: null,\n threadId: null,\n htmlUrl: null,\n isResolved: false,\n isOutdated: false,\n startLine: null,\n startSide: null,\n authorIsBot: detectAuthorIsBot(author),\n };\n}\n\nfunction checkPriority(status: CICheck['status']): number {\n if (status === 'pending') return 2;\n if (status === 'cancelled') return 0;\n return 1;\n}\n\nfunction deduplicateChecks(allChecks: CICheck[]): CICheck[] {\n const byName = new Map<string, CICheck>();\n for (const check of allChecks) {\n const existing = byName.get(check.name);\n if (!existing) {\n byName.set(check.name, check);\n continue;\n }\n const ep = checkPriority(existing.status);\n const np = checkPriority(check.status);\n if (np > ep || (np === ep && (check.startedAt ?? 0) > (existing.startedAt ?? 0))) {\n byName.set(check.name, check);\n }\n }\n return Array.from(byName.values());\n}\n\nfunction extractScalarFields(raw: Record<string, unknown>) {\n return {\n number: typeof raw.number === 'number' ? raw.number : 0,\n title: typeof raw.title === 'string' ? raw.title : '',\n author: extractLogin(raw.author),\n url: typeof raw.url === 'string' ? raw.url : '',\n baseRef: typeof raw.baseRefName === 'string' ? raw.baseRefName : '',\n headRef: typeof raw.headRefName === 'string' ? raw.headRefName : '',\n body: typeof raw.body === 'string' ? raw.body : '',\n additions: typeof raw.additions === 'number' ? raw.additions : 0,\n deletions: typeof raw.deletions === 'number' ? raw.deletions : 0,\n changedFiles: typeof raw.changedFiles === 'number' ? raw.changedFiles : 0,\n createdAt: parseTimestamp(raw.createdAt) ?? 0,\n updatedAt: parseTimestamp(raw.updatedAt) ?? 0,\n mergedAt: parseTimestamp(raw.mergedAt),\n mergeCommitSha: extractOid(raw.mergeCommit),\n mergeStateStatus: extractStringField(raw, 'mergeStateStatus'),\n autoMergeEnabled: raw.autoMergeRequest != null,\n headRefSha: typeof raw.headRefOid === 'string' ? raw.headRefOid : null,\n headCommitInBase: false,\n };\n}\n\n// eslint-disable-next-line no-restricted-syntax -- gh CLI output is untyped JSON\nexport function mapGhPRToPRData(raw: Record<string, unknown>): PRData {\n const isDraft = raw.isDraft === true;\n const ghState = typeof raw.state === 'string' ? raw.state.toUpperCase() : '';\n const state: PRState = isDraft ? 'draft' : (GH_STATE_MAP[ghState] ?? 'open');\n\n const rawChecks = Array.isArray(raw.statusCheckRollup) ? raw.statusCheckRollup : [];\n const checks = deduplicateChecks(rawChecks.map(mapGhCheck));\n const reviewers: PRReviewer[] = extractArrayOrNodes(raw.reviews).map((r) =>\n mapGhReviewer(toRecord(r))\n );\n const comments: PRComment[] = extractArrayOrNodes(raw.comments).map((c) =>\n mapGhComment(toRecord(c))\n );\n\n const labels = extractArrayOrNodes(raw.labels).map((l) => {\n const rec = toRecord(l);\n return {\n name: typeof rec.name === 'string' ? rec.name : '',\n color: typeof rec.color === 'string' && rec.color !== '' ? `#${rec.color}` : '',\n };\n });\n const assignees = extractArrayOrNodes(raw.assignees).map((a) => {\n const rec = toRecord(a);\n return {\n login: extractLogin(rec),\n avatarUrl: extractStringField(rec, 'avatarUrl'),\n };\n });\n const reviewDecision = typeof raw.reviewDecision === 'string' ? raw.reviewDecision : null;\n const mergeable = typeof raw.mergeable === 'string' ? raw.mergeable : null;\n\n return {\n ...extractScalarFields(raw),\n state,\n isDraft,\n checks,\n reviewers,\n comments,\n labels,\n assignees,\n reviewDecision,\n mergeable,\n };\n}\n\nexport async function getPRForCurrentBranch(cwd: string): Promise<PRData | null> {\n try {\n const result = await ghPool.exec(['gh', 'pr', 'view', '--json', GH_PR_JSON_FIELDS], {\n cwd,\n timeoutMs: 15_000,\n });\n const parseResult = GhPRResponseSchema.safeParse(JSON.parse(result.value.trim()));\n if (!parseResult.success) {\n return null;\n }\n return mapGhPRToPRData(parseResult.data);\n } catch {\n return null;\n }\n}\n\nexport async function getPRDiff(cwd: string, prNumber: number): Promise<string> {\n try {\n const result = await runWithTimeout(\n 'gh',\n ['pr', 'diff', String(prNumber), '--color=never'],\n cwd,\n 15_000\n );\n return truncateDiff(result);\n } catch (err: unknown) {\n if (isMaxBufferError(err)) return BUFFER_OVERFLOW_MSG;\n return '';\n }\n}\n\nexport async function getPRFiles(\n cwd: string,\n prNumber: number\n): Promise<Array<{ path: string; status: string }>> {\n try {\n const stdout = await runWithTimeout(\n 'gh',\n ['pr', 'view', String(prNumber), '--json', 'files'],\n cwd,\n 15_000\n );\n // eslint-disable-next-line no-restricted-syntax -- gh CLI output is untyped JSON\n const parsed = JSON.parse(stdout) as {\n files?: Array<{ path?: string; additions?: number; deletions?: number }>;\n };\n if (!Array.isArray(parsed.files)) return [];\n return parsed.files.map((f) => ({\n path: typeof f.path === 'string' ? f.path : '',\n status: f.additions !== undefined || f.deletions !== undefined ? 'M' : 'U',\n }));\n } catch {\n return [];\n }\n}\n\nexport async function getAssignedReviews(cwd: string): Promise<PRData[]> {\n try {\n const result = await ghPool.exec(\n [\n 'gh',\n 'pr',\n 'list',\n '--search',\n 'is:open review-requested:@me',\n '--json',\n GH_PR_JSON_FIELDS,\n '--limit',\n '10',\n ],\n { cwd, timeoutMs: 15_000 }\n );\n const parseResult = GhPRListResponseSchema.safeParse(JSON.parse(result.value.trim()));\n if (!parseResult.success) return [];\n return parseResult.data.map(mapGhPRToPRData);\n } catch {\n return [];\n }\n}\n\nfunction prRankScore(pr: PRData): number {\n if (pr.state === 'open' || pr.state === 'draft') return 3;\n if (pr.state === 'merged') return 2;\n if (pr.state === 'closed') return 1;\n return 0;\n}\n\nexport async function getPRByBranch(cwd: string, branch: string): Promise<PRData | null> {\n try {\n const result = await ghPool.exec(\n [\n 'gh',\n 'pr',\n 'list',\n '--head',\n branch,\n '--state',\n 'all',\n '--limit',\n '5',\n '--json',\n GH_PR_JSON_FIELDS,\n ],\n { cwd, timeoutMs: 15_000 }\n );\n const parseResult = GhPRListResponseSchema.safeParse(JSON.parse(result.value.trim()));\n if (!parseResult.success) return null;\n const prs = parseResult.data.map(mapGhPRToPRData);\n if (prs.length === 0) return null;\n prs.sort((a, b) => {\n const rankDiff = prRankScore(b) - prRankScore(a);\n if (rankDiff !== 0) return rankDiff;\n return b.updatedAt - a.updatedAt;\n });\n return prs[0] ?? null;\n } catch {\n return null;\n }\n}\n\nexport async function getUserPRs(cwd: string): Promise<PRData[]> {\n try {\n const result = await ghPool.exec(\n [\n 'gh',\n 'pr',\n 'list',\n '--author',\n '@me',\n '--state',\n 'open',\n '--json',\n GH_PR_JSON_FIELDS,\n '--limit',\n '10',\n ],\n { cwd, timeoutMs: 15_000 }\n );\n const parseResult = GhPRListResponseSchema.safeParse(JSON.parse(result.value.trim()));\n if (!parseResult.success) return [];\n return parseResult.data.map(mapGhPRToPRData);\n } catch {\n return [];\n }\n}\n\nexport function deduplicatePRs(\n currentPR: PromiseSettledResult<PRData | null>,\n assignedReviews: PromiseSettledResult<PRData[]>,\n userPRs: PromiseSettledResult<PRData[]>\n): { allPRs: PRData[]; currentBranchPR: PRData | null } {\n const allPRs: PRData[] = [];\n const seen = new Set<number>();\n const currentBranchPR = currentPR.status === 'fulfilled' ? currentPR.value : null;\n if (currentBranchPR) {\n allPRs.push(currentBranchPR);\n seen.add(currentBranchPR.number);\n }\n for (const pr of assignedReviews.status === 'fulfilled' ? assignedReviews.value : []) {\n if (!seen.has(pr.number)) {\n allPRs.push(pr);\n seen.add(pr.number);\n }\n }\n for (const pr of userPRs.status === 'fulfilled' ? userPRs.value : []) {\n if (!seen.has(pr.number)) {\n allPRs.push(pr);\n seen.add(pr.number);\n }\n }\n return { allPRs, currentBranchPR };\n}\n\nexport async function approvePR(cwd: string, prNumber: number, body?: string): Promise<void> {\n const args = ['pr', 'review', String(prNumber), '--approve'];\n if (body) args.push('-b', body);\n await runWithTimeout('gh', args, cwd, 15_000);\n}\n\nexport async function mergePR(\n cwd: string,\n prNumber: number,\n strategy: 'squash' | 'merge' | 'rebase'\n): Promise<void> {\n const strategyFlag = `--${strategy}`;\n await runWithTimeout(\n 'gh',\n ['pr', 'merge', String(prNumber), strategyFlag, '--auto'],\n cwd,\n 30_000\n );\n}\n\nexport async function closePR(cwd: string, prNumber: number): Promise<void> {\n await runWithTimeout('gh', ['pr', 'close', String(prNumber)], cwd, 15_000);\n}\n\nexport async function reopenPR(cwd: string, prNumber: number): Promise<void> {\n await runWithTimeout('gh', ['pr', 'reopen', String(prNumber)], cwd, 15_000);\n}\n\nexport async function commentOnPR(cwd: string, prNumber: number, body: string): Promise<void> {\n await runWithTimeout('gh', ['pr', 'comment', String(prNumber), '-b', body], cwd, 15_000);\n}\n\nexport async function requestChanges(cwd: string, prNumber: number, body: string): Promise<void> {\n await runWithTimeout(\n 'gh',\n ['pr', 'review', String(prNumber), '--request-changes', '-b', body],\n cwd,\n 15_000\n );\n}\n\nexport async function addReviewers(\n cwd: string,\n prNumber: number,\n reviewers: string[]\n): Promise<void> {\n await runWithTimeout(\n 'gh',\n ['pr', 'edit', String(prNumber), '--add-reviewer', reviewers.join(',')],\n cwd,\n 15_000\n );\n}\n\n/**\n * Returns the set of labels that currently exist on the repo at cwd. Used to\n * filter label-add calls so we do not fail when a label is missing on the\n * target repo. Returns an empty set on any gh error (caller skips cleanly).\n */\nexport async function listRepoLabels(cwd: string): Promise<Set<string>> {\n try {\n const stdout = await runWithTimeout(\n 'gh',\n ['label', 'list', '--limit', '200', '--json', 'name'],\n cwd,\n 15_000\n );\n const parsed = z.array(z.object({ name: z.string() })).safeParse(JSON.parse(stdout));\n if (!parsed.success) return new Set();\n return new Set(parsed.data.map((l) => l.name));\n } catch {\n return new Set();\n }\n}\n\nexport async function addLabels(cwd: string, prNumber: number, labels: string[]): Promise<void> {\n if (labels.length === 0) return;\n const existing = await listRepoLabels(cwd);\n const toAdd = existing.size === 0 ? [] : labels.filter((l) => existing.has(l));\n if (toAdd.length === 0) return;\n await runWithTimeout(\n 'gh',\n ['pr', 'edit', String(prNumber), '--add-label', toAdd.join(',')],\n cwd,\n 15_000\n );\n}\n\n/**\n * Per-cwd label-ensure cache. Prevents re-invoking `gh label list` / `gh label\n * create` on every PR-attribution event within the daemon's lifetime.\n *\n * `failedLabels` stores a timestamp so a transient `gh` failure (network,\n * rate limit) does not permanently block the label for the daemon's lifetime.\n * After FAILED_LABEL_TTL_MS the entry is treated as absent and ensureLabel\n * retries the create.\n */\nconst FAILED_LABEL_TTL_MS = 10 * 60_000;\nconst ensuredLabels = new Set<string>();\nconst failedLabels = new Map<string, number>();\n\n/**\n * Guarantee that a label exists on the repo at `cwd`. Returns true if the\n * label exists (either already present or freshly created) and false if the\n * label could not be created. Caches both outcomes for the lifetime of the\n * daemon so PR attribution does not hammer `gh` on every event.\n */\nexport async function ensureLabel(\n cwd: string,\n name: string,\n color = '1f2937',\n description = 'Created by Shipyard'\n): Promise<boolean> {\n const cacheKey = `${cwd}:${name}`;\n if (ensuredLabels.has(cacheKey)) return true;\n const failedAt = failedLabels.get(cacheKey);\n if (failedAt !== undefined) {\n if (Date.now() - failedAt <= FAILED_LABEL_TTL_MS) return false;\n failedLabels.delete(cacheKey);\n }\n\n const existing = await listRepoLabels(cwd);\n if (existing.has(name)) {\n ensuredLabels.add(cacheKey);\n return true;\n }\n\n try {\n await runWithTimeout(\n 'gh',\n ['label', 'create', name, '--color', color, '--description', description],\n cwd,\n 15_000\n );\n ensuredLabels.add(cacheKey);\n return true;\n } catch {\n failedLabels.set(cacheKey, Date.now());\n return false;\n }\n}\n\nexport async function removeLabels(cwd: string, prNumber: number, labels: string[]): Promise<void> {\n await runWithTimeout(\n 'gh',\n ['pr', 'edit', String(prNumber), '--remove-label', labels.join(',')],\n cwd,\n 15_000\n );\n}\n\nexport async function addAssignees(\n cwd: string,\n prNumber: number,\n assignees: string[]\n): Promise<void> {\n await runWithTimeout(\n 'gh',\n ['pr', 'edit', String(prNumber), '--add-assignee', assignees.join(',')],\n cwd,\n 15_000\n );\n}\n\nexport async function removeAssignees(\n cwd: string,\n prNumber: number,\n assignees: string[]\n): Promise<void> {\n await runWithTimeout(\n 'gh',\n ['pr', 'edit', String(prNumber), '--remove-assignee', assignees.join(',')],\n cwd,\n 15_000\n );\n}\n\nexport async function markPRReady(cwd: string, prNumber: number): Promise<void> {\n await runWithTimeout('gh', ['pr', 'ready', String(prNumber)], cwd, 15_000);\n}\n\nexport async function convertToDraft(cwd: string, prNumber: number): Promise<void> {\n await runWithTimeout('gh', ['pr', 'ready', String(prNumber), '--undo'], cwd, 15_000);\n}\n\nexport function buildShipyardBodyMarker(taskId: string): string {\n return `<!-- shipyard: task=${taskId} -->`;\n}\n\n/**\n * Append a Shipyard marker comment to the PR body if not already present. Idempotent —\n * if the marker already exists (by substring match on `shipyard: task=`), does nothing.\n */\nexport async function appendShipyardBodyMarker(\n cwd: string,\n prNumber: number,\n taskId: string\n): Promise<void> {\n const bodyJson = await runWithTimeout(\n 'gh',\n ['pr', 'view', String(prNumber), '--json', 'body'],\n cwd,\n 15_000\n );\n let currentBody = '';\n try {\n // eslint-disable-next-line no-restricted-syntax -- gh CLI output is untyped JSON\n const parsed = JSON.parse(bodyJson) as { body?: string };\n currentBody = typeof parsed.body === 'string' ? parsed.body : '';\n } catch {\n currentBody = '';\n }\n if (currentBody.includes('shipyard: task=')) return;\n const marker = buildShipyardBodyMarker(taskId);\n const separator = currentBody.endsWith('\\n') || currentBody.length === 0 ? '' : '\\n\\n';\n const nextBody = `${currentBody}${separator}${marker}\\n`;\n await runWithTimeout('gh', ['pr', 'edit', String(prNumber), '--body', nextBody], cwd, 15_000);\n}\n\n/**\n * Resolve the owner/repo for the current cwd via `gh repo view`. Used by\n * the review-comment helpers below since GitHub's REST endpoints require\n * an explicit owner/repo path even when run inside a clone.\n */\nasync function resolveOwnerRepo(cwd: string): Promise<{ owner: string; repo: string } | null> {\n try {\n const stdout = await runWithTimeout(\n 'gh',\n ['repo', 'view', '--json', 'owner,name'],\n cwd,\n 15_000\n );\n const parsed = z\n .object({ owner: z.object({ login: z.string() }), name: z.string() })\n .safeParse(JSON.parse(stdout));\n if (!parsed.success) return null;\n return { owner: parsed.data.owner.login, repo: parsed.data.name };\n } catch {\n return null;\n }\n}\n\n/**\n * Detect bot-suffixed login (e.g. `github-actions[bot]`).\n */\nfunction detectAuthorIsBot(login: string): boolean {\n return login.endsWith('[bot]');\n}\n\nconst RestReviewCommentSchema = z\n .object({\n id: z.union([z.number(), z.string()]),\n user: z.object({ login: z.string() }).passthrough().nullable().optional(),\n body: z.string().optional(),\n created_at: z.string().optional(),\n updated_at: z.string().optional().nullable(),\n path: z.string().optional().nullable(),\n line: z.number().nullable().optional(),\n original_line: z.number().nullable().optional(),\n side: z.string().nullable().optional(),\n start_line: z.number().nullable().optional(),\n start_side: z.string().nullable().optional(),\n commit_id: z.string().nullable().optional(),\n original_commit_id: z.string().nullable().optional(),\n in_reply_to_id: z.union([z.number(), z.string()]).nullable().optional(),\n pull_request_review_id: z.union([z.number(), z.string()]).nullable().optional(),\n diff_hunk: z.string().nullable().optional(),\n html_url: z.string().nullable().optional(),\n })\n .passthrough();\n\ntype RestReviewComment = z.infer<typeof RestReviewCommentSchema>;\n\nconst GraphqlThreadsResponseSchema = z\n .object({\n data: z\n .object({\n repository: z\n .object({\n pullRequest: z\n .object({\n reviewThreads: z.object({\n nodes: z.array(\n z.object({\n id: z.string(),\n isResolved: z.boolean().optional().default(false),\n isOutdated: z.boolean().optional().default(false),\n comments: z.object({\n nodes: z.array(\n z.object({ databaseId: z.union([z.number(), z.string()]).nullable() })\n ),\n }),\n })\n ),\n }),\n })\n .nullable(),\n })\n .nullable(),\n })\n .nullable(),\n })\n .passthrough();\n\ninterface ThreadInfo {\n threadId: string;\n isResolved: boolean;\n isOutdated: boolean;\n}\n\n/**\n * Build the databaseId -> ThreadInfo map from a `pullRequestReviewThreads`\n * GraphQL response. Each comment's databaseId points to the same thread.\n */\nfunction buildThreadMap(\n parsed: z.infer<typeof GraphqlThreadsResponseSchema>\n): Map<string, ThreadInfo> {\n const map = new Map<string, ThreadInfo>();\n const threads = parsed.data?.repository?.pullRequest?.reviewThreads.nodes ?? [];\n for (const thread of threads) {\n const info: ThreadInfo = {\n threadId: thread.id,\n isResolved: thread.isResolved,\n isOutdated: thread.isOutdated,\n };\n for (const c of thread.comments.nodes) {\n if (c.databaseId === null || c.databaseId === undefined) continue;\n map.set(String(c.databaseId), info);\n }\n }\n return map;\n}\n\nasync function fetchReviewThreadMap(\n cwd: string,\n owner: string,\n repo: string,\n prNumber: number\n): Promise<Map<string, ThreadInfo>> {\n const query = `query($owner: String!, $repo: String!, $pr: Int!) {\n repository(owner: $owner, name: $repo) {\n pullRequest(number: $pr) {\n reviewThreads(first: 100) {\n nodes {\n id\n isResolved\n isOutdated\n comments(first: 100) {\n nodes { databaseId }\n }\n }\n }\n }\n }\n }`;\n try {\n const stdout = await runWithTimeout(\n 'gh',\n [\n 'api',\n 'graphql',\n '-f',\n `query=${query}`,\n '-F',\n `owner=${owner}`,\n '-F',\n `repo=${repo}`,\n '-F',\n `pr=${prNumber}`,\n ],\n cwd,\n 15_000\n );\n const parsed = GraphqlThreadsResponseSchema.safeParse(JSON.parse(stdout));\n if (!parsed.success) return new Map();\n return buildThreadMap(parsed.data);\n } catch {\n return new Map();\n }\n}\n\n/** Coerce GitHub's number|string id into a stable string, or null. */\nfunction coerceIdString(value: number | string | null | undefined): string | null {\n if (value === null || value === undefined) return null;\n return String(value);\n}\n\n/** Build the anchor-related slice (commit, line, side) of the PRComment. */\nfunction extractAnchorFields(raw: RestReviewComment): {\n path: string | null;\n line: number | null;\n side: string | null;\n commitId: string | null;\n startLine: number | null;\n startSide: string | null;\n} {\n return {\n path: raw.path ?? null,\n line: raw.line ?? raw.original_line ?? null,\n side: raw.side ?? null,\n commitId: raw.commit_id ?? raw.original_commit_id ?? null,\n startLine: raw.start_line ?? null,\n startSide: raw.start_side ?? null,\n };\n}\n\nfunction mapReviewCommentToPRComment(\n raw: RestReviewComment,\n threadInfo: ThreadInfo | undefined\n): PRComment {\n const author = raw.user?.login ?? '';\n const anchor = extractAnchorFields(raw);\n return {\n id: String(raw.id),\n author,\n body: raw.body ?? '',\n createdAt: raw.created_at ? (parseTimestamp(raw.created_at) ?? 0) : 0,\n updatedAt: raw.updated_at ? parseTimestamp(raw.updated_at) : null,\n isReviewComment: true,\n diffHunk: raw.diff_hunk ?? null,\n inReplyToId: coerceIdString(raw.in_reply_to_id),\n pullRequestReviewId: coerceIdString(raw.pull_request_review_id),\n threadId: threadInfo?.threadId ?? null,\n htmlUrl: raw.html_url ?? null,\n isResolved: threadInfo?.isResolved ?? false,\n isOutdated: threadInfo?.isOutdated ?? false,\n authorIsBot: detectAuthorIsBot(author),\n ...anchor,\n };\n}\n\n/**\n * Fetch all review comments for a PR with full anchoring fields (commit_id,\n * line, in_reply_to_id, etc.) plus thread state (isResolved, isOutdated)\n * keyed by GraphQL thread id.\n *\n * Combines `gh api /repos/{owner}/{repo}/pulls/{n}/comments` (REST, gives\n * commit_id, position, in_reply_to_id, etc.) with a GraphQL query for\n * `pullRequestReviewThreads { id, isResolved, isOutdated, comments { databaseId } }`\n * to enrich each REST comment with thread metadata.\n *\n * Returns an empty array on any gh error so the caller can degrade\n * gracefully (e.g. unauthenticated, repo without PR, network blip).\n */\nexport async function getPRReviewComments(cwd: string, prNumber: number): Promise<PRComment[]> {\n const ownerRepo = await resolveOwnerRepo(cwd);\n if (!ownerRepo) return [];\n const { owner, repo } = ownerRepo;\n\n let restRaw: unknown;\n try {\n const stdout = await runWithTimeout(\n 'gh',\n ['api', '--paginate', `/repos/${owner}/${repo}/pulls/${prNumber}/comments?per_page=100`],\n cwd,\n 30_000\n );\n /**\n * `gh api --paginate` concatenates JSON arrays from successive pages\n * with no separator (e.g. `[...][...]`). Wrap in brackets and replace\n * `][` to merge into a single array. With per_page=100 most PRs fit\n * in one page so the single-page case is the common path.\n */\n const merged = stdout.replace(/\\]\\s*\\[/g, ',');\n restRaw = JSON.parse(merged);\n } catch {\n return [];\n }\n\n const restParsed = z.array(RestReviewCommentSchema).safeParse(restRaw);\n if (!restParsed.success) return [];\n\n const threadMap = await fetchReviewThreadMap(cwd, owner, repo, prNumber);\n return restParsed.data.map((raw) =>\n mapReviewCommentToPRComment(raw, threadMap.get(String(raw.id)))\n );\n}\n\nconst ReplyResponseSchema = z\n .object({\n id: z.union([z.number(), z.string()]),\n html_url: z.string().nullable().optional(),\n created_at: z.string().optional(),\n })\n .passthrough();\n\n/**\n * Post a reply to an existing review comment thread on a PR.\n *\n * `parentCommentId` is the GitHub numeric comment id (NOT the local\n * Shipyard commentId). Callers should look up `parent.external.commentId`\n * before invoking.\n *\n * Throws on gh error so the caller can surface the failure (e.g. via\n * `pr_action_result` with `success: false`).\n */\nexport async function replyToReviewComment(\n cwd: string,\n prNumber: number,\n parentCommentId: string,\n body: string\n): Promise<{ id: string; htmlUrl: string; createdAt: number }> {\n const ownerRepo = await resolveOwnerRepo(cwd);\n if (!ownerRepo) throw new Error('replyToReviewComment: failed to resolve owner/repo');\n const { owner, repo } = ownerRepo;\n const stdout = await runWithTimeout(\n 'gh',\n [\n 'api',\n '-X',\n 'POST',\n `/repos/${owner}/${repo}/pulls/${prNumber}/comments/${parentCommentId}/replies`,\n '-f',\n `body=${body}`,\n ],\n cwd,\n 30_000\n );\n const parsed = ReplyResponseSchema.safeParse(JSON.parse(stdout));\n if (!parsed.success) throw new Error('replyToReviewComment: unexpected gh response shape');\n return {\n id: String(parsed.data.id),\n htmlUrl: parsed.data.html_url ?? '',\n createdAt: parsed.data.created_at\n ? (parseTimestamp(parsed.data.created_at) ?? Date.now())\n : Date.now(),\n };\n}\n\n/**\n * Resolve a PR review thread via GraphQL. `threadId` is the GraphQL node id\n * (PullRequestReviewThread), NOT a comment id. Throws on gh error.\n */\nexport async function resolveReviewThread(cwd: string, threadId: string): Promise<void> {\n const mutation = `mutation($threadId: ID!) {\n resolveReviewThread(input: { threadId: $threadId }) {\n thread { isResolved }\n }\n }`;\n await runWithTimeout(\n 'gh',\n ['api', 'graphql', '-f', `query=${mutation}`, '-f', `threadId=${threadId}`],\n cwd,\n 15_000\n );\n}\n\n/**\n * Unresolve a previously resolved PR review thread. Mirror of resolveReviewThread.\n */\nexport async function unresolveReviewThread(cwd: string, threadId: string): Promise<void> {\n const mutation = `mutation($threadId: ID!) {\n unresolveReviewThread(input: { threadId: $threadId }) {\n thread { isResolved }\n }\n }`;\n await runWithTimeout(\n 'gh',\n ['api', 'graphql', '-f', `query=${mutation}`, '-f', `threadId=${threadId}`],\n cwd,\n 15_000\n );\n}\n\nexport const _testing = {\n checkPriority,\n deduplicateChecks,\n parseTimestamp,\n mapCheckStatus,\n buildThreadMap,\n mapReviewCommentToPRComment,\n detectAuthorIsBot,\n resetLabelCache(): void {\n ensuredLabels.clear();\n failedLabels.clear();\n },\n /**\n * Replace the module-level gh pool with a pool constructed from the given\n * ExecFileLike. Returns the pool so tests can observe call counts etc.\n * Call `resetGhPool()` in afterEach to restore the real pool.\n */\n replaceGhPool(execFile: ExecFileLike, opts?: { ttlMs?: number }): OneShotPool {\n ghPool = createOneShotPool({ ttlMs: opts?.ttlMs ?? 60_000 }, { execFile });\n return ghPool;\n },\n resetGhPool(): void {\n ghPool = createOneShotPool({ ttlMs: 60_000 });\n },\n};\n","import {\n DEPLOYMENT_STATES,\n type EnvironmentDeployment,\n WORKFLOW_RUN_CONCLUSIONS,\n WORKFLOW_RUN_STATUSES,\n type WorkflowRun,\n} from '@shipyard/loro-schema';\nimport { z } from 'zod';\nimport { parseTimestamp } from './git-pr.js';\nimport { isAncestor } from './git-repo.js';\nimport { runWithTimeout } from './shell.js';\n\nconst DEPLOYMENT_STATE_SET: ReadonlySet<string> = new Set(DEPLOYMENT_STATES);\n\nfunction validateDeploymentState(raw: unknown): EnvironmentDeployment['state'] {\n if (typeof raw === 'string' && DEPLOYMENT_STATE_SET.has(raw)) {\n // eslint-disable-next-line no-restricted-syntax -- validated via Set lookup above\n return raw as EnvironmentDeployment['state'];\n }\n return 'pending';\n}\n\n// eslint-disable-next-line no-restricted-syntax -- gh API JSON output is untyped\nconst GhDeploymentSchema = z.object({\n id: z.number(),\n environment: z.string(),\n sha: z.string(),\n created_at: z.string(),\n});\n\n// eslint-disable-next-line no-restricted-syntax -- gh API JSON output is untyped\nconst GhDeploymentStatusSchema = z.object({\n state: z.string(),\n environment_url: z.string().nullable().optional(),\n log_url: z.string().nullable().optional(),\n created_at: z.string(),\n});\n\nexport async function getConfiguredEnvironments(\n owner: string,\n repo: string,\n cwd: string\n): Promise<string[]> {\n const json = await runWithTimeout(\n 'gh',\n ['api', `/repos/${owner}/${repo}/environments`],\n cwd,\n 15_000\n );\n const parsed = z\n .object({ environments: z.array(z.object({ name: z.string() }).passthrough()) })\n .safeParse(JSON.parse(json));\n if (!parsed.success) return [];\n return parsed.data.environments.map((e) => e.name);\n}\n\nexport async function getLatestDeployments(\n owner: string,\n repo: string,\n mergeCommitSha: string,\n cwd: string\n): Promise<EnvironmentDeployment[]> {\n const deploymentsJson = await runWithTimeout(\n 'gh',\n ['api', `/repos/${owner}/${repo}/deployments?per_page=30`],\n cwd,\n 15_000\n );\n\n const rawDeployments = z\n .array(GhDeploymentSchema.passthrough())\n .safeParse(JSON.parse(deploymentsJson));\n if (!rawDeployments.success) return [];\n\n /** Group by environment, keep latest (by created_at) per env */\n const latestByEnv = new Map<string, z.infer<typeof GhDeploymentSchema>>();\n for (const d of rawDeployments.data) {\n const existing = latestByEnv.get(d.environment);\n if (!existing || d.created_at > existing.created_at) {\n latestByEnv.set(d.environment, d);\n }\n }\n\n const envEntries = Array.from(latestByEnv.values()).slice(0, 10);\n\n await runWithTimeout('git', ['fetch', '--depth=100', 'origin'], cwd, 15_000).catch(() => {});\n\n const settled = await Promise.allSettled(\n envEntries.map(async (deployment) => {\n const statusJson = await runWithTimeout(\n 'gh',\n ['api', `/repos/${owner}/${repo}/deployments/${deployment.id}/statuses?per_page=1`],\n cwd,\n 15_000\n );\n const statusArr = z\n .array(GhDeploymentStatusSchema.passthrough())\n .safeParse(JSON.parse(statusJson));\n const latestStatus = statusArr.success ? statusArr.data[0] : undefined;\n\n const includesCommit = await isAncestor(mergeCommitSha, deployment.sha, cwd);\n\n return {\n environment: deployment.environment,\n state: validateDeploymentState(latestStatus?.state),\n environmentUrl: latestStatus?.environment_url ?? null,\n logUrl: latestStatus?.log_url ?? null,\n deployedAt: parseTimestamp(latestStatus?.created_at ?? deployment.created_at),\n sha: deployment.sha,\n includesCommit,\n } satisfies EnvironmentDeployment;\n })\n );\n\n return settled\n .filter((r): r is PromiseFulfilledResult<EnvironmentDeployment> => r.status === 'fulfilled')\n .map((r) => r.value)\n .filter((d) => d.state !== 'inactive');\n}\n\nconst WORKFLOW_STATUS_SET: ReadonlySet<string> = new Set(WORKFLOW_RUN_STATUSES);\nconst WORKFLOW_CONCLUSION_SET: ReadonlySet<string> = new Set(WORKFLOW_RUN_CONCLUSIONS);\n\nconst GhWorkflowRunSchema = z.object({\n name: z.string(),\n status: z.string(),\n conclusion: z.string().nullable(),\n html_url: z.string(),\n head_sha: z.string(),\n created_at: z.string(),\n event: z.string(),\n});\n\nexport async function getWorkflowRuns(\n owner: string,\n repo: string,\n branch: string,\n referenceCommit: string,\n cwd: string\n): Promise<WorkflowRun[]> {\n const runsJson = await runWithTimeout(\n 'gh',\n ['api', `/repos/${owner}/${repo}/actions/runs?event=push&branch=${branch}&per_page=20`],\n cwd,\n 15_000\n );\n\n const parsed = z\n .object({ workflow_runs: z.array(GhWorkflowRunSchema.passthrough()) })\n .safeParse(JSON.parse(runsJson));\n if (!parsed.success) return [];\n\n const latestByName = new Map<string, z.infer<typeof GhWorkflowRunSchema>>();\n for (const run of parsed.data.workflow_runs) {\n if (!latestByName.has(run.name)) {\n latestByName.set(run.name, run);\n }\n }\n\n const entries = Array.from(latestByName.values()).slice(0, 10);\n\n const settled = await Promise.allSettled(\n entries.map(async (run) => {\n const includesCommit = await isAncestor(referenceCommit, run.head_sha, cwd);\n const status = WORKFLOW_STATUS_SET.has(run.status) ? run.status : 'pending';\n const conclusion =\n run.conclusion && WORKFLOW_CONCLUSION_SET.has(run.conclusion) ? run.conclusion : null;\n\n return {\n name: run.name,\n // eslint-disable-next-line no-restricted-syntax -- validated via Set lookup above\n status: status as WorkflowRun['status'],\n // eslint-disable-next-line no-restricted-syntax -- validated via Set lookup above\n conclusion: conclusion as WorkflowRun['conclusion'],\n url: run.html_url,\n sha: run.head_sha,\n createdAt: parseTimestamp(run.created_at) ?? 0,\n includesCommit,\n } satisfies WorkflowRun;\n })\n );\n\n return settled\n .filter((r): r is PromiseFulfilledResult<WorkflowRun> => r.status === 'fulfilled')\n .map((r) => r.value);\n}\n\nexport async function getRequiredChecks(\n owner: string,\n repo: string,\n branch: string,\n cwd: string\n): Promise<string[]> {\n const json = await runWithTimeout(\n 'gh',\n ['api', `/repos/${owner}/${repo}/branches/${branch}/protection/required_status_checks`],\n cwd,\n 15_000\n );\n const parsed = z\n .object({ contexts: z.array(z.string()) })\n .passthrough()\n .safeParse(JSON.parse(json));\n if (!parsed.success) return [];\n return parsed.data.contexts;\n}\n\nexport async function rerunChecks(cwd: string, prNumber: number): Promise<void> {\n const output = await runWithTimeout(\n 'gh',\n [\n 'pr',\n 'checks',\n String(prNumber),\n '--json',\n 'name,state,link',\n '--jq',\n '.[] | .state + \"\\t\" + .link',\n ],\n cwd,\n 15_000\n );\n const lines = output.trim().split('\\n').filter(Boolean);\n const failedRunIds = new Set<string>();\n const inProgressRunIds = new Set<string>();\n for (const line of lines) {\n const [state, link] = line.split('\\t');\n const match = link?.match(/\\/actions\\/runs\\/(\\d+)/);\n if (!match?.[1]) continue;\n if (state === 'FAILURE') failedRunIds.add(match[1]);\n if (state === 'PENDING') inProgressRunIds.add(match[1]);\n }\n const toRerun = [...failedRunIds].filter((id) => !inProgressRunIds.has(id));\n if (toRerun.length === 0 && inProgressRunIds.size > 0) {\n throw new Error('Checks are already running');\n }\n if (toRerun.length === 0) throw new Error('No failed workflow runs to re-run');\n for (const runId of toRerun) {\n await runWithTimeout('gh', ['run', 'rerun', runId, '--failed'], cwd, 30_000);\n }\n}\n","import { gitExecSafe, _testing as gitPoolTesting } from './git-pool.js';\nimport { isGitRepo } from './git-repo.js';\nimport {\n BUFFER_OVERFLOW_MSG,\n DIFF_TIMEOUT_MS,\n isMaxBufferError,\n runWithTimeout,\n TIMEOUT_MS,\n truncateDiff,\n} from './shell.js';\n\nasync function withIntentToAdd<T>(cwd: string, fn: () => Promise<T>): Promise<T> {\n let added = false;\n try {\n const untracked = await runWithTimeout(\n 'git',\n ['ls-files', '--others', '--exclude-standard'],\n cwd,\n TIMEOUT_MS\n );\n if (untracked) {\n await runWithTimeout('git', ['add', '-N', '.'], cwd, TIMEOUT_MS);\n added = true;\n }\n return await fn();\n } finally {\n if (added) {\n await runWithTimeout('git', ['reset'], cwd, TIMEOUT_MS).catch(() => {});\n }\n }\n}\n\nexport async function getUnstagedDiff(cwd: string): Promise<string> {\n if (!(await isGitRepo(cwd))) return '';\n try {\n const result = await withIntentToAdd(cwd, () =>\n runWithTimeout('git', ['diff', '-U99999', '--no-color'], cwd, DIFF_TIMEOUT_MS)\n );\n return truncateDiff(result);\n } catch (err: unknown) {\n if (isMaxBufferError(err)) return BUFFER_OVERFLOW_MSG;\n throw err;\n }\n}\n\nexport async function getStagedDiff(cwd: string): Promise<string> {\n if (!(await isGitRepo(cwd))) return '';\n try {\n const result = await runWithTimeout(\n 'git',\n ['diff', '--cached', '-U99999', '--no-color'],\n cwd,\n DIFF_TIMEOUT_MS\n );\n return truncateDiff(result);\n } catch (err: unknown) {\n if (isMaxBufferError(err)) return BUFFER_OVERFLOW_MSG;\n throw err;\n }\n}\n\nexport async function getChangedFiles(\n cwd: string\n): Promise<Array<{ path: string; status: string }>> {\n if (!(await isGitRepo(cwd))) return [];\n const out = await runWithTimeout('git', ['status', '--porcelain'], cwd, DIFF_TIMEOUT_MS);\n if (!out) return [];\n return out\n .split('\\n')\n .filter(Boolean)\n .map((line) => ({\n status: line.slice(0, 2).trim(),\n path: line.slice(3),\n }));\n}\n\n/**\n * Return the porcelain status for a single file, or `null` if the file is\n * clean (or the path is outside the repo). Used by `add_comment` to decide\n * whether a new diff comment should be authored against the working tree\n * or against the branch base.\n */\nexport async function getFileGitStatus(cwd: string, path: string): Promise<string | null> {\n if (!(await isGitRepo(cwd))) return null;\n try {\n const out = await runWithTimeout('git', ['status', '--porcelain', '--', path], cwd, TIMEOUT_MS);\n if (!out) return null;\n const firstLine = out.split('\\n')[0] ?? '';\n return firstLine.slice(0, 2).trim() || null;\n } catch {\n return null;\n }\n}\n\nconst BRANCH_DIFF_TIMEOUT_MS = 30_000;\n\n/**\n * Resolve the default branch ref for the given cwd. The result is cached\n * for 5 seconds via the per-cwd OneShotPool in git-pool.ts — repeated calls\n * within the window coalesce to a single subprocess. The prior module-level\n * Map (infinite lifetime) has been replaced with the TTL pool so stale branch\n * info (e.g. after `git remote set-head`) expires automatically.\n */\nexport async function getDefaultBranch(cwd: string): Promise<string | null> {\n const ref = await gitExecSafe(cwd, ['symbolic-ref', 'refs/remotes/origin/HEAD', '--short']);\n if (ref) return ref;\n\n for (const candidate of ['origin/main', 'origin/master']) {\n const ok = await gitExecSafe(cwd, ['rev-parse', '--verify', candidate]);\n if (ok !== null) return candidate;\n }\n\n return null;\n}\n\nexport async function getGitRefExists(cwd: string, ref: string): Promise<boolean> {\n try {\n await runWithTimeout('git', ['rev-parse', '--verify', '--quiet', ref], cwd, 5_000);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function fetchRemoteBranch(cwd: string, branch: string): Promise<boolean> {\n try {\n await runWithTimeout('git', ['fetch', 'origin', branch], cwd, 30_000);\n return true;\n } catch {\n return false;\n }\n}\n\nexport const _testing = {\n /**\n * Dispose all per-cwd git pools so tests with different execFile stubs see\n * fresh results rather than cached ones from a prior test. Replaces the old\n * `defaultBranchCache.clear()` call which cleared the defunct module-level Map.\n */\n clearDefaultBranchCache: () => gitPoolTesting.clearAllPools(),\n};\n\nexport async function getMergeBase(cwd: string, baseBranch: string): Promise<string | null> {\n try {\n return await runWithTimeout('git', ['merge-base', '--', baseBranch, 'HEAD'], cwd, TIMEOUT_MS);\n } catch {\n return null;\n }\n}\n\nexport async function getBranchDiff(cwd: string, baseBranch: string): Promise<string> {\n const mergeBase = await getMergeBase(cwd, baseBranch);\n if (!mergeBase) return '';\n\n try {\n const result = await runWithTimeout(\n 'git',\n ['diff', '-U99999', `${mergeBase}..HEAD`, '--no-color'],\n cwd,\n BRANCH_DIFF_TIMEOUT_MS\n );\n return truncateDiff(result);\n } catch (err: unknown) {\n if (isMaxBufferError(err)) return BUFFER_OVERFLOW_MSG;\n return '';\n }\n}\n\nexport async function getBranchFiles(\n cwd: string,\n baseBranch: string\n): Promise<Array<{ path: string; status: string }>> {\n const mergeBase = await getMergeBase(cwd, baseBranch);\n if (!mergeBase) return [];\n\n try {\n const out = await runWithTimeout(\n 'git',\n ['diff', '--name-status', `${mergeBase}..HEAD`],\n cwd,\n BRANCH_DIFF_TIMEOUT_MS\n );\n if (!out) return [];\n return out\n .split('\\n')\n .filter(Boolean)\n .map((line) => {\n const parts = line.split('\\t');\n return {\n status: parts[0] ?? '',\n path: parts[1] ?? '',\n };\n });\n } catch {\n return [];\n }\n}\n\nexport async function captureTreeSnapshot(cwd: string): Promise<string | null> {\n try {\n const stashRef = await runWithTimeout('git', ['stash', 'create'], cwd, DIFF_TIMEOUT_MS);\n if (stashRef) return stashRef;\n\n return await runWithTimeout('git', ['rev-parse', 'HEAD'], cwd, DIFF_TIMEOUT_MS);\n } catch {\n return null;\n }\n}\n\nexport async function getSnapshotDiff(\n cwd: string,\n fromRef: string,\n toRef: string\n): Promise<string> {\n try {\n const result = await runWithTimeout(\n 'git',\n ['diff', '-U99999', fromRef, toRef, '--no-color'],\n cwd,\n DIFF_TIMEOUT_MS\n );\n return truncateDiff(result);\n } catch (err: unknown) {\n if (isMaxBufferError(err)) return BUFFER_OVERFLOW_MSG;\n return '';\n }\n}\n\nexport async function getSnapshotFiles(\n cwd: string,\n fromRef: string,\n toRef: string\n): Promise<Array<{ path: string; status: string }>> {\n try {\n const out = await runWithTimeout(\n 'git',\n ['diff', '--name-status', fromRef, toRef],\n cwd,\n DIFF_TIMEOUT_MS\n );\n if (!out) return [];\n return out\n .split('\\n')\n .filter(Boolean)\n .map((line) => {\n const parts = line.split('\\t');\n return {\n status: parts[0] ?? '',\n path: parts[1] ?? '',\n };\n });\n } catch {\n return [];\n }\n}\n\nexport async function getStackDiff(cwd: string, fromRef: string, toRef: string): Promise<string> {\n try {\n const result = await runWithTimeout(\n 'git',\n ['diff', '-U99999', `${fromRef}...${toRef}`, '--no-color'],\n cwd,\n DIFF_TIMEOUT_MS\n );\n return truncateDiff(result);\n } catch (err: unknown) {\n if (isMaxBufferError(err)) return BUFFER_OVERFLOW_MSG;\n return '';\n }\n}\n\nexport async function getStackFiles(\n cwd: string,\n fromRef: string,\n toRef: string\n): Promise<Array<{ path: string; status: string }>> {\n try {\n const out = await runWithTimeout(\n 'git',\n ['diff', '--name-status', `${fromRef}...${toRef}`],\n cwd,\n DIFF_TIMEOUT_MS\n );\n if (!out) return [];\n return out\n .split('\\n')\n .filter(Boolean)\n .map((line) => {\n const parts = line.split('\\t');\n return {\n status: parts[0] ?? '',\n path: parts[1] ?? '',\n };\n });\n } catch {\n return [];\n }\n}\n\nexport type ChangeStatus = 'A' | 'D' | 'M' | 'R';\n\nexport type RenameInfo = {\n newPath: string;\n status: ChangeStatus;\n};\n\n/**\n * Read the contents of `path` at the given git ref via `git show <ref>:<path>`.\n *\n * Returns null if the path does not exist at that ref (e.g. the file was added\n * or deleted between refs). Returns null on any git failure — callers should\n * treat absence as \"no content available\" rather than error.\n */\nexport async function getFileAtRef(cwd: string, path: string, ref: string): Promise<string | null> {\n if (!(await isGitRepo(cwd))) return null;\n try {\n return await runWithTimeout('git', ['show', `${ref}:${path}`], cwd, DIFF_TIMEOUT_MS);\n } catch (err: unknown) {\n if (isMaxBufferError(err)) return null;\n return null;\n }\n}\n\n/**\n * Rename status from `git --name-status -M` arrives as `R<percent>` (e.g. `R100`).\n * Normalize to the leading status letter so callers can switch on a stable token.\n */\nfunction parseStatusLetter(raw: string): ChangeStatus | null {\n const letter = raw.charAt(0);\n if (letter === 'A' || letter === 'D' || letter === 'M' || letter === 'R') {\n return letter;\n }\n return null;\n}\n\nfunction parseRenameLine(line: string): { oldPath: string; info: RenameInfo } | null {\n if (!line) return null;\n const parts = line.split('\\t');\n const status = parseStatusLetter(parts[0] ?? '');\n if (status === null) return null;\n if (status === 'R') {\n const oldPath = parts[1];\n const newPath = parts[2];\n if (!oldPath || !newPath) return null;\n return { oldPath, info: { newPath, status: 'R' } };\n }\n const path = parts[1];\n if (!path) return null;\n return { oldPath: path, info: { newPath: path, status } };\n}\n\n/**\n * Detect file changes between two refs with rename detection enabled\n * (`--find-renames=50%`). Returns a map keyed by the OLD path with the new\n * path + status.\n *\n * - 'M' (modified), 'A' (added), 'D' (deleted): oldPath === newPath.\n * - 'R' (renamed): oldPath ≠ newPath; the map key is the old path.\n *\n * Returns an empty map if either ref is invalid or git fails.\n */\nexport async function findRenames(\n cwd: string,\n oldRef: string,\n newRef: string\n): Promise<Map<string, RenameInfo>> {\n const result = new Map<string, RenameInfo>();\n if (!(await isGitRepo(cwd))) return result;\n let out = '';\n try {\n out = await runWithTimeout(\n 'git',\n ['diff', '--name-status', '--find-renames=50%', `${oldRef}..${newRef}`],\n cwd,\n DIFF_TIMEOUT_MS\n );\n } catch {\n return result;\n }\n if (!out) return result;\n for (const line of out.split('\\n')) {\n const parsed = parseRenameLine(line);\n if (parsed) result.set(parsed.oldPath, parsed.info);\n }\n return result;\n}\n","import type { AnthropicAuthMethod, CodexAuthMethod } from '@shipyard/loro-schema';\nimport type {\n CodexAuthStatus,\n GitRepoInfo,\n InstalledAgent,\n MachineCapabilities,\n MCPServerInfo,\n SkillInfo,\n} from '@shipyard/session';\nimport { logger } from '../logger.js';\nimport { withLabelAsync } from '../observability/watchdog-context.js';\nimport { detectAgentProviders } from './agents.js';\nimport { detectCodexAuth } from './codex-auth-detect.js';\nimport { DEFAULT_DETECTOR_TIMEOUT_MS, withDetectorTimeout } from './detector-timeout.js';\nimport { detectMCPServers } from './mcp-servers.js';\nimport { CLAUDE_CODE_RUNTIME_ID } from './runtime/catalog.js';\nimport { detectSkills } from './skills.js';\n\nexport {\n refreshMcpServers,\n refreshSkills,\n refreshInstalledAgents,\n refreshCodexAuthSlice,\n type ScopedCapabilitiesPatch,\n};\n\n/**\n * Partial capabilities — only the slices the scoped re-detect helpers\n * actually mutate. Callers merge into `daemon.capabilities` and re-broadcast.\n *\n * Why partial: the regression fixed by this file's introduction was\n * `capability-watcher` calling the full `detectCapabilities` on every\n * `~/.claude/projects/<sess>.jsonl` write Claude Code performs. The full\n * detect runs `detectEnvironments` (walks every git repo under $HOME,\n * 13-15s on machines with many repos). The scoped helpers below skip\n * that walk and re-run only the ~10ms detector relevant to the file\n * event class — settings.json edits don't need to re-walk $HOME.\n */\ntype ScopedCapabilitiesPatch = Partial<MachineCapabilities>;\n\n/**\n * Each scoped detector is wrapped in `withDetectorTimeout` so a wedged\n * subprocess (network hang on the claude.ai integrations fetch, hung\n * `claude --version`, slow worktree walk) cannot stall the scoped refresh\n * chain. The scoped path goes through `runScopedRefresh` which serializes\n * on `inFlightCapabilityRefresh` — without the wrapper a single hang would\n * block every subsequent full-refresh too. Same fallback shape as the\n * full-detect path in `index.ts`.\n */\n\nasync function refreshMcpServers(deps: {\n environments: GitRepoInfo[] | undefined;\n tokenStore: import('../mcp/token-store.js').MCPTokenStore | undefined;\n /**\n * Gates `fetchClaudeAiIntegrations` (claude.ai Connectors network fetch).\n * See `mcp-servers.ts:shouldFetchClaudeAiIntegrations` for the policy.\n */\n preferredAuth?: AnthropicAuthMethod | null;\n /**\n * Prior detected MCP server list. On detector timeout/error this is used\n * as the patch value so a transient hang does NOT wipe the user's MCP\n * panel. Without this, the wrapper's empty-array fallback would write\n * `[]` into `daemon.capabilities.mcpServers` via `applyScopedPatch` and\n * broadcast the wipe (QA pass 3 — Adversarial + Steward).\n */\n lastKnown: MCPServerInfo[] | undefined;\n /**\n * Incremental scope: when set, only the project-level config files at\n * `changedCwd` are re-scanned. Project-tier entries from other\n * environments are reused from `lastKnown`. Wired by the\n * `buildCwdScopedPatch` cwd-refresh path; unset for the\n * capability-watcher tick (which intentionally re-scans every env).\n */\n changedCwd?: string;\n}): Promise<ScopedCapabilitiesPatch> {\n return withLabelAsync('refreshMcpServers', async () => {\n /*\n * Yield before tagging the loop with our label, matching the pattern in\n * refreshSkills + refreshCodexAuthSlice below. Without this, any hot loop\n * already queued on the main thread gets attributed to 'refreshMcpServers'\n * in the watchdog — producing the 35s false-stall report observed in\n * the 2026-05-28 log triage. The detector itself does network + FS work\n * but yields between iterations; the missing initial yield was the only\n * remaining attribution hole.\n */\n await new Promise<void>((r) => {\n setImmediate(r);\n });\n const mcpServers = await withDetectorTimeout({\n name: 'refresh_mcp_servers',\n run: () =>\n detectMCPServers(\n deps.environments ?? [],\n deps.tokenStore,\n (entry) => logger.warn(entry, entry.event),\n deps.lastKnown,\n CLAUDE_CODE_RUNTIME_ID,\n deps.preferredAuth,\n deps.changedCwd\n ),\n fallback: deps.lastKnown ?? [],\n timeoutMs: DEFAULT_DETECTOR_TIMEOUT_MS,\n });\n return { mcpServers };\n });\n}\n\nasync function refreshSkills(deps: {\n environments: GitRepoInfo[] | undefined;\n /**\n * Prior detected skills list — see `refreshMcpServers` rationale. Same\n * \"preserve on timeout, do not wipe\" semantics.\n */\n lastKnown: SkillInfo[] | undefined;\n}): Promise<ScopedCapabilitiesPatch> {\n return withLabelAsync('refreshSkills', async () => {\n /*\n * Yield to drain queued main-thread work before tagging the loop with our\n * label. Without this, any hot loop already queued on the main thread\n * gets attributed to 'refreshSkills' in the watchdog — producing false\n * 800ms+ stall reports. Mirrors pre-warm-manager.ts:469.\n */\n await new Promise<void>((r) => {\n setImmediate(r);\n });\n const skills = await withDetectorTimeout({\n name: 'refresh_skills',\n run: () => detectSkills(deps.environments ?? [], deps.lastKnown),\n fallback: deps.lastKnown ?? [],\n timeoutMs: DEFAULT_DETECTOR_TIMEOUT_MS,\n });\n return { skills };\n });\n}\n\nasync function refreshInstalledAgents(deps: {\n lastKnown: InstalledAgent[] | undefined;\n}): Promise<ScopedCapabilitiesPatch> {\n return withLabelAsync('refreshInstalledAgents', async () => {\n const installedAgents = await withDetectorTimeout({\n name: 'refresh_installed_agents',\n run: () => detectAgentProviders(deps.lastKnown),\n fallback: deps.lastKnown ?? [],\n timeoutMs: DEFAULT_DETECTOR_TIMEOUT_MS,\n });\n return { installedAgents, installedRuntimes: installedAgents, detectionComplete: true };\n });\n}\n\n/**\n * Scoped refresh of `capabilities.codexAuth` alone. Wired into the\n * capability watcher's `codex-auth` class so `~/.codex/auth.json` writes\n * — including Codex CLI's auto-refresh of the OAuth bearer — keep\n * `daemon.capabilities.codexAuth` current between the 5-min capability\n * backstop ticks. Returns `null` (no patch) when the detector returns\n * `preserved`: the caller leaves the prior status in place to avoid\n * flicker on a transient FS / parse hiccup.\n */\nasync function refreshCodexAuthSlice(deps: {\n methodHint?: CodexAuthMethod | undefined;\n lastKnown: CodexAuthStatus | undefined;\n}): Promise<ScopedCapabilitiesPatch | null> {\n return withLabelAsync('refreshCodexAuthSlice', async () => {\n /*\n * Yield before the auth file read. The 14.7s max stall attributed to this\n * label is attribution noise: withLabelAsync sets the watchdog label, then\n * any OTHER hot loop running while we await the file read gets charged to\n * this label. Yielding first drains queued main-thread work so the await\n * window starts clean. The detector itself is ~10ms of real work.\n */\n await new Promise<void>((r) => {\n setImmediate(r);\n });\n const result = await detectCodexAuth(deps.methodHint);\n if (result.kind === 'preserved') return null;\n return { codexAuth: result.auth };\n });\n}\n","import { readFileSync, statSync } from 'node:fs';\nimport { readFile, stat } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { atomicWriteFile } from '../fs-utils.js';\n\nexport interface MCPOAuthToken {\n accessToken: string;\n refreshToken?: string;\n expiresAt?: number;\n tokenType: string;\n serverUrl: string;\n /** Cached client_id from dynamic client registration (RFC 7591). */\n clientId?: string;\n}\n\ntype TokenMap = Record<string, MCPOAuthToken>;\n\ntype LogFn = (entry: { event: string; [key: string]: unknown }) => void;\n\nconst TOKEN_FILE = 'mcp-tokens.json';\nconst REFRESH_THRESHOLD_MS = 5 * 60 * 1_000;\n\nexport class MCPTokenStore {\n #shipyardHome: string;\n #cache: TokenMap = {};\n #lastMtimeMs = -1;\n #log: LogFn;\n #onChange: ((serverName: string, token: MCPOAuthToken) => void) | null = null;\n /**\n * Serializes ALL mutations through a single promise chain. Without this,\n * concurrent writers (proxy proactive token refresh, oauth-provider\n * persistence, reauth-orchestrator setToken) can interleave read-modify-\n * write on `#cache` and race the file rename. The pre-fix code used a\n * shared `${filePath}.tmp` path which produced the 26 ENOENT errors per\n * 6-min window plus the 218 swallowed `cancelled` cascades observed in\n * the 2026-05-27 log triage — a second writer renamed its .tmp to the\n * same canonical path, and the first writer's rename then failed with\n * ENOENT. atomicWriteFile uses a PID+UUID tmp path so each writer owns\n * its own tmp; the mutation queue additionally prevents last-writer-wins\n * loss of in-flight cache mutations. Mirrors MCPOAuthStateStore.\n */\n #mutationQueue: Promise<void> = Promise.resolve();\n\n constructor(shipyardHome: string, log?: LogFn) {\n this.#shipyardHome = shipyardHome;\n this.#log = log ?? (() => {});\n }\n\n /**\n * Run `work` after all currently-queued mutations complete. A rejected\n * predecessor must NOT block subsequent mutations — chain on both fates.\n */\n #enqueueMutation<T>(work: () => Promise<T>): Promise<T> {\n const next = this.#mutationQueue.then(work, work);\n this.#mutationQueue = next.then(\n () => undefined,\n () => undefined\n );\n return next;\n }\n\n setOnChange(cb: ((serverName: string, token: MCPOAuthToken) => void) | null): void {\n this.#onChange = cb;\n }\n\n #filePath(): string {\n return join(this.#shipyardHome, TOKEN_FILE);\n }\n\n /** Read mtime from disk. Returns -1 if file does not exist. */\n #readMtimeMs(): number {\n try {\n return statSync(this.#filePath()).mtimeMs;\n } catch {\n return -1;\n }\n }\n\n /**\n * Synchronously reload the cache from disk if the file has changed\n * (or if we have never loaded). Uses file mtime to avoid unnecessary reads.\n */\n #loadSync(): void {\n const currentMtime = this.#readMtimeMs();\n if (currentMtime === this.#lastMtimeMs) return;\n\n try {\n if (currentMtime === -1) {\n this.#cache = {};\n this.#lastMtimeMs = currentMtime;\n return;\n }\n const raw = readFileSync(this.#filePath(), 'utf-8');\n // eslint-disable-next-line no-restricted-syntax -- JSON.parse returns unknown; shape validated by file ownership (daemon writes exclusively)\n this.#cache = JSON.parse(raw) as TokenMap;\n this.#lastMtimeMs = currentMtime;\n } catch (err: unknown) {\n this.#log({\n event: 'token_store_parse_failed',\n path: this.#filePath(),\n error: err instanceof Error ? err.message : String(err),\n });\n this.#cache = {};\n /** Set mtime so we re-read on next change rather than retrying every call */\n this.#lastMtimeMs = currentMtime;\n }\n }\n\n /** Async mtime check. Returns -1 if file does not exist. */\n async #readMtimeMsAsync(): Promise<number> {\n try {\n return (await stat(this.#filePath())).mtimeMs;\n } catch {\n return -1;\n }\n }\n\n /**\n * Async load — always reads from disk if the file has been modified since\n * the last read.\n */\n async #load(): Promise<void> {\n const currentMtime = await this.#readMtimeMsAsync();\n if (currentMtime === this.#lastMtimeMs) return;\n\n try {\n if (currentMtime === -1) {\n this.#cache = {};\n this.#lastMtimeMs = currentMtime;\n return;\n }\n const raw = await readFile(this.#filePath(), 'utf-8');\n // eslint-disable-next-line no-restricted-syntax -- JSON.parse returns unknown; shape validated by file ownership (daemon writes exclusively)\n this.#cache = JSON.parse(raw) as TokenMap;\n this.#lastMtimeMs = currentMtime;\n } catch (err: unknown) {\n this.#log({\n event: 'token_store_parse_failed',\n path: this.#filePath(),\n error: err instanceof Error ? err.message : String(err),\n });\n this.#cache = {};\n this.#lastMtimeMs = currentMtime;\n }\n }\n\n async #persist(): Promise<void> {\n await atomicWriteFile(this.#filePath(), JSON.stringify(this.#cache, null, 2), {\n mode: 0o600,\n });\n this.#lastMtimeMs = this.#readMtimeMs();\n }\n\n async getToken(serverName: string): Promise<MCPOAuthToken | null> {\n await this.#load();\n return this.#cache[serverName] ?? null;\n }\n\n async setToken(serverName: string, token: MCPOAuthToken): Promise<void> {\n return this.#enqueueMutation(async () => {\n await this.#load();\n this.#cache[serverName] = token;\n await this.#persist();\n this.#onChange?.(serverName, token);\n });\n }\n\n async deleteToken(serverName: string): Promise<void> {\n return this.#enqueueMutation(async () => {\n await this.#load();\n delete this.#cache[serverName];\n await this.#persist();\n });\n }\n\n async getAllTokens(): Promise<TokenMap> {\n await this.#load();\n return { ...this.#cache };\n }\n\n getTokenSync(serverName: string): MCPOAuthToken | null {\n this.#loadSync();\n return this.#cache[serverName] ?? null;\n }\n\n isExpired(token: MCPOAuthToken): boolean {\n if (!token.expiresAt) return false;\n return Date.now() >= token.expiresAt;\n }\n\n needsRefresh(token: MCPOAuthToken): boolean {\n if (token.expiresAt === undefined) return false;\n return Date.now() >= token.expiresAt - REFRESH_THRESHOLD_MS;\n }\n}\n"],"mappings":"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","names":["existsSync","existsSync","toRecord","open","createRequire","file","preserved","fs","homedir","join","codexAuthFilePath","join","homedir","isCodexAuthFile","isPlainObject","readCodexAuthFile","fs","createRequire","isRecord","CURSOR_KEY_PREFIX","isValidCursorKey","asRecord","notYetWired","notYetWired","readFile","homedir","join","join","join","mkdir","readFile","rename","stat","unlink","writeFile","dirname","join","cacheFilePath","join","readFile","stat","mkdir","dirname","writeFile","rename","unlink","isAuthoritativeNotFound","cached","version","homedir","platform","join","run","access","readFile","homedir","join","defaultFileExists","access","readFile","homedir","join","readFile","stat","homedir","join","readFile","join","stat","homedir","toRecord","run","readFile","join","homedir","readFile","stat","join","join","stat","readFile"]}
|