@schoolai/shipyard 3.14.0 → 3.15.0
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/capability-detector-worker.js +5 -5
- package/dist/{chunk-OX3UY44R.js → chunk-5PBWS7BB.js} +31 -42
- package/dist/chunk-5PBWS7BB.js.map +1 -0
- package/dist/{chunk-RCEAMZVG.js → chunk-6SK6FBYC.js} +2 -2
- package/dist/{chunk-M3WBYTB3.js → chunk-AXHG3QQA.js} +16 -1
- package/dist/chunk-AXHG3QQA.js.map +1 -0
- package/dist/{chunk-T3OTZ66B.js → chunk-B7WZUKYX.js} +219 -86
- package/dist/chunk-B7WZUKYX.js.map +1 -0
- package/dist/{chunk-BUAEJNUG.js → chunk-HPDRJ4VZ.js} +3 -3
- package/dist/{chunk-BUAEJNUG.js.map → chunk-HPDRJ4VZ.js.map} +1 -1
- package/dist/{chunk-WGS7ZW6N.js → chunk-L5FQEZ6Y.js} +3 -3
- package/dist/{chunk-KUPHN3ZN.js → chunk-RHHRJR3L.js} +2 -2
- package/dist/{chunk-3KE2VDKA.js → chunk-VKY7UXTP.js} +25 -3
- package/dist/chunk-VKY7UXTP.js.map +1 -0
- package/dist/{chunk-IWBDVGD2.js → chunk-VTALUCDB.js} +2 -2
- package/dist/cursor-runner.js +3 -3
- package/dist/electron-utility.js +2 -2
- package/dist/index.js +4 -4
- package/dist/{login-HRR3T4SZ.js → login-EYGYOEXL.js} +3 -3
- package/dist/{mcp-servers-GUA5WOHO.js → mcp-servers-DSOX243C.js} +8 -2
- package/dist/{plan-backfill-QNJUWOYP.js → plan-backfill-SMJEKTMM.js} +4 -4
- package/dist/{serve-25I4ML7R.js → serve-DAP6V7SY.js} +339 -147
- package/dist/{serve-25I4ML7R.js.map → serve-DAP6V7SY.js.map} +1 -1
- package/dist/{start-O2DXLW23.js → start-AX2ZK3AY.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-3KE2VDKA.js.map +0 -1
- package/dist/chunk-M3WBYTB3.js.map +0 -1
- package/dist/chunk-OX3UY44R.js.map +0 -1
- package/dist/chunk-T3OTZ66B.js.map +0 -1
- /package/dist/{chunk-RCEAMZVG.js.map → chunk-6SK6FBYC.js.map} +0 -0
- /package/dist/{chunk-WGS7ZW6N.js.map → chunk-L5FQEZ6Y.js.map} +0 -0
- /package/dist/{chunk-KUPHN3ZN.js.map → chunk-RHHRJR3L.js.map} +0 -0
- /package/dist/{chunk-IWBDVGD2.js.map → chunk-VTALUCDB.js.map} +0 -0
- /package/dist/{login-HRR3T4SZ.js.map → login-EYGYOEXL.js.map} +0 -0
- /package/dist/{mcp-servers-GUA5WOHO.js.map → mcp-servers-DSOX243C.js.map} +0 -0
- /package/dist/{plan-backfill-QNJUWOYP.js.map → plan-backfill-SMJEKTMM.js.map} +0 -0
- /package/dist/{start-O2DXLW23.js.map → start-AX2ZK3AY.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shared/capabilities/codex-auth-detect.ts","../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/model-capability-tiers.ts","../src/services/session/profiles/claude-code-profile.ts","../src/services/session/profiles/codex-profile.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-plan-translator.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/conversation/bridges/cursor-bridge.ts","../src/shared/chars-per-token.ts","../src/services/conversation/to-mcp-messages.ts","../src/services/conversation/bridges/cursor-history-injector/sqlite-writer.ts","../src/services/conversation/bridges/cursor-history-injector/fabricator.ts","../src/services/conversation/bridges/cursor-history-injector/proto-types.ts","../src/services/conversation/bridges/cursor-history-injector/sqlite-truncator.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/cursor-permission-policy.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/commands.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/plugin-detection.ts","../src/shared/capabilities/mcp-detection-log.ts","../src/shared/capabilities/models.ts","../src/shared/capabilities/runtime/auth-adapters.ts","../src/shared/capabilities/git-ci.ts","../src/shared/capabilities/git-diff.ts","../src/shared/capabilities/git-pr-search.ts","../src/shared/capabilities/git-pr.ts","../src/shared/capabilities/refresh-helpers.ts"],"sourcesContent":["/**\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 {\n type CodexAuthDetectionResult,\n type CodexAuthRefreshLastKnown,\n type CodexAuthRefreshVerdict,\n decideCodexAuthRefresh,\n detectCodexAuth,\n REFRESH_DEBOUNCE_MS,\n};\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 /** Top-level account id codex persists; preferred over JWT claims. */\n account_id?: string | null;\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\n/**\n * Validate the `tokens` sub-object. `access_token` / `id_token` are\n * optional strings; `account_id` is an optional string-or-null (codex\n * writes `null` when absent). `refresh_token` is intentionally not\n * shape-checked — it is only ever read defensively via optional chaining.\n */\nfunction isCodexTokens(value: unknown): boolean {\n if (!isPlainObject(value)) return false;\n if (value.access_token !== undefined && typeof value.access_token !== 'string') return false;\n if (value.id_token !== undefined && typeof value.id_token !== 'string') return false;\n return (\n value.account_id === undefined ||\n value.account_id === null ||\n typeof value.account_id === 'string'\n );\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 && !isCodexTokens(tokens)) return false;\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 * Read `claims[namespace][field]` when the namespaced claim is an object.\n * OpenAI nests identity claims under namespaced keys\n * (`https://api.openai.com/auth`, `https://api.openai.com/profile`); returns\n * `undefined` when the namespace is absent or not an object. The value is\n * `unknown` — callers type-guard before use.\n */\nfunction readNamespacedClaim(\n claims: Record<string, unknown>,\n namespace: string,\n field: string\n): unknown {\n const ns = claims[namespace];\n return isPlainObject(ns) ? ns[field] : undefined;\n}\n\n/**\n * Resolve the user's email + account id for the settings card. Both are\n * sourced robustly because OpenAI moved them out of the top-level id_token\n * claims into namespaced claims.\n *\n * Account id, in priority order:\n * 1. `tokens.account_id` — the top-level field codex itself persists and\n * reads in `~/.codex/auth.json` (passed as `fileAccountId`).\n * 2. The namespaced claim `https://api.openai.com/auth`.`chatgpt_account_id`\n * — where real OpenAI ChatGPT tokens carry it (codex `AuthClaims`, see\n * `login/src/token_data.rs`).\n * 3. Legacy top-level `account_id` / `chatgpt_account_id` — backwards-compat.\n *\n * Email, in priority order: top-level `chatgpt_account_email` / `email`, then\n * the namespaced `https://api.openai.com/profile`.`email` (org accounts\n * namespace it the same way as the account id; mirrors codex's own\n * top-level-`email` → `profile.email` resolution).\n *\n * Before #4481 only the top-level claims were checked, so the detector read\n * `null` for real tokens that namespace these fields.\n */\nfunction extractIdentity(\n claims: Record<string, unknown>,\n fileAccountId?: string | null\n): { email?: string; accountId?: string } {\n const result: { email?: string; accountId?: string } = {};\n const emailCandidates = [\n claims.chatgpt_account_email,\n claims.email,\n readNamespacedClaim(claims, 'https://api.openai.com/profile', 'email'),\n ];\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 = [\n fileAccountId,\n readNamespacedClaim(claims, 'https://api.openai.com/auth', 'chatgpt_account_id'),\n claims.account_id,\n claims.chatgpt_account_id,\n ];\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 const claims = idToken && idToken.length > 0 ? parseIdTokenClaims(idToken) : null;\n const identity = extractIdentity(claims ?? {}, file.tokens?.account_id);\n if (identity.email) auth.email = identity.email;\n if (identity.accountId) auth.accountId = identity.accountId;\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/**\n * Architectural Invariant #21 refresh-path decision core.\n *\n * Given a detector verdict and the daemon's last-known auth status,\n * decide what the caller should do. Used by BOTH refresh shells:\n * - `refreshCodexAuthSlice` (watcher-fired path, in `refresh-helpers.ts`).\n * - `runCodexAuthRefresh` (login/logout post-action path, in\n * `services/channels/codex-auth-refresher.ts`).\n *\n * The motivating case: codex atomically rewrites `~/.codex/auth.json`\n * during normal token refresh (write-tmp + rename, sometimes\n * delete + write). The filesystem watcher fires mid-window; the detector\n * returns `not-detected` because the file is briefly absent. Without a\n * debounce, this flips the banner to \"signed out\" for hundreds of\n * milliseconds even though codex just refreshed successfully. The\n * `debounce-then-recheck` verdict says: \"treat a single not-detected\n * reading as evidence, not proof, when we previously thought we were\n * authenticated; sleep briefly and look again.\"\n *\n * Pure — no IO, deterministic on inputs, exhaustively switchable.\n */\ntype CodexAuthRefreshLastKnown = 'authenticated' | 'unauthenticated' | 'unknown';\n\ntype CodexAuthRefreshVerdict =\n | { action: 'apply'; auth: CodexAuthStatus }\n | { action: 'preserve'; reason: 'parse-error' | 'fs-error' }\n | { action: 'debounce-then-recheck' };\n\n/**\n * Debounce window before re-detection. 500ms is long enough to clear\n * codex's atomic rename + write window on typical macOS/Linux\n * filesystems (the actual codex Rust writer uses `write_atomically` =\n * tempfile + rename, observed at sub-50ms on APFS/ext4 under no IO\n * pressure). Wider margin chosen for safety under IO load. Short\n * enough that a true sign-out is reflected to the UI within a single\n * user-perceptible beat. Coordinate with `capability-watcher`'s own\n * debounce before widening.\n */\nconst REFRESH_DEBOUNCE_MS = 500;\n\nfunction decideCodexAuthRefresh(\n result: CodexAuthDetectionResult,\n lastKnown: CodexAuthRefreshLastKnown\n): CodexAuthRefreshVerdict {\n switch (result.kind) {\n case 'detected':\n return { action: 'apply', auth: result.auth };\n case 'preserved':\n return { action: 'preserve', reason: result.reason };\n case 'not-detected':\n if (lastKnown === 'authenticated') return { action: 'debounce-then-recheck' };\n return { action: 'apply', auth: result.auth };\n default:\n result satisfies never;\n throw new Error('unreachable: unknown CodexAuthDetectionResult kind');\n }\n}\n","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;\n/**\n * Late-bindable breadcrumb writer. Called with the phase name at each phase\n * entry so the on-disk boot breadcrumb tracks \"what was the daemon doing\"\n * without any per-call-site cost — wrapping a step in `bootstrapPhase` already\n * records it. A native crash mid-phase then leaves the phase name on disk for\n * the next boot's `daemon_catastrophic_restart` to read. The callback is\n * fire-and-forget on the writer side; this primitive never awaits it.\n */\nlet breadcrumbSink: ((phase: string) => void) | 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 * Wire the boot-breadcrumb writer. Bound early in `serve()` (right after the\n * heartbeat) so phases from the very first wrapped step onward record their\n * name to disk for next-boot crash diagnosis.\n */\nexport function setBootstrapPhaseBreadcrumbSink(sink: ((phase: string) => void) | null): void {\n breadcrumbSink = 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 breadcrumbSink = 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 safeRecordBreadcrumb(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\n/**\n * Best-effort name of the boot phase currently executing — the most recently\n * started in-flight phase, falling back to the last completed phase, then\n * `'unknown'`. Used by the early-boot crash guard to label an exception that\n * escaped the boot path with the phase it likely died in.\n */\nexport function getCurrentBootPhase(): string {\n let latest: InFlightPhase | undefined;\n for (const phase of inFlightPhases) latest = phase;\n if (latest) return latest.name;\n const last = accumulator.at(-1);\n return last ? last.name : 'unknown';\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\nfunction safeRecordBreadcrumb(phase: string): void {\n const sink = breadcrumbSink;\n if (!sink) return;\n try {\n sink(phase);\n } catch {\n /** A throw from the breadcrumb writer 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 { validateEnv } from '../env.js';\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 = validateEnv().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', 'claude-fable'];\n\n/**\n * Returns true when `thinking: { type: 'adaptive' }` is supported. Haiku does\n * not support adaptive thinking; Sonnet 4.5+, Opus 4.5+, and Fable/Mythos 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 { 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\ntype SystemMessage = SDKMessage & { type: 'system' };\ntype SystemMessageOf<S extends SystemMessage['subtype']> = Extract<SystemMessage, { subtype: S }>;\n\ntype SubagentUsage = { totalTokens: number; toolUses: number; durationMs: number };\n\n/** Map the SDK's snake_case subagent usage to the camelCase event shape. */\nfunction mapSubagentUsage(\n usage: SystemMessageOf<'task_notification'>['usage']\n): SubagentUsage | undefined {\n if (!usage) return undefined;\n return {\n totalTokens: usage.total_tokens,\n toolUses: usage.tool_uses,\n durationMs: usage.duration_ms,\n };\n}\n\n/** Classify a `compact_boundary` system message into a completion event. */\nfunction classifyCompactBoundary(message: SystemMessageOf<'compact_boundary'>): SubprocessEvent {\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\n/** Classify a `status` system message: failed/started compaction or no-op. */\nfunction classifyCompactStatus(message: SystemMessageOf<'status'>): SubprocessEvent | null {\n if (message.compact_result === 'failed') {\n return {\n type: 'compaction_failed',\n ...(message.compact_error !== undefined ? { errorDetail: message.compact_error } : {}),\n };\n }\n return message.status === 'compacting' ? { type: 'compaction_started' } : null;\n}\n\nexport function classifySystemMessage(message: SystemMessage): 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: mapSubagentUsage(message.usage),\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: mapSubagentUsage(message.usage) ?? { totalTokens: 0, toolUses: 0, durationMs: 0 },\n };\n case 'compact_boundary':\n return classifyCompactBoundary(message);\n case 'status':\n return classifyCompactStatus(message);\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\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\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 /**\n * Background subagent stream events carry a non-null parent_tool_use_id. The\n * committed-message path already suppresses subagent content from the main\n * channel (skipForMainChannel); this streaming fast-path bypasses that guard,\n * so drop subagent deltas here to keep the two paths consistent (#4325).\n * Subagent output still surfaces via the subagent transcript watcher.\n */\n if (extractParentToolUseId(message) !== null) return null;\n\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\nfunction convertAssistantBlock(\n block: unknown,\n parentToolUseId: string | null\n): ContentBlock | null {\n if (!isRecord(block)) return null;\n /**\n * Sub-agent (Task tool) turns carry a non-null parent id; main-agent turns\n * carry null. Stamp it onto text/thinking blocks ONLY when set, so a\n * sub-agent's prose is suppressible from the main channel (`skipForMainChannel`\n * requires every block to carry it) while main-agent blocks keep their shape.\n */\n const parentField = parentToolUseId != null ? { parentToolUseId } : {};\n if (block.type === 'text') {\n return typeof block.text === 'string'\n ? { type: 'text', text: block.text, ...parentField }\n : null;\n }\n if (block.type === 'tool_use') {\n if (typeof block.id !== 'string' || typeof block.name !== 'string') return null;\n return {\n type: 'tool_use',\n toolUseId: block.id,\n toolName: block.name,\n input: toRecord(block.input),\n parentToolUseId,\n };\n }\n if (block.type === 'thinking') {\n return typeof block.thinking === 'string' && block.thinking.length > 0\n ? { type: 'thinking', text: block.thinking, ...parentField }\n : null;\n }\n if (block.type === 'redacted_thinking') {\n return { type: 'thinking', text: REDACTED_THINKING_PLACEHOLDER, ...parentField };\n }\n return null;\n}\n\nexport function convertAssistantContent(\n content: readonly unknown[],\n parentToolUseId: string | null\n): ContentBlock[] {\n const blocks: ContentBlock[] = [];\n\n for (const block of content) {\n const converted = convertAssistantBlock(block, parentToolUseId);\n if (converted !== null) blocks.push(converted);\n }\n\n return blocks;\n}\n\n/**\n * Whether an assistant/echo event's content must be suppressed from the MAIN\n * channel. True when every block carries a non-null `parentToolUseId` — i.e. the\n * whole turn belongs to a sub-agent (Task tool). Main-agent blocks omit the key\n * (or carry null), so the turn reaches the main conversation. The main Thread's\n * enqueue fast-path consults this; sub-agent content still lands in its own\n * thread channel via the transcript watcher.\n */\nexport function skipForMainChannel(content: ContentBlock[]): boolean {\n if (content.length === 0) return true;\n return content.every((b) => 'parentToolUseId' in b && b.parentToolUseId != null);\n}\n\nfunction flattenRawToolResultContent(content: unknown): string {\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return '';\n return content\n .filter((entry) => isRecord(entry) && entry.type === 'text' && typeof entry.text === 'string')\n .map((entry) => (isRecord(entry) && typeof entry.text === 'string' ? entry.text : ''))\n .join('\\n');\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 | readonly unknown[],\n parentToolUseId: string | null\n): ContentBlock[] {\n if (typeof content === 'string') return [];\n const blocks: ContentBlock[] = [];\n for (const block of content) {\n if (!isRecord(block)) continue;\n if (block.type !== 'tool_result') continue;\n if (typeof block.tool_use_id !== 'string') continue;\n const resultContent = flattenRawToolResultContent(block.content);\n blocks.push({\n type: 'tool_result',\n toolUseId: block.tool_use_id,\n content: resultContent,\n isError: block.is_error === true,\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(content: string | readonly unknown[]): 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 if (!isRecord(block)) continue;\n switch (block.type) {\n case 'text':\n if (typeof block.text === 'string' && 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 break;\n }\n }\n return blocks;\n}\n","import type { ModelDescriptor } from '@shipyard/loro-schema';\n\ntype CapabilityTier = NonNullable<ModelDescriptor['capabilityTier']>;\n\n/**\n * Single source of truth for cross-provider model \"intelligence\" ranking.\n *\n * `speedTier` is hand-assigned inside each provider catalog, which is fine\n * because speed is a within-provider judgement. Capability is NOT: the picker\n * shows it as a meter the user compares ACROSS agents, so a `strong` from Claude\n * has to mean the same as a `strong` from Cursor or the meter lies. We therefore\n * assign every model's tier HERE, against one rubric, and the three catalogs\n * pull from this table (via `withCapabilityTiers`) instead of each guessing.\n *\n * Global rubric — editorial (there is no objective cross-provider eval baked in;\n * revise as the model landscape moves):\n * frontier — current flagship, best available judgement (Opus 4.x, GPT-5.5)\n * strong — near-frontier workhorse (Sonnet 4.6, Composer 2.5, GPT-5.4)\n * capable — solid mid-tier (older frontier, e.g. GPT-5.2)\n * light — fast/cheap, lower judgement (Haiku, *-mini)\n * basic — minimal\n *\n * Keyed by descriptor `id`. Ids absent here return undefined and the picker\n * omits the intelligence meter for that model (graceful — no guess).\n */\nconst MODEL_CAPABILITY_TIERS: Record<string, CapabilityTier> = {\n 'claude-opus-4-8': 'frontier',\n 'claude-opus-4-7': 'frontier',\n 'claude-fable-5': 'frontier',\n 'claude-sonnet-4-6': 'strong',\n 'claude-sonnet-4-6[1m]': 'strong',\n 'claude-haiku-4-5-20251001': 'light',\n 'gpt-5.5': 'frontier',\n 'gpt-5.4': 'strong',\n 'gpt-5.3-codex': 'strong',\n 'gpt-5.4-mini': 'light',\n 'gpt-5.2': 'capable',\n 'composer-2.5': 'strong',\n};\n\nexport function capabilityTierFor(modelId: string): CapabilityTier | undefined {\n return MODEL_CAPABILITY_TIERS[modelId];\n}\n\n/**\n * Stamp each descriptor with its canonical capability tier from the table above.\n * Catalogs wrap their model array with this so coverage is automatic — a newly\n * added model picks up its tier the moment it's listed in the rubric, and a\n * model missing from the rubric simply ships no `capabilityTier` (meter hidden)\n * rather than silently carrying a stale or provider-local guess.\n */\nexport function withCapabilityTiers(models: ModelDescriptor[]): ModelDescriptor[] {\n return models.map((model) => ({ ...model, capabilityTier: capabilityTierFor(model.id) }));\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 CompactionProfile,\n ContentBlock,\n RewindTarget,\n PermissionMode as SchemaPermissionMode,\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';\nimport { withCapabilityTiers } from './model-capability-tiers.js';\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\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 /** Claude's SDK queues additional user input during a streaming turn — mid-run injection is safe. */\n canInjectInputMidRun: true,\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: withCapabilityTiers([\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 supportsFastMode: true,\n /**\n * Opus 4.8 Fast Mode uses the newer lower premium tier: 2× standard\n * rates at `$10/M input, $50/M output`.\n */\n fastModePricing: {\n costInputUsd: 10,\n costOutputUsd: 50,\n },\n capabilities: {\n reasoning: true,\n adaptiveThinking: true,\n webSearch: true,\n vision: true,\n },\n },\n {\n id: 'claude-fable-5',\n nativeName: 'claude-fable-5',\n displayName: 'Claude Fable 5',\n description: \"Anthropic's most capable model — Mythos-class, for long-horizon agentic work\",\n note: 'Covered Model · 30-day retention',\n contextWindow: 1_000_000,\n maxOutput: 128_000,\n supportedEfforts: ['none', 'low', 'medium', 'high', 'xhigh', 'ultracode', 'max'],\n defaultEffort: 'xhigh',\n tagline: \"Anthropic's most capable model — Mythos-class, for long-horizon agentic work\",\n speedTier: 'slow',\n costInputUsd: 10,\n costOutputUsd: 50,\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: 200_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 /**\n * Sonnet's 1M context is a separate, opt-in choice because Anthropic\n * gates it behind usage credits on subscription plans (Opus 1M is\n * included on Max; Sonnet 1M is not). Selecting this variant sends the\n * `[1m]` model id to the SDK, which activates 1M routing. If the\n * account has usage credits disabled the turn fails with a clear\n * \"Usage credits required for 1M context\" surface message rather than\n * the base (200K) Sonnet entry, which never touches the credit gate.\n */\n id: 'claude-sonnet-4-6[1m]',\n nativeName: 'claude-sonnet-4-6',\n displayName: 'Claude Sonnet 4.6 (1M)',\n description: '1M context · uses Anthropic usage credits',\n contextWindow: 1_000_000,\n maxOutput: 64_000,\n supportedEfforts: ['none', 'low', 'medium', 'high', 'max'],\n defaultEffort: 'medium',\n tagline: '1M context · uses credits',\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 * Compaction profile — declarative data only.\n *\n * Imperative methods live on `AgentSubprocess` (forceCompact via SDK control,\n * getContextUsage via SDK query) and on the per-runtime bridge modules under\n * `conversation/bridges/`. The profile carries only the static capability\n * declaration and the event matchers consumed by `dispatchToCompactionSM`.\n */\n compaction: {\n capabilities: {\n manualTrigger: 'message',\n threshold: 'tokens',\n settingsMutability: 'live',\n autoCompactToggle: true,\n contextReporting: 'live',\n bridgeFidelity: 'structured-turns',\n preCompactHook: true,\n postCompactHook: true,\n failureReporting: true,\n customInstructions: true,\n /**\n * Claude SDK `getContextUsage().thresholdTokens` returns ~0.85 of the\n * model's max in practice; mirror that as the pre-spawn planner default.\n */\n defaultThresholdFraction: 0.85,\n },\n\n events: {\n /** SDK fires `status.subtype === 'status' && status.status === 'compacting'`. */\n started: { type: 'compaction_started' },\n /** SDK fires `system.subtype === 'compact_boundary'`. */\n completed: { type: 'compaction_completed' },\n /** SDK fires `status.subtype === 'status' && status.compact_result === 'failed'`. */\n failed: { type: 'compaction_failed' },\n },\n } satisfies CompactionProfile,\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 /** Library-only skill index rides a system-prompt append for Claude. */\n skillIndexChannel: 'system-prompt',\n /**\n * Claude's native `Skill` tool is guarded by a PreToolUse hook that\n * redirects library-only skills (not in `options.skills`) to the harness\n * `load_skill` tool. Declaration only here; the hook is wired at spawn.\n */\n nativeSkillToolGuard: { toolName: 'Skill' },\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 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 /**\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 stallTimeoutMs: null,\n toolExecutionStallTimeoutMs: null,\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 CompactionProfile,\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.138.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 for the CLI daemon. The packaged Electron\n * daemon rewrites this JS command path through `resolveNodeExecPath()` with\n * `ELECTRON_RUN_AS_NODE=1` before the JSON-RPC transport spawns it, because\n * Electron installs do not guarantee a `node` binary on PATH for the\n * shebang. On Windows, `.js` is not directly executable by `spawn()` without\n * `shell: true`; the PATH fallback (`where codex`) returns the npm-generated\n * `codex.cmd` shim which is spawnable. Users on Windows therefore retain\n * the prior \"system codex on PATH\" experience until we move to\n * 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>`. Retained to\n * satisfy the required `AgentCapabilityProfile.triggerLogin` contract. Codex\n * login is now driven in-process via the shared app-server\n * (`account/login/start`, see `control-channel/auth-triggers.ts`), so the\n * daemon login path no longer spawns this subprocess descriptor.\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\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 /** Codex accepts mid-thread input — the daemon may inject resource context while a turn runs. */\n canInjectInputMidRun: true,\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 /*\n * TODO(subagent-catalog): render `getShipyardSubagentCatalog()` into the\n * task-level AGENTS.md `[agents]` section via a `renderSubagentsForCodex`\n * function (see apps/daemon/src/shared/subagent-catalog/index.ts). The\n * Codex spawn path assembles the AGENTS.md fragment in\n * codex-subprocess-spawn-helpers.ts; add the rendered section there.\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 * Native compaction profile for Codex — declarative data only.\n *\n * `settingsMutability: 'spawn-only'` means config is fixed at `thread/start`;\n * mutations queue for next spawn. UI shows \"(applies next session)\" pill\n * from this capability flag.\n */\n compaction: {\n capabilities: {\n manualTrigger: 'rpc',\n threshold: 'tokens',\n settingsMutability: 'spawn-only',\n autoCompactToggle: true,\n contextReporting: 'per-turn',\n bridgeFidelity: 'structured-turns',\n preCompactHook: true,\n postCompactHook: true,\n failureReporting: true,\n customInstructions: true,\n /**\n * Codex's per-turn token snapshots target ~0.90 of the model's max as the\n * pre-warn line; slightly higher headroom than Claude because the\n * per-turn cadence means we have fewer samples to react with.\n */\n defaultThresholdFraction: 0.9,\n },\n\n events: {\n /**\n * Matchers key on the NORMALIZED `SubprocessEvent.type` the Codex adapter\n * emits — not the raw Codex protocol notification names. The adapter\n * (`codex-item-translator.ts`) translates Codex's `thread/compacted`\n * (and the `item/started` contextCompaction signal) into a normalized\n * `compaction_completed` SubprocessEvent before it reaches the live\n * dispatch, so the matcher vocabulary is the same `compaction_*` set\n * Claude uses. This is what lets the live dispatch route every runtime's\n * compaction events through the single `dispatchToCompactionSM` helper\n * (Wave 3.4 / B3).\n *\n * Codex currently emits only `compaction_completed` (no separate\n * started/failed normalized events); the `started` matcher is declared\n * for vocabulary parity and fires if the adapter ever emits it.\n */\n started: { type: 'compaction_started' },\n completed: { type: 'compaction_completed' },\n /**\n * Codex surfaces compaction failures by translating its `ErrorNotification`\n * into a normalized `compaction_failed` SubprocessEvent (`errorDetail`\n * field). The dispatcher reads that field for the `compact_failed` SM\n * event.\n */\n failed: { type: 'compaction_failed' },\n },\n } satisfies CompactionProfile,\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 /**\n * Codex narrows skills per-thread via complement-disable on\n * `ThreadStartParams.config` (`skills.config: [{ name, enabled: false }]`).\n * The resolver computes the disable set (detected ∖ active); this maps each\n * name into the thread-start config entry shape.\n */\n skillsMechanism: {\n kind: 'thread-config-disable',\n buildDisableEntries: ({ disableNames }) =>\n disableNames.map((name) => ({ name, enabled: false })),\n },\n /** Codex carries the per-task skill index in `developerInstructions`. */\n skillIndexChannel: 'developer-instructions',\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 * 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 stallTimeoutMs: null,\n toolExecutionStallTimeoutMs: null,\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 * Emit a native Codex `skill` UserInput for a skill chip. Codex's resolver\n * loads the SKILL.md from the given path (or, for `mirror`, the symlink).\n *\n * `native` / `mirror` / `pass-in` / undefined: emit metadata when a path is\n * known. For `pass-in` the paired text block also carries the `skill://`\n * URI rewrite; the redundant metadata is harmless.\n * `unreachable`: skip — Codex rejects a skill ref it can't resolve. The\n * #4197 fallback surfaces the bare `$qa` token as text instead so a\n * skill-only unreachable send is not silently dropped.\n */\nfunction appendNativeSkillInput(out: UserInput[], block: SkillInvocationBlock): void {\n if (block.bodyResolution === 'unreachable') return;\n if (block.path) out.push({ type: 'skill', name: block.name, path: block.path });\n}\n\n/**\n * #4197 fallback: when a send resolves to no Codex input but carried skill\n * chips (unreachable, or reachable but path-less), surface each chip's sigil\n * token as text so the turn is never empty (Invariant #20).\n */\nfunction skillTokenFallback(blocks: ContentBlock[]): UserInput[] {\n const out: UserInput[] = [];\n for (const block of blocks) {\n if (block.type === 'skill_invocation') out.push({ type: 'text', text: skillToken(block) });\n }\n return out;\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 /** Skill chip → native Codex `skill` input (see `appendNativeSkillInput`). */\n case 'skill_invocation':\n appendNativeSkillInput(out, block);\n break;\n default: {\n const _exhaustive: never = block;\n throw new Error(`Unhandled content block: ${JSON.stringify(_exhaustive)}`);\n }\n }\n }\n\n /**\n * Sends that carry any other deliverable content (text OR an image) keep\n * that content and never reach this fallback; only an otherwise-empty turn\n * is rescued. An unrunnable skill must not inject a stray token alongside\n * real content. See `skillTokenFallback`.\n */\n if (out.length === 0) return skillTokenFallback(blocks);\n\n return out;\n}\n","import type { StructuredTask, StructuredTaskStatus, TaskOverlay } from '@shipyard/loro-schema';\nimport type {\n PlanDeltaNotification,\n TurnCompletedNotification,\n} from '@shipyard/session/codex-app-server';\nimport type { SubprocessEvent } from './agent-subprocess.js';\n\nexport type ProposedPlanSource = 'plan_item' | 'plan_delta' | 'raw_block';\n\nexport interface ProposedPlanCaptureContext {\n collaborationMode?: string;\n lastProposedPlan: string;\n lastProposedPlanSource: ProposedPlanSource | null;\n planDeltaBuffers: Map<string, string>;\n proposedPlanStreamHidden: boolean;\n proposedPlanStreamPending: string;\n}\n\nconst PROPOSED_PLAN_OPEN_TAG = '<proposed_plan>';\nconst PROPOSED_PLAN_CLOSE_TAG = '</proposed_plan>';\nconst PROPOSED_PLAN_BLOCK_RE =\n /^[ \\t]*<proposed_plan>[ \\t]*\\r?\\n?([\\s\\S]*?)\\r?\\n?[ \\t]*<\\/proposed_plan>[ \\t]*$/gm;\n\nexport function extractProposedPlanBlock(text: string): {\n plan: string | null;\n visibleText: string;\n} {\n let plan: string | null = null;\n const visibleText = text.replace(PROPOSED_PLAN_BLOCK_RE, (_match, body: string) => {\n plan = body;\n return '';\n });\n return { plan, visibleText: plan === null ? text : visibleText.trim() };\n}\n\nfunction longestSuffixPrefix(value: string, prefixOf: string): number {\n const max = Math.min(value.length, prefixOf.length - 1);\n for (let length = max; length > 0; length--) {\n if (value.endsWith(prefixOf.slice(0, length))) return length;\n }\n return 0;\n}\n\nexport function removeProposedPlanStreamMarkup(\n delta: string,\n ctx: ProposedPlanCaptureContext\n): string {\n ctx.proposedPlanStreamPending += delta;\n let visible = '';\n\n while (ctx.proposedPlanStreamPending.length > 0) {\n if (ctx.proposedPlanStreamHidden) {\n const closeIndex = ctx.proposedPlanStreamPending.indexOf(PROPOSED_PLAN_CLOSE_TAG);\n if (closeIndex === -1) {\n const keepLength = longestSuffixPrefix(\n ctx.proposedPlanStreamPending,\n PROPOSED_PLAN_CLOSE_TAG\n );\n ctx.proposedPlanStreamPending = ctx.proposedPlanStreamPending.slice(\n ctx.proposedPlanStreamPending.length - keepLength\n );\n return visible;\n }\n ctx.proposedPlanStreamPending = ctx.proposedPlanStreamPending.slice(\n closeIndex + PROPOSED_PLAN_CLOSE_TAG.length\n );\n ctx.proposedPlanStreamHidden = false;\n continue;\n }\n\n const openIndex = ctx.proposedPlanStreamPending.indexOf(PROPOSED_PLAN_OPEN_TAG);\n if (openIndex === -1) {\n const keepLength = longestSuffixPrefix(ctx.proposedPlanStreamPending, PROPOSED_PLAN_OPEN_TAG);\n visible += ctx.proposedPlanStreamPending.slice(\n 0,\n ctx.proposedPlanStreamPending.length - keepLength\n );\n ctx.proposedPlanStreamPending = ctx.proposedPlanStreamPending.slice(\n ctx.proposedPlanStreamPending.length - keepLength\n );\n return visible;\n }\n\n visible += ctx.proposedPlanStreamPending.slice(0, openIndex);\n ctx.proposedPlanStreamPending = ctx.proposedPlanStreamPending.slice(\n openIndex + PROPOSED_PLAN_OPEN_TAG.length\n );\n ctx.proposedPlanStreamHidden = true;\n }\n\n return visible;\n}\n\nexport function translatePlanDelta(\n delta: PlanDeltaNotification,\n ctx: ProposedPlanCaptureContext\n): SubprocessEvent[] {\n if (ctx.collaborationMode !== 'plan') return [];\n if (ctx.lastProposedPlanSource === 'plan_item') return [];\n const prior = ctx.planDeltaBuffers.get(delta.itemId) ?? '';\n const next = prior + delta.delta;\n ctx.planDeltaBuffers.set(delta.itemId, next);\n ctx.lastProposedPlan = next;\n ctx.lastProposedPlanSource = 'plan_delta';\n return [];\n}\n\nexport function clearCapturedPlanContent(ctx: ProposedPlanCaptureContext): void {\n ctx.lastProposedPlan = '';\n ctx.lastProposedPlanSource = null;\n ctx.planDeltaBuffers.clear();\n ctx.proposedPlanStreamHidden = false;\n ctx.proposedPlanStreamPending = '';\n}\n\nexport function takePlanContentReady(\n ctx: ProposedPlanCaptureContext,\n collaborationMode: string | undefined,\n turnStatus: TurnCompletedNotification['turn']['status']\n): string | null {\n if (collaborationMode !== 'plan') {\n clearCapturedPlanContent(ctx);\n return null;\n }\n const content = ctx.lastProposedPlan;\n if (content === '') {\n clearCapturedPlanContent(ctx);\n return null;\n }\n const source = ctx.lastProposedPlanSource;\n clearCapturedPlanContent(ctx);\n return source === 'plan_item' || turnStatus === 'completed' ? content : null;\n}\n\n/**\n * One item from a Codex `update_plan` tool call, as carried in the\n * `turn/plan/updated` notification. Mirrors `TurnPlanStep` from\n * `@shipyard/session/codex-app-server` — declared here as a structural\n * type so the translator does not depend on the session package.\n *\n * Status enum is a strict subset of `StructuredTaskStatus`\n * (`StructuredTaskStatus` adds `'cancelled'` which Codex cannot emit).\n */\nexport type PlanStep = {\n step: string;\n status: 'pending' | 'in_progress' | 'completed';\n};\n\nconst canonicalKey = (subject: string): string => subject.trim().toLowerCase();\n\nfunction seedIdMapFromOverlay(overlay: TaskOverlay, idMap: Map<string, string>): void {\n for (const task of overlay.userTasks) {\n const key = canonicalKey(task.subject);\n if (!idMap.has(key)) idMap.set(key, task.id);\n }\n}\n\n/**\n * Compute the next safe numeric ID for a new overlay item.\n *\n * Scans `overlay.userTasks` AND caller-supplied `baseIds` (typically\n * `Object.keys(record.structuredTasks ?? {})`) to prevent collisions with\n * CC-authored tasks on a Claude→Codex switch. Mirrors the pattern in\n * `applyTemplateBatchOp` (`task-manager-overlay.ts`).\n */\nfunction nextNumericId(overlay: TaskOverlay, baseIds: readonly string[]): number {\n const numericIds = [...overlay.userTasks.map((t) => t.id), ...baseIds]\n .map((id) => Number.parseInt(id, 10))\n .filter((n) => !Number.isNaN(n));\n return numericIds.length > 0 ? Math.max(...numericIds) + 1 : 1;\n}\n\nfunction buildAgentItem(step: PlanStep, id: string, now: number): StructuredTask {\n return {\n id,\n subject: step.step,\n status: step.status,\n owner: 'codex',\n blocks: [],\n blockedBy: [],\n createdAt: now,\n updatedAt: now,\n };\n}\n\nfunction statusOverridesUnchanged(\n next: Record<string, StructuredTaskStatus>,\n prev: TaskOverlay['statusOverrides']\n): boolean {\n const nextKeys = Object.keys(next);\n if (nextKeys.length !== Object.keys(prev).length) return false;\n for (const k of nextKeys) {\n if (prev[k] !== next[k]) return false;\n }\n return true;\n}\n\n/**\n * Pure translator for Codex `update_plan` emissions.\n *\n * Codex calls `update_plan` with the FULL plan each time (whole-plan\n * replace, no IDs in the schema). This translator merges the emission\n * into the existing `TaskOverlay` by canonical subject:\n *\n * - Empty `steps`: returns `null` so the caller skips the overlay write.\n * - Matched subjects (canonical key = trim + lowercase): status update via\n * `statusOverrides[id]` — but only when the effective current status\n * (from `statusOverrides` if present, else from `userTasks.status`)\n * differs from the requested status. Same-status re-emissions are no-ops.\n * - New subjects: appended to `userTasks` with the next numeric ID,\n * `owner: 'codex'`.\n * - Items in `overlay.userTasks` NOT mentioned by `steps`: PRESERVED. The\n * model can focus its plan on a subset of items; we don't treat the\n * omission as a delete signal.\n *\n * `idMap` is session-scoped and persists across calls. The first call\n * seeds it from existing `userTasks` so subsequent emissions reuse the\n * same numeric ID for the same canonical subject.\n *\n * `baseIds` should include `Object.keys(record.structuredTasks ?? {})` so\n * Codex-allocated IDs don't collide with CC-authored tasks on a\n * Claude→Codex task switch. `applyCodexPlanUpdateOp` passes these.\n *\n * Returns `null` when nothing materially changed — the caller can skip\n * the overlay write, the version bump, and the broadcast.\n */\nexport function translateCodexPlanUpdate(\n steps: PlanStep[],\n overlay: TaskOverlay,\n idMap: Map<string, string>,\n baseIds: readonly string[] = []\n): TaskOverlay | null {\n if (steps.length === 0) return null;\n\n seedIdMapFromOverlay(overlay, idMap);\n\n const effectiveStatus = new Map<string, StructuredTaskStatus>(\n overlay.userTasks.map((t) => [t.id, overlay.statusOverrides[t.id] ?? t.status])\n );\n\n const statusOverrides: Record<string, StructuredTaskStatus> = { ...overlay.statusOverrides };\n const newItems: StructuredTask[] = [];\n let nextId = nextNumericId(overlay, baseIds);\n const now = Date.now();\n\n for (const step of steps) {\n const key = canonicalKey(step.step);\n const existingId = idMap.get(key);\n\n if (existingId === undefined) {\n const id = String(nextId++);\n idMap.set(key, id);\n newItems.push(buildAgentItem(step, id, now));\n } else if (effectiveStatus.get(existingId) !== step.status) {\n statusOverrides[existingId] = step.status;\n }\n }\n\n if (newItems.length === 0 && statusOverridesUnchanged(statusOverrides, overlay.statusOverrides)) {\n return null;\n }\n\n return {\n ...overlay,\n userTasks: newItems.length > 0 ? [...overlay.userTasks, ...newItems] : overlay.userTasks,\n statusOverrides,\n };\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.\n *\n * Converts Codex `ThreadItem` records and turn-scoped notifications into\n * canonical `SubprocessEvent`s. Unknown item types are logged and dropped for\n * forward compatibility; per-turn state lives in `TranslatorCtx`.\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 { extractProposedPlanBlock, type ProposedPlanSource } from './codex-plan-translator.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 /** Last proposed-plan markdown captured from plan item, plan delta, or raw block. */\n lastProposedPlan: string;\n /** Capture source. Completed plan items are authoritative over fallback sources. */\n lastProposedPlanSource: ProposedPlanSource | null;\n /** Best-effort buffers for experimental `item/plan/delta` chunks. */\n planDeltaBuffers: Map<string, string>;\n /** Whether live assistant deltas are currently inside a proposed-plan block. */\n proposedPlanStreamHidden: boolean;\n /** Buffered live assistant suffix that may be the start of a proposed-plan tag. */\n proposedPlanStreamPending: 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 * Total context window fill (tokens) from the most recent\n * `thread/tokenUsage/updated` notification (`tokenUsage.last.totalTokens`).\n * Written by `handleTokenUsageUpdated` in `codex-turn-event-dispatch.ts`.\n * Null before the first usage notification arrives. Used as `preTokens`\n * on `compaction_completed` so the context fill-bar shows a real baseline\n * after compaction rather than falling back to the synthetic estimate.\n * NOT reset between turns — the last-seen value is valid until a newer\n * notification overwrites it.\n */\n latestContextFillTokens: number | 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 lastProposedPlanSource: null,\n planDeltaBuffers: new Map(),\n proposedPlanStreamHidden: false,\n proposedPlanStreamPending: '',\n emittedToolUseItemIds: new Set(),\n emittedToolResultItemIds: new Set(),\n lastStreamBlockType: null,\n latestContextFillTokens: 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 /**\n * Transient-401 narrowing: a \"missing bearer\" 401 means the Codex\n * app-server lost its in-memory token mid-stream (typically during\n * refresh-token rotation), NOT that the user is signed out. Classifying\n * it as `auth_required` would generate a false sign-out signal — the\n * detector-verifier in `codex-auth-verifier.ts` re-checks disk anyway,\n * but it's cleaner to filter the false positive at the source. The bare\n * \"Unauthorized\" token in the upstream error string would otherwise\n * match the `auth_required` branch below.\n */\n if (/missing\\s+bearer/.test(msg)) return null;\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 /**\n * Issue #3938: Codex emits `warning` notifications during normal\n * operation (e.g. \"compacting skills, skill descriptions were\n * shorter: 2%\") that are progress signals, NOT errors. Surfacing\n * them as `sdk_error` collapses the FSM `running → resumable_idle`\n * and flips task status to `input_required`, so the still-running\n * task appears \"paused\" in the UI. Codex distinguishes `warning`\n * and `error` notification methods at the protocol level — only the\n * latter is fatal. Emit `informational_notice` so the daemon logs\n * the message but the FSM and task status stay untouched.\n */\n return { type: 'informational_notice', source: 'codex_warning', message: 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 *\n * @param preTokens - Context fill at the moment of compaction, derived from\n * the most recent `thread/tokenUsage/updated` notification. Absent when no\n * usage notification arrived before `thread/compacted` fired; in that case\n * the downstream `?? syntheticPre` fallback in `task-compaction.ts` applies.\n * NOT hardcoded to 0 — a literal 0 would suppress the fallback.\n */\nexport function translateContextCompacted(\n _notif: ContextCompactedNotification,\n preTokens?: number\n): SubprocessEvent {\n return { type: 'compaction_completed', ...(preTokens !== undefined ? { preTokens } : {}) };\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\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 { type CanonicalSubagentStatus, classifyCodexAgentStatus, 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 const text =\n ctx.collaborationMode === 'plan'\n ? extractProposedPlanBlock(item.text)\n : { plan: null, visibleText: item.text };\n if (text.plan !== null && ctx.lastProposedPlanSource !== 'plan_item') {\n ctx.lastProposedPlan = text.plan;\n ctx.lastProposedPlanSource = 'raw_block';\n }\n if (text.visibleText === '') return [];\n return [\n {\n type: 'assistant_message',\n messageId: item.id,\n content: [{ type: 'text', text: text.visibleText }],\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 if (ctx.collaborationMode !== 'plan') return [];\n /** Codex's `item/started` for plan items carries empty text; wait for completion. */\n if (item.text === '') return [];\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 * Do not synthesize an `ExitPlanMode` tool card here: that routes\n * through Claude's file-detector path and can publish a stale tracked\n * plan before the direct Codex `plan_content_ready` handoff writes\n * the authoritative content.\n */\n ctx.lastProposedPlan = item.text;\n ctx.lastProposedPlanSource = 'plan_item';\n ctx.planDeltaBuffers.delete(item.id);\n return [];\n}\n\n/**\n * G-9: translate a `contextCompaction` thread item into compaction lifecycle\n * events. Codex fires this item on both `item/started` and `item/completed`\n * (status-less, so we gate on the ledger). The FIRST sighting emits\n * `compaction_started` so the compaction SM enters `compacting`; subsequent\n * sightings emit `compaction_completed`.\n *\n * Why this matters: before this, autonomous Codex compaction translated\n * straight to `compaction_completed` (SM jumped idle → post-flash), so the SM\n * was NEVER in `compacting`. An ErrorNotification arriving mid-compaction\n * came through as a bare `sdk_error` while the SM was `idle`, so the\n * `handleSdkError` `compacting` gate never fired and the failure was silently\n * dropped (no banner, no retry). By entering `compacting` first, an\n * autonomous-compaction failure now reaches the SM via the existing\n * `sdk_error → compact_failed` gate, AND the watchdog (G-10) arms to catch a\n * genuine wedge.\n */\nfunction translateContextCompactionItem(\n item: Extract<KnownThreadItem, { type: 'contextCompaction' }>,\n ctx: TranslatorCtx\n): SubprocessEvent[] {\n if (!ctx.emittedToolUseItemIds.has(item.id)) {\n ctx.emittedToolUseItemIds.add(item.id);\n return [{ type: 'compaction_started' }];\n }\n const fill = ctx.latestContextFillTokens;\n return [{ type: 'compaction_completed', ...(fill !== null ? { preTokens: fill } : {}) }];\n}\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 return translateContextCompactionItem(item, ctx);\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';\nimport { withCapabilityTiers } from './model-capability-tiers.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[] = withCapabilityTiers([\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 prompt/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: native `mode:'plan'` on the init/reinit IPC (since\n * @cursor/sdk@1.0.18) + hooks.json deny-writes hard layer + plan capture via\n * the runner's `onStep` `createPlan` toolCall (→ `plan_proposed` IPC →\n * `plan_content_ready`). `canPlanMode: true`. 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';\nimport type {\n AgentAuthDetectionResult,\n AgentCapabilityProfile,\n CompactionProfile,\n ContentBlock,\n ResolvedAuth,\n RewindTarget,\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 { resolveNodeExecPath } from '../../../shared/spawn-as-node.js';\nimport type { ShipyardSubagent } from '../../../shared/subagent-catalog/index.js';\nimport { cursorTruncateConversation } from '../../conversation/bridges/cursor-bridge.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 type { DaemonToRunnerAgents } from '../cursor-runner-protocol.js';\nimport type { CursorMeCache } from './cursor-me-cache.js';\nimport { CURSOR_MODEL_CATALOG } from './cursor-model-catalog.js';\nimport { cursorPermissionModeMap } from './cursor-permission-policy.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 * Injected me-cache dependency. Populated by the profile-registry init path\n * after `createCursorMeCache` is constructed with the live `Cursor.me` method.\n * Until injection (or when not set), `cursorAuthDetect` runs without identity\n * enrichment — auth still works; the Settings card just shows the key hint\n * only instead of the key name + email.\n */\nlet cursorMeCache: CursorMeCache | null = null;\n\n/**\n * Wire the me-cache into the static profile module. Called once during daemon\n * boot from the profile-registry init path (S4). Subsequent calls overwrite\n * the binding (test ergonomics).\n */\nexport function _setCursorMeCache(cache: CursorMeCache): void {\n cursorMeCache = cache;\n}\n\n/** Test-only: clear the injected me-cache binding. */\nexport function _resetCursorMeCacheForTests(): void {\n cursorMeCache = null;\n}\n\n/**\n * Returns the injected me-cache, or `null` when boot has not yet completed.\n * Used by the reactive verifier (`cursor-auth-verifier.ts` via\n * `control-channel-wiring.ts`) to force a fresh `Cursor.me()` validation\n * when a subprocess `auth_not_logged_in` event arrives.\n */\nexport function getCursorMeCache(): CursorMeCache | null {\n return cursorMeCache;\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 * 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 *\n * Passes the me-cache when available so the `detected` result carries\n * `apiKeyName` and `email` from `Cursor.me()` without a new network call.\n */\nfunction cursorAuthDetectorBinding(methodHint?: string): Promise<AgentAuthDetectionResult> {\n return cursorAuthDetect(methodHint, getEffectiveVaultDeps(), cursorMeCache ?? undefined);\n}\n\n/**\n * Translate the shared subagent catalog into Cursor's `AgentOptions.agents`\n * shape (`Record<string, AgentDefinition>`).\n *\n * Field mapping:\n * catalog.id → map key\n * catalog.description → AgentDefinition.description\n * catalog.systemPrompt → AgentDefinition.prompt\n * catalog.model → AgentDefinition.model (`{ id }` selection or absent)\n * catalog.mcpServerNames → AgentDefinition.mcpServers (array of string names)\n *\n * `model` uses `\"inherit\"` when absent so subagents use the parent's model\n * by default, matching the SDK's own default behavior.\n *\n * MCP servers are passed as bare string names. The Cursor SDK resolves them\n * against the parent agent's registered server map at spawn time — the same\n * servers already registered via `Agent.create({mcpServers})`.\n */\nexport function renderSubagentsForCursor(catalog: ShipyardSubagent[]): DaemonToRunnerAgents {\n const result: DaemonToRunnerAgents = {};\n for (const entry of catalog) {\n const def: DaemonToRunnerAgents[string] = {\n description: entry.description,\n prompt: entry.systemPrompt,\n model: entry.model !== undefined ? { id: entry.model } : 'inherit',\n ...(entry.mcpServerNames !== undefined && entry.mcpServerNames.length > 0\n ? { mcpServers: entry.mcpServerNames }\n : {}),\n };\n result[entry.id] = def;\n }\n return result;\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/api?section=user-keys#user-api-keys.',\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 /** Cursor models a turn as a discrete run — a second concurrent `agent.send()` throws \"already has active run\". */\n canInjectInputMidRun: false,\n },\n\n /**\n * Rewind contract — `@cursor/sdk@1.0.13` has no live-rollback RPC, but the\n * conversation lives in a git-shaped Merkle tree (per-agent `store.db`), so a\n * rewind is a lossless head re-point + ledger trim, done on disk while no SDK\n * process holds the store. We declare `dropLastTurns` (the divider lights up\n * + the handler computes the turn count); `applyLive` stays absent so the\n * dispatch stops the agent first, then the handler's `truncate_agent_store`\n * step calls `truncateNativeStore` on the freed DB. `toSpawnOptions` returns\n * null because the respawn just `Agent.resume`s the truncated store — no\n * spawn-time resume mark. Surviving turns are byte-for-byte native data.\n */\n rewind: {\n supports: new Set<RewindTarget['kind']>(['dropLastTurns']),\n toSpawnOptions(_target: RewindTarget) {\n return null;\n },\n truncateNativeStore: async (deps) => {\n const result = cursorTruncateConversation(deps);\n if (result.kind === 'noop') {\n logger.warn(\n {\n event: 'cursor_rewind_truncate_noop',\n reason: result.reason,\n agentId: deps.agentId,\n numTurnsToDrop: deps.numTurnsToDrop,\n },\n 'cursor_rewind_truncate_noop'\n );\n return;\n }\n logger.info(\n {\n event: 'cursor_rewind_truncated',\n agentId: deps.agentId,\n keptThroughTurnNumber: result.keptThroughTurnNumber,\n runsDeleted: result.runsDeleted,\n },\n 'cursor_rewind_truncated'\n );\n },\n },\n\n /**\n * Spawn contract — drives `CursorAgentSubprocess` (Option B: forked\n * Node child running `cursor-runner.js`). `binaryResolver` returns\n * `resolveNodeExecPath()` (the daemon's own Node binary, or the\n * Electron-main-forwarded binary in a packaged build where the utility\n * process's `process.execPath` points at a missing helper); `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(resolveNodeExecPath()),\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 and dedup. Calling\n * `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 * Null because Cursor's plan capture now rides on the SDK's native\n * `createPlan` toolCall: the runner's `onStep` emits a `plan_proposed` IPC\n * and the subprocess turns it into a `plan_content_ready` SubprocessEvent\n * (`cursor-subprocess.ts`), not through this profile-level `extract`\n * contract. Matches `claude-code-profile.ts` — keeping a stubbed `extract`\n * here would advertise a function the daemon never calls and read a\n * translator-ctx field (`lastProposedPlan`) that no longer exists.\n */\n planContentSource: null,\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 * Compaction profile for Cursor — declarative data only.\n *\n * Cursor's summarization is managed entirely by Cursor's server — Shipyard\n * cannot trigger, configure, or observe it via the SDK. The profile is\n * therefore capability-minimal:\n *\n * - `manualTrigger: 'none'` — no manual trigger exposed.\n * - `threshold: 'none'` + `autoCompactToggle: false` — no threshold to\n * configure; Cursor ignores external threshold hints.\n * - `preCompactHook: true` — Cursor fires a `preCompact` hook that can be\n * observed passively via `.cursor/hooks.json`.\n * - `contextReporting: 'estimated'` — Shipyard derives fill from\n * accumulated turn tokens divided by the model's context window.\n */\n compaction: {\n capabilities: {\n manualTrigger: 'none',\n threshold: 'none',\n settingsMutability: 'spawn-only',\n autoCompactToggle: false,\n contextReporting: 'estimated',\n bridgeFidelity: 'structured-turns',\n preCompactHook: true,\n postCompactHook: false,\n failureReporting: false,\n customInstructions: false,\n /**\n * Cursor exposes no Shipyard-visible threshold (`threshold: 'none'`,\n * `manualTrigger: 'none'`). The planner short-circuits to `direct`\n * for any Cursor destination — defaultThresholdFraction is null to\n * match `threshold: 'none'`.\n */\n defaultThresholdFraction: null,\n },\n\n events: {\n /**\n * Cursor's server begins summarization → the runner forwards a\n * `summary_started` IPC signal (from the `onDelta` interaction stream),\n * which `cursor-subprocess.ts` normalizes to a `compaction_started`\n * SubprocessEvent. Matcher keys on the NORMALIZED event type (same\n * vocabulary as Claude/Codex) so the live dispatch routes it through\n * `dispatchToCompactionSM`. See B2.\n */\n started: { type: 'compaction_started' },\n /** Cursor's summarization finishes → normalized `compaction_completed`. */\n completed: { type: 'compaction_completed' },\n /** Cursor does not surface compaction failures as events. */\n failed: null,\n },\n } satisfies CompactionProfile,\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 native skill lever — A#23. The SDK exposes no `skills`\n * option, so skills reach the agent entirely through the harness\n * `list_skills` / `load_skill` tools. `kind: 'none'` is fully functional —\n * the harness tools + resolver carry the whole feature.\n */\n skillsMechanism: { kind: 'none' },\n /** Cursor's index is a static line in the connect-frozen harness instructions. */\n skillIndexChannel: 'harness-static',\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, then propose your plan by calling ' +\n '`createPlan({ plan: \"...\" })` with the full plan as markdown — that ' +\n 'tool call is how Shipyard captures the plan, so a plan written only ' +\n 'as a chat message will not be captured. Wait for the user to approve ' +\n 'before 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> with their visible IDs (for example, use ' +\n 'id: \"1\" for #1). Keep that same ID if you rename a template item, ' +\n 'and omit id only for brand-new steps. 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 * 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 * 3 min of TRUE silence after the first step has landed. The watchdog is\n * reset by BOTH completed steps (`step_progress`) and streamed output\n * (`stream_activity` — assistant/thinking/tool deltas), so this window now\n * measures a genuine hang, not step cadence. The old 90 s value false-killed\n * healthy-but-slow single steps (long shell/test runs, slow MCP tools, big\n * reads, extended reasoning) that streamed for >90 s without completing a\n * step. 3 min is the agent-operation timeout floor (no agent op below\n * ~2-3 min). Cold-start is handled separately by `firstStepStallTimeoutMs`\n * because the SDK's lazy executor build on the first send can legitimately\n * take longer still.\n */\n stallTimeoutMs: 180_000,\n /**\n * 5 min from spawn to the FIRST `step_progress`. The @cursor/sdk's\n * process-scoped `localExecutorCache` is built lazily on the first\n * `agent.send()` — fresh forks pay this cost (the daemon's spike\n * measurements showed 60+s on a slow daemon). The mid-run watchdog at its\n * original 90 s (now 180 s — see `stallTimeoutMs`) killed cold builds before\n * they could land their first step, which the user perceived as \"Cursor\n * never starts.\" The pool's\n * `reinit` path warmly reuses this cache, so subsequent task switches\n * cost ~1 s — this cold window is only paid by the very first task per\n * runner generation, and at boot by the pre-warm path.\n */\n firstStepStallTimeoutMs: 300_000,\n /**\n * 15 min while a tool call is actively in flight (between\n * `tool_execution_started` and `tool_execution_settled` IPC edges). This\n * covers long-running tools such as `git commit` with a full `pnpm check`\n * pre-commit hook (3–10 min in a monorepo). The mid-run watchdog at 180s\n * was false-killing healthy runners executing those tools because the SDK\n * emits no `stream_activity` deltas during shell/tool execution — only the\n * final result arrives, and the silence tripped the watchdog (#4229/#4047).\n * 15 min is short enough to still catch a genuinely hung tool subprocess;\n * long enough to survive the largest known pre-commit hook suites.\n */\n toolExecutionStallTimeoutMs: 900_000,\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 *\n * ## The `null`-is-ambiguous problem (#4147, M1)\n *\n * The vault wrapper (`serve-factory.ts` `vault.get`) returns `null` in TWO\n * distinguishable-only-by-context cases:\n * 1. **Genuine miss** — no `cursor:api-key` record on disk (logged out).\n * 2. **Transient** — the master key (`cursorVaultKeyRef`) is not yet resolved\n * (a boot window). The encrypted key IS on disk; it just can't be decrypted\n * yet, so the wrapper returns `null` instead of throwing.\n *\n * The detector returns `not-detected` for both. Treating case 2 as a definitive\n * sign-out flips the user to \"Not signed in\" mid-boot even though the key is on\n * disk. Per Invariant #21 (auth mutates only through the detector; preserve on\n * transient not-detected), `decideCursorAuthRefresh` treats a `not-detected`\n * reading as *evidence, not proof* when last-known was `authenticated`, and\n * preserves. This mirrors codex's `decideCodexAuthRefresh`.\n */\nexport {\n type CursorAuthDetectionResult,\n type CursorAuthRefreshLastKnown,\n type CursorAuthRefreshVerdict,\n cursorAuthDetect,\n decideCursorAuthRefresh,\n lastKnownCursorStatus,\n};\n\nimport type { AgentAuthDetectionResult, CursorAuthStatus } from '@shipyard/loro-schema';\nimport type { CursorVaultDeps } from '../../services/session/cursor-auth.js';\nimport type { CursorMeCache } from '../../services/session/profiles/cursor-me-cache.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 * Build a `detected` auth result for a valid key, enriched with `Cursor.me()`\n * identity when the cache has it. Shared by the vault and env paths so the\n * detected-auth shape stays identical (and keeps `cursorAuthDetect` simple).\n *\n * If the cache reports `auth-failed` the key is present but proven invalid —\n * return `NOT_DETECTED` so the capabilities layer surfaces `unauthenticated`.\n * All other outcomes (`identity-ok`, `network-error`, `never`) are treated as\n * authenticated: we fail open on network blips and un-checked keys.\n */\nfunction buildDetectedAuth(key: string, meCache?: CursorMeCache): CursorAuthDetectionResult {\n if (meCache?.getValidationOutcomeForKey(key) === 'auth-failed') {\n return NOT_DETECTED;\n }\n const identity = meCache?.getIdentity();\n return {\n kind: 'detected',\n auth: {\n status: 'authenticated',\n method: 'api-key',\n apiKeyHint: formatCursorKeyHint(key),\n /** Cursor has no real account info — last 4 chars as a stable collision proxy (Step 19). */\n accountId: key.slice(-4),\n ...(identity?.apiKeyName !== undefined ? { apiKeyName: identity.apiKeyName } : {}),\n ...(identity?.email !== undefined ? { email: identity.email } : {}),\n },\n };\n}\n\n/**\n * Detect Cursor auth status without a blocking 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 * @param meCache Optional identity cache populated by `Cursor.me()`.\n * When present, the cached `apiKeyName` and `email` are\n * attached to the `detected` result — no new network call\n * is made here; the cache handles its own refresh lifecycle.\n */\nasync function cursorAuthDetect(\n _methodHint: string | undefined,\n deps: CursorVaultDeps,\n meCache?: CursorMeCache\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)) return buildDetectedAuth(trimmed, meCache);\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)) return buildDetectedAuth(envKey, meCache);\n\n return NOT_DETECTED;\n}\n\n/**\n * Architectural Invariant #21 refresh-path decision core for Cursor.\n *\n * Cursor's analog of `decideCodexAuthRefresh` (codex-auth-detect.ts). Given a\n * detector verdict and the daemon's last-known cursor auth status, decide what\n * the periodic/backstop refresh should do with `capabilities.cursorAuth`.\n *\n * - `detected` → apply the fresh status.\n * - `preserved` → keep last-known (detector saw a vault IO/decrypt throw).\n * - `not-detected` → the `null`-is-ambiguous case (see module header):\n * · last-known `authenticated` → PRESERVE. A bare not-detected during a\n * master-key-unresolved window is evidence, not proof, of sign-out.\n * A genuine sign-out is flipped immediately by the explicit logout\n * path (`runRefreshCursorAuth`) and caught at point-of-use by\n * `verifyAndMarkCursorUnauthenticated` — so preserving here never\n * strands the user falsely-authenticated while actually using Cursor.\n * · otherwise → apply (the user was already not signed in).\n *\n * Pure — no IO, deterministic on inputs, exhaustively switchable. This is\n * applied ONLY on the non-explicit refresh path (`refreshAuthAcrossProfiles`);\n * the explicit login/logout writer deliberately does NOT route through it so an\n * intentional logout flips the badge without waiting for a point-of-use 401.\n */\ntype CursorAuthRefreshLastKnown = 'authenticated' | 'unauthenticated' | 'unknown';\n\ntype CursorAuthRefreshVerdict =\n /**\n * `auth` is `unknown` because the source is `AgentAuthDetectionResult.auth`\n * (the shared detector union, `auth: unknown`) — not a locally-narrowed\n * type like codex's `CodexAuthStatus`. The caller (`assignProfileAuth`) is\n * the narrowing gate: it Zod-parses via the profile adapter before writing\n * the slot. Asserting `CursorAuthStatus` here would be an unchecked cast.\n */\n | { action: 'apply'; auth: unknown }\n | { action: 'preserve'; reason: 'detector-preserved' | 'transient-not-detected' };\n\nfunction decideCursorAuthRefresh(\n result: CursorAuthDetectionResult,\n lastKnown: CursorAuthRefreshLastKnown\n): CursorAuthRefreshVerdict {\n switch (result.kind) {\n case 'detected':\n return { action: 'apply', auth: result.auth };\n case 'preserved':\n return { action: 'preserve', reason: 'detector-preserved' };\n case 'not-detected':\n if (lastKnown === 'authenticated') {\n return { action: 'preserve', reason: 'transient-not-detected' };\n }\n return { action: 'apply', auth: result.auth };\n default:\n result satisfies never;\n throw new Error('unreachable: unknown CursorAuthDetectionResult kind');\n }\n}\n\n/**\n * Narrow a last-known `CursorAuthStatus` into the discriminator\n * `decideCursorAuthRefresh` consumes. Mirrors `lastKnownCodexStatus` in\n * `refresh-helpers.ts`.\n */\nfunction lastKnownCursorStatus(auth: CursorAuthStatus | undefined): CursorAuthRefreshLastKnown {\n if (auth?.status === 'authenticated') return 'authenticated';\n if (auth?.status === 'unauthenticated') return 'unauthenticated';\n return 'unknown';\n}\n","/**\n * cursor-bridge.ts — Cursor conversation bridge.\n *\n * Two public functions:\n *\n * cursorExportConversation — thin wrapper around toMCPMessages() that converts\n * Shipyard's OWN JSONL log (Message[]) into a NeutralConversation. Note: this\n * reads Shipyard's daemon-maintained transcript, NOT Cursor's SDK history —\n * Cursor's `Run.conversation()` is auxiliary and the SDK exposes no\n * history-injection API (audit-cursor-import.md). Pure, no I/O.\n *\n * cursorImportConversation — the only structured-import path that exists for\n * Cursor: fabricate the `ConversationStateStructure` Merkle tree and write it\n * into the SDK's local SQLite stores so a subsequent `Agent.resume(agentId)`\n * reads it back as prior context. Performs I/O via writeCursorHistory.\n *\n * Path resolution (verbatim from @cursor/sdk@1.0.13 dist/esm/index.js):\n *\n * projectsBase = $CURSOR_DATA_DIR || ~/.cursor , then /projects\n * slug(cwd) = cwd.replace(/[^a-zA-Z0-9]/g,'-')\n * .replace(/-+/g,'-')\n * .replace(/^-+|-+$/g,'')\n * (the SDK's `Ki` function — see `Zi(homedir, cwd)` which is\n * `${homedir}/.cursor/projects/${Ki(cwd)}`. NOT the SDK's `Xi`\n * function (encodeURIComponent + %→_ + slice 200), which is\n * used elsewhere in the SDK but NOT for the projects-path slug.\n * Pre-2026-05-30 this file used the Xi formula, which silently\n * produced empty resume context because the writer and reader\n * resolved different paths.)\n * stateRoot = projectsBase/slug(cwd)/sdk-agent-store/<md5hex(cwd)>\n * index.db = stateRoot/index.db\n * store.db = stateRoot/agents/agent-<sha256hex(agentId)>/store.db\n *\n * The SDK honors `CURSOR_DATA_DIR` for the projects base — which is exactly how\n * the integration test isolates writes to a temp dir without touching ~/.cursor.\n *\n * Wave 6 wiring (see /tmp/wave-4-3-implementation-report.md for the two exact\n * edit sites):\n * 1. cursor-subprocess.ts — BEFORE `fork()` (~line 640), the daemon calls\n * cursorImportConversation(neutral, { agentId, cwd, model, ... }) so the\n * store.db exists before the runner process starts. The injection has an\n * exclusive write window (the runner is not yet alive).\n * 2. cursor-runner.ts handleInit — when an `injectedAgentId` is present in the\n * init payload, call `Agent.resume(injectedAgentId, {...})` instead of\n * `Agent.create({...})` to avoid a PRIMARY KEY conflict on the agents row\n * and to make the SDK read the fabricated store.db.\n */\n\nimport { createHash } from 'node:crypto';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Message, NeutralConversation } from '@shipyard/loro-schema';\nimport type { ToMCPMessagesOptions } from '../to-mcp-messages.js';\nimport { toMCPMessages } from '../to-mcp-messages.js';\nimport type { ExportResult, ImportResult } from './bridge-types.js';\nimport {\n cursorTruncateHistory,\n type TruncateCursorHistoryResult,\n} from './cursor-history-injector/sqlite-truncator.js';\nimport { writeCursorHistory } from './cursor-history-injector/sqlite-writer.js';\n\n/**\n * Export a Shipyard Message[] conversation (from the daemon's JSONL log) to a\n * NeutralConversation. Thin wrapper around `toMCPMessages()`.\n */\nexport function cursorExportConversation(\n messages: Message[],\n ctx: {\n sourceModel: string;\n archiveLogPath: string;\n compactionApplied: boolean;\n }\n): ExportResult {\n const opts: ToMCPMessagesOptions = {\n sourceRuntime: 'cursor',\n sourceModel: ctx.sourceModel,\n archiveLogPath: ctx.archiveLogPath,\n compactionApplied: ctx.compactionApplied,\n };\n const { neutral, droppedToolResults, thinkingDropped } = toMCPMessages(messages, opts);\n return { neutral, droppedToolResults, thinkingDropped };\n}\n\nexport interface CursorImportDeps {\n /** Pre-chosen agentId the runner will `Agent.resume()` with. */\n agentId: string;\n /** Absolute workspace path (the agent's cwd). */\n cwd: string;\n /** Model id the resumed agent should report. */\n model: string;\n /** Shipyard task id (provenance, stamped into agents.metadata_json). */\n shipyardTaskId: string;\n /**\n * Override for the Cursor projects base directory. Production passes\n * undefined (resolves to $CURSOR_DATA_DIR || ~/.cursor); tests pass a temp\n * dir. Equivalent to setting the CURSOR_DATA_DIR env var.\n */\n cursorDataDir?: string;\n}\n\n/**\n * Fabricate the Cursor Merkle tree and write it into the SDK's SQLite stores.\n * After this resolves, `Agent.resume(deps.agentId, { local: { cwd } })` will\n * read the injected conversation as prior context.\n */\nexport function cursorImportConversation(\n neutral: NeutralConversation,\n deps: CursorImportDeps\n): ImportResult {\n const paths = resolveCursorDbPaths(deps.cwd, deps.agentId, deps.cursorDataDir);\n\n const result = writeCursorHistory({\n indexDbPath: paths.indexDbPath,\n storeDbPath: paths.storeDbPath,\n agentId: deps.agentId,\n workspaceRef: deps.cwd,\n neutral,\n model: deps.model,\n shipyardTaskId: deps.shipyardTaskId,\n });\n\n return {\n acceptedTurns: result.turnCount,\n formatChosen: 'sqlite',\n warnings:\n result.blobsWritten === 0\n ? [\n 'cursor sqlite injection: empty conversation — only the empty-state root blob was written',\n ]\n : [],\n };\n}\n\nexport interface CursorTruncateDeps {\n /** Absolute workspace path (the agent's cwd) — resolves index.db + store.db. */\n cwd: string;\n /** The persisted Cursor agentId (`TaskRecord.cursorAgentId`) to truncate. */\n agentId: string;\n /** Number of trailing completed turns to drop (the `dropLastTurns` count). */\n numTurnsToDrop: number;\n /** Test override for the Cursor projects base; production passes undefined. */\n cursorDataDir?: string;\n}\n\n/**\n * Rewind a native Cursor conversation by truncating its own SQLite Merkle store\n * to keep turns 0..N. Resolves the per-workspace/per-agent DB paths, then\n * re-points the BlobStore head + drops the runs tail so the next\n * `Agent.resume(agentId)` reconstructs the surviving turns byte-for-byte.\n * Mirror of `cursorImportConversation` for the rewind direction. Performs I/O\n * via cursorTruncateHistory; throws on SQLite errors (caller degrades).\n */\nexport function cursorTruncateConversation(deps: CursorTruncateDeps): TruncateCursorHistoryResult {\n const paths = resolveCursorDbPaths(deps.cwd, deps.agentId, deps.cursorDataDir);\n return cursorTruncateHistory({\n indexDbPath: paths.indexDbPath,\n storeDbPath: paths.storeDbPath,\n agentId: deps.agentId,\n numTurnsToDrop: deps.numTurnsToDrop,\n });\n}\n\nexport interface CursorDbPaths {\n stateRoot: string;\n indexDbPath: string;\n storeDbPath: string;\n}\n\n/**\n * Compute the index.db + store.db paths the SDK uses for a given cwd + agentId.\n * Exported so the integration test can assert the exact paths and so Wave 6 can\n * reuse the resolver without depending on private SDK internals.\n */\nexport function resolveCursorDbPaths(\n cwd: string,\n agentId: string,\n cursorDataDir?: string\n): CursorDbPaths {\n const envDir = process.env.CURSOR_DATA_DIR?.trim();\n const base = cursorDataDir ?? (envDir && envDir.length > 0 ? envDir : join(homedir(), '.cursor'));\n const projectsBase = join(base, 'projects');\n const stateRoot = join(projectsBase, slugForCwd(cwd), 'sdk-agent-store', md5Hex(cwd));\n const indexDbPath = join(stateRoot, 'index.db');\n const storeDbPath = join(stateRoot, 'agents', `agent-${sha256Hex(agentId)}`, 'store.db');\n return { stateRoot, indexDbPath, storeDbPath };\n}\n\n/**\n * Slug a cwd into a single path component, matching the SDK's `Ki` (verbatim\n * from @cursor/sdk@1.0.13 dist/esm/index.js — search for `Ki(e){return`):\n * cwd.replace(/[^a-zA-Z0-9]/g,'-').replace(/-+/g,'-').replace(/^-+|-+$/g,'')\n *\n * This is the slug the SDK uses when constructing the projects-path segment\n * (see `Zi(e,t) = `${e}/.cursor/projects/${Ki(t)}``). The SDK ALSO defines a\n * different function `Xi` (encodeURIComponent + %→_ + slice 200) used in other\n * contexts; using Xi here was the bug — writer and reader resolved different\n * directories and `Agent.resume(injectedId)` silently found no agent.\n *\n * Exported so the sqlite-writer test can assert parity with the SDK regex.\n */\nexport function slugForCwd(cwd: string): string {\n return cwd\n .replace(/[^a-zA-Z0-9]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\nfunction md5Hex(input: string): string {\n return createHash('md5').update(input).digest('hex');\n}\n\nfunction sha256Hex(input: string): string {\n return createHash('sha256').update(input).digest('hex');\n}\n","/**\n * Rough chars-per-token ratio for English prose, used wherever we have to\n * estimate a token count from a length-in-chars (or vice versa) without\n * round-tripping through the model's tokenizer.\n *\n * 4 is the canonical estimate cited by both OpenAI and Anthropic for general\n * text. Code-heavy content runs ~3.5; cache-eligible repeated text runs\n * higher. This is intentionally a single shared constant — every caller\n * that converts between chars and tokens reads it from here so a future\n * revision (e.g. tightening to 3.5) updates one site, not three.\n */\nexport const CHARS_PER_TOKEN = 4;\n","/**\n * toMCPMessages — pure core that converts Shipyard Message[] (from JSONL log)\n * into NeutralConversation for cross-runtime history handoff.\n *\n * Design notes:\n *\n * 1. This is a pure function — no I/O, no side effects, fully testable with\n * table-driven cases. Bridge shells (claude-bridge.ts, codex-bridge.ts,\n * cursor-bridge.ts) call this to produce their exportConversation() result.\n *\n * 2. Dropped block categories (per plan invariant #9 + Wave 4 spec):\n * - ThinkingBlock — model-private; never portable. Counted in thinkingDropped.\n * - 6 Shipyard-internal feedback blocks (DiffReviewFeedback,\n * PreviewAnnotationFeedback, AnnotationFeedback, TaskFeedback,\n * ReviewComment, ReviewDecision) — already text-serialized by existing\n * daemon→SDK boundary. The bridge does NOT re-flatten them; they are\n * simply dropped here because the structured form does not travel.\n *\n * 3. ToolResult orphan invariant (plan invariant #5, Audit C6):\n * - Any ToolUseBlock without a matching ToolResultBlock in a subsequent user\n * message is dropped (both sides of the broken pair).\n * - Any ToolResultBlock whose tool_use_id doesn't match a ToolUseBlock in\n * a PRECEDING assistant message is dropped. Ordering matters here —\n * Set-membership alone would let a tool_result that appears before its\n * tool_use slip through (the eventual tool_use would still register in\n * the set). Destinations on the other side of the bridge (Claude\n * SessionStore, Codex inject_items) require well-formed MCP conversation\n * where every tool_result follows its tool_use, so we enforce ordering\n * explicitly by walking the stream and tracking seen tool_use IDs.\n * - Tracked in droppedToolResults (list of tool_use_id strings).\n * This keeps the exported conversation MCP-spec compliant: every assistant\n * message with tool uses must be followed by a user message of tool results.\n *\n * 4. Estimation: estimatedTokens uses CHARS_PER_TOKEN over all text content in\n * the filtered portable messages. Rough but consistent; callers that need\n * precision should use the SDK's getContextUsage() instead.\n */\n\nimport type {\n AgentId,\n Message,\n NeutralConversation,\n PortableContentBlock,\n PortableMessage,\n} from '@shipyard/loro-schema';\nimport { inflateToolResultContent } from '@shipyard/loro-schema';\nimport { CHARS_PER_TOKEN } from '../../shared/chars-per-token.js';\nimport type { DroppedToolResult } from './bridges/bridge-types.js';\n\nexport interface ToMCPMessagesOptions {\n sourceRuntime: AgentId;\n sourceModel: string;\n archiveLogPath: string;\n compactionApplied: boolean;\n}\n\nexport interface ToMCPMessagesResult {\n neutral: NeutralConversation;\n /** Dropped (orphaned) tool call pairs — each entry carries the toolUseId and whether the result existed. */\n droppedToolResults: DroppedToolResult[];\n /** Count of ThinkingBlocks dropped during filtering. */\n thinkingDropped: number;\n}\n\n/**\n * Block types that are Shipyard-internal feedback and must be dropped.\n * The existing daemon→SDK serialization already converts these to text\n * representations; we do not re-flatten them here.\n */\nconst FEEDBACK_BLOCK_TYPES = new Set([\n 'diff_review_feedback',\n 'preview_annotation_feedback',\n 'annotation_feedback',\n 'task_feedback',\n 'review_comment',\n 'review_decision',\n]);\n\n/**\n * Convert a Shipyard Message[] into a NeutralConversation suitable for\n * cross-runtime handoff.\n *\n * Pure function — deterministic, no I/O, no mutations.\n */\nexport function toMCPMessages(\n messages: Message[],\n opts: ToMCPMessagesOptions\n): ToMCPMessagesResult {\n const { toolUseIds, droppedToolResults, validToolResultIds } = classifyToolPairs(messages);\n const orphanedToolUseIds = new Set<string>();\n for (const id of toolUseIds) {\n if (!validToolResultIds.has(id)) orphanedToolUseIds.add(id);\n }\n\n const portableMessages: PortableMessage[] = [];\n let estimatedCharCount = 0;\n let thinkingDropped = 0;\n\n for (const msg of messages) {\n const converted = convertMessageContent(msg, { validToolResultIds, orphanedToolUseIds });\n estimatedCharCount += converted.charCount;\n thinkingDropped += converted.thinkingDropped;\n portableMessages.push(buildPortableMessage(msg, converted.content));\n }\n\n const turnCount = portableMessages.filter((m) => m.senderKind === 'agent').length;\n const estimatedTokens = Math.ceil(estimatedCharCount / CHARS_PER_TOKEN);\n\n const neutral: NeutralConversation = {\n messages: portableMessages,\n meta: {\n sourceRuntime: opts.sourceRuntime,\n sourceModel: opts.sourceModel,\n turnCount,\n estimatedTokens,\n archiveLogPath: opts.archiveLogPath,\n compactionApplied: opts.compactionApplied,\n },\n };\n\n return { neutral, droppedToolResults, thinkingDropped };\n}\n\n/**\n * Pass 1: walk the message stream IN ORDER, tracking which tool_use IDs have\n * been seen so far. Classify each tool_result:\n * - matches a previously-seen tool_use → valid; ID added to validToolResultIds.\n * - has no preceding tool_use (orphan OR reordered same-message pair) → dropped\n * with hadResult: true.\n *\n * Returns the full set of tool_use IDs seen anywhere, plus the set of\n * tool_result IDs that survived the ordering check. The caller computes\n * orphaned tool_use IDs by set-diff.\n *\n * Why order matters: a tool_result whose tool_use appears AFTER it in the\n * stream is not a valid pair for cross-runtime injection. Destinations\n * (Claude SessionStore, Codex inject_items) require the tool_use to precede\n * its tool_result; replaying out-of-order pairs produces malformed MCP\n * conversations that fail validation or, worse, are silently mis-paired.\n */\nfunction classifyToolPairs(messages: Message[]): {\n toolUseIds: Set<string>;\n validToolResultIds: Set<string>;\n droppedToolResults: DroppedToolResult[];\n} {\n const toolUseIds = new Set<string>();\n const validToolResultIds = new Set<string>();\n const droppedToolResults: DroppedToolResult[] = [];\n\n for (const msg of messages) {\n classifyOneMessage(msg, toolUseIds, validToolResultIds, droppedToolResults);\n }\n\n /**\n * Any tool_use without a downstream in-order matching tool_result is an\n * orphan (hadResult: false).\n */\n for (const id of toolUseIds) {\n if (!validToolResultIds.has(id)) {\n droppedToolResults.push({ toolUseId: id, hadResult: false });\n }\n }\n\n return { toolUseIds, validToolResultIds, droppedToolResults };\n}\n\nfunction classifyOneMessage(\n msg: Message,\n toolUseIds: Set<string>,\n validToolResultIds: Set<string>,\n droppedToolResults: DroppedToolResult[]\n): void {\n for (const block of msg.content) {\n if (block.type === 'tool_use') {\n toolUseIds.add(block.toolUseId);\n } else if (block.type === 'tool_result') {\n if (toolUseIds.has(block.toolUseId)) {\n validToolResultIds.add(block.toolUseId);\n } else {\n /** No preceding tool_use → orphan OR reordered pair. */\n droppedToolResults.push({ toolUseId: block.toolUseId, hadResult: true });\n }\n }\n }\n}\n\ninterface ConvertedContent {\n content: PortableContentBlock[];\n charCount: number;\n thinkingDropped: number;\n}\n\n/**\n * Pass 3 (per message): filter and convert each content block, dropping\n * thinking blocks, feedback blocks, and orphaned tool pairs. Returns the\n * portable content plus running counters for the caller to accumulate.\n */\nfunction convertMessageContent(\n msg: Message,\n refs: { validToolResultIds: Set<string>; orphanedToolUseIds: Set<string> }\n): ConvertedContent {\n const content: PortableContentBlock[] = [];\n let charCount = 0;\n let thinkingDropped = 0;\n\n for (const block of msg.content) {\n if (block.type === 'thinking') {\n thinkingDropped++;\n continue;\n }\n if (shouldDropBlock(block, refs)) continue;\n\n if (block.type === 'tool_result') {\n content.push({\n type: 'tool_result',\n toolUseId: block.toolUseId,\n content: inflateToolResultContent(block.content),\n isError: block.isError,\n ...(block.parentToolUseId !== undefined && {\n parentToolUseId: block.parentToolUseId,\n }),\n });\n charCount += block.content.length;\n continue;\n }\n\n const passthrough = tryConvertPassthroughBlock(block);\n if (passthrough) {\n content.push(passthrough);\n charCount += estimateChars(passthrough);\n }\n }\n\n return { content, charCount, thinkingDropped };\n}\n\n/**\n * Drop predicate for non-thinking blocks: Shipyard-internal feedback blocks\n * and orphaned halves of a broken tool-call pair never travel. A tool_result\n * is dropped unless it appeared AFTER its tool_use in stream order (tracked\n * by classifyToolPairs as validToolResultIds).\n */\nfunction shouldDropBlock(\n block: Message['content'][number],\n refs: { validToolResultIds: Set<string>; orphanedToolUseIds: Set<string> }\n): boolean {\n if (FEEDBACK_BLOCK_TYPES.has(block.type)) return true;\n if (block.type === 'tool_use') return refs.orphanedToolUseIds.has(block.toolUseId);\n if (block.type === 'tool_result') return !refs.validToolResultIds.has(block.toolUseId);\n return false;\n}\n\n/**\n * Structurally pass through the 7 portable block variants (tool_result is\n * handled separately). Returns null for unknown/unsupported types so callers\n * silently drop them (forward-compat). Explicit switch lets TypeScript narrow\n * the type without a cast.\n */\nfunction tryConvertPassthroughBlock(\n block: Message['content'][number]\n): PortableContentBlock | null {\n switch (block.type) {\n case 'text':\n case 'tool_use':\n case 'file_attachment':\n case 'resource_link':\n case 'resource':\n case 'skill_invocation':\n case 'compaction_boundary':\n return block;\n default:\n return null;\n }\n}\n\n/**\n * Build the portable message envelope from the source message + converted\n * content. Empty content is intentionally preserved to keep message ordering.\n *\n * Why empty content is safe here (Invariant #20 does NOT apply):\n *\n * Invariant #20 (\"empty user content must not reach the provider\") is scoped\n * exclusively to the LIVE turn path — the two chokepoints are\n * `sdk-content-builder.ts:toSdkContent` (returns null on empty/all-silent\n * blocks) and `anthropic-adapter.ts:pushMessage` + the init `controller.push`\n * site (both guard on `sdkContent !== null` before calling controller.push).\n *\n * History injection through the bridge path is different:\n * - `NeutralConversation` messages with `content:[]` are NEVER passed to the\n * Anthropic API as a live user turn. They go into a SessionStore\n * (claude-bridge) or `thread/inject_items` (codex-bridge) — both of which\n * tolerate empty content arrays because they model the full turn graph,\n * including thinking-only assistant turns that carried no text.\n * - Dropping the empty message would silently break message ordering for\n * sessions that had thinking-only turns (e.g. a turn of pure `<thinking>`\n * with no text response). Keeping it preserves the `parentUuid` chain in\n * the SessionStore and the turn-ordering in inject_items.\n *\n * The integration tests for both bridges assert this behaviour explicitly\n * (look for \"message with empty content[] round-trips without crash\" in\n * claude-bridge.integration.test.ts and codex-bridge.integration.test.ts).\n */\nfunction buildPortableMessage(msg: Message, content: PortableContentBlock[]): PortableMessage {\n return {\n messageId: msg.messageId,\n seqNo: msg.seqNo,\n channelId: msg.channelId,\n participantId: msg.participantId,\n senderKind: msg.senderKind,\n content,\n timestamp: msg.timestamp,\n ...(msg.model !== undefined && { model: msg.model }),\n ...(msg.reasoningEffort !== undefined && { reasoningEffort: msg.reasoningEffort }),\n ...(msg.permissionMode !== undefined && { permissionMode: msg.permissionMode }),\n ...(msg.isSynthetic !== undefined && { isSynthetic: msg.isSynthetic }),\n ...(msg.anchorToolUseId !== undefined && { anchorToolUseId: msg.anchorToolUseId }),\n ...(msg.correlationId !== undefined && { correlationId: msg.correlationId }),\n };\n}\n\n/**\n * Estimate the character count of a portable block for token estimation.\n * Only text-bearing blocks contribute — structural blocks (tool_use input\n * JSON, etc.) contribute their serialized form.\n */\nfunction estimateChars(block: PortableContentBlock): number {\n switch (block.type) {\n case 'text':\n return block.text.length;\n case 'tool_use':\n return JSON.stringify(block.input).length;\n case 'skill_invocation':\n return block.name.length + (block.description?.length ?? 0);\n case 'file_attachment':\n return (block.preview?.length ?? 0) + block.filename.length;\n case 'resource_link':\n return (block.title?.length ?? 0) + (block.uri?.length ?? 0);\n case 'resource': {\n const r = block.resource;\n if ('text' in r && typeof r.text === 'string') return r.text.length;\n return 0;\n }\n case 'compaction_boundary':\n return block.resumeInstructions.length;\n case 'tool_result':\n /** tool_result is handled separately in the main loop and never reaches here. */\n return 0;\n }\n}\n","/**\n * sqlite-writer.ts — Imperative shell that injects a fabricated Cursor\n * conversation into the SDK's local SQLite stores so a subsequent\n * `Agent.resume(agentId)` reads it back as prior context.\n *\n * This is the ONLY file in the injector that performs I/O. The Merkle tree is\n * built by the pure `fabricateBlobTree`; this shell writes it to disk.\n *\n * Two databases (schemas reverse-engineered verbatim from `@cursor/sdk@1.0.13`\n * dist/cjs/index.js):\n *\n * index.db (per-workspace, shared across agents):\n * agents(agent_id PK, workspace_ref, status, active_run_id,\n * latest_checkpoint_ref_json, name, metadata_json NOT NULL DEFAULT '{}',\n * created_at NOT NULL, updated_at NOT NULL)\n * runs(run_id PK, agent_id NOT NULL REFERENCES agents(agent_id),\n * turn_number NOT NULL, status NOT NULL, model, ...,\n * created_at NOT NULL, updated_at NOT NULL, UNIQUE(agent_id, turn_number))\n *\n * store.db (per-agent, under agents/agent-<sha256hex(agentId)>/):\n * blobs(id TEXT PK, data BLOB) — id is HEX of the raw SHA-256 blob id\n * meta(key TEXT PK, value TEXT) — key \"0\" holds the agent metadata\n *\n * meta[\"0\"].value encoding (from BlobStore metadata serde, class `b`):\n * hex( utf8( JSON.stringify({ agentId, latestRootBlobId: hex(rootBytes),\n * name, mode, isRunEverything, createdAt }) ) )\n * i.e. the metadata object is JSON-stringified (with latestRootBlobId as an\n * inner hex string), UTF-8 encoded, then the whole thing hex-encoded. Both the\n * inner blob-id hex and the outer wrapper use `Buffer.from(x).toString('hex')`.\n *\n * Concurrency / safety (per the injection contract — runs daemon-side BEFORE\n * the cursor-runner fork, so it has an exclusive write window): WAL +\n * busy_timeout guard against the rare case the SDK has the db open, and FK\n * enforcement guarantees `runs.agent_id` references a real `agents` row.\n *\n * runs.status = 'FINISHED' (not 'RUNNING'): a RUNNING row would make the SDK\n * treat the agent as having an in-flight run and block follow-up sends.\n *\n * agents.metadata_json carries `{ shipyard_origin: true, shipyard_task_id }`\n * for provenance so we (and forensic tooling) can tell injected agents apart.\n */\n\nimport { mkdirSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname } from 'node:path';\nimport type { NeutralConversation } from '@shipyard/loro-schema';\nimport { fabricateBlobTree, toHex } from './fabricator.js';\n\n/**\n * Minimal synchronous SQLite surface the injector + rewind truncator use. Both\n * backends below structurally satisfy it, so callers never depend on which one\n * loaded. The on-disk format is backend-interoperable, so a DB written by one is\n * read back by the other (e.g. tests read via `node:sqlite` what the packaged\n * app wrote via `better-sqlite3`).\n */\nexport type CursorSqliteParam = string | number | bigint | Buffer | Uint8Array | null;\n\nexport interface CursorSqliteStatement {\n run(...params: CursorSqliteParam[]): { changes: number | bigint };\n get(...params: CursorSqliteParam[]): unknown;\n all(...params: CursorSqliteParam[]): unknown[];\n}\n\nexport interface CursorSqliteDatabase {\n exec(sql: string): void;\n prepare(sql: string): CursorSqliteStatement;\n close(): void;\n}\n\nexport type CursorSqliteCtor = new (path: string) => CursorSqliteDatabase;\n\n/**\n * One SQLite backend the loader can try. `load` performs the actual `require`\n * (the only I/O); `selectCursorSqliteBackend` owns the try-each-until-one-loads\n * decision so the selection stays pure and exhaustively testable.\n */\nexport interface CursorSqliteBackend {\n readonly name: string;\n readonly load: (req: NodeRequire) => CursorSqliteCtor;\n}\n\nexport type SelectSqliteResult =\n | { ok: true; name: string; ctor: CursorSqliteCtor }\n | { ok: false; error: string };\n\n/**\n * Force the native binding to actually load. `better-sqlite3` defers loading its\n * `.node` addon to the FIRST `new Database(...)`, NOT to `require()` — so an ABI\n * mismatch (the shared pnpm-store copy is electron-rebuilt; dev/test run plain\n * Node) surfaces at construction, not at require. The selector must therefore\n * probe-construct an in-memory DB to decide whether a backend is usable, or it\n * would \"succeed\" on a require that explodes the moment we open a real store.\n */\nfunction probeCtor(ctor: CursorSqliteCtor): CursorSqliteCtor {\n const probe = new ctor(':memory:');\n probe.close();\n return ctor;\n}\n\n/**\n * Backends in priority order. WHY two with a fallback rather than one dependency:\n *\n * - `better-sqlite3` is a native addon. It is tried first because a runtime\n * whose ABI it matches gets the well-tested C++ backend. #4090: an old\n * `node:sqlite`-only path threw on the packaged app (then Node 20.18, which had\n * NO `node:sqlite` builtin), so switch-to-Cursor injected nothing and silently\n * lost all prior conversation context.\n * - `node:sqlite` is the Node 22.5+ builtin (stable/unflagged in Node 22.13,\n * which ships in Electron 42). It wins whenever `better-sqlite3`'s native addon\n * fails to construct: in dev/test (the shared pnpm-store copy is built for a\n * different ABI) AND now in the packaged Electron 42 app, where\n * `better-sqlite3` is no longer electron-rebuilt (its C++ does not compile\n * against E42's V8 `External::New` signature). The disk format is identical, so\n * nothing else cares which backend won.\n *\n * `createRequire` keeps the `node:sqlite` specifier verbatim through esbuild\n * (`platform: 'node'` strips the `node:` prefix off a static import based on a\n * legacy-builtin list that excludes `sqlite`, which would break at runtime), and\n * keeps `better-sqlite3` an external runtime require (see tsup.config.ts).\n *\n * Resolution is LAZY (deferred to the first DB open), NEVER module-scope: the\n * daemon's import graph reaches this file via cursor-bridge at BOOT, and a\n * module-scope require of an unavailable/ABI-mismatched backend would crash boot\n * before the only caller (`cursor-subprocess.#maybeInjectNeutralHandoff`, which\n * try/catches and degrades to a fresh spawn) could run. The boot-safety guard in\n * `sqlite-writer.test.ts` pins this.\n */\nconst SQLITE_BACKENDS: readonly CursorSqliteBackend[] = [\n { name: 'better-sqlite3', load: (req) => probeCtor(req('better-sqlite3')) },\n { name: 'node:sqlite', load: (req) => probeCtor(req('node:sqlite').DatabaseSync) },\n];\n\nconst requireRuntime = createRequire(import.meta.url);\n\n/**\n * Pure decision: try each backend in order, return the first that loads; if none\n * load, return a single error naming every attempt so the failure is actionable.\n * `load` is injected (the only I/O), so this is deterministic under test.\n */\nexport function selectCursorSqliteBackend(\n backends: readonly CursorSqliteBackend[],\n req: NodeRequire\n): SelectSqliteResult {\n const failures: string[] = [];\n for (const backend of backends) {\n try {\n return { ok: true, name: backend.name, ctor: backend.load(req) };\n } catch (err) {\n failures.push(`${backend.name}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n return {\n ok: false,\n error:\n `Cursor history injection requires a SQLite backend, but none could be loaded. ` +\n `Tried better-sqlite3 (the packaged-app backend — must be electron-rebuilt) and ` +\n `node:sqlite (Node 22.5+ builtin). Attempts — ${failures.join('; ')}`,\n };\n}\n\nlet cachedCtor: CursorSqliteCtor | null = null;\n\nfunction loadCursorSqliteCtor(): CursorSqliteCtor {\n if (cachedCtor !== null) return cachedCtor;\n const result = selectCursorSqliteBackend(SQLITE_BACKENDS, requireRuntime);\n if (!result.ok) throw new Error(result.error);\n cachedCtor = result.ctor;\n return cachedCtor;\n}\n\nexport interface WriteCursorHistoryDeps {\n /** Absolute path to the per-workspace index.db. */\n indexDbPath: string;\n /** Absolute path to the per-agent store.db. */\n storeDbPath: string;\n /** The agentId the SDK will `Agent.resume()` with. */\n agentId: string;\n /** Absolute workspace path (cwd) the agent runs in — stored as workspace_ref. */\n workspaceRef: string;\n /** The conversation to inject. */\n neutral: NeutralConversation;\n /** Model id the resumed agent should report (e.g. 'claude-sonnet-4-5'). */\n model: string;\n /** Shipyard task id, stamped into agents.metadata_json for provenance. */\n shipyardTaskId: string;\n}\n\nexport interface WriteCursorHistoryResult {\n /** Lowercase hex of the root state blob id (also the meta latestRootBlobId). */\n rootBlobIdHex: string;\n /** Number of blobs written to store.db. */\n blobsWritten: number;\n /** Number of logical turns injected. */\n turnCount: number;\n}\n\nconst META_KEY = '0';\nconst RUN_TURN_NUMBER = 0;\nconst RUN_STATUS_FINISHED = 'FINISHED';\nconst AGENT_STATUS_IDLE = 'IDLE';\nconst AGENT_MODE_DEFAULT = 'default';\n\n/**\n * Inject a fabricated conversation. Builds the blob tree (pure), then writes\n * the agents/runs rows to index.db and the blob tree + meta pointer to store.db.\n *\n * Throws on any SQLite error. The caller (cursor-bridge) is responsible for\n * computing the two DB paths and for sequencing this BEFORE the runner fork.\n */\nexport function writeCursorHistory(deps: WriteCursorHistoryDeps): WriteCursorHistoryResult {\n const { rootBlobId, blobs, turnCount } = fabricateBlobTree(deps.neutral);\n const rootBlobIdHex = toHex(rootBlobId);\n const now = new Date().toISOString();\n\n writeIndexDb(deps, now);\n /**\n * Cross-DB rollback. The two writes are independent SQLite files with no\n * shared transaction. If `writeStoreDb` throws (disk full, FS permission\n * error, SDK race), the agents/runs rows we already committed in index.db\n * point at a store.db that has no blobs — the Cursor SDK would find the\n * agent but fail to load BlobStore state, surfacing an opaque error on the\n * user's next message. Roll back the index.db row so the failure is clean\n * and a future attempt can re-inject under the same agentId.\n */\n try {\n writeStoreDb(deps, blobs, rootBlobIdHex, now);\n } catch (storeErr) {\n try {\n deleteAgentFromIndexDb(deps);\n } catch {\n /**\n * Rollback is best-effort. If it fails we still want to surface the\n * original store-write error to the caller, not the rollback error —\n * the orphan agents row is recoverable, the underlying write failure\n * is the actionable signal.\n */\n }\n throw storeErr;\n }\n\n return { rootBlobIdHex, blobsWritten: blobs.size, turnCount };\n}\n\nfunction writeIndexDb(deps: WriteCursorHistoryDeps, now: string): void {\n mkdirSync(dirname(deps.indexDbPath), { recursive: true });\n const db = openCursorDb(deps.indexDbPath);\n try {\n db.exec(CREATE_AGENTS_SQL);\n db.exec(CREATE_RUNS_SQL);\n\n const metadataJson = JSON.stringify({\n shipyard_origin: true,\n shipyard_task_id: deps.shipyardTaskId,\n });\n\n /**\n * Wrap both inserts in an explicit transaction. SQLite runs each\n * `.run()` as its own implicit transaction with an fsync — a daemon\n * SIGKILL between the agents insert and the runs insert would leave a\n * dangling agent with no run row, which the SDK reads as \"agent exists\n * but has no history.\" BEGIN/COMMIT makes the pair atomic and skips one\n * fsync.\n */\n db.exec('BEGIN');\n try {\n db.prepare(\n `INSERT OR REPLACE INTO agents\n (agent_id, workspace_ref, status, active_run_id,\n latest_checkpoint_ref_json, name, metadata_json, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`\n ).run(\n deps.agentId,\n deps.workspaceRef,\n AGENT_STATUS_IDLE,\n null,\n null,\n `shipyard-task-${deps.shipyardTaskId}`,\n metadataJson,\n now,\n now\n );\n\n db.prepare(\n `INSERT OR REPLACE INTO runs\n (run_id, agent_id, turn_number, status, model, created_at, updated_at, finished_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)`\n ).run(\n `run-${deps.agentId}-${RUN_TURN_NUMBER}`,\n deps.agentId,\n RUN_TURN_NUMBER,\n RUN_STATUS_FINISHED,\n deps.model,\n now,\n now,\n now\n );\n db.exec('COMMIT');\n } catch (err) {\n db.exec('ROLLBACK');\n throw err;\n }\n } finally {\n db.close();\n }\n}\n\n/**\n * Cross-DB rollback helper for `writeCursorHistory` failure mode. Removes\n * the agent + its run row we just wrote so a failed two-DB injection does\n * not leave permanent orphans in the user's per-workspace index.db.\n */\nfunction deleteAgentFromIndexDb(deps: WriteCursorHistoryDeps): void {\n const db = openCursorDb(deps.indexDbPath);\n try {\n db.exec('BEGIN');\n try {\n db.prepare('DELETE FROM runs WHERE agent_id = ?').run(deps.agentId);\n db.prepare('DELETE FROM agents WHERE agent_id = ?').run(deps.agentId);\n db.exec('COMMIT');\n } catch (err) {\n db.exec('ROLLBACK');\n throw err;\n }\n } finally {\n db.close();\n }\n}\n\nfunction writeStoreDb(\n deps: WriteCursorHistoryDeps,\n blobs: Map<string, Uint8Array>,\n rootBlobIdHex: string,\n now: string\n): void {\n mkdirSync(dirname(deps.storeDbPath), { recursive: true });\n const db = openCursorDb(deps.storeDbPath);\n try {\n db.exec('CREATE TABLE IF NOT EXISTS blobs (id TEXT PRIMARY KEY, data BLOB)');\n db.exec('CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT)');\n\n /**\n * Wrap the blob loop + meta pointer write in one explicit transaction.\n * Without this, SQLite fsyncs after every `.run()` — a 200-blob\n * conversation costs 201 fsyncs (slow on APFS) AND is non-atomic on\n * SIGKILL, leaving a partial blob set that breaks the SDK's Merkle\n * traversal on resume. The meta pointer (latestRootBlobId) MUST land\n * with all referenced blobs or be missing entirely; commit-as-a-unit\n * guarantees that.\n */\n db.exec('BEGIN');\n try {\n const insertBlob = db.prepare('INSERT OR REPLACE INTO blobs (id, data) VALUES (?, ?)');\n for (const [idHex, data] of blobs) {\n insertBlob.run(idHex, Buffer.from(data));\n }\n\n db.prepare('INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)').run(\n META_KEY,\n encodeMetaValue({\n agentId: deps.agentId,\n rootBlobIdHex,\n name: `shipyard-task-${deps.shipyardTaskId}`,\n createdAtMs: Date.parse(now),\n })\n );\n db.exec('COMMIT');\n } catch (err) {\n db.exec('ROLLBACK');\n throw err;\n }\n } finally {\n db.close();\n }\n}\n\n/**\n * Build the hex-encoded metadata value for meta[\"0\"], matching the SDK's\n * BlobStore metadata serde: JSON.stringify(meta) → utf8 bytes → hex.\n * The inner `latestRootBlobId` is itself the hex string of the raw blob id.\n */\nfunction encodeMetaValue(args: {\n agentId: string;\n rootBlobIdHex: string;\n name: string;\n createdAtMs: number;\n}): string {\n const metaObj = {\n agentId: args.agentId,\n latestRootBlobId: args.rootBlobIdHex,\n name: args.name,\n mode: AGENT_MODE_DEFAULT,\n isRunEverything: false,\n createdAt: args.createdAtMs,\n };\n return Buffer.from(JSON.stringify(metaObj), 'utf8').toString('hex');\n}\n\n/**\n * Open a Cursor SQLite store with the same pragmas the SDK uses (WAL +\n * busy_timeout + FK), via whichever SQLite backend the runtime can load.\n * Exported so the rewind truncator (`sqlite-truncator.ts`) shares one backend\n * loader + pragma set rather than duplicating the lazy-require dance. The caller\n * owns `db.close()`.\n */\nexport function openCursorDb(path: string): CursorSqliteDatabase {\n const Ctor = loadCursorSqliteCtor();\n const db = new Ctor(path);\n db.exec('PRAGMA journal_mode = WAL;');\n db.exec('PRAGMA busy_timeout = 5000;');\n db.exec('PRAGMA foreign_keys = ON;');\n return db;\n}\n\n/** store.db meta key holding the per-agent BlobStore metadata (latestRootBlobId). */\nexport const CURSOR_META_KEY = META_KEY;\n\nconst CREATE_AGENTS_SQL = `CREATE TABLE IF NOT EXISTS agents (\n agent_id TEXT PRIMARY KEY,\n workspace_ref TEXT NOT NULL,\n status TEXT NOT NULL,\n active_run_id TEXT,\n latest_checkpoint_ref_json TEXT,\n name TEXT,\n metadata_json TEXT NOT NULL DEFAULT '{}',\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n)`;\n\nconst CREATE_RUNS_SQL = `CREATE TABLE IF NOT EXISTS runs (\n run_id TEXT PRIMARY KEY,\n agent_id TEXT NOT NULL REFERENCES agents(agent_id),\n turn_number INTEGER NOT NULL,\n status TEXT NOT NULL,\n model TEXT,\n model_params_json TEXT,\n start_checkpoint_ref_json TEXT,\n latest_checkpoint_ref_json TEXT,\n error_code TEXT,\n usage_ref TEXT,\n result TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n started_at TEXT,\n finished_at TEXT,\n cancelled_at TEXT,\n expired_at TEXT,\n UNIQUE(agent_id, turn_number)\n)`;\n","/**\n * fabricator.ts — Pure builder for Cursor's content-addressed conversation\n * Merkle tree (`agent.v1.ConversationStateStructure`).\n *\n * Cursor persists a resumable conversation in `store.db` as a Merkle tree of\n * SHA-256-content-addressed protobuf blobs. Reverse-engineered from\n * `@cursor/sdk@1.0.13` (BlobStore.handleCheckpoint + deserializeConversation):\n *\n * blob id = SHA-256(serialized_message_bytes) (raw 32-byte Uint8Array)\n *\n * ConversationStateStructure\n * .turns[] ────────────────────────────► ConversationTurnStructure blob ids\n * .agent_conversation_turn\n * .user_message ──► UserMessage blob id\n * .steps[] ──► ConversationStep blob ids\n *\n * The root blob is the serialized ConversationStateStructure; its id is what\n * gets written to `meta.latestRootBlobId`.\n *\n * Merkle back-link: each UserMessage carries `conversation_state_blob_id`\n * (field 10) = the SHA-256 of the PREVIOUS turn's root state blob. This mirrors\n * how the SDK chains states forward (handleCheckpoint stores a new root after\n * each turn, and the next UserMessage references the prior root). For the first\n * turn the back-link is empty.\n *\n * Pure: no I/O, no mutation of inputs, deterministic. Same NeutralConversation\n * always yields byte-identical blobs and the same root id — this is what the\n * fabricator.test.ts determinism cases assert.\n */\n\nimport { createHash } from 'node:crypto';\nimport type { NeutralConversation, PortableMessage } from '@shipyard/loro-schema';\nimport {\n encodeConversationStateStructure,\n encodeConversationStep,\n encodeConversationTurnStructure,\n encodeUserMessage,\n} from './proto-types.js';\n\nexport interface FabricatedTree {\n /** Raw 32-byte SHA-256 of the root ConversationStateStructure blob. */\n rootBlobId: Uint8Array;\n /**\n * All blobs to write into store.db, keyed by lowercase hex of the blob id.\n * Hex keying matches the SDK's `blobs.id` column (hex-encoded id) and makes\n * the map deterministic and easy to assert against in tests.\n */\n blobs: Map<string, Uint8Array>;\n /** Number of logical turns fabricated (human prompt + its assistant steps). */\n turnCount: number;\n}\n\n/**\n * Build the content-addressed blob tree for a NeutralConversation.\n *\n * A \"turn\" in Cursor's model is one human UserMessage followed by the agent's\n * ConversationSteps (assistant messages) until the next human message. We walk\n * the portable messages in order, grouping each human message with the agent\n * messages that follow it.\n *\n * Tool-use / tool-result blocks do not have a first-class slot in the minimal\n * turn shape we fabricate — they are flattened into the assistant step text so\n * the model still sees them as prior context. (Cursor re-derives its own tool\n * state on the first new turn; we only need the conversation to READ back.)\n */\nexport function fabricateBlobTree(neutral: NeutralConversation): FabricatedTree {\n const blobs = new Map<string, Uint8Array>();\n\n const turns = groupIntoTurns(neutral.messages);\n\n const turnBlobIds: Uint8Array[] = [];\n let previousRootBlobId = new Uint8Array(0);\n\n for (const turn of turns) {\n /** 1. UserMessage blob (back-linked to the previous state root). */\n const userBytes = encodeUserMessage({\n text: turn.userText,\n conversationStateBlobId: previousRootBlobId,\n });\n const userBlobId = sha256(userBytes);\n putBlob(blobs, userBlobId, userBytes);\n\n /** 2. ConversationStep blobs (one per assistant message). */\n const stepBlobIds: Uint8Array[] = [];\n for (const stepText of turn.stepTexts) {\n const stepBytes = encodeConversationStep({ assistantText: stepText });\n const stepBlobId = sha256(stepBytes);\n putBlob(blobs, stepBlobId, stepBytes);\n stepBlobIds.push(stepBlobId);\n }\n\n /** 3. ConversationTurnStructure blob referencing the user message + steps. */\n const turnBytes = encodeConversationTurnStructure({\n userMessageBlobId: userBlobId,\n stepBlobIds,\n });\n const turnBlobId = sha256(turnBytes);\n putBlob(blobs, turnBlobId, turnBytes);\n turnBlobIds.push(turnBlobId);\n\n /**\n * 4. Intermediate state root after this turn — becomes the next turn's\n * back-link. Mirrors handleCheckpoint storing a fresh root each turn.\n */\n const stateBytes = encodeConversationStateStructure({\n turnBlobIds: [...turnBlobIds],\n });\n const stateBlobId = sha256(stateBytes);\n putBlob(blobs, stateBlobId, stateBytes);\n previousRootBlobId = stateBlobId;\n }\n\n /** Final root = the last intermediate state (or empty state when no turns). */\n let rootBlobId: Uint8Array;\n if (turns.length === 0) {\n const emptyState = encodeConversationStateStructure({ turnBlobIds: [] });\n rootBlobId = sha256(emptyState);\n putBlob(blobs, rootBlobId, emptyState);\n } else {\n rootBlobId = previousRootBlobId;\n }\n\n return { rootBlobId, blobs, turnCount: turns.length };\n}\n\ninterface FabricatedTurn {\n userText: string;\n stepTexts: string[];\n}\n\n/**\n * Group portable messages into Cursor turns: one human message + the agent\n * messages that follow it until the next human message.\n *\n * Leading agent messages (before any human message) are attached to a synthetic\n * empty-prompt turn so they are not lost — Cursor tolerates an empty UserMessage\n * text (proto3 default), and the steps still carry the prior assistant context.\n */\nfunction groupIntoTurns(messages: PortableMessage[]): FabricatedTurn[] {\n const turns: FabricatedTurn[] = [];\n let current: FabricatedTurn | null = null;\n\n for (const msg of messages) {\n const text = renderMessageText(msg);\n if (msg.senderKind === 'human') {\n if (current) turns.push(current);\n current = { userText: text, stepTexts: [] };\n } else {\n if (!current) current = { userText: '', stepTexts: [] };\n if (text.length > 0) current.stepTexts.push(text);\n }\n }\n if (current) turns.push(current);\n\n return turns;\n}\n\n/**\n * Flatten a portable message's content blocks into a single text string for\n * the minimal turn shape. Text blocks pass through; tool uses/results are\n * rendered as compact markers so the model sees they happened without us\n * needing to fabricate Cursor's full tool-call proto sub-tree.\n */\nfunction renderMessageText(msg: PortableMessage): string {\n const parts: string[] = [];\n for (const block of msg.content) {\n switch (block.type) {\n case 'text':\n parts.push(block.text);\n break;\n case 'tool_use':\n parts.push(`[tool: ${block.toolName} ${JSON.stringify(block.input)}]`);\n break;\n case 'tool_result': {\n const joined = block.content\n .map((c) => (c.type === 'text' ? c.text : `[${c.type}]`))\n .join('\\n');\n parts.push(`[tool result] ${joined}`);\n break;\n }\n case 'skill_invocation':\n parts.push(`[skill: ${block.name}]`);\n break;\n case 'file_attachment':\n parts.push(`[file: ${block.filename}]`);\n break;\n case 'resource_link':\n parts.push(`[resource: ${block.title ?? block.uri}]`);\n break;\n case 'resource':\n parts.push('[embedded resource]');\n break;\n case 'compaction_boundary':\n parts.push(`[compacted] ${block.resumeInstructions}`);\n break;\n default: {\n const _exhaustive: never = block;\n return _exhaustive;\n }\n }\n }\n return parts.join('\\n');\n}\n\n/** Raw 32-byte SHA-256 digest of the given bytes (ArrayBuffer-backed). */\nfunction sha256(bytes: Uint8Array): Uint8Array<ArrayBuffer> {\n const digest = createHash('sha256').update(bytes).digest();\n const out = new Uint8Array(new ArrayBuffer(digest.length));\n out.set(digest);\n return out;\n}\n\n/** Store a blob keyed by lowercase hex of its id (matches SDK `blobs.id`). */\nfunction putBlob(blobs: Map<string, Uint8Array>, id: Uint8Array, data: Uint8Array): void {\n blobs.set(toHex(id), data);\n}\n\n/** Lowercase hex of a byte array. */\nexport function toHex(bytes: Uint8Array): string {\n let s = '';\n for (const byte of bytes) {\n s += byte.toString(16).padStart(2, '0');\n }\n return s;\n}\n","/**\n * proto-types.ts — Minimal hand-rolled protobuf wire encoder for the 4\n * Cursor agent_pb messages needed to fabricate a resumable conversation:\n *\n * - UserMessage (agent.v1.UserMessage)\n * - ConversationStep (agent.v1.ConversationStep)\n * - ConversationTurnStructure (agent.v1.ConversationTurnStructure, via\n * agent.v1.AgentConversationTurnStructure)\n * - ConversationStateStructure(agent.v1.ConversationStateStructure)\n *\n * Why hand-rolled instead of `@bufbuild/protobuf`:\n * `@bufbuild/protobuf@1.10.0` IS in the pnpm store as a TRANSITIVE dep of\n * `@cursor/sdk`, but it is NOT a declared daemon dependency, so it is not\n * resolvable from the daemon under pnpm's strict hoisting. Importing it\n * would be a phantom dependency that breaks on any `pnpm install`. The four\n * messages we fabricate only use three wire types (string, bytes, embedded\n * message — all LEN-delimited, plus repeated of the same), so a ~60-LOC\n * varint + length-delimited encoder is correct, dependency-free, and\n * verified byte-identical against the SDK's own deserializer field layout.\n *\n * Field layout reverse-engineered directly from `@cursor/sdk@1.0.13`'s bundled\n * proto descriptors (dist/cjs/index.js, `agent.v1.*` typeName registrations):\n *\n * UserMessage:\n * 1 text string (T:9)\n * 10 conversation_state_blob_id bytes (T:12) ← SHA-256 of previous state blob\n * AssistantMessage:\n * 1 text string (T:9)\n * ConversationStep (oneof \"message\"):\n * 1 assistant_message message (AssistantMessage)\n * AgentConversationTurnStructure:\n * 1 user_message bytes (T:12) ← UserMessage blob id\n * 2 steps bytes (T:12, repeated) ← ConversationStep blob ids\n * ConversationTurnStructure (oneof \"turn\"):\n * 1 agent_conversation_turn message (AgentConversationTurnStructure)\n * ConversationStateStructure:\n * 8 turns bytes (T:12, repeated) ← ConversationTurnStructure blob ids\n *\n * proto3 semantics: scalar fields equal to their default (empty string, empty\n * bytes) are NOT serialized. We replicate that so blob content is identical\n * to what the SDK would have written for the same logical message — which is\n * what keeps the SHA-256 content-addressing deterministic and matchable.\n */\n\n/** length-delimited (string, bytes, embedded message) */\nconst WIRE_LEN = 2;\n\n/** Append a base-128 varint encoding of a non-negative integer. */\nfunction writeVarint(out: number[], value: number): void {\n let v = value;\n while (v > 0x7f) {\n out.push((v & 0x7f) | 0x80);\n v >>>= 7;\n }\n out.push(v);\n}\n\n/** Append a field tag (field number << 3 | wire type). */\nfunction writeTag(out: number[], fieldNo: number, wireType: number): void {\n writeVarint(out, (fieldNo << 3) | wireType);\n}\n\n/** Append a length-delimited field: tag, length varint, then the bytes. */\nfunction writeLenField(out: number[], fieldNo: number, bytes: Uint8Array): void {\n writeTag(out, fieldNo, WIRE_LEN);\n writeVarint(out, bytes.length);\n for (const byte of bytes) out.push(byte);\n}\n\nconst TEXT_ENCODER = new TextEncoder();\n\n/** Encode a UTF-8 string as a length-delimited field (proto3: empty → omitted). */\nfunction writeStringField(out: number[], fieldNo: number, value: string): void {\n /** proto3 default — not serialized. */\n if (value.length === 0) return;\n writeLenField(out, fieldNo, TEXT_ENCODER.encode(value));\n}\n\n/** Encode a bytes value as a length-delimited field (proto3: empty → omitted). */\nfunction writeBytesField(out: number[], fieldNo: number, value: Uint8Array): void {\n /** proto3 default — not serialized. */\n if (value.length === 0) return;\n writeLenField(out, fieldNo, value);\n}\n\n/** Encode an embedded message (already-serialized bytes) as a LEN field. */\nfunction writeMessageField(out: number[], fieldNo: number, msgBytes: Uint8Array): void {\n /**\n * Embedded messages ARE serialized even when empty if the field is set — but\n * for our oneof message fields we always have content, so this is fine.\n */\n writeLenField(out, fieldNo, msgBytes);\n}\n\nexport interface UserMessageWire {\n /** Field 1 — the user-visible message text. */\n text: string;\n /** Field 10 — SHA-256 (raw 32 bytes) of the previous state blob, or empty for the first turn. */\n conversationStateBlobId: Uint8Array;\n}\n\n/** Serialize agent.v1.UserMessage. */\nexport function encodeUserMessage(msg: UserMessageWire): Uint8Array {\n const out: number[] = [];\n writeStringField(out, 1, msg.text);\n writeBytesField(out, 10, msg.conversationStateBlobId);\n return Uint8Array.from(out);\n}\n\n/** Serialize agent.v1.AssistantMessage. */\nfunction encodeAssistantMessage(text: string): Uint8Array {\n const out: number[] = [];\n writeStringField(out, 1, text);\n return Uint8Array.from(out);\n}\n\nexport interface ConversationStepWire {\n /** oneof \"message\" → field 1 assistant_message.text. */\n assistantText: string;\n}\n\n/** Serialize agent.v1.ConversationStep with an assistant_message oneof. */\nexport function encodeConversationStep(step: ConversationStepWire): Uint8Array {\n const out: number[] = [];\n const assistant = encodeAssistantMessage(step.assistantText);\n writeMessageField(out, 1, assistant);\n return Uint8Array.from(out);\n}\n\nexport interface AgentConversationTurnWire {\n /** Field 1 — blob id (SHA-256 bytes) of the turn's UserMessage. */\n userMessageBlobId: Uint8Array;\n /** Field 2 (repeated) — blob ids (SHA-256 bytes) of each ConversationStep. */\n stepBlobIds: Uint8Array[];\n}\n\n/** Serialize agent.v1.AgentConversationTurnStructure. */\nfunction encodeAgentConversationTurnStructure(turn: AgentConversationTurnWire): Uint8Array {\n const out: number[] = [];\n writeBytesField(out, 1, turn.userMessageBlobId);\n for (const stepId of turn.stepBlobIds) {\n writeBytesField(out, 2, stepId);\n }\n return Uint8Array.from(out);\n}\n\n/**\n * Serialize agent.v1.ConversationTurnStructure with an\n * agent_conversation_turn oneof (field 1).\n */\nexport function encodeConversationTurnStructure(turn: AgentConversationTurnWire): Uint8Array {\n const out: number[] = [];\n const inner = encodeAgentConversationTurnStructure(turn);\n writeMessageField(out, 1, inner);\n return Uint8Array.from(out);\n}\n\nexport interface ConversationStateWire {\n /** Field 8 (repeated) — blob ids (SHA-256 bytes) of each ConversationTurnStructure. */\n turnBlobIds: Uint8Array[];\n}\n\n/** Serialize agent.v1.ConversationStateStructure. */\nexport function encodeConversationStateStructure(state: ConversationStateWire): Uint8Array {\n const out: number[] = [];\n for (const turnId of state.turnBlobIds) {\n writeBytesField(out, 8, turnId);\n }\n return Uint8Array.from(out);\n}\n","/**\n * sqlite-truncator.ts — Rewind a native Cursor conversation by truncating its\n * own SQLite Merkle store IN PLACE. The inverse of `writeCursorHistory`: where\n * the writer fabricates a tree, this drops the tail of a real one.\n *\n * Cursor stores the conversation as a git-shaped, content-addressed Merkle tree\n * (see `fabricator.ts`): each turn appends a fresh all-turns-so-far root blob\n * and advances the BlobStore head `meta[\"0\"].latestRootBlobId`. The per-turn\n * `runs.latest_checkpoint_ref_json` records that turn's root blob id\n * (`JSON.stringify({ blobId: <hex>, storeKind: \"local-sqlite\" })`, verbatim from\n * `@cursor/sdk@1.0.13` `handleCheckpoint`). Rewinding to keep turns 0..N is\n * therefore a one-pointer move plus ledger cleanup — NO protobuf decoding:\n *\n * 1. Re-point the head: `store.db` meta[\"0\"].latestRootBlobId = turn N's root.\n * 2. Drop the ledger tail: DELETE `index.db` runs WHERE turn_number > N, and\n * re-point the agents row's checkpoint ref + clear active_run_id.\n *\n * The tail blobs left in `store.db` are unreferenced orphans — harmless, exactly\n * like dangling git objects; GC is a separate optional concern. Surviving turns\n * are byte-for-byte the native data, so `Agent.resume(agentId)` reconstructs\n * turns 0..N losslessly. This is why rewind reuses the agent's own store rather\n * than the cross-runtime handoff injector (which is lossy by design — it drops\n * thinking blocks + orphaned tool calls to move context BETWEEN agents).\n *\n * Safety: the caller (rewind handler) runs this only AFTER the agent is stopped\n * (active states) or while it is idle/dead — no live SDK process holds the DB.\n * `openCursorDb`'s WAL + busy_timeout guard the rare residual-handle race, same\n * as the injection contract.\n */\n\nimport { CURSOR_META_KEY, openCursorDb } from './sqlite-writer.js';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** One `runs` ledger row, projected to the only two columns truncation reads. */\nexport interface CursorRunRow {\n turnNumber: number;\n /** `JSON.stringify({ blobId, storeKind })` written by the SDK per checkpoint; null for rows that never checkpointed. */\n latestCheckpointRefJson: string | null;\n}\n\nexport type CursorTruncatePlan =\n | { kind: 'noop'; reason: 'no_runs' | 'no_turns_to_drop' | 'anchor_missing' }\n | {\n kind: 'truncate';\n /** Keep every run with turn_number <= this; delete the rest. */\n keepThroughTurnNumber: number;\n /** Hex root blob id to install as the new BlobStore head. */\n newHeadBlobIdHex: string;\n /** The kept run's checkpoint-ref JSON, re-stamped onto the agents row. */\n keepCheckpointRefJson: string;\n };\n\n/**\n * Pure decision: given the agent's runs (any order) and how many trailing turns\n * to drop, compute the new head + the cutoff turn_number — or a no-op reason.\n *\n * `numTurnsToDrop` matches the `dropLastTurns` RewindTarget's `numTurns` (the\n * count of completed turns AFTER the rewind point). We clamp to keep at least\n * one turn: rewinding to before the very first turn still leaves turn 0 in\n * Cursor's store, because the user-visible revert is carried by the git restore\n * + Shipyard JSONL truncation — over-retaining one turn of agent context is a\n * safe degradation, never data loss, and the user can rewind again.\n */\nexport function planCursorTruncate(\n runs: CursorRunRow[],\n numTurnsToDrop: number\n): CursorTruncatePlan {\n if (runs.length === 0) return { kind: 'noop', reason: 'no_runs' };\n if (numTurnsToDrop <= 0) return { kind: 'noop', reason: 'no_turns_to_drop' };\n\n const sorted = [...runs].sort((a, b) => a.turnNumber - b.turnNumber);\n const keepCount = Math.max(1, sorted.length - numTurnsToDrop);\n if (keepCount >= sorted.length) return { kind: 'noop', reason: 'no_turns_to_drop' };\n\n const keepRun = sorted[keepCount - 1];\n if (keepRun === undefined) return { kind: 'noop', reason: 'no_runs' };\n\n const blobId = extractCheckpointBlobId(keepRun.latestCheckpointRefJson);\n if (blobId === null || keepRun.latestCheckpointRefJson === null) {\n return { kind: 'noop', reason: 'anchor_missing' };\n }\n\n return {\n kind: 'truncate',\n keepThroughTurnNumber: keepRun.turnNumber,\n newHeadBlobIdHex: blobId,\n keepCheckpointRefJson: keepRun.latestCheckpointRefJson,\n };\n}\n\n/**\n * Parse a `runs.latest_checkpoint_ref_json` value and pull out the root blob id.\n * Returns null when the value is missing, unparseable, or lacks a string\n * `blobId` — callers treat null as \"no reliable anchor, do not mutate.\"\n */\nexport function extractCheckpointBlobId(refJson: string | null): string | null {\n if (refJson === null) return null;\n let parsed: unknown;\n try {\n parsed = JSON.parse(refJson);\n } catch {\n return null;\n }\n if (!isRecord(parsed)) return null;\n const blobId = parsed.blobId;\n return typeof blobId === 'string' && blobId.length > 0 ? blobId : null;\n}\n\n/**\n * Re-point the BlobStore head inside an existing meta[\"0\"] value, preserving\n * every other field. The value is `hex(utf8(JSON.stringify({ ...,\n * latestRootBlobId: <hex>, ... })))` (see `sqlite-writer.ts` for the serde).\n * We decode, patch only `latestRootBlobId`, and re-encode — a native agent's\n * meta carries its own name/mode/createdAt that must survive the rewind.\n */\nexport function repointMetaHead(currentHexValue: string, newHeadBlobIdHex: string): string {\n const json = Buffer.from(currentHexValue, 'hex').toString('utf8');\n const obj: unknown = JSON.parse(json);\n if (!isRecord(obj)) {\n throw new Error('cursor store.db meta[\"0\"] did not decode to an object');\n }\n const patched = { ...obj, latestRootBlobId: newHeadBlobIdHex };\n return Buffer.from(JSON.stringify(patched), 'utf8').toString('hex');\n}\n\nexport interface TruncateCursorHistoryDeps {\n /** Absolute path to the per-workspace index.db. */\n indexDbPath: string;\n /** Absolute path to the per-agent store.db. */\n storeDbPath: string;\n /** The agentId whose ledger + store are truncated. */\n agentId: string;\n /** Number of trailing completed turns to drop (the `dropLastTurns` count). */\n numTurnsToDrop: number;\n}\n\nexport type TruncateCursorHistoryResult =\n | { kind: 'noop'; reason: 'no_runs' | 'no_turns_to_drop' | 'anchor_missing' }\n | {\n kind: 'truncated';\n keptThroughTurnNumber: number;\n newHeadBlobIdHex: string;\n runsDeleted: number;\n };\n\n/**\n * Truncate a native Cursor agent's conversation to keep turns 0..N. Reads the\n * runs ledger, plans the cut (pure), then applies it in two on-disk steps.\n *\n * Ordering matters — the two SQLite files (store.db, index.db) can't share a\n * transaction, so the sequence is chosen for crash safety: re-point the\n * store.db BlobStore head FIRST (that single UPDATE is the truncation's commit\n * point — it's what `Agent.resume` reads to reconstruct the conversation), then\n * trim the index.db ledger. A crash between the two leaves the conversation\n * correctly truncated to turn N with only stale `runs` rows / agents ref behind\n * — harmless metadata, the same recoverable class as the orphaned tail blobs.\n * The reverse order would leave the ledger short while the head still pointed at\n * a dropped turn, which `Agent.resume` could read as a fuller conversation than\n * the ledger claims. Throws on SQLite errors or a missing store.db head (the\n * caller logs + degrades — the git + JSONL rewind is authoritative).\n */\nexport function cursorTruncateHistory(\n deps: TruncateCursorHistoryDeps\n): TruncateCursorHistoryResult {\n let plan: CursorTruncatePlan;\n const readDb = openCursorDb(deps.indexDbPath);\n try {\n const rawRuns = readDb\n .prepare(\n 'SELECT turn_number, latest_checkpoint_ref_json FROM runs WHERE agent_id = ? ORDER BY turn_number ASC'\n )\n .all(deps.agentId);\n\n const runs: CursorRunRow[] = [];\n for (const row of rawRuns) {\n if (!isRecord(row) || typeof row.turn_number !== 'number') continue;\n runs.push({\n turnNumber: row.turn_number,\n latestCheckpointRefJson:\n typeof row.latest_checkpoint_ref_json === 'string'\n ? row.latest_checkpoint_ref_json\n : null,\n });\n }\n\n plan = planCursorTruncate(runs, deps.numTurnsToDrop);\n } finally {\n readDb.close();\n }\n\n if (plan.kind === 'noop') return { kind: 'noop', reason: plan.reason };\n\n /** Step 1, commit point: re-point the BlobStore head. A single UPDATE is atomic, so no partial-head window. */\n const storeDb = openCursorDb(deps.storeDbPath);\n try {\n const metaRow = storeDb.prepare('SELECT value FROM meta WHERE key = ?').get(CURSOR_META_KEY);\n if (!isRecord(metaRow) || typeof metaRow.value !== 'string') {\n throw new Error(`cursor store.db has no meta[\"${CURSOR_META_KEY}\"] row to re-point`);\n }\n const repointed = repointMetaHead(metaRow.value, plan.newHeadBlobIdHex);\n storeDb.prepare('UPDATE meta SET value = ? WHERE key = ?').run(repointed, CURSOR_META_KEY);\n } finally {\n storeDb.close();\n }\n\n /** Step 2, ledger cleanup: trim the runs tail + re-stamp the agents ref. A crash before this leaves only stale rows the conversation no longer references — observable but harmless. */\n let runsDeleted = 0;\n const writeDb = openCursorDb(deps.indexDbPath);\n try {\n writeDb.exec('BEGIN');\n try {\n writeDb\n .prepare(\n `UPDATE agents\n SET latest_checkpoint_ref_json = ?, active_run_id = NULL, updated_at = ?\n WHERE agent_id = ?`\n )\n .run(plan.keepCheckpointRefJson, new Date().toISOString(), deps.agentId);\n\n const del = writeDb\n .prepare('DELETE FROM runs WHERE agent_id = ? AND turn_number > ?')\n .run(deps.agentId, plan.keepThroughTurnNumber);\n runsDeleted = Number(del.changes);\n writeDb.exec('COMMIT');\n } catch (err) {\n writeDb.exec('ROLLBACK');\n throw err;\n }\n } finally {\n writeDb.close();\n }\n\n return {\n kind: 'truncated',\n keptThroughTurnNumber: plan.keepThroughTurnNumber,\n newHeadBlobIdHex: plan.newHeadBlobIdHex,\n runsDeleted,\n };\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, plan_required, pro_required,\n * cloud_agent\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 lower.includes('plan_required') ||\n lower.includes('pro_required') ||\n lower.includes('cloud_agent')\n );\n}\n\n/**\n * Plan-tier rejection: the API key authenticates fine but the account's\n * plan does not include the model the user asked for (e.g. free tier asking\n * for composer-2.5 returns code:'plan_required'). Distinguish from other\n * billing errors so the surfaced message is actionable.\n */\nfunction isPlanTierCode(code: string | undefined): boolean {\n if (!code) return false;\n const lower = code.toLowerCase();\n return (\n lower.includes('plan_required') ||\n lower.includes('pro_required') ||\n lower.includes('cloud_agent')\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 * Active-run conflict. Cursor's local executor throws a PLAIN `Error`\n * (`name === 'Error'`) with message \"Agent <id> already has active run\"\n * when a run is created while the agent already has a non-terminal run —\n * it is NOT an `AgentBusyError`, so the `name`-based switch below would\n * misclassify it as `sdk_error / unknown` and surface a fatal banner that\n * stops the agent (the production bug behind 16/16 \"already has active run\"\n * incidents — #3911's busy-retry never fired because it keyed on the error\n * name). Match by message so the generation-guarded `local.force` recovery\n * engages. Checked before the switch so the typed 409 `AgentBusyError`\n * path stays the canonical route when the SDK does surface that class.\n */\n if (/already has active run/i.test(message)) {\n return { canonical: 'sdk_error', subkind: 'busy', detail: message };\n }\n\n /**\n * Billing check runs first — a 402 might surface as AuthenticationError\n * on some paths; we prefer the billing classification. Plan-tier\n * rejection (e.g. free tier trying to use composer-2.5) carries the\n * original SDK message verbatim so the user sees the actionable text\n * (\"upgrade to Pro\"); we prepend a Shipyard-side hint so the UI surface\n * makes it clear this is an account-tier problem, not an invalid key.\n */\n if (isBillingCode(code)) {\n if (isPlanTierCode(code)) {\n return {\n canonical: 'billing_error',\n detail: `Your Cursor plan doesn't include this model. ${message}`,\n };\n }\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 does not publish composer-2.5's context window. The value is\n * mode-dependent (\"up to 1M in Max Mode\" per cursor.com/blog), and\n * composer auto-summarizes at an undisclosed trigger\n * (cursor.com/blog/self-summarization), so there is no fixed denominator\n * to report. `contextWindow` is set to `0` — the established sentinel for\n * \"unknown window\" — which causes the UI to show absolute occupied-token\n * count instead of a percentage against a fabricated denominator.\n *\n * The auto-compaction decision (`task-event-dispatch.ts`) guards\n * `contextWindow <= 0 → noop` before any division, so 0 is safe there.\n * Shipyard should not compute a local compaction threshold for Cursor\n * (it self-summarizes server-side); the existing `threshold: 'none'`\n * path in the profile already disables that. `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 * this can be updated if Cursor exposes the value.\n */\n\nimport type { ModelDescriptor } from '@shipyard/loro-schema';\n\nimport { withCapabilityTiers } from './model-capability-tiers.js';\n\nexport const CURSOR_MODEL_CATALOG: ModelDescriptor[] = withCapabilityTiers([\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: 0,\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","import type { NativeApprovalPolicy, PermissionMode } from '@shipyard/loro-schema';\n\n/**\n * Pure mapper: Shipyard `PermissionMode` -> native Cursor approval policy.\n *\n * Cursor enforces permissions via `.cursor/hooks.json` files, not a runtime\n * API. The hook writer turns these symbolic policies into `--policy` args:\n * - `cursor-hook-allow` -> prompt via Shipyard's daemon socket\n * - `cursor-hook-allow-bypass` -> approve without socket round-trip\n * - `cursor-hook-deny-writes` -> plan-mode hooks\n */\nexport function cursorPermissionModeMap(mode: PermissionMode): NativeApprovalPolicy {\n switch (mode) {\n case 'default':\n case 'accept-edits':\n return { kind: 'cursor-hook-allow' };\n case 'plan':\n return { kind: 'cursor-hook-deny-writes' };\n case 'bypass':\n case 'auto':\n return { kind: 'cursor-hook-allow-bypass' };\n default: {\n const _exhaustive: never = mode;\n return _exhaustive;\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 { 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 { detectCommands } from './commands.js';\nimport { detectCommonDirs } from './common-dirs.js';\nimport {\n DEFAULT_DETECTOR_TIMEOUT_MS,\n ENVIRONMENT_DETECTOR_TIMEOUT_MS,\n SKILLS_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 { logMcpDetectionEntry } from './mcp-detection-log.js';\nimport { detectMCPServers } from './mcp-servers.js';\nimport { detectModels } from './models.js';\nimport { buildRuntimeAuthMapFromSnapshot as buildRuntimeAuthMap } from './runtime/auth-adapters.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 { detectCommands } from './commands.js';\nexport { getRequiredChecks, rerunChecks } 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';\nexport { resolveCodexAuth };\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 /**\n * Architectural Invariant #21 — full-detect backstop must NOT independently\n * flip codexAuth from authenticated → unauthenticated. Codex atomically\n * rewrites `~/.codex/auth.json` during token refresh; a full detect (5-min\n * backstop, or a watcher event that joined an in-flight full refresh)\n * landing in that ENOENT window reads `not-detected` and would flicker the\n * banner — bypassing the debounced watcher path. Preserve last-known here;\n * the authoritative flippers are (a) the watcher path `refreshCodexAuthSlice`\n * (debounce-then-recheck) and (b) the subprocess-error verifier\n * `verifyAndMarkCodexUnauthenticated`. A genuine sign-out is caught by the\n * verifier at point-of-use (the next codex turn 401s → re-detect → flip),\n * so preserving here never strands the user in a falsely-authenticated state\n * while actually using Codex.\n */\n if (result.kind === 'not-detected' && lastKnown?.status === 'authenticated') {\n return lastKnown;\n }\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'\n | 'environments'\n | 'mcpServers'\n | 'skills'\n | 'commands'\n | 'marketplacePlugins'\n | '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 commands: caps.commands,\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 scoped detectors (`models`, `environments`, `mcpServers`,\n * `skills`, `commands`, `marketplacePlugins`).\n */\n lastKnownCapabilities?: Pick<\n MachineCapabilities,\n | 'models'\n | 'environments'\n | 'mcpServers'\n | 'skills'\n | 'commands'\n | 'marketplacePlugins'\n | '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 /**\n * Active repo root for project-tier skill scoping (plan A.2). When set,\n * `detectSkills` scopes the project scan to the active repo + its worktrees\n * (7+3N → 7+3). Undefined for an unscoped workspace → scan all envs (legacy).\n * See `DaemonDeps.activeRepoRoot`.\n */\n activeRepoRoot?: string\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 activeRepoRoot,\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'\n | 'environments'\n | 'mcpServers'\n | 'skills'\n | 'commands'\n | 'marketplacePlugins'\n | 'usesGraphite'\n >\n | undefined;\n codexMethodHint: CodexAuthMethod | undefined;\n lastKnownCodexAuth: CodexAuthStatus | undefined;\n /** Active repo root for project-tier skill scoping (plan A.2). See `DaemonDeps.activeRepoRoot`. */\n activeRepoRoot: string | undefined;\n}\n\nasync function runDetectCapabilitiesBody({\n tokenStore,\n methodHint,\n lastKnownAuth,\n lastKnownAgents,\n lastKnownCapabilities,\n codexMethodHint,\n lastKnownCodexAuth,\n activeRepoRoot,\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, commands, 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 logMcpDetectionEntry,\n lastKnownCapabilities?.mcpServers,\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: () =>\n detectSkills(\n environments,\n lastKnownCapabilities?.skills,\n activeRepoRoot !== undefined ? { activeRepoRoot } : undefined\n ),\n fallback: lastKnownCapabilities?.skills ?? [],\n timeoutMs: SKILLS_DETECTOR_TIMEOUT_MS,\n })\n ),\n bootstrapPhase('detect_commands', () =>\n withDetectorTimeout({\n name: 'detect_commands',\n run: () => detectCommands(environments),\n fallback: lastKnownCapabilities?.commands ?? [],\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 commands,\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 _resetWatchdogContextForTests,\n getCurrentWatchdogLabel,\n getPreviousWatchdogCompletedAtMs,\n getPreviousWatchdogDurationMs,\n getPreviousWatchdogLabel,\n withLabel,\n withLabelAsync,\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 the most-recently-completed block via\n * `getPreviousWatchdogLabel/CompletedAtMs/DurationMs`. The watchdog decides\n * whether to attribute that block to the stall by comparing its completion\n * time against the stall window (`attributeStall`) — the completion TIMESTAMP\n * is the attribution input; `prevDurationMs` is diagnostic context only.\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 * Limitation: all fields are last-writer-wins. Nested `withLabel` calls record\n * the innermost block first, then the outer's `finally` overwrites it — so an\n * outer block always trumps a nested one, and deeply-nested short blocking\n * calls are unattributable. Concurrent async paths (multiple `withLabelAsync`\n * in flight) likewise overwrite each other's `prevCompleted*` values. This is\n * the accepted cost of module-scoped state vs AsyncLocalStorage. For async\n * labels the recorded completion timestamp includes await time; see\n * `attributeStall` for how that affects attribution.\n */\n\nlet currentLabel: string | null = null;\nlet prevCompletedLabel: string | null = null;\nlet prevCompletedDurationMs = 0;\nlet prevCompletedAtMs = 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 completedAt = Date.now();\n prevCompletedLabel = name;\n prevCompletedDurationMs = completedAt - start;\n prevCompletedAtMs = completedAt;\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 completedAt = Date.now();\n prevCompletedLabel = name;\n prevCompletedDurationMs = completedAt - start;\n prevCompletedAtMs = completedAt;\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 getPreviousWatchdogCompletedAtMs(): number {\n return prevCompletedAtMs;\n}\n\nfunction _resetWatchdogContextForTests(): void {\n currentLabel = null;\n prevCompletedLabel = null;\n prevCompletedDurationMs = 0;\n prevCompletedAtMs = 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 { readdir, readFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { basename, join } from 'node:path';\nimport type { CommandInfo, GitRepoInfo } from '@shipyard/session';\n\ntype CommandSource = 'user' | 'project';\ntype CommandSourceAgent = 'claude-code' | 'cursor';\n\ninterface CommandDir {\n path: string;\n source: CommandSource;\n sourceAgent: CommandSourceAgent;\n}\n\nfunction commandNameFromPath(filePath: string): string {\n return basename(filePath).replace(/\\.md$/i, '');\n}\n\nfunction parseCommandDescription(content: string): string {\n const frontmatter = /^---\\n([\\s\\S]*?)\\n---/.exec(content)?.[1];\n const frontmatterDescription = frontmatter\n ? /^description:\\s*[\"']?(.+?)[\"']?\\s*$/m.exec(frontmatter)?.[1]?.trim()\n : undefined;\n if (frontmatterDescription) return frontmatterDescription;\n\n const heading = /^#\\s+(.+?)\\s*$/m.exec(content)?.[1]?.trim();\n if (heading) return heading;\n\n return 'Agent slash command';\n}\n\nasync function readCommandFile(filePath: string, dir: CommandDir): Promise<CommandInfo> {\n let description = 'Agent slash command';\n try {\n description = parseCommandDescription(await readFile(filePath, 'utf-8'));\n } catch {}\n return {\n name: commandNameFromPath(filePath),\n description,\n path: filePath,\n sourceAgent: dir.sourceAgent,\n compatibleAgents: [dir.sourceAgent],\n source: dir.source,\n };\n}\n\nasync function readCommandsFromDir(\n dir: CommandDir,\n depth = 0,\n maxDepth = 4\n): Promise<CommandInfo[]> {\n if (depth > maxDepth) return [];\n try {\n const entries = await readdir(dir.path, { withFileTypes: true });\n const out: CommandInfo[] = [];\n for (const entry of entries) {\n if (entry.name.startsWith('.')) continue;\n const childPath = join(dir.path, entry.name);\n if (entry.isDirectory()) {\n out.push(...(await readCommandsFromDir({ ...dir, path: childPath }, depth + 1)));\n } else if (entry.isFile() && entry.name.toLowerCase().endsWith('.md')) {\n out.push(await readCommandFile(childPath, dir));\n }\n }\n return out;\n } catch {\n return [];\n }\n}\n\nfunction commandKey(command: CommandInfo): string {\n return `${command.sourceAgent ?? ''}:${command.name}`;\n}\n\nfunction dedupeCommands(commands: CommandInfo[]): CommandInfo[] {\n const byKey = new Map<string, CommandInfo>();\n for (const command of commands) {\n const key = commandKey(command);\n if (!byKey.has(key)) {\n byKey.set(key, command);\n continue;\n }\n const existing = byKey.get(key);\n if (existing?.source !== 'user' && command.source === 'user') byKey.set(key, command);\n }\n return [...byKey.values()].sort((a, b) => a.name.localeCompare(b.name));\n}\n\nexport async function detectCommands(environments: GitRepoInfo[]): Promise<CommandInfo[]> {\n const home = homedir();\n const dirs: CommandDir[] = [\n { path: join(home, '.claude', 'commands'), source: 'user', sourceAgent: 'claude-code' },\n ];\n for (const env of environments) {\n dirs.push(\n {\n path: join(env.path, '.claude', 'commands'),\n source: 'project',\n sourceAgent: 'claude-code',\n },\n { path: join(env.path, '.cursor', 'commands'), source: 'project', sourceAgent: 'cursor' }\n );\n }\n\n const commandGroups = await Promise.all(dirs.map((dir) => readCommandsFromDir(dir)));\n return dedupeCommands(commandGroups.flat());\n}\n\nexport const _testing = {\n commandNameFromPath,\n dedupeCommands,\n parseCommandDescription,\n readCommandsFromDir,\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 * Skill scanning does bounded async filesystem work across every detected\n * environment, so large worktree fleets need more wall-clock than the shared\n * detector budget without changing the risk envelope for other detectors.\n */\nexport const SKILLS_DETECTOR_TIMEOUT_MS = 30_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';\nimport {\n type InstalledPluginInput,\n type MarketplaceDirInput,\n type PluginDetectionWarning,\n type PluginManifest,\n planPluginDetection,\n type ScannedPluginInput,\n} from './plugin-detection.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 dirExists(path: string): Promise<boolean> {\n const s = await stat(path).catch(() => null);\n return s?.isDirectory() ?? false;\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\n/**\n * `name@marketplace` — split on the LAST `@` so marketplace names survive\n * (plugin names never contain `@`).\n */\nfunction parseFullId(fullId: string): { name: string; marketplace: string } {\n const at = fullId.lastIndexOf('@');\n if (at <= 0) return { name: fullId, marketplace: '' };\n return { name: fullId.slice(0, at), marketplace: fullId.slice(at + 1) };\n}\n\n/**\n * Scan a single marketplace clone for plugins, reading both `plugins/`\n * (first-party) and `external_plugins/` (third-party). Returns raw manifests —\n * installed/enabled cross-referencing happens in the pure detection core.\n */\nasync function scanMarketplaceDir(\n marketplaceName: string,\n marketplacePath: string\n): Promise<ScannedPluginInput[]> {\n const results: ScannedPluginInput[] = [];\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 manifest = await readJsonFile(pluginJsonPath, PluginJsonSchema);\n if (!manifest) continue;\n results.push({ name: pluginName, marketplace: marketplaceName, isExternal, manifest });\n }\n }\n\n return results;\n}\n\n/**\n * `installPath/.claude-plugin/plugin.json` is the authoritative manifest for an\n * installed plugin — the exact version the user has, independent of whether the\n * marketplace clone still carries it. Returns null when the cache dir/manifest\n * is missing (orphaned install); the install entry still surfaces.\n */\nasync function readInstalledManifest(installPath: string): Promise<PluginManifest | null> {\n return readJsonFile(join(installPath, '.claude-plugin', 'plugin.json'), PluginJsonSchema);\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. Mirror of the `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 /**\n * A throw cycle logs no warnings; reset the de-dup baseline so the next\n * successful cycle re-emits its current warnings (the re-fire-on-recurrence\n * guarantee must survive an error window).\n */\n previousWarningSignatures = new Set();\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\n/**\n * Detection runs on every capability refresh (~30s). Logging a persistent\n * broken-state warning every cycle would flood the daemon log, so a warning is\n * logged only when it NEWLY appears — present this cycle, absent the last. This\n * still re-fires if a condition resolves and later recurs (unlike a\n * once-per-process guard), and holds only one cycle's signatures so it never\n * grows unbounded.\n */\nlet previousWarningSignatures = new Set<string>();\n\nfunction logNewWarnings(warnings: PluginDetectionWarning[]): void {\n const current = new Set<string>();\n for (const warning of warnings) {\n const signature = JSON.stringify(warning);\n current.add(signature);\n if (!previousWarningSignatures.has(signature)) logWarning(warning);\n }\n previousWarningSignatures = current;\n}\n\nfunction logWarning(warning: PluginDetectionWarning): void {\n switch (warning.kind) {\n case 'marketplace_dir_missing':\n logger.warn(\n { marketplace: warning.marketplace, installLocation: warning.installLocation },\n 'plugin_marketplace_dir_missing'\n );\n return;\n case 'installed_manifest_missing_using_scan':\n logger.warn(\n { fullId: warning.fullId, marketplace: warning.marketplace },\n 'plugin_installed_manifest_missing_using_scan'\n );\n return;\n case 'orphaned_install':\n logger.info(\n { fullId: warning.fullId, marketplace: warning.marketplace },\n 'plugin_orphaned_install'\n );\n return;\n default:\n warning satisfies never;\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 installed: InstalledPluginInput[] = await Promise.all(\n Object.entries(installedData?.plugins ?? {}).map(async ([fullId, records]) => {\n /** First-record-wins: Claude Code writes one install record per fullId today. */\n const record = records[0];\n const { name, marketplace } = parseFullId(fullId);\n const cacheManifest = record ? await readInstalledManifest(record.installPath) : null;\n return { fullId, name, marketplace, version: record?.version ?? 'unknown', cacheManifest };\n })\n );\n\n const marketplaceDirs: MarketplaceDirInput[] = [];\n const scanned: ScannedPluginInput[] = [];\n if (knownMarketplaces) {\n await Promise.all(\n Object.entries(knownMarketplaces).map(async ([name, meta]) => {\n const location = meta?.installLocation;\n if (typeof location !== 'string') return;\n const exists = await dirExists(location);\n marketplaceDirs.push({ marketplace: name, installLocation: location, exists });\n if (exists) scanned.push(...(await scanMarketplaceDir(name, location)));\n })\n );\n }\n\n /**\n * `install-counts-cache.json` keys each count by `name@marketplace` (the same\n * fullId used in installed_plugins.json), so the pure core can look up by fullId.\n */\n const installCounts: Record<string, number> = {};\n if (installCountsData) {\n for (const entry of installCountsData.counts)\n installCounts[entry.plugin] = entry.unique_installs;\n }\n\n const plan = planPluginDetection({\n installed,\n scanned,\n marketplaceDirs,\n enabledMap: enabledPlugins?.enabledPlugins ?? {},\n installCounts,\n });\n\n logNewWarnings(plan.warnings);\n\n logger.debug(\n {\n installed: plan.installed.length,\n available: plan.available.length,\n warnings: plan.warnings.length,\n },\n 'Detected marketplace plugins'\n );\n\n return [...plan.installed, ...plan.available];\n}\n","import type { MarketplacePluginInfo } from '@shipyard/session';\n\n/**\n * Subset of a Claude Code plugin manifest (`.claude-plugin/plugin.json`) that\n * Shipyard surfaces. `author` mirrors Claude Code's union shape.\n */\nexport interface PluginManifest {\n name: string;\n description?: string;\n version?: string;\n author?: { name: string } | string;\n}\n\n/**\n * A plugin from `installed_plugins.json`, with its manifest already resolved\n * from the install cache path (`installPath/.claude-plugin/plugin.json`).\n * `cacheManifest` is null when the cache dir or manifest is missing — the\n * authoritative \"this is installed\" signal is the entry's presence, not the\n * manifest, so a missing manifest must NOT drop the plugin.\n */\nexport interface InstalledPluginInput {\n fullId: string;\n name: string;\n marketplace: string;\n version: string;\n cacheManifest: PluginManifest | null;\n}\n\n/** A plugin discovered by scanning a marketplace clone directory. */\nexport interface ScannedPluginInput {\n name: string;\n marketplace: string;\n isExternal: boolean;\n manifest: PluginManifest;\n}\n\n/** Existence of a configured marketplace's install location on disk. */\nexport interface MarketplaceDirInput {\n marketplace: string;\n installLocation: string;\n exists: boolean;\n}\n\nexport interface PluginDetectionInput {\n installed: InstalledPluginInput[];\n scanned: ScannedPluginInput[];\n marketplaceDirs: MarketplaceDirInput[];\n /** `settings.json → enabledPlugins`, keyed by `name@marketplace`. */\n enabledMap: Record<string, boolean>;\n /** `install-counts-cache.json`, keyed by `name@marketplace`. */\n installCounts: Record<string, number>;\n}\n\nexport type PluginDetectionWarning =\n | { kind: 'marketplace_dir_missing'; marketplace: string; installLocation: string }\n | { kind: 'installed_manifest_missing_using_scan'; fullId: string; marketplace: string }\n | { kind: 'orphaned_install'; fullId: string; marketplace: string };\n\nexport interface PluginDetectionPlan {\n /** Every plugin in `installed_plugins.json`, surfaced regardless of marketplace-dir state. */\n installed: MarketplacePluginInfo[];\n /** Plugins discovered in marketplace dirs that are not installed. */\n available: MarketplacePluginInfo[];\n warnings: PluginDetectionWarning[];\n}\n\nexport function resolveAuthor(author: PluginManifest['author']): string {\n if (!author) return 'Unknown';\n if (typeof author === 'string') return author;\n return author.name;\n}\n\nfunction resolveVersion(\n manifestVersion: string | undefined,\n installedVersion: string\n): string | undefined {\n if (manifestVersion) return manifestVersion;\n return installedVersion && installedVersion !== 'unknown' ? installedVersion : undefined;\n}\n\n/**\n * Pure detection core. `installed_plugins.json` (via `input.installed`) is the\n * primary source of truth for \"what's installed\"; marketplace-dir scans\n * (`input.scanned`) are additive discovery of available-but-not-installed\n * plugins. Returns warnings as data — the caller decides how to log them.\n */\nexport function planPluginDetection(input: PluginDetectionInput): PluginDetectionPlan {\n const warnings: PluginDetectionWarning[] = [];\n\n const scannedByFullId = new Map<string, ScannedPluginInput>();\n for (const entry of input.scanned) {\n scannedByFullId.set(`${entry.name}@${entry.marketplace}`, entry);\n }\n\n const installedFullIds = new Set(input.installed.map((entry) => entry.fullId));\n\n for (const dir of input.marketplaceDirs) {\n if (!dir.exists) {\n warnings.push({\n kind: 'marketplace_dir_missing',\n marketplace: dir.marketplace,\n installLocation: dir.installLocation,\n });\n }\n }\n\n const installed: MarketplacePluginInfo[] = input.installed.map((entry) => {\n const scanMatch = scannedByFullId.get(entry.fullId);\n let manifest = entry.cacheManifest;\n if (!manifest && scanMatch) {\n manifest = scanMatch.manifest;\n warnings.push({\n kind: 'installed_manifest_missing_using_scan',\n fullId: entry.fullId,\n marketplace: entry.marketplace,\n });\n } else if (!manifest) {\n warnings.push({\n kind: 'orphaned_install',\n fullId: entry.fullId,\n marketplace: entry.marketplace,\n });\n }\n\n return {\n name: entry.name,\n description: manifest?.description ?? '',\n author: resolveAuthor(manifest?.author),\n marketplace: entry.marketplace,\n installCount: input.installCounts[entry.fullId],\n installed: true,\n enabled: input.enabledMap[entry.fullId] ?? false,\n version: resolveVersion(manifest?.version, entry.version),\n isExternal: scanMatch?.isExternal ?? false,\n };\n });\n\n const available: MarketplacePluginInfo[] = [];\n for (const entry of input.scanned) {\n const fullId = `${entry.name}@${entry.marketplace}`;\n if (installedFullIds.has(fullId)) continue;\n available.push({\n name: entry.name,\n description: entry.manifest.description ?? '',\n author: resolveAuthor(entry.manifest.author),\n marketplace: entry.marketplace,\n installCount: input.installCounts[fullId],\n installed: false,\n enabled: false,\n version: entry.manifest.version,\n isExternal: entry.isExternal,\n });\n }\n\n installed.sort((a, b) => a.name.localeCompare(b.name));\n available.sort(\n (a, b) => (b.installCount ?? 0) - (a.installCount ?? 0) || a.name.localeCompare(b.name)\n );\n\n return { installed, available, warnings };\n}\n","import { logger } from '../logger.js';\n\n/**\n * Log-level routing for the MCP-detection `Log` callback. Extracted from\n * mcp-servers.ts so the detector module isn't carrying logging policy (and so\n * the level decision is independently table-tested).\n *\n * This is a small LOCAL classifier, deliberately separate from the daemon's\n * general `classifyLogLevel` (services/serve-helpers.ts): these entries arrive\n * through an injected `Log` callback and never traverse serve.ts's event-stream\n * `logAdapter`, and detection payloads use `error:` as a descriptive string\n * (which `classifyLogLevel` would read as a severity signal). Consolidating the\n * two routers would mean extracting the shared event taxonomy into its own\n * module — a larger refactor than this log-leveling fix warrants.\n */\n\n/**\n * Detection events that fire on every capability scan against a NORMAL config\n * (no problem) — the bulk of the warn-log spam. These are the only events\n * demoted to `info`. An explicit allowlist (not a field-presence heuristic) so\n * a genuine failure that happens to omit a pino `err` Error —\n * `codex_plugin_mcp_entries_invalid` (carries `errors`, plural),\n * `codex_plugin_mcp_file_unreadable` (no error field), or\n * `codex_plugin_manifest_invalid` (carries `error:` as a descriptive STRING,\n * not a pino Error) — keeps its warn level instead of being silently demoted\n * or wrongly promoted.\n *\n * The two `claudeai_integrations_skipped*` entries are \"configured to skip\"\n * states that fire on every scan (e.g. an api-key user whose auth method can't\n * use Connectors) — never actionable, so info.\n */\nconst ROUTINE_DETECTION_EVENTS = new Set([\n 'codex_plugin_mcps_detected',\n 'codex_marketplace_json_missing',\n 'claudeai_integrations_skipped_by_method',\n 'claudeai_integrations_skipped',\n]);\n\n/**\n * Pure level decision for an mcp-detection log entry. Exported for testing.\n *\n * Only a pino `err` (an actual Error object, per pino's serializer convention —\n * see logger.ts) promotes to `error`. Detection payloads use `error:` for a\n * human-readable STRING (a Zod `.message`, an exception message), which is\n * descriptive, not a severity signal — promoting those would turn transient\n * fetch failures into error-level spam. Routine events → info; everything else\n * keeps the warn level it had before the demotion.\n */\nexport function classifyMcpDetectionLevel(entry: {\n event: string;\n err?: unknown;\n}): 'error' | 'warn' | 'info' {\n if (entry.err !== undefined) return 'error';\n if (ROUTINE_DETECTION_EVENTS.has(entry.event)) return 'info';\n return 'warn';\n}\n\n/**\n * Shared `Log` callback for the three `detectMCPServers` call sites (full\n * detect, scoped refresh, plugin-operations), replacing 3 inline\n * `logger.warn(entry, entry.event)` copies (Rule of Three).\n */\nexport function logMcpDetectionEntry(entry: { event: string; [key: string]: unknown }): void {\n logger[classifyMcpDetectionLevel(entry)](entry, entry.event);\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];\ntype ProfileModelLike = ProfileLike['models'][number];\n\n/** Deprecated model ids: kept in profile catalogs for spawn resolution, hidden from picker. */\nconst PICKER_HIDDEN_MODEL_IDS = new Set(['gpt-5.3-codex']);\n\nfunction pickerVisibleModels(models: ProfileModelLike[]): ProfileModelLike[] {\n return models.filter((model) => !PICKER_HIDDEN_MODEL_IDS.has(model.id));\n}\n\nconst INTENSITY_ORDER: readonly ReasoningEffort[] = [\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n 'ultracode',\n 'max',\n];\n\nfunction 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\nfunction toModelInfo(\n profile: ProfileLike,\n model: ProfileModelLike,\n efforts: ReasoningEffort[] = model.supportedEfforts\n): ModelInfo {\n const firstEffort = efforts[0];\n const reasoning =\n firstEffort !== undefined\n ? {\n efforts,\n defaultEffort: model.defaultEffort\n ? pickDefault(model.defaultEffort, efforts)\n : firstEffort,\n }\n : undefined;\n return {\n id: model.id,\n name: model.displayName,\n provider: profile.id,\n description: model.description,\n reasoning,\n ...(model.supportsFastMode === true ? { supportsFastMode: true as const } : {}),\n ...(model.note !== undefined ? { note: model.note } : {}),\n };\n}\n\n/**\n * Synchronous catalog snapshot for boot-time capability stubs. It intentionally\n * skips binary availability and effort probing; the async detector replaces it\n * with the authoritative list once probes finish.\n */\nexport function buildCatalogModelInfos(): ModelInfo[] {\n return profileRegistry\n .list()\n .flatMap((profile) =>\n pickerVisibleModels(profile.models).map((model) => toModelInfo(profile, model))\n );\n}\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 return pickerVisibleModels(profile.models).map((model) =>\n toModelInfo(profile, model, filterEfforts(model.supportedEfforts))\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 ...(status.apiKeyName !== undefined ? { apiKeyName: status.apiKeyName } : {}),\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\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 { 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 type { AnthropicAuthMethod, CodexAuthMethod } from '@shipyard/loro-schema';\nimport type {\n CodexAuthStatus,\n CommandInfo,\n GitRepoInfo,\n InstalledAgent,\n MachineCapabilities,\n MCPServerInfo,\n SkillInfo,\n} from '@shipyard/session';\nimport { withLabelAsync } from '../observability/watchdog-context.js';\nimport { detectAgentProviders } from './agents.js';\nimport { decideCodexAuthRefresh, detectCodexAuth } from './codex-auth-detect.js';\nimport { detectCommands } from './commands.js';\nimport {\n DEFAULT_DETECTOR_TIMEOUT_MS,\n SKILLS_DETECTOR_TIMEOUT_MS,\n withDetectorTimeout,\n} from './detector-timeout.js';\nimport { logMcpDetectionEntry } from './mcp-detection-log.js';\nimport { detectMCPServers } from './mcp-servers.js';\nimport { detectSkills } from './skills.js';\n\nexport {\n type CodexAuthSliceResult,\n lastKnownCodexStatus,\n refreshCodexAuthSlice,\n refreshCommands,\n refreshInstalledAgents,\n refreshMcpServers,\n refreshSkills,\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 logMcpDetectionEntry,\n deps.lastKnown,\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 /**\n * Active repo root (plan A.2). When set, `detectSkills` scopes the project-tier\n * scan to the active repo + its worktrees instead of every detected environment\n * (the 7+3N explosion collapses to 7+3). Undefined for an unscoped workspace\n * (daemon started at $HOME / no project marker) — detection then scans all envs,\n * the legacy behaviour. Threaded from `serve.ts` (`unscopedWorkspace ?\n * undefined : workspaceRoot`).\n */\n activeRepoRoot: string | 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: () =>\n detectSkills(\n deps.environments ?? [],\n deps.lastKnown,\n deps.activeRepoRoot !== undefined ? { activeRepoRoot: deps.activeRepoRoot } : undefined\n ),\n fallback: deps.lastKnown ?? [],\n timeoutMs: SKILLS_DETECTOR_TIMEOUT_MS,\n });\n return { skills };\n });\n}\n\nasync function refreshCommands(deps: {\n environments: GitRepoInfo[] | undefined;\n lastKnown: CommandInfo[] | undefined;\n}): Promise<ScopedCapabilitiesPatch> {\n return withLabelAsync('refreshCommands', async () => {\n await new Promise<void>((r) => {\n setImmediate(r);\n });\n const commands = await withDetectorTimeout({\n name: 'refresh_commands',\n run: () => detectCommands(deps.environments ?? []),\n fallback: deps.lastKnown ?? [],\n timeoutMs: DEFAULT_DETECTOR_TIMEOUT_MS,\n });\n return { commands };\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 */\n/**\n * Result of one codex-auth slice pass.\n *\n * `patch` is what the caller writes into `daemon.capabilities` (or `null`\n * to preserve last-known). `needsRecheck` is set ONLY on the first pass of\n * the debounce-then-recheck branch: the caller should preserve now and\n * re-invoke the slice with `isRecheck: true` after `REFRESH_DEBOUNCE_MS`.\n *\n * Crucially, the slice does NOT sleep — the wait happens OUTSIDE the\n * capability-refresh coordinator's serialized chain (a `setTimeout` in the\n * caller). Sleeping in-band would hold the single shared refresh chain for\n * 500ms and starve mcp/skills/agents refreshes (the exact head-of-line\n * blocking the scoped-refresh system exists to avoid).\n */\ninterface CodexAuthSliceResult {\n patch: ScopedCapabilitiesPatch | null;\n needsRecheck: boolean;\n}\n\n/**\n * Scoped re-detect of `capabilities.codexAuth`, Invariant #21 watcher-side\n * chokepoint. Codex atomically rewrites `~/.codex/auth.json` during normal\n * token refresh; the watcher races the rewrite, the detector reads ENOENT\n * → `not-detected`, and without the debounce we'd flip the banner for\n * hundreds of ms even though codex just refreshed successfully. When\n * last-known was `authenticated`, treat one `not-detected` reading as\n * evidence-not-proof and ask the caller to recheck after a short window;\n * only flip if a second reading still says not-detected.\n *\n * Pure decision lives in `decideCodexAuthRefresh` (codex-auth-detect.ts);\n * this shell does the IO and maps the verdict to a `patch`/`needsRecheck`.\n */\nasync function refreshCodexAuthSlice(deps: {\n methodHint?: CodexAuthMethod | undefined;\n lastKnown: CodexAuthStatus | undefined;\n /**\n * True on the post-debounce recheck pass — converts a still-`not-detected`\n * reading into a confirmed flip instead of asking to recheck again.\n */\n isRecheck?: boolean;\n}): Promise<CodexAuthSliceResult> {\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 lastKnown = lastKnownCodexStatus(deps.lastKnown);\n const result = await detectCodexAuth(deps.methodHint);\n const verdict = decideCodexAuthRefresh(result, lastKnown);\n switch (verdict.action) {\n case 'apply':\n return { patch: { codexAuth: verdict.auth }, needsRecheck: false };\n case 'preserve':\n return { patch: null, needsRecheck: false };\n case 'debounce-then-recheck':\n if (deps.isRecheck) {\n /**\n * Two consecutive `not-detected` readings across the debounce\n * window with last-known still `authenticated` is the regression\n * bar for \"real sign-out, not write-window.\" Confirm the flip.\n */\n return {\n patch: { codexAuth: { status: 'unauthenticated', method: 'none' } },\n needsRecheck: false,\n };\n }\n return { patch: null, needsRecheck: true };\n default:\n verdict satisfies never;\n return { patch: null, needsRecheck: false };\n }\n });\n}\n\nfunction lastKnownCodexStatus(\n auth: CodexAuthStatus | undefined\n): 'authenticated' | 'unauthenticated' | 'unknown' {\n if (auth?.status === 'authenticated') return 'authenticated';\n if (auth?.status === 'unauthenticated') return 'unauthenticated';\n return 'unknown';\n}\n"],"mappings":"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","names":["field","file","preserved","existsSync","existsSync","toRecord","open","createRequire","fs","homedir","join","codexAuthFilePath","join","homedir","isCodexAuthFile","isPlainObject","readCodexAuthFile","fs","isRecord","isRecord","createRequire","isRecord","createHash","homedir","join","createRequire","createRequire","isRecord","join","homedir","createHash","CURSOR_KEY_PREFIX","isValidCursorKey","asRecord","notYetWired","notYetWired","readFile","homedir","join","dirname","join","join","dirname","mkdir","readFile","rename","stat","unlink","writeFile","dirname","join","cacheFilePath","join","readFile","stat","mkdir","dirname","writeFile","rename","unlink","isAuthoritativeNotFound","cached","version","readFile","homedir","join","homedir","platform","join","run","access","readFile","homedir","join","defaultFileExists","access","readFile","homedir","join","readdir","readFile","stat","homedir","join","readFile","stat","readdir","join","homedir","toRecord","readFile","join","homedir"]}
|