@byok-sdk/client 0.1.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.
Files changed (91) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +11 -0
  3. package/dist/adapters/claude/claude-adapter.d.ts +155 -0
  4. package/dist/adapters/claude/events.d.ts +91 -0
  5. package/dist/adapters/claude/permission-mapping.d.ts +142 -0
  6. package/dist/adapters/claude/process-client.d.ts +103 -0
  7. package/dist/adapters/claude/resolve-approval-mcp-bin.d.ts +45 -0
  8. package/dist/adapters/claude/resolve-bin.d.ts +27 -0
  9. package/dist/adapters/codex/codex-adapter.d.ts +97 -0
  10. package/dist/adapters/codex/events.d.ts +41 -0
  11. package/dist/adapters/codex/permission-mapping.d.ts +107 -0
  12. package/dist/adapters/codex/process-runner.d.ts +86 -0
  13. package/dist/adapters/codex/resolve-bin.d.ts +25 -0
  14. package/dist/adapters/pi/events.d.ts +58 -0
  15. package/dist/adapters/pi/permission-mapping.d.ts +46 -0
  16. package/dist/adapters/pi/pi-adapter.d.ts +29 -0
  17. package/dist/adapters/pi/resolve-bin.d.ts +44 -0
  18. package/dist/adapters/pi/rpc-client.d.ts +101 -0
  19. package/dist/bin/approval-mcp-server.d.ts +69 -0
  20. package/dist/bin/audit-log.d.ts +212 -0
  21. package/dist/bin/byok-agent.d.ts +2 -0
  22. package/dist/bin/byok-agent.js +12347 -0
  23. package/dist/bin/byok-agent.js.map +1 -0
  24. package/dist/bin/byok-approval-mcp.d.ts +2 -0
  25. package/dist/bin/byok-approval-mcp.js +498 -0
  26. package/dist/bin/byok-approval-mcp.js.map +1 -0
  27. package/dist/bin/commands/approvals.d.ts +31 -0
  28. package/dist/bin/commands/approve-reject.d.ts +29 -0
  29. package/dist/bin/commands/doctor.d.ts +15 -0
  30. package/dist/bin/commands/pair.d.ts +7 -0
  31. package/dist/bin/commands/runtimes.d.ts +7 -0
  32. package/dist/bin/commands/service.d.ts +54 -0
  33. package/dist/bin/commands/start.d.ts +21 -0
  34. package/dist/bin/commands/status.d.ts +25 -0
  35. package/dist/bin/commands/support-bundle.d.ts +7 -0
  36. package/dist/bin/commands/tasks.d.ts +27 -0
  37. package/dist/bin/commands/unpair.d.ts +124 -0
  38. package/dist/bin/commands/workspaces.d.ts +16 -0
  39. package/dist/bin/config.d.ts +41 -0
  40. package/dist/bin/control-client.d.ts +50 -0
  41. package/dist/bin/format.d.ts +67 -0
  42. package/dist/bin/runtime-probe.d.ts +34 -0
  43. package/dist/bin/tasks-view.d.ts +49 -0
  44. package/dist/daemon/approvals.d.ts +87 -0
  45. package/dist/daemon/auth-manager.d.ts +52 -0
  46. package/dist/daemon/blob-client.d.ts +22 -0
  47. package/dist/daemon/connection-manager.d.ts +502 -0
  48. package/dist/daemon/control-protocol.d.ts +299 -0
  49. package/dist/daemon/control-server.d.ts +61 -0
  50. package/dist/daemon/create-daemon.d.ts +364 -0
  51. package/dist/daemon/cursor-store.d.ts +30 -0
  52. package/dist/daemon/daemon-owner.d.ts +24 -0
  53. package/dist/daemon/deterministic-jitter.d.ts +20 -0
  54. package/dist/daemon/device-keys.d.ts +45 -0
  55. package/dist/daemon/device-proof-signer.d.ts +41 -0
  56. package/dist/daemon/environment.d.ts +96 -0
  57. package/dist/daemon/git-workspace-store.d.ts +49 -0
  58. package/dist/daemon/git-workspace.d.ts +80 -0
  59. package/dist/daemon/http-client.d.ts +8 -0
  60. package/dist/daemon/journal/journal.d.ts +342 -0
  61. package/dist/daemon/journal/sqlite-journal.d.ts +173 -0
  62. package/dist/daemon/journal/sqlite-support.d.ts +96 -0
  63. package/dist/daemon/journal/storage-policy.d.ts +368 -0
  64. package/dist/daemon/long-poll-transport.d.ts +142 -0
  65. package/dist/daemon/observer.d.ts +345 -0
  66. package/dist/daemon/operational-health.d.ts +87 -0
  67. package/dist/daemon/policy.d.ts +16 -0
  68. package/dist/daemon/progress-batcher.d.ts +31 -0
  69. package/dist/daemon/runtime-capabilities.d.ts +36 -0
  70. package/dist/daemon/session-workspace-store.d.ts +75 -0
  71. package/dist/daemon/store.d.ts +54 -0
  72. package/dist/daemon/task-runner.d.ts +862 -0
  73. package/dist/daemon/truth-memory-client.d.ts +94 -0
  74. package/dist/daemon/url.d.ts +60 -0
  75. package/dist/daemon/ws-transport.d.ts +110 -0
  76. package/dist/diagnostics/diagnostics.d.ts +114 -0
  77. package/dist/diagnostics/support-bundle.d.ts +81 -0
  78. package/dist/index.d.ts +42 -0
  79. package/dist/index.js +10056 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/lifecycle/create-service-lifecycle.d.ts +59 -0
  82. package/dist/lifecycle/exec-runner.d.ts +141 -0
  83. package/dist/lifecycle/launchd.d.ts +55 -0
  84. package/dist/lifecycle/service-types.d.ts +177 -0
  85. package/dist/lifecycle/systemd.d.ts +46 -0
  86. package/dist/lifecycle/winsw.d.ts +64 -0
  87. package/dist/types.d.ts +178 -0
  88. package/dist/util/async-queue.d.ts +45 -0
  89. package/dist/util/atomic-write.d.ts +86 -0
  90. package/dist/util/secure-dir.d.ts +124 -0
  91. package/package.json +66 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/types.ts","../../src/daemon/git-workspace.ts","../../src/util/atomic-write.ts","../../src/lifecycle/exec-runner.ts","../../src/util/secure-dir.ts","../../src/daemon/git-workspace-store.ts","../../src/adapters/pi/resolve-bin.ts","../../src/adapters/pi/permission-mapping.ts","../../src/adapters/pi/events.ts","../../src/util/async-queue.ts","../../src/adapters/pi/rpc-client.ts","../../src/adapters/pi/pi-adapter.ts","../../src/adapters/claude/resolve-bin.ts","../../src/adapters/claude/resolve-approval-mcp-bin.ts","../../src/adapters/claude/permission-mapping.ts","../../src/adapters/claude/events.ts","../../src/adapters/claude/process-client.ts","../../src/bin/approval-mcp-server.ts","../../src/adapters/claude/claude-adapter.ts","../../src/adapters/codex/resolve-bin.ts","../../src/adapters/codex/permission-mapping.ts","../../src/adapters/codex/events.ts","../../src/adapters/codex/process-runner.ts","../../src/adapters/codex/codex-adapter.ts","../../src/daemon/approvals.ts","../../src/daemon/store.ts","../../src/daemon/device-keys.ts","../../src/daemon/url.ts","../../src/daemon/auth-manager.ts","../../src/daemon/http-client.ts","../../src/daemon/blob-client.ts","../../src/daemon/control-protocol.ts","../../src/daemon/control-server.ts","../../src/daemon/deterministic-jitter.ts","../../src/daemon/long-poll-transport.ts","../../src/daemon/ws-transport.ts","../../src/daemon/connection-manager.ts","../../src/daemon/operational-health.ts","../../src/daemon/daemon-owner.ts","../../src/daemon/runtime-capabilities.ts","../../src/daemon/cursor-store.ts","../../src/daemon/observer.ts","../../src/daemon/session-workspace-store.ts","../../src/daemon/journal/journal.ts","../../src/daemon/journal/sqlite-support.ts","../../src/daemon/journal/sqlite-journal.ts","../../src/daemon/journal/storage-policy.ts","../../src/daemon/environment.ts","../../src/daemon/policy.ts","../../src/daemon/progress-batcher.ts","../../src/daemon/task-runner.ts","../../src/daemon/create-daemon.ts","../../src/lifecycle/service-types.ts","../../src/lifecycle/launchd.ts","../../src/lifecycle/systemd.ts","../../src/lifecycle/winsw.ts","../../src/lifecycle/create-service-lifecycle.ts","../../src/bin/config.ts","../../src/bin/control-client.ts","../../src/bin/format.ts","../../src/bin/commands/approvals.ts","../../src/bin/commands/approve-reject.ts","../../src/bin/commands/pair.ts","../../src/bin/runtime-probe.ts","../../src/diagnostics/diagnostics.ts","../../src/bin/commands/doctor.ts","../../src/bin/commands/runtimes.ts","../../src/bin/commands/service.ts","../../src/bin/audit-log.ts","../../src/bin/commands/start.ts","../../src/bin/tasks-view.ts","../../src/bin/commands/status.ts","../../src/diagnostics/support-bundle.ts","../../src/bin/commands/support-bundle.ts","../../src/bin/commands/tasks.ts","../../src/bin/commands/unpair.ts","../../src/bin/commands/workspaces.ts","../../src/bin/byok-agent.ts"],"names":["path","fs","execFile","fileURLToPath","READONLY_TOOLS","subtractDenied","events","usage","STDERR_RING_CAPACITY","spawn","spawnSync","execFileAsync","promisify","DETECT_TIMEOUT_MS","os","toNonNegativeInt","guessContentType","fsConstants","edSign","delay","safeErrorText","createHash","randomUUID","isRecord","errorMessage","randomBytes","sameFileState","tmpSeq","require","existsSync","join","createEnvelope","workspaceId","now","encodeEnvelope","graceMs","TASK_TRANSITIONS","fsp","readFileSync","net","ALL_RUNTIME_IDS","MAX_DEVICE_RECORD_BYTES","lstatSync","fstatSync","sameInode","writeFileSync","linkSync","unlinkSync","STABLE_GIT_ERROR_CATEGORIES","stableGitErrorCategory","createInterface"],"mappings":"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","file":"byok-agent.js","sourcesContent":["import type { AgentEvent, PermissionPolicy, TaskOfferPayload } from '@byok-sdk/protocol';\nimport type { RuntimeEnvironmentRequirements } from './daemon/environment';\n\nexport type { RuntimeEnvironmentRequirements } from './daemon/environment';\n\nexport interface GitWorkspaceConfig {\n mode: 'local-checkpoints';\n}\n\n/**\n * Result of probing whether a runtime is usable on this machine. `authPresent`\n * is computed without ever reading the runtime's own credential storage (see\n * the credential-isolation rule on {@link RuntimeAdapter}) — it only reflects\n * whether a recognized environment variable name is set.\n */\nexport interface RuntimeDetectResult {\n present: boolean;\n version?: string;\n authPresent?: boolean;\n}\n\n/** What a runtime adapter can do, advertised so the daemon can pick/validate adapters. */\nexport interface RuntimeCapabilities {\n steer: boolean;\n resume: boolean;\n /**\n * Whether this adapter can genuinely pause a running session on\n * `needs_approval` and resume it from an out-of-band decision — i.e.\n * whether {@link Session.resolveApproval} really resolves rather than\n * throwing. This is the ONLY source of truth for the wire's\n * `RuntimeInfo.capabilities.approvalInteractive` (`daemon/\n * create-daemon.ts`'s `toRuntimeInfoCapabilities`); the daemon no longer\n * hardcodes a value.\n *\n * Required, deliberately: a new adapter (or a test fake) that forgets to\n * declare it fails to compile rather than silently defaulting to a claim\n * it cannot back.\n */\n approvalInteractive: boolean;\n /** Subset of {@link PermissionPolicy}'s `mode` values this adapter can express without widening. */\n permissionModes: string[];\n}\n\n/**\n * M4 Phase 3: the out-of-band approval channel `TaskRunner` (`daemon/\n * task-runner.ts`) hands to an adapter's `start()` via `TaskContext\n * .approvalChannel`, for a runtime whose approval mechanism genuinely needs\n * to reach back into the daemon from OUTSIDE the adapter's own process — the\n * claude adapter's concrete case: `claude`'s `--permission-prompt-tool`\n * resolves a pending permission entirely inside a SEPARATE MCP-server child\n * process claude itself spawns (see `bin/byok-approval-mcp.ts`), which has\n * no in-process handle to this task's `Session` at all and must instead call\n * back into the SAME daemon over its control socket. `storeDir`/`productId`\n * are exactly what that out-of-process helper needs to find and authenticate\n * against this daemon's control socket (`daemon/control-protocol.ts`\n * `controlEndpointPath`/`controlTokenPath`); `taskId` is how its request gets\n * correlated back to THIS task once it arrives. `resolve()` is the\n * daemon-side counterpart: it resolves the single most-recently-registered\n * pending approval for this task (via `TaskRunner.requestApproval`'s own\n * `ApprovalRegistry` entry — see `daemon/approvals.ts`), and rejects if none\n * is currently pending, mirroring `Session.resolveApproval`'s own\n * no-notion-of-approval-pending fail-closed contract one level up.\n *\n * Optional and adapter-agnostic on purpose: only an adapter whose runtime\n * genuinely supports an out-of-band pause (claude, today) ever reads this;\n * every other adapter (pi, codex) ignores it exactly as before this field\n * existed.\n */\nexport interface ApprovalChannel {\n taskId: string;\n storeDir: string;\n productId: string;\n /** Default wait (ms) before the daemon force-resolves an unanswered approval request as a fail-closed rejection — see `TaskRunner.requestApproval`. */\n timeoutMs: number;\n /** Resolve the single currently-pending out-of-band approval for this task. Rejects if none is pending right now. */\n resolve(approved: boolean, reason?: string): Promise<void>;\n}\n\n/**\n * Per-task execution context handed to {@link RuntimeAdapter.start}. `policy`\n * is the already fail-closed-checked *effective* policy (offer policy merged\n * against the daemon's configured ceiling) — the adapter must obey this, not\n * whatever the raw task offer's own `policy` field said.\n */\nexport interface TaskContext {\n workspaceDir: string;\n policy: PermissionPolicy;\n env: NodeJS.ProcessEnv;\n /** Prepared local checkpoint repository metadata; absent for legacy plain workspaces. */\n gitWorkspace?: {\n workspaceId: string;\n baseline?: string;\n };\n /** M4 Phase 3 — see {@link ApprovalChannel}. Optional/adapter-agnostic: unset for every adapter that never requests an out-of-band approval. */\n approvalChannel?: ApprovalChannel;\n}\n\n/**\n * A running (or resumable) unit of work on a runtime. One `Session` maps to\n * one underlying runtime process/session for the lifetime of a task.\n */\nexport interface Session {\n /** Opaque runtime session id, reported back to the server via `task.complete.sessionRef`. */\n sessionRef: string;\n /** Normalized events for this session; the daemon batches these into `task.progress`. */\n events: AsyncIterable<AgentEvent>;\n /** Inject steering text into a running turn (mid-stream). */\n steer(text: string): Promise<void>;\n /** Send a new instruction on the same session after it has gone idle. */\n followUp(task: TaskOfferPayload): Promise<void>;\n /** Best-effort abort of the current turn (used for `task.cancel`). */\n interrupt(): Promise<void>;\n /** Tear down the underlying runtime process/session. Idempotent. */\n close(): Promise<void>;\n /**\n * Resolve a session paused on `needs_approval` (protocol §5). The\n * server's own state has already moved by the time this is called (§4 —\n * `task.approve`/`task.reject` are best-effort notifications, not\n * requests awaiting a reply): `approved: true` must make the session\n * resume producing events (`task.progress` continuing is the proof);\n * `approved: false` means the caller will immediately follow up with\n * `interrupt()` + `close()` and report `task.fail` — an adapter that has\n * no notion of `needs_approval` at all (i.e. never emits one) should\n * throw a descriptive error here rather than silently no-op, since a\n * caller receiving `task.approve`/`task.reject` for one of its tasks\n * implies something upstream expected approval support that isn't there.\n */\n resolveApproval(approved: boolean, reason?: string): Promise<void>;\n}\n\n/**\n * Uniform seam every concrete runtime (pi now; claude/codex in M2) implements.\n *\n * Credential-isolation rule: an adapter spawns only the runtime's official\n * binary. It never reads, proxies, or forwards that runtime's own credential\n * storage (OAuth tokens, API keys on disk, `~/.claude`, `~/.codex`, `~/.pi`\n * auth state, etc). Presence checks are limited to environment variable\n * *names* (see {@link RuntimeDetectResult.authPresent}).\n *\n * M5: separately, {@link RuntimeAdapter.environmentRequirements} below\n * declares which environment variable NAMES (never values inspected here\n * either) this adapter's runtime needs forwarded into its own spawned\n * process — see that method's own doc comment and `daemon/environment.ts`.\n */\nexport interface RuntimeAdapter {\n id: string;\n detect(): Promise<RuntimeDetectResult>;\n capabilities(): RuntimeCapabilities;\n start(task: TaskOfferPayload, ctx: TaskContext): Promise<Session>;\n /**\n * M5: declares which environment variable names (exact, or `*`-suffixed\n * prefix) this runtime's own CLI needs beyond the always-included\n * platform baseline (`daemon/environment.ts`'s `buildRuntimeEnv`) —\n * `task-runner.ts` builds each task's `TaskContext.env` from this instead\n * of ever handing a spawned agent the daemon's raw `process.env` again.\n * Optional and fail-closed by omission: an adapter that doesn't implement\n * this gets the platform baseline ONLY, never an implicit \"everything.\"\n */\n environmentRequirements?(): RuntimeEnvironmentRequirements;\n}\n\n/**\n * Thrown by `RuntimeAdapter.start` when the task can never succeed on this\n * adapter as offered — an unsupported `PermissionPolicy` (fail-closed) or an\n * instruction shape the adapter can't handle (e.g. a blob-ref in M0) — as\n * opposed to a transient/environmental failure (spawn error, missing\n * credentials) that might succeed on a later retry. The daemon uses this\n * distinction to set `task.fail`'s `retryable` flag correctly instead of\n * treating every `start()` failure the same way.\n */\nexport class PolicyUnsupportedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PolicyUnsupportedError';\n }\n}\n\n/**\n * Thrown by {@link Session.steer} on an adapter whose runtime has no\n * mid-turn steering channel at all (`capabilities().steer === false`) — a\n * permanent property of the runtime, never a transient failure. Typed\n * rather than a bare `Error` so the daemon can classify an inbound\n * `task.steer` for such a runtime as non-retryable (record + ack, cursor\n * advances) instead of stalling the cursor on it forever, without matching\n * on message strings.\n */\nexport class SteerUnsupportedError extends Error {\n /** The `RuntimeAdapter.id` that cannot steer (e.g. `claude`, `codex`). */\n readonly runtimeId: string;\n\n constructor(runtimeId: string, message: string) {\n super(message);\n this.name = 'SteerUnsupportedError';\n this.runtimeId = runtimeId;\n }\n}\n","import { execFile, type ExecFileException } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\nexport interface GitWorkspaceConfig {\n mode: 'local-checkpoints';\n}\n\nexport type GitErrorCategory =\n | 'git-unavailable'\n | 'git-timeout'\n | 'git-output-limit'\n | 'git-command-failed'\n | 'workspace-root-invalid'\n | 'workspace-root-conflict'\n | 'workspace-not-owned'\n | 'repository-root-mismatch'\n | 'repository-invalid'\n | 'lease-busy'\n | 'ledger-invalid';\n\nexport class GitWorkspaceError extends Error {\n constructor(\n public readonly category: GitErrorCategory,\n message: string = category,\n ) {\n super(message);\n this.name = 'GitWorkspaceError';\n }\n}\n\nexport interface GitCommandResult {\n code: number;\n stdout: string;\n stderr: string;\n}\n\nexport interface GitCommandOptions {\n cwd?: string;\n timeout?: number;\n maxBuffer?: number;\n env?: NodeJS.ProcessEnv;\n}\n\nexport type GitRunner = (args: readonly string[], options?: GitCommandOptions) => Promise<GitCommandResult>;\n\nconst DEFAULT_TIMEOUT_MS = 5_000;\nconst DEFAULT_MAX_OUTPUT_BYTES = 64 * 1024;\nconst OWNER_MARKER = '.byok-git-workspace-owner.json';\nconst GIT_ENV_KEYS = new Set([\n 'GIT_DIR',\n 'GIT_WORK_TREE',\n 'GIT_COMMON_DIR',\n 'GIT_OBJECT_DIRECTORY',\n 'GIT_ALTERNATE_OBJECT_DIRECTORIES',\n 'GIT_OBJECT_DIRECTORY_RELATIVE',\n 'GIT_INDEX_FILE',\n 'GIT_CONFIG',\n 'GIT_CONFIG_GLOBAL',\n 'GIT_CONFIG_SYSTEM',\n 'GIT_CONFIG_NOSYSTEM',\n 'GIT_CONFIG_COUNT',\n 'GIT_CONFIG_PARAMETERS',\n 'GIT_CEILING_DIRECTORIES',\n 'GIT_DISCOVERY_ACROSS_FILESYSTEM',\n 'GIT_NAMESPACE',\n 'GIT_REPLACE_REF_BASE',\n 'GIT_SHALLOW_FILE',\n 'GIT_GRAFT_FILE',\n 'GIT_TEMPLATE_DIR',\n]);\n\nfunction gitEnvironment(readOnly: boolean): NodeJS.ProcessEnv {\n const env = { ...process.env };\n for (const key of Object.keys(env)) {\n const normalizedKey = key.toUpperCase();\n if (GIT_ENV_KEYS.has(normalizedKey) || /^GIT_CONFIG_(?:KEY|VALUE)_\\d+$/.test(normalizedKey) || normalizedKey === 'GIT_OPTIONAL_LOCKS') delete env[key];\n }\n if (readOnly) env.GIT_OPTIONAL_LOCKS = '0';\n return env;\n}\n\nexport function stableGitWorkspaceOwnerId(storeDir: string, productId: string): string {\n const identity = `${path.resolve(storeDir)}\\\\0${productId}`;\n return `store-product:${createHash('sha256').update(identity).digest('hex')}`;\n}\nconst GUIDANCE = [\n 'Work only in the provided workspace directory.',\n 'Inspect git status before and after edits.',\n 'When Git identity is already configured, create small ordinary checkpoint commits after coherent, verified units.',\n 'Do not change Git identity.',\n 'Do not push, merge, rebase, stash, reset, clean, switch branches, or delete work.',\n 'Leave incomplete work visible for recovery.',\n].join('\\n');\n\nfunction canonical(value: string): string {\n return path.resolve(value);\n}\n\nfunction isContained(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return relative === '' || (!relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative));\n}\n\nfunction bounded(value: string, max: number): string {\n return Buffer.byteLength(value, 'utf8') <= max ? value : value.slice(0, max);\n}\n\nfunction stableFailure(result: GitCommandResult, args: readonly string[]): GitWorkspaceError {\n if (result.code === 124) return new GitWorkspaceError('git-timeout');\n const command = args[0] === '--version' ? 'preflight' : args[0] === 'init' ? 'init' : 'observation';\n return new GitWorkspaceError('git-command-failed', `Git ${command} failed`);\n}\n\n/** A bounded, no-shell runner for the small Git command allowlist. */\nexport const defaultGitRunner: GitRunner = (args, options = {}) =>\n new Promise((resolve, reject) => {\n execFile('git', [...args], {\n cwd: options.cwd,\n env: options.env,\n shell: false,\n timeout: options.timeout ?? DEFAULT_TIMEOUT_MS,\n maxBuffer: options.maxBuffer ?? DEFAULT_MAX_OUTPUT_BYTES,\n windowsHide: true,\n }, (error: ExecFileException | null, stdout: string, stderr: string) => {\n if (error && typeof error.code !== 'number') {\n reject(error);\n return;\n }\n resolve({\n code: error ? (typeof error.code === 'number' ? error.code : 1) : 0,\n stdout: bounded(stdout, options.maxBuffer ?? DEFAULT_MAX_OUTPUT_BYTES),\n stderr: bounded(stderr, options.maxBuffer ?? DEFAULT_MAX_OUTPUT_BYTES),\n });\n });\n });\n\nexport interface GitWorkspaceOptions {\n run?: GitRunner;\n timeoutMs?: number;\n maxOutputBytes?: number;\n platform?: NodeJS.Platform;\n ownerId?: string;\n}\n\nexport interface GitWorkspaceObservation {\n workspaceDir: string;\n head?: string;\n baseline?: string;\n headChanged: boolean;\n commitsSinceBaseline: number;\n staged: number;\n unstaged: number;\n untracked: number;\n conflicted: number;\n}\n\nexport interface GitWorkspaceLease {\n readonly workspaceDir: string;\n readonly sessionRef?: string;\n release(): void;\n}\n\ninterface OwnerMarker {\n version: 1;\n ownerId: string;\n}\n\nconst workspaceLeases = new Map<string, GitWorkspaceLease>();\nconst sessionLeases = new Map<string, GitWorkspaceLease>();\n\nfunction parseHead(stdout: string): string | undefined {\n const value = stdout.trim();\n return value && /^[0-9a-f]{4,128}$/i.test(value) ? value : undefined;\n}\n\nfunction parsePorcelain(value: string): Pick<GitWorkspaceObservation, 'staged' | 'unstaged' | 'untracked' | 'conflicted'> {\n let staged = 0;\n let unstaged = 0;\n let untracked = 0;\n let conflicted = 0;\n const entries = value.split('\\0');\n for (let index = 0; index < entries.length; index += 1) {\n const entry = entries[index];\n if (!entry) continue;\n const x = entry[0] ?? ' ';\n const y = entry[1] ?? ' ';\n if (x === '?' && y === '?') {\n untracked++;\n } else {\n if (x !== ' ') staged++;\n if (y !== ' ') unstaged++;\n if (x === 'U' || y === 'U' || (x === 'D' && y === 'D') || (x === 'A' && y === 'A')) conflicted++;\n }\n // Porcelain v1 -z emits a second, NUL-delimited pathname for renames\n // and copies. It is data belonging to this entry, never another status.\n if (x === 'R' || x === 'C' || y === 'R' || y === 'C') index += 1;\n }\n return { staged, unstaged, untracked, conflicted };\n}\n\nfunction asGitError(error: unknown, category: GitErrorCategory, message: string): GitWorkspaceError {\n if (error instanceof GitWorkspaceError) return error;\n const code = (error as NodeJS.ErrnoException).code;\n if (code === 'ETIMEDOUT' || (error as { killed?: boolean }).killed) return new GitWorkspaceError('git-timeout');\n if (code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER') return new GitWorkspaceError('git-output-limit');\n return new GitWorkspaceError(category, message);\n}\n\n/** Local Git checkpoint manager. It never invokes a shell or mutating Git command other than init. */\nexport class GitWorkspaceManager {\n readonly workspaceRoot: string;\n readonly ownerId: string;\n private readonly run: GitRunner;\n private readonly timeoutMs: number;\n private readonly maxOutputBytes: number;\n private readonly platform: NodeJS.Platform;\n\n constructor(workspaceRoot: string, options: GitWorkspaceOptions = {}) {\n this.workspaceRoot = canonical(workspaceRoot);\n this.ownerId = options.ownerId ?? stableGitWorkspaceOwnerId(this.workspaceRoot, this.workspaceRoot);\n this.run = options.run ?? defaultGitRunner;\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.maxOutputBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;\n this.platform = options.platform ?? process.platform;\n }\n\n static validateConfig(value: unknown): GitWorkspaceConfig | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new GitWorkspaceError('workspace-root-invalid', 'gitWorkspace must be an object');\n }\n const candidate = value as Record<string, unknown>;\n if (candidate.mode !== 'local-checkpoints' || Object.keys(candidate).some((key) => key !== 'mode')) {\n throw new GitWorkspaceError('workspace-root-invalid', 'gitWorkspace.mode must be local-checkpoints');\n }\n return { mode: 'local-checkpoints' };\n }\n\n async preflight(): Promise<void> {\n try {\n const result = await this.run(['--version'], this.commandOptions(undefined, true));\n if (result.code !== 0) throw stableFailure(result, ['--version']);\n } catch (error) {\n if (error instanceof GitWorkspaceError) throw error;\n throw asGitError(error, 'git-unavailable', 'Git is unavailable');\n }\n await fs.mkdir(this.workspaceRoot, { recursive: true, mode: 0o700 }).catch(() => {\n throw new GitWorkspaceError('workspace-root-invalid', 'workspace root is unavailable');\n });\n await this.ensureOwnerMarker();\n }\n\n async ensureOwnerMarker(): Promise<void> {\n const markerPath = path.join(this.workspaceRoot, OWNER_MARKER);\n let existing: OwnerMarker | undefined;\n try {\n existing = JSON.parse(await fs.readFile(markerPath, 'utf8')) as OwnerMarker;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw new GitWorkspaceError('workspace-root-conflict', 'workspace root owner marker is invalid');\n }\n }\n if (existing && existing.version === 1 && existing.ownerId !== this.ownerId) {\n throw new GitWorkspaceError('workspace-root-conflict', 'workspace root is owned by another daemon');\n }\n if (existing?.ownerId === this.ownerId) return;\n const marker: OwnerMarker = { version: 1, ownerId: this.ownerId };\n try {\n await fs.writeFile(markerPath, JSON.stringify(marker), { flag: 'wx', mode: 0o600 });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'EEXIST') {\n throw new GitWorkspaceError('workspace-root-invalid', 'workspace root owner marker cannot be created');\n }\n let competing: OwnerMarker;\n try {\n competing = JSON.parse(await fs.readFile(markerPath, 'utf8')) as OwnerMarker;\n } catch {\n throw new GitWorkspaceError('workspace-root-conflict', 'workspace root owner marker is invalid');\n }\n if (competing.ownerId !== this.ownerId) throw new GitWorkspaceError('workspace-root-conflict', 'workspace root is owned by another daemon');\n }\n }\n\n async prepareFresh(workspaceDir: string): Promise<GitWorkspaceObservation> {\n const root = await this.assertTaskRoot(workspaceDir);\n let result: GitCommandResult;\n try {\n result = await this.run(['init'], this.commandOptions(root, false));\n } catch {\n throw new GitWorkspaceError('git-command-failed', 'Git initialization failed');\n }\n if (result.code !== 0) throw stableFailure(result, ['init']);\n const actual = await this.readTopLevel(root);\n if (actual !== root) throw new GitWorkspaceError('repository-root-mismatch', 'Git repository root does not match workspace');\n return this.observe(root);\n }\n\n /** Validate an already prepared repository without creating directories or running mutating Git commands. */\n async validateExisting(workspaceDir: string): Promise<GitWorkspaceObservation> {\n const root = await this.assertExistingTaskRoot(workspaceDir);\n const actual = await this.readTopLevel(root);\n if (actual !== root) throw new GitWorkspaceError('repository-root-mismatch', 'Git repository root does not match workspace');\n return this.observe(root);\n }\n\n async observe(workspaceDir: string, baseline?: string): Promise<GitWorkspaceObservation> {\n const root = await this.assertTaskRoot(workspaceDir);\n const actual = await this.readTopLevel(root);\n if (actual !== root) throw new GitWorkspaceError('repository-root-mismatch', 'Git repository root does not match workspace');\n const [headResult, statusResult] = await Promise.all([\n this.read(['rev-parse', '--verify', 'HEAD'], root),\n this.read(['status', '--porcelain=v1', '-z', '--untracked-files=all'], root),\n ]);\n const head = headResult.code === 0 ? parseHead(headResult.stdout) : undefined;\n if (headResult.code === 0 && !head) throw new GitWorkspaceError('repository-invalid', 'Git HEAD is invalid');\n if (statusResult.code !== 0) throw stableFailure(statusResult, ['status']);\n let commitsSinceBaseline = 0;\n if (head) {\n const count = await this.read(baseline ? ['rev-list', '--count', `${baseline}..HEAD`] : ['rev-list', '--count', 'HEAD'], root);\n if (count.code !== 0) throw stableFailure(count, ['rev-list']);\n commitsSinceBaseline = Number.parseInt(count.stdout.trim(), 10);\n if (!Number.isSafeInteger(commitsSinceBaseline) || commitsSinceBaseline < 0) throw new GitWorkspaceError('repository-invalid', 'Git commit count is invalid');\n }\n const dirty = parsePorcelain(statusResult.stdout);\n return {\n workspaceDir: root,\n head,\n baseline,\n headChanged: Boolean(head && baseline && head !== baseline),\n commitsSinceBaseline,\n ...dirty,\n };\n }\n\n async acquireLease(workspaceDir: string, sessionRef?: string): Promise<GitWorkspaceLease> {\n const root = canonical(workspaceDir);\n const existingWorkspace = workspaceLeases.get(root);\n const existingSession = sessionRef ? sessionLeases.get(sessionRef) : undefined;\n if (existingWorkspace || existingSession) throw new GitWorkspaceError('lease-busy', 'workspace is busy');\n let released = false;\n const lease: GitWorkspaceLease = {\n workspaceDir: root,\n sessionRef,\n release: () => {\n if (released) return;\n released = true;\n if (workspaceLeases.get(root) === lease) workspaceLeases.delete(root);\n if (sessionRef && sessionLeases.get(sessionRef) === lease) sessionLeases.delete(sessionRef);\n },\n };\n workspaceLeases.set(root, lease);\n if (sessionRef) sessionLeases.set(sessionRef, lease);\n return lease;\n }\n\n static guidance(): string {\n return GUIDANCE;\n }\n\n static prependGuidance(instruction: string): string {\n return `${GUIDANCE}\\n\\n${instruction}`;\n }\n\n private commandOptions(cwd?: string, readOnly = false): GitCommandOptions {\n return {\n cwd,\n timeout: this.timeoutMs,\n maxBuffer: this.maxOutputBytes,\n env: gitEnvironment(readOnly),\n };\n }\n\n private async read(args: readonly string[], cwd: string): Promise<GitCommandResult> {\n try {\n return await this.run(args, this.commandOptions(cwd, true));\n } catch (error) {\n throw asGitError(error, 'git-command-failed', 'Git observation failed');\n }\n }\n\n private async readTopLevel(root: string): Promise<string> {\n const result = await this.read(['rev-parse', '--show-toplevel'], root);\n if (result.code !== 0) throw new GitWorkspaceError('repository-invalid', 'workspace is not a Git repository');\n return canonical(result.stdout.trim());\n }\n\n private async assertTaskRoot(workspaceDir: string): Promise<string> {\n const candidate = canonical(workspaceDir);\n const realWorkspaceRoot = await fs.realpath(this.workspaceRoot).catch(() => {\n throw new GitWorkspaceError('workspace-root-invalid', 'workspace root is unavailable');\n });\n if (!isContained(this.workspaceRoot, candidate) && !isContained(realWorkspaceRoot, candidate)) {\n throw new GitWorkspaceError('workspace-root-invalid', 'workspace directory is invalid');\n }\n await this.assertExistingAncestry(candidate, realWorkspaceRoot);\n await fs.mkdir(candidate, { recursive: true, mode: 0o700 }).catch(() => {\n throw new GitWorkspaceError('workspace-root-invalid', 'workspace directory is unavailable');\n });\n const realCandidate = await fs.realpath(candidate).catch(() => {\n throw new GitWorkspaceError('workspace-root-invalid', 'workspace directory is unavailable');\n });\n if (!isContained(realWorkspaceRoot, realCandidate)) {\n throw new GitWorkspaceError('workspace-root-invalid', 'workspace directory is invalid');\n }\n return realCandidate;\n }\n\n private async assertExistingAncestry(candidate: string, realWorkspaceRoot: string): Promise<void> {\n let current = candidate;\n while (true) {\n try {\n const realCurrent = await fs.realpath(current);\n if (!isContained(realWorkspaceRoot, realCurrent)) {\n throw new GitWorkspaceError('workspace-root-invalid', 'workspace directory is invalid');\n }\n return;\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (error instanceof GitWorkspaceError || (code !== 'ENOENT' && code !== 'ENOTDIR')) {\n throw new GitWorkspaceError('workspace-root-invalid', 'workspace directory is invalid');\n }\n const parent = path.dirname(current);\n if (parent === current) {\n throw new GitWorkspaceError('workspace-root-invalid', 'workspace directory is invalid');\n }\n current = parent;\n }\n }\n }\n\n private async assertExistingTaskRoot(workspaceDir: string): Promise<string> {\n const candidate = canonical(workspaceDir);\n const realWorkspaceRoot = await fs.realpath(this.workspaceRoot).catch(() => {\n throw new GitWorkspaceError('workspace-root-invalid', 'workspace root is unavailable');\n });\n const realCandidate = await fs.realpath(candidate).catch(() => {\n throw new GitWorkspaceError('repository-invalid', 'workspace directory is unavailable');\n });\n if (!isContained(realWorkspaceRoot, realCandidate)) {\n throw new GitWorkspaceError('workspace-root-invalid', 'workspace directory is invalid');\n }\n return realCandidate;\n }\n}\n\nexport const GIT_WORKSPACE_OWNER_MARKER = OWNER_MARKER;\nexport const LOCAL_GIT_WORKSPACE_GUIDANCE = GUIDANCE;\nexport function prependGitWorkspaceGuidance(instruction: string): string {\n return GitWorkspaceManager.prependGuidance(instruction);\n}\n\nexport function isGitWorkspaceConfig(value: unknown): value is GitWorkspaceConfig {\n try {\n return GitWorkspaceManager.validateConfig(value) !== undefined;\n } catch {\n return false;\n }\n}\n\nexport async function canonicalWorkspaceRoot(value: string): Promise<string> {\n return fs.realpath(value).catch(() => canonical(value));\n}\n\nexport { DEFAULT_MAX_OUTPUT_BYTES as GIT_WORKSPACE_MAX_OUTPUT_BYTES, DEFAULT_TIMEOUT_MS as GIT_WORKSPACE_TIMEOUT_MS };\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\n/** Options for {@link atomicWriteFile}. */\nexport interface AtomicWriteOptions {\n /**\n * POSIX file mode (e.g. `0o600`) to apply to the written file. Applied to\n * the temp file at creation (via `fs.open`'s own `mode` argument, which\n * *is* honored there since the temp file is always freshly created — see\n * point 3 below) and re-asserted with an explicit `chmod` both right\n * after and again once more after the rename. Omit to leave the file at\n * the platform's default create mode.\n */\n mode?: number;\n /**\n * fsync(2) the temp file's contents before renaming it onto the target,\n * then fsync the published target and, on POSIX, its parent directory after\n * the rename. Windows' `FlushFileBuffers` requires a writable file handle\n * and has no directory-flush surface through Node/libuv, so that platform\n * flushes the target through `r+` and relies on the atomic rename for the\n * directory entry. Off by default: this is the strongest platform-native\n * durability form needed by state whose directory entry itself is\n * load-bearing (for example the operational-health run marker). It is not\n * needed for the core no-torn-read guarantee, which comes from rename.\n */\n fsync?: boolean;\n}\n\n/**\n * Monotonic per-process counter for the temp file's suffix. Deliberately\n * NOT `Date.now()`/`Math.random()` — both can collide (a mocked/frozen\n * clock in tests, a low-entropy sandbox), and a suffix collision between\n * two concurrent `atomicWriteFile` calls targeting the same directory would\n * let one call's temp file clobber another's mid-write, defeating the whole\n * point of writing to a private path first. Combined with `process.pid` so\n * two processes sharing a directory don't collide either. Mirrors\n * `session-workspace-store.ts`'s own `tmpSeq` — this helper generalizes\n * that store's pattern for reuse by `store.ts`/`cursor-store.ts`.\n */\nlet tmpSeq = 0;\n\n/**\n * Write `data` to `filePath` such that:\n *\n * 1. **No torn reads.** A concurrent reader opening `filePath` at any point\n * during the write either sees the file's prior complete contents or the\n * new complete contents — never a truncated/partial write. A bare\n * `fs.writeFile` does NOT give you this: it truncates the target in\n * place before writing the new bytes, so a reader racing it can observe\n * (or fail to `JSON.parse`) a half-written file. This helper instead\n * writes to a private temp file in the same directory as `filePath`\n * (same directory is required for the rename below to be atomic — it\n * must stay on one filesystem) and `fs.rename`s it onto the target;\n * POSIX guarantees that rename-onto-an-existing-path is an atomic\n * directory-entry swap.\n * 2. **No corruption on crash.** If the process dies between the write and\n * the rename, `filePath` is untouched — the half-written data only ever\n * existed at the temp path. This does not, by itself, order two\n * concurrent writers deterministically — the last rename to land wins,\n * silently, with no lost-update detection. Callers that need that on\n * top of atomicity (e.g. an in-memory map persisted across many\n * concurrent callers) still need their own serialization, the way\n * `session-workspace-store.ts`'s own per-instance queue does.\n * 3. **Mode preserved across a replace.** POSIX rename replaces the target\n * path's directory entry wholesale — the resulting file's mode is the\n * temp file's mode, not whatever the previously-existing target's mode\n * was. Passing `{ mode }` sets that on the temp file before the rename\n * so callers like `DeviceStore` (0600, holds a private key) get a\n * guaranteed mode on every write, not just the one that first creates\n * the file.\n * 4. **Works on win32 — without ever risking the live target.** POSIX\n * `rename(2)` atomically replaces an existing `filePath` in one step.\n * Windows' rename (`MoveFileEx` under libuv) can refuse to replace an\n * existing target — most commonly `EPERM`, and on some Node/libuv\n * versions `EEXIST` — when something transient (an antivirus scanner or\n * search indexer briefly holding a read handle open on the destination\n * is the usual culprit) is touching it. An earlier version of this\n * helper \"fixed\" that by `unlink`-ing the stale target and retrying the\n * rename once — which is exactly backwards for a helper whose whole job\n * is protecting `filePath` from ever being left corrupt or missing: if\n * the retried rename ALSO failed (the lock wasn't transient after all),\n * the catch block deleted the temp file too, leaving `filePath` gone\n * entirely — worse than the torn write this helper exists to prevent,\n * and fatal for a caller like `DeviceStore` (the device's JWT + private\n * key live at that path with no other copy). Fixed: `renameOnto` below\n * NEVER unlinks `targetPath`. On `EPERM`/`EEXIST` it retries the plain\n * rename with a few short, bounded backoff waits (the lock is normally\n * gone within milliseconds); if every attempt still fails, it throws\n * with `filePath` left completely untouched — the caller keeps the\n * last-good file on disk instead of losing it, at the cost of that one\n * write not landing. Still strictly better than the plain\n * `fs.writeFile` this replaces, which truncates the live file in place\n * unconditionally (so a crash or a racing reader can see a torn file on\n * every platform, every time) rather than only failing-safe on one\n * platform under a transient lock.\n *\n * The caller is responsible for ensuring the parent directory of `filePath`\n * already exists (e.g. via `fs.mkdir(dir, { recursive: true })`) — this\n * helper does not create it, mirroring `DeviceStore`/`CursorStore`/\n * `SessionWorkspaceStore`, which all do that themselves with their own\n * directory mode.\n */\nexport async function atomicWriteFile(\n filePath: string,\n data: string | Uint8Array,\n options: AtomicWriteOptions = {},\n): Promise<void> {\n // Same directory as `filePath` (required for `fs.rename` to be atomic on\n // POSIX — same filesystem) and unique per call so two callers racing to\n // write never collide on the same temp path (see `tmpSeq`'s doc comment).\n const tmpPath = `${filePath}.${process.pid}-${tmpSeq++}.tmp`;\n\n try {\n const handle = await fs.open(tmpPath, 'w', options.mode);\n try {\n await handle.writeFile(data);\n if (options.mode !== undefined) {\n // `open()`'s own `mode` argument only governs permissions at\n // creation time, which is always the case here since `tmpPath` is\n // guaranteed fresh — but re-asserting it explicitly costs nothing\n // and removes any doubt (mirrors `DeviceStore.save`'s pre-existing\n // defensive chmod, for the same reason: don't trust `mode` from a\n // single call site alone when the file holds a private key).\n await handle.chmod(options.mode);\n }\n if (options.fsync) {\n await handle.sync();\n }\n } finally {\n await handle.close();\n }\n } catch (err) {\n await fs.rm(tmpPath, { force: true }).catch(() => {});\n throw err;\n }\n\n await renameOnto(tmpPath, filePath);\n\n if (options.mode !== undefined) {\n // Belt-and-suspenders for the replace case: on every platform this\n // helper supports, the rename above already carried the temp file's\n // mode across verbatim (see point 3 above) — this call is not\n // load-bearing today, but it makes that guarantee independently\n // verifiable by a test (stat the result) rather than an inference from\n // rename's documented semantics.\n await fs.chmod(filePath, options.mode);\n }\n\n if (options.fsync) {\n // fsyncing only the temp file makes its bytes durable, but not the rename\n // that publishes (or clears) a load-bearing marker. Flush the containing\n // directory after every post-rename metadata operation so a successful\n // return means both the file and its directory entry reached storage. The\n // target sync also covers the defensive post-rename chmod above.\n // FlushFileBuffers rejects FILE_GENERIC_READ handles on Windows. `r+`\n // supplies the required GENERIC_WRITE without truncating or modifying the\n // just-published file; POSIX can sync the same file through a read handle.\n const target = await fs.open(filePath, process.platform === 'win32' ? 'r+' : 'r');\n try {\n await target.sync();\n } finally {\n await target.close();\n }\n if (process.platform !== 'win32') {\n const directory = await fs.open(path.dirname(filePath), 'r');\n try {\n await directory.sync();\n } finally {\n await directory.close();\n }\n }\n }\n}\n\n/** Number of `fs.rename` attempts on a win32 `EPERM`/`EEXIST` before giving up (the first attempt plus this many retries). */\nconst RENAME_RETRY_ATTEMPTS = 5;\n/** Base delay between retries, in ms — short because the usual cause (an AV scanner/indexer's transient read handle) clears within milliseconds, not seconds. Backs off linearly (`delay * attempt`) so a handle held slightly longer still has a decent chance without making the caller wait long in the common case. */\nconst RENAME_RETRY_DELAY_MS = 20;\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * `fs.rename(tmpPath, targetPath)` with the win32 retry-on-transient-lock\n * behavior described in {@link atomicWriteFile}'s doc comment (point 4).\n * Split out purely for readability; tests exercise the retry branch\n * indirectly, by mocking `fs.rename` to fail with `EPERM`/`EEXIST` and\n * calling the public `atomicWriteFile` — real POSIX rename never takes this\n * branch itself, only Windows does.\n *\n * Load-bearing invariant: `targetPath` is NEVER unlinked here, under any\n * circumstance, including final failure. The only files this function ever\n * removes are the TEMP file's own leftovers — never the live target. See\n * the module doc comment (point 4) for why an earlier `unlink`-then-rename\n * fallback was actively dangerous and got replaced with this retry loop.\n */\nasync function renameOnto(tmpPath: string, targetPath: string): Promise<void> {\n for (let attempt = 1; attempt <= RENAME_RETRY_ATTEMPTS; attempt++) {\n try {\n await fs.rename(tmpPath, targetPath);\n return;\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== 'EPERM' && code !== 'EEXIST') {\n await fs.rm(tmpPath, { force: true }).catch(() => {});\n throw err;\n }\n if (attempt === RENAME_RETRY_ATTEMPTS) {\n // Every retry still failed — the lock on `targetPath` wasn't\n // transient after all. Clean up only the temp file and throw;\n // `targetPath` is left exactly as it was (the caller's last-good\n // file, not corrupted, not missing) — never unlinked.\n await fs.rm(tmpPath, { force: true }).catch(() => {});\n throw err;\n }\n await delay(RENAME_RETRY_DELAY_MS * attempt);\n }\n }\n}\n","import { execFile } from 'node:child_process';\n\n/**\n * Result of running an external command, regardless of its exit code.\n * `code !== 0` is an ordinary, expected outcome for several callers in this\n * module (e.g. `launchctl bootout` on a service that isn't currently\n * loaded, `systemctl --user is-active` on an inactive unit) — it is NOT\n * treated as a thrown error. See {@link Runner}'s own doc comment for what\n * DOES reject.\n */\nexport interface RunResult {\n code: number;\n stdout: string;\n stderr: string;\n}\n\n/**\n * Runs an external service-manager CLI (`launchctl`, `systemctl`, a\n * WinSW-produced `.exe`, `sc.exe`) and resolves with its exit code +\n * captured stdout/stderr — it deliberately does NOT reject just because the\n * command exited non-zero (see {@link RunResult}'s doc comment: that is\n * everyday signal for several callers here, not failure). It DOES reject\n * for a genuine spawn failure (the executable itself couldn't be found/run\n * at all, e.g. `ENOENT`) — see {@link defaultRunner}'s implementation for\n * how the two are told apart. Callers that need \"ran and returned 0 or\n * throw\" wrap this with {@link runOrThrow}.\n *\n * The DI seam every one of `launchd.ts`/`systemd.ts`/`winsw.ts` accepts\n * (`LaunchdDeps.run`/`SystemdDeps.run`/`WinswDeps.run`) — this is what lets\n * the install/uninstall/start/stop/status logic for all three platforms be\n * unit-tested from any single host OS with a plain mock, per M3-4's own\n * verification requirement, without ever shelling out for real in tests.\n */\nexport type Runner = (command: string, args: string[]) => Promise<RunResult>;\n\n/**\n * Real implementation: `child_process.execFile`, never a shell\n * (`exec`/`shell: true`) — the same reasoning as the pi adapter's own\n * `detect()` (see `templates/packaging/sea/README.md`'s \"Windows note\" and\n * `adapters/pi/pi-adapter.ts`): no shell-quoting hazard for a service name,\n * config path, or WinSW install directory containing spaces or special\n * characters. Every command this module ever invokes (`launchctl`,\n * `systemctl`, a WinSW-produced `.exe`, `sc.exe`) is a genuine native\n * executable, never a `.cmd`/`.bat` shell script, so the one real caveat of\n * `execFile`-without-`shell` on Windows (a `.cmd`/`.bat` target can't be\n * `CreateProcess`'d directly) never applies here.\n *\n * Node's `execFile` callback distinguishes two failure shapes on its error\n * argument: when the target process ran and merely exited non-zero, `error.code`\n * is that NUMERIC exit code; when the executable itself couldn't be spawned\n * (e.g. `ENOENT`), `error.code` is an ERRNO STRING and there is no real exit\n * code at all. This implementation resolves the first case as an ordinary\n * {@link RunResult} (letting callers decide whether a given non-zero exit\n * matters) and rejects only the second (a real inability to run the\n * command at all, which every caller should hear about).\n */\nexport const defaultRunner: Runner = (command, args) =>\n new Promise((resolve, reject) => {\n execFile(command, args, (error, stdout, stderr) => {\n if (error && typeof error.code !== 'number') {\n reject(error);\n return;\n }\n resolve({ code: error ? (error.code as number) : 0, stdout, stderr });\n });\n });\n\n/**\n * Runs `command`/`args` via `run` and throws a clear, labeled error if it\n * exits non-zero — for the subset of calls across launchd/systemd/WinSW\n * that must actually succeed for `install()`/`start()` to honestly report\n * \"the service is now running\" (e.g. `launchctl bootstrap`, `systemctl\n * start`, `winsw install`). Callers that instead want best-effort/tolerant\n * semantics (e.g. \"stop if running, no-op if already stopped\") call `run`\n * directly and ignore the result — see `launchd.ts`/`systemd.ts`/\n * `winsw.ts`'s own `uninstall()`/`stop()` implementations.\n */\nexport async function runOrThrow(run: Runner, command: string, args: string[], label: string): Promise<RunResult> {\n const result = await run(command, args);\n if (result.code !== 0) {\n const detail = (result.stderr || result.stdout).trim();\n throw new Error(`${label} failed (exit ${result.code})${detail ? `: ${detail}` : ''}`);\n }\n return result;\n}\n\n/**\n * Describes what a \"genuinely nothing to do\" outcome looks like for a\n * best-effort stop/uninstall step whose target may legitimately already be\n * absent (not currently loaded/enabled/installed) — as opposed to a genuine\n * failure (permission denied, service busy, a manager fault, the manager\n * itself unreachable) that must NOT be treated the same way. See\n * {@link isIdempotentAbsence}.\n */\nexport interface IdempotentAbsence {\n /** Exit codes that ALONE mean \"already absent\", independent of any stdout/stderr text (e.g. Windows's `ERROR_SERVICE_DOES_NOT_EXIST`, 1060). */\n codes?: readonly number[];\n /** Case-insensitive patterns checked against `stdout + \"\\n\" + stderr`; a match means \"already absent/not loaded/does not exist\" for this platform's tool. */\n patterns: readonly RegExp[];\n /**\n * Case-insensitive patterns checked against the SAME `stdout + \"\\n\" +\n * stderr` text, and consulted BEFORE `codes`/`patterns`: a match here\n * means \"this is a genuine failure\", full stop, even if `codes`/`patterns`\n * would otherwise call the result idempotent absence. Exists because a\n * connectivity/permission/manager-unreachable error can be textually\n * indistinguishable from — or reuse the very same generic OS errno string\n * as — a genuine \"not loaded\"/\"does not exist\" message. Concretely: on a\n * headless host with no reachable `systemd --user` D-Bus session (common\n * for exactly the SSH/no-lingering boxes this daemon runs on),\n * `systemctl --user disable --now` fails with `Failed to connect to bus:\n * No such file or directory` — the SAME \"No such file or directory\" text\n * a genuinely-absent unit can also produce, but here it means \"we could\n * not even ask the manager\", not \"the manager confirms it's gone\".\n * Conflating the two previously let this REAL failure look identical to\n * idempotent absence and then delete the still-relevant plist/unit/exe\n * (cross-model-review P1 #7, round 2 — the same re-orphan shape the\n * original `codes`/`patterns` split was meant to fix in round 1). Each\n * platform module supplies its own `neverAbsence` for the same reason it\n * supplies its own `patterns`/`codes`: the actual wording is tool-specific\n * — see `launchd.ts`/`systemd.ts`/`winsw.ts`'s own constants.\n */\n neverAbsence?: readonly RegExp[];\n}\n\n/**\n * Distinguishes a KNOWN idempotent \"already absent / not loaded / does not\n * exist\" outcome (safe to still proceed with cleanup) from a genuine\n * failure. A non-zero exit is ambiguous on its own: `launchctl bootout`,\n * `systemctl disable --now`, and a WinSW `stop`+`uninstall` all use the SAME\n * non-zero exit for both \"there was nothing to stop/unregister\" (fine, an\n * everyday outcome — see this module's own {@link RunResult} doc comment)\n * and \"I refused/failed to do it\" (not fine) — conflating the two\n * previously let a real failure look identical to success and then delete\n * the plist/unit/exe out from under a still-running service\n * (cross-model-review P1 #7: an orphaned, uncontrollable process). Each\n * platform module supplies its own `patterns`/`codes` because the actual\n * wording/codes are tool-specific — see `launchd.ts`/`systemd.ts`/\n * `winsw.ts`'s own constants.\n *\n * `absence.neverAbsence` is checked FIRST (right after the unambiguous\n * `code === 0` success case) and, on a match, wins outright over any\n * `codes`/`patterns` match — see {@link IdempotentAbsence.neverAbsence}'s\n * own doc comment for why a connectivity/permission/manager-unreachable\n * signal must never be reclassified as absence no matter what else matches\n * (cross-model-review P1 #7, round 2).\n */\nexport function isIdempotentAbsence(result: RunResult, absence: IdempotentAbsence): boolean {\n if (result.code === 0) return true;\n const detail = `${result.stdout}\\n${result.stderr}`;\n if (absence.neverAbsence?.some((pattern) => pattern.test(detail))) return false;\n if (absence.codes?.includes(result.code)) return true;\n return absence.patterns.some((pattern) => pattern.test(detail));\n}\n\n/**\n * Runs `command`/`args` via `run` for a best-effort stop/uninstall step and\n * throws a clear, labeled error UNLESS the result is either a genuine\n * success or a known idempotent \"already absent\" outcome (see\n * {@link isIdempotentAbsence}). Unlike {@link runOrThrow} (which throws on\n * ANY non-zero exit, for calls that must actually succeed), this is the\n * tolerant-but-not-blind form each platform's `uninstall()` needs: proceed\n * to delete the plist/unit/exe+xml ONLY when this resolves without\n * throwing; a thrown error here means \"do NOT delete the control files —\n * surface this to the caller so they can retry\" (see each platform's own\n * `uninstall()`). Each platform's standalone `stop()` uses the same\n * function for the same reason: tolerate \"already stopped/not loaded\", but\n * surface — rather than silently swallow — a genuine failure (permission\n * denied, manager unreachable) instead of misreporting it as \"stopped\"\n * (cross-model-review P1 #7, round 2, second half).\n */\nexport async function runIdempotent(run: Runner, command: string, args: string[], label: string, absence: IdempotentAbsence): Promise<RunResult> {\n const result = await run(command, args);\n if (!isIdempotentAbsence(result, absence)) {\n const detail = (result.stderr || result.stdout).trim();\n throw new Error(`${label} failed (exit ${result.code})${detail ? `: ${detail}` : ''}`);\n }\n return result;\n}\n","import { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport { defaultRunner, type Runner } from '../lifecycle/exec-runner';\n\n/**\n * Finding F7 (cross-model adversarial review): POSIX file MODES\n * (`fs.chmod(dir, 0o700)`) restrict nothing on win32 — Node's `fs.chmod` on\n * Windows only ever toggles the read-only ATTRIBUTE, it never touches the\n * ACL/DACL. Before this fix, `storeDir` (which holds `device.json` — an\n * Ed25519 private key + access token — and `control.token` — the control\n * socket's HMAC secret) was effectively unrestricted-by-this-codebase on\n * Windows despite every `{mode: 0o700}`/`{mode: 0o600}` call site looking\n * identical across platforms; only the OS's own default ACL (typically\n * readable by any local user in the same Users group, depending on parent\n * directory inheritance) applied.\n *\n * `ensureSecureDir` is the ONE chokepoint both `DeviceStore.save()`\n * (`daemon/store.ts`) and `control-server.ts`'s `startControlServer` funnel\n * `storeDir` creation through — the win32 hardening below only needs to\n * exist here, once, rather than being independently (and easily\n * inconsistently) re-added at each call site.\n */\n\n/**\n * Finding R4 (cross-model re-review — F7 residual): the well-known SID for\n * the local `SYSTEM` account (`NT AUTHORITY\\SYSTEM`) — invariant across\n * every Windows locale/edition. See `buildIcaclsArgs`'s own doc comment for\n * why SID form (`*S-...`, icacls's own documented \"prefix with `*`\" syntax)\n * is used here instead of the display name `SYSTEM`.\n */\nconst SYSTEM_SID = '*S-1-5-18';\n/** Finding R4: the well-known SID for the built-in `Administrators` group (`BUILTIN\\Administrators`) — same locale-independence rationale as {@link SYSTEM_SID}. */\nconst ADMINISTRATORS_SID = '*S-1-5-32-544';\n\n/**\n * Pure command-construction seam (finding F7) — kept separate from the\n * actual `icacls` invocation below so it's unit-testable on ANY host OS,\n * not just win32 (this whole SDK is developed on darwin/linux — see\n * `templates/service/winsw/smoke-test.mjs`'s own header comment on the\n * identical constraint for WinSW itself).\n *\n * Removes inherited ACEs (`/inheritance:r`) and grants FULL CONTROL,\n * recursively (`(OI)(CI)F` — Object Inherit, Container Inherit, Full\n * control — so anything created under `dir` afterward inherits the SAME\n * restriction without needing to be re-ACL'd individually) to exactly\n * three principals:\n *\n * - the current user, via `os.userInfo().username` — deliberately NOT the\n * `%USERNAME%` environment variable a hand-typed reference command might\n * use: an env var can be stale, unset, or (in an unusual but real\n * embedding) spoofed by whatever set up this process's environment;\n * querying the OS directly cannot be. This one genuinely has to be a\n * NAME (icacls has no \"current user\" SID shorthand), but it's the\n * account's real name, not a translated built-in label.\n * - `SYSTEM` and `Administrators` — both needed for a Windows-SERVICE\n * topology, where the daemon runs as `SYSTEM` (a WinSW-installed\n * service's default account) while an operator's interactive CLI\n * invocation runs as a normal user against the SAME `storeDir` — see\n * `control-protocol.ts`'s `controlPipeName` doc comment for the\n * identical service-account rationale on the pipe-naming side. Finding\n * R4: referenced by their WELL-KNOWN SIDs ({@link SYSTEM_SID} /\n * {@link ADMINISTRATORS_SID}), not the display names `SYSTEM`/\n * `Administrators` — those two names are LOCALIZED (e.g. a\n * French-language Windows renders the Administrators group as\n * \"Administrateurs\"), so `icacls ... /grant Administrators:...` would\n * silently fail to resolve (and thus fail the whole hardening step) on\n * any non-English install. The SIDs themselves are invariant across\n * every locale/edition; `icacls` accepts SID form directly when prefixed\n * with `*` (its own documented syntax).\n *\n * Returns a plain ARGV array with NO manually-embedded quote characters —\n * this is meant for `child_process.execFile`'s array form (this codebase's\n * own established convention for every external command it ever runs; see\n * `lifecycle/exec-runner.ts`'s `defaultRunner`), which is never a shell and\n * so has no shell-quoting hazard for a `dir`/username containing spaces —\n * Node's own Windows argv encoding (used internally by `execFile`/`spawn`\n * when given an array) already quotes/escapes each element correctly\n * regardless of embedded whitespace. Hand-rolling literal `\"` characters\n * into an array element bound for that API would risk DOUBLE-quoting\n * instead of fixing anything — the icacls reference command sometimes\n * quoted as `\"%USERNAME%\":(OI)(CI)F` is a shell/cmd.exe-level concern that\n * simply does not apply once argv is passed as an array with no shell\n * involved.\n */\nexport function buildIcaclsArgs(dir: string, username: string): string[] {\n return [dir, '/inheritance:r', '/grant:r', `${username}:(OI)(CI)F`, '/grant', `${SYSTEM_SID}:(OI)(CI)F`, '/grant', `${ADMINISTRATORS_SID}:(OI)(CI)F`];\n}\n\n/** Restrictive ACL for one already-created file; no inheritance flags because the target cannot contain children. */\nexport function buildIcaclsFileArgs(filePath: string, username: string): string[] {\n return [\n filePath,\n '/inheritance:r',\n '/grant:r',\n `${username}:F`,\n '/grant',\n `${SYSTEM_SID}:F`,\n '/grant',\n `${ADMINISTRATORS_SID}:F`,\n ];\n}\n\nexport interface EnsureSecureDirOptions {\n /** DI for tests — see `lifecycle/exec-runner.ts`'s identical `Runner` seam. Defaults to `defaultRunner` (real `execFile`, never a shell). */\n run?: Runner;\n /** DI for tests — lets the win32 branch below be exercised (with a fake `run`) from any host OS, mirroring `control-protocol.ts`'s `controlEndpointPath` platform-override convention. Defaults to `process.platform`. */\n platform?: NodeJS.Platform;\n}\n\n/**\n * Finding R4 (cross-model re-review — F7 residual): thrown by\n * {@link ensureSecureDir} on win32 when `icacls` either could not be run at\n * all (e.g. missing binary, or a restricted service account lacking\n * permission to spawn it) or ran and exited non-zero (e.g. it couldn't\n * resolve a principal, or was itself denied). This directory's contents —\n * `device.json` (an Ed25519 private key + access token) or `control.token`\n * (the control socket's HMAC secret) — would otherwise be protected by\n * nothing but the OS's own default ACL, typically readable by any local\n * user; see `docs/security.md`'s own note on why this is now fail-closed\n * rather than a logged-and-ignored warning. See {@link ensureSecureDir}'s\n * own doc comment for how each caller (`DeviceStore.save`,\n * `control-server.ts`'s `startControlServer`) reacts to this.\n */\nexport class SecureDirHardeningError extends Error {\n constructor(\n public readonly dir: string,\n reason: string,\n ) {\n super(\n `failed to apply a restrictive Windows ACL to \"${dir}\": ${reason} — refusing to leave this directory unprotected (it holds device credentials and/or the control-socket token, otherwise readable by any other local user); see docs/security.md`,\n );\n this.name = 'SecureDirHardeningError';\n }\n}\n\nexport class SecureFileHardeningError extends Error {\n constructor(\n public readonly filePath: string,\n reason: string,\n ) {\n super(`failed to apply a restrictive Windows ACL to \"${filePath}\": ${reason}`);\n this.name = 'SecureFileHardeningError';\n }\n}\n\n/**\n * Creates (if needed) and secures `dir`: POSIX `{mode: 0o700}` plus a\n * best-effort `chmod` re-assertion on every platform (unchanged from\n * before this fix — this is what actually restricts access on\n * darwin/linux), PLUS — win32 only — a restrictive DACL via `icacls` (see\n * `buildIcaclsArgs`'s own doc comment for exactly what it grants/removes).\n *\n * Finding R4 (cross-model re-review): the win32 `icacls` step is now\n * FAIL-CLOSED — it used to be best-effort (logged via `console.warn`,\n * never thrown), which meant a host where `icacls` genuinely can't run\n * (missing binary, a locked-down service account) would silently create\n * `storeDir` with NO Windows-side ACL protection at all and carry on as if\n * nothing were wrong. Now it THROWS {@link SecureDirHardeningError}\n * instead, on both failure shapes (the spawn itself failing, or `icacls`\n * running and exiting non-zero). Each real caller already has (or gets,\n * via this fix) an appropriate reaction:\n *\n * - `control-server.ts`'s `startControlServer` calls this as the very\n * FIRST thing, before any socket/pipe exists — a thrown error here\n * propagates out of `startControlServer` with nothing to clean up (no\n * F9-style orphan-listener risk), straight into `create-daemon.ts`'s\n * `start()`'s EXISTING \"any non-`AnotherControlServerRunningError` bind\n * failure degrades non-fatally\" catch block: logs a loud\n * `console.warn` naming the reason (this error's own message) and\n * continues the rest of the daemon WITHOUT a control socket — the\n * correct \"graceful path\" for a control-IPC-layer failure, unchanged\n * code, already exactly right once this function starts throwing.\n * - `DeviceStore.save()` calls this before ever writing `device.json` —\n * a thrown error here propagates directly out of `AuthManager.pair()`\n * (called during `pair()`, before any credential is persisted) as a\n * clear, typed, actionable rejection — pairing simply fails rather than\n * silently leaving an unprotected device keypair/access token on disk.\n *\n * Non-win32 (darwin/linux) behavior is completely unchanged — the POSIX\n * `mkdir`/`chmod` calls above are the only enforcement there, and never\n * throw on their own best-effort `chmod` failure (that one stays\n * genuinely benign — an `EPERM` against a directory this process doesn't\n * own — see the inline comment on it).\n */\nexport async function ensureSecureDir(dir: string, opts: EnsureSecureDirOptions = {}): Promise<void> {\n const platform = opts.platform ?? process.platform;\n const run = opts.run ?? defaultRunner;\n\n await fs.mkdir(dir, { recursive: true, mode: 0o700 });\n await fs.chmod(dir, 0o700).catch(() => {});\n\n if (platform !== 'win32') return;\n\n const { username } = os.userInfo();\n let result: Awaited<ReturnType<Runner>>;\n try {\n result = await run('icacls', buildIcaclsArgs(dir, username));\n } catch (err) {\n throw new SecureDirHardeningError(dir, `could not run icacls: ${err instanceof Error ? err.message : String(err)}`);\n }\n if (result.code !== 0) {\n throw new SecureDirHardeningError(dir, `icacls exited ${result.code}: ${(result.stderr || result.stdout).trim()}`);\n }\n}\n\n/** Re-asserts 0600 on POSIX and a non-inherited owner/SYSTEM/Admin DACL on Windows. */\nexport async function ensureSecureFile(filePath: string, opts: EnsureSecureDirOptions = {}): Promise<void> {\n const platform = opts.platform ?? process.platform;\n const run = opts.run ?? defaultRunner;\n await fs.chmod(filePath, 0o600);\n if (platform !== 'win32') return;\n const { username } = os.userInfo();\n let result: Awaited<ReturnType<Runner>>;\n try {\n result = await run('icacls', buildIcaclsFileArgs(filePath, username));\n } catch (err) {\n throw new SecureFileHardeningError(filePath, `could not run icacls: ${err instanceof Error ? err.message : String(err)}`);\n }\n if (result.code !== 0) {\n throw new SecureFileHardeningError(filePath, `icacls exited ${result.code}: ${(result.stderr || result.stdout).trim()}`);\n }\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { atomicWriteFile } from '../util/atomic-write';\nimport { ensureSecureDir } from '../util/secure-dir';\nimport type { GitErrorCategory, GitWorkspaceObservation } from './git-workspace';\n\nexport type GitWorkspacePhase = 'preparing' | 'active' | 'completed' | 'failed' | 'cancelled' | 'interrupted' | 'salvage';\n\nexport interface GitWorkspaceLedgerRecord {\n workspaceId: string;\n taskId: string;\n workspaceDir: string;\n sessionRef?: string;\n phase: GitWorkspacePhase;\n baseline?: string;\n current?: string;\n commitsSinceBaseline: number;\n staged: number;\n unstaged: number;\n untracked: number;\n conflicted: number;\n createdAt: string;\n updatedAt: string;\n errorCategory?: GitErrorCategory;\n}\n\nexport interface GitWorkspaceLedger {\n version: 1;\n records: GitWorkspaceLedgerRecord[];\n}\n\nconst FILE_NAME = 'git-workspaces.json';\nconst MAX_RECORDS = 500;\nconst PHASES = new Set<GitWorkspacePhase>(['preparing', 'active', 'completed', 'failed', 'cancelled', 'interrupted', 'salvage']);\n\nfunction isRecord(value: unknown): value is GitWorkspaceLedgerRecord {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const candidate = value as Partial<GitWorkspaceLedgerRecord>;\n return typeof candidate.workspaceId === 'string' &&\n typeof candidate.taskId === 'string' &&\n typeof candidate.workspaceDir === 'string' &&\n (candidate.sessionRef === undefined || typeof candidate.sessionRef === 'string') &&\n typeof candidate.phase === 'string' && PHASES.has(candidate.phase as GitWorkspacePhase) &&\n ['commitsSinceBaseline', 'staged', 'unstaged', 'untracked', 'conflicted'].every((key) => typeof candidate[key as keyof GitWorkspaceLedgerRecord] === 'number') &&\n typeof candidate.createdAt === 'string' && typeof candidate.updatedAt === 'string';\n}\n\nfunction isLedger(value: unknown): value is GitWorkspaceLedger {\n return !!value && typeof value === 'object' && !Array.isArray(value) &&\n (value as Partial<GitWorkspaceLedger>).version === 1 &&\n Array.isArray((value as Partial<GitWorkspaceLedger>).records) &&\n (value as Partial<GitWorkspaceLedger>).records!.every(isRecord);\n}\n\nfunction isActive(record: GitWorkspaceLedgerRecord): boolean {\n return record.phase === 'preparing' || record.phase === 'active' || record.phase === 'interrupted';\n}\n\nfunction isProtected(record: GitWorkspaceLedgerRecord): boolean {\n return isActive(record) || record.phase === 'salvage';\n}\n\n/** Private, versioned, serialized recovery ledger for local Git workspaces. */\nexport class GitWorkspaceStore {\n readonly filePath: string;\n private queue: Promise<void> = Promise.resolve();\n private readonly maxRecords: number;\n\n constructor(\n readonly storeDir: string,\n options: { maxRecords?: number } = {},\n ) {\n this.filePath = path.join(storeDir, FILE_NAME);\n this.maxRecords = Math.max(1, Math.floor(options.maxRecords ?? MAX_RECORDS));\n }\n\n async initialize(): Promise<void> {\n await ensureSecureDir(this.storeDir);\n await this.enqueue(async () => { await this.load(); });\n }\n\n async list(): Promise<GitWorkspaceLedgerRecord[]> {\n return this.enqueue(async () => (await this.load()).records.map((record) => ({ ...record })));\n }\n\n async get(workspaceId: string): Promise<GitWorkspaceLedgerRecord | undefined> {\n return this.enqueue(async () => {\n const record = (await this.load()).records.find((entry) => entry.workspaceId === workspaceId);\n return record ? { ...record } : undefined;\n });\n }\n\n async findBySession(sessionRef: string): Promise<GitWorkspaceLedgerRecord | undefined> {\n return this.enqueue(async () => {\n const record = (await this.load()).records.find((entry) => entry.sessionRef === sessionRef);\n return record ? { ...record } : undefined;\n });\n }\n\n async findBySessionAnyPhase(sessionRef: string): Promise<GitWorkspaceLedgerRecord | undefined> {\n return this.enqueue(async () => {\n const record = (await this.load()).records.find((entry) => entry.sessionRef === sessionRef);\n return record ? { ...record } : undefined;\n });\n }\n\n async attachSession(workspaceId: string, sessionRef: string): Promise<void> {\n await this.enqueue(async () => {\n const ledger = await this.load();\n const index = ledger.records.findIndex((entry) => entry.workspaceId === workspaceId);\n if (index < 0) return;\n ledger.records[index] = {\n ...ledger.records[index]!,\n sessionRef,\n updatedAt: new Date().toISOString(),\n };\n await this.save(this.prune(ledger));\n });\n }\n\n async upsert(record: GitWorkspaceLedgerRecord): Promise<void> {\n await this.enqueue(async () => {\n const ledger = await this.load();\n const now = new Date().toISOString();\n const next = { ...record, updatedAt: now };\n const index = ledger.records.findIndex((entry) => entry.workspaceId === record.workspaceId);\n if (index >= 0) ledger.records[index] = next;\n else ledger.records.push({ ...next, createdAt: record.createdAt || now });\n await this.save(this.prune(ledger));\n });\n }\n\n async updateObservation(workspaceId: string, observation: GitWorkspaceObservation, phase?: GitWorkspacePhase, errorCategory?: GitErrorCategory): Promise<void> {\n await this.enqueue(async () => {\n const ledger = await this.load();\n const index = ledger.records.findIndex((entry) => entry.workspaceId === workspaceId);\n if (index < 0) return;\n const record = ledger.records[index]!;\n ledger.records[index] = {\n ...record,\n phase: phase ?? record.phase,\n current: observation.head,\n commitsSinceBaseline: observation.commitsSinceBaseline,\n staged: observation.staged,\n unstaged: observation.unstaged,\n untracked: observation.untracked,\n conflicted: observation.conflicted,\n updatedAt: new Date().toISOString(),\n ...(errorCategory ? { errorCategory } : {}),\n };\n await this.save(this.prune(ledger));\n });\n }\n\n /** Marks old preparation/active records interrupted without reviving protocol tasks. */\n async reconcile(validate?: (record: GitWorkspaceLedgerRecord) => Promise<boolean>): Promise<void> {\n await this.enqueue(async () => {\n const ledger = await this.load();\n let changed = false;\n for (const record of ledger.records) {\n if (!isActive(record)) continue;\n const valid = validate ? await validate(record) : true;\n if (!valid) continue;\n record.phase = 'interrupted';\n record.updatedAt = new Date().toISOString();\n changed = true;\n }\n if (changed) await this.save(this.prune(ledger));\n });\n }\n\n private prune(ledger: GitWorkspaceLedger): GitWorkspaceLedger {\n if (ledger.records.length <= this.maxRecords) return ledger;\n const retained = ledger.records.filter(isProtected);\n const rest = ledger.records.filter((record) => !isProtected(record)).sort((a, b) =>\n b.updatedAt.localeCompare(a.updatedAt) || (a.phase === 'salvage' ? 1 : 0) - (b.phase === 'salvage' ? 1 : 0),\n );\n return { version: 1, records: [...retained, ...rest.slice(0, Math.max(0, this.maxRecords - retained.length))] };\n }\n\n private enqueue<T>(task: () => Promise<T>): Promise<T> {\n const result = this.queue.then(task);\n this.queue = result.then(() => undefined, () => undefined);\n return result;\n }\n\n private async load(): Promise<GitWorkspaceLedger> {\n let raw: string;\n try {\n raw = await fs.readFile(this.filePath, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { version: 1, records: [] };\n throw error;\n }\n let parsed: unknown;\n try { parsed = JSON.parse(raw); } catch { throw new Error('git workspace ledger is corrupt'); }\n if (!isLedger(parsed)) throw new Error('git workspace ledger version is unsupported or invalid');\n return { version: 1, records: parsed.records.map((record) => ({ ...record })) };\n }\n\n private async save(ledger: GitWorkspaceLedger): Promise<void> {\n await ensureSecureDir(this.storeDir);\n await atomicWriteFile(this.filePath, JSON.stringify(ledger, null, 2), { mode: 0o600 });\n }\n}\n\nexport const GIT_WORKSPACE_LEDGER_FILE = FILE_NAME;\nexport const GIT_WORKSPACE_LEDGER_MAX_RECORDS = MAX_RECORDS;\n","import { existsSync, readFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * The pi coding-agent CLI's real npm package name.\n *\n * IMPORTANT (empirically verified 2026-07-16, see the M0-3 report): the name\n * `@mariozechner/pi` — the identifier this task was originally briefed with —\n * is NOT the coding agent. On npm it resolves to an unrelated \"CLI tool for\n * managing vLLM deployments on GPU pods\" (bin: `pi-pods`). The real coding\n * agent was `@mariozechner/pi-coding-agent`, which is now itself deprecated\n * in favor of this package (same maintainers: badlogic, mitsuhiko), as of\n * literally the day before this was written. `package.json` pins the\n * `legacy-node20` dist-tag (0.74.2) rather than `latest` (0.80.7), because\n * `latest` requires Node >=22.19 while this SDK's baseline is Node >=20;\n * both versions were empirically confirmed to speak the identical RPC-mode\n * frame shapes this adapter depends on.\n */\nexport const PI_PACKAGE_NAME = '@earendil-works/pi-coding-agent';\n\nexport interface ResolvedBin {\n command: string;\n source: 'package' | 'path';\n}\n\ninterface MinimalPackageJson {\n name?: string;\n bin?: string | Record<string, string>;\n}\n\nfunction readPackageJson(dir: string): MinimalPackageJson | undefined {\n const candidate = path.join(dir, 'package.json');\n if (!existsSync(candidate)) return undefined;\n try {\n return JSON.parse(readFileSync(candidate, 'utf8')) as MinimalPackageJson;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolve the pi CLI executable. Prefers the optionalDependency installed\n * alongside @byok-sdk/client (guarantees a known-good, version-matched build);\n * falls back to whatever `pi` is on PATH so users with a pre-existing global\n * pi install still work even when the optionalDependency didn't install.\n *\n * `BYOK_PI_BIN` overrides both of the above when set: `PiAdapterOptions.resolveBin`\n * is the injectable seam for in-process tests, but the `byok-agent` CLI bin\n * only ever constructs `new PiAdapter()` with no options (see `createDaemon`),\n * so an out-of-process substitution (e.g. examples/basic's e2e run swapping\n * in the fake-pi fixture ahead of a real pi install) has no other seam to use.\n *\n * Deliberately does NOT use `createRequire(...).resolve()`: this package is\n * pure ESM with no `require` export condition (`exports[\".\"]` only offers\n * `import`), so CJS-style resolution fails outright with\n * `ERR_PACKAGE_PATH_NOT_EXPORTED` — empirically confirmed, not a hypothetical.\n * It also does NOT resolve the `./package.json` subpath directly (also not\n * exported by this package); instead it resolves the package's main entry\n * via `import.meta.resolve` and walks up parent directories to find the\n * package root (identified by a `package.json` whose `name` matches), which\n * is robust to `dist/` layout changes and to whether `./package.json` is\n * ever exported.\n */\nexport function resolvePiBin(): ResolvedBin {\n const override = process.env.BYOK_PI_BIN;\n if (override) {\n return { command: override, source: 'path' };\n }\n try {\n const mainEntryUrl = import.meta.resolve(PI_PACKAGE_NAME);\n let dir = path.dirname(fileURLToPath(mainEntryUrl));\n for (let depth = 0; depth < 6; depth++) {\n const pkg = readPackageJson(dir);\n if (pkg?.name === PI_PACKAGE_NAME) {\n const binRel = typeof pkg.bin === 'string' ? pkg.bin : pkg.bin?.pi;\n if (binRel) {\n return { command: path.join(dir, binRel), source: 'package' };\n }\n break;\n }\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n } catch {\n // optionalDependency not installed, or resolution failed — fall through to PATH.\n }\n return { command: 'pi', source: 'path' };\n}\n","import type { PermissionPolicy } from '@byok-sdk/protocol';\n\nexport interface PiPermissionMapping {\n ok: boolean;\n /** CLI args to append to `pi --mode rpc ...`. Only meaningful when `ok` is true. */\n args: string[];\n /** Present when `ok` is false. */\n reason?: string;\n}\n\n/** pi's own read-only built-ins, per `pi --help`'s documented example: `pi --tools read,grep,find,ls -p ...`. */\nconst READONLY_TOOLS: readonly string[] = ['read', 'grep', 'find', 'ls'];\n\n/**\n * pi's real default active built-in tool set when no `--tools`/`--no-tools`\n * flag is given at all — confirmed against the installed CLI's own source\n * (`defaultActiveToolNames` in `dist/core/sdk.js`, 0.74.2), not inferred.\n * Used only to compute an equivalent `--tools` allowlist for `denyTools`\n * (see the second self-discovered finding in the doc comment below) — a\n * policy with no `allowTools`/`denyTools` at all still emits no args, same\n * as always, so this constant never changes that common-case behavior.\n */\nconst DEFAULT_ACTIVE_TOOLS: readonly string[] = ['read', 'bash', 'edit', 'write'];\n\n/**\n * Map an effective {@link PermissionPolicy} to `pi --mode rpc` CLI args,\n * fail-closed. Empirically grounded (see the M0-3 report):\n *\n * - `auto` / `readonly` are expressible via `--tools` / `--no-tools`.\n * - `confirm` and `plan` are NOT expressible: pi ships no built-in per-call\n * approval gate and explicitly \"skips ... plan mode\" (README); both exist\n * only as example third-party extensions (`examples/extensions/\n * permission-gate.ts`, `examples/extensions/plan-mode/`), which is\n * out-of-scope, speculative surface for M0.\n * - `network: false` is NOT expressible: pi has no network sandbox for its\n * bash tool (\"Pi does not include a built-in sandbox\" — docs/security.md).\n * `network: true` or unset proceeds, since nothing needs enforcing then.\n *\n * Workspace confinement is NOT a pi flag — the caller spawns pi with\n * `cwd: ctx.workspaceDir`, the daemon-created per-task directory.\n *\n * SECOND SELF-DISCOVERED FINDING, same class as the pi-adapter.ts\n * `--session-id` bug (this task, while hardening argv validation):\n * `--exclude-tools` — what `denyTools` used to map to — is ALSO not a real\n * pi CLI flag. Confirmed against real pi 0.74.2: `pi --mode rpc\n * --exclude-tools bash` → `Error: Unknown option: --exclude-tools`, exit\n * code 1, before any model call — and it's absent from both `pi --help`'s\n * own listing and the CLI's actual arg parser (`dist/cli/args.js`), which\n * recognizes only `--tools`/`-t`, `--no-tools`/`-nt`, `--no-builtin-tools`/\n * `-nbt` for tool control. This crashed EVERY real pi invocation for any\n * policy with a non-empty `denyTools`, unconditionally — never caught by\n * this repo's own test suite for the exact same reason as the\n * `--session-id` bug (`fake-pi.mjs` never validated argv; fixed alongside\n * this change). pi has no \"start from the default set, minus these\" flag at\n * all — `--tools` always REPLACES the active set wholesale — so `denyTools`\n * is now resolved to an equivalent allowlist in-process: readonly mode\n * intersects with `READONLY_TOOLS` (as before), any other mode starts from\n * an explicit `allowTools` or pi's own `DEFAULT_ACTIVE_TOOLS`, and\n * `denyTools` is subtracted from that resolved set before it's ever handed\n * to pi as a single `--tools`/`--no-tools` pair of args.\n */\nexport function mapPermissionPolicyToPiArgs(policy: PermissionPolicy): PiPermissionMapping {\n if (policy.network === false) {\n return {\n ok: false,\n args: [],\n reason: 'policy requires network:false, which the pi adapter cannot enforce (pi has no network sandbox)',\n };\n }\n\n if (policy.mode === 'confirm' || policy.mode === 'plan') {\n return {\n ok: false,\n args: [],\n reason: `pi adapter cannot express permission mode \"${policy.mode}\" (no built-in per-call approval gate or plan-only mode without a custom extension)`,\n };\n }\n\n const denyTools = policy.denyTools ?? [];\n\n if (policy.mode === 'readonly') {\n const base = policy.allowTools ? policy.allowTools.filter((tool) => READONLY_TOOLS.includes(tool)) : [...READONLY_TOOLS];\n const effective = subtractDenied(base, denyTools);\n // Never fall through to an absent `--tools` flag here — that would run\n // pi's full default toolset, silently widening a readonly request.\n return { ok: true, args: effective.length === 0 ? ['--no-tools'] : ['--tools', effective.join(',')] };\n }\n\n if (denyTools.length > 0) {\n const base = policy.allowTools && policy.allowTools.length > 0 ? policy.allowTools : [...DEFAULT_ACTIVE_TOOLS];\n const effective = subtractDenied(base, denyTools);\n // Same reasoning as readonly above: an empty result must be an explicit\n // `--no-tools`, never a silently-widening absent flag.\n return { ok: true, args: effective.length === 0 ? ['--no-tools'] : ['--tools', effective.join(',')] };\n }\n\n if (policy.allowTools && policy.allowTools.length > 0) {\n return { ok: true, args: ['--tools', policy.allowTools.join(',')] };\n }\n\n return { ok: true, args: [] };\n}\n\nfunction subtractDenied(tools: readonly string[], denyTools: readonly string[]): string[] {\n const denied = new Set(denyTools);\n return tools.filter((tool) => !denied.has(tool));\n}\n","import type { AgentEvent } from '@byok-sdk/protocol';\nimport type { PiRpcMessage } from './rpc-client';\n\n/**\n * ROOT CAUSE of the 2026-07-16 live GLM run's \"finding #2\" hang (task stuck\n * `Running` forever after pi streamed its final answer; pi process alive,\n * idle, no sockets, only stdio pipes): this mapper used to listen for a pi\n * event type `agent_settled` to know a whole run had finished. That type\n * does not exist anywhere in the real, installed\n * `@earendil-works/pi-coding-agent@0.74.2` package — not in its bundled\n * `docs/rpc.md`, not in `dist/modes/rpc/rpc-types.d.ts`, not in\n * `pi-agent-core`'s own `AgentEvent` union (`dist/types.d.ts`), and not\n * observed even once across live probes against real GLM traffic (raw JSONL\n * frame capture). The real \"whole run is done, pi is idle again\" signal is\n * `agent_end` — confirmed both by `pi-agent-core`'s own doc comment (\"\n * `agent_end` is the last event emitted for a run... The agent becomes idle\n * only after those listeners finish\") and empirically: a live run's frame\n * sequence ended `...turn_end (tool call), ..., turn_end (final text),\n * agent_end` with nothing further arriving even after an 8s idle-grace\n * window. Because this switch had no `agent_end` case, it fell to\n * `default: return undefined` — silently dropped — so `task-runner.ts`'s\n * `pump()` loop never saw a `turn_end` `AgentEvent` and blocked forever on\n * the next one. This repo's own fixture (`fake-pi.mjs`) masked the bug for\n * the whole M0/M1 test suite by emitting a fictional `agent_settled` frame\n * of its own alongside the real `agent_end` one — fixed alongside this\n * change (see fake-pi.mjs's doc comment).\n *\n * `agent_end` (not pi's own per-LLM-turn `turn_end`) is what maps to our\n * `turn_end`: a single pi prompt can produce several internal turns (tool\n * round-trips, each ending its own real `turn_end`); only once the whole\n * run is settled (no auto-retry, compaction-retry, or queued continuation\n * left) is the task actually done. Forwarding pi's own `turn_end` 1:1 would\n * emit multiple confusing `turn_end`s for what the daemon must treat as one\n * task — empirically confirmed: a single-tool-call prompt produced two real\n * `turn_end` frames (one after the tool call, one after the final text) and\n * exactly one `agent_end`.\n *\n * Returns undefined for pi messages with no protocol equivalent (session/\n * compaction/retry bookkeeping — see `ROUTINE_PI_EVENT_TYPES` below —\n * extension UI dialogs, which never reach here at all in production since\n * `PiRpcClient` answers them itself before they'd ever be queued as an\n * event; see rpc-client.ts).\n */\nexport function mapPiMessageToAgentEvent(msg: PiRpcMessage): AgentEvent | undefined {\n switch (msg.type) {\n case 'message_update': {\n const delta = msg.assistantMessageEvent as { type?: string; delta?: string } | undefined;\n if (delta?.type === 'text_delta' && typeof delta.delta === 'string') {\n return { type: 'progress', text: delta.delta };\n }\n return undefined;\n }\n\n case 'tool_execution_start': {\n if (typeof msg.toolName !== 'string') return undefined;\n return { type: 'tool_use', tool: msg.toolName, input: msg.args };\n }\n\n case 'tool_execution_end': {\n if (typeof msg.toolName !== 'string') return undefined;\n return {\n type: 'tool_result',\n tool: msg.toolName,\n output: { result: msg.result, isError: msg.isError === true },\n };\n }\n\n case 'agent_end':\n return { type: 'turn_end' };\n\n /**\n * `artifact` is NOT a real pi RPC message — pi's own `write` tool only\n * ever surfaces as `tool_execution_start`/`tool_execution_end` (see\n * `docs/tools/write.js` in the installed package), and neither carries\n * enough on its own at the `_end` message (no `path`) for this stateless,\n * one-message-at-a-time mapper to correlate back to a written file\n * without introducing per-toolCallId state. This case exists purely so\n * the `fake-pi.mjs` test/e2e fixture (M1-4 blob-path acceptance run) has\n * a way to simulate \"the runtime wrote a file and is reporting it as an\n * artifact\" — real pi emits nothing today that reaches this branch, so\n * production traffic through this adapter never takes it. Revisit if a\n * future pi release adds a native artifact-producing message, or if this\n * needs correlating to a real `write` tool call.\n */\n case 'artifact': {\n if (typeof msg.name !== 'string' || typeof msg.contentType !== 'string') return undefined;\n return { type: 'artifact', name: msg.name, contentType: msg.contentType };\n }\n\n case 'extension_error':\n return { type: 'error', message: typeof msg.error === 'string' ? msg.error : 'pi extension error' };\n\n case 'auto_retry_end':\n if (msg.success === false) {\n return {\n type: 'error',\n message: typeof msg.finalError === 'string' ? msg.finalError : 'pi auto-retry exhausted',\n };\n }\n return undefined;\n\n // Routine pi session/turn/streaming bookkeeping with no `AgentEvent`\n // equivalent — see `ROUTINE_PI_EVENT_TYPES` below, which mirrors this\n // list so `PiSession`'s unmapped-frame accounting (rpc-client.ts's\n // `recordUnmappedFrame`) can tell \"known, expected, silently ignored\"\n // apart from \"genuinely never seen before\" (falls to `default` below).\n case 'agent_start':\n case 'turn_start':\n case 'turn_end': // pi's own per-LLM-turn boundary, not ours — see `agent_end` above\n case 'message_start':\n case 'message_end':\n case 'tool_execution_update':\n case 'queue_update':\n case 'compaction_start':\n case 'compaction_end':\n case 'auto_retry_start':\n case 'session_info_changed':\n case 'thinking_level_changed':\n return undefined;\n\n default:\n return undefined;\n }\n}\n\n/**\n * Pi RPC message types that are routine, expected, and deliberately have no\n * `AgentEvent` equivalent (kept in sync with the switch cases above sharing\n * this comment). Used only for observability: `PiSession`'s event iterator\n * (pi-adapter.ts) calls `PiRpcClient.recordUnmappedFrame` for any message\n * type that maps to `undefined` AND isn't in this set — i.e. traffic nobody\n * has ever told this adapter to expect. That distinction is what makes a\n * regression like this file's root-cause bug (`agent_end` going unhandled)\n * self-diagnosing: a warning fires the first time the new/renamed settle\n * event shows up, instead of the daemon just quietly hanging. `default`-only\n * unknowns (a type not listed in the switch at all) are equally \"not\n * routine\" and get flagged the same way — this set exists so *routine*\n * traffic doesn't also trip that alarm on every single task.\n */\nexport const ROUTINE_PI_EVENT_TYPES: ReadonlySet<string> = new Set([\n 'agent_start',\n 'turn_start',\n 'turn_end',\n 'message_start',\n 'message_end',\n 'tool_execution_update',\n 'queue_update',\n 'compaction_start',\n 'compaction_end',\n 'auto_retry_start',\n 'session_info_changed',\n 'thinking_level_changed',\n]);\n","/**\n * A minimal push/pull async queue: producers call `push`/`end`, consumers\n * `for await` over the queue itself. Shared by the pi RPC client's event\n * stream, the claude/codex adapters' own event streams, and test fixtures\n * (stub sessions) so all of them get the same order-preserving semantics\n * without duplicating it.\n *\n * M4 hardening: this used to be genuinely back-pressure-free — an unbounded\n * internal `buffered` array, so a producer that outpaces its consumer (a\n * runaway/misbehaving runtime adapter, or simply nobody ever reading\n * `session.events`) could grow it without limit. Bounded now: `capacity`\n * (default {@link DEFAULT_ASYNC_QUEUE_CAPACITY}) caps how many items may sit\n * in `buffered` unconsumed. On overflow this fails fast rather than either of\n * the two worse alternatives — silently dropping the newest/oldest event (a\n * consumer would never know its view of the stream has a hole in it) or\n * blocking `push()` (every producer in this codebase calls `push()`\n * synchronously from an I/O callback; blocking there would stall reading the\n * underlying process/socket entirely). Instead, once `capacity` is exceeded,\n * the queue transitions into a permanent error state: every pending and\n * future consumer `next()` call rejects with an {@link AsyncQueueOverflowError}\n * naming the capacity, and all further `push()` calls are silently ignored\n * (mirrors the pre-existing `ended` no-op precedent — once terminal, always\n * terminal). The error state is checked before `ended`, so it wins even if\n * `end()` is called afterward — a caller must learn the stream broke, not\n * see a quiet, ordinary completion.\n */\nexport class AsyncQueueOverflowError extends Error {\n constructor(public readonly capacity: number) {\n super(\n `AsyncQueue exceeded its capacity of ${capacity} buffered item(s) — failing fast rather than growing unbounded, silently dropping events, or blocking push()`,\n );\n this.name = 'AsyncQueueOverflowError';\n }\n}\n\n/** Default `capacity` (see {@link AsyncQueue}'s own doc comment) when the constructor isn't given one — generous for every producer in this codebase (adapter event streams a consumer reads turn-by-turn), while still catching a genuinely runaway/unconsumed stream instead of growing forever. */\nexport const DEFAULT_ASYNC_QUEUE_CAPACITY = 10_000;\n\ninterface QueueWaiter<T> {\n resolve: (result: IteratorResult<T>) => void;\n reject: (err: Error) => void;\n}\n\nexport class AsyncQueue<T> implements AsyncIterable<T> {\n private readonly buffered: T[] = [];\n private readonly waiters: QueueWaiter<T>[] = [];\n private ended = false;\n private failure: Error | undefined;\n\n constructor(private readonly capacity: number = DEFAULT_ASYNC_QUEUE_CAPACITY) {}\n\n push(item: T): void {\n if (this.ended || this.failure) return;\n const waiter = this.waiters.shift();\n if (waiter) {\n // Handed directly to an already-waiting consumer — never touches\n // `buffered`, so this path can never itself cause an overflow.\n waiter.resolve({ value: item, done: false });\n return;\n }\n if (this.buffered.length >= this.capacity) {\n this.fail(new AsyncQueueOverflowError(this.capacity));\n return;\n }\n this.buffered.push(item);\n }\n\n end(): void {\n if (this.ended || this.failure) return;\n this.ended = true;\n for (const waiter of this.waiters.splice(0)) {\n waiter.resolve({ value: undefined as never, done: true });\n }\n }\n\n /** Transitions the queue into its permanent overflow state: rejects every currently-pending waiter and, from then on, every `next()` call (checked ahead of `ended` — see the class doc comment on why the error must win). */\n private fail(error: Error): void {\n if (this.ended || this.failure) return;\n this.failure = error;\n for (const waiter of this.waiters.splice(0)) {\n waiter.reject(error);\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<T> {\n return {\n next: (): Promise<IteratorResult<T>> => {\n if (this.failure) {\n return Promise.reject(this.failure);\n }\n if (this.buffered.length > 0) {\n return Promise.resolve({ value: this.buffered.shift() as T, done: false });\n }\n if (this.ended) {\n return Promise.resolve({ value: undefined as never, done: true });\n }\n return new Promise((resolve, reject) => this.waiters.push({ resolve, reject }));\n },\n };\n }\n}\n","import { spawn, spawnSync, type ChildProcessWithoutNullStreams } from 'node:child_process';\nimport { AsyncQueue } from '../../util/async-queue';\n\nexport type SpawnFn = typeof spawn;\n\n/**\n * A pi RPC-mode message: either a `{type:\"response\", id, success, ...}` reply\n * to a command we sent, or an unsolicited event/extension-UI-request. Field\n * shapes vary by `type` (see docs.md / this task's live probes), so this\n * stays a loose bag rather than a full discriminated union — M0 only needs\n * a handful of fields off of each.\n */\nexport interface PiRpcMessage {\n type: string;\n id?: string;\n [key: string]: unknown;\n}\n\nexport interface PiRpcClientOptions {\n command: string;\n args: string[];\n cwd: string;\n env: NodeJS.ProcessEnv;\n spawnFn?: SpawnFn;\n}\n\n/** Bound on retained stderr lines (see `onStderr`/`buildExitError`) — enough to show a real crash reason without an unbounded footprint for a long-lived process that's merely chatty on stderr. */\nconst STDERR_RING_CAPACITY = 20;\n\n/**\n * pi's 4 blocking \"dialog\" extension-UI methods (rpc.md's \"Extension UI\n * Protocol\": `select`/`confirm`/`input`/`editor` emit an\n * `extension_ui_request` and BLOCK pi's whole run until a matching\n * `extension_ui_response` arrives). The other 5 methods\n * (`notify`/`setStatus`/`setWidget`/`setTitle`/`set_editor_text`) are\n * fire-and-forget and must never get a reply (rpc.md: \"Responses are sent\n * for dialog methods only\") — see `respondToExtensionUiRequest`.\n */\nconst DIALOG_UI_METHODS = new Set(['select', 'confirm', 'input', 'editor']);\n\n/**\n * JSONL request/response + event-stream client for `pi --mode rpc`.\n *\n * Framing per pi's own docs/rpc.md: strict JSONL, LF (`\\n`) as the only\n * record delimiter (a trailing `\\r` is stripped; this deliberately does NOT\n * use `node:readline`, which pi's docs call out as non-compliant because it\n * also splits on U+2028/U+2029 — valid inside JSON strings).\n *\n * Responses are correlated by `id`, never by arrival order: empirically,\n * pi's responses do not preserve request order (an immediate parse-failure\n * response can overtake a slower in-flight command's response).\n */\nexport class PiRpcClient {\n private readonly child: ChildProcessWithoutNullStreams;\n private buffer = '';\n private nextId = 1;\n private readonly pending = new Map<\n string,\n { resolve: (msg: PiRpcMessage) => void; reject: (err: Error) => void }\n >();\n private readonly eventQueue = new AsyncQueue<PiRpcMessage>();\n private closed = false;\n private exitError: Error | undefined;\n /** Bounded tail of recent stderr lines — pi discarded this entirely before (nothing ever read `child.stderr`), which is exactly why finding #1 (`Error: Unknown option: --session-id`, exit 1) had to be root-caused by hand instead of reading it off a thrown error. See `buildExitError`. */\n private readonly stderrRing: string[] = [];\n /** Count of pi RPC message types `PiSession` (pi-adapter.ts) has told us have no `AgentEvent` mapping and aren't routine bookkeeping — see `recordUnmappedFrame`. */\n private readonly unmappedFrameCounts = new Map<string, number>();\n\n constructor(options: PiRpcClientOptions) {\n const spawnFn = options.spawnFn ?? spawn;\n this.child = spawnFn(options.command, options.args, {\n cwd: options.cwd,\n env: options.env,\n stdio: ['pipe', 'pipe', 'pipe'],\n }) as ChildProcessWithoutNullStreams;\n\n this.child.stdout.setEncoding('utf8');\n this.child.stdout.on('data', (chunk: string) => this.onData(chunk));\n\n this.child.stderr.setEncoding('utf8');\n this.child.stderr.on('data', (chunk: string) => this.onStderr(chunk));\n\n // `close` (not `exit`): `exit` can fire before stdio streams finish\n // flushing, which matters a lot for finding #1's \"instant exit\" shape —\n // `close` is Node's guarantee that every stdout/stderr byte the process\n // ever wrote has already been delivered to our listeners, so the error\n // built below always has the complete stderr tail, not a truncated one.\n this.child.on('close', (code, signal) => {\n this.onClosed(this.buildExitError(code, signal));\n });\n this.child.on('error', (err) => {\n this.onClosed(err);\n });\n }\n\n /** Send a command, resolved with its correlated `response` message. */\n send(command: Record<string, unknown> & { type: string; id?: string }): Promise<PiRpcMessage> {\n if (this.closed) {\n return Promise.reject(this.exitError ?? new Error('pi process is closed'));\n }\n const id = command.id ?? `req-${this.nextId++}`;\n const full = { ...command, id };\n return new Promise((resolve, reject) => {\n this.pending.set(id, { resolve, reject });\n this.child.stdin.write(`${JSON.stringify(full)}\\n`, (err) => {\n if (err) {\n this.pending.delete(id);\n reject(err);\n }\n });\n });\n }\n\n /** Every non-response, non-`extension_ui_request` line — the latter is answered directly by this client (see `respondToExtensionUiRequest`) and never enqueued. */\n get events(): AsyncIterable<PiRpcMessage> {\n return this.eventQueue;\n }\n\n /**\n * Record a pi RPC message `type` that `PiSession` (pi-adapter.ts) decided\n * has no `AgentEvent` mapping and isn't routine bookkeeping (see\n * `events.ts`'s `ROUTINE_PI_EVENT_TYPES`) — i.e. genuinely unexpected\n * traffic. Logs once per distinct type (not per occurrence, so a\n * repeating unmapped type can't spam stdout); the running tally is also\n * folded into this client's exit-time error message (`buildExitError`) so\n * a post-mortem on a failed/hung task has it without needing separate log\n * scraping. This is the exact mechanism that would have turned this\n * task's root-cause hang (`agent_end` arriving with no mapping) into a\n * one-line, immediate warning instead of a silent stall.\n */\n recordUnmappedFrame(type: string): void {\n const next = (this.unmappedFrameCounts.get(type) ?? 0) + 1;\n this.unmappedFrameCounts.set(type, next);\n if (next === 1) {\n console.warn(\n `[byok/pi-adapter] pi emitted a frame type with no AgentEvent mapping: \"${type}\" (further occurrences of this type won't be logged individually)`,\n );\n }\n }\n\n /** Best-effort teardown. SIGTERM on POSIX; `taskkill /T /F` on Windows to also reap child processes pi itself spawned (e.g. bash). */\n kill(): void {\n if (this.closed) return;\n const pid = this.child.pid;\n if (process.platform === 'win32' && pid !== undefined) {\n spawnSync('taskkill', ['/pid', String(pid), '/T', '/F']);\n } else {\n this.child.kill('SIGTERM');\n }\n }\n\n private onData(chunk: string): void {\n this.buffer += chunk;\n let newlineIndex = this.buffer.indexOf('\\n');\n while (newlineIndex !== -1) {\n let line = this.buffer.slice(0, newlineIndex);\n this.buffer = this.buffer.slice(newlineIndex + 1);\n if (line.endsWith('\\r')) line = line.slice(0, -1);\n if (line.length > 0) this.onLine(line);\n newlineIndex = this.buffer.indexOf('\\n');\n }\n }\n\n private onLine(line: string): void {\n let msg: PiRpcMessage;\n try {\n msg = JSON.parse(line) as PiRpcMessage;\n } catch {\n return; // a stray non-JSON line is not this client's concern\n }\n if (msg.type === 'response' && typeof msg.id === 'string' && this.pending.has(msg.id)) {\n const waiter = this.pending.get(msg.id);\n this.pending.delete(msg.id);\n waiter?.resolve(msg);\n return;\n }\n if (msg.type === 'extension_ui_request' && typeof msg.id === 'string' && typeof msg.method === 'string') {\n // Answered here, not enqueued — see `respondToExtensionUiRequest`. If\n // left unanswered this blocks pi's entire run exactly like the\n // agent_end/agent_settled root-cause bug does (process alive, idle,\n // waiting on stdin forever) — this was the task's leading hypothesis\n // for finding #2 before the live-frame capture pinned the actual\n // cause on the settle-event mismatch; handled regardless, since it's a\n // real, documented way for a future extension/skill to hang a task.\n this.respondToExtensionUiRequest(msg.id, msg.method);\n return;\n }\n this.eventQueue.push(msg);\n }\n\n /**\n * Answer pi's extension-UI blocking protocol headlessly (rpc.md's\n * \"Extension UI Protocol\"). Fail-closed policy, stated explicitly because\n * it's a security-relevant default, not an incidental one: this NEVER\n * approves or picks a value on the caller's behalf — every dialog method\n * (`select`/`confirm`/`input`/`editor`) gets `{cancelled: true}`, the one\n * response shape rpc.md documents as valid for all four uniformly\n * (\"Dismiss any dialog method... the extension receives `undefined` (for\n * select/input/editor) or `false` (for confirm)\"). An extension asking\n * e.g. `confirm(\"Delete everything?\")` gets a firm decline, never a\n * guessed approval — this adapter has no human in the loop to ask, and\n * silently approving would defeat any extension that uses these dialogs\n * specifically as a permission gate. Fire-and-forget methods\n * (`notify`/`setStatus`/`setWidget`/`setTitle`/`set_editor_text`) get no\n * reply at all — sending one would itself violate rpc.md (\"Responses are\n * sent for dialog methods only\").\n */\n private respondToExtensionUiRequest(id: string, method: string): void {\n if (!DIALOG_UI_METHODS.has(method)) return; // fire-and-forget — no response expected or sent\n this.child.stdin.write(`${JSON.stringify({ type: 'extension_ui_response', id, cancelled: true })}\\n`);\n }\n\n private onStderr(chunk: string): void {\n for (const rawLine of chunk.split('\\n')) {\n const line = rawLine.trim();\n if (line.length === 0) continue;\n this.stderrRing.push(line);\n if (this.stderrRing.length > STDERR_RING_CAPACITY) this.stderrRing.shift();\n }\n }\n\n /**\n * finding #1 (\"bad flag → instant exit\", e.g. the `--session-id`/\n * `--exclude-tools` bugs this task fixes): the daemon used to report only\n * `pi process exited (code=1, signal=null)` — accurate but useless for\n * diagnosing *why* without re-running pi by hand with a raw JSONL logger,\n * exactly as this task's own root-cause investigation had to. Folding in\n * the stderr tail and any unmapped-frame tally makes that self-diagnosing\n * from the thrown error alone.\n */\n private buildExitError(code: number | null, signal: NodeJS.Signals | null): Error {\n const parts = [`pi process exited (code=${code}, signal=${signal})`];\n if (this.stderrRing.length > 0) {\n parts.push(`stderr: ${this.stderrRing.join(' | ')}`);\n }\n if (this.unmappedFrameCounts.size > 0) {\n const summary = [...this.unmappedFrameCounts.entries()].map(([type, count]) => `${type}×${count}`).join(', ');\n parts.push(`unmapped frame types seen: ${summary}`);\n }\n return new Error(parts.join('; '));\n }\n\n private onClosed(err: Error): void {\n if (this.closed) return;\n this.closed = true;\n this.exitError = err;\n for (const [, waiter] of this.pending) waiter.reject(err);\n this.pending.clear();\n this.eventQueue.end();\n }\n}\n","import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport type { AgentEvent, TaskOfferPayload } from '@byok-sdk/protocol';\nimport {\n PolicyUnsupportedError,\n type RuntimeAdapter,\n type RuntimeCapabilities,\n type RuntimeDetectResult,\n type RuntimeEnvironmentRequirements,\n type Session,\n type TaskContext,\n} from '../../types';\nimport { resolvePiBin, type ResolvedBin } from './resolve-bin';\nimport { mapPermissionPolicyToPiArgs } from './permission-mapping';\nimport { mapPiMessageToAgentEvent, ROUTINE_PI_EVENT_TYPES } from './events';\nimport { PiRpcClient, type PiRpcMessage, type SpawnFn } from './rpc-client';\n\nconst execFileAsync = promisify(execFile);\nconst DETECT_TIMEOUT_MS = 5_000;\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * Known provider credential env var *names* (never values) — see the\n * credential-isolation rule on `RuntimeAdapter`. `detect()` only checks\n * whether one of these names is set; it never reads pi's own auth storage\n * (`~/.pi/...`) or any file contents. Not exhaustive (pi supports ~30\n * providers); covers the common ones for a useful `authPresent` signal.\n */\nconst KNOWN_PROVIDER_ENV_VARS = [\n 'ANTHROPIC_API_KEY',\n 'ANTHROPIC_OAUTH_TOKEN',\n 'OPENAI_API_KEY',\n 'GEMINI_API_KEY',\n 'AZURE_OPENAI_API_KEY',\n 'DEEPSEEK_API_KEY',\n 'GROQ_API_KEY',\n 'MISTRAL_API_KEY',\n 'OPENROUTER_API_KEY',\n 'XAI_API_KEY',\n // Confirmed against the installed pi's own docs/providers.md (\"ZAI |\n // `ZAI_API_KEY` | `zai`\") and exercised live against real GLM traffic\n // during this task's acceptance run — omitting it made `authPresent`\n // silently false for a perfectly valid, working z.ai/GLM setup.\n 'ZAI_API_KEY',\n] as const;\n\nexport interface PiAdapterOptions {\n /** Override bin resolution — tests substitute the fake-pi fixture script. */\n resolveBin?: () => ResolvedBin;\n /** Override process spawning — tests substitute a fake spawn. */\n spawnFn?: SpawnFn;\n}\n\nexport class PiAdapter implements RuntimeAdapter {\n readonly id = 'pi';\n\n constructor(private readonly options: PiAdapterOptions = {}) {}\n\n async detect(): Promise<RuntimeDetectResult> {\n const bin = this.resolveBin();\n try {\n // Empirically, pi (0.74.2 and 0.80.7) prints `--version` output to\n // STDERR, not stdout — confirmed with an explicit stdout/stderr probe,\n // not assumed. Check both so this doesn't silently regress if a future\n // pi release moves it back to stdout.\n const { stdout, stderr } = await execFileAsync(bin.command, ['--version'], { timeout: DETECT_TIMEOUT_MS });\n const version = stdout.trim() || stderr.trim();\n const authPresent = KNOWN_PROVIDER_ENV_VARS.some((name) => process.env[name] !== undefined);\n return { present: true, version, authPresent };\n } catch {\n return { present: false };\n }\n }\n\n capabilities(): RuntimeCapabilities {\n // `approvalInteractive: false` — `PiSession.resolveApproval` throws\n // unconditionally: pi has no `needs_approval` notion to resume from.\n return { steer: true, resume: true, approvalInteractive: false, permissionModes: ['auto', 'readonly'] };\n }\n\n /**\n * M5: pi authenticates to its ~30 supported providers via env-var API\n * keys — `detect()`'s own `authPresent` probe above checks this identical\n * list — so these MUST keep flowing into pi's spawned process or pi auth\n * breaks entirely. `KNOWN_PROVIDER_ENV_VARS` above is the single source\n * of truth, reused here rather than duplicated. No `baseNames`: nothing\n * in this adapter or `rpc-client.ts` reads a pi-specific config-discovery\n * variable beyond the platform baseline (`daemon/environment.ts`).\n */\n environmentRequirements(): RuntimeEnvironmentRequirements {\n return { credentialNames: KNOWN_PROVIDER_ENV_VARS };\n }\n\n async start(task: TaskOfferPayload, ctx: TaskContext): Promise<Session> {\n if (typeof task.instruction !== 'string') {\n throw new PolicyUnsupportedError('pi adapter only supports string instructions in M0 (no blob-ref fetch yet)');\n }\n\n const mapping = mapPermissionPolicyToPiArgs(ctx.policy);\n if (!mapping.ok) {\n throw new PolicyUnsupportedError(mapping.reason ?? 'policy rejected by pi adapter');\n }\n\n const bin = this.resolveBin();\n // BLOCKING BUG FOUND + FIXED DURING THE 2026-07-16 LIVE pi x GLM e2e run:\n // this used to pass `--session-id <ref>` to `pi --mode rpc`, but that flag\n // does not exist on the real installed pi CLI (confirmed against both\n // `pi --help` and the package's own bundled `docs/rpc.md` for 0.74.2 —\n // only `--session <path|id>` (resume-only, errors \"No session found...\"\n // for a fresh/unknown id), `--session-dir`, `--no-session`, `--continue`,\n // `--resume` exist). It crashed EVERY real pi invocation unconditionally\n // (`Error: Unknown option: --session-id`, exit code 1) before reaching any\n // model call — never caught by this repo's own test suite because\n // `fake-pi.mjs` never inspected argv beyond `--version` (now fixed\n // alongside this task — see fake-pi.mjs). Not GLM/z.ai specific; this\n // broke 100% of real-pi task dispatch for any provider.\n //\n // Finding #3 (session/workspace continuity) follow-up, now implemented:\n // `task.sessionRef` is only ever non-empty here when `task-runner.ts`\n // has (a) found a recorded workspace for this exact sessionRef in its\n // `SessionWorkspaceStore` and (b) spawned this adapter with\n // `ctx.workspaceDir` set to that SAME directory — see task-runner.ts's\n // `handleOffer`. That matters because pi's real `--session <id>` resume\n // is scoped to the cwd/project a session was created under: resuming\n // from a *different* cwd prompts an interactive \"Session found in\n // different project: ... Fork this session into current directory?\n // [y/N]\" pi cannot answer headlessly, and resuming an id pi never\n // minted fails outright (`No session found matching '<id>'`, exit 1 —\n // empirically confirmed against real pi, both live-probed during this\n // task). An absent `sessionRef` always means \"start fresh\" — pi mints\n // its own session id, which this adapter reads back via `get_state`\n // below and reports as `Session.sessionRef` so a *future* follow-up can\n // resume it. `TaskOfferPayload.workspaceHint` remains unimplemented (no\n // caller populates `DispatchInput` with it yet, and its intended\n // semantics — e.g. does it override or merely suggest a workspace\n // relative to the sessionRef mapping? — are still undesigned; see\n // docs/protocol.md §2's note on this field for the explicit\n // reserved/ignored status); a real implementation is a genuine\n // follow-on design task, not a mechanical fix, and is intentionally\n // left alone here.\n const resumeSessionId = task.sessionRef;\n const args = ['--mode', 'rpc', ...(resumeSessionId ? ['--session', resumeSessionId] : []), ...mapping.args];\n\n const rpc = new PiRpcClient({\n command: bin.command,\n args,\n cwd: ctx.workspaceDir,\n env: ctx.env,\n spawnFn: this.options.spawnFn,\n });\n\n const response = await rpc.send({ type: 'prompt', message: task.instruction });\n if (response.success === false) {\n rpc.kill();\n throw new Error(typeof response.error === 'string' ? response.error : 'pi rejected the initial prompt');\n }\n\n let sessionRef: string;\n if (resumeSessionId) {\n sessionRef = resumeSessionId;\n } else {\n try {\n sessionRef = await resolveFreshSessionId(rpc);\n } catch (err) {\n // Finding F8: fail closed, not a fabricated id — and don't leak the\n // process this adapter just spawned (the `response.success===false`\n // branch above already kills it on ITS failure path; this mirrors\n // that for get_state's).\n rpc.kill();\n throw err;\n }\n }\n return new PiSession(sessionRef, rpc);\n }\n\n private resolveBin(): ResolvedBin {\n return (this.options.resolveBin ?? resolvePiBin)();\n }\n}\n\n/**\n * Learn pi's own real session id for a freshly-started (non-resume) run, so\n * `Session.sessionRef` reports something a *future* follow-up can actually\n * resume via `--session <id>`. `get_state.data.sessionId` is populated from\n * the moment pi's RPC process boots (confirmed live: present even before\n * any prompt is sent, with `messageCount: 0`), so this is safe to call\n * right after the initial prompt is accepted.\n *\n * Finding F8 (fabricated sessionRef): this used to fall back to\n * `crypto.randomUUID()` whenever `get_state` failed, timed out, or omitted\n * `sessionId` — minting an id pi itself never knew about, which could never\n * actually be resumed and silently looked like a legitimate, resumable\n * session to every caller (`TaskRunner`'s `SessionWorkspaceStore`, a future\n * follow-up's `task.offer.sessionRef`, etc). Fail closed instead: if pi\n * doesn't hand back an authoritative session id, `start()` itself fails\n * with the real underlying error (stderr context is already folded in when\n * the rejection comes from the process exiting — see\n * `PiRpcClient.buildExitError`), exactly like any other adapter start()\n * failure `task-runner.ts` already knows how to report as `task.fail`.\n */\nasync function resolveFreshSessionId(rpc: PiRpcClient): Promise<string> {\n let state: PiRpcMessage;\n try {\n state = await rpc.send({ type: 'get_state' });\n } catch (err) {\n throw new Error(`pi did not yield an authoritative session id (get_state failed): ${errorMessage(err)}`, {\n cause: err,\n });\n }\n\n if (state.success === false) {\n const reason = typeof state.error === 'string' ? state.error : 'get_state reported failure';\n throw new Error(`pi did not yield an authoritative session id (get_state failed): ${reason}`);\n }\n\n const data = state.data as { sessionId?: unknown } | undefined;\n if (typeof data?.sessionId === 'string' && data.sessionId.length > 0) {\n return data.sessionId;\n }\n\n throw new Error(\n 'pi did not yield an authoritative session id (get_state succeeded but reported no sessionId) — cannot mint a resumable session',\n );\n}\n\nclass PiSession implements Session {\n constructor(\n public readonly sessionRef: string,\n private readonly rpc: PiRpcClient,\n ) {}\n\n get events(): AsyncIterable<AgentEvent> {\n const rpc = this.rpc;\n return {\n [Symbol.asyncIterator](): AsyncIterator<AgentEvent> {\n const inner = rpc.events[Symbol.asyncIterator]();\n return {\n async next(): Promise<IteratorResult<AgentEvent>> {\n for (;;) {\n const { value, done } = await inner.next();\n if (done) return { value: undefined as never, done: true };\n const mapped = mapPiMessageToAgentEvent(value);\n if (mapped) return { value: mapped, done: false };\n // Unmapped pi message: routine bookkeeping (compaction/retry/\n // session events — see ROUTINE_PI_EVENT_TYPES) is silently\n // ignored, same as before; anything else is genuinely\n // unexpected traffic worth flagging (see recordUnmappedFrame's\n // doc comment) — keep pulling either way, never surfaced.\n if (!ROUTINE_PI_EVENT_TYPES.has(value.type)) {\n rpc.recordUnmappedFrame(value.type);\n }\n }\n },\n };\n },\n };\n }\n\n async steer(text: string): Promise<void> {\n await this.rpc.send({ type: 'steer', message: text });\n }\n\n async followUp(task: TaskOfferPayload): Promise<void> {\n if (typeof task.instruction !== 'string') {\n throw new PolicyUnsupportedError('pi adapter only supports string instructions in M0 (no blob-ref fetch yet)');\n }\n await this.rpc.send({ type: 'prompt', message: task.instruction, streamingBehavior: 'followUp' });\n }\n\n async interrupt(): Promise<void> {\n await this.rpc.send({ type: 'abort' });\n }\n\n async close(): Promise<void> {\n this.rpc.kill();\n }\n\n async resolveApproval(): Promise<void> {\n // pi has no built-in per-call approval gate (see permission-mapping.ts)\n // and never emits `needs_approval` in M0/M1, so this should be\n // unreachable in practice. Kept as an explicit, descriptive failure\n // rather than a silent no-op so a future caller (or a misbehaving\n // server) gets a clear error instead of a hang.\n throw new Error('pi adapter does not support approval resume: pi never emits needs_approval in M0/M1');\n }\n}\n","export interface ResolvedBin {\n command: string;\n source: 'env' | 'path';\n}\n\n/**\n * Resolve the `claude` (Claude Code) CLI executable.\n *\n * Unlike pi (`../pi/resolve-bin.ts`), this package does NOT bundle a\n * matched `claude` build as an optionalDependency. Claude Code is the end\n * user's own globally-installed, individually-authenticated CLI (`claude\n * auth login`, tied to their Anthropic/claude.ai account) — there is\n * nothing useful to vendor: a bundled copy could never carry the user's own\n * login state, and the credential-isolation rule (see `../../types.ts`'s\n * `RuntimeAdapter` doc comment — this adapter must never read, proxy, or\n * forward `~/.claude`'s own auth storage) means this adapter has no\n * business managing a claude install at all, only spawning whatever `claude`\n * the user already has authenticated on their PATH.\n *\n * Resolution is therefore deliberately two-tier, not three like pi's:\n * `BYOK_CLAUDE_BIN` overrides everything when set (the injectable seam for\n * in-process tests — mirrors `BYOK_PI_BIN` and substitutes the\n * `fake-claude.mjs` fixture ahead of a real claude install, exactly as pi's\n * own override does), otherwise this falls back to the literal command name\n * `claude`, resolved via the child process's own PATH lookup — there is no\n * optionalDependency tier in between.\n */\nexport function resolveClaudeBin(): ResolvedBin {\n const override = process.env.BYOK_CLAUDE_BIN;\n if (override) {\n return { command: override, source: 'env' };\n }\n return { command: 'claude', source: 'path' };\n}\n","import { fileURLToPath } from 'node:url';\nimport path from 'node:path';\n\nexport interface ResolvedApprovalMcpBin {\n command: string;\n args: string[];\n source: 'env' | 'dist';\n}\n\n/**\n * Resolve `byok-approval-mcp` — the small stdio MCP server\n * (`bin/byok-approval-mcp.ts`) `claude`'s own `--permission-prompt-tool`\n * spawns as ITS child process (see that file's doc comment, and\n * `permission-mapping.ts`'s `confirm`-mode doc comment, for the full design).\n *\n * Unlike `resolveClaudeBin` (the end user's own separately-installed,\n * separately-authenticated CLI, resolved via bare-name PATH lookup),\n * `byok-approval-mcp` is a script THIS SAME `@byok-sdk/client` package ships —\n * bare-name PATH lookup is NOT safe for it: `@byok-sdk/client` is typically a\n * project-local dependency, so its `node_modules/.bin/byok-approval-mcp`\n * symlink is only on PATH for processes that inherit THAT project's own\n * shell/PATH, not reliably for a background OS service (launchd/systemd\n * often run with a stripped-down PATH that omits project-local\n * `node_modules/.bin` entirely — see `templates/service/**`). Resolving an\n * ABSOLUTE path to this package's own compiled bin avoids depending on PATH\n * at all.\n *\n * `BYOK_APPROVAL_MCP_BIN` overrides everything when set — the injectable\n * seam for tests (mirrors `BYOK_CLAUDE_BIN`/`BYOK_PI_BIN`), letting a test\n * substitute a fixture script instead of computing any real path. The\n * override is a single command string with no separate args (tests don't\n * need to invoke it any differently than `node <script>`); the real default\n * below is `node <absolute-path-to-the-built-bin>`.\n *\n * The default computation is deliberately anchored to THIS module's own\n * `import.meta.url`, resolved once at the real production entry point: when\n * `@byok-sdk/client` is built (`tsup.config.ts`), this file's code ends up\n * bundled into `dist/index.js` at the package root, with `dist/bin/\n * byok-approval-mcp.js` as its direct sibling (same layout `byok-agent.js`\n * already uses) — `path.join(path.dirname(fileURLToPath(import.meta.url)),\n * 'bin', 'byok-approval-mcp.js')` is therefore correct for that one real\n * shape. It is NOT correct for this file's own unbundled TypeScript source\n * location (`src/adapters/claude/` is two directories deeper than `src/`),\n * but nothing in this codebase ever reaches this fallback unbundled — every\n * test that exercises `confirm` mode sets `BYOK_APPROVAL_MCP_BIN` explicitly\n * (see `claude-adapter.test.ts`), exactly like `BYOK_CLAUDE_BIN` already\n * does for the real `claude` binary.\n */\nexport function resolveApprovalMcpBin(): ResolvedApprovalMcpBin {\n const override = process.env.BYOK_APPROVAL_MCP_BIN;\n if (override) {\n return { command: override, args: [], source: 'env' };\n }\n const distBin = path.join(path.dirname(fileURLToPath(import.meta.url)), 'bin', 'byok-approval-mcp.js');\n return { command: process.execPath, args: [distBin], source: 'dist' };\n}\n","import type { PermissionPolicy } from '@byok-sdk/protocol';\n\nexport interface ClaudePermissionMapping {\n ok: boolean;\n /** CLI args to append to `claude -p ...`. Only meaningful when `ok` is true. */\n args: string[];\n /** Present when `ok` is false. */\n reason?: string;\n /**\n * M4 Phase 3: set only for `policy.mode === 'confirm'` — tells\n * `claude-adapter.ts`'s `start()` to additionally spin up the out-of-band\n * approval channel (write the temp `--mcp-config` file pointing at\n * `bin/byok-approval-mcp.ts`, then append `--permission-prompt-tool`) on\n * top of the base `args` returned here. Kept out of `args` itself because\n * generating that config is a real filesystem side effect (a temp\n * directory + file write) that has no business happening inside this\n * otherwise-pure, I/O-free mapping function — see `claude-adapter.ts`'s\n * `start()` for where it actually happens.\n */\n needsApprovalMcp?: boolean;\n}\n\n/**\n * Claude Code's real, capitalized built-in read-only tool names. `Read` is\n * fully empirically confirmed on the installed 2.1.212 binary two ways: (a)\n * under `--permission-mode default` (deny-by-default) with `--allowedTools\n * Read`, a Write attempt is cleanly denied (`permission_denials` populated,\n * no hang); (b) more importantly, under `--tools Read` specifically (the\n * *replacive* flag — see the module doc comment below on why this, not\n * `--allowedTools`, is what this mapper actually uses), the model's own\n * reported tool list (`system/init`'s `tools` array) shrinks to exactly\n * `['Read', ...any always-on MCP tools]` and it cannot even attempt Write\n * (no permission prompt needed — the tool simply isn't offered to it).\n * `Glob`/`Grep` are included by strong, well-documented Claude Code naming\n * convention (identical capitalization pattern to the four tool names\n * empirically confirmed here: Read/Write/Edit/Bash) and were confirmed as\n * syntactically-accepted `--tools`/`--allowedTools` argument values on this\n * real installed binary (no \"unknown tool\" rejection) — but this\n * particular dev machine runs a heavily customized/plugin-extended Claude\n * Code build whose own active tool surface does not include Glob or Grep at\n * all (its `system/init.tools` array is a bespoke orchestration-tool set,\n * not vanilla Claude Code's), so their exact allow-through behavior could\n * not be independently exercised end-to-end here the way Read's was. Flagged\n * for the M2-c freeze decision, not silently assumed.\n */\nconst READONLY_TOOLS: readonly string[] = ['Read', 'Glob', 'Grep'];\n\n/**\n * Map an effective {@link PermissionPolicy} to `claude -p ...` CLI args,\n * fail-closed. Empirically grounded against the real installed `claude`\n * 2.1.212 binary (see the M2-a report) — every claim below was reproduced\n * live, not inferred from `--help` text or training-data recall (`--help`\n * text alone was actively misleading in at least one case: `--allowedTools`\n * reads like a hard allowlist but is NOT one — see the finding below).\n *\n * ## Two DIFFERENT, easily-confused tool-control flags (the central finding)\n *\n * `claude --help` documents two separate flag families that look\n * interchangeable but are not:\n *\n * - `--allowedTools` / `--disallowedTools`: a PERMISSION pre-grant/deny\n * list. Empirically, this only affects whether a tool call needs an\n * interactive prompt — it does NOT reliably restrict what the model can\n * do once a broadly-permissive `--permission-mode` (acceptEdits,\n * bypassPermissions, dontAsk) is also in effect. Confirmed two ways: (a)\n * `--permission-mode acceptEdits --allowedTools Read` still let a Write\n * call succeed (zero `permission_denials`) — the allowlist was silently\n * ignored once the broad grant was in effect; (b) `--permission-mode\n * acceptEdits --disallowedTools Write` correctly blocked the *named*\n * `Write` tool call (`<tool_use_error>Error: No such tool available:\n * Write...`), but the model then simply used `Bash` instead (still\n * enabled) to write the same file — `(Bash completed with no output)`,\n * file created anyway. A single denied tool name is not a security\n * boundary when a general-purpose Bash tool remains available.\n * - `--tools`: REPLACES the entire active built-in tool set (pi's own\n * `--tools` flag works the same way — this is the one place claude and pi\n * share an identical convention). Confirmed: `--tools Read` shrinks\n * `system/init`'s reported `tools` array to just `['Read', ...MCP\n * tools]`; the model then cannot even attempt Write (no tool definition\n * to call), regardless of `--permission-mode`. `--tools \"\"` disables\n * every built-in tool outright (confirmed: only the always-on MCP tool\n * remained). This is the ONLY mechanism this mapper trusts to actually\n * restrict the model's capability surface — never `--allowedTools`/\n * `--disallowedTools` for that purpose.\n *\n * ## Mode mapping\n *\n * - `auto` (no `allowTools`): `--permission-mode acceptEdits`. Empirically\n * confirmed to auto-accept BOTH file edits (Write) and Bash execution\n * with zero `permission_denials` — broader than the interactive-mode\n * folklore that acceptEdits only covers file edits. Verified for a\n * benign `echo ... > file` Bash command specifically; not exhaustively\n * verified across every possible Bash command shape.\n * - `auto` with `allowTools` (no `denyTools`): adds `--tools\n * <allowTools.join(',')>` (the replacive flag) on top of `acceptEdits`,\n * mirroring pi's own `allowTools`-only branch.\n * - `readonly`: ALWAYS `--permission-mode default` (never acceptEdits/\n * bypassPermissions/dontAsk — see the finding above: a permissive mode\n * defeats any restriction) plus `--tools\n * <intersect(allowTools ?? READONLY_TOOLS, READONLY_TOOLS) - denyTools>`.\n * An empty resulting set emits `--tools \"\"` explicitly — never an absent\n * `--tools` flag, which would default to claude's full active set and\n * silently widen a readonly request (the exact class of bug pi's own\n * `--no-tools` fallback exists to prevent).\n * - `plan`: `--permission-mode plan`. Empirically confirmed to never\n * execute the requested mutating tool call against its real target — the\n * model instead writes a plan document and stops. **Caveat, flagged for\n * the M2-c freeze decision, not silently hidden**: it writes that plan\n * file to `~/.claude/plans/<slug>.md` — the real user's home directory,\n * OUTSIDE `ctx.workspaceDir` — unconditionally, regardless of cwd. This\n * is a genuine, confirmed workspace-confinement gap specific to plan\n * mode's own bookkeeping (the path is fixed/product-owned by Claude Code\n * itself, not attacker/model-directed, and no destructive action runs\n * against the actual task target) — mapped as supported rather than\n * failed-closed because refusing would make an entire policy mode whose\n * name and semantics match this protocol's own `plan` mode 1:1\n * completely unusable over a relatively minor, fixed-path side effect,\n * but this is a judgment call for a human to weigh in on, not a fact.\n * - `confirm`: SUPPORTED as of M4 Phase 3 — `--permission-mode default`\n * (deny-by-default baseline, same as `readonly`'s own choice above) plus\n * `allowTools`/`denyTools` mapped exactly like `auto` does (finding F2,\n * fixed same session as the confirm-mode support itself first shipped —\n * see the function body below): an explicit `--tools <allowTools>` when\n * only `allowTools` is set, and a fail-closed refusal whenever `denyTools`\n * is non-empty, since confirm — like `auto`/`plan` and unlike\n * `readonly` — has no bounded, known-safe base tool list to subtract\n * from; the only trustworthy restriction mechanism (`--tools`) is\n * replacive, not subtractive. This composes with, rather than replaces,\n * `--permission-prompt-tool` pointed at a small bundled MCP server\n * (`bin/byok-approval-mcp.ts`) that forwards the pending permission\n * decision to this device's own daemon over its control socket and blocks\n * until a human (or the daemon's own timeout) resolves it. This directly\n * supersedes the M2-a finding that `confirm` was inexpressible: that\n * finding was empirically true for `--permission-mode` ALONE (every\n * decision resolved synchronously, no pause) — `--permission-prompt-tool`\n * is a DIFFERENT flag, undocumented in `claude --help`'s output on the\n * installed 2.1.216 binary (confirmed accepted anyway — an unrecognized\n * flag is rejected outright with `error: unknown option`, this one is\n * not), that genuinely pauses the turn on a real MCP round-trip while\n * claude waits for an answer (M4 Phase 3 STEP 0: live-verified allow,\n * deny, and multi-second-delayed-then-allow, against the real installed\n * binary — see `../../bin/byok-approval-mcp.ts`'s own doc comment for the\n * full empirical writeup, including the one caveat found: a permission-\n * prompt-tool call that NEVER answers at all triggers claude's own\n * internal abandonment of the turn after roughly 1.5s — never actually hit\n * by this design, since `byok-approval-mcp` always eventually answers\n * within its own configured ceiling, but disclosed rather than silently\n * assumed away).\n * - `denyTools` non-empty under `auto`: FAILS CLOSED. Given the\n * `--allowedTools`/`--disallowedTools`-under-a-permissive-mode escape\n * hatch above, the only mechanism this mapper trusts (`--tools`) is\n * REPLACIVE, not subtractive — pi can resolve `denyTools` to an\n * equivalent allowlist because pi's own default active tool set is\n * fixed and known from its installed source; claude's active tool\n * surface is NOT reliably known ahead of time (empirically, this exact\n * dev machine's own installed build exposes a bespoke, non-vanilla tool\n * set — see `READONLY_TOOLS`'s doc comment), so there is no reliable\n * \"default set minus these\" this mapper can construct. Refusing is the\n * fail-closed choice over guessing a set that might not match reality.\n *\n * `network: false` fails closed for the same reason as pi: no verified\n * network sandbox exists for claude's Bash tool either (`claude --help`\n * exposes no network/sandbox flag at all) — this was not independently\n * re-verified against real network traffic the way the tool-restriction\n * findings above were (doing so would require an actual network probe this\n * task didn't run), but is the same conservative, precedent-consistent\n * default pi already applies for an unverifiable constraint.\n */\nexport function mapPermissionPolicyToClaudeArgs(policy: PermissionPolicy): ClaudePermissionMapping {\n if (policy.network === false) {\n return {\n ok: false,\n args: [],\n reason: 'policy requires network:false, which the claude adapter cannot enforce (claude has no network sandbox for its Bash tool)',\n };\n }\n\n const denyTools = policy.denyTools ?? [];\n\n if (policy.mode === 'confirm') {\n // Deny-by-default baseline (never a permissive mode — see readonly's own\n // reasoning above): `--permission-prompt-tool` only intercepts a\n // decision that would otherwise need ONE, so a permissive mode here\n // would defeat confirm's whole point by auto-granting first. The actual\n // `--permission-prompt-tool`/`--mcp-config` flags are appended by\n // `claude-adapter.ts`'s `start()` (see `needsApprovalMcp` above), not\n // here, since generating the mcp-config file is a real I/O side effect.\n //\n // Finding F2 (cross-model adversarial review): this branch used to\n // return unconditionally right here, silently discarding\n // `allowTools`/`denyTools` entirely — a `{mode:'confirm',\n // denyTools:['Bash']}` policy would still let Bash through (subject\n // only to a per-call human prompt), never actually enforcing the\n // caller's denial; that's a silent widening of the requested policy,\n // exactly what this mapper fails closed for everywhere else. Confirm\n // has no bounded, known-safe base tool list the way `readonly` does\n // (`READONLY_TOOLS`) — its whole point is to allow the FULL active\n // tool surface, gated by a human decision per call, not a fixed small\n // set — so its `denyTools` problem is the SAME shape as `auto`/`plan`'s\n // below: the only mechanism this mapper trusts (`--tools`) is\n // REPLACIVE, not subtractive, and there is no reliable \"full active set\n // minus denied\" to compute. Mirrors `auto`'s handling exactly: fail\n // closed whenever `denyTools` is non-empty (composed with `allowTools`\n // or not — an inexpressible constraint is inexpressible either way),\n // otherwise an explicit `--tools <allowTools>` when `allowTools` alone\n // is set.\n if (denyTools.length > 0) {\n return {\n ok: false,\n args: [],\n reason: `claude adapter cannot reliably enforce denyTools ([${denyTools.join(', ')}]) under confirm mode: its only trustworthy tool-restriction mechanism (--tools) replaces the whole active set rather than subtracting from it, and this adapter has no reliable way to learn a target installation's full default tool set to compute \"default minus denied\" (this dev machine's own installed build exposes a non-vanilla, bespoke tool list) — refusing rather than risking a denial that silently doesn't hold`,\n };\n }\n const confirmArgs = ['--permission-mode', 'default'];\n if (policy.allowTools && policy.allowTools.length > 0) {\n confirmArgs.push('--tools', policy.allowTools.join(','));\n }\n return { ok: true, args: confirmArgs, needsApprovalMcp: true };\n }\n\n if (policy.mode === 'readonly') {\n const base = policy.allowTools ? policy.allowTools.filter((tool) => READONLY_TOOLS.includes(tool)) : [...READONLY_TOOLS];\n const effective = subtractDenied(base, denyTools);\n // Never fall through to an absent `--tools` flag here — that would run\n // claude's full active toolset, silently widening a readonly request.\n return { ok: true, args: ['--permission-mode', 'default', '--tools', effective.join(',')] };\n }\n\n // `auto` and `plan` share the same tool-restriction logic below — plan\n // mode never executes a mutating call regardless (see the doc comment\n // above), so an `allowTools`/`denyTools` restriction only shapes what the\n // model is even offered to plan around, not a security boundary for plan\n // mode specifically. Kept as one branch for both, rather than duplicating\n // the denyTools fail-closed reasoning twice.\n if (denyTools.length > 0) {\n return {\n ok: false,\n args: [],\n reason: `claude adapter cannot reliably enforce denyTools ([${denyTools.join(', ')}]): its only trustworthy tool-restriction mechanism (--tools) replaces the whole active set rather than subtracting from it, and this adapter has no reliable way to learn a target installation's full default tool set to compute \"default minus denied\" (this dev machine's own installed build exposes a non-vanilla, bespoke tool list) — refusing rather than risking a denial that silently doesn't hold`,\n };\n }\n\n const permissionMode = policy.mode === 'plan' ? 'plan' : 'acceptEdits';\n const args = ['--permission-mode', permissionMode];\n if (policy.allowTools && policy.allowTools.length > 0) {\n args.push('--tools', policy.allowTools.join(','));\n }\n return { ok: true, args };\n}\n\nfunction subtractDenied(tools: readonly string[], denyTools: readonly string[]): string[] {\n const denied = new Set(denyTools);\n return tools.filter((tool) => !denied.has(tool));\n}\n","import { realpathSync } from 'node:fs';\nimport path from 'node:path';\nimport type { AgentEvent } from '@byok-sdk/protocol';\n\n/**\n * A raw parsed line from `claude --output-format stream-json`. Shapes vary\n * a lot by `type` (and, for `system`, by `subtype`) — see the doc comments\n * on the individual mapping functions below for the concrete shapes this\n * was empirically captured against. Kept as a loose bag rather than a full\n * discriminated union for the same reason pi's `PiRpcMessage` is: this\n * module only needs a handful of fields off of each frame.\n */\nexport interface ClaudeStreamMessage {\n type: string;\n [key: string]: unknown;\n}\n\n/**\n * Cross-message correlation state a single {@link ClaudeSession} (in\n * `../claude-adapter.ts`) owns for its whole lifetime.\n *\n * Unlike pi's `tool_execution_start`/`tool_execution_end` frames (which\n * both carry `toolName` directly, so `../pi/events.ts` can stay a pure,\n * stateless function), claude's Messages-API-shaped transcript splits a\n * tool call across two DIFFERENT frame types: the `assistant` frame's\n * `tool_use` content block carries `{id, name, input}`, but the later\n * `user` frame's `tool_result` content block carries only `{tool_use_id,\n * content, is_error}` — no tool name at all. Since this protocol's own\n * `AgentEvent` schema requires `tool_result.tool: string`, this mapper has\n * no choice but to remember `tool_use_id -> name` from the `tool_use` block\n * and look it up when the matching `tool_result` arrives later. This is a\n * genuine, disclosed structural difference from pi, not an arbitrary\n * design choice — see the M2-a report for the full reasoning.\n */\nexport interface ToolUseCorrelation {\n readonly toolNameByUseId: Map<string, string>;\n}\n\nexport function createToolUseCorrelation(): ToolUseCorrelation {\n return { toolNameByUseId: new Map() };\n}\n\nexport interface MapClaudeMessageOptions {\n /** `ctx.workspaceDir` for the task — used only to compute a workspace-relative `name` for a possible `artifact` AgentEvent (see `tryBuildArtifactEvent`'s doc comment). */\n workspaceDir: string;\n}\n\nexport interface MapClaudeMessageResult {\n events: AgentEvent[];\n /**\n * Set when this exact frame (or, for `assistant`/`user` frames, one\n * content block inside it) was genuinely unrecognized — a frame/subtype/\n * block-type this adapter has never been told to expect — as opposed to\n * routine bookkeeping this mapper deliberately ignores (see\n * `ROUTINE_CLAUDE_SYSTEM_SUBTYPES` and the `thinking`/`redacted_thinking`\n * cases below). The caller (`ClaudeSession`'s event iterator) is\n * responsible for actually recording it (via\n * `ClaudeProcessClient.recordUnmappedFrame`) — mirrors pi's\n * `ROUTINE_PI_EVENT_TYPES` check living in `PiSession`'s iterator rather\n * than inside `mapPiMessageToAgentEvent` itself. At most one label per\n * call even if a frame has several unmapped things in it — sufficient\n * for the \"did this regress\" self-diagnosing purpose this exists for,\n * without needing a list.\n */\n unmappedLabel?: string;\n}\n\n/**\n * `system` frame subtypes empirically observed on real stream-json output\n * from the installed claude 2.1.212 binary that carry no `AgentEvent`\n * equivalent — routine bookkeeping, deliberately ignored:\n *\n * - `init`: session/turn start. Carries `session_id`, `tools`, `cwd`,\n * `permissionMode`, etc. `session_id` specifically is NOT read here —\n * `ClaudeProcessClient.waitForInit()` (`process-client.ts`) captures it\n * directly off the raw line as part of this adapter's own\n * `start()`/sessionRef bookkeeping, since it's needed before any\n * `AgentEvent` mapping is even relevant.\n * - `hook_started` / `hook_response`: fired when the user's own Claude Code\n * installation has configured lifecycle hooks (e.g. `SessionStart`) —\n * machine/config-specific, not part of this protocol's surface at all.\n * - `thinking_tokens`: periodic token-count-estimate bookkeeping emitted\n * while the model is reasoning; no user-visible content.\n *\n * A `system` frame whose `subtype` is NOT in this set is treated as\n * genuinely unmapped (see `mapClaudeMessageToAgentEvents`'s `system` case)\n * rather than silently folded into \"system frames are always routine\" —\n * this is deliberately finer-grained than lumping the whole `system` type\n * together, so a future/unobserved subtype (e.g. something compaction- or\n * budget-related) shows up as a one-time warning instead of disappearing\n * the way the pi adapter's own root-cause hang (a real settle event with no\n * mapping, silently swallowed) did before that bug was found.\n */\nexport const ROUTINE_CLAUDE_SYSTEM_SUBTYPES: ReadonlySet<string> = new Set([\n 'init',\n 'hook_started',\n 'hook_response',\n 'thinking_tokens',\n]);\n\n/** Claude tool names whose successful `tool_result` may correspond to a file written into the task workspace — see `tryBuildArtifactEvent`. `Write` is fully empirically confirmed (real `tool_use_result.filePath`/`.type:\"create\"` shape captured live); `Edit`/`NotebookEdit` are included by the same reasoning/convention as `permission-mapping.ts`'s `Glob`/`Grep` note — not independently re-verified frame-by-frame here. */\nconst FILE_WRITING_TOOLS: ReadonlySet<string> = new Set(['Write', 'Edit', 'NotebookEdit']);\n\nconst EXTENSION_CONTENT_TYPES: Readonly<Record<string, string>> = {\n '.txt': 'text/plain',\n '.md': 'text/markdown',\n '.json': 'application/json',\n '.js': 'text/javascript',\n '.mjs': 'text/javascript',\n '.cjs': 'text/javascript',\n '.ts': 'text/plain',\n '.tsx': 'text/plain',\n '.jsx': 'text/plain',\n '.html': 'text/html',\n '.css': 'text/css',\n '.csv': 'text/csv',\n '.py': 'text/x-python',\n '.yaml': 'application/yaml',\n '.yml': 'application/yaml',\n};\n\n/** Best-effort, extension-based content-type guess — deliberately not a full MIME sniffer (out of scope; `AgentEventSchema.artifact.contentType` just needs a non-empty string). */\nfunction guessContentType(filePath: string): string {\n const ext = path.extname(filePath).toLowerCase();\n return EXTENSION_CONTENT_TYPES[ext] ?? 'application/octet-stream';\n}\n\n/**\n * `assistant` frames carry ONE new Messages-API content block per frame in\n * every live capture this adapter's empirical probes observed (never\n * multiple) — this still iterates the whole `content` array defensively\n * rather than assuming array length 1, since nothing in claude's own\n * documented wire contract guarantees that stays true.\n */\nfunction mapAssistant(msg: ClaudeStreamMessage, correlation: ToolUseCorrelation): MapClaudeMessageResult {\n const message = msg.message as { content?: unknown } | undefined;\n const content = message?.content;\n if (!Array.isArray(content)) return { events: [] };\n\n const events: AgentEvent[] = [];\n let unmappedLabel: string | undefined;\n\n for (const raw of content) {\n const block = raw as { type?: unknown; [key: string]: unknown };\n switch (block.type) {\n case 'text':\n if (typeof block.text === 'string') {\n events.push({ type: 'progress', text: block.text });\n }\n break;\n\n case 'tool_use':\n if (typeof block.id === 'string' && typeof block.name === 'string') {\n correlation.toolNameByUseId.set(block.id, block.name);\n events.push({ type: 'tool_use', tool: block.name, input: block.input });\n }\n break;\n\n // Deliberately NOT mapped to `progress` — mirrors pi's own choice to\n // ignore `thinking_delta` sub-events (see `../pi/events.ts`). Two\n // independent reasons: (1) the daemon's `task-runner.ts` folds every\n // `progress` event's text into `task.complete.summary` verbatim —\n // surfacing raw model reasoning there would leak internal\n // chain-of-thought to whatever SaaS embeds this SDK; (2) on several\n // current-generation models this content is empty by design anyway\n // (`display: \"omitted\"` is the default — see the claude-api skill's\n // \"Thinking & Effort\" reference) even though it was NOT empty in this\n // task's own live captures against `claude-haiku-4-5`. `redacted_thinking`\n // is a documented Anthropic Messages API block type never observed\n // live here; treated identically for the same reasoning.\n case 'thinking':\n case 'redacted_thinking':\n break;\n\n default:\n unmappedLabel = unmappedLabel ?? `assistant-block:${String(block.type)}`;\n }\n }\n\n return { events, unmappedLabel };\n}\n\n/**\n * `user` frames in stream-json output are NOT a human sending input — they\n * are claude echoing a `tool_result` back into the transcript (the same\n * \"user\" role the underlying Messages API uses for tool results). Two\n * concrete verbatim shapes captured live:\n *\n * Denied (no permission granted, headless — see `../claude-adapter.ts`'s\n * doc comment for the full approval-model finding):\n * ```json\n * {\"type\":\"user\",\"message\":{\"role\":\"user\",\"content\":[{\"type\":\"tool_result\",\n * \"content\":\"Claude requested permissions to write to <path>, but you\n * haven't granted it yet.\",\"is_error\":true,\"tool_use_id\":\"toolu_...\"}]},\n * \"tool_use_result\":\"Error: Claude requested permissions to write to\n * <path>, but you haven't granted it yet.\"}\n * ```\n *\n * Successful Write (the shape `tryBuildArtifactEvent` reads):\n * ```json\n * {\"type\":\"user\",\"message\":{\"role\":\"user\",\"content\":[{\"tool_use_id\":\"toolu_...\",\n * \"type\":\"tool_result\",\"content\":\"File created successfully at: <path> ...\"}]},\n * \"tool_use_result\":{\"type\":\"create\",\"filePath\":\"<absolute path>\",\n * \"content\":\"...\",\"structuredPatch\":[],\"originalFile\":null,\"userModified\":false}}\n * ```\n *\n * `content` on the `tool_result` block was only ever observed as a plain\n * string in this task's captures (never the content-block-array shape the\n * general Messages API allows) — `output.content` below is passed through\n * as `unknown` regardless, so a future array shape still round-trips\n * correctly without a mapping change.\n */\nfunction mapUser(msg: ClaudeStreamMessage, correlation: ToolUseCorrelation, options: MapClaudeMessageOptions): MapClaudeMessageResult {\n const message = msg.message as { content?: unknown } | undefined;\n const content = message?.content;\n if (!Array.isArray(content)) return { events: [] };\n\n const events: AgentEvent[] = [];\n let unmappedLabel: string | undefined;\n\n for (const raw of content) {\n const block = raw as { type?: unknown; tool_use_id?: unknown; content?: unknown; is_error?: unknown };\n if (block.type !== 'tool_result') {\n unmappedLabel = unmappedLabel ?? `user-block:${String(block.type)}`;\n continue;\n }\n\n const toolUseId = typeof block.tool_use_id === 'string' ? block.tool_use_id : undefined;\n // Falls back to 'unknown' rather than dropping the event: the\n // AgentEventSchema requires a non-empty `tool` string, and a\n // correlation miss here would mean this adapter's own\n // tool_use<->tool_result bookkeeping has a bug — worth surfacing to the\n // caller as a (still-delivered) event with an honest sentinel name,\n // never silently swallowing real tool-result data.\n const tool = (toolUseId && correlation.toolNameByUseId.get(toolUseId)) || 'unknown';\n const isError = block.is_error === true;\n events.push({ type: 'tool_result', tool, output: { content: block.content, isError } });\n\n if (!isError && FILE_WRITING_TOOLS.has(tool)) {\n const artifact = tryBuildArtifactEvent(msg, options.workspaceDir);\n if (artifact) events.push(artifact);\n }\n }\n\n return { events, unmappedLabel };\n}\n\n/**\n * Real claude has no dedicated \"artifact\" wire message the way pi's fixture\n * fakes one (see `../pi/events.ts`'s doc comment on that case) — but for a\n * successful `Write` (confirmed shape above), the SAME `user` frame's\n * top-level `tool_use_result.filePath` sibling field gives this adapter\n * something pi never had: a real, live-observed, absolute path to the file\n * claude just wrote. This turns it into a workspace-relative `name` for the\n * protocol's `artifact` `AgentEvent`.\n *\n * A written file OUTSIDE `workspaceDir` never produces an artifact event —\n * this is not just defensive coding, it is the concrete fix for a real,\n * confirmed case: `--permission-mode plan` writes its own plan document to\n * `~/.claude/plans/<slug>.md`, the user's actual home directory, regardless\n * of cwd (see `permission-mapping.ts`'s doc comment on that finding). That\n * path always resolves outside `workspaceDir` and must never be reported to\n * the daemon as this task's artifact.\n */\nfunction tryBuildArtifactEvent(msg: ClaudeStreamMessage, workspaceDir: string): AgentEvent | undefined {\n const toolUseResult = msg.tool_use_result as { filePath?: unknown } | undefined;\n const filePath = toolUseResult && typeof toolUseResult.filePath === 'string' ? toolUseResult.filePath : undefined;\n if (!filePath) return undefined;\n\n // `workspaceDir` (`ctx.workspaceDir`) and the absolute `filePath` claude\n // reports can each be expressed through a different symlink alias of the\n // same real location — hit empirically on macOS, where `os.tmpdir()`\n // itself is a symlink (`/var/folders/... -> /private/var/folders/...`)\n // and a spawned child process's own `process.cwd()` reports the\n // REALPATH-resolved form regardless of which alias `cwd` was set to when\n // spawning it. Comparing the raw strings directly misclassifies a file\n // that genuinely IS inside the workspace as outside it purely because of\n // which alias each side happened to use — confirmed live: this silently\n // dropped every artifact event for a workspace created under this\n // machine's own `os.tmpdir()` before this fix. Resolve both through\n // `realpath` before comparing — mirrors `task-runner.ts`'s own\n // `openArtifact()`, which resolves the exact same alias-mismatch class\n // for its downstream containment check.\n //\n // Realpath is applied to the *directory*, not the file itself: the file\n // is expected to exist by the time this runs against real claude output\n // (the tool_result frame only arrives after the write actually\n // happened), but resolving the directory rather than the leaf path keeps\n // this correct even when it doesn't (a stale/removed artifact, or a pure\n // unit test constructing a `tool_use_result` without writing real bytes)\n // — falls back to the raw directory on a realpath failure (e.g. it too\n // doesn't exist), matching `openArtifact`'s own defensive fallback.\n const realWorkspaceDir = tryRealpath(workspaceDir) ?? workspaceDir;\n const fileDir = path.dirname(filePath);\n const realFileDir = tryRealpath(fileDir) ?? fileDir;\n const realFilePath = path.join(realFileDir, path.basename(filePath));\n\n const relative = path.relative(realWorkspaceDir, realFilePath);\n if (relative === '' || relative.startsWith('..') || path.isAbsolute(relative)) {\n return undefined;\n }\n\n return { type: 'artifact', name: relative, contentType: guessContentType(filePath) };\n}\n\nfunction tryRealpath(candidate: string): string | undefined {\n try {\n return realpathSync(candidate);\n } catch {\n return undefined;\n }\n}\n\n/**\n * `result` is claude's real \"whole run settled\" signal (the direct\n * counterpart to pi's `agent_end` — see `../pi/events.ts`'s doc comment on\n * why that distinction mattered there). Confirmed live: it is always the\n * LAST frame of a turn, whether the turn succeeded (`is_error:false`,\n * `subtype:\"success\"`) or failed before ever reaching the model (e.g. an\n * unresolvable `--resume` target: `subtype:\"error_during_execution\"`,\n * `is_error:true`, `errors:[\"No conversation found with session ID: ...\"]`,\n * process exit code 1 — but STILL a clean, parseable stream-json frame,\n * unlike pi's equivalent bad-invocation case which produces no structured\n * output at all and forces the adapter to fall back to a raw stderr tail).\n * `is_error` (not `subtype`) is the field this switches on, since it is a\n * plain boolean rather than a string this adapter would otherwise need to\n * pattern-match against every observed/unobserved subtype spelling.\n *\n * `usage` (pre-freeze protocol addition — see `extractClaudeUsageEvent`'s\n * doc comment) is extracted on BOTH branches, not just success: a real\n * mid-generation API error could still carry partial usage, and an empty/\n * absent `usage` (the confirmed shape on the pre-flight \"no conversation\n * found\" failure — no model call was ever made) just yields no event, same\n * as the success path. Ordering is load-bearing: `usage`, when present, is\n * placed BEFORE `turn_end`/`error` in the returned array — `ClaudeSession`'s\n * event iterator (`../claude-adapter.ts`) buffers this array and drains it\n * in order, and `task-runner.ts`'s `pump()` returns the instant it sees\n * `turn_end`, so anything queued after it would never be read. `error` does\n * not end the read loop the same way, so the ordering there is for\n * consistency rather than a delivery requirement.\n */\nfunction mapResult(msg: ClaudeStreamMessage): MapClaudeMessageResult {\n const usageEvent = extractClaudeUsageEvent(msg.usage);\n // Cross-model review finding: success must require `is_error === false`\n // EXPLICITLY — the previous `!== true` check treated a MISSING or\n // non-boolean `is_error` (a malformed/future `result` frame) as success\n // too, which would have reported task.complete for a turn that never\n // actually said it succeeded. `result` is the wire's own terminal signal\n // (see this function's own doc comment above) — never inferred.\n if (msg.is_error === false) {\n const events: AgentEvent[] = usageEvent ? [usageEvent, { type: 'turn_end' }] : [{ type: 'turn_end' }];\n return { events };\n }\n const errors = Array.isArray(msg.errors) ? msg.errors.filter((e): e is string => typeof e === 'string') : [];\n // Shared between both failure branches below: the SAME \"errors array wins,\n // result string is the fallback\" extraction `is_error === true` has always\n // used. `undefined` means the frame carried neither.\n const diagnostic =\n errors.length > 0 ? errors.join('; ') : typeof msg.result === 'string' && msg.result.length > 0 ? msg.result : undefined;\n const message =\n msg.is_error === true\n ? (diagnostic ?? 'claude reported an error result')\n : // M4 hardening: a missing/invalid `is_error` is already fail-closed\n // (treated as failure, never inferred as success — see above), but\n // this branch used to report ONLY the generic fallback string, even\n // when the frame actually carried a perfectly usable `result`/\n // `errors` payload (real diagnostic content is only read above when\n // `is_error === true` EXACTLY, so a malformed-but-otherwise-populated\n // frame silently lost it). Appending `diagnostic` here (when\n // present) preserves the fail-closed verdict — this is still always\n // an `error` AgentEvent — while no longer discarding whatever the\n // frame actually said. Truncated defensively: this is an\n // unexpected/malformed frame shape, not the normal error path, so\n // the content could in principle be arbitrarily large.\n diagnostic\n ? `claude result frame had a missing/invalid is_error flag (got ${JSON.stringify(msg.is_error)}) — treating as failure, fail-closed; diagnostic content on the frame: ${truncateResultDiagnostic(diagnostic)}`\n : `claude result frame had a missing/invalid is_error flag (got ${JSON.stringify(msg.is_error)}) — treating as failure, fail-closed`;\n const events: AgentEvent[] = usageEvent ? [usageEvent, { type: 'error', message }] : [{ type: 'error', message }];\n return { events };\n}\n\n/** Sane upper bound on how much of a malformed `result` frame's own diagnostic content (`errors`/`result`) gets folded into the fail-closed message above — no existing truncation helper in this file to reuse (the codex adapter's equivalent, `codex-adapter.ts`'s `JSON.stringify(evt).slice(0, 200)`, lives in a different module entirely), so this is its own small, local bound rather than a shared one. */\nconst RESULT_DIAGNOSTIC_MAX_CHARS = 2000;\n\nfunction truncateResultDiagnostic(text: string): string {\n return text.length > RESULT_DIAGNOSTIC_MAX_CHARS ? `${text.slice(0, RESULT_DIAGNOSTIC_MAX_CHARS)}… [truncated]` : text;\n}\n\n/**\n * Maps the `result` frame's `usage` object to a `usage` `AgentEvent`, or\n * `undefined` when nothing usable is present. Field names and shape\n * confirmed via a live minimal probe against the installed claude 2.1.212\n * binary (same version this adapter's other captures were made against —\n * see `claude-adapter.ts`'s class doc comment): a real `result.usage` looks\n * like `{\"input_tokens\":2,\"cache_creation_input_tokens\":35649,\n * \"cache_read_input_tokens\":0,\"output_tokens\":24,\"server_tool_use\":{...},\n * \"service_tier\":\"standard\",...}` — the standard Anthropic Messages API\n * usage shape, carried through verbatim by the Claude Code CLI.\n *\n * Mapping choices:\n * - `inputTokens` <- `input_tokens` verbatim.\n * - `cachedInputTokens` <- `cache_read_input_tokens` (tokens actually SERVED\n * from a prior cache — the same \"reused, cheaper\" semantic as codex's\n * `cached_input_tokens`). Deliberately NOT `cache_creation_input_tokens`\n * (the cost of WRITING a new cache entry — a distinct, more-expensive-not-\n * cheaper concept the wire schema has no separate slot for; dropped\n * rather than conflated).\n * - `outputTokens` <- `output_tokens` verbatim.\n * - `reasoningTokens` / `totalTokens`: never populated for claude — neither\n * a separate reasoning-token count nor a combined total appears anywhere\n * in real claude output (thinking-block content is folded into\n * `output_tokens`, not counted separately), so these stay absent rather\n * than fabricated.\n */\nfunction extractClaudeUsageEvent(rawUsage: unknown): AgentEvent | undefined {\n if (!rawUsage || typeof rawUsage !== 'object') return undefined;\n const usage = rawUsage as Record<string, unknown>;\n const inputTokens = toNonNegativeInt(usage.input_tokens);\n const cachedInputTokens = toNonNegativeInt(usage.cache_read_input_tokens);\n const outputTokens = toNonNegativeInt(usage.output_tokens);\n if (inputTokens === undefined && cachedInputTokens === undefined && outputTokens === undefined) {\n return undefined;\n }\n const event: Extract<AgentEvent, { type: 'usage' }> = { type: 'usage' };\n if (inputTokens !== undefined) event.inputTokens = inputTokens;\n if (cachedInputTokens !== undefined) event.cachedInputTokens = cachedInputTokens;\n if (outputTokens !== undefined) event.outputTokens = outputTokens;\n return event;\n}\n\n/** Matches `AgentEventSchema`'s `usage` fields (`z.number().int().nonnegative().optional()`) — anything else (missing, a string, a float, negative) is treated as not-reported rather than coerced. */\nfunction toNonNegativeInt(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0 ? value : undefined;\n}\n\n/**\n * Map one raw claude stream-json line to zero or more normalized\n * `AgentEvent`s (a single `user` frame can produce two: `tool_result` plus\n * a derived `artifact`). See the per-`type` mapping functions above for the\n * concrete, empirically-captured shapes each branch handles.\n */\nexport function mapClaudeMessageToAgentEvents(\n msg: ClaudeStreamMessage,\n correlation: ToolUseCorrelation,\n options: MapClaudeMessageOptions,\n): MapClaudeMessageResult {\n switch (msg.type) {\n case 'assistant':\n return mapAssistant(msg, correlation);\n case 'user':\n return mapUser(msg, correlation, options);\n case 'result':\n return mapResult(msg);\n case 'system': {\n const subtype = typeof msg.subtype === 'string' ? msg.subtype : undefined;\n if (subtype && ROUTINE_CLAUDE_SYSTEM_SUBTYPES.has(subtype)) return { events: [] };\n return { events: [], unmappedLabel: `system:${subtype ?? 'unknown'}` };\n }\n // Per-turn rate-limit-window bookkeeping, unconditionally emitted\n // alongside every result — no `AgentEvent` equivalent, routine.\n case 'rate_limit_event':\n return { events: [] };\n default:\n return { events: [], unmappedLabel: `top-level:${String(msg.type)}` };\n }\n}\n","import { spawn, spawnSync, type ChildProcessWithoutNullStreams } from 'node:child_process';\nimport { AsyncQueue } from '../../util/async-queue';\nimport type { ClaudeStreamMessage } from './events';\n\nexport type SpawnFn = typeof spawn;\n\nexport interface ClaudeProcessClientOptions {\n command: string;\n args: string[];\n cwd: string;\n env: NodeJS.ProcessEnv;\n spawnFn?: SpawnFn;\n}\n\n/** Bound on retained stderr lines, mirroring pi's identical constant/rationale in `../pi/rpc-client.ts`. */\nconst STDERR_RING_CAPACITY = 20;\n\n/**\n * NDJSON process transport for `claude -p --input-format stream-json\n * --output-format stream-json`.\n *\n * Structurally simpler than pi's `PiRpcClient` in one real way, and\n * different (not simpler) in another:\n *\n * - No request/response correlation. pi's RPC mode replies to each command\n * with a `{type:\"response\", id, success, ...}` — claude's stream-json has\n * no such acknowledgement at all; writing a `{\"type\":\"user\",...}` line\n * just starts (or queues) a turn, and the ONLY confirmation is the\n * ordinary event stream itself (starting with a `system/init` frame).\n * There is therefore no `pending` id->resolver map here.\n * - `waitForInit()` exists specifically to compensate for that missing\n * ack: pi's `start()` fails fast because a bad flag/auth error rejects\n * the pending `send()` promise for the first command. Claude's own\n * `AsyncQueue.end()` (used for the `events` stream) is a CLEAN,\n * non-throwing end — a process that crashes before ever emitting a line\n * would otherwise look, from the async-iteration protocol alone, exactly\n * like a session that legitimately produced zero events, silently\n * swallowing the real failure. `waitForInit()` is a dedicated promise\n * that resolves with the real `session_id` once claude's own\n * `system/init` frame arrives, or rejects with the same enriched\n * exit-error `events` would otherwise swallow — this is what lets\n * `ClaudeAdapter.start()` fail loudly and immediately for a bad\n * `--resume` target etc., mirroring pi's own fail-fast contract with a\n * mechanism suited to claude's ack-less protocol instead of copying pi's\n * request/response one verbatim.\n *\n * Framing, stderr-ring, and unmapped-frame-tally-in-exit-error all mirror\n * `../pi/rpc-client.ts`'s already-proven design directly (LF-delimited\n * JSONL, `node:readline` avoided for the same U+2028/U+2029 reason pi's\n * doc comment explains, `close` not `exit` for the same complete-stderr\n * guarantee) — these are generic, sound patterns, not pi-specific logic,\n * so re-implementing them independently here (rather than importing from\n * `../pi/`) keeps this adapter fully self-contained, matching this repo's\n * existing per-adapter isolation.\n */\nexport class ClaudeProcessClient {\n private readonly child: ChildProcessWithoutNullStreams;\n private buffer = '';\n private readonly eventQueue = new AsyncQueue<ClaudeStreamMessage>();\n private closed = false;\n private exitError: Error | undefined;\n private readonly stderrRing: string[] = [];\n private readonly unmappedFrameCounts = new Map<string, number>();\n\n private sessionId: string | undefined;\n private initWaiter: { resolve: (sessionId: string) => void; reject: (err: Error) => void } | undefined;\n\n constructor(options: ClaudeProcessClientOptions) {\n const spawnFn = options.spawnFn ?? spawn;\n this.child = spawnFn(options.command, options.args, {\n cwd: options.cwd,\n env: options.env,\n stdio: ['pipe', 'pipe', 'pipe'],\n }) as ChildProcessWithoutNullStreams;\n\n this.child.stdout.setEncoding('utf8');\n this.child.stdout.on('data', (chunk: string) => this.onData(chunk));\n\n this.child.stderr.setEncoding('utf8');\n this.child.stderr.on('data', (chunk: string) => this.onStderr(chunk));\n\n // `close` (not `exit`) — see pi's rpc-client.ts doc comment for why\n // this matters: it's Node's guarantee every stdout/stderr byte the\n // process wrote has already been delivered, so a bad-flag/auth-failure\n // exit error always carries the complete stderr tail.\n this.child.on('close', (code, signal) => {\n this.onClosed(this.buildExitError(code, signal));\n });\n this.child.on('error', (err) => {\n this.onClosed(err);\n });\n }\n\n /**\n * Write a new user turn onto stdin (`--input-format stream-json`'s wire\n * shape: `{\"type\":\"user\",\"message\":{\"role\":\"user\",\"content\":[{\"type\":\n * \"text\",\"text\":...}]}}`). Used identically for the very first turn\n * (`ClaudeAdapter.start()`) and any later same-session turn\n * (`ClaudeSession.followUp()`) — empirically confirmed live that claude\n * keeps a `--input-format stream-json` process alive across multiple\n * sequential turns on ONE persistent process/session (same `session_id`\n * reported on each turn's own `system/init` and `result` frames), only\n * exiting when stdin is closed or the process is killed. This is the\n * mechanism `followUp()` relies on instead of spawning a fresh\n * `--resume`'d process per follow-up.\n */\n writeUserMessage(text: string): void {\n if (this.closed) {\n throw this.exitError ?? new Error('claude process is closed');\n }\n const line = `${JSON.stringify({ type: 'user', message: { role: 'user', content: [{ type: 'text', text }] } })}\\n`;\n this.child.stdin.write(line, (err) => {\n if (err) {\n console.error(`[byok/claude-adapter] failed to write to claude stdin: ${err.message}`);\n }\n });\n }\n\n /**\n * Resolves with claude's own `session_id` once its `system/init` frame\n * arrives (see this class's doc comment for why this exists at all).\n * Idempotent: once resolved, further calls resolve immediately with the\n * same id; if the process already closed before init ever arrived,\n * every call rejects with that same exit error.\n */\n waitForInit(): Promise<string> {\n if (this.sessionId !== undefined) return Promise.resolve(this.sessionId);\n if (this.closed) return Promise.reject(this.exitError ?? new Error('claude process is closed'));\n return new Promise((resolve, reject) => {\n this.initWaiter = { resolve, reject };\n });\n }\n\n /** Every parsed stream-json line — `system/init` is consumed internally (see `waitForInit`) but is also forwarded here like any other frame, so routine-frame accounting in `ClaudeSession`'s mapper stays uniform. */\n get events(): AsyncIterable<ClaudeStreamMessage> {\n return this.eventQueue;\n }\n\n /**\n * Record a claude stream-json frame/subtype/content-block label that\n * `ClaudeSession`'s event iterator (`../claude-adapter.ts`) decided has\n * no `AgentEvent` mapping and isn't routine bookkeeping (see\n * `events.ts`'s `MapClaudeMessageResult.unmappedLabel` doc comment) —\n * i.e. genuinely unexpected traffic. Mirrors pi's\n * `PiRpcClient.recordUnmappedFrame` exactly: logs once per distinct\n * label, folds the running tally into a later exit error for a\n * post-mortem without separate log scraping.\n */\n recordUnmappedFrame(label: string): void {\n const next = (this.unmappedFrameCounts.get(label) ?? 0) + 1;\n this.unmappedFrameCounts.set(label, next);\n if (next === 1) {\n console.warn(\n `[byok/claude-adapter] claude emitted a frame with no AgentEvent mapping: \"${label}\" (further occurrences of this label won't be logged individually)`,\n );\n }\n }\n\n /** Best-effort teardown. SIGTERM on POSIX; `taskkill /T /F` on Windows to also reap child processes claude itself spawned (e.g. Bash) — mirrors pi's cross-platform `kill()` exactly. Empirically confirmed on this (POSIX) machine: a running claude process exits cleanly within ~1s of SIGTERM (observed exit code 143 = 128+SIGTERM, i.e. claude catches and handles the signal itself rather than needing a harder kill). */\n kill(): void {\n if (this.closed) return;\n const pid = this.child.pid;\n if (process.platform === 'win32' && pid !== undefined) {\n spawnSync('taskkill', ['/pid', String(pid), '/T', '/F']);\n } else {\n this.child.kill('SIGTERM');\n }\n }\n\n private onData(chunk: string): void {\n this.buffer += chunk;\n let newlineIndex = this.buffer.indexOf('\\n');\n while (newlineIndex !== -1) {\n let line = this.buffer.slice(0, newlineIndex);\n this.buffer = this.buffer.slice(newlineIndex + 1);\n if (line.endsWith('\\r')) line = line.slice(0, -1);\n if (line.length > 0) this.onLine(line);\n newlineIndex = this.buffer.indexOf('\\n');\n }\n }\n\n private onLine(line: string): void {\n let msg: ClaudeStreamMessage;\n try {\n msg = JSON.parse(line) as ClaudeStreamMessage;\n } catch {\n return; // a stray non-JSON line is not this client's concern\n }\n\n if (\n this.sessionId === undefined &&\n msg.type === 'system' &&\n msg.subtype === 'init' &&\n typeof msg.session_id === 'string' &&\n msg.session_id.length > 0\n ) {\n this.sessionId = msg.session_id;\n this.initWaiter?.resolve(this.sessionId);\n this.initWaiter = undefined;\n }\n\n this.eventQueue.push(msg);\n }\n\n private onStderr(chunk: string): void {\n for (const rawLine of chunk.split('\\n')) {\n const line = rawLine.trim();\n if (line.length === 0) continue;\n this.stderrRing.push(line);\n if (this.stderrRing.length > STDERR_RING_CAPACITY) this.stderrRing.shift();\n }\n }\n\n /** Mirrors pi's `buildExitError` exactly — stderr tail + unmapped-frame tally folded into one self-diagnosing message. */\n private buildExitError(code: number | null, signal: NodeJS.Signals | null): Error {\n const parts = [`claude process exited (code=${code}, signal=${signal})`];\n if (this.stderrRing.length > 0) {\n parts.push(`stderr: ${this.stderrRing.join(' | ')}`);\n }\n if (this.unmappedFrameCounts.size > 0) {\n const summary = [...this.unmappedFrameCounts.entries()].map(([label, count]) => `${label}×${count}`).join(', ');\n parts.push(`unmapped frame labels seen: ${summary}`);\n }\n return new Error(parts.join('; '));\n }\n\n private onClosed(err: Error): void {\n if (this.closed) return;\n this.closed = true;\n this.exitError = err;\n this.initWaiter?.reject(err);\n this.initWaiter = undefined;\n this.eventQueue.end();\n }\n}\n","import { createInterface } from 'node:readline';\n\n/**\n * M4 Phase 3: the testable core of `byok-approval-mcp` (`byok-approval-mcp.ts`\n * is the thin stdio-wiring entry point — mirrors this repo's existing\n * `bin/commands/*.ts` split: real logic lives in a plain module, the bin\n * script itself is glue no test ever imports directly).\n *\n * `byok-approval-mcp` is the MCP stdio server `claude`'s own\n * `--permission-prompt-tool` spawns AS ITS OWN CHILD PROCESS when the claude\n * adapter runs a task under `PermissionPolicy.mode: 'confirm'` (see\n * `../adapters/claude/permission-mapping.ts`'s `confirm`-mode doc comment).\n * It implements just enough of the MCP stdio transport (JSON-RPC 2.0,\n * newline-delimited, per the spec) to expose ONE tool — empirically\n * confirmed end-to-end against the real installed claude 2.1.216 binary\n * (M4 Phase 3 STEP 0): `initialize` -> `notifications/initialized` ->\n * `tools/list` -> `tools/call`, with the tool's arguments shaped exactly\n * `{tool_name, input, tool_use_id}` (claude's own real wire shape,\n * live-captured) and its expected response shaped\n * `{content:[{type:'text', text: JSON.stringify({behavior:'allow',\n * updatedInput} | {behavior:'deny', message})}]}` — the SAME shape the\n * Claude Agent SDK's in-process `canUseTool` callback returns (see\n * platform.claude.com/docs/en/agent-sdk/user-input), just crossing a\n * process boundary via MCP instead of an in-process function call.\n */\n\nexport const APPROVAL_TOOL_NAME = 'approval_prompt';\n\n/** Bound on how much of a tool call's `input` gets folded into the wire `task.await_approval.summary` — mirrors `events.ts`'s `RESULT_DIAGNOSTIC_MAX_CHARS`/`truncateResultDiagnostic` convention: a human-facing summary, not a full audit record. */\nexport const APPROVAL_SUMMARY_MAX_CHARS = 500;\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/** `${toolName}: ${input}`, bounded — the human-readable description carried into `task.await_approval.summary` and (via the daemon/CLI's own rendering) whatever a real approver actually reads before deciding. */\nexport function summarizeToolCall(toolName: string, input: unknown): string {\n let inputStr: string;\n try {\n inputStr = JSON.stringify(input);\n } catch (err) {\n inputStr = `<unserializable input: ${errorMessage(err)}>`;\n }\n const bounded =\n inputStr.length > APPROVAL_SUMMARY_MAX_CHARS ? `${inputStr.slice(0, APPROVAL_SUMMARY_MAX_CHARS)}… [truncated]` : inputStr;\n return `${toolName}: ${bounded}`;\n}\n\nexport interface ApprovalOutcome {\n approved: boolean;\n reason?: string;\n}\n\n/** What `byok-approval-mcp.ts` (the real entry point) injects — the one real dependency this module has on the outside world. */\nexport interface ApprovalMcpDeps {\n /** Requests a decision from the daemon this task is running on. Any rejection/throw here is treated as fail-closed (deny) by `handleMcpRequest` — never surfaced to claude as a raw protocol error. */\n requestApproval(taskId: string, summary: string): Promise<ApprovalOutcome>;\n}\n\ninterface JsonRpcRequestLike {\n jsonrpc?: unknown;\n id?: unknown;\n method?: unknown;\n params?: unknown;\n}\n\n/**\n * Handles exactly one already-parsed JSON-RPC request object and returns the\n * exact response object to write back (`undefined` for a notification that\n * expects no reply, e.g. `notifications/initialized`) — no stdio/process\n * concerns at all, so tests call this directly with a stub {@link\n * ApprovalMcpDeps} instead of spawning a real process or a real control\n * socket. `serveApprovalMcpOverStdio` below is the only caller in production.\n */\nexport async function handleMcpRequest(\n req: JsonRpcRequestLike,\n deps: ApprovalMcpDeps,\n taskId: string,\n): Promise<Record<string, unknown> | undefined> {\n const id = req.id;\n\n if (req.method === 'initialize') {\n const params = (req.params ?? {}) as { protocolVersion?: unknown };\n return {\n jsonrpc: '2.0',\n id,\n result: {\n protocolVersion: typeof params.protocolVersion === 'string' ? params.protocolVersion : '2024-11-05',\n capabilities: { tools: {} },\n serverInfo: { name: 'byok-approval-mcp', version: '0.0.1' },\n },\n };\n }\n\n if (req.method === 'notifications/initialized') {\n return undefined; // notification — no response\n }\n\n if (req.method === 'tools/list') {\n return {\n jsonrpc: '2.0',\n id,\n result: {\n tools: [\n {\n name: APPROVAL_TOOL_NAME,\n description:\n 'Requests operator approval for a pending tool call. Blocks until a human (or this device\\'s daemon) decides, or the configured timeout elapses (fail-closed deny on timeout).',\n inputSchema: {\n type: 'object',\n properties: {\n tool_name: { type: 'string' },\n input: { type: 'object' },\n },\n },\n },\n ],\n },\n };\n }\n\n if (req.method === 'tools/call') {\n const params = (req.params ?? {}) as { name?: unknown; arguments?: unknown };\n if (params.name !== APPROVAL_TOOL_NAME) {\n return { jsonrpc: '2.0', id, error: { code: -32602, message: `unknown tool \"${String(params.name)}\"` } };\n }\n const args = (params.arguments ?? {}) as { tool_name?: unknown; input?: unknown };\n const toolName = typeof args.tool_name === 'string' ? args.tool_name : 'unknown tool';\n const input = args.input ?? {};\n const summary = summarizeToolCall(toolName, input);\n\n let outcome: ApprovalOutcome;\n try {\n outcome = await deps.requestApproval(taskId, summary);\n } catch (err) {\n // Fail-closed (task's own mandate): a daemon that's unreachable, a\n // control request that times out, or any other failure reaching the\n // approving device must never leave claude's own MCP call unanswered\n // — that risks claude abandoning the whole turn on its own (M4 Phase 3\n // STEP 0 found claude gives up on a permission-prompt-tool call that\n // never answers at all, ~1.5s in) rather than cleanly denying just\n // this one tool call and letting the conversation continue.\n outcome = { approved: false, reason: `could not reach the approving device: ${errorMessage(err)}` };\n }\n\n const payload = outcome.approved\n ? { behavior: 'allow' as const, updatedInput: input }\n : { behavior: 'deny' as const, message: outcome.reason ?? 'denied' };\n return { jsonrpc: '2.0', id, result: { content: [{ type: 'text', text: JSON.stringify(payload) }] } };\n }\n\n if (id !== undefined) {\n return { jsonrpc: '2.0', id, error: { code: -32601, message: `unknown method: ${String(req.method)}` } };\n }\n return undefined;\n}\n\nexport interface ServeApprovalMcpOptions {\n taskId: string;\n deps: ApprovalMcpDeps;\n /** Defaults to `process.stdin`/`process.stdout` — overridable so tests can drive this over in-memory streams. */\n input?: NodeJS.ReadableStream;\n output?: NodeJS.WritableStream;\n}\n\n/**\n * Wires {@link handleMcpRequest} to real NDJSON stdio (the MCP stdio\n * transport: one JSON-RPC message per line, both directions) — the only\n * genuinely process-shaped piece of this module. Each line is handled\n * independently and asynchronously (never serialized against the others),\n * since claude's own parallel-tool-use can legitimately fire more than one\n * concurrent `tools/call` over the same connection.\n */\nexport function serveApprovalMcpOverStdio(opts: ServeApprovalMcpOptions): void {\n const input = opts.input ?? process.stdin;\n const output = opts.output ?? process.stdout;\n const rl = createInterface({ input, terminal: false });\n\n rl.on('line', (line) => {\n const trimmed = line.trim();\n if (!trimmed) return;\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n return; // a stray non-JSON line is not this server's concern\n }\n void handleMcpRequest(parsed as JsonRpcRequestLike, opts.deps, opts.taskId).then((response) => {\n if (response !== undefined) output.write(`${JSON.stringify(response)}\\n`);\n });\n });\n}\n","import { execFile } from 'node:child_process';\nimport { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { promisify } from 'node:util';\nimport type { AgentEvent, TaskOfferPayload } from '@byok-sdk/protocol';\nimport {\n PolicyUnsupportedError,\n SteerUnsupportedError,\n type ApprovalChannel,\n type RuntimeAdapter,\n type RuntimeCapabilities,\n type RuntimeDetectResult,\n type RuntimeEnvironmentRequirements,\n type Session,\n type TaskContext,\n} from '../../types';\nimport { resolveClaudeBin, type ResolvedBin } from './resolve-bin';\nimport { resolveApprovalMcpBin, type ResolvedApprovalMcpBin } from './resolve-approval-mcp-bin';\nimport { mapPermissionPolicyToClaudeArgs } from './permission-mapping';\nimport { createToolUseCorrelation, mapClaudeMessageToAgentEvents, type ToolUseCorrelation } from './events';\nimport { ClaudeProcessClient, type SpawnFn } from './process-client';\nimport { APPROVAL_TOOL_NAME } from '../../bin/approval-mcp-server';\n\n/** The MCP server NAME this adapter registers `byok-approval-mcp` under in the generated `--mcp-config` (arbitrary, local to this file) — combined with {@link APPROVAL_TOOL_NAME} (imported, single-sourced from `bin/approval-mcp-server.ts` so the two can never independently drift) to form the `mcp__<server>__<tool>` identifier `--permission-prompt-tool` expects. */\nconst APPROVAL_MCP_SERVER_NAME = 'byokapproval';\n\nconst execFileAsync = promisify(execFile);\n\n/** Applied to both `detect()` probe calls (`--version`, `auth status --json`) — mirrors codex-adapter.ts's identical `DETECT_TIMEOUT_MS`/rationale exactly (cross-model review finding: these two claude probes previously had NO timeout at all, unlike codex's, so a hung claude CLI could block daemon startup and every `detect()` call indefinitely). `detect()` runs on every allowlist-narrowed task offer, so a small ceiling is cheap insurance against either probe ever unexpectedly hanging. */\nconst DETECT_TIMEOUT_MS = 5000;\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/** Best-effort teardown of the temp `--mcp-config` directory `start()` creates for `confirm` mode (see its own doc comment) — never throws, since a cleanup failure must never mask the real error/result it's cleaning up after. No-ops when `dir` is `undefined` (every mode other than `confirm`). */\nasync function cleanupApprovalMcpConfigDir(dir: string | undefined): Promise<void> {\n if (!dir) return;\n await fs.rm(dir, { recursive: true, force: true }).catch(() => {});\n}\n\nexport interface ClaudeAdapterOptions {\n /** Override bin resolution — tests substitute the fake-claude fixture script. */\n resolveBin?: () => ResolvedBin;\n /** Override process spawning — tests substitute a fake spawn. */\n spawnFn?: SpawnFn;\n /** M4 Phase 3: override `byok-approval-mcp` bin resolution — tests substitute a fixture script instead of computing a real dist path. Mirrors `resolveBin` above. */\n resolveApprovalMcpBin?: () => ResolvedApprovalMcpBin;\n}\n\n/**\n * Claude Code runtime adapter (`claude -p --input-format stream-json\n * --output-format stream-json`) — the M2-a counterpart to `../pi/pi-adapter.ts`.\n * Every behavioral claim in this file's own doc comments and its sibling\n * modules (`events.ts`, `permission-mapping.ts`, `process-client.ts`) was\n * empirically reproduced against the real installed `claude` 2.1.212 binary\n * on a logged-in machine (per this task's own \"do NOT trust docs over the\n * real binary\" mandate — `claude --help` was actively wrong/misleading for\n * `--allowedTools`, see `permission-mapping.ts`) — not inferred from\n * training-data recall or the Claude API/Agent-SDK docs, which describe a\n * DIFFERENT product surface (the Messages API, not this CLI's headless\n * wire format).\n *\n * ## The central finding: claude's headless approval model has no\n * `needs_approval` pause, at all\n *\n * This is the first real use of the `needs_approval` /\n * `Session.resolveApproval` seam any adapter in this codebase has\n * implemented (pi never emits `needs_approval` — see `PiSession\n * .resolveApproval`'s own doc comment) — so this finding directly informs\n * the M2-c protocol-freeze decision on that seam.\n *\n * Empirically (see the M2-a report for the full live-capture evidence):\n * spawning `claude -p` **non-interactively** with a tool call that would\n * normally prompt a human is resolved **synchronously, before the turn\n * continues** — there is no pause, no wait, no later resumption point:\n *\n * - Under `--permission-mode default` (or no flag at all — headless has no\n * TTY to interactively ask), an unapproved tool call is immediately\n * AUTO-DENIED with a synthesized `tool_result`\n * (`\"Claude requested permissions to write to <path>, but you haven't\n * granted it yet.\"`, `is_error:true`) and the run continues normally to\n * its own `result` frame — no hang, and nothing this adapter could ever\n * resume later even if it wanted to.\n * - Under a permissive `--permission-mode` (`acceptEdits`/`bypassPermissions`),\n * the call is auto-GRANTED, again synchronously, again with nothing to\n * pause on.\n *\n * There is consequently no claude stream-json frame this adapter could\n * ever map to the protocol's `needs_approval` `AgentEvent` — the decision\n * is always already made by the time any frame reaches this adapter at\n * all. `resolveApproval()` below throws a descriptive error rather than\n * silently no-op'ing, mirroring `PiSession.resolveApproval`'s own\n * documented reasoning exactly: a caller that ever receives\n * `task.approve`/`task.reject` for one of this adapter's tasks implies\n * something upstream expected approval support this adapter genuinely does\n * not have.\n *\n * `PermissionPolicy.mode: 'confirm'` — the policy mode whose whole point is\n * \"ask a human, then proceed\" — was therefore rejected outright at\n * `start()` through M2/M3 (fail-closed, see `permission-mapping.ts`), never\n * silently downgraded to auto-accept or auto-deny.\n *\n * ## M4 Phase 3 update: a genuine out-of-band pause DOES exist — it is\n * just invisible to everything written above\n *\n * `--permission-prompt-tool` (a DIFFERENT flag from `--permission-mode`,\n * undocumented in `claude --help`'s own output on the installed 2.1.216\n * binary but empirically confirmed accepted — an unrecognized flag is\n * rejected outright with `error: unknown option`, this one is not) makes\n * claude block a turn on a real MCP round-trip to a server it spawns\n * itself, waiting for that server to answer allow/deny before continuing —\n * genuinely pausing, for real wall-clock time (live-verified: an instant\n * allow/deny, AND a deliberate multi-second delayed answer, both worked\n * identically; only a permission-prompt-tool call that never answers AT\n * ALL was found to make claude abandon the turn on its own, after roughly\n * 1.5s — never actually reachable by this design, since the bundled\n * `bin/byok-approval-mcp.ts` always eventually answers within its own\n * configured ceiling).\n *\n * Everything above this section remains true and is NOT superseded by\n * this: claude's own stream-json output still emits nothing while this\n * pause is in progress — the gap between a `tool_use` frame and its\n * `tool_result` is indistinguishable from ordinary model latency on the\n * wire, and there is still no `needs_approval`-shaped frame this adapter's\n * event mapper could ever produce. The pause is real, but it is invisible\n * to `ClaudeSession.events` and to `task-runner.ts`'s `pump()` entirely —\n * it is only ever observable from OUTSIDE this adapter's own process, by\n * the separate MCP-server child process claude itself spawns. This is why\n * `confirm` mode's daemon-side wiring (`task-runner.ts`'s `requestApproval`,\n * `types.ts`'s `ApprovalChannel`) is driven from the control socket, not\n * from any `AgentEvent` — see those files' own doc comments for the full\n * design this finding drove. `confirm` is now SUPPORTED (see\n * `permission-mapping.ts` and `resolveApproval()` below), still fail-closed\n * whenever no approval channel was actually wired up for this session.\n *\n * ## Steering was also found unsupported (a second, related finding)\n *\n * Live-probed via a persistent `--input-format stream-json` process:\n * writing a second `{\"type\":\"user\",...}` message to stdin WHILE a turn is\n * still generating does NOT redirect that in-flight turn — it QUEUES as a\n * separate, subsequent turn, processed only after the first one reaches\n * its own `result`. This is genuinely useful for `followUp()` (a new turn\n * \"after [the session] has gone idle\" — exactly the queued-after-result\n * case), but it is not what `Session.steer`'s \"inject steering text into a\n * running turn (mid-stream)\" contract promises. `capabilities().steer` is\n * therefore `false`, and `steer()` throws rather than silently behaving\n * like a queued follow-up under a name that implies live redirection.\n */\nexport class ClaudeAdapter implements RuntimeAdapter {\n readonly id = 'claude';\n\n constructor(private readonly options: ClaudeAdapterOptions = {}) {}\n\n async detect(): Promise<RuntimeDetectResult> {\n const bin = this.resolveBin();\n try {\n // Empirically confirmed (unlike pi, which prints to stderr — see\n // ../pi/pi-adapter.ts's own doc comment on that): claude 2.1.212\n // prints `--version` output to STDOUT.\n const { stdout } = await execFileAsync(bin.command, ['--version'], { timeout: DETECT_TIMEOUT_MS });\n const version = stdout.trim();\n const authPresent = await this.probeAuthPresent(bin.command);\n return { present: true, version, authPresent };\n } catch {\n return { present: false };\n }\n }\n\n capabilities(): RuntimeCapabilities {\n // M4 Phase 3: 'confirm' added — see permission-mapping.ts's confirm-mode\n // doc comment for the empirical basis (`--permission-prompt-tool`,\n // live-verified against the real installed binary).\n // `approvalInteractive: true` — the confirm path is genuinely wired end\n // to end: `--permission-prompt-tool` → the out-of-process approval MCP\n // server (`bin/byok-approval-mcp.ts`) → this daemon's control socket →\n // `ClaudeSession.resolveApproval` really resuming the paused turn.\n return { steer: false, resume: true, approvalInteractive: true, permissionModes: ['auto', 'readonly', 'plan', 'confirm'] };\n }\n\n /**\n * M5: deliberate product-boundary decision, not an oversight — byok's\n * current ToS posture for claude is login-state-only (`claude auth\n * login`'s own OAuth session — see `probeAuthPresent` below), so this\n * adapter declares NO credential env vars at all; env-based API-key\n * passthrough for claude is a separate, still-pending product decision.\n * A product that genuinely needs it can opt in locally per-device via\n * `DaemonConfig.runtimeEnvironment.claude.allow` (`create-daemon.ts`).\n * `baseNames` is empty too: nothing in this adapter reads a\n * claude-specific config-discovery variable (e.g. `CLAUDE_CONFIG_DIR`)\n * today — if a future version of this adapter starts reading one, it\n * belongs here, not left to rely on the platform baseline alone.\n */\n environmentRequirements(): RuntimeEnvironmentRequirements {\n return { credentialNames: [] };\n }\n\n async start(task: TaskOfferPayload, ctx: TaskContext): Promise<Session> {\n if (typeof task.instruction !== 'string') {\n throw new PolicyUnsupportedError('claude adapter only supports string instructions in M2 (no blob-ref fetch yet)');\n }\n\n const mapping = mapPermissionPolicyToClaudeArgs(ctx.policy);\n if (!mapping.ok) {\n throw new PolicyUnsupportedError(mapping.reason ?? 'policy rejected by claude adapter');\n }\n\n // M4 Phase 3: `confirm` mode's approval channel. Generating the\n // temp --mcp-config file is a real filesystem side effect (see\n // permission-mapping.ts's `needsApprovalMcp` doc comment for why this\n // lives here, in start(), rather than in the pure mapping function) —\n // deliberately OUTSIDE ctx.workspaceDir (a fresh, 0700 os.tmpdir()\n // subdirectory instead) so it never shows up to the agent's own\n // workspace-scoped Read/Glob/Grep, even though its contents (a storeDir\n // path, productId, and this taskId — no secret/token material at all;\n // the actual control-socket auth token stays under storeDir, unrelated\n // to this file) would be low-value to an agent that found it anyway.\n let approvalMcpConfigDir: string | undefined;\n if (mapping.needsApprovalMcp) {\n if (!ctx.approvalChannel) {\n // Internal-consistency fail-closed: TaskRunner always populates this\n // (see task-runner.ts's handleOffer) — a missing one here means\n // something upstream is badly wired, not a normal policy rejection.\n throw new PolicyUnsupportedError(\n 'claude adapter requires policy.mode \"confirm\" to be started with an approval channel (TaskContext.approvalChannel) — none was provided',\n );\n }\n const approvalMcpBin = (this.options.resolveApprovalMcpBin ?? resolveApprovalMcpBin)();\n approvalMcpConfigDir = await fs.mkdtemp(path.join(os.tmpdir(), 'byok-approval-mcp-'));\n await fs.chmod(approvalMcpConfigDir, 0o700).catch(() => {});\n const mcpConfigPath = path.join(approvalMcpConfigDir, 'mcp-config.json');\n const mcpConfig = {\n mcpServers: {\n [APPROVAL_MCP_SERVER_NAME]: {\n command: approvalMcpBin.command,\n args: approvalMcpBin.args,\n env: {\n BYOK_STORE_DIR: ctx.approvalChannel.storeDir,\n BYOK_PRODUCT_ID: ctx.approvalChannel.productId,\n BYOK_TASK_ID: ctx.approvalChannel.taskId,\n BYOK_APPROVAL_TIMEOUT_MS: String(ctx.approvalChannel.timeoutMs),\n },\n },\n },\n };\n await fs.writeFile(mcpConfigPath, JSON.stringify(mcpConfig), { mode: 0o600 });\n mapping.args = [\n ...mapping.args,\n '--permission-prompt-tool',\n `mcp__${APPROVAL_MCP_SERVER_NAME}__${APPROVAL_TOOL_NAME}`,\n '--mcp-config',\n mcpConfigPath,\n // Never let this task's confirm-mode run pick up some OTHER MCP\n // server from ambient project/user config — the approval channel is\n // the only MCP server this invocation should ever see.\n '--strict-mcp-config',\n ];\n }\n\n const bin = this.resolveBin();\n const resumeSessionId = task.sessionRef;\n const args = [\n '-p',\n '--input-format',\n 'stream-json',\n '--output-format',\n 'stream-json',\n // REQUIRED alongside `--output-format stream-json` in `--print` mode —\n // empirically confirmed: omitting this exits 1 immediately with\n // \"Error: When using --print, --output-format=stream-json requires\n // --verbose\", before spawning any model call.\n '--verbose',\n ...(resumeSessionId ? ['--resume', resumeSessionId] : []),\n ...mapping.args,\n ];\n\n const client = new ClaudeProcessClient({\n command: bin.command,\n args,\n cwd: ctx.workspaceDir,\n env: ctx.env,\n spawnFn: this.options.spawnFn,\n });\n\n // `--input-format stream-json` expects the first turn's instruction on\n // stdin too, not as a positional CLI argument — empirically confirmed\n // live (this task's persistent-process multi-turn probes never passed\n // a positional prompt at all, relying entirely on this same write for\n // turn one). Using the identical mechanism for turn one and every\n // `followUp()` afterward (see `ClaudeSession.followUp` /\n // `ClaudeProcessClient.writeUserMessage`) avoids two different\n // send-a-prompt code paths.\n client.writeUserMessage(task.instruction);\n\n let sessionRef: string;\n try {\n // Resolves with claude's own real `session_id` off its `system/init`\n // frame — see `ClaudeProcessClient.waitForInit`'s doc comment for why\n // this is needed at all (claude's stream-json protocol has no\n // request/response ack the way pi's RPC mode does) and why, unlike\n // pi's `resolveFreshSessionId`, no separate follow-up round-trip is\n // needed: claude always surfaces `session_id` directly on the very\n // first frame of a successful run, resume or fresh alike (confirmed:\n // a `--resume <id>` run's own `system/init.session_id` always equals\n // the requested id). An unresolvable `--resume` target (or any other\n // immediate failure) never emits an `init` frame at all and instead\n // exits promptly — `waitForInit()` rejects with the enriched exit\n // error in that case (see `process-client.ts`), which is exactly\n // what should make `start()` fail here, fail-closed, never a\n // fabricated sessionRef.\n sessionRef = await client.waitForInit();\n } catch (err) {\n client.kill();\n await cleanupApprovalMcpConfigDir(approvalMcpConfigDir);\n throw err;\n }\n\n // Cross-model review finding: the doc comment above states this is\n // \"confirmed\" to always hold empirically — but nothing actually verified\n // it in code, so a future/unobserved claude behavior (or a bug) silently\n // resuming a DIFFERENT session than `task.sessionRef` asked for would\n // have gone completely unnoticed: this adapter would return a\n // `ClaudeSession` for whatever `sessionRef` claude happened to report,\n // running the task against the wrong workspace/history with no signal\n // to the caller at all. Fail closed instead of trusting the assumption.\n if (resumeSessionId !== undefined && sessionRef !== resumeSessionId) {\n client.kill();\n await cleanupApprovalMcpConfigDir(approvalMcpConfigDir);\n throw new Error(\n `claude --resume echoed a different session id than requested (requested ${resumeSessionId}, got ${sessionRef}) — refusing to continue in a possibly-wrong session (fail-closed)`,\n );\n }\n\n return new ClaudeSession(sessionRef, client, ctx.workspaceDir, ctx.approvalChannel, approvalMcpConfigDir);\n }\n\n /**\n * `claude auth status --json` is claude's OWN non-secret login-state\n * signal (see the credential-isolation rule on `RuntimeAdapter` in\n * `../../types.ts`) — empirically confirmed live on this logged-in\n * machine to report `{\"loggedIn\":true,\"authMethod\":\"claude.ai\",\n * \"apiProvider\":\"firstParty\",\"email\":\"...\",\"orgId\":\"...\",\"orgName\":\"...\",\n * \"subscriptionType\":\"max\"}`, with no token/key material anywhere in it.\n * This spawns the binary and parses ONLY its own reported status — it\n * never reads `~/.claude` or any credential file itself, matching pi's\n * `authPresent` computation being limited to environment-variable\n * *names* (`../pi/pi-adapter.ts`'s `KNOWN_PROVIDER_ENV_VARS`), just via\n * claude's own equivalent non-secret probe instead (claude's auth is\n * OAuth-session-based via `claude auth login`, not primarily an env var,\n * so pi's env-var-presence approach doesn't apply here the same way).\n * A failed/unparseable probe (binary present but not logged in, a future\n * claude release changing this output shape, etc.) fails closed to\n * `false` — this never affects `present`, which is solely about whether\n * `--version` itself succeeded.\n */\n private async probeAuthPresent(command: string): Promise<boolean> {\n try {\n const { stdout } = await execFileAsync(command, ['auth', 'status', '--json'], { timeout: DETECT_TIMEOUT_MS });\n const parsed = JSON.parse(stdout) as { loggedIn?: unknown };\n return parsed.loggedIn === true;\n } catch {\n return false;\n }\n }\n\n private resolveBin(): ResolvedBin {\n return (this.options.resolveBin ?? resolveClaudeBin)();\n }\n}\n\nclass ClaudeSession implements Session {\n private readonly correlation: ToolUseCorrelation = createToolUseCorrelation();\n\n constructor(\n public readonly sessionRef: string,\n private readonly client: ClaudeProcessClient,\n private readonly workspaceDir: string,\n /** M4 Phase 3: set only when this session was started under `policy.mode: 'confirm'` — see `resolveApproval()`. */\n private readonly approvalChannel?: ApprovalChannel,\n /** M4 Phase 3: the temp `--mcp-config` directory `start()` created for this session, if any — removed in `close()`. */\n private readonly approvalMcpConfigDir?: string,\n ) {}\n\n get events(): AsyncIterable<AgentEvent> {\n const client = this.client;\n const correlation = this.correlation;\n const workspaceDir = this.workspaceDir;\n return {\n [Symbol.asyncIterator](): AsyncIterator<AgentEvent> {\n const inner = client.events[Symbol.asyncIterator]();\n // A single raw claude frame can map to more than one AgentEvent\n // (e.g. a Write `tool_result` plus a derived `artifact` — see\n // `events.ts`'s `mapUser`) — buffered here and drained before\n // pulling the next raw line, so this iterator still yields exactly\n // one `AgentEvent` per `next()` call like every other adapter's\n // `Session.events`.\n let pending: AgentEvent[] = [];\n // Cross-model re-review finding (P1 regression, the \"claude-hang\n // class\"): set once THIS turn's own `result` frame has been read off\n // `inner` — `result` is claude's real \"whole run settled\" signal and\n // is always the LAST frame of a turn, success or failure alike (see\n // `events.ts`'s `mapResult` doc comment). On the SUCCESS path\n // (`turn_end`) this is inert: `task-runner.ts`'s `pump()` returns the\n // instant it sees `turn_end`, so no further `next()` call ever\n // happens. It matters on the FAILURE/malformed path: `mapResult`\n // maps a non-success result to a plain `error` AgentEvent with no\n // `turn_end` — and unlike codex (one process per turn, whose own\n // process-close watcher ends the queue — see codex-adapter.ts's\n // `runCodexTurn`), claude's process is PERSISTENT: it stays alive\n // after `result`, awaiting a possible `followUp()` write on stdin\n // (see process-client.ts's own doc comment). Nothing would otherwise\n // ever end this iterator, so `task-runner.ts`'s `pump()` would await\n // a raw line that never arrives — a real, confirmed hang, not just a\n // theoretical one. Once `turnSettled` is true and `pending` has been\n // fully drained (every event from the `result` frame delivered),\n // this iterator ends itself (`done:true`) WITHOUT pulling `inner`\n // again — ending only THIS TURN's own exposed event stream, never\n // the underlying session-lifetime `client.events` queue a future\n // `followUp()` still needs, and never killing the process itself\n // (that stays this session's `close()`/`interrupt()`'s job). This is\n // exactly what lets `pump()`'s existing \"iterable ended without\n // turn_end\" branch report the task as Failed instead of hanging.\n let turnSettled = false;\n return {\n async next(): Promise<IteratorResult<AgentEvent>> {\n for (;;) {\n const buffered = pending.shift();\n if (buffered) return { value: buffered, done: false };\n\n if (turnSettled) return { value: undefined as never, done: true };\n\n const { value, done } = await inner.next();\n if (done) return { value: undefined as never, done: true };\n\n if (value.type === 'result') turnSettled = true;\n\n const mapped = mapClaudeMessageToAgentEvents(value, correlation, { workspaceDir });\n if (mapped.unmappedLabel) {\n client.recordUnmappedFrame(mapped.unmappedLabel);\n }\n if (mapped.events.length > 0) {\n pending = mapped.events;\n }\n // Nothing to yield yet (routine frame, or an unmapped one) —\n // loop around and pull the next raw line.\n }\n },\n };\n },\n };\n }\n\n /**\n * Not supported — see the class-level doc comment on `ClaudeAdapter` for\n * the full empirical basis (a message written to stdin mid-turn was\n * proven to queue as a follow-up turn, not redirect the running one).\n * `capabilities().steer` reports `false` for exactly this reason; this\n * throws rather than silently behaving like `followUp()` under the\n * `steer()` name, which would promise live redirection it cannot deliver.\n */\n async steer(): Promise<void> {\n throw new SteerUnsupportedError(\n 'claude',\n 'claude adapter does not support mid-turn steering: writing to claude\\'s stdin while a turn is in flight queues as a separate subsequent turn rather than redirecting the running one (empirically confirmed) — see capabilities().steer',\n );\n }\n\n async followUp(task: TaskOfferPayload): Promise<void> {\n if (typeof task.instruction !== 'string') {\n throw new PolicyUnsupportedError('claude adapter only supports string instructions in M2 (no blob-ref fetch yet)');\n }\n // Writes onto the SAME persistent process this session already has\n // open — empirically confirmed live that claude keeps a\n // `--input-format stream-json` process alive across sequential turns,\n // reusing the identical `session_id`, until stdin closes or the\n // process is killed (see `ClaudeProcessClient.writeUserMessage`'s doc\n // comment).\n this.client.writeUserMessage(task.instruction);\n }\n\n /**\n * Real claude has no distinct \"abort but stay alive\" primitive the way\n * pi's RPC mode does (`{type:'abort'}`, after which pi keeps running and\n * stays queryable) — nothing in `claude --help` exposes one, and this\n * task's probes found none. SIGTERM (via `ClaudeProcessClient.kill()`)\n * is the only verified way to stop an in-flight turn, so `interrupt()`\n * and `close()` both resolve to the same underlying action here. This is\n * consistent with how they are actually used together: `task-runner.ts`'s\n * `handleCancel` always calls `interrupt()` immediately followed by\n * `close()` on the same task, never `interrupt()` alone expecting the\n * session to remain usable afterward.\n */\n async interrupt(): Promise<void> {\n this.client.kill();\n }\n\n async close(): Promise<void> {\n this.client.kill();\n await cleanupApprovalMcpConfigDir(this.approvalMcpConfigDir);\n }\n\n /**\n * M4 Phase 3: routes into the out-of-band approval channel `start()`\n * threaded through from `TaskContext.approvalChannel` — see that type's\n * own doc comment (`../../types.ts`) for the full design, and\n * `permission-mapping.ts`'s `confirm`-mode doc comment for the empirical\n * basis. `approved`/`reason` map directly onto `ApprovalChannel.resolve`'s\n * own parameters, which in turn resolve the SAME `ApprovalRegistry` entry\n * `bin/byok-approval-mcp.ts`'s pending `approvals.request` control call is\n * awaiting — answering that call is what lets claude's own blocked\n * `tools/call` (and therefore the paused turn) proceed.\n *\n * Still throws when no channel is present — every adapter/session that\n * ISN'T running under `confirm` mode (the overwhelming majority) has\n * nothing to resolve, and a caller receiving `task.approve`/`task.reject`\n * for one of those implies something upstream expected approval support\n * that isn't there, exactly as this method's doc comment always said.\n * `ApprovalChannel.resolve` itself throws the equally-descriptive \"no\n * pending approval\" error for the narrower case (confirm mode, but nothing\n * currently pending) — this method doesn't need its own separate check for\n * that.\n */\n async resolveApproval(approved: boolean, reason?: string): Promise<void> {\n if (!this.approvalChannel) {\n throw new Error(\n 'claude adapter has no approval channel for this session (not running under policy.mode \"confirm\") — under every other mode, claude resolves every permission decision synchronously (auto-denied under a restrictive --permission-mode, auto-granted under a permissive one) before this adapter ever sees the corresponding frame, so there is nothing to resume later',\n );\n }\n await this.approvalChannel.resolve(approved, reason);\n }\n}\n","export interface ResolvedBin {\n command: string;\n source: 'env' | 'path';\n}\n\n/**\n * Resolve the codex CLI executable.\n *\n * Unlike pi (bundled as an npm optionalDependency — see\n * `../pi/resolve-bin.ts`), the real OpenAI Codex CLI (empirically `codex-cli\n * 0.144.5` on the machine this adapter was built/verified against, installed\n * at a plain PATH location — not inside this repo's `node_modules`) is not\n * published as an npm package this SDK could sensibly depend on: it's a\n * standalone global install (native installer / `npm i -g @openai/codex` /\n * homebrew, depending on platform and version). There is no package-relative\n * resolution to attempt, so this is simpler than pi's version: an explicit\n * override for tests, else a bare PATH lookup.\n *\n * `BYOK_CODEX_BIN` overrides PATH lookup — substituting the fake-codex test\n * fixture, exactly like `BYOK_PI_BIN` does for pi. The `byok-agent` CLI bin\n * only ever constructs `new CodexAdapter()` with no options (mirroring\n * `createDaemon`'s pi wiring), so an out-of-process substitution (e.g. a\n * future e2e harness swapping in a fake binary ahead of a real codex install)\n * has no other seam to use.\n */\nexport function resolveCodexBin(): ResolvedBin {\n const override = process.env.BYOK_CODEX_BIN;\n if (override) {\n return { command: override, source: 'env' };\n }\n return { command: 'codex', source: 'path' };\n}\n","import type { PermissionPolicy } from '@byok-sdk/protocol';\n\nexport interface CodexPermissionMapping {\n ok: boolean;\n /** `-c key=value` args (as separate argv entries, e.g. `['-c', 'sandbox_mode=read-only']`) to append to `codex exec`/`codex exec resume`. Only meaningful when `ok` is true. */\n args: string[];\n /** Present when `ok` is false. */\n reason?: string;\n}\n\n/**\n * Map an effective {@link PermissionPolicy} to `codex exec`/`codex exec\n * resume` CLI args, fail-closed. Empirically grounded against the real\n * installed `codex exec --json` (`codex-cli 0.144.5`) — every claim below was\n * driven live in a scratch directory before being encoded here, exactly like\n * the pi adapter's own M0-3 findings (`../pi/permission-mapping.ts`), and the\n * same class of \"the CLI's own --help lies\" bug showed up again independently\n * (see the confirm/plan case below).\n *\n * - Uses `-c sandbox_mode=<value>` (a config-override key), NEVER the `-s`/\n * `--sandbox` CLI flag, and NEVER `-a`/`--ask-for-approval`:\n * - `-s`/`--sandbox` works on a fresh `codex exec` but is REJECTED\n * outright (\"error: unexpected argument '-s' found\") on `codex exec\n * resume` — confirmed against the real binary, not inferred from\n * --help (which lists `-s` for `exec` but, correctly for once, omits\n * it entirely from `resume`'s own --help).\n * - `-a`/`--ask-for-approval` is documented in `codex exec --help`\n * itself, yet REJECTED outright by `codex exec`'s real arg parser\n * (\"error: unexpected argument '-a' found\") — a second, independent\n * instance of the exact doc/binary mismatch class the pi adapter's own\n * `--session-id`/`--exclude-tools` findings already hit. Never used.\n * - `-c sandbox_mode=...` was confirmed empirically to produce the\n * IDENTICAL restriction as `-s` on a fresh `exec` (a read-only-sandbox\n * write attempt fails the same way either way), and to also work on\n * `resume` (where `-s` cannot be used at all) — so this one mechanism\n * is used everywhere, for both a fresh start and every later resume,\n * instead of switching mechanisms depending on call site.\n * - CRITICAL: `codex exec resume` does NOT auto-inherit the sandbox mode\n * the session was originally started with. Empirically confirmed: a\n * session started with `sandbox_mode=read-only` (which correctly\n * denied a write on its first turn) had that SAME write SUCCEED on a\n * later `codex exec resume` with no sandbox flag re-passed — silently\n * falling back to this machine's own ambient `~/.codex/config.toml`\n * default. This is exactly the \"silently widens\" failure this whole\n * mapping exists to prevent, so this adapter re-pins\n * `-c sandbox_mode=...` (and `-c approval_policy=never`, see below) on\n * *every* invocation — the initial `start()` AND every `followUp()` —\n * never relying on \"it was already set once.\"\n * - `auto` -> `sandbox_mode=workspace-write`. Empirically, this permits\n * writes inside the given cwd (the task workspace) AND the OS temp dir\n * (e.g. `/tmp`/`$TMPDIR`) — NOT strictly confined to the workspace, a\n * real, non-obvious scope worth knowing about (confirmed: a shell write to\n * `/tmp/...` succeeds even though it's outside `ctx.workspaceDir`; a write\n * to `$HOME` is correctly denied with a clean \"operation not permitted\",\n * not a hang or silent no-op).\n * - `readonly` -> `sandbox_mode=read-only`. Empirically denies every write —\n * both `apply_patch`-style file edits and shell-redirection writes — with\n * an immediate, clean, non-interactive denial (real stderr: \"writing is\n * blocked by read-only sandbox; rejected by user approval settings\").\n * Never a hang, never a silent bypass.\n * - `confirm` / `plan` are NOT expressible and fail closed. `codex exec` has\n * no interactive approval channel at all in this build — confirmed two\n * independent ways: (1) the flag that would request one (`-a`/\n * `--ask-for-approval`) is rejected outright by the real parser (see\n * above); (2) even reaching the underlying setting via the `-c\n * approval_policy=...` config-key path (which IS accepted), a\n * sandbox-denied action under a non-`never` policy resolves the \"ask\"\n * *internally* with no wire-visible pause and no way for an external\n * caller to answer it: it just auto-denies, and the model narrates the\n * denial as a normal `agent_message` — there is no `needs_approval`-\n * equivalent signal anywhere in the `--json` stream to map to (see\n * `../codex/events.ts`'s module doc comment). `plan` has no dedicated\n * codex equivalent either (no plan-only/no-exec CLI mode exists on this\n * build). Rather than pretend either is supported, both fail closed here —\n * the same posture as pi's own `confirm`/`plan` rejection.\n * - `network: true` is NOT expressible and fails closed. The one config key\n * that should enable network under `workspace-write`\n * (`sandbox_workspace_write.network_access=true`) was tested three times\n * against the real binary — including a pure `-c`-only invocation with no\n * `-s` flag mixed in, ruling out CLI-flag/config-table interference as the\n * cause — and never restored real network access: a `curl` to a live host\n * still failed every time, though its failure mode shifted from a\n * DNS-level block (exit 6, \"Could not resolve host\") to a data-level block\n * (exit 56, \"Failure receiving network data\"), hinting the override does\n * *something* internally but not enough to trust as a real grant. A\n * control run under `sandbox_mode=danger-full-access` confirmed network\n * genuinely works from this environment (HTTP 200), so the gap is in this\n * specific override on this codex build, not the test methodology. This\n * adapter never silently proceeds without the grant it was asked for, so\n * `network: true` is rejected rather than quietly running with no network\n * and no explanation. `network: false`/unset needs no special handling:\n * both sandbox modes this adapter ever selects have NO network by default\n * (confirmed empirically for both `read-only` and plain `workspace-write`)\n * — the safe case is also the default case, so nothing to enforce.\n * - `allowTools`/`denyTools` are NOT expressible and fail closed when\n * non-empty. `codex exec` has no verified per-tool allow/deny surface —\n * only the coarse `sandbox_mode` dial — unlike pi's real `--tools`/\n * `--no-tools`. Rather than silently drop a requested tool restriction,\n * this rejects it outright.\n * - `approval_policy=never` is pinned unconditionally on every `ok: true`\n * result, for the same \"never trust the ambient default\" reason as\n * `sandbox_mode` above: a fresh `codex exec` invoked with NO sandbox/\n * approval flags at all on the reference machine successfully ran a live\n * network `curl` with zero prompting — proof this machine's own\n * `~/.codex/config.toml` default is more permissive than anything this\n * adapter should ever grant implicitly. Every invocation pins both keys\n * explicitly so behavior never depends on the end user's own codex config.\n */\nexport function mapPermissionPolicyToCodexArgs(policy: PermissionPolicy): CodexPermissionMapping {\n if (policy.mode === 'confirm' || policy.mode === 'plan') {\n return {\n ok: false,\n args: [],\n reason: `codex adapter cannot express permission mode \"${policy.mode}\" (codex exec has no interactive approval channel — sandbox-denied actions resolve internally with no needs_approval-equivalent wire signal, and -a/--ask-for-approval is rejected outright by codex exec's real arg parser despite being documented in --help)`,\n };\n }\n\n if (policy.network === true) {\n return {\n ok: false,\n args: [],\n reason:\n 'codex adapter cannot guarantee network:true (empirically, -c sandbox_workspace_write.network_access=true did not restore real network access on the installed codex build — see this file\\'s module doc comment) — never silently proceeds without the requested grant',\n };\n }\n\n if ((policy.allowTools && policy.allowTools.length > 0) || (policy.denyTools && policy.denyTools.length > 0)) {\n return {\n ok: false,\n args: [],\n reason:\n 'codex adapter cannot express allowTools/denyTools (codex exec has no verified per-tool allow/deny surface, only the coarse sandbox_mode) — never silently ignores a requested tool restriction',\n };\n }\n\n const sandboxMode = policy.mode === 'readonly' ? 'read-only' : 'workspace-write';\n return { ok: true, args: ['-c', `sandbox_mode=${sandboxMode}`, '-c', 'approval_policy=never'] };\n}\n","import path from 'node:path';\nimport type { AgentEvent } from '@byok-sdk/protocol';\nimport type { CodexRawEvent } from './process-runner';\n\n/**\n * `codex exec --json` event catalog, empirically captured (raw JSONL frames,\n * not inferred from docs) driving the real installed `codex-cli 0.144.5`\n * across: plain chat, file writes (`apply_patch`-style), shell commands,\n * network attempts, sandbox denials, an invalid-model API error, and a\n * SIGTERM-killed-then-resumed thread. Two nesting levels: top-level frames\n * (`thread.started`, `turn.started`, `item.started`, `item.completed`,\n * `turn.completed`, `turn.failed`, and a top-level `error` distinct from any\n * item), and — inside `item.started`/`item.completed` — a nested `item.type`\n * (`agent_message`, `command_execution`, `file_change`, `error`).\n *\n * `thread.started` (always the first line codex ever prints, both for a\n * fresh `codex exec` and for `codex exec resume`) is deliberately NOT\n * handled here — it's consumed directly by `../codex-adapter.ts`'s\n * `runCodexTurn` to resolve `Session.sessionRef` before this mapper ever\n * sees a line, mirroring how pi's adapter resolves a fresh session id via\n * `get_state` before constructing its `Session` (`../pi/pi-adapter.ts`'s\n * `resolveFreshSessionId`). It's still listed in\n * {@link ROUTINE_CODEX_EVENT_TYPES} for defensiveness, in case it were ever\n * unexpectedly seen again mid-stream.\n *\n * No case here ever produces `{type: 'needs_approval'}` — deliberately, not\n * an oversight. `codex exec` (this build) has no wire-visible signal for it\n * at all: a sandbox-denied action under any approval policy resolves\n * internally with no pause an external caller could ever answer — confirmed\n * empirically (a `sandbox_mode=read-only` write attempt, and separately an\n * `approval_policy=untrusted` shell command outside the sandbox's own\n * trusted-command allowlist, both either just ran when the sandbox allowed\n * it or were silently auto-denied when it didn't, narrated only as a normal\n * `agent_message` — never a distinct event this mapper could hook). See\n * `../codex-adapter.ts`'s `resolveApproval`, which throws rather than\n * pretending to support a resume path that cannot exist on the wire.\n */\nexport function mapCodexEventToAgentEvents(evt: CodexRawEvent, workspaceDir: string): AgentEvent[] {\n switch (evt.type) {\n case 'turn.completed': {\n // `usage` (input/cached-input/output/reasoning-output token counts) —\n // pre-freeze protocol change (see `packages/protocol/src/agent-event.ts`)\n // added a `usage` AgentEvent variant specifically for this data, which\n // was real and present here but had no wire slot before that. Mapped\n // 1:1 from codex's own field names (`extractCodexUsageEvent` below);\n // no `total_tokens` field has ever been observed on real codex output,\n // so `totalTokens` is never populated here — never synthesized by\n // summing, per this adapter's \"forward only what's actually reported\"\n // convention.\n //\n // Ordering is load-bearing, not stylistic: `usage` is placed BEFORE\n // `turn_end` in the returned array. `codex-adapter.ts`'s `runCodexTurn`\n // pushes each element of this array onto the session's queue in order,\n // and `task-runner.ts`'s `pump()` returns immediately (ending the read\n // loop) the instant it sees `turn_end` — an event queued AFTER it would\n // never be drained. See `../claude/events.ts`'s `mapResult`, which has\n // the identical ordering constraint for the same reason.\n const usageEvent = extractCodexUsageEvent(evt.usage);\n return usageEvent ? [usageEvent, { type: 'turn_end' }] : [{ type: 'turn_end' }];\n }\n\n case 'turn.failed':\n // The real turn-level failure signal — NOT `item.completed{type:\n // 'error'}` (see below, which is informational/non-fatal and can\n // appear even on a fully successful turn). Deliberately does NOT also\n // synthesize a `turn_end`: task-runner.ts's `pump()` only treats an\n // explicit `turn_end` as success, and an events iterable that ends\n // without one already reports `task.fail` on its own (the codex\n // process exits non-zero right after this frame, ending the stream\n // naturally) — so this only needs to make the failure reason visible\n // via `task.progress` before that happens.\n return [{ type: 'error', message: extractErrorMessage(evt.error) ?? 'codex turn failed' }];\n\n case 'error':\n // Top-level (not nested in an item) — empirically seen paired\n // immediately before a `turn.failed`, carrying the same underlying API\n // error message (itself a JSON-encoded string from the provider\n // response) verbatim, deliberately not re-parsed — forwarding exactly\n // what codex reported is more honest than guessing at its structure.\n return [{ type: 'error', message: typeof evt.message === 'string' ? evt.message : 'codex reported an error' }];\n\n case 'item.started':\n return mapItem(evt.item, 'started', workspaceDir);\n\n case 'item.completed':\n return mapItem(evt.item, 'completed', workspaceDir);\n\n // `thread.started`/`turn.started` carry no AgentEvent-mappable content —\n // see the module doc comment above for why `thread.started` is handled\n // upstream instead. Both are also listed in ROUTINE_CODEX_EVENT_TYPES.\n case 'thread.started':\n case 'turn.started':\n return [];\n\n default:\n return []; // caller (codex-adapter.ts) records this as an unmapped frame unless isRoutineCodexEvent(evt)\n }\n}\n\n/**\n * Maps `turn.completed.usage` to a `usage` `AgentEvent`, or `undefined` when\n * nothing usable is present (e.g. `usage: {}`, empirically also seen on real\n * codex — never emit a content-free `usage` event just because the key\n * existed). Field names are verbatim from real codex output — confirmed live\n * against the installed `codex-cli` binary while building this mapping\n * (`turn.completed` -> `{\"usage\":{\"input_tokens\":24963,\"cached_input_tokens\":\n * 9984,\"output_tokens\":5,\"reasoning_output_tokens\":0}}`), matching the\n * shape this adapter's own fixture (`fake-codex.mjs`) and unit tests already\n * encoded from the ORIGINAL M2-b capture. `0` is a real, reportable value\n * (not absence) for every one of these fields — only a non-number/missing\n * value is treated as \"not reported\".\n */\nfunction extractCodexUsageEvent(rawUsage: unknown): AgentEvent | undefined {\n if (!rawUsage || typeof rawUsage !== 'object') return undefined;\n const usage = rawUsage as Record<string, unknown>;\n const inputTokens = toNonNegativeInt(usage.input_tokens);\n const cachedInputTokens = toNonNegativeInt(usage.cached_input_tokens);\n const outputTokens = toNonNegativeInt(usage.output_tokens);\n const reasoningTokens = toNonNegativeInt(usage.reasoning_output_tokens);\n if (\n inputTokens === undefined &&\n cachedInputTokens === undefined &&\n outputTokens === undefined &&\n reasoningTokens === undefined\n ) {\n return undefined;\n }\n const event: Extract<AgentEvent, { type: 'usage' }> = { type: 'usage' };\n if (inputTokens !== undefined) event.inputTokens = inputTokens;\n if (cachedInputTokens !== undefined) event.cachedInputTokens = cachedInputTokens;\n if (outputTokens !== undefined) event.outputTokens = outputTokens;\n if (reasoningTokens !== undefined) event.reasoningTokens = reasoningTokens;\n return event;\n}\n\n/** Matches `AgentEventSchema`'s `usage` fields (`z.number().int().nonnegative().optional()`) — anything else (missing, a string, a float, negative) is treated as not-reported rather than coerced. */\nfunction toNonNegativeInt(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0 ? value : undefined;\n}\n\ntype ItemPhase = 'started' | 'completed';\n\nfunction mapItem(rawItem: unknown, phase: ItemPhase, workspaceDir: string): AgentEvent[] {\n if (!rawItem || typeof rawItem !== 'object') return [];\n const item = rawItem as Record<string, unknown>;\n const itemType = item.type;\n\n switch (itemType) {\n case 'agent_message': {\n // Empirically only ever observed as `item.completed` — codex delivers\n // the whole message atomically, not as streamed token deltas the way\n // pi's `text_delta` does (see `../pi/events.ts`). An `item.started`\n // for `agent_message` has never been seen; if it ever is, this falls\n // through to the empty-array default and gets flagged as unmapped\n // (see `isRoutineCodexEvent`/`unmappedFrameKey`) rather than silently\n // treated as equivalent to `.completed`.\n if (phase !== 'completed') return [];\n return typeof item.text === 'string' ? [{ type: 'progress', text: item.text }] : [];\n }\n\n case 'command_execution': {\n const command = typeof item.command === 'string' ? item.command : undefined;\n if (phase === 'started') {\n return command !== undefined ? [{ type: 'tool_use', tool: 'command_execution', input: { command } }] : [];\n }\n return [\n {\n type: 'tool_result',\n tool: 'command_execution',\n output: {\n command,\n aggregatedOutput: item.aggregated_output,\n exitCode: item.exit_code,\n status: item.status,\n },\n },\n ];\n }\n\n case 'file_change': {\n const changes = Array.isArray(item.changes) ? item.changes : [];\n if (phase === 'started') {\n return [{ type: 'tool_use', tool: 'file_change', input: { changes } }];\n }\n return [\n { type: 'tool_result', tool: 'file_change', output: { changes, status: item.status } },\n ...extractArtifactEvents(changes, workspaceDir),\n ];\n }\n\n case 'error': {\n // Informational/warning-level, NOT necessarily a task failure — e.g.\n // \"Exceeded skills context budget...\" (this environment's installed\n // skill count exceeds codex's own model-visible budget) appeared as\n // `item_0` on EVERY single empirical capture made while building this\n // adapter, success or failure alike, and \"Model metadata for `<bad\n // model>` not found. Defaulting to fallback metadata...\" appeared\n // ahead of a turn that otherwise still ran. Forwarded honestly as an\n // `AgentEvent` (task-runner.ts's `pump()` already tolerates `error`\n // AgentEvents as non-fatal progress — see its own `sendArtifact`\n // failure handling, which does the same) rather than pattern-matching\n // on message text to guess which `error` items \"really\" matter, which\n // would be fragile and machine-specific (this exact notice may not\n // even appear on a machine with fewer installed codex skills).\n return typeof item.message === 'string' ? [{ type: 'error', message: item.message }] : [];\n }\n\n default:\n return [];\n }\n}\n\n/**\n * `file_change` items report the changed file's ABSOLUTE path. Converting to\n * a workspace-relative name before emitting an `artifact` AgentEvent matters\n * for two independent reasons, not just style:\n *\n * 1. `task-runner.ts`'s `openArtifact(workspaceDir, name)` resolves `name`\n * via `path.resolve(realWorkspaceDir, name)` — and `path.resolve` returns\n * an absolute second argument VERBATIM, discarding `realWorkspaceDir`\n * entirely (unlike `path.join`). Handing it codex's raw absolute path\n * would only happen to pass its containment check by coincidence (when\n * that absolute path happens to already be textually prefixed by the\n * realpath'd workspace dir) rather than by the intended, robust\n * relative-path contract every other adapter's artifact name follows\n * (pi's fixture, e.g., always uses a simple relative filename).\n * 2. It lets this mapper itself fail closed — skip, don't forward — a\n * `file_change` that (for whatever reason) landed outside the given\n * `workspaceDir` (`path.relative` starting with `..`), rather than\n * silently handing task-runner.ts's own containment check a path it has\n * to reject on this adapter's behalf.\n *\n * `contentType` is a best-effort extension guess: `file_change` items report\n * only `path`/`kind`, never a content type (unlike pi's synthetic artifact\n * message, which carries one directly) — `application/octet-stream` for\n * anything not in the small known-extension table below is an honest \"don't\n * know\" default, not a wrong guess dressed up as a real one.\n */\nfunction extractArtifactEvents(changes: unknown[], workspaceDir: string): AgentEvent[] {\n const events: AgentEvent[] = [];\n for (const rawChange of changes) {\n if (!rawChange || typeof rawChange !== 'object') continue;\n const change = rawChange as Record<string, unknown>;\n const absolutePath = typeof change.path === 'string' ? change.path : undefined;\n const kind = typeof change.kind === 'string' ? change.kind : undefined;\n if (!absolutePath || kind === 'delete') continue; // nothing to upload for a deletion\n\n const relative = path.relative(workspaceDir, absolutePath);\n if (relative.length === 0 || relative.startsWith('..') || path.isAbsolute(relative)) continue; // outside the workspace — never trust/forward (see doc comment above)\n\n events.push({ type: 'artifact', name: relative, contentType: guessContentType(relative) });\n }\n return events;\n}\n\nconst CONTENT_TYPE_BY_EXTENSION: Readonly<Record<string, string>> = {\n '.txt': 'text/plain',\n '.md': 'text/markdown',\n '.json': 'application/json',\n '.js': 'text/javascript',\n '.mjs': 'text/javascript',\n '.cjs': 'text/javascript',\n '.ts': 'text/plain',\n '.html': 'text/html',\n '.css': 'text/css',\n '.py': 'text/x-python',\n '.yml': 'application/yaml',\n '.yaml': 'application/yaml',\n '.csv': 'text/csv',\n};\n\nfunction guessContentType(relativePath: string): string {\n return CONTENT_TYPE_BY_EXTENSION[path.extname(relativePath).toLowerCase()] ?? 'application/octet-stream';\n}\n\nfunction extractErrorMessage(rawError: unknown): string | undefined {\n if (typeof rawError === 'string') return rawError;\n if (!rawError || typeof rawError !== 'object') return undefined;\n const message = (rawError as Record<string, unknown>).message;\n return typeof message === 'string' ? message : undefined;\n}\n\n/** Top-level codex event types with no `AgentEvent` equivalent, by design (not \"not yet handled\") — kept in sync with the switch cases above sharing this comment. Used only for observability, mirroring pi's `ROUTINE_PI_EVENT_TYPES`: `codex-adapter.ts`'s per-line pump only records a frame as genuinely unmapped (`unmappedFrameKey` + a one-time console.warn) when it maps to an empty array AND its type isn't in this set. */\nexport const ROUTINE_CODEX_EVENT_TYPES: ReadonlySet<string> = new Set(['thread.started', 'turn.started']);\n\nexport function isRoutineCodexEvent(evt: CodexRawEvent): boolean {\n return ROUTINE_CODEX_EVENT_TYPES.has(evt.type);\n}\n\n/** Diagnostic key for unmapped-frame accounting: for `item.*` frames, folds in the nested `item.type` (e.g. `\"item.completed:reasoning\"`) so a never-seen item shape is distinguishable from a never-seen top-level type. */\nexport function unmappedFrameKey(evt: CodexRawEvent): string {\n if (evt.type === 'item.started' || evt.type === 'item.completed') {\n const item = evt.item;\n const itemType = item && typeof item === 'object' && typeof (item as Record<string, unknown>).type === 'string' ? (item as Record<string, unknown>).type : 'unknown';\n return `${evt.type}:${String(itemType)}`;\n }\n return evt.type;\n}\n","import { spawn, spawnSync, type ChildProcessByStdio } from 'node:child_process';\nimport type { Readable } from 'node:stream';\n\nexport type SpawnFn = typeof spawn;\n\n/** stdin is `null` (never a Writable) — this process never pipes stdin to the child; see the module doc comment below for why. */\ntype CodexChildProcess = ChildProcessByStdio<null, Readable, Readable>;\n\n/**\n * One parsed line of `codex exec --json` / `codex exec resume --json`\n * output. Field shapes vary by `type` (see `./events.ts`'s module doc\n * comment for the empirically-captured catalog), so this stays a loose bag\n * rather than a full discriminated union, mirroring `PiRpcMessage` in\n * `../pi/rpc-client.ts`.\n */\nexport interface CodexRawEvent {\n type: string;\n [key: string]: unknown;\n}\n\nexport interface CodexProcessOptions {\n command: string;\n args: string[];\n cwd: string;\n env: NodeJS.ProcessEnv;\n spawnFn?: SpawnFn;\n /** Called once per parsed JSONL line, in arrival order. */\n onEvent: (evt: CodexRawEvent) => void;\n}\n\n/** Bound on retained stderr lines (see `onStderr`/`buildExitError`) — mirrors `STDERR_RING_CAPACITY` in `../pi/rpc-client.ts`. */\nconst STDERR_RING_CAPACITY = 20;\n\n/**\n * Spawns and streams ONE `codex exec` / `codex exec resume` invocation — i.e.\n * exactly one turn.\n *\n * Unlike pi (a single long-lived RPC server process for a whole session's\n * lifetime — see `../pi/rpc-client.ts`), `codex exec` is a one-shot batch\n * process per turn with no persistent request/response channel: it takes its\n * prompt as an argv positional, streams JSONL to stdout for the one turn\n * it's running, and exits. `../codex-adapter.ts`'s `CodexSession` constructs\n * a fresh `CodexProcessRunner` for every turn (the initial `start()` and\n * every later `followUp()`), forwarding each one's lines into the same\n * long-lived event queue.\n *\n * stdin is deliberately never piped to the child (`stdio: ['ignore', 'pipe',\n * 'pipe']`): `codex exec --help` documents that a piped, non-TTY stdin is\n * read and appended to the prompt as a `<stdin>` block even when a prompt was\n * ALSO given as an argv positional, and empirically every single real\n * invocation made while building this adapter logged \"Reading additional\n * input from stdin...\" on stderr regardless of whether a prompt argument was\n * given. Leaving `stdio: ['pipe', ...]` open for stdin and never closing it\n * risks codex blocking on that read forever — exactly the hang class this\n * task was built to avoid (the pi adapter's own `agent_end`/`agent_settled`\n * mismatch left a task stuck `Running` forever in the M0/M1 GLM run).\n * `'ignore'` presents immediate EOF instead, which was verified live with a\n * dedicated Node `child_process` probe before this was written: no hang,\n * clean completion at normal model latency. This adapter never needs to\n * SEND codex anything over stdin — there is no in-band steer/approval\n * protocol (see `../codex-adapter.ts`'s `steer`/`resolveApproval`).\n */\nexport class CodexProcessRunner {\n private readonly child: CodexChildProcess;\n private readonly onEvent: (evt: CodexRawEvent) => void;\n private buffer = '';\n private readonly stderrRing: string[] = [];\n private closed = false;\n private exitCode: number | null = null;\n private exitSignal: NodeJS.Signals | null = null;\n private readonly closedPromise: Promise<void>;\n private resolveClosed!: () => void;\n\n constructor(options: CodexProcessOptions) {\n this.onEvent = options.onEvent;\n const spawnFn = options.spawnFn ?? spawn;\n this.child = spawnFn(options.command, options.args, {\n cwd: options.cwd,\n env: options.env,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n this.closedPromise = new Promise((resolve) => {\n this.resolveClosed = resolve;\n });\n\n this.child.stdout.setEncoding('utf8');\n this.child.stdout.on('data', (chunk: string) => this.onData(chunk));\n\n this.child.stderr.setEncoding('utf8');\n this.child.stderr.on('data', (chunk: string) => this.onStderr(chunk));\n\n // `close` (not `exit`), mirroring rpc-client.ts's own reasoning: `close`\n // is Node's guarantee every stdout/stderr byte the process wrote has\n // already reached our listeners, so a post-mortem error built afterward\n // always has the complete stderr tail.\n this.child.on('close', (code, signal) => {\n this.exitCode = code;\n this.exitSignal = signal;\n this.finishClosing();\n });\n this.child.on('error', () => {\n // e.g. ENOENT for a missing binary — buildExitError's stderr tail will\n // be empty in this case, but exitCode/exitSignal staying null is\n // itself informative (never claims a fabricated exit code).\n this.finishClosing();\n });\n }\n\n private finishClosing(): void {\n if (this.closed) return;\n this.closed = true;\n this.resolveClosed();\n }\n\n /** Resolves once the child process has fully exited (both exit and stdio-flush guaranteed — see the `close` listener above). Never rejects. */\n waitClosed(): Promise<void> {\n return this.closedPromise;\n }\n\n get isClosed(): boolean {\n return this.closed;\n }\n\n /**\n * Best-effort teardown. SIGTERM on POSIX: SIGINT was empirically confirmed\n * to be silently ignored by `codex exec` (a real, direct test — a 60s\n * shell `sleep` ran to full, unaffected completion despite SIGINT sent at\n * t=4s) — a genuine, evidence-based correction to this task's own initial\n * assumption (\"interrupt: SIGINT — POSIX here\"). SIGTERM was separately\n * confirmed to terminate the process immediately (exit code 143) with no\n * orphaned child processes left behind (the shell command it was running\n * died with it), and — critically — the underlying codex thread remained\n * cleanly resumable afterward via `codex exec resume` (no corruption from\n * killing mid-turn). `taskkill /T /F` on Windows, mirroring\n * `../pi/rpc-client.ts`'s own cross-platform convention.\n */\n kill(): void {\n if (this.closed) return;\n const pid = this.child.pid;\n if (process.platform === 'win32' && pid !== undefined) {\n spawnSync('taskkill', ['/pid', String(pid), '/T', '/F']);\n } else {\n this.child.kill('SIGTERM');\n }\n }\n\n /** Builds a descriptive error folding in the exit code/signal and the stderr tail — mirrors `PiRpcClient.buildExitError`'s reasoning: a post-mortem on a failed start/resume should never need separately re-running codex by hand with a raw JSONL logger to learn why. */\n buildExitError(context: string): Error {\n const parts = [`${context} (exit code=${this.exitCode}, signal=${this.exitSignal})`];\n if (this.stderrRing.length > 0) {\n parts.push(`stderr: ${this.stderrRing.join(' | ')}`);\n }\n return new Error(parts.join('; '));\n }\n\n private onData(chunk: string): void {\n this.buffer += chunk;\n let newlineIndex = this.buffer.indexOf('\\n');\n while (newlineIndex !== -1) {\n let line = this.buffer.slice(0, newlineIndex);\n this.buffer = this.buffer.slice(newlineIndex + 1);\n if (line.endsWith('\\r')) line = line.slice(0, -1);\n if (line.length > 0) this.parseLine(line);\n newlineIndex = this.buffer.indexOf('\\n');\n }\n }\n\n private parseLine(line: string): void {\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n return; // a stray non-JSON line is not this runner's concern\n }\n if (!parsed || typeof parsed !== 'object' || typeof (parsed as { type?: unknown }).type !== 'string') {\n return;\n }\n this.onEvent(parsed as CodexRawEvent);\n }\n\n private onStderr(chunk: string): void {\n for (const rawLine of chunk.split('\\n')) {\n const line = rawLine.trim();\n if (line.length === 0) continue;\n this.stderrRing.push(line);\n if (this.stderrRing.length > STDERR_RING_CAPACITY) this.stderrRing.shift();\n }\n }\n}\n","import { execFile } from 'node:child_process';\nimport { promises as fs } from 'node:fs';\nimport { promisify } from 'node:util';\nimport type { AgentEvent, TaskOfferPayload } from '@byok-sdk/protocol';\nimport {\n PolicyUnsupportedError,\n SteerUnsupportedError,\n type RuntimeAdapter,\n type RuntimeCapabilities,\n type RuntimeDetectResult,\n type RuntimeEnvironmentRequirements,\n type Session,\n type TaskContext,\n} from '../../types';\nimport { AsyncQueue } from '../../util/async-queue';\nimport { resolveCodexBin, type ResolvedBin } from './resolve-bin';\nimport { mapPermissionPolicyToCodexArgs } from './permission-mapping';\nimport { isRoutineCodexEvent, mapCodexEventToAgentEvents, unmappedFrameKey } from './events';\nimport { CodexProcessRunner, type CodexRawEvent, type SpawnFn } from './process-runner';\n\nconst execFileAsync = promisify(execFile);\n\n/** Applied to both `detect()` probe calls — both are local-only and empirically fast (~50-80ms each), but detect() runs on every allowlist-narrowed task offer (see task-runner.ts's `pickAdapter`), so a small ceiling is cheap insurance against either ever unexpectedly hanging. */\nconst DETECT_TIMEOUT_MS = 5000;\n\nexport interface CodexAdapterOptions {\n /** Override bin resolution — tests substitute the fake-codex fixture script. */\n resolveBin?: () => ResolvedBin;\n /** Override process spawning — tests substitute a fake spawn. */\n spawnFn?: SpawnFn;\n}\n\n/**\n * `RuntimeAdapter` for the OpenAI Codex CLI (`codex exec --json`), the M2-b\n * counterpart to `../pi/pi-adapter.ts`. Every empirical claim in this file\n * and its sibling modules (`events.ts`, `permission-mapping.ts`,\n * `process-runner.ts`) was driven live against the real installed `codex-cli\n * 0.144.5` in a scratch directory before being encoded — repeating the pi\n * adapter's own M0-3 discipline (\"docs lied and shipped a nonexistent flag\")\n * independently found the exact same bug class on codex:\n *\n * - `codex exec --help` documents `-a`/`--ask-for-approval`; the real\n * parser rejects it outright on `codex exec` (\"unexpected argument\").\n * - `-s`/`--sandbox` works on a fresh `codex exec` but is rejected outright\n * on `codex exec resume` (whose own --help correctly omits it).\n * - `codex exec resume` does NOT auto-inherit the sandbox mode a session\n * was originally started with — a read-only-started session's write\n * SUCCEEDED on a bare resume with no sandbox override re-passed,\n * silently falling back to this machine's own ambient config default.\n * - This task's own brief assumed SIGINT for `interrupt()`; empirically,\n * `codex exec` ignores SIGINT entirely (a 60s `sleep` ran to completion\n * despite SIGINT at t=4s) — SIGTERM is used instead (confirmed to work:\n * immediate exit, no orphaned children, thread stays resumable after).\n *\n * See `./permission-mapping.ts` and `./process-runner.ts` for the full\n * per-finding writeups (sandbox scope, network, approval model, resume\n * mechanics, stdin handling).\n *\n * Architecture, and how it differs from pi: pi is one long-lived `pi --mode\n * rpc` process for a whole session's lifetime, driven by a bidirectional\n * JSONL request/response protocol (`../pi/rpc-client.ts`). `codex exec` has\n * no such thing — it's a one-shot batch process per turn, prompt in via\n * argv, JSONL out via stdout, process exits. `CodexSession` here instead\n * spawns a fresh `CodexProcessRunner` for every turn (the initial `start()`\n * and every later `followUp()`), and forwards each one's mapped events into\n * one shared, session-lifetime `AsyncQueue` — the thing `Session.events`\n * actually exposes. `sessionRef` is codex's own `thread_id`, learned from\n * `thread.started`, which is reliably the first JSONL line codex ever prints\n * (confirmed across every empirical capture, fresh starts and resumes\n * alike) — `runCodexTurn` below awaits specifically for that line before\n * resolving, mirroring pi's own \"resolve a real session id before\n * constructing the Session, fail closed if you can't\" discipline\n * (`../pi/pi-adapter.ts`'s `resolveFreshSessionId`, finding F8).\n */\nexport class CodexAdapter implements RuntimeAdapter {\n readonly id = 'codex';\n\n constructor(private readonly options: CodexAdapterOptions = {}) {}\n\n async detect(): Promise<RuntimeDetectResult> {\n const bin = this.resolveBin();\n try {\n const versionResult = await execFileAsync(bin.command, ['--version'], { timeout: DETECT_TIMEOUT_MS });\n const version = versionResult.stdout.trim() || versionResult.stderr.trim();\n const authPresent = await this.probeAuthPresent(bin);\n return { present: true, version, authPresent };\n } catch {\n return { present: false };\n }\n }\n\n /**\n * `authPresent` without ever reading `~/.codex/auth.json` (credential-\n * isolation rule, `../../types.ts`): spawns codex's OWN `login status`\n * subcommand and interprets its human-readable report — the exact\n * \"non-secret signal\" this adapter is required to use, and cleaner than\n * pi's env-var-name check since codex's real credential model (on the\n * reference machine) is a ChatGPT OAuth session, not an env var.\n *\n * Two independently-verified channel gotchas apply here, the \"pi lesson\"\n * yet again:\n * - `codex login status`'s human-readable \"Logged in using ChatGPT\"\n * message prints on STDERR, not stdout (the opposite-channel\n * counterpart of pi's own `--version`-goes-to-stderr surprise) — both\n * streams are checked here for exactly that reason.\n * - The NOT-logged-in message/exit-code shape was deliberately never\n * empirically tested: this machine has a real, live ChatGPT login, and\n * running `codex logout` to observe the negative case would have\n * broken that login for the rest of this session/machine. The match\n * below is intentionally conservative (`/logged in (using|with)/i`,\n * not a bare `\"logged in\"` substring) specifically because a bare\n * substring check would false-positive on a plausible negative message\n * like \"Not logged in\" (itself containing the substring \"logged in\").\n * This is a documented, known gap — flagged for M2-c / a follow-up\n * empirical pass on a logged-out machine, not asserted as verified.\n */\n private async probeAuthPresent(bin: ResolvedBin): Promise<boolean> {\n try {\n const result = await execFileAsync(bin.command, ['login', 'status'], { timeout: DETECT_TIMEOUT_MS });\n return /logged in (using|with)/i.test(`${result.stdout}\\n${result.stderr}`);\n } catch (err) {\n const withStreams = err as { stdout?: string; stderr?: string };\n return /logged in (using|with)/i.test(`${withStreams.stdout ?? ''}\\n${withStreams.stderr ?? ''}`);\n }\n }\n\n capabilities(): RuntimeCapabilities {\n // `approvalInteractive: false` — `codex exec` never emits a\n // `needs_approval`-equivalent event, so there is nothing to resume and\n // `CodexSession.resolveApproval` throws unconditionally.\n return { steer: false, resume: true, approvalInteractive: false, permissionModes: ['auto', 'readonly'] };\n }\n\n /**\n * M5: same deliberate posture as the claude adapter (see its own doc\n * comment) — codex authenticates via its own `codex login`-managed\n * ChatGPT OAuth session (`probeAuthPresent` above), not an env var, so\n * there is no credential env var this adapter needs forwarded; env-based\n * API-key passthrough remains a separate, pending product decision. No\n * `baseNames` either: nothing in this adapter reads a codex-specific\n * config-discovery variable (e.g. `CODEX_HOME`) today.\n */\n environmentRequirements(): RuntimeEnvironmentRequirements {\n return { credentialNames: [] };\n }\n\n async start(task: TaskOfferPayload, ctx: TaskContext): Promise<Session> {\n if (typeof task.instruction !== 'string') {\n throw new PolicyUnsupportedError('codex adapter only supports string instructions in M2 (no blob-ref fetch yet)');\n }\n\n const mapping = mapPermissionPolicyToCodexArgs(ctx.policy);\n if (!mapping.ok) {\n throw new PolicyUnsupportedError(mapping.reason ?? 'policy rejected by codex adapter');\n }\n\n const bin = this.resolveBin();\n const queue = new AsyncQueue<AgentEvent>();\n const recordUnmapped = makeUnmappedFrameRecorder(new Map<string, number>());\n\n // Realpath'd once, up front — see `resolveRealWorkspaceDir`'s doc\n // comment for why this matters even on a single-machine, non-adversarial\n // path (unlike task-runner.ts's own realpath use, which is defending\n // against symlink swaps): `file_change` items report codex's own\n // absolute paths, built from the CHILD PROCESS's `process.cwd()`, which\n // Node/the OS resolve through any symlink in `ctx.workspaceDir` — a\n // stock `os.tmpdir()`-based workspace on macOS (`/var/folders/...`,\n // itself a symlink to `/private/var/folders/...`) hits this on literally\n // every run, not just a contrived edge case.\n const workspaceDir = await resolveRealWorkspaceDir(ctx.workspaceDir);\n\n const { sessionRef, runner } = await runCodexTurn({\n command: bin.command,\n resumeRef: task.sessionRef,\n instruction: task.instruction,\n policyArgs: mapping.args,\n cwd: ctx.workspaceDir,\n env: ctx.env,\n spawnFn: this.options.spawnFn,\n workspaceDir,\n queue,\n recordUnmapped,\n expectedSessionRef: task.sessionRef,\n preparedGit: ctx.gitWorkspace !== undefined,\n });\n\n return new CodexSession({\n sessionRef,\n command: bin.command,\n workspaceDir,\n env: ctx.env,\n spawnFn: this.options.spawnFn,\n queue,\n recordUnmapped,\n initialRunner: runner,\n preparedGit: ctx.gitWorkspace !== undefined,\n });\n }\n\n private resolveBin(): ResolvedBin {\n return (this.options.resolveBin ?? resolveCodexBin)();\n }\n}\n\n/**\n * Self-discovered finding while building this adapter's own test suite\n * (caught by a real timeout, not inspection): `fs.mkdtemp(path.join(os.\n * tmpdir(), ...))` on macOS returns a path through `/var/folders/...`, which\n * is itself a symlink to `/private/var/folders/...` — confirmed with a\n * direct probe (`fs.realpathSync(os.tmpdir())`). A child process spawned\n * with `cwd` set to the *symlinked* form still reports the *realpath'd* form\n * from its own `process.cwd()` (confirmed with a dedicated spawn probe) —\n * and `file_change` items build their absolute `path` from exactly that.\n * Without this, `events.ts`'s `extractArtifactEvents` would compute a\n * `path.relative(workspaceDir, absolutePath)` full of `../` segments for a\n * file genuinely inside the workspace, trip its own outside-the-workspace\n * safety check, and silently drop the artifact event — not a contrived edge\n * case, but the literal default shape of any workspace root built from\n * `os.tmpdir()` on macOS. Mirrors task-runner.ts's own `openArtifact`, which\n * realpaths its workspace root for the identical reason (there, defending\n * against a symlink swap; here, just matching what the child process's own\n * OS-resolved cwd will report) — same fallback too: a realpath failure\n * (workspace deleted out from under it, etc.) falls through to the original\n * path unchanged rather than failing the whole turn over it.\n */\nasync function resolveRealWorkspaceDir(workspaceDir: string): Promise<string> {\n return fs.realpath(workspaceDir).catch(() => workspaceDir);\n}\n\n/** Count of codex frame \"keys\" (see `unmappedFrameKey`) this session has told us have no `AgentEvent` mapping and aren't routine bookkeeping — i.e. genuinely unexpected traffic. Logs once per distinct key, mirroring `PiRpcClient.recordUnmappedFrame`'s exact reasoning: this is the mechanism that turns a future regression (like this task's own root-cause \"read `thread.started` on every line, not just the first\" class of bug would have been) into an immediate, self-diagnosing warning instead of a silent drop. */\nfunction makeUnmappedFrameRecorder(counts: Map<string, number>): (key: string) => void {\n return (key: string): void => {\n const next = (counts.get(key) ?? 0) + 1;\n counts.set(key, next);\n if (next === 1) {\n console.warn(\n `[byok/codex-adapter] codex emitted a frame with no AgentEvent mapping: \"${key}\" (further occurrences of this type won't be logged individually)`,\n );\n }\n };\n}\n\ninterface RunTurnParams {\n command: string;\n resumeRef: string | undefined;\n instruction: string;\n policyArgs: string[];\n cwd: string;\n env: NodeJS.ProcessEnv;\n spawnFn: SpawnFn | undefined;\n workspaceDir: string;\n queue: AsyncQueue<AgentEvent>;\n recordUnmapped: (key: string) => void;\n /**\n * When resuming, the sessionRef this call expects codex to echo back in\n * `thread.started` — required for BOTH `start()`'s externally-supplied\n * `task.sessionRef` and `followUp()`'s own previously-recorded\n * `sessionRef` (see `CodexSession.followUp`'s doc comment for why the\n * latter also passes this now). Fail-closed on a mismatch: the\n * already-spawned runner for this attempt is killed and the call throws\n * rather than silently adopting whatever id codex actually reported —\n * this is a real check, not just a diagnostic log.\n */\n expectedSessionRef?: string | undefined;\n preparedGit?: boolean;\n}\n\ninterface RunTurnResult {\n sessionRef: string;\n runner: CodexProcessRunner;\n}\n\n/**\n * `--skip-git-repo-check` is used for plain workspaces, not derived from policy:\n * real `codex exec` (confirmed live, via this adapter's own e2e run against a\n * plain non-git scratch workspace) refuses to run at all outside a Git\n * repository — \"Not inside a trusted directory and --skip-git-repo-check\n * was not specified\", exit 1, no JSONL emitted — unless this flag is passed.\n * A successfully prepared Git workspace already satisfies that precondition,\n * so the flag is omitted there. `task-runner.ts`'s `resolveWorkspaceDir`\n * creates plain directories (`fs.mkdir(dir, {recursive:true})`, never a git\n * repo), so the plain-workspace path must retain the flag. It carries no\n * sandbox/approval semantics of its own (purely a \"do you want the git-repo\n * safety net\" gate) — confirmed via `codex exec --help`, which documents it\n * separately from every sandbox/approval flag.\n */\nfunction buildArgv(resumeRef: string | undefined, policyArgs: string[], instruction: string, preparedGit = false): string[] {\n const base = resumeRef !== undefined ? ['exec', 'resume', resumeRef] : ['exec'];\n return [...base, '--json', ...(preparedGit ? [] : ['--skip-git-repo-check']), ...policyArgs, instruction];\n}\n\n/**\n * Spawn one `codex exec`/`codex exec resume` turn, await its first line\n * (must be `thread.started` — fail closed otherwise, never fabricate a\n * `sessionRef`, mirroring `../pi/pi-adapter.ts`'s finding F8), then keep\n * pumping the rest of that process's output into `params.queue` in the\n * background for as long as it runs. Shared by both `CodexAdapter.start()`\n * (a fresh turn, or a resume-via-`task.sessionRef`) and\n * `CodexSession.followUp()` (always a resume).\n */\nasync function runCodexTurn(params: RunTurnParams): Promise<RunTurnResult> {\n const argv = buildArgv(params.resumeRef, params.policyArgs, params.instruction, params.preparedGit);\n\n let firstLineSettled = false;\n let resolveFirstLine!: (ref: string) => void;\n let rejectFirstLine!: (err: Error) => void;\n const firstLine = new Promise<string>((resolve, reject) => {\n resolveFirstLine = resolve;\n rejectFirstLine = reject;\n });\n\n // Set once THIS turn's own mapped events include an explicit `turn_end` —\n // see the `waitClosed()` watcher below (cross-model review finding, the\n // \"pi-hang class\") for why this matters: `turn_end` already told\n // task-runner.ts's `pump()` this specific turn is done, so the shared\n // session-lifetime queue must stay open afterward (a later `followUp()`\n // reuses this exact same queue — see `CodexSession` below).\n let turnEnded = false;\n\n const runner = new CodexProcessRunner({\n command: params.command,\n args: argv,\n cwd: params.cwd,\n env: params.env,\n spawnFn: params.spawnFn,\n onEvent: (evt: CodexRawEvent) => {\n if (!firstLineSettled) {\n firstLineSettled = true;\n if (evt.type === 'thread.started' && typeof evt.thread_id === 'string' && evt.thread_id.length > 0) {\n resolveFirstLine(evt.thread_id);\n } else {\n rejectFirstLine(\n new Error(`codex did not yield thread.started as its first event (got ${JSON.stringify(evt).slice(0, 200)})`),\n );\n }\n return;\n }\n const mapped = mapCodexEventToAgentEvents(evt, params.workspaceDir);\n for (const agentEvent of mapped) {\n if (agentEvent.type === 'turn_end') turnEnded = true;\n params.queue.push(agentEvent);\n }\n if (mapped.length === 0 && !isRoutineCodexEvent(evt)) {\n params.recordUnmapped(unmappedFrameKey(evt));\n }\n },\n });\n\n /**\n * Cross-model review finding (the \"pi-hang class\" — a task that never\n * completes): `codex exec` is one-shot PER TURN (see this module's own\n * doc comment) — a failed turn (`turn.failed`, mapped to an `error`\n * AgentEvent, deliberately NOT a `turn_end`) or any other unexpected exit\n * (crash, an `interrupt()`-triggered SIGTERM) ends the child process\n * without ever producing the one signal task-runner.ts's `pump()` treats\n * as terminal. Nothing else in this file ever called `params.queue.end()`\n * for that case — confirmed reproducible: the events async-iterable's\n * `next()` stays pending forever, 250ms+ after the process has already\n * exited. pi's own `PiRpcClient.onClosed` (`../pi/rpc-client.ts`)\n * unconditionally ends its eventQueue on process close — correct THERE\n * because pi is one long-lived process for a WHOLE session (closing means\n * the whole session is over). Codex is architecturally different: a fresh\n * process per turn, sharing ONE session-lifetime queue across turns (see\n * `CodexSession.followUp()`) — unconditionally ending it here would wrongly\n * terminate a session a later `followUp()` is about to keep using. So:\n * only when THIS turn never reached `turn_end` do we surface a terminal\n * `error` AgentEvent (exit code/signal + stderr ring tail via\n * `buildExitError` — the real reason, never fabricated) and end the queue.\n * `waitClosed()` never rejects (see process-runner.ts), so no `.catch()`\n * is needed; pushing/ending an already-ended queue (e.g. `close()` beat\n * this watcher to it) is a harmless no-op (`AsyncQueue` is idempotent).\n */\n void runner.waitClosed().then(() => {\n if (turnEnded) return;\n params.queue.push({ type: 'error', message: runner.buildExitError('codex exited without completing the turn').message });\n params.queue.end();\n });\n\n // Race the first line against the process closing before ever producing\n // one (bad flag, ENOENT, an unknown resume id — \"Error: thread/resume:\n // ... no rollout found for thread id ...\" — all empirically confirmed to\n // exit fast with no JSONL at all, never a hang). Built as an explicit\n // executor rather than `Promise.race` so the \"losing\" side can never\n // become an unhandled rejection: `runner.waitClosed()` itself only ever\n // resolves (see process-runner.ts), and `firstLine` always has its\n // resolve/reject consumed below regardless of which settles first.\n let sessionRef: string;\n try {\n sessionRef = await new Promise<string>((resolve, reject) => {\n let settled = false;\n firstLine.then(\n (ref) => {\n if (!settled) {\n settled = true;\n resolve(ref);\n }\n },\n (err: unknown) => {\n if (!settled) {\n settled = true;\n reject(err instanceof Error ? err : new Error(String(err)));\n }\n },\n );\n void runner.waitClosed().then(() => {\n if (!settled) {\n settled = true;\n reject(runner.buildExitError('codex exited before yielding an authoritative thread id'));\n }\n });\n });\n } catch (err) {\n runner.kill();\n throw err;\n }\n\n // Cross-model review finding: this used to only `console.warn` and\n // continue on a mismatch — \"a runtime silently falling back to a\n // different session runs the task in the WRONG context.\" `expectedSessionRef`\n // here is always an EXTERNALLY supplied ask (`CodexAdapter.start()`'s\n // `task.sessionRef`, from the server/daemon — never `CodexSession\n // .followUp()`, which intentionally omits it; see that method's own doc\n // comment for why its own internal resume is handled differently). A\n // mismatch against an external expectation means this adapter can no\n // longer trust that codex resumed the workspace/history the caller\n // actually meant — fail closed rather than quietly proceeding.\n if (params.expectedSessionRef !== undefined && sessionRef !== params.expectedSessionRef) {\n runner.kill();\n throw new Error(\n `codex exec resume echoed a different thread id than requested (requested ${params.expectedSessionRef}, got ${sessionRef}) — refusing to continue in a possibly-wrong session (fail-closed)`,\n );\n }\n\n return { sessionRef, runner };\n}\n\ninterface CodexSessionOptions {\n sessionRef: string;\n command: string;\n workspaceDir: string;\n env: NodeJS.ProcessEnv;\n spawnFn: SpawnFn | undefined;\n queue: AsyncQueue<AgentEvent>;\n recordUnmapped: (key: string) => void;\n initialRunner: CodexProcessRunner;\n preparedGit: boolean;\n}\n\nclass CodexSession implements Session {\n /**\n * NOT `readonly` (cross-model review finding): `followUp()` below\n * re-assigns this from the runtime's own CONFIRMED reflected id on each\n * resume — see its own doc comment. Silently keeping the value captured at\n * construction time was the original bug (the NEW id `runCodexTurn`\n * returns was discarded, so every later `followUp()` kept resuming the\n * OLD, potentially stale, id); that stays fixed here. A LATER cross-model\n * re-review found the fix above was itself incomplete: `followUp()` now\n * also verifies the reflected id matches what it asked to resume BEFORE\n * this field is touched — a mismatch throws (fail-closed) instead of ever\n * reaching this assignment, so `sessionRef` only ever advances to an id\n * codex has proven it actually resumed, never one it silently swapped in.\n */\n public sessionRef: string;\n private readonly command: string;\n private readonly workspaceDir: string;\n private readonly env: NodeJS.ProcessEnv;\n private readonly spawnFn: SpawnFn | undefined;\n private readonly queue: AsyncQueue<AgentEvent>;\n private readonly recordUnmapped: (key: string) => void;\n private readonly preparedGit: boolean;\n private currentRunner: CodexProcessRunner | undefined;\n private closed = false;\n\n constructor(options: CodexSessionOptions) {\n this.sessionRef = options.sessionRef;\n this.command = options.command;\n this.workspaceDir = options.workspaceDir;\n this.env = options.env;\n this.spawnFn = options.spawnFn;\n this.queue = options.queue;\n this.recordUnmapped = options.recordUnmapped;\n this.preparedGit = options.preparedGit;\n this.currentRunner = options.initialRunner;\n void this.forgetRunnerOnceClosed(options.initialRunner);\n }\n\n get events(): AsyncIterable<AgentEvent> {\n return this.queue;\n }\n\n private async forgetRunnerOnceClosed(runner: CodexProcessRunner): Promise<void> {\n await runner.waitClosed();\n if (this.currentRunner === runner) this.currentRunner = undefined;\n }\n\n /**\n * New turn, same session, via the real resume mechanism (`codex exec\n * resume <sessionRef> ...`). Maps `task.policy` FRESH on every call — a\n * deliberate, evidence-based divergence from pi's own `followUp()`\n * (`../pi/pi-adapter.ts`), which ignores `task.policy` entirely and relies\n * on argv baked in once at `start()`. That's safe for pi only because pi\n * reuses one already-running RPC process for its whole session lifetime,\n * so there is nothing to re-apply. codex has no such invariant: a resume\n * spawns a BRAND NEW process, and empirically that new process does NOT\n * inherit the sandbox mode the session originally started with (see this\n * file's module doc comment) — omitting a fresh, explicit mapping here\n * would silently run the follow-up turn under this machine's ambient codex\n * config default instead of the policy this specific follow-up was\n * offered under, exactly the silent-widen failure mode this adapter exists\n * to prevent.\n *\n * Cross-model RE-review finding (this corrects the previous wave's own\n * reasoning, quoted below for context): `expectedSessionRef` IS now passed\n * to `runCodexTurn`, set to the exact id this call asked to resume\n * (`resumeRef`, captured up front before the call). The previous version\n * of this method deliberately omitted it — \"this resume targets OUR OWN\n * previously-recorded `sessionRef`, not an externally supplied server\n * expectation crossing a trust boundary... whatever id codex reports back\n * for THIS resume is unambiguously the current, authoritative id for this\n * session\" — but that reasoning let a resume-A/reports-B mismatch silently\n * MIGRATE this session's identity instead of failing closed: codex has no\n * documented contract for re-keying a thread on resume, so a mismatch here\n * must be treated as an error, exactly like `start()`'s own\n * `task.sessionRef` comparison (see `runCodexTurn`'s doc comment on that\n * check) — never silently adopted. `runCodexTurn` kills the (failed) new\n * runner and throws on a mismatch, BEFORE `sessionRef`/`currentRunner`\n * below are ever touched — so a thrown mismatch leaves this session in its\n * previous, still-good state rather than partially migrated. The\n * `sessionRef` return value is still captured and re-assigned below (the\n * ORIGINAL bug this fixes, one wave further back: the return value used to\n * be discarded entirely, so every later `followUp()` kept resuming a\n * stale id even after codex had moved on) — it just can now only ever be\n * the SAME id this call asked to resume, never a silently-different one.\n */\n async followUp(task: TaskOfferPayload): Promise<void> {\n if (typeof task.instruction !== 'string') {\n throw new PolicyUnsupportedError('codex adapter only supports string instructions in M2 (no blob-ref fetch yet)');\n }\n if (this.closed) {\n throw new Error('cannot follow up on a closed codex session');\n }\n\n const mapping = mapPermissionPolicyToCodexArgs(task.policy);\n if (!mapping.ok) {\n throw new PolicyUnsupportedError(mapping.reason ?? 'policy rejected by codex adapter');\n }\n\n const resumeRef = this.sessionRef;\n let sessionRef: string;\n let runner: CodexProcessRunner;\n try {\n ({ sessionRef, runner } = await runCodexTurn({\n command: this.command,\n resumeRef,\n instruction: task.instruction,\n policyArgs: mapping.args,\n cwd: this.workspaceDir,\n env: this.env,\n spawnFn: this.spawnFn,\n workspaceDir: this.workspaceDir,\n queue: this.queue,\n recordUnmapped: this.recordUnmapped,\n expectedSessionRef: resumeRef,\n preparedGit: this.preparedGit,\n }));\n } catch (err) {\n // Fix (queue-leak-on-failure): confirmed empirically with a diagnostic\n // unbounded `for await` over `session.events` — the SAME shared queue\n // this method's own `runCodexTurn` call already writes into is exposed\n // to the caller from before this call even started (`this.queue` ===\n // `session.events`, session-lifetime). `runCodexTurn` already kills the\n // FAILED attempt's own runner before throwing in both its failure\n // branches (a bad/missing first frame, and this exact session-identity\n // mismatch — see its own doc comment), but never touches `this.queue`.\n // The identity-mismatch case in particular routinely reaches\n // `turn.completed` (mapped to `turn_end`) on the wire BEFORE the\n // mismatch is even detected — this turn's own `onEvent` callback keeps\n // draining the child's stdout independently of when `runCodexTurn`'s\n // own promise settles, and a synchronous fixture's whole output can\n // arrive in one 'data' chunk, processed before the \"await sessionRef\"\n // continuation ever runs. That means `runCodexTurn`'s own \"this turn\n // never reached turn_end\" background watcher sees `turnEnded === true`\n // and correctly declines to end the queue itself (see that watcher's\n // doc comment: a later `followUp()` reusing this same queue is the\n // normal case it's protecting) — leaving NOTHING that will ever end\n // it, so a consumer that reads past everything already buffered gets a\n // `next()` that never resolves. Ending it here closes that gap,\n // mirroring `close()`'s own `this.queue.end()` — deliberately NOT\n // setting `this.closed`, since a failed followUp() must not corrode\n // the SESSION itself (a later `followUp()` with a matching id still\n // succeeds — see the cross-model re-review test above); only this\n // queue's usefulness ends, since nothing can safely keep sharing it\n // once a turn's own result has been this explicitly distrusted.\n this.queue.end();\n throw err;\n }\n this.sessionRef = sessionRef;\n this.currentRunner = runner;\n void this.forgetRunnerOnceClosed(runner);\n }\n\n /** Best-effort abort of the current turn. SIGTERM's the currently-running child, if any — see `process-runner.ts`'s `kill()` doc comment for why SIGTERM (not SIGINT) and why this is safe: the underlying codex thread survives and stays resumable, confirmed empirically. A no-op when no turn is currently in flight. */\n async interrupt(): Promise<void> {\n this.currentRunner?.kill();\n }\n\n async close(): Promise<void> {\n if (this.closed) return;\n this.closed = true;\n this.currentRunner?.kill();\n this.queue.end();\n }\n\n /**\n * `codex exec` has no in-band channel to inject text into an already-\n * running turn — confirmed empirically, not assumed: there is no stdin\n * protocol (stdin is never even piped to the child — see\n * `process-runner.ts`'s module doc comment), SIGINT (a plausible\n * interrupt-and-redirect signal) is silently ignored outright, and `codex\n * exec resume` only ever starts a brand NEW turn strictly after the\n * current one has fully finished — it cannot inject into one still in\n * flight. Throws honestly rather than silently no-op-ing, matching this\n * task's explicit instruction and `capabilities().steer === false` above.\n */\n async steer(): Promise<void> {\n throw new SteerUnsupportedError(\n 'codex',\n 'codex adapter does not support steer: codex exec has no in-band channel to inject text into a running turn (no stdin protocol, SIGINT is ignored, and resume only starts a new turn after the current one finishes)',\n );\n }\n\n /**\n * `codex exec` never emits a `needs_approval`-equivalent event on the wire\n * — confirmed empirically (see `events.ts`'s module doc comment): a\n * sandbox-denied action resolves the approval decision internally with no\n * pause an external caller could ever observe or answer, regardless of\n * `approval_policy`. Since this session can therefore never have emitted a\n * `needs_approval` `AgentEvent` in the first place, a caller reaching this\n * method implies something upstream expected approval support that isn't\n * there — thrown as a descriptive error rather than a silent no-op,\n * mirroring `../pi/pi-adapter.ts`'s identical `resolveApproval`.\n */\n async resolveApproval(): Promise<void> {\n throw new Error(\n 'codex adapter does not support approval resume: codex exec never emits a needs_approval-equivalent event (sandbox-denied actions resolve internally with no wire-visible pause)',\n );\n }\n}\n","/**\n * M4 Phase 2: minimal pending-approval registry backing the control\n * socket's `approvals.list`/`approvals.resolve` methods.\n *\n * Nothing PRODUCES an approval yet in Phase 2 — every one of the three\n * bundled runtime adapters (pi/claude/codex) still has no interactive\n * `needs_approval` path (see `create-daemon.ts`'s `toRuntimeInfoCapabilities`\n * doc comment) — so `list()` always returns `[]` and `resolve()` always\n * throws {@link ApprovalNotFoundError} against a real daemon today. This\n * class exists now so Phase 3 (the claude permission-prompt path) only has\n * to call `register()` from wherever it detects a prompt; the control-socket\n * plumbing (`control-server.ts`'s method registry, the CLI's `approve`/\n * `reject` commands) is already wired end-to-end against this same registry.\n */\n\nexport type ApprovalDecision = 'approve' | 'reject';\n\n/**\n * M4 (additive-minor, `task.approval_resolved`): distinguishes a resolution\n * that arrived over the wire (a server-sent `task.approve`/`task.reject`,\n * relayed here via `TaskContext.approvalChannel.resolve` — `task-runner.ts`'s\n * `handleOffer`) from one this device decided on its own (the local\n * `approvals.resolve` control-socket RPC, a fail-closed `requestApproval`\n * timeout, or a fail-closed finish/eviction rejection). `TaskRunner` uses\n * this to decide whether to report `task.approval_resolved` back to the\n * server: a wire-triggered resolution is something the server already knows\n * about (it sent the decision itself) and must never be echoed back;\n * everything else is new information only the device has, and — capability\n * permitting — gets reported. `'local'` is the default (see `resolve()`\n * below) precisely because it's the common case: every call site in this\n * module and `task-runner.ts` except the one wire-relay closure is local by\n * construction.\n */\nexport type ApprovalOrigin = 'wire' | 'local';\n\n/** What `approvals.list` returns per pending approval — deliberately small; a runtime-specific payload (e.g. the exact tool call awaiting approval) is Phase 3's concern, not this registry's. */\nexport interface PendingApproval {\n approvalId: string;\n taskId: string;\n summary?: string;\n createdAt: string;\n}\n\nexport class ApprovalNotFoundError extends Error {\n constructor(approvalId: string) {\n super(`no pending approval with id \"${approvalId}\"`);\n this.name = 'ApprovalNotFoundError';\n }\n}\n\n/** Cap on simultaneously pending approvals — generous for any plausible concurrent-approval workload, and existing purely as a defensive bound (mirrors `task-runner.ts`'s `MAX_TRACKED_TASK_IDS`/`observer.ts`'s `MAX_TRACKED_TASKS`), not a real-world limit this is expected to ever approach. */\nexport const MAX_PENDING_APPROVALS = 200;\n\ntype ResolveCallback = (decision: ApprovalDecision, reason: string | undefined, origin: ApprovalOrigin) => void;\n\ninterface RegisteredApproval {\n approval: PendingApproval;\n onResolve: ResolveCallback;\n}\n\n/**\n * `register()`/`resolve()` are the producer/consumer halves of one pending\n * approval: a future runtime adapter integration calls `register()` when it\n * pauses a task awaiting a decision and gets called back via `onResolve`\n * once `resolve()` is invoked (locally, or — Phase 2's actual wiring — via\n * the control socket's `approvals.resolve` RPC). `list()` is a pure read\n * for `approvals.list`.\n */\nexport class ApprovalRegistry {\n private readonly pending = new Map<string, RegisteredApproval>();\n\n /**\n * Registers a new pending approval, evicting the OLDEST entry first if\n * already at {@link MAX_PENDING_APPROVALS} — bounded, not unbounded\n * growth, for a long-lived daemon. The evicted entry's own `onResolve` is\n * called (as a reject, with a reason naming the eviction) rather than\n * simply dropped: whatever registered it (a future Phase 3 producer,\n * e.g. a paused runtime session awaiting a decision) is very likely\n * still waiting on that callback firing at all — silently stranding it\n * would leave that producer hanging forever instead of unblocking it\n * with a clear, if unwelcome, outcome.\n */\n register(approval: PendingApproval, onResolve: ResolveCallback): void {\n if (this.pending.size >= MAX_PENDING_APPROVALS) {\n const oldestId = this.pending.keys().next().value;\n if (oldestId !== undefined) {\n const evicted = this.pending.get(oldestId);\n this.pending.delete(oldestId);\n console.warn(\n `[byok/client] approval registry exceeded ${MAX_PENDING_APPROVALS} pending entries — evicted the oldest (${oldestId})`,\n );\n // 'local': an eviction is this registry's own bookkeeping, never a\n // relayed server decision — see `ApprovalOrigin`'s own doc comment.\n evicted?.onResolve(\n 'reject',\n `evicted: approval registry exceeded ${MAX_PENDING_APPROVALS} pending entries`,\n 'local',\n );\n }\n }\n this.pending.set(approval.approvalId, { approval, onResolve });\n }\n\n list(): PendingApproval[] {\n return [...this.pending.values()].map((entry) => entry.approval);\n }\n\n /**\n * Throws {@link ApprovalNotFoundError} for an unknown/already-resolved id —\n * never silently no-ops, since a caller (the control socket's\n * `approvals.resolve`) needs to distinguish \"resolved\" from \"nothing to\n * resolve\".\n *\n * `origin` defaults to `'local'` (see {@link ApprovalOrigin}'s own doc\n * comment for why that's the correct default, not just a convenient one):\n * every existing caller of this method — the control socket's\n * `approvals.resolve` RPC (`create-daemon.ts`), `TaskRunner`'s\n * `requestApproval` timeout and `finish()` fail-closed cleanup\n * (`task-runner.ts`) — resolves a decision this device made on its own.\n * The one exception, a server-sent wire `task.approve`/`task.reject`\n * relayed through `TaskContext.approvalChannel.resolve`\n * (`task-runner.ts`'s `handleOffer`), passes `'wire'` explicitly.\n */\n resolve(approvalId: string, decision: ApprovalDecision, reason?: string, origin: ApprovalOrigin = 'local'): void {\n const entry = this.pending.get(approvalId);\n if (!entry) throw new ApprovalNotFoundError(approvalId);\n this.pending.delete(approvalId);\n entry.onResolve(decision, reason, origin);\n }\n}\n","import {\n constants as fsConstants,\n fstatSync,\n linkSync,\n lstatSync,\n unlinkSync,\n promises as fs,\n} from 'node:fs';\nimport { randomUUID } from 'node:crypto';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { atomicWriteFile } from '../util/atomic-write';\nimport { ensureSecureDir, type EnsureSecureDirOptions } from '../util/secure-dir';\n\nexport interface DeviceRecord {\n deviceId: string;\n /** Current access token (JWT), renewed via challenge/token without re-pairing (protocol §6.2). */\n accessToken: string;\n /** ISO-8601 expiry for `accessToken` (our best knowledge of it — see auth-manager.ts for how this is derived after `/byok/pair`, which reports no explicit expiry itself). */\n expiresAt: string;\n /** Ed25519 private key, PKCS8 PEM. Never leaves this device. Stored as a 0600 file; OS keychain integration is deferred (tracked as a future roadmap item, not promised for any specific milestone). */\n devicePrivateKeyPem: string;\n /** Ed25519 public key, base64url — re-sent verbatim on a post-revocation re-pair (protocol §6.3). */\n devicePublicKey: string;\n}\n\nconst MAX_DEVICE_RECORD_BYTES = 256 * 1024;\n\nfunction sameInode(left: import('node:fs').BigIntStats, right: import('node:fs').BigIntStats): boolean {\n return left.dev === right.dev && left.ino === right.ino;\n}\n\nfunction sameFileState(left: import('node:fs').BigIntStats, right: import('node:fs').BigIntStats): boolean {\n return (\n sameInode(left, right) &&\n left.size === right.size &&\n left.mtimeNs === right.mtimeNs &&\n left.ctimeNs === right.ctimeNs\n );\n}\n\nfunction sameContentState(left: import('node:fs').BigIntStats, right: import('node:fs').BigIntStats): boolean {\n return sameInode(left, right) && left.size === right.size && left.mtimeNs === right.mtimeNs;\n}\n\nfunction parseDeviceRecord(raw: string): DeviceRecord | undefined {\n const parsed = JSON.parse(raw) as Partial<DeviceRecord>;\n if (\n typeof parsed.deviceId === 'string' &&\n typeof parsed.accessToken === 'string' &&\n typeof parsed.expiresAt === 'string' &&\n typeof parsed.devicePrivateKeyPem === 'string' &&\n typeof parsed.devicePublicKey === 'string'\n ) {\n return {\n deviceId: parsed.deviceId,\n accessToken: parsed.accessToken,\n expiresAt: parsed.expiresAt,\n devicePrivateKeyPem: parsed.devicePrivateKeyPem,\n devicePublicKey: parsed.devicePublicKey,\n };\n }\n return undefined;\n}\n\n/**\n * Persists the device identity issued by `pair()` — deviceId, current\n * access token + its expiry, and the device's own Ed25519 keypair. This is\n * the ONLY credential material the daemon itself ever holds — never a\n * runtime's own credentials (see the credential-isolation rule on\n * `RuntimeAdapter`). Stored 0600 under `storeDir` (default\n * `~/.byok/<productId>/`); OS keychain storage is deferred (tracked as a\n * future roadmap item, not promised for any specific milestone).\n */\nexport class DeviceStore {\n private readonly filePath: string;\n\n /**\n * `secureDirOptions` is a test-only DI seam (mirrors `EnsureSecureDirOptions`'s\n * own `run`/`platform` overrides) — every real caller omits it, getting\n * real `ensureSecureDir(storeDir)` behavior unchanged. It exists so\n * finding R4's fail-closed contract (\"on win32, an `icacls` failure makes\n * `save()` — and thus `AuthManager.pair()` — reject with a clear typed\n * `SecureDirHardeningError` instead of silently persisting an\n * ACL-unprotected credential\") is verifiable from a real `darwin`/`linux`\n * CI/dev machine, not just asserted.\n */\n constructor(\n storeDir: string,\n private readonly secureDirOptions?: EnsureSecureDirOptions,\n ) {\n this.filePath = path.join(storeDir, 'device.json');\n }\n\n static defaultDir(productId: string): string {\n return path.join(os.homedir(), '.byok', productId);\n }\n\n /**\n * Resolve the one store pathname every daemon/CLI component must share.\n * A configured relative path is anchored once at process entry rather than\n * being reinterpreted after a diagnostics operation temporarily changes\n * cwd to pin a quarantine directory inode.\n */\n static resolveDir(productId: string, configured?: string): string {\n return path.resolve(configured ?? DeviceStore.defaultDir(productId));\n }\n\n async load(): Promise<DeviceRecord | undefined> {\n const opened = await this.openBounded();\n if (!opened) return undefined;\n try {\n return parseDeviceRecord(opened.raw);\n } finally {\n await opened.handle.close();\n }\n }\n\n /**\n * Read and remove the exact bounded, no-follow device record under the\n * caller's mutation lease. The hard-link guard keeps the inspected inode\n * identifiable until the synchronous pathname check and unlink complete.\n */\n async remove(): Promise<DeviceRecord | undefined> {\n const opened = await this.openBounded();\n if (!opened) return undefined;\n const guardPath = `${this.filePath}.${process.pid}.${randomUUID()}.remove`;\n try {\n const record = parseDeviceRecord(opened.raw);\n linkSync(this.filePath, guardPath);\n const openStat = fstatSync(opened.handle.fd, { bigint: true });\n const guarded = lstatSync(guardPath, { bigint: true });\n const named = lstatSync(this.filePath, { bigint: true });\n // Creating the guard hard-link legitimately changes ctime/link count on\n // the inode, so the post-link check compares identity + content-bearing\n // size/mtime. The bounded read already compared ctime before publication.\n if (!sameContentState(openStat, opened.stat) || !sameInode(guarded, opened.stat) || !sameContentState(named, opened.stat)) {\n throw new Error('device identity changed before removal');\n }\n unlinkSync(this.filePath);\n unlinkSync(guardPath);\n return record;\n } finally {\n try { unlinkSync(guardPath); } catch { /* unpublished guard may not exist */ }\n await opened.handle.close();\n }\n }\n\n async save(record: DeviceRecord): Promise<void> {\n const storeDir = path.dirname(this.filePath);\n // `mkdir`'s own `mode` only applies at CREATION time — a pre-existing\n // storeDir (predating this fix, or created by something else with a\n // more permissive mode) keeps whatever it already had until explicitly\n // chmod'd. Re-asserted on every save, best-effort — mirrors\n // `bin/audit-log.ts`'s `appendAuditEvent`, which has the identical gap\n // (and the identical fix) for the same reason: a failure here (e.g. a\n // storeDir owned by a different user) must never block the save itself.\n // Finding F7: on win32, `ensureSecureDir` ALSO applies a restrictive\n // DACL via `icacls` — POSIX modes alone restrict nothing there. See\n // `util/secure-dir.ts`'s own doc comment. Finding R4: this now THROWS\n // (`SecureDirHardeningError`) on a win32 `icacls` failure instead of\n // warning and continuing — propagates straight out of `save()` (and so\n // out of `AuthManager.pair()`, since nothing here catches it), before\n // `device.json` is ever written.\n await ensureSecureDir(storeDir, this.secureDirOptions);\n // Atomic (temp file + rename) so a concurrent reader never observes a\n // torn/partial file and a crash mid-write never corrupts the existing\n // one — see `util/atomic-write.ts`. This file holds the device private\n // key, so both the atomicity and the 0600 mode are load-bearing, not\n // cosmetic; `{ mode: 0o600 }` is re-asserted on every save (not just the\n // one that first creates the file).\n await atomicWriteFile(this.filePath, JSON.stringify(record, null, 2), { mode: 0o600 });\n }\n\n async clear(): Promise<void> {\n await fs.rm(this.filePath, { force: true });\n }\n\n private async openBounded(): Promise<{\n handle: Awaited<ReturnType<typeof fs.open>>;\n raw: string;\n stat: import('node:fs').BigIntStats;\n } | undefined> {\n let namedBefore: import('node:fs').BigIntStats;\n try {\n namedBefore = await fs.lstat(this.filePath, { bigint: true });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw new Error('device identity could not be inspected safely', { cause: err });\n }\n if (!namedBefore.isFile() || namedBefore.isSymbolicLink()) {\n throw new Error('device identity is not a real regular file');\n }\n let handle: Awaited<ReturnType<typeof fs.open>>;\n try {\n handle = await fs.open(\n this.filePath,\n fsConstants.O_RDONLY | fsConstants.O_NONBLOCK | (fsConstants.O_NOFOLLOW ?? 0),\n );\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw new Error('device identity could not be opened safely', { cause: err });\n }\n try {\n const before = await handle.stat({ bigint: true });\n const namedAfterOpen = await fs.lstat(this.filePath, { bigint: true });\n if (\n !before.isFile() ||\n !namedAfterOpen.isFile() ||\n namedAfterOpen.isSymbolicLink() ||\n !sameFileState(namedBefore, before) ||\n !sameFileState(before, namedAfterOpen)\n ) {\n throw new Error('device identity pathname changed before safe open');\n }\n if (before.size <= 0 || before.size > BigInt(MAX_DEVICE_RECORD_BYTES)) {\n throw new Error('device identity exceeds the bounded read limit');\n }\n const size = Number(before.size);\n const buffer = Buffer.alloc(size);\n const { bytesRead } = await handle.read(buffer, 0, size, 0);\n const after = await handle.stat({ bigint: true });\n const namedAfterRead = await fs.lstat(this.filePath, { bigint: true });\n if (\n bytesRead !== size ||\n !sameFileState(before, after) ||\n !sameFileState(after, namedAfterRead) ||\n namedAfterRead.isSymbolicLink()\n ) {\n throw new Error('device identity changed during bounded read');\n }\n return { handle, raw: buffer.toString('utf8'), stat: after };\n } catch (err) {\n await handle.close();\n throw err;\n }\n }\n}\n","import { createPrivateKey, generateKeyPairSync, sign as edSign, type KeyObject } from 'node:crypto';\n\n/**\n * Device identity keypair (protocol §6): Ed25519, generated once on first\n * pair and reused across re-pairs (§6.3 — \"a fresh device keypair is not\n * required\" when re-pairing after revocation). The private key never\n * leaves this device; only the public key ever goes over the wire\n * (`PairRequest.devicePublicKey`).\n *\n * Encoding choice: an OKP (Ed25519) key's JWK `x` member is defined by\n * RFC 8037 as the raw 32-byte public key, base64url-encoded with no\n * padding — exactly \"Ed25519 public key, base64url-encoded\" per\n * docs/protocol.md §6.1, and avoids shipping an ASN.1/SPKI wrapper the\n * server would otherwise have to strip. Signatures are the raw 64-byte\n * Ed25519 signature (`crypto.sign(null, data, privateKey)` — Ed25519 needs\n * no digest algorithm), also base64url-encoded.\n */\nexport interface DeviceKeyPair {\n publicKeyBase64Url: string;\n privateKey: KeyObject;\n}\n\nexport function generateDeviceKeyPair(): DeviceKeyPair {\n const { publicKey, privateKey } = generateKeyPairSync('ed25519');\n return { publicKeyBase64Url: publicKeyToBase64Url(publicKey), privateKey };\n}\n\nfunction publicKeyToBase64Url(publicKey: KeyObject): string {\n const jwk = publicKey.export({ format: 'jwk' }) as { x?: string };\n if (!jwk.x) throw new Error('failed to export Ed25519 public key as JWK');\n return jwk.x;\n}\n\n/** PKCS8 PEM — the on-disk storage form (0600 file under storeDir). OS keychain integration is deferred (tracked as a future roadmap item, not promised for any specific milestone). */\nexport function exportPrivateKeyPem(privateKey: KeyObject): string {\n return privateKey.export({ type: 'pkcs8', format: 'pem' }) as string;\n}\n\nexport function importPrivateKeyPem(pem: string): KeyObject {\n return createPrivateKey(pem);\n}\n\n/**\n * S1 (GAP-004): the domain-separation prefix this device signs along with a\n * challenge nonce, byte-identical to the server's own\n * `NONCE_SIGNING_DOMAIN` (`packages/server/src/auth.ts`). The device key is a\n * long-lived identity key that later planes will also sign structured\n * messages with; tagging the domain is what stops a signature made for one of\n * those from being replayable as a token-renewal credential.\n *\n * Not shared through a package: the two ends agree on a wire constant, and\n * inventing a dependency between server and client to hold one string literal\n * would couple them far harder than the literal does.\n */\nexport const NONCE_SIGNING_DOMAIN = 'byok-nonce-v1\\n';\n\n/**\n * Sign a challenge nonce with the device private key: the signed message is\n * {@link NONCE_SIGNING_DOMAIN} followed by `nonce` (UTF-8), and the result is\n * the raw 64-byte Ed25519 signature, base64url-encoded (protocol §6.2). A\n * server on the domain-separated contract rejects the undomained form, so\n * there is no variant of this that omits the prefix.\n */\nexport function signNonce(privateKey: KeyObject, nonce: string): string {\n const signature = edSign(null, Buffer.from(NONCE_SIGNING_DOMAIN + nonce, 'utf8'), privateKey);\n return signature.toString('base64url');\n}\n","/** Normalize a configured `serverUrl` (http/https/ws/wss, any path) to an http(s) base with no path/query. */\nexport function toHttpBase(serverUrl: string): string {\n const url = new URL(serverUrl);\n if (url.protocol === 'ws:') url.protocol = 'http:';\n else if (url.protocol === 'wss:') url.protocol = 'https:';\n url.pathname = '/';\n url.search = '';\n return url.toString();\n}\n\n/** Derive the `/byok/ws` WebSocket URL from a configured `serverUrl`. */\nexport function toWsUrl(serverUrl: string): string {\n const url = new URL('/byok/ws', toHttpBase(serverUrl));\n url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';\n return url.toString();\n}\n\n/**\n * M5: thrown by {@link assertServerUrlAllowed} — see that function's own doc\n * comment for the full allow/deny rule this names. Deliberately ONE error\n * type for every way the gate can refuse a `serverUrl` (plaintext-to-remote,\n * or a scheme this SDK's transport has no meaning for at all): a catching\n * caller only ever needs \"the configured server URL failed the\n * transport-security gate\", never which specific sub-case fired — the\n * message text (not the type) carries that detail.\n */\nexport class InsecureServerUrlError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'InsecureServerUrlError';\n }\n}\n\nexport interface AssertServerUrlAllowedOptions {\n /**\n * Explicit escape hatch: when `true`, a `http:`/`ws:` `serverUrl` whose\n * host is NOT loopback is allowed through instead of throwing. Does\n * nothing for an unsupported scheme (see {@link assertServerUrlAllowed}'s\n * own doc comment) — that rejection is unconditional. Threaded from\n * `DaemonConfig.dangerouslyAllowInsecureRemote`; this function itself\n * never logs anything when the hatch is exercised — it stays a pure,\n * synchronous, easily-unit-testable gate — so a caller that sets this\n * true is expected to emit its own warning (see `create-daemon.ts`'s\n * `checkServerUrl`).\n */\n dangerouslyAllowInsecureRemote?: boolean;\n}\n\n/**\n * IPv4 dotted-quad with a first octet of `127` (the full RFC1122 loopback\n * block, `127.0.0.0/8`) — matched against an already-canonicalized\n * `URL.hostname`. The WHATWG URL parser normalizes every alternate IPv4\n * encoding (hex `0x7f000001`, bare-integer `2130706433`, octal `0177.0.0.1`,\n * short forms like `127.1`) to this same plain decimal-octet form before\n * `.hostname` is ever read, and genuinely reinterprets a leading zero as\n * octal (e.g. `0127.0.0.1` canonicalizes to `87.0.0.1`, NOT `127.0.0.1`) —\n * so there is no obfuscated spelling of a 127.0.0.0/8 address that reaches\n * this regex un-normalized, and no leading-zero form to additionally guard\n * against here.\n */\nconst IPV4_127_SLASH_8 = /^127(?:\\.(?:25[0-5]|2[0-4]\\d|1?\\d?\\d)){3}$/;\n\n/**\n * `hostname` is expected to already be `new URL(...).hostname` — lowercased\n * and, for an IPv6 literal, bracketed, per WHATWG URL semantics. Tolerates\n * an unbracketed IPv6 literal too (stripped before comparison) purely\n * defensively, since nothing about this check depends on where `hostname`\n * came from.\n */\nfunction isLoopbackHostname(hostname: string): boolean {\n const bare = hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;\n const normalized = bare.toLowerCase();\n if (normalized === 'localhost' || normalized.endsWith('.localhost')) return true;\n if (normalized === '::1') return true;\n return IPV4_127_SLASH_8.test(normalized);\n}\n\n/**\n * M5: transport-security gate for a configured `serverUrl` — refuses\n * plaintext (`ws:`/`http:`) transport to any non-loopback host, so a device\n * can never be talked into pairing with (and sending its pairing code /\n * device credentials to) a remote host in the clear. Call this ONCE at each\n * real entry point a raw, operator-supplied `serverUrl` first enters the\n * client (`create-daemon.ts`'s `pair()`/`start()`) rather than inside\n * `toHttpBase`/`toWsUrl` themselves: ws-transport, the long-poll fallback,\n * and blob-client all read `serverUrl` from that SAME `DaemonConfig`, never\n * an independently-supplied URL of their own, so those two call sites are\n * already the single common path every one of them goes through.\n *\n * Rules, checked in order:\n * - `https:`/`wss:` — always allowed, any host (TLS is the actual\n * plaintext-network defense; this gate has nothing further to add there).\n * - `http:`/`ws:` — allowed only when the hostname is loopback: exactly\n * `localhost` or any `*.localhost` subdomain, an IPv4 literal in\n * `127.0.0.0/8`, or the IPv6 loopback `::1` — see {@link isLoopbackHostname}.\n * - `http:`/`ws:` to any other host — refused with a clear, typed\n * {@link InsecureServerUrlError} naming the offending URL and the fix\n * (use `wss:`/`https:`, or pass `dangerouslyAllowInsecureRemote: true` if\n * this is a deliberate, understood exception) — UNLESS\n * `opts.dangerouslyAllowInsecureRemote` is `true`.\n * - Any other scheme (or a `serverUrl` that fails to parse as a URL at\n * all) — always refused, regardless of `dangerouslyAllowInsecureRemote`:\n * the escape hatch is specifically for \"plaintext to a remote host I\n * understand the risk of\", not \"a scheme this transport doesn't\n * implement at all\".\n */\nexport function assertServerUrlAllowed(rawUrl: string, opts: AssertServerUrlAllowedOptions = {}): void {\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch (err) {\n throw new InsecureServerUrlError(`invalid server URL \"${rawUrl}\": ${err instanceof Error ? err.message : String(err)}`);\n }\n\n switch (url.protocol) {\n case 'https:':\n case 'wss:':\n return;\n case 'http:':\n case 'ws:':\n if (opts.dangerouslyAllowInsecureRemote || isLoopbackHostname(url.hostname)) return;\n throw new InsecureServerUrlError(\n `refusing to connect to \"${rawUrl}\" over plaintext ${url.protocol.replace(':', '')} — \"${url.hostname}\" is not a ` +\n 'loopback host. Use wss:/https: for any non-loopback server, or pass { dangerouslyAllowInsecureRemote: true } ' +\n '(DaemonConfig) if you understand and accept the risk of sending device credentials over an unencrypted connection.',\n );\n default:\n throw new InsecureServerUrlError(\n `refusing to connect to \"${rawUrl}\" — unsupported scheme \"${url.protocol}\" (expected http:, https:, ws:, or wss:).`,\n );\n }\n}\n","import os from 'node:os';\nimport type { ChallengeResponse, PairResponse, TokenResponse } from '@byok-sdk/protocol';\nimport { DeviceStore, type DeviceRecord } from './store';\nimport { generateDeviceKeyPair, exportPrivateKeyPem, importPrivateKeyPem, signNonce } from './device-keys';\nimport { toHttpBase } from './url';\n\n/**\n * Thrown when the server has revoked this device: a 401 on `/byok/challenge`\n * or `/byok/token` (protocol §6.3). The only recourse is a fresh\n * `/byok/pair` — callers must surface a clear \"re-pair needed\" state and\n * must NOT retry the renewal in a loop.\n */\nexport class DeviceRevokedError extends Error {\n constructor(message = 'device has been revoked by the server; re-pair required') {\n super(message);\n this.name = 'DeviceRevokedError';\n }\n}\n\n/**\n * Conservative assumed lifetime for the token minted directly by\n * `/byok/pair`, which — unlike `/byok/token` — reports no explicit\n * `expiresAt` (only an opaque `refreshHint`). docs/protocol.md §6.1\n * documents a \"~1h lifetime\"; renewing proactively well before that leaves a\n * comfortable margin regardless of what `refreshHint` turns out to mean.\n */\nconst ASSUMED_PAIR_TOKEN_TTL_MS = 45 * 60 * 1000;\n/** Renew this long before a token's recorded expiry — both proactively (background timer) and as the \"already close enough to expiry, renew now\" reactive threshold. */\nconst RENEW_MARGIN_MS = 60 * 1000;\n\nexport interface AuthManagerOptions {\n serverUrl: string;\n store: DeviceStore;\n deviceName?: string;\n /** Called once revocation is detected, so a caller (ConnectionManager) can stop retrying and surface the state instead of looping. */\n onRevoked?: () => void;\n}\n\n/**\n * Owns device pairing and the access token lifecycle (protocol §6):\n * generates/reuses the device Ed25519 keypair, pairs, and renews the access\n * token both proactively (before expiry) and reactively (on a 401 from any\n * caller). This is the single source of truth for \"the current valid JWT\"\n * that WS connects, blob HTTP calls, and the long-poll fallback all use.\n */\nexport class AuthManager {\n private record: DeviceRecord | undefined;\n private renewing: Promise<string> | undefined;\n private proactiveTimer: ReturnType<typeof setTimeout> | undefined;\n private revoked = false;\n private stopped = false;\n private pairing = false;\n private credentialMutationTail: Promise<void> = Promise.resolve();\n\n constructor(private readonly opts: AuthManagerOptions) {}\n\n get deviceId(): string | undefined {\n return this.record?.deviceId;\n }\n\n isRevoked(): boolean {\n return this.revoked;\n }\n\n /** Load a previously-paired device record from disk, if any (idempotent — a second call is a no-op once loaded). */\n async loadExisting(): Promise<DeviceRecord | undefined> {\n this.stopped = false;\n if (!this.record) {\n this.record = await this.opts.store.load();\n }\n if (this.record) this.scheduleProactiveRenewal();\n return this.record;\n }\n\n /** `POST /byok/pair` (v2): generates a device keypair on first pair, reuses it on any subsequent (e.g. post-revocation) re-pair. */\n async pair(pairingCode: string): Promise<DeviceRecord> {\n this.stopped = false;\n this.pairing = true;\n if (this.proactiveTimer) clearTimeout(this.proactiveTimer);\n this.proactiveTimer = undefined;\n try {\n return await this.runCredentialMutation(async () => {\n const existing = this.record ?? (await this.opts.store.load());\n const keyPair = existing\n ? { privateKey: importPrivateKeyPem(existing.devicePrivateKeyPem), publicKeyBase64Url: existing.devicePublicKey }\n : generateDeviceKeyPair();\n\n const url = new URL('/byok/pair', toHttpBase(this.opts.serverUrl));\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n pairingCode,\n deviceName: this.opts.deviceName ?? os.hostname(),\n devicePublicKey: keyPair.publicKeyBase64Url,\n }),\n });\n if (!res.ok) {\n throw new Error(`pairing failed: HTTP ${res.status} ${await safeErrorText(res)}`.trimEnd());\n }\n const body = (await res.json()) as PairResponse;\n\n const record: DeviceRecord = {\n deviceId: body.deviceId,\n accessToken: body.accessToken,\n expiresAt: resolvePairExpiry(body.refreshHint),\n devicePrivateKeyPem: exportPrivateKeyPem(keyPair.privateKey),\n devicePublicKey: keyPair.publicKeyBase64Url,\n };\n await this.opts.store.save(record);\n this.record = record;\n this.revoked = false;\n return record;\n });\n } finally {\n this.pairing = false;\n // Pairing is a short-lived credential mutation, not the start of the\n // daemon lifecycle. loadExisting() is the only place that arms a timer.\n }\n }\n\n /** The current, non-expired access token — renews first if it's expired or close to it. Throws {@link DeviceRevokedError} if the device has been revoked. */\n async getValidAccessToken(): Promise<string> {\n if (!this.record) throw new Error('device is not paired yet; call pair(pairingCode) first');\n if (this.revoked) throw new DeviceRevokedError();\n if (msUntilExpiry(this.record.expiresAt) > RENEW_MARGIN_MS) return this.record.accessToken;\n return this.renew();\n }\n\n /** Force a renewal regardless of the cached token's remaining lifetime — the reactive path, used after a caller sees a 401. */\n async handleUnauthorized(): Promise<string> {\n if (this.revoked) throw new DeviceRevokedError();\n return this.renew();\n }\n\n async stop(): Promise<void> {\n this.stopped = true;\n if (this.proactiveTimer) clearTimeout(this.proactiveTimer);\n this.proactiveTimer = undefined;\n // A timer may already have entered renew() before stop() cleared it. Its\n // final step persists device.json, so daemon ownership cannot be released\n // until that promise settles. Renewal failure is surfaced later by the\n // next token consumer; shutdown only needs the writer barrier here.\n await this.credentialMutationTail;\n }\n\n private async renew(): Promise<string> {\n if (this.stopped) throw new Error('auth manager is stopped; load existing credentials before renewing');\n if (!this.renewing) {\n this.renewing = this.runCredentialMutation(() => this.doRenew()).finally(() => {\n this.renewing = undefined;\n });\n }\n return this.renewing;\n }\n\n private async doRenew(): Promise<string> {\n if (!this.record) throw new Error('device is not paired yet; call pair(pairingCode) first');\n const record = this.record;\n const base = toHttpBase(this.opts.serverUrl);\n const privateKey = importPrivateKeyPem(record.devicePrivateKeyPem);\n\n const challengeRes = await fetch(new URL('/byok/challenge', base), {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ deviceId: record.deviceId }),\n });\n if (challengeRes.status === 401) this.markRevoked();\n if (!challengeRes.ok) {\n throw new Error(\n `token renewal (challenge) failed: HTTP ${challengeRes.status} ${await safeErrorText(challengeRes)}`.trimEnd(),\n );\n }\n const { nonce } = (await challengeRes.json()) as ChallengeResponse;\n const signature = signNonce(privateKey, nonce);\n\n const tokenRes = await fetch(new URL('/byok/token', base), {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ deviceId: record.deviceId, nonce, signature }),\n });\n if (tokenRes.status === 401) this.markRevoked();\n if (!tokenRes.ok) {\n throw new Error(`token renewal (token) failed: HTTP ${tokenRes.status} ${await safeErrorText(tokenRes)}`.trimEnd());\n }\n const body = (await tokenRes.json()) as TokenResponse;\n const updated: DeviceRecord = { ...record, accessToken: body.accessToken, expiresAt: body.expiresAt };\n await this.opts.store.save(updated);\n this.record = updated;\n this.scheduleProactiveRenewal();\n return updated.accessToken;\n }\n\n /** Always throws — `never` return type lets call sites use `if (x === 401) this.markRevoked();` without an explicit `return`/`throw` of their own. */\n private markRevoked(): never {\n this.revoked = true;\n if (this.proactiveTimer) clearTimeout(this.proactiveTimer);\n this.opts.onRevoked?.();\n throw new DeviceRevokedError();\n }\n\n private scheduleProactiveRenewal(): void {\n if (this.proactiveTimer) clearTimeout(this.proactiveTimer);\n this.proactiveTimer = undefined;\n if (!this.record || this.revoked || this.stopped || this.pairing) return;\n const delay = Math.max(0, msUntilExpiry(this.record.expiresAt) - RENEW_MARGIN_MS);\n const timer = setTimeout(() => {\n this.renew().catch(() => {\n // Best-effort background renewal; a real failure (including\n // DeviceRevokedError) surfaces to whoever next calls\n // getValidAccessToken()/handleUnauthorized() instead of being lost here.\n });\n }, delay);\n timer.unref?.();\n this.proactiveTimer = timer;\n }\n\n private async runCredentialMutation<T>(operation: () => Promise<T>): Promise<T> {\n const predecessor = this.credentialMutationTail;\n let release!: () => void;\n this.credentialMutationTail = new Promise<void>((resolve) => {\n release = resolve;\n });\n await predecessor;\n try {\n return await operation();\n } finally {\n release();\n }\n }\n}\n\nfunction msUntilExpiry(expiresAt: string): number {\n return new Date(expiresAt).getTime() - Date.now();\n}\n\nfunction resolvePairExpiry(refreshHint: string | undefined): string {\n if (refreshHint) {\n const parsed = new Date(refreshHint);\n if (!Number.isNaN(parsed.getTime())) return parsed.toISOString();\n }\n return new Date(Date.now() + ASSUMED_PAIR_TOKEN_TTL_MS).toISOString();\n}\n\nasync function safeErrorText(res: Response): Promise<string> {\n try {\n return await res.text();\n } catch {\n return '';\n }\n}\n","import type { AuthManager } from './auth-manager';\n\n/**\n * `fetch` with the current device bearer token attached. On a 401, renews\n * the token once (reactive renewal, protocol §6.2) and retries exactly\n * once — never loops. A second 401 (or {@link AuthManager.handleUnauthorized}\n * throwing `DeviceRevokedError`) propagates to the caller.\n */\nexport async function authedFetch(url: string | URL, init: RequestInit, auth: AuthManager): Promise<Response> {\n const token = await auth.getValidAccessToken();\n const res = await fetch(url, withAuth(init, token));\n if (res.status !== 401) return res;\n\n const renewed = await auth.handleUnauthorized();\n return fetch(url, withAuth(init, renewed));\n}\n\nfunction withAuth(init: RequestInit, token: string): RequestInit {\n return { ...init, headers: { ...(init.headers as Record<string, string> | undefined), Authorization: `Bearer ${token}` } };\n}\n","import { createHash, randomUUID } from 'node:crypto';\nimport type { BlobRef } from '@byok-sdk/protocol';\nimport type { AuthManager } from './auth-manager';\nimport { authedFetch } from './http-client';\nimport { toHttpBase } from './url';\n\n/** Seam `TaskRunner` depends on, so tests can substitute a fake without spinning up real HTTP endpoints. */\nexport interface BlobResolver {\n resolveInstruction(blobRef: BlobRef): Promise<string>;\n uploadArtifact(content: string | Uint8Array, contentType: string): Promise<BlobRef>;\n}\n\nasync function safeErrorText(res: Response): Promise<string> {\n try {\n return await res.text();\n } catch {\n return '';\n }\n}\n\n/**\n * HTTP-side blob transfer (protocol §7): resolving an instruction `blobRef`\n * into its actual content, and uploading an artifact too large to inline.\n * Both require a valid bearer token, handled via `authedFetch`.\n */\nexport class BlobClient implements BlobResolver {\n constructor(\n private readonly serverUrl: string,\n private readonly auth: AuthManager,\n ) {}\n\n /** `blobRef` -> `GET /byok/blobs/:id/url` -> fetch the presigned download URL -> text content. Always resolves fresh rather than trusting any inlined `BlobRef.url`, per docs/protocol.md §7. */\n async resolveInstruction(blobRef: BlobRef): Promise<string> {\n const base = toHttpBase(this.serverUrl);\n const urlRes = await authedFetch(\n new URL(`/byok/blobs/${encodeURIComponent(blobRef.blobId)}/url`, base),\n { method: 'GET' },\n this.auth,\n );\n if (!urlRes.ok) {\n throw new Error(`failed to resolve blob download url: HTTP ${urlRes.status} ${await safeErrorText(urlRes)}`.trimEnd());\n }\n const { downloadUrl } = (await urlRes.json()) as { downloadUrl: string };\n\n // M1-4 e2e finding: the reference `LocalDiskBlobStore` mints\n // *origin-relative* content URLs (`/byok/blobs/:id/content?sig=...`),\n // same-origin with the rest of `byok.hono` — but a real object-store\n // `BlobStore` (S3/GCS/R2) would return a fully-qualified presigned URL.\n // A bare `fetch(downloadUrl)` throws outright on the relative form (no\n // \"current page\" for Node's fetch to resolve against — confirmed, not\n // hypothetical); `new URL(x, base)` handles both: relative resolves\n // against the server's own origin, and an already-absolute URL is\n // returned unchanged (base is ignored per the WHATWG URL spec).\n const contentRes = await fetch(new URL(downloadUrl, base));\n if (!contentRes.ok) {\n throw new Error(`failed to download blob content: HTTP ${contentRes.status}`);\n }\n const bytes = new Uint8Array(await contentRes.arrayBuffer());\n const observedHash = `sha256:${createHash('sha256').update(bytes).digest('hex')}`;\n if (observedHash !== blobRef.contentHash || bytes.length !== blobRef.size) {\n throw new Error(\n `downloaded blob failed declared integrity: expected ${blobRef.contentHash}/${blobRef.size} bytes, observed ${observedHash}/${bytes.length} bytes`,\n );\n }\n return new TextDecoder().decode(bytes);\n }\n\n /** `POST /byok/blobs` (declares size/contentType/contentHash) -> PUT the bytes to the presigned upload URL -> a `BlobRef` for `task.artifact.blobRef`. */\n async uploadArtifact(content: string | Uint8Array, contentType: string): Promise<BlobRef> {\n const bytes = typeof content === 'string' ? new TextEncoder().encode(content) : content;\n const contentHash = `sha256:${createHash('sha256').update(bytes).digest('hex')}`;\n const base = toHttpBase(this.serverUrl);\n const reservationId = `blob_${randomUUID()}`;\n\n const createRes = await authedFetch(\n new URL('/byok/blobs', base),\n {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'idempotency-key': reservationId,\n },\n body: JSON.stringify({ size: bytes.length, contentType, contentHash }),\n },\n this.auth,\n );\n if (!createRes.ok) {\n throw new Error(`failed to create blob: HTTP ${createRes.status} ${await safeErrorText(createRes)}`.trimEnd());\n }\n const { blobId, uploadUrl } = (await createRes.json()) as { blobId: string; uploadUrl: string };\n\n // Same relative-vs-absolute handling as resolveInstruction() above.\n const putRes = await fetch(new URL(uploadUrl, base), {\n method: 'PUT',\n headers: { 'content-type': contentType },\n body: bytes,\n });\n if (!putRes.ok) {\n throw new Error(`failed to upload blob content: HTTP ${putRes.status}`);\n }\n\n await this.#finalize(base, blobId, reservationId);\n\n return { blobId, contentHash, size: bytes.length, contentType };\n }\n\n async #finalize(base: string, blobId: string, reservationId: string): Promise<void> {\n let lastFailure: unknown;\n for (let attempt = 1; attempt <= 2; attempt += 1) {\n let response: Response;\n try {\n response = await authedFetch(\n new URL(`/byok/blobs/${encodeURIComponent(blobId)}/finalize`, base),\n {\n method: 'POST',\n headers: { 'idempotency-key': reservationId },\n },\n this.auth,\n );\n } catch (error) {\n lastFailure = error;\n if (attempt === 2) throw error;\n continue;\n }\n if (response.ok) return;\n if (response.status < 500 || attempt === 2) {\n throw new Error(\n `failed to finalize blob: HTTP ${response.status} ${await safeErrorText(response)}`.trimEnd(),\n );\n }\n lastFailure = new Error(`failed to finalize blob: HTTP ${response.status}`);\n }\n throw lastFailure;\n }\n}\n","import { createHash, createHmac, randomBytes, timingSafeEqual } from 'node:crypto';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type { TaskState } from '@byok-sdk/protocol';\nimport type { ApprovalDecision, PendingApproval } from './approvals';\nimport type { StorageCategory } from './journal/journal';\nimport type { StoragePressureState } from './journal/storage-policy';\nimport type { OperationalHealthSnapshot } from './operational-health';\n\n/**\n * M4 Phase 2: shared local-IPC contract between the daemon's control server\n * (`control-server.ts`) and the CLI's control client (`bin/control-client.ts`)\n * — frame shapes, endpoint path/pipe-name derivation, and the HMAC handshake\n * math. Both sides import from here so the two can never independently drift\n * (e.g. a mismatched HMAC label string, or a socket path computed two\n * slightly different ways).\n *\n * Transport: NDJSON (one JSON object per line) over a Unix domain socket\n * (darwin/linux) or a Windows named pipe — both addressed by the same\n * path-like string via Node's `net` module, so neither `control-server.ts`\n * nor `bin/control-client.ts` needs to special-case the transport itself,\n * only the path/pipe-name derivation below.\n */\n\nexport const CONTROL_PROTOCOL_VERSION = 1;\n\n/** Handshake must complete within this long, on both sides — see each side's own timer. */\nexport const HANDSHAKE_TIMEOUT_MS = 3000;\n\n// ---------------------------------------------------------------------------\n// Endpoint path / pipe name derivation\n// ---------------------------------------------------------------------------\n\n/**\n * Conservative soft limit for a Unix domain socket path, in UTF-8 bytes.\n * macOS's `sockaddr_un.sun_path` is 104 bytes total (including the NUL\n * terminator and any prefix the kernel reserves), so anything comfortably\n * under 104 avoids `ENAMETOOLONG` at `bind()`/`connect()` time on the\n * tightest common platform.\n */\nconst UNIX_SOCKET_PATH_SOFT_LIMIT = 100;\n\nfunction shortHash(input: string): string {\n return createHash('sha256').update(input, 'utf8').digest('hex').slice(0, 16);\n}\n\n/**\n * The Unix domain socket path for a daemon rooted at `storeDir`. Prefers\n * `<storeDir>/control.sock` (keeps every one of this daemon's local state\n * files under one directory, which is already created+chmod'd 0700 by the\n * time this matters — see `control-server.ts`'s `startControlServer`);\n * falls back, whenever the natural path would risk exceeding {@link\n * UNIX_SOCKET_PATH_SOFT_LIMIT}, to a short, deterministic path nested under\n * a PER-DAEMON PRIVATE subdirectory of `os.tmpdir()` — derived from a hash\n * of `storeDir` alone, so both the daemon and any CLI invocation pointed at\n * the same `storeDir` independently compute the identical fallback path.\n *\n * Nested one level deep (rather than a bare `<hash>.sock` file directly in\n * the shared, world-traversable `os.tmpdir()`) specifically so\n * `control-server.ts`'s `bindControlEndpoint` can create+chmod that\n * subdirectory 0700 BEFORE ever binding inside it — the directory's own\n * mode gates traversal into it regardless of the socket file's own\n * (briefly default-permissioned, until the post-bind `chmod`) mode, closing\n * what would otherwise be a real window for another user on the same\n * machine to reach a socket living directly in a shared tmpdir.\n */\nexport function controlSocketPath(storeDir: string): string {\n const candidate = path.join(storeDir, 'control.sock');\n if (Buffer.byteLength(candidate, 'utf8') <= UNIX_SOCKET_PATH_SOFT_LIMIT) return candidate;\n return path.join(os.tmpdir(), `byok-${shortHash(storeDir)}`, 'sock');\n}\n\n/**\n * The Windows named pipe name for a daemon identified by `productId` +\n * (`path.resolve`-normalized) `storeDir`. Named pipes have no filesystem\n * path (no stale-file cleanup concern the way Unix sockets have — see\n * `control-server.ts`), but DO share one flat namespace across the whole\n * machine, so the name must be scoped to this exact daemon instance: two\n * different products, or two different store directories (e.g. two agents\n * of the same product — see `templates/service/README.md`'s \"running\n * multiple agents\" section), must never collide. `storeDir` is resolved\n * before hashing so a trivial path-form difference (trailing slash, etc.)\n * between the two sides can't split the name.\n *\n * NOT keyed by the OS user: a WinSW-installed service runs the daemon under\n * the Windows service account (e.g. `SYSTEM`) while the operator CLI runs\n * as the interactive user, so both sides must derive the identical name\n * from the same `storeDir` alone. Impostor servers are defeated by the\n * mutual HMAC handshake below, not by pipe-name secrecy — keying by user\n * was security theater that broke the service-account topology.\n */\nexport function controlPipeName(productId: string, storeDir: string): string {\n const id = shortHash(`${productId}|${path.resolve(storeDir)}`);\n return `\\\\\\\\.\\\\pipe\\\\byok-${id}`;\n}\n\n/**\n * Dispatches to {@link controlPipeName} on `win32`, {@link controlSocketPath}\n * everywhere else. `platform` defaults to `process.platform`; overridable\n * for tests exercising a specific platform's branch on any host (mirrors\n * `lifecycle/create-service-lifecycle.ts`'s identical `platform` override —\n * the REAL win32 named-pipe semantics can only be proven on actual Windows,\n * which CI's `ipc-smoke` job does; this override just makes the PATH-CHOICE\n * logic itself testable everywhere).\n */\nexport function controlEndpointPath(productId: string, storeDir: string, platform: NodeJS.Platform = process.platform): string {\n return platform === 'win32' ? controlPipeName(productId, storeDir) : controlSocketPath(storeDir);\n}\n\n/** Where the daemon writes its per-session control-auth token (see the handshake section below). Always a real file, even on Windows (pipes have no path of their own to piggyback secrets on). */\nexport function controlTokenPath(storeDir: string): string {\n return path.join(storeDir, 'control.token');\n}\n\n// ---------------------------------------------------------------------------\n// Handshake: mutual HMAC proof, token never sent over the wire\n// ---------------------------------------------------------------------------\n\nconst SERVER_PROOF_LABEL = 'byok-control-server|';\nconst CLIENT_AUTH_LABEL = 'byok-control-client|';\n\nexport function randomNonceHex(): string {\n return randomBytes(32).toString('hex');\n}\n\nfunction hmacHex(token: string, message: string): string {\n return createHmac('sha256', token).update(message, 'utf8').digest('hex');\n}\n\n/** What the server proves to the client: it holds `token`, bound to the client's own nonce so a captured proof can't be replayed against a different handshake. */\nexport function computeServerProof(token: string, clientNonce: string): string {\n return hmacHex(token, SERVER_PROOF_LABEL + clientNonce);\n}\n\n/** What the client proves to the server, symmetrically, bound to the server's nonce. */\nexport function computeClientAuth(token: string, serverNonce: string): string {\n return hmacHex(token, CLIENT_AUTH_LABEL + serverNonce);\n}\n\n/** Constant-time hex-string comparison (`crypto.timingSafeEqual` requires equal-length buffers; a length mismatch is itself a safe, immediate \"not equal\" — no early-exit on content). */\nexport function timingSafeEqualHex(a: string, b: string): boolean {\n const bufA = Buffer.from(a, 'hex');\n const bufB = Buffer.from(b, 'hex');\n if (bufA.length !== bufB.length) return false;\n return timingSafeEqual(bufA, bufB);\n}\n\n// ---------------------------------------------------------------------------\n// Handshake frame shapes + parsers\n// ---------------------------------------------------------------------------\n\nexport interface ClientHello {\n v: 1;\n hello: 'client';\n nonce: string;\n}\nexport interface ServerHello {\n v: 1;\n hello: 'server';\n proof: string;\n nonce: string;\n}\nexport interface ClientAuth {\n v: 1;\n auth: string;\n}\nexport interface ServerReady {\n v: 1;\n ready: true;\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nexport function parseClientHello(value: unknown): ClientHello | undefined {\n if (!isRecord(value)) return undefined;\n if (value.v !== CONTROL_PROTOCOL_VERSION || value.hello !== 'client' || typeof value.nonce !== 'string') return undefined;\n return { v: CONTROL_PROTOCOL_VERSION, hello: 'client', nonce: value.nonce };\n}\n\nexport function parseServerHello(value: unknown): ServerHello | undefined {\n if (!isRecord(value)) return undefined;\n if (\n value.v !== CONTROL_PROTOCOL_VERSION ||\n value.hello !== 'server' ||\n typeof value.proof !== 'string' ||\n typeof value.nonce !== 'string'\n ) {\n return undefined;\n }\n return { v: CONTROL_PROTOCOL_VERSION, hello: 'server', proof: value.proof, nonce: value.nonce };\n}\n\nexport function parseClientAuth(value: unknown): ClientAuth | undefined {\n if (!isRecord(value)) return undefined;\n if (value.v !== CONTROL_PROTOCOL_VERSION || typeof value.auth !== 'string') return undefined;\n return { v: CONTROL_PROTOCOL_VERSION, auth: value.auth };\n}\n\nexport function parseServerReady(value: unknown): ServerReady | undefined {\n if (!isRecord(value)) return undefined;\n if (value.v !== CONTROL_PROTOCOL_VERSION || value.ready !== true) return undefined;\n return { v: CONTROL_PROTOCOL_VERSION, ready: true };\n}\n\n// ---------------------------------------------------------------------------\n// RPC frame shapes (post-handshake)\n// ---------------------------------------------------------------------------\n\nexport interface RawControlRequest {\n /** Not narrowed to `1` here on purpose — an unexpected value is a `bad_version` RESPONSE, not a parse failure; see `control-server.ts`. */\n v: unknown;\n id: string;\n method: string;\n params?: unknown;\n}\n\n/** Loose shape check for an incoming request line: only `id`/`method` need to be well-formed for the server to be able to respond at all (including a `bad_version`/`unknown_method` response) — `v` is deliberately passed through unvalidated. */\nexport function parseRawControlRequest(value: unknown): RawControlRequest | undefined {\n if (!isRecord(value)) return undefined;\n if (typeof value.id !== 'string' || typeof value.method !== 'string') return undefined;\n return { v: value.v, id: value.id, method: value.method, params: value.params };\n}\n\nexport interface ControlErrorShape {\n code: string;\n message: string;\n}\n\nexport interface ControlResponseOk {\n v: 1;\n id: string;\n ok: true;\n result?: unknown;\n /** Present (and `true`) only on the final frame of a streaming method — see `control-server.ts`'s dispatch. */\n done?: true;\n}\n\nexport interface ControlResponseErr {\n v: 1;\n id: string;\n ok: false;\n error: ControlErrorShape;\n}\n\nexport type ControlResponse = ControlResponseOk | ControlResponseErr;\n\nexport interface ControlEventFrame {\n v: 1;\n id: string;\n event: unknown;\n}\n\nexport function encodeFrame(frame: unknown): string {\n return `${JSON.stringify(frame)}\\n`;\n}\n\n/** Thrown by a method handler to control the wire error `{code, message}` a caller sees — anything else thrown surfaces as a generic `internal_error`. See `control-server.ts`'s dispatch and `bin/control-client.ts`'s `request()` (which re-throws this same class on the client side). */\nexport class ControlError extends Error {\n constructor(\n public readonly code: string,\n message: string,\n ) {\n super(message);\n this.name = 'ControlError';\n }\n}\n\n// ---------------------------------------------------------------------------\n// NDJSON line framing\n// ---------------------------------------------------------------------------\n\n/**\n * Bound on a single NDJSON line's byte length. Every real frame this\n * protocol ever sends (handshake frames, requests/responses/events) is well\n * under this — it exists purely as a defensive cap against a misbehaving or\n * hostile peer streaming an unterminated line forever to grow `pending`\n * without bound. Exceeding it is a fail-closed condition: {@link\n * NdjsonLineReader.push} throws, and every caller (`control-server.ts`,\n * `bin/control-client.ts`) destroys the connection on that throw.\n */\nexport const MAX_LINE_BYTES = 64 * 1024;\n\n/**\n * Buffers raw socket bytes and yields complete lines. Splits on the raw byte\n * `0x0a` BEFORE any UTF-8 decoding (mirrors `bin/audit-log.ts`'s\n * `followAuditLog`) — `0x0A` can only ever appear as an actual newline in\n * valid UTF-8, so this never risks decoding a multi-byte character that\n * happened to straddle a chunk boundary.\n */\nexport class NdjsonLineReader {\n private pending: Buffer = Buffer.alloc(0);\n\n /** @throws if the still-unterminated remainder exceeds {@link MAX_LINE_BYTES} — see that constant's own doc comment. */\n push(chunk: Buffer): string[] {\n this.pending = this.pending.length > 0 ? Buffer.concat([this.pending, chunk]) : chunk;\n const lines: string[] = [];\n let newlineIndex: number;\n // eslint-disable-next-line no-cond-assign\n while ((newlineIndex = this.pending.indexOf(0x0a)) !== -1) {\n const line = this.pending.subarray(0, newlineIndex).toString('utf8');\n this.pending = this.pending.subarray(newlineIndex + 1);\n if (line.length > 0) lines.push(line);\n }\n if (this.pending.length > MAX_LINE_BYTES) {\n throw new Error(`NDJSON line exceeded ${MAX_LINE_BYTES} bytes without a terminating newline`);\n }\n return lines;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Method contracts (Phase 2 surface) — shared by create-daemon.ts's control\n// method registry and the CLI commands that call them.\n// ---------------------------------------------------------------------------\n\nexport interface ControlActiveTask {\n taskId: string;\n state: TaskState;\n}\n\n/**\n * M4 Phase 4 (part B.3, observability): a cheap per-active-task queue-depth\n * watermark for the `status` result. The IDEAL metric here would be each\n * runtime adapter's own event-queue depth (`util/async-queue.ts`'s\n * `AsyncQueue`) — but that queue lives inside each adapter's concrete\n * `Session` implementation, and `Session.events` (`types.ts`) is typed only\n * as a plain `AsyncIterable<AgentEvent>`, which has no queryable backlog\n * size; reaching it would mean adding a new method to the `Session`\n * interface AND implementing it in all three bundled adapters\n * (pi/claude/codex), which is out of scope for this pass. This instead\n * reflects two things `TaskRunner` already cheaply knows about the SAME\n * task without any new plumbing: how much progress is buffered locally\n * (not yet flushed as a `task.progress` batch), and how many out-of-band\n * approval requests are currently in flight for it. See\n * `task-runner.ts`'s `getQueueWatermarks` for how each field is computed.\n */\nexport interface TaskQueueWatermark {\n taskId: string;\n /** Events buffered in this task's `ProgressBatcher`, not yet flushed as a `task.progress` batch. */\n progressBatcherPending: number;\n /** Approval requests currently in flight for this task: 1 if one is actively dispatched (registered + `task.await_approval` sent) plus however many more are queued behind it (M4 Phase 4 fold-in — see `TaskRunner.requestApproval`). */\n pendingApprovals: number;\n}\n\n/**\n * S3b (L-003): local storage usage and pressure, as the `status` method\n * reports them (architecture §12.7.2.1).\n *\n * Named `storage*` throughout, NOT `watermark*`: {@link TaskQueueWatermark}\n * above is a per-task progress-buffer depth and has nothing to do with disk.\n * Two unrelated concepts sharing a name on one status result is how an\n * operator reads the wrong number during an incident.\n *\n * Present only when a daemon actually runs a storage policy\n * (`DaemonConfig.hostedJournal.storagePolicy`). Absent means \"not measured\",\n * which is a different statement from \"measured, and fine\" — so it is an\n * absent field rather than a zeroed one.\n */\nexport interface ControlStorageStatus {\n /** §12.7.2.1's four states. `hard-pressure` declines new offers; `emergency` refuses to ack at all. */\n pressureState: StoragePressureState;\n /** `maxStoreBytes` — the budget `usedBytes` is measured against. */\n budgetBytes: number;\n /** Total across every category below, as of `measuredAt`. */\n usedBytes: number;\n /** Bytes available to this daemon on the store's filesystem — the free-space axis of the watermark, independent of the budget. */\n freeBytes: number;\n measuredAt: string;\n /** The five §12.7.2.1 categories, always reported separately — a single total cannot drive a category-scoped cleanup order or a category-scoped never-delete list. */\n categories: ControlStorageCategoryUsage[];\n /** The most recent bounded WAL checkpoint + incremental vacuum, if one has run in this daemon's lifetime. */\n lastCompaction?: ControlStorageCompaction;\n}\n\nexport interface ControlStorageCategoryUsage {\n category: StorageCategory;\n bytes: number;\n /** `true` when this is a host-reported or sampled figure rather than one measured off the filesystem. */\n approximate: boolean;\n}\n\nexport interface ControlStorageCompaction {\n checkpointed: boolean;\n walFramesRemaining: number;\n pagesVacuumed: number;\n durationMs: number;\n at: string;\n}\n\n/** Result shape for the `status` method — see `create-daemon.ts`'s control-method wiring for how each field is sourced, and `bin/format.ts`'s `formatLiveStatusLines` for how the CLI renders it. */\nexport interface ControlStatusResult {\n pid: number;\n uptimeMs: number;\n paired: boolean;\n deviceId?: string;\n /** The connection state machine's own current value (`ws-transport.ts`'s `ConnectionState`) — e.g. `'open'`, `'degraded'` (long-poll fallback), `'revoked'`, `'closed'`, `'connecting'`. */\n transport: string;\n activeTasks: ControlActiveTask[];\n runtimeIds: string[];\n /** M4 Phase 4 (part B.3): per-active-task queue watermarks — see {@link TaskQueueWatermark}. */\n queueWatermarks: TaskQueueWatermark[];\n /**\n * Finding F4 (cross-model adversarial review): the actual pending\n * approvals currently dispatched — the SAME entries `approvals.list`\n * returns (`ApprovalRegistry.list()`), surfaced here too so a single\n * `status` call can show an operator every `approvalId` they'd need to\n * `approve`/`reject`, without a second control-socket round trip. This is\n * `approvalsPending`'s own source list (`approvalsPending ===\n * approvals.length`, always).\n */\n approvals: PendingApproval[];\n /** M4 Phase 4 (part B.3): total approvals currently DISPATCHED (registered) across the whole daemon — the same count `approvals.list` returns, surfaced here too for a one-call status view. */\n approvalsPending: number;\n /** S3b (L-003): local storage usage + pressure — see {@link ControlStorageStatus}. Absent unless a storage policy is configured. */\n storage?: ControlStorageStatus;\n /** Local lifecycle/retry budget. This is not the transport state above. */\n operationalHealth: OperationalHealthSnapshot;\n}\n\nexport interface ApprovalsListResult {\n approvals: PendingApproval[];\n}\n\nexport type { ApprovalDecision, PendingApproval } from './approvals';\n\nexport interface ApprovalsResolveParams {\n approvalId: string;\n decision: ApprovalDecision;\n reason?: string;\n}\n\nexport function parseApprovalsResolveParams(value: unknown): ApprovalsResolveParams | undefined {\n if (!isRecord(value)) return undefined;\n if (typeof value.approvalId !== 'string') return undefined;\n if (value.decision !== 'approve' && value.decision !== 'reject') return undefined;\n if (value.reason !== undefined && typeof value.reason !== 'string') return undefined;\n return { approvalId: value.approvalId, decision: value.decision, reason: value.reason };\n}\n\n/**\n * M4 Phase 3: the control method `byok-approval-mcp` (`bin/byok-approval-mcp.ts`)\n * calls FROM a claude-spawned MCP-server child process — a genuinely\n * different OS process from the daemon, reachable only over this same\n * control socket (see `../types.ts`'s `ApprovalChannel` doc comment for the\n * full why). `taskId` correlates the request to an active task;\n * `summary` is a short, human-readable description of the gated action\n * (carried verbatim into the wire `task.await_approval.summary`).\n */\nexport interface ApprovalsRequestParams {\n taskId: string;\n summary: string;\n}\n\nexport function parseApprovalsRequestParams(value: unknown): ApprovalsRequestParams | undefined {\n if (!isRecord(value)) return undefined;\n if (typeof value.taskId !== 'string' || value.taskId.length === 0) return undefined;\n if (typeof value.summary !== 'string') return undefined;\n return { taskId: value.taskId, summary: value.summary };\n}\n\n/** Result of `approvals.request` — the outcome `byok-approval-mcp` translates into its own MCP `allow`/`deny` answer. */\nexport interface ApprovalsRequestResult {\n approved: boolean;\n reason?: string;\n}\n\nexport type ShutdownReason = 'unpair' | 'operator';\n\nexport interface ShutdownParams {\n reason?: ShutdownReason;\n}\n\nexport function parseShutdownParams(value: unknown): ShutdownParams {\n if (!isRecord(value)) return {};\n return value.reason === 'unpair' || value.reason === 'operator' ? { reason: value.reason } : {};\n}\n","import { randomBytes } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport net from 'node:net';\nimport path from 'node:path';\nimport { atomicWriteFile } from '../util/atomic-write';\nimport { ensureSecureDir } from '../util/secure-dir';\nimport {\n computeClientAuth,\n computeServerProof,\n controlEndpointPath,\n controlTokenPath,\n encodeFrame,\n parseClientAuth,\n parseClientHello,\n parseRawControlRequest,\n randomNonceHex,\n timingSafeEqualHex,\n ControlError,\n HANDSHAKE_TIMEOUT_MS,\n NdjsonLineReader,\n type ControlErrorShape,\n} from './control-protocol';\n\n/**\n * M4 Phase 2: the daemon-side local control socket — Unix domain socket\n * (darwin/linux) or Windows named pipe, mutually authenticated by an\n * HMAC handshake over a token that never crosses the wire (see\n * `control-protocol.ts`), speaking a small NDJSON request/response(/event)\n * RPC protocol. Transport-only and daemon-agnostic: `create-daemon.ts`\n * supplies the actual method handlers (`status`, `tasks.subscribe`,\n * `approvals.*`, `shutdown`) as a plain registry — this module knows\n * nothing about `Daemon`/`TaskRunner` internals, which keeps it testable\n * (and reusable) on its own.\n */\n\nexport class AnotherControlServerRunningError extends Error {\n constructor(endpoint: string) {\n super(`another daemon's control server appears to already be running at \"${endpoint}\" — refusing to start a second one`);\n this.name = 'AnotherControlServerRunningError';\n }\n}\n\n/** Default cap on simultaneous pre-handshake (\"half-open\") connections — see `startControlServer`'s own comment on why. */\nexport const MAX_HALF_OPEN_CONNECTIONS = 8;\n\nexport interface ControlMethodContext {\n /** Emits one `event` frame for a streaming method's current request. */\n emit: (event: unknown) => void;\n /** Aborts once the client disconnects — a streaming handler must stop producing events and release whatever it subscribed to. */\n signal: AbortSignal;\n}\n\nexport type UnaryMethod = (params: unknown) => Promise<unknown> | unknown;\nexport type StreamMethod = (params: unknown, ctx: ControlMethodContext) => Promise<void>;\n\nexport interface ControlMethods {\n unary: Record<string, UnaryMethod>;\n stream: Record<string, StreamMethod>;\n}\n\nexport interface ControlServerOptions {\n storeDir: string;\n productId: string;\n methods: ControlMethods;\n /** Test-only override — default `HANDSHAKE_TIMEOUT_MS` (3000ms). */\n handshakeTimeoutMs?: number;\n /** Test-only override — default `MAX_HALF_OPEN_CONNECTIONS` (8). */\n maxHalfOpenConnections?: number;\n}\n\nexport interface ControlServerHandle {\n /** The bound Unix socket path or Windows pipe name. */\n endpoint: string;\n /** Stops accepting new connections, destroys every open one, and removes the socket/token files (a Windows pipe leaves no file to remove). Idempotent. */\n close(): Promise<void>;\n}\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nfunction toControlErrorShape(err: unknown): ControlErrorShape {\n if (err instanceof ControlError) return { code: err.code, message: err.message };\n return { code: 'internal_error', message: errorMessage(err) };\n}\n\n/**\n * Unix-only: a socket FILE left over from a daemon that didn't shut down\n * cleanly (crash, `kill -9`) is otherwise indistinguishable on disk from one\n * a currently-running daemon is actively listening on. Attempts a real\n * connect to tell the two apart:\n *\n * - `ECONNREFUSED` — nothing is listening; the file is stale. Safe to unlink.\n * - A successful connect — a live daemon IS listening; fatal, never unlinked.\n * - Anything else (permission denied, a connect that hangs past the probe\n * timeout, the path existing but not being a socket at all) — cannot\n * positively confirm it's stale, so this fails closed exactly like a live\n * listener (mirrors this repo's `bin/commands/unpair.ts` \"unknown state is\n * unsafe\" convention) rather than guessing and risking two daemons racing\n * the same store.\n */\nfunction probeUnixSocketAlive(socketPath: string): Promise<boolean> {\n return new Promise((resolve) => {\n const socket = net.createConnection(socketPath);\n const finish = (alive: boolean): void => {\n clearTimeout(timer);\n socket.removeAllListeners();\n socket.destroy();\n resolve(alive);\n };\n const timer = setTimeout(() => finish(true), 1000); // no answer within 1s: cannot confirm stale -> fail closed\n socket.once('connect', () => finish(true));\n socket.once('error', (err: NodeJS.ErrnoException) => finish(err.code !== 'ECONNREFUSED'));\n });\n}\n\nasync function handleStaleUnixSocket(socketPath: string): Promise<void> {\n const exists = await fs.stat(socketPath).then(\n () => true,\n () => false,\n );\n if (!exists) return;\n const alive = await probeUnixSocketAlive(socketPath);\n if (alive) throw new AnotherControlServerRunningError(socketPath);\n await fs.rm(socketPath, { force: true });\n}\n\n/**\n * Hardening finding (P2 re-gate): `fs.chmod` just above/below this call is\n * fire-and-forget (`.catch(() => {})`) because tightening the mode on a\n * directory this process doesn't OWN fails with `EPERM` — not because that\n * failure is safe to ignore. On a shared, world-writable `os.tmpdir()` (the\n * long-storeDir-path fallback branch of `controlSocketPath`), an attacker on\n * the same machine can pre-create the exact deterministic `byok-<hash>`\n * directory name (derived from a hash of `storeDir` alone, so it's fully\n * predictable ahead of time) — e.g. as a symlink to somewhere else, or\n * simply owned by a different uid with a permissive mode. `fs.mkdir` above\n * is a silent no-op against an already-existing directory (never throws,\n * never fixes ownership), so without this check the swallowed `chmod`\n * failure would fall straight through to `handleStaleUnixSocket` and this\n * daemon would bind its control socket's Unix domain socket file INSIDE\n * that attacker-owned/aliased directory — handing a same-machine attacker a\n * way to plant their own listener at the exact path this daemon is about to\n * bind, or delete/replace the legitimate socket file later (the directory's\n * own owner controls what's inside it, regardless of the socket file's own\n * mode).\n *\n * `lstat` (never `stat`, which follows a symlink) closes this: fail CLOSED\n * (throw) rather than silently proceeding whenever the path that's actually\n * there is either a symlink or not owned by this exact process's own uid —\n * the two properties a same-machine attacker could control that \"the\n * directory exists\" alone can't rule out once `chmod` has already failed\n * silently. Applied unconditionally (not just in the tmpdir-fallback\n * branch): a no-op in the common `storeDir` case (already owned + 0700 by\n * this same process — see `startControlServer`), genuine defense-in-depth\n * where it actually matters.\n *\n * Throws a plain `Error` — like any other non-`AnotherControlServerRunningError`\n * bind failure this module raises (see `startControlServer`'s own doc\n * comment) — so the caller (`create-daemon.ts`'s `start()`) degrades\n * non-fatally: it logs a clear warning and continues without a control\n * socket, rather than bricking the rest of the daemon over it.\n */\nasync function assertOwnedPrivateDir(dir: string): Promise<void> {\n const uid = process.getuid?.();\n if (uid === undefined) return; // non-POSIX — this is only ever called from the non-win32 branch below, but stay defensive\n const st = await fs.lstat(dir);\n if (st.isSymbolicLink()) {\n throw new Error(\n `refusing to bind control socket under \"${dir}\": path is a symlink, not a real directory (possible attacker-controlled path in a shared temp directory)`,\n );\n }\n if (st.uid !== uid) {\n throw new Error(\n `refusing to bind control socket under \"${dir}\": directory is owned by uid ${st.uid}, not this process's own uid ${uid} (possible attacker-controlled path in a shared temp directory)`,\n );\n }\n}\n\nasync function bindControlEndpoint(server: net.Server, endpoint: string): Promise<void> {\n if (process.platform !== 'win32') {\n // Ensure the socket's own parent directory is private BEFORE the\n // socket file itself ever exists — closes the default-perms window on\n // the socket file (see `control-protocol.ts`'s `controlSocketPath` doc\n // comment): a directory's own 0700 mode blocks any OTHER user from even\n // traversing into it, regardless of the socket file's transient mode\n // between `listen()` creating it and the `chmod` below tightening it.\n // A no-op re-assertion for the common (storeDir) case, already 0700 —\n // this only does real work for the tmpdir long-path fallback, whose\n // parent subdirectory doesn't exist yet the first time a given\n // storeDir hits it.\n const endpointDir = path.dirname(endpoint);\n await fs.mkdir(endpointDir, { recursive: true, mode: 0o700 });\n await fs.chmod(endpointDir, 0o700).catch(() => {});\n await assertOwnedPrivateDir(endpointDir);\n await handleStaleUnixSocket(endpoint);\n }\n await new Promise<void>((resolve, reject) => {\n const onError = (err: NodeJS.ErrnoException): void => {\n server.removeListener('listening', onListening);\n if (err.code === 'EADDRINUSE') reject(new AnotherControlServerRunningError(endpoint));\n else reject(err);\n };\n const onListening = (): void => {\n server.removeListener('error', onError);\n resolve();\n };\n server.once('error', onError);\n server.once('listening', onListening);\n server.listen(endpoint);\n });\n if (process.platform !== 'win32') {\n await fs.chmod(endpoint, 0o600).catch(() => {});\n }\n}\n\n/**\n * Per-connection handshake + request-dispatch state machine.\n * `onHandshakeSettled` fires exactly once — either once the handshake\n * actually completes (`phase` reaches `'ready'`) or, if it never does,\n * once the socket closes — so the caller's half-open-connection count\n * (see `MAX_HALF_OPEN_CONNECTIONS`) is always released, never leaked.\n */\nfunction handleConnection(\n socket: net.Socket,\n token: string,\n methods: ControlMethods,\n handshakeTimeoutMs: number,\n onHandshakeSettled: () => void,\n): void {\n const reader = new NdjsonLineReader();\n const activeStreams = new Map<string, AbortController>();\n let phase: 'client-hello' | 'client-auth' | 'ready' = 'client-hello';\n let serverNonce = '';\n let destroyed = false;\n let handshakeSettled = false;\n\n function settleHandshake(): void {\n if (handshakeSettled) return;\n handshakeSettled = true;\n onHandshakeSettled();\n }\n\n const handshakeTimer = setTimeout(() => {\n if (phase !== 'ready') socket.destroy();\n }, handshakeTimeoutMs);\n handshakeTimer.unref?.();\n\n function sendFrame(frame: unknown): void {\n if (!destroyed && socket.writable) socket.write(encodeFrame(frame));\n }\n\n function handleClientHello(parsed: unknown): void {\n const hello = parseClientHello(parsed);\n if (!hello) {\n socket.destroy();\n return;\n }\n serverNonce = randomNonceHex();\n sendFrame({ v: 1, hello: 'server', proof: computeServerProof(token, hello.nonce), nonce: serverNonce });\n phase = 'client-auth';\n }\n\n function handleClientAuth(parsed: unknown): void {\n const auth = parseClientAuth(parsed);\n if (!auth || !timingSafeEqualHex(auth.auth, computeClientAuth(token, serverNonce))) {\n socket.destroy();\n return;\n }\n clearTimeout(handshakeTimer);\n phase = 'ready';\n settleHandshake();\n sendFrame({ v: 1, ready: true });\n }\n\n function dispatch(id: string, method: string, params: unknown): void {\n const unary = methods.unary[method];\n if (unary) {\n Promise.resolve()\n .then(() => unary(params))\n .then((result) => sendFrame({ v: 1, id, ok: true, result }))\n .catch((err: unknown) => sendFrame({ v: 1, id, ok: false, error: toControlErrorShape(err) }));\n return;\n }\n const stream = methods.stream[method];\n if (stream) {\n const controller = new AbortController();\n activeStreams.set(id, controller);\n stream(params, { emit: (event) => sendFrame({ v: 1, id, event }), signal: controller.signal })\n .then(() => {\n activeStreams.delete(id);\n if (!controller.signal.aborted) sendFrame({ v: 1, id, ok: true, done: true });\n })\n .catch((err: unknown) => {\n activeStreams.delete(id);\n sendFrame({ v: 1, id, ok: false, error: toControlErrorShape(err) });\n });\n return;\n }\n sendFrame({ v: 1, id, ok: false, error: { code: 'unknown_method', message: `unknown method \"${method}\"` } });\n }\n\n function handleRequestLine(parsed: unknown): void {\n const raw = parseRawControlRequest(parsed);\n if (!raw) {\n // Can't even extract an id/method to respond against — fail closed by\n // closing the connection rather than guessing at a shape to reply with.\n socket.destroy();\n return;\n }\n if (raw.v !== 1) {\n sendFrame({ v: 1, id: raw.id, ok: false, error: { code: 'bad_version', message: `unsupported protocol version: ${String(raw.v)}` } });\n return;\n }\n dispatch(raw.id, raw.method, raw.params);\n }\n\n function handleLine(line: string): void {\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n socket.destroy();\n return;\n }\n if (phase === 'client-hello') handleClientHello(parsed);\n else if (phase === 'client-auth') handleClientAuth(parsed);\n else handleRequestLine(parsed);\n }\n\n socket.on('data', (chunk: Buffer) => {\n let lines: string[];\n try {\n lines = reader.push(chunk);\n } catch {\n // MAX_LINE_BYTES exceeded (control-protocol.ts) — fail closed.\n socket.destroy();\n return;\n }\n for (const line of lines) handleLine(line);\n });\n socket.on('error', () => {\n // 'close' always follows and does cleanup below — swallow so a peer\n // reset/EPIPE never becomes an unhandled 'error' crash.\n });\n socket.on('close', () => {\n destroyed = true;\n clearTimeout(handshakeTimer);\n settleHandshake(); // in case it closed (timeout, malformed hello/auth, over-cap) before ever completing\n for (const controller of activeStreams.values()) controller.abort();\n activeStreams.clear();\n });\n}\n\n/**\n * Binds the platform endpoint (Unix socket or Windows pipe — see\n * `control-protocol.ts`) FIRST, and only once that succeeds generates and\n * persists a fresh per-session token to `<storeDir>/control.token` (0600).\n * This ordering matters: if a bind fails because ANOTHER daemon's control\n * server already owns this endpoint (see\n * {@link AnotherControlServerRunningError}), that other daemon's own token\n * file must be left completely untouched — writing (and, on failure,\n * deleting) a token before the bind attempt would corrupt or erase the\n * still-running daemon's valid token out from under it.\n *\n * Throws {@link AnotherControlServerRunningError} if a live listener already\n * owns this endpoint (fatal — the caller, `create-daemon.ts`, treats this as\n * a hard startup failure); any OTHER bind failure propagates as a plain\n * `Error` so the caller can decide to degrade instead (the control socket\n * must never be allowed to brick the rest of the daemon).\n */\nexport async function startControlServer(opts: ControlServerOptions): Promise<ControlServerHandle> {\n // Finding F7: on win32, ALSO applies a restrictive DACL via `icacls` —\n // POSIX modes (the `{mode: 0o700}` this replaces) restrict nothing there.\n // See `util/secure-dir.ts`'s own doc comment; `control.token` (written\n // below, once the bind succeeds) inherits this directory's ACL.\n await ensureSecureDir(opts.storeDir);\n\n const token = randomBytes(32).toString('hex'); // in-memory only until the bind below actually succeeds\n const tokenPath = controlTokenPath(opts.storeDir);\n const endpoint = controlEndpointPath(opts.productId, opts.storeDir);\n const handshakeTimeoutMs = opts.handshakeTimeoutMs ?? HANDSHAKE_TIMEOUT_MS;\n const sockets = new Set<net.Socket>();\n // Defensive cap against a peer opening many connections and never\n // completing (or slow-drip-ing) the handshake on any of them, tying up\n // resources — beyond this, a new connection is closed immediately rather\n // than given its own handshake timer. Real usage never approaches this\n // (each CLI command opens one connection, uses it briefly, and closes\n // it), so this only ever bites a misbehaving/hostile peer.\n const maxHalfOpenConnections = opts.maxHalfOpenConnections ?? MAX_HALF_OPEN_CONNECTIONS;\n let halfOpenCount = 0;\n const server = net.createServer((socket) => {\n if (halfOpenCount >= maxHalfOpenConnections) {\n socket.destroy();\n return;\n }\n halfOpenCount += 1;\n sockets.add(socket);\n socket.on('close', () => sockets.delete(socket));\n handleConnection(socket, token, opts.methods, handshakeTimeoutMs, () => {\n halfOpenCount -= 1;\n });\n });\n\n await bindControlEndpoint(server, endpoint); // throws without ever touching the token file — see doc comment above\n\n try {\n await atomicWriteFile(tokenPath, token, { mode: 0o600 });\n } catch (err) {\n // Finding F9 (cross-model adversarial review): the bind just above\n // already succeeded — `server` is actively listening on `endpoint`. A\n // token-write failure (disk full, storeDir removed out from under this\n // call, a permission change mid-flight) used to propagate straight out\n // of this function without ever tearing that listener down: the caller\n // never gets a `ControlServerHandle` to `close()` (the throw happens\n // before this function ever returns one — see `create-daemon.ts`'s own\n // \"continuing without it\" degrade path, which only ever sees the\n // exception, never the live socket underneath it), so the listener was\n // silently ORPHANED — unreachable for the rest of the process's\n // lifetime, and blocking every future bind attempt at this exact\n // `endpoint` with `EADDRINUSE`/{@link AnotherControlServerRunningError}\n // (e.g. a later retry, or this same daemon's next `start()`) even\n // though nothing valid is actually listening behind it anymore in any\n // useful sense (its token was never written, so no client could ever\n // complete a handshake against it either). `atomicWriteFile` itself\n // already guarantees `tokenPath` was never created/left partial on\n // failure (its own temp-file-only cleanup — see `util/atomic-write.ts`),\n // so there is nothing to unwind on that side; only the listener this\n // function itself just stood up needs tearing down before rethrowing.\n // Mirrors `close()`'s own teardown shape below (destroy any sockets\n // that connected in this narrow window, close the server, remove the\n // socket file — never a pipe, which has no file to remove).\n for (const socket of sockets) socket.destroy();\n await new Promise<void>((resolve) => server.close(() => resolve()));\n if (process.platform !== 'win32') {\n await fs.rm(endpoint, { force: true }).catch(() => {});\n }\n throw err;\n }\n\n let closed = false;\n async function close(): Promise<void> {\n if (closed) return;\n closed = true;\n for (const socket of sockets) socket.destroy();\n await new Promise<void>((resolve) => server.close(() => resolve()));\n if (process.platform !== 'win32') {\n await fs.rm(endpoint, { force: true }).catch(() => {});\n }\n await fs.rm(tokenPath, { force: true }).catch(() => {});\n }\n\n return { endpoint, close };\n}\n","import { createHash } from 'node:crypto';\n\nexport type JitterDomain = 'reconnect' | 'upload' | 'maintenance';\n\nexport interface DeterministicJitterInput {\n seed: string;\n domain: JitterDomain;\n sequence: number;\n baseMs: number;\n ratio?: number;\n}\n\n/**\n * Stable, domain-separated fleet jitter. The same identity/domain/sequence\n * always produces the same integer delay, while a different domain cannot\n * accidentally reuse the same hash stream. There is deliberately no random\n * fallback: callers must have loaded the device identity before constructing\n * an automatic retry loop.\n */\nexport function deterministicJitterMs(input: DeterministicJitterInput): number {\n const ratio = input.ratio ?? 0.2;\n if (input.seed.length === 0) throw new Error('deterministic jitter seed must not be empty');\n if (!Number.isSafeInteger(input.sequence) || input.sequence < 0) {\n throw new Error('deterministic jitter sequence must be a non-negative safe integer');\n }\n if (!Number.isFinite(input.baseMs) || input.baseMs < 0) {\n throw new Error('deterministic jitter baseMs must be a finite non-negative number');\n }\n if (!Number.isFinite(ratio) || ratio < 0 || ratio > 1) {\n throw new Error('deterministic jitter ratio must be between 0 and 1');\n }\n if (input.baseMs === 0 || ratio === 0) return Math.round(input.baseMs);\n\n const digest = createHash('sha256')\n .update('byok-jitter-v1\\0', 'utf8')\n .update(input.domain, 'utf8')\n .update('\\0', 'utf8')\n .update(input.seed, 'utf8')\n .update('\\0', 'utf8')\n .update(String(input.sequence), 'utf8')\n .digest();\n // 53 deterministic bits fit exactly in a JS number. Mapping to [0, 1)\n // avoids platform-dependent bigint/float conversions.\n const high = digest.readUInt32BE(0) & 0x001fffff;\n const low = digest.readUInt32BE(4);\n const unit = (high * 0x1_0000_0000 + low) / 0x20_0000_0000_0000;\n const multiplier = 1 - ratio + unit * ratio * 2;\n return Math.max(0, Math.round(input.baseMs * multiplier));\n}\n\nexport interface FleetJitter {\n delay(domain: JitterDomain, sequence: number, baseMs: number): number;\n}\n\nexport function createFleetJitter(productId: string, deviceId: string): FleetJitter {\n if (productId.length === 0 || deviceId.length === 0) {\n throw new Error('productId and deviceId are required for fleet jitter');\n }\n const seed = `${productId}\\0${deviceId}`;\n return {\n delay: (domain, sequence, baseMs) => deterministicJitterMs({ seed, domain, sequence, baseMs }),\n };\n}\n","import { MessagesSendResponseSchema, parseMessage, UnknownMessageTypeError, type Envelope } from '@byok-sdk/protocol';\nimport { AuthManager, DeviceRevokedError } from './auth-manager';\nimport { authedFetch } from './http-client';\nimport { toHttpBase } from './url';\n\nexport interface LongPollClientOptions {\n serverUrl: string;\n auth: AuthManager;\n getCursor: () => number | undefined;\n onEnvelope: (envelope: Envelope) => void;\n /** Called once the device is found to be revoked (401 surfaced through {@link AuthManager}) — the loop stops itself rather than retrying. */\n onRevoked?: () => void;\n /**\n * M4 Phase 4 (version-negotiation drill fix), scope narrowed by finding F1:\n * called ONLY for a batch entry that failed to parse because its `type`\n * is entirely unrecognized (`parseMessage` throwing\n * {@link UnknownMessageTypeError} — mirrors `ws-transport.ts`'s identical\n * per-frame tolerance for that SPECIFIC failure) and which still carries a\n * numeric envelope-level `seq` AND a recognizably task-class `type` (a\n * `task.` prefix — see `extractSkippableSeq`'s own doc comment for why a\n * `conn.*`-shaped or type-less entry is deliberately excluded, mirroring\n * F2's \"conn.* is never cursor-tracked\" rule), so the caller can advance\n * its cursor/watermark past it even though there is no real `Envelope` to\n * hand to `onEnvelope`. Without this, a persistently-redelivered\n * unrecognized-type entry (the real server retains and redelivers an\n * un-acked envelope, protocol §9) would keep reappearing at the same\n * cursor position forever.\n *\n * Finding F1: a RECOGNIZED type that fails schema validation\n * ({@link EnvelopeValidationError} — e.g. a `task.offer` whose\n * `PermissionPolicy` rejects an unknown constraint) is deliberately NOT\n * reported here. That failure is a genuinely malformed control message,\n * not forward-compat tolerance — forwarding its `seq` here would\n * permanently ack a message the daemon never actually understood (the\n * server would stop redelivering it, silently stranding whatever it was\n * offering). The WS path never had this hazard (an unparseable WS frame\n * has no skip-side cursor bookkeeping at all — see\n * `ws-transport.ts` — so it simply gets redelivered later); this callback\n * being scoped to `UnknownMessageTypeError` only is what makes long-poll\n * match that same \"no silent permanent ack\" property for real. Optional\n * only for constructor/test convenience — `ConnectionManager` always\n * supplies it.\n */\n onSkippedSeq?: (seq: number) => void;\n /**\n * Finding R1 (cross-model re-review — the F1 fix alone was NOT-CLOSED):\n * called for a batch entry whose `type` WAS recognized but whose payload\n * failed schema validation ({@link EnvelopeValidationError}) — a genuine\n * delivery failure at that specific seq, not forward-compat tolerance\n * (contrast {@link onSkippedSeq}, which is scoped to the opposite case,\n * an entirely unrecognized type). F1's own fix — simply not forwarding\n * this seq to `onSkippedSeq` — turned out to be insufficient on its own:\n * a LATER valid envelope in the same or a later batch would still\n * silently advance the durable cursor PAST this seq once its own handler\n * succeeded, since nothing had told `ConnectionManager` this seq needed\n * the same stall treatment a thrown handler failure already gets — an\n * INDIRECT permanent ack, one hop removed from the exact bug F1 set out\n * to fix. `ConnectionManager` (`noteValidationFailure`) engages\n * `stalledAtSeq` for this seq the same way `process()`'s own catch block\n * does for a real thrown handler — freezing `dedupWatermark()` at the\n * durable cursor (so the server's retain-and-redeliver semantics,\n * protocol §9, keep this seq alive) and, via that SAME existing\n * machinery, holding back the cursor for anything else delivered after it\n * in the same batch too, exactly as a real handler failure already would.\n * Optional only for constructor/test convenience — `ConnectionManager`\n * always supplies it.\n */\n onValidationFailedSeq?: (seq: number) => void;\n /**\n * Finding P2 (Fix 2a): true while a `task.*` envelope's handler has failed\n * and hasn't yet been successfully reprocessed\n * (`ConnectionManager.stalledAtSeq`). While true, `getCursor()` stays\n * frozen below the actual delivery watermark (see\n * `ConnectionManager.dedupWatermark`'s own doc comment) — so a non-empty\n * response here doesn't mean \"new events arrived\", it can just as well\n * mean \"the whole post-cursor backlog got re-pulled again with no\n * progress\". Without a backoff for that case (distinct from \"zero\n * events\"), a persistently-failing handler made this loop spin at RTT\n * against the server. Optional only for constructor/test convenience —\n * `ConnectionManager` always supplies it.\n */\n isStalled?: () => boolean;\n /** Backoff between failed poll attempts (network/HTTP errors), AND between cycles that made no cursor progress while stalled (finding P2/Fix 2a — see {@link isStalled}). The reference server holds each successful, non-stalled request open ~50s itself (protocol §8), so this only matters when a request errors outright or is stalled. Default 2s. */\n retryDelayMs?: number;\n /** Deterministic delay authority for automatic failed/stalled cycles. */\n retryDelayForAttempt?: (attempt: number, baseDelayMs: number) => number;\n onOperationalOutcome?: (outcome: 'success' | 'failure') => void;\n /**\n * Minimum delay before the next request when a poll comes back with zero\n * events. The reference server holds each request open ~50s waiting for\n * something to happen, which throttles the loop for free; a server that\n * (like this SDK's own test stub) responds immediately instead would\n * otherwise make this a tight busy-loop. Default 250ms.\n */\n idleDelayMs?: number;\n}\n\ninterface LooseEventsPollResponse {\n /** Raw, not-yet-validated entries — see `parseLooseEventsPollResponse`'s own doc comment for why each is validated individually, not as one array. */\n events: unknown[];\n cursor: number;\n}\n\n/** Finding R1: soft cap on `LongPollClient`'s own `warnedValidationFailureSeqs` bookkeeping — see that field's own doc comment for why this is a simple \"clear outright\" reset rather than an eviction policy: a rare/pathological path, not a hot one. */\nconst MAX_TRACKED_VALIDATION_FAILURE_WARNINGS = 1000;\n\n/**\n * M4 Phase 4 (version-negotiation drill fix): validates ONLY the OUTER shape\n * of a `/byok/events` response — `events` is an array of not-yet-validated\n * entries, `cursor` is an integer. Deliberately does NOT validate each\n * entry against the frozen `EnvelopeSchema` here the way the protocol\n * package's own `EventsPollResponseSchema` (`z.array(EnvelopeSchema)`)\n * used to be applied in one shot: that meant a SINGLE unrecognized-type\n * entry anywhere in the batch failed the ENTIRE `.parse()` call, silently\n * discarding every other, otherwise-valid entry right alongside it — a real\n * forward-compat gap the WS transport never had (`ws-transport.ts` decodes\n * and dispatches one frame at a time). Each entry is now validated\n * individually, right where it's consumed (`LongPollClient.loop`, below),\n * via `parseMessage` — the SAME per-message validator `decodeEnvelope`\n * (ws-transport.ts's own per-frame decode) calls internally — so the two\n * transports draw from one shared notion of \"valid\" and cannot drift apart\n * on it again.\n */\nfunction parseLooseEventsPollResponse(raw: unknown): LooseEventsPollResponse {\n if (typeof raw !== 'object' || raw === null) {\n throw new Error('events poll response is not an object');\n }\n const { events, cursor } = raw as { events?: unknown; cursor?: unknown };\n if (!Array.isArray(events)) {\n throw new Error('events poll response.events is not an array');\n }\n if (typeof cursor !== 'number' || !Number.isInteger(cursor)) {\n throw new Error('events poll response.cursor is not an integer');\n }\n return { events, cursor };\n}\n\n/**\n * M4 Phase 4 (gatekeeper MEDIUM advisory): a numeric envelope-level `seq`\n * opportunistically read off a batch entry that failed `parseMessage` — but\n * ONLY when the entry's own `type` string also looks task-shaped (a\n * `task.` prefix), mirroring `ConnectionManager`'s own (unexported)\n * `isTaskEnvelopeType` distinction. Finding F2 documents that `conn.*` types\n * are NEVER cursor-tracked, even when perfectly well-formed — there is no\n * way to tell a hypothetical future `conn.something` type apart from that\n * rule from raw shape alone, so a skipped entry that isn't recognizably\n * task-class (wrong prefix, or no `type`/`seq` at all) must not be allowed\n * to touch the cursor either. `undefined` whenever the entry doesn't\n * qualify — used only to feed `onSkippedSeq`, never to treat the entry as\n * processable.\n */\nfunction extractSkippableSeq(raw: unknown): number | undefined {\n if (typeof raw !== 'object' || raw === null) return undefined;\n const { type, seq } = raw as { type?: unknown; seq?: unknown };\n if (typeof type !== 'string' || !type.startsWith('task.')) return undefined;\n return typeof seq === 'number' && Number.isInteger(seq) ? seq : undefined;\n}\n\n/**\n * Protocol §8 long-poll fallback: `GET /byok/events?cursor=N` in a loop,\n * used while WS connectivity is unavailable (see `ConnectionManager`), plus\n * `POST /byok/messages` for the daemon's own outbound envelopes while in\n * this mode (finding F6 — long-poll is a full transport, not receive-only:\n * see docs/protocol.md §8).\n *\n * Design B (finding N4): this is a stateless drainer, symmetric with\n * `WsTransport.sendNow` — it holds no outbound queue of its own.\n * `ConnectionManager` owns the single shared outbox both transports drain\n * from (so a transport switch never strands a queued envelope);\n * `postBatch` is a single POST attempt, reporting back whether the server\n * accepted it. All retry/backoff policy (and re-checking which transport is\n * currently active) lives in the caller (`ConnectionManager.drainOutbox`).\n */\nexport class LongPollClient {\n private running = false;\n /**\n * Finding R1: seqs this loop has already `console.warn`'d about for a\n * validation-failed (recognized-type, invalid-payload) entry — a poison\n * entry is redelivered on every poll cycle for as long as it stalls the\n * cursor (protocol §9), so without this the SAME warning would repeat\n * every ~poll-interval, forever, for one persistently-malformed message.\n * Never cleared: once a seq is fixed (a corrected redelivery is\n * processed), the server never redelivers that seq again, so there is\n * nothing left to re-warn about for it either. Soft-capped — this is a\n * pathological/rare path (unlike a per-task hot structure), so on the\n * rare chance a connection somehow accumulates an unreasonable number of\n * distinct poisoned seqs, this is simply cleared outright (accepting a\n * handful of possible re-warnings) rather than carrying any per-entry\n * eviction bookkeeping for a case this unlikely.\n */\n private readonly warnedValidationFailureSeqs = new Set<number>();\n\n constructor(private readonly opts: LongPollClientOptions) {}\n\n start(): void {\n if (this.running) return;\n this.running = true;\n void this.loop();\n }\n\n stop(): void {\n this.running = false;\n }\n\n /**\n * POST one batch of envelopes to `/byok/messages` (finding F6/protocol\n * §8.2) — a single attempt, no internal retry loop. Every envelope in\n * `envelopes` is routed through the server's single inbound gate\n * (`ConnectionHub.handleInbound`), so a resend of the SAME batch (same\n * envelope `id`s — the caller must never rebuild them) is deduped\n * server-side into a safe no-op rather than reprocessed (§9). Returns\n * `true` once the server has accepted the batch.\n */\n async postBatch(envelopes: Envelope[]): Promise<boolean> {\n try {\n const base = toHttpBase(this.opts.serverUrl);\n const res = await authedFetch(\n new URL('/byok/messages', base),\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ messages: envelopes }),\n },\n this.opts.auth,\n );\n if (!res.ok) return false;\n MessagesSendResponseSchema.parse(await res.json());\n return true;\n } catch (err) {\n if (err instanceof DeviceRevokedError) {\n this.running = false;\n this.opts.onRevoked?.();\n }\n return false;\n }\n }\n\n private async loop(): Promise<void> {\n let retryAttempt = 0;\n while (this.running) {\n try {\n const base = toHttpBase(this.opts.serverUrl);\n const url = new URL('/byok/events', base);\n const cursor = this.opts.getCursor();\n if (cursor !== undefined) url.searchParams.set('cursor', String(cursor));\n\n const res = await authedFetch(url, { method: 'GET' }, this.opts.auth);\n if (!res.ok) {\n this.opts.onOperationalOutcome?.('failure');\n const baseMs = this.opts.retryDelayMs ?? 2000;\n await sleep(this.opts.retryDelayForAttempt?.(retryAttempt++, baseMs) ?? baseMs);\n continue;\n }\n\n // Finding F3-on-long-poll: each polled envelope flows through\n // `ConnectionManager.deliver()`/`process()` exactly like a WS-pushed\n // one — no eager batch-level cursor advance here. The durable\n // cursor now only ever advances AFTER a `task.*` handler's side\n // effects resolve successfully (see `ConnectionManager.process`),\n // identically on both transports; `parsed.cursor` (the server's own\n // batch high-water) is intentionally not consulted for that — the\n // client tracks its own delivery/dedup watermark instead (Design A).\n //\n // M4 Phase 4 (version-negotiation drill fix): the outer shape\n // (`events` array + `cursor`) is validated loosely; each entry is\n // then validated INDIVIDUALLY via `parseMessage` — mirrors\n // `ws-transport.ts`'s identical per-frame tolerance (see\n // `parseLooseEventsPollResponse`'s own doc comment for the full\n // rationale). An entry that fails for ANY reason is silently\n // skipped for THIS batch — it never fails the rest of the batch —\n // but (finding F1, revised by finding R1) the two failure classes\n // are NOT treated identically, unlike `ws-transport.ts`'s own\n // blanket `catch {}`:\n // - `UnknownMessageTypeError` (an entirely unrecognized `type` —\n // genuine forward-compat tolerance, e.g. a future minor\n // server's new message type): recognizably task-class entries\n // (see `extractSkippableSeq`'s own doc comment for why\n // `conn.*`-shaped or type-less entries are excluded) still\n // advance the cursor/watermark past it (`onSkippedSeq`), so a\n // persistently-redelivered unparseable entry can never stall\n // this device's progress.\n // - Any OTHER failure (in practice `EnvelopeValidationError`: a\n // RECOGNIZED type whose payload fails schema validation) is a\n // genuine delivery failure at that seq, not a forward-compat\n // case. Finding R1: this now engages the SAME stall machinery a\n // thrown handler failure does (`onValidationFailedSeq` ->\n // `ConnectionManager.noteValidationFailure`) rather than merely\n // withholding the skip-forward — the F1 fix alone still let a\n // LATER valid envelope in the same/a later batch silently drag\n // the cursor past this seq once ITS OWN handler succeeded (see\n // `onValidationFailedSeq`'s own doc comment for the full\n // before/after). Freezing the cursor via the stall (rather than\n // just not advancing it here) is what lets the server's\n // ordinary retain-and-redeliver semantics (protocol §9) keep\n // this seq alive, and holds back anything delivered after it\n // too, until a corrected version is actually processed.\n const parsed = parseLooseEventsPollResponse(await res.json());\n // Finding R1 (Codex's new P2): true the moment THIS batch contains\n // at least one validation-failed entry — used below to apply the\n // stalled backoff on the VERY SAME cycle the failure is first\n // discovered. `onValidationFailedSeq` chains its own `stalledAtSeq`\n // mutation onto `ConnectionManager`'s FIFO `processingChain` (it\n // must — see that method's own doc comment for why a synchronous\n // mutation here would race an earlier still-in-flight envelope in\n // the same batch), so `this.opts.isStalled?.()` read synchronously,\n // right here, would NOT yet reflect a failure `onValidationFailedSeq`\n // was JUST called for a moment earlier in this same for-loop — a\n // real hot-loop risk (this cycle's own failure would only show up\n // in `isStalled()` starting from the NEXT cycle) without this local\n // flag closing that one-cycle gap.\n let hadValidationFailureThisBatch = false;\n for (const raw of parsed.events) {\n let envelope: Envelope;\n try {\n envelope = parseMessage(raw);\n } catch (err) {\n if (err instanceof UnknownMessageTypeError) {\n const skippableSeq = extractSkippableSeq(raw);\n if (skippableSeq !== undefined) this.opts.onSkippedSeq?.(skippableSeq);\n } else {\n const failedSeq = extractSkippableSeq(raw);\n if (failedSeq !== undefined) {\n hadValidationFailureThisBatch = true;\n this.opts.onValidationFailedSeq?.(failedSeq);\n // Finding R1: once per seq, not once per poll — this exact\n // entry gets redelivered on every cycle for as long as it\n // stalls the cursor (protocol §9's retain-and-redeliver),\n // so without the `warnedValidationFailureSeqs` guard this\n // would spam identically forever.\n if (!this.warnedValidationFailureSeqs.has(failedSeq)) {\n if (this.warnedValidationFailureSeqs.size > MAX_TRACKED_VALIDATION_FAILURE_WARNINGS) {\n this.warnedValidationFailureSeqs.clear(); // see this Set's own doc comment — a rare-path reset, not a hot one\n }\n this.warnedValidationFailureSeqs.add(failedSeq);\n console.warn(\n `[byok/client] long-poll: a recognized message type at seq=${failedSeq} failed payload validation — skipped for this batch, cursor frozen so the server keeps redelivering it until a corrected version arrives:`,\n err,\n );\n }\n }\n }\n continue;\n }\n this.opts.onEnvelope(envelope);\n }\n\n if (parsed.events.length === 0) {\n retryAttempt = 0;\n this.opts.onOperationalOutcome?.('success');\n await sleep(this.opts.idleDelayMs ?? 250);\n } else if (this.opts.isStalled?.() || hadValidationFailureThisBatch) {\n // Finding P2 (Fix 2a) / R1: a non-empty batch while stalled (or\n // one that just NOW triggered the stall — see\n // `hadValidationFailureThisBatch`'s own doc comment for why that\n // local flag is needed on top of `isStalled()`) means this cycle\n // made no real cursor progress — apply the same backoff a failed\n // HTTP attempt gets, instead of looping back immediately at RTT.\n this.opts.onOperationalOutcome?.('failure');\n const baseMs = this.opts.retryDelayMs ?? 2000;\n await sleep(this.opts.retryDelayForAttempt?.(retryAttempt++, baseMs) ?? baseMs);\n } else {\n retryAttempt = 0;\n this.opts.onOperationalOutcome?.('success');\n }\n } catch (err) {\n if (err instanceof DeviceRevokedError) {\n this.running = false;\n this.opts.onRevoked?.();\n return;\n }\n if (!this.running) return;\n this.opts.onOperationalOutcome?.('failure');\n const baseMs = this.opts.retryDelayMs ?? 2000;\n await sleep(this.opts.retryDelayForAttempt?.(retryAttempt++, baseMs) ?? baseMs);\n }\n }\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { WebSocket } from 'ws';\nimport {\n createEnvelope,\n decodeEnvelope,\n encodeEnvelope,\n PROTOCOL_VERSION,\n type CapabilityFlag,\n type Envelope,\n type RuntimeInfo,\n} from '@byok-sdk/protocol';\nimport { toWsUrl } from './url';\n\nexport type ConnectionState = 'connecting' | 'open' | 'closed' | 'degraded' | 'revoked';\n\n/** The WS upgrade itself was rejected with a non-101 HTTP status (e.g. 401 for an expired/invalid bearer token). Surfaced via `onConnectOutcome` so `ConnectionManager` can force a reactive token renewal before the next attempt (protocol §6.2, \"reactively on 401\"). */\nexport class WsUnexpectedStatusError extends Error {\n constructor(public readonly status: number) {\n super(`WS upgrade rejected with HTTP ${status}`);\n this.name = 'WsUnexpectedStatusError';\n }\n}\n\nexport interface BackoffOptions {\n baseMs?: number;\n maxMs?: number;\n factor?: number;\n}\n\nexport interface LivenessOptions {\n /** Terminate and reconnect if no data/ping arrives for this long. Default 75s (server pings every 30s per the pinned heartbeat convention). */\n timeoutMs?: number;\n /** How often to check for silence. Default: timeoutMs/3, floored at 1s. */\n checkIntervalMs?: number;\n}\n\nexport interface WsTransportOptions {\n serverUrl: string;\n /** Resolves the current valid bearer token; called fresh before every connect attempt (initial and every reconnect) so a proactively-renewed token is always used. */\n getToken: () => Promise<string>;\n deviceId: string;\n productId: string;\n capabilities: CapabilityFlag[];\n /** Detected runtimes, sent on every `conn.hello` (protocol §10 gap #4/#11). */\n runtimes?: RuntimeInfo[];\n /** The redelivery cursor to send as `conn.hello.cursor` (protocol §9) — read fresh on every connect so a value learned mid-connection is used on the next reconnect. */\n getCursor?: () => number | undefined;\n onEnvelope: (envelope: Envelope) => void;\n onStateChange?: (state: ConnectionState) => void;\n /**\n * Fired the moment `conn.ack` is processed and the connection becomes\n * usable — independent of `onConnectOutcome`, which only fires on close (a\n * healthy, still-open connection never reaches it). Carries the ack's own\n * `capabilities` (untyped `string[]` on the wire, forward-compat — a\n * server may advertise a flag this build doesn't recognize yet), so a\n * caller can learn what the CURRENTLY connected server understands (e.g.\n * the `approval_resolved` capability flag — see\n * `ConnectionManager.getServerCapabilities`) instead of it being silently\n * discarded after the handshake completes.\n */\n onAcked?: (capabilities: string[]) => void;\n /**\n * Fired once per connection attempt when the socket closes, reporting\n * whether that attempt ever reached `conn.ack` (`acked`) before closing,\n * and the causing error when the attempt failed before a socket even\n * opened (e.g. `getToken()` rejecting). Used by `ConnectionManager` to\n * count consecutive failures for the long-poll fallback (protocol §8).\n */\n onConnectOutcome?: (acked: boolean, err?: unknown) => void;\n backoff?: BackoffOptions;\n liveness?: LivenessOptions;\n /** Deterministic automatic reconnect delay. Manual `connect({auto:false})` never reaches this scheduler. */\n reconnectDelayMs?: (attempt: number, baseDelayMs: number) => number;\n}\n\n/**\n * The daemon's outbound-only WS connection: opens, sends `conn.hello`, waits\n * for `conn.ack`, and reconnects with capped exponential backoff + jitter on\n * drop.\n *\n * Design B (finding N4): this transport is a stateless drainer — it holds no\n * outbound queue of its own. `ConnectionManager` owns the single shared\n * outbox both transports drain from (so a transport switch never strands a\n * queued envelope); `sendNow` just attempts to hand one envelope to the\n * live socket right now and reports back whether that actually happened,\n * leaving all queueing/retry policy to the caller.\n *\n * Auto-reconnect can be paused (`stopAutoReconnect`) and single attempts\n * made on demand (`connect({ auto: false })`) — used by `ConnectionManager`\n * to probe WS recovery every few minutes while long-polling, without this\n * transport's own backoff loop fighting that cadence.\n */\nexport class WsTransport {\n private socket: WebSocket | undefined;\n private closedByUser = false;\n private autoReconnect = true;\n private acked = false;\n private everAckedThisAttempt = false;\n private reconnectAttempt = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n private livenessTimer: ReturnType<typeof setInterval> | undefined;\n private lastActivity = 0;\n private lastUnexpectedStatus: number | undefined;\n private ackWaiters: Array<{ resolve: () => void; reject: (err: Error) => void }> = [];\n\n constructor(private readonly opts: WsTransportOptions) {}\n\n connect(opts: { auto?: boolean } = {}): void {\n this.autoReconnect = opts.auto ?? true;\n this.closedByUser = false;\n void this.openSocket();\n }\n\n /** Stop scheduling further reconnect attempts (any pending one is cancelled too); the current socket, if any, is left alone. Used when handing retry ownership to a slower external cadence (e.g. the long-poll fallback's periodic WS probe). */\n stopAutoReconnect(): void {\n this.autoReconnect = false;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n }\n\n /** Resume normal auto-reconnect-on-close behavior (does not itself trigger a connect — only affects future closes). */\n resumeAutoReconnect(): void {\n this.autoReconnect = true;\n }\n\n get isOpen(): boolean {\n return this.acked;\n }\n\n /**\n * Attempt to send ONE envelope right now; returns whether it actually went\n * out. `false` means the socket isn't currently open+acked — the caller\n * (`ConnectionManager.drainOutbox`, Design B/finding N4) owns re-queueing\n * and retrying later (e.g. on the next `onAcked`), since this transport no\n * longer buffers anything itself.\n */\n sendNow(envelope: Envelope): boolean {\n if (this.socket && this.socket.readyState === WebSocket.OPEN && this.acked) {\n this.socket.send(encodeEnvelope(envelope));\n return true;\n }\n return false;\n }\n\n waitForAck(timeoutMs = 10_000): Promise<void> {\n if (this.acked) return Promise.resolve();\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error('Timed out waiting for conn.ack')), timeoutMs);\n this.ackWaiters.push({\n resolve: () => {\n clearTimeout(timer);\n resolve();\n },\n reject: (err) => {\n clearTimeout(timer);\n reject(err);\n },\n });\n });\n }\n\n close(): void {\n this.closedByUser = true;\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n this.socket?.close();\n }\n\n private async openSocket(): Promise<void> {\n const url = toWsUrl(this.opts.serverUrl);\n this.acked = false;\n this.everAckedThisAttempt = false;\n this.opts.onStateChange?.('connecting');\n\n let token: string;\n try {\n token = await this.opts.getToken();\n } catch (err) {\n this.opts.onStateChange?.('closed');\n this.opts.onConnectOutcome?.(false, err);\n if (!this.closedByUser && this.autoReconnect) this.scheduleReconnect();\n return;\n }\n\n const socket = new WebSocket(url, {\n headers: { Authorization: `Bearer ${token}` },\n });\n this.socket = socket;\n this.lastActivity = Date.now();\n this.startLivenessCheck(socket);\n\n socket.on('open', () => {\n const hello = createEnvelope('conn.hello', {\n protocolVersions: [PROTOCOL_VERSION],\n capabilities: this.opts.capabilities,\n deviceId: this.opts.deviceId,\n productId: this.opts.productId,\n runtimes: this.opts.runtimes,\n cursor: this.opts.getCursor?.(),\n });\n socket.send(encodeEnvelope(hello));\n });\n\n socket.on('ping', () => {\n this.lastActivity = Date.now();\n });\n\n socket.on('message', (data, isBinary) => {\n this.lastActivity = Date.now();\n const bytes = toBytes(data, isBinary);\n let envelope: Envelope;\n try {\n envelope = decodeEnvelope(bytes);\n } catch {\n return; // unparsable or unknown-type frame — ignore for forward-compat\n }\n if (envelope.type === 'conn.ack') {\n this.reconnectAttempt = 0;\n this.acked = true;\n this.everAckedThisAttempt = true;\n this.opts.onStateChange?.('open');\n for (const waiter of this.ackWaiters.splice(0)) waiter.resolve();\n this.opts.onAcked?.(envelope.payload.capabilities);\n }\n this.opts.onEnvelope(envelope);\n });\n\n socket.on('close', () => {\n this.socket = undefined;\n this.stopLivenessCheck();\n this.opts.onStateChange?.('closed');\n const acked = this.everAckedThisAttempt;\n const status = this.lastUnexpectedStatus;\n this.lastUnexpectedStatus = undefined;\n this.opts.onConnectOutcome?.(acked, status !== undefined ? new WsUnexpectedStatusError(status) : undefined);\n if (!this.closedByUser && this.autoReconnect) this.scheduleReconnect();\n });\n\n // A 'close' event always follows 'error'/'unexpected-response' for ws\n // sockets; avoid an unhandled-error crash and let the close handler\n // drive reconnection/outcome reporting.\n socket.on('error', () => {});\n socket.on('unexpected-response', (_req, res) => {\n this.lastUnexpectedStatus = res.statusCode;\n res.resume(); // drain so the socket can close cleanly\n socket.terminate();\n });\n }\n\n private scheduleReconnect(): void {\n const { baseMs = 1000, maxMs = 30_000, factor = 2 } = this.opts.backoff ?? {};\n const delay = Math.min(maxMs, baseMs * factor ** this.reconnectAttempt);\n const jitter = this.opts.reconnectDelayMs?.(this.reconnectAttempt, delay) ?? delay;\n this.reconnectAttempt += 1;\n this.reconnectTimer = setTimeout(() => void this.openSocket(), jitter);\n }\n\n private startLivenessCheck(socket: WebSocket): void {\n const { timeoutMs = 75_000, checkIntervalMs = Math.max(1000, Math.floor(timeoutMs / 3)) } = this.opts.liveness ?? {};\n this.livenessTimer = setInterval(() => {\n if (Date.now() - this.lastActivity > timeoutMs) {\n // Force-close; the 'close' handler drives reconnection exactly as\n // it would for any other drop.\n socket.terminate();\n }\n }, checkIntervalMs);\n this.livenessTimer.unref?.();\n }\n\n private stopLivenessCheck(): void {\n if (this.livenessTimer) {\n clearInterval(this.livenessTimer);\n this.livenessTimer = undefined;\n }\n }\n}\n\nfunction toBytes(data: unknown, _isBinary: boolean): Uint8Array {\n if (Buffer.isBuffer(data)) return data;\n if (Array.isArray(data)) return Buffer.concat(data as Buffer[]);\n if (data instanceof ArrayBuffer) return new Uint8Array(data);\n return Buffer.from(String(data), 'utf8');\n}\n","import { MAX_MESSAGES_PER_BATCH, type CapabilityFlag, type Envelope, type RuntimeInfo } from '@byok-sdk/protocol';\nimport { AuthManager, DeviceRevokedError } from './auth-manager';\nimport type { CursorStore } from './cursor-store';\nimport { createFleetJitter, type FleetJitter } from './deterministic-jitter';\nimport { LongPollClient } from './long-poll-transport';\nimport {\n WsTransport,\n WsUnexpectedStatusError,\n type BackoffOptions,\n type ConnectionState,\n type LivenessOptions,\n} from './ws-transport';\n\nexport type { ConnectionState } from './ws-transport';\n\n/** `true` for every `task.*` envelope type — the ONLY types the redelivery cursor accounts for (protocol §1.2/§9; finding F2). `conn.*` types (e.g. `conn.ack`) carry a `seq` for schema uniformity but are never cursor-tracked. */\nfunction isTaskEnvelopeType(type: Envelope['type']): boolean {\n return type.startsWith('task.');\n}\n\nexport interface ConnectionManagerOptions {\n serverUrl: string;\n deviceId: string;\n productId: string;\n capabilities: CapabilityFlag[];\n runtimes: RuntimeInfo[];\n auth: AuthManager;\n cursorStore: CursorStore;\n /**\n * May return a promise; `ConnectionManager` awaits it before considering\n * this envelope \"processed\" (findings F2/F3 — see `deliver`/`process`\n * below). A handler that throws/rejects is caught here, not propagated.\n */\n onEnvelope: (envelope: Envelope) => void | Promise<void>;\n onStateChange?: (state: ConnectionState) => void;\n backoff?: BackoffOptions;\n liveness?: LivenessOptions;\n /** Consecutive never-acked WS connect failures before falling back to long-poll (protocol §8). Default 3. */\n wsFailureThreshold?: number;\n /** While long-polling, how often to retry establishing WS (protocol §8, \"e.g. every 5 min\"). Default 5 minutes. */\n wsRetryIntervalMs?: number;\n /** Backoff between failed long-poll HTTP attempts. Default 2s. */\n longPollRetryDelayMs?: number;\n /** Minimum delay before the next long-poll request after an empty (no-events) response. Default 250ms. */\n longPollIdleDelayMs?: number;\n fleetJitter?: FleetJitter;\n onOperationalOutcome?: (outcome: 'success' | 'failure', source: 'reconnect' | 'upload') => void;\n}\n\n/**\n * Owns the daemon's one logical connection to the server, which may be\n * backed by either transport the wire protocol defines: WS (the normal\n * path) or long-poll (protocol §8's fallback for environments where an\n * outbound WSS connection isn't viable). Both funnel every received\n * envelope through the same cursor-dedupe/persistence logic (protocol §9),\n * so redelivery is safe regardless of which transport happens to deliver a\n * given envelope — including during the brief overlap window when handing\n * off between them.\n *\n * `send()` (Design B, finding N4) pushes onto a single shared outbox this\n * class owns and drains through whichever transport is currently active —\n * WS raw-sends while acked, `POST /byok/messages` while long-polling\n * (finding F6, long-poll is a full transport, not receive-only; see\n * docs/protocol.md §8) — so a transport switch mid-flight never strands a\n * queued envelope. See `drainOutbox`.\n */\nexport class ConnectionManager {\n private readonly fleetJitter: FleetJitter;\n private readonly ws: WsTransport;\n private readonly longPoll: LongPollClient;\n private mode: 'ws' | 'long-poll' = 'ws';\n private consecutiveFailures = 0;\n private wsRetryTimer: ReturnType<typeof setInterval> | undefined;\n private wsProbeSequence = 0;\n private uploadRetryAttempt = 0;\n private cursor: number | undefined;\n /**\n * Finding F3 (at-most-once redelivery): the lowest `task.*` envelope `seq`\n * whose handler failed and hasn't yet been successfully reprocessed. While\n * set, the cursor is frozen at its pre-failure value even if later\n * envelopes succeed — advancing past a still-unresolved failure would\n * mean a future reconnect's redelivery skips it forever (it's <= the\n * persisted cursor), which is exactly the bug this fixes. Cleared once an\n * envelope carrying this exact seq is reprocessed (via redelivery after a\n * reconnect) and succeeds; everything from there back up to the new\n * cursor gets safely re-attempted too, relying on the idempotency\n * guarantees in docs/protocol.md §9.\n */\n private stalledAtSeq: number | undefined;\n /**\n * Design A (Wave 2, F3-on-long-poll): the second, in-memory watermark\n * alongside the durable `cursor`. `cursor` only ever advances AFTER a\n * `task.*` handler's side effects resolve successfully, and is persisted\n * (see `advanceCursor`) — that semantics is unchanged. `deliveredSeq`\n * advances eagerly, the instant a `task.*` envelope is admitted past\n * dedup (see `deliver`/`noteDelivered`), independent of whether its\n * handler has even started, let alone succeeded. It exists so a\n * long-poll re-query (`LongPollClient`'s `getCursor`) doesn't re-pull an\n * envelope that's already been delivered once and is still in flight —\n * `handleOffer` is NOT idempotent and must never be re-pulled while a\n * first attempt is still running. On WS this same field is written the\n * same way, but since a live WS connection only ever pushes a given `seq`\n * once, it never has an observable effect there beyond mirroring\n * `cursor` (see `dedupWatermark`'s doc comment for why redelivery\n * correctness doesn't depend on resetting it anywhere).\n */\n private deliveredSeq: number | undefined;\n /** Finding F3: serializes `onEnvelope` calls into a per-connection FIFO — one envelope's handler always fully settles before the next one starts. */\n private processingChain: Promise<void> = Promise.resolve();\n /**\n * Design B (finding N4): the ONE outbound queue both transports drain\n * from — holds `Envelope` OBJECTS, never re-encoded/rebuilt strings, so a\n * resend after a failed send attempt is byte-identical to the original\n * (same `id`), which is what lets the server's per-(deviceId,id) dedup\n * (Wave 1) recognize it as a safe no-op retry rather than a second\n * application (protocol §9). A transport switch (long-poll <-> WS) never\n * touches this queue — see `drainOutbox` — so nothing queued while one\n * transport was active is ever stranded when the other takes over.\n */\n private readonly outbox: Envelope[] = [];\n /**\n * Finding F5(b): how many envelopes `drainOutbox`'s long-poll branch has\n * currently spliced OUT of `this.outbox` for an in-flight (not yet\n * confirmed delivered) `postBatch` call — 0 the rest of the time. See\n * `outboxLength`'s own doc comment for why this needs to be tracked\n * separately from `this.outbox.length` at all.\n */\n private inFlightBatchSize = 0;\n private draining = false;\n private stopped = false;\n private revoked = false;\n private settledWaiters: Array<(err?: unknown) => void> = [];\n private pendingCursorSave: Promise<void> = Promise.resolve();\n /**\n * Finding P2 (Fix 2b): seqs currently admitted into `processingChain` but\n * not yet settled — added in `deliver()` the moment a `task.*` envelope is\n * accepted past the ordinary watermark check, removed in `process()`'s\n * `finally` once that specific attempt resolves (success OR failure).\n * While stalled, `dedupWatermark()` deliberately stays frozen below\n * already-delivered seqs (see its own doc comment) so the failed seq's own\n * redelivery can get through — but that same frozen watermark also means\n * every OTHER seq above it rides along on every re-poll too. Without this,\n * a seq already mid-flight (e.g. a `task.offer` whose `adapter.start()`\n * hasn't resolved yet) would be re-enqueued into `processingChain` on\n * every such re-poll, piling up duplicate copies that — once the first\n * finally resolves and the chain unwinds through them — run its handler\n * again; for `task.offer` specifically, a second adapter session\n * orphaning the first (`TaskRunner`'s own `this.tasks.has` guard, finding\n * P2c, is the second, independent layer against exactly that).\n */\n private readonly inFlightSeqs = new Set<number>();\n /**\n * Finding P2 (Fix 2b): seqs whose handler has already resolved\n * successfully at least once this session, tracked only while a stall is\n * in effect — cleared the moment `stalledAtSeq` itself clears (see\n * `process()`), since once unstalled the ordinary watermark check via\n * `deliveredSeq` already covers everything delivered so far, making this\n * redundant. Needed because the stall-gap-prevention rule in `process()`\n * deliberately does NOT advance `cursor` past a seq above the\n * still-unresolved `stalledAtSeq`, even once that seq's own handler\n * succeeds — so `dedupWatermark()` alone can't distinguish \"already\n * succeeded, don't re-run\" from \"never yet attempted\" for anything in\n * that gap.\n */\n private readonly processedSeqs = new Set<number>();\n /**\n * Finding P3: the pending `drainOutbox` long-poll retry backoff, if any —\n * cancellable so `enterRevoked()` can unblock it immediately instead of\n * waiting out the rest of the delay before the loop notices `revoked` and\n * exits. See `drainRetryDelay`.\n */\n private cancelPendingDrainRetry: (() => void) | undefined;\n /**\n * The capabilities the CURRENTLY connected server advertised in its\n * `conn.ack` — untyped `string[]` (forward-compat: a server may advertise\n * a flag this build doesn't recognize yet), populated by {@link onAcked}\n * and read by {@link getServerCapabilities}. Empty until the very first\n * successful handshake.\n *\n * Finding R2 (cross-model re-review — was P1): strictly PER-CONNECTION,\n * not per-daemon-lifetime. Cleared to `[]` the instant the acked WS\n * connection ends for ANY reason — an ordinary disconnect (`onWsOutcome`'s\n * `acked` branch), `stop()`, or a transport switch to long-poll\n * (`enterLongPoll`) — and only ever repopulated by a FRESH `conn.ack`.\n * The previous version of this doc comment claimed long-poll mode simply\n * \"stays at whatever the last real WS `conn.ack` said\" — that was the bug:\n * a daemon that once learned e.g. `approval_resolved` from an earlier WS\n * session kept believing it applied to whatever it's connected to NOW,\n * even after a disconnect/degrade where nothing has actually confirmed\n * that's still true (a reconnect could land on a DIFFERENT server behind a\n * load balancer; long-poll fallback itself never performs an equivalent\n * handshake at all). Concretely, `TaskRunner.sendApprovalResolved` gates\n * `task.approval_resolved` on this list — sending it to a server that\n * doesn't actually understand it over the long-poll path would get a\n * batch-level 400 from `MessagesSendRequestSchema` (protocol §8.2), which\n * `drainOutbox`'s retry-the-same-batch-forever loop then head-of-line\n * blocks EVERY envelope queued behind it on, permanently. Clearing this\n * eagerly means that gate reliably fails closed (falls back to the\n * pre-existing implicit-resume inference, unconditionally — see\n * `sendApprovalResolved`'s own doc comment) the moment the connection that\n * advertised the capability is no longer the one actually in use.\n */\n private serverCapabilities: string[] = [];\n\n constructor(private readonly opts: ConnectionManagerOptions) {\n this.fleetJitter = opts.fleetJitter ?? createFleetJitter(opts.productId, opts.deviceId);\n this.ws = new WsTransport({\n serverUrl: opts.serverUrl,\n getToken: () => opts.auth.getValidAccessToken(),\n deviceId: opts.deviceId,\n productId: opts.productId,\n capabilities: opts.capabilities,\n runtimes: opts.runtimes,\n getCursor: () => this.cursor,\n onEnvelope: (envelope) => this.deliver(envelope),\n onStateChange: (state) => {\n if (!this.stopped && !this.revoked) this.opts.onStateChange?.(state);\n },\n onAcked: (capabilities) => this.onAcked(capabilities),\n onConnectOutcome: (acked, err) => this.onWsOutcome(acked, err),\n backoff: opts.backoff,\n liveness: opts.liveness,\n reconnectDelayMs: (attempt, baseMs) => this.fleetJitter.delay('reconnect', attempt, baseMs),\n });\n\n this.longPoll = new LongPollClient({\n serverUrl: opts.serverUrl,\n auth: opts.auth,\n // Design A: the query cursor for the NEXT `GET /byok/events` is the\n // same watermark `deliver()` dedupes against (see `dedupWatermark`) —\n // normally the eager `deliveredSeq` (so an in-flight envelope isn't\n // re-pulled), but the durable `cursor` while `stalledAtSeq` is set, so\n // the failed envelope (and everything after it) IS re-pulled and\n // re-attempted.\n getCursor: () => this.dedupWatermark(),\n onEnvelope: (envelope) => this.deliver(envelope),\n onRevoked: () => this.enterRevoked(),\n // M4 Phase 4 (version-negotiation drill fix): a batch entry\n // LongPollClient couldn't parse into a known Envelope at all (an\n // unrecognized message type) still needs its cursor/watermark\n // advanced past it, exactly like a successfully-processed envelope\n // would — see `noteSkippedSeq`'s own doc comment.\n onSkippedSeq: (seq) => this.noteSkippedSeq(seq),\n // Finding R1: a batch entry LongPollClient recognized the TYPE of but\n // whose payload failed validation — a genuine delivery failure at\n // that seq, engaged the same way a thrown handler failure is (see\n // `noteValidationFailure`'s own doc comment).\n onValidationFailedSeq: (seq) => this.noteValidationFailure(seq),\n // Finding P2 (Fix 2a): lets the long-poll loop distinguish \"this\n // non-empty batch was a stalled backlog re-pull, no cursor progress\n // was made\" from ordinary forward progress, so it can back off\n // instead of spinning at RTT — see `LongPollClient`'s own doc comment\n // on `isStalled`.\n isStalled: () => this.stalledAtSeq !== undefined,\n retryDelayMs: opts.longPollRetryDelayMs,\n retryDelayForAttempt: (attempt, baseMs) => this.fleetJitter.delay('reconnect', attempt, baseMs),\n onOperationalOutcome: (outcome) => opts.onOperationalOutcome?.(outcome, 'reconnect'),\n idleDelayMs: opts.longPollIdleDelayMs,\n });\n }\n\n async start(): Promise<void> {\n this.cursor = await this.opts.cursorStore.load(this.opts.serverUrl, this.opts.deviceId);\n this.ws.connect({ auto: true });\n }\n\n /**\n * Design B (finding N4): push onto the single shared outbox and try to\n * drain it now. Never routes directly to either transport itself — see\n * `drainOutbox`.\n */\n send(envelope: Envelope): void {\n this.outbox.push(envelope);\n void this.drainOutbox();\n }\n\n /**\n * Design B (finding N4): drain the shared outbox through whichever\n * transport is currently active, re-checking `this.mode` fresh on every\n * iteration so a transport switch mid-drain is picked up immediately\n * rather than fighting a stale decision made before the switch.\n *\n * WS: a synchronous, one-at-a-time `sendNow` per envelope while open+\n * acked; stops (without dropping anything — the remainder stays queued)\n * the moment it isn't, and is re-invoked once `onAcked` fires.\n *\n * Long-poll: POSTs the outbox in chunks of at most\n * `MAX_MESSAGES_PER_BATCH` (finding P1) — the server hard-caps a single\n * `/byok/messages` batch there (`MessagesSendRequestSchema`, protocol\n * §8.2) and 400s the WHOLE request if it's exceeded, which — before this\n * fix — meant more than that queued during an outage produced an oversize\n * batch that the server would reject forever, since the client re-queued\n * and retried the identical (still oversize) batch unchanged. Each chunk\n * is one `LongPollClient.postBatch` call; on success the loop continues\n * (more may still be queued, or the next chunk still needs sending), on\n * failure that SAME chunk is unshifted back (order-preserving, same\n * Envelope objects/ids — never rebuilt, so a retry is exactly the resend\n * Wave 1's server-side dedup expects) and retried after a short backoff,\n * re-reading `this.mode` each time so a WS recovery that happens\n * mid-retry is honored on the very next loop iteration instead of only\n * after this attempt's backoff chain gives up.\n *\n * Re-entrancy is guarded by `draining`: a call arriving while a drain is\n * already in progress just returns — the in-progress loop's own\n * `while (this.outbox.length > 0)` check will pick up anything newly\n * pushed (or left over after a mode switch) on its very next iteration.\n */\n private async drainOutbox(): Promise<void> {\n if (this.draining) return;\n this.draining = true;\n try {\n while (this.outbox.length > 0) {\n if (this.stopped || this.revoked) return;\n\n if (this.mode === 'ws') {\n if (!this.ws.isOpen) return; // onAcked() re-invokes drainOutbox() once it is\n const envelope = this.outbox[0]!;\n if (!this.ws.sendNow(envelope)) return; // defensive; isOpen already checked above\n this.outbox.shift();\n continue;\n }\n\n const batch = this.outbox.splice(0, MAX_MESSAGES_PER_BATCH);\n // Finding F5(b): tracked for the DURATION of the `postBatch` await —\n // `batch` has already left `this.outbox` (spliced out above) but\n // isn't confirmed delivered yet, so a plain `this.outbox.length`\n // read right now would UNDERCOUNT it entirely (this is exactly what\n // a stalled/hung `postBatch` call means: neither queued nor\n // delivered, just stuck). See `outboxLength`'s own doc comment.\n this.inFlightBatchSize = batch.length;\n let ok: boolean;\n try {\n ok = await this.longPoll.postBatch(batch);\n } finally {\n this.inFlightBatchSize = 0;\n }\n if (ok) {\n this.uploadRetryAttempt = 0;\n this.opts.onOperationalOutcome?.('success', 'upload');\n continue;\n }\n\n this.opts.onOperationalOutcome?.('failure', 'upload');\n\n this.outbox.unshift(...batch); // retry, preserving order — same objects, same ids (finding F1)\n // Finding P3: a revoked device can never recover without a fresh\n // pair() — retrying (and thus scheduling another backoff timer)\n // would spin forever and keep the process alive for no reason.\n // `postBatch`'s own DeviceRevokedError handling has already called\n // `enterRevoked()` (synchronously, before `postBatch` resolves) by\n // the time `ok` is `false` for that reason, so this check catches\n // it on the very next iteration rather than sleeping first.\n if (this.stopped || this.revoked) return;\n const baseMs = this.opts.longPollRetryDelayMs ?? 2000;\n await this.drainRetryDelay(this.fleetJitter.delay('upload', this.uploadRetryAttempt++, baseMs));\n }\n } finally {\n this.draining = false;\n }\n }\n\n /**\n * Finding P3: backoff delay for `drainOutbox`'s long-poll retry loop.\n * Unlike a plain `setTimeout`-based wait, this is (a) cancellable —\n * `enterRevoked()` calls `cancelPendingDrainRetry()` to unblock an\n * in-flight wait immediately instead of leaving `drainOutbox` parked here\n * for up to the rest of the delay before it next checks `this.revoked` —\n * and (b) unref'd, so the timer never keeps the Node process alive by\n * itself while nothing else (a live long-poll GET, an open WS connection)\n * legitimately is.\n */\n private drainRetryDelay(ms: number): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(() => {\n this.cancelPendingDrainRetry = undefined;\n resolve();\n }, ms);\n timer.unref?.();\n this.cancelPendingDrainRetry = () => {\n clearTimeout(timer);\n this.cancelPendingDrainRetry = undefined;\n resolve();\n };\n });\n }\n\n isTransportDegraded(): boolean {\n return this.mode === 'long-poll';\n }\n\n /**\n * The capabilities the CURRENTLY connected server advertised in its\n * `conn.ack` — e.g. lets a caller gate a daemon->server message on whether\n * THIS server understands it before sending (see `task-runner.ts`'s\n * `sendApprovalResolved`, gated on `approval_resolved`). Empty before the\n * first handshake completes, AND (finding R2) once again empty after any\n * disconnect/degrade — see `serverCapabilities`'s own doc comment for why\n * this is strictly per-connection rather than \"sticky\" across one.\n */\n getServerCapabilities(): readonly string[] {\n return this.serverCapabilities;\n }\n\n isConnected(): boolean {\n return this.mode === 'ws' && this.ws.isOpen;\n }\n\n isRevoked(): boolean {\n return this.revoked;\n }\n\n /**\n * Resolves once the connection has settled — either a working, acked WS\n * connection, or the long-poll fallback taking over (protocol §8). This\n * lets `daemon.start()` return promptly even when WS is unavailable from\n * the very first attempt, rather than hanging until a WS `conn.ack` that\n * may never come.\n *\n * Rejects with {@link DeviceRevokedError} — instead of hanging until\n * `timeoutMs` — if the device turns out to be revoked while settling (or\n * already was): a cold `daemon.start()` against an already-revoked device\n * must fail fast, not surface a generic timeout (protocol §6.3).\n */\n waitForAck(timeoutMs = 10_000): Promise<void> {\n if (this.ws.isOpen || this.mode === 'long-poll') return Promise.resolve();\n if (this.revoked) return Promise.reject(new DeviceRevokedError());\n return new Promise((resolve, reject) => {\n let settle: (err?: unknown) => void = () => {};\n const timer = setTimeout(() => {\n this.settledWaiters = this.settledWaiters.filter((w) => w !== settle);\n reject(new Error('Timed out waiting for the connection to settle (WS ack or long-poll fallback)'));\n }, timeoutMs);\n settle = (err?: unknown) => {\n clearTimeout(timer);\n if (err) reject(err);\n else resolve();\n };\n this.settledWaiters.push(settle);\n });\n }\n\n /**\n * Stops both transports and waits for every in-flight envelope handler\n * (the F3 FIFO chain) and the most recent cursor write to actually land on\n * disk — otherwise a `stop()` racing a just-processed envelope's\n * persistence could lose that cursor advance, or leave a handler running\n * unobserved after the daemon reports itself stopped.\n *\n * Finding F5(b) (cross-model adversarial review): `drainTimeoutMs`, when\n * passed, bounds how long this waits for the shared outbox (`this.outbox`\n * — Design B) to actually finish draining BEFORE flipping `this.stopped`\n * and closing the transports. Before this fix, `stop()` set `stopped`\n * synchronously and never waited for `drainOutbox` at all: an envelope\n * `send()` had just pushed moments earlier (e.g. `TaskRunner.shutdownTask`'s\n * own `task.fail`, sent right before `create-daemon.ts`'s\n * `performControlShutdown` calls this) could still be sitting UNSENT in\n * `this.outbox` — mid long-poll retry backoff, or simply not yet picked up\n * by the fire-and-forget `drainOutbox()` `send()` kicked off — and this\n * method would happily proceed to `stopped = true` / `ws.close()` regardless,\n * after which NOTHING ever drains it again: silently lost, even though\n * `TaskRunner` believed it had been sent. `drainTimeoutMs` omitted (the\n * default) preserves the EXACT prior behavior for every other existing\n * caller (an ordinary `daemon.stop()`/`unpair()`) — only the control-socket\n * shutdown path opts into the bounded wait (see `create-daemon.ts`'s\n * `performControlShutdown`). This can never claim delivery that didn't\n * happen: on a timeout, whatever's still queued stays exactly where it is\n * (readable via {@link outboxLength} immediately after this resolves) —\n * it does NOT force-flush or pretend success.\n */\n async stop(drainTimeoutMs?: number): Promise<void> {\n if (drainTimeoutMs !== undefined) {\n await this.waitForOutboxDrained(drainTimeoutMs);\n }\n this.stopped = true;\n // Finding R2: this daemon's own connection is ending — whatever the\n // server last advertised no longer applies to anything (there's nothing\n // left to send to). See `serverCapabilities`'s own doc comment.\n this.serverCapabilities = [];\n if (this.wsRetryTimer) clearInterval(this.wsRetryTimer);\n this.longPoll.stop();\n this.ws.close();\n await this.processingChain;\n await this.pendingCursorSave;\n }\n\n /**\n * Finding F5(b): how many envelopes are neither confirmed delivered NOR\n * safely re-queued — meant to be read right after a bounded {@link stop}\n * call returns, to know honestly whether the drain actually finished (0)\n * or timed out with something still stuck (>0). See `create-daemon.ts`'s\n * `performControlShutdown`, which surfaces this on the `shutdown-complete`\n * audit event rather than silently claiming everything was delivered.\n *\n * Deliberately `this.outbox.length + this.inFlightBatchSize`, NOT just\n * `this.outbox.length` alone: `drainOutbox`'s long-poll branch SPLICES a\n * batch out of `this.outbox` before awaiting `postBatch` (so a concurrent\n * `send()` sees an accurate, non-double-counted queue) — while that POST\n * is in flight (or, this finding's whole point, genuinely STALLED and\n * never resolving), those envelopes have already left `this.outbox` but\n * are not delivered either. Reading `this.outbox.length` alone at exactly\n * that moment would undercount to 0 — silently implying full delivery\n * for the one case (a hung POST) this finding exists to catch honestly.\n */\n outboxLength(): number {\n return this.outbox.length + this.inFlightBatchSize;\n }\n\n /**\n * Finding F5(b): polls {@link outboxLength} (not `this.outbox.length`\n * alone — see that method's own doc comment for why a spliced-out,\n * in-flight batch would otherwise be invisible here) rather than hooking\n * a single `drainOutbox()` promise directly — a drain in progress can\n * itself loop through multiple retry/backoff cycles (`drainRetryDelay`)\n * while the server is unreachable, and a fresh, INDEPENDENT\n * `drainOutbox()` call can also be triggered concurrently (`send()`, a\n * mode switch's own `void this.drainOutbox()`) — polling the one thing\n * that actually matters (is anything still undelivered) can never go\n * stale the way capturing one specific in-flight promise reference\n * could. Kicks off one more `drainOutbox()` attempt itself first\n * (harmless no-op if one is already running — see its own re-entrancy\n * guard) in case nothing is currently actively retrying (e.g. WS just\n * dropped and long-poll hasn't taken over yet), so this bounded wait\n * isn't just passively hoping something else happens to be making\n * progress.\n */\n private waitForOutboxDrained(timeoutMs: number): Promise<void> {\n if (this.outboxLength() === 0) return Promise.resolve();\n void this.drainOutbox();\n return new Promise((resolve) => {\n const deadline = Date.now() + timeoutMs;\n const poll = (): void => {\n if (this.outboxLength() === 0 || this.stopped || this.revoked || Date.now() >= deadline) {\n resolve();\n return;\n }\n const timer = setTimeout(poll, 20);\n timer.unref?.();\n };\n poll();\n });\n }\n\n /**\n * Findings F2 + F3. Two rules, both pinned in docs/protocol.md §1.2/§9:\n *\n * - F2 (redelivery dead on reconnect): cursor accounting covers ONLY\n * `task.*` envelopes. `conn.ack` carries a `seq` too (required by the\n * schema for schema uniformity across every server->daemon type), but a\n * reconnecting server sends it BEFORE replaying the backlog and always\n * assigns it the next (i.e. highest-so-far) per-device seq — advancing\n * the cursor for it would make every backlog envelope's (necessarily\n * lower) seq look already-delivered and drop it. `conn.*` envelopes\n * never advance the cursor.\n * - F3 (at-most-once): the old code persisted the cursor advance BEFORE\n * `onEnvelope` even ran (fire-and-forget) — a handler that then failed\n * left a redelivery-proof envelope permanently marked processed. Inbound\n * envelopes are now serialized through `processingChain` (one handler\n * fully settles before the next starts) and the cursor only advances\n * AFTER the handler resolves successfully; a rejection leaves the\n * cursor where it was (see `stalledAtSeq`), so a future reconnect's\n * redelivery re-attempts it — safe because every server->daemon type is\n * documented idempotent (protocol §9).\n */\n private deliver(envelope: Envelope): void {\n const tracked = isTaskEnvelopeType(envelope.type) && typeof envelope.seq === 'number';\n const watermark = this.dedupWatermark();\n if (tracked && watermark !== undefined && envelope.seq! <= watermark) return; // redelivered — idempotent skip (protocol §9)\n\n if (tracked) {\n const seq = envelope.seq!;\n // Finding P2 (Fix 2b): a redelivery of a seq already in flight (its\n // prior attempt hasn't settled yet) or already succeeded this session\n // — both possible even though `seq > watermark` while stalled (see\n // `dedupWatermark`'s doc comment) — must not be re-appended to\n // `processingChain`. The stalled seq itself is deliberately NOT\n // excluded by this check once its prior attempt has settled (removed\n // from `inFlightSeqs` in `process()`'s `finally`, never added to\n // `processedSeqs` since it failed) — that's exactly the redelivery\n // this whole mechanism exists to let through for a fresh retry.\n if (this.inFlightSeqs.has(seq) || this.processedSeqs.has(seq)) return;\n this.inFlightSeqs.add(seq);\n this.noteDelivered(seq);\n }\n\n this.processingChain = this.processingChain.then(() => this.process(envelope, tracked));\n }\n\n /**\n * Design A: the watermark `deliver()` dedupes inbound `task.*` envelopes\n * against, and the same value `LongPollClient` queries the next\n * `GET /byok/events` cursor with (see the constructor). Normally this is\n * `deliveredSeq` — which is always >= `cursor` (every envelope that\n * reaches `advanceCursor` already passed through `noteDelivered` first,\n * see `deliver`) — so this is the literal `max(cursor, deliveredSeq)` the\n * design calls for, just expressed via that invariant rather than an\n * explicit `Math.max`.\n *\n * While `stalledAtSeq` is set, this collapses to the durable `cursor`\n * alone, deliberately ignoring however far `deliveredSeq` had already run\n * ahead before the failure was known: that's what lets the stalled\n * envelope's own redelivery (and everything after it, right up to a\n * fresh success) get past this same dedup check instead of being\n * self-deduped by the client's own earlier eager tracking of envelopes\n * whose outcome wasn't known yet. No separate \"reset deliveredSeq on\n * reconnect\" step is needed for this to be correct — collapsing to\n * `cursor` exactly while stalled already produces the right answer on\n * every redelivery path (long-poll re-query AND a WS reconnect's\n * backlog replay alike), and NOT resetting it unconditionally on every\n * reconnect is what lets `deliveredSeq` keep doing its job of not\n * re-pulling/re-dispatching something already in flight across a\n * reconnect that happens to land while a handler is still running.\n */\n private dedupWatermark(): number | undefined {\n return this.stalledAtSeq !== undefined ? this.cursor : (this.deliveredSeq ?? this.cursor);\n }\n\n /** Design A: eagerly advance the in-memory delivery watermark — called for every `task.*` envelope `deliver()` admits past dedup, regardless of transport or of whether its handler has even started yet. */\n private noteDelivered(seq: number): void {\n if (this.deliveredSeq === undefined || seq > this.deliveredSeq) this.deliveredSeq = seq;\n }\n\n private async process(envelope: Envelope, tracked: boolean): Promise<void> {\n const seq = tracked ? envelope.seq! : undefined;\n try {\n await this.opts.onEnvelope(envelope);\n if (!tracked) return;\n this.processedSeqs.add(seq!); // finding P2 (Fix 2b) — see its own doc comment\n // Still behind an earlier, not-yet-resolved failure: this envelope\n // (even though it just succeeded) is not the one unblocking the\n // cursor. Advancing here would create a gap a future redelivery could\n // never fill (the skipped-over failed seq would look already-seen).\n if (this.stalledAtSeq !== undefined && envelope.seq !== this.stalledAtSeq) return;\n this.stalledAtSeq = undefined;\n this.processedSeqs.clear(); // no longer needed once unstalled — deliveredSeq/watermark already covers everything delivered so far\n this.advanceCursor(envelope.seq!);\n } catch (err) {\n if (tracked && this.stalledAtSeq === undefined) this.stalledAtSeq = envelope.seq;\n console.error(\n `[byok/client] envelope handler failed for ${envelope.type}${\n typeof envelope.seq === 'number' ? ` (seq=${envelope.seq})` : ''\n }; cursor left unadvanced so a reconnect redelivers it:`,\n err,\n );\n } finally {\n if (tracked) this.inFlightSeqs.delete(seq!);\n }\n }\n\n /**\n * M4 Phase 4 (version-negotiation drill fix): `LongPollClient` calls this\n * for a batch entry it could not parse into a known `Envelope` at all (an\n * unrecognized message type — mirrors `ws-transport.ts`'s identical\n * per-frame tolerance, see `long-poll-transport.ts`'s own doc comment on\n * `parseLooseEventsPollResponse`) but which still carried a numeric,\n * task-class envelope-level `seq` (the caller only invokes this for a\n * `task.`-prefixed type — see `long-poll-transport.ts`'s own\n * `extractSkippableSeq`; `conn.*`-shaped or type-less entries never reach\n * here at all, mirroring F2's \"conn.* is never cursor-tracked\" rule).\n * There is no real `Envelope` to hand to a handler — a genuinely\n * unrecognized type has nothing this build could ever act on.\n *\n * GATEKEEPER-CAUGHT REGRESSION (fixed here): this used to call\n * `advanceCursor(seq)` DIRECTLY, synchronously, the instant a skip was\n * detected in `LongPollClient.loop()`'s per-entry for-loop. That is NOT\n * \"instantaneous and race-free\" the way the previous version of this\n * comment claimed — the hazard was never the skip racing against itself,\n * it was the skip racing AHEAD of an EARLIER real envelope in the SAME\n * batch that is still in flight on `processingChain` (`deliver()`, above,\n * only ever CHAINS `process()` onto that promise chain — it never awaits\n * it before returning). Concretely, batch `[real seq1, unknown seq2]`:\n * `deliver(seq1)` chains `process(seq1)` but returns immediately without\n * running it; the for-loop then reaches `seq2` and (pre-fix) called\n * `advanceCursor(2)` synchronously, BEFORE `process(seq1)` had even\n * started, let alone failed. If `seq1`'s handler then failed,\n * `stalledAtSeq` became 1 — but the durable cursor was already 2, so\n * `dedupWatermark()` returned 2, and every future redelivery of seq1 was\n * dedup-dropped as \"already past the cursor\" forever: permanent envelope\n * loss, exactly the F3 bug class the whole `stalledAtSeq`/frozen-watermark\n * mechanism exists to prevent.\n *\n * Fix: the cursor-advancing half is now CHAINED onto `processingChain`\n * too, exactly like `process()`'s own post-handler bookkeeping — so it\n * only ever runs once every earlier envelope already queued ahead of it\n * has fully settled (success or failure), and can observe `stalledAtSeq`'s\n * REAL, up-to-date value rather than whatever it happened to be at the\n * instant the skip was first noticed. The guard mirrors `process()`'s own\n * success-path guard exactly: never advance past a still-unresolved\n * earlier failure, unless (degenerate, cannot really happen for a skip)\n * this exact seq IS the stalled one.\n *\n * `noteDelivered` (the eager, in-memory watermark) stays UNCHAINED —\n * called immediately, unconditionally, regardless of `stalledAtSeq` —\n * matching `deliver()`'s own eager, unconditional call for a real\n * envelope: its only job is \"don't re-pull something already handed off,\"\n * independent of outcome, and that property does not depend on FIFO\n * ordering the way the DURABLE cursor does.\n *\n * Deliberately NO top-level `dedupWatermark() <= seq` early-return before\n * queuing the chained callback (an earlier draft of this fix had one, and\n * it was itself subtly wrong): `deliveredSeq` can already reflect a seq\n * from the FIRST time it was ever seen, while the DURABLE cursor is still\n * behind it because a stall intervened before that seq's chained\n * advancement ran — a pre-check keyed on `deliveredSeq` would then\n * wrongly treat a LATER redelivery of the same seq (arriving once the\n * stall has since cleared) as \"already accounted for\" and never queue\n * another attempt, permanently stranding the cursor one seq short. Always\n * queuing is safe and cheap: `advanceCursor`'s own `seq <= this.cursor`\n * guard already makes a genuinely-redundant call a no-op, so there is no\n * correctness reason to short-circuit earlier, only a (here, unnecessary)\n * micro-optimization one.\n */\n private noteSkippedSeq(seq: number): void {\n this.noteDelivered(seq);\n this.processingChain = this.processingChain.then(() => {\n if (this.stalledAtSeq === undefined || seq === this.stalledAtSeq) {\n this.advanceCursor(seq);\n }\n });\n }\n\n /**\n * Finding R1 (cross-model re-review — was NOT-CLOSED against F1):\n * `LongPollClient` calls this for a batch entry whose `type` it\n * recognized but whose payload failed schema validation\n * ({@link EnvelopeValidationError}) — a genuine delivery failure at that\n * seq, unlike `noteSkippedSeq`'s forward-compat case. Deliberately mirrors\n * `process()`'s own catch block (`if (tracked && this.stalledAtSeq ===\n * undefined) this.stalledAtSeq = envelope.seq;`) as closely as possible:\n * the SAME \"only the lowest unresolved failure holds the stall\" rule, the\n * SAME resulting freeze of `dedupWatermark()` at the durable cursor\n * (protocol §9 keeps this seq alive), and — because it's the SAME\n * `stalledAtSeq` field `process()`'s own post-success guard already\n * checks — anything ELSE delivered after this seq (same batch or a later\n * one) is automatically held back from advancing the cursor too, with\n * zero changes needed to `process()` itself.\n *\n * Chained onto `processingChain` for exactly the reason `noteSkippedSeq`\n * documents for its own identical chaining (see that method's sibling\n * doc comment on `LongPollClient`, \"GATEKEEPER-CAUGHT REGRESSION\"): an\n * EARLIER real envelope in the SAME batch may still be in flight on that\n * FIFO chain when this is called (`deliver()` only ever chains\n * `process()` onto it, never awaits before returning) — mutating\n * `stalledAtSeq` synchronously here could race ahead of that still-\n * unresolved earlier envelope. Chaining instead guarantees this only\n * takes effect once every earlier-queued envelope has already settled,\n * and reads `stalledAtSeq`'s real, up-to-date value rather than whatever\n * it happened to be the instant the failure was first noticed.\n *\n * No `noteDelivered` call here (contrast `noteSkippedSeq`, which does\n * call it): a validation-failed entry never becomes a real `Envelope` and\n * never reaches `deliver()`, so it was never \"delivered\" in the eager\n * in-memory-watermark sense that field tracks — there is nothing for it\n * to eagerly mark. Once a corrected redelivery of this exact seq DOES\n * arrive as a real envelope, it flows through the ordinary `deliver()`\n * path (which calls `noteDelivered` itself) and, on success, clears the\n * stall via `process()`'s own existing logic — no special-casing needed.\n */\n private noteValidationFailure(seq: number): void {\n this.processingChain = this.processingChain.then(() => {\n if (this.stalledAtSeq === undefined) this.stalledAtSeq = seq;\n });\n }\n\n private advanceCursor(seq: number): void {\n if (this.cursor !== undefined && seq <= this.cursor) return;\n this.cursor = seq;\n // Chain onto the previous save rather than firing independently: two\n // overlapping writes to the same file have no guaranteed completion\n // order, so an earlier (lower-seq) save finishing *after* a later one\n // could silently clobber it back to a stale value. Chaining forces\n // strict write order, matching call order (which matches seq order,\n // since advanceCursor is only ever called with an increasing value).\n this.pendingCursorSave = this.pendingCursorSave\n .catch(() => {\n // don't let an earlier failure abort the chain for later saves\n })\n .then(() => this.opts.cursorStore.save(this.opts.serverUrl, this.opts.deviceId, seq))\n .catch(() => {\n // Best-effort persistence: a failed write just means a future\n // reconnect might redeliver slightly more than strictly necessary,\n // which is safe under at-least-once delivery (protocol §9).\n });\n }\n\n /**\n * Fires the moment a connection attempt reaches `conn.ack` — independent\n * of whether/when it later closes. This is the ONLY place that can\n * reliably detect \"WS is back up\" while long-polling: a healthy\n * connection stays open indefinitely, so it never reaches `onWsOutcome`\n * (which is close-only) at all.\n */\n private onAcked(capabilities: string[]): void {\n this.serverCapabilities = capabilities;\n this.consecutiveFailures = 0;\n this.notifySettled();\n this.opts.onOperationalOutcome?.('success', 'reconnect');\n if (this.mode === 'long-poll') this.exitLongPoll();\n void this.drainOutbox(); // Design B: pick up anything queued while WS was (re)connecting\n }\n\n private onWsOutcome(acked: boolean, err?: unknown): void {\n if (this.stopped || this.revoked) return;\n\n // Finding R2: this specific attempt WAS acked at some point but has now\n // closed — the connection that advertised `serverCapabilities` is gone.\n // Cleared BEFORE the `if (acked) return;` early-out below, so this runs\n // on every acked-then-closed outcome regardless of what happens next\n // (a fast auto-reconnect, a slower one, or none at all pending\n // `enterLongPoll`) — only a FRESH `conn.ack` (`onAcked`) repopulates it.\n if (acked) this.serverCapabilities = [];\n\n if (err instanceof WsUnexpectedStatusError && err.status === 401) {\n // Reactive renewal (protocol §6.2): the cached token was rejected on\n // the wire even though our own expiry bookkeeping thought it was\n // still good. Force a renewal now so the next attempt (this one just\n // failed) uses a fresh token; a genuinely revoked device surfaces via\n // handleUnauthorized() throwing DeviceRevokedError below.\n this.opts.auth.handleUnauthorized().catch((renewErr: unknown) => {\n if (renewErr instanceof DeviceRevokedError) this.enterRevoked();\n });\n }\n\n // acked===true here just means \"this now-closed attempt was healthy at\n // some point\" — `onAcked()` already handled resetting failures/exiting\n // long-poll the moment that happened, so there's nothing left to do.\n if (acked) return;\n\n this.opts.onOperationalOutcome?.('failure', 'reconnect');\n this.consecutiveFailures += 1;\n if (this.mode === 'ws' && this.consecutiveFailures >= (this.opts.wsFailureThreshold ?? 3)) {\n this.enterLongPoll();\n }\n }\n\n private notifySettled(err?: unknown): void {\n for (const waiter of this.settledWaiters.splice(0)) waiter(err);\n }\n\n private enterLongPoll(): void {\n this.mode = 'long-poll';\n // Finding R2: defensive/belt-and-suspenders — in practice the acked\n // disconnect that precedes this already cleared it via `onWsOutcome`\n // above, but long-poll performs no equivalent handshake of its own\n // (docs/protocol.md §8.1), so this transport must never be able to\n // observe a stale, non-empty `serverCapabilities` from here on either.\n this.serverCapabilities = [];\n this.ws.stopAutoReconnect();\n this.opts.onStateChange?.('degraded');\n this.longPoll.start();\n this.notifySettled();\n void this.drainOutbox(); // Design B: anything already queued now drains over the freshly-started long-poll POST path\n\n this.scheduleWsProbe();\n }\n\n private exitLongPoll(): void {\n if (this.wsRetryTimer) {\n clearInterval(this.wsRetryTimer);\n this.wsRetryTimer = undefined;\n }\n this.longPoll.stop();\n this.mode = 'ws';\n this.consecutiveFailures = 0;\n this.ws.resumeAutoReconnect();\n void this.drainOutbox(); // Design B: anything still queued from long-poll now drains over WS\n }\n\n private scheduleWsProbe(): void {\n const baseMs = this.opts.wsRetryIntervalMs ?? 5 * 60 * 1000;\n const delayMs = this.fleetJitter.delay('reconnect', this.wsProbeSequence++, baseMs);\n const timer = setTimeout(() => {\n this.wsRetryTimer = undefined;\n if (this.stopped || this.revoked || this.mode !== 'long-poll') return;\n this.ws.connect({ auto: false });\n this.scheduleWsProbe();\n }, delayMs);\n timer.unref?.();\n this.wsRetryTimer = timer;\n }\n\n private enterRevoked(): void {\n if (this.revoked) return;\n this.revoked = true;\n if (this.wsRetryTimer) clearInterval(this.wsRetryTimer);\n this.longPoll.stop();\n this.ws.close(); // stop all reconnection attempts entirely — never a retry loop (protocol §6.3)\n // Finding P3: the outbox drain must stop too, not just the receive\n // side — otherwise a queued send keeps retrying (and re-arming a\n // backoff timer) forever, since a revoked device can never recover\n // without a fresh pair(). `drainOutbox`'s own `this.revoked` check\n // (now true) stops it from scheduling another retry, but if it's\n // ALREADY parked inside `drainRetryDelay` from a previous cycle,\n // cancel that wait immediately rather than leaving it queued for up to\n // the rest of the delay.\n this.cancelPendingDrainRetry?.();\n this.opts.onStateChange?.('revoked');\n // Unblock a cold start()'s pending waitForAck() immediately with the\n // typed error instead of leaving it to time out (see waitForAck doc). A\n // no-op if the connection already settled earlier (settledWaiters empty)\n // — e.g. revocation discovered while already connected/running.\n this.notifySettled(new DeviceRevokedError());\n }\n}\n","import { randomUUID } from 'node:crypto';\nimport { constants as fsConstants, promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { atomicWriteFile } from '../util/atomic-write';\nimport { ensureSecureDir } from '../util/secure-dir';\n\nexport type OperationalHealthState = 'healthy' | 'degraded' | 'recovering';\nexport type OperationalFailureSource = 'reconnect' | 'upload' | 'maintenance' | 'lifecycle';\n\ninterface FailureEvent {\n at: string;\n source: OperationalFailureSource;\n}\n\nexport interface OperationalCrashRecord {\n detectedAt: string;\n previousRunStartedAt: string;\n}\n\ninterface RunMarker {\n id: string;\n startedAt: string;\n pid: number;\n}\n\ninterface HealthFileV1 {\n version: 1;\n state: OperationalHealthState;\n failures: FailureEvent[];\n crashes: OperationalCrashRecord[];\n currentRun?: RunMarker;\n}\n\nexport const OPERATIONAL_HEALTH_FILENAME = 'operational-health.json';\nexport const MAX_OPERATIONAL_HEALTH_FILE_BYTES = 1024 * 1024;\n\nexport interface OpenOperationalHealthFile {\n handle: Awaited<ReturnType<typeof fs.open>>;\n stat: import('node:fs').BigIntStats;\n}\n\nfunction sameFileState(left: import('node:fs').BigIntStats, right: import('node:fs').BigIntStats): boolean {\n return (\n left.dev === right.dev &&\n left.ino === right.ino &&\n left.size === right.size &&\n left.mtimeNs === right.mtimeNs &&\n left.ctimeNs === right.ctimeNs\n );\n}\n\n/**\n * Bind the pathname to a regular-file handle before any bytes are read.\n * POSIX additionally gets O_NOFOLLOW/O_NONBLOCK. On Windows those flags are\n * unavailable, so the pre-open lstat plus handle/path identity checks are the\n * fail-closed authority: a static reparse point is rejected before open, and\n * a raced replacement cannot match the already-observed inode/file state.\n */\nexport async function openOperationalHealthFile(\n storeDir: string,\n): Promise<OpenOperationalHealthFile | undefined> {\n const filePath = path.join(storeDir, OPERATIONAL_HEALTH_FILENAME);\n let namedBefore: import('node:fs').BigIntStats;\n try {\n namedBefore = await fs.lstat(filePath, { bigint: true });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw err;\n }\n if (!namedBefore.isFile() || namedBefore.isSymbolicLink()) {\n throw new Error('operational health state is not a real regular file');\n }\n\n let handle: Awaited<ReturnType<typeof fs.open>> | undefined;\n try {\n handle = await fs.open(\n filePath,\n fsConstants.O_RDONLY | (fsConstants.O_NONBLOCK ?? 0) | (fsConstants.O_NOFOLLOW ?? 0),\n );\n const opened = await handle.stat({ bigint: true });\n const namedAfter = await fs.lstat(filePath, { bigint: true });\n if (\n !opened.isFile() ||\n !namedAfter.isFile() ||\n namedAfter.isSymbolicLink() ||\n !sameFileState(namedBefore, opened) ||\n !sameFileState(opened, namedAfter)\n ) {\n throw new Error('operational health pathname changed before safe open');\n }\n return { handle, stat: opened };\n } catch (err) {\n await handle?.close().catch(() => undefined);\n throw err;\n }\n}\n\nexport type OperationalHealthFileInspection =\n | { status: 'missing' }\n | {\n status: 'valid';\n sizeBytes: number;\n state: OperationalHealthState;\n failureCount: number;\n crashCount: number;\n currentRunStartedAt?: string;\n lastCrashAt?: string;\n }\n | { status: 'corrupt'; sizeBytes: number; reason: string }\n | { status: 'unavailable'; sizeBytes?: number; reason: string };\n\nexport type OperationalHealthSnapshot =\n | {\n availability: 'available';\n state: OperationalHealthState;\n failureCount: number;\n windowMs: number;\n failureThreshold: number;\n crashCount: number;\n lastCrashAt?: string;\n currentRunStartedAt?: string;\n }\n | { availability: 'unavailable'; reason: string };\n\nexport interface OperationalHealthOptions {\n windowMs?: number;\n failureThreshold?: number;\n maxFailures?: number;\n maxCrashes?: number;\n clock?: () => Date;\n runId?: () => string;\n pid?: number;\n}\n\nexport class OperationalHealthTracker {\n readonly #filePath: string;\n readonly #windowMs: number;\n readonly #failureThreshold: number;\n readonly #maxFailures: number;\n readonly #maxCrashes: number;\n readonly #clock: () => Date;\n readonly #runId: () => string;\n readonly #pid: number;\n #state: HealthFileV1 | undefined;\n #unavailableReason: string | undefined;\n #writeTail: Promise<void> = Promise.resolve();\n #started = false;\n\n constructor(storeDir: string, options: OperationalHealthOptions = {}) {\n this.#filePath = path.join(storeDir, OPERATIONAL_HEALTH_FILENAME);\n this.#windowMs = options.windowMs ?? 60_000;\n this.#failureThreshold = options.failureThreshold ?? 3;\n this.#maxFailures = options.maxFailures ?? 128;\n this.#maxCrashes = options.maxCrashes ?? 20;\n this.#clock = options.clock ?? (() => new Date());\n this.#runId = options.runId ?? randomUUID;\n this.#pid = options.pid ?? process.pid;\n if (!Number.isSafeInteger(this.#windowMs) || this.#windowMs <= 0) throw new Error('health windowMs must be positive');\n if (!Number.isSafeInteger(this.#failureThreshold) || this.#failureThreshold <= 0) throw new Error('health failureThreshold must be positive');\n if (!Number.isSafeInteger(this.#maxFailures) || this.#maxFailures <= 0) throw new Error('health maxFailures must be positive');\n if (!Number.isSafeInteger(this.#maxCrashes) || this.#maxCrashes <= 0) throw new Error('health maxCrashes must be positive');\n if (this.#maxFailures < this.#failureThreshold) throw new Error('health maxFailures must cover failureThreshold');\n }\n\n async startRun(): Promise<OperationalHealthSnapshot> {\n if (this.#started) return this.snapshot();\n this.#started = true;\n const now = this.#clock();\n let loaded: HealthFileV1;\n try {\n loaded = await this.#load();\n } catch (err) {\n this.#unavailableReason = err instanceof Error ? err.message : String(err);\n return this.snapshot();\n }\n this.#state = loaded;\n this.#prune(now);\n // The load boundary enforces the same bounded-history invariant as the\n // writer. A shape-valid file produced by an older/manual writer must not\n // bypass the configured memory/disk bound simply because no new event is\n // appended during this run.\n loaded.failures = loaded.failures.slice(-this.#maxFailures);\n loaded.crashes = loaded.crashes.slice(-this.#maxCrashes);\n if (loaded.failures.length >= this.#failureThreshold) loaded.state = 'degraded';\n if (loaded.currentRun) {\n loaded.crashes.push({ detectedAt: now.toISOString(), previousRunStartedAt: loaded.currentRun.startedAt });\n loaded.crashes = loaded.crashes.slice(-this.#maxCrashes);\n }\n loaded.currentRun = { id: this.#runId(), startedAt: now.toISOString(), pid: this.#pid };\n await this.#persist();\n return this.snapshot();\n }\n\n async recordFailure(source: OperationalFailureSource): Promise<void> {\n if (!this.#state || this.#unavailableReason) return;\n const now = this.#clock();\n this.#prune(now);\n this.#state.failures.push({ at: now.toISOString(), source });\n this.#state.failures = this.#state.failures.slice(-this.#maxFailures);\n if (this.#state.failures.length >= this.#failureThreshold || this.#state.state === 'recovering') {\n this.#state.state = 'degraded';\n }\n await this.#persist();\n }\n\n async recordSuccess(_source: OperationalFailureSource): Promise<void> {\n if (!this.#state || this.#unavailableReason) return;\n const now = this.#clock();\n this.#prune(now);\n if (this.#state.state === 'healthy') return;\n if (this.#state.state === 'degraded') {\n this.#state.state = 'recovering';\n } else if (this.#state.state === 'recovering' && this.#state.failures.length < this.#failureThreshold) {\n this.#state.state = 'healthy';\n } else {\n return;\n }\n await this.#persist();\n }\n\n async markCleanStop(): Promise<void> {\n if (!this.#state || this.#unavailableReason || !this.#started) return;\n this.#state.currentRun = undefined;\n await this.#persist();\n this.#started = false;\n }\n\n snapshot(): OperationalHealthSnapshot {\n if (this.#unavailableReason) return { availability: 'unavailable', reason: this.#unavailableReason };\n if (!this.#state) return { availability: 'unavailable', reason: 'operational health has not been loaded' };\n this.#prune(this.#clock());\n return {\n availability: 'available',\n state: this.#state.state,\n failureCount: this.#state.failures.length,\n windowMs: this.#windowMs,\n failureThreshold: this.#failureThreshold,\n crashCount: this.#state.crashes.length,\n ...(this.#state.crashes.at(-1) ? { lastCrashAt: this.#state.crashes.at(-1)!.detectedAt } : {}),\n ...(this.#state.currentRun ? { currentRunStartedAt: this.#state.currentRun.startedAt } : {}),\n };\n }\n\n async #load(): Promise<HealthFileV1> {\n let opened: OpenOperationalHealthFile | undefined;\n try {\n opened = await openOperationalHealthFile(path.dirname(this.#filePath));\n } catch (err) {\n throw new Error('operational health state could not be read');\n }\n if (!opened) return { version: 1, state: 'healthy', failures: [], crashes: [] };\n try {\n const inspected = await readOperationalHealthHandle(opened.handle, opened.stat);\n if (inspected.status !== 'read') throw new Error(inspected.reason);\n let parsed: unknown;\n try {\n parsed = JSON.parse(inspected.raw);\n } catch {\n throw new Error('operational health state is corrupt JSON');\n }\n if (!isHealthFile(parsed)) throw new Error('operational health state has an invalid shape');\n return parsed;\n } finally {\n await opened.handle.close();\n }\n }\n\n #prune(now: Date): void {\n if (!this.#state) return;\n const nowMs = now.getTime();\n const cutoff = nowMs - this.#windowMs;\n // A wall-clock rollback must not turn a bounded 60-second budget into an\n // hour-long degradation. Events dated after the clock we are evaluating\n // are outside this window just as surely as events older than the cutoff;\n // discard them instead of retaining them until wall time catches up.\n this.#state.failures = this.#state.failures.filter((event) => {\n const eventMs = Date.parse(event.at);\n return eventMs >= cutoff && eventMs <= nowMs;\n });\n // Entering `recovering` already required a real successful outcome. Once\n // the failures that caused degradation leave the window, the budget is\n // healthy again even if an otherwise-idle daemon has no second outcome to\n // report. The in-memory transition is persisted by the next state write\n // (including clean stop); a restart also prunes before writing its marker.\n if (this.#state.state === 'recovering' && this.#state.failures.length < this.#failureThreshold) {\n this.#state.state = 'healthy';\n }\n }\n\n async #persist(): Promise<void> {\n if (!this.#state) return;\n const body = JSON.stringify(this.#state, null, 2);\n this.#writeTail = this.#writeTail.then(async () => {\n await ensureSecureDir(path.dirname(this.#filePath));\n await atomicWriteFile(this.#filePath, body, { mode: 0o600, fsync: true });\n });\n try {\n await this.#writeTail;\n } catch (err) {\n this.#unavailableReason = 'operational health state could not be persisted';\n throw err;\n }\n }\n}\n\n/**\n * Read-only S7-b inspection seam. Unlike `OperationalHealthTracker.startRun`,\n * this never writes a run marker, prunes history, or repairs malformed bytes;\n * doctor can therefore report on an offline daemon without changing the very\n * evidence it is inspecting.\n */\nasync function inspectOperationalHealthHandle(\n handle: Awaited<ReturnType<typeof fs.open>>,\n expected?: import('node:fs').BigIntStats,\n): Promise<Exclude<OperationalHealthFileInspection, { status: 'missing' }>> {\n const read = await readOperationalHealthHandle(handle, expected);\n if (read.status !== 'read') return read;\n const { raw, sizeBytes } = read;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return { status: 'corrupt', sizeBytes, reason: 'operational health state is corrupt JSON' };\n }\n if (!isHealthFile(parsed)) {\n return { status: 'corrupt', sizeBytes, reason: 'operational health state has an invalid shape' };\n }\n return {\n status: 'valid',\n sizeBytes,\n state: parsed.state,\n failureCount: parsed.failures.length,\n crashCount: parsed.crashes.length,\n ...(parsed.currentRun ? { currentRunStartedAt: new Date(Date.parse(parsed.currentRun.startedAt)).toISOString() } : {}),\n ...(parsed.crashes.at(-1)\n ? { lastCrashAt: new Date(Date.parse(parsed.crashes.at(-1)!.detectedAt)).toISOString() }\n : {}),\n };\n}\n\nasync function readOperationalHealthHandle(\n handle: Awaited<ReturnType<typeof fs.open>>,\n expected?: import('node:fs').BigIntStats,\n): Promise<\n | { status: 'read'; raw: string; sizeBytes: number }\n | Extract<OperationalHealthFileInspection, { status: 'unavailable' }>\n> {\n let before: import('node:fs').BigIntStats;\n try {\n before = await handle.stat({ bigint: true });\n } catch {\n return { status: 'unavailable', reason: 'operational health state could not be inspected' };\n }\n const sizeBytes = Number(before.size);\n if (expected && !sameFileState(before, expected)) {\n return { status: 'unavailable', sizeBytes, reason: 'operational health handle identity changed before inspection' };\n }\n if (!before.isFile()) {\n return { status: 'unavailable', sizeBytes, reason: 'operational health state is not a regular file' };\n }\n if (sizeBytes > MAX_OPERATIONAL_HEALTH_FILE_BYTES) {\n return {\n status: 'unavailable',\n sizeBytes,\n reason: 'operational health state exceeds the 1 MiB read limit; corruption is unconfirmed',\n };\n }\n try {\n const buffer = Buffer.alloc(sizeBytes);\n const { bytesRead } = await handle.read(buffer, 0, sizeBytes, 0);\n const after = await handle.stat({ bigint: true });\n if (\n bytesRead !== sizeBytes ||\n after.size !== before.size ||\n after.mtimeNs !== before.mtimeNs ||\n after.ctimeNs !== before.ctimeNs\n ) {\n return { status: 'unavailable', sizeBytes: Number(after.size), reason: 'operational health state changed during inspection' };\n }\n return { status: 'read', raw: buffer.toString('utf8'), sizeBytes };\n } catch {\n return { status: 'unavailable', sizeBytes, reason: 'operational health state could not be read' };\n }\n}\n\n/**\n * Open a pathname-bound regular-file handle before inspecting. POSIX uses\n * no-follow/non-blocking flags; Windows uses the pre-open and post-open\n * pathname/handle identity checks in openOperationalHealthFile.\n */\nexport async function inspectOperationalHealthFile(storeDir: string): Promise<OperationalHealthFileInspection> {\n let opened: OpenOperationalHealthFile | undefined;\n try {\n opened = await openOperationalHealthFile(storeDir);\n } catch {\n return { status: 'unavailable', reason: 'operational health state could not be opened safely' };\n }\n if (!opened) return { status: 'missing' };\n try {\n return await inspectOperationalHealthHandle(opened.handle, opened.stat);\n } finally {\n await opened.handle.close();\n }\n}\n\nexport { inspectOperationalHealthHandle };\n\nfunction isHealthFile(value: unknown): value is HealthFileV1 {\n if (typeof value !== 'object' || value === null) return false;\n const candidate = value as Partial<HealthFileV1>;\n const keys = Object.keys(candidate);\n if (keys.some((key) => !['version', 'state', 'failures', 'crashes', 'currentRun'].includes(key))) return false;\n if (candidate.version !== 1 || !['healthy', 'degraded', 'recovering'].includes(String(candidate.state))) return false;\n if (!Array.isArray(candidate.failures) || !candidate.failures.every(isFailureEvent)) return false;\n if (!Array.isArray(candidate.crashes) || !candidate.crashes.every(isCrashRecord)) return false;\n if (candidate.currentRun !== undefined && !isRunMarker(candidate.currentRun)) return false;\n return true;\n}\n\nfunction isFailureEvent(value: unknown): value is FailureEvent {\n if (typeof value !== 'object' || value === null) return false;\n const event = value as Partial<FailureEvent>;\n return (\n Object.keys(event).every((key) => ['at', 'source'].includes(key)) &&\n typeof event.at === 'string' &&\n Number.isFinite(Date.parse(event.at)) &&\n ['reconnect', 'upload', 'maintenance', 'lifecycle'].includes(String(event.source))\n );\n}\n\nfunction isCrashRecord(value: unknown): value is OperationalCrashRecord {\n if (typeof value !== 'object' || value === null) return false;\n const record = value as Partial<OperationalCrashRecord>;\n return (\n Object.keys(record).every((key) => ['detectedAt', 'previousRunStartedAt'].includes(key)) &&\n typeof record.detectedAt === 'string' &&\n Number.isFinite(Date.parse(record.detectedAt)) &&\n typeof record.previousRunStartedAt === 'string' &&\n Number.isFinite(Date.parse(record.previousRunStartedAt))\n );\n}\n\nfunction isRunMarker(value: unknown): value is RunMarker {\n if (typeof value !== 'object' || value === null) return false;\n const marker = value as Partial<RunMarker>;\n return (\n Object.keys(marker).every((key) => ['id', 'startedAt', 'pid'].includes(key)) &&\n typeof marker.id === 'string' &&\n typeof marker.startedAt === 'string' &&\n Number.isFinite(Date.parse(marker.startedAt)) &&\n typeof marker.pid === 'number' &&\n Number.isSafeInteger(marker.pid)\n );\n}\n","import { createHash, randomUUID } from 'node:crypto';\nimport { constants as fsConstants, promises as fs } from 'node:fs';\nimport { createConnection, createServer, type Server } from 'node:net';\nimport path from 'node:path';\nimport { ensureSecureDir } from '../util/secure-dir';\n\nexport const DAEMON_OWNER_FILENAME = 'daemon-owner.json';\nconst RECLAIM_FILENAME = `${DAEMON_OWNER_FILENAME}.reclaim`;\nconst MAX_OWNER_BYTES = 4096;\nconst RECLAIM_MALFORMED_GRACE_MS = 30_000;\n// Node exposes the current process lifetime without relying on `ps`, procps,\n// PowerShell, or another host command. Foreign-PID reuse is distinguished by\n// the kernel-owned liveness listener recorded alongside this timestamp.\nconst SELF_PROCESS_STARTED_AT = new Date(Date.now() - process.uptime() * 1_000).toISOString();\n\ninterface OwnerRecord {\n version: 2;\n pid: number;\n nonce: string;\n role: 'daemon' | 'doctor';\n acquiredAt: string;\n processStartedAt: string;\n livenessPort: number;\n}\n\nexport interface DaemonOwnerLease {\n release(): Promise<void>;\n}\n\ninterface LivenessListener {\n port: number;\n close(): Promise<void>;\n}\n\n// A canonical-path-derived loopback listener is the cross-process mutex for\n// the owner/reclaim transition. The listener identifies its store hash to\n// another conforming contender: the same hash means \"active\"; a different\n// valid hash means an unrelated store collided on this port and both sides can\n// safely use the next deterministic candidate. A listener that explicitly\n// closes/resets without presenting the contract is not mutex authority and is\n// skipped. A connected listener that stays silent remains fail-closed: it may\n// be this store's holder with a starved event loop, so advancing would discard\n// the kernel mutex as an independent safety authority. Keeping this mutex separate is important:\n// probing a stale owner's random liveness port must not observe the\n// contender's own transition listener.\n// Stay below the host ephemeral-client range used by the test/runtime HTTP and\n// WebSocket connections. Candidate negotiation handles collisions between\n// BYOK stores inside this reserved deterministic window.\nconst STORE_MUTEX_PORT_BASE = 10_000;\nconst STORE_MUTEX_PORT_COUNT = 20_000;\nconst STORE_MUTEX_PORT_CANDIDATES = 32;\nconst STORE_MUTEX_ID_PREFIX = 'byok-store-mutex-v1:';\nconst STORE_MUTEX_PROBE_TIMEOUT_MS = 1_000;\n\nfunction storeMutexIdentity(canonicalStoreDir: string): string {\n return createHash('sha256').update(canonicalStoreDir).digest('hex');\n}\n\nfunction storeMutexPort(identity: string, attempt: number): number {\n const digest = Buffer.from(identity, 'hex');\n const start = digest.readUInt32BE(0) % STORE_MUTEX_PORT_COUNT;\n const step = 1 + (digest.readUInt32BE(4) % (STORE_MUTEX_PORT_COUNT - 1));\n return STORE_MUTEX_PORT_BASE + ((start + attempt * step) % STORE_MUTEX_PORT_COUNT);\n}\n\nexport class DaemonOwnerActiveError extends Error {\n constructor(public readonly role: OwnerRecord['role'] | 'unknown') {\n super(`store mutation lease is already held by an active ${role} process`);\n this.name = 'DaemonOwnerActiveError';\n }\n}\n\nfunction isOwnerRecord(value: unknown): value is OwnerRecord {\n if (typeof value !== 'object' || value === null) return false;\n const candidate = value as Partial<OwnerRecord>;\n return (\n candidate.version === 2 &&\n Number.isSafeInteger(candidate.pid) &&\n (candidate.pid ?? 0) > 0 &&\n typeof candidate.nonce === 'string' &&\n candidate.nonce.length === 36 &&\n (candidate.role === 'daemon' || candidate.role === 'doctor') &&\n typeof candidate.acquiredAt === 'string' &&\n Number.isFinite(Date.parse(candidate.acquiredAt)) &&\n typeof candidate.processStartedAt === 'string' &&\n Number.isFinite(Date.parse(candidate.processStartedAt)) &&\n Number.isSafeInteger(candidate.livenessPort) &&\n (candidate.livenessPort ?? 0) > 0 &&\n (candidate.livenessPort ?? 0) <= 65_535\n );\n}\n\nasync function readOwner(filePath: string): Promise<OwnerRecord | undefined> {\n let namedBefore: import('node:fs').BigIntStats;\n try {\n namedBefore = await fs.lstat(filePath, { bigint: true });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw err;\n }\n if (!namedBefore.isFile() || namedBefore.isSymbolicLink()) {\n throw new Error('store mutation owner path is not a real regular file');\n }\n let handle: Awaited<ReturnType<typeof fs.open>> | undefined;\n try {\n handle = await fs.open(\n filePath,\n fsConstants.O_RDONLY | (fsConstants.O_NONBLOCK ?? 0) | (fsConstants.O_NOFOLLOW ?? 0),\n );\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw err;\n }\n try {\n const stat = await handle.stat({ bigint: true });\n const namedAfterOpen = await fs.lstat(filePath, { bigint: true });\n if (\n !stat.isFile() ||\n !namedAfterOpen.isFile() ||\n namedAfterOpen.isSymbolicLink() ||\n stat.dev !== namedBefore.dev ||\n stat.ino !== namedBefore.ino ||\n stat.size !== namedBefore.size ||\n stat.mtimeNs !== namedBefore.mtimeNs ||\n stat.ctimeNs !== namedBefore.ctimeNs ||\n stat.dev !== namedAfterOpen.dev ||\n stat.ino !== namedAfterOpen.ino ||\n stat.size !== namedAfterOpen.size ||\n stat.mtimeNs !== namedAfterOpen.mtimeNs ||\n stat.ctimeNs !== namedAfterOpen.ctimeNs\n ) {\n throw new Error('store mutation owner path changed before safe open');\n }\n if (stat.size <= 0 || stat.size > MAX_OWNER_BYTES) return undefined;\n const size = Number(stat.size);\n const buffer = Buffer.alloc(size);\n const { bytesRead } = await handle.read(buffer, 0, size, 0);\n const after = await handle.stat({ bigint: true });\n const namedAfterRead = await fs.lstat(filePath, { bigint: true });\n if (\n bytesRead !== size ||\n after.dev !== stat.dev ||\n after.ino !== stat.ino ||\n after.size !== stat.size ||\n after.mtimeNs !== stat.mtimeNs ||\n after.ctimeNs !== stat.ctimeNs ||\n namedAfterRead.dev !== stat.dev ||\n namedAfterRead.ino !== stat.ino ||\n namedAfterRead.size !== stat.size ||\n namedAfterRead.mtimeNs !== stat.mtimeNs ||\n namedAfterRead.ctimeNs !== stat.ctimeNs\n ) {\n throw new Error('store mutation owner path changed during inspection');\n }\n const raw = buffer.toString('utf8');\n const parsed: unknown = JSON.parse(raw);\n return isOwnerRecord(parsed) ? parsed : undefined;\n } catch (err) {\n if (err instanceof Error && err.message.startsWith('store mutation owner path changed')) throw err;\n return undefined;\n } finally {\n await handle.close();\n }\n}\n\nfunction pidIsAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n return (err as NodeJS.ErrnoException).code === 'EPERM';\n }\n}\n\nasync function processOwnsRecord(record: OwnerRecord): Promise<boolean> {\n if (!pidIsAlive(record.pid)) return false;\n if (record.pid === process.pid && record.processStartedAt !== SELF_PROCESS_STARTED_AT) return false;\n // The listener is the kernel-owned liveness authority. A PID can be reused,\n // but the replacement process does not inherit this bound port. Probing by\n // attempting the same exclusive bind therefore distinguishes a real live\n // lease from an unrelated process without `ps`, PowerShell, /proc, or a\n // platform-specific dependency. EADDRINUSE is intentionally fail-closed:\n // an unrelated listener collision may delay recovery, but can never admit\n // two store writers.\n return portIsBound(record.livenessPort);\n}\n\nasync function portIsBound(port: number): Promise<boolean> {\n const probe = createServer();\n return new Promise<boolean>((resolve, reject) => {\n const finish = (result: boolean): void => {\n probe.removeAllListeners();\n resolve(result);\n };\n probe.once('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') finish(true);\n else reject(err);\n });\n probe.listen({ host: '127.0.0.1', port, exclusive: true }, () => {\n probe.close((err) => {\n if (err) reject(err);\n else finish(false);\n });\n });\n });\n}\n\nasync function createLivenessListener(): Promise<LivenessListener> {\n const server: Server = createServer((socket) => socket.end());\n const port = await new Promise<number>((resolve, reject) => {\n server.once('error', reject);\n server.listen({ host: '127.0.0.1', port: 0, exclusive: true }, () => {\n server.removeListener('error', reject);\n const address = server.address();\n if (!address || typeof address === 'string') {\n reject(new Error('store mutation liveness listener did not expose a TCP port'));\n return;\n }\n resolve(address.port);\n });\n });\n server.unref();\n let closed = false;\n return {\n port,\n close: () =>\n new Promise<void>((resolve, reject) => {\n if (closed) {\n resolve();\n return;\n }\n closed = true;\n server.close((err) => (err ? reject(err) : resolve()));\n }),\n };\n}\n\ntype StoreMutexProbe =\n | { kind: 'identity'; identity: string }\n | { kind: 'foreign-or-gone' }\n | { kind: 'uncertain' };\n\nasync function probeStoreMutex(port: number): Promise<StoreMutexProbe> {\n return new Promise<StoreMutexProbe>((resolve) => {\n const socket = createConnection({ host: '127.0.0.1', port });\n let settled = false;\n let raw = '';\n const finish = (result: StoreMutexProbe): void => {\n if (settled) return;\n settled = true;\n socket.destroy();\n resolve(result);\n };\n socket.setEncoding('utf8');\n // A conforming mutex writes its identity immediately after accept. A\n // connection that stays open without doing so is ambiguous rather than\n // proven foreign: a conforming same-store process may have accepted the\n // socket and then had its event loop starved. Preserve the independent\n // kernel authority by failing closed on that timeout.\n socket.setTimeout(STORE_MUTEX_PROBE_TIMEOUT_MS, () => finish({ kind: 'uncertain' }));\n socket.on('data', (chunk: string) => {\n raw += chunk;\n if (raw.length > STORE_MUTEX_ID_PREFIX.length + 64 + 1) finish({ kind: 'foreign-or-gone' });\n });\n socket.once('end', () => {\n const line = raw.trimEnd();\n const identity = line.startsWith(STORE_MUTEX_ID_PREFIX)\n ? line.slice(STORE_MUTEX_ID_PREFIX.length)\n : undefined;\n finish(\n identity && /^[a-f0-9]{64}$/.test(identity)\n ? { kind: 'identity', identity }\n : { kind: 'foreign-or-gone' },\n );\n });\n // The port disappeared between bind failure and connect, or belongs to a\n // non-BYOK listener that reset the probe. Neither can be the current\n // transition authority; the owner/reclaim records remain the durable\n // second authority before any lease is returned.\n socket.once('error', () => finish({ kind: 'foreign-or-gone' }));\n });\n}\n\nasync function acquireStoreMutex(canonicalStoreDir: string): Promise<LivenessListener> {\n const identity = storeMutexIdentity(canonicalStoreDir);\n for (let attempt = 0; attempt < STORE_MUTEX_PORT_CANDIDATES; attempt += 1) {\n const server: Server = createServer((socket) => socket.end(`${STORE_MUTEX_ID_PREFIX}${identity}\\n`));\n const port = storeMutexPort(identity, attempt);\n try {\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen({ host: '127.0.0.1', port, exclusive: true }, () => {\n server.removeListener('error', reject);\n resolve();\n });\n });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'EADDRINUSE') throw err;\n const probe = await probeStoreMutex(port);\n if (probe.kind === 'uncertain' || (probe.kind === 'identity' && probe.identity === identity)) {\n throw new DaemonOwnerActiveError('unknown');\n }\n continue;\n }\n server.unref();\n let closed = false;\n return {\n port,\n close: () =>\n new Promise<void>((resolve, reject) => {\n if (closed) {\n resolve();\n return;\n }\n closed = true;\n server.close((err) => (err ? reject(err) : resolve()));\n }),\n };\n }\n throw new DaemonOwnerActiveError('unknown');\n}\n\nasync function reclaimExistsAndIsActive(reclaimPath: string): Promise<boolean> {\n let stat: Awaited<ReturnType<typeof fs.stat>>;\n try {\n stat = await fs.lstat(reclaimPath);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return false;\n throw err;\n }\n if (!stat.isFile()) throw new Error('store mutation reclaim marker is not a regular file');\n const owner = await readOwner(reclaimPath);\n if (owner) return processOwnsRecord(owner);\n // A marker without the complete PID + process-start identity contract is\n // malformed, never an alternate compatibility authority. Keep only a short\n // fail-closed grace for a creator that may have crashed mid-publication.\n return Date.now() - stat.mtimeMs <= RECLAIM_MALFORMED_GRACE_MS;\n}\n\nasync function createOwner(filePath: string, record: OwnerRecord): Promise<boolean> {\n const tempPath = `${filePath}.${record.pid}.${record.nonce}.tmp`;\n let handle: Awaited<ReturnType<typeof fs.open>> | undefined;\n try {\n handle = await fs.open(tempPath, 'wx', 0o600);\n await handle.writeFile(`${JSON.stringify(record)}\\n`, 'utf8');\n await handle.chmod(0o600);\n await handle.sync();\n await handle.close();\n try {\n await fs.link(tempPath, filePath);\n return true;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'EEXIST') return false;\n throw err;\n }\n } finally {\n await handle?.close().catch(() => undefined);\n await fs.rm(tempPath, { force: true }).catch(() => undefined);\n }\n}\n\n/**\n * Cross-process, fail-closed ownership for store mutations that must never\n * race a daemon. A separate exclusive reclaim file serializes stale-owner recovery so two\n * starters cannot accidentally rename each other's newly-acquired lease.\n */\nexport async function acquireDaemonOwner(\n storeDir: string,\n role: OwnerRecord['role'],\n clock: () => Date = () => new Date(),\n): Promise<DaemonOwnerLease> {\n await ensureSecureDir(storeDir);\n // Resolve aliases before deriving the kernel mutex identity. `ownerPath`\n // may still be reached through the operator-supplied spelling below, but a\n // symlink/junction alias and the canonical directory must contend for the\n // same transition mutex or they could otherwise run two stale-owner\n // reclaim sequences against the same underlying pathnames.\n const canonicalStoreDir = await fs.realpath(storeDir);\n // The mutex closes the stale-owner/reclaim TOCTOU: only one conforming\n // process can inspect, remove and republish these pathnames at a time. It is\n // retained for the full lease so another process cannot pass the pathname\n // checks during the small owner-file publication/release windows.\n const mutex = await acquireStoreMutex(canonicalStoreDir);\n let liveness: LivenessListener | undefined;\n try {\n liveness = await createLivenessListener();\n } catch (err) {\n await mutex.close().catch(() => undefined);\n throw err;\n }\n const ownerPath = path.join(storeDir, DAEMON_OWNER_FILENAME);\n const reclaimPath = path.join(storeDir, RECLAIM_FILENAME);\n const record: OwnerRecord = {\n version: 2,\n pid: process.pid,\n nonce: randomUUID(),\n role,\n acquiredAt: clock().toISOString(),\n processStartedAt: SELF_PROCESS_STARTED_AT,\n livenessPort: liveness.port,\n };\n\n try {\n for (;;) {\n if (await reclaimExistsAndIsActive(reclaimPath)) {\n throw new Error('store mutation lease is being reclaimed; retry after the current operation finishes');\n }\n await fs.rm(reclaimPath, { force: true });\n\n if (await createOwner(ownerPath, record)) {\n let released = false;\n return {\n release: async () => {\n if (released) return;\n const current = await readOwner(ownerPath);\n if (current?.nonce !== record.nonce) {\n throw new Error('store mutation lease identity changed before release');\n }\n await fs.rm(ownerPath);\n released = true;\n try {\n await liveness.close();\n } finally {\n await mutex.close();\n }\n },\n };\n }\n\n const existing = await readOwner(ownerPath);\n if (existing && (await processOwnsRecord(existing))) throw new DaemonOwnerActiveError(existing.role);\n\n if (!(await createOwner(reclaimPath, record))) {\n throw new Error('store mutation lease is being reclaimed; retry after the current operation finishes');\n }\n try {\n const rechecked = await readOwner(ownerPath);\n if (rechecked && (await processOwnsRecord(rechecked))) throw new DaemonOwnerActiveError(rechecked.role);\n if (rechecked || (await fs.stat(ownerPath).then(() => true, (err: NodeJS.ErrnoException) => {\n if (err.code === 'ENOENT') return false;\n throw err;\n }))) {\n await fs.rm(ownerPath);\n }\n } finally {\n const currentReclaim = await readOwner(reclaimPath);\n if (currentReclaim?.nonce === record.nonce) await fs.rm(reclaimPath, { force: true });\n }\n }\n } catch (err) {\n await liveness.close().catch(() => undefined);\n await mutex.close().catch(() => undefined);\n throw err;\n }\n}\n","import type { RuntimeCapabilities as ProtocolRuntimeCapabilities } from '@byok-sdk/protocol';\nimport type { RuntimeCapabilities } from '../types';\n\n/**\n * Maps a `RuntimeAdapter`'s own internal `capabilities()` result\n * (`../types.ts`'s `RuntimeCapabilities` — `{steer, resume,\n * approvalInteractive, permissionModes}`, always-required fields) onto the\n * wire's `RuntimeCapabilities` shape (`@byok-sdk/protocol` — the same field names,\n * but all-optional).\n *\n * Every field, `approvalInteractive` included, is a pure passthrough of the\n * adapter's own self-report: the adapter is the single source of truth for\n * what its runtime can do, and this function does no interpretation of its\n * own. Previously `approvalInteractive` was hardcoded `false` at the sole\n * caller, which had gone stale — as of M4 Phase 3 claude genuinely does\n * support interactive approval, via `--permission-prompt-tool` routing\n * `ClaudeSession.resolveApproval` into the local out-of-process MCP approval\n * channel (`bin/byok-approval-mcp.ts`) under `policy.mode: 'confirm'` (see\n * docs/protocol.md §5.1/§11.2) — so the wire advertised a capability claim no\n * adapter owned. pi and codex report `false` for the same honest reason they\n * always did: neither has any notion of pausing for approval\n * (`resolveApproval()` throws unconditionally for both — see `../types.ts`'s\n * `Session.resolveApproval` doc comment).\n *\n * This lives in its own module, rather than beside either of its two callers,\n * because those two callers sit on opposite sides of an import edge:\n * `create-daemon.ts` imports `task-runner.ts`, so exporting the mapper from\n * `create-daemon.ts` would make `task-runner.ts` import back into it and close\n * a cycle. A leaf module with no local imports beyond `../types` is the one\n * place both can reach.\n *\n * The connection-level `interactive-approval` flag (`CAPABILITY_FLAGS`,\n * `@byok-sdk/protocol`) is a separate, connection-scoped signal and is NOT derived\n * from this: `create-daemon.ts`'s `computeCapabilities` keeps its own\n * semantics.\n */\nexport function toRuntimeInfoCapabilities(caps: RuntimeCapabilities): ProtocolRuntimeCapabilities {\n return {\n steer: caps.steer,\n resume: caps.resume,\n approvalInteractive: caps.approvalInteractive,\n permissionModes: caps.permissionModes,\n };\n}\n","import { promises as fs } from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport path from 'node:path';\nimport { atomicWriteFile } from '../util/atomic-write';\n\n/**\n * Persists the highest processed server->daemon envelope `seq` per\n * (server, device) pair (protocol §9, at-least-once redelivery), so a\n * restarted daemon can send an accurate `conn.hello.cursor` and the server\n * can skip re-delivering envelopes it already knows were handled. Keyed by a\n * hash of `serverUrl` + `deviceId` together (not just `serverUrl`) so\n * filenames stay filesystem-safe regardless of scheme/port/path.\n *\n * Finding F5 (stale cursor across re-pair): `POST /byok/pair` always mints a\n * brand new `deviceId` (see `packages/server/src/http.ts`), including on a\n * re-pair against the same `serverUrl` (e.g. recovering from revocation,\n * protocol §6.3). A cursor keyed by `serverUrl` alone would hand the fresh\n * device's very first connection a stale, unrelated cursor value left over\n * from whatever device previously used this URL — the new device's own\n * server-side outbox starts its `seq` counter back at 1, so that stale\n * cursor would make the server's redelivery filter (`seq > cursor`) throw\n * away every legitimate envelope sent to it. Keying by the pair means a new\n * deviceId always starts with a genuinely fresh (absent) cursor entry;\n * `clear()` additionally lets `create-daemon.ts`'s `pair()` proactively wipe\n * the previous device's entry for this `serverUrl` as a hygiene measure.\n */\nexport class CursorStore {\n constructor(private readonly storeDir: string) {}\n\n private fileFor(serverUrl: string, deviceId: string): string {\n const key = createHash('sha256').update(`${serverUrl}::${deviceId}`).digest('hex').slice(0, 32);\n return path.join(this.storeDir, `cursor-${key}.json`);\n }\n\n async load(serverUrl: string, deviceId: string): Promise<number | undefined> {\n let raw: string;\n try {\n raw = await fs.readFile(this.fileFor(serverUrl, deviceId), 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw err;\n }\n try {\n const parsed = JSON.parse(raw) as { cursor?: unknown };\n const v = parsed.cursor;\n // Wave 2 hardening: a corrupt/tampered/hand-edited cursor file (a\n // negative number, a float, NaN/Infinity via a prior bad write, etc.)\n // must not be trusted as a redelivery cursor — reporting a bogus value\n // as `conn.hello.cursor` could make the server's `seq > cursor` filter\n // behave unpredictably. Falling back to `undefined` (treated the same\n // as \"no cursor file yet\") is always safe under at-least-once delivery\n // (protocol §9): worst case, more gets redelivered than strictly\n // necessary, never less. Mirrors the nonnegative-integer guard Wave 1\n // already added server-side for `EventsPollQuerySchema`/`GET\n // /byok/events`'s `cursor` query param (`http.ts`) — this is the\n // client-file half of the same hardening.\n return typeof v === 'number' && Number.isInteger(v) && v >= 0 ? v : undefined;\n } catch {\n return undefined;\n }\n }\n\n async save(serverUrl: string, deviceId: string, cursor: number): Promise<void> {\n const file = this.fileFor(serverUrl, deviceId);\n await fs.mkdir(path.dirname(file), { recursive: true, mode: 0o700 });\n // Atomic (temp file + rename) so a `load()` racing an in-flight `save()`\n // (e.g. redelivery bookkeeping alongside a concurrent reconnect) never\n // observes a torn/partial file and falls back to `undefined` for a\n // cursor that was, in fact, already durably persisted — see\n // `util/atomic-write.ts`.\n await atomicWriteFile(file, JSON.stringify({ cursor }));\n }\n\n /** Remove any persisted cursor for (serverUrl, deviceId) — a no-op if none exists. Called from `pair()` (finding F5) so a device that's about to be replaced never leaves a cursor a future, unrelated device could somehow inherit. */\n async clear(serverUrl: string, deviceId: string): Promise<void> {\n await fs.rm(this.fileFor(serverUrl, deviceId), { force: true });\n }\n}\n","import {\n partitionAgentEvents,\n TASK_TRANSITIONS,\n type AgentEvent,\n type BlobRef,\n type Envelope,\n type RuntimeInfo,\n type TaskState,\n} from '@byok-sdk/protocol';\nimport type { ConnectionState } from './ws-transport';\n\n/**\n * M3-2a: local observability for the daemon — the seam a CLI (M3-2b) drives a\n * live task feed, a task list, and approve/reject/unpair from, all LOCALLY\n * against a running daemon (no SaaS-side polling required).\n *\n * Sourcing, without editing `task-runner.ts`: `TaskRunner` never calls\n * anything in this file directly and has no notion it exists. Every\n * task-lifecycle transition it makes is already observable from OUTSIDE the\n * class through two seams `create-daemon.ts` itself owns and constructs:\n *\n * - `TaskRunnerDeps.send` (the callback `TaskRunner` calls for every\n * `task.claim` / `task.started` / `task.progress` / `task.artifact` /\n * `task.await_approval` / `task.complete` / `task.fail` / `task.decline` /\n * `task.cancelled` it ever emits) — `create-daemon.ts` already builds this\n * closure itself (`send: (envelope) => connection?.send(envelope)`); this\n * module just gets a chance to look at the same envelope before it goes\n * out. See `handleOutboundEnvelope`.\n * - `ConnectionManagerOptions.onEnvelope`/`onStateChange` — likewise already\n * `create-daemon.ts`'s own closures (`(envelope) =>\n * runner?.handleEnvelope(envelope)`, `(state) => { connectionState = state;\n * }`). `onEnvelope` additionally exposes the raw INBOUND `task.offer` — the\n * one event with no corresponding outbound envelope of its own — see\n * `handleInboundEnvelope`.\n *\n * Neither seam required adding anything to `TaskRunnerDeps`/`TaskRunner`\n * itself: both were already plain functions `create-daemon.ts` constructs,\n * so wrapping them (call this module first, then the real behavior,\n * unchanged) is the entire integration.\n */\n\n/** Every local event kind this daemon can emit — see {@link DaemonEvent}. */\nexport type DaemonEventKind = DaemonEvent['kind'];\n\nexport type DaemonEvent =\n | { kind: 'offered'; ts: string; taskId: string; runtime?: string }\n | { kind: 'claimed'; ts: string; taskId: string; claimedRuntime?: string }\n | { kind: 'started'; ts: string; taskId: string }\n /** One per normalized `AgentEvent` (not one per `task.progress` batch) — matches \"a live task feed\" better than re-exposing the wire's own batching. */\n | { kind: 'progress'; ts: string; taskId: string; event: AgentEvent }\n | { kind: 'artifact'; ts: string; taskId: string; name: string; contentType: string; inline?: string; blobRef?: BlobRef }\n /**\n * Finding F4: `approvalId` is populated whenever `TaskRunner` dispatched\n * this approval THROUGH the normal `requestApproval`/`onApprovalDispatched`\n * path (see `noteApprovalDispatched`) — `undefined` only for a\n * hypothetical caller of `handleOutboundEnvelope` that never went through\n * that hook (there is no other producer of `task.await_approval` today).\n * This is the one piece of information an operator needs to actually\n * call `approve`/`reject` (or the `approvals` CLI command) against this\n * specific pending decision — before this fix, nothing surfaced it\n * outside the control socket's `approvals.list`/`approvals.request`\n * internals.\n */\n | { kind: 'awaiting-approval'; ts: string; taskId: string; summary: string; approvalId?: string }\n | { kind: 'completed'; ts: string; taskId: string; summary: string; sessionRef: string }\n /**\n * Covers BOTH a post-claim `task.fail` and a pre-claim `task.decline` —\n * `preClaim` distinguishes the two. This mirrors the protocol's own\n * `Offered -> Failed` convention (docs/protocol.md \"Declined vs. Failed\";\n * `TASK_TRANSITIONS`, `@byok-sdk/protocol`): a decline and a failure are the\n * same outcome from a dispatcher's point of view, so this module doesn't\n * invent a parallel `declined` kind the wire model itself doesn't have.\n */\n | { kind: 'failed'; ts: string; taskId: string; reason: string; retryable: boolean; preClaim?: boolean }\n | { kind: 'cancelled'; ts: string; taskId: string; reason?: string }\n | { kind: 'connection'; ts: string; state: ConnectionState }\n | { kind: 'paired'; ts: string; deviceId: string }\n | { kind: 'unpaired'; ts: string }\n | { kind: 'runtimes-detected'; ts: string; runtimes: RuntimeInfo[] }\n /** M4 Phase 2: the control socket's `shutdown` RPC was invoked — emitted once, before this daemon starts tearing itself down, so it lands in the audit log via the exact same subscribe->append plumbing every other event already uses (see `bin/commands/start.ts`). Informational only — do NOT gate any teardown decision on this event; see `shutdown-complete`. */\n | { kind: 'shutdown-requested'; ts: string; reason: string }\n /**\n * M4 Phase 2: emitted once, AFTER the control-socket-driven shutdown\n * sequence has fully finished — active tasks reported failed over the\n * (at that point still-open) connection, then the connection/control\n * socket actually closed (see `create-daemon.ts`'s `performControlShutdown`,\n * which calls this last). This is the event `bin/commands/start.ts` must\n * wait for before treating the daemon as done: reacting to\n * `shutdown-requested` instead would race `daemon.stop()` against the\n * still-in-flight `task.fail` send and silently drop it (confirmed via a\n * real regression — see `daemon-control-socket.test.ts`).\n *\n * Finding F5(b): `undeliveredOutboxCount`, when defined, is the honest\n * post-drain read of `ConnectionManager.outboxLength()` — 0 means the\n * bounded outbox drain (see `ConnectionManager.stop`) genuinely finished\n * before the connection closed; a positive number means that many\n * envelopes (almost certainly including a `task.fail`\n * `shutdownActiveTasks` just enqueued) never actually left the outbox.\n * `undefined` only for a hypothetical caller of `noteShutdownComplete`\n * that didn't pass one — `create-daemon.ts`'s own `performControlShutdown`\n * (the only real producer of this event) always does.\n */\n | { kind: 'shutdown-complete'; ts: string; reason: string; undeliveredOutboxCount?: number }\n /**\n * M4 Phase 3 hardening: a wire `task.approve`/`task.reject` (or this\n * device's own redelivered copy of one) arrived for an out-of-band\n * approval a DIFFERENT, faster path (a racing local `approvals.resolve`\n * over the control socket, or this exact decision arriving twice) had\n * already resolved — `TaskRunner.handleApprove`/`handleReject`\n * (`task-runner.ts`) emit this instead of failing the task a second time.\n * Audit-only: never gates any teardown/task-state decision, purely a\n * record that a stale message was seen and correctly ignored — see\n * `NoPendingApprovalError`'s own doc comment (`task-runner.ts`) for the\n * full race this closes.\n */\n | { kind: 'stale-approval-decision'; ts: string; taskId: string; decision: 'approve' | 'reject'; reason?: string }\n | { kind: 'git-workspace'; ts: string; taskId: string; workspaceId: string; phase: string; headChanged?: boolean; commitsSinceBaseline?: number; dirty?: { staged: number; unstaged: number; untracked: number; conflicted: number }; errorCategory?: string };\n\nexport type DaemonEventListener = (event: DaemonEvent) => void;\nexport type Unsubscribe = () => void;\n\n/** `daemon.tasks()`'s per-task view — current local state + whatever summary/outcome was last reported for it. */\nexport interface DaemonTaskInfo {\n taskId: string;\n state: TaskState;\n runtime?: string;\n /** Actual runtime selected for this task, as reported by the outbound `task.claim` payload. Distinct from `runtime`, which remains the requested offer runtime. */\n claimedRuntime?: string;\n /** Last known human-readable text for this task's current state: an await-approval summary, a complete summary, or a fail/cancel reason — whichever was most recently reported. */\n summary?: string;\n /** Only set once this task has actually reached `task.complete`. */\n sessionRef?: string;\n /** `true` only when `state === 'Failed'` resulted from a pre-claim `task.decline` rather than a post-claim `task.fail` — see the `DaemonEvent` `failed` variant's doc comment. */\n declined?: boolean;\n updatedAt: string;\n}\n\n/**\n * M3-B parity (see `task-runner.ts`'s `MAX_TRACKED_TASK_IDS` doc comment,\n * same rationale): this daemon is meant to run as a long-lived background\n * service, so a per-task registry that only ever grows is a slow memory\n * leak. Only TERMINAL entries (`Complete`/`Failed`/`Cancelled`) are ever\n * evicted, oldest first — active entries are never removed here, the same\n * way `TaskRunner.tasks` itself is bounded by real concurrency rather than\n * an explicit cap.\n */\nexport const MAX_TRACKED_TASKS = 2000;\n\nfunction isTerminalState(state: TaskState): boolean {\n // Derived from TASK_TRANSITIONS (single authority — docs/protocol.md,\n // `task-state.ts`'s own doc comment: \"Complete / Failed / Cancelled are\n // terminal (no outgoing edges)\") rather than a hand-maintained list that\n // could drift from it.\n return TASK_TRANSITIONS[state].length === 0;\n}\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\n/**\n * Owns both halves of the local observability surface: the pub/sub\n * (`subscribe`/`emit`) and the derived per-task registry (`tasks`). A plain\n * `Set<listener>` with `subscribe` returning its own removal closure — not\n * `node:events`' `EventEmitter` — keeps unsubscribe trivially leak-free\n * (delete-by-reference, no string event names, no listener-count footguns)\n * and keeps `DaemonEvent` a single typed union instead of a per-event-name\n * overload table.\n */\nexport class DaemonObserver {\n private readonly listeners = new Set<DaemonEventListener>();\n private readonly taskInfo = new Map<string, DaemonTaskInfo>();\n /**\n * Finding F4: `approvalId` for a taskId's NEXT `task.await_approval`,\n * stashed by `noteApprovalDispatched` and consumed (read + deleted) the\n * moment `handleOutboundEnvelope`'s `task.await_approval` case actually\n * emits the corresponding `awaiting-approval` event — see that hook's own\n * doc comment for why this is always populated first (both calls happen\n * synchronously, in that order, from `TaskRunner.dispatchApproval`).\n * Read-and-delete keeps this self-bounding: an entry never outlives the\n * one event it was stashed for, so this can never leak across a\n * long-lived daemon's lifetime the way an evict-on-schedule cache would\n * need explicit bookkeeping to avoid.\n */\n private readonly pendingApprovalIdByTask = new Map<string, string>();\n\n subscribe(listener: DaemonEventListener): Unsubscribe {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /** Current locally-known tasks, in first-seen order. */\n tasks(): DaemonTaskInfo[] {\n return [...this.taskInfo.values()];\n }\n\n /**\n * Feed a raw INBOUND (server -> daemon) envelope. Deliberately narrow: only\n * `task.offer` produces a local event here — every other inbound type\n * (`task.cancel`/`task.steer`/`task.approve`/`task.reject`) is a\n * best-effort notification whose OWN observable effect already surfaces\n * through the daemon's outbound envelopes (`task.cancelled`, `task.progress`\n * resuming, `task.fail`, ...) — see `handleOutboundEnvelope`, which is\n * where those are actually reported from.\n */\n handleInboundEnvelope(envelope: Envelope): void {\n if (envelope.type !== 'task.offer') return;\n const taskId = envelope.task_id;\n\n // Redelivery guard (protocol §9, at-least-once delivery): this observer\n // has no visibility into TaskRunner's own private `finishedTaskIds`/\n // `this.tasks` redelivery dedup, so it mirrors the same idempotency\n // independently using its OWN record instead — any taskId this observer\n // already has an entry for was necessarily already offered once before\n // (an entry can only ever be created here or in `handleOutboundEnvelope`,\n // both of which only ever fire for a taskId TaskRunner itself has already\n // seen), so a second `task.offer` for it is never \"the first time\" here\n // either. Without this, a stalled-cursor re-poll redelivering an\n // already-succeeded offer (`task-runner.ts`'s own doc comment on\n // `finishedTaskIds` describes exactly this scenario) would locally\n // regress a finished task back to `Offered`.\n if (this.taskInfo.has(taskId)) return;\n\n this.upsertTask(taskId, { state: 'Offered', runtime: envelope.payload.runtime });\n this.emit({ kind: 'offered', ts: nowIso(), taskId, runtime: envelope.payload.runtime });\n }\n\n /**\n * Feed a raw OUTBOUND (daemon -> server) envelope — this is where every\n * task-lifecycle local event actually comes from: `TaskRunner` already\n * calls `deps.send(...)` for each of these at exactly the moment its own\n * state machine decides the transition happened.\n */\n handleOutboundEnvelope(envelope: Envelope): void {\n const ts = nowIso();\n switch (envelope.type) {\n case 'task.claim': {\n const taskId = envelope.task_id;\n const claimedRuntime = envelope.payload.runtime;\n this.upsertTask(taskId, {\n state: 'Claimed',\n ...(claimedRuntime !== undefined ? { claimedRuntime } : {}),\n });\n this.emit({ kind: 'claimed', ts, taskId, ...(claimedRuntime !== undefined ? { claimedRuntime } : {}) });\n return;\n }\n case 'task.started': {\n const taskId = envelope.task_id;\n this.upsertTask(taskId, { state: 'Running' });\n this.emit({ kind: 'started', ts, taskId });\n return;\n }\n case 'task.progress': {\n const taskId = envelope.task_id;\n this.upsertTask(taskId, { state: 'Running' });\n // `known`-only (`partitionAgentEvents`, `@byok-sdk/protocol`): an\n // unrecognized-type event is an opaque forward-compat placeholder\n // (agent-event.ts) this daemon can't meaningfully normalize locally\n // either — skip it here the same way `TaskRunner`'s own consumers\n // are told to.\n const { known } = partitionAgentEvents(envelope.payload.events);\n for (const event of known) {\n this.emit({ kind: 'progress', ts, taskId, event });\n }\n return;\n }\n case 'task.artifact': {\n const taskId = envelope.task_id;\n this.emit({\n kind: 'artifact',\n ts,\n taskId,\n name: envelope.payload.name,\n contentType: envelope.payload.contentType,\n inline: envelope.payload.inline,\n blobRef: envelope.payload.blobRef,\n });\n return;\n }\n case 'task.await_approval': {\n const taskId = envelope.task_id;\n // Finding F4: read-and-delete — see `pendingApprovalIdByTask`'s own\n // doc comment for why this never needs a separate eviction policy.\n const approvalId = this.pendingApprovalIdByTask.get(taskId);\n this.pendingApprovalIdByTask.delete(taskId);\n this.upsertTask(taskId, { state: 'AwaitApproval', summary: envelope.payload.summary });\n this.emit({ kind: 'awaiting-approval', ts, taskId, summary: envelope.payload.summary, approvalId });\n return;\n }\n case 'task.complete': {\n const taskId = envelope.task_id;\n this.upsertTask(taskId, {\n state: 'Complete',\n summary: envelope.payload.summary,\n sessionRef: envelope.payload.sessionRef,\n });\n this.emit({\n kind: 'completed',\n ts,\n taskId,\n summary: envelope.payload.summary,\n sessionRef: envelope.payload.sessionRef,\n });\n return;\n }\n case 'task.fail': {\n const taskId = envelope.task_id;\n const retryable = envelope.payload.retryable ?? false;\n this.upsertTask(taskId, { state: 'Failed', summary: envelope.payload.reason });\n this.emit({ kind: 'failed', ts, taskId, reason: envelope.payload.reason, retryable });\n return;\n }\n case 'task.decline': {\n const taskId = envelope.task_id;\n const retryable = envelope.payload.retryable ?? false;\n this.upsertTask(taskId, { state: 'Failed', summary: envelope.payload.reason, declined: true });\n this.emit({ kind: 'failed', ts, taskId, reason: envelope.payload.reason, retryable, preClaim: true });\n return;\n }\n case 'task.cancelled': {\n const taskId = envelope.task_id;\n this.upsertTask(taskId, { state: 'Cancelled', summary: envelope.payload.reason });\n this.emit({ kind: 'cancelled', ts, taskId, reason: envelope.payload.reason });\n return;\n }\n default:\n return; // conn.* and every server->daemon-only type never flow through the outbound `send` hook\n }\n }\n\n noteConnectionState(state: ConnectionState): void {\n this.emit({ kind: 'connection', ts: nowIso(), state });\n }\n\n notePaired(deviceId: string): void {\n this.emit({ kind: 'paired', ts: nowIso(), deviceId });\n }\n\n noteUnpaired(): void {\n this.emit({ kind: 'unpaired', ts: nowIso() });\n }\n\n noteRuntimesDetected(runtimes: RuntimeInfo[]): void {\n this.emit({ kind: 'runtimes-detected', ts: nowIso(), runtimes });\n }\n\n /** M4 Phase 2: see the `shutdown-requested` `DaemonEvent` variant's own doc comment. */\n noteShutdownRequested(reason: string): void {\n this.emit({ kind: 'shutdown-requested', ts: nowIso(), reason });\n }\n\n /** M4 Phase 2: see the `shutdown-complete` `DaemonEvent` variant's own doc comment (finding F5(b): `undeliveredOutboxCount`). */\n noteShutdownComplete(reason: string, undeliveredOutboxCount?: number): void {\n this.emit({ kind: 'shutdown-complete', ts: nowIso(), reason, undeliveredOutboxCount });\n }\n\n /** M4 Phase 3 hardening: see the `stale-approval-decision` `DaemonEvent` variant's own doc comment. */\n noteStaleApprovalDecision(taskId: string, decision: 'approve' | 'reject', reason?: string): void {\n this.emit({ kind: 'stale-approval-decision', ts: nowIso(), taskId, decision, reason });\n }\n\n noteGitWorkspace(event: {\n taskId: string;\n workspaceId: string;\n phase: string;\n headChanged?: boolean;\n commitsSinceBaseline?: number;\n dirty?: { staged: number; unstaged: number; untracked: number; conflicted: number };\n errorCategory?: string;\n }): void {\n this.emit({ kind: 'git-workspace', ts: nowIso(), ...event });\n }\n /**\n * Finding F4: wired from `TaskRunnerDeps.onApprovalDispatched`, called\n * synchronously by `TaskRunner.dispatchApproval` BEFORE its own\n * `deps.send(createEnvelope('task.await_approval', ...))` — stashes\n * `approvalId` so `handleOutboundEnvelope`'s `task.await_approval` case\n * (triggered by that very `send` call) can attach it to the\n * `awaiting-approval` `DaemonEvent` it emits. Never emits anything\n * itself — purely a handoff, same as `upsertTask`'s bookkeeping role for\n * other events.\n */\n noteApprovalDispatched(taskId: string, approvalId: string): void {\n this.pendingApprovalIdByTask.set(taskId, approvalId);\n }\n\n private upsertTask(\n taskId: string,\n patch: Partial<Pick<DaemonTaskInfo, 'runtime' | 'claimedRuntime' | 'summary' | 'sessionRef' | 'declined'>> & { state: TaskState },\n ): void {\n const existing = this.taskInfo.get(taskId);\n const next: DaemonTaskInfo = {\n ...existing,\n ...patch,\n taskId,\n updatedAt: nowIso(),\n };\n this.taskInfo.set(taskId, next);\n this.evictIfNeeded();\n }\n\n /**\n * Finding P2/#11 (observer half): the \"no terminal entry to evict\" branch\n * used to just give up and leave the registry unbounded for as long as\n * every tracked task stayed nonterminal (many concurrent/stuck offers that\n * never reach Complete/Failed/Cancelled — the exact case this cap exists\n * for, since a normal quickly-resolving workload always has terminal\n * entries to evict well before this). Falling back to \"never evict\" here\n * defeats the whole point of `MAX_TRACKED_TASKS`. Fix: fall back to\n * evicting the OLDEST entry regardless of state (same insertion-order\n * idiom as everywhere else this file/`task-runner.ts` bound a collection),\n * logged since it's a real, if rare, observability loss — this registry is\n * a local READ-MODEL only (see the module doc comment), never consulted by\n * `TaskRunner`'s own state machine, so evicting a still-active task's\n * entry here can't affect that task's actual execution — it only means\n * `tasks()`/a CLI's task list can no longer show it until it reports\n * another transition (which re-inserts it via `upsertTask`).\n */\n private evictIfNeeded(): void {\n if (this.taskInfo.size <= MAX_TRACKED_TASKS) return;\n for (const [taskId, info] of this.taskInfo) {\n if (isTerminalState(info.state)) {\n this.taskInfo.delete(taskId);\n return;\n }\n }\n const oldest = this.taskInfo.keys().next().value;\n if (oldest !== undefined) {\n console.warn(\n `[byok/client] daemon task registry exceeded ${MAX_TRACKED_TASKS} entries with none terminal — evicting the oldest nonterminal task (${oldest}) from local observability only (its actual execution is unaffected)`,\n );\n this.taskInfo.delete(oldest);\n }\n }\n\n /**\n * Listener errors are caught here so a broken subscriber (e.g. a CLI's\n * rendering bug) can never propagate back into the real send/onEnvelope\n * path this module wraps — see this file's own module doc comment.\n *\n * Finding #6: `DaemonEventListener` is typed `(event: DaemonEvent) =>\n * void`, but TypeScript's structural typing does not stop a caller from\n * subscribing an `async` function (or anything else returning a promise)\n * where a void-returning callback is expected — nothing here ever\n * validates that at runtime. The `try`/`catch` below only ever catches a\n * SYNCHRONOUS throw; an async listener doesn't throw synchronously, it\n * RETURNS an already-rejected (or later-rejecting) promise, which sails\n * straight past that catch. Left unhandled, that promise's rejection\n * becomes an `unhandledRejection` on the process — which, depending on\n * the host's Node version/flags, can crash the entire daemon over one\n * subscriber's bug (e.g. a CLI's own progress renderer awaiting something\n * that throws). Fix: treat the listener's return value as \"possibly a\n * promise\" regardless of its declared type, and attach a `.catch` so a\n * later rejection is caught and logged exactly like a synchronous throw,\n * never left to become unhandled. This call stays synchronous itself\n * (never `await`s a listener) — `emit` is invoked from the send/cursor\n * path (`handleOutboundEnvelope`/`handleInboundEnvelope`, wired in\n * directly from `create-daemon.ts`'s `send`/`onEnvelope` closures) and\n * must never make a subscriber's own async work a precondition for\n * cursor advancement or the next envelope being processed.\n */\n private emit(event: DaemonEvent): void {\n for (const listener of this.listeners) {\n try {\n const result = listener(event) as unknown;\n if (result instanceof Promise) {\n result.catch((err: unknown) => {\n console.error('[byok/client] daemon event listener rejected (async)', err);\n });\n }\n } catch (err) {\n console.error('[byok/client] daemon event listener threw', err);\n }\n }\n }\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\n/** What's recoverable for a given `sessionRef` — see the class doc comment. */\nexport interface SessionWorkspaceRecord {\n workspaceDir: string;\n /**\n * The underlying runtime's own resumable session identifier.\n */\n runtimeSessionId: string;\n /** Additive workspace kind; missing legacy values remain plain. */\n workspaceKind?: 'plain' | 'git';\n /** Opaque private Git workspace ledger identifier. */\n gitWorkspaceId?: string;\n}\n\ninterface StoredEntry {\n workspaceDir: string;\n runtimeSessionId: string;\n workspaceKind?: 'plain' | 'git';\n gitWorkspaceId?: string;\n updatedAt: string;\n}\n\ntype StoredShape = Record<string, StoredEntry>;\n\nfunction isStoredShape(value: unknown): value is StoredShape {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isStoredEntry(value: unknown): value is StoredEntry {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as Partial<StoredEntry>).workspaceDir === 'string' &&\n typeof (value as Partial<StoredEntry>).runtimeSessionId === 'string' &&\n ((value as Partial<StoredEntry>).workspaceKind === undefined || (value as Partial<StoredEntry>).workspaceKind === 'plain' || (value as Partial<StoredEntry>).workspaceKind === 'git') &&\n ((value as Partial<StoredEntry>).gitWorkspaceId === undefined || typeof (value as Partial<StoredEntry>).gitWorkspaceId === 'string')\n );\n}\n\n/**\n * Monotonic per-process suffix for `save()`'s temp file (never\n * `Date.now()`/`Math.random()` — both can collide under a mocked/frozen\n * clock or a restricted-entropy sandbox, and a suffix collision between two\n * concurrent `save()` calls would defeat the whole point of writing to a\n * private temp path). Combined with `process.pid` below so two\n * `SessionWorkspaceStore` instances in the same process (e.g. a test's own\n * read-only \"storeView\" alongside the daemon's real instance, both pointed\n * at the same `storeDir`) never pick the same temp filename, and two\n * separate daemon processes sharing a `storeDir` don't either.\n */\nlet tmpSeq = 0;\n\n/**\n * Persists `sessionRef -> {workspaceDir, runtimeSessionId}` across daemon\n * restarts (finding #3 from the 2026-07-16 live GLM run): a `task.offer`\n * carrying a `sessionRef` this device has previously reported (via a prior\n * task's `task.complete.sessionRef`) reuses that exact workspace directory\n * as the new task's cwd — which is what lets a runtime adapter's own resume\n * mechanism (e.g. pi's `--session <id>`, scoped to the cwd/project a session\n * was created under — see pi-adapter.ts) actually find the session again.\n * An unknown or absent `sessionRef` is simply not in this map, and\n * `task-runner.ts` treats that identically to \"no sessionRef was ever\n * offered\" — fresh workspace, fresh session.\n *\n * One JSON file under `storeDir`, mirroring `DeviceStore`/`CursorStore`'s\n * own persistence style: always read/write straight through to disk, no\n * in-memory cache that could go stale or need invalidating across multiple\n * `TaskRunner`/daemon instances sharing the same `storeDir` (exactly the\n * \"map persisted across daemon restart\" requirement).\n *\n * Two correctness properties `task-runner.ts` depends on, neither of which\n * a bare `fs.writeFile` + independent `fs.readFile` calls actually gives\n * you:\n *\n * 1. **No torn reads.** `record()` is deliberately fire-and-forgotten from\n * `handleOffer` (see its call site) — it must never block `task.started`\n * on a disk write. But a bare `fs.writeFile` is not atomic: it truncates\n * the file before writing the new bytes, so a `get()` racing an\n * in-flight `record()` on another task's offer can `JSON.parse` a\n * half-written file, fail, and silently fall back to `{}` (see `load()`)\n * — resolving what should have been a resume to a fresh workspace.\n * `save()` below instead writes to a private temp file in the same\n * directory and `fs.rename`s it onto the real path, which POSIX\n * guarantees is atomic when both paths share a filesystem (true here —\n * same directory): any concurrent reader sees either the fully-old or\n * fully-new bytes, never a partial write.\n * 2. **No lost updates.** Two `record()` calls for two different\n * `sessionRef`s that overlap (both `load()` the same on-disk snapshot,\n * each mutate their own key into their own in-memory copy, then `save()`\n * back to back) would otherwise let the second `save()` overwrite the\n * first's key with a snapshot that never saw it — each individual\n * `save()` being atomic does not prevent this. `enqueue()` below chains\n * every `get()`/`record()` through one serial promise queue per\n * instance, so no two load-modify-save cycles (or a read and a\n * concurrent write) ever interleave.\n */\nexport class SessionWorkspaceStore {\n private readonly filePath: string;\n\n /**\n * Serial \"mutex\" queue: every `get()`/`record()` chains its work off this\n * promise and replaces it, so operations on this instance always run\n * one-at-a-time, in call order — never interleaved. The queue's own tail\n * is never allowed to reject (a failed task must not wedge every\n * subsequent caller behind a rejected promise); the failure still\n * propagates to that call's own caller via the returned promise.\n */\n private queue: Promise<void> = Promise.resolve();\n\n constructor(storeDir: string) {\n this.filePath = path.join(storeDir, 'session-workspaces.json');\n }\n\n async get(sessionRef: string): Promise<SessionWorkspaceRecord | undefined> {\n return this.enqueue(async () => {\n const all = await this.load();\n const entry = all[sessionRef];\n if (!entry) return undefined;\n return {\n workspaceDir: entry.workspaceDir,\n runtimeSessionId: entry.runtimeSessionId,\n ...(entry.workspaceKind ? { workspaceKind: entry.workspaceKind } : {}),\n ...(entry.gitWorkspaceId ? { gitWorkspaceId: entry.gitWorkspaceId } : {}),\n };\n });\n }\n\n async record(sessionRef: string, entry: SessionWorkspaceRecord): Promise<void> {\n await this.enqueue(async () => {\n const all = await this.load();\n all[sessionRef] = {\n workspaceDir: entry.workspaceDir,\n runtimeSessionId: entry.runtimeSessionId,\n ...(entry.workspaceKind ? { workspaceKind: entry.workspaceKind } : {}),\n ...(entry.gitWorkspaceId ? { gitWorkspaceId: entry.gitWorkspaceId } : {}),\n updatedAt: new Date().toISOString(),\n };\n await this.save(all);\n });\n }\n\n /** See the class doc comment's \"no lost updates\" property. */\n private enqueue<T>(task: () => Promise<T>): Promise<T> {\n const result = this.queue.then(task);\n // Swallow here (not on `result`, which the caller still awaits/rejects\n // on normally) purely so a rejected task doesn't permanently wedge the\n // queue for every operation enqueued after it.\n this.queue = result.then(\n () => undefined,\n () => undefined,\n );\n return result;\n }\n\n private async load(): Promise<StoredShape> {\n let raw: string;\n try {\n raw = await fs.readFile(this.filePath, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return {};\n throw err;\n }\n try {\n const parsed = JSON.parse(raw) as unknown;\n if (!isStoredShape(parsed)) return {};\n const result: StoredShape = {};\n for (const [key, value] of Object.entries(parsed)) {\n if (isStoredEntry(value)) result[key] = value;\n }\n return result;\n } catch {\n // Fail safe on a corrupt/torn file: treat it as empty rather than\n // throwing (see `task-runner.ts`'s `handleOffer`, which must always\n // be able to resolve \"no known workspace\" and continue with a fresh\n // one). `save()`'s atomic rename is what prevents this from actually\n // happening for writes made through this class; this remains only a\n // defense for a file corrupted some other way (hand-edited, an old\n // pre-fix write, etc).\n return {};\n }\n }\n\n private async save(all: StoredShape): Promise<void> {\n const dir = path.dirname(this.filePath);\n await fs.mkdir(dir, { recursive: true, mode: 0o700 });\n // Same directory as the real target (required for `fs.rename` to be\n // atomic on POSIX — same filesystem), and unique per call so two\n // instances/processes racing to save never collide on the same temp\n // path (see `tmpSeq`'s doc comment).\n const tmpPath = `${this.filePath}.${process.pid}-${tmpSeq++}.tmp`;\n try {\n await fs.writeFile(tmpPath, JSON.stringify(all, null, 2), 'utf8');\n await fs.rename(tmpPath, this.filePath);\n } catch (err) {\n await fs.rm(tmpPath, { force: true });\n throw err;\n }\n }\n}\n","/**\n * The daemon's durable local journal port (sprint S3.3 / architecture\n * §12.7.2).\n *\n * The journal is NOT a debug log. It is the correctness precondition for\n * acking the hosted mailbox: the cloud retires a mailbox row when the daemon's\n * next poll carries a cursor past it (§12.7.3 — \"领走即弃\" means *cursor moved\n * past*, not *read*), so the moment the cursor advances over an envelope, that\n * envelope exists nowhere but this machine. Everything in this file exists to\n * make \"the bytes are durable\" a fact the cursor can be gated on.\n *\n * Two shapes here are load-bearing and deliberate:\n *\n * - **Bounded records.** The journal stores reliability metadata and small\n * bounded bytes. Prompts, tool output, artifacts, workspaces, and blobs stay\n * on the filesystem and are referenced, never inlined (§12.7.2). An oversized\n * record is rejected with {@link JournalRecordTooLargeError} rather than\n * silently truncated — a truncated envelope is not the envelope, and a\n * journal that quietly stores something else than what arrived is worse than\n * one that refuses.\n * - **Cleanable categories are a closed set that excludes protected data.**\n * §12.7.2.1's never-auto-delete list (unacked envelopes, Running/\n * AwaitApproval tasks, unconfirmed terminals, anything carrying a recovery\n * marker, user workspaces, provider secrets, quarantine evidence) is\n * enforced by {@link CleanableCategory} not having names for those things,\n * so the cleanup path cannot ask for one. A runtime filter would put the\n * never-delete list one bug away from deleting recovery evidence exactly\n * once, in production.\n */\n\nimport { createHash } from 'node:crypto';\n\n/**\n * The journal's one hash function, shared by every producer so a stored digest\n * and a recomputed one are comparable without a second convention. `sha256:`\n * prefixed because the algorithm has to travel with the value — an unprefixed\n * hex string is a hash of unknown provenance the day this changes.\n */\nexport function journalHash(bytes: string): string {\n return `sha256:${createHash('sha256').update(bytes, 'utf8').digest('hex')}`;\n}\n\n/**\n * Who this daemon is, as recorded on every journal row (§12.7.2's minimum\n * fact set, first three entries). Carried explicitly rather than captured at\n * construction because `deviceId` is only known after `AuthManager`\n * `loadExisting()` resolves, strictly after the journal is built.\n */\nexport interface JournalIdentity {\n readonly tenantId: string;\n readonly productId: string;\n readonly deviceId: string;\n}\n\n/**\n * One inbound envelope, as received from the mailbox and about to be made\n * durable. `bytes` is the canonical v1 encoding (`encodeEnvelope`) of the\n * envelope this daemon parsed — the frozen codec's round-trip guarantee is\n * what makes that a faithful record — and `bytesHash` is its digest, so a\n * later reader can tell a redelivery of the same envelope from a different\n * envelope reusing an id.\n */\nexport interface ReceivedEnvelopeRecord {\n readonly identity: JournalIdentity;\n readonly envelopeId: string;\n /** The envelope's `task_id`, when it carries one. Required whenever {@link opensTask} is true. */\n readonly taskId?: string;\n /** The mailbox `seq` this envelope arrived at — the received cursor (§12.7.2's minimum fact set). */\n readonly seq: number;\n /** Canonical v1 bytes. Bounded — see {@link JournalRecordTooLargeError}. */\n readonly bytes: string;\n /** `sha256:<hex>` over {@link bytes}. */\n readonly bytesHash: string;\n readonly receivedAt: string;\n /**\n * Whether this envelope OPENS a local task record, i.e. whether the same\n * transaction must also create the `journal_task` row §12.7.3 requires\n * (\"v1 bytes 与本机 task record 已在同一个本机 transaction durable append\").\n * The caller decides this from the envelope's own type — it is the one\n * party that already knows, and re-deriving it inside the journal would put\n * a second copy of protocol semantics somewhere it does not belong.\n */\n readonly opensTask: boolean;\n}\n\n/**\n * What {@link LocalTaskJournal.appendEnvelope} hands back. The cursor may\n * advance past {@link seq} once — and only once — this exists.\n */\nexport interface JournalReceipt {\n readonly envelopeId: string;\n readonly seq: number;\n readonly bytesHash: string;\n readonly committedAt: string;\n /**\n * `false` when this exact envelope id was ALREADY durable and this call\n * changed nothing — the redelivery case (§8.3's at-least-once wire means\n * every envelope can arrive twice; a crash between commit and ack\n * guarantees at least one will). A `false` here is a successful, correct\n * outcome, not an error: it says the bytes are durable, which is all the\n * cursor needed to know.\n */\n readonly created: boolean;\n}\n\n/** The admission decision for an offered task, as recorded on `journal_task`. */\nexport interface AdmissionRecord {\n readonly taskId: string;\n readonly admitted: boolean;\n readonly reason?: string;\n readonly retryable?: boolean;\n readonly claimedRuntime?: string;\n /** Digest of the effective policy this task runs under — the policy itself is not stored (bounded records). */\n readonly effectivePolicyHash?: string;\n /** Filesystem reference to the task's workspace. A path, never its contents. */\n readonly workspaceRef?: string;\n readonly decidedAt: string;\n}\n\n/**\n * One local execution-state transition. Idempotent by {@link transitionId}:\n * a replayed transition (recovery re-running a step, a redelivered envelope\n * driving the same move) records nothing new.\n */\nexport interface LocalTransitionRecord {\n readonly transitionId: string;\n readonly taskId: string;\n readonly from?: string;\n readonly to: string;\n readonly occurredAt: string;\n /** Small bounded free-form note. Not a place for tool output. */\n readonly detail?: string;\n}\n\n/** Whether the cloud has confirmed the terminal this daemon produced (§12.7.3's \"terminal 生成后、truth 写入前\" window). */\nexport type TerminalTruthState = 'pending' | 'confirmed' | 'failed';\n\n/**\n * A task's terminal, as it exists locally. The PAYLOAD is not stored — only\n * its hash, plus enough retry state to know whether the cloud has taken it.\n */\nexport interface LocalTerminalRecord {\n readonly taskId: string;\n readonly terminalType: 'complete' | 'failed' | 'cancelled';\n readonly payloadHash: string;\n readonly truthState: TerminalTruthState;\n /** How many times delivery to the cloud has been attempted. */\n readonly attempt: number;\n readonly lastError?: string;\n readonly recordedAt: string;\n}\n\n/** A task the journal knows about that has no terminal and no recovery marker — i.e. one this daemon was in the middle of when it stopped. */\nexport interface RecoverableTask {\n readonly taskId: string;\n readonly envelopeId: string;\n readonly seq: number;\n readonly identity: JournalIdentity;\n readonly localState: string;\n readonly claimedRuntime?: string;\n readonly workspaceRef?: string;\n readonly updatedAt: string;\n}\n\n/**\n * What recovery decided about a task. `interrupted` is the honest default for\n * a daemon restart: local runtime sessions do not survive the process, so the\n * task is recorded as interrupted rather than pretended back into life — the\n * same semantics `GitWorkspaceStore.reconcile()` already applies to a lease\n * whose owner is gone. Nothing here deletes anything; a row that has been\n * through recovery carries a marker, and §12.7.2.1 forbids auto-deleting\n * those.\n */\nexport type RecoveryDisposition = 'resumed' | 'interrupted' | 'abandoned';\n\nexport interface RecoveryOutcome {\n readonly disposition: RecoveryDisposition;\n readonly reason?: string;\n readonly occurredAt?: string;\n}\n\n/**\n * The five storage categories §12.7.2.1 requires to be measured SEPARATELY —\n * the cleanup order and the never-delete list are both category-scoped, so a\n * single \"bytes used\" number cannot drive either.\n */\nexport type StorageCategory = 'journal' | 'cache' | 'log' | 'workspace' | 'quarantine';\n\nexport interface CategoryUsage {\n readonly bytes: number;\n /** `true` when this is a host-reported or sampled figure rather than a measured one. */\n readonly approximate: boolean;\n}\n\nexport interface LocalStorageUsage {\n readonly measuredAt: string;\n readonly totalBytes: number;\n readonly categories: Readonly<Record<StorageCategory, CategoryUsage>>;\n}\n\n/**\n * The categories automatic cleanup may act on, in §12.7.2.1's order. This\n * union is the never-auto-delete list's enforcement: `quarantine`,\n * unacked envelopes, live tasks, unconfirmed terminals, recovery-marked rows,\n * and user-designated workspaces have NO name here, so no cleanup call can\n * name one. Adding a member is therefore a deliberate, reviewable act rather\n * than a filter that silently stops matching.\n */\nexport type CleanableCategory =\n /** Expired upload/download temp files and rebuildable caches. */\n | 'expired-temp'\n /** Rotated logs past their retention. */\n | 'rotated-log'\n /** Journal rows for tasks whose terminal the cloud has confirmed and that carry no recovery marker. */\n | 'confirmed-journal'\n /** Generated workspaces the HOST explicitly marked ephemeral, for tasks already terminal. */\n | 'ephemeral-workspace'\n /** Local artifacts with no remaining reference, after a reference scan plus grace period. */\n | 'orphan-artifact';\n\nexport interface CleanupCandidate {\n readonly candidateId: string;\n readonly category: CleanableCategory;\n /** What to act on — a filesystem path, or a journal key. Interpreted by the cleanup worker, never by the journal. */\n readonly ref: string;\n readonly eligibleAt: string;\n readonly reason: string;\n readonly attempts: number;\n readonly lastError?: string;\n}\n\nexport interface CleanupResult {\n readonly candidateId: string;\n readonly outcome: 'deleted' | 'skipped' | 'failed';\n readonly bytesReclaimed?: number;\n readonly error?: string;\n readonly at: string;\n}\n\nexport interface CompactOptions {\n /**\n * `passive` never blocks a concurrent reader/writer and may checkpoint\n * nothing; `truncate` waits for the WAL to be fully applied and resets it.\n * Both are maintenance calls and belong off the active-task hot path\n * (§12.7.2).\n */\n readonly checkpoint?: 'passive' | 'truncate';\n /** Upper bound on freelist pages returned to the filesystem this pass. Bounded so compaction cannot monopolise the single writer. */\n readonly incrementalVacuumPages?: number;\n}\n\nexport interface CompactResult {\n readonly checkpointed: boolean;\n /** WAL frames still outstanding after the checkpoint attempt — `0` means the WAL was fully applied. */\n readonly walFramesRemaining: number;\n readonly pagesVacuumed: number;\n readonly durationMs: number;\n}\n\n/**\n * The daemon-local durable journal (sprint S3.3's minimum API, verbatim,\n * plus {@link close}).\n *\n * A port, not an implementation detail: architecture §12.7.2 lets a host\n * inject its own backend, but only one that meets the same durability\n * contract. `SqliteLocalTaskJournal` is the shipped production implementation;\n * a plain JSON/JSONL store is explicitly NOT an acceptable substitute in\n * hosted mode, because it cannot honour the one property this interface exists\n * for — that `appendEnvelope` resolving means the bytes survived a power cut.\n */\nexport interface LocalTaskJournal {\n /**\n * Make one inbound envelope durable. Resolving means committed and fsynced;\n * only then may the mailbox cursor advance past `record.seq`.\n *\n * Idempotent by envelope id: appending the same envelope twice returns the\n * original receipt with `created: false` and writes nothing new. That is\n * what makes redelivery — which the at-least-once wire guarantees will\n * happen after any crash between commit and ack — a no-op rather than a\n * second side effect.\n */\n appendEnvelope(record: ReceivedEnvelopeRecord): Promise<JournalReceipt>;\n /** Record the admission decision for a task whose offer envelope is already durable. */\n recordAdmission(record: AdmissionRecord): Promise<void>;\n /** Record one local execution-state transition. Idempotent by transition id. */\n recordTransition(record: LocalTransitionRecord): Promise<void>;\n /** Record (or update the retry state of) a task's terminal. Idempotent by task id: a replay with the same payload hash is a no-op beyond retry bookkeeping. */\n recordTerminal(record: LocalTerminalRecord): Promise<void>;\n /** Tasks with no terminal and no recovery marker — what this daemon was in the middle of when it last stopped. */\n listRecoverable(): Promise<RecoverableTask[]>;\n /** Close out one recoverable task by writing its recovery marker. Never deletes; a marked row is on §12.7.2.1's never-auto-delete list. */\n markRecovered(taskId: string, outcome: RecoveryOutcome): Promise<void>;\n /** Per-category storage usage (§12.7.2.1) — the input to the watermark state machine. */\n measureUsage(): Promise<LocalStorageUsage>;\n /** Cleanup candidates eligible at `now`, oldest first, at most `limit`. Only {@link CleanableCategory} members can ever appear. */\n listCleanupCandidates(now: Date, limit: number): Promise<CleanupCandidate[]>;\n /** Record what the cleanup worker actually did with a candidate. */\n markCleanupResult(result: CleanupResult): Promise<void>;\n /** Bounded WAL checkpoint + incremental vacuum. Maintenance only; never on the envelope path. */\n compact(options: CompactOptions): Promise<CompactResult>;\n /**\n * Release the underlying handle. Beyond S3.3's minimum API — the daemon\n * owns this object's lifetime and has to be able to end it, and the crash\n * matrix needs an explicit \"clean shutdown\" to contrast against dropping\n * the reference without one.\n */\n close(): Promise<void>;\n}\n\n/**\n * Thrown when hosted journal mode is configured on a runtime that cannot\n * provide a real SQLite backend.\n *\n * This is architecture §12.7.2's no-silent-downgrade rule made executable:\n * \"为兼容 Node 20 而退回的普通文件实现不能冒充 production durability.\" A daemon\n * that acks a mailbox on the strength of a journal that does not fsync loses\n * tasks only under power-cut timings — it passes every happy-path test it will\n * ever be given. Refusing to start is the only honest behaviour, so this is\n * thrown from CONSTRUCTION, before a single envelope has been accepted.\n */\nexport class JournalUnavailableError extends Error {\n constructor(reason: string, options?: { cause?: unknown }) {\n super(\n `hosted journal mode requires a runtime with a working node:sqlite (Node 22.5+); refusing to start: ${reason}. ` +\n 'A plain-file journal is not an acceptable substitute — it cannot honour the fsync-before-ack ordering the ' +\n 'hosted mailbox cursor depends on (architecture §12.7.2). Upgrade Node, or run this daemon in its default ' +\n 'self-hosted mode with no hostedJournal configured.',\n );\n this.name = 'JournalUnavailableError';\n if (options?.cause !== undefined) this.cause = options.cause;\n }\n}\n\n/**\n * Thrown when the journal database is unreadable and has been moved aside.\n *\n * The database is renamed (with its WAL/SHM siblings) into\n * `<storeDir>/quarantine/`, timestamped, alongside a manifest naming the\n * reason — and then this is thrown. Nothing is deleted and nothing is\n * silently rebuilt: a fresh empty database opened over a corrupt one would\n * report \"no recoverable tasks\" for a machine that has some, and destroy the\n * only evidence of why. §12.7.2.1 puts quarantine on the never-auto-delete\n * list; clearing it is an explicit operator action.\n */\nexport class JournalCorruptError extends Error {\n constructor(\n readonly dbPath: string,\n readonly quarantinePath: string,\n reason: string,\n options?: { cause?: unknown },\n ) {\n super(\n `the local task journal at \"${dbPath}\" could not be opened (${reason}). It has been moved to \"${quarantinePath}\" ` +\n 'with a manifest and NOT deleted; nothing was rebuilt over it. Inspect the quarantined database before ' +\n 'restarting this daemon — a fresh journal would report an empty recovery set for a machine that may have ' +\n 'unfinished tasks.',\n );\n this.name = 'JournalCorruptError';\n if (options?.cause !== undefined) this.cause = options.cause;\n }\n}\n\n/**\n * Thrown when a record exceeds the journal's per-record byte bound.\n *\n * The journal holds reliability metadata and small bounded bytes; large\n * payloads live on the filesystem and are referenced (§12.7.2). Rejecting is\n * the point — truncating would make the stored envelope a different envelope\n * than the one acked, which is precisely the failure this whole subsystem\n * exists to rule out.\n */\nexport class JournalRecordTooLargeError extends Error {\n constructor(\n readonly field: string,\n readonly actualBytes: number,\n readonly limitBytes: number,\n ) {\n super(\n `journal record field \"${field}\" is ${actualBytes} bytes, over the ${limitBytes}-byte bound — refusing it rather ` +\n 'than truncating (a truncated envelope is not the envelope that was acked). The journal stores reliability ' +\n 'metadata and small bounded bytes only; large payloads belong on the filesystem, referenced by local_artifact_ref.',\n );\n this.name = 'JournalRecordTooLargeError';\n }\n}\n\n/** Thrown when a record references a task the journal has no row for — a transition or terminal for a task whose offer envelope was never appended. Fail-closed: the alternative is inventing the missing task row, which would fabricate recovery evidence. */\nexport class JournalUnknownTaskError extends Error {\n constructor(readonly taskId: string, operation: string) {\n super(\n `${operation} references task \"${taskId}\", which has no journal_task row — its offer envelope was never appended. ` +\n 'Refusing rather than synthesising the missing row: a fabricated task record is fabricated recovery evidence.',\n );\n this.name = 'JournalUnknownTaskError';\n }\n}\n\n/** Thrown when the journal is used after {@link LocalTaskJournal.close}. */\nexport class JournalClosedError extends Error {\n constructor(operation: string) {\n super(`the local task journal is closed; ${operation} cannot be served`);\n this.name = 'JournalClosedError';\n }\n}\n","/**\n * `node:sqlite` capability detection and connection setup for the daemon's\n * durable local journal.\n *\n * This deliberately MIRRORS `packages/server/src/sqlite-support.ts` in shape\n * rather than importing it. `@byok-sdk/client` has no dependency on `@byok-sdk/server`\n * outside its own dev/test tree, and it must not gain one: the daemon ships to\n * an end user's machine and the reference server does not. The two files are\n * therefore the same idea applied twice on purpose — the server's module is\n * internal to that package and stays untouched by this slice — with the\n * differences that matter here spelled out below:\n *\n * - the durability pragmas are the journal's own (`foreign_keys=ON`,\n * `synchronous=FULL`, `auto_vacuum=INCREMENTAL`), not the reference stores';\n * - \"unavailable\" is fail-closed for a REASON here (architecture §12.7.2's\n * no-silent-downgrade rule: a hosted daemon that cannot open a real SQLite\n * database refuses to start rather than substituting a file journal that\n * only looks durable), so the typed error it raises is the journal's own —\n * see `JournalUnavailableError` in `journal.ts`.\n */\nimport { createRequire } from 'node:module';\nimport { chmodSync, existsSync } from 'node:fs';\nimport type { DatabaseSync } from 'node:sqlite';\n\n/** Every post-construction boundary crossed before a journal handle is returned to its owner. */\nexport type JournalOpenStep =\n | 'after-open'\n | 'after-auto-vacuum'\n | 'after-wal'\n | 'after-foreign-keys'\n | 'after-synchronous'\n | 'after-header-read';\n\n/**\n * Test-only fault seam for proving that every post-open initialization failure\n * closes the native handle before control returns to the journal constructor.\n */\nexport interface JournalOpenFaultSeam {\n onStep?(step: JournalOpenStep): void;\n /** Test-only close override; production always calls `DatabaseSync.close()`. */\n close?(db: DatabaseSync): void;\n}\n\n/**\n * Initialization failed after SQLite returned a native handle, and closing\n * that handle also failed. Callers must retain their cross-process ownership\n * lease because the helper can no longer prove that no writer remains alive.\n */\nexport class JournalHandleCleanupError extends Error {\n constructor(message: string, readonly failures: readonly unknown[]) {\n super(message);\n this.name = 'JournalHandleCleanupError';\n }\n}\n\n/** `node:sqlite`'s minimum Node.js version (https://nodejs.org/api/sqlite.html). */\nconst MIN_NODE_MAJOR = 22;\nconst MIN_NODE_MINOR = 5;\n\n/**\n * Whether `nodeVersion` (a `major.minor.patch` string shaped like\n * `process.versions.node`) is new enough for `node:sqlite` to exist at all.\n * A version-string heuristic only — `node:sqlite` shipped in 22.5.0 behind\n * `--experimental-sqlite` and became usable unflagged later, so a runtime\n * passing this can still fail to load the module. {@link isSqliteAvailable}\n * is the authoritative check; this one only exists to turn the common\n * \"Node too old\" case into a specific message. Unparsable input returns\n * `true` (the `require` below is the real gate; don't false-negative on a\n * version shape this hasn't seen).\n */\nexport function isSqliteCapableNodeVersion(nodeVersion: string): boolean {\n const [majorStr, minorStr] = nodeVersion.split('.');\n const major = Number(majorStr);\n const minor = Number(minorStr);\n if (!Number.isFinite(major) || !Number.isFinite(minor)) return true;\n return major > MIN_NODE_MAJOR || (major === MIN_NODE_MAJOR && minor >= MIN_NODE_MINOR);\n}\n\nlet sqliteModule: typeof import('node:sqlite') | undefined;\n\n/**\n * Synchronously load `node:sqlite` via `createRequire` rather than a dynamic\n * `import()`. `DatabaseSync`'s entire API is synchronous, and the journal is\n * constructed synchronously from `createDaemonWithAdapters` alongside every\n * other daemon-local store (`DeviceStore`, `CursorStore`, ...) — an async\n * factory here would leak into every one of those call sites for nothing.\n * `node:sqlite` is a built-in, so `require` resolves it even from this\n * `\"type\": \"module\"` package. Memoized: the throw is re-derived per call from\n * the version check rather than cached, which keeps the failure message\n * accurate without keeping a rejected value around.\n */\nexport function loadSqliteModule(): typeof import('node:sqlite') {\n if (sqliteModule) return sqliteModule;\n if (!isSqliteCapableNodeVersion(process.versions.node)) {\n throw new Error(\n `node:sqlite requires Node.js ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR}+; detected ${process.versions.node}`,\n );\n }\n const require = createRequire(import.meta.url);\n sqliteModule = require('node:sqlite') as typeof import('node:sqlite');\n return sqliteModule;\n}\n\n/**\n * Whether `node:sqlite` can ACTUALLY be loaded right now. This is what the\n * journal's own test suites use for `describe.skipIf(!isSqliteAvailable())`\n * (the same idiom `@byok-sdk/server`'s SQLite suites already use), and what\n * `createDaemonWithAdapters` calls before constructing a hosted journal so\n * the refusal is a typed, up-front error instead of a cryptic\n * `Cannot find module 'node:sqlite'` from deep inside the first append.\n */\nexport function isSqliteAvailable(): boolean {\n try {\n loadSqliteModule();\n return true;\n } catch {\n return false;\n }\n}\n\n/** POSIX mode the journal database and its WAL/SHM siblings are restricted to — owner read/write only. Same convention as `daemon/store.ts`'s device credential file. */\nconst SECURE_FILE_MODE = 0o600;\n\n/**\n * Open (or create) the journal database at `path` with the durability\n * settings architecture §12.7.2 pins, in the order they have to be applied:\n *\n * 1. `auto_vacuum = INCREMENTAL` — MUST precede table creation. `auto_vacuum`\n * is only settable on a database with no schema yet; setting it afterward\n * is silently ignored, and `compact()`'s `PRAGMA incremental_vacuum` would\n * then be a no-op that reports success.\n * 2. `journal_mode = WAL` — a reader and the single writer proceed without\n * blocking each other, and it is what makes \"drop the instance, reopen the\n * same file\" (the entire crash-matrix method) reliable.\n * 3. `foreign_keys = ON` — the journal's tables are a real graph\n * (transition -> task -> envelope); an orphan row here is corrupted\n * recovery evidence, not a tolerable inconsistency.\n * 4. `synchronous = FULL` — every ack-critical transaction fsyncs before it\n * reports committed. This is THE setting the \"durable append then cursor\n * ack\" ordering rests on; NORMAL would let the WAL commit land in the OS\n * page cache, so the cursor could advance over an envelope a power cut\n * then erases. Applied database-wide rather than per-transaction: the\n * journal's whole reason to exist is ack-critical writes, and the\n * maintenance paths that do not need it (checkpoint, incremental vacuum)\n * are off the hot path anyway.\n *\n * `busyTimeoutMs` bounds how long a write waits on the lock before throwing\n * `SQLITE_BUSY` — bounded on purpose, so contention surfaces as an error the\n * caller sees rather than an unbounded stall on the envelope path.\n *\n * Throws whatever `node:sqlite` throws (module load failure, a corrupt file,\n * an unreadable directory). Every caller is `SqliteLocalTaskJournal`'s\n * constructor, which turns each of those into its own typed error — see\n * `sqlite-journal.ts`.\n */\nexport function openJournalDatabase(\n path: string,\n busyTimeoutMs: number,\n faults?: JournalOpenFaultSeam,\n): DatabaseSync {\n const { DatabaseSync } = loadSqliteModule();\n const db = new DatabaseSync(path, { timeout: busyTimeoutMs });\n try {\n faults?.onStep?.('after-open');\n db.exec('PRAGMA auto_vacuum = INCREMENTAL;');\n faults?.onStep?.('after-auto-vacuum');\n db.exec('PRAGMA journal_mode = WAL;');\n faults?.onStep?.('after-wal');\n db.exec('PRAGMA foreign_keys = ON;');\n faults?.onStep?.('after-foreign-keys');\n db.exec('PRAGMA synchronous = FULL;');\n faults?.onStep?.('after-synchronous');\n // Forces a real header read: a file that is not a SQLite database (or whose\n // header is damaged) fails HERE, at open, where the quarantine path can act\n // on it — not later, mid-append, with a half-written transaction in flight.\n db.prepare('SELECT count(*) AS n FROM sqlite_schema').get();\n faults?.onStep?.('after-header-read');\n return db;\n } catch (err) {\n try {\n if (faults?.close) faults.close(db);\n else db.close();\n } catch (closeError) {\n throw new JournalHandleCleanupError(\n 'local task journal initialization failed and its SQLite handle could not be closed',\n [err, closeError],\n );\n }\n throw err;\n }\n}\n\n/**\n * Restrict the journal database and its WAL/SHM siblings to owner-only\n * read/write. The journal holds raw task envelopes (instructions, policy) with\n * no other access-control layer of its own, so it must not be left at whatever\n * the process umask would give it. Call AFTER the schema exists, so the\n * WAL/SHM files SQLite creates lazily on first write are already there; a\n * sibling that does not exist yet is skipped rather than treated as an error.\n */\nexport function secureJournalFilePermissions(dbPath: string): void {\n for (const candidate of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {\n if (existsSync(candidate)) {\n chmodSync(candidate, SECURE_FILE_MODE);\n }\n }\n}\n","/**\n * `SqliteLocalTaskJournal` — the production {@link LocalTaskJournal}\n * (architecture §12.7.2).\n *\n * One database, `<storeDir>/daemon.db`, holding the eight §12.7.2 tables. The\n * three properties this file exists to provide, and the mechanism for each:\n *\n * 1. **A commit means fsynced.** `synchronous=FULL` plus WAL (see\n * `sqlite-support.ts`'s `openJournalDatabase` for the pragma order and why\n * it matters). `appendEnvelope` resolving is the daemon's licence to let\n * the mailbox cursor move past that seq, so anything weaker here turns\n * every power cut into a task-loss window.\n * 2. **Envelope bytes, task record, and idempotency receipt land together or\n * not at all.** One `BEGIN IMMEDIATE` transaction covers all three\n * (§12.7.3: \"v1 bytes 与本机 task record 已在同一个本机 transaction durable\n * append\"). This is the repo's first multi-statement SQLite transaction, so\n * the idiom is established here: `BEGIN IMMEDIATE` (take the write lock up\n * front — `DEFERRED` would upgrade mid-transaction and can deadlock two\n * writers), work, `COMMIT`, and a `ROLLBACK` on any throw.\n * 3. **A redelivered envelope is a no-op.** The wire is at-least-once and a\n * crash between commit and ack GUARANTEES a redelivery, so idempotency is\n * the normal path, not the exceptional one: the receipt row keyed by\n * envelope id is looked up inside the same transaction that would write it.\n *\n * Writes are serialized through a single-writer promise queue. `node:sqlite`\n * is fully synchronous, so this is not about mutual exclusion within one\n * operation — it is about ordering across them, and about giving the fault\n * seam and the busy timeout one place to live. The timeout is BOUNDED\n * (`busyTimeoutMs`) so lock contention surfaces as an error the envelope path\n * can report rather than an unbounded stall.\n */\nimport { existsSync, mkdirSync, readdirSync, renameSync, statSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { DatabaseSync } from 'node:sqlite';\nimport {\n JournalClosedError,\n JournalCorruptError,\n JournalRecordTooLargeError,\n JournalUnavailableError,\n JournalUnknownTaskError,\n type AdmissionRecord,\n type CategoryUsage,\n type CleanableCategory,\n type CleanupCandidate,\n type CleanupResult,\n type CompactOptions,\n type CompactResult,\n type JournalReceipt,\n type LocalStorageUsage,\n type LocalTaskJournal,\n type LocalTerminalRecord,\n type LocalTransitionRecord,\n type RecoverableTask,\n type RecoveryOutcome,\n type ReceivedEnvelopeRecord,\n type StorageCategory,\n} from './journal';\nimport {\n isSqliteAvailable,\n JournalHandleCleanupError,\n openJournalDatabase,\n secureJournalFilePermissions,\n type JournalOpenFaultSeam,\n} from './sqlite-support';\n\nexport { JournalHandleCleanupError };\n\n/** The single database file, per §12.7.2's \"建议单库 `<storeDir>/daemon.db`\". */\nexport const JOURNAL_DB_FILENAME = 'daemon.db';\n\n/** Where a database that failed to open is moved to. On §12.7.2.1's never-auto-delete list. */\nexport const JOURNAL_QUARANTINE_DIRNAME = 'quarantine';\n\n/**\n * Default per-record byte bound. Generous next to a real `task.offer` (an\n * instruction plus a policy object — kilobytes), tight enough that an\n * envelope carrying an inlined artifact is refused instead of turning the\n * journal into a blob store. See {@link JournalRecordTooLargeError}.\n */\nexport const DEFAULT_MAX_RECORD_BYTES = 256 * 1024;\n\n/** Default bound on how long a write waits for the write lock before failing. */\nexport const DEFAULT_JOURNAL_BUSY_TIMEOUT_MS = 5_000;\n\n/** Bound on a transition's free-form `detail` note — this is metadata, not a place for tool output. */\nconst MAX_TRANSITION_DETAIL_BYTES = 4 * 1024;\n\n/**\n * Named points inside a write where {@link JournalFaultSeam} may throw.\n *\n * These exist so the crash matrix can put a failure at an exact ordering\n * boundary — \"after the envelope row, before the task row\", \"after the receipt,\n * before the commit\" — deterministically, with no wall clock and no real\n * process kill. Same DI shape as `EnsureSecureDirOptions.run`\n * (`util/secure-dir.ts`): a seam the production path never supplies, exercised\n * from any host.\n */\nexport type JournalFaultStep =\n | 'append:before-begin'\n | 'append:after-envelope'\n | 'append:after-task'\n | 'append:after-receipt'\n | 'append:before-commit'\n | 'admission:before-commit'\n | 'transition:before-commit'\n | 'terminal:before-commit'\n | 'recovery:before-commit'\n | 'cleanup:before-commit'\n | 'prune:before-commit';\n\nexport interface JournalFaultSeam {\n /** Throw to simulate a crash or IO error at exactly this step. Return normally to proceed. */\n onStep?(step: JournalFaultStep): void;\n}\n\nexport interface SqliteLocalTaskJournalOptions {\n /** The daemon's store directory. The database lives at `<storeDir>/daemon.db` and quarantine at `<storeDir>/quarantine/`. */\n readonly storeDir: string;\n /** Bound on waiting for the write lock. Default {@link DEFAULT_JOURNAL_BUSY_TIMEOUT_MS}. */\n readonly busyTimeoutMs?: number;\n /** Per-record byte bound. Default {@link DEFAULT_MAX_RECORD_BYTES}. */\n readonly maxRecordBytes?: number;\n /** Test seam — see {@link JournalFaultSeam}. Never supplied in production. */\n readonly faults?: JournalFaultSeam;\n /** Test seam for post-open/pre-return SQLite initialization failures. Never supplied in production. */\n readonly openFaults?: JournalOpenFaultSeam;\n /** Injected clock, so receipt/quarantine timestamps are deterministic under test. Defaults to the real one. */\n readonly clock?: () => Date;\n}\n\n/**\n * The eight tables of §12.7.2, verbatim in purpose:\n *\n * - `journal_envelope` — tenant/product/device, seq, envelope id, task id, raw\n * bytes and hash, commit/ack times;\n * - `journal_task` — admission, claimed runtime, effective policy hash,\n * workspace ref, current local state, recovery marker;\n * - `journal_transition` — transition id, from/to, `occurred_at`, idempotent\n * by transition id;\n * - `journal_terminal` — terminal payload hash, truth write state, last\n * retry/error;\n * - `journal_idempotency` — outbound request / envelope / receipt ids;\n * - `local_artifact_ref` — path/hash/size/ref state of filesystem objects,\n * never the payload itself;\n * - `local_cleanup_candidate` — `eligible_at`, reason, class, attempt/error,\n * for safe GC;\n * - `local_storage_usage` — measured or approximate bytes per category.\n *\n * `CREATE TABLE IF NOT EXISTS` only, matching the repo's existing SQLite store\n * (there is no migration machinery here, and this schema has no shipped\n * predecessor to migrate from).\n *\n * The foreign keys are load-bearing rather than decorative: with\n * `foreign_keys=ON`, a transition or terminal for a task whose offer envelope\n * was never appended is refused by the database itself. An orphan row in a\n * recovery journal is not a tolerable inconsistency — it is recovery evidence\n * that describes a task nothing can account for.\n */\nconst SCHEMA = `\nCREATE TABLE IF NOT EXISTS journal_envelope (\n envelope_id TEXT PRIMARY KEY,\n tenant_id TEXT NOT NULL,\n product_id TEXT NOT NULL,\n device_id TEXT NOT NULL,\n seq INTEGER NOT NULL,\n task_id TEXT,\n bytes TEXT NOT NULL,\n bytes_hash TEXT NOT NULL,\n received_at TEXT NOT NULL,\n committed_at TEXT NOT NULL,\n acked_at TEXT\n);\nCREATE INDEX IF NOT EXISTS journal_envelope_seq ON journal_envelope (device_id, seq);\n\nCREATE TABLE IF NOT EXISTS journal_task (\n task_id TEXT PRIMARY KEY,\n envelope_id TEXT NOT NULL REFERENCES journal_envelope (envelope_id),\n tenant_id TEXT NOT NULL,\n product_id TEXT NOT NULL,\n device_id TEXT NOT NULL,\n seq INTEGER NOT NULL,\n admitted INTEGER,\n admission_reason TEXT,\n admission_retryable INTEGER,\n claimed_runtime TEXT,\n effective_policy_hash TEXT,\n workspace_ref TEXT,\n local_state TEXT NOT NULL,\n recovery_marker TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS journal_transition (\n transition_id TEXT PRIMARY KEY,\n task_id TEXT NOT NULL REFERENCES journal_task (task_id),\n from_state TEXT,\n to_state TEXT NOT NULL,\n occurred_at TEXT NOT NULL,\n detail TEXT\n);\nCREATE INDEX IF NOT EXISTS journal_transition_task ON journal_transition (task_id, occurred_at);\n\nCREATE TABLE IF NOT EXISTS journal_terminal (\n task_id TEXT PRIMARY KEY REFERENCES journal_task (task_id),\n terminal_type TEXT NOT NULL,\n payload_hash TEXT NOT NULL,\n truth_state TEXT NOT NULL,\n attempt INTEGER NOT NULL,\n last_error TEXT,\n recorded_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS journal_idempotency (\n scope TEXT NOT NULL,\n key TEXT NOT NULL,\n task_id TEXT,\n receipt TEXT NOT NULL,\n created_at TEXT NOT NULL,\n PRIMARY KEY (scope, key)\n);\n\nCREATE TABLE IF NOT EXISTS local_artifact_ref (\n ref_id TEXT PRIMARY KEY,\n task_id TEXT,\n path TEXT NOT NULL,\n hash TEXT,\n size_bytes INTEGER NOT NULL,\n ref_state TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS local_cleanup_candidate (\n candidate_id TEXT PRIMARY KEY,\n category TEXT NOT NULL,\n ref TEXT NOT NULL,\n eligible_at TEXT NOT NULL,\n reason TEXT NOT NULL,\n attempts INTEGER NOT NULL DEFAULT 0,\n last_error TEXT,\n outcome TEXT,\n resolved_at TEXT\n);\nCREATE INDEX IF NOT EXISTS local_cleanup_candidate_eligible\n ON local_cleanup_candidate (resolved_at, eligible_at);\n\nCREATE TABLE IF NOT EXISTS local_storage_usage (\n category TEXT PRIMARY KEY,\n bytes INTEGER NOT NULL,\n approximate INTEGER NOT NULL,\n measured_at TEXT NOT NULL\n);\n`;\n\n/** `local_state` for a task whose admission declined it — terminal for local purposes, and NOT something recovery should re-offer. */\nconst DECLINED_STATE = 'declined';\n/** `local_state` a task starts in: its offer envelope is durable, nothing has been decided yet. */\nconst RECEIVED_STATE = 'received';\n\n/** The categories `measureUsage` reports. Host-reported ones default to zero-approximate rather than being guessed at. */\nconst HOST_REPORTED_CATEGORIES: readonly StorageCategory[] = ['cache', 'log', 'workspace'];\n\nfunction byteLength(value: string): number {\n return Buffer.byteLength(value, 'utf8');\n}\n\nfunction fileBytes(path: string): number {\n try {\n return statSync(path).size;\n } catch {\n return 0;\n }\n}\n\nfunction directoryBytes(dir: string): number {\n let total = 0;\n let entries: import('node:fs').Dirent[];\n try {\n entries = readdirSync(dir, { withFileTypes: true, encoding: 'utf8' });\n } catch {\n return 0;\n }\n for (const entry of entries) {\n const full = join(dir, entry.name);\n total += entry.isDirectory() ? directoryBytes(full) : fileBytes(full);\n }\n return total;\n}\n\n/**\n * Move a database that could not be opened aside, with its WAL/SHM siblings\n * and a manifest, and return where it went.\n *\n * `renameSync` within one directory tree is atomic, so there is no window in\n * which the file is half-moved. NOTHING is deleted: a corrupt journal is the\n * only record of what this machine was doing, and the failure mode this\n * protects against — opening a fresh empty database over it, reporting \"no\n * recoverable tasks\", and losing the evidence of why — is silent and\n * unrecoverable. The manifest is written last so its presence means the move\n * completed.\n */\nfunction quarantineDatabase(storeDir: string, dbPath: string, reason: string, now: Date): string {\n const dir = join(storeDir, JOURNAL_QUARANTINE_DIRNAME);\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n const stamp = now.toISOString().replace(/[:.]/g, '-');\n let base = `${stamp}-${JOURNAL_DB_FILENAME}`;\n // Two quarantines within the same millisecond (a restart loop against a\n // corrupt file is exactly how that happens) must not overwrite each other.\n for (let attempt = 1; existsSync(join(dir, base)); attempt += 1) {\n base = `${stamp}-${attempt}-${JOURNAL_DB_FILENAME}`;\n }\n const moved: string[] = [];\n for (const suffix of ['', '-wal', '-shm']) {\n const from = `${dbPath}${suffix}`;\n if (!existsSync(from)) continue;\n const to = join(dir, `${base}${suffix}`);\n renameSync(from, to);\n moved.push(to);\n }\n writeFileSync(\n join(dir, `${base}.manifest.json`),\n `${JSON.stringify({ quarantinedAt: now.toISOString(), reason, originalPath: dbPath, files: moved }, null, 2)}\\n`,\n { mode: 0o600 },\n );\n return join(dir, base);\n}\n\nexport class SqliteLocalTaskJournal implements LocalTaskJournal {\n readonly #db: DatabaseSync;\n readonly #dbPath: string;\n readonly #storeDir: string;\n readonly #maxRecordBytes: number;\n readonly #faults: JournalFaultSeam | undefined;\n readonly #clock: () => Date;\n /**\n * The single-writer queue's tail. Every operation chains onto it, so two\n * concurrent callers never interleave two transactions — and the `#closed`\n * check happens in queue order, not at call time, so an operation queued\n * before `close()` still runs.\n */\n #tail: Promise<unknown> = Promise.resolve();\n #closed = false;\n /**\n * The one in-flight or settled `close()`, so closing twice is a no-op that\n * resolves rather than a `JournalClosedError`. `close` is the one operation\n * whose postcondition is already satisfied on an already-closed journal, and\n * the daemon's shutdown sequence is documented idempotent — every other step\n * in it tolerates a second call, so this one has to as well.\n */\n #closing: Promise<void> | undefined;\n\n constructor(options: SqliteLocalTaskJournalOptions) {\n // Checked BEFORE anything touches the filesystem: §12.7.2's\n // no-silent-downgrade rule is about refusing to start, and a refusal that\n // has already created directories is a worse refusal.\n if (!isSqliteAvailable()) {\n throw new JournalUnavailableError(`node:sqlite could not be loaded on Node ${process.versions.node}`);\n }\n\n this.#storeDir = options.storeDir;\n this.#dbPath = join(options.storeDir, JOURNAL_DB_FILENAME);\n this.#maxRecordBytes = options.maxRecordBytes ?? DEFAULT_MAX_RECORD_BYTES;\n this.#faults = options.faults;\n this.#clock = options.clock ?? (() => new Date());\n\n mkdirSync(options.storeDir, { recursive: true, mode: 0o700 });\n\n // Open + schema are one unit for quarantine purposes: a file whose header\n // reads fine but whose schema cannot be created is just as unusable, and\n // just as much evidence, as one that fails at open.\n let db: DatabaseSync | undefined;\n try {\n db = openJournalDatabase(\n this.#dbPath,\n options.busyTimeoutMs ?? DEFAULT_JOURNAL_BUSY_TIMEOUT_MS,\n options.openFaults,\n );\n db.exec(SCHEMA);\n } catch (err) {\n // `openJournalDatabase` owns the handle until it returns. If that helper\n // could not prove cleanup, this constructor has no handle to close and\n // must preserve the typed mutation-barrier failure for the daemon rather\n // than relabeling it as ordinary corruption and releasing the lease.\n if (err instanceof JournalHandleCleanupError) throw err;\n // An open handle is itself a store writer/lock authority. Close it before\n // quarantine and before the caller can release its cross-process lease;\n // otherwise a schema failure could leave an unreachable live SQLite\n // handle behind while a second daemon is admitted.\n try {\n db?.close();\n } catch (closeError) {\n throw new JournalHandleCleanupError(\n 'local task journal initialization failed and its SQLite handle could not be closed',\n [err, closeError],\n );\n }\n const reason = err instanceof Error ? err.message : String(err);\n const quarantinePath = quarantineDatabase(options.storeDir, this.#dbPath, reason, this.#clock());\n throw new JournalCorruptError(this.#dbPath, quarantinePath, reason, { cause: err });\n }\n this.#db = db;\n try {\n secureJournalFilePermissions(this.#dbPath);\n } catch (err) {\n // Permission hardening failure is not database corruption and must not\n // move evidence. It is still a construction failure, with the handle\n // synchronously closed before ownership can unwind.\n try {\n db.close();\n } catch (closeError) {\n throw new JournalHandleCleanupError(\n 'local task journal permission hardening failed and its SQLite handle could not be closed',\n [err, closeError],\n );\n }\n throw err;\n }\n }\n\n // ---------------------------------------------------------------------\n // Single-writer queue + the repo's first multi-statement transaction idiom\n // ---------------------------------------------------------------------\n\n #enqueue<T>(operation: string, work: () => T): Promise<T> {\n const run = this.#tail.then(() => {\n if (this.#closed) throw new JournalClosedError(operation);\n return work();\n });\n // The queue must survive a failed operation: chain the NEXT caller onto a\n // settled promise regardless of this one's outcome, or one rejected write\n // would poison every write after it.\n this.#tail = run.then(\n () => undefined,\n () => undefined,\n );\n return run;\n }\n\n /**\n * `BEGIN IMMEDIATE` … `COMMIT`, with `ROLLBACK` on any throw.\n *\n * `IMMEDIATE` rather than the default `DEFERRED`: the write lock is taken up\n * front, so a transaction can never discover halfway through that it cannot\n * upgrade. The `ROLLBACK` is itself wrapped — if the failure was the commit\n * or the connection, SQLite may already have rolled back and a second\n * `ROLLBACK` throws \"cannot rollback - no transaction is active\"; swallowing\n * that is correct, and swallowing it must not mask the ORIGINAL error, which\n * is what is rethrown.\n */\n #transaction<T>(work: () => T): T {\n this.#db.exec('BEGIN IMMEDIATE');\n let result: T;\n try {\n result = work();\n this.#db.exec('COMMIT');\n } catch (err) {\n try {\n this.#db.exec('ROLLBACK');\n } catch {\n // Already rolled back by SQLite itself — see above.\n }\n throw err;\n }\n return result;\n }\n\n #fault(step: JournalFaultStep): void {\n this.#faults?.onStep?.(step);\n }\n\n #requireTask(taskId: string, operation: string): void {\n const row = this.#db.prepare('SELECT task_id FROM journal_task WHERE task_id = ?').get(taskId);\n if (!row) throw new JournalUnknownTaskError(taskId, operation);\n }\n\n // ---------------------------------------------------------------------\n // LocalTaskJournal\n // ---------------------------------------------------------------------\n\n /**\n * The ack-critical path. Envelope bytes, the task record it opens, and the\n * idempotency receipt all land in ONE transaction, or none of them do.\n *\n * The receipt lookup happens INSIDE that transaction rather than as a cheap\n * pre-check outside it: `BEGIN IMMEDIATE` already holds the write lock by\n * then, so \"is this a redelivery?\" and \"write it\" cannot be separated by\n * another writer. The duplicate answer is served from the stored receipt,\n * so a redelivery returns the ORIGINAL commit time and hash — the caller\n * learns the bytes are durable and that this call changed nothing, which is\n * exactly what the cursor needed.\n */\n appendEnvelope(record: ReceivedEnvelopeRecord): Promise<JournalReceipt> {\n const bytes = byteLength(record.bytes);\n if (bytes > this.#maxRecordBytes) {\n return Promise.reject(new JournalRecordTooLargeError('bytes', bytes, this.#maxRecordBytes));\n }\n if (record.opensTask && record.taskId === undefined) {\n return Promise.reject(\n new Error('ReceivedEnvelopeRecord.opensTask is true but no taskId was supplied — refusing to append a task-opening envelope with no task identity'),\n );\n }\n\n return this.#enqueue('appendEnvelope', () => {\n this.#fault('append:before-begin');\n return this.#transaction((): JournalReceipt => {\n const existing = this.#db\n .prepare('SELECT receipt FROM journal_idempotency WHERE scope = ? AND key = ?')\n .get('envelope', record.envelopeId) as { receipt: string } | undefined;\n if (existing) {\n const prior = JSON.parse(existing.receipt) as Omit<JournalReceipt, 'created'>;\n return { ...prior, created: false };\n }\n\n const committedAt = this.#clock().toISOString();\n this.#db\n .prepare(\n `INSERT INTO journal_envelope\n (envelope_id, tenant_id, product_id, device_id, seq, task_id, bytes, bytes_hash, received_at, committed_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n record.envelopeId,\n record.identity.tenantId,\n record.identity.productId,\n record.identity.deviceId,\n record.seq,\n record.taskId ?? null,\n record.bytes,\n record.bytesHash,\n record.receivedAt,\n committedAt,\n );\n this.#fault('append:after-envelope');\n\n if (record.opensTask && record.taskId !== undefined) {\n // `OR IGNORE`: a second, different envelope re-opening the same task\n // id (a re-offer after the cloud lost track) must not clobber the\n // admission/claim state the first one already accumulated. The\n // envelope row above still records that the second envelope arrived.\n this.#db\n .prepare(\n `INSERT OR IGNORE INTO journal_task\n (task_id, envelope_id, tenant_id, product_id, device_id, seq, local_state, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n record.taskId,\n record.envelopeId,\n record.identity.tenantId,\n record.identity.productId,\n record.identity.deviceId,\n record.seq,\n RECEIVED_STATE,\n committedAt,\n committedAt,\n );\n }\n this.#fault('append:after-task');\n\n const receipt: Omit<JournalReceipt, 'created'> = {\n envelopeId: record.envelopeId,\n seq: record.seq,\n bytesHash: record.bytesHash,\n committedAt,\n };\n this.#db\n .prepare('INSERT INTO journal_idempotency (scope, key, task_id, receipt, created_at) VALUES (?, ?, ?, ?, ?)')\n .run('envelope', record.envelopeId, record.taskId ?? null, JSON.stringify(receipt), committedAt);\n this.#fault('append:after-receipt');\n this.#fault('append:before-commit');\n\n return { ...receipt, created: true };\n });\n });\n }\n\n recordAdmission(record: AdmissionRecord): Promise<void> {\n return this.#enqueue('recordAdmission', () => {\n this.#transaction(() => {\n this.#requireTask(record.taskId, 'recordAdmission');\n this.#db\n .prepare(\n `UPDATE journal_task\n SET admitted = ?, admission_reason = ?, admission_retryable = ?, claimed_runtime = ?,\n effective_policy_hash = ?, workspace_ref = ?, local_state = ?, updated_at = ?\n WHERE task_id = ?`,\n )\n .run(\n record.admitted ? 1 : 0,\n record.reason ?? null,\n record.retryable === undefined ? null : record.retryable ? 1 : 0,\n record.claimedRuntime ?? null,\n record.effectivePolicyHash ?? null,\n record.workspaceRef ?? null,\n record.admitted ? 'admitted' : DECLINED_STATE,\n record.decidedAt,\n record.taskId,\n );\n this.#fault('admission:before-commit');\n });\n });\n }\n\n /**\n * Idempotent by transition id. `INSERT OR IGNORE` decides it: when the row\n * already exists nothing is inserted AND the task's `local_state` is left\n * alone, so replaying an old transition cannot drag a task's state\n * backwards — which is precisely what recovery replaying a stored sequence\n * would otherwise do.\n */\n recordTransition(record: LocalTransitionRecord): Promise<void> {\n if (record.detail !== undefined && byteLength(record.detail) > MAX_TRANSITION_DETAIL_BYTES) {\n return Promise.reject(\n new JournalRecordTooLargeError('detail', byteLength(record.detail), MAX_TRANSITION_DETAIL_BYTES),\n );\n }\n return this.#enqueue('recordTransition', () => {\n this.#transaction(() => {\n this.#requireTask(record.taskId, 'recordTransition');\n const inserted = this.#db\n .prepare(\n `INSERT OR IGNORE INTO journal_transition (transition_id, task_id, from_state, to_state, occurred_at, detail)\n VALUES (?, ?, ?, ?, ?, ?)`,\n )\n .run(\n record.transitionId,\n record.taskId,\n record.from ?? null,\n record.to,\n record.occurredAt,\n record.detail ?? null,\n );\n if (inserted.changes > 0) {\n this.#db\n .prepare('UPDATE journal_task SET local_state = ?, updated_at = ? WHERE task_id = ?')\n .run(record.to, record.occurredAt, record.taskId);\n }\n this.#fault('transition:before-commit');\n });\n });\n }\n\n /**\n * First terminal wins, matching the cloud's own receipt rule (§12.6.4:\n * 不覆写第一份事实). A repeat carrying the SAME payload hash is a delivery\n * retry and updates only the retry bookkeeping (`truth_state`, `attempt`,\n * `last_error`); a repeat carrying a DIFFERENT hash is a second, distinct\n * terminal for a task that already has one, and is recorded nowhere — the\n * first fact stands.\n */\n recordTerminal(record: LocalTerminalRecord): Promise<void> {\n return this.#enqueue('recordTerminal', () => {\n this.#transaction(() => {\n this.#requireTask(record.taskId, 'recordTerminal');\n const existing = this.#db\n .prepare('SELECT payload_hash FROM journal_terminal WHERE task_id = ?')\n .get(record.taskId) as { payload_hash: string } | undefined;\n\n if (existing === undefined) {\n this.#db\n .prepare(\n `INSERT INTO journal_terminal\n (task_id, terminal_type, payload_hash, truth_state, attempt, last_error, recorded_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n record.taskId,\n record.terminalType,\n record.payloadHash,\n record.truthState,\n record.attempt,\n record.lastError ?? null,\n record.recordedAt,\n record.recordedAt,\n );\n this.#db\n .prepare('UPDATE journal_task SET local_state = ?, updated_at = ? WHERE task_id = ?')\n .run(`terminal:${record.terminalType}`, record.recordedAt, record.taskId);\n } else if (existing.payload_hash === record.payloadHash) {\n this.#db\n .prepare('UPDATE journal_terminal SET truth_state = ?, attempt = ?, last_error = ?, updated_at = ? WHERE task_id = ?')\n .run(record.truthState, record.attempt, record.lastError ?? null, record.recordedAt, record.taskId);\n }\n this.#fault('terminal:before-commit');\n });\n });\n }\n\n /**\n * What this daemon was in the middle of: a task whose offer envelope is\n * durable, that has no terminal, that was not declined, and that recovery\n * has not already closed out.\n *\n * A task with a terminal is NOT here even when the cloud has not confirmed\n * it — that is terminal REDELIVERY (§12.7.3's \"terminal 生成后、truth 写入前\"\n * row), a different track with different evidence, and folding the two\n * together would have recovery re-admit a task that already finished.\n */\n listRecoverable(): Promise<RecoverableTask[]> {\n return this.#enqueue('listRecoverable', () => {\n const rows = this.#db\n .prepare(\n `SELECT t.task_id, t.envelope_id, t.seq, t.tenant_id, t.product_id, t.device_id,\n t.local_state, t.claimed_runtime, t.workspace_ref, t.updated_at\n FROM journal_task t\n LEFT JOIN journal_terminal term ON term.task_id = t.task_id\n WHERE t.recovery_marker IS NULL\n AND term.task_id IS NULL\n AND t.local_state <> ?\n ORDER BY t.created_at ASC, t.task_id ASC`,\n )\n .all(DECLINED_STATE) as Array<Record<string, unknown>>;\n return rows.map((row): RecoverableTask => {\n const claimedRuntime = row.claimed_runtime as string | null;\n const workspaceRef = row.workspace_ref as string | null;\n return {\n taskId: row.task_id as string,\n envelopeId: row.envelope_id as string,\n seq: Number(row.seq),\n identity: {\n tenantId: row.tenant_id as string,\n productId: row.product_id as string,\n deviceId: row.device_id as string,\n },\n localState: row.local_state as string,\n ...(claimedRuntime === null ? {} : { claimedRuntime }),\n ...(workspaceRef === null ? {} : { workspaceRef }),\n updatedAt: row.updated_at as string,\n };\n });\n });\n }\n\n /**\n * Writes the recovery marker. Idempotent and additive: a task already\n * marked is left exactly as it was (the FIRST recovery decision is the real\n * one), and no path here deletes anything — §12.7.2.1 puts recovery-marked\n * records on the never-auto-delete list, and this is what puts them there.\n */\n markRecovered(taskId: string, outcome: RecoveryOutcome): Promise<void> {\n return this.#enqueue('markRecovered', () => {\n this.#transaction(() => {\n this.#requireTask(taskId, 'markRecovered');\n const occurredAt = outcome.occurredAt ?? this.#clock().toISOString();\n this.#db\n .prepare('UPDATE journal_task SET recovery_marker = ?, updated_at = ? WHERE task_id = ? AND recovery_marker IS NULL')\n .run(\n JSON.stringify({ disposition: outcome.disposition, reason: outcome.reason ?? null, occurredAt }),\n occurredAt,\n taskId,\n );\n this.#fault('recovery:before-commit');\n });\n });\n }\n\n /**\n * Per-category bytes (§12.7.2.1). `journal` and `quarantine` are MEASURED\n * off the filesystem — they are this object's own footprint, so guessing\n * would be inexcusable. `cache`/`log`/`workspace` are owned by other\n * subsystems, so they come from whatever they last reported into\n * `local_storage_usage`; with nothing reported the answer is an explicit\n * zero-marked-approximate, never a fabricated estimate.\n */\n measureUsage(): Promise<LocalStorageUsage> {\n return this.#enqueue('measureUsage', () => {\n const reported = new Map(\n (\n this.#db.prepare('SELECT category, bytes, approximate FROM local_storage_usage').all() as Array<\n Record<string, unknown>\n >\n ).map((row) => [\n row.category as string,\n { bytes: Number(row.bytes), approximate: Number(row.approximate) === 1 } satisfies CategoryUsage,\n ]),\n );\n\n const journalBytes =\n fileBytes(this.#dbPath) + fileBytes(`${this.#dbPath}-wal`) + fileBytes(`${this.#dbPath}-shm`);\n const categories: Record<StorageCategory, CategoryUsage> = {\n journal: { bytes: journalBytes, approximate: false },\n quarantine: {\n bytes: directoryBytes(join(this.#storeDir, JOURNAL_QUARANTINE_DIRNAME)),\n approximate: false,\n },\n cache: reported.get('cache') ?? { bytes: 0, approximate: true },\n log: reported.get('log') ?? { bytes: 0, approximate: true },\n workspace: reported.get('workspace') ?? { bytes: 0, approximate: true },\n };\n const totalBytes = Object.values(categories).reduce((sum, usage) => sum + usage.bytes, 0);\n return { measuredAt: this.#clock().toISOString(), totalBytes, categories };\n });\n }\n\n /**\n * Record what another subsystem measured for a category it owns. Beyond\n * S3.3's minimum API and deliberately restricted to the three categories\n * this journal does NOT measure itself — reporting a number for `journal`\n * or `quarantine` would let a stale figure override a measured one.\n */\n reportCategoryUsage(category: (typeof HOST_REPORTED_CATEGORIES)[number], usage: CategoryUsage): Promise<void> {\n return this.#enqueue('reportCategoryUsage', () => {\n this.#db\n .prepare(\n `INSERT INTO local_storage_usage (category, bytes, approximate, measured_at) VALUES (?, ?, ?, ?)\n ON CONFLICT (category) DO UPDATE SET bytes = excluded.bytes, approximate = excluded.approximate,\n measured_at = excluded.measured_at`,\n )\n .run(category, usage.bytes, usage.approximate ? 1 : 0, this.#clock().toISOString());\n });\n }\n\n /**\n * Register something the cleanup worker may act on. Beyond S3.3's minimum\n * API (which has no producer for the candidate table), and the only way a\n * row gets in: `category` is typed {@link CleanableCategory}, so protected\n * data has no spelling that would let it be enqueued in the first place.\n */\n enqueueCleanupCandidate(candidate: {\n readonly candidateId: string;\n readonly category: CleanableCategory;\n readonly ref: string;\n readonly eligibleAt: string;\n readonly reason: string;\n }): Promise<void> {\n return this.#enqueue('enqueueCleanupCandidate', () => {\n this.#db\n .prepare(\n `INSERT OR IGNORE INTO local_cleanup_candidate (candidate_id, category, ref, eligible_at, reason, attempts)\n VALUES (?, ?, ?, ?, ?, 0)`,\n )\n .run(candidate.candidateId, candidate.category, candidate.ref, candidate.eligibleAt, candidate.reason);\n });\n }\n\n listCleanupCandidates(now: Date, limit: number): Promise<CleanupCandidate[]> {\n return this.#enqueue('listCleanupCandidates', () => {\n const rows = this.#db\n .prepare(\n `SELECT candidate_id, category, ref, eligible_at, reason, attempts, last_error\n FROM local_cleanup_candidate\n WHERE resolved_at IS NULL AND eligible_at <= ?\n ORDER BY eligible_at ASC, candidate_id ASC\n LIMIT ?`,\n )\n .all(now.toISOString(), limit) as Array<Record<string, unknown>>;\n return rows.map((row): CleanupCandidate => {\n const lastError = row.last_error as string | null;\n return {\n candidateId: row.candidate_id as string,\n category: row.category as CleanableCategory,\n ref: row.ref as string,\n eligibleAt: row.eligible_at as string,\n reason: row.reason as string,\n attempts: Number(row.attempts),\n ...(lastError === null ? {} : { lastError }),\n };\n });\n });\n }\n\n /**\n * `deleted`/`skipped` resolve the candidate; `failed` does NOT — it bumps\n * the attempt count and records the error, leaving the row eligible again.\n * That asymmetry is what makes a cleanup worker crash safe in either order:\n * crash after deleting the file but before marking, and the candidate is\n * retried against a file that is already gone (a no-op the worker reports as\n * `deleted`); crash after marking but before deleting, and the metadata says\n * resolved for something still on disk, which the next reference scan\n * re-enqueues. Neither order can lose protected data, because protected data\n * cannot be a candidate at all.\n */\n markCleanupResult(result: CleanupResult): Promise<void> {\n return this.#enqueue('markCleanupResult', () => {\n this.#transaction(() => {\n this.#db\n .prepare(\n `UPDATE local_cleanup_candidate\n SET attempts = attempts + 1,\n last_error = ?,\n outcome = ?,\n resolved_at = ?\n WHERE candidate_id = ?`,\n )\n .run(result.error ?? null, result.outcome, result.outcome === 'failed' ? null : result.at, result.candidateId);\n this.#fault('cleanup:before-commit');\n });\n });\n }\n\n /**\n * §12.7.2.1's cleanup step 3: drop one task's journal rows, but ONLY when\n * the cloud has confirmed its terminal and it carries no recovery marker.\n *\n * Beyond S3.3's minimum API, and the ONLY deletion path this journal has.\n * The eligibility test is the first statement INSIDE the transaction that\n * would delete, so \"is this row protected?\" and \"delete it\" cannot be\n * separated by another writer marking it recovered in between — a check\n * performed outside the write lock is a check that can go stale, and the row\n * it goes stale on is recovery evidence.\n *\n * The idempotency receipt goes with the rows. That is deliberate and it is\n * what `retentionMs['confirmed-journal']` exists to protect: once the receipt\n * is gone, a redelivery of that envelope would be appended as new, so the\n * candidate's retention MUST outlast the mailbox redelivery window\n * (`storage-policy.ts`'s `DEFAULT_RETENTION_MS` carries the longest default\n * of the five for exactly this reason). Keeping the receipt forever would\n * trade that risk for an unbounded table, which is the growth this step is\n * here to stop.\n *\n * Returns `false` — having deleted nothing — when the guard refuses.\n */\n pruneConfirmedJournalTask(taskId: string): Promise<boolean> {\n return this.#enqueue('pruneConfirmedJournalTask', () =>\n this.#transaction(() => {\n const eligible = this.#db\n .prepare(\n `SELECT t.task_id\n FROM journal_task t\n JOIN journal_terminal term ON term.task_id = t.task_id\n WHERE t.task_id = ?\n AND t.recovery_marker IS NULL\n AND term.truth_state = 'confirmed'`,\n )\n .get(taskId);\n if (!eligible) return false;\n\n // Child-first, so `foreign_keys=ON` is satisfied at every statement\n // rather than deferred to the commit — a deletion order the database\n // itself rejects is a deletion order that was never reviewed.\n this.#db.prepare('DELETE FROM journal_transition WHERE task_id = ?').run(taskId);\n this.#db.prepare('DELETE FROM journal_terminal WHERE task_id = ?').run(taskId);\n this.#db.prepare('DELETE FROM local_artifact_ref WHERE task_id = ?').run(taskId);\n this.#db.prepare('DELETE FROM journal_task WHERE task_id = ?').run(taskId);\n this.#db.prepare('DELETE FROM journal_idempotency WHERE task_id = ?').run(taskId);\n this.#db.prepare('DELETE FROM journal_envelope WHERE task_id = ?').run(taskId);\n this.#fault('prune:before-commit');\n return true;\n }),\n );\n }\n\n /**\n * WAL checkpoint plus a BOUNDED incremental vacuum. Maintenance only — it\n * goes through the same single-writer queue as everything else, so it can\n * never run concurrently with an ack-critical append, and `incrementalVacuumPages`\n * caps how long one pass can hold that queue.\n */\n compact(options: CompactOptions): Promise<CompactResult> {\n return this.#enqueue('compact', () => {\n const startedAt = Date.now();\n const mode = options.checkpoint === 'truncate' ? 'TRUNCATE' : 'PASSIVE';\n const checkpoint = this.#db.prepare(`PRAGMA wal_checkpoint(${mode})`).get() as\n | { busy: number; log: number; checkpointed: number }\n | undefined;\n\n const freelistBefore = this.#freelistPages();\n if (options.incrementalVacuumPages !== undefined && options.incrementalVacuumPages > 0) {\n this.#db.exec(`PRAGMA incremental_vacuum(${Math.floor(options.incrementalVacuumPages)});`);\n }\n const freelistAfter = this.#freelistPages();\n\n const log = Number(checkpoint?.log ?? 0);\n const checkpointed = Number(checkpoint?.checkpointed ?? 0);\n return {\n checkpointed: Number(checkpoint?.busy ?? 0) === 0,\n walFramesRemaining: Math.max(0, log - checkpointed),\n pagesVacuumed: Math.max(0, freelistBefore - freelistAfter),\n durationMs: Date.now() - startedAt,\n };\n });\n }\n\n #freelistPages(): number {\n const row = this.#db.prepare('PRAGMA freelist_count').get() as { freelist_count?: number } | undefined;\n return Number(row?.freelist_count ?? 0);\n }\n\n close(): Promise<void> {\n // Deliberately NOT via `#enqueue`: that path rejects with\n // `JournalClosedError` once `#closed` is set, which is right for every\n // operation that still needs an open database and wrong for the one that\n // wanted it closed. Still chained onto `#tail` the same way, so an\n // operation queued before this one still runs against an open handle.\n if (this.#closing) return this.#closing;\n const run = this.#tail.then(() => {\n this.#closed = true;\n this.#db.close();\n });\n this.#tail = run.then(\n () => undefined,\n () => undefined,\n );\n this.#closing = run;\n return run;\n }\n}\n","/**\n * `LocalStoragePolicy`, the watermark state machine, and the classified GC\n * engine (architecture §12.7.2.1).\n *\n * §12.7.2 gives the daemon a database it must not lose. This file is the other\n * half of that promise: a machine that runs out of disk cannot commit an\n * ack-critical transaction, and a daemon that keeps acking mailbox rows it\n * cannot durably record is losing tasks. So local storage stops being an\n * operational afterthought and becomes an admission-control input.\n *\n * Three shapes here are load-bearing:\n *\n * - **The state machine is §12.7.2.1's table, not a threshold check.** Four\n * states with distinct *behaviours*: `normal` runs unhurried maintenance;\n * `pressure` alerts and cleans only what can be rebuilt; `hard-pressure`\n * stops taking NEW work while everything that finishes existing work keeps\n * running; `emergency` refuses to ack at all. The difference between\n * `hard-pressure` and `emergency` is the whole design: one declines offers\n * (a task the dispatcher can place elsewhere), the other freezes the cursor\n * (a task the mailbox will redeliver). Neither deletes anything to make room.\n * - **Cleanup is ordered and bounded, and it cannot name protected data.**\n * The order is §12.7.2.1's 1-5, verbatim. The categories are\n * {@link CleanableCategory}, which has no member for an unacked envelope, a\n * `Running` task, an unconfirmed terminal, a recovery-marked row, a user\n * workspace, or quarantine evidence — so no amount of pressure can express\n * deleting one. Under pressure the order is TRUNCATED to its rebuildable\n * prefix rather than extended: being short of disk is the worst moment to\n * start deleting durable records, and the two cheap categories are the ones\n * that give space back immediately.\n * - **Everything measurable is injected.** Usage comes from the journal, free\n * space from a provider (`fs.statfs` in production), time from a clock, and\n * the cadence from a caller-driven `tick()`. There is no wall-clock race\n * anywhere in this file's behaviour, which is what lets the S3.4 disk-pressure\n * matrix assert state transitions instead of waiting for them.\n */\n\nimport { promises as fs } from 'node:fs';\nimport { isAbsolute, join } from 'node:path';\nimport type {\n CategoryUsage,\n CleanableCategory,\n CleanupCandidate,\n CleanupResult,\n CompactResult,\n LocalStorageUsage,\n LocalTaskJournal,\n StorageCategory,\n} from './journal';\n\n// ---------------------------------------------------------------------------\n// Policy\n// ---------------------------------------------------------------------------\n\n/** §12.7.2.1's recommended soft watermark: \"达到约 80% budget\". */\nexport const DEFAULT_SOFT_BUDGET_RATIO = 0.8;\n/** §12.7.2.1's recommended hard watermark: \"达到约 90% budget\". */\nexport const DEFAULT_HARD_BUDGET_RATIO = 0.9;\n/**\n * Free bytes below which one ack-critical transaction can no longer be\n * guaranteed, i.e. §12.7.2.1's `emergency` trigger. Sized for a WAL frame\n * batch plus the checkpoint headroom a `synchronous=FULL` commit needs, not\n * for a single row — a commit that cannot grow the WAL fails as surely as one\n * that cannot grow the database.\n */\nexport const DEFAULT_ACK_CRITICAL_RESERVE_BYTES = 8 * 1024 * 1024;\n/** Upper bound on how many candidates one cleanup pass may act on. Bounded so a pass cannot monopolise the journal's single writer. */\nexport const DEFAULT_CLEANUP_BATCH_LIMIT = 64;\n/** Upper bound on freelist pages one compaction pass returns to the filesystem. */\nexport const DEFAULT_INCREMENTAL_VACUUM_PAGES = 64;\n/** Unhurried maintenance cadence while `normal` — §12.7.2.1's \"常规低频 GC/compaction\". */\nexport const DEFAULT_NORMAL_COMPACTION_INTERVAL_MS = 60 * 60 * 1000;\n/** The accelerated cadence §12.7.2.1 asks for at `pressure` and above (\"加快 journal compaction\"). */\nexport const DEFAULT_PRESSURE_COMPACTION_INTERVAL_MS = 5 * 60 * 1000;\n\n/**\n * Per-category retention, as milliseconds between something becoming garbage\n * and becoming ELIGIBLE for automatic cleanup (§12.7.5).\n *\n * `confirmed-journal` is deliberately the longest: pruning a journal row also\n * drops its idempotency receipt, so its retention MUST outlast the mailbox\n * redelivery window, or a very late redelivery would re-append an envelope\n * this device already finished. `orphan-artifact` carries §12.7.5's 24-hour\n * grace period, which is the reference scan's safety margin, not a guess.\n */\nexport const DEFAULT_RETENTION_MS: Readonly<Record<CleanableCategory, number>> = {\n 'expired-temp': 60 * 60 * 1000,\n 'rotated-log': 7 * 24 * 60 * 60 * 1000,\n 'confirmed-journal': 30 * 24 * 60 * 60 * 1000,\n 'ephemeral-workspace': 24 * 60 * 60 * 1000,\n 'orphan-artifact': 24 * 60 * 60 * 1000,\n};\n\n/**\n * Log rotation parameters (§12.7.2.1 lists them among a `LocalStoragePolicy`'s\n * minimum contents).\n *\n * This SDK does not own the daemon's log writer — the host does. These are\n * therefore the CONTRACT a host's rotator reads, and the reason they live here\n * rather than in host config is that the rotated files they produce become\n * `rotated-log` cleanup candidates governed by the same retention above. Two\n * separate numbers for \"when to rotate\" and \"when to delete\" is exactly how a\n * disk fills up with files nobody owns.\n */\nexport interface LogRotationPolicy {\n /** Rotate the active log once it exceeds this size. */\n readonly maxFileBytes: number;\n /** How many rotated generations to keep before the oldest becomes a `rotated-log` cleanup candidate. */\n readonly keepFiles: number;\n}\n\nexport const DEFAULT_LOG_ROTATION: LogRotationPolicy = { maxFileBytes: 8 * 1024 * 1024, keepFiles: 5 };\n\n/** Bounded compaction scheduling — see {@link LocalStoragePressureEngine.tick}. */\nexport interface CompactionPolicy {\n readonly incrementalVacuumPages: number;\n readonly normalIntervalMs: number;\n readonly pressureIntervalMs: number;\n}\n\n/**\n * The host-injected policy, resolved and validated (§12.7.2.1: \"由 host/daemon\n * config 注入,至少包含 `maxStoreBytes`、`minFreeBytes`、soft/hard watermark、\n * 各数据类别的 retention、workspace policy 与 log rotation\").\n */\nexport interface LocalStoragePolicy {\n /** Total bytes this daemon's store directory may occupy. The budget the soft/hard ratios apply to. */\n readonly maxStoreBytes: number;\n /** Free bytes on the store's filesystem below which this device is at HARD pressure regardless of its own budget. */\n readonly minFreeBytes: number;\n /** Free bytes below which this device is at SOFT pressure. Defaults to twice {@link minFreeBytes}, so pressure engages one doubling before the floor. */\n readonly softMinFreeBytes: number;\n readonly softBudgetRatio: number;\n readonly hardBudgetRatio: number;\n readonly ackCriticalReserveBytes: number;\n readonly retentionMs: Readonly<Record<CleanableCategory, number>>;\n readonly logRotation: LogRotationPolicy;\n readonly cleanupBatchLimit: number;\n readonly compaction: CompactionPolicy;\n}\n\n/** What a host actually writes. Everything but the two budget numbers has a §12.7.2.1 default. */\nexport interface LocalStoragePolicyInput {\n maxStoreBytes: number;\n minFreeBytes: number;\n softMinFreeBytes?: number;\n softBudgetRatio?: number;\n hardBudgetRatio?: number;\n ackCriticalReserveBytes?: number;\n retentionMs?: Partial<Record<CleanableCategory, number>>;\n logRotation?: Partial<LogRotationPolicy>;\n cleanupBatchLimit?: number;\n compaction?: Partial<CompactionPolicy>;\n}\n\n/**\n * Thrown when a storage policy is internally inconsistent or out of range.\n *\n * Rejected at CONSTRUCTION, before a daemon exists, for the same reason\n * `JournalUnavailableError` is: a policy whose hard watermark sits below its\n * soft one, or whose budget is zero, produces a daemon that behaves plausibly\n * until the day it matters. There is no clamping and no \"closest sensible\n * value\" here — a misconfigured durability policy is a configuration bug to\n * fix, not a number to guess at.\n */\nexport class LocalStoragePolicyError extends Error {\n constructor(field: string, reason: string) {\n super(`DaemonConfig.hostedJournal.storagePolicy.${field} ${reason}`);\n this.name = 'LocalStoragePolicyError';\n }\n}\n\n/**\n * Thrown by {@link LocalStoragePressureEngine.assertAckCriticalAllowed} while\n * the device is in `emergency`.\n *\n * Thrown from the daemon's envelope handler, BEFORE the journal append, which\n * is what makes it §12.7.2.1's \"fail-closed,不 ack 新 mailbox row\": the\n * handler rejects, so `ConnectionManager` records a stall instead of advancing\n * the cursor, so the mailbox keeps the row and redelivers it. The task is not\n * lost — it is left where it is still safe, which is the cloud.\n */\nexport class LocalStorageEmergencyError extends Error {\n constructor(reason: string) {\n super(\n `local storage is in emergency state and cannot guarantee an ack-critical journal transaction (${reason}); ` +\n 'refusing to accept this envelope so the mailbox keeps it and redelivers. No local record was deleted to make room.',\n );\n this.name = 'LocalStorageEmergencyError';\n }\n}\n\nfunction requirePositiveInt(value: unknown, field: string): number {\n if (typeof value !== 'number' || !Number.isFinite(value) || !Number.isInteger(value) || value <= 0) {\n throw new LocalStoragePolicyError(field, `must be a positive integer number of bytes — got ${JSON.stringify(value)}`);\n }\n return value;\n}\n\nfunction requireRatio(value: unknown, field: string): number {\n if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0 || value > 1) {\n throw new LocalStoragePolicyError(field, `must be a ratio in (0, 1] — got ${JSON.stringify(value)}`);\n }\n return value;\n}\n\nfunction requireNonNegativeInt(value: unknown, field: string): number {\n if (typeof value !== 'number' || !Number.isFinite(value) || !Number.isInteger(value) || value < 0) {\n throw new LocalStoragePolicyError(field, `must be a non-negative integer — got ${JSON.stringify(value)}`);\n }\n return value;\n}\n\nconst CLEANABLE_CATEGORIES: readonly CleanableCategory[] = [\n 'expired-temp',\n 'rotated-log',\n 'confirmed-journal',\n 'ephemeral-workspace',\n 'orphan-artifact',\n];\n\n/**\n * Validate and fill in a host's policy. The ONE place a `LocalStoragePolicy`\n * comes into existence, so every consumer downstream can treat its fields as\n * already checked.\n */\nexport function resolveLocalStoragePolicy(input: LocalStoragePolicyInput): LocalStoragePolicy {\n if (input === null || typeof input !== 'object') {\n throw new LocalStoragePolicyError('', 'must be an object with at least maxStoreBytes and minFreeBytes');\n }\n const maxStoreBytes = requirePositiveInt(input.maxStoreBytes, 'maxStoreBytes');\n const minFreeBytes = requirePositiveInt(input.minFreeBytes, 'minFreeBytes');\n const softMinFreeBytes = requirePositiveInt(input.softMinFreeBytes ?? minFreeBytes * 2, 'softMinFreeBytes');\n const softBudgetRatio = requireRatio(input.softBudgetRatio ?? DEFAULT_SOFT_BUDGET_RATIO, 'softBudgetRatio');\n const hardBudgetRatio = requireRatio(input.hardBudgetRatio ?? DEFAULT_HARD_BUDGET_RATIO, 'hardBudgetRatio');\n if (softBudgetRatio >= hardBudgetRatio) {\n throw new LocalStoragePolicyError(\n 'softBudgetRatio',\n `must be strictly below hardBudgetRatio — got soft=${softBudgetRatio}, hard=${hardBudgetRatio}. A soft watermark at or above the hard one means the device would never get a warning state at all.`,\n );\n }\n if (softMinFreeBytes < minFreeBytes) {\n throw new LocalStoragePolicyError(\n 'softMinFreeBytes',\n `must be at least minFreeBytes — got soft=${softMinFreeBytes}, min=${minFreeBytes}. A soft free-space floor below the hard one is unreachable.`,\n );\n }\n const ackCriticalReserveBytes = requirePositiveInt(\n input.ackCriticalReserveBytes ?? DEFAULT_ACK_CRITICAL_RESERVE_BYTES,\n 'ackCriticalReserveBytes',\n );\n if (ackCriticalReserveBytes > minFreeBytes) {\n throw new LocalStoragePolicyError(\n 'ackCriticalReserveBytes',\n `must not exceed minFreeBytes — got reserve=${ackCriticalReserveBytes}, min=${minFreeBytes}. An emergency floor above the hard floor would put the device into emergency without ever passing through hard pressure, skipping the admission decline that is supposed to prevent it.`,\n );\n }\n\n const retentionMs: Record<CleanableCategory, number> = { ...DEFAULT_RETENTION_MS };\n for (const [key, value] of Object.entries(input.retentionMs ?? {})) {\n if (!CLEANABLE_CATEGORIES.includes(key as CleanableCategory)) {\n throw new LocalStoragePolicyError(\n `retentionMs.${key}`,\n `is not a cleanable category. Retention can only be configured for ${CLEANABLE_CATEGORIES.join(', ')} — protected data (unacked envelopes, live tasks, unconfirmed terminals, recovery-marked records, user workspaces, quarantine evidence) has no retention because it is never auto-deleted (§12.7.2.1).`,\n );\n }\n retentionMs[key as CleanableCategory] = requireNonNegativeInt(value, `retentionMs.${key}`);\n }\n\n const logRotation: LogRotationPolicy = {\n maxFileBytes: requirePositiveInt(input.logRotation?.maxFileBytes ?? DEFAULT_LOG_ROTATION.maxFileBytes, 'logRotation.maxFileBytes'),\n keepFiles: requireNonNegativeInt(input.logRotation?.keepFiles ?? DEFAULT_LOG_ROTATION.keepFiles, 'logRotation.keepFiles'),\n };\n\n const compaction: CompactionPolicy = {\n incrementalVacuumPages: requirePositiveInt(\n input.compaction?.incrementalVacuumPages ?? DEFAULT_INCREMENTAL_VACUUM_PAGES,\n 'compaction.incrementalVacuumPages',\n ),\n normalIntervalMs: requirePositiveInt(\n input.compaction?.normalIntervalMs ?? DEFAULT_NORMAL_COMPACTION_INTERVAL_MS,\n 'compaction.normalIntervalMs',\n ),\n pressureIntervalMs: requirePositiveInt(\n input.compaction?.pressureIntervalMs ?? DEFAULT_PRESSURE_COMPACTION_INTERVAL_MS,\n 'compaction.pressureIntervalMs',\n ),\n };\n if (compaction.pressureIntervalMs > compaction.normalIntervalMs) {\n throw new LocalStoragePolicyError(\n 'compaction.pressureIntervalMs',\n `must not be longer than compaction.normalIntervalMs — got pressure=${compaction.pressureIntervalMs}, normal=${compaction.normalIntervalMs}. §12.7.2.1 requires compaction to ACCELERATE under pressure.`,\n );\n }\n\n return {\n maxStoreBytes,\n minFreeBytes,\n softMinFreeBytes,\n softBudgetRatio,\n hardBudgetRatio,\n ackCriticalReserveBytes,\n retentionMs,\n logRotation,\n cleanupBatchLimit: requirePositiveInt(input.cleanupBatchLimit ?? DEFAULT_CLEANUP_BATCH_LIMIT, 'cleanupBatchLimit'),\n compaction,\n };\n}\n\n/**\n * When something that became garbage at `since` becomes eligible for automatic\n * cleanup. The ONE place retention turns into a timestamp, so a producer\n * calling `enqueueCleanupCandidate` and this engine consuming it agree by\n * construction rather than by two matching constants.\n */\nexport function cleanupEligibleAt(policy: LocalStoragePolicy, category: CleanableCategory, since: Date): string {\n return new Date(since.getTime() + policy.retentionMs[category]).toISOString();\n}\n\n// ---------------------------------------------------------------------------\n// The watermark state machine (§12.7.2.1's table)\n// ---------------------------------------------------------------------------\n\n/**\n * §12.7.2.1's four states, verbatim:\n *\n * | state | trigger | behaviour |\n * | --- | --- | --- |\n * | `normal` | below soft | unhurried GC/compaction |\n * | `pressure` | ≥ soft budget, or free below the soft minimum | alert; clean only rebuildable/expired categories; accelerate compaction |\n * | `hard-pressure` | ≥ hard budget, or free below the hard minimum | stop admitting new ordinary tasks; terminal/truth flush, delete, export and recovery all continue |\n * | `emergency` | one ack-critical transaction can no longer be guaranteed | fail closed: do not ack new mailbox rows; preserve existing recovery evidence |\n */\nexport type StoragePressureState = 'normal' | 'pressure' | 'hard-pressure' | 'emergency';\n\nexport interface StorageMeasurement {\n readonly usage: LocalStorageUsage;\n readonly freeBytes: number;\n}\n\n/**\n * The state machine itself — a pure function of policy, measurement, and\n * whether an ack-critical write has already been observed to fail.\n *\n * Evaluated worst-first: `emergency` is not \"very bad pressure\", it is a\n * different claim (the next commit may not land), so it is decided before any\n * budget arithmetic. `latchedFailure` exists because the cheapest evidence\n * that a transaction cannot complete is one that already did not: a disk-full\n * error from an ack-critical write is a fact, where free-space arithmetic is\n * an estimate.\n */\nexport function computePressureState(\n policy: LocalStoragePolicy,\n measurement: StorageMeasurement,\n latchedFailure?: string,\n): StoragePressureState {\n if (latchedFailure !== undefined) return 'emergency';\n if (measurement.freeBytes < policy.ackCriticalReserveBytes) return 'emergency';\n if (\n measurement.usage.totalBytes >= policy.maxStoreBytes * policy.hardBudgetRatio ||\n measurement.freeBytes < policy.minFreeBytes\n ) {\n return 'hard-pressure';\n }\n if (\n measurement.usage.totalBytes >= policy.maxStoreBytes * policy.softBudgetRatio ||\n measurement.freeBytes < policy.softMinFreeBytes\n ) {\n return 'pressure';\n }\n return 'normal';\n}\n\n/**\n * §12.7.2.1's cleanup order, 1-5:\n *\n * 1. expired upload/download temp files and rebuildable caches;\n * 2. rotated logs past their retention;\n * 3. journal rows for tasks whose terminal the cloud confirmed and that carry\n * no recovery marker — **compact first, then batch delete**;\n * 4. host-marked ephemeral workspaces for tasks already terminal;\n * 5. orphan artifacts, after a reference scan plus grace period.\n *\n * Under pressure the order is TRUNCATED to steps 1-2, not extended. Steps 3-5\n * touch durable records, need a compaction or a reference scan first, and give\n * their space back slowly; steps 1-2 are pure rebuildable garbage and give it\n * back immediately. Deleting durable evidence is exactly the wrong reflex when\n * the disk is nearly full, so it stays on the unhurried `normal` cadence where\n * a mistake is recoverable.\n */\nexport function cleanupOrderFor(state: StoragePressureState): readonly CleanableCategory[] {\n return state === 'normal'\n ? (['expired-temp', 'rotated-log', 'confirmed-journal', 'ephemeral-workspace', 'orphan-artifact'] as const)\n : (['expired-temp', 'rotated-log'] as const);\n}\n\n// ---------------------------------------------------------------------------\n// The cleanup worker seam\n// ---------------------------------------------------------------------------\n\n/** What a {@link CleanupExecutor} did with one candidate. Mirrors {@link CleanupResult} minus the bookkeeping the engine fills in. */\nexport interface CleanupExecution {\n readonly outcome: 'deleted' | 'skipped' | 'failed';\n readonly bytesReclaimed?: number;\n readonly error?: string;\n}\n\n/**\n * Performs one candidate's actual deletion.\n *\n * A seam rather than a method because the journal owns metadata and the\n * filesystem owns bytes, and the crash window BETWEEN them (delete the file,\n * die before marking; mark, die before deleting) is S3.4 point 12. Keeping\n * them separate is what lets that window be tested at all.\n *\n * It receives a {@link CleanupCandidate}, whose `category` is a\n * {@link CleanableCategory} — so an executor cannot be handed protected data\n * even by a caller trying to.\n */\nexport type CleanupExecutor = (candidate: CleanupCandidate) => Promise<CleanupExecution>;\n\n/** `confirmed-journal` candidates address a journal task, not a path. This prefix is that distinction, spelled out. */\nexport const JOURNAL_TASK_REF_PREFIX = 'task:';\n\nasync function pathBytes(target: string): Promise<number> {\n let stat: Awaited<ReturnType<typeof fs.stat>>;\n try {\n stat = await fs.stat(target);\n } catch {\n return 0;\n }\n if (!stat.isDirectory()) return stat.size;\n let total = 0;\n const entries = await fs.readdir(target, { withFileTypes: true }).catch(() => []);\n for (const entry of entries) total += await pathBytes(join(target, entry.name));\n return total;\n}\n\n/**\n * The default cleanup worker: filesystem removal for the four path-addressed\n * categories, and a delegated journal prune for `confirmed-journal`.\n *\n * Two deliberate behaviours:\n *\n * - **A missing path is `deleted`, not `failed`.** That is S3.4 point 12's\n * first order (file gone, metadata not yet marked) converging on retry: the\n * retry finds nothing to do and says so, rather than looping forever on a\n * candidate whose work is already done.\n * - **A relative `ref` is refused.** Cleanup resolves paths against nothing —\n * a relative ref would delete whatever the daemon's cwd happens to make it,\n * which is not a bug worth having once.\n */\nexport function createFilesystemCleanupExecutor(\n options: { readonly pruneJournalTask?: (taskId: string) => Promise<boolean> } = {},\n): CleanupExecutor {\n return async (candidate) => {\n if (candidate.category === 'confirmed-journal') {\n if (!candidate.ref.startsWith(JOURNAL_TASK_REF_PREFIX)) {\n return { outcome: 'failed', error: `a confirmed-journal candidate's ref must be \"${JOURNAL_TASK_REF_PREFIX}<taskId>\" — got ${JSON.stringify(candidate.ref)}` };\n }\n if (options.pruneJournalTask === undefined) {\n return { outcome: 'skipped', error: 'no journal prune hook is wired; journal rows are never removed by the filesystem worker' };\n }\n const taskId = candidate.ref.slice(JOURNAL_TASK_REF_PREFIX.length);\n const pruned = await options.pruneJournalTask(taskId);\n // Not pruned means the guard refused: the terminal is unconfirmed, or a\n // recovery marker appeared since this candidate was enqueued. `skipped`\n // resolves it without deleting anything, which is the correct outcome —\n // a protected row is not a failure to retry.\n return pruned ? { outcome: 'deleted' } : { outcome: 'skipped', error: 'the journal refused to prune this task (unconfirmed terminal, or a recovery marker)' };\n }\n if (!isAbsolute(candidate.ref)) {\n return { outcome: 'failed', error: `cleanup ref must be an absolute path — got ${JSON.stringify(candidate.ref)}` };\n }\n const bytes = await pathBytes(candidate.ref);\n try {\n await fs.rm(candidate.ref, { recursive: true, force: true });\n } catch (err) {\n return { outcome: 'failed', error: err instanceof Error ? err.message : String(err) };\n }\n return { outcome: 'deleted', bytesReclaimed: bytes };\n };\n}\n\n// ---------------------------------------------------------------------------\n// The engine\n// ---------------------------------------------------------------------------\n\n/** What the status surface renders, and what a `tick()` hands back. */\nexport interface StorageStatusSnapshot {\n readonly state: StoragePressureState;\n readonly measuredAt: string;\n readonly budgetBytes: number;\n readonly usedBytes: number;\n readonly freeBytes: number;\n readonly categories: Readonly<Record<StorageCategory, CategoryUsage>>;\n readonly lastCompaction?: CompactResult & { readonly at: string };\n}\n\nexport type StoragePressureEvent =\n /** §12.7.2.1's \"发出告警\" — emitted on every transition, including back down to `normal`. */\n | { readonly kind: 'state-changed'; readonly from: StoragePressureState; readonly to: StoragePressureState; readonly snapshot: StorageStatusSnapshot }\n | { readonly kind: 'cleanup'; readonly result: CleanupResult; readonly category: CleanableCategory }\n | { readonly kind: 'compaction'; readonly result: CompactResult };\n\nexport interface StorageTickResult {\n readonly state: StoragePressureState;\n readonly snapshot: StorageStatusSnapshot;\n readonly cleaned: readonly CleanupResult[];\n readonly compaction?: CompactResult;\n}\n\nexport interface TimerLike {\n setInterval(handler: () => void, ms: number): unknown;\n clearInterval(handle: unknown): void;\n}\n\nexport interface LocalStoragePressureEngineOptions {\n readonly policy: LocalStoragePolicy | LocalStoragePolicyInput;\n readonly journal: LocalTaskJournal;\n /** Free bytes on the store's filesystem. `fs.statfs` in production (see {@link createStatfsFreeBytesProvider}); a fixed number under test. */\n readonly freeBytesProvider: () => number | Promise<number>;\n /** Performs deletions. Defaults to {@link createFilesystemCleanupExecutor}. */\n readonly executor?: CleanupExecutor;\n readonly clock?: () => Date;\n readonly onEvent?: (event: StoragePressureEvent) => void;\n /** Reports only the scheduler's own maintenance pass outcome; never includes task-domain failures. */\n readonly onMaintenanceOutcome?: (outcome: 'success' | 'failure') => void;\n /** Injected so `start()`'s periodic driver is substitutable; the matrix never uses it and drives {@link LocalStoragePressureEngine.tick} directly. */\n readonly timers?: TimerLike;\n}\n\n/**\n * Drives §12.7.2.1: measure, decide the state, clean in order, compact within\n * bounds — and answer the two questions the rest of the daemon asks\n * ({@link admissionGuard}, {@link assertAckCriticalAllowed}).\n *\n * The cadence is a caller-driven {@link tick}. `start()` merely arranges for\n * something to call it periodically, so a host with its own scheduler can skip\n * it entirely, and the disk-pressure matrix can advance state deterministically\n * with no timer at all. Nothing here runs on the envelope or task hot path:\n * the only two things the hot path calls are the two synchronous questions,\n * both of which read a field.\n */\nexport class LocalStoragePressureEngine {\n readonly policy: LocalStoragePolicy;\n readonly #journal: LocalTaskJournal;\n readonly #freeBytesProvider: () => number | Promise<number>;\n readonly #executor: CleanupExecutor;\n readonly #clock: () => Date;\n readonly #onEvent: ((event: StoragePressureEvent) => void) | undefined;\n readonly #onMaintenanceOutcome: ((outcome: 'success' | 'failure') => void) | undefined;\n readonly #timers: TimerLike;\n\n #state: StoragePressureState = 'normal';\n #snapshot: StorageStatusSnapshot | undefined;\n #latchedFailure: string | undefined;\n #lastCompaction: (CompactResult & { at: string }) | undefined;\n #nextCompactionAtMs = 0;\n #timer: unknown;\n #timerIntervalMs = 0;\n #tickInFlight: Promise<StorageTickResult> | undefined;\n\n constructor(options: LocalStoragePressureEngineOptions) {\n // Resolved unconditionally, not \"resolved if it looks unresolved\": an\n // already-resolved policy is a valid input and comes back out unchanged, so\n // there is no shape-sniffing to get wrong, and an engine a host builds\n // directly gets the same up-front rejection `createDaemon` gives.\n this.policy = resolveLocalStoragePolicy(options.policy);\n this.#journal = options.journal;\n this.#freeBytesProvider = options.freeBytesProvider;\n this.#executor = options.executor ?? createFilesystemCleanupExecutor();\n this.#clock = options.clock ?? (() => new Date());\n this.#onEvent = options.onEvent;\n this.#onMaintenanceOutcome = options.onMaintenanceOutcome;\n this.#timers = options.timers ?? {\n setInterval: (handler, ms) => {\n const timer = setInterval(handler, ms);\n timer.unref?.();\n return timer;\n },\n clearInterval: (handle) => clearInterval(handle as NodeJS.Timeout),\n };\n }\n\n get state(): StoragePressureState {\n return this.#state;\n }\n\n /** The last measured snapshot, or `undefined` before the first {@link tick}. */\n snapshot(): StorageStatusSnapshot | undefined {\n return this.#snapshot;\n }\n\n /**\n * §12.7.2.1's hard-pressure row, as a `TaskRunnerDeps.admissionGuard`:\n * \"停止接收新的普通 task;仍允许 terminal/truth flush、删除、导出、doctor 与\n * 恢复操作\".\n *\n * The decline is RETRYABLE because pressure is a property of this device at\n * this moment — a dispatcher re-routing the task to another device genuinely\n * helps, and the same device may take it in a minute. Nothing in this method\n * touches the disk; it reads the state the last tick computed, so an offer\n * arriving between ticks is answered instantly.\n */\n admissionGuard(): { readonly admit: true } | { readonly admit: false; readonly reason: string; readonly retryable: boolean } {\n if (this.#state === 'hard-pressure') {\n return { admit: false, reason: 'local storage hard pressure', retryable: true };\n }\n if (this.#state === 'emergency') {\n return { admit: false, reason: 'local storage emergency: cannot guarantee an ack-critical journal transaction', retryable: true };\n }\n return { admit: true };\n }\n\n /** Throws {@link LocalStorageEmergencyError} while in `emergency`. Called immediately before every ack-critical journal append. */\n assertAckCriticalAllowed(): void {\n if (this.#state !== 'emergency') return;\n throw new LocalStorageEmergencyError(\n this.#latchedFailure ??\n `free space is below the ${this.policy.ackCriticalReserveBytes}-byte ack-critical reserve`,\n );\n }\n\n /**\n * Latch `emergency` from an ack-critical write that ACTUALLY failed.\n *\n * A commit that returned `SQLITE_FULL` is stronger evidence than any free-space\n * estimate, and it must not be forgotten on the next tick just because the\n * arithmetic happens to look survivable. The latch clears only when a tick\n * measures a genuinely `normal` device — not `pressure`, not `hard-pressure`:\n * coming back from \"the disk refused a write\" requires actual headroom, not a\n * borderline reading.\n */\n noteAckCriticalFailure(reason: string): void {\n this.#latchedFailure = reason;\n this.#transitionTo('emergency', this.#snapshot);\n }\n\n /**\n * One maintenance pass: measure, transition, clean in order, compact if due.\n *\n * Ordered this way on purpose — the cleanup pass acts on the state THIS\n * measurement produced, so a device that just crossed into pressure cleans on\n * the same tick it alerts, rather than one cadence later.\n */\n tick(): Promise<StorageTickResult> {\n if (this.#tickInFlight) return this.#tickInFlight;\n const tick = this.#runTick();\n this.#tickInFlight = tick;\n void tick.then(\n () => {\n if (this.#tickInFlight === tick) this.#tickInFlight = undefined;\n },\n () => {\n if (this.#tickInFlight === tick) this.#tickInFlight = undefined;\n },\n );\n return tick;\n }\n\n async #runTick(): Promise<StorageTickResult> {\n const usage = await this.#journal.measureUsage();\n const freeBytes = await this.#freeBytesProvider();\n const measurement: StorageMeasurement = { usage, freeBytes };\n\n // The latch clears only against a genuinely `normal` reading — see\n // `noteAckCriticalFailure` for why a borderline one is not enough.\n if (this.#latchedFailure !== undefined && computePressureState(this.policy, measurement) === 'normal') {\n this.#latchedFailure = undefined;\n }\n const state = computePressureState(this.policy, measurement, this.#latchedFailure);\n\n const snapshot: StorageStatusSnapshot = {\n state,\n measuredAt: usage.measuredAt,\n budgetBytes: this.policy.maxStoreBytes,\n usedBytes: usage.totalBytes,\n freeBytes,\n categories: usage.categories,\n ...(this.#lastCompaction ? { lastCompaction: this.#lastCompaction } : {}),\n };\n this.#snapshot = snapshot;\n if (state !== this.#state) this.#transitionTo(state, snapshot);\n\n const cleaned = await this.#runCleanupPass(state);\n const compaction = await this.#compactIfDue(state);\n\n // A compaction result that landed during THIS tick belongs to this tick's\n // snapshot; recomputing it here (rather than waiting for the next tick)\n // keeps `status` from reporting a stale \"last compaction\" immediately after\n // one ran.\n const finalSnapshot: StorageStatusSnapshot = this.#lastCompaction\n ? { ...snapshot, lastCompaction: this.#lastCompaction }\n : snapshot;\n this.#snapshot = finalSnapshot;\n\n return { state, snapshot: finalSnapshot, cleaned, ...(compaction ? { compaction } : {}) };\n }\n\n /** Begin periodic ticking. A host with its own scheduler need never call this. */\n start(): void {\n this.#arm(this.#intervalMs());\n }\n\n async stop(): Promise<void> {\n if (this.#timer !== undefined) this.#timers.clearInterval(this.#timer);\n this.#timer = undefined;\n this.#timerIntervalMs = 0;\n // Clearing the cadence prevents new maintenance, but the callback may\n // already be inside SQLite. Wait for that pass to settle before the daemon\n // closes the owned journal. Its scheduler callback reports any failure;\n // shutdown's responsibility here is the barrier, not reporting it twice.\n await this.#tickInFlight?.catch(() => {});\n }\n\n #intervalMs(): number {\n return this.#state === 'normal' ? this.policy.compaction.normalIntervalMs : this.policy.compaction.pressureIntervalMs;\n }\n\n #arm(intervalMs: number): void {\n if (this.#timer !== undefined && this.#timerIntervalMs === intervalMs) return;\n if (this.#timer !== undefined) this.#timers.clearInterval(this.#timer);\n this.#timerIntervalMs = intervalMs;\n this.#timer = this.#timers.setInterval(() => {\n // A slow checkpoint must never overlap the next cadence. Apart from\n // duplicating maintenance work, concurrent ticks would make stop()'s\n // single in-flight barrier incomplete.\n if (this.#tickInFlight) return;\n // A maintenance pass that throws (an unreadable journal, a filesystem\n // that will not answer statfs) must not take the process down from a\n // timer callback with no caller to reject to. The state simply does not\n // advance, which leaves the last known one in force — and the last known\n // one erring toward MORE restriction is the safe direction.\n void this.tick().then(\n () => this.#onMaintenanceOutcome?.('success'),\n (err: unknown) => {\n this.#onMaintenanceOutcome?.('failure');\n console.warn(\n `[byok/client] local storage maintenance pass failed (state stays \"${this.#state}\"): ${err instanceof Error ? err.message : String(err)}`,\n );\n },\n );\n }, intervalMs);\n }\n\n #transitionTo(state: StoragePressureState, snapshot: StorageStatusSnapshot | undefined): void {\n if (state === this.#state) return;\n const from = this.#state;\n this.#state = state;\n if (this.#timer !== undefined) this.#arm(this.#intervalMs());\n if (snapshot !== undefined) {\n this.#onEvent?.({ kind: 'state-changed', from, to: state, snapshot: { ...snapshot, state } });\n }\n }\n\n /**\n * §12.7.2.1's ordered, bounded cleanup.\n *\n * One bounded batch is read from the journal and then walked in CATEGORY\n * order rather than the eligibility order the query returns — the order in\n * the spec is a priority, not a schedule, and a batch full of orphan\n * artifacts must not push the cheap rebuildable categories out of the pass.\n * The batch limit bounds the whole pass, not each category, so the total work\n * per tick is what the policy says it is.\n */\n async #runCleanupPass(state: StoragePressureState): Promise<CleanupResult[]> {\n const allowed = cleanupOrderFor(state);\n const now = this.#clock();\n const candidates = await this.#journal.listCleanupCandidates(now, this.policy.cleanupBatchLimit);\n const results: CleanupResult[] = [];\n\n for (const category of allowed) {\n const group = candidates.filter((candidate) => candidate.category === category);\n if (group.length === 0) continue;\n // §12.7.2.1 step 3, verbatim: \"先 compact 再 batch delete\". Pruning rows\n // out of a database whose WAL has not been applied yet just moves the\n // pages around; compacting first is what makes the delete actually\n // return space.\n if (category === 'confirmed-journal') await this.#compact(state);\n for (const candidate of group) {\n const result = await this.#execute(candidate);\n results.push(result);\n this.#onEvent?.({ kind: 'cleanup', result, category });\n }\n }\n return results;\n }\n\n async #execute(candidate: CleanupCandidate): Promise<CleanupResult> {\n let execution: CleanupExecution;\n try {\n execution = await this.#executor(candidate);\n } catch (err) {\n // The executor crashed mid-candidate — S3.4 point 12's first order. The\n // candidate stays UNRESOLVED (`failed` does not set `resolved_at`, see\n // `markCleanupResult`), so the next pass retries it; the retry finds the\n // work already done and converges.\n execution = { outcome: 'failed', error: err instanceof Error ? err.message : String(err) };\n }\n const result: CleanupResult = {\n candidateId: candidate.candidateId,\n outcome: execution.outcome,\n ...(execution.bytesReclaimed === undefined ? {} : { bytesReclaimed: execution.bytesReclaimed }),\n ...(execution.error === undefined ? {} : { error: execution.error }),\n at: this.#clock().toISOString(),\n };\n await this.#journal.markCleanupResult(result);\n return result;\n }\n\n async #compactIfDue(state: StoragePressureState): Promise<CompactResult | undefined> {\n const nowMs = this.#clock().getTime();\n if (nowMs < this.#nextCompactionAtMs) return undefined;\n return this.#compact(state);\n }\n\n /**\n * A bounded WAL checkpoint plus incremental vacuum.\n *\n * `truncate` above `normal` because that is the mode that actually returns\n * the WAL file's space; `passive` while normal because it never blocks a\n * reader and there is no hurry. Both are bounded by\n * `incrementalVacuumPages`, and both go through the journal's own\n * single-writer queue — so a compaction can never interleave with an\n * ack-critical append, and can never hold the queue for longer than that\n * page bound allows.\n */\n async #compact(state: StoragePressureState): Promise<CompactResult> {\n const result = await this.#journal.compact({\n checkpoint: state === 'normal' ? 'passive' : 'truncate',\n incrementalVacuumPages: this.policy.compaction.incrementalVacuumPages,\n });\n this.#lastCompaction = { ...result, at: this.#clock().toISOString() };\n this.#nextCompactionAtMs =\n this.#clock().getTime() +\n (state === 'normal' ? this.policy.compaction.normalIntervalMs : this.policy.compaction.pressureIntervalMs);\n this.#onEvent?.({ kind: 'compaction', result });\n return result;\n }\n}\n\n/**\n * Production free-space provider: bytes available to an unprivileged process\n * on the filesystem holding `dir`.\n *\n * `bavail`, not `bfree` — the reserved blocks `bfree` includes are not space\n * this daemon can write into, and treating them as headroom is how a device\n * discovers it is out of disk at commit time instead of at measurement time.\n */\nexport function createStatfsFreeBytesProvider(dir: string): () => Promise<number> {\n return async () => {\n const stats = await fs.statfs(dir);\n return Number(stats.bavail) * Number(stats.bsize);\n };\n}\n","/**\n * M5: per-runtime environment allowlist for spawned agent child processes.\n *\n * Before this module existed, `task-runner.ts` built every task's\n * `TaskContext.env` as `process.env` verbatim — the daemon's OWN full\n * environment, unfiltered, handed to whichever runtime CLI (`pi`/`claude`/\n * `codex`) `pickAdapter` selected. Any credential-shaped variable sitting in\n * the daemon's own environment for a completely unrelated reason (an\n * `AWS_SECRET_ACCESS_KEY`, `DATABASE_URL`, `GITHUB_TOKEN` set for the\n * daemon's OWN deployment, nothing to do with any coding-agent runtime) was\n * therefore inherited by every single spawned agent process — a\n * credential-leak gap, not a deliberate design choice.\n *\n * {@link buildRuntimeEnv} replaces that blanket passthrough with an explicit\n * allowlist, built fresh per task from three layers:\n *\n * 1. A small, always-included platform baseline ({@link BASE_PLATFORM_ALLOWLIST}\n * / {@link WINDOWS_BASE_ALLOWLIST}) — the bare minimum any CLI needs to\n * resolve its own binaries/libraries, find a home/temp directory, and\n * behave sanely in a non-interactive shell.\n * 2. Whatever ADDITIONAL names the *specific* runtime adapter about to be\n * spawned declares it actually needs\n * (`RuntimeAdapter.environmentRequirements()` — see `../types.ts`). An\n * adapter that declares nothing at all (doesn't implement the optional\n * method) gets the platform baseline ONLY — fail-closed by construction,\n * not by an extra check here.\n * 3. A per-device, per-runtime operator override (`DaemonConfig\n * .runtimeEnvironment` — see `create-daemon.ts`) — a local escape hatch\n * for a product/operator that knows it needs one more variable forwarded\n * to one specific runtime on this one device.\n *\n * One hard, unconditional deny always wins over all three layers above,\n * including the operator's own override: `BYOK_*`, this SDK's own\n * control-plane variables, must never reach a spawned agent process — see\n * {@link HARD_DENY_PATTERNS}.\n *\n * Every name in every list may be an exact match or a `*`-suffixed prefix\n * (e.g. `'LC_*'` matches `LC_ALL`, `LC_CTYPE`, ...).\n */\n\n/**\n * What one runtime adapter declares it needs beyond the always-included\n * platform baseline. Returned from the optional\n * `RuntimeAdapter.environmentRequirements()` method (`../types.ts`).\n */\nexport interface RuntimeEnvironmentRequirements {\n /**\n * Extra non-secret, config-discovery-shaped variable names this runtime's\n * own CLI reads (e.g. a `<RUNTIME>_CONFIG_DIR`-style override) — anything\n * that isn't itself a credential. Optional: most adapters need nothing\n * beyond the platform baseline.\n */\n baseNames?: readonly string[];\n /**\n * Credential/auth variable names this runtime's own CLI reads to\n * authenticate (e.g. a provider API key). Kept as its own field (distinct\n * from `baseNames`) so a product's own security review can reason about\n * \"what credential-shaped names does this runtime get\" as a single,\n * explicit list per adapter — see e.g. the pi adapter's\n * `KNOWN_PROVIDER_ENV_VARS`.\n */\n credentialNames?: readonly string[];\n}\n\n/** Inputs to {@link buildRuntimeEnv}. */\nexport interface BuildRuntimeEnvOptions {\n /**\n * The daemon's own ambient environment (normally `process.env`). Never\n * mutated — every returned variable is copied into a fresh object.\n */\n ambient: NodeJS.ProcessEnv;\n /**\n * The selected runtime adapter's own declared requirements —\n * `undefined` (no `environmentRequirements()` implementation on that\n * adapter) means \"platform baseline only,\" fail-closed.\n */\n requirements?: RuntimeEnvironmentRequirements;\n /**\n * This device's own operator-configured escape hatch for this one runtime\n * (`DaemonConfig.runtimeEnvironment?.[adapterId]?.allow`) — merged in like\n * any other allowlist entry, still subject to the hard deny below.\n */\n locallyAllowedNames?: readonly string[];\n /**\n * Test seam: which platform's extra base vars to include\n * ({@link WINDOWS_BASE_ALLOWLIST} vs none) — defaults to `process.platform`\n * so callers never have to think about it, while still letting a test\n * exercise the win32 branch deterministically on any host OS.\n */\n platform?: NodeJS.Platform;\n}\n\n/**\n * Always included regardless of runtime or platform — the bare minimum any\n * CLI needs to resolve its own binary/libraries, find a home/temp\n * directory, and behave sanely in a non-interactive shell. `XDG_*` matters\n * specifically: a user with `XDG_CONFIG_HOME` set relies on it for\n * claude/codex's own login-state discovery — omitting it would silently\n * break auth detection for those users, not just cosmetic config lookup.\n *\n * F3: the four standard proxy variables are included here deliberately, in\n * both `SCREAMING_CASE` (what curl and most CLIs check first) and lowercase\n * `snake_case` (the conventional form on Unix — some tools check only one\n * spelling, some check both), not gated behind any adapter's own\n * `environmentRequirements()`: an agent CLI spawned behind a corporate proxy\n * with none of these forwarded silently loses all outbound network access —\n * a materially worse default than forwarding a proxy URL. See\n * docs/security.md's environment-allowlist section for the accepted\n * trade-off this implies (a proxy URL may itself embed proxy credentials).\n */\nconst BASE_PLATFORM_ALLOWLIST: readonly string[] = [\n 'PATH',\n 'HOME',\n 'USERPROFILE',\n 'TMPDIR',\n 'TEMP',\n 'TMP',\n 'LANG',\n 'TZ',\n 'TERM',\n 'SHELL',\n 'LC_*',\n 'XDG_*',\n 'HTTP_PROXY',\n 'HTTPS_PROXY',\n 'NO_PROXY',\n 'ALL_PROXY',\n 'http_proxy',\n 'https_proxy',\n 'no_proxy',\n 'all_proxy',\n];\n\n/** Additional always-included names on win32 only — see {@link BuildRuntimeEnvOptions.platform}. */\nconst WINDOWS_BASE_ALLOWLIST: readonly string[] = [\n 'SystemRoot',\n 'COMSPEC',\n 'PATHEXT',\n 'windir',\n 'SYSTEMDRIVE',\n 'PROGRAMFILES',\n 'APPDATA',\n 'LOCALAPPDATA',\n];\n\n/**\n * Hard deny — wins unconditionally over every allowlist layer above (the\n * platform baseline, an adapter's own declared requirements, AND the\n * operator's own local override): this SDK's own control-plane variables\n * must never reach a spawned agent process, full stop. A product embedding\n * this SDK cannot accidentally (or deliberately, via\n * `runtimeEnvironment.<id>.allow`) punch a hole in this. Checked LAST in\n * {@link buildRuntimeEnv}'s per-variable decision, deliberately: it must be\n * the final word on every single variable, never short-circuited past by an\n * earlier allow match.\n */\nconst HARD_DENY_PATTERNS: readonly string[] = ['BYOK_*'];\n\n/**\n * F1: `caseInsensitive` is `true` only on win32 (see {@link buildRuntimeEnv}).\n * Windows environment variable names are case-insensitive at the OS level\n * but NOT case-normalized by Node — `process.env` hands back whatever\n * casing the variable actually has there (`Path`, `ComSpec`,\n * `SystemDrive`, `ProgramFiles`, ...), which routinely does not match this\n * module's own SCREAMING_CASE pattern spelling byte-for-byte. Uppercasing\n * both sides before comparing (rather than, say, only uppercasing `name`)\n * keeps this symmetric and correct regardless of which side happens to be\n * mixed-case. Non-win32 platforms never set `caseInsensitive`, so this stays\n * byte-exact there — unchanged from before F1.\n */\nfunction matchesPattern(name: string, pattern: string, caseInsensitive: boolean): boolean {\n const candidateName = caseInsensitive ? name.toUpperCase() : name;\n const candidatePattern = caseInsensitive ? pattern.toUpperCase() : pattern;\n return candidatePattern.endsWith('*')\n ? candidateName.startsWith(candidatePattern.slice(0, -1))\n : candidateName === candidatePattern;\n}\n\nfunction matchesAny(name: string, patterns: readonly string[], caseInsensitive: boolean): boolean {\n return patterns.some((pattern) => matchesPattern(name, pattern, caseInsensitive));\n}\n\n/**\n * Build the environment one specific runtime's spawned child process should\n * actually receive — a fresh object, never `options.ambient` itself and\n * never mutated in place. See this module's own doc comment for the full\n * allow/deny model.\n */\nexport function buildRuntimeEnv(options: BuildRuntimeEnvOptions): Record<string, string> {\n const platform = options.platform ?? process.platform;\n // F1: win32 only — see `matchesPattern`'s own doc comment for why OS-cased\n // keys make case-sensitive matching silently wrong there specifically.\n // Every other platform keeps exact case-sensitive matching, unchanged.\n const caseInsensitive = platform === 'win32';\n const allowPatterns: readonly string[] = [\n ...BASE_PLATFORM_ALLOWLIST,\n ...(platform === 'win32' ? WINDOWS_BASE_ALLOWLIST : []),\n ...(options.requirements?.baseNames ?? []),\n ...(options.requirements?.credentialNames ?? []),\n ...(options.locallyAllowedNames ?? []),\n ];\n\n const result: Record<string, string> = {};\n for (const [name, value] of Object.entries(options.ambient)) {\n if (value === undefined) continue;\n // Deny checked LAST, deliberately (see HARD_DENY_PATTERNS's own doc\n // comment) — this must be the final word on every single variable. Also\n // case-insensitive on win32 (F1): a mixed-case `Byok_Secret` must be\n // denied there exactly as `BYOK_SECRET` is denied everywhere else — the\n // operator's own local override must not be able to punch a hole in the\n // hard deny just because win32 happened to hand back different casing.\n if (matchesAny(name, allowPatterns, caseInsensitive) && !matchesAny(name, HARD_DENY_PATTERNS, caseInsensitive)) {\n result[name] = value;\n }\n }\n return result;\n}\n","import type { PermissionMode, PermissionPolicy } from '@byok-sdk/protocol';\n\n/**\n * Permissiveness ranking used only to compare an offered policy against the\n * device operator's configured ceiling (`permissionDefaults`). The wire\n * protocol doesn't define an ordering for `PermissionMode`, so this is a\n * judgment call: `plan` produces no side effects (safest), `readonly` allows\n * autonomous but non-mutating tools, `confirm` allows anything but gates each\n * action on a human, `auto` allows anything with no gate at all (most\n * latitude without a human in the loop).\n */\nconst MODE_RANK: Record<PermissionMode, number> = {\n plan: 0,\n readonly: 1,\n confirm: 2,\n auto: 3,\n};\n\nexport interface PolicyDecision {\n ok: boolean;\n /** The merged, effective policy. Only meaningful when `ok` is true. */\n policy: PermissionPolicy;\n /** Present when `ok` is false. */\n reason?: string;\n}\n\nfunction intersectOptional(a: string[] | undefined, b: string[] | undefined): string[] | undefined {\n if (!a) return b;\n if (!b) return a;\n const bSet = new Set(b);\n return a.filter((tool) => bSet.has(tool));\n}\n\nfunction unionOptional(a: string[] | undefined, b: string[] | undefined): string[] {\n return Array.from(new Set([...(a ?? []), ...(b ?? [])]));\n}\n\n/**\n * `network` merge: an explicit `false` on either side wins (it's a request\n * to restrict that nothing here should silently overrule); otherwise an\n * explicit `true` on either side wins; if neither side expressed an opinion\n * the result is `undefined`; and it's left to the adapter mapping to decide\n * what \"unspecified\" defaults to for that runtime.\n */\nfunction mergeNetwork(offered: boolean | undefined, ceiling: boolean | undefined): boolean | undefined {\n if (offered === false || ceiling === false) return false;\n if (offered === true || ceiling === true) return true;\n return undefined;\n}\n\n/**\n * Merge an offered task policy against the daemon operator's configured\n * ceiling, fail-closed. This is a runtime-agnostic safety gate independent\n * of whether the eventually-chosen adapter can even express the result — see\n * each adapter's own permission mapping for that second, adapter-specific\n * gate (e.g. `mapPermissionPolicyToPiArgs`).\n */\nexport function computeEffectivePolicy(\n offered: PermissionPolicy,\n ceiling: PermissionPolicy | undefined,\n): PolicyDecision {\n if (!ceiling) {\n return { ok: true, policy: offered };\n }\n\n if (MODE_RANK[offered.mode] > MODE_RANK[ceiling.mode]) {\n return {\n ok: false,\n policy: offered,\n reason: `offered policy mode \"${offered.mode}\" exceeds this device's configured ceiling \"${ceiling.mode}\"`,\n };\n }\n\n const allowTools = intersectOptional(offered.allowTools, ceiling.allowTools);\n const denyTools = unionOptional(offered.denyTools, ceiling.denyTools);\n const network = mergeNetwork(offered.network, ceiling.network);\n const workspaceRoot = offered.workspaceRoot ?? ceiling.workspaceRoot;\n\n return {\n ok: true,\n policy: {\n mode: offered.mode,\n ...(allowTools ? { allowTools } : {}),\n ...(denyTools.length > 0 ? { denyTools } : {}),\n ...(workspaceRoot !== undefined ? { workspaceRoot } : {}),\n ...(network !== undefined ? { network } : {}),\n },\n };\n}\n","import type { AgentEvent } from '@byok-sdk/protocol';\n\nexport type ProgressEmitter = (seq: number, events: AgentEvent[]) => void;\n\nexport interface ProgressBatcherOptions {\n /** Flush immediately once this many events are buffered. Default 10. */\n maxBatchSize?: number;\n /** Otherwise flush at most this often (ms) while events are pending. Default 250 (~4/sec). */\n flushIntervalMs?: number;\n}\n\n/**\n * Coalesces a task's `AgentEvent`s into seq-ordered `task.progress` batches:\n * flush immediately at `maxBatchSize` events, otherwise at most every\n * `flushIntervalMs` while anything is buffered. One instance per task —\n * `seq` is a per-task monotonic counter starting at 1.\n */\nexport class ProgressBatcher {\n private buffer: AgentEvent[] = [];\n private seq = 0;\n private timer: ReturnType<typeof setTimeout> | undefined;\n private readonly maxBatchSize: number;\n private readonly flushIntervalMs: number;\n\n constructor(\n private readonly emit: ProgressEmitter,\n options: ProgressBatcherOptions = {},\n ) {\n this.maxBatchSize = options.maxBatchSize ?? 10;\n this.flushIntervalMs = options.flushIntervalMs ?? 250;\n }\n\n push(event: AgentEvent): void {\n this.buffer.push(event);\n if (this.buffer.length >= this.maxBatchSize) {\n this.flush();\n return;\n }\n this.ensureTimer();\n }\n\n /** M4 Phase 4 (part B.3, observability): events buffered right now, not yet flushed as a `task.progress` batch — a cheap per-task queue-depth watermark for the daemon's control-socket `status` result (see `task-runner.ts`'s `getQueueWatermarks`). */\n get pendingCount(): number {\n return this.buffer.length;\n }\n\n flush(): void {\n this.clearTimer();\n if (this.buffer.length === 0) return;\n const batch = this.buffer;\n this.buffer = [];\n this.seq += 1;\n this.emit(this.seq, batch);\n }\n\n /** Stop the pending flush timer without flushing (used on teardown). */\n stop(): void {\n this.clearTimer();\n }\n\n private ensureTimer(): void {\n if (this.timer) return;\n this.timer = setTimeout(() => this.flush(), this.flushIntervalMs);\n }\n\n private clearTimer(): void {\n if (this.timer) {\n clearTimeout(this.timer);\n this.timer = undefined;\n }\n }\n}\n","import { randomUUID } from 'node:crypto';\nimport { promises as fs, constants as fsConstants } from 'node:fs';\nimport type { FileHandle } from 'node:fs/promises';\nimport path from 'node:path';\nimport {\n createEnvelope,\n RuntimeIdSchema,\n type AgentEvent,\n type BlobRef,\n type Envelope,\n type PermissionMode,\n type PermissionPolicy,\n type RuntimeId,\n type TaskOfferPayload,\n} from '@byok-sdk/protocol';\nimport { PolicyUnsupportedError, SteerUnsupportedError, type RuntimeAdapter, type Session, type TaskContext } from '../types';\nimport { ApprovalNotFoundError, type ApprovalDecision, type ApprovalOrigin, type ApprovalRegistry } from './approvals';\nimport type { BlobResolver } from './blob-client';\nimport type { TaskQueueWatermark } from './control-protocol';\nimport { buildRuntimeEnv } from './environment';\nimport { computeEffectivePolicy } from './policy';\nimport { toRuntimeInfoCapabilities } from './runtime-capabilities';\nimport { ProgressBatcher, type ProgressBatcherOptions } from './progress-batcher';\nimport type { SessionWorkspaceStore } from './session-workspace-store';\nimport type { GitWorkspaceManager, GitWorkspaceLease, GitWorkspaceObservation, GitWorkspaceError, GitErrorCategory } from './git-workspace';\nimport { prependGitWorkspaceGuidance } from './git-workspace';\nimport type { GitWorkspaceStore, GitWorkspaceLedgerRecord, GitWorkspacePhase } from './git-workspace-store';\n\n/**\n * M4 Phase 3: default wait for `requestApproval` (see its own doc comment)\n * before force-resolving an unanswered out-of-band approval as a fail-closed\n * rejection — generous enough for a real human to actually notice and act on\n * an approval prompt, short enough that a genuinely abandoned task doesn't\n * tie up daemon/task bookkeeping forever. Overridable via\n * `TaskRunnerDeps.approvalTimeoutMs` (ultimately `DaemonConfig`-configurable —\n * see `create-daemon.ts`).\n */\nexport const DEFAULT_APPROVAL_TIMEOUT_MS = 10 * 60_000;\n\n/**\n * Finding F5(a) (cross-model adversarial review): bound on how long\n * `shutdownTask` waits for a single task's OWN `session.interrupt()` before\n * giving up on it specifically and reporting `task.fail` anyway. Without an\n * INNER bound here, a hung `interrupt()` (a misbehaving runtime adapter\n * whose promise never settles) meant `task.fail` for THAT task was never\n * sent at all — not eventually, not ever — because the send was sequenced\n * strictly AFTER the `await`. The OUTER deadline\n * `create-daemon.ts`'s `performControlShutdown` races `shutdownActiveTasks`\n * against (`SHUTDOWN_TASK_TEARDOWN_DEADLINE_MS`) does not help: racing at\n * that layer only unblocks the CALLER to proceed to `stop()`/closing the\n * connection — it does nothing to unstick THIS function's own\n * still-suspended `await`, which just keeps running (harmlessly, since\n * nothing awaits it anymore) in the background forever after, its\n * `deps.send` line never reached. Deliberately shorter than the outer\n * 10s deadline so one hung task's own interrupt can't itself consume the\n * whole outer budget and starve however many OTHER tasks\n * `shutdownActiveTasks` awaits concurrently via `Promise.all`. Overridable\n * via `TaskRunnerDeps.shutdownInterruptTimeoutMs` (ultimately\n * `DaemonOverrides.shutdown.taskInterruptTimeoutMs` — see `create-daemon.ts`).\n */\nexport const DEFAULT_SHUTDOWN_INTERRUPT_TIMEOUT_MS = 5_000;\n\n/** Bound best-effort Git observation so terminal protocol outcomes cannot wait forever on repository I/O. */\nconst GIT_OBSERVATION_TIMEOUT_MS = 5_000;\n\n/**\n * M4 Phase 4 (fold-in from the P3 gate): bound on how many `requestApproval`\n * calls may sit QUEUED (not yet dispatched — see that method's own doc\n * comment) for the same task at once. Claude's parallel tool use can fire\n * more than one concurrent approval request for the same taskId; this is a\n * defensive ceiling on that fan-out, mirroring `approvals.ts`'s own\n * `MAX_PENDING_APPROVALS` (a whole-daemon cap) one level down (a per-task\n * cap) — not a realistic workload limit. A request arriving once a task's\n * queue is already at this size is rejected fail-closed immediately, the\n * same shape `requestApproval` already uses for an unknown/inactive taskId.\n */\nexport const MAX_PENDING_APPROVALS_PER_TASK = 16;\n\n/**\n * M4 Phase 3 hardening (orchestrator-directed fix): thrown by the\n * `ctx.approvalChannel.resolve` closure built in `handleOffer` below when\n * this task has no CURRENTLY pending out-of-band approval to resolve.\n * Distinguished from a plain `Error` specifically so `handleApprove`/\n * `handleReject` can tell \"a wire task.approve/task.reject arrived for an\n * approval a DIFFERENT, faster path (a racing local `approvals.resolve`, or\n * this exact decision arriving twice) already resolved\" — a benign,\n * expected race, audit-worthy but never task-state-affecting — apart from\n * \"the session's own resolveApproval() failed for some other, genuine\n * reason\" (an adapter-level problem, which still fails the task exactly as\n * before). Only ever thrown for an adapter that actually wires up a real\n * approval channel (claude, under `confirm` mode) — pi/codex's own\n * `resolveApproval()` still throw their own unrelated, adapter-specific\n * \"not supported at all\" errors, which are NOT instances of this class and\n * therefore still fall through to the pre-existing fail-the-task behavior,\n * unchanged.\n */\nexport class NoPendingApprovalError extends Error {\n constructor(public readonly taskId: string) {\n super(`no pending out-of-band approval to resolve for task ${taskId}`);\n this.name = 'NoPendingApprovalError';\n }\n}\n\n/** Inline artifact payloads must stay under this many UTF-8 bytes — mirrors the frozen `TaskArtifactPayloadSchema.inline` limit in `packages/protocol` (see docs/protocol.md §7). Anything bigger goes through the blob client. */\nconst MAX_INLINE_ARTIFACT_BYTES = 64 * 1024;\n\n/**\n * M3-B: cap for both `finishedTaskIds` and `pendingCancelled` below (each\n * gains one entry per finished/cancelled task and was never pruned) — fine\n * for the short-lived CLI invocations M0-M2 ran as, but M3 turns the daemon\n * into a background service meant to stay up for weeks, so unbounded growth\n * here is a real, if slow, memory leak. Each collection evicts its OLDEST\n * (first-inserted) entry once over this cap — the same bounded-ring idiom\n * `ConnectionHub`'s per-device dedup window already uses server-side\n * (packages/server/src/hub.ts's `DEDUP_RING_CAPACITY`), just applied here to\n * task ids. `Map`/`Set` iterate in insertion order (ECMA-262), so \"oldest\"\n * always means \"finished/cancelled longest ago\" — neither collection is\n * touched on a read, only on insert, so eviction order depends purely on\n * insertion time. See `finishedTaskIds` and `pendingCancelled`'s own doc\n * comments below for why a cap this size can't remove an entry either\n * invariant still needs.\n */\nexport const MAX_TRACKED_TASK_IDS = 2000;\n\n/**\n * M5 batch-3 (workstream 2): stable, documented reason PREFIX a `task.fail`\n * carries when `payload.limits.maxDurationMs` (daemon-authoritative\n * wall-clock enforcement — see `armMaxDurationTimer`) is exceeded. Only the\n * prefix itself is the contract an embedder can match against\n * (`reason.startsWith(...)`); everything after it is human-readable detail,\n * not part of the stable shape.\n */\nexport const MAX_DURATION_EXCEEDED_REASON_PREFIX = 'resource limit exceeded: maxDurationMs';\n\n/** M5 batch-3 (workstream 2): same contract as {@link MAX_DURATION_EXCEEDED_REASON_PREFIX}, for `DaemonConfig.maxTaskOutputBytes` — see `TaskRunner.pump`'s own per-event byte counting. */\nexport const MAX_OUTPUT_BYTES_EXCEEDED_REASON_PREFIX = 'resource limit exceeded: maxTaskOutputBytes';\n\n/**\n * M5 batch-3 (workstream 2): default cap (64 MiB) on accumulated\n * (approximate) agent-event output bytes this daemon tolerates for a single\n * task before tearing it down as a resource-limit violation — see\n * `TaskRunnerDeps.maxTaskOutputBytes` and `DaemonConfig.maxTaskOutputBytes`\n * (`create-daemon.ts`) for the full contract, including the\n * zero/negative-is-a-config-error / `Number.POSITIVE_INFINITY`-is-the-real-\n * opt-out pin.\n */\nexport const DEFAULT_MAX_TASK_OUTPUT_BYTES = 64 * 1024 * 1024;\n\nexport interface TaskRunnerDeps {\n adapters: RuntimeAdapter[];\n runtimeAllowlist?: string[];\n /**\n * M5 batch-3 (workstream 1): auto-select priority order for `pickAdapter`'s\n * no-explicit-runtime branch — see `DaemonConfig.runtimePreference`'s own\n * doc comment (`create-daemon.ts`) for the full rationale behind this\n * existing at all. Unset defaults to {@link DEFAULT_RUNTIME_PREFERENCE}\n * (pi LAST, deliberately — product decision: pi is this SDK's fallback\n * runtime, not its default). Independent of `runtimeAllowlist` above\n * (which restricts WHICH runtimes are eligible at all) — this only orders\n * the attempt sequence among whatever that allowlist, if set, already let\n * through.\n */\n runtimePreference?: RuntimeId[];\n /** M5: see `DaemonConfig.runtimeEnvironment`'s own doc comment (`create-daemon.ts`) — the per-device, per-runtime env-allowlist override `handleOffer` merges into `buildRuntimeEnv`'s `locallyAllowedNames`. */\n runtimeEnvironment?: Record<string, { allow?: string[] }>;\n permissionDefaults?: PermissionPolicy;\n workspaceRoot: string;\n deviceId: string;\n send: (envelope: Envelope) => void;\n blobClient: BlobResolver;\n batcherOptions?: ProgressBatcherOptions;\n /**\n * Finding #3 (session/workspace continuity): persists `sessionRef ->\n * workspaceDir` across daemon restarts so a `task.offer` naming a\n * previously-reported `sessionRef` reuses that exact workspace instead of\n * a fresh `workspaceRoot/<taskId>` — see `handleOffer` and\n * `SessionWorkspaceStore`'s own doc comment.\n */\n sessionWorkspaces: SessionWorkspaceStore;\n gitWorkspaceManager?: GitWorkspaceManager;\n gitWorkspaceStore?: GitWorkspaceStore;\n onGitWorkspaceEvent?: (event: {\n taskId: string;\n workspaceId: string;\n phase: GitWorkspacePhase;\n observation?: GitWorkspaceObservation;\n errorCategory?: string;\n }) => void;\n /**\n * M4 Phase 3: this daemon's control-socket identity + the shared registry\n * backing the control socket's own `approvals.list`/`approvals.resolve`\n * methods (`create-daemon.ts` constructs ONE `ApprovalRegistry` and passes\n * the SAME instance here) — see `requestApproval`'s own doc comment for\n * why `TaskRunner` needs a handle on all three. `storeDir`/`productId` are\n * copied verbatim into every task's `TaskContext.approvalChannel`.\n */\n approvalRegistry: ApprovalRegistry;\n storeDir: string;\n productId: string;\n /** Default `requestApproval` timeout — see {@link DEFAULT_APPROVAL_TIMEOUT_MS}. */\n approvalTimeoutMs?: number;\n /**\n * M4 Phase 3 hardening: called by `handleApprove`/`handleReject` instead of\n * failing the task when the referenced approval turns out to be stale\n * (see {@link NoPendingApprovalError}) — an audit-only signal, never\n * gating any task-state decision. `create-daemon.ts` wires this to\n * `DaemonObserver.noteStaleApprovalDecision`, the same way every other\n * locally-observable daemon event reaches the audit log/`tasks --follow`.\n * Optional so a caller that doesn't care about this audit trail (e.g. a\n * minimal test harness) isn't forced to supply one.\n */\n onStaleApprovalDecision?: (taskId: string, decision: ApprovalDecision, reason?: string) => void;\n /**\n * Finding F4 (cross-model adversarial review): operators had no way to\n * ever learn a pending approval's `approvalId` short of reading raw\n * audit-log JSON — `approve`/`reject` require one, but nothing surfaced\n * it. Called synchronously from `dispatchApproval`, BEFORE `deps.send`'s\n * own `task.await_approval` — `create-daemon.ts` wires this to\n * `DaemonObserver.noteApprovalDispatched`, which stashes `approvalId`\n * keyed by `taskId` so the observer's `task.await_approval` handling\n * (triggered by that very `deps.send` call, synchronously, right after\n * this) can attach it to the `awaiting-approval` `DaemonEvent` it emits\n * (see `observer.ts`'s own doc comment). Optional so a minimal test\n * harness that doesn't care about this audit-trail detail isn't forced\n * to supply one — mirrors `onStaleApprovalDecision`'s own contract.\n */\n onApprovalDispatched?: (taskId: string, approvalId: string) => void;\n /** Finding F5(a): overrides {@link DEFAULT_SHUTDOWN_INTERRUPT_TIMEOUT_MS} — see `teardownActiveTask`'s own doc comment. Also the grace window `teardownActiveTask`'s hard-kill escalation (`session.close()`) gets once `session.interrupt()` itself fails to settle in time — see that method's own doc comment for why the same window is reused for both steps. */\n shutdownInterruptTimeoutMs?: number;\n /**\n * M5 batch-3 (workstream 2): overrides {@link DEFAULT_MAX_TASK_OUTPUT_BYTES}\n * — see that constant's own doc comment and `DaemonConfig.maxTaskOutputBytes`\n * (`create-daemon.ts`) for the full contract. Validated (rejecting\n * zero/negative) at the `DaemonConfig` layer, not here — this seam trusts\n * its caller, same as every other optional numeric override on this\n * interface (`shutdownInterruptTimeoutMs`, `approvalTimeoutMs`).\n */\n maxTaskOutputBytes?: number;\n /**\n * M4 (additive-minor, `task.approval_resolved`): the negotiated\n * `conn.ack.capabilities` of the CURRENTLY (or most recently) connected\n * server — read fresh at call time (mirrors `getCursor`/`getToken`'s own\n * \"read fresh, not captured once\" convention elsewhere in this codebase),\n * since the capability is learned asynchronously, after this `TaskRunner`\n * is already constructed (`create-daemon.ts`'s `start()` builds `deps`\n * before `connection` exists). `create-daemon.ts` wires this to\n * `ConnectionManager.getServerCapabilities`. Optional, and treated as \"no\n * capabilities\" when absent, so a minimal test harness that doesn't care\n * about this gate isn't forced to supply one — see `sendApprovalResolved`.\n */\n getServerCapabilities?: () => readonly string[];\n /**\n * S3b (L-002): a pre-claim veto on new offers, consulted once per offer\n * immediately after the redelivery-dedup check and ahead of every other\n * admission check in `handleOffer`.\n *\n * It exists for local storage pressure (architecture §12.7.2.1's hard\n * watermark: \"停止接收新的普通 task;仍允许 terminal/truth flush、删除、导出、\n * doctor 与恢复操作\"). Placing it here rather than deeper in `handleOffer`\n * is what makes that split real: an offer never reaches adapter selection,\n * workspace creation, or `task.claim`, so declining costs nothing on disk —\n * while every path that FINISHES existing work runs through code this seam\n * is not on, and keeps working.\n *\n * Synchronous, matching every other single-purpose callback on this\n * interface. A decline is `retryable` by the guard's own decision — pressure\n * is a property of THIS device at THIS moment, so a dispatcher re-routing\n * the task elsewhere genuinely helps; a guard declining for a reason that\n * will not change says so.\n *\n * Optional and absent by default: with no guard supplied, `handleOffer`\n * behaves exactly as it did before this seam existed.\n */\n admissionGuard?: (offer: { readonly taskId: string; readonly payload: TaskOfferPayload }) => AdmissionGuardDecision;\n}\n\n/** See {@link TaskRunnerDeps.admissionGuard}. */\nexport type AdmissionGuardDecision =\n | { readonly admit: true }\n | { readonly admit: false; readonly reason: string; readonly retryable: boolean };\n\ninterface ActiveTask {\n taskId: string;\n adapter: RuntimeAdapter;\n session: Session;\n workspaceDir: string;\n gitWorkspaceId?: string;\n gitLease?: GitWorkspaceLease;\n gitBaseline?: string;\n batcher: ProgressBatcher;\n summaryParts: string[];\n /**\n * M4 Phase 3: the `ApprovalRegistry` id of the single out-of-band approval\n * currently DISPATCHED (registered + `task.await_approval` sent) for this\n * task, if any — set by `requestApproval`/`dispatchApproval`, cleared once\n * resolved (by a real decision or by the timeout). `undefined` whenever\n * nothing is dispatched right now — including while `approvalQueue` below\n * is non-empty but hasn't been dispatched yet. See `requestApproval` and\n * `TaskContext.approvalChannel.resolve`'s doc comments.\n */\n pendingApprovalId?: string;\n /**\n * M4 Phase 4 (fold-in from the P3 gate): FIFO queue of `requestApproval`\n * calls for this SAME task that arrived while another one was already\n * dispatched (`pendingApprovalId` set) — see `requestApproval`'s own doc\n * comment for the full concurrency bug this fixes (claude's parallel tool\n * use can call it more than once for one task before the first resolves).\n * Bounded by {@link MAX_PENDING_APPROVALS_PER_TASK}.\n */\n approvalQueue: QueuedApprovalRequest[];\n /**\n * M5 batch-3 (workstream 2): the wall-clock timer enforcing\n * `payload.limits.maxDurationMs` for this task, if the offer set one — see\n * `armMaxDurationTimer`. `undefined` when no `maxDurationMs` was set.\n * Cleared unconditionally at the top of `finish()` so every terminal\n * outcome (success, fail, cancel, or daemon shutdown) leaves no dangling\n * timer and can never fire a stray fail for a task that already ended a\n * different way.\n */\n maxDurationTimer?: ReturnType<typeof setTimeout>;\n /**\n * M5 batch-3 (workstream 2): running total of accumulated agent-event\n * output bytes counted so far for `DaemonConfig.maxTaskOutputBytes`\n * enforcement — see `TaskRunner.pump`'s own per-event counting for exactly\n * what's counted (a serialized-payload-length approximation, not an exact\n * wire-byte accountant).\n */\n outputBytesSoFar: number;\n /**\n * M5 batch-3 (workstream 2): set at the very start of\n * `teardownActiveTask`, before either `session.interrupt()` or its\n * hard-kill `session.close()` escalation runs. Both are real teardown\n * primitives that MAY end this task's own `session.events` iterable as a\n * side effect (e.g. claude's `interrupt()`/`close()` are both\n * `client.kill()`, which SIGTERMs the process — killing it ends the\n * stdout stream that backs `events`). Without this flag, `pump()`'s own\n * \"the events iterable ended without an explicit turn_end\" fallback\n * (which exists for a genuinely UNEXPECTED adapter/process crash) can't\n * tell that apart from a teardown *this* runner itself just triggered, and\n * would report its OWN `task.fail` (retryable: true, \"runtime session\n * ended without completing the task\") — racing `teardownActiveTask`'s own\n * intended, more specific outcome, and potentially winning it: for a\n * fast-closing session, `pump()`'s reaction to the queue ending is a\n * SHORTER chain than `teardownActiveTask`'s own remaining steps (a\n * possible hard-kill await, an identity re-check, then send+finish).\n * `finish()` deletes this task from `this.tasks` BEFORE calling\n * `session.close()` for exactly the same reason (see `handleCancel`'s own\n * doc comment on `pump`'s identity check) — this flag covers the\n * additional window `teardownActiveTask`'s own PRE-finish() hard-kill\n * `close()` call opens that the delete-before-close ordering alone\n * doesn't.\n */\n beingTornDown?: boolean;\n}\n\n/** One not-yet-dispatched `requestApproval` call waiting its turn — see `ActiveTask.approvalQueue`. */\ninterface QueuedApprovalRequest {\n summary: string;\n resolve: (result: { approved: boolean; reason?: string }) => void;\n /**\n * C1 (cross-model review, P1): forwarded verbatim to `dispatchApproval`\n * once this request is actually dispatched (`dispatchNextQueuedApproval`)\n * — see `requestApproval`'s own doc comment for why this exists at all.\n */\n onOrigin?: (origin: ApprovalOrigin) => void;\n}\n\ntype PickResult =\n | { ok: true; adapter: RuntimeAdapter }\n | { ok: false; reason: string; retryable: boolean };\n\n/**\n * M5 (claimed runtime): `RuntimeAdapter.id` is a bare `string` (`../types.ts`)\n * — deliberately wider than the frozen wire `RuntimeIdSchema`, so a custom,\n * embedder-supplied adapter for a runtime this protocol doesn't know about\n * can still be plugged in. `task.claim.runtime` (`TaskClaimPayloadSchema`)\n * is narrower (`'pi' | 'claude' | 'codex'`), so the picked adapter's id must\n * be checked before it can be sent on the wire — mirrors `create-daemon.ts`'s\n * own `isRuntimeId` gate for `conn.hello.runtimes` reporting. An adapter\n * whose id isn't one of these is simply omitted from `task.claim.runtime`\n * (never sent as an invalid enum value), the same fail-closed-by-omission\n * shape `detectRuntimes` already applies.\n */\nfunction isKnownRuntimeId(id: string): id is RuntimeId {\n return RuntimeIdSchema.safeParse(id).success;\n}\n\n/**\n * M5 batch-3 (workstream 1): default auto-select priority order — claude,\n * then codex, then pi LAST. Product decision: pi is this SDK's FALLBACK\n * runtime (tried only once nothing better is available/capable), not the\n * default it silently was before this change (see `ALL_RUNTIME_IDS`'s own\n * doc comment, `create-daemon.ts`, for how the old accidental default arose).\n * Overridable per-daemon via `DaemonConfig.runtimePreference` /\n * `TaskRunnerDeps.runtimePreference`; this is only the fallback when that's\n * left unset.\n */\nconst DEFAULT_RUNTIME_PREFERENCE: readonly RuntimeId[] = ['claude', 'codex', 'pi'];\n\n/**\n * Reorders `candidates` by `preference` (lower index tried first), appending\n * every candidate whose id isn't named in `preference` at all — e.g. a\n * product-supplied adapter for a runtime id outside the frozen\n * `RuntimeIdSchema` enum (`RuntimeAdapter.id` is deliberately a plain\n * `string`, wider than `RuntimeId` — see `types.ts`'s own doc comment) —\n * after every ranked one, in their original relative order. Safe because\n * `Array.prototype.sort` has been a stable sort since ES2019: two candidates\n * that tie on rank (both unranked, or the same explicit rank) never get\n * reordered relative to each other. This guarantees a candidate already\n * present in `deps.adapters` is never silently dropped from auto-select just\n * because `preference` doesn't happen to mention its id.\n */\nfunction orderByPreference(candidates: readonly RuntimeAdapter[], preference: readonly string[]): RuntimeAdapter[] {\n const rank = new Map(preference.map((id, index) => [id, index]));\n return [...candidates].sort((a, b) => (rank.get(a.id) ?? preference.length) - (rank.get(b.id) ?? preference.length));\n}\n\n/**\n * M5 batch-3 (workstream 1): whether `adapter` can express `mode` AT ALL —\n * consults the exact same `RuntimeCapabilities.permissionModes` already\n * reported on the wire (`create-daemon.ts`'s `toRuntimeInfoCapabilities`)\n * rather than instantiating or probing anything new. A pure, synchronous,\n * zero-I/O check — deliberately consulted BEFORE `adapter.detect()` in\n * `pickAdapter` below, so a structurally-incapable candidate never pays for\n * a real subprocess probe it could never have won anyway.\n *\n * This is a NEW pre-claim gate (M5 batch-3). The pre-existing POST-claim\n * gate — `adapter.start()` throwing `PolicyUnsupportedError` for a policy it\n * can't express (e.g. pi's own `mapPermissionPolicyToPiArgs` rejecting\n * `confirm`/`plan`, `pi/permission-mapping.ts`) — is UNCHANGED and stays in\n * place as defense-in-depth for any mismatch this capability check doesn't\n * happen to catch (e.g. a future adapter whose declared `permissionModes`\n * doesn't perfectly match its own mapping's real behavior). Before this\n * gate existed, a `confirm`-mode task auto-selected (or explicitly\n * requested) onto an adapter that can't express it would claim first and\n * only discover the mismatch once `adapter.start()` actually threw —\n * needlessly occupying the claim when a capable adapter may have been\n * sitting right there (auto path) or simply wasting a claim/fail round trip\n * for no possible outcome (explicit path).\n */\nfunction adapterSupportsMode(adapter: RuntimeAdapter, mode: PermissionMode): boolean {\n return adapter.capabilities().permissionModes.includes(mode);\n}\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * M5 batch-3 (workstream 2): races `fn()` against `timeoutMs`, resolving\n * `true` once `fn()` itself settles (success OR rejection — a rejection is\n * swallowed here, the same best-effort contract every teardown call in this\n * file already applies to `session.interrupt()`/`session.close()`) and\n * `false` if `timeoutMs` elapses first with `fn()` still pending. Unlike a\n * plain `Promise.race`, the caller can tell WHICH one won —\n * `teardownActiveTask` needs that to decide whether to escalate to a hard\n * kill.\n */\nfunction raceSettleFirst(fn: () => Promise<void>, timeoutMs: number): Promise<boolean> {\n return new Promise((resolve) => {\n let settled = false;\n const timer = setTimeout(() => {\n if (!settled) {\n settled = true;\n resolve(false);\n }\n }, timeoutMs);\n timer.unref?.();\n void (async () => {\n try {\n await fn();\n } catch {\n // best-effort — the caller only cares whether this settled in time\n }\n if (!settled) {\n settled = true;\n clearTimeout(timer);\n resolve(true);\n }\n })();\n });\n}\n\n/**\n * M5 batch-3 (workstream 2): approximate output size of one normalized\n * `AgentEvent`, for `DaemonConfig.maxTaskOutputBytes` enforcement (`pump`\n * below) — the UTF-8 byte length of `JSON.stringify(event)`. This is a\n * serialized-payload-length APPROXIMATION of the event's eventual wire cost,\n * not an exact accountant: `task.progress` batching/envelope framing\n * overhead is not included, and for an `artifact` event this counts only the\n * event's own `{name, contentType}` shape — the artifact's actual file bytes\n * are read/uploaded separately by `sendArtifact` and are NOT counted here\n * (capping that would need a different hook; out of scope for this cap).\n * Good enough to catch a genuinely runaway task without needing an exact\n * wire-byte accountant. Never throws: a shape `JSON.stringify` can't handle\n * (it never should for a well-formed `AgentEvent`) counts as 0 bytes rather\n * than crashing the task loop over an accounting nicety.\n */\nfunction estimateEventBytes(event: AgentEvent): number {\n try {\n return Buffer.byteLength(JSON.stringify(event), 'utf8');\n } catch {\n return 0;\n }\n}\n\ntype OpenArtifactResult = { ok: true; handle: FileHandle } | { ok: false; reason: string };\n\n/**\n * Finding F7/N5 (artifact path traversal + TOCTOU symlink race): resolve an\n * artifact `name` against `workspaceDir`, then **open it and verify the\n * open file descriptor** — never a path-based check followed by a separate\n * re-open by pathname.\n *\n * The prior version (`resolveArtifactPath`) realpath'd the candidate to\n * verify containment and returned a *path string*; `sendArtifact` then\n * reopened that path via `fs.readFile(path)`. That's a classic\n * check-then-use race: between the realpath check and the later open, the\n * final path component can be swapped for a symlink pointing outside the\n * workspace (a compromised/buggy runtime, or something written by the very\n * agent turn that reported this artifact name), and the reopen would\n * silently follow it. Confirmed pre-fix: swapping the artifact's final\n * component for a symlink to `/etc/hosts` after the containment check\n * passed but before the read caused the daemon to read and upload\n * `/etc/hosts` as the task artifact.\n *\n * Fix: the LEXICAL pathname containment check below (`path.resolve` +\n * string-prefix) is only a fast, well-messaged early reject (defense in\n * depth — rejects absolute `name`s and `../` traversal before touching the\n * filesystem at all). It is followed by a SECOND, filesystem-resolving\n * containment check (finding P4/Codex): `fs.realpath` the full candidate\n * path and re-check containment against the realpath'd workspace root. This\n * exists because the lexical check alone cannot catch an INTERMEDIATE path\n * component that's actually a symlink pointing outside the workspace — e.g.\n * `name = \"sublink/secret.txt\"` where `<workspace>/sublink` is a symlink to\n * an outside directory: `<workspace>/sublink/secret.txt` lexically starts\n * with `<workspace>/` regardless of what `sublink` points at, and\n * `O_NOFOLLOW` (below) only guards the *final* path component per POSIX\n * `open(2)` semantics — it has nothing to reject when the final component,\n * once the intermediate symlink is followed, is itself a perfectly ordinary\n * regular file. Resolving the realpath of the WHOLE candidate and checking\n * containment against it catches this: the resolved path lands outside the\n * workspace root regardless of which component in the middle was the\n * symlink. After both containment checks pass, the actual TOCTOU security\n * boundary is still `O_NOFOLLOW` on the `open()` call itself, which fails\n * atomically (`ELOOP`) if the FINAL path component is a symlink — there is\n * no window between \"check\" and \"use\" for that component specifically,\n * just an open that refuses to follow one — plus an `fstat` on the\n * resulting *file descriptor* (not the path) to confirm it's a regular\n * file. `sendArtifact` reads from that same handle and closes it when done;\n * the bytes it hashes/inlines/uploads are the exact bytes that passed every\n * check, not a re-read of whatever exists at the path afterward.\n *\n * Residual (documented, not fixed here): a *static* intermediate symlink\n * (created ahead of time, no race needed) is now closed by the realpath\n * containment check above. The only gap left is a genuine RACE: an\n * intermediate directory component swapped for a symlink AFTER the\n * candidate's realpath call above resolves but BEFORE the subsequent\n * `open()`. Closing that fully needs Linux's `openat2`/`RESOLVE_BENEATH`\n * (resolve-and-open as one atomic, symlink-constrained operation), which\n * Node's stdlib doesn't expose, and isn't implemented cross-platform here.\n *\n * M3 TODO (Windows): `fs.constants.O_NOFOLLOW` is `undefined` on Windows,\n * so the `?? 0` below no-ops the flag there (reparse-point/symlink handling\n * for that platform isn't implemented yet) — the realpath+prefix\n * containment checks remain the floor of protection on Windows until it\n * is.\n */\nasync function openArtifact(workspaceDir: string, name: string): Promise<OpenArtifactResult> {\n // Workspace root is daemon-created (see `resolveWorkspaceDir`) and\n // trusted — realpath'd exactly once, not derived from the untrusted\n // `name`, so this step has no TOCTOU exposure of its own.\n const realWorkspaceDir = await fs.realpath(workspaceDir).catch(() => workspaceDir);\n const candidate = path.resolve(realWorkspaceDir, name);\n\n const prefix = realWorkspaceDir.endsWith(path.sep) ? realWorkspaceDir : realWorkspaceDir + path.sep;\n if (candidate !== realWorkspaceDir && !candidate.startsWith(prefix)) {\n return { ok: false, reason: `artifact name \"${name}\" resolves outside the task workspace — rejected` };\n }\n\n // Finding P4/Codex: the check above is LEXICAL and does not catch an\n // intermediate path component that's actually a symlink pointing outside\n // the workspace (`O_NOFOLLOW` below only guards the final component).\n // Resolve the full candidate's real path and re-check containment against\n // it — this fails closed whenever any intermediate component resolves\n // outside the workspace root, even though the final component (once\n // resolved) is an ordinary regular file. A realpath failure here (ENOENT,\n // a broken intermediate link, etc.) falls through to the `open()` below\n // unchanged, so that call produces the natural, consistent \"could not be\n // opened\" error instead of a differently-worded one — it doesn't grant\n // any additional access, since `open()` would fail for the same\n // underlying reason (and still can't follow a symlinked final component\n // either way).\n let realCandidate = candidate;\n try {\n realCandidate = await fs.realpath(candidate);\n } catch {\n // handled by the open() call below\n }\n if (realCandidate !== realWorkspaceDir && !realCandidate.startsWith(prefix)) {\n return { ok: false, reason: `artifact name \"${name}\" resolves outside the task workspace — rejected` };\n }\n\n const O_NOFOLLOW = fsConstants.O_NOFOLLOW ?? 0;\n let handle: FileHandle;\n try {\n handle = await fs.open(candidate, fsConstants.O_RDONLY | O_NOFOLLOW);\n } catch (err) {\n return { ok: false, reason: `artifact \"${name}\" could not be opened: ${errorMessage(err)}` };\n }\n\n try {\n const st = await handle.stat();\n if (!st.isFile()) {\n await handle.close().catch(() => {});\n return { ok: false, reason: `artifact \"${name}\" is not a regular file` };\n }\n } catch (err) {\n await handle.close().catch(() => {});\n return { ok: false, reason: `artifact \"${name}\" could not be verified: ${errorMessage(err)}` };\n }\n\n return { ok: true, handle };\n}\n\n/**\n * Per-connection task orchestration: offer -> (decline | claim -> adapter\n * session -> started) -> seq-ordered progress batches -> complete/fail/\n * cancelled, plus approve/reject/cancel/steer handling.\n *\n * M1 rework (docs/protocol.md §3, §5, §10 — `packages/protocol` is frozen,\n * not editable here): pre-claim rejections (unknown/disallowed runtime,\n * policy exceeding this device's ceiling) now send `task.decline` and never\n * claim at all — `TASK_TRANSITIONS.Offered` gained a direct `-> Failed` edge\n * precisely so this no longer has to claim-then-fail. A successful claim is\n * followed by `task.started` only once the adapter session has actually\n * started (`task.claim` alone no longer implies `Running`). Cancellation\n * reports the explicit `task.cancelled` message instead of the old\n * `task.fail({reason:'cancelled'})` convention.\n */\nexport class TaskRunner {\n private readonly tasks = new Map<string, ActiveTask>();\n /**\n * Finding F4 (cancel lost during the offer-processing window): a\n * `task.cancel` for a taskId that hasn't finished `handleOffer` yet (still\n * awaiting adapter detection / instruction resolution / workspace setup /\n * `adapter.start()`) has no `this.tasks` entry to land on — it used to be\n * silently dropped, and the runtime session `handleOffer` was about to\n * register would then run an unsupervised (\"zombie\") turn nobody asked\n * for anymore. Recording the taskId here lets `handleOffer` consult it at\n * the two points where it can still safely react (see its body): before\n * claiming at all (decline instead of ever starting a session), and right\n * after `adapter.start()` resolves but before this task is registered as\n * active (tear the just-started session down immediately, before its\n * event loop ever pumps a single event). Consumed (deleted) at whichever\n * checkpoint handles it; a cancel for a taskId that's already active,\n * already finished, or never offered at all leaves a harmless entry that\n * nothing will ever consult.\n *\n * M3-B: that last sentence is exactly the unbounded-growth vector this\n * needed closed for long-lived operation — a cancel for a taskId nobody\n * ever claims (unknown, already active, or already finished) leaves a\n * permanent entry with nothing left to consume it. Bounded to\n * `MAX_TRACKED_TASK_IDS` via `setPendingCancelled` below, oldest evicted\n * first: safe because every entry this field's correctness actually\n * depends on is consumed (deleted) by one of `handleOffer`'s two\n * checkpoints within that SAME task's own offer-processing window — one\n * in-flight task's startup latency, nowhere near enough churn for eviction\n * to remove an entry still inside its consuming window before it's read.\n */\n private readonly pendingCancelled = new Map<string, string | undefined>();\n /**\n * Finding #5 (Codex counterexample): taskIds currently INSIDE `handleOffer`\n * — from the moment it decides an offer is worth processing until it\n * reaches one of its own resolution points (decline, fail, the\n * checkpoint-2 cancel-teardown, or successful registration into\n * `this.tasks`). Bounded eviction on `pendingCancelled` (below) must never\n * remove an entry for a taskId in this set: doing so is exactly the bug —\n * block task A in `adapter.start()`, deliver A's own `task.cancel` (so\n * `pendingCancelled` gets an entry for A while A is still in-flight),\n * then deliver `MAX_TRACKED_TASK_IDS` more cancels for unrelated taskIds\n * nobody ever offered — under naive oldest-wins eviction, A's entry (the\n * single oldest) gets evicted purely because of unrelated churn, so when\n * `adapter.start()` finally resolves, checkpoint 2 finds no cancel marker\n * and the already-cancelled task starts a real session. See\n * `evictPendingCancelled` below for the fix, and\n * `task-runner-bounded-collections.test.ts` for a test mirroring this\n * exact scenario. Membership here is naturally tiny (bounded by this\n * device's real concurrent-offer-processing count, nowhere near\n * `MAX_TRACKED_TASK_IDS`), so scanning past it to find an evictable entry\n * costs nothing.\n */\n private readonly inFlightOffers = new Set<string>();\n /**\n * Finding P2 (Fix 2c): taskIds that have reached a terminal outcome\n * (Complete/Failed/Cancelled) this session — populated in `finish()`.\n * While `ConnectionManager`'s stalled-cursor long-poll re-pull is frozen\n * behind an unrelated failing seq, it can legitimately redeliver an\n * ALREADY-succeeded `task.offer` — the client's own cursor hasn't advanced\n * past it yet (docs/protocol.md §9's \"cursor advance timing\" rule\n * explicitly relies on redelivered handlers being idempotent for exactly\n * this reason). `handleOffer` must treat a redelivered offer for a taskId\n * that's already active (`this.tasks`) or already finished (this set) as\n * a no-op — never a second `adapter.start()` call, which would orphan the\n * first session.\n *\n * M3-B: unbounded otherwise — a long-lived daemon that's finished many\n * thousands of tasks over its uptime would keep every single taskId\n * forever. Bounded to `MAX_TRACKED_TASK_IDS` via `addFinishedTaskId`\n * below, oldest evicted first. Safe for the redelivery-idempotency\n * invariant above because the stalled-cursor scenario above redelivers\n * this device's own recent backlog for one connection, not an arbitrary\n * point in this daemon's whole history — this device would have to claim\n * and finish `MAX_TRACKED_TASK_IDS` more tasks before a genuinely-still-\n * pending redelivery for an older taskId even arrives, let alone gets\n * processed, for eviction to ever remove an entry that redelivery still\n * needed.\n *\n * Finding #5 (honesty follow-up): unlike `pendingCancelled`, plain\n * oldest-first eviction IS correct here — every entry in this set is\n * already fully resolved (finish() only adds a taskId after it reached a\n * terminal outcome), so there is no \"in-flight\" entry an eviction could\n * corrupt out from under a running `handleOffer()`. The assumption above\n * is a HEURISTIC bound, not a proof: it holds as long as no single\n * connection's genuinely-still-pending redelivery backlog ever exceeds\n * `MAX_TRACKED_TASK_IDS` finished tasks, which is a real (if distant)\n * possibility for an extremely long-stalled connection, not a\n * mathematical impossibility. Should it ever be violated, the failure\n * mode is strictly milder than `pendingCancelled`'s own pre-fix bug: a\n * redelivered `task.offer` for an evicted, already-finished taskId would\n * re-run `handleOffer` from scratch — at worst a duplicate\n * claim/start/complete for a task that already succeeded once — never a\n * task that should be dead starting a brand-new session against explicit\n * cancellation intent.\n */\n private readonly finishedTaskIds = new Set<string>();\n /**\n * M4 Phase 2 (daemon control socket `shutdown` RPC): set once by\n * {@link stopAcceptingOffers}, checked at the very top of `handleOffer` —\n * see that method's own doc comment for why offers must stop being\n * claimed BEFORE currently-active tasks are reported failed in\n * {@link shutdownActiveTasks}, not after. Irreversible for this\n * `TaskRunner` instance; a fresh one is constructed on the daemon's next\n * `start()`.\n */\n private stoppingOffers = false;\n\n constructor(private readonly deps: TaskRunnerDeps) {}\n\n get activeTaskCount(): number {\n return this.tasks.size;\n }\n\n /** M5 batch-3 (workstream 2): effective `maxTaskOutputBytes` cap for this daemon — see {@link DEFAULT_MAX_TASK_OUTPUT_BYTES}'s own doc comment. */\n private get maxTaskOutputBytes(): number {\n return this.deps.maxTaskOutputBytes ?? DEFAULT_MAX_TASK_OUTPUT_BYTES;\n }\n\n /**\n * M4 Phase 4 (part B.3, observability): per-active-task queue watermarks\n * for the control socket's `status` result — see\n * `control-protocol.ts`'s `TaskQueueWatermark` doc comment for why this\n * reflects the daemon's own progress-batcher backlog and in-flight\n * approval count, not the adapter's own event-queue depth.\n */\n getQueueWatermarks(): TaskQueueWatermark[] {\n return [...this.tasks.values()].map((active) => ({\n taskId: active.taskId,\n progressBatcherPending: active.batcher.pendingCount,\n pendingApprovals: (active.pendingApprovalId !== undefined ? 1 : 0) + active.approvalQueue.length,\n }));\n }\n\n /** M4 Phase 2: stop claiming any FUTURE `task.offer` — see `stoppingOffers`'s own doc comment. Idempotent. */\n stopAcceptingOffers(): void {\n this.stoppingOffers = true;\n }\n\n /**\n * M4 Phase 2: best-effort shutdown of every currently ACTIVE task, for the\n * control socket's `shutdown` RPC. Mirrors `handleCancel`'s best-effort\n * `session.interrupt()` style (an interrupt failure is swallowed; the\n * terminal message is sent either way) but reports `task.fail` rather than\n * `task.cancelled` — these tasks aren't ending because the SERVER\n * cancelled them, they're ending because this device is shutting down.\n * `retryable: true` throughout: nothing about the task/policy itself was\n * ever at fault, only this device's own availability right now.\n *\n * Snapshots `this.tasks` into a plain array up front rather than iterating\n * the live `Map` — `finish()` (called per task below) deletes from that\n * same map as each shutdown settles, and a snapshot avoids relying on\n * \"mutate while iterating\" semantics being followed correctly here.\n *\n * Must be called AFTER {@link stopAcceptingOffers} and BEFORE the\n * connection is closed: the caller (`create-daemon.ts`'s\n * `performControlShutdown`) awaits this method to fully settle — every\n * `task.fail` actually enqueued via `deps.send` — before it ever calls\n * `stop()` (which closes the connection). Stopping offers first (rather\n * than closing the connection first) is what prevents a new\n * `task.offer` from being claimed in the window while these are being\n * torn down.\n *\n * This ordering invariant is NOT just about `performControlShutdown`'s\n * own internal statement order — it also depends on nothing ELSE\n * closing the connection first. A real regression (gatekeeper-caught,\n * fixed in `create-daemon.ts`/`bin/commands/start.ts`) had exactly that\n * happen: `start.ts` used to wake up on the EARLIER `shutdown-requested`\n * event (fired synchronously, before this method even calls\n * `session.interrupt()`) and call `daemon.stop()` itself, racing ahead\n * and closing the connection before this method's `task.fail` send ever\n * reached the outbox drain. `start.ts` now waits for the LATER\n * `shutdown-complete` event (emitted only after `performControlShutdown`'s\n * own `stop()` call has already resolved), so it can no longer race\n * ahead of this method — see `daemon-control-socket.test.ts`'s dedicated\n * regression test for the exact scenario.\n */\n async shutdownActiveTasks(reason: string): Promise<void> {\n const active = [...this.tasks.values()];\n await Promise.all(active.map((task) => this.shutdownTask(task, reason)));\n }\n\n /**\n * M5 batch-3 (workstream 2): the ONE shared per-task teardown sequence —\n * \"reuse the exact interrupt/teardown machinery `shutdownActiveTasks`\n * uses, do not invent a second teardown path\" applies to BOTH callers:\n * graceful daemon shutdown ({@link shutdownTask}, `retryable: true`) and\n * resource-limit enforcement ({@link failActiveTaskForResourceLimit},\n * `retryable: false`, wall-clock `maxDurationMs` / output-cap\n * `maxTaskOutputBytes`).\n *\n * Finding F5(a) (pre-existing, unchanged by this refactor):\n * `session.interrupt()` is raced against `timeoutMs`\n * ({@link DEFAULT_SHUTDOWN_INTERRUPT_TIMEOUT_MS}, overridable via\n * `TaskRunnerDeps.shutdownInterruptTimeoutMs`) rather than awaited\n * unconditionally, so a hung `interrupt()` (a misbehaving adapter) can\n * never block `task.fail` from being sent at all.\n *\n * New in this batch — hard-kill escalation: when `interrupt()` does NOT\n * settle within that same grace window, `session.close()` is tried next\n * (ALSO raced against `timeoutMs`, for the identical reason: a hung\n * `close()` must not be able to block this forever either — which matters\n * far more here than it used to for the pre-existing graceful-shutdown-only\n * caller, since THAT path is additionally bounded by an outer deadline\n * (`SHUTDOWN_TASK_TEARDOWN_DEADLINE_MS`/`DaemonConfig.shutdownGraceMs`,\n * `create-daemon.ts`), while resource-limit enforcement fires during\n * ordinary operation with no such outer bound watching it). `close()` is\n * every adapter's harder teardown primitive — an actual process-level kill\n * (SIGTERM, or `taskkill /F` on Windows — see e.g.\n * `ClaudeProcessClient.kill()`/`PiRpcClient.kill()`) as opposed to pi's own\n * soft in-band `interrupt()` (an RPC `abort` message that leaves the\n * process alive and resumable) — so escalating to it is the closest thing\n * to a \"hard kill\" the `Session` interface exposes. `finish()` below calls\n * `session.close()` again regardless (documented idempotent) — this isn't\n * a substitute for that, only an earlier, bounded attempt at actually\n * stopping a stuck runtime before this method gives up and reports failure\n * anyway.\n *\n * Re-checks task identity (`this.tasks.get(...) === active`) immediately\n * before sending `task.fail`: the interrupt/hard-kill race above has await\n * points during which a DIFFERENT path (a racing `task.cancel`/\n * `task.reject`, or the session completing normally on its own) may have\n * already finished this exact task and sent its own terminal message.\n * Sending a SECOND terminal message for an already-finished task would be\n * a genuine protocol bug, not a benign race — mirrors `pump()`'s own\n * identity-check guard for the same class of race.\n */\n private async teardownActiveTask(active: ActiveTask, reason: string, retryable: boolean): Promise<void> {\n // See `ActiveTask.beingTornDown`'s own doc comment: must be set BEFORE\n // either step below, since either one (not just the hard-kill escalation)\n // can end this task's `session.events` iterable as a side effect.\n active.beingTornDown = true;\n await this.observeGit(active, 'salvage');\n const timeoutMs = this.deps.shutdownInterruptTimeoutMs ?? DEFAULT_SHUTDOWN_INTERRUPT_TIMEOUT_MS;\n const interrupted = await raceSettleFirst(() => active.session.interrupt(), timeoutMs);\n if (!interrupted) {\n await raceSettleFirst(() => active.session.close(), timeoutMs);\n }\n if (this.tasks.get(active.taskId) !== active) return;\n this.deps.send(createEnvelope('task.fail', { reason, retryable }, { taskId: active.taskId }));\n await this.finish(active.taskId);\n }\n\n /** Graceful-shutdown caller of {@link teardownActiveTask} — see `shutdownActiveTasks`'s own doc comment. `retryable: true`: nothing about the task/policy itself was ever at fault, only this device's own availability right now. */\n private async shutdownTask(active: ActiveTask, reason: string): Promise<void> {\n await this.teardownActiveTask(active, `daemon shutting down: ${reason}`, true);\n }\n\n /**\n * M5 batch-3 (workstream 2): shared entry point for both resource-limit\n * enforcers (wall-clock `maxDurationMs` — {@link armMaxDurationTimer} —\n * and output-cap `maxTaskOutputBytes` — see `pump`). Looks the task up\n * FRESH by id and no-ops if it's already gone — finished via any other\n * path (normal completion, cancel, reject, daemon shutdown, or a\n * DIFFERENT resource-limit trip already caught it first). `retryable:\n * false` unconditionally: hitting a configured resource ceiling is never a\n * transient/environmental failure a retry could fix — the same task under\n * the same limits would just hit it again.\n */\n private async failActiveTaskForResourceLimit(taskId: string, reason: string): Promise<void> {\n const active = this.tasks.get(taskId);\n if (!active) return;\n await this.teardownActiveTask(active, reason, false);\n }\n\n /**\n * M5 batch-3 (workstream 2): daemon-authoritative wall-clock enforcement\n * for `payload.limits.maxDurationMs` — previously accepted and silently\n * ignored (see `handleOffer`'s own doc comment on the `limits.maxTokens`\n * gate for the historical context this superseded). Armed once, at the\n * moment this task is registered as active (`handleOffer`, still inside\n * the synchronous construct -> register -> arm -> pump handoff — arming a\n * timer is synchronous, `setTimeout` never invokes its callback in the\n * same tick, so this doesn't reopen the race that handoff's own doc\n * comment guards against). Cleared unconditionally in `finish()` so every\n * terminal outcome leaves no dangling timer and can never double-fail an\n * already-finished task — the fresh `this.tasks.get` lookup in\n * `failActiveTaskForResourceLimit`/`teardownActiveTask`'s own identity\n * re-check is the second, belt-and-suspenders layer of that same guarantee\n * for the rare case the timer's callback was already scheduled before\n * `finish()` had a chance to clear it.\n */\n private armMaxDurationTimer(active: ActiveTask, maxDurationMs: number): void {\n const timer = setTimeout(() => {\n void this.failActiveTaskForResourceLimit(\n active.taskId,\n `${MAX_DURATION_EXCEEDED_REASON_PREFIX}: task exceeded its configured wall-clock limit of ${maxDurationMs}ms`,\n );\n }, maxDurationMs);\n timer.unref?.();\n active.maxDurationTimer = timer;\n }\n\n async handleEnvelope(envelope: Envelope): Promise<void> {\n switch (envelope.type) {\n case 'task.offer':\n await this.handleOffer(envelope.task_id, envelope.payload);\n return;\n case 'task.cancel':\n await this.handleCancel(envelope.task_id, envelope.payload.reason);\n return;\n case 'task.steer':\n await this.handleSteer(envelope.task_id, envelope.payload.text);\n return;\n case 'task.approve':\n await this.handleApprove(envelope.task_id, envelope.payload.approvalId);\n return;\n case 'task.reject':\n await this.handleReject(envelope.task_id, envelope.payload.reason, envelope.payload.approvalId);\n return;\n default:\n return; // conn.* and daemon->server-only types are handled elsewhere / not applicable\n }\n }\n\n private async handleOffer(taskId: string, payload: TaskOfferPayload): Promise<void> {\n // Finding P2, Fix 2c (redelivered offer for an already-active/finished\n // task): checked first, ahead of everything below — a redelivered\n // `task.offer` for a taskId this device already claimed/started, or\n // already finished, can never be \"the first time\" for it, so there is\n // nothing left to decide. Without this, the stalled-cursor long-poll\n // re-pull (see `ConnectionManager.dedupWatermark`) redelivering this\n // same offer while its first `adapter.start()` is still in flight (or\n // well after it already succeeded) would start a SECOND adapter session\n // for the same task, orphaning the first.\n if (this.tasks.has(taskId) || this.finishedTaskIds.has(taskId)) {\n return;\n }\n\n // S3b (L-002): the pre-claim admission veto — see\n // `TaskRunnerDeps.admissionGuard`'s own doc comment. Consulted here,\n // AFTER the dedup check above (a redelivery of an offer this device\n // already accepted is not a new admission, and must stay a silent no-op\n // rather than becoming a decline) and BEFORE everything below, so a\n // declined offer never touches an adapter, a workspace, or the wire\n // beyond its own `task.decline`.\n const guarded = this.deps.admissionGuard?.({ taskId, payload });\n if (guarded !== undefined && !guarded.admit) {\n this.decline(taskId, guarded.reason, guarded.retryable);\n return;\n }\n\n // M4 Phase 2: the control socket's `shutdown` RPC flips this before\n // tearing down active tasks (see `stopAcceptingOffers`'s own doc\n // comment) — any offer arriving after that point is declined outright,\n // never claimed.\n if (this.stoppingOffers) {\n this.decline(taskId, 'daemon is shutting down', true);\n return;\n }\n\n // Finding #5: mark this taskId as \"in-flight\" for the entire remainder\n // of this call — `evictPendingCancelled` must never remove a\n // `pendingCancelled` entry for a taskId in this set (see its own doc\n // comment and `inFlightOffers`'s class-level doc comment for the exact\n // counterexample this closes). The `finally` below clears it on every\n // exit path (decline, fail, the checkpoint-2 cancel-teardown, or\n // successful registration) — never leaked past this one call.\n this.inFlightOffers.add(taskId);\n try {\n // Finding F4, checkpoint 1 (\"before claim where possible -> decline\n // path\"): a task.cancel already arrived for this exact taskId before\n // this offer was even looked at. Decline outright — never claim, never\n // spawn a runtime session for a task that's already dead. Checked first\n // (ahead of every other pre-claim check below) so a pre-cancelled offer\n // costs nothing beyond this map lookup.\n if (this.pendingCancelled.has(taskId)) {\n const reason = this.pendingCancelled.get(taskId);\n this.pendingCancelled.delete(taskId);\n this.decline(taskId, reason ? `cancelled before claim: ${reason}` : 'cancelled before claim', false);\n return;\n }\n\n // M5 batch-3 (workstream 1): `limits.maxTokens` has no hard-enforcement\n // path on ANY bundled runtime adapter today — nothing actually counts\n // or caps tokens against it. Silently accepting the offer would let a\n // caller believe a token ceiling is in effect when nothing checks it;\n // declining fail-closed, pre-claim, is honest about that gap and lets\n // the dispatcher route the task elsewhere instead of running\n // unbounded. `retryable: true` — a different device's adapter set (or\n // a future SDK version) might genuinely enforce this, so re-routing\n // can help even though nothing here can. `limits.maxDurationMs` is\n // deliberately left OUT of this admission gate: unlike maxTokens, it\n // IS hard-enforced — daemon-authoritative, at the TaskRunner layer\n // itself (a wall-clock timer armed once this task is registered as\n // active — see `armMaxDurationTimer` — not delegated to any adapter),\n // so there is no gap here to decline fail-closed for.\n if (payload.limits?.maxTokens !== undefined) {\n this.decline(\n taskId,\n `offer requests limits.maxTokens (${payload.limits.maxTokens}), which no bundled runtime adapter enforces — declining fail-closed rather than silently ignoring it`,\n true,\n );\n return;\n }\n\n // M5 batch-3 (workstream 1): `policy.workspaceRoot` IS merged into the\n // effective policy handed to the adapter (`computeEffectivePolicy`,\n // policy.ts) as `ctx.policy.workspaceRoot` — but no bundled adapter\n // actually reads or enforces it; every adapter derives its real\n // confinement from `ctx.workspaceDir` (the daemon-created per-task\n // directory) instead (see docs/security.md's \"Workspace confinement is\n // a convention, not a sandbox\" section). An OFFER that asks for this\n // control is asking for something that looks live but isn't — decline\n // it fail-closed rather than silently accept an unenforced security\n // constraint. Deliberately checks the RAW offer's own\n // `payload.policy.workspaceRoot`, never the merged/effective policy:\n // `computeEffectivePolicy` falls back to the device's configured\n // CEILING's `workspaceRoot` when the offer itself didn't set one\n // (policy.ts), and that ceiling-only case is a separate, operator-owned\n // decision handled by a one-time startup warning instead (see\n // `create-daemon.ts`'s `start()`) — checking the effective value here\n // would incorrectly decline every single offer once an operator\n // configures ANY ceiling workspaceRoot, not just the ones that actually\n // asked for one.\n if (payload.policy.workspaceRoot !== undefined) {\n this.decline(\n taskId,\n 'offer policy requests workspaceRoot, which no bundled runtime adapter enforces — declining fail-closed rather than silently accepting an unenforced security control',\n true,\n );\n return;\n }\n\n const pick = await this.pickAdapter(payload.runtime, payload.policy.mode);\n if (!pick.ok) {\n this.decline(taskId, pick.reason, pick.retryable);\n return;\n }\n\n const decision = computeEffectivePolicy(payload.policy, this.deps.permissionDefaults);\n if (!decision.ok) {\n this.decline(taskId, decision.reason ?? 'policy rejected', false);\n return;\n }\n\n let known: Awaited<ReturnType<SessionWorkspaceStore['get']>> = undefined;\n let workspaceDir: string;\n let gitLease: GitWorkspaceLease | undefined;\n let gitWorkspaceId: string | undefined;\n let gitBaseline: string | undefined;\n let gitExisting = false;\n let plainWorkspaceNeedsResolve = false;\n if (this.deps.gitWorkspaceManager && this.deps.gitWorkspaceStore) {\n known = payload.sessionRef ? await this.deps.sessionWorkspaces.get(payload.sessionRef) : undefined;\n const gitManager = this.deps.gitWorkspaceManager;\n const gitStore = this.deps.gitWorkspaceStore;\n if (payload.sessionRef) {\n const ledger = await gitStore.findBySessionAnyPhase(payload.sessionRef).catch(() => undefined);\n const sameProtocolTask = ledger?.taskId === taskId;\n const interruptedOldTask = ledger?.phase === 'interrupted' && sameProtocolTask;\n const activeDifferentTask = ledger !== undefined && ledger.taskId !== taskId && (ledger.phase === 'preparing' || ledger.phase === 'active');\n if (!known || known.workspaceKind !== 'git' || !known.gitWorkspaceId || !ledger ||\n ledger.workspaceId !== known.gitWorkspaceId || ledger.sessionRef !== payload.sessionRef ||\n path.resolve(ledger.workspaceDir) !== path.resolve(known.workspaceDir) ||\n interruptedOldTask || activeDifferentTask) {\n this.decline(taskId, 'session is incompatible with Git workspace mode', true);\n return;\n }\n workspaceDir = known.workspaceDir;\n gitWorkspaceId = known.gitWorkspaceId;\n gitBaseline = ledger.baseline;\n gitExisting = true;\n try {\n await gitManager.validateExisting(workspaceDir);\n } catch {\n this.decline(taskId, 'workspace is busy or unavailable', true);\n return;\n }\n } else {\n workspaceDir = path.join(this.deps.workspaceRoot, taskId);\n }\n try {\n gitLease = await gitManager.acquireLease(workspaceDir, payload.sessionRef);\n } catch {\n this.decline(taskId, 'workspace is busy or unavailable', true);\n return;\n }\n } else if (!this.deps.gitWorkspaceManager && !this.deps.gitWorkspaceStore) {\n known = payload.sessionRef ? await this.deps.sessionWorkspaces.get(payload.sessionRef) : undefined;\n workspaceDir = known?.workspaceDir ?? path.join(this.deps.workspaceRoot, taskId);\n plainWorkspaceNeedsResolve = true;\n } else {\n this.decline(taskId, 'workspace mode is unavailable', true);\n return;\n }\n\n // Every check above is local/config-driven (an adapter's `detect()` is\n\n // the only I/O, and it costs nothing to have run before committing) and\n // needed no commitment from this device. Only now do we actually take\n // the task — `task.decline` above is the alternative path for anything\n // that got this far without claiming.\n this.deps.send(\n createEnvelope(\n 'task.claim',\n {\n deviceId: this.deps.deviceId,\n // M5 (claimed runtime, docs/protocol.md §3.1): the ACTUAL adapter\n // `pickAdapter` just selected — covers both the explicit-runtime\n // path (`payload.runtime` named one) and the auto-select\n // (preference-ordered, pi last by default — M5 batch-3, see\n // `DEFAULT_RUNTIME_PREFERENCE`) path (`payload.runtime` was\n // absent) uniformly, since `pick.adapter` already reflects\n // whichever one won either way. Distinct from `payload.runtime`\n // (the merely REQUESTED runtime): this is what closes the gap\n // where an auto-selected task left the server never learning\n // which runtime actually ran.\n runtime: isKnownRuntimeId(pick.adapter.id) ? pick.adapter.id : undefined,\n // S0/D-4 (`task.claim.capabilities`, docs/protocol.md §2.4): the\n // selected adapter's own capability self-report, carried on the\n // same message that establishes the task↔runtime binding. The\n // server gates control messages (`task.steer`) on this and only\n // this — connection-level `conn.hello.runtimes[].capabilities`\n // stays discovery, because it is transport-shaped (a long-poll-only\n // daemon never sends `conn.hello`) and describes a device rather\n // than a task.\n //\n // Sent UNCONDITIONALLY, deliberately NOT gated on\n // `isKnownRuntimeId` the way `runtime` above is: `runtime` is a\n // closed protocol enum a custom adapter has no member of, but\n // capabilities are a self-report every adapter can make honestly.\n // Gating them would silently strip a custom steer-capable\n // adapter's own truth and leave the server fail-closing on it\n // forever.\n capabilities: toRuntimeInfoCapabilities(pick.adapter.capabilities()),\n },\n { taskId },\n ),\n );\n\n // Resolve the instruction blob after claim; workspace preparation follows.\n let resolvedInstruction: string;\n try {\n resolvedInstruction = await this.resolveInstruction(payload.instruction);\n if (plainWorkspaceNeedsResolve) workspaceDir = await this.resolveWorkspaceDir(taskId, known?.workspaceDir);\n } catch (err) {\n gitLease?.release();\n await this.fail(taskId, `failed to resolve instruction blob: ${errorMessage(err)}`, true);\n return;\n }\n\n if (this.deps.gitWorkspaceManager && gitLease) {\n try {\n let observation: GitWorkspaceObservation;\n if (gitExisting) {\n observation = await this.deps.gitWorkspaceManager.validateExisting(workspaceDir);\n } else {\n const workspaceId = randomUUID();\n const now = new Date().toISOString();\n gitWorkspaceId = workspaceId;\n await this.deps.gitWorkspaceStore?.upsert({\n workspaceId,\n taskId,\n workspaceDir,\n phase: 'preparing',\n commitsSinceBaseline: 0,\n staged: 0,\n unstaged: 0,\n untracked: 0,\n conflicted: 0,\n createdAt: now,\n updatedAt: now,\n });\n this.deps.onGitWorkspaceEvent?.({ taskId, workspaceId, phase: 'preparing' });\n observation = await this.deps.gitWorkspaceManager.prepareFresh(workspaceDir);\n }\n const workspaceId = gitWorkspaceId ?? randomUUID();\n const phase: GitWorkspacePhase = 'active';\n const now = new Date().toISOString();\n const ledgerRecord: GitWorkspaceLedgerRecord = {\n workspaceId,\n taskId,\n workspaceDir,\n sessionRef: payload.sessionRef,\n phase,\n baseline: gitBaseline ?? observation.head,\n current: observation.head,\n commitsSinceBaseline: observation.commitsSinceBaseline,\n staged: observation.staged,\n unstaged: observation.unstaged,\n untracked: observation.untracked,\n conflicted: observation.conflicted,\n createdAt: now,\n updatedAt: now,\n };\n await this.deps.gitWorkspaceStore?.upsert(ledgerRecord);\n this.deps.onGitWorkspaceEvent?.({ taskId, workspaceId, phase, observation });\n gitWorkspaceId = workspaceId;\n gitBaseline = gitBaseline ?? observation.head;\n } catch (err) {\n const category = (err as GitWorkspaceError).category ?? 'repository-invalid';\n await this.updateGitPhaseBestEffort(gitWorkspaceId, 'failed', category);\n gitLease.release();\n this.deps.onGitWorkspaceEvent?.({ taskId, workspaceId: gitWorkspaceId ?? '', phase: 'failed', errorCategory: category });\n await this.fail(taskId, 'Git workspace preparation failed', true);\n return;\n }\n }\n\n const ctx: TaskContext = {\n workspaceDir,\n policy: decision.policy,\n ...(gitWorkspaceId ? { gitWorkspace: { workspaceId: gitWorkspaceId, baseline: gitBaseline } } : {}),\n // M5: no longer `process.env` verbatim (see `environment.ts`'s own\n // module doc comment for the credential-leak gap that closed) —\n // built fresh per task from the SPECIFIC adapter `pickAdapter`\n // above already selected, so this always runs after adapter\n // selection: `pick.adapter.environmentRequirements?.()` (undefined\n // ⇒ platform baseline only, fail-closed) plus this device's own\n // `runtimeEnvironment` override, keyed by that same adapter's `id`.\n env: buildRuntimeEnv({\n ambient: process.env,\n requirements: pick.adapter.environmentRequirements?.(),\n locallyAllowedNames: this.deps.runtimeEnvironment?.[pick.adapter.id]?.allow,\n }),\n // M4 Phase 3: adapter-agnostic and cheap to always populate — only an\n // adapter whose runtime genuinely supports an out-of-band approval\n // pause (claude, today) ever reads this. `resolve` is a closure over\n // `taskId` (not a pre-bound approvalId): it looks up whichever\n // approval is CURRENTLY pending for this task at call time, since one\n // task/session can face several approval requests, one at a time,\n // over its life. See `types.ts`'s `ApprovalChannel` doc comment.\n approvalChannel: {\n taskId,\n storeDir: this.deps.storeDir,\n productId: this.deps.productId,\n timeoutMs: this.deps.approvalTimeoutMs ?? DEFAULT_APPROVAL_TIMEOUT_MS,\n resolve: async (approved, reason) => {\n const currentActive = this.tasks.get(taskId);\n const pendingId = currentActive?.pendingApprovalId;\n if (!pendingId) {\n throw new NoPendingApprovalError(taskId);\n }\n // 'wire': this closure is invoked ONLY by an adapter's own\n // `session.resolveApproval()` (e.g. `ClaudeSession.resolveApproval`\n // under `confirm` mode), which in turn is called ONLY from\n // `handleApprove`/`handleReject` below — i.e. a server-sent wire\n // `task.approve`/`task.reject`. The server already knows this\n // decision (it sent it); `task.approval_resolved` must never be\n // sent back for it — see `ApprovalOrigin`'s own doc comment\n // (`approvals.ts`) and `sendApprovalResolved`'s gate below.\n this.deps.approvalRegistry.resolve(pendingId, approved ? 'approve' : 'reject', reason, 'wire');\n },\n },\n };\n const effectiveOffer: TaskOfferPayload = {\n ...payload,\n instruction: gitWorkspaceId ? prependGitWorkspaceGuidance(resolvedInstruction) : resolvedInstruction,\n // Never forward a sessionRef this device has no recorded workspace\n // for (stale, from another device, or simply made up) — an adapter\n // that tries to resume an id it never minted fails outright (pi:\n // \"No session found matching '<id>'\", exit 1, empirically confirmed)\n // instead of silently starting fresh, so an unresolvable sessionRef\n // must look identical to \"none supplied\" by the time it reaches the\n // adapter, not get forwarded as a resume attempt doomed to fail.\n sessionRef: known ? payload.sessionRef : undefined,\n };\n\n let session: Session;\n try {\n session = await pick.adapter.start(effectiveOffer, ctx);\n } catch (err) {\n const retryable = !(err instanceof PolicyUnsupportedError);\n await this.updateGitPhaseBestEffort(gitWorkspaceId, 'failed', 'repository-invalid');\n gitLease?.release();\n await this.fail(taskId, `adapter failed to start: ${errorMessage(err)}`, retryable);\n return;\n }\n\n // Finding F4, checkpoint 2 (\"consulted when start() resolves\"): a\n // task.cancel arrived while adapter.start() was in flight — i.e. AFTER\n // task.claim already went out above, so declining is no longer an\n // option. Tear the just-started session down before it's ever\n // registered as active (this.tasks.set below) or reported task.started,\n // so pump() never begins and no zombie turn runs — then report the\n // outcome exactly like a post-registration cancel would (M1 gap #6:\n // task.cancelled, not task.fail).\n if (this.pendingCancelled.has(taskId)) {\n const reason = this.pendingCancelled.get(taskId);\n this.pendingCancelled.delete(taskId);\n try {\n await session.interrupt();\n } catch {\n // best-effort — still report cancellation below\n }\n try {\n await session.close();\n } catch {\n // best-effort teardown\n }\n gitLease?.release();\n await this.updateGitPhaseBestEffort(gitWorkspaceId, 'cancelled');\n this.deps.send(createEnvelope('task.cancelled', { reason }, { taskId }));\n return;\n }\n\n // Claimed -> Running (M1 gap #2): report `task.started` only once the\n // adapter session has actually started — never implied by `task.claim`.\n this.deps.send(createEnvelope('task.started', {}, { taskId }));\n\n // This handoff (construct `active` -> register it -> kick off `pump()`)\n // must stay synchronous, with no `await` in between: a `task.cancel`\n // (or `task.steer`/`task.approve`/`task.reject`) for this exact taskId\n // can arrive and be processed by `handleEnvelope` at any `await` point,\n // and every one of those handlers starts with `this.tasks.get(taskId)`\n // — if this task isn't registered yet, they silently no-op (see e.g.\n // `handleCancel`). An earlier version of this method awaited the\n // sessionWorkspaces write (below) before registering `active` and broke\n // exactly this: a cancel racing a task.offer lost its `interrupt()`/\n // `task.cancelled` entirely.\n const active: ActiveTask = {\n taskId,\n adapter: pick.adapter,\n session,\n workspaceDir,\n gitWorkspaceId,\n gitLease,\n gitBaseline,\n summaryParts: [],\n batcher: new ProgressBatcher(\n (seq, events) => this.deps.send(createEnvelope('task.progress', { seq, events }, { taskId, seq })),\n this.deps.batcherOptions,\n ),\n approvalQueue: [],\n outputBytesSoFar: 0,\n };\n this.tasks.set(taskId, active);\n // M5 batch-3 (workstream 2): see `armMaxDurationTimer`'s own doc\n // comment — still inside the synchronous construct -> register -> arm\n // -> pump handoff described just below (no `await` yet).\n if (payload.limits?.maxDurationMs !== undefined) {\n this.armMaxDurationTimer(active, payload.limits.maxDurationMs);\n }\n void this.pump(active);\n\n // Record (or refresh) this session's resumable workspace for any future\n // task.offer that carries the same sessionRef, fire-and-forget:\n // `session.sessionRef` is always the adapter's real, resumable\n // identifier (see PiSession / resolveFreshSessionId) whether or not\n // *this* dispatch was itself a resume. Deliberately not awaited — see\n // the comment above; losing this mapping only costs a future resume\n // opportunity, never the correctness of the task in progress.\n void this.deps.sessionWorkspaces\n .record(session.sessionRef, {\n workspaceDir,\n runtimeSessionId: session.sessionRef,\n ...(gitWorkspaceId ? { workspaceKind: 'git' as const, gitWorkspaceId } : {}),\n })\n .catch(() => {});\n if (gitWorkspaceId && this.deps.gitWorkspaceStore) {\n void this.deps.gitWorkspaceStore.attachSession(gitWorkspaceId, session.sessionRef).catch(() => {});\n }\n } finally {\n this.inFlightOffers.delete(taskId);\n }\n }\n\n /** Protocol §7: an instruction too large to inline arrives as a `blobRef` — resolve it via the blob client rather than failing closed. */\n private async resolveInstruction(instruction: TaskOfferPayload['instruction']): Promise<string> {\n if (typeof instruction === 'string') return instruction;\n return this.deps.blobClient.resolveInstruction(instruction.blobRef);\n }\n\n private async pump(active: ActiveTask): Promise<void> {\n try {\n for await (const event of active.session.events) {\n // A concurrent task.cancel/task.reject may already have finished\n // (and deleted) this task while this loop was awaiting the next\n // event — e.g. the runtime's own interrupt handling settles with a\n // trailing turn_end shortly after handleCancel() already reported\n // task.cancelled and started tearing the session down. That event\n // is stray at this point: without this check, the turn_end branch\n // below would unconditionally resend task.complete (and any\n // buffered task.progress) for a task the server already moved to a\n // terminal state, which it can only log as a dropped/illegal\n // transition (console.warn) rather than the silent-drop §9\n // guarantees for genuinely stale terminal messages. Mirrors the\n // same check already used below for the non-turn_end loop exits.\n if (this.tasks.get(active.taskId) !== active) return;\n\n // M5 batch-3 (workstream 2): DaemonConfig.maxTaskOutputBytes\n // enforcement — see `estimateEventBytes`'s own doc comment for\n // exactly what's counted (a serialized-payload-length\n // approximation) and what isn't (batching overhead; an artifact's\n // actual file bytes, uploaded separately by `sendArtifact`). Checked\n // here, before any per-event-type handling below, so a task that's\n // about to be torn down for this never pays for `sendArtifact`'s own\n // disk I/O or dispatches a pointless approval request first.\n active.outputBytesSoFar += estimateEventBytes(event);\n if (active.outputBytesSoFar > this.maxTaskOutputBytes) {\n active.batcher.flush();\n await this.failActiveTaskForResourceLimit(\n active.taskId,\n `${MAX_OUTPUT_BYTES_EXCEEDED_REASON_PREFIX}: task emitted approximately ${active.outputBytesSoFar} bytes of output (serialized-event-length approximation), exceeding the configured limit of ${this.maxTaskOutputBytes} bytes`,\n );\n return;\n }\n\n if (event.type === 'needs_approval') {\n active.batcher.flush();\n // Acceptance finding 1 (dormant branch bypassing the approval\n // registry): this used to mint its own approvalId and stamp it\n // onto `active.pendingApprovalId` directly, entirely bypassing\n // `deps.approvalRegistry` — no registry entry ever existed for it,\n // and nothing ever cleared this field for it either (clearing\n // lived ONLY in `dispatchApproval`'s own `onResolve` callback,\n // which is registered only when a request actually goes through\n // the registry). For a hypothetical adapter mixing this\n // stream-based path with the out-of-band `approvalChannel` path\n // on the SAME task (e.g. a custom session whose `resolveApproval()`\n // sometimes delegates to `ctx.approvalChannel.resolve()`), that\n // meant: this event could clobber an already-dispatched channel\n // approval's id (a later wire decision for the REAL dispatched\n // approval would then look stale and be dropped); a resolved\n // dormant approval left a stale id blocking every later\n // `requestApproval` call for this task until the task finished;\n // and routing a wire decision through `ctx.approvalChannel.resolve()`\n // for a dormant id that was never registered threw\n // `ApprovalNotFoundError` — not treated as benign staleness by\n // `handleApprove`/`handleReject` — failing the task outright.\n //\n // Fix: reuse `requestApproval`, the SAME entry point a real\n // out-of-band approval (MCP-triggered) goes through. This gives\n // the dormant path the exact same lifecycle: it queues (rather\n // than clobbers) behind an already-dispatched approval for this\n // task, registers in `deps.approvalRegistry` once actually\n // dispatched, and arms the same timeout — see\n // `task-runner-approval.test.ts`'s mixed-path regression test.\n //\n // C1 (cross-model review, P1): reusing `requestApproval` fixed the\n // registry-bypass above, but its returned promise used to be\n // discarded outright (`void`d with no continuation at all). That\n // was harmless for the WIRE path — `handleApprove`/`handleReject`\n // already call `active.session.resolveApproval()` themselves,\n // directly, before ever touching the registry (see\n // `clearPendingApproval`'s own doc comment) — but a decision that\n // resolves THIS registry entry any OTHER way (the local\n // control-socket CLI's `approvals.resolve`, this request's own\n // `dispatchApproval` timeout, or a bounded-eviction fallback in\n // `ApprovalRegistry.register`) never goes through\n // `handleApprove`/`handleReject` at all — so nothing ever called\n // `session.resolveApproval()` for it. The runtime session stayed\n // paused forever even though the daemon (and, for a `'local'`\n // origin, the server too, via `sendApprovalResolved`) already\n // considered the approval resolved.\n //\n // Fix: chain a continuation onto the SAME promise that forwards\n // the decision into `active.session.resolveApproval()` — but ONLY\n // when the resolution's origin is NOT `'wire'`, since the wire\n // path already did that itself, synchronously, before this\n // registry entry was ever resolved; forwarding again here would\n // double-resolve the session. `origin` is deliberately NOT part of\n // the promise's own resolved value — that shape (`{approved,\n // reason}`) is `requestApproval`'s public contract, asserted\n // exactly by this file's own tests and relied on by\n // `byok-approval-mcp.ts`/`create-daemon.ts`'s control socket —\n // instead it's threaded through via the optional `onOrigin`\n // callback parameter (additive, invisible to every other caller).\n // See `task-runner-approval.test.ts`'s \"C1\" describe block for the\n // local-resolve / wire-resolve / timeout regression tests, and\n // `clearPendingApproval`'s own doc comment for the sibling wire\n // half of this exact design.\n const { taskId } = active;\n let resolutionOrigin: ApprovalOrigin = 'local';\n void this.requestApproval(taskId, event.summary, (origin) => {\n resolutionOrigin = origin;\n }).then(async ({ approved, reason }) => {\n if (resolutionOrigin === 'wire') return;\n // The task may have finished (completed/failed/cancelled) by the\n // time this settles — look it up fresh rather than trust the\n // `active` closed over above, mirroring every other post-await\n // guard in this method (e.g. this loop's own stray-event check,\n // and the catch block below).\n if (this.tasks.get(taskId) !== active) return;\n try {\n await active.session.resolveApproval(approved, reason);\n } catch (err) {\n await this.fail(taskId, `failed to resume session after approval decision: ${errorMessage(err)}`, false);\n }\n });\n continue;\n }\n if (event.type === 'turn_end') {\n active.batcher.push(event);\n active.batcher.flush();\n await this.observeGit(active, 'completed');\n this.deps.send(\n createEnvelope(\n 'task.complete',\n { summary: active.summaryParts.join(''), sessionRef: active.session.sessionRef },\n { taskId: active.taskId, sessionRef: active.session.sessionRef },\n ),\n );\n await this.finish(active.taskId);\n return;\n }\n if (event.type === 'progress') {\n active.summaryParts.push(event.text);\n }\n if (event.type === 'artifact') {\n await this.sendArtifact(active, event.name, event.contentType);\n }\n active.batcher.push(event);\n }\n // The events iterable ended without an explicit turn_end. This is\n // usually the underlying runtime process exiting unexpectedly — but\n // it's also exactly what happens when `handleCancel`/`handleReject`\n // concurrently call `session.close()` while this loop is still\n // awaiting the same iterable (ending it is how those paths stop the\n // session). Check identity against the tasks map — if something else\n // already finished this exact active task, its own message\n // (task.cancelled / task.fail) already reported the outcome; this is\n // not a second failure. M5 batch-3 (workstream 2): `beingTornDown` is\n // the SAME guard for `teardownActiveTask`'s own controlled teardown\n // (graceful shutdown / resource-limit enforcement) — see\n // `ActiveTask.beingTornDown`'s own doc comment for why the identity\n // check alone doesn't cover that path's pre-finish() hard-kill\n // `close()` call.\n if (this.tasks.get(active.taskId) !== active || active.beingTornDown) return;\n await this.fail(active.taskId, 'runtime session ended without completing the task', true);\n } catch (err) {\n if (this.tasks.get(active.taskId) !== active || active.beingTornDown) return;\n active.batcher.flush();\n await this.fail(active.taskId, `runtime error: ${errorMessage(err)}`, true);\n }\n }\n\n /**\n * Protocol §7: an `artifact` `AgentEvent` only names a file the runtime\n * wrote into the task workspace (`name`/`contentType` — it carries no\n * content of its own); this reads it from disk and sends the actual\n * `task.artifact` wire message — inline (base64) under 64KB, or via blob\n * upload above that, with a sha-256 `contentHash`.\n *\n * Finding F7/N5: `name` is untrusted (it's whatever the runtime/agent\n * reported — ultimately model-influenced) and used to be `path.join`'d\n * onto `workspaceDir` with no check that the result stayed inside it, so\n * `../../<anything>` (or an absolute `name`, which `path.resolve` accepts\n * verbatim as the whole path) could read and exfiltrate an arbitrary file\n * on the host as a task artifact. A later fix (`resolveArtifactPath`)\n * closed the traversal case by realpath-checking containment, but still\n * returned a path string that was reopened by pathname afterward — a\n * check-then-use TOCTOU race letting the final component be swapped for\n * an out-of-workspace symlink between the check and the read.\n * `openArtifact` now opens the file (with `O_NOFOLLOW`) and verifies the\n * resulting file descriptor directly; this reads from that same handle,\n * never re-opening by pathname. Read/upload failures (including a\n * rejected name or a blocked symlink swap) are also not silent: they\n * surface as a loud `error` `AgentEvent` batched into `task.progress`,\n * and are logged — the task itself can still reach `task.complete`\n * normally, but the dropped artifact is now visible in the event stream\n * rather than swallowed.\n */\n private async sendArtifact(active: ActiveTask, name: string, contentType: string): Promise<void> {\n const opened = await openArtifact(active.workspaceDir, name);\n if (!opened.ok) {\n this.reportArtifactError(active, name, opened.reason);\n return;\n }\n\n let bytes: Buffer;\n try {\n bytes = await opened.handle.readFile();\n } catch (err) {\n this.reportArtifactError(active, name, `failed to read artifact \"${name}\": ${errorMessage(err)}`);\n return;\n } finally {\n await opened.handle.close().catch(() => {});\n }\n\n if (bytes.length <= MAX_INLINE_ARTIFACT_BYTES) {\n const inline = bytes.toString('base64');\n if (new TextEncoder().encode(inline).length <= MAX_INLINE_ARTIFACT_BYTES) {\n this.deps.send(createEnvelope('task.artifact', { name, contentType, inline }, { taskId: active.taskId }));\n return;\n }\n }\n\n try {\n const blobRef: BlobRef = await this.deps.blobClient.uploadArtifact(bytes, contentType);\n this.deps.send(createEnvelope('task.artifact', { name, contentType, blobRef }, { taskId: active.taskId }));\n } catch (err) {\n this.reportArtifactError(active, name, `failed to upload artifact \"${name}\": ${errorMessage(err)}`);\n }\n }\n\n /** Loud, non-silent artifact failure (finding F7): logged, and folded into this task's own progress stream as an `error` AgentEvent rather than swallowed — the task itself can still complete normally, but the omission is now visible. */\n private reportArtifactError(active: ActiveTask, name: string, reason: string): void {\n console.error(`[byok/client] artifact \"${name}\" for task ${active.taskId} dropped: ${reason}`);\n active.batcher.push({ type: 'error', message: reason });\n }\n\n private async handleCancel(taskId: string, reason: string | undefined): Promise<void> {\n const active = this.tasks.get(taskId);\n if (!active) {\n // Finding F4: not registered yet — record it in case handleOffer is\n // still in flight for this exact taskId (claimed but not yet started;\n // see the class-level doc on `pendingCancelled` and the two\n // checkpoints in handleOffer). A genuinely stale/unknown/already-\n // finished taskId just leaves a harmless, never-consulted entry —\n // identical in effect to the old silent-drop behavior for that case\n // (M3-B: except now bounded — see `setPendingCancelled`).\n this.setPendingCancelled(taskId, reason);\n return;\n }\n try {\n await active.session.interrupt();\n } catch {\n // best-effort — still report cancellation below\n }\n await this.observeGit(active, 'salvage');\n // Deliberately NOT active.batcher.flush()-ed here (M1-4 e2e finding):\n // §4's \"server state is authoritative on its own action\" rule means the\n // server already moved this task to `Cancelled` — and already closed\n // this task's ServerTaskEvent queue (hub.ts's onStateChange, called\n // synchronously from cancelTask() before task.cancel is even sent) —\n // before this notification reaches the daemon at all. Any progress\n // still buffered in the batcher at this point can therefore never reach\n // an embedder no matter what: sending it only draws a\n // dropped/illegal-transition warning on the server for a `task.progress`\n // arriving against an already-terminal task (hub.ts's onProgress has no\n // §9 stale-terminal-message idempotency for task.progress the way it\n // does for task.complete/fail/cancelled). `finish()` below already stops\n // the batcher; nothing else needs to happen with its buffer contents.\n // M1 gap #6: the canonical, explicit cancellation message — no longer\n // `task.fail({reason:'cancelled'})`.\n this.deps.send(createEnvelope('task.cancelled', { reason }, { taskId }));\n await this.finish(taskId);\n }\n\n /** M3-B: bounded insert for `pendingCancelled` — see its class-level doc comment and `MAX_TRACKED_TASK_IDS`. Evicts the oldest SAFE-TO-EVICT entry once over cap — see `evictPendingCancelled` (finding #5: not simply \"the oldest entry\", which could be an in-flight offer's own cancel marker). */\n private setPendingCancelled(taskId: string, reason: string | undefined): void {\n this.pendingCancelled.set(taskId, reason);\n if (this.pendingCancelled.size > MAX_TRACKED_TASK_IDS) {\n this.evictPendingCancelled();\n }\n }\n\n /**\n * Finding #5 (Codex counterexample — see `inFlightOffers`'s class-level\n * doc comment for the exact scenario): evicts the OLDEST entry that is\n * NOT a taskId currently inside `handleOffer`'s in-flight window, rather\n * than unconditionally the single oldest entry. `Map` iterates in\n * insertion order, so this is \"oldest entry that's safe to drop,\" which\n * only differs from \"the oldest entry, period\" when that oldest entry\n * happens to belong to a task still being processed — exactly the case\n * that must never be evicted, since `handleOffer`'s own checkpoint 2\n * still needs to observe it.\n *\n * `inFlightOffers` is naturally tiny (bounded by this device's real\n * concurrent-offer-processing count — normally single digits, driven by\n * how many `task.offer`s are simultaneously mid-`adapter.start()` — nowhere\n * near `MAX_TRACKED_TASK_IDS`), so this scan is cheap in practice: it\n * finds a safe entry at or near the front almost always. The only case\n * where NO entry is safe to evict is every single tracked cancel\n * belonging to a currently in-flight offer, which would require this\n * device to have `MAX_TRACKED_TASK_IDS` offers mid-processing\n * simultaneously — implausible, but handled without corrupting anything:\n * this insert is simply allowed to leave the map one entry over cap\n * rather than evict something still needed, and it shrinks back under cap\n * as those in-flight offers resolve and their entries get CONSUMED\n * (deleted by `handleOffer` itself) rather than evicted.\n */\n private evictPendingCancelled(): void {\n for (const key of this.pendingCancelled.keys()) {\n if (!this.inFlightOffers.has(key)) {\n this.pendingCancelled.delete(key);\n return;\n }\n }\n console.warn(\n `[byok/client] pendingCancelled exceeded ${MAX_TRACKED_TASK_IDS} entries with every tracked taskId currently in-flight — leaving it temporarily over cap rather than evict a marker a running handleOffer() still needs`,\n );\n }\n\n /**\n * S0/H-006: an inbound `task.steer` is normally impossible for a runtime\n * that cannot steer — the hub gates it at claim-time capability\n * (`steer_unsupported_runtime`) and never sends the envelope. If one\n * arrives anyway (a forged sender, a pre-gate server, a device whose\n * adapter set changed), the session throws {@link SteerUnsupportedError},\n * which is a PERMANENT property of that runtime, not a transient failure.\n *\n * Rethrowing it would hand it to `ConnectionManager.process()`\n * (`connection-manager.ts` `stalledAtSeq`), which freezes the cursor at\n * that seq and redelivers the same envelope forever — every retry\n * guaranteed to fail identically, and every later envelope for every\n * other task blocked behind it. So this is classified as a\n * non-retryable protocol/authority error: record it and return normally,\n * which acks the envelope and lets the cursor advance. Nothing is\n * swallowed — the steer simply has no reachable success state, and the\n * honest terminal action is to log it and move on.\n *\n * Every OTHER error stays transient and is rethrown untouched, preserving\n * the existing stall/redelivery semantics exactly.\n */\n private async handleSteer(taskId: string, text: string): Promise<void> {\n const active = this.tasks.get(taskId);\n if (!active) return;\n try {\n await active.session.steer(text);\n } catch (err) {\n if (err instanceof SteerUnsupportedError) {\n console.error(\n `[byok/client] inbound task.steer for task ${taskId} rejected: runtime \"${err.runtimeId}\" has no steering channel (${err.message}) — acked without retry; this envelope should have been gated server-side`,\n );\n return;\n }\n throw err;\n }\n }\n\n /**\n * M4 Phase 3: the daemon-side half of the out-of-band approval channel\n * (`types.ts`'s `ApprovalChannel`) — called from `create-daemon.ts`'s\n * `approvals.request` control method, itself called by `byok-approval-mcp`\n * (a claude-spawned MCP-server child process, NOT the adapter/session\n * in-process — see `ApprovalChannel`'s own doc comment for the full why\n * this seam exists at all rather than an `AgentEvent`).\n *\n * Deliberately independent of the dormant `needs_approval` `AgentEvent`\n * path in `pump()` below (~line 611): empirically confirmed (M4 Phase 3\n * STEP 0), claude's own stream-json output emits NOTHING while a\n * permission-prompt-tool call is outstanding — the gap between a `tool_use`\n * frame and its `tool_result` is invisible on the wire, indistinguishable\n * from ordinary model \"thinking\" latency. `pump()`'s for-await loop over\n * `active.session.events` therefore has no event to ever branch on for\n * this case; the ONLY signal that a task is paused arrives out-of-band,\n * over the control socket, which is exactly what this method is for. The\n * `needs_approval` path stays dormant, untouched, for a hypothetical\n * future adapter whose runtime DOES expose the pause on its own event\n * stream.\n *\n * Sends `task.await_approval` (protocol §5), registers a fresh entry in\n * `deps.approvalRegistry`, and races it against `deps.approvalTimeoutMs`\n * (default {@link DEFAULT_APPROVAL_TIMEOUT_MS}) — an unanswered request\n * force-resolves as a fail-closed rejection once the deadline passes. Both\n * that timeout AND a real decision (server wire `task.approve`/\n * `task.reject` via `handleApprove`/`handleReject` below, OR the local\n * CLI's `approvals.resolve` in `control-server.ts`) converge on the exact\n * same `ApprovalRegistry.resolve()` call — \"first resolution wins, the\n * loser is a clean already-resolved no-op\" is `ApprovalRegistry`'s own\n * existing guarantee, reused here rather than reimplemented.\n *\n * Fails closed immediately (no registry entry ever created) for a `taskId`\n * that isn't currently active on this device — a stale/unknown/\n * already-finished task has nothing to pause.\n *\n * M4 Phase 4 (fold-in from the P3 gate — concurrent-approval-overwrite\n * fix): claude's parallel tool use can call this MORE THAN ONCE for the\n * SAME task before the first call's approval is resolved — each parallel\n * tool call is its own independent `byok-approval-mcp` `tools/call`\n * request, and the MCP protocol lets several be in flight on one\n * connection at once (see `byok-approval-mcp.ts`'s own doc comment on\n * sharing one control-socket connection across them). Before this fix,\n * `active.pendingApprovalId = approvalId` above was unconditional — a\n * second concurrent call for the same task silently overwrote the first\n * call's id, so only the LATEST request was ever wire-resolvable\n * (`ctx.approvalChannel.resolve`, below, and any server `task.approve`/\n * `task.reject`, both resolve by looking up `active.pendingApprovalId`);\n * every earlier one could only ever time out.\n *\n * Fix: only ONE approval per task is ever actually DISPATCHED (registered\n * in `approvalRegistry` + `task.await_approval` sent + its own timeout\n * window running) at a time — see `dispatchApproval` below. A second\n * (third, ...) concurrent call for a task that already has one dispatched\n * queues (FIFO, `active.approvalQueue`) instead of overwriting anything,\n * and is only dispatched — with its OWN fresh approvalId and its OWN\n * timeout window starting at THAT dispatch, not at this call's arrival —\n * once the currently-dispatched one resolves (see\n * `dispatchNextQueuedApproval`). The MCP callers on the other end are\n * already independently blocked, each awaiting its own `requestApproval`\n * promise, so this added latency for a queued request is transparent to\n * them: nothing here changes what claude itself observes beyond \"the\n * answer took a bit longer.\" Bounded by\n * {@link MAX_PENDING_APPROVALS_PER_TASK}: a request arriving once this\n * task's queue is already full is rejected fail-closed immediately,\n * mirroring the unknown/inactive-taskId case above.\n *\n * C1 (cross-model review, P1): `onOrigin`, if supplied, is invoked\n * synchronously — strictly BEFORE this method's own returned promise\n * resolves — with the `ApprovalOrigin` (`'wire' | 'local'`) the eventual\n * decision actually resolved through (see `ApprovalRegistry.resolve`'s own\n * `origin` parameter). Purely additive/internal: every existing caller\n * (`byok-approval-mcp.ts`, `create-daemon.ts`'s control socket, this file's\n * own tests) omits it and observes exactly the same `{approved, reason}`\n * resolution as before. `pump()`'s dormant `needs_approval` branch is the\n * one caller that supplies it, to decide whether it still needs to\n * forward the decision into `active.session.resolveApproval()` itself —\n * see that branch's own doc comment for why origin can't simply ride\n * along on the resolved value instead.\n */\n async requestApproval(\n taskId: string,\n summary: string,\n onOrigin?: (origin: ApprovalOrigin) => void,\n ): Promise<{ approved: boolean; reason?: string }> {\n const active = this.tasks.get(taskId);\n if (!active) {\n return { approved: false, reason: 'task is not currently active on this device' };\n }\n\n if (active.pendingApprovalId !== undefined) {\n if (active.approvalQueue.length >= MAX_PENDING_APPROVALS_PER_TASK) {\n return {\n approved: false,\n reason: `too many approval requests already queued for task ${taskId} (max ${MAX_PENDING_APPROVALS_PER_TASK}) — rejected fail-closed`,\n };\n }\n return new Promise((resolve) => {\n active.approvalQueue.push({ summary, resolve, onOrigin });\n });\n }\n\n return this.dispatchApproval(active, summary, onOrigin);\n }\n\n /**\n * Actually dispatch one approval request for `active`'s task: register it\n * in `deps.approvalRegistry`, send its `task.await_approval`, and start its\n * own `deps.approvalTimeoutMs` window — see `requestApproval`'s own doc\n * comment for why this is split out (only ever ONE dispatched per task at\n * a time; everything else queues). Called either immediately\n * (`requestApproval`, nothing else pending for this task) or from\n * `dispatchNextQueuedApproval` once the previously-dispatched request for\n * this same task resolves.\n *\n * C1: `onOrigin` — see `requestApproval`'s own doc comment — is forwarded\n * verbatim from whichever caller dispatched this (directly, or via\n * `QueuedApprovalRequest.onOrigin` once `dispatchNextQueuedApproval` pulls\n * it off the queue) and invoked from the registered `onResolve` callback\n * below, BEFORE `resolve(...)` — so it always fires strictly before this\n * method's own returned promise settles.\n */\n private dispatchApproval(\n active: ActiveTask,\n summary: string,\n onOrigin?: (origin: ApprovalOrigin) => void,\n ): Promise<{ approved: boolean; reason?: string }> {\n const { taskId } = active;\n const approvalId = randomUUID();\n active.pendingApprovalId = approvalId;\n // Finding F4: see `onApprovalDispatched`'s own doc comment — must fire\n // BEFORE `deps.send` below so the observer has already stashed this\n // approvalId by the time that same synchronous call triggers\n // `DaemonObserver.handleOutboundEnvelope`'s `task.await_approval` case.\n this.deps.onApprovalDispatched?.(taskId, approvalId);\n // Mirrors the dormant needs_approval branch's own flush-before-pausing\n // discipline (~line 611 below): whatever progress already accumulated\n // this turn should reach the server before the task's state moves to\n // AwaitApproval, not sit buffered behind an indefinite pause.\n active.batcher.flush();\n // M5 (approval targeting): approvalId is always included — see\n // TaskAwaitApprovalPayloadSchema's own doc comment (@byok-sdk/protocol) for\n // why no capability gating is needed to send it safely.\n this.deps.send(createEnvelope('task.await_approval', { summary, approvalId }, { taskId }));\n\n const timeoutMs = this.deps.approvalTimeoutMs ?? DEFAULT_APPROVAL_TIMEOUT_MS;\n return new Promise((resolve) => {\n const timer = setTimeout(() => {\n try {\n this.deps.approvalRegistry.resolve(approvalId, 'reject', `approval timed out after ${timeoutMs}ms with no decision`);\n } catch {\n // Already resolved by a real decision that raced the timer — the\n // registered onResolve callback below already fired; nothing left\n // to do here.\n }\n }, timeoutMs);\n timer.unref?.();\n\n this.deps.approvalRegistry.register(\n { approvalId, taskId, summary, createdAt: new Date().toISOString() },\n (decision: ApprovalDecision, reason: string | undefined, origin: ApprovalOrigin) => {\n clearTimeout(timer);\n if (active.pendingApprovalId === approvalId) active.pendingApprovalId = undefined;\n // M4 (additive-minor): report a LOCAL resolution to the server\n // immediately — but never a 'wire' one (the server already knows;\n // see `ApprovalOrigin`'s own doc comment, `approvals.ts`). This is\n // the single convergence point for every local path: the CLI's\n // `approvals.resolve`, this same method's own timeout branch above,\n // `finish()`'s fail-closed cleanup, and the registry's own\n // bounded-eviction fallback all funnel through `onResolve` here.\n if (origin === 'local') {\n this.sendApprovalResolved(taskId, approvalId, decision);\n }\n // C1: fires BEFORE `resolve(...)` below — a caller chaining\n // `.then()` onto this method's returned promise (`pump()`'s\n // dormant `needs_approval` branch) must already be able to see\n // this origin by the time that continuation runs.\n onOrigin?.(origin);\n resolve({ approved: decision === 'approve', reason });\n this.dispatchNextQueuedApproval(active);\n },\n );\n });\n }\n\n /**\n * M4 (additive-minor, `task.approval_resolved` — see `messages.ts`'s own\n * doc comment on `TaskApprovalResolvedPayloadSchema` for the full wire\n * rationale): report a LOCALLY-resolved approval to the server\n * immediately, gated on the negotiated `approval_resolved` capability\n * (`deps.getServerCapabilities` — an old server that never advertises it\n * never receives this message; the daemon then falls back to the\n * pre-existing implicit-resume inference, unconditionally, exactly as\n * before this message existed — the N/N-1 compatibility path).\n *\n * Ordering (verified by `task-runner-approval-resolved.test.ts`): this is\n * called, and therefore `deps.send` pushes this envelope onto the outbox,\n * SYNCHRONOUSLY from the `onResolve` callback above — strictly BEFORE the\n * `resolve(...)` call on the very next line that unblocks whatever was\n * awaiting `requestApproval()`'s promise (`byok-approval-mcp`, ultimately\n * the paused runtime turn). Any further progress from the resumed session\n * can only be produced AFTER that unblock, which needs at least one more\n * microtask/event-loop turn — so `task.approval_resolved` is always queued\n * ahead of it with no extra bookkeeping needed here.\n */\n private sendApprovalResolved(taskId: string, approvalId: string, decision: ApprovalDecision): void {\n const capabilities = this.deps.getServerCapabilities?.() ?? [];\n if (!capabilities.includes('approval_resolved')) return;\n this.deps.send(\n createEnvelope(\n 'task.approval_resolved',\n { approvalId, decision, resolvedBy: 'local', at: new Date().toISOString() },\n { taskId },\n ),\n );\n }\n\n /**\n * FIFO: once a task's currently-dispatched approval resolves (real\n * decision or timeout), dispatch the next queued request for that SAME\n * task, if any — see `requestApproval`'s own doc comment. A no-op when\n * nothing is queued.\n */\n private dispatchNextQueuedApproval(active: ActiveTask): void {\n const next = active.approvalQueue.shift();\n if (!next) return;\n void this.dispatchApproval(active, next.summary, next.onOrigin).then(next.resolve);\n }\n\n /**\n * Acceptance finding 1 (dormant `needs_approval` branch bypassing the\n * approval registry): resolves whatever `deps.approvalRegistry` entry\n * `pendingId` names (if any — a caller passes `undefined` when nothing was\n * pending to begin with), tagged `'wire'` — the same origin\n * `ctx.approvalChannel.resolve` already uses for a server-sent\n * `task.approve`/`task.reject` (see `ApprovalOrigin`'s own doc comment:\n * `'wire'` is what keeps `sendApprovalResolved` from echoing\n * `task.approval_resolved` back to a server that already knows this\n * decision, since it sent it).\n *\n * Needed because `active.session.resolveApproval()` is adapter-defined:\n * - A channel-based session (claude) already resolves this exact registry\n * entry itself, via `ctx.approvalChannel.resolve` (`handleOffer` above)\n * — by the time this runs, that entry is already gone, so this call\n * throws `ApprovalNotFoundError`, swallowed below: the same\n * first-resolution-wins race every other caller of `.resolve()` in this\n * file already treats as benign (see e.g. `dispatchApproval`'s own\n * timeout branch).\n * - A stream-based session (the dormant `needs_approval` path in `pump()`,\n * now dispatched via `requestApproval` exactly like a real out-of-band\n * approval) resolves ONLY through its own in-process `resolveApproval()`\n * call — nothing else ever touches `deps.approvalRegistry` for it, so\n * without this call its registry entry and `active.pendingApprovalId`\n * would otherwise linger until this approval's own timeout (or the task\n * finishing) instead of clearing the moment the decision actually lands\n * — which would leave any OTHER approval queued behind it\n * (`active.approvalQueue`) stuck waiting for that same timeout.\n *\n * Called from `handleApprove`/`handleReject` AFTER `active.session\n * .resolveApproval()` has already been given the decision — never before,\n * since for the channel-based case that call is what actually resolves\n * the registry entry `pendingId` names.\n *\n * CRITICAL follow-up to finding 1 above: `pendingId` is a required\n * parameter — deliberately NOT read from `active.pendingApprovalId` inside\n * this method (indeed, this method no longer takes `active` at all). For a\n * channel-based session (claude), the `await active.session\n * .resolveApproval()` in `handleApprove`/`handleReject` BELOW THIS CALL is\n * exactly what synchronously drives `ctx.approvalChannel.resolve` ->\n * `approvalRegistry.resolve(A)` -> A's own `onResolve`\n * (`dispatchApproval` above) -> `dispatchNextQueuedApproval` — and that\n * last step, still inside the SAME synchronous call and therefore still\n * strictly BEFORE the caller's own `await` settles, dispatches the next\n * queued approval (B) and reassigns `active.pendingApprovalId = B`. A\n * caller that read `active.pendingApprovalId` only AFTER that `await`\n * returned (as this method itself used to, before it took `pendingId` as a\n * parameter) would therefore observe B, not A — resolving B (silently,\n * with A's decision: an auto-approve or a force-reject of an approval no\n * one ever actually decided) instead of the already-gone entry for A this\n * call is actually meant to (harmlessly) no-op against. Callers now\n * capture the target id BEFORE that await (`handleApprove`/`handleReject`\n * below) so this can only ever be asked to resolve the id it was meant to\n * all along. See `task-runner-approval.test.ts`'s channel-routing\n * regression test for this exact interleaving reproduced end to end.\n */\n private clearPendingApproval(pendingId: string | undefined, decision: ApprovalDecision, reason: string | undefined): void {\n if (pendingId === undefined) return;\n try {\n this.deps.approvalRegistry.resolve(pendingId, decision, reason, 'wire');\n } catch (err) {\n // C3 (cross-model review, P2): narrowed to ONLY the benign\n // already-resolved race this catch was ever meant to cover — a bare\n // `catch {}` here used to swallow EVERYTHING, but\n // `ApprovalRegistry.resolve` deletes the entry BEFORE invoking its\n // registered `onResolve` callback (`dispatchApproval` above), so a\n // genuine bug in that callback (`sendApprovalResolved` throwing,\n // `dispatchNextQueuedApproval` failing to dispatch the next queued\n // approval, this same file's own `onOrigin` hook throwing) vanished\n // here too, silently, with nothing ever finding out.\n if (err instanceof ApprovalNotFoundError) {\n // Already resolved via ctx.approvalChannel.resolve (the channel-based\n // adapter path) — benign, same first-resolution-wins guarantee\n // `ApprovalRegistry` already documents on its own `resolve()` method.\n return;\n }\n // Anything else is a genuine failure, not a benign race — propagate\n // it to the caller's existing error handling. Neither `handleApprove`\n // nor `handleReject` wraps this call in a try/catch of their own, so\n // this bubbles all the way up through `handleEnvelope` to\n // `ConnectionManager.process()`'s own existing catch, which logs it\n // and leaves the cursor unadvanced so a reconnect redelivers this\n // exact `task.approve`/`task.reject` for a retry — the same handling\n // every other envelope-handler failure already gets.\n throw err;\n }\n }\n\n /**\n * Protocol §5 approval flow: the server's own state already moved\n * `AwaitApproval -> Running` before this best-effort notification arrives\n * (§4) — resuming the session is what makes `task.progress` continue.\n *\n * M4 Phase 3 hardening (orchestrator-directed fix): a wire `task.approve`\n * can legitimately arrive AFTER a different, faster path (a racing local\n * `approvals.resolve` over the control socket, or this exact message\n * redelivered) already resolved the SAME approval — `ApprovalRegistry`'s\n * own \"first resolution wins\" guarantee means `session.resolveApproval()`\n * throws {@link NoPendingApprovalError} for that loser, not because\n * anything is actually wrong. Before this fix, ANY thrown error here\n * (stale or genuine) failed the whole task — for the stale case that\n * meant a task the winning path had ALREADY correctly resumed (and which\n * may go on to complete normally) got marked `Failed` anyway, purely\n * because a second, now-meaningless notification arrived late. Stale is\n * now an audit-only no-op; a genuine failure (the session itself\n * couldn't resume for some real reason) still fails the task exactly as\n * before.\n */\n private async handleApprove(taskId: string, approvalId: string | undefined): Promise<void> {\n const active = this.tasks.get(taskId);\n if (!active) return;\n // M5 (approval targeting, docs/protocol.md): checked FIRST, before ever\n // touching active.session. Closes the race NoPendingApprovalError alone\n // could not: approval A resolves, approval B is dispatched next for the\n // SAME task (active.pendingApprovalId now B), and a LATE task.approve\n // meant for A arrives after. Pre-M5, `ctx.approvalChannel.resolve`\n // always resolved \"whichever approval is currently pending\" (B),\n // silently applying A's decision to B. A mismatch here is an\n // audit-only no-op via the same onStaleApprovalDecision hook\n // NoPendingApprovalError already uses. An absent approvalId (legacy\n // server, or one that never recorded an id) preserves the pre-M5\n // behavior exactly: resolve whichever approval is currently pending.\n if (approvalId !== undefined && approvalId !== active.pendingApprovalId) {\n this.deps.onStaleApprovalDecision?.(\n taskId,\n 'approve',\n `approvalId ${approvalId} does not match the currently pending approval` +\n (active.pendingApprovalId ? ` (${active.pendingApprovalId})` : ' (none pending)'),\n );\n return;\n }\n // CRITICAL: captured BEFORE the await below — see `clearPendingApproval`'s\n // own doc comment for exactly why reading `active.pendingApprovalId`\n // only AFTER `resolveApproval()` settles is wrong: for a channel-based\n // session, that same await's own synchronous side effects (racing\n // through `approvalRegistry.resolve` -> `dispatchNextQueuedApproval`)\n // can already have reassigned it to a different, queued approval by the\n // time control returns here.\n const resolvedId = approvalId ?? active.pendingApprovalId;\n try {\n await active.session.resolveApproval(true);\n } catch (err) {\n if (err instanceof NoPendingApprovalError) {\n this.deps.onStaleApprovalDecision?.(taskId, 'approve');\n return;\n }\n await this.fail(taskId, `failed to resume session after approval: ${errorMessage(err)}`, false);\n return;\n }\n // Acceptance finding 1: see `clearPendingApproval`'s own doc comment.\n this.clearPendingApproval(resolvedId, 'approve', undefined);\n }\n\n /**\n * Protocol §5 approval flow: the server's own state already moved\n * `AwaitApproval -> Failed` before this best-effort notification arrives\n * (§4) — the daemon's job is just to stop the session and prove it via\n * `task.fail`.\n *\n * M4 Phase 3 hardening (orchestrator-directed fix): same race as\n * `handleApprove` above, but the pre-fix bug here was worse — this method\n * unconditionally interrupted the session and sent `task.fail` regardless\n * of whether `resolveApproval` even threw, so a stale/late wire\n * `task.reject` (the local CLI, or a racing wire approve, already\n * resolved this exact approval a different way) would tear down and fail\n * a task that was already correctly approved and possibly still running\n * fine. Now: a {@link NoPendingApprovalError} short-circuits to an\n * audit-only no-op BEFORE the interrupt/fail/finish sequence — nothing\n * about this task's state is touched. Any OTHER outcome (success, or a\n * genuine non-staleness error) falls through to the existing\n * interrupt+`task.fail`+finish sequence unchanged: the server's own\n * record already moved `AwaitApproval -> Failed` for a REAL reject\n * (§4's \"server state is authoritative on its own action\" rule), so the\n * daemon must still conform to that regardless of whether telling the\n * session about it succeeded.\n */\n private async handleReject(taskId: string, reason: string | undefined, approvalId: string | undefined): Promise<void> {\n const active = this.tasks.get(taskId);\n if (!active) return;\n // M5 (approval targeting): same validate-first mismatch check as\n // handleApprove above — see that method's own comment for the full\n // race this closes. Returned early here means NONE of the\n // interrupt+task.fail+finish sequence below runs for a stale decision:\n // the currently-pending (different) approval stays untouched and the\n // task is not torn down.\n if (approvalId !== undefined && approvalId !== active.pendingApprovalId) {\n this.deps.onStaleApprovalDecision?.(\n taskId,\n 'reject',\n `approvalId ${approvalId} does not match the currently pending approval` +\n (active.pendingApprovalId ? ` (${active.pendingApprovalId})` : ' (none pending)'),\n );\n return;\n }\n // CRITICAL: captured BEFORE the await below — see handleApprove above\n // and `clearPendingApproval`'s own doc comment for the full race this\n // closes (identical here: a channel-based session's own resolution,\n // still inside this await, can already have reassigned\n // `active.pendingApprovalId` to a different, queued approval).\n const resolvedId = approvalId ?? active.pendingApprovalId;\n try {\n await active.session.resolveApproval(false, reason);\n } catch (err) {\n if (err instanceof NoPendingApprovalError) {\n this.deps.onStaleApprovalDecision?.(taskId, 'reject', reason);\n return;\n }\n // best-effort — still report the rejection outcome below\n }\n // Acceptance finding 1: see `clearPendingApproval`'s own doc comment.\n // Must run BEFORE `finish()` below — its own fail-closed cleanup\n // defaults to origin 'local' (see `ApprovalRegistry.resolve`'s default\n // parameter), which would incorrectly echo `task.approval_resolved`\n // back to a server that already knows this decision (it sent this\n // task.reject itself) if this hadn't already cleared it as 'wire' here.\n this.clearPendingApproval(resolvedId, 'reject', reason);\n try {\n await active.session.interrupt();\n } catch {\n // best-effort\n }\n await this.observeGit(active, 'salvage');\n // Same reasoning as handleCancel() above: the server already moved this\n // task to `Failed` and closed its event queue before this notification\n // arrived, so flushing buffered progress here would be unobservable and\n // only trigger a spurious server-side warning.\n this.deps.send(createEnvelope('task.fail', { reason: reason ?? 'rejected', retryable: false }, { taskId }));\n await this.finish(taskId);\n }\n\n /** Pre-claim, fail-closed rejection (protocol §3.2) — never claims first. */\n private decline(taskId: string, reason: string, retryable: boolean): void {\n this.deps.send(createEnvelope('task.decline', { reason, retryable }, { taskId }));\n }\n\n private async fail(taskId: string, reason: string, retryable: boolean): Promise<void> {\n const active = this.tasks.get(taskId);\n if (active) await this.observeGit(active, 'salvage');\n this.deps.send(createEnvelope('task.fail', { reason, retryable }, { taskId }));\n await this.finish(taskId);\n }\n\n private async observeGit(active: ActiveTask, phase: GitWorkspacePhase): Promise<void> {\n if (!active.gitWorkspaceId || !this.deps.gitWorkspaceManager || !this.deps.gitWorkspaceStore) return;\n try {\n const observation = await new Promise<GitWorkspaceObservation>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error('Git workspace observation timed out')), GIT_OBSERVATION_TIMEOUT_MS);\n timer.unref?.();\n void this.deps.gitWorkspaceManager!.observe(active.workspaceDir, active.gitBaseline).then(\n (value) => { clearTimeout(timer); resolve(value); },\n (error) => { clearTimeout(timer); reject(error); },\n );\n });\n await this.deps.gitWorkspaceStore.updateObservation(active.gitWorkspaceId, observation, phase);\n this.deps.onGitWorkspaceEvent?.({ taskId: active.taskId, workspaceId: active.gitWorkspaceId, phase, observation });\n } catch (err) {\n const category = ((err as GitWorkspaceError).category ?? 'repository-invalid') as GitErrorCategory;\n await this.updateGitPhaseBestEffort(active.gitWorkspaceId, phase, category);\n this.deps.onGitWorkspaceEvent?.({ taskId: active.taskId, workspaceId: active.gitWorkspaceId, phase, errorCategory: category });\n }\n }\n\n private async updateGitPhaseBestEffort(workspaceId: string | undefined, phase: GitWorkspacePhase, errorCategory?: GitErrorCategory): Promise<void> {\n if (!workspaceId || !this.deps.gitWorkspaceStore) return;\n const current = await this.deps.gitWorkspaceStore.get(workspaceId).catch(() => undefined);\n if (!current) return;\n await this.deps.gitWorkspaceStore.upsert({ ...current, phase, ...(errorCategory ? { errorCategory } : {}) }).catch(() => {});\n }\n\n private async finish(taskId: string): Promise<void> {\n const active = this.tasks.get(taskId);\n if (!active) return;\n // M5 batch-3 (workstream 2): see `armMaxDurationTimer`'s own doc\n // comment — `finish()` is the single choke point every terminal outcome\n // (normal completion, fail, cancel, or daemon shutdown) already funnels\n // through, so clearing here (unconditionally, before anything else)\n // guarantees no leaked timer and no stray fail after this task has\n // already ended a different way.\n if (active.maxDurationTimer) {\n clearTimeout(active.maxDurationTimer);\n active.maxDurationTimer = undefined;\n }\n active.batcher.stop();\n this.tasks.delete(taskId);\n this.addFinishedTaskId(taskId); // finding P2 (Fix 2c) — see its own doc comment\n\n // M4 Phase 4 (gatekeeper LOW advisory): a task can finish (complete,\n // fail, or cancel) while ONE approval is still DISPATCHED\n // (`active.pendingApprovalId`) and/or MORE are QUEUED behind it\n // (`active.approvalQueue` — see `requestApproval`'s own doc comment for\n // the full concurrent-approval design). Left alone, a queued request\n // would eventually get dispatched (a fresh, pointless `task.await_approval`\n // + timeout window for a task that no longer exists) once whatever it\n // was queued behind finally resolves; the dispatched one's own timer\n // would keep running for up to `approvalTimeoutMs` regardless. Both are\n // resolved fail-closed HERE instead: the queue is drained and rejected\n // FIRST (each queued promise settles immediately, never dispatched at\n // all), so that resolving the dispatched one next — which triggers\n // `dispatchNextQueuedApproval` via its own `onResolve` callback — finds\n // an already-empty queue and dispatches nothing. Order matters: doing\n // it the other way around would let that callback pull the first\n // queued entry and dispatch it for real.\n const queued = active.approvalQueue.splice(0);\n for (const request of queued) {\n request.resolve({\n approved: false,\n reason: `task ${taskId} finished before this queued approval request could be dispatched`,\n });\n }\n if (active.pendingApprovalId !== undefined) {\n try {\n this.deps.approvalRegistry.resolve(active.pendingApprovalId, 'reject', `task ${taskId} finished`);\n } catch {\n // Already resolved by a real decision/timeout that raced this —\n // benign, same \"first resolution wins\" guarantee ApprovalRegistry\n // already documents; nothing left to do.\n }\n }\n\n if (active.gitLease) active.gitLease.release();\n\n try {\n await active.session.close();\n } catch {\n // best-effort teardown\n }\n }\n\n /** M3-B: bounded insert for `finishedTaskIds` — see its class-level doc comment and `MAX_TRACKED_TASK_IDS`. Evicts the oldest (first-inserted) entry once over cap, same idiom as `ConnectionHub.checkAndRecordDuplicate` (packages/server/src/hub.ts). */\n private addFinishedTaskId(taskId: string): void {\n this.finishedTaskIds.add(taskId);\n if (this.finishedTaskIds.size > MAX_TRACKED_TASK_IDS) {\n const oldest = this.finishedTaskIds.values().next().value;\n if (oldest !== undefined) this.finishedTaskIds.delete(oldest);\n }\n }\n\n /** `reuseDir`, when set (a known sessionRef's recorded workspace), is used verbatim instead of a fresh `workspaceRoot/<taskId>` directory — `mkdir recursive` is idempotent either way, so ensuring-exists is safe to do unconditionally. */\n private async resolveWorkspaceDir(taskId: string, reuseDir: string | undefined): Promise<string> {\n const dir = reuseDir ?? path.join(this.deps.workspaceRoot, taskId);\n await fs.mkdir(dir, { recursive: true });\n return dir;\n }\n\n /**\n * M5 batch-3 (workstream 1): selects which adapter runs this offer, now\n * gated on both PRESENCE (`adapter.detect()`, as before) and CAPABILITY\n * (`adapterSupportsMode` — can this adapter even express `policyMode`?\n * new in this batch) — pre-claim, in both the explicit-runtime and\n * auto-select branches.\n *\n * Explicit-runtime branch (`requestedRuntime` set): semantics otherwise\n * unchanged from before this batch — allowlist and known-adapter checks\n * first, THEN the new capability check, THEN presence. A capability\n * mismatch here is a permanent characteristic of naming THIS runtime with\n * THIS policy (e.g. pi never supports `confirm`, on any device, by\n * design — `pi/permission-mapping.ts`) — `retryable: false`, the same\n * class as \"not in allowlist\"/\"unknown runtime\" above it, since retrying\n * this exact (runtime, mode) pair anywhere changes nothing.\n *\n * Auto-select branch (`requestedRuntime` absent): candidates are ordered\n * by `runtimePreference` (default {@link DEFAULT_RUNTIME_PREFERENCE}) —\n * see `orderByPreference` — then walked in that order; a candidate that\n * can't express `policyMode` is skipped (not detected at all — capability\n * is checked first, cheaper than a real subprocess probe) and the walk\n * continues down the preference order, exactly as \"skip non-supporting\n * adapters and continue down the order\" describes. If NOTHING eligible\n * supports the mode, `retryable: true` — unlike the explicit branch, this\n * is device-specific (which runtimes happen to be installed here), so a\n * different device's installed runtime set might satisfy it.\n */\n private async pickAdapter(requestedRuntime: string | undefined, policyMode: PermissionMode): Promise<PickResult> {\n const allowlist = this.deps.runtimeAllowlist;\n\n if (requestedRuntime) {\n if (allowlist && !allowlist.includes(requestedRuntime)) {\n return {\n ok: false,\n reason: `runtime \"${requestedRuntime}\" is not in this device's runtime allowlist`,\n retryable: false,\n };\n }\n const adapter = this.deps.adapters.find((a) => a.id === requestedRuntime);\n if (!adapter) {\n return { ok: false, reason: `unknown runtime \"${requestedRuntime}\"`, retryable: false };\n }\n if (!adapterSupportsMode(adapter, policyMode)) {\n return {\n ok: false,\n reason: `runtime \"${requestedRuntime}\" cannot express permission mode \"${policyMode}\"`,\n retryable: false,\n };\n }\n const detected = await adapter.detect();\n if (!detected.present) {\n return {\n ok: false,\n reason: `runtime \"${requestedRuntime}\" is not installed/available on this device`,\n retryable: true,\n };\n }\n return { ok: true, adapter };\n }\n\n const eligible = allowlist ? this.deps.adapters.filter((a) => allowlist.includes(a.id)) : this.deps.adapters;\n // M5 batch-3: product decision — pi is the FALLBACK runtime, not the\n // default. Ordered independently of `deps.adapters`'s own construction\n // order (which stays whatever `buildDefaultAdapters`/the embedder built\n // it as — see `ALL_RUNTIME_IDS`'s doc comment, `create-daemon.ts`).\n const candidates = orderByPreference(eligible, this.deps.runtimePreference ?? DEFAULT_RUNTIME_PREFERENCE);\n for (const adapter of candidates) {\n if (!adapterSupportsMode(adapter, policyMode)) continue;\n const detected = await adapter.detect();\n if (detected.present) return { ok: true, adapter };\n }\n return {\n ok: false,\n reason: `no available runtime on this device can express permission mode \"${policyMode}\"`,\n retryable: true,\n };\n }\n}\n","import { createEnvelope, encodeEnvelope, TASK_TRANSITIONS } from '@byok-sdk/protocol';\nimport type { CapabilityFlag, Envelope, RuntimeId, RuntimeInfo } from '@byok-sdk/protocol';\nimport type { PermissionPolicy } from '@byok-sdk/protocol';\nimport type { RuntimeAdapter, GitWorkspaceConfig } from '../types';\nimport { PiAdapter } from '../adapters/pi/pi-adapter';\nimport { ClaudeAdapter } from '../adapters/claude/claude-adapter';\nimport { CodexAdapter } from '../adapters/codex/codex-adapter';\nimport { ApprovalNotFoundError, ApprovalRegistry } from './approvals';\nimport { AuthManager } from './auth-manager';\nimport { BlobClient } from './blob-client';\nimport { assertServerUrlAllowed } from './url';\nimport type { BackoffOptions, ConnectionState, LivenessOptions } from './ws-transport';\nimport { AnotherControlServerRunningError, startControlServer } from './control-server';\nimport type { ControlMethods, ControlServerHandle } from './control-server';\nimport {\n ControlError,\n parseApprovalsRequestParams,\n parseApprovalsResolveParams,\n parseShutdownParams,\n type ControlActiveTask,\n type ControlStatusResult,\n type ControlStorageStatus,\n type ShutdownReason,\n} from './control-protocol';\nimport { ConnectionManager } from './connection-manager';\nimport { createFleetJitter, type FleetJitter } from './deterministic-jitter';\nimport { OperationalHealthTracker, type OperationalHealthSnapshot } from './operational-health';\nimport { acquireDaemonOwner, type DaemonOwnerLease } from './daemon-owner';\nimport { toRuntimeInfoCapabilities } from './runtime-capabilities';\nimport { CursorStore } from './cursor-store';\nimport { DaemonObserver, type DaemonEventListener, type DaemonTaskInfo, type Unsubscribe } from './observer';\nimport { SessionWorkspaceStore } from './session-workspace-store';\nimport { GitWorkspaceManager, stableGitWorkspaceOwnerId } from './git-workspace';\nimport { GitWorkspaceStore } from './git-workspace-store';\nimport { DeviceStore, type DeviceRecord } from './store';\nimport { JournalUnavailableError, journalHash, type JournalIdentity, type LocalTaskJournal, type ReceivedEnvelopeRecord, type StorageCategory } from './journal/journal';\nimport { JournalHandleCleanupError, SqliteLocalTaskJournal } from './journal/sqlite-journal';\nimport { isSqliteAvailable, type JournalOpenFaultSeam } from './journal/sqlite-support';\nimport {\n createFilesystemCleanupExecutor,\n createStatfsFreeBytesProvider,\n LocalStoragePressureEngine,\n resolveLocalStoragePolicy,\n type LocalStoragePolicy,\n type LocalStoragePolicyInput,\n} from './journal/storage-policy';\nimport { DEFAULT_MAX_TASK_OUTPUT_BYTES, TaskRunner, type TaskRunnerDeps } from './task-runner';\nimport type { ProgressBatcherOptions } from './progress-batcher';\n\n/**\n * M4 Phase 2 (originally control-socket-only). M5 batch-3 (workstream 2):\n * now the shared DEFAULT for every graceful-shutdown path via\n * `runShutdownSequence` — overridable per-daemon via\n * `DaemonConfig.shutdownGraceMs`. Bound on how long the graceful-shutdown\n * sequence waits for `TaskRunner.shutdownActiveTasks` before proceeding to\n * the rest of teardown regardless — an active task's `session.interrupt()`\n * hanging (a misbehaving runtime adapter) must never block the daemon from\n * actually stopping.\n */\nconst SHUTDOWN_TASK_TEARDOWN_DEADLINE_MS = 10_000;\n\n/** Finding F5(b): default bound on how long `performControlShutdown` waits for the outbox to actually drain before closing the connection — see `ConnectionManager.stop`'s own doc comment. Overridable via `DaemonOverrides.shutdown.outboxDrainTimeoutMs`. */\nconst DEFAULT_SHUTDOWN_OUTBOX_DRAIN_TIMEOUT_MS = 5_000;\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms);\n timer.unref?.();\n });\n}\n\n/**\n * Optional white-label product display info — purely opaque passthrough\n * (never interpreted, validated, or rendered by the daemon itself). Carried\n * through to `DaemonStatus.branding` (see `status()` below) so a downstream\n * CLI or audit log can render/stamp product identity without the daemon\n * needing to know anything about presentation. Deliberately a small,\n * open-ish shape rather than an exhaustive theming schema — add fields here\n * only as concrete consumers (CLI UX, audit log) need them.\n */\nexport interface DaemonBranding {\n /** Product/company name for banners, prompts, audit log entries, etc. */\n displayName?: string;\n /** Support/help URL surfaced alongside branding. */\n supportUrl?: string;\n /** Brand accent color (any CSS-color-like string — hex, name, etc.); not parsed or validated here. */\n accent?: string;\n}\n\n/**\n * S3b (L-002): opt-in durable local journal for hosted deployments\n * (architecture §12.7.2).\n *\n * Explicit and off by default, because it changes what an ack MEANS. With no\n * journal configured (the self-hosted default this SDK has always shipped),\n * the daemon's redelivery cursor advances on handler success exactly as\n * before. With one configured, every inbound envelope is committed and fsynced\n * to `<storeDir>/daemon.db` BEFORE the handler resolves — and since\n * `ConnectionManager` only advances the cursor once the handler resolves\n * (`connection-manager.ts`), acking before committing stops being something\n * this daemon can express, rather than something it is careful not to do.\n *\n * Turning this on when the runtime has no working `node:sqlite` is a typed\n * construction failure, not a downgrade to a file journal — see\n * `JournalUnavailableError`. That refusal is the point (§12.7.2): a journal\n * that does not fsync loses tasks only under power-cut timings, so it passes\n * every test anyone will ever run against it.\n */\nexport interface HostedJournalConfig {\n /**\n * The backend. Only `sqlite` today, and spelled out rather than implied by\n * the section's presence so adding a second one later is an additive change\n * to a closed set instead of a re-interpretation of an existing config.\n */\n mode: 'sqlite';\n /**\n * The tenant every journal row on this device is scoped to (§12.7.2's\n * minimum fact set opens with tenant/product/device). Required: a hosted\n * daemon that cannot say which tenant its durable evidence belongs to has\n * evidence nobody can act on.\n */\n tenantId: string;\n /** Bound on waiting for the journal's write lock, ms. Defaults to the journal's own bound. */\n busyTimeoutMs?: number;\n /** Per-record byte bound. Defaults to the journal's own bound; oversized records are refused, never truncated. */\n maxRecordBytes?: number;\n /**\n * S3b (L-003): opt-in local storage policy — §12.7.2.1's watermarks,\n * classified GC, and bounded WAL compaction. See `LocalStoragePolicyInput`\n * (`journal/storage-policy.ts`); `maxStoreBytes` and `minFreeBytes` are the\n * only two a host must supply.\n *\n * Optional WITHIN hosted journal mode, and off by default there too: a\n * journal without a policy is a daemon that records durably and never\n * declines, which is exactly the right behaviour on a host that manages its\n * own disk. Setting it is what turns local storage into an admission-control\n * input — hard pressure declines new offers (retryably) while terminal\n * flush, delete, export and recovery keep running, and `emergency` refuses\n * to ack at all rather than acking a row it cannot durably record.\n */\n storagePolicy?: LocalStoragePolicyInput;\n}\n\nexport interface DaemonConfig {\n productName: string;\n productId: string;\n serverUrl: string;\n deviceName?: string;\n workspaceRoot: string;\n /** Disabled by default. Enables local-only Git checkpoint repositories. */\n gitWorkspace?: GitWorkspaceConfig;\n /** Disabled by default. Enables the durable local task journal — see {@link HostedJournalConfig}. */\n hostedJournal?: HostedJournalConfig;\n /**\n * Restricts which runtimes this daemon will ever use — enforced in two\n * places that must stay consistent: `createDaemon` (this file) builds its\n * bundled adapter set FROM this list (unset = all three bundled adapters\n * — pi, claude, codex; set = exactly the listed runtime ids, unknown ids\n * ignored — see `buildDefaultAdapters`), and `TaskRunner.pickAdapter`\n * (`task-runner.ts`) separately fail-closed-rejects any `task.offer`\n * naming a runtime outside this list regardless of which adapters were\n * constructed. `createDaemonWithAdapters` callers supply their own\n * `adapters` array directly, so for them this field is enforcement-only,\n * unchanged from M1/M2.\n */\n runtimeAllowlist?: string[];\n /**\n * M5 batch-3 (workstream 1): explicit auto-select priority order for\n * `TaskRunner.pickAdapter`'s no-explicit-runtime branch (`task-runner.ts`)\n * — tried in listed order; the first candidate that is both PRESENT\n * (`adapter.detect()`) and CAPABLE (declares the offer's\n * `PermissionPolicy.mode` in its own `capabilities().permissionModes` —\n * see `adapterSupportsMode`) wins. Unset defaults to\n * `DEFAULT_RUNTIME_PREFERENCE` (`task-runner.ts`): `['claude', 'codex',\n * 'pi']` — pi LAST, deliberately.\n *\n * Product decision: pi is this SDK's FALLBACK runtime, not its default.\n * Before this field existed, the auto-select path had no notion of\n * priority at all — it simply walked `deps.adapters` in whatever order\n * `buildDefaultAdapters`/the embedder constructed them, which for\n * `createDaemon`'s bundled set meant `ALL_RUNTIME_IDS`'s construction\n * order (`['pi', 'claude', 'codex']`) doubled as the de-facto selection\n * priority — silently making pi the default winner whenever it was\n * present, for no better reason than being listed first in an array never\n * meant to encode a priority. This field makes the real priority an\n * explicit, independently-configurable decision instead of an accident of\n * construction order — see `ALL_RUNTIME_IDS`'s own doc comment below for\n * the construction-vs-selection-order split this introduces.\n *\n * Only affects the auto-select (no `task.offer.runtime`) path — an offer\n * naming an explicit runtime is unaffected (unchanged semantics: that\n * exact adapter is used, or the offer is declined; never a fallback\n * substitution). Independent of `runtimeAllowlist` above (which restricts\n * WHICH runtimes are eligible at all): this only orders the attempt\n * sequence among whatever that allowlist, if set, already let through.\n */\n runtimePreference?: RuntimeId[];\n /**\n * The device operator's configured policy CEILING — every `task.offer`'s\n * own policy is merged against this and fail-closed-rejected if it asks\n * for more latitude than this allows (`daemon/policy.ts`'s\n * `computeEffectivePolicy`).\n *\n * M5 batch-3 (workstream 1): `workspaceRoot` set on THIS ceiling is still\n * merged into the effective policy handed to an adapter as\n * `ctx.policy.workspaceRoot` (`computeEffectivePolicy` is unchanged) — but\n * no bundled adapter (pi/claude/codex) actually reads or enforces it;\n * every adapter derives its real confinement from `ctx.workspaceDir` (the\n * daemon-created per-task directory) instead — see docs/security.md's\n * \"Workspace confinement is a convention, not a sandbox\" section. Setting\n * it here is therefore silently inert rather than actively dangerous by\n * itself (an OFFER independently asking for its OWN `workspaceRoot` is a\n * separate, fail-closed-declined case — see `TaskRunner.handleOffer` —\n * precisely because THAT looks like a live security control when it\n * isn't). `start()` below logs a loud, one-time `console.warn` whenever\n * this ceiling sets `workspaceRoot`, so an operator who configured it\n * expecting real enforcement finds out immediately instead of trusting a\n * control nothing honors.\n */\n permissionDefaults?: PermissionPolicy;\n storeDir?: string;\n /** Optional white-label branding — see `DaemonBranding`. Carried through verbatim to `status().branding`. */\n branding?: DaemonBranding;\n /**\n * M5: per-device, per-runtime escape hatch into the environment allowlist\n * `task-runner.ts` builds each task's spawn environment from\n * (`daemon/environment.ts`'s `buildRuntimeEnv`) — keyed by runtime id\n * (`'pi' | 'claude' | 'codex'`, though not typed that narrowly here since\n * an id with no matching adapter is simply never looked up). `allow`\n * entries are exact variable names or `*`-suffixed prefixes, merged in\n * alongside that runtime adapter's own declared\n * `environmentRequirements()` — this can never override the hard\n * `BYOK_*` deny (see `environment.ts`'s own doc comment).\n */\n runtimeEnvironment?: Record<string, { allow?: string[] }>;\n /**\n * M5: explicit escape hatch for `url.ts`'s `assertServerUrlAllowed` — see\n * that function's own doc comment for the full allow/deny rule. Default\n * (unset/`false`): a `serverUrl` using plaintext `ws:`/`http:` is only\n * accepted when its host is loopback (`localhost`/`*.localhost`,\n * `127.0.0.0/8`, `::1`); anything else over plaintext throws a typed\n * `InsecureServerUrlError` from `pair()`/`start()` below, BEFORE any\n * network call is attempted, rather than silently sending the pairing\n * code / device credentials to a remote host in the clear. Set this\n * `true` only when you have deliberately decided to accept that risk\n * (e.g. a trusted private network with no TLS terminator in front of the\n * server) — doing so also logs a loud `console.warn` (see\n * `checkServerUrl`, this file) every time it actually changes the\n * outcome. Never overrides an unsupported scheme (anything other than\n * `http:`/`https:`/`ws:`/`wss:`), which is refused unconditionally.\n */\n dangerouslyAllowInsecureRemote?: boolean;\n /**\n * M5 batch-3 (workstream 2): caps accumulated (approximate,\n * serialized-event-length) agent-event output bytes this daemon will\n * tolerate for a single task before tearing it down as a resource-limit\n * violation (`task.fail`, `retryable: false`, reason prefixed\n * `resource limit exceeded: maxTaskOutputBytes` — see\n * `MAX_OUTPUT_BYTES_EXCEEDED_REASON_PREFIX`, `task-runner.ts`) — see\n * `TaskRunner.pump`'s own doc comment for exactly what's counted and what\n * isn't. Default {@link DEFAULT_MAX_TASK_OUTPUT_BYTES} (64 MiB) when\n * unset.\n *\n * `0` or a negative number is a config validation error, thrown\n * synchronously from `createDaemonWithAdapters`/`createDaemon` — NOT a\n * supported way to disable the cap. Pass `Number.POSITIVE_INFINITY`\n * explicitly instead to opt out of enforcement altogether.\n */\n maxTaskOutputBytes?: number;\n /**\n * M5 batch-3 (workstream 2): deadline bound on the graceful-shutdown\n * sequence's own wait for `TaskRunner.shutdownActiveTasks` to finish\n * interrupting/failing every active task before this daemon proceeds to\n * actually stop regardless — see `runShutdownSequence`'s own doc comment\n * for the full sequence this bounds, and for why every graceful-shutdown\n * path (`stop()`, `unpair()`, the control socket's `shutdown` RPC) now\n * shares it. Default 10s (`SHUTDOWN_TASK_TEARDOWN_DEADLINE_MS`) — the same\n * bound the control-socket shutdown path already used before this field\n * existed.\n */\n shutdownGraceMs?: number;\n}\n\nexport interface DaemonStatus {\n paired: boolean;\n connected: boolean;\n /** True once the connection has fallen back to long-poll (protocol §8) — transport info only (finding F6): long-poll is a full transport, so work still proceeds normally while this holds; outbound envelopes POST to /byok/messages instead of going out over WS. */\n degraded: boolean;\n /** True once the server has revoked this device (401 on challenge/token, protocol §6.3). The only recourse is calling `pair()` again — the daemon does not keep retrying on its own. */\n revoked: boolean;\n deviceId?: string;\n activeTaskCount: number;\n /** Passthrough of `DaemonConfig.branding` — `undefined` when the product configured none. See `DaemonBranding`. */\n branding?: DaemonBranding;\n /** Local lifecycle/retry budget, separate from transport fallback state. */\n operationalHealth: OperationalHealthSnapshot;\n}\n\nexport interface Daemon {\n pair(pairingCode: string): Promise<DeviceRecord>;\n start(): Promise<void>;\n stop(): Promise<void>;\n status(): DaemonStatus;\n /**\n * M3-2a: local observability — subscribe to live `DaemonEvent`s (task\n * feed, connection/pairing state changes, runtime-detection results) as\n * they happen on THIS daemon, no SaaS-side polling required. Returns an\n * unsubscribe function; a listener that throws is caught and logged, never\n * propagated (see `observer.ts`). Purely additive: emitting these never\n * changes `status()` or any existing wire/task behavior.\n */\n subscribe(listener: DaemonEventListener): Unsubscribe;\n /** M3-2a: current locally-known tasks and their derived state/summary (for a `tasks` CLI subcommand) — reflects only what this daemon has observed since it started; see `observer.ts`'s `DaemonObserver.tasks`. */\n tasks(): DaemonTaskInfo[];\n /**\n * M3-2a: clears this device's persisted identity/credentials and\n * disconnects — the next `start()` throws until `pair()` is called again.\n * Safe to call at any point in the daemon's lifecycle (never paired,\n * paired-but-not-started, or running).\n */\n unpair(): Promise<void>;\n /**\n * M3-2a: locally resolve a task currently paused on `needs_approval` —\n * drives the exact same code path a server-sent `task.approve` does\n * (`TaskRunner.handleApprove`), invoked directly instead of over the wire.\n * Honest-but-currently-unexercised: none of the three bundled adapters\n * (pi/claude/codex) ever actually pauses for approval — each one's\n * `resolveApproval` throws unconditionally (see `toRuntimeInfoCapabilities`'s\n * doc comment below) — so calling this against a task on this daemon today\n * always fails that task with a clear reason instead of resuming it,\n * exactly as an honest, doing-nothing-magic implementation should. Ready\n * for the day a runtime adapter implements real interactive approval, with\n * no further changes needed here. A no-op (resolves immediately) for a\n * `taskId` this daemon doesn't currently have active.\n */\n approve(taskId: string): Promise<void>;\n /** M3-2a: same as {@link approve} but rejects — see that method's doc comment. */\n reject(taskId: string, reason?: string): Promise<void>;\n}\n\n/** Internal seam so tests can substitute stub adapters / faster backoff+batch+liveness+long-poll timing. `createDaemonWithAdapters` (which takes this) is also the real entry point for products supplying a hand-built adapter set `createDaemon` can't construct on its own — e.g. custom adapter options, or an adapter that REPLACES a bundled runtime's implementation under the same id. Honest limit: an adapter id outside `pi`/`claude`/`codex` cannot pass wire validation today — `RuntimeIdSchema` (`@byok-sdk/protocol`) is a closed `z.enum(['pi', 'claude', 'codex'])`, and `isRuntimeId` filtering below (see `detectRuntimes`) drops any detected adapter outside that set before it ever reaches a wire-visible field. A genuinely fourth/namespaced runtime id is a future protocol change, not something this seam enables today. */\nexport interface DaemonOverrides {\n backoff?: BackoffOptions;\n batch?: ProgressBatcherOptions;\n liveness?: LivenessOptions;\n /** M4 Phase 3: overrides `TaskRunner`'s default out-of-band approval wait (`DEFAULT_APPROVAL_TIMEOUT_MS`, 10 minutes) before an unanswered `requestApproval` force-resolves as a fail-closed rejection. */\n approvalTimeoutMs?: number;\n /** Finding F5: overrides for the control-socket shutdown path's own bounded waits — see `TaskRunner.shutdownTask`'s and `ConnectionManager.stop`'s own doc comments. Both default to 5s; neither affects an ordinary (non-shutdown-RPC) `daemon.stop()` call. */\n shutdown?: {\n /** Bound on how long `shutdownTask` waits for a single task's own `session.interrupt()` before giving up on it specifically and reporting `task.fail` anyway. Default `DEFAULT_SHUTDOWN_INTERRUPT_TIMEOUT_MS`. */\n taskInterruptTimeoutMs?: number;\n /** Bound on how long the control-socket shutdown path waits for the outbox to actually drain before closing the connection. Default `DEFAULT_SHUTDOWN_OUTBOX_DRAIN_TIMEOUT_MS`. */\n outboxDrainTimeoutMs?: number;\n };\n longPoll?: {\n /** Consecutive never-acked WS connect failures before falling back to long-poll. Default 3. */\n wsFailureThreshold?: number;\n /** While long-polling, how often to retry establishing WS. Default 5 minutes. */\n wsRetryIntervalMs?: number;\n /** Backoff between failed long-poll HTTP attempts. Default 2s. */\n retryDelayMs?: number;\n /** Minimum delay before the next long-poll request after an empty (no-events) response — avoids busy-looping against a server that responds instantly. Default 250ms. */\n idleDelayMs?: number;\n };\n /**\n * Test/product injection seam for the local Git workspace boundary. The\n * supplied manager/store are used only when `config.gitWorkspace` is enabled;\n * an absent Git config therefore cannot accidentally activate either object.\n */\n gitWorkspace?: {\n manager?: GitWorkspaceManager;\n store?: GitWorkspaceStore;\n };\n /**\n * S3b: injection seam for the durable local journal, mirroring\n * `gitWorkspace` above — used only when `config.hostedJournal` is set, so an\n * absent journal config cannot accidentally activate a supplied object. Also\n * the host-injected-implementation path §12.7.2 allows: a backend other than\n * `SqliteLocalTaskJournal` is acceptable if it meets the same durability\n * contract (a resolved `appendEnvelope` means fsynced), and unacceptable\n * otherwise — this seam does not verify that, the host asserting it does.\n *\n * A journal supplied here is NOT closed by `stop()`; whoever injected it\n * owns its lifetime.\n */\n hostedJournal?: {\n journal?: LocalTaskJournal;\n /** Test-only post-open SQLite initialization fault seam. */\n openFaults?: JournalOpenFaultSeam;\n /**\n * S3b (L-003): injection seam for the storage pressure engine, same rule\n * as `journal` above — used only when `config.hostedJournal` is set, and\n * NOT started or stopped by this daemon. Whoever injects one owns its\n * cadence, which is what lets the disk-pressure matrix drive `tick()` by\n * hand with fake usage/free providers and no timer at all.\n *\n * An injected engine still answers both questions the daemon asks it\n * (admission under hard pressure, ack-critical refusal under emergency)\n * and still backs the `storage` section of the control-socket status.\n */\n pressureEngine?: LocalStoragePressureEngine;\n };\n}\n\n/**\n * The outbound envelope types that carry a task's terminal, matching the set\n * the cloud records a terminal receipt for (`cloud/src/inbound.ts`'s\n * `applyLifecycle`). `task.decline` is deliberately NOT here: declining is\n * refusing to take a task, not producing a result for one.\n *\n * `task.complete`/`task.fail`/`task.cancelled` -> the terminal kind recorded locally.\n */\nfunction terminalKindOf(type: string): 'complete' | 'failed' | 'cancelled' | undefined {\n if (type === 'task.complete') return 'complete';\n if (type === 'task.fail') return 'failed';\n if (type === 'task.cancelled') return 'cancelled';\n return undefined;\n}\n\n/**\n * One inbound envelope, as the journal wants it.\n *\n * `bytes` is the CANONICAL v1 encoding of the envelope this daemon parsed, not\n * the socket's original byte sequence — the frozen codec's round-trip\n * guarantee is what makes that a faithful record, and it is the same choice\n * the cloud's own terminal receipt makes.\n *\n * `opensTask` is decided here, from the envelope's own type, rather than\n * inside the journal: `task.offer` is the one inbound type that brings a task\n * into existence on this device, and that is protocol knowledge this file\n * already has and the journal should not acquire a second copy of.\n */\nfunction toJournalEnvelopeRecord(envelope: Envelope, identity: JournalIdentity): ReceivedEnvelopeRecord {\n const bytes = encodeEnvelope(envelope);\n return {\n identity,\n envelopeId: envelope.id,\n ...(envelope.task_id === undefined ? {} : { taskId: envelope.task_id }),\n seq: envelope.seq ?? 0,\n bytes,\n bytesHash: journalHash(bytes),\n receivedAt: new Date().toISOString(),\n opensTask: envelope.type === 'task.offer',\n };\n}\n\nfunction isRuntimeId(id: string): id is RuntimeId {\n return id === 'pi' || id === 'claude' || id === 'codex';\n}\n\n/** Runtimes actually detected as present on this device, typed per protocol §10 gap #4 (`ConnHelloPayload.runtimes`). Computed once at `start()` — re-probing on every reconnect would mean re-spawning each runtime's `--version` check for no real benefit within one daemon lifetime. */\nasync function detectRuntimes(adapters: RuntimeAdapter[]): Promise<RuntimeInfo[]> {\n const detections = await Promise.all(adapters.map(async (adapter) => ({ adapter, detected: await adapter.detect() })));\n const runtimes: RuntimeInfo[] = [];\n for (const { adapter, detected } of detections) {\n if (!detected.present || !isRuntimeId(adapter.id)) continue;\n const info: RuntimeInfo = { id: adapter.id };\n if (detected.version !== undefined) info.version = detected.version;\n if (detected.authPresent !== undefined) info.authPresent = detected.authPresent;\n // Pre-freeze addition (`RuntimeInfo.capabilities`, `messages.ts`):\n // surfaces this SAME adapter's own `capabilities()` (already used above\n // by `computeCapabilities` for the connection-level `steer` flag) into\n // the per-runtime wire field — see `toRuntimeInfoCapabilities`'s doc\n // comment.\n info.capabilities = toRuntimeInfoCapabilities(adapter.capabilities());\n runtimes.push(info);\n }\n return runtimes;\n}\n\n/**\n * M0 gatekeeper finding ②: advertise only what this device can actually do,\n * not a static spread of every known flag. `steer` reflects whether any\n * configured adapter can express it; `blob-upload` is unconditional now\n * that the blob client (protocol §7) genuinely implements it.\n *\n * C2 (cross-model review, P2): `approval-targeting` is unconditional too,\n * for the same reason `blob-upload` is — this daemon has included\n * `approvalId` on `task.await_approval`/`task.approve`/`task.reject`\n * unconditionally since M5 (see `TaskRunner.dispatchApproval`/\n * `handleApprove`/`handleReject`, `task-runner.ts`), so there is no\n * adapter-specific gate to check the way `steer` has. Without this, every\n * daemon built from this codebase advertised nothing here, so the server's\n * own `targeted` marking (`ConnectionHub.approveTask`/`rejectTask` —\n * `packages/server/src/hub.ts`'s `getDeviceCapabilities(...).includes(\n * 'approval-targeting')` check) always saw an upgraded daemon as legacy —\n * see `CAPABILITY_FLAGS`'s own doc comment (`@byok-sdk/protocol`'s `version.ts`)\n * for why this flag is purely informational/observability, not a functional\n * gate, and therefore safe to advertise unconditionally the moment a daemon\n * genuinely does what it claims (as this one already does).\n */\nfunction computeCapabilities(adapters: RuntimeAdapter[]): CapabilityFlag[] {\n const flags: CapabilityFlag[] = [];\n if (adapters.some((adapter) => adapter.capabilities().steer)) flags.push('steer');\n flags.push('blob-upload');\n flags.push('approval-targeting');\n return flags;\n}\n\n/**\n * Canonical construction/identity order for `createDaemon`'s bundled adapter\n * set (`buildDefaultAdapters` below) and for `conn.hello.runtimes`\n * reporting order (`detectRuntimes`) — this is NOT the auto-select priority\n * order.\n *\n * M5 batch-3 (workstream 1): auto-select priority now lives entirely in\n * `task-runner.ts`, as its own explicit order independent of this one — see\n * `DEFAULT_RUNTIME_PREFERENCE`/`TaskRunner.pickAdapter`, overridable\n * per-daemon via `DaemonConfig.runtimePreference` above. Before this change,\n * `pickAdapter`'s no-runtime branch walked `deps.adapters` directly (this\n * array's own construction order), so listing pi first here silently made\n * it the de-facto DEFAULT auto-selected runtime whenever present — the\n * opposite of the product decision that pi is the FALLBACK runtime (tried\n * only once nothing better is available/capable), not the default. That\n * conflation is why this constant's order and the auto-select order are now\n * two independent things: this one stays `['pi', 'claude', 'codex']`\n * (unchanged — still a perfectly fine construction/reporting order, and\n * changing it would needlessly reshuffle `conn.hello.runtimes` for no\n * reason), while `DEFAULT_RUNTIME_PREFERENCE` states the actual selection\n * priority explicitly (`['claude', 'codex', 'pi']`, pi last) instead of\n * leaving it as an implicit side effect of this list's order.\n */\nconst ALL_RUNTIME_IDS: readonly RuntimeId[] = ['pi', 'claude', 'codex'];\n\nfunction buildAdapter(id: RuntimeId): RuntimeAdapter {\n switch (id) {\n case 'pi':\n return new PiAdapter();\n case 'claude':\n return new ClaudeAdapter();\n case 'codex':\n return new CodexAdapter();\n }\n}\n\n/**\n * Builds `createDaemon`'s bundled adapter set from `DaemonConfig.runtimeAllowlist`\n * — see that field's own doc comment for the unset-vs-set contract. Filters\n * `ALL_RUNTIME_IDS` (rather than mapping the allowlist directly) so an\n * allowlist entry that isn't a real runtime id is silently ignored — the same\n * \"unknown id never gets an adapter\" fail-closed shape `TaskRunner.pickAdapter`\n * already applies to an unknown *requested* runtime — and it de-duplicates\n * repeated entries for free.\n */\nfunction buildDefaultAdapters(runtimeAllowlist: string[] | undefined): RuntimeAdapter[] {\n const ids = runtimeAllowlist\n ? ALL_RUNTIME_IDS.filter((id) => runtimeAllowlist.includes(id))\n : ALL_RUNTIME_IDS;\n return ids.map(buildAdapter);\n}\n\nexport function createDaemonWithAdapters(\n config: DaemonConfig,\n adapters: RuntimeAdapter[],\n overrides: DaemonOverrides = {},\n): Daemon {\n // M5 batch-3 (workstream 2): validated synchronously, up front — see\n // `DaemonConfig.maxTaskOutputBytes`'s own doc comment for the full\n // zero/negative-is-an-error / `Number.POSITIVE_INFINITY`-is-the-real-\n // opt-out pin. `configured > 0` is `false` for `NaN`, `0`, and any\n // negative number, and `true` for `Number.POSITIVE_INFINITY` — exactly the\n // three-way split this config wants.\n if (config.maxTaskOutputBytes !== undefined && !(config.maxTaskOutputBytes > 0)) {\n throw new Error(\n `DaemonConfig.maxTaskOutputBytes must be a positive number (or omitted to use the ${DEFAULT_MAX_TASK_OUTPUT_BYTES}-byte default) — got ${config.maxTaskOutputBytes}. Pass Number.POSITIVE_INFINITY to explicitly disable the cap; 0 or a negative number is rejected rather than silently treated as \"disabled\".`,\n );\n }\n\n const storeDir = DeviceStore.resolveDir(config.productId, config.storeDir);\n const store = new DeviceStore(storeDir);\n const operationalHealth = new OperationalHealthTracker(storeDir);\n let fleetJitter: FleetJitter | undefined;\n let maintenanceSequence = 0;\n const cursorStore = new CursorStore(storeDir);\n const sessionWorkspaces = new SessionWorkspaceStore(storeDir);\n const gitWorkspaceManager = config.gitWorkspace ? overrides.gitWorkspace?.manager ?? new GitWorkspaceManager(config.workspaceRoot, { ownerId: stableGitWorkspaceOwnerId(storeDir, config.productId) }) : undefined;\n const gitWorkspaceStore = config.gitWorkspace ? overrides.gitWorkspace?.store ?? new GitWorkspaceStore(storeDir) : undefined;\n // S3b (L-002), same three-part shape as `gitWorkspace` above: optional\n // config field, conditional construction, override seam. An absent\n // `hostedJournal` constructs NOTHING — no database file, no directory, no\n // reference — which is what keeps the default self-hosted path identical to\n // what it was before this slice.\n //\n // Fail-closed on a runtime without `node:sqlite` needs no check here: this\n // is the constructor that refuses (`JournalUnavailableError`), before any\n // filesystem work, and it propagates straight out of `createDaemon`.\n let resolvedStoragePolicy: LocalStoragePolicy | undefined;\n if (config.hostedJournal) {\n // Validated synchronously and up front, the same way `maxTaskOutputBytes`\n // is above — a misconfigured durability section must fail at\n // construction, not at the first envelope that needed it.\n if (config.hostedJournal.mode !== 'sqlite') {\n throw new Error(`DaemonConfig.hostedJournal.mode must be \"sqlite\" — got ${JSON.stringify(config.hostedJournal.mode)}`);\n }\n if (typeof config.hostedJournal.tenantId !== 'string' || config.hostedJournal.tenantId.trim() === '') {\n throw new Error(\n 'DaemonConfig.hostedJournal.tenantId must be a non-empty tenant id — a hosted journal row with no tenant is durable evidence nobody can act on',\n );\n }\n // Resolved HERE, in the same pure-config block, and deliberately BEFORE\n // any journal is constructed: rejecting a malformed storage policy must\n // not depend on this runtime having `node:sqlite`, or the same bad config\n // would surface as `JournalUnavailableError` on Node 20 and\n // `LocalStoragePolicyError` on Node 22. Config errors are config errors on\n // every runtime.\n if (config.hostedJournal.storagePolicy) {\n resolvedStoragePolicy = resolveLocalStoragePolicy(config.hostedJournal.storagePolicy);\n }\n }\n // Capability detection is side-effect-free and therefore remains a\n // construction-time failure. Opening/schema-initializing/quarantining the\n // SQLite file is intentionally deferred until `startUnderLease` owns the\n // cross-process store lease; a rejected second daemon must not touch the\n // active daemon's DB/WAL/SHM before discovering that it is rejected.\n if (config.hostedJournal && overrides.hostedJournal?.journal === undefined && !isSqliteAvailable()) {\n throw new JournalUnavailableError(`node:sqlite could not be loaded on Node ${process.versions.node}`);\n }\n\n let ownedJournal: SqliteLocalTaskJournal | undefined;\n let journal: LocalTaskJournal | undefined = config.hostedJournal ? overrides.hostedJournal?.journal : undefined;\n let ownedPressureEngine: LocalStoragePressureEngine | undefined;\n let hostedStorageInitializationBarrierComplete = true;\n let pressureEngine: LocalStoragePressureEngine | undefined = config.hostedJournal\n ? overrides.hostedJournal?.pressureEngine\n : undefined;\n\n /** Construct every daemon-owned hosted writer only after ownership exists. */\n function initializeOwnedHostedStorage(): void {\n if (!config.hostedJournal) return;\n if (!journal) {\n try {\n ownedJournal = new SqliteLocalTaskJournal({\n storeDir,\n ...(config.hostedJournal.busyTimeoutMs === undefined ? {} : { busyTimeoutMs: config.hostedJournal.busyTimeoutMs }),\n ...(config.hostedJournal.maxRecordBytes === undefined ? {} : { maxRecordBytes: config.hostedJournal.maxRecordBytes }),\n ...(overrides.hostedJournal?.openFaults === undefined ? {} : { openFaults: overrides.hostedJournal.openFaults }),\n });\n } catch (err) {\n if (err instanceof JournalHandleCleanupError) hostedStorageInitializationBarrierComplete = false;\n throw err;\n }\n journal = ownedJournal;\n }\n if (resolvedStoragePolicy && !pressureEngine) {\n const activeJournal = journal;\n const cleanupJournal = ownedJournal;\n ownedPressureEngine = new LocalStoragePressureEngine({\n policy: resolvedStoragePolicy,\n journal: activeJournal,\n freeBytesProvider: createStatfsFreeBytesProvider(storeDir),\n executor: createFilesystemCleanupExecutor(\n cleanupJournal ? { pruneJournalTask: (taskId) => cleanupJournal.pruneConfirmedJournalTask(taskId) } : {},\n ),\n timers: {\n setInterval: (handler, baseMs) => {\n if (!fleetJitter) throw new Error('maintenance scheduler started before device identity was loaded');\n const timer = setInterval(handler, fleetJitter.delay('maintenance', maintenanceSequence++, baseMs));\n timer.unref?.();\n return timer;\n },\n clearInterval: (handle) => clearInterval(handle as NodeJS.Timeout),\n },\n onMaintenanceOutcome: (outcome) => {\n const write = outcome === 'success'\n ? operationalHealth.recordSuccess('maintenance')\n : operationalHealth.recordFailure('maintenance');\n void write.catch((err: unknown) => {\n console.warn(`[byok/client] failed to persist operational health: ${err instanceof Error ? err.message : String(err)}`);\n });\n },\n onEvent: (event) => {\n if (event.kind !== 'state-changed') return;\n console.warn(\n `[byok/client] local storage pressure: ${event.from} -> ${event.to} (used ${event.snapshot.usedBytes} of ${event.snapshot.budgetBytes} budget bytes, ${event.snapshot.freeBytes} free)`,\n );\n },\n });\n pressureEngine = ownedPressureEngine;\n }\n }\n /**\n * S3b: serializes terminal journal writes against the outbound send that\n * follows each one, and gives `runShutdownSequence` something to await.\n *\n * `TaskRunnerDeps.send` is synchronous by contract, so the journal write\n * cannot simply be awaited inline. Chaining instead keeps the ordering\n * (journal committed, THEN the terminal goes on the wire) without changing\n * that contract — and the shutdown sequence awaits this tail before the\n * outbox drain, so a `task.fail` produced during teardown can never be left\n * mid-chain while the connection closes out from under it.\n */\n let journalTerminalTail: Promise<void> = Promise.resolve();\n // M3-2a: local observability — constructed once per daemon instance (not\n // per `start()`) so `subscribe()`/`tasks()` work immediately after\n // `createDaemonWithAdapters()` returns and keep accumulating across an\n // internal stop()/start() cycle within the same instance. See `observer.ts`.\n const observer = new DaemonObserver();\n // M4 Phase 2: registry backing the control socket's `approvals.list`/\n // `approvals.resolve` methods — see `approvals.ts`'s module doc comment.\n // Nothing populates it yet in Phase 2; it's constructed now so Phase 3\n // only needs to add producers.\n const approvalRegistry = new ApprovalRegistry();\n\n let connection: ConnectionManager | undefined;\n let connectionState: ConnectionState = 'closed';\n let runner: TaskRunner | undefined;\n // M4 Phase 2: local control socket (see `control-server.ts`) — started in\n // `start()`, closed in `stop()`. `undefined` whenever the daemon isn't\n // running, or when binding it failed non-fatally (see `start()`'s own\n // try/catch below).\n let controlServerHandle: ControlServerHandle | undefined;\n let daemonOwnerLease: DaemonOwnerLease | undefined;\n let shutdownPromise: Promise<void> | undefined;\n const pendingLateMutationBarriers = new Set<Promise<void>>();\n /** M4 Phase 2: when this `start()` began — backs the control socket's `status.uptimeMs`. */\n let startedAt: number | undefined;\n\n // M3-2a: `let`, not `const` — `unpair()` below rebuilds this from scratch\n // (fresh, no cached in-memory `record`) rather than mutating the existing\n // instance. `AuthManager` has no reset/forget method of its own (out of\n // scope: owned by a concurrent worker's untouched file) and caches its\n // `record` in memory once loaded, so merely clearing `store` on disk isn't\n // enough on its own — a same-process `loadExisting()` call would keep\n // returning the cached record. Reconstructing `auth` is the seam this file\n // already owns end-to-end; `pair`/`start`/`status`/`stop` all read the\n // CURRENT closure variable at call time, so a fresh instance is picked up\n // by every one of them with no further wiring.\n function buildAuthManager(): AuthManager {\n return new AuthManager({\n serverUrl: config.serverUrl,\n store,\n deviceName: config.deviceName,\n onRevoked: () => {\n connectionState = 'revoked';\n },\n });\n }\n let auth = buildAuthManager();\n\n /**\n * M5: `assertServerUrlAllowed`'s call site — see that function's own doc\n * comment (`url.ts`) for why `pair()`/`start()` are the right (and only\n * needed) two places to call it from. Checked WITHOUT the escape hatch\n * FIRST, deliberately: that is the only way to tell whether\n * `dangerouslyAllowInsecureRemote` actually changed the outcome (as\n * opposed to being set but inert, e.g. against a `serverUrl` that was\n * already loopback) — only a hatch that genuinely let something through\n * deserves the loud warning below, emitted via the exact same\n * `console.warn('[byok/client] ...')` convention this file already uses\n * for its other non-fatal, operator-facing warnings (see the\n * control-socket bind-failure warning in `start()`).\n *\n * F2 (fixed here): `config.dangerouslyAllowInsecureRemote` being set only\n * means \"forgive a plaintext-to-non-loopback rejection\" — it does NOT mean\n * \"forgive literally any rejection this gate can ever produce.\" An\n * unsupported scheme (e.g. `ftp:`) or a `serverUrl` that fails to parse as\n * a URL at all is refused by `assertServerUrlAllowed` UNCONDITIONALLY,\n * regardless of `dangerouslyAllowInsecureRemote` (see that function's own\n * doc comment) — the previous version of this catch block forwarded the\n * hatch's boolean straight past that distinction and warned-and-proceeded\n * for EVERY rejection once the flag was set. Fixed by re-running the exact\n * same check WITH the hatch passed through once the flag is confirmed set;\n * only a second call that ALSO passes proves the hatch genuinely covers\n * this specific rejection and earns the warn-and-proceed below. If the\n * second call throws too, that throw propagates out of this function\n * unchanged (nothing here catches it) — correctly, since the hatch was\n * never going to cover this rejection in the first place.\n */\n function checkServerUrl(): void {\n try {\n assertServerUrlAllowed(config.serverUrl);\n } catch (err) {\n if (!config.dangerouslyAllowInsecureRemote) throw err;\n assertServerUrlAllowed(config.serverUrl, { dangerouslyAllowInsecureRemote: true });\n const reason = err instanceof Error ? err.message : String(err);\n console.warn(\n `[byok/client] WARNING: dangerouslyAllowInsecureRemote is set — proceeding with an insecure server URL (${config.serverUrl}). ` +\n `Device credentials and task data will be sent in the clear to a non-loopback host. This should never be used in a real ` +\n `deployment. (${reason})`,\n );\n }\n }\n\n let lifecycleMutationTail: Promise<void> = Promise.resolve();\n\n async function runLifecycleMutation<T>(operation: () => Promise<T>): Promise<T> {\n const predecessor = lifecycleMutationTail;\n let release!: () => void;\n lifecycleMutationTail = new Promise<void>((resolve) => {\n release = resolve;\n });\n await predecessor;\n try {\n return await operation();\n } finally {\n release();\n }\n }\n\n async function pair(pairingCode: string): Promise<DeviceRecord> {\n checkServerUrl();\n // Serialize every lifecycle mutation, not only pair/pair. A process-local\n // operation may borrow the daemon's retained cross-process lease, so pair,\n // start, stop, control shutdown and unpair must never decide independently\n // who releases that shared lease.\n return runLifecycleMutation(() => pairUnderLease(pairingCode));\n }\n\n async function pairUnderLease(pairingCode: string): Promise<DeviceRecord> {\n // Pairing persists device.json. It intentionally does not arm proactive\n // renewal (AuthManager.loadExisting does that under start()'s lease), so a\n // short-lived pair command can release ownership once the write lands.\n const acquiredHere = daemonOwnerLease === undefined;\n if (acquiredHere) daemonOwnerLease = await acquireDaemonOwner(storeDir, 'daemon');\n // Finding F5: capture whatever device is currently on disk for this\n // serverUrl (if any) BEFORE pairing — `auth.pair()` mints/persists a\n // brand new deviceId (the server always does, even on a same-keypair\n // re-pair; see docs/protocol.md §6.3) and there would be no way to\n // recover the outgoing deviceId afterward to know whose cursor to clear.\n // Reading straight from `store` (not `auth.deviceId`) works whether or\n // not `start()`/`loadExisting()` ran in this process before `pair()`.\n try {\n const previous = await store.load();\n const record = await auth.pair(pairingCode);\n if (previous && previous.deviceId !== record.deviceId) {\n await cursorStore.clear(config.serverUrl, previous.deviceId);\n }\n observer.notePaired(record.deviceId);\n if (acquiredHere) {\n await daemonOwnerLease?.release();\n daemonOwnerLease = undefined;\n }\n return record;\n } catch (err) {\n if (acquiredHere) {\n await daemonOwnerLease?.release();\n daemonOwnerLease = undefined;\n }\n throw err;\n }\n }\n\n async function start(): Promise<void> {\n checkServerUrl();\n await runLifecycleMutation(startUnderLease);\n }\n\n async function startUnderLease(): Promise<void> {\n if (!daemonOwnerLease) daemonOwnerLease = await acquireDaemonOwner(storeDir, 'daemon');\n try {\n // This is the first point at which daemon-owned hosted storage may touch\n // the filesystem. The lease was acquired above, so SQLite open/schema/\n // quarantine and every pressure-engine writer are inside the same\n // authority boundary as auth renewal and the rest of daemon lifecycle.\n initializeOwnedHostedStorage();\n const activeJournal = journal;\n const activePressureEngine = pressureEngine;\n const activeOwnedPressureEngine = ownedPressureEngine;\n // Loading an existing record arms proactive token renewal, whose final\n // step writes device.json. Acquire the store mutation lease first so a\n // rejected second daemon can never leave that timer behind as a writer.\n const record = await auth.loadExisting();\n if (!record) {\n throw new Error('device is not paired yet; call pair(pairingCode) first');\n }\n fleetJitter = createFleetJitter(config.productId, record.deviceId);\n\n // M5 batch-3 (workstream 1): see `DaemonConfig.permissionDefaults`'s own\n // doc comment above — a configured ceiling `workspaceRoot` is merged\n // into every task's effective policy but enforced by no bundled adapter.\n // Logged once per `start()` (not per task, not per offer) — same\n // operator-facing, non-fatal `console.warn` convention `checkServerUrl`'s\n // `dangerouslyAllowInsecureRemote` warning above already uses in this\n // file. This is purely a LOCAL-ceiling warning: an OFFER independently\n // asking for its own `workspaceRoot` is a different, fail-closed-declined\n // case handled by `TaskRunner.handleOffer`, not here.\n if (config.permissionDefaults?.workspaceRoot !== undefined) {\n console.warn(\n `[byok/client] WARNING: permissionDefaults.workspaceRoot (\"${config.permissionDefaults.workspaceRoot}\") is configured, but no bundled runtime adapter (pi/claude/codex) enforces PermissionPolicy.workspaceRoot — every adapter confines a task to ctx.workspaceDir instead. This ceiling value has no enforcement effect; see docs/security.md's \"Workspace confinement is a convention, not a sandbox\" section.`,\n );\n }\n\n // S3b (L-002): the recovery scan, before anything can accept new work.\n //\n // Every task the journal still has open is one this daemon was in the\n // middle of when it last stopped. Local runtime sessions do not survive\n // the process, so each is marked `interrupted` rather than pretended back\n // into life — the same honest semantics `GitWorkspaceStore.reconcile()`\n // already applies to a lease whose owner is gone, and the same one\n // `SqliteTaskStore` documents on the server side (\"record persistence, not\n // live task reconnection\"). Marking never deletes: a recovery-marked row\n // is on §12.7.2.1's never-auto-delete list precisely so the evidence\n // outlives the restart.\n //\n // Not wrapped in a try/catch: a journal that cannot be read is not a\n // degraded mode to carry on in. Hosted mode was configured explicitly, so\n // failing `start()` is the fail-closed behaviour §12.7.2 asks for.\n if (activeJournal) {\n const recoverable = await activeJournal.listRecoverable();\n for (const task of recoverable) {\n await activeJournal.markRecovered(task.taskId, {\n disposition: 'interrupted',\n reason: `daemon restarted while this task was in local state \"${task.localState}\"; local runtime sessions do not survive the process`,\n });\n }\n if (recoverable.length > 0) {\n console.warn(\n `[byok/client] local journal recovery: ${recoverable.length} task(s) were interrupted by the previous shutdown and have been marked (not resumed, not deleted): ${recoverable\n .map((task) => task.taskId)\n .join(', ')}`,\n );\n }\n }\n\n // S3b (L-003): one measurement before this daemon can accept anything, so\n // the admission guard's first answer comes from a real reading rather than\n // the optimistic `normal` a fresh engine starts in — a device that booted\n // already over its hard watermark must decline the first offer, not the\n // second. Awaited, and deliberately not caught: hosted mode plus a storage\n // policy is an explicit request to gate on local storage, and a daemon that\n // cannot measure it cannot honour that (§12.7.2's fail-closed posture).\n // An INJECTED engine is left alone — its owner drives its cadence.\n if (activeOwnedPressureEngine) {\n await activeOwnedPressureEngine.tick();\n activeOwnedPressureEngine.start();\n }\n\n startedAt = Date.now();\n // M4 Phase 2: a second start() on THIS SAME Daemon instance (e.g. the\n // revoke -> re-pair -> start() again recovery flow) restarts its own\n // control socket rather than colliding with itself — `stop()` was not\n // necessarily called in between (mirrors `connection`/`runner` above,\n // which are also silently replaced on a second start()). Only a\n // DIFFERENT process/instance still holding this storeDir's control\n // socket open is the \"another daemon is running\" fatal case below.\n if (controlServerHandle) {\n await controlServerHandle.close();\n controlServerHandle = undefined;\n }\n // The control socket must never brick the rest of the daemon: \"another\n // daemon's control server is already running against this exact\n // storeDir\" is the one bind failure that stays fatal (a second daemon\n // writing to the same store concurrently is a real hazard); any other\n // bind failure (e.g. an unsupported filesystem) is logged and the\n // daemon proceeds without a control socket at all.\n try {\n controlServerHandle = await startControlServer({ storeDir, productId: config.productId, methods: controlMethods });\n } catch (err) {\n if (err instanceof AnotherControlServerRunningError) throw err;\n console.warn(\n `[byok/client] control socket failed to start (continuing without it): ${err instanceof Error ? err.message : String(err)}`,\n );\n controlServerHandle = undefined;\n }\n // The run marker begins only after this process has passed the daemon's\n // existing single-owner bind check. Writing it before that check would let\n // a rejected second process overwrite the live daemon's marker and create\n // a false crash record on the next restart.\n await operationalHealth.startRun();\n\n if (gitWorkspaceManager) {\n await gitWorkspaceManager.preflight();\n await gitWorkspaceStore?.initialize();\n await gitWorkspaceStore?.reconcile();\n }\n\n const [runtimes, blobClient] = await Promise.all([\n detectRuntimes(adapters),\n Promise.resolve(new BlobClient(config.serverUrl, auth)),\n ]);\n // M3-2a: local runtime-detection result — computed once per `start()`,\n // same as the `conn.hello.runtimes` it also feeds (see `detectRuntimes`'s\n // own doc comment on why this isn't re-probed on every reconnect).\n observer.noteRuntimesDetected(runtimes);\n const capabilities = computeCapabilities(adapters);\n\n // S3b: this daemon's journal identity — only knowable here, after\n // `auth.loadExisting()` has resolved the deviceId.\n const journalIdentity: JournalIdentity | undefined = config.hostedJournal\n ? { tenantId: config.hostedJournal.tenantId, productId: config.productId, deviceId: record.deviceId }\n : undefined;\n\n /**\n * S3b: outbound send.\n *\n * The no-journal branch is the ORIGINAL closure, character for character —\n * the default path must not gain so much as an extra `await`, or the\n * \"opt-in, byte-equivalent by default\" claim is only approximately true.\n *\n * The journal branch records a terminal BEFORE it goes on the wire, so a\n * crash in that window leaves the terminal hash locally (to be retried)\n * rather than only in the cloud (§12.7.3's \"terminal 生成后、truth 写入前\"\n * row). A journal write that FAILS still sends: §12.7.2.1 keeps terminal\n * flush running even under hard pressure, and stranding a finished task on\n * the cloud side because the local bookkeeping hiccupped would be a worse\n * outcome than a missing local row.\n */\n const sendEnvelope: TaskRunnerDeps['send'] =\n activeJournal && journalIdentity\n ? (envelope) => {\n observer.handleOutboundEnvelope(envelope);\n const terminalKind = terminalKindOf(envelope.type);\n const taskId = envelope.task_id;\n if (terminalKind === undefined || taskId === undefined) {\n connection?.send(envelope);\n return;\n }\n const payloadHash = journalHash(encodeEnvelope(envelope));\n journalTerminalTail = journalTerminalTail\n .then(() =>\n activeJournal.recordTerminal({\n taskId,\n terminalType: terminalKind,\n payloadHash,\n truthState: 'pending',\n attempt: 1,\n recordedAt: new Date().toISOString(),\n }),\n )\n .catch((err: unknown) => {\n console.warn(\n `[byok/client] could not record task ${taskId}'s terminal in the local journal (sending it anyway): ${err instanceof Error ? err.message : String(err)}`,\n );\n })\n .then(() => {\n connection?.send(envelope);\n });\n }\n : (envelope) => {\n observer.handleOutboundEnvelope(envelope);\n connection?.send(envelope);\n };\n\n const deps: TaskRunnerDeps = {\n adapters,\n runtimeAllowlist: config.runtimeAllowlist,\n // M5 batch-3: see `DaemonConfig.runtimePreference`'s own doc comment above.\n runtimePreference: config.runtimePreference,\n permissionDefaults: config.permissionDefaults,\n workspaceRoot: config.workspaceRoot,\n deviceId: record.deviceId,\n // M5: see `DaemonConfig.runtimeEnvironment`'s own doc comment above.\n runtimeEnvironment: config.runtimeEnvironment,\n // M3-2a: `send` is already this file's OWN closure (not something\n // `TaskRunner` builds) — every `task.claim`/`task.started`/\n // `task.progress`/`task.artifact`/`task.await_approval`/\n // `task.complete`/`task.fail`/`task.decline`/`task.cancelled`\n // `TaskRunner` ever emits passes through here. Feeding the observer\n // first (never throws — see `observer.ts`) and then sending exactly as\n // before is the entire integration; `task-runner.ts` itself is\n // untouched. See `observer.ts`'s module doc comment.\n send: sendEnvelope,\n blobClient,\n batcherOptions: overrides.batch,\n sessionWorkspaces,\n gitWorkspaceManager,\n gitWorkspaceStore,\n onGitWorkspaceEvent: (event) => observer.noteGitWorkspace({\n taskId: event.taskId,\n workspaceId: event.workspaceId,\n phase: event.phase,\n headChanged: event.observation?.headChanged,\n commitsSinceBaseline: event.observation?.commitsSinceBaseline,\n dirty: event.observation ? { staged: event.observation.staged, unstaged: event.observation.unstaged, untracked: event.observation.untracked, conflicted: event.observation.conflicted } : undefined,\n errorCategory: event.errorCategory,\n }),\n\n // M4 Phase 3: the SAME `ApprovalRegistry` instance the control\n // socket's own `approvals.list`/`approvals.resolve` methods already\n // share (see that field's own construction above) — `TaskRunner\n // .requestApproval` registers into it directly, so a decision arriving\n // via either the server wire or the local CLI resolves the identical\n // entry. `storeDir`/`productId` let `TaskContext.approvalChannel`\n // (populated per-task by `TaskRunner`) tell an out-of-process helper\n // (`bin/byok-approval-mcp.ts`) exactly which control socket to dial.\n approvalRegistry,\n storeDir,\n productId: config.productId,\n approvalTimeoutMs: overrides.approvalTimeoutMs,\n // Finding F5(a): see TaskRunnerDeps.shutdownInterruptTimeoutMs's own doc comment.\n shutdownInterruptTimeoutMs: overrides.shutdown?.taskInterruptTimeoutMs,\n // M5 batch-3 (workstream 2): see DaemonConfig.maxTaskOutputBytes's own doc comment — already validated above.\n maxTaskOutputBytes: config.maxTaskOutputBytes,\n // M4 Phase 3 hardening: bridges TaskRunner's stale-approval-race\n // finding out to the SAME local observability seam every other\n // daemon-local event already uses (see observer.ts's own module doc\n // comment) — TaskRunner itself still has no notion `DaemonObserver`\n // exists, exactly like every other `deps.send`-shaped seam here.\n onStaleApprovalDecision: (taskId, decision, reason) => {\n observer.noteStaleApprovalDecision(taskId, decision, reason);\n },\n // Finding F4: see `TaskRunnerDeps.onApprovalDispatched`'s own doc\n // comment — lets `observer`'s `awaiting-approval` DaemonEvent (and\n // thus `tasks --follow`) surface the approvalId an operator actually\n // needs to call `approve`/`reject`/`approvals` against.\n onApprovalDispatched: (taskId, approvalId) => {\n observer.noteApprovalDispatched(taskId, approvalId);\n },\n // M4 (additive-minor, `task.approval_resolved`): read fresh at call\n // time via `connection` (assigned just below — safe by the time this\n // is actually invoked, same closure pattern `send` above already\n // relies on) rather than captured once here, since the negotiated\n // capability is only known once the handshake completes, strictly\n // after this `deps` object is constructed.\n getServerCapabilities: () => connection?.getServerCapabilities() ?? [],\n // S3b (L-003): the production admission guard — §12.7.2.1's hard-pressure\n // row. Reads the state the last maintenance tick computed (no disk work\n // on the offer path), and is absent entirely when no storage policy is\n // configured, which is what keeps `handleOffer` byte-identical for every\n // daemon that does not opt in.\n ...(activePressureEngine ? { admissionGuard: () => activePressureEngine.admissionGuard() } : {}),\n };\n runner = new TaskRunner(deps);\n\n connection = new ConnectionManager({\n serverUrl: config.serverUrl,\n deviceId: record.deviceId,\n productId: config.productId,\n capabilities,\n runtimes,\n auth,\n cursorStore,\n // Finding F3: return (not void-and-forget) so ConnectionManager can\n // await this handler and only advance/persist its redelivery cursor\n // once it actually resolves — see connection-manager.ts's `process`.\n // M3-2a: also this file's own closure, unrelated to F3's redelivery\n // semantics above — `handleInboundEnvelope` only ever looks at\n // `task.offer` (the one event with no corresponding outbound envelope\n // of its own) and never throws, so it can't affect cursor advancement.\n // S3b (L-002): where \"ack after durable commit\" stops being a\n // discipline and becomes the only expressible behaviour.\n //\n // `ConnectionManager.process` advances (and persists) the redelivery\n // cursor ONLY when this handler resolves, and merely records a stall\n // when it throws (`connection-manager.ts`) — that was already true, and\n // is not changed by this slice. Putting the journal transaction INSIDE\n // this handler therefore makes the ordering structural: the cursor\n // cannot move past a seq whose envelope is not yet committed, because\n // the only thing that moves the cursor is this function resolving, and\n // this function does not resolve until the commit does. There is no\n // second path to the cursor to keep in step, and the transport is\n // untouched.\n //\n // Placed after the observer (which never throws and owns no durable\n // state) and before the runner, so the bytes are on disk before any\n // work is scheduled off them. A redelivered envelope is absorbed by the\n // journal's own receipt and costs one no-op transaction.\n //\n // The no-journal branch is the ORIGINAL closure, unchanged.\n onEnvelope:\n activeJournal && journalIdentity\n ? async (envelope) => {\n observer.handleInboundEnvelope(envelope);\n // S3b (L-003): §12.7.2.1's `emergency` row — \"fail-closed,不 ack\n // 新 mailbox row;保留现有 recovery evidence\". Throwing HERE, ahead\n // of the append, reuses the ordering the journal branch already\n // established: the handler rejects, so the cursor does not move,\n // so the mailbox keeps the row and redelivers it later. The task\n // is not lost; it is left in the one place that still has room\n // for it. Nothing is deleted to make space.\n activePressureEngine?.assertAckCriticalAllowed();\n await activeJournal.appendEnvelope(toJournalEnvelopeRecord(envelope, journalIdentity));\n return runner?.handleEnvelope(envelope) ?? Promise.resolve();\n }\n : (envelope) => {\n observer.handleInboundEnvelope(envelope);\n return runner?.handleEnvelope(envelope) ?? Promise.resolve();\n },\n onStateChange: (state) => {\n connectionState = state;\n observer.noteConnectionState(state);\n },\n backoff: overrides.backoff,\n liveness: overrides.liveness,\n wsFailureThreshold: overrides.longPoll?.wsFailureThreshold,\n wsRetryIntervalMs: overrides.longPoll?.wsRetryIntervalMs,\n longPollRetryDelayMs: overrides.longPoll?.retryDelayMs,\n longPollIdleDelayMs: overrides.longPoll?.idleDelayMs,\n fleetJitter,\n onOperationalOutcome: (outcome, source) => {\n const write = outcome === 'success'\n ? operationalHealth.recordSuccess(source)\n : operationalHealth.recordFailure(source);\n void write.catch((err: unknown) => {\n console.warn(`[byok/client] failed to persist operational health: ${err instanceof Error ? err.message : String(err)}`);\n });\n },\n });\n await connection.start();\n await connection.waitForAck();\n } catch (err) {\n try {\n // startUnderLease already owns the process-local lifecycle slot. Run\n // teardown directly; queueing requestShutdown here would wait on this\n // operation itself and deadlock.\n await runShutdownSequence('startup failed', { drainTimeoutMs: 0 });\n } catch (cleanupError) {\n throw new AggregateError([err, cleanupError], 'daemon startup failed and teardown was incomplete');\n }\n throw err;\n }\n }\n\n /**\n * M5 batch-3 (workstream 2): the ONE graceful-shutdown sequence, shared by\n * every path that stops this daemon while it might have active tasks —\n * closes the M5 ledger item \"SIGTERM path doesn't send task.fail\". Before\n * this, `stop()` and `performControlShutdown` were two INDEPENDENT\n * implementations: `stop()` just dropped the connection outright with no\n * notion of active tasks at all, so the OS-signal path\n * (`bin/commands/start.ts`'s SIGINT/SIGTERM handler -> this daemon's own\n * public `stop()`) never sent `task.fail` for whatever was still running.\n * Now there is exactly one teardown sequence, and every caller (`stop()`,\n * `unpair()` via `stop()`, and `performControlShutdown`) shares it: stop\n * accepting new offers -> best-effort interrupt+fail every active task,\n * over the STILL-OPEN connection (`TaskRunner.shutdownActiveTasks`,\n * deadline-bounded by `config.shutdownGraceMs` — default\n * `SHUTDOWN_TASK_TEARDOWN_DEADLINE_MS` — so a hung task teardown can never\n * block this daemon from actually stopping) -> bounded wait for that\n * outbox to actually drain (finding F5(b)) -> close the connection / stop\n * the auth renewal timer / close the control socket.\n *\n * CRITICAL preservation (M4 Phase 2 fix, unchanged by this refactor): the\n * connection must not close until AFTER `shutdownActiveTasks` has actually\n * enqueued its `task.fail`(s) — see `performControlShutdown`'s own doc\n * comment for the exact regression (`start.ts` used to wake on the earlier\n * `shutdown-requested` event and race `daemon.stop()` ahead of the\n * still-in-flight send) this ordering fixes. That ordering is unchanged\n * here: stopAcceptingOffers -> shutdownActiveTasks -> THEN connection\n * teardown, for every caller alike, including the OS-signal path that\n * previously skipped straight to connection teardown.\n *\n * Idempotent: a second call (e.g. `performControlShutdown`'s own internal\n * call, followed by `bin/commands/start.ts`'s subsequent `daemon.stop()`\n * once `shutdown-complete` wakes it — see that file's own doc comment)\n * finds `runner`'s active-task map already empty (the first call's own\n * `finish()`s already deleted every entry), so `shutdownActiveTasks` sends\n * nothing the second time; `stopAcceptingOffers` is already idempotent by\n * its own contract; `connection.stop()` is documented idempotent\n * (`connection-manager.ts`); and `controlServerHandle` is reassigned to\n * `undefined` after the first close, so a second call's `?.close()` is a\n * no-op. See `daemon-control-socket.test.ts`'s \"REGRESSION\n * (gatekeeper-caught)\" test for exactly this double-teardown shape (a\n * control-socket shutdown followed by `runStartCommand`'s own\n * `daemon.stop()`), which must neither double-fail a task nor throw.\n */\n async function runShutdownSequence(reason: string, opts: { drainTimeoutMs?: number } = {}): Promise<void> {\n const errors: unknown[] = [];\n let mutationBarrierComplete = hostedStorageInitializationBarrierComplete;\n if (!hostedStorageInitializationBarrierComplete) {\n errors.push(new Error('hosted storage initialization left an unclosed SQLite handle; ownership lease retained'));\n }\n const attempt = async (operation: () => void | Promise<void>, mutationBarrier: boolean): Promise<boolean> => {\n try {\n await operation();\n return true;\n } catch (err) {\n errors.push(err);\n if (mutationBarrier) mutationBarrierComplete = false;\n return false;\n }\n };\n\n // A prior shutdown attempt may have hit its deadline while task teardown\n // continued in the background. A retry must not release ownership merely\n // because its own fresh runner pass is empty: the late pass is still a\n // possible journal producer until it settles.\n if (pendingLateMutationBarriers.size > 0) {\n const prior = Promise.allSettled([...pendingLateMutationBarriers]);\n let priorSettled = false;\n void prior.then(() => {\n priorSettled = true;\n });\n const graceMs = config.shutdownGraceMs ?? SHUTDOWN_TASK_TEARDOWN_DEADLINE_MS;\n await Promise.race([prior, delay(graceMs)]);\n if (!priorSettled) {\n mutationBarrierComplete = false;\n errors.push(new Error('a prior active task teardown remains unsettled; ownership lease retained'));\n }\n }\n\n // S3b (L-003): stop the maintenance cadence first — a compaction pass\n // starting while the journal is being drained would hold the single writer\n // against the terminal writes below for no benefit. Only the engine THIS\n // daemon constructed; an injected one belongs to its injector, exactly like\n // an injected journal is not closed here. Idempotent, like every other step\n // in this sequence.\n const stoppingOwnedPressureEngine = ownedPressureEngine;\n const stoppingOwnedJournal = ownedJournal;\n const maintenanceStopped = stoppingOwnedPressureEngine?.stop() ?? Promise.resolve();\n await attempt(() => runner?.stopAcceptingOffers(), true);\n const activeTeardown = runner?.shutdownActiveTasks(reason) ?? Promise.resolve();\n const graceMs = config.shutdownGraceMs ?? SHUTDOWN_TASK_TEARDOWN_DEADLINE_MS;\n let activeTeardownSettled = false;\n const observedActiveTeardown = activeTeardown.then(\n () => {\n activeTeardownSettled = true;\n },\n (err: unknown) => {\n activeTeardownSettled = true;\n throw err;\n },\n );\n await attempt(() => Promise.race([observedActiveTeardown, delay(graceMs)]), true);\n if (!activeTeardownSettled) {\n mutationBarrierComplete = false;\n errors.push(new Error('active task teardown did not settle before the shutdown grace deadline'));\n pendingLateMutationBarriers.add(observedActiveTeardown);\n void observedActiveTeardown.finally(() => pendingLateMutationBarriers.delete(observedActiveTeardown)).catch(() => undefined);\n }\n // S3b: in hosted mode, a terminal is journaled before it is handed to the\n // outbox (see `sendEnvelope`), so a `task.fail` that `shutdownActiveTasks`\n // just produced may still be mid-chain right now. Awaiting the chain here\n // — before the drain wait below, which is what decides the connection is\n // idle — is what keeps that fail from being written into an outbox nobody\n // is draining any more. Exactly a no-op when no journal is configured.\n const journalTailSettled = journal ? await attempt(() => journalTerminalTail, true) : true;\n // stop() cleared the maintenance timer synchronously above. Await the pass\n // that may already have been inside SQLite only here, immediately before\n // closing the owned journal, so task interruption is not held behind a\n // slow checkpoint while the journal-close race remains impossible.\n const maintenanceSettled = await attempt(() => maintenanceStopped, true);\n // Finding F5(b): bounded wait for the outbox (e.g. the task.fail(s)\n // shutdownActiveTasks just enqueued) to actually drain before closing\n // the connection out from under it — see ConnectionManager.stop's own\n // doc comment for why an unbounded wait wasn't safe to make the\n // universal default, and ConnectionManager.outboxLength's own doc\n // comment for the honest-audit read a caller may take afterward.\n const drainTimeoutMs =\n opts.drainTimeoutMs ?? overrides.shutdown?.outboxDrainTimeoutMs ?? DEFAULT_SHUTDOWN_OUTBOX_DRAIN_TIMEOUT_MS;\n const connectionStopped = await attempt(() => connection?.stop(drainTimeoutMs), true);\n // Close the owned journal only after every producer has stopped: active\n // task teardown and its terminal tail settled, maintenance settled, and\n // the connection can no longer deliver a new inbound envelope. Closing it\n // earlier would let a failed/slow connection shutdown append into a closed\n // database after this function released the store lease.\n if (activeTeardownSettled && journalTailSettled && maintenanceSettled && connectionStopped) {\n const journalClosed = await attempt(() => stoppingOwnedJournal?.close(), true);\n if (journalClosed) {\n if (journal === stoppingOwnedJournal) journal = undefined;\n if (ownedJournal === stoppingOwnedJournal) ownedJournal = undefined;\n if (pressureEngine === stoppingOwnedPressureEngine) pressureEngine = undefined;\n if (ownedPressureEngine === stoppingOwnedPressureEngine) ownedPressureEngine = undefined;\n }\n } else if (stoppingOwnedJournal) {\n mutationBarrierComplete = false;\n }\n await attempt(() => auth.stop(), true);\n connectionState = 'closed';\n // M4 Phase 2: stop the control socket in every shutdown path — this is\n // the single lifecycle choke point every caller (a foreground abort via\n // `bin/commands/start.ts`, `unpair()` below, and the control socket's\n // OWN `shutdown` RPC — see `performControlShutdown`) already funnels\n // through, so nothing else needs its own control-socket teardown logic.\n await attempt(async () => {\n await controlServerHandle?.close();\n controlServerHandle = undefined;\n }, true);\n if (mutationBarrierComplete && daemonOwnerLease) {\n await attempt(() => operationalHealth.markCleanStop(), false);\n await attempt(async () => {\n await daemonOwnerLease?.release();\n daemonOwnerLease = undefined;\n }, false);\n }\n if (errors.length === 1) throw errors[0];\n if (errors.length > 1) {\n throw new AggregateError(errors, 'daemon shutdown completed with errors');\n }\n if (!mutationBarrierComplete) {\n // Defensive invariant: every mutation-barrier failure is recorded above.\n // Keep the lease if that invariant is ever violated rather than allowing\n // doctor or a second daemon to overlap a residual writer.\n throw new Error('daemon shutdown mutation barrier is incomplete; ownership lease retained');\n }\n }\n\n /**\n * Public `Daemon.stop()` (also `unpair()`'s own teardown, below) — see\n * `runShutdownSequence`'s own doc comment for the sequence this now runs.\n * `opts` is an internal-only extension of the public `stop(): Promise<void>`\n * interface (this file already has the analogous `performControlShutdown`\n * convention of calling this closure directly with extra options a plain\n * `Daemon.stop()` caller never needs to pass): `performControlShutdown`\n * below supplies its own `reason` instead of this default.\n */\n async function stop(opts: { drainTimeoutMs?: number; reason?: string } = {}): Promise<void> {\n await requestShutdown(opts.reason ?? 'operator', { drainTimeoutMs: opts.drainTimeoutMs });\n }\n\n function requestShutdown(reason: string, opts: { drainTimeoutMs?: number } = {}): Promise<void> {\n if (shutdownPromise) return shutdownPromise;\n const current = runLifecycleMutation(() => runShutdownSequence(reason, opts));\n shutdownPromise = current;\n void current.finally(() => {\n if (shutdownPromise === current) shutdownPromise = undefined;\n }).catch(() => undefined);\n return current;\n }\n\n /**\n * M3-2a: clears this device's persisted identity and disconnects. Safe at\n * any point in the lifecycle:\n * - `stop()` is a no-op beyond clearing state if `start()` was never\n * called (`connection` stays `undefined`; `auth.stop()` on a\n * never-renewed `AuthManager` just no-ops its unset timer).\n * - `store.clear()` (`fs.rm(..., { force: true })`) is a no-op if this\n * device was never paired.\n * Reads the on-disk record BEFORE clearing (mirrors `pair()`'s own F5\n * pattern above) so the cursor hygiene cleanup below knows which device's\n * entry to remove; rebuilding `auth` (see `buildAuthManager`) is what\n * actually makes the NEXT `start()` require a fresh `pair()` — clearing\n * `store` alone would leave a same-process `AuthManager`'s cached\n * in-memory record still usable.\n */\n async function unpair(): Promise<void> {\n await runLifecycleMutation(unpairUnderLease);\n }\n\n async function unpairUnderLease(): Promise<void> {\n // The outer lifecycle slot prevents pair/start/control shutdown from\n // entering while teardown and destructive credential cleanup span two\n // cross-process lease acquisitions.\n await runShutdownSequence('operator');\n // stop() releases only after every daemon writer settles. Reacquire before\n // destructive identity cleanup; if another daemon won the gap, fail\n // closed rather than clearing state under it.\n const cleanupLease = await acquireDaemonOwner(storeDir, 'daemon');\n try {\n // The identity being removed is read under the same lease as both the\n // device and cursor mutations. A pair that wins stop()'s release gap is\n // therefore either wholly before this cleanup (and is fully removed) or\n // wholly after it; stale pre-lease identity can never drive cleanup.\n const current = await store.remove();\n if (current) {\n await cursorStore.clear(config.serverUrl, current.deviceId);\n }\n } finally {\n await cleanupLease.release();\n }\n auth = buildAuthManager();\n observer.noteUnpaired();\n }\n\n /**\n * M3-2a: local approve/reject — see the `Daemon` interface's own doc\n * comments on {@link Daemon.approve}/{@link Daemon.reject} for the full\n * rationale (honest-but-currently-unexercised; every bundled adapter's\n * `resolveApproval` throws unconditionally today). Constructs the exact\n * envelope shape a server-sent `task.approve`/`task.reject` would be and\n * feeds it straight to `runner.handleEnvelope` — `TaskRunner`'s only public\n * entry point — rather than reaching into its private `handleApprove`/\n * `handleReject`. `seq: 0` is an inert local sentinel: this call never\n * passes through `ConnectionManager`, so nothing ever reads it as a real\n * redelivery cursor value, and `TaskRunner` itself only ever reads\n * `task_id`/`payload` off an approve/reject envelope, never `seq`.\n */\n async function approve(taskId: string): Promise<void> {\n if (!runner) throw new Error('daemon is not started; call start() first');\n await runner.handleEnvelope(createEnvelope('task.approve', {}, { taskId, seq: 0 }));\n }\n\n async function reject(taskId: string, reason?: string): Promise<void> {\n if (!runner) throw new Error('daemon is not started; call start() first');\n await runner.handleEnvelope(createEnvelope('task.reject', { reason }, { taskId, seq: 0 }));\n }\n\n // -------------------------------------------------------------------------\n // M4 Phase 2: control socket method registry (`control-server.ts` is\n // daemon-agnostic; this is the glue that closes over THIS daemon\n // instance's own state). Built once; every handler below reads `runner`/\n // `connection`/`connectionState`/`auth` fresh at CALL time via normal JS\n // closure semantics, so it stays correct across this daemon's own\n // start()/stop() cycles.\n // -------------------------------------------------------------------------\n\n function buildControlStatus(): ControlStatusResult {\n const snapshot = pressureEngine?.snapshot();\n const storageStatus: ControlStorageStatus | undefined =\n snapshot === undefined\n ? undefined\n : {\n pressureState: snapshot.state,\n budgetBytes: snapshot.budgetBytes,\n usedBytes: snapshot.usedBytes,\n freeBytes: snapshot.freeBytes,\n measuredAt: snapshot.measuredAt,\n categories: (Object.keys(snapshot.categories) as StorageCategory[])\n .sort()\n .map((category) => ({\n category,\n bytes: snapshot.categories[category].bytes,\n approximate: snapshot.categories[category].approximate,\n })),\n ...(snapshot.lastCompaction\n ? {\n lastCompaction: {\n checkpointed: snapshot.lastCompaction.checkpointed,\n walFramesRemaining: snapshot.lastCompaction.walFramesRemaining,\n pagesVacuumed: snapshot.lastCompaction.pagesVacuumed,\n durationMs: snapshot.lastCompaction.durationMs,\n at: snapshot.lastCompaction.at,\n },\n }\n : {}),\n };\n const activeTasks: ControlActiveTask[] = observer\n .tasks()\n .filter((task) => TASK_TRANSITIONS[task.state].length > 0) // non-terminal only — see the `status` method's own doc comment (control-protocol.ts)\n .map((task) => ({ taskId: task.taskId, state: task.state }));\n // Finding F4: computed once and reused for both `approvals` (the actual\n // entries, so `status`'s live section can render approvalIds without a\n // second control-socket round trip) and `approvalsPending` (the same\n // list's count) — same source `approvals.list` itself calls.\n const pendingApprovals = approvalRegistry.list();\n return {\n pid: process.pid,\n uptimeMs: startedAt !== undefined ? Date.now() - startedAt : 0,\n paired: auth.deviceId !== undefined,\n deviceId: auth.deviceId,\n transport: connectionState,\n activeTasks,\n runtimeIds: adapters.map((adapter) => adapter.id),\n // M4 Phase 4 (part B.3): queue watermarks come from TaskRunner's own\n // active-task map (distinct from `observer.tasks()` above, which is\n // derived from the envelope feed) — see `TaskRunner.getQueueWatermarks`'s\n // own doc comment for why this is a progress-batcher-backlog +\n // in-flight-approval-count proxy rather than the adapter's own event\n // queue depth.\n queueWatermarks: runner?.getQueueWatermarks() ?? [],\n approvals: pendingApprovals,\n approvalsPending: pendingApprovals.length,\n // S3b (L-003): the storage section, present only when a policy is\n // configured AND a measurement has actually happened. An engine that has\n // never ticked reports nothing rather than a zeroed snapshot — \"not\n // measured\" and \"measured, and empty\" are different facts, and a status\n // surface that conflates them is how an operator concludes a full disk is\n // fine.\n ...(storageStatus === undefined ? {} : { storage: storageStatus }),\n operationalHealth: operationalHealth.snapshot(),\n };\n }\n\n /**\n * The control socket's `shutdown` RPC — see this method's own protocol\n * doc comment (`control-protocol.ts`'s `ShutdownParams`) for the wire\n * contract. M5 batch-3 (workstream 2): delegates the actual teardown\n * sequence to `runShutdownSequence` — see that function's own doc comment\n * for the full \"stop accepting -> fail active tasks -> drain -> close\"\n * sequence every graceful-shutdown path now shares — and wraps it with\n * this RPC's own audit events. Invoked from the RPC handler via\n * `setImmediate` (see `controlMethods` below) so the `{acknowledged:true}`\n * response has already been written to the wire before any of this runs.\n *\n * Gatekeeper-confirmed regression (fixed pre-M5; PRESERVED, not\n * reintroduced, by this refactor): `noteShutdownRequested` fires\n * SYNCHRONOUSLY, before `shutdownActiveTasks` even calls\n * `session.interrupt()` — `observer.emit()` calls its listeners\n * synchronously, so `bin/commands/start.ts`'s subscriber used to be woken\n * IMMEDIATELY, race ahead, and call `daemon.stop()` (which sets\n * `ConnectionManager.stopped = true` synchronously) before the active\n * task's `task.fail` was ever sent — silently stranding it in a\n * post-`stopped` outbox that `drainOutbox` refuses to flush. Fixed by\n * emitting a SEPARATE, later `shutdown-complete` event only once\n * `runShutdownSequence` below has fully resolved — `start.ts` now waits\n * for that one instead, so it can never race ahead of this function's own\n * internal ordering. `shutdown-requested` is kept as an earlier,\n * informational-only audit marker; nothing may gate teardown decisions on\n * it. The ordering itself (stopAcceptingOffers -> shutdownActiveTasks ->\n * THEN connection teardown) now lives inside `runShutdownSequence` rather\n * than duplicated in this function's own body, but the observable\n * guarantee `start.ts` depends on — `shutdown-complete` fires only after\n * every active task's `task.fail` has actually been enqueued and the\n * connection has begun closing — is unchanged.\n */\n async function performControlShutdown(reason: ShutdownReason | undefined): Promise<void> {\n const effectiveReason = reason ?? 'operator';\n observer.noteShutdownRequested(effectiveReason);\n // Hardening finding (P2 re-gate): `noteShutdownComplete` now fires in a\n // `finally` — `start.ts`'s own wait for THIS event (see the doc comment\n // above) is what makes `runStartCommand` return at all. Before this fix,\n // a throw anywhere in the body below (every step `runShutdownSequence`\n // takes is best-effort in its OWN implementation today, but nothing here\n // guaranteed one of them could never throw in the future) would\n // propagate out of this function without ever emitting\n // `shutdown-complete`, leaving `start.ts` waiting forever — exactly the\n // class of hang this event was introduced to prevent in the first\n // place. `finally` runs on both the success path and any throw, and does\n // not swallow the throw itself (it still propagates to this function's\n // own caller — the `shutdown` control method's `.catch()` in\n // `controlMethods` below — afterward).\n try {\n await requestShutdown(`control socket shutdown (${effectiveReason})`);\n } finally {\n // Finding F5(b): read AFTER runShutdownSequence() returns — 0 means\n // the drain genuinely finished in time; a positive count is an honest\n // record that this many envelopes (almost certainly including a\n // task.fail shutdownActiveTasks just sent) never actually left the\n // outbox, rather than the audit log silently implying full delivery.\n observer.noteShutdownComplete(effectiveReason, connection?.outboxLength() ?? 0);\n }\n }\n\n const controlMethods: ControlMethods = {\n unary: {\n status: () => buildControlStatus(),\n 'approvals.list': () => ({ approvals: approvalRegistry.list() }),\n 'approvals.resolve': (params) => {\n const parsed = parseApprovalsResolveParams(params);\n if (!parsed) throw new ControlError('bad_request', 'approvals.resolve requires {approvalId, decision}');\n try {\n approvalRegistry.resolve(parsed.approvalId, parsed.decision, parsed.reason);\n } catch (err) {\n if (err instanceof ApprovalNotFoundError) throw new ControlError('not_found', err.message);\n throw err;\n }\n return { resolved: true };\n },\n // M4 Phase 3: called by `bin/byok-approval-mcp.ts` — a claude-spawned\n // MCP-server child process, not this daemon's own adapter/session\n // in-process (see `types.ts`'s `ApprovalChannel` doc comment). Awaits\n // `TaskRunner.requestApproval`'s own returned promise directly, which\n // is exactly what lets this control call stay pending for as long as\n // `approvalTimeoutMs` allows (`control-server.ts`'s unary dispatch has\n // no timeout of its own — see its `dispatch()`) — the caller's own\n // `requestTimeoutMs` (`bin/control-client.ts`) must be configured\n // longer than that for the same reason.\n 'approvals.request': (params) => {\n const parsed = parseApprovalsRequestParams(params);\n if (!parsed) throw new ControlError('bad_request', 'approvals.request requires {taskId, summary}');\n if (!runner) throw new ControlError('not_found', 'daemon is not started');\n return runner.requestApproval(parsed.taskId, parsed.summary);\n },\n shutdown: (params) => {\n const { reason } = parseShutdownParams(params);\n // Fire-and-forget, deliberately AFTER this handler's own return\n // value has been serialized and written to the socket (see\n // `control-server.ts`'s dispatch: it awaits this handler, THEN\n // writes the response) — `setImmediate` schedules the teardown for\n // the next macrotask tick, strictly after that write.\n setImmediate(() => {\n void performControlShutdown(reason).catch((err: unknown) => {\n console.error('[byok/client] error during control-socket shutdown teardown:', err);\n });\n });\n return { acknowledged: true };\n },\n },\n stream: {\n 'tasks.subscribe': (_params, ctx) =>\n new Promise<void>((resolve) => {\n const unsubscribeObserver = observer.subscribe((event) => ctx.emit(event));\n ctx.signal.addEventListener(\n 'abort',\n () => {\n unsubscribeObserver();\n resolve();\n },\n { once: true },\n );\n }),\n },\n };\n\n function subscribe(listener: DaemonEventListener): Unsubscribe {\n return observer.subscribe(listener);\n }\n\n function tasks(): DaemonTaskInfo[] {\n return observer.tasks();\n }\n\n function status(): DaemonStatus {\n return {\n paired: auth.deviceId !== undefined,\n connected: connectionState === 'open',\n degraded: connection?.isTransportDegraded() ?? false,\n revoked: connection?.isRevoked() ?? auth.isRevoked(),\n deviceId: auth.deviceId,\n activeTaskCount: runner?.activeTaskCount ?? 0,\n branding: config.branding,\n operationalHealth: operationalHealth.snapshot(),\n };\n }\n\n return { pair, start, stop, status, subscribe, tasks, unpair, approve, reject };\n}\n\n/**\n * Public white-label entry point (M0-M3): the \"5-line launcher\" — a product\n * only needs a `DaemonConfig`, no hand-built adapter list. The bundled\n * adapter set is built from `config.runtimeAllowlist` (see\n * `buildDefaultAdapters` and that field's own doc comment for the exact\n * unset-vs-set contract); with no `runtimeAllowlist` configured, the default\n * is ALL THREE bundled adapters (pi, claude, codex), not pi alone: M0/M1\n * hard-wired pi-only unconditionally, which meant any product wanting\n * claude/codex had to drop to `createDaemonWithAdapters` and hand-build\n * adapters just to get a runtime that was already built into this SDK.\n * `detectRuntimes` only ever advertises what's actually present on the\n * device (protocol §10 gap #4), so constructing an adapter for a runtime the\n * device doesn't have costs one quick failed `--version` probe at `start()`\n * and is otherwise invisible — there's no reason to withhold it by default.\n * Products that DO want to restrict to a subset set `runtimeAllowlist`\n * (also independently enforced at task-pick time — see\n * `TaskRunnerDeps.runtimeAllowlist` / `TaskRunner.pickAdapter`); products\n * needing something this can't build (custom adapter options, a fourth\n * in-house runtime, test stubs) use `createDaemonWithAdapters` directly.\n */\nexport function createDaemon(config: DaemonConfig): Daemon {\n return createDaemonWithAdapters(config, buildDefaultAdapters(config.runtimeAllowlist));\n}\n","/**\n * What the OS service manager should actually execute to run the daemon in\n * the background. Deliberately requires an explicit `command` (an absolute\n * path is strongly recommended, not just a bare command name) rather than\n * ever trying to auto-resolve one internally — see\n * `create-service-lifecycle.ts`'s module doc comment for why. A bare\n * command name relies on the OS service manager's own minimal PATH, which\n * commonly does NOT include nvm/volta/homebrew node install directories —\n * a frequent real-world \"service can't find node\" bug on every one of the\n * three platforms this module supports.\n */\nexport interface ServiceProgram {\n command: string;\n /**\n * Args passed verbatim to `command` — e.g. `[agentBinPath, 'start',\n * '--config', configPath]` for a plain node + script run (see\n * {@link nodeAgentProgram}), or `['start', '--config', configPath]` alone\n * if `command` is already a self-contained bundled binary (see\n * `templates/packaging/`). Every platform generator passes these through\n * untouched — `winsw.ts` emits one `<argument>` element per entry rather\n * than a single shell-quoted string specifically so a path containing\n * spaces never needs manual escaping (see that file's doc comment).\n */\n args: string[];\n /** Working directory for the running service process. Each platform generator has its own documented default (see `launchd.ts`/`systemd.ts`/`winsw.ts`) when omitted. */\n cwd?: string;\n}\n\nexport interface NodeAgentProgramOptions {\n /** Absolute path to the `byok-agent` entry script to run. No auto-detection — see `create-service-lifecycle.ts`'s doc comment. */\n agentBin: string;\n /** Absolute path to the JSON config file `byok-agent start` should load — resolve this to an absolute path BEFORE calling, since the service will run with the OS service manager's own cwd, not the caller's. */\n configPath: string;\n /** Node executable to invoke `agentBin` with. Defaults to `process.execPath` (the currently running node) — always an absolute, real path, unlike a bare `node` on PATH. */\n nodeBin?: string;\n cwd?: string;\n}\n\n/**\n * Convenience builder for the common case: run `node <agentBin> start\n * --config <configPath>` as the service's program. Still requires the\n * caller to supply an absolute `agentBin` — this helper is a formatting\n * convenience only, not a resolution mechanism.\n */\nexport function nodeAgentProgram(opts: NodeAgentProgramOptions): ServiceProgram {\n const program: ServiceProgram = {\n command: opts.nodeBin ?? process.execPath,\n args: [opts.agentBin, 'start', '--config', opts.configPath],\n };\n if (opts.cwd !== undefined) program.cwd = opts.cwd;\n return program;\n}\n\nexport interface ServiceDefinition {\n /** Stable service identifier — becomes the launchd `Label`, the systemd unit's basename, and the WinSW `<id>` (sanitized per-platform via {@link sanitizeServiceName}). Typically `DaemonConfig.productId`. */\n name: string;\n /** Human-readable display name — systemd `Description=`, WinSW `<name>`/`<description>`. Defaults to `name` if omitted. */\n displayName?: string;\n /** What to run — see {@link ServiceProgram}. */\n program: ServiceProgram;\n /** Directory the service's stdout/stderr logs are written under (created if missing). On Windows this also doubles as the default WinSW install directory — see `windows.installDir`. */\n logDir: string;\n /**\n * Windows/WinSW-only inputs. Required when actually constructing a\n * lifecycle on `win32` (`create-service-lifecycle.ts` throws a clear\n * error otherwise); ignored on macOS/Linux.\n */\n windows?: {\n /**\n * Absolute path to the product-bundled WinSW executable. Decision-6\n * boundary: this SDK never bundles or downloads this binary itself —\n * see `templates/service/winsw/README.md`. The lifecycle copies it\n * into `installDir` under this service's own name (WinSW's own\n * convention: the exe and its XML config must share a basename).\n */\n winswBin: string;\n /** Directory the renamed WinSW exe + generated XML are installed into. Defaults to `logDir`. */\n installDir?: string;\n };\n}\n\n/** Options for {@link ServiceLifecycle.install} — an escape hatch for the rare case of reinstalling with a changed program (e.g. after an upgrade moved the agent binary) without reconstructing the whole lifecycle object. Omit to reuse the program given to `createServiceLifecycle`. */\nexport interface ServiceInstallOptions {\n program?: ServiceProgram;\n}\n\nexport interface ServiceStatusResult {\n /** Whether the platform's own service manager has this service registered at all (a plist/unit/WinSW-config file present — checked directly, not inferred from `running`). */\n installed: boolean;\n /** Whether it's currently running, per the platform's own authoritative query (`launchctl print`, `systemctl --user is-active`, `sc.exe query`) — never a locally-cached guess. `false` here means \"confirmed not running\" ONLY when `determinate` is also `true` — see that field's own doc comment. */\n running: boolean;\n /**\n * Finding P1 #2 (residual, round 3): whether `running`/`installed` above\n * were actually CONFIRMED by a clean query, as opposed to a fallback\n * because the platform's own service-manager tool could not be asked at\n * all. `run()` (`exec-runner.ts`'s `Runner`) resolves an ordinary\n * non-throwing `RunResult` for a bus-connect failure, an unreachable\n * launchd GUI domain, or a permission-denied query — the SAME shape a\n * genuine \"not running\" query returns — so without this field, a caller\n * receiving `running: false` could not tell \"the manager confirms it's\n * not running\" apart from \"the manager could not even be asked\" (both\n * silently collapsed into the same boolean). Concretely:\n *\n * - `true`: either an authoritative \"running\"/\"active\" match, or a query\n * that resolved with a KNOWN clean \"not running\"/\"not loaded\"/\"not\n * found\" result.\n * - `false`: the query itself could not be answered — a\n * connectivity/permission/manager-unreachable failure (each platform\n * classifies this with the SAME `neverAbsence`-style pattern list its\n * `uninstall()`/`stop()` already use for the identical reason — see\n * `systemd.ts`/`launchd.ts`/`winsw.ts`'s own\n * `*_CONNECTIVITY_OR_PERMISSION_FAILURE` constants). `running: false`\n * in this case is a FALLBACK, not a confirmed fact.\n *\n * Callers that must not fail open on an unreachable manager (see\n * `bin/commands/unpair.ts`'s `checkServiceState`) must treat\n * `determinate: false` exactly the same as a thrown `status()` call.\n */\n determinate: boolean;\n /** Raw human-readable output from the underlying platform tool, for the `service-status` CLI subcommand and debugging. Never parsed further than the booleans above. */\n detail: string;\n}\n\n/**\n * The lifecycle API M3-4 asks for: `install(opts) / uninstall() / start() /\n * stop() / status()`. Every method but `install` is deliberately\n * parameterless — the service's identity/program/logDir are already fixed\n * at `createServiceLifecycle(definition, ...)` construction time (mirrors\n * `createDaemon(config)`'s own \"5-line launcher\" shape), so `uninstall`/\n * `start`/`stop`/`status` always act on that one already-known service.\n *\n * Crash-restart is ALWAYS delegated to the OS supervisor (launchd\n * `KeepAlive`, systemd `Restart=on-failure`, WinSW `<onfailure>`) — no\n * implementation of this interface runs an in-process supervisor loop of\n * its own.\n *\n * Idempotency convention shared by every platform implementation: `install`\n * and `start` hard-fail (throw) if the final \"make it actually running\"\n * step fails, since silently doing nothing there would misreport success.\n * `stop` is best-effort/tolerant ONLY of a KNOWN idempotent \"already\n * stopped\"/\"not loaded\"/\"not installed\" result (mirrors `Daemon.unpair()`'s\n * own \"safe to call at any point in the lifecycle\" convention in\n * `daemon/create-daemon.ts` for that idempotent case) — a genuine failure\n * (permission denied, manager unreachable, the exe locked/busy) is thrown\n * instead of being misreported as \"stopped\", using the same precise\n * classifier `uninstall` uses (cross-model-review P1 #7, round 2, second\n * half: silently swallowing a real `stop()` failure undermines the operator's\n * ability to trust \"stopped\" at all). `uninstall` is tolerant ONLY of a\n * KNOWN idempotent \"not loaded\"/\"does not exist\"/\"already absent\" result\n * from its stop+unregister step (see `exec-runner.ts`'s\n * `isIdempotentAbsence`) — a genuine failure (permission denied, service\n * busy, manager error, manager UNREACHABLE — e.g. no reachable systemd\n * `--user` D-Bus session or launchd GUI domain for this uid, textually\n * indistinguishable from \"already absent\" unless explicitly excluded, see\n * `exec-runner.ts`'s `IdempotentAbsence.neverAbsence`) is thrown instead,\n * and the plist/unit/winsw exe+xml are deliberately left in place, so a\n * still-running service never loses its control files and becomes an\n * orphan nobody can stop/uninstall (cross-model-review P1 #7).\n */\nexport interface ServiceLifecycle {\n /** Writes the platform service definition and registers + starts it with the OS service manager. Safe to call again later (e.g. after an upgrade): overwrites the definition and reloads it. */\n install(opts?: ServiceInstallOptions): Promise<void>;\n /** Stops (if running) and fully removes the service registration + generated definition file. Safe to call when not installed. Throws — and leaves the control file in place — if the underlying service manager reports a genuine failure rather than success/\"not installed\"; see this interface's own doc comment. */\n uninstall(): Promise<void>;\n /** Starts an already-installed service. Throws a clear error if it isn't installed. */\n start(): Promise<void>;\n /** Stops a running service without uninstalling it. Safe to call when already stopped (or not installed/not loaded). Throws if the underlying service manager reports a genuine failure instead (e.g. permission denied, manager unreachable) rather than silently reporting success; see this interface's own doc comment. */\n stop(): Promise<void>;\n /** Current installed/running state, queried fresh from the platform's own service manager. */\n status(): Promise<ServiceStatusResult>;\n}\n\n/**\n * Sanitizes a free-form product/service identifier into something safe to\n * embed in a launchd `Label`, a systemd unit filename, and a WinSW `<id>`\n * (which doubles as a Windows service name AND a generated filename) — the\n * intersection of all three platforms' safe-identifier rules is\n * \"letters, digits, `.`, `-`, `_`\". Anything outside that set collapses to\n * `-`. A LEADING `-` is then stripped even though `-` is itself an allowed\n * character: `systemctl`'s argument parser (and, generally, any\n * getopt-style CLI) mistakes a bare positional argument starting with `-`\n * for an option rather than the service/unit name — e.g. `systemctl --user\n * enable --now -foo.service` — which would otherwise misparse every one of\n * `launchd.ts`/`systemd.ts`/`winsw.ts`'s own `run()` calls that pass this\n * sanitized name straight through as a CLI argument (cross-model-review P1\n * #8). Called independently by each platform module (not once centrally) so\n * every one of `launchd.ts`/`systemd.ts`/`winsw.ts` stays correct even when\n * used directly, without going through `createServiceLifecycle`'s\n * dispatcher.\n */\nexport function sanitizeServiceName(name: string): string {\n const cleaned = name.trim().replace(/[^A-Za-z0-9._-]+/g, '-');\n const safe = cleaned.replace(/^-+/, '');\n if (!safe) {\n throw new Error(`service name \"${name}\" has no valid characters left after sanitizing (allowed: letters, digits, \".\", \"-\", \"_\"; cannot consist only of leading \"-\")`);\n }\n return safe;\n}\n","import { promises as fsp } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { defaultRunner, runIdempotent, runOrThrow, type IdempotentAbsence, type Runner } from './exec-runner';\nimport { sanitizeServiceName, type ServiceDefinition, type ServiceInstallOptions, type ServiceLifecycle, type ServiceProgram, type ServiceStatusResult } from './service-types';\n\n/**\n * Genuine-failure text that must NEVER be reclassified as \"job already\n * absent\", checked before `LAUNCHD_NOT_LOADED`'s own `patterns` (see\n * `exec-runner.ts`'s `IdempotentAbsence.neverAbsence`). Both verified\n * directly against real `launchctl` output on macOS (Darwin 25.5.0):\n * `launchctl bootout system/<id>` as a non-root user → `Boot-out failed: 1:\n * Operation not permitted` (a real permission failure); `launchctl bootout\n * gui/1/<id>` (uid 1 has no active GUI session — the same \"headless box\"\n * shape as systemd's missing `--user` D-Bus session) → `Could not find\n * domain for user gui: 1`, exit 112 — launchd cannot even ask whether the\n * job is loaded, which is a REAL failure to surface, not evidence it's\n * absent (cross-model-review P1 #7, round 2 — the same re-orphan shape as\n * the systemd bus failure, for launchd).\n */\nconst LAUNCHD_CONNECTIVITY_OR_PERMISSION_FAILURE: readonly RegExp[] = [\n /operation not permitted/i,\n /could not find domain/i,\n /permission denied/i,\n /access denied/i,\n];\n\n/**\n * What `launchctl bootout`/`launchctl stop` prints/exits with when there was\n * nothing loaded to boot out — as opposed to a genuine failure (permission\n * denied, an unreachable GUI domain, launchd itself misbehaving), which must\n * be surfaced rather than treated the same way (see `uninstall()`/`stop()`\n * below and cross-model-review P1 #7). `/no such process/i` is verified\n * directly against real `launchctl bootout` output for a job that was never\n * loaded (`Boot-out failed: 3: No such process`, exit 3).\n *\n * Deliberately does NOT include a bare \"domain...not found/does not exist\"\n * pattern (present in an earlier version of this fix): it never matched any\n * verified real \"not loaded\" output, and an unreachable/nonexistent GUI\n * domain is exactly the genuine-failure shape `LAUNCHD_CONNECTIVITY_OR_PERMISSION_FAILURE`\n * above exists to catch, not evidence of absence.\n */\nconst LAUNCHD_NOT_LOADED: IdempotentAbsence = {\n patterns: [/no such process/i, /could not find (specified )?service/i, /not loaded/i],\n neverAbsence: LAUNCHD_CONNECTIVITY_OR_PERMISSION_FAILURE,\n};\n\n/** DI seam for tests — see `exec-runner.ts`'s `Runner` doc comment for why a mocked `run` is enough to unit-test all of this file's install/uninstall/start/stop/status logic on any host OS. */\nexport interface LaunchdDeps {\n run?: Runner;\n fs?: Pick<typeof fsp, 'mkdir' | 'writeFile' | 'rm' | 'stat'>;\n homedir?: () => string;\n /** Defaults to `process.getuid` — macOS/Linux only; this module is never constructed on `win32` (see `create-service-lifecycle.ts`). */\n getuid?: () => number;\n}\n\nfunction escapeXml(value: string): string {\n return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;').replace(/'/g, '&apos;');\n}\n\nfunction plistString(value: string): string {\n return `<string>${escapeXml(value)}</string>`;\n}\n\n/**\n * Generates a launchd LaunchAgent plist for `label` running `program`,\n * logging to `logDir`. Pure/no I/O — unit-tested directly for exact content\n * shape.\n *\n * - `RunAtLoad`: true — starts immediately on `launchctl bootstrap`.\n * - `KeepAlive.SuccessfulExit: false` — the standard, widely-documented\n * launchd idiom for \"restart only on crash/non-zero-or-signaled exit, do\n * NOT restart after a clean `exit(0)`\". This is the crash-restart M3-4\n * asks for, delegated entirely to launchd — nothing in this SDK\n * supervises the process itself.\n * - `ThrottleInterval: 10` — matches the WinSW recipe's `onfailure delay=\"10\n * sec\"` (see `winsw.ts`) so a crash-looping process backs off at a\n * comparable rate on every platform, rather than launchd's own default\n * (which is already 10s, but left implicit is easy to mistake for\n * \"unthrottled\").\n * - `StandardOutPath`/`StandardErrorPath` under `logDir` — this is what M3-4\n * asks for explicitly (\"StandardOut/Error paths under storeDir\"), unlike\n * `systemd.ts`'s unit (which ALSO writes append-mode log files under\n * `logDir` for cross-platform parity, even though systemd's own native\n * idiom is the journal).\n */\nexport function generateLaunchdPlist(def: { label: string; program: ServiceProgram; logDir: string }): string {\n const { label, program, logDir } = def;\n const args = [program.command, ...program.args];\n const cwd = program.cwd ?? os.homedir();\n const outLog = path.join(logDir, `${label}.out.log`);\n const errLog = path.join(logDir, `${label}.err.log`);\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n ${plistString(label)}\n <key>ProgramArguments</key>\n <array>\n${args.map((a) => ` ${plistString(a)}`).join('\\n')}\n </array>\n <key>WorkingDirectory</key>\n ${plistString(cwd)}\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <dict>\n <key>SuccessfulExit</key>\n <false/>\n </dict>\n <key>ThrottleInterval</key>\n <integer>10</integer>\n <key>StandardOutPath</key>\n ${plistString(outLog)}\n <key>StandardErrorPath</key>\n ${plistString(errLog)}\n</dict>\n</plist>\n`;\n}\n\n/**\n * macOS LaunchAgent lifecycle, built on the modern `launchctl` subcommand\n * interface (`bootstrap`/`bootout`/`enable`/`kickstart`/`print`, targeting\n * `gui/<uid>` — the per-user GUI domain LaunchAgents run in — rather than\n * the legacy `load`/`unload`/`start`/`stop`).\n *\n * `start`/`stop` mapping (a real nuance worth documenting, not an arbitrary\n * choice): `KeepAlive` means a plain signal-kill (`launchctl kill`) would\n * just have launchd immediately restart the job — that's the crash-restart\n * feature working exactly as designed, but it means \"kill\" can't implement\n * a genuine \"stop\" on its own. `bootout` (fully unloading the job from the\n * domain) is the only primitive that stops it without KeepAlive fighting\n * back, so `stop()` = `bootout` and `start()` = `bootstrap` again (reload\n * from the still-on-disk plist) — not `kickstart`, which only force-restarts\n * an ALREADY-loaded job.\n */\nexport function createLaunchdLifecycle(def: ServiceDefinition, deps: LaunchdDeps = {}): ServiceLifecycle {\n const run = deps.run ?? defaultRunner;\n const fs = deps.fs ?? fsp;\n const homedir = deps.homedir ?? (() => os.homedir());\n const getuid =\n deps.getuid ??\n (() => {\n if (typeof process.getuid !== 'function') {\n throw new Error('launchd lifecycle requires a POSIX uid (process.getuid unavailable) — this module only runs on macOS');\n }\n return process.getuid();\n });\n\n const label = sanitizeServiceName(def.name);\n const plistPath = () => path.join(homedir(), 'Library', 'LaunchAgents', `${label}.plist`);\n const domainTarget = () => `gui/${getuid()}`;\n const serviceTarget = () => `${domainTarget()}/${label}`;\n\n async function fileExists(p: string): Promise<boolean> {\n try {\n await fs.stat(p);\n return true;\n } catch {\n return false;\n }\n }\n\n async function writePlist(program: ServiceProgram): Promise<void> {\n const xml = generateLaunchdPlist({ label, program, logDir: def.logDir });\n await fs.mkdir(path.dirname(plistPath()), { recursive: true });\n await fs.mkdir(def.logDir, { recursive: true });\n await fs.writeFile(plistPath(), xml, 'utf8');\n }\n\n async function install(opts: ServiceInstallOptions = {}): Promise<void> {\n await writePlist(opts.program ?? def.program);\n // Best-effort: clear any stale prior load first (e.g. a re-install)\n // — \"not currently loaded\" is an expected, ignorable outcome, not a\n // real failure (see `exec-runner.ts`'s `RunResult` doc comment).\n await run('launchctl', ['bootout', serviceTarget()]);\n await runOrThrow(run, 'launchctl', ['bootstrap', domainTarget(), plistPath()], 'launchctl bootstrap');\n await runOrThrow(run, 'launchctl', ['enable', serviceTarget()], 'launchctl enable');\n // RunAtLoad already starts it on bootstrap; kickstart -k guarantees a\n // fresh start even if bootstrap raced with a leftover instance.\n // Best-effort: RunAtLoad is the load-bearing guarantee here.\n await run('launchctl', ['kickstart', '-k', serviceTarget()]);\n }\n\n async function uninstall(): Promise<void> {\n // Tolerant of \"wasn't loaded\" (fine — nothing to stop/unregister), but a\n // REAL failure (permission denied, launchd itself misbehaving) must NOT\n // be masked: only delete the plist once we know the job is actually\n // gone from the domain, so a still-running job never loses its control\n // file and becomes an orphan nobody can stop/uninstall\n // (cross-model-review P1 #7).\n await runIdempotent(run, 'launchctl', ['bootout', serviceTarget()], 'launchctl bootout', LAUNCHD_NOT_LOADED);\n await fs.rm(plistPath(), { force: true });\n }\n\n async function start(): Promise<void> {\n if (!(await fileExists(plistPath()))) {\n throw new Error(`service \"${label}\" is not installed (no plist at ${plistPath()}) — call install() first`);\n }\n await run('launchctl', ['bootstrap', domainTarget(), plistPath()]); // best-effort — \"already bootstrapped\" is fine\n await runOrThrow(run, 'launchctl', ['kickstart', '-k', serviceTarget()], 'launchctl kickstart');\n }\n\n async function stop(): Promise<void> {\n // Tolerant of \"already stopped/not loaded\" (fine — nothing to stop),\n // but a REAL failure (permission denied, an unreachable GUI domain)\n // must be surfaced rather than silently reported as \"stopped\"\n // (cross-model-review P1 #7, round 2, second half).\n await runIdempotent(run, 'launchctl', ['bootout', serviceTarget()], 'launchctl bootout', LAUNCHD_NOT_LOADED);\n }\n\n async function status(): Promise<ServiceStatusResult> {\n const installed = await fileExists(plistPath());\n const result = await run('launchctl', ['print', serviceTarget()]);\n const detail = result.stdout || result.stderr;\n const running = result.code === 0 && /\\bstate\\s*=\\s*running\\b/i.test(detail);\n // Finding P1 #2 (residual, round 3): see `systemd.ts`'s `status()` for\n // the full rationale — reuses this file's own\n // `LAUNCHD_CONNECTIVITY_OR_PERMISSION_FAILURE` (an unreachable GUI\n // domain or a permission failure on THIS query is not evidence of \"not\n // running\") so callers can tell a confirmed result apart from one the\n // manager could not even answer — see `service-types.ts`'s\n // `ServiceStatusResult.determinate`.\n const determinate = running || !LAUNCHD_CONNECTIVITY_OR_PERMISSION_FAILURE.some((pattern) => pattern.test(detail));\n return { installed, running, determinate, detail };\n }\n\n return { install, uninstall, start, stop, status };\n}\n","import { promises as fsp } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { defaultRunner, runIdempotent, runOrThrow, type IdempotentAbsence, type Runner } from './exec-runner';\nimport { sanitizeServiceName, type ServiceDefinition, type ServiceInstallOptions, type ServiceLifecycle, type ServiceProgram, type ServiceStatusResult } from './service-types';\n\n/** DI seam for tests — see `exec-runner.ts`'s `Runner` doc comment. */\nexport interface SystemdDeps {\n run?: Runner;\n fs?: Pick<typeof fsp, 'mkdir' | 'writeFile' | 'rm' | 'stat'>;\n homedir?: () => string;\n}\n\n/**\n * Genuine-failure text that must NEVER be reclassified as \"unit already\n * absent\", checked before `SYSTEMD_NOT_LOADED`'s own `patterns` (see\n * `exec-runner.ts`'s `IdempotentAbsence.neverAbsence`). The load-bearing one\n * is `Failed to connect to bus: No such file or directory` — the standard,\n * very common systemd message when there is no reachable `systemd --user`\n * D-Bus session for this uid (headless/SSH without `loginctl\n * enable-linger` — exactly where this daemon commonly runs). Its own\n * \"No such file or directory\" wording is textually indistinguishable from a\n * genuinely-absent unit's ENOENT unless the \"connect to ... bus\" prefix is\n * checked for and excluded first: without this, that bus-connect failure\n * was previously misread as \"already absent\", deleting the still-relevant\n * unit file out from under a service that may still be installed/running —\n * the exact orphan bug #7 was supposed to fix, reintroduced by this one\n * over-broad pattern (cross-model-review P1 #7, round 2).\n */\nconst SYSTEMD_CONNECTIVITY_OR_PERMISSION_FAILURE: readonly RegExp[] = [\n /failed to connect to.*bus/i,\n /connection refused/i,\n /access denied/i,\n /permission denied/i,\n /interactive authentication required/i,\n];\n\n/**\n * What `systemctl --user disable --now`/`systemctl --user stop` prints/exits\n * with when the unit isn't installed/loaded at all — as opposed to a\n * genuine failure (permission denied, no running `--user` instance, a\n * manager fault), which must be surfaced rather than treated the same way\n * (see `uninstall()`/`stop()` below and cross-model-review P1 #7).\n *\n * Deliberately does NOT include a bare \"no such file or directory\" pattern\n * (present in an earlier version of this fix): both genuine absence shapes\n * this module actually needs to tolerate — `stop` on an unloaded unit\n * (\"Unit foo.service not loaded.\") and `disable`/other unit-file lookups on\n * one that was never written (\"Unit file foo.service does not exist.\") —\n * are already covered by the two patterns below without it, while the bare\n * ENOENT string is ALSO exactly what a bus-connect failure produces (see\n * `SYSTEMD_CONNECTIVITY_OR_PERMISSION_FAILURE` above) — there is no\n * genuine-absence case this module relies on that only the bare pattern\n * would have caught.\n */\nconst SYSTEMD_NOT_LOADED: IdempotentAbsence = {\n patterns: [/not loaded/i, /does not exist/i],\n neverAbsence: SYSTEMD_CONNECTIVITY_OR_PERMISSION_FAILURE,\n};\n\n/**\n * True if `value` contains any C0 control character (newline, CR, NUL,\n * etc., code points below 32) or DEL (code point 127) - checked by\n * character code rather than a regex escape sequence for that range, so\n * there is no ambiguity about which literal bytes are being matched.\n */\nfunction hasControlChar(value: string): boolean {\n for (let i = 0; i < value.length; i += 1) {\n const code = value.charCodeAt(i);\n if (code < 32 || code === 127) return true;\n }\n return false;\n}\n\n/**\n * Rejects (rather than silently mangling or truncating) a value about to be\n * embedded in a generated systemd unit file if it contains any control\n * character. Unit files are line-oriented `Key=value` text: a raw newline\n * in `displayName`/`cwd`/a log path/an arg would split one logical\n * directive into two, letting an attacker- or mistake-controlled value\n * inject an ENTIRE ADDITIONAL, attacker-chosen unit directive\n * (cross-model-review P1 #8) — there is no escape sequence that makes an\n * embedded raw newline safe here, so this rejects outright rather than\n * attempting to neutralize it in place.\n */\nfunction assertNoControlChars(value: string, field: string): void {\n if (hasControlChar(value)) {\n throw new Error(\n `systemd unit ${field} must not contain control characters (newline/CR/etc.) — refusing to generate a unit file that could inject an unintended directive (got ${JSON.stringify(value)})`,\n );\n }\n}\n\n/**\n * Escapes a literal `%` as systemd's own documented `%%` — systemd expands\n * `%`-prefixed specifiers (`%h`, `%n`, `%i`, ...) in unit file directive\n * values (`systemd.unit(5)`'s \"Specifiers\" section), so a raw `%` in a\n * supposedly-verbatim path/name would otherwise risk being silently\n * reinterpreted rather than passed through as written\n * (cross-model-review P1 #8).\n */\nfunction escapeSystemdPercent(value: string): string {\n return value.replace(/%/g, '%%');\n}\n\n/**\n * systemd unit-file quoting (`systemd.syntax(7)`): `ExecStart=` is\n * whitespace-tokenized like a shell command line unless quoted. Every\n * token is wrapped in double quotes and has embedded backslashes/quotes\n * escaped — unconditionally, not just when a token happens to contain\n * whitespace — so there is no \"does this need quoting\" judgment call that\n * could get a space-containing config path wrong. Per\n * `systemd.service(5)`'s \"Command Lines\" section, `ExecStart=` ALSO expands\n * `%`-specifiers and `$FOO`/`${FOO}` environment variables in the raw\n * command line before tokenizing — both neutralized here too (`$` doubled\n * to `$$`, systemd's own documented escape for a literal dollar sign; `%`\n * doubled to `%%`) so `program.command`/`program.args` reach the process\n * exactly as given (see `service-types.ts`'s `ServiceProgram.args` doc\n * comment: \"passed verbatim\"), never silently rewritten by systemd\n * (cross-model-review P1 #8). A control character (e.g. an embedded\n * newline) is rejected outright — see `assertNoControlChars`; a quoted\n * string still can't survive an embedded newline in a line-oriented unit\n * file.\n */\nfunction quoteSystemdArg(value: string): string {\n assertNoControlChars(value, 'program.command/program.args entry');\n const escaped = escapeSystemdPercent(value)\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"')\n .replace(/\\$/g, () => '$$');\n return `\"${escaped}\"`;\n}\n\n/**\n * Generates a systemd user unit for `name` running `program`, logging to\n * `logDir`. Pure/no I/O — unit-tested directly for exact content shape, and\n * (locally, when `systemd-analyze` is available) verified with\n * `systemd-analyze verify` — see `templates/service/systemd/README.md`.\n *\n * `Restart=on-failure` + `RestartSec=10` is the crash-restart M3-4 asks for,\n * delegated entirely to systemd. `StandardOutput`/`StandardError` are\n * pointed at append-mode files under `logDir` for parity with the launchd\n * plist's `StandardOutPath`/`StandardErrorPath` and the WinSW `<logpath>` —\n * systemd's own native idiom (the journal, `journalctl --user -u <name>`)\n * still works unconditionally alongside this (systemd always journals\n * unit's output; explicitly setting `StandardOutput=append:...` needs\n * systemd >= 240, present on every currently-supported distro this SDK\n * targets) and is documented in the README as the alternative.\n */\nexport function generateSystemdUnit(def: { name: string; displayName: string; program: ServiceProgram; logDir: string }): string {\n const { name, displayName, program, logDir } = def;\n // Every interpolated value is validated/escaped BEFORE being written into\n // the template below — never after — so there is no path that emits an\n // unchecked value into the generated unit file (cross-model-review P1\n // #8). `name` is checked here too even though every real caller already\n // ran it through `sanitizeServiceName` (see `service-types.ts`), since\n // this is a directly exported, directly unit-tested pure function that\n // must be safe on its own, not just when called via\n // `createSystemdLifecycle`.\n assertNoControlChars(name, 'name');\n assertNoControlChars(displayName, 'displayName');\n const cwd = program.cwd ?? os.homedir();\n assertNoControlChars(cwd, 'program.cwd');\n const outLog = path.join(logDir, `${name}.out.log`);\n const errLog = path.join(logDir, `${name}.err.log`);\n assertNoControlChars(outLog, 'logDir');\n assertNoControlChars(errLog, 'logDir');\n const execStart = [program.command, ...program.args].map(quoteSystemdArg).join(' ');\n return `[Unit]\nDescription=${escapeSystemdPercent(displayName)}\n\n[Service]\nType=simple\nExecStart=${execStart}\nWorkingDirectory=${escapeSystemdPercent(cwd)}\nRestart=on-failure\nRestartSec=10\nStandardOutput=append:${escapeSystemdPercent(outLog)}\nStandardError=append:${escapeSystemdPercent(errLog)}\n\n[Install]\nWantedBy=default.target\n`;\n}\n\n/**\n * Linux systemd **user** service lifecycle (`~/.config/systemd/user/`,\n * `systemctl --user ...`) — deliberately not a system-wide unit under\n * `/etc/systemd/system/`, so install/uninstall never needs root, matching\n * launchd's per-user LaunchAgent (not a system Daemon) and WinSW's\n * per-machine Windows Service the same way each platform's own idiomatic\n * \"run this in the background for me\" mechanism works.\n *\n * Requires a running systemd **user instance** for this user (normal on any\n * desktop/login-manager session, and on modern systemd with\n * `loginctl enable-linger` for a headless box) — a bare container with no\n * systemd user session at all will fail every `systemctl --user` call here\n * with a clear error surfaced from `runOrThrow`, not a silent no-op.\n */\nexport function createSystemdLifecycle(def: ServiceDefinition, deps: SystemdDeps = {}): ServiceLifecycle {\n const run = deps.run ?? defaultRunner;\n const fs = deps.fs ?? fsp;\n const homedir = deps.homedir ?? (() => os.homedir());\n\n const name = sanitizeServiceName(def.name);\n const unitName = `${name}.service`;\n const unitPath = () => path.join(homedir(), '.config', 'systemd', 'user', unitName);\n\n async function fileExists(p: string): Promise<boolean> {\n try {\n await fs.stat(p);\n return true;\n } catch {\n return false;\n }\n }\n\n async function writeUnit(program: ServiceProgram): Promise<void> {\n const unit = generateSystemdUnit({ name, displayName: def.displayName ?? def.name, program, logDir: def.logDir });\n await fs.mkdir(path.dirname(unitPath()), { recursive: true });\n await fs.mkdir(def.logDir, { recursive: true });\n await fs.writeFile(unitPath(), unit, 'utf8');\n }\n\n async function install(opts: ServiceInstallOptions = {}): Promise<void> {\n await writeUnit(opts.program ?? def.program);\n await runOrThrow(run, 'systemctl', ['--user', 'daemon-reload'], 'systemctl daemon-reload');\n // `enable --now` both enables (survives logout/reboot, given linger)\n // AND starts in one call.\n await runOrThrow(run, 'systemctl', ['--user', 'enable', '--now', unitName], 'systemctl enable --now');\n }\n\n async function uninstall(): Promise<void> {\n // Tolerant of \"wasn't installed/running\" (fine — nothing to\n // stop/unregister), but a REAL failure (permission denied, no running\n // `--user` instance, a manager fault) must NOT be masked: only delete\n // the unit file once we know it's actually disabled/stopped or was\n // never there, so a still-running unit never loses its control file\n // and becomes an orphan nobody can stop/uninstall (cross-model-review\n // P1 #7).\n await runIdempotent(run, 'systemctl', ['--user', 'disable', '--now', unitName], 'systemctl disable --now', SYSTEMD_NOT_LOADED);\n await fs.rm(unitPath(), { force: true });\n await run('systemctl', ['--user', 'daemon-reload']); // best-effort — no control file left to protect at this point\n }\n\n async function start(): Promise<void> {\n if (!(await fileExists(unitPath()))) {\n throw new Error(`service \"${name}\" is not installed (no unit file at ${unitPath()}) — call install() first`);\n }\n await runOrThrow(run, 'systemctl', ['--user', 'start', unitName], 'systemctl start');\n }\n\n async function stop(): Promise<void> {\n // Tolerant of \"already stopped/not loaded\" (fine — nothing to stop),\n // but a REAL failure (permission denied, no running `--user` instance,\n // a manager fault) must be surfaced rather than silently reported as\n // \"stopped\" (cross-model-review P1 #7, round 2, second half).\n await runIdempotent(run, 'systemctl', ['--user', 'stop', unitName], 'systemctl stop', SYSTEMD_NOT_LOADED);\n }\n\n async function status(): Promise<ServiceStatusResult> {\n const installed = await fileExists(unitPath());\n const result = await run('systemctl', ['--user', 'is-active', unitName]);\n const detail = (result.stdout || result.stderr).trim();\n const running = result.code === 0 && detail === 'active';\n // Finding P1 #2 (residual, round 3): a bus-connect/permission failure on\n // THIS query is not evidence of \"inactive\" — it means `systemctl`\n // couldn't even be asked. Reuses the same `neverAbsence`-style pattern\n // this file already applies to `uninstall()`/`stop()` (see\n // `SYSTEMD_CONNECTIVITY_OR_PERMISSION_FAILURE`'s own doc comment) so a\n // caller like `bin/commands/unpair.ts`'s `checkServiceState` can tell\n // \"confirmed not running\" apart from \"couldn't tell\" — see\n // `service-types.ts`'s `ServiceStatusResult.determinate`.\n const determinate = running || !SYSTEMD_CONNECTIVITY_OR_PERMISSION_FAILURE.some((pattern) => pattern.test(detail));\n return { installed, running, determinate, detail };\n }\n\n return { install, uninstall, start, stop, status };\n}\n","import { promises as fsp } from 'node:fs';\nimport path from 'node:path';\nimport { defaultRunner, runIdempotent, runOrThrow, type IdempotentAbsence, type Runner } from './exec-runner';\nimport { sanitizeServiceName, type ServiceDefinition, type ServiceInstallOptions, type ServiceLifecycle, type ServiceProgram, type ServiceStatusResult } from './service-types';\n\n/**\n * Genuine-failure text that must NEVER be reclassified as \"service already\n * absent/stopped\", checked before `WINSW_NOT_INSTALLED`'s/\n * `WINSW_ALREADY_STOPPED`'s own `patterns` (see `exec-runner.ts`'s\n * `IdempotentAbsence.neverAbsence`) — the same defense-in-depth applied to\n * the systemd bus-connect false-positive and launchd's unreachable-domain\n * false-positive (cross-model-review P1 #7, round 2), audited here for\n * parity even though no live Windows host was available to reproduce a\n * false match directly (see `generateWinswXml`'s own doc comment on why\n * this macOS dev box cannot execute WinSW/`sc.exe` at all — the\n * `windows-service-smoke` CI job is the real verification for this\n * platform).\n */\nconst WINSW_CONNECTIVITY_OR_PERMISSION_FAILURE: readonly RegExp[] = [\n /access is denied/i,\n /access denied/i,\n /permission denied/i,\n /being used by another process/i,\n];\n\n/**\n * What WinSW/`sc.exe` prints or exits with when the service isn't installed\n * at all — as opposed to a genuine failure (access denied, the exe\n * locked/busy, a WinSW/SCM fault), which must be surfaced rather than\n * treated the same way (see `uninstall()` below and cross-model-review P1\n * #7). Windows's own `ERROR_SERVICE_DOES_NOT_EXIST` is exit code 1060 (see\n * this same phrase/code already asserted in `status()`'s own test).\n */\nconst WINSW_NOT_INSTALLED: IdempotentAbsence = {\n codes: [1060],\n patterns: [/does not exist/i, /non-existent service/i],\n neverAbsence: WINSW_CONNECTIVITY_OR_PERMISSION_FAILURE,\n};\n\n/**\n * Superset of `WINSW_NOT_INSTALLED` used by the standalone `stop()` (see\n * below): tolerates EITHER \"not installed at all\" OR \"installed but already\n * stopped\" — Windows's own `ERROR_SERVICE_NOT_ACTIVE` is exit code 1062,\n * FormatMessage text \"The service has not been started.\" (a long-stable,\n * well-documented Win32 SCM error code, distinct from and adjacent to\n * `ERROR_SERVICE_DOES_NOT_EXIST`'s 1060) — as opposed to a genuine failure\n * (access denied, the exe locked/busy), which must still be surfaced\n * (cross-model-review P1 #7, round 2, second half).\n */\nconst WINSW_ALREADY_STOPPED: IdempotentAbsence = {\n codes: [1062, ...(WINSW_NOT_INSTALLED.codes ?? [])],\n patterns: [/not running/i, /has not been started/i, ...WINSW_NOT_INSTALLED.patterns],\n neverAbsence: WINSW_CONNECTIVITY_OR_PERMISSION_FAILURE,\n};\n\n/** DI seam for tests — see `exec-runner.ts`'s `Runner` doc comment. */\nexport interface WinswDeps {\n run?: Runner;\n fs?: Pick<typeof fsp, 'mkdir' | 'writeFile' | 'rm' | 'stat' | 'copyFile'>;\n}\n\nfunction xmlEscape(value: string): string {\n return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;').replace(/'/g, '&apos;');\n}\n\n/**\n * Generates a WinSW (https://github.com/winsw/winsw) service descriptor XML\n * for `id` running `program`, logging to `logDir`. Pure/no I/O — unit-tested\n * directly for exact content shape; the REAL proof this is valid WinSW XML\n * is the `windows-service-smoke` CI job (`.github/workflows/ci.yml`), which\n * actually runs `winsw install` against generated output on a real\n * `windows-latest` runner — this macOS dev box cannot execute WinSW at all.\n *\n * Each argument becomes its own `<argument>` element (WinSW's supported\n * repeatable-element form) rather than a single space-joined `<arguments>`\n * string — this sidesteps shell-style quoting entirely for a config path\n * containing spaces, the exact same concern the pi adapter's\n * `execFile`-without-`shell` note raises for Windows (see\n * `templates/packaging/sea/README.md`'s \"Windows note\": WinSW itself\n * launches `<executable>` directly, no shell involved, so an unescaped\n * space in a single `<arguments>` string would be split in the wrong\n * place — one `<argument>` per token has no such ambiguity).\n *\n * `<onfailure action=\"restart\" delay=\"10 sec\"/>` (with a second, longer\n * backoff on repeated failure) is the crash-restart M3-4 asks for,\n * delegated entirely to WinSW/the Windows SCM — nothing in this SDK\n * supervises the process itself. `<startmode>Automatic</startmode>` mirrors\n * launchd's `RunAtLoad`/systemd's `WantedBy=default.target`: the service\n * also starts automatically on the next machine boot, not just right now.\n */\nexport function generateWinswXml(def: { id: string; displayName: string; program: ServiceProgram; logDir: string }): string {\n const { id, displayName, program, logDir } = def;\n const argXml = program.args.map((a) => ` <argument>${xmlEscape(a)}</argument>`).join('\\n');\n const cwdXml = program.cwd ? `\\n <workingdirectory>${xmlEscape(program.cwd)}</workingdirectory>` : '';\n return `<service>\n <id>${xmlEscape(id)}</id>\n <name>${xmlEscape(displayName)}</name>\n <description>${xmlEscape(displayName)} (managed by byok-agent; see templates/service/winsw/README.md)</description>\n <executable>${xmlEscape(program.command)}</executable>\n${argXml}${cwdXml}\n <logpath>${xmlEscape(logDir)}</logpath>\n <log mode=\"roll\"></log>\n <startmode>Automatic</startmode>\n <onfailure action=\"restart\" delay=\"10 sec\"/>\n <onfailure action=\"restart\" delay=\"30 sec\"/>\n <resetfailure>1 hour</resetfailure>\n</service>\n`;\n}\n\n/**\n * Windows Service lifecycle via WinSW — the standard, widely-used .NET\n * service wrapper that gives any exe/command real Windows Service Control\n * Manager (SCM) integration (crash-restart, logging, boot autostart)\n * without this SDK hand-rolling the SCM protocol in Node (which has no\n * native control-handler support in core — the reason a wrapper is needed\n * at all).\n *\n * Decision-6 boundary: the product supplies the WinSW binary\n * (`def.windows.winswBin`); this module only generates the correct config\n * and drives install/uninstall/start/stop/status around it. WinSW's own\n * convention is that its executable and XML config share a basename in the\n * same directory (`<id>.exe` + `<id>.xml`), so `install()` copies the\n * product-supplied binary into place under that name rather than invoking\n * it in place — this is the version-agnostic approach documented across\n * WinSW v2/v3, unlike relying on a specific `--config` CLI flag that may\n * differ between major versions.\n *\n * `status()` queries `sc.exe` (the real Windows SCM query tool, always\n * present) rather than parsing WinSW's own `status` subcommand text —\n * authoritative ground truth independent of WinSW's own output, and the\n * exact tool `templates/service/winsw/smoke-test.mjs` / the CI job also\n * assert against.\n */\nexport function createWinswLifecycle(def: ServiceDefinition, deps: WinswDeps = {}): ServiceLifecycle {\n const run = deps.run ?? defaultRunner;\n const fs = deps.fs ?? fsp;\n\n const windows = def.windows;\n if (!windows) {\n throw new Error('WinSW service lifecycle requires `ServiceDefinition.windows.winswBin` (the product-bundled WinSW executable path)');\n }\n // Captured as their own bindings (not read off `windows` again below) so\n // TS's narrowing of the `if (!windows) throw` above — which does not\n // survive into the nested `writeFiles` closure — doesn't matter.\n const winswBin = windows.winswBin;\n const id = sanitizeServiceName(def.name);\n const installDir = windows.installDir ?? def.logDir;\n const exePath = path.join(installDir, `${id}.exe`);\n const xmlPath = path.join(installDir, `${id}.xml`);\n\n async function fileExists(p: string): Promise<boolean> {\n try {\n await fs.stat(p);\n return true;\n } catch {\n return false;\n }\n }\n\n async function writeFiles(program: ServiceProgram): Promise<void> {\n const xml = generateWinswXml({ id, displayName: def.displayName ?? def.name, program, logDir: def.logDir });\n await fs.mkdir(installDir, { recursive: true });\n await fs.mkdir(def.logDir, { recursive: true });\n await fs.copyFile(winswBin, exePath);\n await fs.writeFile(xmlPath, xml, 'utf8');\n }\n\n async function install(opts: ServiceInstallOptions = {}): Promise<void> {\n await writeFiles(opts.program ?? def.program);\n await runOrThrow(run, exePath, ['install'], 'winsw install');\n await runOrThrow(run, exePath, ['start'], 'winsw start');\n }\n\n async function uninstall(): Promise<void> {\n // Tolerant of \"wasn't running/installed\" (fine), but a REAL failure\n // (access denied, the exe locked/busy, a WinSW/SCM fault) at EITHER\n // step must NOT be masked: only delete the exe+xml once we know the\n // service is actually stopped and unregistered (or was never there),\n // so a still-running service never loses its control files and\n // becomes an orphan nobody can stop/uninstall (cross-model-review P1\n // #7).\n await runIdempotent(run, exePath, ['stop'], 'winsw stop', WINSW_NOT_INSTALLED);\n await runIdempotent(run, exePath, ['uninstall'], 'winsw uninstall', WINSW_NOT_INSTALLED);\n await fs.rm(exePath, { force: true });\n await fs.rm(xmlPath, { force: true });\n }\n\n async function start(): Promise<void> {\n if (!(await fileExists(xmlPath))) {\n throw new Error(`service \"${id}\" is not installed (no config at ${xmlPath}) — call install() first`);\n }\n await runOrThrow(run, exePath, ['start'], 'winsw start');\n }\n\n async function stop(): Promise<void> {\n // Tolerant of \"already stopped/not installed\" (fine — nothing to\n // stop), but a REAL failure (access denied, the exe locked/busy, an SCM\n // fault) must be surfaced rather than silently reported as \"stopped\"\n // (cross-model-review P1 #7, round 2, second half).\n await runIdempotent(run, exePath, ['stop'], 'winsw stop', WINSW_ALREADY_STOPPED);\n }\n\n async function status(): Promise<ServiceStatusResult> {\n const installed = await fileExists(xmlPath);\n const result = await run('sc.exe', ['query', id]);\n const detail = (result.stdout || result.stderr).trim();\n const running = result.code === 0 && /\\bSTATE\\b.*\\bRUNNING\\b/i.test(detail);\n // Finding P1 #2 (residual, round 3): see `systemd.ts`'s `status()` for\n // the full rationale — reuses this file's own\n // `WINSW_CONNECTIVITY_OR_PERMISSION_FAILURE` so callers can tell a\n // confirmed result (including a clean \"does not exist\", code 1060 —\n // unaffected, since that text never matches this pattern list) apart\n // from a query the SCM/WinSW could not even answer — see\n // `service-types.ts`'s `ServiceStatusResult.determinate`.\n const determinate = running || !WINSW_CONNECTIVITY_OR_PERMISSION_FAILURE.some((pattern) => pattern.test(detail));\n return { installed, running, determinate, detail };\n }\n\n return { install, uninstall, start, stop, status };\n}\n","import { createLaunchdLifecycle, type LaunchdDeps } from './launchd';\nimport { createSystemdLifecycle, type SystemdDeps } from './systemd';\nimport { createWinswLifecycle, type WinswDeps } from './winsw';\nimport type { ServiceDefinition, ServiceLifecycle } from './service-types';\n\nexport class UnsupportedServicePlatformError extends Error {\n constructor(platform: string) {\n super(`no OS service lifecycle for platform \"${platform}\" — supported: darwin (launchd), linux (systemd --user), win32 (WinSW)`);\n this.name = 'UnsupportedServicePlatformError';\n }\n}\n\nexport interface CreateServiceLifecycleOptions {\n /**\n * Overrides `process.platform` — test-only seam for exercising a\n * specific platform's generator/install logic from any host (combine\n * with a mocked `deps.run`/`deps.fs`, since the real launchctl/systemctl/\n * WinSW binaries obviously aren't present on the \"wrong\" OS).\n */\n platform?: NodeJS.Platform;\n /** Platform-specific DI seams (mocked exec, mocked fs, mocked homedir/getuid) — only the fields matching the resolved platform are ever read. */\n deps?: LaunchdDeps & SystemdDeps & WinswDeps;\n}\n\n/**\n * Platform-dispatched entry point for M3-4's lifecycle API: manages the\n * daemon as a background OS service via the platform's own idiomatic\n * mechanism —\n *\n * - **macOS**: a launchd LaunchAgent (`launchd.ts`).\n * - **Linux**: a systemd user unit (`systemd.ts`).\n * - **Windows**: a WinSW-wrapped Windows Service (`winsw.ts`) — Node has no\n * native SCM control-handler support in core, so a wrapper is used\n * rather than hand-rolling the SCM protocol; see `winsw.ts`'s own doc\n * comment for why WinSW specifically.\n *\n * Every implementation delegates crash-restart entirely to the OS\n * supervisor (`KeepAlive`/`Restart=on-failure`/`<onfailure>`) — none of them\n * runs an in-process supervisor loop.\n *\n * Deliberately does NOT try to auto-resolve `ServiceDefinition.program`'s\n * `command`/`agentBin` from `import.meta.resolve`/`import.meta.url`-style\n * introspection the way `adapters/pi/resolve-bin.ts` does for pi's\n * optionalDependency. That pattern is a genuinely hazardous fit here: a\n * relative path from THIS source file to `bin/byok-agent.ts` (`../bin/...`,\n * since `lifecycle/` and `bin/` are sibling directories under `src/`) does\n * NOT survive tsup's bundling unchanged — `src/index.ts` and\n * `src/bin/byok-agent.ts` are two SEPARATE, independently-bundled tsup\n * entries (see `tsup.config.ts`), so any code from `lifecycle/` ends up\n * inlined into `dist/index.js` itself, whose OWN directory is `dist/`, not\n * `dist/lifecycle/` — a path relative to \"wherever this bundled code\n * actually runs from\" would need to be `./bin/byok-agent.js` there, the\n * OPPOSITE of the `../bin/...` that's correct in unbundled `src/`. Guessing\n * across that bundle boundary is exactly the class of hazard\n * `templates/packaging/sea/README.md` had to empirically work around for\n * pi's own resolution path. Rather than add a second such hazard, this\n * module requires the caller to supply an explicit, already-resolved\n * `program.command`/args (see `service-types.ts`'s `nodeAgentProgram` —\n * still just a formatting convenience, not a resolution mechanism) — the\n * `install`/`uninstall`/`service-*` CLI subcommands (`bin/commands/service.ts`)\n * default `agentBin` to `process.argv[1]` instead, which Node always\n * populates correctly with the actual script path being run regardless of\n * how it was invoked, bundled or not.\n */\nexport function createServiceLifecycle(def: ServiceDefinition, opts: CreateServiceLifecycleOptions = {}): ServiceLifecycle {\n const platform = opts.platform ?? process.platform;\n switch (platform) {\n case 'darwin':\n return createLaunchdLifecycle(def, opts.deps);\n case 'linux':\n return createSystemdLifecycle(def, opts.deps);\n case 'win32':\n return createWinswLifecycle(def, opts.deps);\n default:\n throw new UnsupportedServicePlatformError(platform);\n }\n}\n","import { readFileSync } from 'node:fs';\nimport type { DaemonConfig } from '../daemon/create-daemon';\nimport { DeviceStore } from '../daemon/store';\nimport { GitWorkspaceManager } from '../daemon/git-workspace';\n\n/**\n * Shared CLI plumbing: config-file loading and a tiny hand-rolled arg\n * parser. Deliberately no arg-parsing library — every subcommand in this\n * bin has at most one or two flags, so a generic parser would be more\n * machinery than the surface it serves. See `byok-agent.ts`'s header\n * comment for the overall command/read-model design this supports.\n */\n\nconst REQUIRED_FIELDS = ['productName', 'productId', 'serverUrl', 'workspaceRoot'] as const;\n\n/**\n * Thrown by {@link loadConfig} on a missing/unreadable/invalid config.\n * Never calls `process.exit` itself (unlike the pre-M3-2b bin, which did) —\n * every caller, including tests, controls its own exit behavior; only\n * `byok-agent.ts`'s top-level `main().catch(...)` turns this into a clean\n * stderr message + `exit(1)`.\n */\nexport class ConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ConfigError';\n }\n}\n\n/**\n * Loads a `DaemonConfig` from a JSON file, if given, merged with explicit\n * overrides (e.g. `pair`'s `--server`). Every subcommand in this bin —\n * including the read-only ones (`status`/`runtimes`/`tasks`) — loads\n * config the same way: they all need `productId`/`storeDir`/`branding`/\n * `runtimeAllowlist` from the same one product install, so there is only\n * ever one config shape to reason about.\n */\nexport function loadConfig(configPath: string | undefined, overrides: Partial<DaemonConfig> = {}): DaemonConfig {\n let base: Partial<DaemonConfig> = {};\n if (configPath) {\n let raw: string;\n try {\n raw = readFileSync(configPath, 'utf8');\n } catch (err) {\n throw new ConfigError(`could not read config at \"${configPath}\": ${err instanceof Error ? err.message : String(err)}`);\n }\n try {\n base = JSON.parse(raw) as Partial<DaemonConfig>;\n } catch (err) {\n throw new ConfigError(`config at \"${configPath}\" is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n const merged: Partial<DaemonConfig> = { ...base, ...overrides };\n if (merged.gitWorkspace !== undefined) {\n try {\n GitWorkspaceManager.validateConfig(merged.gitWorkspace);\n } catch (error) {\n throw new ConfigError(error instanceof Error ? error.message : 'invalid gitWorkspace configuration');\n }\n }\n for (const field of REQUIRED_FIELDS) {\n if (!merged[field]) {\n throw new ConfigError(`config is missing required field \"${field}\"`);\n }\n }\n return merged as DaemonConfig;\n}\n\n/**\n * Same `storeDir` resolution `create-daemon.ts` uses internally\n * (`config.storeDir ?? DeviceStore.defaultDir(config.productId)`) — reused\n * here via `DeviceStore`'s own static helper (not reimplemented) so a query\n * subcommand always looks in the exact same place `createDaemon`/\n * `createDaemonWithAdapters` would persist to.\n */\nexport function resolveStoreDir(config: Pick<DaemonConfig, 'storeDir' | 'productId'>): string {\n return DeviceStore.resolveDir(config.productId, config.storeDir);\n}\n\n/** Value following `flag` in `args` (e.g. `--config <path>`), or `undefined`. */\nexport function argValue(args: string[], flag: string): string | undefined {\n const idx = args.indexOf(flag);\n const value = idx >= 0 ? args[idx + 1] : undefined;\n return value !== undefined && !value.startsWith('--') ? value : undefined;\n}\n\n/** Whether a bare boolean flag (e.g. `--follow`, `--yes`) is present anywhere in `args`. */\nexport function hasFlag(args: string[], flag: string): boolean {\n return args.includes(flag);\n}\n\n/**\n * Positional (non-flag) arguments, in order, with a fixed set of known\n * `--flag <value>` pairs removed (flag AND its value). Bare boolean flags\n * (e.g. `--follow`/`--yes`) are handled separately via {@link hasFlag} and\n * don't need to be named here unless they'd otherwise be mistaken for a\n * positional. Order-independent: `pair CODE --server URL` and\n * `pair --server URL CODE` both yield `[\"CODE\"]`.\n */\nexport function positionalArgs(args: string[], valueFlags: string[] = []): string[] {\n const result: string[] = [];\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === undefined) continue;\n if (valueFlags.includes(arg)) {\n i++; // also skip the value that belongs to this flag\n continue;\n }\n result.push(arg);\n }\n return result;\n}\n","import { constants as fsConstants, promises as fs } from 'node:fs';\nimport net from 'node:net';\nimport {\n CONTROL_PROTOCOL_VERSION,\n ControlError,\n HANDSHAKE_TIMEOUT_MS,\n NdjsonLineReader,\n computeClientAuth,\n computeServerProof,\n controlEndpointPath,\n controlTokenPath,\n encodeFrame,\n isRecord,\n parseServerHello,\n parseServerReady,\n randomNonceHex,\n timingSafeEqualHex,\n} from '../daemon/control-protocol';\n\n/**\n * M4 Phase 2: the CLI-side half of the control socket — connects, performs\n * the mutual HMAC handshake (`../daemon/control-protocol.ts`), and exposes a\n * small `request()`/`subscribe()` surface every rewired command\n * (`status`/`tasks --follow`/`unpair`/`approve`/`reject`) builds on.\n *\n * `connectControlClient` never throws for the ordinary \"daemon isn't\n * running\" case — it returns a typed `{ok:false, reason}` result instead\n * (see {@link ConnectControlResult}), so a caller can render a clean\n * fallback message rather than catching an exception. Missing\n * `control.token` (the daemon was never started, or was stopped) is by far\n * the most common reason; any other connect/handshake failure collapses\n * into the same shape — a CLI user doesn't need to know WHY the control\n * socket isn't reachable, only that it isn't and a fallback is being used.\n */\n\nexport interface ControlClientOptions {\n storeDir: string;\n productId: string;\n /** Default: `HANDSHAKE_TIMEOUT_MS` (3000ms) — matches the server's own handshake timeout. */\n handshakeTimeoutMs?: number;\n /** Default 10000ms — applied per `request()` call; never applied to `subscribe()`, which is expected to stay open indefinitely. */\n requestTimeoutMs?: number;\n}\n\nexport interface ControlClient {\n /** Sends `{method, params}`, resolves with the server's `result`, or rejects with a {@link ControlError} (or a plain `Error` for a connection-level failure/timeout). */\n request<T = unknown>(method: string, params?: unknown): Promise<T>;\n /** Sends a streaming request; `onEvent` fires for each `event` frame. Returns a handle whose `close()` ends the WHOLE connection (per the protocol: \"client may just close the connection to unsubscribe\") — don't share a client between a `subscribe()` and other concurrent `request()` calls if you need them to outlive each other. */\n subscribe(method: string, params: unknown, onEvent: (event: unknown) => void): { close: () => void };\n /** Closes the underlying connection. Safe to call more than once. */\n close(): void;\n}\n\nexport type ConnectControlResult = { ok: true; client: ControlClient } | { ok: false; reason: string };\n\nconst MAX_CONTROL_TOKEN_BYTES = 256;\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nfunction sameFileState(left: import('node:fs').BigIntStats, right: import('node:fs').BigIntStats): boolean {\n return (\n left.dev === right.dev &&\n left.ino === right.ino &&\n left.size === right.size &&\n left.mtimeNs === right.mtimeNs &&\n left.ctimeNs === right.ctimeNs\n );\n}\n\n/**\n * Read the authentication token through a bounded pathname-bound handle.\n * Diagnostics calls this client even when no daemon is expected, so a FIFO,\n * symlink swap, or oversized local file must become an ordinary offline result\n * rather than blocking the CLI or consuming unbounded memory.\n */\nasync function readControlToken(tokenPath: string): Promise<string | undefined> {\n let namedBefore: import('node:fs').BigIntStats;\n try {\n namedBefore = await fs.lstat(tokenPath, { bigint: true });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw err;\n }\n if (!namedBefore.isFile() || namedBefore.isSymbolicLink()) {\n throw new Error('control token is not a real regular file');\n }\n const handle = await fs.open(\n tokenPath,\n fsConstants.O_RDONLY | (fsConstants.O_NONBLOCK ?? 0) | (fsConstants.O_NOFOLLOW ?? 0),\n );\n try {\n const opened = await handle.stat({ bigint: true });\n const namedAfterOpen = await fs.lstat(tokenPath, { bigint: true });\n if (\n !opened.isFile() ||\n !namedAfterOpen.isFile() ||\n namedAfterOpen.isSymbolicLink() ||\n !sameFileState(namedBefore, opened) ||\n !sameFileState(opened, namedAfterOpen)\n ) {\n throw new Error('control token pathname changed before safe open');\n }\n if (opened.size < 0 || opened.size > BigInt(MAX_CONTROL_TOKEN_BYTES)) {\n throw new Error('control token exceeds the bounded read limit');\n }\n const size = Number(opened.size);\n const bytes = Buffer.alloc(size);\n const { bytesRead } = await handle.read(bytes, 0, size, 0);\n const afterRead = await handle.stat({ bigint: true });\n const namedAfterRead = await fs.lstat(tokenPath, { bigint: true });\n if (\n bytesRead !== size ||\n namedAfterRead.isSymbolicLink() ||\n !sameFileState(opened, afterRead) ||\n !sameFileState(afterRead, namedAfterRead)\n ) {\n throw new Error('control token changed during bounded read');\n }\n return bytes.toString('utf8').trim();\n } finally {\n await handle.close();\n }\n}\n\n/** Reads the control token, connects, and performs the handshake — see the module doc comment for why failures here collapse into `{ok:false, reason}` rather than throwing. */\nexport async function connectControlClient(opts: ControlClientOptions): Promise<ConnectControlResult> {\n const tokenPath = controlTokenPath(opts.storeDir);\n let token: string;\n try {\n const read = await readControlToken(tokenPath);\n if (read === undefined) {\n return { ok: false, reason: 'daemon is not running (no control.token found)' };\n }\n token = read;\n } catch (err) {\n return { ok: false, reason: `could not read the control token: ${errorMessage(err)}` };\n }\n if (!token) {\n return { ok: false, reason: 'control token file is empty' };\n }\n\n const endpoint = controlEndpointPath(opts.productId, opts.storeDir);\n try {\n const client = await connectAndHandshake(endpoint, token, opts);\n return { ok: true, client };\n } catch (err) {\n return { ok: false, reason: `daemon control socket not reachable: ${errorMessage(err)}` };\n }\n}\n\nfunction connectAndHandshake(endpoint: string, token: string, opts: ControlClientOptions): Promise<ControlClient> {\n return new Promise((resolve, reject) => {\n const socket = net.createConnection(endpoint);\n const reader = new NdjsonLineReader();\n let phase: 'server-hello' | 'ready' = 'server-hello';\n let settled = false;\n const clientNonce = randomNonceHex();\n\n const timer = setTimeout(() => {\n fail(new Error('handshake timed out'));\n }, opts.handshakeTimeoutMs ?? HANDSHAKE_TIMEOUT_MS);\n timer.unref?.();\n\n function fail(err: unknown): void {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n socket.removeAllListeners();\n socket.destroy();\n reject(err instanceof Error ? err : new Error(String(err)));\n }\n\n function succeed(): void {\n settled = true;\n clearTimeout(timer);\n socket.removeListener('error', onError);\n socket.removeListener('data', onData);\n resolve(createControlClient(socket, reader, opts));\n }\n\n function onData(chunk: Buffer): void {\n // Hardening finding (P2 re-gate): `reader.push` throws once the\n // still-unterminated remainder exceeds MAX_LINE_BYTES\n // (control-protocol.ts) — a hostile/broken peer sending a >64KiB line\n // with no newline. Uncaught, this would propagate out of the 'data'\n // listener and crash the whole CLI process (Node has no default\n // recovery for an exception thrown inside an EventEmitter callback).\n // Mirrors control-server.ts's own identical guard around its matching\n // `reader.push` call — route into this same handshake's `fail()` path\n // instead, exactly like every other handshake failure here.\n let lines: string[];\n try {\n lines = reader.push(chunk);\n } catch (err) {\n fail(err);\n return;\n }\n for (const line of lines) {\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n fail(new Error('malformed handshake frame'));\n return;\n }\n if (phase === 'server-hello') {\n const hello = parseServerHello(parsed);\n if (!hello) {\n fail(new Error('malformed or unexpected server hello'));\n return;\n }\n if (!timingSafeEqualHex(hello.proof, computeServerProof(token, clientNonce))) {\n fail(new Error('server failed to prove it holds the control token'));\n return;\n }\n socket.write(encodeFrame({ v: CONTROL_PROTOCOL_VERSION, auth: computeClientAuth(token, hello.nonce) }));\n phase = 'ready';\n continue;\n }\n if (!parseServerReady(parsed)) {\n fail(new Error('server did not confirm readiness'));\n return;\n }\n succeed();\n return;\n }\n }\n\n function onError(err: unknown): void {\n fail(err);\n }\n\n socket.once('error', onError);\n socket.once('connect', () => {\n socket.write(encodeFrame({ v: CONTROL_PROTOCOL_VERSION, hello: 'client', nonce: clientNonce }));\n socket.on('data', onData);\n });\n });\n}\n\ninterface PendingCall {\n resolve: (value: unknown) => void;\n reject: (err: unknown) => void;\n onEvent?: (event: unknown) => void;\n}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number, message: string): Promise<T> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(message)), ms);\n timer.unref?.();\n promise.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (err: unknown) => {\n clearTimeout(timer);\n reject(err);\n },\n );\n });\n}\n\nfunction createControlClient(socket: net.Socket, reader: NdjsonLineReader, opts: ControlClientOptions): ControlClient {\n const pending = new Map<string, PendingCall>();\n let idSeq = 0;\n let closed = false;\n\n function handleFrame(parsed: unknown): void {\n if (!isRecord(parsed) || typeof parsed.id !== 'string') return;\n const entry = pending.get(parsed.id);\n if (!entry) return;\n if ('event' in parsed) {\n entry.onEvent?.(parsed.event);\n return;\n }\n if (parsed.ok === true) {\n pending.delete(parsed.id);\n entry.resolve(parsed.done === true ? undefined : (parsed as { result?: unknown }).result);\n return;\n }\n pending.delete(parsed.id);\n const shape = (parsed as { error?: { code?: unknown; message?: unknown } }).error;\n entry.reject(\n new ControlError(\n typeof shape?.code === 'string' ? shape.code : 'internal_error',\n typeof shape?.message === 'string' ? shape.message : 'unknown control error',\n ),\n );\n }\n\n socket.on('data', (chunk: Buffer) => {\n // Same hardening as connectAndHandshake's own onData above: `reader.push`\n // throws on a >64KiB unterminated line (MAX_LINE_BYTES,\n // control-protocol.ts) — uncaught, that would crash this CLI process\n // from inside an EventEmitter 'data' callback. This connection is\n // already past the handshake (there is no `fail()` closure here), so\n // fail closed the same way a malformed/unexpected frame elsewhere in\n // this function already does: destroy the connection (which rejects\n // every pending call via the 'close' handler below) rather than risk\n // continuing to read from a peer that just proved it doesn't speak this\n // protocol.\n let lines: string[];\n try {\n lines = reader.push(chunk);\n } catch {\n socket.destroy();\n return;\n }\n for (const line of lines) {\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n continue; // ignore a malformed line rather than tearing down an otherwise-healthy connection\n }\n handleFrame(parsed);\n }\n });\n socket.on('close', () => {\n closed = true;\n for (const entry of pending.values()) entry.reject(new Error('control connection closed'));\n pending.clear();\n });\n socket.on('error', () => {\n // 'close' always follows and rejects every pending call above — swallow\n // here so a peer reset never becomes an unhandled 'error' crash.\n });\n\n function send(method: string, params: unknown, onEvent?: (event: unknown) => void): { id: string; promise: Promise<unknown> } {\n const id = `c${++idSeq}`;\n const promise = new Promise<unknown>((resolve, reject) => {\n pending.set(id, { resolve, reject, onEvent });\n });\n socket.write(encodeFrame({ v: CONTROL_PROTOCOL_VERSION, id, method, params }));\n return { id, promise };\n }\n\n return {\n async request<T>(method: string, params?: unknown): Promise<T> {\n if (closed) throw new Error('control connection is closed');\n const { promise } = send(method, params);\n const result = await withTimeout(promise, opts.requestTimeoutMs ?? 10_000, `control request \"${method}\" timed out`);\n return result as T;\n },\n subscribe(method, params, onEvent) {\n const { id, promise } = send(method, params, onEvent);\n promise.catch(() => {\n // subscribe()'s lifetime is managed via close()/onEvent, not this\n // promise — swallow so destroying the connection later (which\n // rejects every pending call, this one included) never surfaces as\n // an unhandled rejection.\n });\n return {\n close: (): void => {\n pending.delete(id);\n socket.destroy();\n },\n };\n },\n close(): void {\n socket.destroy();\n },\n };\n}\n\n/**\n * Unpair's own poll for \"has the daemon actually exited yet\" (see\n * `bin/commands/unpair.ts`): both the control token file being gone AND a\n * fresh connect attempt being refused, checked directly rather than through\n * a full `connectControlClient` handshake — cheaper per poll, and matches\n * the exact two-condition check the M4 design calls for.\n */\nexport async function isControlDaemonGone(storeDir: string, productId: string): Promise<boolean> {\n const tokenGone = await fs.stat(controlTokenPath(storeDir)).then(\n () => false,\n (err) => (err as NodeJS.ErrnoException).code === 'ENOENT',\n );\n if (!tokenGone) return false;\n\n const endpoint = controlEndpointPath(productId, storeDir);\n return new Promise<boolean>((resolve) => {\n const socket = net.createConnection(endpoint);\n const finish = (gone: boolean): void => {\n socket.removeAllListeners();\n socket.destroy();\n resolve(gone);\n };\n socket.once('connect', () => finish(false));\n socket.once('error', (err: NodeJS.ErrnoException) => finish(err.code === 'ECONNREFUSED' || err.code === 'ENOENT'));\n });\n}\n","import type { AgentEvent } from '@byok-sdk/protocol';\nimport type { ConnectionState, DaemonBranding, DaemonEvent, DaemonTaskInfo } from '../index';\nimport type { ControlStatusResult, PendingApproval } from '../daemon/control-protocol';\nimport type { ProbedRuntime } from './runtime-probe';\nimport type { TaskCounts, DerivedTaskInfo } from './tasks-view';\n\n/**\n * Pure line-formatting helpers shared by every subcommand — no I/O, no\n * process/console access, just `string`/`string[]` in and out, so every\n * function here is directly assertable in a test. PLAIN text only: no\n * ANSI/SGR color codes and no TTY control sequences anywhere in this file\n * (see `byok-agent.ts`'s header comment on why this CLI stays\n * headless/plain-structured, not a TUI). `JSON.stringify` is used purely\n * for its string-escaping (embedded quotes/newlines never break a line),\n * not to imply the overall output is JSON.\n */\n\nfunction quote(text: string): string {\n return JSON.stringify(text);\n}\n\n/**\n * Finding F8 (cross-model adversarial review): mirrors `bin/audit-log.ts`'s\n * own `[redacted: N bytes]` placeholder style EXACTLY (byte count, not a\n * hash — same convention, same wording), so a redacted stdout line and a\n * redacted (replayed-from-audit-log) line read identically. Deliberately\n * NOT imported from `audit-log.ts` itself — that module does real\n * filesystem I/O and this one is pure by design (see the module doc\n * comment above); duplicating this one small, stable string format is\n * cheaper than crossing that boundary.\n */\nfunction redactedByteCountPlaceholder(text: string): string {\n return `[redacted: ${Buffer.byteLength(text, 'utf8')} bytes]`;\n}\n\n/** Git failures are rendered only from the closed stable category set. */\nconst STABLE_GIT_ERROR_CATEGORIES = new Set([\n 'git-unavailable',\n 'git-timeout',\n 'git-output-limit',\n 'git-command-failed',\n 'workspace-root-invalid',\n 'workspace-root-conflict',\n 'workspace-not-owned',\n 'repository-root-mismatch',\n 'repository-invalid',\n 'lease-busy',\n 'ledger-invalid',\n]);\n\nfunction stableGitErrorCategory(value: string | undefined): string | undefined {\n return value !== undefined && STABLE_GIT_ERROR_CATEGORIES.has(value) ? value : undefined;\n}\n\n/** Renders one `task.progress`-derived `AgentEvent` compactly — the inner payload of a `progress`-kind `DaemonEvent`. */\nexport function formatAgentEvent(event: AgentEvent): string {\n switch (event.type) {\n case 'progress':\n return `progress: ${quote(event.text)}`;\n case 'tool_use':\n return `tool_use: ${event.tool}`;\n case 'tool_result':\n return `tool_result: ${event.tool}`;\n case 'artifact':\n return `artifact: ${event.name} (${event.contentType})`;\n case 'needs_approval':\n return `needs_approval: ${quote(event.summary)}`;\n case 'turn_end':\n return 'turn_end';\n case 'error':\n return `error: ${quote(event.message)}`;\n case 'usage': {\n const parts: string[] = [];\n if (event.inputTokens !== undefined) parts.push(`in=${event.inputTokens}`);\n if (event.outputTokens !== undefined) parts.push(`out=${event.outputTokens}`);\n if (event.totalTokens !== undefined) parts.push(`total=${event.totalTokens}`);\n return `usage: ${parts.length ? parts.join(' ') : '(no fields reported)'}`;\n }\n }\n}\n\nexport interface FormatDaemonEventLineOptions {\n /**\n * Finding F8 (cross-model adversarial review): redact an\n * `awaiting-approval` event's `summary` to a `[redacted: N bytes]`\n * placeholder instead of the raw text. `summary` can carry the exact\n * tool-call text (a shell command, a file's contents) a `confirm`-mode\n * policy is gating — `start.ts`'s stdout is captured verbatim by\n * launchd/systemd/WinSW service logs, which have no business holding\n * that. Default `false` (full fidelity) — every OTHER caller\n * (`tasks --follow`'s control-socket path, which is authenticated;\n * and its audit-log-tailing fallback, whose events are ALREADY redacted\n * at the source by `audit-log.ts` regardless of this flag) keeps showing\n * whatever it already legitimately can. Only `bin/commands/start.ts`\n * sets this to `true`.\n */\n redactApprovalSummary?: boolean;\n}\n\n/**\n * One line per `DaemonEvent`. Shared by `start` (printed to stdout live\n * while it runs) and `tasks --follow` (tailing the identical shape back out\n * of the audit log) so the two ways of watching the same feed read\n * identically.\n */\nexport function formatDaemonEventLine(event: DaemonEvent, options: FormatDaemonEventLineOptions = {}): string {\n const prefix = `[${event.ts}]`;\n switch (event.kind) {\n case 'offered':\n return `${prefix} offered taskId=${event.taskId}${event.runtime ? ` runtime=${event.runtime}` : ''}`;\n case 'claimed':\n return `${prefix} claimed taskId=${event.taskId}${event.claimedRuntime !== undefined ? ` claimedRuntime=${event.claimedRuntime}` : ''}`;\n case 'started':\n return `${prefix} started taskId=${event.taskId}`;\n case 'progress':\n return `${prefix} progress taskId=${event.taskId} ${formatAgentEvent(event.event)}`;\n case 'artifact':\n return `${prefix} artifact taskId=${event.taskId} name=${event.name} contentType=${event.contentType}`;\n case 'awaiting-approval': {\n // Finding F4: approvalId is what an operator actually needs to call\n // `approve`/`reject`/`approvals` against this pending decision —\n // omitted (rather than shown as e.g. \"approvalId=undefined\") for the\n // rare event with none, so the plain-text shape never implies a\n // literal \"undefined\" id exists.\n // Finding F8: see `FormatDaemonEventLineOptions.redactApprovalSummary`'s\n // own doc comment.\n const summary = options.redactApprovalSummary ? redactedByteCountPlaceholder(event.summary) : event.summary;\n return `${prefix} awaiting-approval taskId=${event.taskId}${event.approvalId ? ` approvalId=${event.approvalId}` : ''} summary=${quote(summary)}`;\n }\n case 'completed':\n return `${prefix} completed taskId=${event.taskId} sessionRef=${event.sessionRef} summary=${quote(event.summary)}`;\n case 'failed':\n return `${prefix} failed taskId=${event.taskId} retryable=${event.retryable}${event.preClaim ? ' preClaim=true' : ''} reason=${quote(event.reason)}`;\n case 'cancelled':\n return `${prefix} cancelled taskId=${event.taskId}${event.reason ? ` reason=${quote(event.reason)}` : ''}`;\n case 'connection':\n return `${prefix} connection state=${event.state}`;\n case 'paired':\n return `${prefix} paired deviceId=${event.deviceId}`;\n case 'unpaired':\n return `${prefix} unpaired`;\n case 'runtimes-detected':\n return `${prefix} runtimes-detected ids=${event.runtimes.map((r) => r.id).join(',') || '(none)'}`;\n case 'shutdown-requested':\n return `${prefix} shutdown-requested reason=${quote(event.reason)}`;\n case 'shutdown-complete':\n // Finding F5(b): undeliveredOutboxCount is an honest audit signal\n // (0 = drain genuinely finished; >0 = that many envelopes, e.g. a\n // task.fail, never actually left the outbox) — rendered whenever\n // defined (including 0), distinct from an older audit entry that\n // predates this fix and simply has no such field at all.\n return `${prefix} shutdown-complete reason=${quote(event.reason)}${event.undeliveredOutboxCount !== undefined ? ` undeliveredOutboxCount=${event.undeliveredOutboxCount}` : ''}`;\n case 'stale-approval-decision':\n return `${prefix} stale-approval-decision taskId=${event.taskId} decision=${event.decision}${event.reason ? ` reason=${quote(event.reason)}` : ''}`;\n case 'git-workspace': {\n const parts = [\n `${prefix} git-workspace taskId=${event.taskId}`,\n `workspaceId=${event.workspaceId}`,\n `phase=${event.phase}`,\n event.headChanged !== undefined ? `headChanged=${event.headChanged}` : undefined,\n event.commitsSinceBaseline !== undefined ? `commits=${event.commitsSinceBaseline}` : undefined,\n event.dirty ? `dirty=${event.dirty.staged}/${event.dirty.unstaged}/${event.dirty.untracked}/${event.dirty.conflicted}` : undefined,\n stableGitErrorCategory(event.errorCategory) ? `errorCategory=${stableGitErrorCategory(event.errorCategory)}` : undefined,\n ].filter((part): part is string => part !== undefined);\n return parts.join(' ');\n }\n }\n}\n\nexport function formatTaskLine(task: DaemonTaskInfo | DerivedTaskInfo): string {\n const git = 'git' in task ? task.git : undefined;\n const gitStatus = git\n ? [\n `git=${git.phase}`,\n git.commitsSinceBaseline !== undefined ? `commits=${git.commitsSinceBaseline}` : undefined,\n git.dirty ? `dirty=${git.dirty.staged}/${git.dirty.unstaged}/${git.dirty.untracked}/${git.dirty.conflicted}` : undefined,\n ].filter((part): part is string => part !== undefined).join(' ')\n : undefined;\n const parts = [\n task.taskId,\n task.state,\n task.runtime ? `runtime=${task.runtime}` : undefined,\n gitStatus,\n task.claimedRuntime !== undefined ? `claimedRuntime=${task.claimedRuntime}` : undefined,\n `updatedAt=${task.updatedAt}`,\n task.sessionRef ? `sessionRef=${task.sessionRef}` : undefined,\n task.declined ? 'declined=true' : undefined,\n task.summary ? `summary=${quote(task.summary)}` : undefined,\n ].filter((part): part is string => Boolean(part));\n return parts.join(' ');\n}\n\nexport function formatTaskListLines(tasks: readonly (DaemonTaskInfo | DerivedTaskInfo)[]): string[] {\n if (tasks.length === 0) return ['(no tasks observed yet)'];\n return tasks.map(formatTaskLine);\n}\n\nexport function formatRuntimeLines(runtimes: readonly ProbedRuntime[]): string[] {\n if (runtimes.length === 0) return ['(no runtimes configured — check runtimeAllowlist)'];\n return runtimes.map((r) => {\n if (!r.present) return `${r.id}: absent`;\n const caps: string[] = [];\n if (r.steer) caps.push('steer');\n if (r.resume) caps.push('resume');\n const parts = [\n 'present',\n r.version ? `version=${r.version}` : undefined,\n r.authPresent !== undefined ? `authPresent=${r.authPresent}` : undefined,\n `capabilities=${caps.length ? caps.join(',') : '(none)'}`,\n `modes=${r.permissionModes.length ? r.permissionModes.join(',') : '(none)'}`,\n ].filter((part): part is string => Boolean(part));\n return `${r.id}: ${parts.join(' ')}`;\n });\n}\n\nexport interface StatusView {\n productName: string;\n productId: string;\n branding?: DaemonBranding;\n paired: boolean;\n deviceId?: string;\n connection?: { state: ConnectionState; ts: string };\n runtimes: readonly ProbedRuntime[];\n taskCounts: TaskCounts;\n auditLogPath: string;\n auditLogLineCount: number;\n}\n\nexport function formatStatusLines(view: StatusView): string[] {\n const lines: string[] = [];\n const label = view.branding?.displayName ?? view.productName;\n lines.push(`product: ${label} (${view.productId})`);\n if (view.branding?.supportUrl) lines.push(`support: ${view.branding.supportUrl}`);\n lines.push(`paired: ${view.paired ? 'yes' : 'no'}${view.deviceId ? ` deviceId=${view.deviceId}` : ''}`);\n lines.push(\n view.connection\n ? `connection: last-known=${view.connection.state} at=${view.connection.ts}`\n : 'connection: unknown (no audit log yet — run `byok-agent start` at least once to begin observing)',\n );\n const runtimeSummary = view.runtimes.map((r) => `${r.id}=${r.present ? 'present' : 'absent'}`).join(' ');\n lines.push(`runtimes: ${runtimeSummary || '(none configured)'}`);\n const c = view.taskCounts;\n lines.push(\n `tasks: total=${c.total} offered=${c.Offered} claimed=${c.Claimed} running=${c.Running} awaitApproval=${c.AwaitApproval} complete=${c.Complete} failed=${c.Failed} cancelled=${c.Cancelled}`,\n );\n lines.push(`audit-log: ${view.auditLogPath} (${view.auditLogLineCount} event${view.auditLogLineCount === 1 ? '' : 's'})`);\n return lines;\n}\n\n/**\n * M4 Phase 2: renders the control socket's live `status` result — appended\n * after {@link formatStatusLines}' persisted-state view when a running\n * daemon is actually reachable (see `bin/commands/status.ts`). Every line\n * is prefixed `live-` (or is the single `live:` summary line) so it's\n * unambiguous which lines are a live snapshot of a running process versus\n * the historical/persisted view above them.\n */\nexport function formatLiveStatusLines(live: ControlStatusResult): string[] {\n const lines: string[] = [\n `live: pid=${live.pid} uptimeMs=${live.uptimeMs} transport=${live.transport}`,\n `live-paired: ${live.paired ? 'yes' : 'no'}${live.deviceId ? ` deviceId=${live.deviceId}` : ''}`,\n `live-runtimes: ${live.runtimeIds.length ? live.runtimeIds.join(',') : '(none)'}`,\n ];\n const health = live.operationalHealth;\n if (health.availability === 'unavailable') {\n lines.push(`live-operational-health: unavailable reason=${quote(health.reason)}`);\n } else {\n lines.push(\n `live-operational-health: state=${health.state} failures=${health.failureCount}/${health.failureThreshold} windowMs=${health.windowMs} crashes=${health.crashCount}${health.lastCrashAt ? ` lastCrashAt=${health.lastCrashAt}` : ''}`,\n );\n }\n if (live.activeTasks.length === 0) {\n lines.push('live-active-tasks: (none)');\n } else {\n for (const task of live.activeTasks) {\n lines.push(`live-active-task: ${task.taskId} ${task.state}`);\n }\n }\n // M4 Phase 4 (part B.3): queue watermarks — see ControlStatusResult's own\n // doc comment (control-protocol.ts) for why this is a progress-batcher\n // backlog + in-flight-approval-count proxy, not the adapter's own event\n // queue depth.\n lines.push(`live-approvals-pending: ${live.approvalsPending}`);\n // Finding F4: the actual pending approvals (not just the count above) —\n // an operator can read an approvalId straight off `status` without also\n // running the dedicated `approvals` command. Kept compact (no `age`\n // column, unlike `formatApprovalsListLines`'s dedicated listing) since\n // this is one section of a bigger status view, not a purpose-built table.\n if (live.approvals.length === 0) {\n lines.push('live-approvals: (none)');\n } else {\n for (const approval of live.approvals) {\n lines.push(`live-approval: ${approval.approvalId} taskId=${approval.taskId} summary=${quote(summaryExcerpt(approval.summary))}`);\n }\n }\n if (live.queueWatermarks.length === 0) {\n lines.push('live-queue-watermarks: (none)');\n } else {\n for (const watermark of live.queueWatermarks) {\n lines.push(\n `live-queue-watermark: ${watermark.taskId} progressBatcherPending=${watermark.progressBatcherPending} pendingApprovals=${watermark.pendingApprovals}`,\n );\n }\n }\n // S3b (L-003): local storage usage and pressure (§12.7.2.1). Rendered ONLY\n // when the daemon actually measures it — a daemon with no storage policy\n // configured emits nothing here rather than a row of zeros, so this section\n // appearing at all means the numbers in it are real. Deliberately printed\n // after the queue watermarks, and named `live-storage-*`: these two sections\n // are unrelated, and the adjacency is the whole reason the names must not\n // both say \"watermark\".\n const storage = live.storage;\n if (storage !== undefined) {\n lines.push(\n `live-storage: state=${storage.pressureState} used=${storage.usedBytes} budget=${storage.budgetBytes} free=${storage.freeBytes} measuredAt=${storage.measuredAt}`,\n );\n for (const category of storage.categories) {\n lines.push(`live-storage-category: ${category.category} bytes=${category.bytes}${category.approximate ? ' (approximate)' : ''}`);\n }\n if (storage.lastCompaction) {\n lines.push(\n `live-storage-compaction: checkpointed=${storage.lastCompaction.checkpointed} walFramesRemaining=${storage.lastCompaction.walFramesRemaining} pagesVacuumed=${storage.lastCompaction.pagesVacuumed} durationMs=${storage.lastCompaction.durationMs} at=${storage.lastCompaction.at}`,\n );\n }\n }\n return lines;\n}\n\n/** Cap on a rendered approval summary's length before truncating with an ellipsis — these can be arbitrarily long tool-input dumps (see `docs/security.md`'s F8 note on why the FULL summary is only ever shown over the authenticated control socket, never service-log stdout); this is purely a display-width concern for a CLI table, not a redaction. */\nconst SUMMARY_EXCERPT_MAX_LEN = 60;\n\nfunction summaryExcerpt(summary: string | undefined): string {\n if (!summary) return '(no summary)';\n return summary.length > SUMMARY_EXCERPT_MAX_LEN ? `${summary.slice(0, SUMMARY_EXCERPT_MAX_LEN)}…` : summary;\n}\n\n/** `Date.parse(createdAt)` failing (or an implausible clock skew making `nowMs - created` negative) never renders a negative/NaN age — clamped to 0 rather than surfacing an internal computation artifact in operator-facing output. */\nfunction formatAge(ms: number): string {\n const totalSeconds = Math.floor(Math.max(0, ms) / 1000);\n if (totalSeconds < 60) return `${totalSeconds}s`;\n const totalMinutes = Math.floor(totalSeconds / 60);\n if (totalMinutes < 60) return `${totalMinutes}m`;\n const totalHours = Math.floor(totalMinutes / 60);\n if (totalHours < 24) return `${totalHours}h`;\n const totalDays = Math.floor(totalHours / 24);\n return `${totalDays}d`;\n}\n\n/**\n * Finding F4: renders `approvals.list`'s registry entries for the new\n * `byok-agent approvals` command (`bin/commands/approvals.ts`) — columns\n * approvalId, taskId, age, summary excerpt, per that finding's own spec.\n * `nowMs` is injected (rather than read via `Date.now()` here) so tests get\n * deterministic age rendering; the real caller passes `Date.now()`.\n */\nexport function formatApprovalsListLines(approvals: readonly PendingApproval[], nowMs: number): string[] {\n if (approvals.length === 0) return ['(no pending approvals)'];\n return approvals.map((approval) => {\n const ageMs = nowMs - Date.parse(approval.createdAt);\n return `${approval.approvalId} taskId=${approval.taskId} age=${formatAge(ageMs)} summary=${quote(summaryExcerpt(approval.summary))}`;\n });\n}\n","import { ControlError, type ApprovalsListResult } from '../../daemon/control-protocol';\nimport { connectControlClient } from '../control-client';\nimport { formatApprovalsListLines } from '../format';\n\nexport interface ApprovalsListDeps {\n log?: (line: string) => void;\n error?: (line: string) => void;\n /** DI for tests: substitute the real control-socket connection attempt. */\n connectControl?: typeof connectControlClient;\n /** DI for tests: pin \"now\" for deterministic age rendering — see `formatApprovalsListLines`. */\n now?: () => number;\n}\n\n/**\n * Finding F4 (cross-model adversarial review): `byok-agent approvals` —\n * before this command existed, an operator had no way to ever learn a\n * pending approval's `approvalId` short of reading raw `audit.jsonl`\n * entries by hand (and even that only worked if the daemon happened to\n * surface one there at all): `approve`/`reject` both *require* an\n * `approvalId`, but nothing in this CLI ever printed one.\n *\n * Lists the control socket's `approvals.list` result — the exact same\n * `ApprovalRegistry` entries `approve`/`reject` resolve against\n * (`create-daemon.ts`'s method registry, backed by `daemon/approvals.ts`) —\n * as one line per pending approval: `approvalId`, `taskId`, `age`, and a\n * (possibly truncated — see `formatApprovalsListLines`) summary excerpt.\n *\n * No persisted-state fallback, mirroring `approve`/`reject`\n * (`commands/approve-reject.ts`): a pending approval only ever means\n * anything against a LIVE daemon, so daemon-unreachable is reported as a\n * clear, specific error (and this command exits non-zero) rather than a\n * silent \"no approvals\" — those are different outcomes and a script\n * parsing this output needs to be able to tell them apart.\n */\nexport async function runApprovalsCommand(storeDir: string, productId: string, deps: ApprovalsListDeps = {}): Promise<void> {\n const log = deps.log ?? ((line: string) => console.log(line));\n const error = deps.error ?? ((line: string) => console.error(line));\n const connectControl = deps.connectControl ?? connectControlClient;\n const now = deps.now ?? (() => Date.now());\n\n const conn = await connectControl({ storeDir, productId });\n if (!conn.ok) {\n const message = `cannot list approvals: daemon not reachable (${conn.reason}) — is \\`byok-agent start\\` (or the installed service) running?`;\n error(message);\n throw new Error(message);\n }\n\n try {\n const result = await conn.client.request<ApprovalsListResult>('approvals.list');\n for (const line of formatApprovalsListLines(result.approvals, now())) log(line);\n } catch (err) {\n if (err instanceof ControlError) {\n error(`approvals list failed: ${err.message}`);\n } else {\n error(`approvals list failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n throw err;\n } finally {\n conn.client.close();\n }\n}\n","import { ControlError } from '../../daemon/control-protocol';\nimport { connectControlClient } from '../control-client';\n\nexport interface ApproveRejectDeps {\n log?: (line: string) => void;\n error?: (line: string) => void;\n /** DI for tests: substitute the real control-socket connection attempt. */\n connectControl?: typeof connectControlClient;\n}\n\n/**\n * M4 Phase 2: `approve`/`reject` now genuinely work from a separate,\n * short-lived CLI invocation — they call the control socket's\n * `approvals.resolve` method (`create-daemon.ts`'s method registry, backed\n * by `daemon/approvals.ts`'s `ApprovalRegistry`) rather than requiring a\n * `Daemon` this same process just started (which never worked at all: see\n * git history for the pre-M4 version of this module, which called\n * `daemon.approve`/`daemon.reject` directly and always failed with\n * \"daemon is not started\" for exactly that reason — `byok-agent.ts` used to\n * not even dispatch to these commands as a result).\n *\n * Still honest about what these can resolve TODAY: no bundled runtime\n * adapter (pi/claude/codex) raises an approval yet (see `create-daemon.ts`'s\n * `toRuntimeInfoCapabilities` doc comment), so nothing ever calls\n * `ApprovalRegistry.register()` in this SDK version — every `approve`/\n * `reject` against a real daemon today resolves to the registry's own\n * `not_found` error, UNLESS the daemon isn't reachable at all, in which case\n * that's reported first. Both failure modes are reported with a clear,\n * specific message rather than a generic \"not started\" one.\n */\nexport async function runApproveCommand(\n storeDir: string,\n productId: string,\n approvalId: string,\n deps: ApproveRejectDeps = {},\n): Promise<void> {\n return resolveApproval(storeDir, productId, approvalId, 'approve', undefined, deps);\n}\n\nexport async function runRejectCommand(\n storeDir: string,\n productId: string,\n approvalId: string,\n reason: string | undefined,\n deps: ApproveRejectDeps = {},\n): Promise<void> {\n return resolveApproval(storeDir, productId, approvalId, 'reject', reason, deps);\n}\n\nasync function resolveApproval(\n storeDir: string,\n productId: string,\n approvalId: string,\n decision: 'approve' | 'reject',\n reason: string | undefined,\n deps: ApproveRejectDeps,\n): Promise<void> {\n const log = deps.log ?? ((line: string) => console.log(line));\n const error = deps.error ?? ((line: string) => console.error(line));\n const connectControl = deps.connectControl ?? connectControlClient;\n const verb = decision === 'approve' ? 'approved' : 'rejected';\n\n const conn = await connectControl({ storeDir, productId });\n if (!conn.ok) {\n const message = `cannot ${decision} approvalId=${approvalId}: daemon not reachable (${conn.reason}) — is \\`byok-agent start\\` (or the installed service) running?`;\n error(message);\n throw new Error(message);\n }\n\n try {\n await conn.client.request('approvals.resolve', { approvalId, decision, reason });\n log(`${verb}: approvalId=${approvalId}${reason ? ` reason=${JSON.stringify(reason)}` : ''}`);\n } catch (err) {\n if (err instanceof ControlError && err.code === 'not_found') {\n // Finding F4: an unknown/already-resolved approvalId is exactly the\n // moment an operator needs pointing at the ONE command that lists\n // valid ones (`byok-agent approvals`) — before that command existed,\n // there was no way to learn a correct id short of raw audit-log JSON.\n // `err` itself (re-thrown below, unchanged) still carries the\n // original message alone; this hint is rendered-output-only.\n error(`${err.message} — run \\`byok-agent approvals\\` to see pending approvalIds`);\n } else {\n error(`${decision} failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n throw err;\n } finally {\n conn.client.close();\n }\n}\n","import { createDaemon, type Daemon, type DaemonConfig } from '../../index';\n\nexport interface PairDeps {\n log?: (line: string) => void;\n /** DI for tests: skip constructing a real `createDaemon(config)` and drive a stub/pre-built instance instead. */\n daemon?: Pick<Daemon, 'pair'>;\n}\n\nexport async function runPairCommand(config: DaemonConfig, code: string, deps: PairDeps = {}): Promise<void> {\n const log = deps.log ?? ((line: string) => console.log(line));\n const daemon = deps.daemon ?? createDaemon(config);\n const result = await daemon.pair(code);\n log(`paired: deviceId=${result.deviceId}`);\n}\n","import { PiAdapter, ClaudeAdapter, CodexAdapter, type RuntimeAdapter } from '../index';\n\n/**\n * Mirrors `create-daemon.ts`'s own `buildDefaultAdapters`/`buildAdapter`/\n * `ALL_RUNTIME_IDS` (the bundled pi/claude/codex set, filtered by\n * `DaemonConfig.runtimeAllowlist`) — NOT a call into that file, which isn't\n * exported and is out of this change's scope to edit. Small enough (3 ids)\n * that duplicating it here beats reaching into `create-daemon.ts`'s\n * internals; if the two ever drift, `create-daemon-white-label.test.ts`'s\n * own allowlist coverage is the tell.\n */\nconst ALL_RUNTIME_IDS = ['pi', 'claude', 'codex'] as const;\nexport const RUNTIME_PROBE_TIMEOUT_MS = 5_000;\nconst MAX_RUNTIME_ID_CHARS = 128;\nconst MAX_RUNTIME_VERSION_CHARS = 256;\nconst MAX_PERMISSION_MODES = 32;\nconst MAX_PERMISSION_MODE_CHARS = 64;\n\nfunction boundedSingleLine(value: string, maxChars: number): string {\n return value.replace(/[\\r\\n\\t]/g, ' ').slice(0, maxChars);\n}\n\nasync function detectWithTimeout(adapter: RuntimeAdapter, timeoutMs: number): ReturnType<RuntimeAdapter['detect']> {\n let timer: NodeJS.Timeout | undefined;\n try {\n return await Promise.race([\n adapter.detect(),\n new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => reject(new Error('runtime detection timed out')), timeoutMs);\n timer.unref?.();\n }),\n ]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\n/** The bundled adapter set `byok-agent status`/`byok-agent runtimes` probe by default — same unset-vs-set allowlist contract as `createDaemon` itself. */\nexport function defaultRuntimeAdapters(runtimeAllowlist: string[] | undefined): RuntimeAdapter[] {\n const ids = runtimeAllowlist ? ALL_RUNTIME_IDS.filter((id) => runtimeAllowlist.includes(id)) : ALL_RUNTIME_IDS;\n return ids.map((id) => {\n switch (id) {\n case 'pi':\n return new PiAdapter();\n case 'claude':\n return new ClaudeAdapter();\n case 'codex':\n return new CodexAdapter();\n }\n });\n}\n\n/**\n * What `byok-agent status`/`byok-agent runtimes` show per runtime — a\n * flattened, display-ready merge of `RuntimeDetectResult` and\n * `RuntimeCapabilities` (see `../types.ts`). Always probed fresh (this\n * module never reads from the daemon or the audit log) — see\n * `byok-agent.ts`'s header comment for why a live, standalone probe is the\n * honest choice for \"what's on this machine right now\" instead of a\n * historical snapshot.\n */\nexport interface ProbedRuntime {\n id: string;\n present: boolean;\n version?: string;\n authPresent?: boolean;\n steer: boolean;\n resume: boolean;\n permissionModes: string[];\n}\n\n/**\n * Runs `detect()`/`capabilities()` on each adapter, in parallel. Every\n * bundled adapter's own `detect()` already catches its own failures (e.g.\n * `pi-adapter.ts`'s `detect()` wraps its version probe in try/catch and\n * resolves `{present: false}` rather than rejecting) — the catch here is a\n * defensive backstop for a `RuntimeAdapter` that doesn't hold that\n * convention, not a workaround for an observed failure in the bundled\n * three.\n */\nexport async function probeRuntimes(\n adapters: readonly RuntimeAdapter[],\n options: { timeoutMs?: number } = {},\n): Promise<ProbedRuntime[]> {\n const timeoutMs = options.timeoutMs ?? RUNTIME_PROBE_TIMEOUT_MS;\n if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0) throw new Error('runtime probe timeout must be a positive integer');\n return Promise.all(\n adapters.map(async (adapter): Promise<ProbedRuntime> => {\n let id = 'unavailable';\n let steer = false;\n let resume = false;\n let permissionModes: string[] = [];\n try {\n id = boundedSingleLine(adapter.id, MAX_RUNTIME_ID_CHARS);\n const caps = adapter.capabilities();\n steer = caps.steer === true;\n resume = caps.resume === true;\n permissionModes = caps.permissionModes\n .slice(0, MAX_PERMISSION_MODES)\n .map((mode) => boundedSingleLine(mode, MAX_PERMISSION_MODE_CHARS));\n const detected = await detectWithTimeout(adapter, timeoutMs);\n return {\n id,\n present: detected.present === true,\n ...(detected.version === undefined\n ? {}\n : { version: boundedSingleLine(detected.version, MAX_RUNTIME_VERSION_CHARS) }),\n ...(typeof detected.authPresent === 'boolean' ? { authPresent: detected.authPresent } : {}),\n steer,\n resume,\n permissionModes,\n };\n } catch {\n return { id, present: false, steer, resume, permissionModes };\n }\n }),\n );\n}\n","import { createHash, randomUUID } from 'node:crypto';\nimport {\n closeSync,\n constants as fsConstants,\n fchmodSync,\n fsyncSync,\n fstatSync,\n linkSync,\n lstatSync,\n openSync,\n opendirSync,\n readSync,\n unlinkSync,\n writeFileSync,\n} from 'node:fs';\nimport { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type { DaemonConfig, RuntimeAdapter } from '../index';\nimport { connectControlClient } from '../bin/control-client';\nimport { defaultRuntimeAdapters, probeRuntimes } from '../bin/runtime-probe';\nimport type { ControlStatusResult } from '../daemon/control-protocol';\nimport { JOURNAL_DB_FILENAME, JOURNAL_QUARANTINE_DIRNAME } from '../daemon/journal/sqlite-journal';\nimport { isSqliteAvailable, loadSqliteModule } from '../daemon/journal/sqlite-support';\nimport {\n inspectOperationalHealthHandle,\n inspectOperationalHealthFile,\n MAX_OPERATIONAL_HEALTH_FILE_BYTES,\n openOperationalHealthFile,\n type OperationalHealthFileInspection,\n OPERATIONAL_HEALTH_FILENAME,\n} from '../daemon/operational-health';\nimport { acquireDaemonOwner } from '../daemon/daemon-owner';\nimport { ensureSecureDir } from '../util/secure-dir';\n\nexport const MAX_QUARANTINE_ENTRIES = 100;\n// Inventory validation is synchronous while the checked quarantine directory\n// inode is cwd-pinned. Two entries are needed for each health evidence pair;\n// bounding the scan to 2x the public 100-entry output cap keeps worst-case\n// digest work near 100 MiB instead of the former ~10.38 GiB.\nexport const MAX_QUARANTINE_SCAN_ENTRIES = MAX_QUARANTINE_ENTRIES * 2;\nexport const MAX_QUARANTINE_READ_BYTES = 128 * 1024 * 1024;\nexport const MAX_DEVICE_RECORD_BYTES = 64 * 1024;\nexport const MAX_JOURNAL_COPY_BYTES = 512 * 1024 * 1024;\nconst MAX_QUARANTINE_MANIFEST_BYTES = 64 * 1024;\n\nexport type DiagnosticStatus = 'pass' | 'warn' | 'fail';\n\nexport interface DiagnosticCheck {\n id: 'config' | 'device' | 'runtimes' | 'control' | 'health' | 'journal' | 'workspace' | 'quarantine';\n status: DiagnosticStatus;\n summary: string;\n}\n\nexport interface DiagnosticsSnapshot {\n version: 1;\n generatedAt: string;\n product: { nameHash: string; idHash: string };\n system: { node: string; platform: NodeJS.Platform; arch: string; sqliteAvailable: boolean };\n config: {\n serverProtocol: 'http' | 'https' | 'ws' | 'wss' | 'invalid' | 'unsupported';\n customStoreDir: boolean;\n hostedJournal: boolean;\n runtimeAllowlistCount?: number;\n };\n device: { status: 'paired' | 'unpaired' | 'unavailable'; deviceIdHash?: string };\n runtimes: Array<{\n idHash: string;\n present: boolean;\n versionPresent: boolean;\n authPresent?: boolean;\n steer: boolean;\n resume: boolean;\n permissionModeCount: number;\n }>;\n control:\n | { status: 'offline'; reason: string }\n | {\n status: 'online';\n pid: number;\n uptimeMs: number;\n transport: string;\n activeTaskCount: number;\n pendingApprovalCount: number;\n operationalHealth: ControlStatusResult['operationalHealth'];\n storage?: ControlStatusResult['storage'];\n };\n health: OperationalHealthFileInspection;\n journal: {\n status: 'missing' | 'present' | 'corrupt' | 'unavailable';\n sizeBytes?: number;\n walBytes?: number;\n integrity?: 'ok' | 'not-checked';\n reason?: string;\n };\n workspace: { status: 'available' | 'missing' | 'unavailable'; writable?: boolean; reason?: string };\n quarantine: {\n status: 'available' | 'missing' | 'unavailable';\n count: number;\n scannedCount: number;\n truncated: boolean;\n entries: Array<{ nameHash: string; sizeBytes: number; modifiedAt: string }>;\n reason?: string;\n };\n checks: DiagnosticCheck[];\n}\n\nexport interface CollectDiagnosticsOptions {\n clock?: () => Date;\n adapters?: RuntimeAdapter[];\n connectControl?: typeof connectControlClient;\n runtimeProbeTimeoutMs?: number;\n}\n\nexport type OperationalHealthFixResult =\n | { status: 'not-needed'; reason: 'missing' | 'valid' }\n | { status: 'quarantined'; evidenceName: string; manifestName: string; sha256: string; sizeBytes: number };\n\nfunction safeProtocol(serverUrl: string): DiagnosticsSnapshot['config']['serverProtocol'] {\n try {\n const protocol = new URL(serverUrl).protocol.replace(/:$/, '');\n return protocol === 'http' || protocol === 'https' || protocol === 'ws' || protocol === 'wss' ? protocol : 'unsupported';\n } catch {\n return 'invalid';\n }\n}\n\nasync function fileSize(filePath: string): Promise<number | undefined> {\n try {\n const stat = await fs.stat(filePath);\n return stat.isFile() ? stat.size : undefined;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw err;\n }\n}\n\nasync function inspectDevice(storeDir: string): Promise<DiagnosticsSnapshot['device']> {\n const filePath = path.join(storeDir, 'device.json');\n let pathStat: import('node:fs').Stats;\n try {\n pathStat = await fs.lstat(filePath);\n if (!pathStat.isFile()) return { status: 'unavailable' };\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return { status: 'unpaired' };\n return { status: 'unavailable' };\n }\n let handle: Awaited<ReturnType<typeof fs.open>>;\n try {\n handle = await fs.open(\n filePath,\n fsConstants.O_RDONLY | fsConstants.O_NONBLOCK | (fsConstants.O_NOFOLLOW ?? 0),\n );\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return { status: 'unpaired' };\n return { status: 'unavailable' };\n }\n try {\n const stat = await handle.stat();\n const namedAfterOpen = await fs.lstat(filePath);\n if (\n !stat.isFile() ||\n !namedAfterOpen.isFile() ||\n namedAfterOpen.isSymbolicLink() ||\n stat.dev !== pathStat.dev ||\n stat.ino !== pathStat.ino ||\n stat.size !== pathStat.size ||\n stat.mtimeMs !== pathStat.mtimeMs ||\n stat.ctimeMs !== pathStat.ctimeMs ||\n stat.dev !== namedAfterOpen.dev ||\n stat.ino !== namedAfterOpen.ino ||\n stat.size !== namedAfterOpen.size ||\n stat.mtimeMs !== namedAfterOpen.mtimeMs ||\n stat.ctimeMs !== namedAfterOpen.ctimeMs ||\n stat.size <= 0 ||\n stat.size > MAX_DEVICE_RECORD_BYTES\n ) return { status: 'unavailable' };\n const bytes = Buffer.alloc(stat.size);\n const { bytesRead } = await handle.read(bytes, 0, bytes.length, 0);\n const after = await handle.stat();\n const namedAfterRead = await fs.lstat(filePath);\n if (\n bytesRead !== bytes.length ||\n after.dev !== stat.dev ||\n after.ino !== stat.ino ||\n after.size !== stat.size ||\n after.mtimeMs !== stat.mtimeMs ||\n after.ctimeMs !== stat.ctimeMs ||\n namedAfterRead.dev !== stat.dev ||\n namedAfterRead.ino !== stat.ino ||\n namedAfterRead.size !== stat.size ||\n namedAfterRead.mtimeMs !== stat.mtimeMs ||\n namedAfterRead.ctimeMs !== stat.ctimeMs\n ) {\n return { status: 'unavailable' };\n }\n const parsed = JSON.parse(bytes.toString('utf8')) as Record<string, unknown>;\n return typeof parsed.deviceId === 'string' && parsed.deviceId.length > 0\n ? { status: 'paired', deviceIdHash: stableIdentifierHash(parsed.deviceId) }\n : { status: 'unavailable' };\n } catch {\n return { status: 'unavailable' };\n } finally {\n await handle.close();\n }\n}\n\ninterface FileIdentity {\n dev: bigint;\n ino: bigint;\n size: bigint;\n mtimeNs: bigint;\n ctimeNs: bigint;\n}\n\nasync function regularFileIdentity(filePath: string): Promise<FileIdentity | undefined> {\n try {\n const stat = await fs.lstat(filePath, { bigint: true });\n if (!stat.isFile()) throw new Error('journal component is not a regular file');\n return { dev: stat.dev, ino: stat.ino, size: stat.size, mtimeNs: stat.mtimeNs, ctimeNs: stat.ctimeNs };\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw err;\n }\n}\n\nfunction sameIdentity(left: FileIdentity | undefined, right: FileIdentity | undefined): boolean {\n if (!left || !right) return left === right;\n return (\n left.dev === right.dev &&\n left.ino === right.ino &&\n left.size === right.size &&\n left.mtimeNs === right.mtimeNs &&\n left.ctimeNs === right.ctimeNs\n );\n}\n\nfunction identityFromBigIntStat(stat: {\n dev: bigint;\n ino: bigint;\n size: bigint;\n mtimeNs: bigint;\n ctimeNs: bigint;\n}): FileIdentity {\n return { dev: stat.dev, ino: stat.ino, size: stat.size, mtimeNs: stat.mtimeNs, ctimeNs: stat.ctimeNs };\n}\n\nasync function copyOpenFileBounded(\n source: Awaited<ReturnType<typeof fs.open>>,\n expected: FileIdentity,\n destinationPath: string,\n): Promise<boolean> {\n const destination = await fs.open(destinationPath, 'wx', 0o600);\n try {\n const buffer = Buffer.allocUnsafe(64 * 1024);\n const expectedBytes = Number(expected.size);\n let position = 0;\n while (position < expectedBytes) {\n const length = Math.min(buffer.length, expectedBytes - position);\n const { bytesRead } = await source.read(buffer, 0, length, position);\n if (bytesRead === 0) return false;\n let written = 0;\n while (written < bytesRead) {\n const result = await destination.write(buffer, written, bytesRead - written, position + written);\n if (result.bytesWritten === 0) throw new Error('diagnostics snapshot destination stopped accepting bytes');\n written += result.bytesWritten;\n }\n position += bytesRead;\n }\n await destination.sync();\n return sameIdentity(expected, identityFromBigIntStat(await source.stat({ bigint: true })));\n } finally {\n await destination.close();\n }\n}\n\nasync function inspectJournal(storeDir: string): Promise<DiagnosticsSnapshot['journal']> {\n const journalPath = path.join(storeDir, JOURNAL_DB_FILENAME);\n try {\n const mainIdentity = await regularFileIdentity(journalPath);\n if (mainIdentity === undefined) return { status: 'missing' };\n const walIdentity = await regularFileIdentity(path.join(storeDir, `${JOURNAL_DB_FILENAME}-wal`));\n let sizeBytes = Number(mainIdentity.size);\n let walBytes = walIdentity === undefined ? undefined : Number(walIdentity.size);\n if (!isSqliteAvailable()) {\n return { status: 'present', sizeBytes, ...(walBytes === undefined ? {} : { walBytes }), integrity: 'not-checked' };\n }\n const componentNames = [JOURNAL_DB_FILENAME, `${JOURNAL_DB_FILENAME}-wal`, `${JOURNAL_DB_FILENAME}-shm`] as const;\n const initial = new Map<string, FileIdentity | undefined>();\n for (const name of componentNames) initial.set(name, await regularFileIdentity(path.join(storeDir, name)));\n const snapshotMain = initial.get(JOURNAL_DB_FILENAME);\n if (!snapshotMain) return { status: 'unavailable', reason: 'journal changed during diagnostics snapshot' };\n sizeBytes = Number(snapshotMain.size);\n walBytes = initial.get(`${JOURNAL_DB_FILENAME}-wal`) === undefined\n ? undefined\n : Number(initial.get(`${JOURNAL_DB_FILENAME}-wal`)!.size);\n const opened = new Map<string, { handle: Awaited<ReturnType<typeof fs.open>>; identity: FileIdentity }>();\n let totalBytes = 0n;\n try {\n for (const name of componentNames) {\n let handle: Awaited<ReturnType<typeof fs.open>>;\n try {\n handle = await fs.open(\n path.join(storeDir, name),\n fsConstants.O_RDONLY | fsConstants.O_NONBLOCK | (fsConstants.O_NOFOLLOW ?? 0),\n );\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT' && name !== JOURNAL_DB_FILENAME) continue;\n throw err;\n }\n const stat = await handle.stat({ bigint: true });\n if (!stat.isFile()) {\n await handle.close();\n throw new Error('journal component is not a regular file');\n }\n const identity = identityFromBigIntStat(stat);\n if (!sameIdentity(initial.get(name), identity)) {\n await handle.close();\n return { status: 'unavailable', sizeBytes, ...(walBytes === undefined ? {} : { walBytes }), reason: 'journal changed during diagnostics snapshot' };\n }\n totalBytes += identity.size;\n opened.set(name, { handle, identity });\n }\n if (totalBytes > BigInt(MAX_JOURNAL_COPY_BYTES)) {\n return {\n status: 'present',\n sizeBytes,\n ...(walBytes === undefined ? {} : { walBytes }),\n integrity: 'not-checked',\n reason: 'journal exceeds the bounded diagnostics copy limit',\n };\n }\n const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'byok-journal-inspect-'));\n const { DatabaseSync } = loadSqliteModule();\n let db: InstanceType<typeof DatabaseSync> | undefined;\n try {\n for (const name of componentNames) {\n const component = opened.get(name);\n if (component && !(await copyOpenFileBounded(component.handle, component.identity, path.join(tempDir, name)))) {\n return { status: 'unavailable', sizeBytes, ...(walBytes === undefined ? {} : { walBytes }), reason: 'journal changed during diagnostics snapshot' };\n }\n }\n for (const [name, component] of opened) {\n if (\n !sameIdentity(component.identity, identityFromBigIntStat(await component.handle.stat({ bigint: true }))) ||\n !sameIdentity(component.identity, await regularFileIdentity(path.join(storeDir, name)))\n ) {\n return { status: 'unavailable', sizeBytes, ...(walBytes === undefined ? {} : { walBytes }), reason: 'journal changed during diagnostics snapshot' };\n }\n }\n for (const name of componentNames) {\n if (!opened.has(name) && (await regularFileIdentity(path.join(storeDir, name))) !== undefined) {\n return { status: 'unavailable', sizeBytes, ...(walBytes === undefined ? {} : { walBytes }), reason: 'journal changed during diagnostics snapshot' };\n }\n }\n const header = Buffer.alloc(16);\n const copiedHandle = await fs.open(path.join(tempDir, JOURNAL_DB_FILENAME), 'r');\n try {\n const { bytesRead } = await copiedHandle.read(header, 0, header.length, 0);\n if (bytesRead !== 16 || header.toString('binary') !== 'SQLite format 3\\u0000') {\n return { status: 'corrupt', sizeBytes, ...(walBytes === undefined ? {} : { walBytes }), reason: 'journal has an invalid SQLite header' };\n }\n } finally {\n await copiedHandle.close();\n }\n db = new DatabaseSync(path.join(tempDir, JOURNAL_DB_FILENAME), { readOnly: true });\n const result = db.prepare('PRAGMA quick_check(1)').get() as { quick_check?: unknown } | undefined;\n if (result?.quick_check !== 'ok') {\n return { status: 'corrupt', sizeBytes, ...(walBytes === undefined ? {} : { walBytes }), reason: 'journal quick_check failed' };\n }\n return { status: 'present', sizeBytes, ...(walBytes === undefined ? {} : { walBytes }), integrity: 'ok' };\n } catch {\n return { status: 'unavailable', sizeBytes, ...(walBytes === undefined ? {} : { walBytes }), reason: 'journal snapshot could not be checked' };\n } finally {\n db?.close();\n await fs.rm(tempDir, { recursive: true, force: true });\n }\n } finally {\n await Promise.all([...opened.values()].map(({ handle }) => handle.close().catch(() => undefined)));\n }\n } catch {\n return { status: 'unavailable', reason: 'journal files could not be inspected' };\n }\n}\n\nasync function inspectWorkspace(workspaceRoot: string): Promise<DiagnosticsSnapshot['workspace']> {\n try {\n const stat = await fs.stat(workspaceRoot);\n if (!stat.isDirectory()) return { status: 'unavailable', reason: 'workspace root is not a directory' };\n try {\n await fs.access(workspaceRoot, fsConstants.R_OK | fsConstants.W_OK);\n return { status: 'available', writable: true };\n } catch {\n return { status: 'available', writable: false };\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return { status: 'missing' };\n return { status: 'unavailable', reason: 'workspace root could not be inspected' };\n }\n}\n\ninterface PinnedQuarantineFile {\n sizeBytes: number;\n modifiedAt: string;\n bytes?: Buffer;\n}\n\ninterface QuarantineReadBudget {\n remainingBytes: number;\n}\n\nfunction readPinnedQuarantineFile(\n name: string,\n maxBytes: number,\n includeBytes: boolean,\n budget: QuarantineReadBudget,\n): PinnedQuarantineFile {\n if (path.basename(name) !== name || name === '.' || name === '..') {\n throw new Error('quarantine manifest contains an invalid evidence name');\n }\n const namedBefore = lstatSync(name, { bigint: true });\n if (!namedBefore.isFile() || namedBefore.isSymbolicLink()) {\n throw new Error('quarantine entry is not a real regular file');\n }\n const fd = openSync(name, fsConstants.O_RDONLY | fsConstants.O_NONBLOCK | (fsConstants.O_NOFOLLOW ?? 0));\n try {\n const opened = fstatSync(fd, { bigint: true });\n if (!opened.isFile() || !sameInode(opened, namedBefore) || opened.size < 0 || opened.size > BigInt(maxBytes)) {\n throw new Error('quarantine entry could not be opened as a bounded regular file');\n }\n let bytes: Buffer | undefined;\n if (includeBytes) {\n const sizeBytes = Number(opened.size);\n if (sizeBytes > budget.remainingBytes) {\n throw new Error('quarantine validation exceeds the 128 MiB cumulative read limit');\n }\n budget.remainingBytes -= sizeBytes;\n bytes = Buffer.alloc(sizeBytes);\n let position = 0;\n while (position < bytes.length) {\n const bytesRead = readSync(fd, bytes, position, bytes.length - position, position);\n if (bytesRead === 0) throw new Error('quarantine entry ended during bounded read');\n position += bytesRead;\n }\n }\n const openedAfter = fstatSync(fd, { bigint: true });\n const namedAfter = lstatSync(name, { bigint: true });\n if (!sameFileState(openedAfter, opened) || !sameFileState(namedAfter, opened)) {\n throw new Error('quarantine entry changed during inspection');\n }\n return {\n sizeBytes: Number(opened.size),\n modifiedAt: new Date(Number(opened.mtimeMs)).toISOString(),\n ...(bytes === undefined ? {} : { bytes }),\n };\n } finally {\n closeSync(fd);\n }\n}\n\nfunction isHealthQuarantineManifest(value: unknown): value is {\n version: 1;\n quarantinedAt: string;\n reason: string;\n sourcePath: string;\n evidenceFile: string;\n sha256: string;\n sizeBytes: number;\n} {\n if (typeof value !== 'object' || value === null) return false;\n const candidate = value as Record<string, unknown>;\n return (\n candidate.version === 1 &&\n typeof candidate.quarantinedAt === 'string' &&\n Number.isFinite(Date.parse(candidate.quarantinedAt)) &&\n typeof candidate.reason === 'string' &&\n typeof candidate.sourcePath === 'string' &&\n typeof candidate.evidenceFile === 'string' &&\n typeof candidate.sha256 === 'string' &&\n /^[0-9a-f]{64}$/.test(candidate.sha256) &&\n Number.isSafeInteger(candidate.sizeBytes) &&\n (candidate.sizeBytes as number) >= 0 &&\n (candidate.sizeBytes as number) <= MAX_OPERATIONAL_HEALTH_FILE_BYTES\n );\n}\n\nfunction isJournalQuarantineManifest(value: unknown): value is {\n quarantinedAt: string;\n reason: string;\n originalPath: string;\n files: string[];\n} {\n if (typeof value !== 'object' || value === null) return false;\n const candidate = value as Record<string, unknown>;\n return (\n typeof candidate.quarantinedAt === 'string' &&\n Number.isFinite(Date.parse(candidate.quarantinedAt)) &&\n typeof candidate.reason === 'string' &&\n typeof candidate.originalPath === 'string' &&\n Array.isArray(candidate.files) &&\n candidate.files.length > 0 &&\n candidate.files.length <= 3 &&\n candidate.files.every((file) => typeof file === 'string')\n );\n}\n\nfunction inspectQuarantinePinned(\n dir: string,\n expectedDirectory: import('node:fs').BigIntStats,\n): DiagnosticsSnapshot['quarantine'] {\n const previousCwd = process.cwd();\n try {\n process.chdir(dir);\n const pinned = lstatSync('.', { bigint: true });\n if (!pinned.isDirectory() || !sameInode(pinned, expectedDirectory)) {\n throw new Error('quarantine directory changed during inspection');\n }\n const selected: import('node:fs').Dirent[] = [];\n let scanTruncated = false;\n const directory = opendirSync('.');\n try {\n for (;;) {\n const entry = directory.readSync();\n if (!entry) break;\n if (selected.length === MAX_QUARANTINE_SCAN_ENTRIES) {\n scanTruncated = true;\n break;\n }\n selected.push(entry);\n }\n } finally {\n directory.closeSync();\n }\n const evidence = new Map<string, PinnedQuarantineFile>();\n const processedManifests = new Set<string>();\n const readBudget: QuarantineReadBudget = { remainingBytes: MAX_QUARANTINE_READ_BYTES };\n\n const processManifest = (manifestName: string): void => {\n if (processedManifests.has(manifestName)) return;\n processedManifests.add(manifestName);\n const manifestFile = readPinnedQuarantineFile(manifestName, MAX_QUARANTINE_MANIFEST_BYTES, true, readBudget);\n let parsed: unknown;\n try {\n parsed = JSON.parse(manifestFile.bytes?.toString('utf8') ?? '');\n } catch {\n throw new Error('quarantine manifest is invalid JSON');\n }\n if (isHealthQuarantineManifest(parsed)) {\n if (`${parsed.evidenceFile}.manifest.json` !== manifestName) {\n throw new Error('health quarantine manifest is not bound to its evidence name');\n }\n const file = readPinnedQuarantineFile(parsed.evidenceFile, MAX_OPERATIONAL_HEALTH_FILE_BYTES, true, readBudget);\n if (\n file.sizeBytes !== parsed.sizeBytes ||\n createHash('sha256').update(file.bytes ?? Buffer.alloc(0)).digest('hex') !== parsed.sha256\n ) {\n throw new Error('health quarantine evidence does not match its manifest');\n }\n if (evidence.has(parsed.evidenceFile)) throw new Error('quarantine evidence is referenced more than once');\n evidence.set(parsed.evidenceFile, file);\n return;\n }\n if (isJournalQuarantineManifest(parsed)) {\n const manifestBase = manifestName.slice(0, -'.manifest.json'.length);\n const boundNames = parsed.files.map((file) => {\n if (path.dirname(path.resolve(file)) !== path.resolve('.')) {\n throw new Error('journal quarantine manifest points outside quarantine');\n }\n return path.basename(file);\n });\n if (!boundNames.includes(manifestBase)) {\n throw new Error('journal quarantine manifest is not bound to its primary database evidence');\n }\n for (const name of boundNames) {\n if (evidence.has(name)) throw new Error('quarantine evidence is referenced more than once');\n evidence.set(name, readPinnedQuarantineFile(name, MAX_JOURNAL_COPY_BYTES, false, readBudget));\n }\n return;\n }\n throw new Error('quarantine manifest shape is invalid');\n };\n\n for (const entry of selected) {\n if (entry.name.endsWith('.manifest.json')) processManifest(entry.name);\n }\n\n for (const entry of selected) {\n if (!entry.name.endsWith('.manifest.json') && !evidence.has(entry.name)) {\n const primaryName = entry.name.endsWith('-wal') || entry.name.endsWith('-shm')\n ? entry.name.slice(0, -4)\n : entry.name;\n try {\n processManifest(`${primaryName}.manifest.json`);\n } catch {\n throw new Error('quarantine evidence has no valid manifest binding');\n }\n if (!evidence.has(entry.name)) throw new Error('quarantine evidence has no valid manifest binding');\n }\n }\n\n const entries = [...evidence.entries()]\n .slice(0, MAX_QUARANTINE_ENTRIES)\n .map(([name, file]) => ({ nameHash: stableIdentifierHash(name), sizeBytes: file.sizeBytes, modifiedAt: file.modifiedAt }))\n .sort((a, b) => a.nameHash.localeCompare(b.nameHash));\n return {\n status: 'available',\n count: evidence.size,\n scannedCount: selected.length,\n truncated: scanTruncated || evidence.size > entries.length,\n entries,\n };\n } finally {\n process.chdir(previousCwd);\n }\n}\n\nasync function inspectQuarantine(storeDir: string): Promise<DiagnosticsSnapshot['quarantine']> {\n const dir = path.join(storeDir, JOURNAL_QUARANTINE_DIRNAME);\n let directory: import('node:fs').BigIntStats;\n try {\n directory = await fs.lstat(dir, { bigint: true });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return { status: 'missing', count: 0, scannedCount: 0, truncated: false, entries: [] };\n }\n return {\n status: 'unavailable',\n count: 0,\n scannedCount: 0,\n truncated: false,\n entries: [],\n reason: 'quarantine directory could not be inspected',\n };\n }\n if (!directory.isDirectory() || directory.isSymbolicLink()) {\n return { status: 'unavailable', count: 0, scannedCount: 0, truncated: false, entries: [], reason: 'quarantine path is not a real directory' };\n }\n try {\n return inspectQuarantinePinned(dir, directory);\n } catch {\n return { status: 'unavailable', count: 0, scannedCount: 0, truncated: false, entries: [], reason: 'quarantine manifest or evidence binding is invalid' };\n }\n}\n\nfunction checksFor(snapshot: Omit<DiagnosticsSnapshot, 'checks'>): DiagnosticCheck[] {\n return [\n {\n id: 'config',\n status: snapshot.config.serverProtocol === 'invalid' ? 'fail' : 'pass',\n summary: `server protocol=${snapshot.config.serverProtocol}; hostedJournal=${snapshot.config.hostedJournal}`,\n },\n {\n id: 'device',\n status: snapshot.device.status === 'unavailable' ? 'fail' : snapshot.device.status === 'unpaired' ? 'warn' : 'pass',\n summary: snapshot.device.status,\n },\n {\n id: 'runtimes',\n status: snapshot.runtimes.some((runtime) => runtime.present) ? 'pass' : 'warn',\n summary: `${snapshot.runtimes.filter((runtime) => runtime.present).length}/${snapshot.runtimes.length} present`,\n },\n {\n id: 'control',\n status: snapshot.control.status === 'online' ? 'pass' : 'warn',\n summary: snapshot.control.status === 'online' ? `online transport=${snapshot.control.transport}` : 'daemon offline',\n },\n {\n id: 'health',\n status:\n snapshot.health.status === 'corrupt' || snapshot.health.status === 'unavailable'\n ? 'fail'\n : snapshot.health.status === 'missing'\n ? 'warn'\n : 'pass',\n summary: snapshot.health.status,\n },\n {\n id: 'journal',\n status:\n snapshot.journal.status === 'unavailable' || snapshot.journal.status === 'corrupt'\n ? 'fail'\n : snapshot.journal.status === 'missing'\n ? 'warn'\n : 'pass',\n summary: snapshot.journal.status,\n },\n {\n id: 'workspace',\n status:\n snapshot.workspace.status === 'unavailable'\n ? 'fail'\n : snapshot.workspace.status === 'missing' || snapshot.workspace.writable === false\n ? 'warn'\n : 'pass',\n summary: `${snapshot.workspace.status}${snapshot.workspace.writable === false ? '; read-only' : ''}`,\n },\n {\n id: 'quarantine',\n status: snapshot.quarantine.status === 'unavailable' ? 'fail' : snapshot.quarantine.count > 0 ? 'warn' : 'pass',\n summary: `${snapshot.quarantine.count} evidence file(s)`,\n },\n ];\n}\n\nexport async function collectDiagnostics(\n config: DaemonConfig,\n storeDir: string,\n options: CollectDiagnosticsOptions = {},\n): Promise<DiagnosticsSnapshot> {\n const resolvedStoreDir = path.resolve(storeDir);\n const adapters = options.adapters ?? defaultRuntimeAdapters(config.runtimeAllowlist);\n const connectControl = options.connectControl ?? connectControlClient;\n const [device, probedRuntimes, health, journal, workspace, quarantine, controlConnection] = await Promise.all([\n inspectDevice(resolvedStoreDir),\n probeRuntimes(adapters, { timeoutMs: options.runtimeProbeTimeoutMs }),\n inspectOperationalHealthFile(resolvedStoreDir),\n inspectJournal(resolvedStoreDir),\n inspectWorkspace(config.workspaceRoot),\n inspectQuarantine(resolvedStoreDir),\n connectControl({ storeDir: resolvedStoreDir, productId: config.productId }),\n ]);\n const runtimes: DiagnosticsSnapshot['runtimes'] = probedRuntimes.map((runtime) => ({\n idHash: stableIdentifierHash(runtime.id),\n present: runtime.present,\n versionPresent: runtime.version !== undefined,\n ...(runtime.authPresent === undefined ? {} : { authPresent: runtime.authPresent }),\n steer: runtime.steer,\n resume: runtime.resume,\n permissionModeCount: runtime.permissionModes.length,\n }));\n\n let control: DiagnosticsSnapshot['control'];\n if (!controlConnection.ok) {\n control = { status: 'offline', reason: 'daemon control socket unavailable' };\n } else {\n try {\n const live = await controlConnection.client.request<ControlStatusResult>('status');\n control = {\n status: 'online',\n pid: live.pid,\n uptimeMs: live.uptimeMs,\n transport: live.transport,\n activeTaskCount: live.activeTasks.length,\n pendingApprovalCount: live.approvalsPending,\n operationalHealth: live.operationalHealth,\n ...(live.storage ? { storage: live.storage } : {}),\n };\n } catch {\n control = { status: 'offline', reason: 'daemon status request failed' };\n } finally {\n controlConnection.client.close();\n }\n }\n\n const withoutChecks: Omit<DiagnosticsSnapshot, 'checks'> = {\n version: 1,\n generatedAt: (options.clock ?? (() => new Date()))().toISOString(),\n product: { nameHash: stableIdentifierHash(config.productName), idHash: stableIdentifierHash(config.productId) },\n system: { node: process.versions.node, platform: process.platform, arch: process.arch, sqliteAvailable: isSqliteAvailable() },\n config: {\n serverProtocol: safeProtocol(config.serverUrl),\n customStoreDir: config.storeDir !== undefined,\n hostedJournal: config.hostedJournal !== undefined,\n ...(config.runtimeAllowlist ? { runtimeAllowlistCount: config.runtimeAllowlist.length } : {}),\n },\n device,\n runtimes,\n control,\n health,\n journal,\n workspace,\n quarantine,\n };\n return { ...withoutChecks, checks: checksFor(withoutChecks) };\n}\n\nexport function stableIdentifierHash(value: string): string {\n return createHash('sha256').update(value, 'utf8').digest('hex');\n}\n\nfunction sameInode(left: import('node:fs').BigIntStats, right: import('node:fs').BigIntStats): boolean {\n return left.dev === right.dev && left.ino === right.ino;\n}\n\nfunction sameFileState(left: import('node:fs').BigIntStats, right: import('node:fs').BigIntStats): boolean {\n return (\n sameInode(left, right) &&\n left.size === right.size &&\n left.mtimeNs === right.mtimeNs &&\n left.ctimeNs === right.ctimeNs\n );\n}\n\n/**\n * Run the destructive publication against a cwd-pinned directory inode. Node\n * does not expose openat/linkat; a checked `process.chdir()` plus a fully\n * synchronous callback is the only cross-platform way to prevent the known\n * `quarantine/` pathname from being swapped to a symlink between validation\n * and link creation. No event-loop callback can observe the temporary cwd.\n */\nfunction publishQuarantineEvidencePinned(\n quarantineDir: string,\n expectedDirectory: import('node:fs').BigIntStats,\n sourcePath: string,\n sourceFd: number,\n sourceStat: import('node:fs').BigIntStats,\n evidenceName: string,\n manifestName: string,\n quarantinedAt: string,\n reason: string,\n): { sha256: string; sizeBytes: number } {\n const previousCwd = process.cwd();\n let entered = false;\n let evidenceCreated = false;\n let manifestCreated = false;\n let sourceRemoved = false;\n let evidenceTemp: string | undefined;\n let manifestTemp: string | undefined;\n try {\n process.chdir(quarantineDir);\n entered = true;\n const pinned = lstatSync('.', { bigint: true });\n if (!pinned.isDirectory() || !sameInode(pinned, expectedDirectory)) {\n throw new Error('quarantine path changed before publication; refusing quarantine');\n }\n const openSource = fstatSync(sourceFd, { bigint: true });\n const namedSource = lstatSync(sourcePath, { bigint: true });\n if (!sameFileState(openSource, sourceStat) || !sameFileState(namedSource, sourceStat)) {\n throw new Error('operational health source identity changed before quarantine');\n }\n const sizeBytes = Number(sourceStat.size);\n if (sizeBytes > MAX_OPERATIONAL_HEALTH_FILE_BYTES) {\n throw new Error('operational health state exceeds the bounded quarantine read limit');\n }\n const bytes = Buffer.alloc(sizeBytes);\n let position = 0;\n while (position < sizeBytes) {\n const bytesRead = readSync(sourceFd, bytes, position, sizeBytes - position, position);\n if (bytesRead === 0) throw new Error('operational health state ended during bounded copy');\n position += bytesRead;\n }\n const afterRead = fstatSync(sourceFd, { bigint: true });\n if (!sameFileState(afterRead, sourceStat)) {\n throw new Error('operational health state changed during bounded copy');\n }\n const sha256 = createHash('sha256').update(bytes).digest('hex');\n evidenceTemp = `.${evidenceName}.${randomUUID()}.tmp`;\n const evidenceFd = openSync(evidenceTemp, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL, 0o600);\n try {\n writeFileSync(evidenceFd, bytes);\n fchmodSync(evidenceFd, 0o600);\n fsyncSync(evidenceFd);\n } finally {\n closeSync(evidenceFd);\n }\n linkSync(evidenceTemp, evidenceName);\n evidenceCreated = true;\n const evidence = lstatSync(evidenceName, { bigint: true });\n const tempEvidence = lstatSync(evidenceTemp, { bigint: true });\n if (!evidence.isFile() || !sameInode(evidence, tempEvidence) || evidence.size !== sourceStat.size) {\n throw new Error('quarantined operational health evidence does not match the bounded copy');\n }\n unlinkSync(evidenceTemp);\n evidenceTemp = undefined;\n const finalOpenSource = fstatSync(sourceFd, { bigint: true });\n const finalNamedSource = lstatSync(sourcePath, { bigint: true });\n if (!sameFileState(finalOpenSource, sourceStat) || !sameFileState(finalNamedSource, sourceStat)) {\n throw new Error('operational health source changed before removal');\n }\n const manifestBody = `${JSON.stringify(\n {\n version: 1,\n quarantinedAt,\n reason,\n sourcePath,\n evidenceFile: evidenceName,\n sha256,\n sizeBytes,\n },\n null,\n 2,\n )}\\n`;\n manifestTemp = `.${manifestName}.${randomUUID()}.tmp`;\n const manifestFd = openSync(manifestTemp, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL, 0o600);\n try {\n writeFileSync(manifestFd, manifestBody, 'utf8');\n fchmodSync(manifestFd, 0o600);\n fsyncSync(manifestFd);\n } finally {\n closeSync(manifestFd);\n }\n linkSync(manifestTemp, manifestName);\n manifestCreated = true;\n unlinkSync(manifestTemp);\n manifestTemp = undefined;\n // The copied bytes were fsynced before publication. On POSIX, also make\n // both evidence directory entries durable before removing the only source\n // pathname; otherwise a power loss could persist the unlink while losing\n // the newly-linked names. Node/libuv exposes no Windows directory fsync,\n // so Windows retains the strongest platform-native file flush + link order.\n if (process.platform !== 'win32') {\n const quarantineDirectoryFd = openSync('.', fsConstants.O_RDONLY);\n try {\n fsyncSync(quarantineDirectoryFd);\n } finally {\n closeSync(quarantineDirectoryFd);\n }\n }\n const removalOpenSource = fstatSync(sourceFd, { bigint: true });\n const removalNamedSource = lstatSync(sourcePath, { bigint: true });\n if (!sameFileState(removalOpenSource, sourceStat) || !sameFileState(removalNamedSource, sourceStat)) {\n throw new Error('operational health source changed before removal');\n }\n unlinkSync(sourcePath);\n sourceRemoved = true;\n if (process.platform !== 'win32') {\n const directoryFd = openSync(path.dirname(sourcePath), fsConstants.O_RDONLY);\n try {\n fsyncSync(directoryFd);\n } finally {\n closeSync(directoryFd);\n }\n }\n return { sha256, sizeBytes };\n } catch (err) {\n if (evidenceTemp) {\n try { unlinkSync(evidenceTemp); } catch { /* best-effort removal of unpublished temp */ }\n }\n if (manifestTemp) {\n try { unlinkSync(manifestTemp); } catch { /* best-effort removal of unpublished temp */ }\n }\n if (manifestCreated && !sourceRemoved) {\n try { unlinkSync(manifestName); } catch { /* preserve the original error */ }\n }\n if (evidenceCreated && !sourceRemoved) {\n try { unlinkSync(evidenceName); } catch { /* preserve the original error */ }\n }\n throw err;\n } finally {\n if (entered) process.chdir(previousCwd);\n }\n}\n\n/**\n * The only S7-b repair: preserve a confirmed-corrupt health file in the\n * never-auto-delete quarantine. Callers must separately enforce the CLI's\n * `--fix --yes` and offline-daemon preconditions.\n */\nexport async function quarantineCorruptOperationalHealth(\n storeDir: string,\n options: { clock?: () => Date } = {},\n): Promise<OperationalHealthFixResult> {\n const resolvedStoreDir = path.resolve(storeDir);\n const owner = await acquireDaemonOwner(resolvedStoreDir, 'doctor', options.clock);\n try {\n const sourcePath = path.join(resolvedStoreDir, OPERATIONAL_HEALTH_FILENAME);\n let opened: Awaited<ReturnType<typeof openOperationalHealthFile>>;\n try {\n opened = await openOperationalHealthFile(resolvedStoreDir);\n } catch (err) {\n throw new Error('operational health state could not be opened safely; refusing quarantine', { cause: err });\n }\n if (!opened) return { status: 'not-needed', reason: 'missing' };\n const source = opened.handle;\n try {\n const inspection = await inspectOperationalHealthHandle(source, opened.stat);\n if (inspection.status === 'valid') return { status: 'not-needed', reason: 'valid' };\n if (inspection.status === 'unavailable') {\n throw new Error(`${inspection.reason}; refusing to quarantine unconfirmed corruption`);\n }\n\n const sourceStat = await source.stat({ bigint: true });\n if (!sourceStat.isFile()) throw new Error('operational health state is not a regular file; refusing quarantine');\n\n const quarantineDir = path.join(resolvedStoreDir, JOURNAL_QUARANTINE_DIRNAME);\n try {\n const existing = await fs.lstat(quarantineDir);\n if (!existing.isDirectory() || existing.isSymbolicLink()) {\n throw new Error('quarantine path is not a real directory; refusing quarantine');\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n await fs.mkdir(quarantineDir, { mode: 0o700 });\n }\n await ensureSecureDir(quarantineDir);\n const securedQuarantine = await fs.lstat(quarantineDir, { bigint: true });\n if (!securedQuarantine.isDirectory() || securedQuarantine.isSymbolicLink()) {\n throw new Error('quarantine path changed during validation; refusing quarantine');\n }\n const stamp = (options.clock ?? (() => new Date()))().toISOString().replace(/[:.]/g, '-');\n const evidenceName = `${stamp}-${randomUUID()}-${OPERATIONAL_HEALTH_FILENAME}`;\n const manifestName = `${evidenceName}.manifest.json`;\n const hashed = publishQuarantineEvidencePinned(\n quarantineDir,\n securedQuarantine,\n sourcePath,\n source.fd,\n sourceStat,\n evidenceName,\n manifestName,\n (options.clock ?? (() => new Date()))().toISOString(),\n inspection.reason,\n );\n return { status: 'quarantined', evidenceName, manifestName, sha256: hashed.sha256, sizeBytes: hashed.sizeBytes };\n } finally {\n await source.close();\n }\n } finally {\n await owner.release();\n }\n}\n\nexport { OPERATIONAL_HEALTH_FILENAME };\n","import type { DaemonConfig } from '../../index';\nimport {\n collectDiagnostics,\n quarantineCorruptOperationalHealth,\n type CollectDiagnosticsOptions,\n type DiagnosticsSnapshot,\n type OperationalHealthFixResult,\n} from '../../diagnostics/diagnostics';\nimport { resolveStoreDir } from '../config';\n\nexport interface DoctorOptions extends CollectDiagnosticsOptions {\n json?: boolean;\n fix?: boolean;\n confirmed?: boolean;\n log?: (line: string) => void;\n}\n\nexport class DoctorConfirmationRequiredError extends Error {\n constructor() {\n super('doctor --fix requires explicit --yes confirmation');\n this.name = 'DoctorConfirmationRequiredError';\n }\n}\n\nexport class DoctorDaemonRunningError extends Error {\n constructor() {\n super('doctor --fix refuses while the daemon control socket is reachable; stop the daemon first');\n this.name = 'DoctorDaemonRunningError';\n }\n}\n\nfunction formatDoctorLines(snapshot: DiagnosticsSnapshot, fixResult?: OperationalHealthFixResult): string[] {\n const lines = [\n `doctor: productHash=${snapshot.product.nameHash} generatedAt=${snapshot.generatedAt}`,\n `system: node=${snapshot.system.node} platform=${snapshot.system.platform} arch=${snapshot.system.arch} sqlite=${snapshot.system.sqliteAvailable ? 'available' : 'unavailable'}`,\n ];\n for (const check of snapshot.checks) lines.push(`check ${check.id}: ${check.status} (${check.summary})`);\n if (snapshot.health.status === 'corrupt' || snapshot.health.status === 'unavailable') {\n lines.push(`health-detail: ${snapshot.health.reason}; bytes=${snapshot.health.sizeBytes ?? 'unknown'}`);\n }\n if (snapshot.quarantine.truncated) {\n lines.push(`quarantine-detail: inventory truncated after ${snapshot.quarantine.scannedCount} scanned entries`);\n }\n if (fixResult?.status === 'quarantined') {\n lines.push(\n `fix: quarantined ${fixResult.sizeBytes} bytes as ${fixResult.evidenceName}; manifest=${fixResult.manifestName}; sha256=${fixResult.sha256}`,\n );\n } else if (fixResult) {\n lines.push(`fix: no change (${fixResult.reason})`);\n }\n return lines;\n}\n\nexport async function runDoctorCommand(config: DaemonConfig, options: DoctorOptions = {}): Promise<void> {\n if (options.fix && !options.confirmed) throw new DoctorConfirmationRequiredError();\n const storeDir = resolveStoreDir(config);\n let snapshot = await collectDiagnostics(config, storeDir, options);\n let fixResult: OperationalHealthFixResult | undefined;\n if (options.fix) {\n if (snapshot.control.status === 'online') throw new DoctorDaemonRunningError();\n fixResult = await quarantineCorruptOperationalHealth(storeDir, { clock: options.clock });\n snapshot = await collectDiagnostics(config, storeDir, options);\n }\n const log = options.log ?? ((line: string) => console.log(line));\n if (options.json) {\n log(JSON.stringify({ diagnostics: snapshot, ...(fixResult ? { fix: fixResult } : {}) }, null, 2));\n return;\n }\n for (const line of formatDoctorLines(snapshot, fixResult)) log(line);\n}\n","import { type DaemonConfig, type RuntimeAdapter } from '../../index';\nimport { formatRuntimeLines } from '../format';\nimport { defaultRuntimeAdapters, probeRuntimes } from '../runtime-probe';\n\nexport interface RuntimesDeps {\n log?: (line: string) => void;\n /** DI for tests: probe these adapters instead of constructing the real bundled pi/claude/codex set. */\n adapters?: RuntimeAdapter[];\n}\n\nexport async function runRuntimesCommand(config: DaemonConfig, deps: RuntimesDeps = {}): Promise<void> {\n const log = deps.log ?? ((line: string) => console.log(line));\n const adapters = deps.adapters ?? defaultRuntimeAdapters(config.runtimeAllowlist);\n const runtimes = await probeRuntimes(adapters);\n for (const line of formatRuntimeLines(runtimes)) log(line);\n}\n","import path from 'node:path';\nimport { createServiceLifecycle, nodeAgentProgram, type DaemonConfig, type ServiceDefinition, type ServiceLifecycle } from '../../index';\nimport { argValue, resolveStoreDir } from '../config';\n\nexport interface ServiceCommandDeps {\n log?: (line: string) => void;\n /** DI for tests: drive a pre-built lifecycle instead of the real platform-dispatched `createServiceLifecycle`. */\n lifecycle?: ServiceLifecycle;\n}\n\n/**\n * Builds the SAME `ServiceDefinition` every one of `install`/`uninstall`/\n * `service-start`/`service-stop`/`service-status` derives — critical so\n * `uninstall`/`service-stop`/`service-status` compute the exact same\n * service name (and, on Windows, install directory) `install` used,\n * without requiring the operator to re-supply identical ad hoc flags to\n * five separate invocations. `--name`/`--agent-bin`/`--node-bin`/\n * `--winsw-bin`/`--winsw-install-dir` are override escape hatches; every\n * default is derived deterministically from `config` alone (mirrors\n * `bin/config.ts`'s own doc comment: every subcommand loads config the same\n * way).\n *\n * `agentBin` defaults to `process.argv[1]` — the actual script path Node is\n * currently running, always correct regardless of how this CLI was\n * invoked (global install, `npx`, a product's own `node_modules/.bin`\n * symlink) — NOT an `import.meta`-based guess; see\n * `lifecycle/create-service-lifecycle.ts`'s doc comment for why this\n * module family never tries to resolve that path itself. A product\n * shipping a single compiled binary (`templates/packaging/`) instead of\n * `node + byok-agent.js` should pass `--agent-bin`/`--node-bin` explicitly,\n * or construct a `ServiceDefinition` directly via `createServiceLifecycle`\n * rather than this convenience CLI subcommand.\n *\n * `configPath` is resolved to an ABSOLUTE path before being baked into the\n * generated service's `--config <path>` argument: a service launched by\n * launchd/systemd/WinSW starts with the OS service manager's OWN minimal\n * environment and working directory, not the operator's interactive shell\n * — a relative path here would resolve against whatever cwd the service\n * manager happens to choose, not where the operator ran `install` from.\n */\nexport function buildServiceDefinition(config: DaemonConfig, configPath: string, rest: string[]): ServiceDefinition {\n const name = argValue(rest, '--name') ?? config.productId;\n const agentBin = argValue(rest, '--agent-bin') ?? process.argv[1] ?? 'byok-agent';\n const nodeBin = argValue(rest, '--node-bin') ?? process.execPath;\n const absoluteConfigPath = path.resolve(configPath);\n const logDir = path.join(resolveStoreDir(config), 'service-logs');\n\n const definition: ServiceDefinition = {\n name,\n displayName: config.branding?.displayName ?? config.productName,\n program: nodeAgentProgram({ agentBin, configPath: absoluteConfigPath, nodeBin }),\n logDir,\n };\n\n const winswBin = argValue(rest, '--winsw-bin');\n if (winswBin) {\n const installDir = argValue(rest, '--winsw-install-dir');\n definition.windows = installDir ? { winswBin, installDir } : { winswBin };\n }\n return definition;\n}\n\nfunction buildLifecycle(config: DaemonConfig, configPath: string, rest: string[], deps: ServiceCommandDeps): ServiceLifecycle {\n return deps.lifecycle ?? createServiceLifecycle(buildServiceDefinition(config, configPath, rest));\n}\n\nfunction serviceNameFor(config: DaemonConfig, rest: string[]): string {\n return argValue(rest, '--name') ?? config.productId;\n}\n\n/**\n * Generates the platform service definition (plist/unit/WinSW xml),\n * registers it with the OS service manager, and starts it — see\n * `lifecycle/create-service-lifecycle.ts` for the per-platform mechanics.\n * On Windows, `--winsw-bin <path>` is required (the product-bundled WinSW\n * executable — Decision-6: this SDK never bundles/downloads it itself; see\n * `templates/service/winsw/README.md`).\n */\nexport async function runInstallCommand(config: DaemonConfig, configPath: string, rest: string[], deps: ServiceCommandDeps = {}): Promise<void> {\n const log = deps.log ?? ((line: string) => console.log(line));\n const lifecycle = buildLifecycle(config, configPath, rest, deps);\n await lifecycle.install();\n log(`service installed and started: ${serviceNameFor(config, rest)}`);\n}\n\n/** Stops (if running) and fully removes the service registration + generated definition file. Safe to call when not installed. */\nexport async function runUninstallCommand(config: DaemonConfig, configPath: string, rest: string[], deps: ServiceCommandDeps = {}): Promise<void> {\n const log = deps.log ?? ((line: string) => console.log(line));\n const lifecycle = buildLifecycle(config, configPath, rest, deps);\n await lifecycle.uninstall();\n log(`service uninstalled: ${serviceNameFor(config, rest)}`);\n}\n\n/** Starts an already-installed service (named so it never collides with the existing `start`, which runs the daemon in the foreground — see `byok-agent.ts`'s header comment). */\nexport async function runServiceStartCommand(config: DaemonConfig, configPath: string, rest: string[], deps: ServiceCommandDeps = {}): Promise<void> {\n const log = deps.log ?? ((line: string) => console.log(line));\n const lifecycle = buildLifecycle(config, configPath, rest, deps);\n await lifecycle.start();\n log(`service started: ${serviceNameFor(config, rest)}`);\n}\n\n/** Stops a running service without uninstalling it. */\nexport async function runServiceStopCommand(config: DaemonConfig, configPath: string, rest: string[], deps: ServiceCommandDeps = {}): Promise<void> {\n const log = deps.log ?? ((line: string) => console.log(line));\n const lifecycle = buildLifecycle(config, configPath, rest, deps);\n await lifecycle.stop();\n log(`service stopped: ${serviceNameFor(config, rest)}`);\n}\n\n/** Reports installed/running state straight from the platform's own service manager. */\nexport async function runServiceStatusCommand(config: DaemonConfig, configPath: string, rest: string[], deps: ServiceCommandDeps = {}): Promise<void> {\n const log = deps.log ?? ((line: string) => console.log(line));\n const lifecycle = buildLifecycle(config, configPath, rest, deps);\n const status = await lifecycle.status();\n log(`installed: ${status.installed ? 'yes' : 'no'}`);\n // Finding P1 #2 (residual, round 3): a plain `running: no` would misreport\n // an INDETERMINATE query (manager unreachable/permission denied — see\n // `ServiceStatusResult.determinate`) as a confirmed \"not running\" result.\n // Said so explicitly instead; the raw `detail` line right after still\n // carries the underlying tool output for diagnosis.\n const runningLabel = status.running ? 'yes' : status.determinate ? 'no' : 'unknown (could not query the service manager)';\n log(`running: ${runningLabel}`);\n log(`detail: ${status.detail.trim() || '(none)'}`);\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { AgentEvent, BlobRef, RuntimeInfo } from '@byok-sdk/protocol';\nimport { type ConnectionState, type DaemonEvent, type DaemonEventListener } from '../index';\nimport { atomicWriteFile } from '../util/atomic-write';\n\n/**\n * The audit log is the ONLY channel a separate, short-lived CLI invocation\n * (`status`/`tasks`/`tasks --follow`) has into what an already-running\n * `byok-agent start` process has observed — see `byok-agent.ts`'s header\n * comment for the full read-model rationale. One JSON line per\n * `DaemonEvent`, oldest first, append-only.\n *\n * Finding P1 #3 (SECURITY): a `DaemonEvent` can carry a task's raw\n * instruction-derived output — `tool_use.input`/`tool_result.output` are\n * `z.unknown()` in `@byok-sdk/protocol` (a shell command, a whole file's\n * contents echoed back, anything), `progress`/`needs_approval`/`completed`/\n * `failed`/`cancelled` all carry free-form agent/operator text, and\n * `artifact.inline` is literally base64 file bytes. Persisting all of that\n * VERBATIM into a durable, append-only, potentially long-retained file —\n * previously created at the default `0666 & umask` mode (NOT 0600), with\n * `storeDir` only chmod'd 0700 at the moment it's first created (a\n * pre-existing custom `storeDir` kept whatever mode it already had) — is\n * exactly the kind of thing that turns \"helpful audit trail\" into \"durable\n * secret/credential/source leak\" the moment anything else on the machine can\n * read it. Fixed on two independent axes:\n *\n * 1. **Redaction** (`redactForAudit`/`redactAgentEvent`): only event type,\n * taskId, timestamps, tool/runtime NAMES, sizes/counts, and closed-enum\n * state fields are ever written to disk — every free-form text/bytes\n * field is replaced with its byte SIZE. `readAuditEvents`/`followAuditLog`\n * reconstruct a `DaemonEvent`-shaped value from that redacted projection\n * for their callers (`tasks-view.ts`/`format.ts` stay unchanged and none\n * the wiser) by substituting an unambiguous `[redacted: N bytes]`\n * placeholder wherever real content used to be — so a replayed\n * `tasks`/`status`/`tasks --follow` view degrades to showing sizes\n * instead of content, which is the correct, honest trade-off for a\n * broadly-readable-by-default durable file. The LIVE human-facing stdout\n * stream (`bin/commands/start.ts`, fed directly from the in-memory\n * `DaemonEvent` before it ever reaches this module) is unaffected and\n * keeps full fidelity — this redaction applies ONLY to what's written to\n * disk.\n * 2. **Permissions**: the file is tightened to 0600 BEFORE any new content\n * is written, on every single append (mirrors `util/atomic-write.ts`'s\n * own defensive re-chmod, for the identical reason: `open()`'s own\n * `mode` argument only governs permissions at CREATION time, so a\n * pre-existing file — predating this fix, or loosened by something else\n * — keeps whatever mode it already had until explicitly chmod'd).\n * `storeDir` gets the same defensive re-`chmod` to 0700 on every append.\n *\n * Finding P1 #3b (STILL-OPEN, now fixed): the chmod used to run AFTER\n * `appendFile` rather than before — for a pre-existing permissive file\n * that meant the newly-appended line briefly landed in a file that was\n * still world-readable, and if `appendFile` itself failed, the chmod\n * (being sequenced after it) never ran at all, leaving the file exactly\n * as permissive as it started. Fixed by reordering so the chmod always\n * happens FIRST: there is no window where a new append lands in a\n * still-permissive file, and the tightening takes effect even when the\n * append that follows it fails. This closes the gap going forward; it\n * does NOT retroactively scrub plaintext a pre-fix build of this code\n * may have already written into an inherited permissive file — only\n * that the file stops being world-readable from the first append\n * onward.\n *\n * Finding P2/#11 (audit half): also bounded/rotated now — `appendAuditEvent`\n * checks the file's size (cheap `fs.stat`) on every append and, once it\n * exceeds `MAX_AUDIT_LOG_BYTES`, atomically rewrites it down to the most\n * recent `AUDIT_LOG_TRIM_TARGET_LINES` lines (reusing `atomicWriteFile`, so\n * a concurrent `tasks`/`tasks --follow` read never observes a torn file\n * mid-rotation) — so a long-lived daemon's audit.jsonl no longer grows\n * forever. `followAuditLog` no longer re-reads the entire file every poll\n * either; see its own doc comment.\n *\n * Finding P2 (new, round 1, now fixed): that trim used to be purely\n * positional (the most recent N lines, full stop) — which could evict\n * EVERY event a still-running task ever had if it went quiet for long\n * enough, permanently erasing it from `tasks`/`status` even though it was\n * never actually done. `compactPreservingLiveTasks` now preserves one\n * lifecycle-anchor line for any still-open (non-terminal) task that would\n * otherwise be fully evicted — see its own doc comment.\n *\n * Finding P2 (new, round 2, now fixed): round 1's anchor preservation had no\n * cap of its own — a daemon that crashes leaving many non-terminal tasks\n * behind (or one that keeps creating non-terminal tasks that never reach a\n * terminal kind) accumulates one anchor per distinct non-terminal taskId\n * FOREVER, defeating `MAX_AUDIT_LOG_BYTES`'s own size cap (the whole point\n * of rotation) and making every append past the cap an ever-larger O(n)\n * read + atomic-rewrite. `compactPreservingLiveTasks` now also bounds the\n * anchors themselves to `MAX_LIVE_TASK_ANCHORS`, keeping the most\n * recently-touched ones and dropping the oldest overflow with a single\n * logged warning — see that constant's own doc comment.\n */\n\nexport function auditLogPath(storeDir: string): string {\n return path.join(storeDir, 'audit.jsonl');\n}\n\n/** 0600: this file can carry tool names, task ids, and sizes/counts derived from potentially sensitive task data — never group/world-readable, same bar as `device.json` (`daemon/store.ts`). */\nconst AUDIT_LOG_MODE = 0o600;\nconst AUDIT_STORE_DIR_MODE = 0o700;\n\n/**\n * Finding P2/#11 (audit half): rotate once the file exceeds this size,\n * trimming to the most recent `AUDIT_LOG_TRIM_TARGET_LINES` lines. Checked\n * via a cheap `fs.stat` (O(1), not a full read) on every single append; the\n * expensive read-all-lines + atomic-rewrite only actually runs once the cap\n * is crossed, and trimming well under the cap (redacted lines are small —\n * mostly ids/sizes/counts) means it won't immediately re-trigger on the next\n * append either. Deliberately simple size/line based bounding, not a\n * time-based retention policy — \"keep it simple\" per this finding's own\n * scope note.\n */\nexport const MAX_AUDIT_LOG_BYTES = 10 * 1024 * 1024;\nexport const AUDIT_LOG_TRIM_TARGET_LINES = 5000;\n\n/**\n * Finding P2 (new, round 2): the hard cap on how many non-terminal-task\n * lifecycle anchors {@link compactPreservingLiveTasks} will ever preserve in\n * a single rotation — without this, a daemon that crashes leaving many\n * non-terminal tasks behind (or a bug that keeps creating tasks that never\n * reach a terminal kind) accumulates one anchor per distinct taskId with no\n * upper bound, defeating `MAX_AUDIT_LOG_BYTES`'s own size cap and turning\n * every subsequent append into an ever-larger O(n) read + atomic-rewrite.\n * Mirrors `daemon/observer.ts`'s `MAX_TRACKED_TASKS`/`task-runner.ts`'s\n * `MAX_TRACKED_TASK_IDS` registries: bounded to a generously-sized \"a\n * handful of genuinely concurrent tasks never gets close to this\" cap, kept\n * the most RECENTLY-touched (by last-seen line index) and dropping the\n * oldest overflow with a single `console.warn` per rotation (not one per\n * dropped anchor — a runaway leak should be visible without spamming the\n * log). A dropped task simply reverts to the pre-round-1 behavior (falls\n * out of `tasks`/`status` once its own events age out of the retained\n * tail) rather than the file growing without bound.\n */\nexport const MAX_LIVE_TASK_ANCHORS = 500;\n\nfunction byteSize(text: string | undefined): number | undefined {\n return text === undefined ? undefined : Buffer.byteLength(text, 'utf8');\n}\n\n/**\n * Rough serialized-size estimate for an arbitrary (`unknown`) value —\n * `tool_use.input`/`tool_result.output` are typed `z.unknown()` in\n * `@byok-sdk/protocol` precisely because a tool's input/output can be anything\n * (a command string, a JSON object, a whole file's contents). `JSON.stringify`\n * can itself throw (a circular structure, a lone BigInt) — caught\n * defensively since this is only ever a size ESTIMATE for the audit trail,\n * never allowed to break the append it's part of.\n */\nfunction valueByteSize(value: unknown): number | undefined {\n if (value === undefined) return undefined;\n try {\n const json = JSON.stringify(value);\n return json === undefined ? undefined : Buffer.byteLength(json, 'utf8');\n } catch {\n return undefined;\n }\n}\n\n/** Unambiguous, never-confusable-with-real-content marker substituted for a redacted text/bytes field on READ (see `reconstructDaemonEvent`/`reconstructAgentEvent`) — never written to disk itself (only the size is). */\nfunction placeholderFor(size: number | undefined): string {\n return size === undefined ? '[redacted]' : `[redacted: ${size} bytes]`;\n}\n\n/** Git failures are serialized only as this closed, stable category set — never raw Git errors or command output. */\nconst STABLE_GIT_ERROR_CATEGORIES = new Set([\n 'git-unavailable',\n 'git-timeout',\n 'git-output-limit',\n 'git-command-failed',\n 'workspace-root-invalid',\n 'workspace-root-conflict',\n 'workspace-not-owned',\n 'repository-root-mismatch',\n 'repository-invalid',\n 'lease-busy',\n 'ledger-invalid',\n]);\n\nfunction stableGitErrorCategory(value: unknown): string | undefined {\n return typeof value === 'string' && STABLE_GIT_ERROR_CATEGORIES.has(value) ? value : undefined;\n}\n\nfunction gitCount(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : undefined;\n}\n\nfunction gitDirty(value: unknown): { staged: number; unstaged: number; untracked: number; conflicted: number } | undefined {\n const dirty = asRecord(value);\n const staged = gitCount(dirty.staged);\n const unstaged = gitCount(dirty.unstaged);\n const untracked = gitCount(dirty.untracked);\n const conflicted = gitCount(dirty.conflicted);\n return staged !== undefined && unstaged !== undefined && untracked !== undefined && conflicted !== undefined\n ? { staged, unstaged, untracked, conflicted }\n : undefined;\n}\n\n/**\n * Finding P1 #3: the redacted projection of a `task.progress`-derived\n * `AgentEvent` that's actually written to disk — every free-form field\n * (`text`/`input`/`output`/`summary`/`message`) becomes a `*Size` byte count;\n * `tool`/`name`/`contentType` (identifiers, not content) and `usage`'s token\n * COUNTS survive verbatim.\n */\nfunction redactAgentEvent(event: AgentEvent): Record<string, unknown> {\n switch (event.type) {\n case 'progress':\n return { type: 'progress', textSize: byteSize(event.text) };\n case 'tool_use':\n return { type: 'tool_use', tool: event.tool, inputSize: valueByteSize(event.input) };\n case 'tool_result':\n return { type: 'tool_result', tool: event.tool, outputSize: valueByteSize(event.output) };\n case 'artifact':\n return { type: 'artifact', name: event.name, contentType: event.contentType };\n case 'needs_approval':\n return { type: 'needs_approval', summarySize: byteSize(event.summary) };\n case 'turn_end':\n return { type: 'turn_end' };\n case 'error':\n return { type: 'error', messageSize: byteSize(event.message) };\n case 'usage':\n return {\n type: 'usage',\n inputTokens: event.inputTokens,\n cachedInputTokens: event.cachedInputTokens,\n outputTokens: event.outputTokens,\n reasoningTokens: event.reasoningTokens,\n totalTokens: event.totalTokens,\n };\n }\n}\n\n/**\n * Finding P1 #3: the redacted projection of a `DaemonEvent` that's actually\n * written to disk. See this file's module doc comment for the full\n * rationale; `reconstructDaemonEvent` is this function's read-side inverse.\n */\nfunction redactForAudit(event: DaemonEvent): Record<string, unknown> {\n const base = { kind: event.kind, ts: event.ts };\n switch (event.kind) {\n case 'offered':\n return { ...base, taskId: event.taskId, runtime: event.runtime };\n case 'claimed':\n return { ...base, taskId: event.taskId, claimedRuntime: event.claimedRuntime };\n case 'started':\n return { ...base, taskId: event.taskId };\n case 'progress':\n return { ...base, taskId: event.taskId, event: redactAgentEvent(event.event) };\n case 'artifact':\n return {\n ...base,\n taskId: event.taskId,\n name: event.name,\n contentType: event.contentType,\n // `inline` is base64 file bytes (up to the 64KB inline cap) — never\n // persisted. `blobRef.url` is a presigned URL — itself effectively a\n // time-limited bearer credential for the actual bytes, so it's\n // dropped too; only the safe pointer/size metadata survives.\n inlineSize: byteSize(event.inline),\n blobRef: event.blobRef\n ? {\n blobId: event.blobRef.blobId,\n contentHash: event.blobRef.contentHash,\n size: event.blobRef.size,\n contentType: event.blobRef.contentType,\n }\n : undefined,\n };\n case 'awaiting-approval':\n return { ...base, taskId: event.taskId, summarySize: byteSize(event.summary) };\n case 'completed':\n return { ...base, taskId: event.taskId, summarySize: byteSize(event.summary), sessionRef: event.sessionRef };\n case 'failed':\n return {\n ...base,\n taskId: event.taskId,\n reasonSize: byteSize(event.reason),\n retryable: event.retryable,\n preClaim: event.preClaim,\n };\n case 'cancelled':\n return { ...base, taskId: event.taskId, reasonSize: byteSize(event.reason) };\n case 'connection':\n return { ...base, state: event.state };\n case 'paired':\n return { ...base, deviceId: event.deviceId };\n case 'unpaired':\n return { ...base };\n case 'runtimes-detected':\n return { ...base, runtimes: event.runtimes };\n case 'shutdown-requested':\n // Not sensitive/free-form the way task instruction/output text is —\n // this is an internally-constructed operational message (see\n // `create-daemon.ts`'s control-socket shutdown wiring), so it's kept\n // verbatim rather than redacted to a size.\n return { ...base, reason: event.reason };\n case 'shutdown-complete':\n // Finding R3 (cross-model re-review): `undeliveredOutboxCount`\n // (finding F5(b)) is a plain NUMBER, not free-form text — no\n // redaction concern at all — but this branch used to share the\n // `shutdown-requested` case above verbatim, which only ever copied\n // `reason` across, silently dropping this field on every persisted\n // write. A replayed `tasks --follow`/audit read therefore always saw\n // `undeliveredOutboxCount: undefined`, indistinguishable from \"0\n // undelivered\" — exactly the false \"everything was delivered\"\n // impression F5(b) exists to prevent. See `reconstructDaemonEvent`'s\n // own `shutdown-complete` case for the read-side symmetry this needs.\n return { ...base, reason: event.reason, undeliveredOutboxCount: event.undeliveredOutboxCount };\n case 'stale-approval-decision':\n // `reason` here is an operator-supplied free-text reject reason (same\n // redaction rule as `failed`/`cancelled` above) — `decision` is just\n // the fixed 'approve'|'reject' identifier, kept verbatim.\n return { ...base, taskId: event.taskId, decision: event.decision, reasonSize: byteSize(event.reason) };\n case 'git-workspace':\n // Git observations are deliberately coarse: paths, commit ids,\n // filenames, messages, raw Git output, and free-form errors never cross\n // this boundary. The opaque workspaceId is safe to retain for correlation.\n return {\n ...base,\n taskId: event.taskId,\n workspaceId: event.workspaceId,\n phase: event.phase,\n headChanged: event.headChanged,\n commitsSinceBaseline: event.commitsSinceBaseline,\n dirty: event.dirty,\n errorCategory: stableGitErrorCategory(event.errorCategory),\n };\n }\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value !== null && typeof value === 'object' ? (value as Record<string, unknown>) : {};\n}\nfunction str(value: unknown, fallback = ''): string {\n return typeof value === 'string' ? value : fallback;\n}\nfunction num(value: unknown): number | undefined {\n return typeof value === 'number' ? value : undefined;\n}\nfunction bool(value: unknown, fallback: boolean): boolean {\n return typeof value === 'boolean' ? value : fallback;\n}\n\n/** Read-side inverse of {@link redactAgentEvent}: reconstructs an `AgentEvent`-SHAPED value with a `[redacted: N bytes]` placeholder wherever real content used to be. An unrecognized/corrupt inner `type` degrades to a harmless opaque `error` event rather than throwing — mirrors this whole module's \"never let one bad line break the read\" contract. */\nfunction reconstructAgentEvent(raw: unknown): AgentEvent {\n const r = asRecord(raw);\n const type = str(r.type);\n switch (type) {\n case 'progress':\n return { type: 'progress', text: placeholderFor(num(r.textSize)) };\n case 'tool_use':\n return { type: 'tool_use', tool: str(r.tool), input: placeholderFor(num(r.inputSize)) };\n case 'tool_result':\n return { type: 'tool_result', tool: str(r.tool), output: placeholderFor(num(r.outputSize)) };\n case 'artifact':\n return { type: 'artifact', name: str(r.name), contentType: str(r.contentType) };\n case 'needs_approval':\n return { type: 'needs_approval', summary: placeholderFor(num(r.summarySize)) };\n case 'turn_end':\n return { type: 'turn_end' };\n case 'error':\n return { type: 'error', message: placeholderFor(num(r.messageSize)) };\n case 'usage':\n return {\n type: 'usage',\n inputTokens: num(r.inputTokens),\n cachedInputTokens: num(r.cachedInputTokens),\n outputTokens: num(r.outputTokens),\n reasoningTokens: num(r.reasoningTokens),\n totalTokens: num(r.totalTokens),\n };\n default:\n return { type: 'error', message: `[unrecognized audit event type: ${type || '(missing)'}]` };\n }\n}\n\n/** Read-side inverse of {@link redactForAudit} — see this file's module doc comment. `raw` has already passed {@link isAuditRecordShaped} (has string `kind`/`ts`) by the time this is called; an unrecognized `kind` (corrupt line, or a future version's new kind) returns `undefined` and is dropped by the caller like any other bad line. */\nfunction reconstructDaemonEvent(raw: Record<string, unknown>): DaemonEvent | undefined {\n const kind = str(raw.kind);\n const ts = str(raw.ts);\n switch (kind) {\n case 'offered':\n return { kind: 'offered', ts, taskId: str(raw.taskId), runtime: typeof raw.runtime === 'string' ? raw.runtime : undefined };\n case 'claimed': {\n const claimedRuntime = typeof raw.claimedRuntime === 'string' ? raw.claimedRuntime : undefined;\n return claimedRuntime === undefined\n ? { kind: 'claimed', ts, taskId: str(raw.taskId) }\n : { kind: 'claimed', ts, taskId: str(raw.taskId), claimedRuntime };\n }\n case 'started':\n return { kind: 'started', ts, taskId: str(raw.taskId) };\n case 'progress':\n return { kind: 'progress', ts, taskId: str(raw.taskId), event: reconstructAgentEvent(raw.event) };\n case 'artifact': {\n const blobRefPresent = raw.blobRef !== undefined && raw.blobRef !== null;\n const blobRefRaw = asRecord(raw.blobRef);\n const blobRef: BlobRef | undefined = blobRefPresent\n ? {\n blobId: str(blobRefRaw.blobId),\n contentHash: str(blobRefRaw.contentHash),\n size: num(blobRefRaw.size) ?? 0,\n contentType: str(blobRefRaw.contentType),\n }\n : undefined;\n const inlineSize = num(raw.inlineSize);\n return {\n kind: 'artifact',\n ts,\n taskId: str(raw.taskId),\n name: str(raw.name),\n contentType: str(raw.contentType),\n inline: inlineSize === undefined ? undefined : placeholderFor(inlineSize),\n blobRef,\n };\n }\n case 'awaiting-approval':\n return { kind: 'awaiting-approval', ts, taskId: str(raw.taskId), summary: placeholderFor(num(raw.summarySize)) };\n case 'completed':\n return {\n kind: 'completed',\n ts,\n taskId: str(raw.taskId),\n summary: placeholderFor(num(raw.summarySize)),\n sessionRef: str(raw.sessionRef),\n };\n case 'failed':\n return {\n kind: 'failed',\n ts,\n taskId: str(raw.taskId),\n reason: placeholderFor(num(raw.reasonSize)),\n retryable: bool(raw.retryable, false),\n preClaim: typeof raw.preClaim === 'boolean' ? raw.preClaim : undefined,\n };\n case 'cancelled': {\n const reasonSize = num(raw.reasonSize);\n return {\n kind: 'cancelled',\n ts,\n taskId: str(raw.taskId),\n reason: reasonSize === undefined ? undefined : placeholderFor(reasonSize),\n };\n }\n case 'connection':\n return { kind: 'connection', ts, state: str(raw.state) as ConnectionState };\n case 'paired':\n return { kind: 'paired', ts, deviceId: str(raw.deviceId) };\n case 'unpaired':\n return { kind: 'unpaired', ts };\n case 'runtimes-detected':\n return { kind: 'runtimes-detected', ts, runtimes: Array.isArray(raw.runtimes) ? (raw.runtimes as RuntimeInfo[]) : [] };\n case 'shutdown-requested':\n return { kind: 'shutdown-requested', ts, reason: str(raw.reason) };\n case 'shutdown-complete':\n // Finding R3: read-side symmetry with `redactForAudit`'s own\n // `shutdown-complete` case — `undeliveredOutboxCount` is a plain\n // number, reconstructed verbatim (never a placeholder — there was\n // never anything to redact here), `undefined` only for an\n // audit-log line written before this fix existed (or a\n // corrupt/non-numeric value).\n return { kind: 'shutdown-complete', ts, reason: str(raw.reason), undeliveredOutboxCount: num(raw.undeliveredOutboxCount) };\n case 'stale-approval-decision': {\n const reasonSize = num(raw.reasonSize);\n return {\n kind: 'stale-approval-decision',\n ts,\n taskId: str(raw.taskId),\n decision: str(raw.decision) as 'approve' | 'reject',\n reason: reasonSize === undefined ? undefined : placeholderFor(reasonSize),\n };\n }\n case 'git-workspace': {\n const commitsSinceBaseline = gitCount(raw.commitsSinceBaseline);\n const dirty = gitDirty(raw.dirty);\n return {\n kind: 'git-workspace',\n ts,\n taskId: str(raw.taskId),\n workspaceId: str(raw.workspaceId),\n phase: str(raw.phase),\n headChanged: typeof raw.headChanged === 'boolean' ? raw.headChanged : undefined,\n commitsSinceBaseline,\n dirty,\n errorCategory: stableGitErrorCategory(raw.errorCategory),\n };\n }\n default:\n return undefined;\n }\n}\n\n/**\n * Appends one `DaemonEvent` as a single redacted JSON line (finding P1 #3 —\n * see this file's module doc comment) at 0600, and rotates the file if it's\n * grown past the size cap (finding P2/#11). Plain `fs.open('a')` +\n * `appendFile` — sufficient for an append-only log (no torn-read risk the\n * way a whole-file replace has; see `util/atomic-write.ts`'s own doc comment\n * for why THAT helper exists for whole-file writes instead of just being\n * used here too — rotation below is the one path in this file that DOES\n * replace the whole file, and does use it).\n */\nexport async function appendAuditEvent(storeDir: string, event: DaemonEvent): Promise<void> {\n await fs.mkdir(storeDir, { recursive: true, mode: AUDIT_STORE_DIR_MODE });\n // `mkdir`'s own `mode` only applies at CREATION time — a pre-existing\n // storeDir (predating this fix, or created by something else with a more\n // permissive mode) keeps whatever it already had. Re-assert explicitly on\n // every append, best-effort: this directory also holds device.json/cursor\n // state, so locking it down helps those as a side effect, but a failure\n // here (e.g. a storeDir owned by a different user) must never block the\n // append itself.\n await fs.chmod(storeDir, AUDIT_STORE_DIR_MODE).catch(() => {});\n\n const filePath = auditLogPath(storeDir);\n const line = `${JSON.stringify(redactForAudit(event))}\\n`;\n const handle = await fs.open(filePath, 'a', AUDIT_LOG_MODE);\n try {\n // Finding P1 #3b: chmod BEFORE appending, not after. `open()`'s own\n // `mode` argument only governs permissions at file-CREATION time, so a\n // PRE-EXISTING file (predating this fix, or loosened by something else)\n // keeps whatever mode it already had until explicitly chmod'd here —\n // doing that FIRST means there is never a window where the line we're\n // about to write lands in a still-permissive file, and the tightening\n // still takes effect even if the `appendFile` below then fails (it's no\n // longer gated behind a write that might throw before ever reaching\n // it). Mirrors `util/atomic-write.ts`'s own defensive re-chmod, for the\n // identical reason (don't trust \"governed at creation only\" for a file\n // that can carry sensitive metadata).\n await handle.chmod(AUDIT_LOG_MODE);\n await handle.appendFile(line, 'utf8');\n } finally {\n await handle.close();\n }\n\n await rotateIfNeeded(filePath);\n}\n\n/**\n * `DaemonEvent.kind`s that end a task's lifecycle — once one of these\n * appears anywhere for a taskId, `deriveTasksFromEvents` (`tasks-view.ts`)\n * can reconstruct that task's final state from that ONE event alone\n * (`upsert` seeds a fresh record from whatever patch a terminal event\n * carries), so no earlier event of its needs to survive a rotation. A small\n * local set rather than importing from `@byok-sdk/protocol`/`tasks-view.ts`:\n * those describe reducer OUTPUT states, not `DaemonEvent.kind`s, and only\n * these three kinds ever end a task (mirrors `tasks-view.ts`'s own\n * `deriveTasksFromEvents` switch).\n */\nconst TERMINAL_EVENT_KINDS = new Set(['completed', 'failed', 'cancelled']);\n\nfunction eventTaskId(event: DaemonEvent): string | undefined {\n // Git observations are audit metadata, never task lifecycle events. In\n // particular they must not keep an otherwise-evicted task alive during\n // rotation or manufacture a task in the replay reducer.\n if (event.kind === 'git-workspace') return undefined;\n return 'taskId' in event ? event.taskId : undefined;\n}\n\n/**\n * Finding P2 (new, round 1): a pure positional \"keep the last N lines\" trim\n * can evict EVERY event a still-running (non-terminal) task ever had — if a\n * task's `offered`/`started`/`progress` events are all old enough to fall\n * in the dropped prefix, and it hasn't reached a terminal kind\n * (`completed`/`failed`/`cancelled`) anywhere in the file, there is\n * nothing left for `deriveTasksFromEvents` to reconstruct it from —\n * `tasks`/`status` silently forget a task that is still actually running.\n *\n * Deliberately simple (a full retention policy is more than this finding's\n * own scope calls for): scan every line once, tracking per taskId whether\n * a terminal kind occurs anywhere in the file and the index of its LAST\n * occurrence. Any taskId with no terminal kind whose last occurrence falls\n * in the portion about to be dropped gets exactly that one line preserved\n * — spliced in immediately before the kept tail (so the file stays\n * oldest-first overall, matching every other invariant this module\n * documents) as a lifecycle anchor. That's just enough for the reducer to\n * know the task exists and its last-known state; it does NOT preserve that\n * task's entire historical event stream (which could itself be unbounded\n * for a long-running task with many `progress` events — preserving all of\n * it would defeat the point of rotation). A task that already reached a\n * terminal kind needs no anchor at all: it's fully reconstructable from\n * that one terminal event, wherever it happens to fall.\n *\n * Finding P2 (new, round 2): round 1's anchor count had no cap of its own —\n * bounded by \"the number of DISTINCT non-terminal tasks old enough to be\n * affected\", which in realistic operation is small, but is NOT actually\n * bounded when a daemon crashes leaving many non-terminal tasks behind, or\n * a bug keeps creating tasks that never reach a terminal kind. Anchors are\n * now additionally capped at {@link MAX_LIVE_TASK_ANCHORS}: once the number\n * of candidate anchors exceeds it, only the most RECENTLY-touched ones (by\n * last-seen line index) are kept, the oldest overflow is dropped, and a\n * single warning is logged for the whole rotation (not once per dropped\n * anchor). This keeps `kept.length` bounded by `targetLines +\n * MAX_LIVE_TASK_ANCHORS` in the worst case — still slightly over\n * `targetLines`, by design (see round 1's own trade-off), but no longer\n * unboundedly so. Self-correcting either way: once an anchored task reaches\n * a terminal kind, a later rotation stops preserving it at all.\n */\nfunction compactPreservingLiveTasks(lines: readonly string[], targetLines: number): string[] {\n if (lines.length <= targetLines) return [...lines];\n\n const cutIndex = lines.length - targetLines; // lines[0, cutIndex) would normally be dropped entirely\n const hasTerminalEvent = new Set<string>();\n const lastIndexForTask = new Map<string, number>();\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line === undefined) continue;\n const event = parseAuditLine(line);\n if (!event) continue;\n const taskId = eventTaskId(event);\n if (taskId === undefined) continue;\n lastIndexForTask.set(taskId, i);\n if (TERMINAL_EVENT_KINDS.has(event.kind)) hasTerminalEvent.add(taskId);\n }\n\n let anchorIndices: number[] = [];\n for (const [taskId, lastIndex] of lastIndexForTask) {\n if (hasTerminalEvent.has(taskId)) continue; // reconstructable from its own terminal event, wherever that falls\n if (lastIndex < cutIndex) anchorIndices.push(lastIndex); // otherwise about to be fully evicted\n }\n anchorIndices.sort((a, b) => a - b); // ascending: oldest-touched first, most-recently-touched last\n\n if (anchorIndices.length > MAX_LIVE_TASK_ANCHORS) {\n const totalCandidates = anchorIndices.length;\n const droppedCount = totalCandidates - MAX_LIVE_TASK_ANCHORS;\n anchorIndices = anchorIndices.slice(-MAX_LIVE_TASK_ANCHORS); // keep the most RECENTLY-touched, drop the oldest overflow\n console.warn(\n `[byok/client] audit log rotation: ${totalCandidates} non-terminal task lifecycle anchors exceeded MAX_LIVE_TASK_ANCHORS (${MAX_LIVE_TASK_ANCHORS}) — dropped the oldest ${droppedCount}, kept the most recently-touched ${MAX_LIVE_TASK_ANCHORS}; dropped tasks will stop appearing in tasks/status once their own events age out of the retained tail`,\n );\n }\n\n return [...anchorIndices.map((i) => lines[i]), ...lines.slice(cutIndex)].filter((l): l is string => l !== undefined);\n}\n\n/** Finding P2/#11 (audit half): see `MAX_AUDIT_LOG_BYTES`'s own doc comment. Finding P2 (new): see {@link compactPreservingLiveTasks}. */\nasync function rotateIfNeeded(filePath: string): Promise<void> {\n let size: number;\n try {\n size = (await fs.stat(filePath)).size;\n } catch {\n return; // ENOENT or similar — nothing to rotate\n }\n if (size <= MAX_AUDIT_LOG_BYTES) return;\n\n const lines = await readCompleteLines(filePath);\n const kept = compactPreservingLiveTasks(lines, AUDIT_LOG_TRIM_TARGET_LINES);\n const content = kept.length > 0 ? `${kept.join('\\n')}\\n` : '';\n // Atomic (temp file + rename) so a concurrent `readAuditEvents`/\n // `followAuditLog` reader never observes a torn/partial file mid-rotation\n // — same helper `daemon/store.ts`/`daemon/cursor-store.ts` use for their\n // own whole-file replaces.\n await atomicWriteFile(filePath, content, { mode: AUDIT_LOG_MODE });\n}\n\n/**\n * Adapts {@link appendAuditEvent} into a `DaemonEventListener` for\n * `daemon.subscribe()` (used by the `start` command). `DaemonEventListener`\n * is synchronous — `observer.ts`'s `emit()` never awaits a listener (see its\n * own doc comment on why, including the finding #6 async-safety fix) — so a\n * naive fire-and-forget `appendAuditEvent(...).catch(...)` per call would\n * have a real problem: the underlying `fs.open`/`appendFile` calls could\n * complete OUT OF ORDER under load, silently corrupting the log's own event\n * ordering. This chains each append onto the previous one (still\n * async/non-blocking from the listener's point of view) so writes always\n * land in emission order, and a failed write (reported via `onError`) never\n * breaks the chain for subsequent events.\n */\nexport function createAuditAppender(storeDir: string, onError: (err: unknown) => void = () => {}): DaemonEventListener {\n let chain: Promise<void> = Promise.resolve();\n return (event: DaemonEvent) => {\n chain = chain.then(() => appendAuditEvent(storeDir, event)).catch(onError);\n };\n}\n\nfunction isAuditRecordShaped(value: unknown): value is Record<string, unknown> {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { kind?: unknown }).kind === 'string' &&\n typeof (value as { ts?: unknown }).ts === 'string'\n );\n}\n\n/** Parses one line; returns `undefined` (never throws) for a blank, corrupt, or unrecognized-kind line so one bad line can't take down a whole `status`/`tasks` read. Reconstructs a `DaemonEvent`-shaped value from the redacted on-disk projection — see the module doc comment. */\nfunction parseAuditLine(line: string): DaemonEvent | undefined {\n const trimmed = line.trim();\n if (!trimmed) return undefined;\n try {\n const parsed: unknown = JSON.parse(trimmed);\n if (!isAuditRecordShaped(parsed)) return undefined;\n return reconstructDaemonEvent(parsed);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Every line that's definitely COMPLETE — i.e. every line except the last\n * element `raw.split('\\n')` produces, which is either `''` (when `raw` ends\n * with `\\n`, the normal fully-flushed case) or a genuinely not-yet-terminated\n * partial line (when `raw` was read mid-write). Dropping that last element\n * either way means a `--follow` reader can never observe — and thus never\n * permanently skip — a torn line from a write it caught mid-flush; it just\n * gets picked up whole on a later poll once the writer finishes it.\n */\nfunction completeLines(raw: string): string[] {\n const parts = raw.split('\\n');\n parts.pop();\n return parts;\n}\n\nasync function readCompleteLines(filePath: string): Promise<string[]> {\n let raw: string;\n try {\n raw = await fs.readFile(filePath, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return [];\n throw err;\n }\n return completeLines(raw);\n}\n\n/** Full historical read (oldest first) — `[]` if the log doesn't exist yet (e.g. `start` has never run). Used by `status`/`tasks` (no `--follow`). */\nexport async function readAuditEvents(storeDir: string): Promise<DaemonEvent[]> {\n const lines = await readCompleteLines(auditLogPath(storeDir));\n const events: DaemonEvent[] = [];\n for (const line of lines) {\n const event = parseAuditLine(line);\n if (event) events.push(event);\n }\n return events;\n}\n\nexport interface FollowOptions {\n signal: AbortSignal;\n /** How often to check the file for new bytes. Default 200ms — plenty responsive for a human tailing output, without busy-looping. */\n pollIntervalMs?: number;\n /**\n * `true` (default): start at the file's CURRENT length — a `tail -f`,\n * streaming only events appended from the moment `followAuditLog` was\n * called. `false`: replay the full existing log first, then keep\n * streaming — mainly useful for tests that want both in one pass.\n */\n fromEnd?: boolean;\n}\n\n/** Cancellable delay: resolves early the instant `signal` aborts, so a follow loop stops promptly instead of waiting out a full poll interval. */\nfunction delay(ms: number, signal: AbortSignal): Promise<void> {\n if (signal.aborted) return Promise.resolve();\n return new Promise((resolve) => {\n const onAbort = (): void => {\n clearTimeout(timer);\n resolve();\n };\n const timer = setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/**\n * Tails `filePath` (the audit log) for newly-appended `DaemonEvent` lines\n * until `options.signal` aborts. No native filesystem-event watching (no\n * `fs.watch` — inconsistent across platforms, especially the rename-based\n * atomic writes this package uses elsewhere for OTHER files).\n *\n * Finding P2/#11 (audit half): the previous implementation re-read the\n * ENTIRE file from byte 0 on every single poll, re-parsing every\n * already-emitted line just to find the handful of new ones at the end —\n * O(file size) work every `pollIntervalMs`, forever, for as long as\n * `tasks --follow` stays attached. This tracks a byte OFFSET across polls\n * instead: each poll opens the file and reads only the bytes appended since\n * the last read (`FileHandle.read` at a specific position), advancing\n * `offset` by exactly that many bytes — only genuinely new bytes are ever\n * read or decoded.\n *\n * UTF-8 safety: the new bytes are split on the RAW BYTE `0x0a` ('\\n')\n * BEFORE any UTF-8 decoding happens, not on an already-decoded string —\n * `0x0A` can only ever appear as an actual newline in valid UTF-8\n * (continuation bytes are always `0x80`-`0xBF`), so this never risks\n * decoding a torn multi-byte character that happened to straddle a chunk\n * boundary. Bytes after the last `\\n` in a chunk are held in `pending`\n * (as a `Buffer`, still undecoded) until a future poll's bytes complete\n * that line — mirrors `completeLines`'s existing \"never guess at a torn\n * trailing line\" contract for `readAuditEvents`, just incremental.\n *\n * Rotation tolerance: if `appendAuditEvent`'s own size-cap rotation (or\n * anything else) replaces the file out from under an in-progress follow,\n * `offset` resets to 0 and `pending` is cleared — the follow session\n * survives (rather than throwing or garbling) at the cost of re-emitting\n * the post-rotation file's retained lines as if they were new.\n *\n * Finding P2 (new): that replacement is detected by file IDENTITY\n * (`dev:ino`), not by comparing sizes. The previous implementation only\n * reset `offset` when the new file was SMALLER than it (`st.size <\n * offset`) — sufficient for the common case (a big pre-rotation file\n * trimmed down to a small one), but `rotateIfNeeded`'s replace is an atomic\n * temp-file + `fs.rename` (see `atomicWriteFile`), which swaps the\n * underlying INODE regardless of whether the new file happens to be\n * smaller OR LARGER than the reader's current offset. A `--follow` session\n * that attached while the log was still tiny (a small `offset`) can have a\n * rotation land a compacted-but-still-much-bigger-than-that-tiny-offset\n * file in its place — the old size-only check missed exactly that case\n * (`st.size < offset` was false), so it kept reading from the stale\n * `offset` INTO THE NEW FILE's bytes: skipping that file's own prefix\n * entirely and very likely starting mid-JSON-line. Tracking `dev:ino`\n * across polls catches ANY replacement — smaller, larger, anything — and\n * resets `offset` to 0 so the new file is always re-read from its own\n * start. The size-based check is kept as a secondary fallback (a\n * same-identity in-place truncate, or a platform where `ino` isn't a\n * reliable identity signal).\n */\nexport async function followAuditLog(\n filePath: string,\n onEvent: (event: DaemonEvent) => void,\n options: FollowOptions,\n): Promise<void> {\n const { signal, pollIntervalMs = 200, fromEnd = true } = options;\n\n let offset = 0;\n // Explicit `Buffer` (not the narrower type `Buffer.alloc(0)` alone would\n // infer): this gets reassigned from `Buffer.concat`/`.subarray`, whose\n // return types don't always narrow identically across @types/node\n // versions — the plain `Buffer` alias covers all of them.\n let pending: Buffer = Buffer.alloc(0);\n // Finding P2 (new): `dev:ino` of the file `offset` was last measured\n // against — `undefined` until the first successful stat of an existing\n // file. See this function's own doc comment (\"Rotation tolerance\").\n let lastFileIdentity: string | undefined;\n\n if (fromEnd) {\n try {\n const st = await fs.stat(filePath);\n offset = st.size;\n lastFileIdentity = `${st.dev}:${st.ino}`;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n offset = 0;\n }\n }\n\n async function readNewBytes(): Promise<Buffer> {\n let handle;\n try {\n handle = await fs.open(filePath, 'r');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return Buffer.alloc(0);\n throw err;\n }\n try {\n const st = await handle.stat();\n const identity = `${st.dev}:${st.ino}`;\n if (lastFileIdentity !== undefined && identity !== lastFileIdentity) {\n // The file at this path was replaced (e.g. an atomic rotation)\n // since our last read — a different inode means our byte offset no\n // longer means anything for THIS file's bytes, regardless of\n // whether the new file is smaller OR LARGER than the old offset\n // (a purely size-based check misses the latter — finding P2 (new)).\n offset = 0;\n pending = Buffer.alloc(0);\n } else if (st.size < offset) {\n // Same identity but shrunk (e.g. truncated in place rather than\n // replaced) — keep the original size-based fallback for that case,\n // and as a safety net on a platform where `ino` isn't reliable.\n offset = 0;\n pending = Buffer.alloc(0);\n }\n lastFileIdentity = identity;\n if (st.size <= offset) return Buffer.alloc(0);\n const length = st.size - offset;\n const buffer = Buffer.alloc(length);\n const { bytesRead } = await handle.read(buffer, 0, length, offset);\n offset += bytesRead;\n return buffer.subarray(0, bytesRead);\n } finally {\n await handle.close();\n }\n }\n\n while (!signal.aborted) {\n const chunk = await readNewBytes();\n if (chunk.length > 0) {\n const combined = pending.length > 0 ? Buffer.concat([pending, chunk]) : chunk;\n const lastNewline = combined.lastIndexOf(0x0a);\n if (lastNewline === -1) {\n pending = combined;\n } else {\n const completeText = combined.subarray(0, lastNewline + 1).toString('utf8');\n pending = Buffer.from(combined.subarray(lastNewline + 1));\n for (const line of completeText.split('\\n')) {\n if (!line) continue;\n const event = parseAuditLine(line);\n if (event) onEvent(event);\n }\n }\n }\n\n if (signal.aborted) break;\n await delay(pollIntervalMs, signal);\n }\n}\n","import { createDaemon, type Daemon, type DaemonConfig } from '../../index';\nimport { createAuditAppender } from '../audit-log';\nimport { resolveStoreDir } from '../config';\nimport { formatDaemonEventLine } from '../format';\n\nexport interface StartDeps {\n log?: (line: string) => void;\n error?: (line: string) => void;\n /** DI for tests: drive a pre-built (e.g. stub-adapter-backed) `Daemon` instead of the real `createDaemon(config)`. */\n daemon?: Daemon;\n /** Test hook: fires once `daemon.start()` has resolved and the banner line has been logged — lets a test abort deterministically instead of racing real timing. Unused by the real CLI entry. */\n onReady?: () => void;\n /** Required: there is no sane default \"never stop\" signal. The real CLI entry (`byok-agent.ts`) wires this to SIGINT/SIGTERM; tests wire their own `AbortController`. */\n signal: AbortSignal;\n}\n\n/**\n * Runs the daemon in the foreground until `deps.signal` aborts. Every\n * `DaemonEvent` it observes is (a) appended to `<storeDir>/audit.jsonl` —\n * the only channel a separate `status`/`tasks`/`runtimes` invocation has\n * into this process' state, see `byok-agent.ts`'s header comment — and (b)\n * printed as one line to stdout via the SAME formatter `tasks --follow`\n * uses when tailing that log, so watching `start`'s own stdout and tailing\n * the audit log show identical text.\n */\nexport async function runStartCommand(config: DaemonConfig, deps: StartDeps): Promise<void> {\n const log = deps.log ?? ((line: string) => console.log(line));\n const error = deps.error ?? ((line: string) => console.error(line));\n const storeDir = resolveStoreDir(config);\n const daemon = deps.daemon ?? createDaemon(config);\n\n const appendToAudit = createAuditAppender(storeDir, (err) =>\n error(`audit log append failed: ${err instanceof Error ? err.message : String(err)}`),\n );\n // M4 Phase 2: the daemon's control socket (`shutdown` RPC — see\n // `create-daemon.ts`'s `performControlShutdown`) can stop the daemon from\n // OUTSIDE this process (a separate `byok-agent unpair`/`service-stop`-like\n // invocation), with no OS signal involved at all. Without reacting to\n // that here, this function would hang forever awaiting `deps.signal`'s\n // abort, which would never come — see the wait below.\n //\n // Gatekeeper-confirmed regression (fixed here): this used to wait for\n // `shutdown-requested`, which fires SYNCHRONOUSLY at the very START of\n // `performControlShutdown` — before it has even called\n // `session.interrupt()` on an active task, let alone sent that task's\n // `task.fail`. Waking up that early let this function's own\n // `daemon.stop()` call below race ahead and close the connection\n // (`ConnectionManager.stopped = true`, synchronously) before the\n // still-in-flight `task.fail` send could reach the outbox drain,\n // silently dropping it. `shutdown-complete` fires only once\n // `performControlShutdown` has ALREADY finished its own internal\n // `stop()` — waiting for that instead means this function's `daemon.stop()`\n // below always runs strictly after the real teardown (interrupt -> send\n // task.fail -> finish -> stop) has completed, so it can never race ahead\n // of it; see `daemon-control-socket.test.ts`'s dedicated regression test.\n let controlShutdownComplete = false;\n let notifyControlShutdown: (() => void) | undefined;\n // Subscribe BEFORE start() so the earliest events (runtimes-detected,\n // connection) are captured too — mirrors daemon-observer.test.ts's own\n // \"subscribe before pair()/start()\" convention.\n const unsubscribe = daemon.subscribe((event) => {\n appendToAudit(event);\n // Finding F8 (cross-model adversarial review): this stdout stream is\n // captured verbatim by whatever's running `start` — a human's terminal,\n // but ALSO launchd/systemd/WinSW service logs when installed as a\n // background service. An `awaiting-approval` summary can carry the\n // exact tool-call text (a shell command, a file's contents) a\n // `confirm`-mode policy is gating; redact it here the same way\n // `appendToAudit` above already redacts it on disk. The full summary\n // stays available via the AUTHENTICATED control socket — the new\n // `approvals` CLI command, `approvals.list`, or `tasks --follow`'s own\n // `tasks.subscribe` path (`bin/commands/tasks.ts`, which does NOT set\n // this flag).\n log(formatDaemonEventLine(event, { redactApprovalSummary: true }));\n if (event.kind === 'shutdown-complete') {\n controlShutdownComplete = true;\n notifyControlShutdown?.();\n }\n });\n\n try {\n await daemon.start();\n // Exact \"daemon started: ...\" prefix preserved from the pre-M3-2b bin —\n // examples/basic/README.md tells a human operator to watch stdout for\n // this literal text.\n const label = config.branding?.displayName ?? config.productName;\n log(`daemon started: product=${label} (${config.productId}) server=${config.serverUrl}`);\n deps.onReady?.();\n\n if (!deps.signal.aborted && !controlShutdownComplete) {\n await new Promise<void>((resolve) => {\n notifyControlShutdown = resolve;\n deps.signal.addEventListener('abort', () => resolve(), { once: true });\n });\n }\n\n unsubscribe();\n await daemon.stop();\n log('daemon stopped');\n } catch (err) {\n unsubscribe();\n await daemon.stop().catch((cleanupErr: unknown) => {\n error(`cleanup failed during shutdown: ${cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr)}`);\n });\n throw err;\n }\n}\n","import { TASK_STATES, type TaskState } from '@byok-sdk/protocol';\nimport { type ConnectionState, type DaemonEvent, type DaemonTaskInfo } from '../index';\n\nexport interface TaskGitStatus {\n /** Opaque local correlation ID; never a path or commit ID. */\n workspaceId: string;\n phase: string;\n headChanged?: boolean;\n commitsSinceBaseline?: number;\n dirty?: { staged: number; unstaged: number; untracked: number; conflicted: number };\n errorCategory?: string;\n}\n\nexport type DerivedTaskInfo = DaemonTaskInfo & { git?: TaskGitStatus };\n\nconst STABLE_GIT_PHASES = new Set(['preparing', 'active', 'completed', 'failed', 'cancelled', 'interrupted', 'salvage']);\nconst STABLE_GIT_ERROR_CATEGORIES = new Set([\n 'git-unavailable',\n 'git-timeout',\n 'git-output-limit',\n 'git-command-failed',\n 'workspace-root-invalid',\n 'workspace-root-conflict',\n 'workspace-not-owned',\n 'repository-root-mismatch',\n 'repository-invalid',\n 'lease-busy',\n 'ledger-invalid',\n]);\n\nfunction nonNegativeSafeInteger(value: number | undefined): number | undefined {\n return value !== undefined && Number.isSafeInteger(value) && value >= 0 ? value : undefined;\n}\n\nfunction deriveGitStatus(event: Extract<DaemonEvent, { kind: 'git-workspace' }>): TaskGitStatus {\n const dirty = event.dirty\n ? {\n staged: nonNegativeSafeInteger(event.dirty.staged),\n unstaged: nonNegativeSafeInteger(event.dirty.unstaged),\n untracked: nonNegativeSafeInteger(event.dirty.untracked),\n conflicted: nonNegativeSafeInteger(event.dirty.conflicted),\n }\n : undefined;\n const sanitizedDirty = dirty && Object.values(dirty).every((count) => count !== undefined)\n ? (dirty as TaskGitStatus['dirty'])\n : undefined;\n return {\n workspaceId: event.workspaceId,\n phase: STABLE_GIT_PHASES.has(event.phase) ? event.phase : 'unknown',\n ...(typeof event.headChanged === 'boolean' ? { headChanged: event.headChanged } : {}),\n ...(nonNegativeSafeInteger(event.commitsSinceBaseline) !== undefined\n ? { commitsSinceBaseline: nonNegativeSafeInteger(event.commitsSinceBaseline) }\n : {}),\n ...(sanitizedDirty ? { dirty: sanitizedDirty } : {}),\n ...(event.errorCategory !== undefined && STABLE_GIT_ERROR_CATEGORIES.has(event.errorCategory)\n ? { errorCategory: event.errorCategory }\n : {}),\n };\n}\n\n/**\n * Reconstructs the same shape `DaemonObserver.tasks()` exposes to a LIVE\n * in-process daemon, but from a REPLAYED sequence of already-logged\n * `DaemonEvent`s instead — this is what lets a separate, short-lived\n * `byok-agent tasks`/`status` invocation show task state without attaching\n * to the `start` process that actually observed it (see `byok-agent.ts`'s\n * header comment). Deliberately a standalone reducer, not a call into\n * `DaemonObserver` itself: `DaemonObserver`'s own public methods\n * (`handleInboundEnvelope`/`handleOutboundEnvelope`) take a raw protocol\n * `Envelope`, not the already-normalized `DaemonEvent` this module receives\n * from the audit log — the two shapes don't line up, so this mirrors that\n * reducer's logic operating on `DaemonEvent.kind` directly instead.\n */\nexport function deriveTasksFromEvents(events: readonly DaemonEvent[]): DerivedTaskInfo[] {\n const tasks = new Map<string, DerivedTaskInfo>();\n\n function upsert(\n taskId: string,\n ts: string,\n patch: Partial<Omit<DerivedTaskInfo, 'taskId' | 'updatedAt'>> & { state: TaskState },\n ): void {\n const existing = tasks.get(taskId);\n tasks.set(taskId, { ...existing, ...patch, taskId, updatedAt: ts });\n }\n\n for (const event of events) {\n switch (event.kind) {\n case 'offered':\n upsert(event.taskId, event.ts, { state: 'Offered', runtime: event.runtime });\n break;\n case 'claimed':\n upsert(event.taskId, event.ts, {\n state: 'Claimed',\n ...(event.claimedRuntime !== undefined ? { claimedRuntime: event.claimedRuntime } : {}),\n });\n break;\n case 'started':\n upsert(event.taskId, event.ts, { state: 'Running' });\n break;\n case 'progress':\n upsert(event.taskId, event.ts, { state: 'Running' });\n break;\n case 'awaiting-approval':\n upsert(event.taskId, event.ts, { state: 'AwaitApproval', summary: event.summary });\n break;\n case 'completed':\n upsert(event.taskId, event.ts, { state: 'Complete', summary: event.summary, sessionRef: event.sessionRef });\n break;\n case 'failed':\n upsert(event.taskId, event.ts, {\n state: 'Failed',\n summary: event.reason,\n ...(event.preClaim ? { declined: true } : {}),\n });\n break;\n case 'cancelled':\n upsert(event.taskId, event.ts, { state: 'Cancelled', summary: event.reason });\n break;\n case 'git-workspace': {\n const existing = tasks.get(event.taskId);\n // Git-only events are observational supplements. They cannot create a\n // task row or change lifecycle authority, and only update an existing\n // row created by a lifecycle event.\n if (existing) {\n tasks.set(event.taskId, {\n ...existing,\n git: deriveGitStatus(event),\n updatedAt: event.ts,\n });\n }\n break;\n }\n // 'artifact' carries no task-STATE transition of its own (observer.ts\n // never calls its own upsertTask for it either); 'connection'/\n // 'paired'/'unpaired'/'runtimes-detected' are daemon-level, not\n // per-task.\n default:\n break;\n }\n }\n\n return [...tasks.values()];\n}\n\n/**\n * Most recent `connection` DaemonEvent, if the log has any — used by\n * `status` to show a best-effort \"last known\" transport state. Never a\n * live/current guarantee: if `start` isn't running right now, this is\n * simply whatever it last reported before exiting (or nothing, if it never\n * ran at all) — see `byok-agent.ts`'s header comment.\n */\nexport function lastConnectionState(events: readonly DaemonEvent[]): { state: ConnectionState; ts: string } | undefined {\n let last: { state: ConnectionState; ts: string } | undefined;\n for (const event of events) {\n if (event.kind === 'connection') last = { state: event.state, ts: event.ts };\n }\n return last;\n}\n\nexport type TaskCounts = Record<TaskState, number> & { total: number };\n\n/** Zero-filled over every `TaskState` (via `TASK_STATES`, the single authority — not a hand-maintained list) so a state with zero current tasks still renders instead of being silently absent. */\nexport function tallyTaskStates(tasks: readonly DaemonTaskInfo[]): TaskCounts {\n const counts = Object.fromEntries(TASK_STATES.map((state) => [state, 0])) as TaskCounts;\n counts.total = tasks.length;\n for (const task of tasks) counts[task.state] += 1;\n return counts;\n}\n","import { type DaemonConfig, type RuntimeAdapter } from '../../index';\nimport { DeviceStore } from '../../daemon/store';\nimport type { ControlStatusResult } from '../../daemon/control-protocol';\nimport { auditLogPath, readAuditEvents } from '../audit-log';\nimport { connectControlClient } from '../control-client';\nimport { resolveStoreDir } from '../config';\nimport { formatLiveStatusLines, formatStatusLines, type StatusView } from '../format';\nimport { defaultRuntimeAdapters, probeRuntimes } from '../runtime-probe';\nimport { deriveTasksFromEvents, lastConnectionState, tallyTaskStates } from '../tasks-view';\n\nexport interface StatusDeps {\n log?: (line: string) => void;\n /** DI for tests: probe these adapters instead of constructing the real bundled pi/claude/codex set. */\n adapters?: RuntimeAdapter[];\n /** DI for tests: substitute the real control-socket connection attempt. */\n connectControl?: typeof connectControlClient;\n}\n\n/**\n * `paired`/`deviceId` are read straight off `DeviceStore` on disk (NOT via\n * a freshly-constructed `Daemon.status()`) — a `Daemon` this process just\n * constructed has never called `start()`/`pair()`, so its in-memory\n * `AuthManager` never loaded the on-disk record and would always report\n * `paired: false` even for a device that's genuinely paired. See\n * `byok-agent.ts`'s header comment for the full read-model rationale.\n *\n * M4 Phase 2: after the persisted-state view above, this ALSO tries the\n * control socket (see `control-client.ts`) — if a `byok-agent start` (or\n * the installed service) is actually running right now, its live pid/\n * uptime/transport/active-tasks are appended, clearly marked `live-`; if\n * not reachable, one line says so and the persisted view above stands on\n * its own, exactly as before this feature existed.\n */\nexport async function runStatusCommand(config: DaemonConfig, deps: StatusDeps = {}): Promise<void> {\n const log = deps.log ?? ((line: string) => console.log(line));\n const storeDir = resolveStoreDir(config);\n const adapters = deps.adapters ?? defaultRuntimeAdapters(config.runtimeAllowlist);\n const connectControl = deps.connectControl ?? connectControlClient;\n\n const [record, events, runtimes] = await Promise.all([\n new DeviceStore(storeDir).load(),\n readAuditEvents(storeDir),\n probeRuntimes(adapters),\n ]);\n const tasks = deriveTasksFromEvents(events);\n\n const view: StatusView = {\n productName: config.productName,\n productId: config.productId,\n branding: config.branding,\n paired: record !== undefined,\n deviceId: record?.deviceId,\n connection: lastConnectionState(events),\n runtimes,\n taskCounts: tallyTaskStates(tasks),\n auditLogPath: auditLogPath(storeDir),\n auditLogLineCount: events.length,\n };\n for (const line of formatStatusLines(view)) log(line);\n\n const conn = await connectControl({ storeDir, productId: config.productId });\n if (!conn.ok) {\n log(`live status: daemon not reachable (${conn.reason})`);\n return;\n }\n try {\n const live = await conn.client.request<ControlStatusResult>('status');\n for (const line of formatLiveStatusLines(live)) log(line);\n } catch (err) {\n log(`live status unavailable: ${err instanceof Error ? err.message : String(err)}`);\n } finally {\n conn.client.close();\n }\n}\n","import { randomUUID } from 'node:crypto';\nimport { constants as fsConstants, promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { DaemonConfig, DaemonEvent } from '../index';\nimport { auditLogPath } from '../bin/audit-log';\nimport { atomicWriteFile } from '../util/atomic-write';\nimport { ensureSecureDir, ensureSecureFile, type EnsureSecureDirOptions } from '../util/secure-dir';\nimport {\n collectDiagnostics,\n type CollectDiagnosticsOptions,\n type DiagnosticsSnapshot,\n} from './diagnostics';\n\nexport const MAX_SUPPORT_AUDIT_TAIL_BYTES = 256 * 1024;\nexport const MAX_SUPPORT_AUDIT_FACTS = 200;\n\nexport interface SupportBundle {\n version: 1;\n generatedAt: string;\n product: { nameHash: string; idHash: string };\n system: DiagnosticsSnapshot['system'];\n config: {\n serverProtocol: 'http' | 'https' | 'ws' | 'wss' | 'invalid' | 'unsupported';\n customStoreDir: boolean;\n hostedJournal: boolean;\n runtimeAllowlistCount?: number;\n };\n device: { status: DiagnosticsSnapshot['device']['status']; deviceIdHash?: string };\n runtimes: DiagnosticsSnapshot['runtimes'];\n control:\n | { status: 'offline' }\n | {\n status: 'online';\n pid: number;\n uptimeMs: number;\n transport: 'connecting' | 'open' | 'closed' | 'degraded' | 'revoked' | 'unavailable';\n activeTaskCount: number;\n pendingApprovalCount: number;\n operationalHealth:\n | { availability: 'unavailable' }\n | {\n availability: 'available';\n state: 'healthy' | 'degraded' | 'recovering';\n failureCount: number;\n windowMs: number;\n failureThreshold: number;\n crashCount: number;\n lastCrashAt?: string;\n currentRunStartedAt?: string;\n };\n storagePresent: boolean;\n };\n health: DiagnosticsSnapshot['health'];\n journal: DiagnosticsSnapshot['journal'];\n workspace: DiagnosticsSnapshot['workspace'];\n quarantine: {\n status: DiagnosticsSnapshot['quarantine']['status'];\n count: number;\n scannedCount: number;\n truncated: boolean;\n entries: DiagnosticsSnapshot['quarantine']['entries'];\n };\n checks: Array<Pick<DiagnosticsSnapshot['checks'][number], 'id' | 'status'>>;\n recentEvents: {\n status: 'available' | 'missing' | 'unavailable';\n included: number;\n sourceBytesRead: number;\n sourceTruncated: boolean;\n facts: Array<{ kind: DaemonEvent['kind']; ts: string }>;\n };\n redaction: {\n policy: 'allowlist-v1';\n omitted: string[];\n transformed: string[];\n };\n}\n\nconst AUDIT_KINDS = new Set<DaemonEvent['kind']>([\n 'artifact',\n 'awaiting-approval',\n 'cancelled',\n 'claimed',\n 'completed',\n 'connection',\n 'failed',\n 'git-workspace',\n 'offered',\n 'paired',\n 'progress',\n 'runtimes-detected',\n 'shutdown-complete',\n 'shutdown-requested',\n 'stale-approval-decision',\n 'started',\n 'unpaired',\n]);\n\nfunction isAuditKind(value: unknown): value is DaemonEvent['kind'] {\n return typeof value === 'string' && AUDIT_KINDS.has(value as DaemonEvent['kind']);\n}\n\nfunction sameFileState(left: import('node:fs').BigIntStats, right: import('node:fs').BigIntStats): boolean {\n return (\n left.dev === right.dev &&\n left.ino === right.ino &&\n left.size === right.size &&\n left.mtimeNs === right.mtimeNs &&\n left.ctimeNs === right.ctimeNs\n );\n}\n\nasync function recentAuditFacts(storeDir: string): Promise<SupportBundle['recentEvents']> {\n const filePath = auditLogPath(storeDir);\n let pathStat: import('node:fs').BigIntStats;\n try {\n pathStat = await fs.lstat(filePath, { bigint: true });\n if (!pathStat.isFile() || pathStat.isSymbolicLink()) {\n return { status: 'unavailable', included: 0, sourceBytesRead: 0, sourceTruncated: false, facts: [] };\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return { status: 'missing', included: 0, sourceBytesRead: 0, sourceTruncated: false, facts: [] };\n }\n return { status: 'unavailable', included: 0, sourceBytesRead: 0, sourceTruncated: false, facts: [] };\n }\n let handle: Awaited<ReturnType<typeof fs.open>>;\n try {\n handle = await fs.open(\n filePath,\n fsConstants.O_RDONLY | fsConstants.O_NONBLOCK | (fsConstants.O_NOFOLLOW ?? 0),\n );\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return { status: 'missing', included: 0, sourceBytesRead: 0, sourceTruncated: false, facts: [] };\n }\n return { status: 'unavailable', included: 0, sourceBytesRead: 0, sourceTruncated: false, facts: [] };\n }\n try {\n const stat = await handle.stat({ bigint: true });\n const namedAfterOpen = await fs.lstat(filePath, { bigint: true });\n if (\n !stat.isFile() ||\n !namedAfterOpen.isFile() ||\n namedAfterOpen.isSymbolicLink() ||\n !sameFileState(pathStat, stat) ||\n !sameFileState(stat, namedAfterOpen)\n ) {\n return { status: 'unavailable', included: 0, sourceBytesRead: 0, sourceTruncated: false, facts: [] };\n }\n const sourceSize = Number(stat.size);\n const length = Math.min(sourceSize, MAX_SUPPORT_AUDIT_TAIL_BYTES);\n const start = Math.max(0, sourceSize - length);\n const buffer = Buffer.alloc(length);\n const { bytesRead } = await handle.read(buffer, 0, length, start);\n const afterRead = await handle.stat({ bigint: true });\n const namedAfterRead = await fs.lstat(filePath, { bigint: true });\n if (\n bytesRead !== length ||\n namedAfterRead.isSymbolicLink() ||\n !sameFileState(stat, afterRead) ||\n !sameFileState(afterRead, namedAfterRead)\n ) {\n return { status: 'unavailable', included: 0, sourceBytesRead: 0, sourceTruncated: false, facts: [] };\n }\n let text = buffer.subarray(0, bytesRead).toString('utf8');\n if (start > 0) text = text.slice(Math.max(0, text.indexOf('\\n') + 1));\n const lines = text.split('\\n').filter(Boolean).slice(-MAX_SUPPORT_AUDIT_FACTS);\n const facts: Array<{ kind: DaemonEvent['kind']; ts: string }> = [];\n for (const line of lines) {\n try {\n const value = JSON.parse(line) as Record<string, unknown>;\n if (isAuditKind(value.kind) && typeof value.ts === 'string' && Number.isFinite(Date.parse(value.ts))) {\n facts.push({ kind: value.kind, ts: new Date(Date.parse(value.ts)).toISOString() });\n }\n } catch {\n // A torn/malformed historical line is omitted and represented by the\n // included count; raw bytes are never copied into the bundle.\n }\n }\n return { status: 'available', included: facts.length, sourceBytesRead: bytesRead, sourceTruncated: sourceSize > bytesRead, facts };\n } catch {\n return { status: 'unavailable', included: 0, sourceBytesRead: 0, sourceTruncated: false, facts: [] };\n } finally {\n await handle.close();\n }\n}\n\nfunction projectControl(control: DiagnosticsSnapshot['control']): SupportBundle['control'] {\n if (control.status === 'offline') return { status: 'offline' };\n const transport = ['connecting', 'open', 'closed', 'degraded', 'revoked'].includes(control.transport)\n ? (control.transport as 'connecting' | 'open' | 'closed' | 'degraded' | 'revoked')\n : 'unavailable';\n const operationalHealth =\n control.operationalHealth.availability === 'available'\n ? {\n availability: 'available' as const,\n state: control.operationalHealth.state,\n failureCount: control.operationalHealth.failureCount,\n windowMs: control.operationalHealth.windowMs,\n failureThreshold: control.operationalHealth.failureThreshold,\n crashCount: control.operationalHealth.crashCount,\n }\n : { availability: 'unavailable' as const };\n return {\n status: 'online',\n pid: control.pid,\n uptimeMs: control.uptimeMs,\n transport,\n activeTaskCount: control.activeTaskCount,\n pendingApprovalCount: control.pendingApprovalCount,\n operationalHealth,\n storagePresent: control.storage !== undefined,\n };\n}\n\nexport async function createSupportBundle(\n config: DaemonConfig,\n storeDir: string,\n options: CollectDiagnosticsOptions = {},\n): Promise<SupportBundle> {\n const [snapshot, recentEvents] = await Promise.all([collectDiagnostics(config, storeDir, options), recentAuditFacts(storeDir)]);\n return {\n version: 1,\n generatedAt: snapshot.generatedAt,\n product: snapshot.product,\n system: snapshot.system,\n config: {\n serverProtocol: snapshot.config.serverProtocol,\n customStoreDir: snapshot.config.customStoreDir,\n hostedJournal: snapshot.config.hostedJournal,\n ...(snapshot.config.runtimeAllowlistCount === undefined ? {} : { runtimeAllowlistCount: snapshot.config.runtimeAllowlistCount }),\n },\n device: {\n status: snapshot.device.status,\n ...(snapshot.device.deviceIdHash ? { deviceIdHash: snapshot.device.deviceIdHash } : {}),\n },\n runtimes: snapshot.runtimes,\n control: projectControl(snapshot.control),\n health: snapshot.health,\n journal: snapshot.journal,\n workspace: snapshot.workspace,\n quarantine: {\n status: snapshot.quarantine.status,\n count: snapshot.quarantine.count,\n scannedCount: snapshot.quarantine.scannedCount,\n truncated: snapshot.quarantine.truncated,\n entries: snapshot.quarantine.entries,\n },\n checks: snapshot.checks.map(({ id, status }) => ({ id, status })),\n recentEvents,\n redaction: {\n policy: 'allowlist-v1',\n omitted: [\n 'server URL host/path/query',\n 'store/workspace/config paths',\n 'control token and provider credentials',\n 'task, prompt, tool input/output and approval text',\n 'raw audit and quarantine contents',\n ],\n transformed: ['productName/productId/deviceId/runtimeId/quarantine filenames -> SHA-256', 'audit events -> closed kind/timestamp only'],\n },\n };\n}\n\n/**\n * Publish a complete bundle at a previously-unused path. The same-directory\n * hard-link makes publication atomic and `EEXIST`-safe: no reader can see a\n * partial JSON file and an existing operator artifact is never overwritten.\n */\nexport async function writeSupportBundle(\n outputPath: string,\n bundle: SupportBundle,\n secureFileOptions: EnsureSecureDirOptions = {},\n): Promise<void> {\n const dir = path.dirname(outputPath);\n const parentStat = await fs.stat(dir);\n if (!parentStat.isDirectory()) throw new Error('support bundle output parent is not a directory');\n // Harden an EMPTY private directory before any bundle byte exists. On\n // Windows, changing a file's DACL after writing is too late: another local\n // user can open the inherited-ACL temp file first and retain that handle.\n // Files created below this directory inherit the restrictive DACL, while\n // the final hard-link still remains on the operator-selected filesystem.\n const privateDir = path.join(dir, `.${path.basename(outputPath)}.${process.pid}.${randomUUID()}.private`);\n const tempPath = path.join(privateDir, 'bundle.tmp');\n try {\n await fs.mkdir(privateDir, { mode: 0o700 });\n await ensureSecureDir(privateDir, secureFileOptions);\n await atomicWriteFile(tempPath, `${JSON.stringify(bundle, null, 2)}\\n`, { mode: 0o600, fsync: true });\n await ensureSecureFile(tempPath, secureFileOptions);\n await fs.link(tempPath, outputPath);\n const published = await fs.open(outputPath, 'r+');\n try {\n await published.sync();\n } finally {\n await published.close();\n }\n if (process.platform !== 'win32') {\n const parent = await fs.open(dir, 'r');\n try {\n await parent.sync();\n } finally {\n await parent.close();\n }\n }\n } finally {\n await fs.rm(privateDir, { recursive: true, force: true }).catch(() => undefined);\n }\n}\n","import path from 'node:path';\nimport type { DaemonConfig } from '../../index';\nimport { createSupportBundle, writeSupportBundle } from '../../diagnostics/support-bundle';\nimport type { CollectDiagnosticsOptions } from '../../diagnostics/diagnostics';\nimport { resolveStoreDir } from '../config';\n\nexport interface SupportBundleOptions extends CollectDiagnosticsOptions {\n outputPath: string;\n log?: (line: string) => void;\n}\n\nexport async function runSupportBundleCommand(config: DaemonConfig, options: SupportBundleOptions): Promise<void> {\n if (!options.outputPath) throw new Error('support-bundle requires --output <path>');\n const outputPath = path.resolve(options.outputPath);\n const bundle = await createSupportBundle(config, resolveStoreDir(config), options);\n await writeSupportBundle(outputPath, bundle);\n const log = options.log ?? ((line: string) => console.log(line));\n log(`support bundle written: ${outputPath}`);\n log(`redaction policy: ${bundle.redaction.policy}; omitted=${bundle.redaction.omitted.length}; transformed=${bundle.redaction.transformed.length}`);\n}\n","import { type DaemonConfig, type DaemonEvent } from '../../index';\nimport { auditLogPath, followAuditLog, readAuditEvents } from '../audit-log';\nimport { connectControlClient } from '../control-client';\nimport { resolveStoreDir } from '../config';\nimport { formatDaemonEventLine, formatTaskListLines } from '../format';\nimport { deriveTasksFromEvents } from '../tasks-view';\n\nexport interface TasksListDeps {\n log?: (line: string) => void;\n}\n\n/** `byok-agent tasks` (no `--follow`): current known tasks, reconstructed from the audit log — see `byok-agent.ts`'s header comment. */\nexport async function runTasksListCommand(config: DaemonConfig, deps: TasksListDeps = {}): Promise<void> {\n const log = deps.log ?? ((line: string) => console.log(line));\n const storeDir = resolveStoreDir(config);\n const events = await readAuditEvents(storeDir);\n const tasks = deriveTasksFromEvents(events);\n for (const line of formatTaskListLines(tasks)) log(line);\n}\n\nexport interface TasksFollowDeps {\n log?: (line: string) => void;\n /** Required — see `commands/start.ts`'s identical `StartDeps.signal` doc comment for why there's no sane default. */\n signal: AbortSignal;\n pollIntervalMs?: number;\n /** DI for tests: substitute the real control-socket connection attempt. */\n connectControl?: typeof connectControlClient;\n}\n\n/**\n * `byok-agent tasks --follow`: M4 Phase 2 — prefers a LIVE stream over the\n * control socket's `tasks.subscribe` method (see `control-client.ts`),\n * which taps the exact same `DaemonObserver` events `start`'s own stdout\n * already shows, full fidelity, as they happen. Falls back to tailing the\n * SAME `audit.jsonl` a running `start` appends to (like `tail -f`, not a\n * full replay — run plain `byok-agent tasks` first for history) whenever\n * the control socket isn't reachable (daemon not running, or an older\n * daemon build with no control socket at all) — see `byok-agent.ts`'s\n * header comment for the historical rationale this fallback preserves.\n */\nexport async function runTasksFollowCommand(config: DaemonConfig, deps: TasksFollowDeps): Promise<void> {\n const log = deps.log ?? ((line: string) => console.log(line));\n const storeDir = resolveStoreDir(config);\n const connectControl = deps.connectControl ?? connectControlClient;\n\n const conn = await connectControl({ storeDir, productId: config.productId });\n if (conn.ok) {\n await new Promise<void>((resolve) => {\n const subscription = conn.client.subscribe('tasks.subscribe', {}, (event) => {\n log(formatDaemonEventLine(event as DaemonEvent));\n });\n const onAbort = (): void => {\n subscription.close();\n conn.client.close();\n resolve();\n };\n if (deps.signal.aborted) onAbort();\n else deps.signal.addEventListener('abort', onAbort, { once: true });\n });\n return;\n }\n\n const path = auditLogPath(storeDir);\n await followAuditLog(path, (event: DaemonEvent) => log(formatDaemonEventLine(event)), {\n signal: deps.signal,\n pollIntervalMs: deps.pollIntervalMs,\n fromEnd: true,\n });\n}\n","import { createInterface } from 'node:readline/promises';\nimport type { Daemon, ServiceLifecycle } from '../../index';\nimport { connectControlClient, isControlDaemonGone } from '../control-client';\n\n/** Thrown when `unpair` didn't get a `--yes`/confirmed and either declined interactively or has no TTY to prompt on. Caught by `byok-agent.ts`'s top-level handler like any other error (clean message, exit 1) — never left to hang. */\nexport class UnpairNotConfirmedError extends Error {\n constructor() {\n super('unpair cancelled: not confirmed (pass --yes to skip the prompt — required for a headless/background invocation, since there is no TTY to ask on)');\n this.name = 'UnpairNotConfirmedError';\n }\n}\n\n/**\n * Finding P1 #2: thrown instead of clearing the store when the OS\n * background service (`byok-agent install`) is currently installed AND\n * running — see this file's own module doc comment for the full \"why\".\n * Unconditional: unlike {@link UnpairUnknownDaemonStateError}, `--force`\n * never bypasses this one — it exists for a KNOWN-unsafe state, not an\n * uncertain one.\n */\nexport class UnpairBlockedByRunningServiceError extends Error {\n constructor(detail: string) {\n super(\n `unpair refused: the background service is currently running (${detail || 'installed and running'}) — stop it first (byok-agent service-stop), then retry unpair`,\n );\n this.name = 'UnpairBlockedByRunningServiceError';\n }\n}\n\n/**\n * Finding P1 #2 (residual, now fixed across two rounds): thrown instead of\n * clearing the store when unpair could NOT positively confirm that no\n * background service/daemon is running. Three shapes all collapse to\n * \"unknown\", unsafe BY DEFAULT — exactly like a confirmed-running service —\n * unless the caller opts in via `--force`:\n *\n * - Round 1: a `deps.lifecycle` that could not even be constructed\n * (unsupported platform, win32 without `--winsw-bin`, or no config to\n * build one from at all).\n * - Round 1: a `status()` call that itself rejected (the query to the\n * platform's service manager failed outright).\n * - Round 3: a `status()` call that RESOLVED but reported\n * `determinate: false` — the manager query itself could not be answered\n * (no reachable systemd `--user` D-Bus session, no launchd GUI domain for\n * this uid, permission denied), so `running: false` in that response is a\n * fallback, not a confirmed fact; see `lifecycle/service-types.ts`'s\n * `ServiceStatusResult.determinate`. Every one of `systemd.ts`/\n * `launchd.ts`/`winsw.ts` used to collapse exactly this case into a plain\n * `running: false`, which this file's `checkServiceState` then trusted at\n * face value — reopening the identical fail-open gap round 1 fixed for\n * the other two shapes.\n *\n * Bypassable by `--force`, deliberately unlike\n * {@link UnpairBlockedByRunningServiceError}: this error means \"can't\n * tell\", not \"confirmed unsafe\".\n */\nexport class UnpairUnknownDaemonStateError extends Error {\n constructor(reason: string) {\n super(\n `unpair refused: could not confirm whether a background service is running (${reason}) — proceeding blind risks a running daemon silently re-writing the credential. Stop any \\`byok-agent\\` process/service yourself and retry, or pass --force to proceed anyway once you are sure none is running.`,\n );\n this.name = 'UnpairUnknownDaemonStateError';\n }\n}\n\n/**\n * Finding F6 (cross-model adversarial review): thrown instead of clearing\n * the store on the LIVE (control-socket) unpair path when the daemon's\n * actual exit could NOT be confirmed — the shutdown RPC request itself\n * failed/never got through, teardown hung past `waitForControlExit`'s\n * deadline, or the exit-poll otherwise never observed `isControlDaemonGone`\n * before timing out. All three collapse to the same observable signal\n * (`exited === false`): a daemon that never actually received/finished the\n * shutdown is presumably STILL RUNNING, with its `AuthManager`'s proactive\n * renewal timer ready to write a fresh `device.json` right back over\n * whatever `unpair()` is about to clear — clearing anyway (the pre-fix\n * behavior) meant the log line had to openly admit \"did not confirm exit...\n * local device identity has still been cleared\" as if that were routine,\n * when it is exactly the silently-self-reverting hazard finding P1 #2\n * originally set out to close. Bypassable via `--force`, same shape as\n * {@link UnpairUnknownDaemonStateError} — this means \"can't confirm it\n * actually stopped\", an explicit, logged-as-unsafe override, never a\n * silent default.\n */\nexport class UnpairExitUnconfirmedError extends Error {\n constructor() {\n super(\n 'unpair refused: the daemon was told to shut down over the control socket but did not confirm exit before the timeout — it may still be running, and its next proactive token renewal could silently re-write device.json, undoing this unpair. Verify no `byok-agent` process is still running against this store and retry, or pass --force to clear the local credential anyway (unsafe — see UnpairExitUnconfirmedError\\'s own doc comment).',\n );\n this.name = 'UnpairExitUnconfirmedError';\n }\n}\n\nexport interface UnpairDeps {\n log?: (line: string) => void;\n /** `--yes`: skip the confirmation prompt entirely. */\n confirmed?: boolean;\n /** Defaults to `process.stdin.isTTY` — overridable so a test never depends on the real test-runner's stdin. */\n isTTY?: boolean;\n input?: NodeJS.ReadableStream;\n output?: NodeJS.WritableStream;\n /**\n * Finding P1 #2: an already-constructed lifecycle for the OS background\n * service this product MIGHT be installed as — `byok-agent.ts`'s `unpair`\n * dispatch builds this the same way `bin/commands/service.ts` does\n * (`buildServiceDefinition` + `createServiceLifecycle`) and passes it\n * through. `undefined` means \"could not even check\" (unsupported\n * platform, or Windows without `--winsw-bin`) — this is NOT the same as\n * \"confirmed not running\": see {@link UnpairUnknownDaemonStateError} and\n * the module doc comment for what that residual gap means and why it's\n * refused by default (bypassable only via `--force`).\n */\n lifecycle?: Pick<ServiceLifecycle, 'status'>;\n /**\n * Finding P1 #2 (residual): explicit opt-in to proceed when the service\n * check could NOT positively confirm \"not running\" (lifecycle\n * unavailable, or its `status()` call itself failed) — see\n * {@link UnpairUnknownDaemonStateError}. Does NOT bypass a lifecycle that\n * actively confirmed the service IS running\n * ({@link UnpairBlockedByRunningServiceError} is unconditional either\n * way) — `--force` overrides uncertainty, never a known-unsafe result.\n *\n * Finding F6: this SAME flag also overrides the LIVE (control-socket)\n * path's own exit-confirmation gate — see\n * {@link UnpairExitUnconfirmedError}. One flag, two independent unsafe\n * overrides (whichever path this invocation actually took), each logged\n * as an explicit WARNING rather than silently accepted.\n */\n force?: boolean;\n /**\n * M4 Phase 2: `storeDir`/`productId` to attempt a LIVE control-socket\n * unpair before ever falling back to the service-state-based flow below\n * — see this file's own module doc comment. Omitting either (e.g. an\n * older test exercising only the fallback path) skips straight to that\n * flow, exactly as before this feature existed.\n */\n storeDir?: string;\n productId?: string;\n /** DI for tests: substitute the real control-socket connection attempt. */\n connectControl?: typeof connectControlClient;\n /** DI for tests: substitute the real \"has the daemon actually exited\" probe. */\n isControlDaemonGone?: typeof isControlDaemonGone;\n /** How long to wait for the daemon to actually exit after `shutdown` is sent, before giving up (the store is still cleared either way — see the live-path log message). Default 15000ms. */\n controlExitTimeoutMs?: number;\n /** Poll interval while waiting for exit. Default 300ms. */\n controlExitPollIntervalMs?: number;\n}\n\n/**\n * Finding P1 #2 (residual, now fixed across two rounds): the three outcomes\n * {@link runUnpairCommand} acts on. A `lifecycle` that's `undefined`, whose\n * `status()` call rejects, OR whose `status()` call resolves with\n * `determinate: false` (round 3 — see `lifecycle/service-types.ts`'s\n * `ServiceStatusResult.determinate`: the platform's own manager query\n * itself could not be answered) all collapse to `'unknown'` — deliberately\n * NOT reinterpreted as \"confirmed not running\" (that was the original\n * fail-open bug, and round 3's residual reopening of it via a `status()`\n * that resolves cleanly instead of rejecting). Only a `status()` call that\n * resolves with `determinate: true` is trusted at face value per\n * `ServiceStatusResult`'s own contract (\"queried fresh from the platform's\n * own service manager... never a locally-cached guess\" — see\n * `lifecycle/service-types.ts`).\n */\ntype ServiceCheckResult =\n | { outcome: 'confirmed-not-running' }\n | { outcome: 'confirmed-running'; detail: string }\n | { outcome: 'unknown'; reason: string };\n\nasync function checkServiceState(lifecycle: Pick<ServiceLifecycle, 'status'> | undefined): Promise<ServiceCheckResult> {\n if (!lifecycle) {\n return { outcome: 'unknown', reason: 'no background-service lifecycle could be constructed for this platform/config' };\n }\n try {\n const status = await lifecycle.status();\n if (status.running) {\n return { outcome: 'confirmed-running', detail: status.detail };\n }\n if (!status.determinate) {\n // Finding P1 #2 (residual, round 3): `status()` RESOLVED (didn't\n // throw) with `running: false`, but it was NOT a clean confirmation —\n // the manager query itself failed (unreachable/permission-denied).\n // Treat exactly like a thrown `status()` call: cannot confirm no\n // daemon is running.\n return {\n outcome: 'unknown',\n reason: `service status could not be confirmed — the service manager query was indeterminate rather than a clean \"not running\" result${status.detail ? `: ${status.detail}` : ''}`,\n };\n }\n return { outcome: 'confirmed-not-running' };\n } catch (err) {\n return { outcome: 'unknown', reason: `checking service status failed: ${err instanceof Error ? err.message : String(err)}` };\n }\n}\n\n/**\n * `unpair()` itself only needs a `Daemon` this process just constructed\n * (never started) — clearing the on-disk device record and rebuilding\n * `AuthManager` in-memory doesn't require attaching to a live `start`\n * process (see `create-daemon.ts`'s `unpair()` doc comment: \"safe to call at\n * any point in the lifecycle\"). This is the one mutating query-adjacent\n * command that genuinely works standalone, unlike `approve`/`reject` — see\n * `commands/approve-reject.ts`.\n *\n * Confirmation: `--yes` skips the prompt outright. Without it, an\n * interactive TTY gets a y/N prompt; a non-TTY invocation (background/CI)\n * throws {@link UnpairNotConfirmedError} immediately rather than hanging on\n * stdin input that will never arrive — this CLI must work headless (see\n * `byok-agent.ts`'s header comment).\n *\n * ## M4 Phase 2: the control socket makes live unpair actually possible\n *\n * When `deps.storeDir`/`deps.productId` are supplied (the real\n * `byok-agent.ts` dispatch always supplies them), this first tries the\n * control socket (`control-client.ts`). If a `byok-agent start` — foreground\n * OR installed as a service, no distinction needed anymore — is genuinely\n * reachable right now, that's a definitively confirmed \"yes, something is\n * running against this store\", strictly better than the OS-service-state\n * GUESS the rest of this doc comment describes: after confirming, this\n * sends `shutdown {reason:'unpair'}`, then waits for the daemon to actually\n * exit (polling `isControlDaemonGone` — both the control token file gone AND\n * a fresh connect refused).\n *\n * Finding F6 (cross-model adversarial review, fixed same session): that\n * exit confirmation is now load-bearing, not advisory — clearing the store\n * only proceeds when `exited` is true, OR the caller passed `--force`\n * (logged as an explicit WARNING either way). Before this fix, `daemon\n * .unpair()` ran UNCONDITIONALLY regardless of whether the daemon ever\n * actually confirmed exit — a shutdown RPC that failed outright, teardown\n * that hung, or an exit-poll that simply timed out all still cleared\n * `device.json` as if the daemon were confirmed gone, when it might still be\n * fully running with its `AuthManager`'s proactive renewal timer poised to\n * write a fresh credential right back — the exact silently-self-reverting\n * hazard finding P1 #2 (below) was originally about, reopened on this one\n * path. See {@link UnpairExitUnconfirmedError}. Only when the control socket\n * is NOT reachable AT ALL (daemon not running at all, or an older daemon\n * build predating this feature) does this fall through to the heuristic,\n * OS-service-state-based flow this whole doc comment otherwise describes —\n * untouched, including every refusal below.\n *\n * ## Finding P1 #2: unpair used to silently fail (and self-revert) against a running daemon\n *\n * Clearing `device.json` on disk does nothing to a SEPARATE, already-running\n * `byok-agent start` process (foreground OR installed as a background OS\n * service) — that process loaded its own `AuthManager` at `start()` time and\n * keeps the device's JWT + private key cached in memory regardless of what\n * happens to the file afterward. Worse: `AuthManager`'s proactive renewal\n * timer (`auth-manager.ts`) fires on its own schedule and unconditionally\n * writes its in-memory record BACK to `device.json` on every successful\n * renewal — so a standalone `unpair` against a live daemon didn't just fail\n * to stop it, it got silently UNDONE by that daemon's own next renewal,\n * while the daemon stayed authorized and connected the whole time. There is\n * no IPC control socket yet (planned for M4) to reach a separate process and\n * actually tell it to stop, so this fix cannot make unpair truly live —\n * only honest:\n *\n * - If an installed OS service can be QUERIED (`deps.lifecycle` was\n * successfully constructed AND its `status()` call resolves) and it\n * reports `running: true`, this throws\n * {@link UnpairBlockedByRunningServiceError} BEFORE even prompting for\n * confirmation, rather than proceeding and quietly losing the race.\n * Unconditional — `--force` does not bypass this; see below.\n * - Finding P1 #2 residual, round 1 (now fixed): every OTHER path used\n * to FAIL OPEN — no `deps.lifecycle` at all (unsupported platform, win32\n * without `--winsw-bin`, or no config to build one from), or a\n * `status()` call that itself errored, both silently fell through to\n * \"proceed as if safe\". That is now treated as \"cannot confirm no daemon\n * is running\", which is unsafe BY DEFAULT: it throws\n * {@link UnpairUnknownDaemonStateError} (before prompting, same position\n * as the confirmed-running case above) unless the caller passes\n * `--force`, which proceeds anyway and logs an explicit warning\n * alongside the usual success message instead of the usual NOTE.\n * - Finding P1 #2 residual, round 3 (now fixed): a `status()` call that\n * RESOLVED (didn't throw) with `running: false` was ALSO being trusted\n * at face value even when the platform's own query had actually failed\n * to reach the service manager at all — `systemd.ts`/`launchd.ts`/\n * `winsw.ts` used to collapse a bus-connect/permission-denied/\n * manager-unreachable query failure into a plain `running: false`,\n * textually and structurally indistinguishable from a clean \"confirmed\n * not running\" (the exact same re-open shape round 1 fixed for the\n * other two paths). `ServiceStatusResult` is now tri-state\n * (`determinate: boolean` — see `lifecycle/service-types.ts`), every\n * platform's `status()` sets it accurately, and `checkServiceState`\n * treats `determinate: false` exactly like a thrown `status()` call.\n * Only a `status()` call that resolves `running: false` AND\n * `determinate: true` is trusted at face value and proceeds without\n * needing `--force` — this fix does not make every unpair require\n * `--force`, only the genuinely-unconfirmable ones.\n * - A `start` running directly in the foreground (no OS service involved)\n * used to be undetectable at all from a separate short-lived CLI\n * invocation, even when the OS-service check above came back clean. The\n * M4 control-socket path above now closes exactly this gap — a reachable\n * control socket is a definitive \"yes, something is running\" regardless\n * of whether it's a foreground process or an installed service. This\n * heuristic OS-service-state flow (and its residual \"foreground daemon\n * is invisible\" gap) only still applies when the control socket itself\n * isn't reachable at all.\n */\n\n/**\n * Shared confirmation prompt for BOTH the live (control-socket) and\n * fallback (OS-service-state) unpair paths in {@link runUnpairCommand}\n * below: `--yes` (`deps.confirmed`) skips it outright; an interactive TTY\n * gets a y/N prompt; a non-TTY invocation (background/CI) throws\n * {@link UnpairNotConfirmedError} immediately rather than hanging on stdin\n * input that will never arrive.\n */\nasync function confirmUnpair(deps: Pick<UnpairDeps, 'confirmed' | 'isTTY' | 'input' | 'output'>, isTTY: boolean): Promise<void> {\n if (deps.confirmed) return;\n if (!isTTY) {\n throw new UnpairNotConfirmedError();\n }\n const rl = createInterface({ input: deps.input ?? process.stdin, output: deps.output ?? process.stdout });\n let answer: string;\n try {\n answer = await rl.question(\n 'This clears the locally paired device identity; the next `start` will require re-pairing. Continue? [y/N] ',\n );\n } finally {\n rl.close();\n }\n if (!/^y(es)?$/i.test(answer.trim())) {\n throw new UnpairNotConfirmedError();\n }\n}\n\n/** Cancellable-by-nothing plain delay — this poll loop is itself bounded by `timeoutMs`, so no separate abort signal is needed. */\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function waitForControlExit(\n storeDir: string,\n productId: string,\n checkGone: typeof isControlDaemonGone,\n timeoutMs: number,\n pollIntervalMs: number,\n): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n if (await checkGone(storeDir, productId)) return true;\n if (Date.now() >= deadline) return false;\n await delay(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));\n }\n}\n\nexport async function runUnpairCommand(daemon: Pick<Daemon, 'unpair'>, deps: UnpairDeps = {}): Promise<void> {\n const log = deps.log ?? ((line: string) => console.log(line));\n const isTTY = deps.isTTY ?? Boolean(process.stdin.isTTY);\n\n if (deps.storeDir !== undefined && deps.productId !== undefined) {\n const connectControl = deps.connectControl ?? connectControlClient;\n const conn = await connectControl({ storeDir: deps.storeDir, productId: deps.productId });\n if (conn.ok) {\n try {\n // Declining (or a non-TTY throw) must not leak this connection —\n // the `finally` below closes it regardless of which way this\n // settles, including the confirmation-declined path, which used to\n // fall straight through to the thrown error without ever reaching\n // `conn.client.close()`.\n await confirmUnpair(deps, isTTY);\n // Best-effort: the daemon has already responded `ok` by the time\n // `request()` resolves (or the connection simply drops as it tears\n // itself down) — either way, the poll below is the real\n // confirmation, not this call's own success/failure.\n await conn.client.request('shutdown', { reason: 'unpair' }).catch(() => {});\n } finally {\n conn.client.close();\n }\n\n const checkGone = deps.isControlDaemonGone ?? isControlDaemonGone;\n const exited = await waitForControlExit(\n deps.storeDir,\n deps.productId,\n checkGone,\n deps.controlExitTimeoutMs ?? 15_000,\n deps.controlExitPollIntervalMs ?? 300,\n );\n\n // Finding F6: fail closed on an unconfirmed exit — see\n // UnpairExitUnconfirmedError's own doc comment. Covers all three named\n // failure shapes (the shutdown RPC itself failing, teardown hanging,\n // or the exit-poll simply timing out): every one of them means\n // `exited` is false here, so this one gate gets all three.\n if (!exited && !deps.force) {\n throw new UnpairExitUnconfirmedError();\n }\n\n await daemon.unpair();\n if (exited) {\n log(\n 'unpaired: the running daemon was told to shut down over the control socket, confirmed exited, and the local device identity has been cleared.',\n );\n } else {\n log(\n 'unpaired: local device identity cleared. WARNING: --force was used to proceed even though the daemon did NOT confirm exit within the timeout after being told to shut down over the control socket — if it is still running, its next proactive token renewal will re-write device.json and silently undo this unpair. Verify no byok-agent process is still running against this store.',\n );\n }\n return;\n }\n }\n\n const serviceState = await checkServiceState(deps.lifecycle);\n if (serviceState.outcome === 'confirmed-running') {\n throw new UnpairBlockedByRunningServiceError(serviceState.detail);\n }\n if (serviceState.outcome === 'unknown' && !deps.force) {\n throw new UnpairUnknownDaemonStateError(serviceState.reason);\n }\n\n await confirmUnpair(deps, isTTY);\n\n await daemon.unpair();\n if (serviceState.outcome === 'unknown') {\n log(\n `unpaired: local device identity cleared. WARNING: --force was used to proceed WITHOUT confirming no background service/daemon is running (${serviceState.reason}) — if one IS running against this same store, its next proactive token renewal will re-write device.json and silently undo this unpair. Stop it yourself, then re-run unpair to verify. (Live unpair over the control socket, above, is used automatically whenever it's reachable.)`,\n );\n } else {\n log(\n 'unpaired: local device identity cleared. NOTE: this cannot detect or stop a `byok-agent start` running directly in the foreground with no reachable control socket (an older daemon build, or one that failed to bind it) — if one is running against this same store, its next proactive token renewal will re-write device.json and silently undo this unpair; stop that process yourself first. (An installed background SERVICE is checked automatically; a reachable control socket is used automatically and is the fully-safe path — see above.)',\n );\n }\n}\n","import type { DaemonConfig } from '../../index';\nimport { GitWorkspaceStore, type GitWorkspaceLedgerRecord } from '../../daemon/git-workspace-store';\nimport { resolveStoreDir } from '../config';\n\nconst STABLE_ERROR_CATEGORIES = new Set([\n 'git-unavailable',\n 'git-timeout',\n 'git-output-limit',\n 'git-command-failed',\n 'workspace-root-invalid',\n 'workspace-root-conflict',\n 'workspace-not-owned',\n 'repository-root-mismatch',\n 'repository-invalid',\n 'lease-busy',\n 'ledger-invalid',\n]);\n\nexport interface WorkspacesCommandDeps {\n log?: (line: string) => void;\n store?: Pick<GitWorkspaceStore, 'list'>;\n showPaths?: boolean;\n}\n\nfunction abbreviateCommit(value: string | undefined): string {\n if (!value) return '-';\n return value.length > 8 ? value.slice(0, 8) : value;\n}\n\nfunction formatWorkspaceLine(record: GitWorkspaceLedgerRecord, showPaths: boolean): string {\n const parts = [\n `taskId=${record.taskId}`,\n `workspaceId=${record.workspaceId}`,\n `phase=${record.phase}`,\n `baseline=${abbreviateCommit(record.baseline)}`,\n `current=${abbreviateCommit(record.current)}`,\n `commits=${record.commitsSinceBaseline}`,\n `dirty=${record.staged}/${record.unstaged}/${record.untracked}/${record.conflicted}`,\n `updatedAt=${record.updatedAt}`,\n ];\n if (record.errorCategory && STABLE_ERROR_CATEGORIES.has(record.errorCategory)) parts.push(`error=${record.errorCategory}`);\n if (showPaths) parts.push(`path=${record.workspaceDir}`);\n return parts.join(' ');\n}\n\n/**\n * Lists the private Git workspace ledger without probing or changing any\n * workspace. The ledger store already defines missing, corrupt, and future\n * version behavior; this command deliberately preserves those outcomes.\n */\nexport async function runWorkspacesCommand(config: DaemonConfig, deps: WorkspacesCommandDeps = {}): Promise<void> {\n const log = deps.log ?? ((line: string) => console.log(line));\n const store = deps.store ?? new GitWorkspaceStore(resolveStoreDir(config));\n const records = await store.list();\n if (records.length === 0) {\n log('(no workspaces recorded)');\n return;\n }\n for (const record of records) log(formatWorkspaceLine(record, deps.showPaths === true));\n}\n\nexport { abbreviateCommit, formatWorkspaceLine };\n","#!/usr/bin/env node\nimport { createDaemon, createServiceLifecycle, DeviceRevokedError, type ServiceLifecycle } from '../index';\nimport { argValue, hasFlag, loadConfig, positionalArgs, resolveStoreDir } from './config';\nimport { runApprovalsCommand } from './commands/approvals';\nimport { runApproveCommand, runRejectCommand } from './commands/approve-reject';\nimport { runPairCommand } from './commands/pair';\nimport { runDoctorCommand } from './commands/doctor';\nimport { runRuntimesCommand } from './commands/runtimes';\nimport {\n buildServiceDefinition,\n runInstallCommand,\n runServiceStartCommand,\n runServiceStatusCommand,\n runServiceStopCommand,\n runUninstallCommand,\n} from './commands/service';\nimport { runStartCommand } from './commands/start';\nimport { runStatusCommand } from './commands/status';\nimport { runSupportBundleCommand } from './commands/support-bundle';\nimport { runTasksFollowCommand, runTasksListCommand } from './commands/tasks';\nimport { runUnpairCommand } from './commands/unpair';\nimport { runWorkspacesCommand } from './commands/workspaces';\n\n/**\n * `byok-agent`: a PLAIN structured CLI (subcommands + line-oriented stdout +\n * a tail-able JSONL log) — deliberately NOT a TUI. No ink/blessed/React\n * reconciler, no full-screen TTY control codes. Every subcommand must work\n * headless (piped stdout, no TTY, running as a background service) and\n * cross-platform; see `bin/format.ts` for the plain-text-only rendering\n * this relies on.\n *\n * ## The read model — persisted state, a live probe, and (M4 Phase 2) a live control socket\n *\n * `start` is a long-lived foreground process (or an installed background\n * service running the same command). `status`/`runtimes`/`tasks`/\n * `tasks --follow`/`unpair`/`approve`/`reject` are all separate, short-lived\n * invocations. As of M4 Phase 2 there IS a local IPC channel between them —\n * a Unix domain socket / Windows named pipe (`daemon/control-server.ts`,\n * `bin/control-client.ts`), mutually authenticated by an HMAC handshake over\n * a token that never crosses the wire — but it's only reachable while a\n * `start` (foreground or service) is actually running, so every\n * short-lived command still has an honest, historical/persisted-state\n * fallback for when it isn't:\n *\n * - `status`/`tasks` (no `--follow`) read PERSISTED STATE first, always:\n * `<storeDir>/device.json` (via `DeviceStore`, for paired/deviceId — a\n * freshly-constructed `Daemon` that never called `start()`/`pair()` in\n * THIS process would otherwise always report `paired: false`, which would\n * be actively wrong for an already-paired device) and\n * `<storeDir>/audit.jsonl` (the audit log `start` appends every\n * `DaemonEvent` to — see `bin/audit-log.ts` — replayed into a task list /\n * last-known-connection-state via `bin/tasks-view.ts`). `status`\n * additionally tries the control socket afterward: if reachable, a\n * clearly-marked `live-*` section (pid/uptime/transport/active tasks) is\n * appended; if not, one line says so and the persisted view above stands\n * on its own, never faked as \"live\".\n * - `runtimes` (and the compact runtime summary inside `status`) is a FRESH\n * STANDALONE PROBE instead: it constructs the same bundled pi/claude/codex\n * adapter set `createDaemon` would (see `bin/runtime-probe.ts`) and calls\n * `detect()`/`capabilities()` directly, independent of whether any daemon\n * is running. \"What's on this machine right now\" is more useful live than\n * stale, and detection is cheap/side-effect-free, so there's no reason to\n * read a historical snapshot here instead. The control socket deliberately\n * never duplicates this probe (see `control-protocol.ts`'s `status`\n * method doc comment) — this CLI keeps owning it.\n * - `tasks --follow` prefers subscribing to the control socket's\n * `tasks.subscribe` (a genuinely live feed, full fidelity, the same\n * events `start`'s own stdout shows); falls back to tailing\n * `audit.jsonl` from its CURRENT end forward (like `tail -f`) when the\n * socket isn't reachable — see `bin/audit-log.ts`'s `followAuditLog`. Run\n * plain `tasks` first for history either way.\n * - `unpair` tries the control socket first: if reachable, that's a\n * DEFINITIVE \"yes, a daemon is running against this store\" (foreground or\n * service, no distinction needed anymore) — it sends `shutdown\n * {reason:'unpair'}` and waits for the daemon to actually exit. Finding F6:\n * `device.json` is only cleared once that exit is CONFIRMED (or `--force`\n * is passed, logged as an explicit WARNING) — an unconfirmed exit (the RPC\n * failing, teardown hanging, or the exit-poll timing out) refuses instead,\n * since the daemon may still be running and could silently re-write the\n * credential (see `commands/unpair.ts`'s `UnpairExitUnconfirmedError`).\n * Only when the socket isn't reachable does it fall back to\n * the heuristic, OS-service-state-based flow this command has had since\n * finding P1 #2: refusing outright when an installed background service\n * is confirmed running, or when it cannot even confirm one ISN'T running\n * (bypassable with `--force`) — see `commands/unpair.ts`'s own doc\n * comment for the full history and residual gap that heuristic flow\n * still has (a foreground process is invisible to it, which is exactly\n * what the control-socket path above now fixes).\n * - `approve`/`reject` call the control socket's `approvals.resolve`\n * directly — there's no persisted-state fallback for these (approving a\n * task only ever means anything against a LIVE daemon); daemon\n * unreachable is reported as a clear, specific error. Still honest about\n * what these can resolve today: no bundled runtime adapter raises an\n * approval yet, so a real daemon always answers `not_found` — see\n * `commands/approve-reject.ts`'s own doc comment.\n * - `approvals` (finding F4: operators otherwise had no way to ever learn\n * an `approvalId` to pass to `approve`/`reject`) calls the control\n * socket's `approvals.list` and renders one line per pending approval\n * (approvalId/taskId/age/summary excerpt) — same no-fallback rule as\n * `approve`/`reject` above. See `commands/approvals.ts`'s own doc\n * comment.\n *\n * `pair`/`start` are the only two commands that mutate/run a live daemon in\n * THIS process, unchanged in spirit from the pre-M3-2b bin.\n */\n\nfunction usage(): never {\n console.error(\n [\n 'Usage:',\n ' byok-agent pair <code> --server <url> [--config <path>]',\n ' byok-agent start [--config <path>] (or BYOK_CONFIG env var)',\n ' byok-agent status [--config <path>]',\n ' byok-agent doctor [--json] [--fix --yes] [--config <path>]',\n ' byok-agent support-bundle --output <path> [--config <path>]',\n ' byok-agent runtimes [--config <path>]',\n ' byok-agent tasks [--follow] [--config <path>]',\n ' byok-agent workspaces [--show-paths] [--config <path>]',\n ' byok-agent unpair [--yes] [--force] [--config <path>]',\n ' byok-agent approvals [--config <path>] (list pending approvalIds — see approve/reject below)',\n ' byok-agent approve <approvalId> [--config <path>]',\n ' byok-agent reject <approvalId> [--reason <text>] [--config <path>]',\n '',\n ' Background OS service (launchd/systemd/WinSW) — see templates/service/**:',\n ' byok-agent install [--config <path>] [--name <svc>] [--agent-bin <path>] [--node-bin <path>] [--winsw-bin <path>] [--winsw-install-dir <path>]',\n ' byok-agent uninstall [--config <path>] [--name <svc>]',\n ' byok-agent service-start [--config <path>] [--name <svc>]',\n ' byok-agent service-stop [--config <path>] [--name <svc>]',\n ' byok-agent service-status [--config <path>] [--name <svc>]',\n ].join('\\n'),\n );\n process.exit(1);\n}\n\nfunction configPathFrom(args: string[]): string | undefined {\n return argValue(args, '--config') ?? process.env.BYOK_CONFIG;\n}\n\n/** Wires an `AbortController` to SIGINT/SIGTERM for a long-running subcommand (`start`, `tasks --follow`). */\nfunction abortOnSignal(): AbortController {\n const controller = new AbortController();\n const abort = (): void => controller.abort();\n process.on('SIGINT', abort);\n process.on('SIGTERM', abort);\n return controller;\n}\n\nasync function main(): Promise<void> {\n const [, , command, ...rest] = process.argv;\n\n if (command === 'pair') {\n const [code] = positionalArgs(rest, ['--server', '--config']);\n const server = argValue(rest, '--server');\n if (!code || !server) usage();\n const config = loadConfig(argValue(rest, '--config'), { serverUrl: server });\n return runPairCommand(config, code);\n }\n\n if (command === 'start') {\n const configPath = configPathFrom(rest);\n if (!configPath) {\n console.error('start requires --config <path> or a BYOK_CONFIG env var');\n process.exit(1);\n }\n const config = loadConfig(configPath);\n const controller = abortOnSignal();\n return runStartCommand(config, { signal: controller.signal });\n }\n\n if (command === 'status') {\n const config = loadConfig(configPathFrom(rest));\n return runStatusCommand(config);\n }\n\n if (command === 'doctor') {\n const config = loadConfig(configPathFrom(rest));\n return runDoctorCommand(config, {\n json: hasFlag(rest, '--json'),\n fix: hasFlag(rest, '--fix'),\n confirmed: hasFlag(rest, '--yes'),\n });\n }\n\n if (command === 'support-bundle') {\n const outputPath = argValue(rest, '--output');\n if (!outputPath) usage();\n const config = loadConfig(configPathFrom(rest));\n return runSupportBundleCommand(config, { outputPath });\n }\n\n if (command === 'runtimes') {\n const config = loadConfig(configPathFrom(rest));\n return runRuntimesCommand(config);\n }\n\n if (command === 'tasks') {\n const config = loadConfig(configPathFrom(rest));\n if (hasFlag(rest, '--follow')) {\n const controller = abortOnSignal();\n return runTasksFollowCommand(config, { signal: controller.signal });\n }\n return runTasksListCommand(config);\n }\n\n if (command === 'workspaces') {\n const config = loadConfig(configPathFrom(rest));\n return runWorkspacesCommand(config, { showPaths: hasFlag(rest, '--show-paths') });\n }\n\n if (command === 'unpair') {\n const configPath = configPathFrom(rest);\n const config = loadConfig(configPath);\n const daemon = createDaemon(config);\n // Finding P1 #2: best-effort — reuses the exact same\n // ServiceDefinition/lifecycle `service.ts`'s own commands build, so\n // \"is a service installed/running\" is answered from the SAME identity\n // `install`/`service-status` would use, not a second guess. Construction\n // itself throws on an unsupported platform, or on win32 without\n // `--winsw-bin` (see `lifecycle/winsw.ts`) — in either case there is no\n // way to query a service's state at all, so `lifecycle` stays\n // `undefined` and `runUnpairCommand` treats that the same as any other\n // \"cannot confirm no daemon is running\" state (finding P1 #2 residual):\n // refused by default, bypassable with `--force`.\n let lifecycle: ServiceLifecycle | undefined;\n if (configPath) {\n try {\n lifecycle = createServiceLifecycle(buildServiceDefinition(config, configPath, rest));\n } catch {\n lifecycle = undefined;\n }\n }\n return runUnpairCommand(daemon, {\n confirmed: hasFlag(rest, '--yes'),\n lifecycle,\n force: hasFlag(rest, '--force'),\n storeDir: resolveStoreDir(config),\n productId: config.productId,\n });\n }\n\n if (command === 'approvals') {\n const config = loadConfig(configPathFrom(rest));\n const storeDir = resolveStoreDir(config);\n return runApprovalsCommand(storeDir, config.productId);\n }\n\n if (command === 'approve' || command === 'reject') {\n const [approvalId] = positionalArgs(rest, ['--reason', '--config']);\n if (!approvalId) usage();\n const config = loadConfig(configPathFrom(rest));\n const storeDir = resolveStoreDir(config);\n if (command === 'approve') return runApproveCommand(storeDir, config.productId, approvalId);\n return runRejectCommand(storeDir, config.productId, approvalId, argValue(rest, '--reason'));\n }\n\n if (\n command === 'install' ||\n command === 'uninstall' ||\n command === 'service-start' ||\n command === 'service-stop' ||\n command === 'service-status'\n ) {\n const configPath = configPathFrom(rest);\n if (!configPath) {\n console.error(`${command} requires --config <path> or a BYOK_CONFIG env var`);\n process.exit(1);\n }\n const config = loadConfig(configPath);\n if (command === 'install') return runInstallCommand(config, configPath, rest);\n if (command === 'uninstall') return runUninstallCommand(config, configPath, rest);\n if (command === 'service-start') return runServiceStartCommand(config, configPath, rest);\n if (command === 'service-stop') return runServiceStopCommand(config, configPath, rest);\n return runServiceStatusCommand(config, configPath, rest);\n }\n\n usage();\n}\n\nmain().catch((err: unknown) => {\n if (err instanceof DeviceRevokedError) {\n // A cold `daemon.start()` against an already-revoked device fails fast\n // with this typed error (see ConnectionManager.waitForAck) instead of\n // hanging for the ack timeout — give the operator a clear, actionable\n // message instead of a generic one.\n console.error('device revoked — re-pair needed (run: byok-agent pair <code> --server <url>)');\n process.exit(1);\n }\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n});\n"]}