@letrquan/book 0.3.0 → 0.4.0-beta.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 (148) hide show
  1. package/CHANGELOG.md +1024 -0
  2. package/README.md +6 -3
  3. package/dist/{additional-roots-H7UNAEHS.js → additional-roots-VAWRQ625.js} +8 -7
  4. package/dist/{app-GE4OHJOC.js → app-J7BVPSUH.js} +5397 -2953
  5. package/dist/app-J7BVPSUH.js.map +1 -0
  6. package/dist/chunk-32WBCUAN.js +660 -0
  7. package/dist/chunk-32WBCUAN.js.map +1 -0
  8. package/dist/{chunk-525CAZPY.js → chunk-4DKHLZRI.js} +6 -6
  9. package/dist/{chunk-4AS7LKKQ.js → chunk-62EEAUID.js} +2 -2
  10. package/dist/{chunk-AQEQX4FF.js → chunk-AHC7OU75.js} +385 -55
  11. package/dist/chunk-AHC7OU75.js.map +1 -0
  12. package/dist/{chunk-EFJ2NH6E.js → chunk-AJZWLKLQ.js} +63 -14
  13. package/dist/chunk-AJZWLKLQ.js.map +1 -0
  14. package/dist/chunk-B5FC3MYZ.js +395 -0
  15. package/dist/chunk-B5FC3MYZ.js.map +1 -0
  16. package/dist/{chunk-67UZEWWF.js → chunk-DNFQTSMJ.js} +53 -11
  17. package/dist/chunk-DNFQTSMJ.js.map +1 -0
  18. package/dist/{chunk-TLX3H2CL.js → chunk-E5WLQSKA.js} +231 -40
  19. package/dist/chunk-E5WLQSKA.js.map +1 -0
  20. package/dist/chunk-ECLC4CIJ.js +1181 -0
  21. package/dist/chunk-ECLC4CIJ.js.map +1 -0
  22. package/dist/chunk-EEX6QNXV.js +127 -0
  23. package/dist/chunk-EEX6QNXV.js.map +1 -0
  24. package/dist/chunk-EFXVSQ5J.js +931 -0
  25. package/dist/chunk-EFXVSQ5J.js.map +1 -0
  26. package/dist/{chunk-RFJ6Q6LE.js → chunk-ENLB7NYV.js} +577 -164
  27. package/dist/chunk-ENLB7NYV.js.map +1 -0
  28. package/dist/{chunk-IME7R2UI.js → chunk-FPR7SKIE.js} +1268 -883
  29. package/dist/chunk-FPR7SKIE.js.map +1 -0
  30. package/dist/{chunk-VPNLCMVR.js → chunk-HFB74CLM.js} +13 -5
  31. package/dist/chunk-HFB74CLM.js.map +1 -0
  32. package/dist/{chunk-5RDRAO4B.js → chunk-HOZXKOE3.js} +37 -1
  33. package/dist/chunk-HOZXKOE3.js.map +1 -0
  34. package/dist/chunk-IDYWN37T.js +36 -0
  35. package/dist/chunk-IDYWN37T.js.map +1 -0
  36. package/dist/{chunk-YC6W4EJH.js → chunk-JGF5HLSI.js} +193 -75
  37. package/dist/chunk-JGF5HLSI.js.map +1 -0
  38. package/dist/{chunk-5YHTKWJN.js → chunk-KDNWMKXV.js} +2447 -907
  39. package/dist/chunk-KDNWMKXV.js.map +1 -0
  40. package/dist/{chunk-Y2VHN7TC.js → chunk-MEOB2DZA.js} +11 -1
  41. package/dist/chunk-MEOB2DZA.js.map +1 -0
  42. package/dist/{chunk-KBQS35OV.js → chunk-MV5PQNIA.js} +2 -2
  43. package/dist/chunk-N2G4Q7ME.js +2672 -0
  44. package/dist/chunk-N2G4Q7ME.js.map +1 -0
  45. package/dist/{chunk-62QL5QUP.js → chunk-OJBMDM5H.js} +17 -1
  46. package/dist/chunk-OJBMDM5H.js.map +1 -0
  47. package/dist/{chunk-56SIEMDX.js → chunk-PTDC7ZUP.js} +2 -2
  48. package/dist/{chunk-X4NJT436.js → chunk-REASC2QG.js} +67 -28
  49. package/dist/chunk-REASC2QG.js.map +1 -0
  50. package/dist/chunk-SBTU5BEC.js +114 -0
  51. package/dist/chunk-SBTU5BEC.js.map +1 -0
  52. package/dist/{chunk-HQI7NYGX.js → chunk-SWPDKLNM.js} +2 -2
  53. package/dist/{chunk-W3XFHEF4.js → chunk-UCFJ43OS.js} +140 -28
  54. package/dist/chunk-UCFJ43OS.js.map +1 -0
  55. package/dist/{chunk-QYBD22H5.js → chunk-W7SLYS3M.js} +80 -16
  56. package/dist/chunk-W7SLYS3M.js.map +1 -0
  57. package/dist/{chunk-SOW4WRQP.js → chunk-WV3O5PGX.js} +3 -3
  58. package/dist/{chunk-JTPOI3KU.js → chunk-XJRJVXJR.js} +262 -38
  59. package/dist/chunk-XJRJVXJR.js.map +1 -0
  60. package/dist/{chunk-224FJZLH.js → chunk-YIL6HTJX.js} +228 -5
  61. package/dist/chunk-YIL6HTJX.js.map +1 -0
  62. package/dist/{command-approvals-VBIU6BLM.js → command-approvals-ZRY66LCW.js} +5 -4
  63. package/dist/context-C3RAP6K5.js +41 -0
  64. package/dist/{hook-approvals-ZVT4V7IM.js → hook-approvals-DPQD5H65.js} +5 -4
  65. package/dist/index.js +657 -754
  66. package/dist/index.js.map +1 -1
  67. package/dist/{interactive-assets-T4I4SEHU.js → interactive-assets-73AQO5WP.js} +11 -6
  68. package/dist/{interactive-assets-T4I4SEHU.js.map → interactive-assets-73AQO5WP.js.map} +1 -1
  69. package/dist/job-runner.js +10 -3
  70. package/dist/job-runner.js.map +1 -1
  71. package/dist/job-supervisor.js +13 -4
  72. package/dist/job-supervisor.js.map +1 -1
  73. package/dist/loader-DQNPDKOX.js +27 -0
  74. package/dist/{mcp-approvals-HJ2VDYMC.js → mcp-approvals-27LJYADQ.js} +5 -4
  75. package/dist/{mcp-config-RNB5LEVE.js → mcp-config-GXSODNCM.js} +3 -2
  76. package/dist/memory-store-I6Z54VUN.js +51 -0
  77. package/dist/{model-window-store-MTSQ5JDJ.js → model-window-store-6VKXXTPJ.js} +4 -3
  78. package/dist/{openai-compatible-2OB54YST.js → openai-compatible-IPUNBJ53.js} +5 -3
  79. package/dist/{permission-approvals-YLV6UC5W.js → permission-approvals-Q5IMFEZI.js} +5 -4
  80. package/dist/{permissions-DHOKF3W2.js → permissions-7Y35X6HZ.js} +26 -9
  81. package/dist/provider-approvals-5AGH3RVT.js +76 -0
  82. package/dist/{sandbox-WRYTZH3D.js → sandbox-N2RY72GN.js} +6 -5
  83. package/dist/{scrollback-35ME2GFX.js → scrollback-GD76GNM4.js} +36 -28
  84. package/dist/scrollback-GD76GNM4.js.map +1 -0
  85. package/dist/sdk.d.ts +876 -64
  86. package/dist/sdk.js +57 -37
  87. package/dist/sdk.js.map +1 -1
  88. package/dist/settings-loader-KDBH45AQ.js +43 -0
  89. package/dist/{settings-removed-JWWPT4WA.js → settings-removed-3ATWJEF3.js} +2 -2
  90. package/dist/shell-selection-Z5WORZU4.js +31 -0
  91. package/dist/shell-selection-Z5WORZU4.js.map +1 -0
  92. package/package.json +5 -5
  93. package/dist/app-GE4OHJOC.js.map +0 -1
  94. package/dist/chunk-224FJZLH.js.map +0 -1
  95. package/dist/chunk-5RDRAO4B.js.map +0 -1
  96. package/dist/chunk-5YHTKWJN.js.map +0 -1
  97. package/dist/chunk-62QL5QUP.js.map +0 -1
  98. package/dist/chunk-67UZEWWF.js.map +0 -1
  99. package/dist/chunk-6OQQOMZR.js +0 -785
  100. package/dist/chunk-6OQQOMZR.js.map +0 -1
  101. package/dist/chunk-AQEQX4FF.js.map +0 -1
  102. package/dist/chunk-C7ADUNPR.js +0 -273
  103. package/dist/chunk-C7ADUNPR.js.map +0 -1
  104. package/dist/chunk-EFJ2NH6E.js.map +0 -1
  105. package/dist/chunk-IME7R2UI.js.map +0 -1
  106. package/dist/chunk-J62VZYOB.js +0 -1339
  107. package/dist/chunk-J62VZYOB.js.map +0 -1
  108. package/dist/chunk-JTPOI3KU.js.map +0 -1
  109. package/dist/chunk-QYBD22H5.js.map +0 -1
  110. package/dist/chunk-RFJ6Q6LE.js.map +0 -1
  111. package/dist/chunk-S4JMID4G.js +0 -259
  112. package/dist/chunk-S4JMID4G.js.map +0 -1
  113. package/dist/chunk-TLX3H2CL.js.map +0 -1
  114. package/dist/chunk-VPNLCMVR.js.map +0 -1
  115. package/dist/chunk-W3XFHEF4.js.map +0 -1
  116. package/dist/chunk-X4NJT436.js.map +0 -1
  117. package/dist/chunk-X66I2NQO.js +0 -137
  118. package/dist/chunk-X66I2NQO.js.map +0 -1
  119. package/dist/chunk-Y2VHN7TC.js.map +0 -1
  120. package/dist/chunk-YC6W4EJH.js.map +0 -1
  121. package/dist/context-CBOBDY5Q.js +0 -38
  122. package/dist/loader-S77OVTHH.js +0 -18
  123. package/dist/memory-store-DZUT5HUH.js +0 -75
  124. package/dist/scrollback-35ME2GFX.js.map +0 -1
  125. package/dist/settings-loader-JUNPGAAM.js +0 -35
  126. package/dist/shell-selection-CDHGJ4GC.js +0 -17
  127. /package/dist/{additional-roots-H7UNAEHS.js.map → additional-roots-VAWRQ625.js.map} +0 -0
  128. /package/dist/{chunk-525CAZPY.js.map → chunk-4DKHLZRI.js.map} +0 -0
  129. /package/dist/{chunk-4AS7LKKQ.js.map → chunk-62EEAUID.js.map} +0 -0
  130. /package/dist/{chunk-KBQS35OV.js.map → chunk-MV5PQNIA.js.map} +0 -0
  131. /package/dist/{chunk-56SIEMDX.js.map → chunk-PTDC7ZUP.js.map} +0 -0
  132. /package/dist/{chunk-HQI7NYGX.js.map → chunk-SWPDKLNM.js.map} +0 -0
  133. /package/dist/{chunk-SOW4WRQP.js.map → chunk-WV3O5PGX.js.map} +0 -0
  134. /package/dist/{command-approvals-VBIU6BLM.js.map → command-approvals-ZRY66LCW.js.map} +0 -0
  135. /package/dist/{context-CBOBDY5Q.js.map → context-C3RAP6K5.js.map} +0 -0
  136. /package/dist/{hook-approvals-ZVT4V7IM.js.map → hook-approvals-DPQD5H65.js.map} +0 -0
  137. /package/dist/{loader-S77OVTHH.js.map → loader-DQNPDKOX.js.map} +0 -0
  138. /package/dist/{mcp-approvals-HJ2VDYMC.js.map → mcp-approvals-27LJYADQ.js.map} +0 -0
  139. /package/dist/{mcp-config-RNB5LEVE.js.map → mcp-config-GXSODNCM.js.map} +0 -0
  140. /package/dist/{memory-store-DZUT5HUH.js.map → memory-store-I6Z54VUN.js.map} +0 -0
  141. /package/dist/{model-window-store-MTSQ5JDJ.js.map → model-window-store-6VKXXTPJ.js.map} +0 -0
  142. /package/dist/{openai-compatible-2OB54YST.js.map → openai-compatible-IPUNBJ53.js.map} +0 -0
  143. /package/dist/{permission-approvals-YLV6UC5W.js.map → permission-approvals-Q5IMFEZI.js.map} +0 -0
  144. /package/dist/{permissions-DHOKF3W2.js.map → permissions-7Y35X6HZ.js.map} +0 -0
  145. /package/dist/{sandbox-WRYTZH3D.js.map → provider-approvals-5AGH3RVT.js.map} +0 -0
  146. /package/dist/{settings-loader-JUNPGAAM.js.map → sandbox-N2RY72GN.js.map} +0 -0
  147. /package/dist/{settings-removed-JWWPT4WA.js.map → settings-loader-KDBH45AQ.js.map} +0 -0
  148. /package/dist/{shell-selection-CDHGJ4GC.js.map → settings-removed-3ATWJEF3.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/run-status.ts","../src/commands/print-dispatch.ts","../src/stream-json.ts","../src/reader-gone.ts","../src/headless.ts","../src/mcp.ts","../src/project-approval-notices.ts"],"sourcesContent":["import {\n closeSync,\n mkdirSync,\n openSync,\n readdirSync,\n readFileSync,\n renameSync,\n rmSync,\n statfsSync,\n statSync,\n unlinkSync,\n writeSync,\n} from 'node:fs';\nimport { join } from 'node:path';\nimport { resolveBookHome } from './book-home.js';\nimport { isProcessAlive } from './jobs/process-tree.js';\n\n/**\n * A small, always-current file saying what a run is doing right now.\n *\n * `book status` answers \"what was this asked to do and what has it spent\" from the\n * session JSONL, which is durable and never rewritten. What the JSONL cannot\n * answer is *liveness*: at hour 90 the only on-disk signal that a run is healthy\n * is the transcript's mtime, and that advances at exactly the same rate for a\n * productive run, a refusal spin, and a run wedged on a permission prompt. The\n * default `--output-format text` writes nothing at all until the run terminates,\n * and the alternative is a firehose. Between silence and every reasoning delta\n * there was nothing an operator could leave on.\n *\n * So: one bounded record, rewritten at each turn boundary, carrying the handful of\n * facts a supervisor needs to decide \"is this stuck\" — plus a crash record written\n * from the exit path, because when a long run dies today nothing durable says why.\n *\n * Deliberately synchronous. The file is ~1 KB against turns that take seconds, and\n * the crash path runs inside `process.on('exit')`, where nothing async can run at\n * all. Written to a temp file and renamed, so a reader never sees a torn record.\n */\n\nexport const RUN_STATUS_VERSION = 1;\n\nexport interface RunStatusRecord {\n readonly version: typeof RUN_STATUS_VERSION;\n readonly sessionId: string;\n readonly runId: string;\n /** The process holding this run, so a reader can test liveness itself. */\n readonly pid: number;\n readonly startedAt: number;\n readonly updatedAt: number;\n readonly turn: number;\n readonly elapsedMs: number;\n /** Canonical name of the most recent tool call, if any. */\n readonly lastTool?: string;\n /** The todo currently marked in progress, if any. */\n readonly currentTodo?: string;\n readonly openTodos: number;\n readonly costUsd: number | null;\n readonly budgetUsd?: number;\n /** Free bytes on the volume holding the workspace, when the platform reports it. */\n readonly freeDiskBytes?: number;\n /** Set once the run has stopped, so a reader can tell finished from wedged. */\n readonly terminal?: {\n readonly status: string;\n readonly reason: string;\n readonly message?: string;\n };\n /**\n * Set when the process died without a terminal outcome. This is the difference\n * between \"the objective finished\" and \"the socket died\", which a supervisor\n * otherwise cannot tell apart.\n */\n readonly crash?: { readonly message: string; readonly at: number };\n}\n\nexport function runStatusDir(home = resolveBookHome()): string {\n return join(home, 'runs');\n}\n\nexport function runStatusPath(sessionId: string, home = resolveBookHome()): string {\n // Session ids are uuids, but a caller could pass anything; keep it a filename.\n const safe = sessionId.replace(/[^A-Za-z0-9_-]/g, '_');\n return join(runStatusDir(home), `${safe}.json`);\n}\n\n/** Free bytes on the volume holding `path`, or undefined where unavailable. */\nexport function freeDiskBytes(path: string): number | undefined {\n try {\n const stats = statfsSync(path);\n const free = Number(stats.bavail) * Number(stats.bsize);\n return Number.isFinite(free) && free >= 0 ? free : undefined;\n } catch {\n // statfs is not available on every platform or filesystem, and a status write\n // must never be the thing that ends a run.\n return undefined;\n }\n}\n\n/** Write atomically: a reader either sees the previous record or this one. */\nexport function writeRunStatus(record: RunStatusRecord, home = resolveBookHome()): void {\n const target = runStatusPath(record.sessionId, home);\n const temp = `${target}.${process.pid}.tmp`;\n try {\n mkdirSync(runStatusDir(home), { recursive: true });\n const fd = openSync(temp, 'w');\n try {\n writeSync(fd, JSON.stringify(record, null, 2));\n } finally {\n closeSync(fd);\n }\n renameSync(temp, target);\n } catch {\n // Observability must never take the run down with it.\n try {\n rmSync(temp, { force: true });\n } catch {\n /* ignore */\n }\n }\n}\n\nexport function readRunStatus(\n sessionId: string,\n home = resolveBookHome(),\n): RunStatusRecord | undefined {\n try {\n const parsed: unknown = JSON.parse(readFileSync(runStatusPath(sessionId, home), 'utf8'));\n if (!parsed || typeof parsed !== 'object') return undefined;\n const record = parsed as RunStatusRecord;\n return record.version === RUN_STATUS_VERSION ? record : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function clearRunStatus(sessionId: string, home = resolveBookHome()): void {\n try {\n rmSync(runStatusPath(sessionId, home), { force: true });\n } catch {\n /* ignore */\n }\n}\n\n/** `<session>.json`, or the `<session>.json.<pid>.tmp` an interrupted atomic write leaves. */\nconst RUN_RECORD_NAME = /\\.json$/;\nconst RUN_TEMP_NAME = /\\.json\\..+\\.tmp$/;\n\n/**\n * True when `path` holds the record of a run that may still be going: a numeric pid\n * naming a live process, and neither a terminal nor a crash outcome. Anything else\n * (torn JSON, no pid, a dead process, a finished run) is not worth keeping.\n */\nfunction recordsLiveRun(path: string): boolean {\n try {\n const parsed: unknown = JSON.parse(readFileSync(path, 'utf8'));\n if (!parsed || typeof parsed !== 'object') return false;\n const record = parsed as Partial<RunStatusRecord>;\n if (record.terminal || record.crash) return false;\n const pid = record.pid;\n // `process.kill(0, 0)` signals the whole process group, so anything that is not\n // a positive integer must never reach the liveness probe.\n if (typeof pid !== 'number' || !Number.isInteger(pid) || pid <= 0) return false;\n return isProcessAlive(pid);\n } catch {\n return false;\n }\n}\n\n/**\n * Remove run records last written more than `days` ago, so `runs/` follows the same\n * retention as the sessions it describes instead of growing without bound (#422).\n *\n * A run rewrites its record at each turn boundary, but a live run can still go that\n * long without one (stream-json input waiting on stdin, a question handler that never\n * returns, a wedged turn). So a record past the cutoff is kept while it names a live\n * process and carries no terminal or crash outcome; a file is read only once it is\n * past the cutoff. Only `*.json` records and leftover `*.json.*.tmp` write files are\n * touched; directories, symlinks and every other file are left alone. Best effort,\n * like every startup sweep: one entry that fails does not stop the rest.\n */\nexport function cleanupRunStatus(days: number, home = resolveBookHome(), now = Date.now()): number {\n const cutoff = now - Math.max(1, days) * 86_400_000;\n const directory = runStatusDir(home);\n let removed = 0;\n try {\n for (const entry of readdirSync(directory, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const isRecord = RUN_RECORD_NAME.test(entry.name);\n if (!isRecord && !RUN_TEMP_NAME.test(entry.name)) continue;\n const path = join(directory, entry.name);\n try {\n if (statSync(path).mtimeMs >= cutoff) continue;\n if (isRecord && recordsLiveRun(path)) continue;\n unlinkSync(path);\n removed++;\n } catch {\n // Rewritten or removed by another process meanwhile.\n }\n }\n } catch {\n // No runs directory yet, or unreadable: nothing to sweep.\n }\n return removed;\n}\n\nexport interface RunStatusSeed {\n readonly sessionId: string;\n readonly runId: string;\n readonly workspace: string;\n readonly budgetUsd?: number;\n readonly startedAt: number;\n readonly home?: string;\n}\n\nexport interface RunStatusUpdate {\n readonly turn: number;\n readonly lastTool?: string;\n readonly currentTodo?: string;\n readonly openTodos: number;\n readonly costUsd: number | null;\n readonly terminal?: RunStatusRecord['terminal'];\n}\n\n/**\n * Keeps one run's status file current.\n *\n * Created by a host rather than by the loop: a subagent and a managed agent both\n * call `runAgentLoop` directly, and each writing its own liveness file would make\n * \"is the run alive\" ambiguous. The host that owns the session owns the file.\n */\nexport class RunStatusWriter {\n private readonly seed: RunStatusSeed;\n private last: RunStatusRecord;\n private crashHandlerInstalled = false;\n\n constructor(seed: RunStatusSeed) {\n this.seed = seed;\n this.last = {\n version: RUN_STATUS_VERSION,\n sessionId: seed.sessionId,\n runId: seed.runId,\n pid: process.pid,\n startedAt: seed.startedAt,\n updatedAt: seed.startedAt,\n turn: 0,\n elapsedMs: 0,\n openTodos: 0,\n costUsd: null,\n budgetUsd: seed.budgetUsd,\n freeDiskBytes: freeDiskBytes(seed.workspace),\n };\n writeRunStatus(this.last, seed.home);\n }\n\n update(update: RunStatusUpdate, now = Date.now()): void {\n this.last = {\n ...this.last,\n updatedAt: now,\n elapsedMs: now - this.seed.startedAt,\n turn: update.turn,\n lastTool: update.lastTool ?? this.last.lastTool,\n currentTodo: update.currentTodo,\n openTodos: update.openTodos,\n costUsd: update.costUsd,\n freeDiskBytes: freeDiskBytes(this.seed.workspace),\n terminal: update.terminal ?? this.last.terminal,\n };\n writeRunStatus(this.last, this.seed.home);\n }\n\n /**\n * Record that the process is dying without a terminal outcome.\n *\n * Synchronous by necessity: this runs from `process.on('exit')`, where the event\n * loop is already closed and no promise will ever settle.\n */\n recordCrash(message: string, now = Date.now()): void {\n if (this.last.terminal) return; // finished properly; not a crash\n if (this.last.crash) return;\n this.last = { ...this.last, updatedAt: now, crash: { message, at: now } };\n writeRunStatus(this.last, this.seed.home);\n }\n\n /**\n * Install last-resort handlers so an unhandled fault leaves a record.\n *\n * There is no `uncaughtException` or `unhandledRejection` handler anywhere in the\n * codebase, and `index.ts` ends in a bare `program.parse()` whose returned promise\n * nothing awaits — so a rejection escaping the action handler becomes an unhandled\n * rejection and the operator gets a stack trace on a stderr they may have\n * redirected days ago. Returns a disposer.\n */\n installCrashHandlers(): () => void {\n if (this.crashHandlerInstalled) return () => {};\n this.crashHandlerInstalled = true;\n // ONLY `exit`. Registering an `uncaughtException` or `unhandledRejection`\n // listener REPLACES Node's default print-and-exit(1) with whatever the listener\n // does — and a listener that merely records would swallow the fault, leave the\n // awaited chain unsettled so this writer's own disposer never runs, and let the\n // process drain and exit 0. A supervisor polling for a terminal outcome would\n // read a hard crash as success. Node fires `exit` during its default death\n // anyway, so this handler alone already captures the record, at no cost to the\n // exit code.\n const onExit = (): void => {\n this.recordCrash('The process exited before the run reached a terminal outcome.');\n };\n process.on('exit', onExit);\n return () => {\n process.off('exit', onExit);\n this.crashHandlerInstalled = false;\n };\n }\n\n snapshot(): RunStatusRecord {\n return this.last;\n }\n}\n","/**\n * Slash-command dispatch for hosts that have no interactive surface: print /\n * headless mode (`book -p …`) and the SDK.\n *\n * The TUI resolves a submitted `/name` in three ordered steps — the built-in\n * registry (`createBuiltinCommandRegistry`), then the user/project command\n * files (`discoverCommands`), then \"not a command, send the text as typed\".\n * This module walks the same three steps against the same registries and the\n * same `resolveCommandBody`, so print mode cannot fork command semantics. What\n * differs is only what a non-interactive host may do with the resulting effect.\n *\n * A print host can send a prompt. It cannot open a modal, toggle a panel,\n * switch themes, or resume a session, so a command whose effect needs an\n * interactive host is refused *before* its `execute` runs: several built-ins\n * write settings or files as a side effect (`/config`, `/export`, `/memory\n * approve`), and running one only to discover the host cannot show its result\n * would be worse than not running it at all. The gate is the declarative\n * `nonInteractive` flag on the command definition, never a guess about the\n * effect a given argument string happens to produce.\n */\n\nimport type { AgentConfig, PermissionMode } from '../types/runtime.js';\nimport type { CommandContext, SlashCommand } from '../types/commands.js';\nimport { commandEnforcementContext, parseSlashInput, resolveCommandBody } from './resolve.js';\nimport { discoverCommands } from './loader.js';\nimport {\n createBuiltinCommandRegistry,\n type BuiltinCommandContext,\n type BuiltinCommandEffect,\n} from './builtins.js';\nimport type { CommandRegistry } from './registry.js';\nimport type { AgentManager } from '../agents/manager.js';\nimport type { AgentRunContext } from '../types/runs.js';\nimport type { ActiveGoal } from '../types/goal.js';\nimport { formatGoalStatus, goalKickoffPrompt } from '../agent/goal.js';\nimport { reviewRunnerFor } from '../review/runner.js';\nimport { reviewReportJson, runHostReview } from '../review/host.js';\n\nexport type BuiltinPrintRegistry = CommandRegistry<BuiltinCommandContext, BuiltinCommandEffect>;\n\n/** Ambient facts a non-interactive host can state truthfully about its run. */\nexport interface PrintCommandEnvironment {\n /** Frozen run config; supplies workspace, model, and provider. */\n config: AgentConfig;\n /** Permission mode of the run. */\n mode: PermissionMode;\n /** Session the command is resolved against (`${BOOK_SESSION_ID}`). */\n sessionId: string;\n /** Cancels in-flight shell substitution, exactly as the TUI's does. */\n signal?: AbortSignal;\n /**\n * The managed-agent runtime for commands the host performs by running agents\n * rather than by sending a prompt (`/review`), together with the run those\n * agents belong to. A host that omits it refuses those commands instead of\n * pretending.\n *\n * `manager` is a factory so an ordinary print run never pays to build one, and\n * `runContext` is required alongside it rather than optional: budget\n * enforcement is keyed by `rootRunId` (`RunAccounting.checkBeforeModelCall`),\n * so a manager supplied without one would spawn agents under a fresh, unbudgeted\n * root and quietly spend past `--max-budget-usd`. Coupling them in one field\n * makes that combination unrepresentable.\n */\n agents?: {\n manager: () => AgentManager;\n runContext: AgentRunContext;\n };\n /**\n * The session's `/goal`, for a host whose loop checks one (`AgentSession`). A\n * host that omits it refuses `/goal` rather than accepting a goal nothing checks.\n */\n goal?: {\n get(): ActiveGoal | undefined;\n set(condition: string): void;\n clear(): ActiveGoal | undefined;\n };\n}\n\n/** What the host should do with one submitted line. */\nexport type PrintCommandDispatch =\n /** Run this text as the user turn. Set for prompt-body commands. */\n | {\n kind: 'prompt';\n prompt: string;\n /** Frontmatter enforcement (allowed-tools / model), as the TUI passes it. */\n commandContext?: CommandContext;\n /**\n * What an unnamed session is named after instead of `prompt`: the line the user typed for a\n * prompt-body command (`/init`, `/deploy staging`), the condition for `/goal` (#524).\n */\n sessionNameSource?: string;\n /** Non-fatal shell-substitution failures, exactly as the TUI collects them. */\n shellErrors?: string[];\n /**\n * `prompt` is the resolved body of a project command (`.book/commands/*.md`), or a built-in\n * prompt that carries the repository's text (`/security-review`'s REVIEW.md), so its\n * mentions inline only files git has committed, unchanged (#564).\n */\n projectCommand?: boolean;\n }\n /** The effect handler already did the work; the host runs no model turn. */\n | {\n kind: 'handled';\n command: string;\n /** Human-readable rendering, used by `--output-format text`. */\n output?: string;\n /**\n * Machine-readable rendering for `--output-format json` / `stream-json`.\n * A maintained output contract: see `review/host.ts#ReviewJsonReport`.\n */\n data?: unknown;\n }\n /** Not a command: send the line to the model unchanged. */\n | { kind: 'passthrough'; prompt: string };\n\n/**\n * Performs one built-in effect in a non-interactive host. Returning `handled`\n * means the work is done and no model turn should run for this input. The third\n * argument is the name the user actually typed (an alias, possibly), so a\n * handler can name it in an error.\n */\nexport type PrintEffectHandler<Type extends BuiltinCommandEffect['type']> = (\n effect: Extract<BuiltinCommandEffect, { type: Type }>,\n env: PrintCommandEnvironment,\n command: string,\n) => PrintCommandDispatch | Promise<PrintCommandDispatch>;\n\ntype AnyPrintEffectHandler = (\n effect: BuiltinCommandEffect,\n env: PrintCommandEnvironment,\n command: string,\n) => PrintCommandDispatch | Promise<PrintCommandDispatch>;\n\n/**\n * Effect-type → handler map. An effect with no registered handler is refused\n * loudly rather than degraded into \"send the slash string to the model\".\n */\nexport class PrintEffectRegistry {\n private readonly handlers = new Map<BuiltinCommandEffect['type'], AnyPrintEffectHandler>();\n\n register<Type extends BuiltinCommandEffect['type']>(\n type: Type,\n handler: PrintEffectHandler<Type>,\n ): this {\n // Sound in this direction: the stored handler is only ever invoked with an\n // effect whose `type` matches the key it was registered under.\n this.handlers.set(type, handler as AnyPrintEffectHandler);\n return this;\n }\n\n has(type: BuiltinCommandEffect['type']): boolean {\n return this.handlers.has(type);\n }\n\n handledTypes(): BuiltinCommandEffect['type'][] {\n return [...this.handlers.keys()];\n }\n\n handle(\n effect: BuiltinCommandEffect,\n env: PrintCommandEnvironment,\n command: string,\n ): Promise<PrintCommandDispatch> | undefined {\n const handler = this.handlers.get(effect.type);\n return handler ? Promise.resolve(handler(effect, env, command)) : undefined;\n }\n}\n\n/** A slash command exists but this host cannot run it. Never falls back to prose. */\nexport class UnsupportedPrintCommandError extends Error {\n readonly command: string;\n\n constructor(command: string, message: string) {\n super(message);\n this.name = 'UnsupportedPrintCommandError';\n this.command = command;\n }\n}\n\n/**\n * The command ran and rejected its own invocation (bad flag, bad argument).\n *\n * Separate from {@link UnsupportedPrintCommandError} because the command *is*\n * supported here; it is the arguments that are wrong. Both end the run non-zero:\n * a print host that printed \"✕ Unknown review option: --dep\" and exited 0 would\n * let a CI job believe a review it never ran had passed.\n */\nexport class PrintCommandUsageError extends Error {\n readonly command: string;\n\n constructor(command: string, message: string) {\n super(message);\n this.name = 'PrintCommandUsageError';\n this.command = command;\n }\n}\n\n/**\n * Why `--fix` stops here rather than running unattended.\n *\n * `applyReviewFixes` spawns patcher agents that edit files and then commits the\n * verified patch into the user's repository. A non-interactive host cannot\n * answer a managed-agent permission prompt — `AgentManager` denies every one\n * when no interactive host is attached — so an unattended `--fix` would either\n * fail every patch on a denial or, under `--permission-mode bypassPermissions`,\n * commit unreviewed changes with nobody watching. The read-only review is wired\n * end to end; the applying half stays where a human can see it.\n */\nconst FIX_REFUSAL = [\n '✕ /review --fix needs an interactive session.',\n '',\n '--fix spawns patcher agents that edit files and commit verified patches. A non-interactive',\n 'host cannot approve those tool calls, so the fix pass would either be denied outright or',\n 'commit unreviewed changes with no one watching.',\n '',\n 'Run `book` interactively and use /review --fix there, or run `book -p \"/review --deep\"`',\n 'and apply the reported fixes yourself.',\n].join('\\n');\n\n/**\n * Run `/review` from a host with no interactive surface.\n *\n * The target is resolved host-side by the pipeline (`runHostReview` →\n * `resolveReviewTarget`) from `env.config.workspace` and the parsed scope, so\n * `--base`, path scoping and `<base>...<head>` behave exactly as in the TUI and\n * the reviewer agents still get an immutable diff they cannot re-select.\n */\nasync function performPrintReview(\n effect: Extract<BuiltinCommandEffect, { type: 'review' }>,\n env: PrintCommandEnvironment,\n command: string,\n): Promise<PrintCommandDispatch> {\n if (effect.scope.fix) throw new UnsupportedPrintCommandError(command, FIX_REFUSAL);\n if (!env.agents) {\n throw new UnsupportedPrintCommandError(\n command,\n `✕ /${command} needs the managed-agent runtime, and this host did not provide one.`,\n );\n }\n\n const result = await runHostReview({\n scope: effect.scope,\n workspace: env.config.workspace,\n // Every reviewer, lens and verifier agent is spawned under the host's run,\n // so the whole pipeline is billed and budgeted as one root.\n runner: reviewRunnerFor(env.agents.manager(), {\n // The stored session the run belongs to, as the TUI passes its own. Without it\n // each agent's tool-use records carry a made-up `agent:<id>` session id that\n // matches no session file, and `book tool-stats` counts every one separately.\n parentSessionId: env.agents.runContext.sessionId,\n rootRunId: env.agents.runContext.rootRunId,\n parentRunId: env.agents.runContext.runId,\n }),\n });\n // A review that could not run at all must end the run non-zero. An\n // inconclusive *verdict* is different: the review ran, its coverage warnings\n // are in the report, and the caller gates on `verdict`.\n if (result.error) throw new Error(result.segments.join('\\n\\n'));\n return {\n kind: 'handled',\n command,\n output: result.segments.join('\\n\\n'),\n data: reviewReportJson(result),\n };\n}\n\n/**\n * The effects a plain print host can perform on its own: send a prompt, print a\n * message the command produced, and run the host-orchestrated review. Anything\n * that needs to mutate host state or open a surface stays unregistered, and an\n * unregistered effect is refused rather than degraded.\n */\nexport function createPrintEffectRegistry(): PrintEffectRegistry {\n return new PrintEffectRegistry()\n .register('send-prompt', (effect) => ({\n kind: 'prompt',\n prompt: effect.prompt,\n commandContext: effect.context,\n projectCommand: effect.projectCommand,\n }))\n .register('local-message', (effect, _env, command) => {\n if (effect.isError) throw new PrintCommandUsageError(command, effect.content);\n return { kind: 'handled', command, output: effect.content };\n })\n .register('review', performPrintReview)\n .register('set-goal', (effect, env, command) => {\n if (!env.goal) throw new UnsupportedPrintCommandError(command, GOAL_REFUSAL);\n env.goal.set(effect.condition);\n const kickoff = goalKickoffPrompt(effect.condition);\n return {\n kind: 'prompt',\n prompt: kickoff,\n commandContext: {\n command: {\n name: 'goal',\n description: 'Set a goal Book checks before stopping',\n body: kickoff,\n source: 'project',\n },\n resolvedBody: kickoff,\n },\n sessionNameSource: effect.condition,\n };\n })\n .register('clear-goal', (_effect, env, command) => {\n if (!env.goal) throw new UnsupportedPrintCommandError(command, GOAL_REFUSAL);\n const cleared = env.goal.clear();\n return {\n kind: 'handled',\n command,\n output: cleared\n ? formatGoalStatus({ state: 'cleared', condition: cleared.condition })\n : 'No goal set',\n };\n });\n}\n\nconst GOAL_REFUSAL = '✕ /goal needs a host that checks goals; this one does not.';\n\nexport interface PrintCommandDeps {\n /** Defaults to the shared built-in registry the TUI uses. */\n builtins?: BuiltinPrintRegistry;\n /** Defaults to the `send-prompt`-only registry. */\n effects?: PrintEffectRegistry;\n /** Defaults to `discoverCommands(workspace)` — the TUI's loader. */\n commands?: SlashCommand[];\n}\n\n/**\n * Context handed to a built-in's `execute` in print mode.\n *\n * Only fields a non-interactive host knows are populated; conversation state\n * is empty because resolution happens before the turn exists. A command may\n * therefore be marked `nonInteractive` only when it depends on nothing beyond\n * workspace, session id, model, provider, permission mode, and config.\n */\nfunction printBuiltinContext(\n env: PrintCommandEnvironment,\n commands: SlashCommand[],\n): BuiltinCommandContext {\n return {\n workspace: env.config.workspace,\n sessionId: env.sessionId,\n model: env.config.model,\n provider: env.config.provider,\n currentTurn: 0,\n messages: [],\n lastError: null,\n runtimeConfig: env.config,\n mode: env.mode,\n usage: null,\n activeGoal: env.goal?.get(),\n turnDurationMs: 0,\n contextHistory: [],\n compactBoundaries: [],\n commandCount: commands.length,\n skillCount: 0,\n resolveAmbientContext: () => ({\n subagentCount: 0,\n hasMemoryIndex: false,\n hasClaudeMdLoader: false,\n }),\n };\n}\n\nfunction supportedCommandHelp(builtins: BuiltinPrintRegistry, commands: SlashCommand[]): string[] {\n const lines = ['Commands supported in print mode:'];\n for (const definition of builtins.getDefinitions()) {\n if (definition.nonInteractive) lines.push(` /${definition.name} — ${definition.description}`);\n for (const subcommand of definition.nonInteractiveSubcommands ?? []) {\n lines.push(` /${definition.name} ${subcommand} — ${definition.description}`);\n }\n }\n const custom = commands.map((command) => `/${command.name}`);\n lines.push(\n custom.length > 0\n ? ` custom commands from .book/commands: ${custom.slice(0, 12).join(' ')}${custom.length > 12 ? ' …' : ''}`\n : ' plus any custom command in .book/commands/ or ~/.book/commands/',\n );\n return lines;\n}\n\nfunction unsupported(\n command: string,\n reason: string,\n builtins: BuiltinPrintRegistry,\n commands: SlashCommand[],\n): UnsupportedPrintCommandError {\n return new UnsupportedPrintCommandError(\n command,\n [\n `✕ /${command} ${reason}`,\n '',\n ...supportedCommandHelp(builtins, commands),\n '',\n `Run book without --print (interactive mode) to use /${command}.`,\n ].join('\\n'),\n );\n}\n\n/**\n * Resolve one submitted line for a non-interactive host.\n *\n * Throws {@link UnsupportedPrintCommandError} when the line names a real\n * command this host cannot perform. An unknown `/name` is not a command at all\n * — the TUI sends it to the model unchanged, and so does this.\n */\nexport async function resolvePrintCommand(\n input: string,\n env: PrintCommandEnvironment,\n deps: PrintCommandDeps = {},\n): Promise<PrintCommandDispatch> {\n const parsed = parseSlashInput(input);\n if (!parsed || !parsed.name) return { kind: 'passthrough', prompt: input };\n\n const builtins = deps.builtins ?? createBuiltinCommandRegistry();\n const effects = deps.effects ?? createPrintEffectRegistry();\n const commands = deps.commands ?? discoverCommands(env.config.workspace);\n const context = printBuiltinContext(env, commands);\n\n const resolved = builtins.resolve(parsed.name, context);\n // A `tuiOnly` command is the TUI's own state, so a non-interactive host treats the name as one\n // it has never heard of: a project command may claim it, and otherwise it passes through.\n if (resolved && !resolved.definition.tuiOnly) {\n const subcommand = parsed.rawArguments.trim().split(/\\s+/)[0] ?? '';\n const allowedHere =\n resolved.definition.nonInteractive ||\n (resolved.definition.nonInteractiveSubcommands?.includes(subcommand) ?? false);\n if (!allowedHere) {\n throw unsupported(\n parsed.name,\n 'needs an interactive session: it changes host state instead of producing a prompt.',\n builtins,\n commands,\n );\n }\n if (!resolved.available) {\n throw unsupported(\n parsed.name,\n `is unavailable: ${resolved.unavailableReason ?? 'no reason given'}`,\n builtins,\n commands,\n );\n }\n const effect = resolved.definition.execute(\n { name: resolved.invokedName, rawArguments: parsed.rawArguments },\n context,\n );\n const dispatch = await effects.handle(effect, env, resolved.invokedName);\n if (!dispatch) {\n throw unsupported(\n parsed.name,\n `resolved to the '${effect.type}' effect, which a non-interactive host cannot perform.`,\n builtins,\n commands,\n );\n }\n if (dispatch.kind === 'handled') return { ...dispatch, command: parsed.name };\n // A command that turns into a prompt names a fresh session after what was typed, not after\n // the body it generated; `/goal` already chose its own source (the condition).\n return dispatch.kind === 'prompt'\n ? { ...dispatch, sessionNameSource: dispatch.sessionNameSource ?? input.trim() }\n : dispatch;\n }\n\n const custom = commands.find((command) => command.name === parsed.name);\n if (!custom) return { kind: 'passthrough', prompt: input };\n\n // Same resolver, same order (shell substitution, then variables), same trust\n // model as the TUI. A repository-declared body that substitutes shell is\n // refused here exactly as it is there: this host cannot prompt for the\n // decision, so an unapproved command ends the run instead of running its\n // shell unattended.\n const { resolved: body, shellErrors } = await resolveCommandBody(\n custom,\n parsed.rawArguments,\n {\n sessionId: env.sessionId,\n workspace: env.config.workspace,\n model: env.config.model,\n projectCommands: env.config.settings.commands.projectCommands,\n },\n env.signal,\n );\n return {\n kind: 'prompt',\n prompt: body,\n commandContext: commandEnforcementContext(custom, body),\n sessionNameSource: input.trim(),\n shellErrors,\n projectCommand: custom.source === 'project',\n };\n}\n","import type { AgentTerminalOutcome } from './types/terminal.js';\n\n/** Known event types in the stream-json wire format. */\nexport type StreamJsonEvent =\n | { type: 'user'; content: string }\n | { type: 'system'; model?: string; cwd?: string; [key: string]: unknown }\n | { type: 'session'; session_id?: string }\n | { type: 'run_start'; run?: unknown }\n | { type: 'assistant'; text?: string }\n | { type: 'reasoning'; text?: string }\n | { type: 'tool_use'; tool_call?: unknown }\n | { type: 'tool_result'; tool_result?: unknown }\n | { type: 'user_question'; request?: unknown; status?: 'pending' | 'unavailable' }\n | { type: 'user_question_result'; request_id?: string; response?: unknown }\n | { type: 'agent_start' | 'agent_update' | 'agent_result'; agent?: unknown }\n | {\n type: 'background_job_start' | 'background_job_update' | 'background_job_result';\n job?: unknown;\n }\n | { type: 'background_job_output'; jobId?: string; revision?: number }\n | { type: 'background_job_dismiss'; jobId?: string }\n | { type: 'agent_question'; agentId?: string; request?: unknown }\n | { type: 'agent_status'; agent?: unknown }\n | { type: 'agent_activity'; agentId?: string; activity?: unknown }\n | { type: 'agent_text_delta'; agentId?: string; text?: string }\n | { type: 'agent_message'; agentId?: string; message?: unknown }\n | { type: 'agent_completion'; notification?: unknown }\n | { type: 'agent_permission'; agentId?: string; request?: unknown }\n /**\n * A managed child's own line for the operator: a refusal it hit, with the child's label already\n * on the text. Not part of the child's record and not part of the parent's transcript, so a\n * print-mode host that read only `tool_result` and `agent_*` records had no way to learn a\n * delegated step did not run (#305 item 4).\n */\n | { type: 'agent_notice'; agentId?: string; message?: string }\n | { type: 'evidence_update'; evidence?: unknown }\n /**\n * The turn is being retried; discard every `assistant`/`reasoning` delta\n * emitted for it so far. Only the replacement attempt reaches the transcript,\n * so a consumer that concatenates blindly would keep text no history records.\n */\n | { type: 'attempt_discarded'; reason?: string }\n | {\n type: 'retry';\n phase?: string;\n attempt?: number;\n max?: number | null;\n delay_ms?: number;\n reason?: string;\n }\n | { type: 'agent_apply'; agentId?: string; evidenceId?: string; status?: string }\n | { type: 'hook_event'; event?: string; [key: string]: unknown }\n | { type: 'mode_change'; mode?: string }\n | { type: 'plan_approval'; status?: string }\n /**\n * A slash command the host performed itself, instead of running a model turn.\n * `output` is the human rendering; `data` is the command's machine contract\n * (for `/review`, `ReviewJsonReport` from `review/host.ts`).\n */\n | { type: 'command_result'; command?: string; output?: string; data?: unknown }\n | { type: 'prompt_suggestions'; suggestions?: string[] }\n | { type: 'notice'; message?: string }\n /** A `/goal` check: the fields of a `GoalStatusEvent` (`state`, `condition`, `reason`, …). */\n | { type: 'goal_status'; state?: string; condition?: string; [key: string]: unknown }\n | { type: 'error'; error?: string }\n /**\n * The run's terminal record, and the last line of the stream.\n *\n * `outcome` and `stopReason` sit at the top level: a supervised loop reads the\n * outcome from here (see the `jq` selector in `docs/guide/long-runs.md`), and\n * `result.outcome` / `result.stopReason` are kept for hosts already reading them\n * there. It is the run's own `AgentTerminalOutcome`, not a restatement of it, so\n * a status the run cannot emit cannot typecheck into this record.\n *\n * `result` is the host-performed part of the record — the answer, the usage, the\n * accounting, and the conversation when the run passed\n * `--include-result-messages`, which #307 made opt-in to keep a long run's last\n * line small. Nothing in the parser reads into it, so it stays `unknown` here.\n */\n | {\n type: 'result';\n stopReason?: string;\n outcome?: AgentTerminalOutcome;\n result?: unknown;\n }\n | { type: 'done' };\n\nexport type StreamJsonDiagnosticCode = 'invalid-json' | 'invalid-shape' | 'oversized-line';\n\nexport interface StreamJsonDiagnostic {\n code: StreamJsonDiagnosticCode;\n message: string;\n line?: string;\n}\n\nexport interface StreamParserOptions {\n maxBufferedLineBytes?: number;\n onDiagnostic?: (diagnostic: StreamJsonDiagnostic) => void;\n}\n\nconst EVENT_TYPES = new Set<StreamJsonEvent['type']>([\n 'user',\n 'system',\n 'session',\n 'run_start',\n 'assistant',\n 'reasoning',\n 'tool_use',\n 'tool_result',\n 'user_question',\n 'user_question_result',\n 'agent_start',\n 'background_job_start',\n 'background_job_update',\n 'background_job_output',\n 'background_job_result',\n 'background_job_dismiss',\n 'agent_update',\n 'agent_result',\n 'agent_question',\n 'agent_status',\n 'agent_activity',\n 'agent_text_delta',\n 'agent_message',\n 'agent_completion',\n 'agent_permission',\n 'agent_notice',\n 'evidence_update',\n 'attempt_discarded',\n 'retry',\n 'agent_apply',\n 'hook_event',\n 'mode_change',\n 'plan_approval',\n 'command_result',\n 'prompt_suggestions',\n 'notice',\n 'error',\n 'result',\n 'done',\n]);\n\nconst DEFAULT_MAX_BUFFERED_LINE_BYTES = 1024 * 1024;\n\nexport function parseStreamLineDetailed(line: string): {\n event?: StreamJsonEvent;\n diagnostic?: StreamJsonDiagnostic;\n} {\n const trimmed = line.trim();\n if (!trimmed) return {};\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch (error) {\n return {\n diagnostic: {\n code: 'invalid-json',\n message: `Invalid stream-json record: ${error instanceof Error ? error.message : String(error)}`,\n line: trimmed,\n },\n };\n }\n\n if (\n parsed === null ||\n typeof parsed !== 'object' ||\n Array.isArray(parsed) ||\n !('type' in parsed) ||\n typeof parsed.type !== 'string' ||\n !EVENT_TYPES.has(parsed.type as StreamJsonEvent['type']) ||\n (parsed.type === 'user' && typeof (parsed as { content?: unknown }).content !== 'string')\n ) {\n return {\n diagnostic: {\n code: 'invalid-shape',\n message: 'Stream-json records must be objects with a supported type and valid fields.',\n line: trimmed,\n },\n };\n }\n\n return { event: parsed as StreamJsonEvent };\n}\n\nexport function createStreamParser(\n onEvent: (event: StreamJsonEvent) => void,\n options: StreamParserOptions = {},\n) {\n const maxBufferedLineBytes = options.maxBufferedLineBytes ?? DEFAULT_MAX_BUFFERED_LINE_BYTES;\n if (!Number.isSafeInteger(maxBufferedLineBytes) || maxBufferedLineBytes < 1) {\n throw new Error('maxBufferedLineBytes must be a positive safe integer');\n }\n\n let buffer = '';\n let discardingOversizedLine = false;\n\n const emitLine = (line: string): void => {\n const { event, diagnostic } = parseStreamLineDetailed(line.replace(/\\r$/, ''));\n if (event) onEvent(event);\n if (diagnostic) options.onDiagnostic?.(diagnostic);\n };\n\n const append = (segment: string, terminated: boolean): void => {\n if (discardingOversizedLine) {\n if (terminated) discardingOversizedLine = false;\n return;\n }\n\n if (Buffer.byteLength(buffer) + Buffer.byteLength(segment) > maxBufferedLineBytes) {\n buffer = '';\n options.onDiagnostic?.({\n code: 'oversized-line',\n message: `Stream-json record exceeds the ${maxBufferedLineBytes}-byte limit.`,\n });\n discardingOversizedLine = !terminated;\n return;\n }\n\n buffer += segment;\n if (terminated) {\n emitLine(buffer);\n buffer = '';\n }\n };\n\n return {\n feed(chunk: string | Buffer): void {\n const segments = chunk.toString().split('\\n');\n for (let index = 0; index < segments.length; index++) {\n append(segments[index] ?? '', index < segments.length - 1);\n }\n },\n\n flush(): void {\n if (!discardingOversizedLine && buffer.length > 0) emitLine(buffer);\n buffer = '';\n discardingOversizedLine = false;\n },\n };\n}\n","import { Writable } from 'node:stream';\n\n/**\n * Has the reader of a print run's output gone?\n *\n * A closed pipe is only noticed on a write, and the notice arrives after the\n * write returns: `stdout.write` succeeds, the OS notices the far end is closed,\n * and the failure comes back on the write's callback and on the stream's\n * `error` event. A run that only watches the event hears about a reader that\n * left during a silent turn a whole tool call too late (#340), which is why\n * both this module and the CLI's pipe handler classify the same codes.\n */\nconst READER_GONE_CODES: ReadonlySet<string> = new Set([\n 'EPIPE',\n 'EOF',\n 'ERR_STREAM_DESTROYED',\n 'ECONNRESET',\n]);\n\n/**\n * True when `error` says nobody is reading this stream any more.\n *\n * Everything else is a real failure and belongs to whoever threw it: a\n * permission error on the pipe is not a reader that walked away, and swallowing\n * it would report a healthy run as cancelled.\n */\nexport function isReaderGoneError(error: unknown): boolean {\n const code = (error as NodeJS.ErrnoException | null | undefined)?.code;\n return code !== undefined && READER_GONE_CODES.has(code);\n}\n\n/**\n * How long a tool boundary waits for the records announcing it to be taken.\n *\n * A reader that is gone answers within milliseconds — measured on Windows at\n * 1 to 2 ms after the write, for a native pipe and for Git Bash alike — while a\n * reader that is merely slow must not hold the run at a tool boundary. So the\n * wait ends at the first of: the write's callback, the run's signal, the cap.\n */\nexport const READER_FLUSH_CAP_MS = 1000;\n\n/**\n * Watches a run's output stream for a reader that has gone, and lets a tool\n * boundary wait for the records it is about to announce.\n */\nexport interface ReaderFlush {\n /** Aborted the moment a write reports that the reader is gone. */\n readonly signal: AbortSignal;\n /**\n * Write one record. The write is made outside any promise, so a sink that\n * throws on `write` throws out of the caller exactly as a bare write does.\n */\n write(line: string): void;\n /**\n * Resolves once nothing this flush wrote is still outstanding, or at the cap.\n *\n * Free when the reader has caught up: no promise to settle, no timer, and no\n * listener on the run's signal. A reader that has made a hold wait the cap is\n * under backpressure rather than gone, so later holds stop waiting while its\n * writes are still pending — a live reader must not cost a cap at every call\n * of a run.\n */\n hold(signal: AbortSignal | undefined): Promise<void>;\n}\n\n/**\n * A flush for `stdout`, or `undefined` when it cannot report a failed write.\n *\n * Only a Node `Writable` qualifies — `process.stdout` and any `Writable` a host\n * passes do, and the SDK's bare `{ write }` sink does not. Guessing from the\n * `write` signature instead would take a wrapper that forwards nothing for a\n * writer that reports nothing, and read a two-parameter sink's `encoding` as a\n * callback it will never be handed.\n */\nexport function createReaderFlush(\n stdout: unknown,\n options: { capMs?: number } = {},\n): ReaderFlush | undefined {\n if (!(stdout instanceof Writable)) return undefined;\n const capMs = options.capMs ?? READER_FLUSH_CAP_MS;\n const controller = new AbortController();\n /** Writes this flush has made and not yet been answered. */\n let pending = 0;\n /** Whether a hold has already spent the cap on this reader. */\n let slow = false;\n const waiters = new Set<() => void>();\n\n const drained = (): void => {\n if (pending > 0) return;\n // The reader caught up, so the next boundary waits again: a stall that ends\n // costs one cap, not the whole run.\n slow = false;\n for (const release of [...waiters]) release();\n waiters.clear();\n };\n\n return {\n signal: controller.signal,\n write(line: string): void {\n pending++;\n stdout.write(line, (error) => {\n if (error && isReaderGoneError(error)) controller.abort();\n pending--;\n drained();\n });\n },\n hold(signal: AbortSignal | undefined): Promise<void> {\n if (pending === 0 || slow || signal?.aborted) return Promise.resolve();\n return new Promise<void>((resolve) => {\n let settled = false;\n const finish = (): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n signal?.removeEventListener('abort', finish);\n waiters.delete(finish);\n resolve();\n };\n const timer = setTimeout(() => {\n slow = true;\n finish();\n }, capMs);\n waiters.add(finish);\n signal?.addEventListener('abort', finish, { once: true });\n // An abort between the check above and the subscription would\n // otherwise leave the hold waiting out the cap.\n if (signal?.aborted) finish();\n });\n },\n };\n}\n","import type { AgentConfig } from './types/runtime.js';\nimport { planWasLost } from './agent/session-state.js';\nimport { finalAnswerText } from './agent/final-answer.js';\nimport { RunStatusWriter } from './run-status.js';\nimport type { CompactResult, CompactBoundary } from './types/sessions.js';\nimport type { ImageAttachment, Message, Usage } from './types/messages.js';\nimport type { HeadlessOptions, HeadlessPlanOutcome, HeadlessResult } from './types/public-sdk.js';\nimport type {\n PermissionDecision,\n PlanApprovalResult,\n ToolCall,\n ToolResult,\n UserQuestionRequest,\n UserQuestionResponse,\n} from './types/tools.js';\nimport {\n buildPlanApprovalQuestion,\n planApprovalFromUserQuestionResponse,\n planStopDecision,\n} from './tools/plan-mode.js';\nimport { resolvePrintCommand, type PrintCommandDispatch } from './commands/print-dispatch.js';\nimport { formatGoalStatus } from './agent/goal.js';\nimport type { CommandContext, HostCommandResult } from './types/commands.js';\nimport type { AgentActivity, AgentCompletionNotification } from './agents/types.js';\nimport {\n classifyAbortReason,\n createTerminalOutcome,\n type AgentTerminalOutcome,\n} from './types/terminal.js';\nimport { createAgentRunContext, type AgentRunContext, type AgentRunResult } from './types/runs.js';\nimport { compactionGate, usageAtGate, usagePressureTokens } from './agent/compact.js';\nimport { maskAtGate } from './agent/tool-output-masking.js';\nimport { resolveContextLimit } from './models.js';\nimport type { ToolRegistry } from './tools/registry.js';\nimport { seedObservationLedger } from './tools/file-provenance.js';\nimport { normalizePersistedTodos } from './tools/todo.js';\nimport { estimateUsageCost } from './pricing.js';\nimport { createSessionHistoryTools } from './tools/session-history.js';\nimport {\n createStreamParser,\n type StreamJsonDiagnostic,\n type StreamJsonEvent,\n} from './stream-json.js';\nimport { AgentSession, type AgentSessionRunRequest } from './session/agent-session.js';\nimport { SessionRuntime } from './session/runtime.js';\nimport { seedShellIds } from './jobs/shell-ids.js';\nimport type { AgentEvent } from './session/agent-events.js';\nimport type { CarriedSpend } from './session/run-accounting.js';\nimport {\n buildAgentCompletionMessage,\n takeAgentCompletionBatch,\n} from './agents/completion-notification.js';\nimport { getOrCreateAgentManager } from './agents/manager.js';\nimport { uniqueAgentDisplayName } from './agents/naming.js';\nimport { resolvePermissionMode } from './permission-mode.js';\nimport { separateInlineReasoning } from './reasoning-tags.js';\nimport { getPrimaryArg } from './tools/primary-arg.js';\nimport { toolResultErrorMessage } from './tools/result.js';\nimport { onAbort, throwIfAborted } from './async.js';\nimport { createReaderFlush } from './reader-gone.js';\n\n/**\n * Re-price restored tokens.\n *\n * The tokens are one pool but may have been spent across several models, and the\n * records do not attribute them. Charging the whole pool at the most expensive\n * model's rate keeps the restored total an upper bound — the safe direction for a\n * spend ceiling. Any unpriceable model makes the total unknown.\n */\nfunction carriedCostUsd(usage: Usage, models: readonly string[]): number | null {\n let worst: number | null = null;\n for (const model of models) {\n const quote = estimateUsageCost(model, usage, 'pool');\n if (quote.status !== 'known') return null;\n worst = worst === null ? quote.costUsd : Math.max(worst, quote.costUsd);\n }\n return worst;\n}\n\n/**\n * Read a whole piped prompt for the `text` input format.\n *\n * `-p` has always documented \"reads prompt from the flag or stdin\", but stdin was\n * only consumed for `--input-format stream-json`, so `book -p < prompt.txt` failed\n * on a prompt it had been handed. A long prompt had to be interpolated into argv.\n *\n * A TTY is left alone and reported as no prompt: an interactive `book -p` with no\n * argument would otherwise block on a read the user has no reason to expect,\n * looking like a hang rather than the usage error it is.\n */\nasync function readPipedPrompt(stream: NodeJS.ReadableStream): Promise<string | undefined> {\n if ((stream as NodeJS.ReadStream).isTTY) return undefined;\n const chunks: string[] = [];\n for await (const chunk of stream) {\n chunks.push(typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString('utf8'));\n }\n const prompt = chunks.join('').trim();\n return prompt || undefined;\n}\n\n/**\n * Destroy `stream` when `signal` aborts, so a pending read of a prompt that never\n * finishes arriving rejects instead of holding a cancelled run open. Returns the\n * cleanup.\n */\nfunction destroyOnAbort(\n stream: NodeJS.ReadableStream,\n signal: AbortSignal | undefined,\n): () => void {\n if (!signal) return () => {};\n return onAbort(signal, () => {\n const reason = signal.reason instanceof Error ? signal.reason : new Error('Aborted');\n (stream as NodeJS.ReadableStream & { destroy?: (error?: Error) => void }).destroy?.(reason);\n });\n}\n\n/**\n * Resolve `true` when `promise` settles first and `false` when `signal` aborts first.\n * The promise is left running; only the wait for it ends.\n */\nasync function raceAbort(\n promise: Promise<unknown>,\n signal: AbortSignal | undefined,\n): Promise<boolean> {\n if (!signal) {\n await promise;\n return true;\n }\n if (signal.aborted) return false;\n let release: (() => void) | undefined;\n const aborted = new Promise<false>((resolve) => {\n release = onAbort(signal, () => resolve(false));\n });\n try {\n return await Promise.race([promise.then(() => true as const), aborted]);\n } finally {\n release?.();\n }\n}\n\nexport async function runHeadless(\n config: AgentConfig,\n registry: ToolRegistry,\n opts: HeadlessOptions,\n): Promise<HeadlessResult> {\n const mode = resolvePermissionMode(config.settings, opts.mode);\n const stdout = opts.stdout ?? process.stdout;\n /**\n * The watch for a reader that has gone, and the hold a tool boundary takes on\n * the records it is about to announce (#340). A closed pipe is only noticed on\n * a write, and the notice arrives after the write returns, so a run whose\n * reader left during a silent turn — nothing written, nothing to report it —\n * used to execute the calls of a turn it had already paid for.\n *\n * `stream-json` on a real stream is the only case: a `text` or `json` answer\n * is written once, at the end, and a host that passed a bare `{ write }` sink\n * has no callback to report a failure through. Everything else keeps exactly\n * the path it had.\n */\n const flush = opts.outputFormat === 'stream-json' ? createReaderFlush(stdout) : undefined;\n /**\n * The run's signal. Composed, not replaced, so a caller abort reads exactly\n * as it did before — and a reader-gone abort carries no reason, the same as\n * the closed-pipe abort in `cli/run.ts`, so the two classify alike and leave\n * the same exit code.\n */\n const runSignal =\n flush && opts.signal\n ? AbortSignal.any([opts.signal, flush.signal])\n : (flush?.signal ?? opts.signal);\n const emit = (obj: unknown) => {\n if (obj && typeof obj === 'object' && 'type' in obj) {\n opts.onEvent?.(obj as StreamJsonEvent);\n }\n const line = JSON.stringify(obj) + '\\n';\n if (flush) flush.write(line);\n else stdout.write(line);\n };\n /**\n * What the event printers remember across one run: the managed children's\n * progress labels, which arrive once each on `agent_start` and are read by every\n * later `agent_activity`, and whether an error has already been reported.\n */\n const eventState: HeadlessEventState = {\n childLabels: new Map<string, string>(),\n errorReported: false,\n };\n /** Set once the run's liveness file exists; released in the outer `finally`. */\n let disposeCrashHandlers: (() => void) | undefined;\n let sessionDisposed = false;\n /** The session SessionStart ran for, so a run that throws on abort still ends it. */\n let startedSessionId: string | undefined;\n const agentSession = new AgentSession({\n runtime: new SessionRuntime(),\n });\n /**\n * Stop the run's children, background shells and timers. SessionEnd runs after this,\n * never before: on an aborted run the children otherwise kept working for up to 10 s\n * per SessionEnd hook (#248). Idempotent; the outer `finally` calls it too.\n */\n const disposeSession = (): void => {\n if (sessionDisposed) return;\n sessionDisposed = true;\n agentSession.dispose('headless_complete');\n };\n const runtime = agentSession.getRuntime();\n // Seed the plan from the resumed session. Both lists are mutated in place by\n // their tools, so pushing into the runtime's arrays is what makes the plan\n // visible to the loop — reassigning would detach the runtime from the\n // ToolContext the loop seeds from.\n runtime.todos.push(...normalizePersistedTodos(opts.plan?.todos));\n if (opts.plan?.tasks?.length) runtime.tasks.push(...opts.plan.tasks);\n // An unmet `/goal` the resumed session recorded keeps being checked at each stop.\n agentSession.restoreGoal(opts.goal);\n // Resuming prior work with nothing to show for it is the case worth naming: an\n // empty list renders as no list at all, so without this the model cannot tell a\n // dropped plan from a task that never had one.\n // `plan === undefined` means no plan record was ever written — an ordinary\n // conversation that never called TodoWrite. Reporting that as \"your plan did not\n // survive\" told every such resumed session to rebuild a plan it never had, and\n // pushed the model to invent one. Only a record that came back empty is a loss.\n runtime.planUnrestored = planWasLost({\n planRecordExisted: opts.plan !== undefined,\n priorMessages: opts.history.length,\n todos: runtime.todos.length,\n tasks: runtime.tasks.length,\n });\n seedShellIds(runtime.backgroundShells, opts.transcript ?? opts.history, opts.history);\n\n try {\n if (opts.outputFormat === 'stream-json') {\n emit({ type: 'system', model: config.model, cwd: config.workspace });\n }\n\n // Resolve or create a session for persistence.\n const store = opts.persistSession === false ? undefined : opts.sessionStore;\n let sessionId = opts.sessionId;\n if (store && !sessionId && opts.sessionName) {\n sessionId = store.findByName(opts.sessionName)?.id;\n }\n if (store && sessionId && opts.forkSession) {\n sessionId = undefined; // start a new session, copy history only\n }\n let sessionName = opts.sessionName;\n let sessionCreated = opts.sessionCreated === true;\n if (store && !sessionId) {\n sessionId = store.create({\n cwd: config.workspace,\n name: sessionName,\n driver: config.sessionDriver,\n });\n sessionCreated = true;\n }\n if (store && sessionId && !sessionName) {\n sessionName = store.findById(sessionId)?.name;\n }\n if (sessionCreated && sessionId && opts.outputFormat === 'stream-json') {\n emit({ type: 'session', session_id: sessionId });\n }\n if (store && sessionId) {\n registry.registerAll(\n createSessionHistoryTools({ store, sessionId: () => sessionId as string }),\n );\n }\n\n if (sessionId) {\n await agentSession.startLifecycle(\n config,\n sessionId,\n opts.history.length > 0 ? 'resume' : 'startup',\n {\n onHookEvent: createHookEventHandler(opts, emit),\n },\n );\n startedSessionId = sessionId;\n }\n const runtimeSessionId = sessionId ?? crypto.randomUUID();\n\n // The run's liveness file. Headless is the host that most needs it: the\n // default `--output-format text` emits nothing at all until termination, so\n // without this an unattended run is completely opaque while it works. Owned\n // here rather than in the loop because subagents and managed agents call the\n // loop directly and must not each claim to be \"the run\".\n const statusWriter = new RunStatusWriter({\n sessionId: runtimeSessionId,\n runId: runtimeSessionId,\n workspace: config.workspace,\n budgetUsd: opts.maxBudgetUsd,\n startedAt: Date.now(),\n });\n disposeCrashHandlers = statusWriter.installCrashHandlers();\n\n // Headless permission policy: if a prompt would be shown and no rule resolves\n // it, deny the tool — headless can't interactively prompt — and say so, so the\n // refusal names that cause rather than a policy (#264). Callers who want full\n // autonomy should pass mode: 'auto' or 'bypassPermissions'.\n const permissionRequired = async (): Promise<PermissionDecision> => ({\n result: 'deny',\n reason: 'no_approver',\n });\n\n // The one interactive escape hatch this host has. Everything that needs a\n // human decision (AskUserQuestion, plan approval) goes through it, so\n // `userQuestionStatus` describes both.\n const userQuestionStatus = opts.onUserQuestionRequired ? 'pending' : 'unavailable';\n const askUser = async (\n request: UserQuestionRequest,\n context: { signal?: AbortSignal },\n ): Promise<UserQuestionResponse> => {\n try {\n return opts.onUserQuestionRequired\n ? await opts.onUserQuestionRequired(request, context)\n : {\n action: 'decline',\n message: 'User input is unavailable in non-interactive mode.',\n };\n } catch (error) {\n return {\n action: 'cancel',\n message: `User question handler failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n };\n\n /**\n * Plan approval without a terminal. `bypassPermissions` still auto-approves.\n * A host that supplied a question handler answers the plan through it. A\n * host with no handler cannot approve anything, so the run stops at the\n * first plan instead of retrying ExitPlanMode until --max-turns is gone.\n */\n const decidePlanApproval = async (plan: string): Promise<PlanApprovalResult> => {\n if (mode === 'bypassPermissions') return 'approve';\n if (!opts.onUserQuestionRequired) return planStopDecision('approval_unavailable');\n const request = buildPlanApprovalQuestion(plan, crypto.randomUUID());\n emitAgentEvent(\n { type: 'user_question', request, status: userQuestionStatus },\n opts,\n emit,\n eventState,\n );\n const response = await askUser(request, { signal: runSignal });\n emitAgentEvent(\n { type: 'user_question_result', requestId: request.id, response },\n opts,\n emit,\n eventState,\n );\n return planApprovalFromUserQuestionResponse(request, response);\n };\n /**\n * Set once a plan ends the run because this host could not approve it. Held\n * in a box: the plan-approval callback assigns it from a closure, and a\n * plain `let` would still read as `null` at the output sites below.\n */\n const planNotApplied: { outcome?: HeadlessPlanOutcome } = {};\n\n let lastUsage: Usage | null = null;\n let lastOutcome: AgentTerminalOutcome | null = null;\n /**\n * Whether an abort may reclassify the run as cancelled when it ends a wait\n * for managed children. Set once the prompts are done, and only ever false\n * when the run's last turn failed: a failure is what went wrong, whatever\n * arrived afterwards (#248).\n */\n let mayReclassify = true;\n /** The opening message of the latest model run: the answer is read from that run only. */\n let finalRunOpeningId: string | undefined;\n const runResults: AgentRunResult[] = [];\n const recordRunResult = (result: AgentRunResult): void => {\n const existing = runResults.findIndex(\n (candidate) => candidate.context.runId === result.context.runId,\n );\n if (existing >= 0) runResults[existing] = result;\n else runResults.push(result);\n };\n const recordManagedRunResult = (\n agent: Extract<AgentEvent, { type: 'agent_result' }>['agent'],\n ): void => {\n if (!agent.runId) return;\n const context = createAgentRunContext({\n sessionId: agent.parentSessionId ?? runtimeSessionId,\n runId: agent.runId,\n rootRunId: agent.rootRunId ?? agent.runId,\n parentRunId: agent.parentRunId,\n source: 'internal',\n startedAt: agent.runStartedAt ?? agent.startedAt ?? agent.createdAt,\n });\n const outcome =\n agent.runOutcome ??\n (agent.status === 'completed'\n ? createTerminalOutcome('completed', 'normal_completion', { partialOutput: false })\n : createTerminalOutcome('failed', 'runtime_error', {\n partialOutput: Boolean(agent.result),\n message: agent.error ?? `Managed agent ended with status ${agent.status}.`,\n }));\n recordRunResult({\n context,\n outcome,\n usage: agent.runUsage ?? null,\n accounting: runtime.runAccounting.snapshotRun(agent.runId),\n ambient: runtime.snapshotRunAmbient(agent.runId),\n });\n };\n const recordManagedCompletionResult = (notification: AgentCompletionNotification): void => {\n if (\n !notification.runId ||\n runResults.some((candidate) => candidate.context.runId === notification.runId)\n )\n return;\n const completion = notification.completion;\n const outcome =\n notification.outcome ??\n (completion.status === 'completed'\n ? createTerminalOutcome('completed', 'normal_completion', { partialOutput: false })\n : completion.status === 'stopped'\n ? createTerminalOutcome('cancelled', 'user_cancelled', {\n partialOutput: Boolean(completion.summary),\n message: completion.error,\n })\n : completion.status === 'interrupted'\n ? createTerminalOutcome('interrupted', 'transport_interrupted', {\n partialOutput: Boolean(completion.summary),\n message: completion.error,\n })\n : createTerminalOutcome('failed', 'runtime_error', {\n partialOutput: Boolean(completion.summary),\n message: completion.error,\n }));\n recordRunResult({\n context: createAgentRunContext({\n sessionId: notification.parentSessionId ?? runtimeSessionId,\n runId: notification.runId,\n rootRunId: notification.rootRunId ?? notification.runId,\n parentRunId: notification.parentRunId,\n source: 'internal',\n startedAt: completion.startedAt ?? completion.createdAt,\n }),\n outcome,\n usage: completion.usage ?? null,\n accounting: runtime.runAccounting.snapshotRun(notification.runId),\n ambient: runtime.snapshotRunAmbient(notification.runId),\n });\n };\n const rootContexts = new Map<string, AgentRunContext>();\n let lastHostCompactAttemptKey: string | null = null;\n const contextHistory: Message[] = [...opts.history];\n const transcript: Message[] = [...(opts.transcript ?? opts.history)];\n const compactBoundaries: CompactBoundary[] = [...(opts.compactBoundaries ?? [])];\n seedObservationLedger(runtime.fileObservationLedger, transcript);\n\n const loopConfig: AgentConfig = {\n ...config,\n maxTurns: opts.maxTurns ?? config.maxTurns,\n };\n const createRunCallbacks = (\n runContext: AgentRunContext,\n onOutcome: (outcome: AgentTerminalOutcome) => void,\n ): AgentSessionRunRequest['callbacks'] => ({\n onEvent: (event) => {\n if (event.type === 'agent_result') recordManagedRunResult(event.agent);\n if (event.type === 'terminal') {\n lastOutcome = event.outcome;\n onOutcome(event.outcome);\n }\n emitAgentEvent(event, opts, emit, eventState);\n },\n // No header rewrite at turn boundaries: load() derives updatedAt from\n // the last appended record, so the on-disk header is never authoritative.\n onTurnStart: () => {},\n onDone: () => {},\n onPermissionRequired: permissionRequired,\n onModeChange: (newMode) => {\n if (opts.outputFormat === 'stream-json') {\n emit({ type: 'mode_change', mode: newMode });\n }\n },\n /**\n * The hold at a tool boundary. The `tool_use` records for the calls about\n * to run have been written by now, so waiting for them to be taken is\n * what turns a reader that has gone into an abort BEFORE the call runs\n * (#340) instead of one call later. Free when the reader has caught up,\n * bounded when it has not, and absent — so a no-op — for every other\n * output format and for a host sink with no callback to answer.\n */\n beforeToolExecution: flush ? () => flush.hold(runSignal) : undefined,\n onPlanApprovalRequired: async (plan) => {\n const decision = await decidePlanApproval(plan);\n if (typeof decision === 'object' && decision.decision === 'stop') {\n planNotApplied.outcome = {\n status: 'not_applied',\n reason: decision.reason,\n plan,\n message: decision.message,\n };\n }\n if (opts.outputFormat === 'stream-json') {\n emit({ type: 'plan_approval', status: planApprovalStatus(decision) });\n }\n return decision;\n },\n onUserQuestionRequired: askUser,\n userQuestionStatus,\n onRetry: (phase, attempt, max, delayMs, reason) => {\n // `max` is -1 when retries are unbounded (the watchdog); the wire says null.\n const limit = max < 0 ? null : max;\n if (opts.outputFormat === 'stream-json') {\n emit({\n type: 'retry',\n phase,\n attempt,\n max: limit,\n delay_ms: delayMs,\n ...(reason ? { reason } : {}),\n });\n } else if (opts.quiet !== true) {\n process.stderr.write(\n `retry: ${phase} attempt ${attempt}${limit !== null ? `/${limit}` : ''} in ${Math.round(delayMs / 1000)}s${reason ? ` (${reason})` : ''}\\n`,\n );\n }\n },\n onHookEvent: createHookEventHandler(opts, emit),\n onUsage: (nextUsage) => {\n lastUsage = nextUsage;\n lastHostCompactAttemptKey = null;\n },\n onCompact: async (history, usage, hints) => {\n const outcome = await agentSession.compact({\n config,\n history,\n compactBoundaries,\n sessionId,\n transcriptOrdinal: transcript.length,\n runContext,\n runtime,\n timelineStore: store,\n onCommitted: (_result, boundary) => compactBoundaries.push(boundary),\n options: {\n ...hints,\n trigger: 'auto',\n preContextTokens: usage ? usagePressureTokens(usage) : undefined,\n signal: runSignal,\n onHookEvent: createHookEventHandler(opts, emit),\n },\n });\n if (outcome.result.status === 'compacted') {\n emitCompactBoundary(opts.outputFormat, emit, outcome.result);\n lastUsage = null;\n }\n return outcome.result;\n },\n // Deferred compaction (plans/async-compaction-plan.md): same plumbing,\n // reducer on the snapshot first, judge and record at the next boundary.\n prepareCompact: async (snapshot, usage, hints) => {\n const outcome = await agentSession.prepareCompact({\n config,\n history: snapshot,\n compactBoundaries,\n sessionId,\n transcriptOrdinal: transcript.length,\n runContext,\n runtime,\n options: {\n ...hints,\n trigger: 'auto',\n preContextTokens: usage ? usagePressureTokens(usage) : undefined,\n signal: hints?.signal ?? runSignal,\n onHookEvent: createHookEventHandler(opts, emit),\n },\n });\n return outcome.status === 'prepared' ? outcome.prepared : outcome.result;\n },\n commitCompact: async (prepared, history, hints) => {\n const outcome = await agentSession.commitCompact({\n prepared,\n history,\n config,\n sessionId,\n transcriptOrdinal: transcript.length,\n runContext,\n runtime,\n timelineStore: store,\n onCommitted: (_result, boundary) => compactBoundaries.push(boundary),\n options: {\n signal: hints?.signal ?? runSignal,\n onHookEvent: createHookEventHandler(opts, emit),\n },\n });\n if (outcome.result.status === 'compacted') {\n emitCompactBoundary(opts.outputFormat, emit, outcome.result);\n lastUsage = null;\n }\n return outcome.result;\n },\n onAssistantMessageComplete: (message) => {\n if (!transcript.some((item) => item.id === message.id)) transcript.push(message);\n // The completed turn, always. `--include-partial-messages` adds the deltas\n // on top of this; it does not decide whether the stream carries assistant\n // text at all. Emitting only deltas made the flag load-bearing for the\n // basic contract, which is why leaving it off had to mean \"maximum volume\".\n if (opts.outputFormat === 'stream-json' && message.content) {\n // A host notice is what Book said, not what the model answered, and the\n // wire has to say so: the record's shape is otherwise indistinguishable\n // from an ordinary reply (#248).\n emit({\n type: 'assistant',\n text: message.content,\n complete: true,\n ...(message.hostNotice ? { host_notice: true } : {}),\n });\n }\n },\n });\n const runParentTurn = async (\n prompt: string,\n displayMessage: string,\n userMessage: Message,\n runContext: AgentRunContext,\n commandContext?: CommandContext,\n typedText?: string,\n ): Promise<void> => {\n // An earlier prompt's error must not hide why this one failed.\n eventState.errorReported = false;\n let runOutcome: AgentTerminalOutcome | undefined;\n finalRunOpeningId = userMessage.id;\n lastUsage = null;\n let updated: Message[];\n try {\n updated = await agentSession.run({\n config: loopConfig,\n registry,\n prompt,\n history: contextHistory,\n compactBoundaries,\n mode,\n sessionId: runtimeSessionId,\n timelineStore: store,\n signal: runSignal,\n callbacks: createRunCallbacks(runContext, (outcome) => {\n runOutcome = outcome;\n }),\n runContext,\n maxBudgetUsd: opts.maxBudgetUsd,\n options: {\n displayMessage,\n userMessageId: userMessage.id,\n userMessageTimestamp: userMessage.timestamp,\n userFileObservations: userMessage.fileObservations,\n userAttachments: userMessage.attachments,\n userMessageKind: userMessage.kind,\n // The answer walk is bounded by `openingMessageId`, so a derived opening\n // message no longer lets it walk past the run.\n userMessageDerived: userMessage.derivedContent,\n manageSessionHooks: sessionId ? false : undefined,\n // Completion messages are host-generated notifications, not user\n // prompts. Keep UserPromptSubmit hooks from rewriting or blocking them.\n skipUserPromptHooks: userMessage.kind === 'agent-notification',\n parentSessionId: runtimeSessionId,\n runContext,\n runtime,\n // Only what the user typed invokes a skill by `$name`, as in the TUI.\n typedText,\n // Command frontmatter enforcement, exactly as the TUI passes it.\n allowedTools: commandContext?.allowedTools,\n modelOverride: commandContext?.modelOverride,\n commands: commandContext ? [commandContext.command] : undefined,\n statusWriter,\n // No human can resolve a permission prompt here: `permissionRequired`\n // answers `deny` unconditionally.\n unattended: true,\n },\n });\n } catch (error) {\n const failedOutcome =\n runOutcome ??\n createTerminalOutcome('interrupted', 'missing_terminal', { partialOutput: false });\n recordRunResult({\n context: runContext,\n outcome: failedOutcome,\n usage: runtime.runAccounting.snapshotRun(runContext.runId)?.directUsage ?? lastUsage,\n accounting: runtime.runAccounting.snapshotRun(runContext.runId),\n ambient: runtime.snapshotRunAmbient(runContext.runId),\n });\n throw error;\n }\n const priorIds = new Set(transcript.map((message) => message.id));\n transcript.push(\n ...updated.filter((message) => !priorIds.has(message.id) && message.role === 'assistant'),\n );\n contextHistory.length = 0;\n contextHistory.push(...updated);\n const turnOutcome =\n runOutcome ??\n createTerminalOutcome('interrupted', 'missing_terminal', {\n partialOutput: updated.some((message) => message.role === 'assistant'),\n });\n recordRunResult({\n context: runContext,\n outcome: turnOutcome,\n usage: runtime.runAccounting.snapshotRun(runContext.runId)?.directUsage ?? lastUsage,\n accounting: runtime.runAccounting.snapshotRun(runContext.runId),\n ambient: runtime.snapshotRunAmbient(runContext.runId),\n });\n };\n\n /**\n * Expand one submitted line's leading `/command` through the same\n * registries and the same `resolveCommandBody` the TUI uses. A command\n * whose effect this host cannot perform throws\n * `UnsupportedPrintCommandError` instead of reaching the model as a\n * literal \"/name\" string.\n *\n * `runContext` is the root this line is accounted under — the same one a\n * model turn for it would use — so a command the host performs by spawning\n * agents is billed and budget-checked exactly like a turn.\n */\n const dispatchSubmittedPrompt = (\n submitted: string,\n runContext: AgentRunContext,\n ): Promise<PrintCommandDispatch> =>\n opts.expandSlashCommands === false\n ? Promise.resolve({ kind: 'passthrough', prompt: submitted })\n : resolvePrintCommand(submitted, {\n config,\n mode,\n sessionId: runtimeSessionId,\n signal: runSignal,\n agents: {\n // Built only when an agent-backed command (`/review`) asks for it,\n // and attached to this session's runtime so it is disposed with the\n // run. Its events join the same stream-json output as the main loop,\n // and its finished runs land in `runs` like any other execution.\n manager: () =>\n getOrCreateAgentManager(config, registry.getDefinitions(), {\n runtime,\n permissionMode: mode,\n eventSink: (event) => {\n if (event.type === 'agent_result') recordManagedRunResult(event.agent);\n emitAgentEvent(event, opts, emit, eventState);\n },\n hookEventSink: createHookEventHandler(opts, emit),\n }),\n runContext,\n },\n goal: {\n get: () => agentSession.getGoal(),\n set: (condition) => {\n agentSession.setGoal(condition, goalTarget());\n },\n clear: () => agentSession.clearGoal(goalTarget()),\n },\n });\n\n /** Where a `/goal` change is recorded: the persisted session, when there is one. */\n const goalTarget = () => ({\n sessionId,\n timelineStore: store && sessionId ? store : undefined,\n });\n\n /**\n * Slash commands the host performed itself, in submission order. A run made\n * only of those never produces a turn outcome, and reporting it as\n * `interrupted` would tell a machine caller that a review which completed\n * had been cut short.\n */\n const commandResults: HostCommandResult[] = [];\n /**\n * Inclusive spend of the most recent host-performed command — the same\n * \"latest unit of work\" `lastUsage` reports for a model turn.\n *\n * Kept separate rather than folded into `lastUsage`, which drives the\n * cross-turn compaction decision: a review's child-agent totals were never\n * in the parent's context window, and adding them there would compact the\n * parent history against tokens it does not hold.\n */\n let commandUsage: Usage | null = null;\n\n // Collect prompts: text input -> single prompt, from the flag or stdin;\n // stream-json -> read stdin.\n const prompts: string[] = [];\n if (opts.inputFormat === 'text') {\n let prompt = opts.prompt;\n if (prompt === undefined) {\n const stream = opts.stdin ?? process.stdin;\n // A prompt that never finishes arriving must not hold a cancelled run open.\n // A TTY returns at once inside `readPipedPrompt`, so it is never destroyed.\n const release = destroyOnAbort(stream, runSignal);\n try {\n prompt = await readPipedPrompt(stream);\n } finally {\n release();\n }\n throwIfAborted(runSignal);\n }\n if (!prompt) {\n throw new Error(\n 'print mode requires a prompt: pass one to -p, pipe one on stdin, or use --input-format stream-json',\n );\n }\n prompts.push(prompt);\n } else {\n // stream-json input: newline-delimited {type:'user', content} from stdin.\n const stream = opts.stdin ?? process.stdin;\n const diagnostics: StreamJsonDiagnostic[] = [];\n const parser = createStreamParser(\n (event) => {\n if (event.type === 'user') prompts.push(event.content);\n },\n {\n maxBufferedLineBytes: opts.maxInputLineBytes,\n onDiagnostic: (diagnostic) => diagnostics.push(diagnostic),\n },\n );\n const release = destroyOnAbort(stream, runSignal);\n try {\n for await (const chunk of stream) {\n parser.feed(chunk as string | Buffer);\n }\n } finally {\n release();\n }\n throwIfAborted(runSignal);\n parser.flush();\n if (diagnostics.length > 0) throw new Error(diagnostics[0]?.message);\n if (opts.prompt) prompts.unshift(opts.prompt);\n }\n\n // A USD cap has to bound the OBJECTIVE, not one prompt. Every submitted line\n // mints a fresh root and `startRoot` seeds the full cap into it, so a hundred\n // stream-json prompts under a $50 cap would authorise $5000 inside a single\n // process. Carry the accumulated spend into each subsequent root through the\n // same seam that already carries it across processes.\n //\n // A carry restored from disk names no `persistedUsage`: the `usage` records it\n // was summed from already cover all of it. Each later carry in this process is\n // an in-process total, so it brings the watermark its root actually reached.\n let carriedSpend: CarriedSpend | undefined = opts.carriedUsage\n ? {\n usage: opts.carriedUsage,\n costUsd: carriedCostUsd(\n opts.carriedUsage,\n opts.carriedModels?.length ? opts.carriedModels : [config.model],\n ),\n }\n : undefined;\n\n for (const submitted of prompts) {\n // The run exists before dispatch, not after it. A host-performed command\n // spawns managed agents of its own, and those agents are only budgeted and\n // accounted when they are spawned under a root that already carries\n // `maxBudgetUsd` — resolving the command first would leave `/review`\n // spending outside every cap the caller set.\n const runId = crypto.randomUUID();\n const runContext = createAgentRunContext({\n sessionId: runtimeSessionId,\n runId,\n source: opts.runSource ?? 'headless',\n resumedFromRunId:\n runResults.length === 0\n ? (opts.resumedFromRunId ??\n (opts.history.length > 0\n ? [...opts.history].reverse().find((message) => message.role === 'user')?.id\n : undefined))\n : undefined,\n });\n runtime.runAccounting.startRoot(runContext, opts.maxBudgetUsd);\n // The root exists before a turn does, so the session can persist its spend\n // even when no turn ever runs under it: a `/review` performed by the host\n // spends entirely in its reviewer agents, and no response of the root will\n // ever report it (#336).\n if (store && sessionId) {\n agentSession.trackRunUsage(runContext.rootRunId, { sessionId, timelineStore: store });\n }\n // Carry spend forward from earlier processes of this session, so a USD cap\n // bounds the objective rather than one process.\n if (carriedSpend) {\n runtime.runAccounting.seedRoot(runContext.rootRunId, carriedSpend);\n }\n\n const dispatch = await dispatchSubmittedPrompt(submitted, runContext);\n if (dispatch.kind === 'prompt' && dispatch.shellErrors?.length) {\n // The TUI drops these silently; a non-interactive host that swallowed\n // them would ship \"[shell error: …]\" into the prompt with no trace.\n for (const shellError of dispatch.shellErrors) {\n process.stderr.write(`warning: ${shellError}\\n`);\n }\n }\n if (dispatch.kind === 'handled') {\n // The effect handler already did the work: no model turn for this line.\n const handled: HostCommandResult = {\n command: dispatch.command,\n output: dispatch.output,\n data: dispatch.data,\n };\n commandResults.push(handled);\n const accounting = runtime.runAccounting.snapshotRoot(runContext.rootRunId);\n commandUsage = accounting.inclusiveUsage ?? commandUsage;\n recordRunResult({\n context: runContext,\n outcome: createTerminalOutcome('completed', 'normal_completion', {\n partialOutput: false,\n }),\n // The host itself made no provider call; everything spent here was\n // spent by the agents this command ran, which is the inclusive figure.\n usage: accounting.inclusiveUsage,\n accounting,\n ambient: runtime.snapshotRunAmbient(runContext.runId),\n });\n if (opts.outputFormat === 'text') {\n if (dispatch.output) stdout.write(`${dispatch.output}\\n`);\n } else if (\n opts.outputFormat === 'stream-json' &&\n (dispatch.output !== undefined || dispatch.data !== undefined)\n ) {\n // One record carries both renderings: `output` for a human reading the\n // stream, `data` for the machine contract (see review/host.ts).\n // Only on the line-delimited wire: `json` is a single-document format,\n // and a second top-level object there breaks `JSON.parse(stdout)`.\n emit({ type: 'command_result', ...handled });\n }\n // A handled command spent real money — a `/review`'s reviewer agents are\n // the whole cost of the line — so the carry has to move with it. Leaving\n // it naming the previous prompt's root made every later prompt re-seed a\n // STALE total that still credited the old root: the handled command's own\n // spend was missing from the next root's budget, and re-seeding the old\n // root re-stamped its hand-over floor against a total it had not passed on.\n carriedSpend = {\n usage: accounting.inclusiveUsage,\n costUsd: accounting.inclusiveCostUsd,\n persistedUsage: runtime.runAccounting.persistedUsage(runContext.rootRunId),\n fromRootRunId: runContext.rootRunId,\n };\n continue;\n }\n const prompt = dispatch.prompt;\n const commandContext = dispatch.kind === 'prompt' ? dispatch.commandContext : undefined;\n const userMessage: Message = {\n id: runId,\n role: 'user',\n content: prompt,\n // With a command context, `prompt` is a resolved command body, not typed\n // input -- repository-authored for a project command. Marking it keeps\n // print and SDK runs on the same footing as the TUI.\n derivedContent: commandContext ? true : undefined,\n includeInContext: true,\n kind: 'conversation',\n timestamp: Date.now(),\n };\n\n // Cross-turn auto-compact before appending the new user message -- masking\n // first, as in the loop: when it alone brings the last request's count\n // under the gate, nothing is summarized.\n if (config.autoCompactEnabled !== false && usageAtGate(lastUsage, config)) {\n const pressure = usagePressureTokens(lastUsage);\n const gate = compactionGate(config);\n const masked = maskAtGate(contextHistory, gate, pressure, gate);\n if (masked.maskedCount > 0) {\n contextHistory.length = 0;\n contextHistory.push(...masked.history);\n if (masked.underLine) lastUsage = null;\n }\n }\n const contextLimit = resolveContextLimit(config);\n const hostCompactAttemptKey = `${usagePressureTokens(lastUsage)}:${contextHistory.length}`;\n if (\n config.autoCompactEnabled !== false &&\n contextLimit != null &&\n usageAtGate(lastUsage, config) &&\n lastHostCompactAttemptKey !== hostCompactAttemptKey\n ) {\n lastHostCompactAttemptKey = hostCompactAttemptKey;\n try {\n const outcome = await agentSession.compact({\n config,\n history: contextHistory,\n compactBoundaries,\n sessionId,\n transcriptOrdinal: transcript.length,\n runContext,\n runtime,\n timelineStore: store,\n onCommitted: (compactResult, boundary) => {\n contextHistory.length = 0;\n contextHistory.push(...compactResult.replacementHistory);\n compactBoundaries.push(boundary);\n lastUsage = null;\n },\n options: {\n trigger: 'auto',\n preContextTokens: usagePressureTokens(lastUsage),\n signal: runSignal,\n upcomingUserIntent: prompt,\n onHookEvent: createHookEventHandler(opts, emit),\n },\n });\n if (outcome.result.status === 'compacted') {\n emitCompactBoundary(opts.outputFormat, emit, outcome.result);\n }\n } catch {\n // non-fatal\n }\n }\n\n const recorded = await agentSession.recordUserMessage({\n config,\n sessionId: runtimeSessionId,\n displayMessage: prompt,\n userMessage,\n sessionName,\n sessionNameSource: dispatch.kind === 'prompt' ? dispatch.sessionNameSource : undefined,\n timelineStore: store && sessionId ? store : undefined,\n expandShellInput: false,\n projectCommand: dispatch.kind === 'prompt' ? dispatch.projectCommand : undefined,\n runtime,\n signal: runSignal,\n });\n // A mention left as written is reported, on stderr like the shell errors above, so the\n // user knows why a file did not reach the turn (#567).\n for (const notice of recorded.mentionNotices) process.stderr.write(`${notice}\\n`);\n sessionName = recorded.sessionName;\n const contextMessage = recorded.contextMessage;\n transcript.push(userMessage);\n rootContexts.set(runContext.rootRunId, runContext);\n await runParentTurn(\n contextMessage,\n prompt,\n userMessage,\n runContext,\n commandContext,\n // What the user typed is the line they submitted, whatever it resolved to: a command's\n // body or a built-in command's prompt is not.\n submitted,\n );\n // Fold this prompt's inclusive spend into the carry so the next root starts\n // where this one finished instead of back at zero — along with how much of it\n // a record already covers. The total can run ahead of the records: a\n // background agent or a compaction judge can spend after this root's last\n // `onUsage`, and a continuation the budget gate refused is charged but never\n // reported. Seeding the next root's watermark with the whole total would\n // skip that remainder for good, so the next root's first record writes it.\n const spentSoFar = runtime.runAccounting.snapshotRoot(runContext.rootRunId);\n carriedSpend = {\n usage: spentSoFar.inclusiveUsage,\n costUsd: spentSoFar.inclusiveCostUsd,\n persistedUsage: runtime.runAccounting.persistedUsage(runContext.rootRunId),\n // Naming the root the totals came from: the next root's first record\n // carries this one's remainder, so this one is closed rather than left to\n // write the same tokens a second time at the end of the session (#336).\n fromRootRunId: runContext.rootRunId,\n };\n // An unapprovable plan is the deliverable: queued prompts would only\n // re-plan against a workspace nothing is allowed to change.\n if (planNotApplied.outcome) break;\n }\n\n // Background children outlive the root tool call. Keep the runtime alive,\n // feed each completion back through the parent model, and acknowledge only\n // after that continuation turn succeeds.\n const managedAgentManager = planNotApplied.outcome ? undefined : runtime.agentManager;\n if (managedAgentManager) {\n const deliveredCompletionIds = new Set(\n transcript.flatMap((message) =>\n (message.agentNotifications ?? [])\n .map((notification) => notification.deliveryId)\n .filter((id): id is string => Boolean(id)),\n ),\n );\n while (true) {\n // Waiting for active children is the one place an abort reclassifies the\n // run: a reader that goes away after the last turn already ended — after\n // it failed, most of all — changes nothing about how that run ended.\n const idle =\n !runSignal?.aborted && (await raceAbort(managedAgentManager.waitForIdle(), runSignal));\n if (!idle) {\n if (mayReclassify) lastOutcome = classifyAbortReason(runSignal?.reason, true);\n break;\n }\n const pending = (await managedAgentManager.listPendingCompletions()).filter(\n (notification) => notification.parentSessionId === runtimeSessionId,\n );\n if (pending.length === 0) break;\n const alreadyDelivered = pending.filter((notification) =>\n deliveredCompletionIds.has(notification.deliveryId),\n );\n for (const notification of alreadyDelivered) {\n await managedAgentManager.acknowledgeCompletion(notification.deliveryId);\n }\n const fresh = pending.filter(\n (notification) => !deliveredCompletionIds.has(notification.deliveryId),\n );\n if (fresh.length === 0) continue;\n const firstRootRunId = fresh[0]?.rootRunId;\n const sameRoot = firstRootRunId\n ? fresh.filter((notification) => notification.rootRunId === firstRootRunId)\n : fresh;\n const batch = takeAgentCompletionBatch(sameRoot);\n for (const notification of batch) recordManagedCompletionResult(notification);\n const built = batch.map((notification: AgentCompletionNotification) =>\n buildAgentCompletionMessage(notification),\n );\n const displayMessage = built.map((item) => item.displayMessage).join('\\n');\n const userMessage: Message = {\n id: crypto.randomUUID(),\n role: 'user',\n content: displayMessage,\n contextContent: built.map((item) => item.contextMessage).join('\\n'),\n includeInContext: true,\n kind: 'agent-notification',\n agentNotifications: built.map((item) => item.display),\n timestamp: Date.now(),\n };\n const recorded = await agentSession.recordUserMessage({\n config,\n sessionId: runtimeSessionId,\n displayMessage,\n contextMessage: userMessage.contextContent,\n userMessage,\n // The local name is deliberately not reassigned from the result: a\n // notification never names the session (#446).\n sessionName,\n timelineStore: store && sessionId ? store : undefined,\n expandShellInput: false,\n runtime,\n signal: runSignal,\n });\n transcript.push(userMessage);\n const parentContext = batch[0]?.rootRunId\n ? rootContexts.get(batch[0].rootRunId)\n : undefined;\n const runContext = createAgentRunContext({\n sessionId: runtimeSessionId,\n source: opts.runSource ?? 'headless',\n rootRunId: parentContext?.rootRunId ?? batch[0]?.rootRunId,\n parentRunId: batch[0]?.runId ?? parentContext?.runId,\n });\n if (parentContext) rootContexts.set(runContext.rootRunId, parentContext);\n else rootContexts.set(runContext.rootRunId, runContext);\n await runParentTurn(recorded.contextMessage, displayMessage, userMessage, runContext);\n for (const notification of batch) {\n deliveredCompletionIds.add(notification.deliveryId);\n await managedAgentManager.acknowledgeCompletion(notification.deliveryId);\n }\n }\n }\n\n const outcome =\n lastOutcome ??\n (commandResults.length > 0\n ? createTerminalOutcome('completed', 'normal_completion', { partialOutput: false })\n : createTerminalOutcome('interrupted', 'missing_terminal', {\n partialOutput: transcript.some((message) => message.role === 'assistant'),\n }));\n runResults.sort((left, right) => left.context.startedAt - right.context.startedAt);\n // A run made only of host-performed commands has no last turn, so reporting\n // `null` would say \"this cost nothing\" about work that really spent tokens.\n const reportedUsage = lastUsage ?? commandUsage;\n // A turn that failed failed: an abort afterwards is a reader going away, a\n // cancel, or a timeout, and none of them is what went wrong (#248).\n mayReclassify = lastOutcome?.status !== 'failed';\n // No model turn in this process (a run of host-performed commands, such as\n // `book -p --continue \"/review\"`) has no answer: the walk would otherwise read the\n // previous process's answer out of the resumed history (#248).\n const lastText =\n finalRunOpeningId === undefined ? '' : finalAnswerText(contextHistory, finalRunOpeningId);\n // Only a reply that opened with a closed reasoning block is rewritten. Any other\n // answer is kept exactly as the model wrote it, so an indented first line (YAML,\n // code piped to a file) keeps its indent.\n const inline = separateInlineReasoning(lastText);\n const answer = inline.found ? inline.content.trimEnd() : lastText;\n const result: HeadlessResult = {\n messages: contextHistory,\n transcript,\n compactBoundaries,\n usage: reportedUsage,\n accounting: runtime.runAccounting.snapshotAll(),\n outcome,\n runs: runResults,\n sessionId,\n plan: planNotApplied.outcome,\n commandResults,\n answer,\n };\n\n if (opts.jsonSchema) {\n try {\n result.structured = JSON.parse(answer);\n } catch {\n result.structuredError = 'Failed to parse JSON from assistant output';\n }\n }\n\n // Prompt suggestions: ask model for follow-up prompts.\n if (opts.promptSuggestions && opts.outputFormat === 'stream-json') {\n try {\n const suggestions = await generatePromptSuggestions(\n config,\n registry,\n contextHistory,\n runSignal,\n store?.readImageAttachment\n ? (attachment) => store.readImageAttachment!(runtimeSessionId, attachment)\n : undefined,\n );\n if (suggestions.length > 0) {\n emit({ type: 'prompt_suggestions', suggestions });\n }\n } catch {\n // Non-fatal: suggestions are best-effort.\n }\n }\n\n if (opts.outputFormat === 'text') {\n const stopped = planNotApplied.outcome;\n if (stopped) {\n // The plan is the deliverable when nothing could approve it; the\n // trailing status line keeps \"produced a plan\" from reading as\n // \"did the work\".\n stdout.write(`${stopped.plan}\\n\\n${stopped.message}\\n`);\n } else {\n if (answer) stdout.write(answer + '\\n');\n }\n } else if (opts.outputFormat === 'json') {\n // Exactly one top-level document: everything the run produced, including\n // commands the host performed itself, is carried here.\n emit({\n result: {\n messages: contextHistory,\n usage: reportedUsage,\n accounting: result.accounting,\n outcome,\n stopReason: outcome.reason,\n runs: runResults,\n structured: result.structured,\n structuredError: result.structuredError,\n plan: result.plan,\n commandResults,\n answer,\n },\n });\n } else if (opts.outputFormat === 'stream-json') {\n emit({\n type: 'result',\n // At the top level, beside `stopReason`, because that is where a\n // supervised loop reads the outcome from: `jq -e 'select(.type==\"result\")\n // | .outcome.reason==\"objective_complete\"'` was written against this\n // record and read a null. `result.outcome` stays for hosts already\n // reading it there.\n stopReason: outcome.reason,\n outcome,\n result: {\n // Off by default: a long run's conversation is half a megabyte of JSONL\n // on one line, which every reader has to buffer before it can look at\n // the field it came for. `--include-result-messages` asks for it back.\n ...(opts.includeResultMessages ? { messages: contextHistory } : {}),\n usage: reportedUsage,\n accounting: result.accounting,\n outcome,\n stopReason: outcome.reason,\n runs: runResults,\n structured: result.structured,\n structuredError: result.structuredError,\n plan: result.plan,\n commandResults,\n answer,\n },\n });\n }\n\n // A failed run with no answer used to say nothing at all in text or json output when\n // the loop reported no error of its own: a prompt a UserPromptSubmit hook refused\n // exited 1 with empty stdout and stderr. stream-json carries the outcome in `result`.\n // An SDK host is skipped: it gets the outcome on its `result` event and owns the\n // stderr of the process it embedded Book in.\n if (\n opts.outputFormat !== 'stream-json' &&\n opts.runSource !== 'sdk' &&\n outcome.status === 'failed' &&\n outcome.message &&\n !answer &&\n !planNotApplied.outcome &&\n !eventState.errorReported\n ) {\n process.stderr.write(`error: ${outcome.message}\\n`);\n }\n\n if (sessionId) {\n // A run that completed reports `completion`, a failed one `error`, and only\n // then does an abort count: an `aborted` signal is how a cancel, a timeout\n // and a reader that walked away all arrive, and none of them may rewrite\n // how the run actually ended (#248).\n const sessionEndReason =\n outcome.status === 'completed'\n ? 'completion'\n : outcome.status === 'failed'\n ? 'error'\n : outcome.status === 'cancelled' || runSignal?.aborted\n ? 'aborted'\n : 'completion';\n disposeSession();\n await agentSession.endLifecycle(config, sessionId, sessionEndReason, {\n onHookEvent: createHookEventHandler(opts, emit),\n endOutcome: outcome,\n });\n }\n\n return result;\n } catch (error) {\n // A run that throws after SessionStart used to skip SessionEnd entirely (#248).\n // An abort that lands inside a tool is the common case (a hook call rethrows the\n // aborted signal): a cancelled print run, or a stream-json run whose reader went\n // away. A missing prompt is another. End the session SessionStart opened, then\n // rethrow. There is no outcome here, so the signal decides between `aborted` and\n // `error`, and the outcome handed to the hooks is synthesized for the same reason.\n // `endLifecycle` fires at most once per session. It gets no signal, as in\n // the TUI: the run's signal may be the one that aborted, and every hook already\n // runs under its own fresh 10 s timeout.\n if (startedSessionId) {\n disposeSession();\n await agentSession\n .endLifecycle(config, startedSessionId, runSignal?.aborted ? 'aborted' : 'error', {\n onHookEvent: createHookEventHandler(opts, emit),\n endOutcome: runSignal?.aborted\n ? classifyAbortReason(runSignal.reason, false)\n : createTerminalOutcome('failed', 'runtime_error', { partialOutput: false }),\n })\n .catch((hookError: unknown) => {\n console.warn(\n `SessionEnd hook failed: ${hookError instanceof Error ? hookError.message : String(hookError)}`,\n );\n });\n }\n throw error;\n } finally {\n disposeCrashHandlers?.();\n disposeSession();\n }\n}\n\n/**\n * Wire status for the `plan_approval` stream-json event: approve | reject |\n * revise | stop.\n *\n * This host asks the plan as a user question with two options, so it has no way\n * to answer `approve-fresh` — approving with a fresh context reseeds a\n * conversation, which only the interactive TUI owns. `bypassPermissions` answers\n * `approve` and a host with no handler answers `stop`; a free-text answer is the\n * approver's revision feedback, so it is `revise`.\n */\nfunction planApprovalStatus(decision: PlanApprovalResult): string {\n return typeof decision === 'string' ? decision : decision.decision;\n}\n\ntype HeadlessEmit = (event: unknown) => void;\n\n/** What the event printers remember across one run. */\ninterface HeadlessEventState {\n /** Managed children's progress labels by agent id; see `writeTextProgress`. */\n childLabels: Map<string, string>;\n /** Set once an `error` line or record was written for this run. */\n errorReported: boolean;\n}\n\nfunction createHookEventHandler(\n opts: HeadlessOptions,\n emit: HeadlessEmit,\n): ((event: string, payload: Record<string, unknown>) => void) | undefined {\n if (!opts.includeHookEvents || opts.outputFormat !== 'stream-json') return undefined;\n return (event, payload) => emit({ type: 'hook_event', event, ...payload });\n}\n\nfunction emitAgentEvent(\n event: AgentEvent,\n opts: HeadlessOptions,\n emit: HeadlessEmit,\n state: HeadlessEventState,\n): void {\n if (event.type === 'terminal') return;\n if (event.type === 'agent_text_delta' && opts.forwardSubagentText !== true) return;\n opts.onAgentEvent?.(event);\n if (event.type === 'notice') {\n if (opts.outputFormat === 'stream-json') emit({ type: 'notice', message: event.message });\n else console.warn(event.message);\n return;\n }\n // A `/goal` check: whether the run continues, and why. A progress line like any\n // other under `text`, so `--quiet` (and the SDK, which owns its stderr) silences it --\n // except, under `--quiet`, a `failed` or `paused` goal: it ends the run failed with no\n // outcome message, so it is the only line saying why the exit code is non-zero.\n if (event.type === 'goal_status') {\n const endsRunFailed = event.event.state === 'failed' || event.event.state === 'paused';\n if (opts.outputFormat === 'stream-json') emit({ type: 'goal_status', ...event.event });\n else if (\n opts.outputFormat === 'text' &&\n opts.runSource !== 'sdk' &&\n (opts.quiet !== true || endsRunFailed)\n ) {\n process.stderr.write(\n `goal: ${progressLine(formatGoalStatus(event.event), PROGRESS_NOTICE_MAX)}\\n`,\n );\n }\n return;\n }\n // A managed child's own line for the operator (#305 item 4). A child runs unattended and its\n // result is summarised into a handoff, so a step that was refused and never ran is\n // indistinguishable from one it chose to skip — and only the TUI was rendering this, so a\n // print-mode operator learned nothing. The label is already on the text, because the child's\n // prompt is the delegating model's. Unlike the progress lines, and like `notice`, this is not\n // silenced by `--quiet`: it is not progress, it is something that did not happen, and the\n // answer alone would not show it.\n if (event.type === 'agent_notice') {\n if (opts.outputFormat === 'stream-json') {\n emit({ type: 'agent_notice', agentId: event.agentId, message: event.message });\n } else {\n process.stderr.write(`notice: ${progressLine(event.message, PROGRESS_NOTICE_MAX)}\\n`);\n }\n return;\n }\n if (event.type === 'error') {\n state.errorReported = true;\n if (opts.outputFormat === 'stream-json') emit({ type: 'error', error: event.error });\n else process.stderr.write(`error: ${event.error}\\n`);\n return;\n }\n if (opts.outputFormat === 'text' && opts.quiet !== true) {\n writeTextProgress(event, opts, state);\n }\n if (opts.outputFormat !== 'stream-json') return;\n\n switch (event.type) {\n case 'run_started':\n emit({ type: 'run_start', run: event.context, ambient: event.ambient });\n break;\n case 'text':\n // Deltas are opt IN, and are additional to the completed message emitted at\n // turn end. Commander leaves an unpassed boolean `undefined`, so the old\n // `!== false` gate meant the flag did nothing and every run paid maximum\n // stream volume whether or not anyone asked for them.\n if (opts.includePartialMessages === true)\n emit({ type: 'assistant', text: event.content, complete: false });\n break;\n case 'reasoning':\n if (opts.includePartialMessages === true) emit({ type: 'reasoning', text: event.content });\n break;\n case 'tool_use':\n emit({ type: 'tool_use', tool_call: event.toolCall });\n break;\n case 'tool_result':\n emit({ type: 'tool_result', tool_result: event.toolResult });\n break;\n case 'user_question':\n emit({ type: 'user_question', request: event.request, status: event.status });\n break;\n case 'user_question_result':\n emit({\n type: 'user_question_result',\n request_id: event.requestId,\n response: event.response,\n });\n break;\n case 'agent_start':\n case 'background_job_start':\n case 'background_job_update':\n case 'background_job_output':\n case 'background_job_result':\n case 'background_job_dismiss':\n case 'agent_update':\n case 'agent_result':\n case 'agent_question':\n case 'agent_status':\n case 'agent_activity':\n case 'agent_text_delta':\n case 'agent_message':\n case 'agent_completion':\n case 'agent_permission':\n case 'agent_apply':\n case 'evidence_update':\n case 'skill_lifecycle':\n case 'attempt_discarded':\n emit(event);\n break;\n case 'system':\n case 'session':\n case 'result':\n case 'done':\n break;\n }\n}\n\n/** Longest primary argument a progress line shows. */\nconst PROGRESS_ARG_MAX = 120;\n/** Longest error a `--verbose` result line shows. */\nconst PROGRESS_ERROR_MAX = 160;\n/**\n * Longest child-notice line. A notice carries a refusal message, which quotes a model-chosen\n * path, so the line is folded and capped exactly as a progress line is — the operator's terminal\n * is the last place an escape sequence from a model argument should reach.\n */\nconst PROGRESS_NOTICE_MAX = 400;\n\n/**\n * The first non-blank line of `text`, cut to `max` characters, so a plan, an\n * agent message or unparsed JSON arguments cannot turn one record into many.\n */\nfunction progressLine(text: string, max: number): string {\n const first = text.trim().split(/\\r?\\n/, 1)[0];\n // A control character (a bare CR, an escape sequence, a bidi override) would let an argument or a tool name rewrite the terminal.\n const printable = Array.from(first, (char) => {\n const code = char.codePointAt(0) ?? 0;\n const control =\n code < 32 ||\n (code >= 0x7f && code <= 0x9f) ||\n code === 0x061c ||\n code === 0x200e ||\n code === 0x200f ||\n (code >= 0x2028 && code <= 0x202e) ||\n (code >= 0x2066 && code <= 0x2069);\n return control ? ' ' : char;\n })\n .join('')\n .trimEnd();\n const chars = Array.from(printable);\n return chars.length > max ? `${chars.slice(0, max - 1).join('')}…` : printable;\n}\n\n/**\n * One line per tool call on stderr in text mode. Without it a print run is\n * silent from the first request to the final answer — 35 minutes and a hundred\n * tool calls with nothing on the terminal (#225) — and the only way to see it was\n * alive was to tail the session file. `--verbose` adds the result of each call;\n * `--quiet` turns the lines off. stdout stays the final answer alone.\n *\n * A managed child's calls (`Task`, `AgentSpawn`, `/review`) print too, indented\n * and named after the child's profile: ` [explorer] [Read] src/a.ts`, and under\n * `--verbose` ` → success 3ms src/a.ts`. The manager reports each child call\n * as an `agent_activity`; ignoring those left a run that delegated silent after\n * `[Task] explorer` until the child finished (#248).\n */\nfunction writeTextProgress(\n event: AgentEvent,\n opts: HeadlessOptions,\n state: HeadlessEventState,\n): void {\n if (event.type === 'tool_use') {\n process.stderr.write(`${toolCallProgress(event.toolCall)}\\n`);\n return;\n }\n if (event.type === 'tool_result' && opts.verbose === true) {\n process.stderr.write(` ${toolResultProgress(event.toolResult)}\\n`);\n return;\n }\n if (event.type === 'agent_start') {\n // Two children of one profile would both print as `[explorer]`: number the later ones\n // the way the manager numbers display names (`explorer 2`). A child that starts again\n // (a follow-up) keeps its label.\n if (!state.childLabels.has(event.agent.id)) {\n state.childLabels.set(\n event.agent.id,\n uniqueAgentDisplayName(event.agent.profile ?? event.agent.name, state.childLabels.values()),\n );\n }\n return;\n }\n if (event.type === 'agent_activity') {\n writeChildToolProgress(event.agentId, event.activity, opts, state);\n }\n}\n\n/** A managed child's tool call when it starts, and its result under `--verbose`. */\nfunction writeChildToolProgress(\n agentId: string,\n activity: AgentActivity,\n opts: HeadlessOptions,\n state: HeadlessEventState,\n): void {\n if (activity.kind !== 'tool' || !activity.toolCall) return;\n if (activity.status === 'running') {\n const child = progressLine(state.childLabels.get(agentId) ?? 'agent', PROGRESS_ARG_MAX);\n process.stderr.write(` [${child}] ${toolCallProgress(activity.toolCall)}\\n`);\n return;\n }\n // A finished call carries its result. The manager's end-of-run sweep re-reports a\n // call it never saw finish, with no result, and that prints nothing.\n if (opts.verbose === true && activity.result) {\n process.stderr.write(` ${toolResultProgress(activity.result)}\\n`);\n }\n}\n\n/** `[Name] primary-arg` for one tool call. */\nfunction toolCallProgress(call: ToolCall): string {\n const arg = progressLine(getPrimaryArg(call.arguments), PROGRESS_ARG_MAX);\n return `[${progressLine(call.name, PROGRESS_ARG_MAX)}]${arg ? ` ${arg}` : ''}`;\n}\n\n/** `→ status 12ms target: error` for one tool result. */\nfunction toolResultProgress(result: ToolResult): string {\n const duration = result.metrics?.durationMs;\n // A turn's call lines all print before its results, so each result names its target.\n const target = progressLine(result.presentation?.target ?? '', PROGRESS_ARG_MAX);\n const error =\n result.status === 'success'\n ? ''\n : progressLine(toolResultErrorMessage(result) ?? '', PROGRESS_ERROR_MAX);\n const detail = [target, error].filter(Boolean).join(': ');\n return `→ ${result.status}${duration !== undefined ? ` ${Math.round(duration)}ms` : ''}${detail ? ` ${detail}` : ''}`;\n}\n\nfunction emitCompactBoundary(\n outputFormat: HeadlessOptions['outputFormat'],\n emit: HeadlessEmit,\n result: Extract<CompactResult, { status: 'compacted' }>,\n): void {\n if (outputFormat !== 'stream-json') return;\n emit({\n type: 'system',\n subtype: 'compact_boundary',\n trigger: result.trigger,\n pre_tokens: result.preContextTokens,\n compact_id: result.compactId,\n generation: result.generation,\n pre_messages: result.preMessageCount,\n post_messages: result.replacementHistory.length,\n carried_messages: result.carriedCount,\n post_tokens: result.postContextTokens,\n checkpoint_version: 2,\n strategy: result.strategy,\n model_calls: result.modelCalls,\n degraded: result.degraded,\n coverage_status: result.checkpoint.coverage?.status ?? 'complete',\n // This generation's status above; the conversation's accumulated one here.\n coverage_lifetime_status: result.checkpoint.coverage?.lifetime?.status ?? 'complete',\n coverage: result.checkpoint.coverage,\n warning: result.warning,\n // The reducer audit, when the host has something to report: suspect inputs\n // found in the summarized span and inherited constraints the reducer let go of.\n ...(result.checkpoint.audit ? { audit: result.checkpoint.audit } : {}),\n // Deferred compaction: the judge's verdict on the steps taken while the reducer ran.\n ...(result.judge ? { judge: result.judge } : {}),\n });\n}\n\nasync function generatePromptSuggestions(\n config: AgentConfig,\n _registry: ToolRegistry,\n history: Message[],\n signal?: AbortSignal,\n resolveAttachment?: (attachment: ImageAttachment) => Promise<Uint8Array> | Uint8Array,\n): Promise<string[]> {\n const { chatCompletionStream } = await import('./provider/openai-compatible.js');\n const { buildMessages } = await import('./agent/context.js');\n\n const suggestionMessages = await buildMessages(\n config,\n [\n ...history,\n {\n id: crypto.randomUUID(),\n role: 'user' as const,\n content:\n 'Based on the conversation above, suggest 1-3 follow-up prompts the user might want to ask next. Keep each suggestion under 80 characters. Return ONLY a JSON array of strings, no other text.',\n includeInContext: true,\n timestamp: Date.now(),\n },\n ],\n undefined,\n undefined,\n signal,\n undefined,\n undefined,\n resolveAttachment,\n );\n\n const stream = chatCompletionStream(config, suggestionMessages, [], { signal });\n let content = '';\n for await (const event of stream) {\n if (event.type === 'text' && event.content) {\n content += event.content;\n }\n }\n\n // Parse JSON array from the response.\n try {\n const jsonMatch = content.match(/\\[[\\s\\S]*?\\]/);\n if (jsonMatch) {\n const parsed = JSON.parse(jsonMatch[0]);\n if (Array.isArray(parsed)) {\n return parsed.filter((s) => typeof s === 'string' && s.length > 0).slice(0, 3);\n }\n }\n } catch {\n // Fallback: try to extract quoted strings.\n const quoted = content.match(/\"([^\"]+)\"/g);\n if (quoted) {\n return quoted.map((s) => s.replace(/^\"|\"$/g, '')).slice(0, 3);\n }\n }\n return [];\n}\n","/**\n * MCP client host: connects declared servers over stdio, Streamable HTTP, or\n * legacy SSE and exposes their tools as `mcp__<server>__<tool>` definitions.\n *\n * The protocol layer (handshake/version negotiation, request lifecycle,\n * cancellation notifications, result validation) is the official\n * `@modelcontextprotocol/sdk` `Client`. Remote transports come from the SDK.\n * The stdio transport stays in-repo so Book retains child-process observation,\n * bounded stderr capture, deterministic listener cleanup, and\n * SIGTERM→SIGKILL escalation on shutdown.\n */\nimport spawn from 'cross-spawn';\nimport type { ChildProcess } from 'child_process';\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport { ReadBuffer, serializeMessage } from '@modelcontextprotocol/sdk/shared/stdio.js';\nimport {\n ElicitRequestSchema,\n ErrorCode,\n McpError,\n ToolListChangedNotificationSchema,\n type JSONRPCMessage,\n} from '@modelcontextprotocol/sdk/types.js';\nimport type {\n ElicitationHandler,\n ElicitationResponse,\n ToolDefinition,\n ToolContext,\n} from './types/tools.js';\nimport { toElicitationFields, validateElicitationContent } from './mcp-elicitation.js';\nimport { buildChildEnv } from './child-env.js';\nimport { toolFailure, toolSuccess } from './tools/result.js';\nimport { getPackageVersion } from './version-info.js';\nimport {\n consoleMcpDiagnosticSink,\n resolveMcpServerList,\n type McpDiagnosticSink,\n type McpServerConfig,\n} from './mcp-config.js';\n\nexport {\n loadMcpConfig,\n resolveMcpServerList,\n formatMcpServerCommand,\n consoleMcpDiagnosticSink,\n} from './mcp-config.js';\nexport type {\n McpServerConfig,\n McpServerSource,\n ResolvedMcpServer,\n McpDiagnostic,\n McpDiagnosticSink,\n} from './mcp-config.js';\n\nexport interface McpToolDef {\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n}\n\nexport interface McpConnection {\n name: string;\n client: Client;\n /** Present only for locally spawned stdio servers. */\n process?: ChildProcess;\n tools: McpToolDef[];\n /** In-flight requests issued through this host, visible to hosts and tests. */\n pending: Map<number, { method: string }>;\n closed: boolean;\n /** Bounded tail of the server's stderr output. */\n readonly stderr: string;\n /** Negotiated protocol revision reported by the server. */\n protocolVersion?: string;\n serverInfo?: { name: string; version: string };\n capabilities?: Record<string, unknown>;\n /** Gracefully terminate any remote session and close the owned transport. */\n close(): Promise<void>;\n}\n\nexport interface McpConnectionOptions {\n home?: string;\n signal?: AbortSignal;\n initializationTimeoutMs?: number;\n requestTimeoutMs?: number;\n maxStderrBytes?: number;\n /** Lifecycle observer used by hosts/tests that account for owned child processes. */\n onProcessSpawn?: (name: string, process: ChildProcess) => void;\n /**\n * Explicit servers to connect. A host that has evaluated project-server\n * approval passes the approved subset here.\n *\n * When omitted, only user-scoped servers (<BOOK_HOME>/mcp.json) are\n * connected: they are user-owned, so no approval gate applies. Project\n * servers from <workspace>/.mcp.json are repository-controlled and are\n * skipped, because approval cannot be evaluated without settings. Omitting\n * this therefore fails closed rather than connecting whatever the workspace\n * declared.\n */\n servers?: Record<string, McpServerConfig>;\n /** Warning sink; defaults to stderr. Ink hosts must supply a non-console sink. */\n onDiagnostic?: McpDiagnosticSink;\n /** Invoked after this host refreshes `connection.tools` for a list_changed notification. */\n onToolListChanged?: (serverName: string) => void;\n /** Invoked when a successfully initialized server later disconnects. */\n onConnectionClosed?: (serverName: string) => void;\n /**\n * Host prompt for MCP form elicitation. Supplying it is what declares the\n * `elicitation` client capability, so a host that cannot reach a user never\n * advertises one — servers then fail the request themselves instead of\n * waiting on a prompt nobody will see.\n */\n onElicit?: ElicitationHandler;\n}\n\nconst DEFAULT_INITIALIZATION_TIMEOUT_MS = 10_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 30_000;\nconst DEFAULT_MAX_STDERR_BYTES = 8_192;\n\ntype ResolvedConnectionOptions = McpConnectionOptions &\n Required<Pick<McpConnectionOptions, 'initializationTimeoutMs' | 'requestTimeoutMs'>> & {\n onDiagnostic: McpDiagnosticSink;\n };\n\nfunction waitForProcessExit(child: ChildProcess, timeoutMs: number): Promise<boolean> {\n if (child.exitCode !== null || child.signalCode !== null) return Promise.resolve(true);\n return new Promise((resolve) => {\n let settled = false;\n const finish = (exited: boolean) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n child.removeListener('exit', onExit);\n resolve(exited);\n };\n const onExit = () => finish(true);\n const timer = setTimeout(() => finish(false), timeoutMs);\n timer.unref();\n child.once('exit', onExit);\n });\n}\n\nasync function terminateProcess(child: ChildProcess): Promise<void> {\n child.stdin?.end();\n if (child.exitCode === null && child.signalCode === null) child.kill();\n if (!(await waitForProcessExit(child, 250))) {\n child.kill('SIGKILL');\n await waitForProcessExit(child, 750);\n }\n child.stdin?.destroy();\n child.stdout?.destroy();\n child.stderr?.destroy();\n child.unref();\n}\n\n/**\n * Newline-delimited JSON-RPC transport over a child process this host spawns\n * and owns. Mirrors the SDK's stdio transport contract while keeping the\n * ChildProcess observable and the shutdown path deterministic.\n */\nclass StdioProcessTransport implements Transport {\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n\n private child?: ChildProcess;\n private readonly readBuffer = new ReadBuffer();\n private stderrTail = '';\n private closed = false;\n private cleanupListeners: () => void = () => {};\n protocolVersion?: string;\n\n constructor(\n private readonly name: string,\n private readonly config: McpServerConfig,\n private readonly options: {\n maxStderrBytes: number;\n onSpawn?: (child: ChildProcess) => void;\n },\n ) {}\n\n get process(): ChildProcess | undefined {\n return this.child;\n }\n\n get stderr(): string {\n return this.stderrTail;\n }\n\n setProtocolVersion(version: string): void {\n this.protocolVersion = version;\n }\n\n start(): Promise<void> {\n if (this.child) {\n return Promise.reject(new Error(`MCP server ${this.name} transport already started`));\n }\n if (!this.config.command) {\n return Promise.reject(new Error(`MCP server ${this.name} is not a stdio server`));\n }\n const child = spawn(this.config.command, this.config.args ?? [], {\n env: buildChildEnv(process.env, this.config.env),\n cwd: this.config.cwd,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n this.child = child;\n this.options.onSpawn?.(child);\n\n const onStdoutData = (data: Buffer) => {\n this.readBuffer.append(data);\n while (true) {\n let message: JSONRPCMessage | null;\n try {\n message = this.readBuffer.readMessage();\n } catch (error) {\n // readMessage consumes the offending line before throwing, so the\n // loop always advances past malformed output.\n this.onerror?.(error instanceof Error ? error : new Error(String(error)));\n continue;\n }\n if (!message) break;\n this.onmessage?.(message);\n }\n };\n const onStderrData = (data: Buffer) => {\n this.stderrTail = (this.stderrTail + data.toString()).slice(-this.options.maxStderrBytes);\n };\n const onChildError = (error: Error) => {\n this.onerror?.(error);\n this.teardown();\n };\n // Swallowed here; write failures surface through the send() callback. This one\n // listener is never removed: a write queued on stdin — a large request, or the\n // cancellation sent on abort — can fail after teardown, once the server's pipe is\n // closed, and a stream left with no `error` handler raises that as an uncaught\n // exception (#338).\n const onStdinError = () => {};\n const onExit = () => this.teardown();\n const onClose = () => this.teardown();\n\n this.cleanupListeners = () => {\n child.stdout?.removeListener('data', onStdoutData);\n child.stderr?.removeListener('data', onStderrData);\n child.removeListener('error', onChildError);\n // `child.stdin`'s no-op error listener is deliberately not removed: a write still\n // queued on it can only fail once the child is gone, which is exactly when this runs.\n child.removeListener('exit', onExit);\n child.removeListener('close', onClose);\n this.cleanupListeners = () => {};\n };\n child.stdout?.on('data', onStdoutData);\n child.stderr?.on('data', onStderrData);\n child.once('error', onChildError);\n child.stdin?.on('error', onStdinError);\n child.once('exit', onExit);\n child.once('close', onClose);\n return Promise.resolve();\n }\n\n send(message: JSONRPCMessage): Promise<void> {\n return new Promise((resolve, reject) => {\n const stdin = this.child?.stdin;\n if (this.closed || !stdin || stdin.destroyed) {\n reject(new Error(`MCP server ${this.name} stdin is closed`));\n return;\n }\n try {\n stdin.write(serializeMessage(message), (error) => {\n if (error) reject(error);\n else resolve();\n });\n } catch (error) {\n reject(error instanceof Error ? error : new Error(String(error)));\n }\n });\n }\n\n /** Child died or streams closed underneath us: settle pending work, then reap. */\n private teardown(): void {\n if (this.closed) return;\n this.closed = true;\n this.cleanupListeners();\n this.onclose?.();\n if (this.child) void terminateProcess(this.child).catch(() => {});\n }\n\n async close(): Promise<void> {\n if (this.closed) return;\n this.closed = true;\n this.cleanupListeners();\n // Reject pending requests before the (graceful, up to ~1s) process reap.\n this.onclose?.();\n if (this.child) await terminateProcess(this.child).catch(() => {});\n }\n}\n\nfunction isMcpErrorWithCode(error: unknown, code: ErrorCode): boolean {\n return error instanceof McpError && error.code === code;\n}\n\nfunction withStderrContext(message: string, transport: { stderr: string }): string {\n const tail = transport.stderr.trim();\n return tail ? `${message} (stderr: ${tail})` : message;\n}\n\nfunction createSecretRedactor(config: McpServerConfig): (message: string) => string {\n let queryValues: string[] = [];\n try {\n queryValues = config.url ? [...new URL(config.url).searchParams.values()] : [];\n } catch {\n // Explicit configs are validated by the transport path; redaction remains best effort.\n }\n const secrets = [\n ...Object.values(config.env ?? {}),\n ...Object.values(config.headers ?? {}),\n ...queryValues,\n ]\n .filter((value) => value.length > 0)\n .sort((left, right) => right.length - left.length);\n return (message) => {\n let redacted = message;\n for (const secret of secrets) redacted = redacted.replaceAll(secret, '<redacted>');\n return redacted;\n };\n}\n\ninterface McpContentBlock {\n type?: string;\n text?: string;\n mimeType?: string;\n uri?: string;\n resource?: { uri?: string; text?: string; mimeType?: string };\n}\n\n/** Flatten MCP content blocks into the plain-text tool output Book renders. */\nexport function renderMcpContent(result: Record<string, unknown>): {\n text: string;\n isError: boolean;\n} {\n const blocks = Array.isArray(result.content) ? (result.content as McpContentBlock[]) : [];\n const parts: string[] = [];\n for (const block of blocks) {\n if (!block || typeof block !== 'object') continue;\n switch (block.type) {\n case 'text':\n if (typeof block.text === 'string') parts.push(block.text);\n break;\n case 'image':\n case 'audio':\n parts.push(`[${block.type}${block.mimeType ? `: ${block.mimeType}` : ''}]`);\n break;\n case 'resource_link':\n parts.push(`[resource_link: ${block.uri ?? 'unknown'}]`);\n break;\n case 'resource': {\n const resource = block.resource;\n if (resource && typeof resource.text === 'string') parts.push(resource.text);\n else if (resource?.uri) {\n parts.push(\n `[resource: ${resource.uri}${resource.mimeType ? ` (${resource.mimeType})` : ''}]`,\n );\n }\n break;\n }\n default:\n break;\n }\n }\n if (parts.length === 0 && result.structuredContent !== undefined) {\n parts.push(JSON.stringify(result.structuredContent, null, 2));\n }\n return { text: parts.join('\\n'), isError: result.isError === true };\n}\n\nasync function listAllTools(\n client: Client,\n requestTimeoutMs: number,\n signal?: AbortSignal,\n): Promise<McpToolDef[]> {\n const tools: McpToolDef[] = [];\n let cursor: string | undefined;\n do {\n const page = await client.listTools(cursor ? { cursor } : undefined, {\n timeout: requestTimeoutMs,\n signal,\n });\n for (const tool of page.tools) {\n tools.push({\n name: tool.name,\n description: tool.description ?? '',\n inputSchema: (tool.inputSchema ?? { type: 'object', properties: {} }) as Record<\n string,\n unknown\n >,\n });\n }\n cursor = page.nextCursor;\n } while (cursor);\n return tools;\n}\n\ninterface LiveConnection extends McpConnection {\n requestCounter: number;\n redact: (message: string) => string;\n}\n\ntype OwnedTransport = Transport & {\n process?: ChildProcess;\n protocolVersion?: string;\n terminateSession?: () => Promise<void>;\n};\n\ninterface TransportHandle {\n transport: OwnedTransport;\n getStderr: () => string;\n getProtocolVersion: () => string | undefined;\n}\n\nfunction isRemoteConfig(config: McpServerConfig): boolean {\n return config.type === 'http' || config.type === 'sse' || Boolean(config.url && !config.command);\n}\n\nfunction createTransport(\n name: string,\n cfg: McpServerConfig,\n options: ResolvedConnectionOptions,\n): TransportHandle {\n if (isRemoteConfig(cfg)) {\n if (!cfg.url) throw new Error(`MCP server ${name} has no URL`);\n const url = new URL(cfg.url);\n const headers = { ...(cfg.headers ?? {}) };\n if (cfg.type === 'sse') {\n let protocolVersion: string | undefined;\n const transport = new SSEClientTransport(url, {\n // The SDK derives the SSE GET headers from requestInit too. Supplying\n // them here therefore covers both the initial stream and later POSTs.\n requestInit: { headers },\n });\n const sdkSetProtocolVersion = transport.setProtocolVersion.bind(transport);\n transport.setProtocolVersion = (version: string) => {\n protocolVersion = version;\n sdkSetProtocolVersion(version);\n };\n return {\n transport,\n getStderr: () => '',\n getProtocolVersion: () => protocolVersion,\n };\n }\n const transport = new StreamableHTTPClientTransport(url, {\n requestInit: { headers },\n });\n return {\n transport,\n getStderr: () => '',\n getProtocolVersion: () => transport.protocolVersion,\n };\n }\n\n const transport = new StdioProcessTransport(name, cfg, {\n maxStderrBytes: options.maxStderrBytes ?? DEFAULT_MAX_STDERR_BYTES,\n onSpawn: (child) => options.onProcessSpawn?.(name, child),\n });\n return {\n transport,\n getStderr: () => transport.stderr,\n getProtocolVersion: () => transport.protocolVersion,\n };\n}\n\n/**\n * Route `elicitation/create` to the host prompt. Anything Book cannot present\n * faithfully — URL mode, or a schema outside the renderable subset — is\n * declined, which is a protocol-legal answer the server already handles.\n */\nfunction registerElicitationHandler(\n client: Client,\n name: string,\n options: ResolvedConnectionOptions,\n): void {\n const onElicit = options.onElicit;\n if (!onElicit) return;\n let counter = 0;\n\n client.setRequestHandler(\n ElicitRequestSchema,\n async (request, extra): Promise<ElicitationResponse> => {\n const params = request.params;\n if (params.mode === 'url') {\n options.onDiagnostic({\n level: 'warn',\n message: `MCP server \"${name}\" requested URL elicitation, which Book does not support`,\n server: name,\n });\n return { action: 'decline' };\n }\n\n const converted = toElicitationFields(params.requestedSchema);\n if ('error' in converted) {\n options.onDiagnostic({\n level: 'warn',\n message: `Declined an elicitation from MCP server \"${name}\": ${converted.error}`,\n server: name,\n });\n return { action: 'decline' };\n }\n\n const response = await onElicit(\n {\n id: `${name}:${++counter}`,\n server: name,\n message: params.message,\n fields: converted.fields,\n },\n { signal: extra?.signal },\n );\n if (response.action !== 'accept') return { action: response.action };\n\n const validated = validateElicitationContent(converted.fields, response.content);\n if ('error' in validated) {\n options.onDiagnostic({\n level: 'warn',\n message: `Discarded an elicitation answer for MCP server \"${name}\": ${validated.error}`,\n server: name,\n });\n return { action: 'cancel' };\n }\n return { action: 'accept', content: validated.content };\n },\n );\n}\n\nasync function connectMcpServer(\n name: string,\n cfg: McpServerConfig,\n options: ResolvedConnectionOptions,\n failure?: { error?: unknown },\n): Promise<McpConnection | null> {\n let handle: TransportHandle | undefined;\n let liveConnection: LiveConnection | undefined;\n let transportClosed = false;\n const redact = createSecretRedactor(cfg);\n\n try {\n handle = createTransport(name, cfg, options);\n const { transport, getStderr, getProtocolVersion } = handle;\n // Protocol.connect wraps these callbacks and preserves the callbacks that\n // were installed first. Keep the host's lifecycle state in that preserved\n // callback so a remote disconnect or a child exit removes stale tools from\n // the next provider request.\n transport.onclose = () => {\n transportClosed = true;\n if (!liveConnection || liveConnection.closed) return;\n liveConnection.closed = true;\n options.onConnectionClosed?.(name);\n };\n transport.onerror = (error) => {\n options.onDiagnostic({\n level: 'warn',\n message: redact(`MCP server \"${name}\" transport error: ${error.message}`),\n server: name,\n });\n };\n const client = new Client(\n { name: 'book', version: getPackageVersion() },\n { capabilities: options.onElicit ? { elicitation: { form: {} } } : {} },\n );\n registerElicitationHandler(client, name, options);\n\n await client.connect(transport, {\n timeout: options.initializationTimeoutMs,\n signal: options.signal,\n });\n const supportsTools = client.getServerCapabilities()?.tools !== undefined;\n const tools = supportsTools\n ? await listAllTools(client, options.requestTimeoutMs, options.signal)\n : [];\n if (transportClosed) throw new Error('connection closed during initialization');\n\n const conn: LiveConnection = {\n name,\n client,\n process: transport.process,\n tools,\n pending: new Map(),\n closed: false,\n requestCounter: 0,\n redact,\n get stderr() {\n return redact(getStderr());\n },\n protocolVersion: getProtocolVersion(),\n serverInfo: client.getServerVersion(),\n capabilities: client.getServerCapabilities() as Record<string, unknown> | undefined,\n async close() {\n try {\n await transport.terminateSession?.();\n } catch (error) {\n options.onDiagnostic({\n level: 'warn',\n message: redact(\n `Failed to terminate MCP server \"${name}\" session: ${error instanceof Error ? error.message : String(error)}`,\n ),\n server: name,\n });\n } finally {\n await client.close();\n }\n },\n };\n liveConnection = conn;\n\n if (supportsTools) {\n let refreshing = false;\n client.setNotificationHandler(ToolListChangedNotificationSchema, async () => {\n if (refreshing || conn.closed) return;\n refreshing = true;\n try {\n conn.tools = await listAllTools(client, options.requestTimeoutMs);\n options.onToolListChanged?.(name);\n } catch (error) {\n options.onDiagnostic({\n level: 'warn',\n message: redact(\n `Failed to refresh tools for MCP server \"${name}\": ${error instanceof Error ? error.message : String(error)}`,\n ),\n server: name,\n });\n } finally {\n refreshing = false;\n }\n });\n }\n\n return conn;\n } catch (error) {\n if (failure) failure.error = error;\n const message = redact(error instanceof Error ? error.message : String(error));\n options.onDiagnostic({\n level: 'warn',\n message: withStderrContext(`Failed to connect to MCP server \"${name}\": ${message}`, {\n stderr: redact(handle?.getStderr() ?? ''),\n }),\n server: name,\n });\n if (handle?.transport.terminateSession) {\n await handle.transport.terminateSession().catch(() => {});\n }\n await handle?.transport.close().catch(() => {});\n return null;\n }\n}\n\n/**\n * A Streamable HTTP endpoint that is really a legacy SSE one answers the initial\n * POST with 404 or 405 rather than anything protocol-shaped.\n *\n * `book mcp add <name> <url>` infers `http` from the URL having a scheme, which\n * is right for most servers and silently wrong for the older ones; the stored\n * config cannot distinguish an inferred `http` from one the user chose, so the\n * only signal available is the server's own rejection. Retry once as SSE when\n * that is what came back, and say so, rather than leaving a working server\n * looking broken with `--transport sse` as an undiscoverable fix.\n */\nfunction rejectedStreamableHttp(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error);\n return /\\b(404|405)\\b|Not Found|Method Not Allowed/i.test(message);\n}\n\nasync function connectRemoteWithSseFallback(\n name: string,\n cfg: McpServerConfig,\n options: ResolvedConnectionOptions,\n): Promise<McpConnection | null> {\n const eligible = isRemoteConfig(cfg) && cfg.type !== 'sse';\n if (!eligible) return connectMcpServer(name, cfg, options);\n\n const failure: { error?: unknown } = {};\n const connection = await connectMcpServer(name, cfg, options, failure);\n if (connection || !rejectedStreamableHttp(failure.error)) return connection;\n\n options.onDiagnostic({\n level: 'warn',\n message: `MCP server \"${name}\" rejected Streamable HTTP; retrying as legacy SSE. Set \"type\": \"sse\" to skip this.`,\n server: name,\n });\n return connectMcpServer(name, { ...cfg, type: 'sse' }, options);\n}\n\nfunction buildToolDefinition(\n conn: McpConnection,\n tool: McpToolDef,\n requestTimeoutMs: number,\n): ToolDefinition {\n const prefixedName = `mcp__${conn.name}__${tool.name}`;\n const live = conn as LiveConnection;\n return {\n name: prefixedName,\n description: `[MCP:${conn.name}] ${tool.description || tool.name}`,\n parameters: tool.inputSchema || { type: 'object', properties: {} },\n execute: async (args: Record<string, unknown>, ctx: ToolContext) => {\n const requestId = ++live.requestCounter;\n conn.pending.set(requestId, { method: tool.name });\n try {\n const result = await conn.client.callTool({ name: tool.name, arguments: args }, undefined, {\n timeout: requestTimeoutMs,\n resetTimeoutOnProgress: true,\n signal: ctx.signal,\n });\n const rendered = renderMcpContent(result as Record<string, unknown>);\n if (rendered.isError) {\n return toolFailure(\n `MCP tool ${prefixedName} failed: ${rendered.text || 'the server reported an error'}`,\n { code: 'mcp_tool_error', content: rendered.text },\n );\n }\n return toolSuccess(rendered.text, { data: result });\n } catch (error) {\n let message: string;\n if (ctx.signal?.aborted) {\n message = `MCP request aborted: ${tool.name}`;\n } else if (conn.closed && isMcpErrorWithCode(error, ErrorCode.ConnectionClosed)) {\n message = `MCP server ${conn.name} disconnected`;\n } else {\n message = live.redact(error instanceof Error ? error.message : String(error));\n }\n const tail = conn.stderr.trim();\n return toolFailure(\n `MCP tool ${prefixedName} failed: ${message}${tail ? ` (stderr: ${tail})` : ''}`,\n { code: 'mcp_tool_failed' },\n );\n } finally {\n conn.pending.delete(requestId);\n }\n },\n };\n}\n\n/** Current tool definitions for live connections; hosts rebuild per turn to pick up list changes. */\nexport function buildMcpToolDefinitions(\n connections: McpConnection[],\n requestTimeoutMs: number = DEFAULT_REQUEST_TIMEOUT_MS,\n): ToolDefinition[] {\n const tools: ToolDefinition[] = [];\n for (const conn of connections) {\n if (conn.closed) continue;\n for (const tool of conn.tools) tools.push(buildToolDefinition(conn, tool, requestTimeoutMs));\n }\n return tools;\n}\n\nexport async function connectMcpServers(\n workspace: string,\n options: McpConnectionOptions = {},\n): Promise<{ connections: McpConnection[]; tools: ToolDefinition[] }> {\n const resolved: ResolvedConnectionOptions = {\n ...options,\n initializationTimeoutMs: options.initializationTimeoutMs ?? DEFAULT_INITIALIZATION_TIMEOUT_MS,\n requestTimeoutMs: options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,\n onDiagnostic: options.onDiagnostic ?? consoleMcpDiagnosticSink,\n };\n let servers: Array<{ name: string; config: McpServerConfig }>;\n if (options.servers) {\n servers = Object.entries(options.servers).map(([name, config]) => ({ name, config }));\n } else {\n // No caller-supplied subset means no host evaluated project-server\n // approval, so repository-controlled servers cannot be trusted here.\n // Fail closed: connect user-scoped servers only and name what was skipped.\n const declared = resolveMcpServerList(workspace, {\n home: options.home,\n onDiagnostic: resolved.onDiagnostic,\n });\n for (const server of declared) {\n if (server.source === 'user') continue;\n resolved.onDiagnostic({\n level: 'warn',\n message: `Skipping project-declared MCP server \"${server.name}\" (${server.path}): it requires approval, and this caller supplied no approved server list.`,\n server: server.name,\n });\n }\n servers = declared.filter((server) => server.source === 'user');\n }\n\n const results = await Promise.allSettled(\n servers.map(({ name, config }) => connectRemoteWithSseFallback(name, config, resolved)),\n );\n const connections: McpConnection[] = [];\n for (const [index, result] of results.entries()) {\n if (result.status === 'rejected') {\n const server = servers[index];\n resolved.onDiagnostic({\n level: 'warn',\n message: `Failed to connect to MCP server \"${server.name}\": ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`,\n server: server.name,\n });\n continue;\n }\n if (!result.value) continue;\n connections.push(result.value);\n }\n return { connections, tools: buildMcpToolDefinitions(connections, resolved.requestTimeoutMs) };\n}\n\nexport async function disconnectMcpServers(connections: McpConnection[]): Promise<void> {\n const closing = connections.map(async (conn) => {\n if (conn.closed) return;\n conn.closed = true;\n await conn.close().catch(() => {});\n });\n await Promise.all(closing);\n}\n","/**\n * What a non-interactive host says about repository-declared configuration the\n * resolver withheld.\n *\n * Project-declared allow rules and hook entries need a one-time decision from\n * the user. Print and SDK runs cannot ask for one, so they report what they are\n * skipping and continue — otherwise the only symptom is a hook that silently\n * never fires. The two hosts said the same thing in the same twenty lines, and\n * each re-read and re-parsed `.book/settings.json` once per gate; the notice\n * lives here so there is one wording and one read.\n */\nimport { join } from 'path';\nimport { collectSkippedInstructionNotices } from './claude-md.js';\nimport { collectSkippedCommandNotices } from './commands/loader.js';\nimport { collectDeclaredDirectories, partitionProjectDirectories } from './additional-roots.js';\nimport { collectDeclaredHooks, partitionProjectHooks } from './hook-approvals.js';\nimport { partitionProjectAllowRules } from './permission-approvals.js';\nimport {\n describeApiKeyDeclaration,\n describeDroppedOverride,\n describeOrigin,\n describeReservedProvider,\n describeUnaffectedSelection,\n describeWithheldSelection,\n LEGACY_BASE_URL_ID,\n type WorkspaceProviderGate,\n} from './provider-approvals.js';\nimport { renderUntrustedText } from './hook-approvals.js';\nimport { collectSkippedReviewNotices } from './review/config.js';\nimport { providerTrustCommand } from './trust-command.js';\nimport {\n formatIgnoredWorkspaceSandboxKey,\n ignoredWorkspaceSandboxKeys,\n isUserSettingsFile,\n loadSettingsFile,\n settingsLayerPaths,\n workspaceLayerThatEnabledSandbox,\n} from './settings-loader.js';\nimport { TRUSTED_SETTINGS_LOCATION } from './settings-scope.js';\nimport type { ResolvedSettings } from './settings.js';\n\nexport interface WithheldProjectDeclarations {\n workspace: string;\n settings: ResolvedSettings;\n /** False under `--no-settings`, where no layer was read in the first place. */\n settingsEnabled: boolean;\n /**\n * What the provider gate withheld and dropped (`AgentConfig.workspaceProviderGate`). Omitted\n * by a host that has no config to read it from, which then reports no provider notices.\n */\n providerGate?: WorkspaceProviderGate;\n}\n\n/**\n * One warning per provider-gate outcome the user can act on (#418), each naming the command that\n * decides it. A provider the user rejected is not reported again, as a rejected hook is not, and\n * neither is a model selection that fell back because of one: the user already decided.\n */\nexport function collectWithheldProviderNotices(\n gate: WorkspaceProviderGate,\n workspace: string,\n): string[] {\n const notices: string[] = [];\n // Every command a notice suggests is built here: a provider id is repository-authored, and\n // pasting one unquoted would run whatever a hostile id spells.\n const approveCommand = (id: string): string => {\n const { command, note } = providerTrustCommand(workspace, id);\n return `\\`${command}\\`${note}`;\n };\n\n for (const dropped of gate.droppedOverrides) {\n notices.push(`⚠ ${describeDroppedOverride(dropped)}`);\n }\n\n for (const entry of gate.partition.reserved) {\n notices.push(`⚠ ${describeReservedProvider(entry)}`);\n }\n\n const pendingIds = new Set(gate.partition.pending.map((entry) => entry.id));\n for (const entry of gate.partition.pending) {\n const id = renderUntrustedText(entry.id, 64);\n const origin = entry.declaration.baseURL ?? entry.declaration.baseUrl;\n notices.push(\n `⚠ Ignoring workspace-declared provider \"${id}\" (${describeOrigin(origin)}, key: ${describeApiKeyDeclaration(\n entry.declaration.apiKey,\n workspace,\n )}) from ` +\n `${entry.layers.map((layer) => renderUntrustedText(layer)).join(', ')}: it requires ` +\n `approval. Run ${approveCommand(entry.id)} to review and approve it.`,\n );\n }\n\n for (const selection of gate.withheldSelections) {\n if (!pendingIds.has(selection.providerId)) continue;\n notices.push(\n `⚠ ${describeWithheldSelection(selection)} Run ${approveCommand(selection.providerId)} ` +\n 'to approve it.',\n );\n }\n\n // The user's own selections that merely share a prefix with a withheld provider are not\n // changed; saying so once is what tells them the withheld provider is not what they chose.\n for (const selection of gate.unaffectedSelections) {\n if (!pendingIds.has(selection.providerId)) continue;\n notices.push(`⚠ ${describeUnaffectedSelection(selection)}`);\n }\n\n if (gate.legacyBaseUrl?.state === 'pending') {\n notices.push(\n `⚠ Ignoring baseUrl \"${renderUntrustedText(gate.legacyBaseUrl.baseUrl)}\" from ` +\n `${LEGACY_BASE_URL_ID}: it would receive BOOK_API_KEY, so it requires approval. Run ` +\n `${approveCommand(LEGACY_BASE_URL_ID)} to review and approve it.`,\n );\n }\n\n return notices;\n}\n\n/**\n * One warning per withheld declaration, in the order a host should print them.\n *\n * Empty under `--no-settings`: nothing was withheld for want of approval there,\n * because no settings layer was read at all. Reporting a pending approval then\n * would send the user after a decision that changes nothing — and, since the\n * decision store is the empty default too, would also announce hooks the user\n * has already approved as if they were awaiting a first decision.\n */\nexport function collectWithheldProjectNotices(input: WithheldProjectDeclarations): string[] {\n // `--no-settings` reads no layer, so the gate holds nothing but the legacy `.bookrc.json`\n // `baseUrl`, which is ignored until approved whether or not a settings layer was read.\n const providerNotices = input.providerGate\n ? collectWithheldProviderNotices(input.providerGate, input.workspace)\n : [];\n if (!input.settingsEnabled) return providerNotices;\n\n const projectPath = join(input.workspace, '.book', 'settings.json');\n // At `$HOME` this is the user's own file, which the loader read as the user layer and\n // withheld nothing from (#429).\n const projectSettings = isUserSettingsFile(projectPath) ? null : loadSettingsFile(projectPath);\n const notices: string[] = [];\n\n const allow = partitionProjectAllowRules(\n projectSettings?.permissions?.allow ?? [],\n input.settings.permissions.projectAllowRules,\n );\n for (const rule of allow.pending) {\n notices.push(\n `⚠ Ignoring project-declared permission rule \"${rule}\": it requires approval. Run \\`book doctor\\` to see how to grant it.`,\n );\n }\n\n const hooks = partitionProjectHooks(\n collectDeclaredHooks(projectSettings),\n input.settings.hooks.projectEntries,\n );\n if (hooks.pending.length > 0) {\n const byEvent = new Map<string, number>();\n for (const hook of hooks.pending) {\n byEvent.set(hook.event, (byEvent.get(hook.event) ?? 0) + 1);\n }\n const summary = [...byEvent].map(([event, count]) => `${event} x${count}`).join(', ');\n notices.push(\n `⚠ Ignoring ${hooks.pending.length} project-declared hook(s) (${summary}):` +\n ' hooks require approval. Run `book doctor` to approve them.',\n );\n }\n\n // A withheld `additionalDirectories` entry is the one that has no other symptom: the run\n // simply cannot see the directory, and the model reports the file as missing rather than as\n // un-approved. The notice names the real path, because that is what the decision is keyed by.\n const directories = partitionProjectDirectories(\n collectDeclaredDirectories(input.workspace, projectSettings?.additionalDirectories ?? []),\n input.settings.projectDirectories,\n );\n for (const directory of directories.pending) {\n notices.push(\n `⚠ Ignoring project-declared additionalDirectories entry \"${directory.declared}\"` +\n ` (really ${directory.realPath}): it requires approval. Run \\`book doctor\\` to see how to grant it.`,\n );\n }\n\n // A withheld sandbox key is the quietest of the three families, and the most\n // misleading without a word: the session is simply *less* protected than the\n // repository says, so nothing fails and the run looks ordinary. Reported with\n // the values the file wrote — a key named alone does not tell the reader\n // whether the repository was asking for the sandbox or for its absence — and\n // with the file the value has to go in, since the layer it came from is not\n // where Book reads it from.\n //\n // Both workspace layers are read. The loader filters the sandbox keys of the\n // local one exactly as it does the project one — `.gitignore` does not stop a\n // force-added `settings.local.json` from reaching a clone — so a local file\n // asking to widen the sandbox was being stripped in silence, which is the one\n // symptom these notices exist to remove. The file is named because there are\n // now two of them and the reader has to know which to edit.\n const ignoredSandboxKeys = ignoredWorkspaceSandboxKeys(projectSettings ?? {});\n if (ignoredSandboxKeys.length > 0) {\n const listed = ignoredSandboxKeys.map(formatIgnoredWorkspaceSandboxKey).join(', ');\n notices.push(\n `⚠ Ignoring sandbox settings declared by ${projectPath}: ${listed}. ` +\n `A file inside the workspace may turn the sandbox on and add deny entries, but not loosen it. ` +\n TRUSTED_SETTINGS_LOCATION,\n );\n }\n const localPath = join(input.workspace, '.book', 'settings.local.json');\n const localSettings = loadSettingsFile(localPath);\n const ignoredLocalSandboxKeys = ignoredWorkspaceSandboxKeys(localSettings ?? {});\n if (ignoredLocalSandboxKeys.length > 0) {\n const listed = ignoredLocalSandboxKeys.map(formatIgnoredWorkspaceSandboxKey).join(', ');\n notices.push(\n `⚠ Ignoring sandbox settings declared by ${localPath}: ${listed}. ` +\n `A file inside the workspace may turn the sandbox on and add deny entries, but not loosen it. ` +\n TRUSTED_SETTINGS_LOCATION,\n );\n }\n\n // `sandbox.enabled` is the one key a workspace layer may set, and the loader\n // pairs it with `autoAllowBashIfSandboxed: false` so a repository cannot\n // pre-approve the commands that follow its own sandbox (#373). That is a\n // policy change with no other symptom: every command is still sandboxed and\n // still succeeds, and the user simply stops being asked. Only the layer that\n // actually flipped `enabled` is reported — a repository repeating a key the\n // user already set changed nothing, and saying otherwise on every run is how a\n // notice gets ignored.\n //\n // The user-global layer is the baseline the question needs: whether a\n // workspace layer *turned the sandbox on* depends on what the trusted layers\n // had already decided, and a report that omitted it would name a repository for\n // the user's own decision. Its path comes from the loader, the one place that\n // knows how that file is resolved.\n const userPath = settingsLayerPaths(input.workspace)[0];\n const activation = workspaceLayerThatEnabledSandbox([\n { path: userPath, trust: 'trusted', document: loadSettingsFile(userPath) },\n { path: projectPath, trust: 'repository', document: projectSettings },\n { path: localPath, trust: 'local', document: localSettings },\n ]);\n if (activation) {\n notices.push(\n `⚠ ${activation} declared sandbox.enabled=true, so sandbox.autoAllowBashIfSandboxed is ` +\n `false for this session: no Bash command is auto-approved. ${TRUSTED_SETTINGS_LOCATION}`,\n );\n }\n\n return [...notices, ...providerNotices];\n}\n\n/**\n * One warning per project file the loaders refused because it links out of the repository or to\n * a file that is not Markdown (#539, #543): instruction files, REVIEW.md and project command\n * files. Not tied to `--no-settings`: they are read whatever the settings layers are.\n */\nexport function collectSkippedProjectFileNotices(workspace: string): string[] {\n return [\n ...collectSkippedInstructionNotices(workspace),\n ...collectSkippedReviewNotices(workspace),\n ...collectSkippedCommandNotices(workspace),\n ];\n}\n"],"mappings":"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","names":["result","outcome","transport","join","join"]}