@wrongstack/core 0.297.0 → 0.298.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 (800) hide show
  1. package/dist/chronicle/index.js +126 -22
  2. package/dist/chronicle/project-server-client.d.ts +12 -0
  3. package/dist/chronicle/project-server-protocol.d.ts +22 -0
  4. package/dist/chronicle/project-server.js +238 -157
  5. package/dist/coordination/agents/index.js +136 -1
  6. package/dist/coordination/agents/role-skills.d.ts +3 -2
  7. package/dist/coordination/brain-trace.d.ts +2 -1
  8. package/dist/coordination/director/director-task-registry.d.ts +12 -0
  9. package/dist/coordination/fleet-supervisor.d.ts +21 -0
  10. package/dist/coordination/index.d.ts +23 -21
  11. package/dist/coordination/index.js +16493 -16068
  12. package/dist/coordination/mail-tools.d.ts +3 -3
  13. package/dist/coordination/mailbox-credential-store.d.ts +22 -2
  14. package/dist/coordination/mailbox-credential-throttle.d.ts +63 -0
  15. package/dist/coordination/mailbox-project-server-client.d.ts +16 -0
  16. package/dist/coordination/mailbox-project-server-protocol.d.ts +43 -5
  17. package/dist/coordination/mailbox-project-server.js +508 -253
  18. package/dist/coordination/provider-status-tracker.d.ts +2 -0
  19. package/dist/coordination/remote-mailbox-credential-store.d.ts +5 -5
  20. package/dist/coordination/remote-mailbox.d.ts +8 -4
  21. package/dist/coordination/sqlite-mailbox-credentials.d.ts +11 -0
  22. package/dist/core/fallback-profile-manager.d.ts +14 -0
  23. package/dist/core/index.js +451 -137
  24. package/dist/core/instruction-bundle.d.ts +12 -0
  25. package/dist/core/system-prompt-builder.d.ts +14 -0
  26. package/dist/core/system-prompt-skill-bodies.d.ts +1 -1
  27. package/dist/core/system-prompt-skill-text.d.ts +1 -2
  28. package/dist/defaults/index.js +2081 -1102
  29. package/dist/design/index.js +47 -8
  30. package/dist/execution/design-materialize.d.ts +22 -0
  31. package/dist/execution/index.js +495 -248
  32. package/dist/execution/skill-loader.d.ts +10 -1
  33. package/dist/execution/tool-error-taxonomy.d.ts +31 -0
  34. package/dist/execution/tool-executor.d.ts +1 -0
  35. package/dist/goal/index.js +3 -1
  36. package/dist/hooks/index.js +5 -0
  37. package/dist/hq/auth-audit.d.ts +6 -0
  38. package/dist/hq/auth-store.d.ts +59 -3
  39. package/dist/hq/index.js +401 -101
  40. package/dist/hq/kanban-store.d.ts +3 -0
  41. package/dist/hq/protocol/core.d.ts +3 -15
  42. package/dist/hq/protocol/envelope.d.ts +29 -0
  43. package/dist/hq/protocol/governance.d.ts +34 -0
  44. package/dist/hq/protocol/project.d.ts +3 -0
  45. package/dist/hq/protocol/resume.d.ts +1 -1
  46. package/dist/hq/protocol.d.ts +9 -8
  47. package/dist/hq/protocol.js +675 -0
  48. package/dist/index.js +8518 -6416
  49. package/dist/infrastructure/index.js +198 -101
  50. package/dist/kernel/events/session-events.d.ts +3 -0
  51. package/dist/kernel/events/tool-events.d.ts +3 -1
  52. package/dist/models/index.js +1 -1
  53. package/dist/observability/index.js +27 -0
  54. package/dist/observability/prometheus.d.ts +11 -0
  55. package/dist/plugin/index.d.ts +5 -1
  56. package/dist/plugin/index.js +950 -509
  57. package/dist/plugins/review-store-maintenance.d.ts +26 -0
  58. package/dist/plugins/review-types.d.ts +6 -0
  59. package/dist/security/capabilities.d.ts +45 -1
  60. package/dist/security/error-sanitize.d.ts +49 -0
  61. package/dist/security/file-permissions.d.ts +41 -0
  62. package/dist/security/index.d.ts +9 -6
  63. package/dist/security/index.js +3007 -2032
  64. package/dist/security/permission-policy.d.ts +55 -3
  65. package/dist/security/secret-vault.d.ts +17 -0
  66. package/dist/security/totp.d.ts +86 -0
  67. package/dist/skills/frontmatter.d.ts +12 -1
  68. package/dist/skills/github-fetcher.d.ts +48 -0
  69. package/dist/skills/index.js +137 -26
  70. package/dist/skills/limits.d.ts +19 -0
  71. package/dist/skills/skill-installer.d.ts +13 -0
  72. package/dist/storage/index.js +928 -732
  73. package/dist/storage/provider-config-watcher.d.ts +1 -0
  74. package/dist/storage/session-helpers.d.ts +1 -0
  75. package/dist/storage/session-store.d.ts +9 -2
  76. package/dist/storage/session-workspace-checkpoints.d.ts +5 -0
  77. package/dist/tools/fallback-manage-tools.d.ts +6 -0
  78. package/dist/tools/index.js +287 -131
  79. package/dist/tools/mcp-use.d.ts +1 -1
  80. package/dist/types/blocks.d.ts +7 -0
  81. package/dist/types/config/autonomy.d.ts +12 -3
  82. package/dist/types/config/mcp-features.d.ts +9 -1
  83. package/dist/types/config/root.d.ts +10 -4
  84. package/dist/types/context-window.d.ts +15 -0
  85. package/dist/types/index.d.ts +1 -1
  86. package/dist/types/secret-vault.d.ts +8 -0
  87. package/dist/types/session.d.ts +2 -0
  88. package/dist/types/skill.d.ts +56 -0
  89. package/dist/types/tool-executor.d.ts +2 -0
  90. package/dist/utils/env-typed.d.ts +64 -0
  91. package/dist/utils/glob-match.d.ts +21 -1
  92. package/dist/utils/heap-watchdog.js +1 -1
  93. package/dist/utils/incoming-images.d.ts +19 -0
  94. package/dist/utils/index.d.ts +15 -12
  95. package/dist/utils/index.js +3083 -2801
  96. package/dist/utils/path-segment.d.ts +29 -0
  97. package/dist/utils/win32-cmd.d.ts +25 -0
  98. package/dist/worktree/index.js +5 -0
  99. package/package.json +8 -3
  100. package/skills/chimera/SKILL.md +16 -4
  101. package/skills/data-governance/SKILL.md +92 -0
  102. package/skills/wrongstack-kanban/SKILL.md +125 -64
  103. package/dist/agent-status-helpers.d.ts.map +0 -1
  104. package/dist/agent-status-tracker.d.ts.map +0 -1
  105. package/dist/boot.d.ts.map +0 -1
  106. package/dist/chronicle/context.d.ts.map +0 -1
  107. package/dist/chronicle/decision-adapter.d.ts.map +0 -1
  108. package/dist/chronicle/domain-adapter.d.ts.map +0 -1
  109. package/dist/chronicle/event-hash.d.ts.map +0 -1
  110. package/dist/chronicle/file-observer.d.ts.map +0 -1
  111. package/dist/chronicle/health-monitor.d.ts.map +0 -1
  112. package/dist/chronicle/identity.d.ts.map +0 -1
  113. package/dist/chronicle/index.d.ts.map +0 -1
  114. package/dist/chronicle/index.js.map +0 -7
  115. package/dist/chronicle/journal.d.ts.map +0 -1
  116. package/dist/chronicle/legacy-journal-import.d.ts.map +0 -1
  117. package/dist/chronicle/metrics-store.d.ts.map +0 -1
  118. package/dist/chronicle/partition-filename.d.ts.map +0 -1
  119. package/dist/chronicle/partition-range-cache.d.ts.map +0 -1
  120. package/dist/chronicle/process-adapter.d.ts.map +0 -1
  121. package/dist/chronicle/project-access.d.ts.map +0 -1
  122. package/dist/chronicle/project-server-client.d.ts.map +0 -1
  123. package/dist/chronicle/project-server-endpoint.d.ts.map +0 -1
  124. package/dist/chronicle/project-server-protocol.d.ts.map +0 -1
  125. package/dist/chronicle/project-server.d.ts.map +0 -1
  126. package/dist/chronicle/project-server.js.map +0 -7
  127. package/dist/chronicle/prompt-manifest.d.ts.map +0 -1
  128. package/dist/chronicle/provider-adapter.d.ts.map +0 -1
  129. package/dist/chronicle/query.d.ts.map +0 -1
  130. package/dist/chronicle/review-adapter.d.ts.map +0 -1
  131. package/dist/chronicle/rollup-adapter.d.ts.map +0 -1
  132. package/dist/chronicle/sink.d.ts.map +0 -1
  133. package/dist/chronicle/sqlite-journal.d.ts.map +0 -1
  134. package/dist/chronicle/sqlite-query.d.ts.map +0 -1
  135. package/dist/chronicle/stream-adapter.d.ts.map +0 -1
  136. package/dist/chronicle/tool-adapter.d.ts.map +0 -1
  137. package/dist/chronicle/types.d.ts.map +0 -1
  138. package/dist/coordination/adaptive-concurrency.d.ts.map +0 -1
  139. package/dist/coordination/agent-bridge.d.ts.map +0 -1
  140. package/dist/coordination/agent-monitor.d.ts.map +0 -1
  141. package/dist/coordination/agent-subagent-runner.d.ts.map +0 -1
  142. package/dist/coordination/agents/agent-prompts.d.ts.map +0 -1
  143. package/dist/coordination/agents/index.d.ts.map +0 -1
  144. package/dist/coordination/agents/index.js.map +0 -7
  145. package/dist/coordination/agents/phase1-discovery.d.ts.map +0 -1
  146. package/dist/coordination/agents/phase2-planning.d.ts.map +0 -1
  147. package/dist/coordination/agents/phase3-build.d.ts.map +0 -1
  148. package/dist/coordination/agents/phase3-techstack.d.ts.map +0 -1
  149. package/dist/coordination/agents/phase3-wave1-platform.d.ts.map +0 -1
  150. package/dist/coordination/agents/phase3-wave2-meta.d.ts.map +0 -1
  151. package/dist/coordination/agents/phase4-verify.d.ts.map +0 -1
  152. package/dist/coordination/agents/phase5-review.d.ts.map +0 -1
  153. package/dist/coordination/agents/phase6-domain.d.ts.map +0 -1
  154. package/dist/coordination/agents/phase7-knowledge.d.ts.map +0 -1
  155. package/dist/coordination/agents/phase8-delivery.d.ts.map +0 -1
  156. package/dist/coordination/agents/phase8-wave3-products.d.ts.map +0 -1
  157. package/dist/coordination/agents/phase9-meta.d.ts.map +0 -1
  158. package/dist/coordination/agents/phase9-wave4-platform-meta.d.ts.map +0 -1
  159. package/dist/coordination/agents/project-agent-config-validation.d.ts.map +0 -1
  160. package/dist/coordination/agents/project-agent-consolidation.d.ts.map +0 -1
  161. package/dist/coordination/agents/project-agent-files.d.ts.map +0 -1
  162. package/dist/coordination/agents/project-agent-identity-types.d.ts.map +0 -1
  163. package/dist/coordination/agents/project-agent-identity.d.ts.map +0 -1
  164. package/dist/coordination/agents/project-agent-knowledge-manifests.d.ts.map +0 -1
  165. package/dist/coordination/agents/project-agent-learning-entries.d.ts.map +0 -1
  166. package/dist/coordination/agents/project-agent-learning-normalize.d.ts.map +0 -1
  167. package/dist/coordination/agents/project-agent-learning-policy.d.ts.map +0 -1
  168. package/dist/coordination/agents/project-agent-learning-structured.d.ts.map +0 -1
  169. package/dist/coordination/agents/project-agent-paths.d.ts.map +0 -1
  170. package/dist/coordination/agents/project-agent-profile.d.ts.map +0 -1
  171. package/dist/coordination/agents/role-skills.d.ts.map +0 -1
  172. package/dist/coordination/agents/types.d.ts.map +0 -1
  173. package/dist/coordination/agents.d.ts.map +0 -1
  174. package/dist/coordination/auto-extend.d.ts.map +0 -1
  175. package/dist/coordination/autonomous-brain.d.ts.map +0 -1
  176. package/dist/coordination/autonomous-coordinator.d.ts.map +0 -1
  177. package/dist/coordination/brain-cache.d.ts.map +0 -1
  178. package/dist/coordination/brain-heuristics.d.ts.map +0 -1
  179. package/dist/coordination/brain-ledger.d.ts.map +0 -1
  180. package/dist/coordination/brain-monitor.d.ts.map +0 -1
  181. package/dist/coordination/brain-rules.d.ts.map +0 -1
  182. package/dist/coordination/brain-telemetry.d.ts.map +0 -1
  183. package/dist/coordination/brain-trace.d.ts.map +0 -1
  184. package/dist/coordination/brain.d.ts.map +0 -1
  185. package/dist/coordination/change-manager.d.ts.map +0 -1
  186. package/dist/coordination/checkpoint-wiring.d.ts.map +0 -1
  187. package/dist/coordination/collab-bus.d.ts.map +0 -1
  188. package/dist/coordination/collab-debug-types.d.ts.map +0 -1
  189. package/dist/coordination/collab-debug.d.ts.map +0 -1
  190. package/dist/coordination/collab-director-host.d.ts.map +0 -1
  191. package/dist/coordination/commit-safety.d.ts.map +0 -1
  192. package/dist/coordination/consensus-protocol.d.ts.map +0 -1
  193. package/dist/coordination/coordinator/error-classifier.d.ts.map +0 -1
  194. package/dist/coordination/delegate-tool.d.ts.map +0 -1
  195. package/dist/coordination/dep-watcher-bridge.d.ts.map +0 -1
  196. package/dist/coordination/dep-watcher.d.ts.map +0 -1
  197. package/dist/coordination/director/director-btw-notes.d.ts.map +0 -1
  198. package/dist/coordination/director/director-budget-policy.d.ts.map +0 -1
  199. package/dist/coordination/director/director-collab.d.ts.map +0 -1
  200. package/dist/coordination/director/director-errors.d.ts.map +0 -1
  201. package/dist/coordination/director/director-task-registry.d.ts.map +0 -1
  202. package/dist/coordination/director/director-toolset.d.ts.map +0 -1
  203. package/dist/coordination/director-basic-tools.d.ts.map +0 -1
  204. package/dist/coordination/director-collab-tools.d.ts.map +0 -1
  205. package/dist/coordination/director-host-contracts.d.ts.map +0 -1
  206. package/dist/coordination/director-input-helpers.d.ts.map +0 -1
  207. package/dist/coordination/director-kanban-queue-helpers.d.ts.map +0 -1
  208. package/dist/coordination/director-options.d.ts.map +0 -1
  209. package/dist/coordination/director-prompts.d.ts.map +0 -1
  210. package/dist/coordination/director-quality-gate-tool.d.ts.map +0 -1
  211. package/dist/coordination/director-session.d.ts.map +0 -1
  212. package/dist/coordination/director-spawn-model.d.ts.map +0 -1
  213. package/dist/coordination/director-tools.d.ts.map +0 -1
  214. package/dist/coordination/director.d.ts.map +0 -1
  215. package/dist/coordination/dispatcher.d.ts.map +0 -1
  216. package/dist/coordination/file-author-tracker.d.ts.map +0 -1
  217. package/dist/coordination/fleet-bus.d.ts.map +0 -1
  218. package/dist/coordination/fleet-event-validation.d.ts.map +0 -1
  219. package/dist/coordination/fleet-manager.d.ts.map +0 -1
  220. package/dist/coordination/fleet-spawn.d.ts.map +0 -1
  221. package/dist/coordination/fleet-status-tool.d.ts.map +0 -1
  222. package/dist/coordination/fleet-supervisor.d.ts.map +0 -1
  223. package/dist/coordination/fleet.d.ts.map +0 -1
  224. package/dist/coordination/global-mailbox-completion.d.ts.map +0 -1
  225. package/dist/coordination/global-mailbox-paths.d.ts.map +0 -1
  226. package/dist/coordination/icoordinator.d.ts.map +0 -1
  227. package/dist/coordination/ifleet-manager.d.ts.map +0 -1
  228. package/dist/coordination/in-memory-transport.d.ts.map +0 -1
  229. package/dist/coordination/index.d.ts.map +0 -1
  230. package/dist/coordination/index.js.map +0 -7
  231. package/dist/coordination/knowledge-graph.d.ts.map +0 -1
  232. package/dist/coordination/large-answer-store.d.ts.map +0 -1
  233. package/dist/coordination/mail-tools.d.ts.map +0 -1
  234. package/dist/coordination/mailbox-actions.d.ts.map +0 -1
  235. package/dist/coordination/mailbox-auth-types.d.ts.map +0 -1
  236. package/dist/coordination/mailbox-codecs.d.ts.map +0 -1
  237. package/dist/coordination/mailbox-constants.d.ts.map +0 -1
  238. package/dist/coordination/mailbox-credential-store.d.ts.map +0 -1
  239. package/dist/coordination/mailbox-events.d.ts.map +0 -1
  240. package/dist/coordination/mailbox-health.d.ts.map +0 -1
  241. package/dist/coordination/mailbox-hooks.d.ts.map +0 -1
  242. package/dist/coordination/mailbox-http-auth.d.ts.map +0 -1
  243. package/dist/coordination/mailbox-http-rate-limit.d.ts.map +0 -1
  244. package/dist/coordination/mailbox-http-router.d.ts.map +0 -1
  245. package/dist/coordination/mailbox-http-validation.d.ts.map +0 -1
  246. package/dist/coordination/mailbox-message-codec.d.ts.map +0 -1
  247. package/dist/coordination/mailbox-parse-state.d.ts.map +0 -1
  248. package/dist/coordination/mailbox-project-server-client.d.ts.map +0 -1
  249. package/dist/coordination/mailbox-project-server-endpoint.d.ts.map +0 -1
  250. package/dist/coordination/mailbox-project-server-protocol.d.ts.map +0 -1
  251. package/dist/coordination/mailbox-project-server.d.ts.map +0 -1
  252. package/dist/coordination/mailbox-project-server.js.map +0 -7
  253. package/dist/coordination/mailbox-receipt-folding.d.ts.map +0 -1
  254. package/dist/coordination/mailbox-registry-codec.d.ts.map +0 -1
  255. package/dist/coordination/mailbox-retention-state.d.ts.map +0 -1
  256. package/dist/coordination/mailbox-status-mappers.d.ts.map +0 -1
  257. package/dist/coordination/mailbox-tool.d.ts.map +0 -1
  258. package/dist/coordination/mailbox-type-properties.d.ts.map +0 -1
  259. package/dist/coordination/mailbox-types.d.ts.map +0 -1
  260. package/dist/coordination/model-matrix.d.ts.map +0 -1
  261. package/dist/coordination/multi-agent-coordinator.d.ts.map +0 -1
  262. package/dist/coordination/multi-agent-timeout.d.ts.map +0 -1
  263. package/dist/coordination/null-fleet-bus.d.ts.map +0 -1
  264. package/dist/coordination/package-author-tracker.d.ts.map +0 -1
  265. package/dist/coordination/package-outdated-watcher.d.ts.map +0 -1
  266. package/dist/coordination/provider-status-tracker.d.ts.map +0 -1
  267. package/dist/coordination/remote-mailbox-credential-store.d.ts.map +0 -1
  268. package/dist/coordination/remote-mailbox.d.ts.map +0 -1
  269. package/dist/coordination/single-instance-mailbox.d.ts.map +0 -1
  270. package/dist/coordination/spawn-budget.d.ts.map +0 -1
  271. package/dist/coordination/sqlite-mailbox-compaction.d.ts.map +0 -1
  272. package/dist/coordination/sqlite-mailbox-credentials.d.ts.map +0 -1
  273. package/dist/coordination/sqlite-mailbox-rows.d.ts.map +0 -1
  274. package/dist/coordination/sqlite-mailbox-schema.d.ts.map +0 -1
  275. package/dist/coordination/sqlite-mailbox.d.ts.map +0 -1
  276. package/dist/coordination/subagent-budget.d.ts.map +0 -1
  277. package/dist/coordination/subagent-nicknames.d.ts.map +0 -1
  278. package/dist/coordination/subagent-result-tool.d.ts.map +0 -1
  279. package/dist/coordination/task-auctioneer.d.ts.map +0 -1
  280. package/dist/coordination/task-dag.d.ts.map +0 -1
  281. package/dist/coordination/techstack-mailbox-consumer.d.ts.map +0 -1
  282. package/dist/coordination/transport.d.ts.map +0 -1
  283. package/dist/coordination/worktree-task-runner.d.ts.map +0 -1
  284. package/dist/core/agent-internals.d.ts.map +0 -1
  285. package/dist/core/agent-loop.d.ts.map +0 -1
  286. package/dist/core/agent-response.d.ts.map +0 -1
  287. package/dist/core/agent-tools.d.ts.map +0 -1
  288. package/dist/core/agent-types.d.ts.map +0 -1
  289. package/dist/core/agent.d.ts.map +0 -1
  290. package/dist/core/btw.d.ts.map +0 -1
  291. package/dist/core/context.d.ts.map +0 -1
  292. package/dist/core/continue-intent.d.ts.map +0 -1
  293. package/dist/core/continue-to-next-iteration.d.ts.map +0 -1
  294. package/dist/core/conversation-state.d.ts.map +0 -1
  295. package/dist/core/fallback-model.d.ts.map +0 -1
  296. package/dist/core/fallback-profile-manager.d.ts.map +0 -1
  297. package/dist/core/fleet-pulse.d.ts.map +0 -1
  298. package/dist/core/index.d.ts.map +0 -1
  299. package/dist/core/index.js.map +0 -7
  300. package/dist/core/input-builder.d.ts.map +0 -1
  301. package/dist/core/instruction-bundle.d.ts.map +0 -1
  302. package/dist/core/iteration-limit.d.ts.map +0 -1
  303. package/dist/core/mailbox-loop.d.ts.map +0 -1
  304. package/dist/core/model-availability-calendar.d.ts.map +0 -1
  305. package/dist/core/model-ref.d.ts.map +0 -1
  306. package/dist/core/model-ref.js.map +0 -7
  307. package/dist/core/modes/brief.d.ts.map +0 -1
  308. package/dist/core/modes/default.d.ts.map +0 -1
  309. package/dist/core/modes/teach.d.ts.map +0 -1
  310. package/dist/core/provider-runner.d.ts.map +0 -1
  311. package/dist/core/queued-messages.d.ts.map +0 -1
  312. package/dist/core/request-provider-binding.d.ts.map +0 -1
  313. package/dist/core/run-env.d.ts.map +0 -1
  314. package/dist/core/streaming-response-builder.d.ts.map +0 -1
  315. package/dist/core/system-prompt-blocks.d.ts.map +0 -1
  316. package/dist/core/system-prompt-builder.d.ts.map +0 -1
  317. package/dist/core/system-prompt-environment-probes.d.ts.map +0 -1
  318. package/dist/core/system-prompt-environment.d.ts.map +0 -1
  319. package/dist/core/system-prompt-memory-skills.d.ts.map +0 -1
  320. package/dist/core/system-prompt-plan.d.ts.map +0 -1
  321. package/dist/core/system-prompt-shell.d.ts.map +0 -1
  322. package/dist/core/system-prompt-skill-bodies.d.ts.map +0 -1
  323. package/dist/core/system-prompt-skill-text.d.ts.map +0 -1
  324. package/dist/defaults/index.d.ts.map +0 -1
  325. package/dist/defaults/index.js.map +0 -7
  326. package/dist/design/index.d.ts.map +0 -1
  327. package/dist/design/index.js.map +0 -7
  328. package/dist/execution/auto-compaction-middleware.d.ts.map +0 -1
  329. package/dist/execution/autonomous-runner.d.ts.map +0 -1
  330. package/dist/execution/autonomy-brain.d.ts.map +0 -1
  331. package/dist/execution/autonomy-prompt-contributor.d.ts.map +0 -1
  332. package/dist/execution/brain-chain.d.ts.map +0 -1
  333. package/dist/execution/brain-circuit.d.ts.map +0 -1
  334. package/dist/execution/brain-evaluation.d.ts.map +0 -1
  335. package/dist/execution/brain-runtime-constants.d.ts.map +0 -1
  336. package/dist/execution/brain-runtime.d.ts.map +0 -1
  337. package/dist/execution/compaction-core.d.ts.map +0 -1
  338. package/dist/execution/compaction-scoring.d.ts.map +0 -1
  339. package/dist/execution/compaction-summary-cache.d.ts.map +0 -1
  340. package/dist/execution/compactor.d.ts.map +0 -1
  341. package/dist/execution/council-brain.d.ts.map +0 -1
  342. package/dist/execution/council-orchestrator.d.ts.map +0 -1
  343. package/dist/execution/council-personas.d.ts.map +0 -1
  344. package/dist/execution/council-profiles.d.ts.map +0 -1
  345. package/dist/execution/council-prompts.d.ts.map +0 -1
  346. package/dist/execution/council-resolution.d.ts.map +0 -1
  347. package/dist/execution/design-color.d.ts.map +0 -1
  348. package/dist/execution/design-detect.d.ts.map +0 -1
  349. package/dist/execution/design-kit-loader.d.ts.map +0 -1
  350. package/dist/execution/design-materialize.d.ts.map +0 -1
  351. package/dist/execution/design-project-store.d.ts.map +0 -1
  352. package/dist/execution/design-tune.d.ts.map +0 -1
  353. package/dist/execution/design-verify.d.ts.map +0 -1
  354. package/dist/execution/enhance-recovery.d.ts.map +0 -1
  355. package/dist/execution/error-handler.d.ts.map +0 -1
  356. package/dist/execution/eternal-autonomy-types.d.ts.map +0 -1
  357. package/dist/execution/eternal-autonomy.d.ts.map +0 -1
  358. package/dist/execution/goal-preamble.d.ts.map +0 -1
  359. package/dist/execution/index.d.ts.map +0 -1
  360. package/dist/execution/index.js.map +0 -7
  361. package/dist/execution/intelligent-compactor.d.ts.map +0 -1
  362. package/dist/execution/model-runtime.d.ts.map +0 -1
  363. package/dist/execution/one-shot-llm.d.ts.map +0 -1
  364. package/dist/execution/parallel-eternal-engine.d.ts.map +0 -1
  365. package/dist/execution/prompt-enhancer.d.ts.map +0 -1
  366. package/dist/execution/prompt-enhancer.js.map +0 -7
  367. package/dist/execution/prompt-loader.d.ts.map +0 -1
  368. package/dist/execution/provider-runner-impl.d.ts.map +0 -1
  369. package/dist/execution/regex-patterns.d.ts.map +0 -1
  370. package/dist/execution/retry-policy.d.ts.map +0 -1
  371. package/dist/execution/selective-compactor.d.ts.map +0 -1
  372. package/dist/execution/skill-loader.d.ts.map +0 -1
  373. package/dist/execution/strategy-compactor.d.ts.map +0 -1
  374. package/dist/execution/subagent-compaction.d.ts.map +0 -1
  375. package/dist/execution/tool-executor-logging.d.ts.map +0 -1
  376. package/dist/execution/tool-executor-results.d.ts.map +0 -1
  377. package/dist/execution/tool-executor-stream.d.ts.map +0 -1
  378. package/dist/execution/tool-executor-support.d.ts.map +0 -1
  379. package/dist/execution/tool-executor.d.ts.map +0 -1
  380. package/dist/extension/extension-points.d.ts.map +0 -1
  381. package/dist/extension/index.d.ts.map +0 -1
  382. package/dist/extension/index.js.map +0 -7
  383. package/dist/extension/registry.d.ts.map +0 -1
  384. package/dist/fleet-notifier.d.ts.map +0 -1
  385. package/dist/goal/checkpoint.d.ts.map +0 -1
  386. package/dist/goal/goal-assessor.d.ts.map +0 -1
  387. package/dist/goal/goal-planner.d.ts.map +0 -1
  388. package/dist/goal/goal-runner.d.ts.map +0 -1
  389. package/dist/goal/index.d.ts.map +0 -1
  390. package/dist/goal/index.js.map +0 -7
  391. package/dist/goal/phase-board-mutations.d.ts.map +0 -1
  392. package/dist/goal/phase-graph-builder.d.ts.map +0 -1
  393. package/dist/goal/phase-orchestrator-integration.d.ts.map +0 -1
  394. package/dist/goal/phase-orchestrator-queries.d.ts.map +0 -1
  395. package/dist/goal/phase-orchestrator-runtime.d.ts.map +0 -1
  396. package/dist/goal/phase-orchestrator-types.d.ts.map +0 -1
  397. package/dist/goal/phase-orchestrator.d.ts.map +0 -1
  398. package/dist/goal/phase-store.d.ts.map +0 -1
  399. package/dist/goal/types.d.ts.map +0 -1
  400. package/dist/hooks/http-executor.d.ts.map +0 -1
  401. package/dist/hooks/index.d.ts.map +0 -1
  402. package/dist/hooks/index.js.map +0 -7
  403. package/dist/hooks/registry.d.ts.map +0 -1
  404. package/dist/hooks/runner.d.ts.map +0 -1
  405. package/dist/hooks/shell-executor.d.ts.map +0 -1
  406. package/dist/hooks/shell-hooks-equal.d.ts.map +0 -1
  407. package/dist/hq/alerts.d.ts.map +0 -1
  408. package/dist/hq/auth-audit.d.ts.map +0 -1
  409. package/dist/hq/auth-store.d.ts.map +0 -1
  410. package/dist/hq/bootstrap-store.d.ts.map +0 -1
  411. package/dist/hq/brain-bridge.d.ts.map +0 -1
  412. package/dist/hq/bridge-context.d.ts.map +0 -1
  413. package/dist/hq/commands.d.ts.map +0 -1
  414. package/dist/hq/cost-bridge.d.ts.map +0 -1
  415. package/dist/hq/exposure.d.ts.map +0 -1
  416. package/dist/hq/factory.d.ts.map +0 -1
  417. package/dist/hq/fleet-bridge.d.ts.map +0 -1
  418. package/dist/hq/index.d.ts.map +0 -1
  419. package/dist/hq/index.js.map +0 -7
  420. package/dist/hq/kanban-store.d.ts.map +0 -1
  421. package/dist/hq/mailbox-mapper.d.ts.map +0 -1
  422. package/dist/hq/persistence/event-log.d.ts.map +0 -1
  423. package/dist/hq/persistence/jsonl-io.d.ts.map +0 -1
  424. package/dist/hq/persistence/simple-log.d.ts.map +0 -1
  425. package/dist/hq/persistence/snapshot-store.d.ts.map +0 -1
  426. package/dist/hq/persistence/timeseries-store.d.ts.map +0 -1
  427. package/dist/hq/persistence.d.ts.map +0 -1
  428. package/dist/hq/protocol/brain.d.ts.map +0 -1
  429. package/dist/hq/protocol/browser.d.ts.map +0 -1
  430. package/dist/hq/protocol/client.d.ts.map +0 -1
  431. package/dist/hq/protocol/core.d.ts.map +0 -1
  432. package/dist/hq/protocol/fleet.d.ts.map +0 -1
  433. package/dist/hq/protocol/kanban.d.ts.map +0 -1
  434. package/dist/hq/protocol/mailbox.d.ts.map +0 -1
  435. package/dist/hq/protocol/mcp.d.ts.map +0 -1
  436. package/dist/hq/protocol/peer.d.ts.map +0 -1
  437. package/dist/hq/protocol/project.d.ts.map +0 -1
  438. package/dist/hq/protocol/resume.d.ts.map +0 -1
  439. package/dist/hq/protocol/session.d.ts.map +0 -1
  440. package/dist/hq/protocol/tool.d.ts.map +0 -1
  441. package/dist/hq/protocol.d.ts.map +0 -1
  442. package/dist/hq/publisher.d.ts.map +0 -1
  443. package/dist/hq/redaction.d.ts.map +0 -1
  444. package/dist/hq/session-bridge.d.ts.map +0 -1
  445. package/dist/hq/tool-bridge.d.ts.map +0 -1
  446. package/dist/hq/transcript-mapper.d.ts.map +0 -1
  447. package/dist/hq/worktree-bridge.d.ts.map +0 -1
  448. package/dist/hq/write-queues.d.ts.map +0 -1
  449. package/dist/index.d.ts.map +0 -1
  450. package/dist/index.js.map +0 -7
  451. package/dist/infrastructure/context-manager.d.ts.map +0 -1
  452. package/dist/infrastructure/index.d.ts.map +0 -1
  453. package/dist/infrastructure/index.js.map +0 -7
  454. package/dist/infrastructure/logger.d.ts.map +0 -1
  455. package/dist/infrastructure/mcp-servers.d.ts.map +0 -1
  456. package/dist/infrastructure/path-resolver.d.ts.map +0 -1
  457. package/dist/infrastructure/provider-cache-ledger.d.ts.map +0 -1
  458. package/dist/infrastructure/token-counter.d.ts.map +0 -1
  459. package/dist/kernel/container.d.ts.map +0 -1
  460. package/dist/kernel/events/agent-events.d.ts.map +0 -1
  461. package/dist/kernel/events/brain-events.d.ts.map +0 -1
  462. package/dist/kernel/events/file-events.d.ts.map +0 -1
  463. package/dist/kernel/events/fleet-events.d.ts.map +0 -1
  464. package/dist/kernel/events/memory-events.d.ts.map +0 -1
  465. package/dist/kernel/events/network-events.d.ts.map +0 -1
  466. package/dist/kernel/events/process-events.d.ts.map +0 -1
  467. package/dist/kernel/events/provider-events.d.ts.map +0 -1
  468. package/dist/kernel/events/sdd-events.d.ts.map +0 -1
  469. package/dist/kernel/events/session-events.d.ts.map +0 -1
  470. package/dist/kernel/events/tool-events.d.ts.map +0 -1
  471. package/dist/kernel/events/worktree-events.d.ts.map +0 -1
  472. package/dist/kernel/events.d.ts.map +0 -1
  473. package/dist/kernel/index.d.ts.map +0 -1
  474. package/dist/kernel/index.js.map +0 -7
  475. package/dist/kernel/pipeline.d.ts.map +0 -1
  476. package/dist/kernel/run-controller.d.ts.map +0 -1
  477. package/dist/kernel/tokens.d.ts.map +0 -1
  478. package/dist/mailbox-attach.d.ts.map +0 -1
  479. package/dist/middleware/collab-pause.d.ts.map +0 -1
  480. package/dist/models/alibaba-token-plan-catalog.d.ts.map +0 -1
  481. package/dist/models/codex-catalog.d.ts.map +0 -1
  482. package/dist/models/index.d.ts.map +0 -1
  483. package/dist/models/index.js.map +0 -7
  484. package/dist/models/llm-selector.d.ts.map +0 -1
  485. package/dist/models/mode-store.d.ts.map +0 -1
  486. package/dist/models/model-intelligence.d.ts.map +0 -1
  487. package/dist/models/model-router.d.ts.map +0 -1
  488. package/dist/models/models-registry.d.ts.map +0 -1
  489. package/dist/models/provider-model-resolve.d.ts.map +0 -1
  490. package/dist/notifications/index.d.ts.map +0 -1
  491. package/dist/notifications/index.js.map +0 -7
  492. package/dist/notifications/notifier-impl.d.ts.map +0 -1
  493. package/dist/notifications/notifier.d.ts.map +0 -1
  494. package/dist/notifications/types.d.ts.map +0 -1
  495. package/dist/observability/event-bridge.d.ts.map +0 -1
  496. package/dist/observability/health.d.ts.map +0 -1
  497. package/dist/observability/index.d.ts.map +0 -1
  498. package/dist/observability/index.js.map +0 -7
  499. package/dist/observability/metrics.d.ts.map +0 -1
  500. package/dist/observability/network-telemetry.d.ts.map +0 -1
  501. package/dist/observability/otel-tracer.d.ts.map +0 -1
  502. package/dist/observability/otlp-metrics.d.ts.map +0 -1
  503. package/dist/observability/otlp-traces.d.ts.map +0 -1
  504. package/dist/observability/process-telemetry.d.ts.map +0 -1
  505. package/dist/observability/prometheus.d.ts.map +0 -1
  506. package/dist/observability/redact-command.d.ts.map +0 -1
  507. package/dist/observability/tracer.d.ts.map +0 -1
  508. package/dist/plugin/api.d.ts.map +0 -1
  509. package/dist/plugin/config.d.ts.map +0 -1
  510. package/dist/plugin/index.d.ts.map +0 -1
  511. package/dist/plugin/index.js.map +0 -7
  512. package/dist/plugin/loader.d.ts.map +0 -1
  513. package/dist/plugins/auto-review-plugin.d.ts.map +0 -1
  514. package/dist/plugins/chimera-plugin.d.ts.map +0 -1
  515. package/dist/plugins/prompts-plugin.d.ts.map +0 -1
  516. package/dist/plugins/review-claim-registry.d.ts.map +0 -1
  517. package/dist/plugins/review-context-builder.d.ts.map +0 -1
  518. package/dist/plugins/review-finding-commands.d.ts.map +0 -1
  519. package/dist/plugins/review-finding-integration.d.ts.map +0 -1
  520. package/dist/plugins/review-finding-parser.d.ts.map +0 -1
  521. package/dist/plugins/review-finding-store.d.ts.map +0 -1
  522. package/dist/plugins/review-finding-types.d.ts.map +0 -1
  523. package/dist/plugins/review-report-integration.d.ts.map +0 -1
  524. package/dist/plugins/review-report-store.d.ts.map +0 -1
  525. package/dist/plugins/review-report-types.d.ts.map +0 -1
  526. package/dist/plugins/review-types.d.ts.map +0 -1
  527. package/dist/plugins/skills-plugin.d.ts.map +0 -1
  528. package/dist/plugins/sync-plugin.d.ts.map +0 -1
  529. package/dist/prompts/index.d.ts.map +0 -1
  530. package/dist/prompts/prompt-installer.d.ts.map +0 -1
  531. package/dist/prompts/prompt-manifest-store.d.ts.map +0 -1
  532. package/dist/registry/index.d.ts.map +0 -1
  533. package/dist/registry/index.js.map +0 -7
  534. package/dist/registry/provider-registry.d.ts.map +0 -1
  535. package/dist/registry/slash-command-registry.d.ts.map +0 -1
  536. package/dist/registry/tool-registry.d.ts.map +0 -1
  537. package/dist/replay/hash.d.ts.map +0 -1
  538. package/dist/replay/index.d.ts.map +0 -1
  539. package/dist/replay/index.js.map +0 -7
  540. package/dist/replay/replay-provider-runner.d.ts.map +0 -1
  541. package/dist/security/capabilities.d.ts.map +0 -1
  542. package/dist/security/config-secrets.d.ts.map +0 -1
  543. package/dist/security/directory-permission-policy.d.ts.map +0 -1
  544. package/dist/security/directory-policy-schema.d.ts.map +0 -1
  545. package/dist/security/index.d.ts.map +0 -1
  546. package/dist/security/index.js.map +0 -7
  547. package/dist/security/kanban-boundary.d.ts.map +0 -1
  548. package/dist/security/permission-policy-schema.d.ts.map +0 -1
  549. package/dist/security/permission-policy.d.ts.map +0 -1
  550. package/dist/security/readonly-permission-policy.d.ts.map +0 -1
  551. package/dist/security/secret-scrubber.d.ts.map +0 -1
  552. package/dist/security/secret-vault.d.ts.map +0 -1
  553. package/dist/security/trust-boundary.d.ts.map +0 -1
  554. package/dist/security/yolo-risk.d.ts.map +0 -1
  555. package/dist/session-registry-atomic-file.d.ts.map +0 -1
  556. package/dist/session-registry-types.d.ts.map +0 -1
  557. package/dist/session-registry.d.ts.map +0 -1
  558. package/dist/skills/foreign-sources.d.ts.map +0 -1
  559. package/dist/skills/frontmatter.d.ts.map +0 -1
  560. package/dist/skills/github-fetcher.d.ts.map +0 -1
  561. package/dist/skills/index.d.ts.map +0 -1
  562. package/dist/skills/index.js.map +0 -7
  563. package/dist/skills/limits.d.ts.map +0 -1
  564. package/dist/skills/manifest-store.d.ts.map +0 -1
  565. package/dist/skills/registry/github-direct-adapter.d.ts.map +0 -1
  566. package/dist/skills/registry/registry-adapter.d.ts.map +0 -1
  567. package/dist/skills/registry/skills-sh-adapter.d.ts.map +0 -1
  568. package/dist/skills/skill-generator.d.ts.map +0 -1
  569. package/dist/skills/skill-installer.d.ts.map +0 -1
  570. package/dist/storage/annotations-store.d.ts.map +0 -1
  571. package/dist/storage/attachment-store.d.ts.map +0 -1
  572. package/dist/storage/cloud-sync.d.ts.map +0 -1
  573. package/dist/storage/completed-work-checkpoint.d.ts.map +0 -1
  574. package/dist/storage/config-loader/bootstrap.d.ts.map +0 -1
  575. package/dist/storage/config-loader/default-repair.d.ts.map +0 -1
  576. package/dist/storage/config-loader/defaults.d.ts.map +0 -1
  577. package/dist/storage/config-loader/diagnostics.d.ts.map +0 -1
  578. package/dist/storage/config-loader/env-overrides.d.ts.map +0 -1
  579. package/dist/storage/config-loader/in-project-policy.d.ts.map +0 -1
  580. package/dist/storage/config-loader/inline-provider-models.d.ts.map +0 -1
  581. package/dist/storage/config-loader/legacy-sage-migration.d.ts.map +0 -1
  582. package/dist/storage/config-loader/path-identity.d.ts.map +0 -1
  583. package/dist/storage/config-loader/types.d.ts.map +0 -1
  584. package/dist/storage/config-loader/validation.d.ts.map +0 -1
  585. package/dist/storage/config-loader.d.ts.map +0 -1
  586. package/dist/storage/config-migration.d.ts.map +0 -1
  587. package/dist/storage/config-store.d.ts.map +0 -1
  588. package/dist/storage/director-state.d.ts.map +0 -1
  589. package/dist/storage/file-session-writer.d.ts.map +0 -1
  590. package/dist/storage/goal-coordination.d.ts.map +0 -1
  591. package/dist/storage/goal-kanban.d.ts.map +0 -1
  592. package/dist/storage/goal-store.d.ts.map +0 -1
  593. package/dist/storage/index.d.ts.map +0 -1
  594. package/dist/storage/index.js.map +0 -7
  595. package/dist/storage/input-history-store.d.ts.map +0 -1
  596. package/dist/storage/memory-backend.d.ts.map +0 -1
  597. package/dist/storage/memory-consolidator.d.ts.map +0 -1
  598. package/dist/storage/memory-graph-backend.d.ts.map +0 -1
  599. package/dist/storage/plan-store.d.ts.map +0 -1
  600. package/dist/storage/plan-templates.d.ts.map +0 -1
  601. package/dist/storage/prompt-store.d.ts.map +0 -1
  602. package/dist/storage/prompt-usage-store.d.ts.map +0 -1
  603. package/dist/storage/provider-config-watcher.d.ts.map +0 -1
  604. package/dist/storage/queue-store.d.ts.map +0 -1
  605. package/dist/storage/recovery-lock.d.ts.map +0 -1
  606. package/dist/storage/replay-log-store.d.ts.map +0 -1
  607. package/dist/storage/session-analyzer.d.ts.map +0 -1
  608. package/dist/storage/session-checkpoint-cas.d.ts.map +0 -1
  609. package/dist/storage/session-event-bridge.d.ts.map +0 -1
  610. package/dist/storage/session-helpers.d.ts.map +0 -1
  611. package/dist/storage/session-id-resolver.d.ts.map +0 -1
  612. package/dist/storage/session-id.d.ts.map +0 -1
  613. package/dist/storage/session-read-scrubber.d.ts.map +0 -1
  614. package/dist/storage/session-reader.d.ts.map +0 -1
  615. package/dist/storage/session-recovery.d.ts.map +0 -1
  616. package/dist/storage/session-resume-validation.d.ts.map +0 -1
  617. package/dist/storage/session-rewind-apply.d.ts.map +0 -1
  618. package/dist/storage/session-rewinder.d.ts.map +0 -1
  619. package/dist/storage/session-store/delete-session-artifacts.d.ts.map +0 -1
  620. package/dist/storage/session-store/delete-session-guards.d.ts.map +0 -1
  621. package/dist/storage/session-store/directory-scan.d.ts.map +0 -1
  622. package/dist/storage/session-store/directory-session-files.d.ts.map +0 -1
  623. package/dist/storage/session-store/events.d.ts.map +0 -1
  624. package/dist/storage/session-store/fork-session.d.ts.map +0 -1
  625. package/dist/storage/session-store/index-reader.d.ts.map +0 -1
  626. package/dist/storage/session-store/load-cache.d.ts.map +0 -1
  627. package/dist/storage/session-store/load-session-data.d.ts.map +0 -1
  628. package/dist/storage/session-store/paths.d.ts.map +0 -1
  629. package/dist/storage/session-store/prune-helpers.d.ts.map +0 -1
  630. package/dist/storage/session-store/replay.d.ts.map +0 -1
  631. package/dist/storage/session-store/search-events.d.ts.map +0 -1
  632. package/dist/storage/session-store/shard-manifest.d.ts.map +0 -1
  633. package/dist/storage/session-store/summary-builder.d.ts.map +0 -1
  634. package/dist/storage/session-store/summary-header.d.ts.map +0 -1
  635. package/dist/storage/session-store/types.d.ts.map +0 -1
  636. package/dist/storage/session-store.d.ts.map +0 -1
  637. package/dist/storage/session-summary.d.ts.map +0 -1
  638. package/dist/storage/session-tool-call-ends.d.ts.map +0 -1
  639. package/dist/storage/session-writer-scrubber.d.ts.map +0 -1
  640. package/dist/storage/session-writer-truncate.d.ts.map +0 -1
  641. package/dist/storage/storage-concurrency.d.ts.map +0 -1
  642. package/dist/storage/task-store.d.ts.map +0 -1
  643. package/dist/storage/todos-checkpoint.d.ts.map +0 -1
  644. package/dist/storage/tool-audit-log.d.ts.map +0 -1
  645. package/dist/tasking/index.d.ts.map +0 -1
  646. package/dist/tasking/index.js.map +0 -7
  647. package/dist/tasking/task-store.d.ts.map +0 -1
  648. package/dist/tasking/task-tracker.d.ts.map +0 -1
  649. package/dist/tools/council-tool.d.ts.map +0 -1
  650. package/dist/tools/fallback-chain-manage-tool.d.ts.map +0 -1
  651. package/dist/tools/fallback-favorite-manage-tool.d.ts.map +0 -1
  652. package/dist/tools/fallback-manage-helpers.d.ts.map +0 -1
  653. package/dist/tools/fallback-manage-tool-options.d.ts.map +0 -1
  654. package/dist/tools/fallback-manage-tools.d.ts.map +0 -1
  655. package/dist/tools/fallback-model-ref-parse.d.ts.map +0 -1
  656. package/dist/tools/fallback-provider-key-store.d.ts.map +0 -1
  657. package/dist/tools/fallback-system-config-view-tool.d.ts.map +0 -1
  658. package/dist/tools/index.d.ts.map +0 -1
  659. package/dist/tools/index.js.map +0 -7
  660. package/dist/tools/mcp-control.d.ts.map +0 -1
  661. package/dist/tools/mcp-use.d.ts.map +0 -1
  662. package/dist/tools/one-shot-llm-tool.d.ts.map +0 -1
  663. package/dist/tools/plugin-manager.d.ts.map +0 -1
  664. package/dist/types/agent-bridge.d.ts.map +0 -1
  665. package/dist/types/attachment.d.ts.map +0 -1
  666. package/dist/types/autonomy.d.ts.map +0 -1
  667. package/dist/types/blocks.d.ts.map +0 -1
  668. package/dist/types/compactor.d.ts.map +0 -1
  669. package/dist/types/config/autonomy.d.ts.map +0 -1
  670. package/dist/types/config/context.d.ts.map +0 -1
  671. package/dist/types/config/fleet-chat.d.ts.map +0 -1
  672. package/dist/types/config/mcp-features.d.ts.map +0 -1
  673. package/dist/types/config/providers.d.ts.map +0 -1
  674. package/dist/types/config/root.d.ts.map +0 -1
  675. package/dist/types/config/runtime.d.ts.map +0 -1
  676. package/dist/types/config/skills-fleet-brain.d.ts.map +0 -1
  677. package/dist/types/config/tools.d.ts.map +0 -1
  678. package/dist/types/config.d.ts.map +0 -1
  679. package/dist/types/context-evidence.d.ts.map +0 -1
  680. package/dist/types/context-window.d.ts.map +0 -1
  681. package/dist/types/council.d.ts.map +0 -1
  682. package/dist/types/default-config.d.ts.map +0 -1
  683. package/dist/types/design-kit.d.ts.map +0 -1
  684. package/dist/types/error-handler.d.ts.map +0 -1
  685. package/dist/types/errors.d.ts.map +0 -1
  686. package/dist/types/file-event-record.d.ts.map +0 -1
  687. package/dist/types/hooks.d.ts.map +0 -1
  688. package/dist/types/index.d.ts.map +0 -1
  689. package/dist/types/index.js.map +0 -7
  690. package/dist/types/input-reader.d.ts.map +0 -1
  691. package/dist/types/logger.d.ts.map +0 -1
  692. package/dist/types/memory.d.ts.map +0 -1
  693. package/dist/types/messages.d.ts.map +0 -1
  694. package/dist/types/mode-prompts.d.ts.map +0 -1
  695. package/dist/types/mode.d.ts.map +0 -1
  696. package/dist/types/models-registry.d.ts.map +0 -1
  697. package/dist/types/multi-agent.d.ts.map +0 -1
  698. package/dist/types/observability.d.ts.map +0 -1
  699. package/dist/types/one-shot-llm.d.ts.map +0 -1
  700. package/dist/types/path-resolver.d.ts.map +0 -1
  701. package/dist/types/permission.d.ts.map +0 -1
  702. package/dist/types/plugin.d.ts.map +0 -1
  703. package/dist/types/prompt-registry.d.ts.map +0 -1
  704. package/dist/types/prompt.d.ts.map +0 -1
  705. package/dist/types/provider-runner.d.ts.map +0 -1
  706. package/dist/types/provider.d.ts.map +0 -1
  707. package/dist/types/quota-regex.d.ts.map +0 -1
  708. package/dist/types/renderer.d.ts.map +0 -1
  709. package/dist/types/retry-policy.d.ts.map +0 -1
  710. package/dist/types/secret-scrubber.d.ts.map +0 -1
  711. package/dist/types/secret-vault.d.ts.map +0 -1
  712. package/dist/types/selector.d.ts.map +0 -1
  713. package/dist/types/session-markers.d.ts.map +0 -1
  714. package/dist/types/session-markers.js.map +0 -7
  715. package/dist/types/session-reader.d.ts.map +0 -1
  716. package/dist/types/session-rewinder.d.ts.map +0 -1
  717. package/dist/types/session.d.ts.map +0 -1
  718. package/dist/types/side-effect.d.ts.map +0 -1
  719. package/dist/types/skill.d.ts.map +0 -1
  720. package/dist/types/slash-command.d.ts.map +0 -1
  721. package/dist/types/spec.d.ts.map +0 -1
  722. package/dist/types/system-prompt-contributor.d.ts.map +0 -1
  723. package/dist/types/system-prompt.d.ts.map +0 -1
  724. package/dist/types/task-graph.d.ts.map +0 -1
  725. package/dist/types/token-counter.d.ts.map +0 -1
  726. package/dist/types/tool-executor.d.ts.map +0 -1
  727. package/dist/types/tool-markers.d.ts.map +0 -1
  728. package/dist/types/tool.d.ts.map +0 -1
  729. package/dist/types/utility-types.d.ts.map +0 -1
  730. package/dist/utils/assert-never.d.ts.map +0 -1
  731. package/dist/utils/atomic-write.d.ts.map +0 -1
  732. package/dist/utils/cache-key.d.ts.map +0 -1
  733. package/dist/utils/child-env.d.ts.map +0 -1
  734. package/dist/utils/color.d.ts.map +0 -1
  735. package/dist/utils/compaction-preview.d.ts.map +0 -1
  736. package/dist/utils/config-backup.d.ts.map +0 -1
  737. package/dist/utils/config-json.d.ts.map +0 -1
  738. package/dist/utils/connectivity.d.ts.map +0 -1
  739. package/dist/utils/context-breakdown.d.ts.map +0 -1
  740. package/dist/utils/context-evidence.d.ts.map +0 -1
  741. package/dist/utils/continuous-memory-profiler.d.ts.map +0 -1
  742. package/dist/utils/crash-shield.d.ts.map +0 -1
  743. package/dist/utils/deep-merge.d.ts.map +0 -1
  744. package/dist/utils/diff.d.ts.map +0 -1
  745. package/dist/utils/error.d.ts.map +0 -1
  746. package/dist/utils/error.js.map +0 -7
  747. package/dist/utils/expect-defined.d.ts.map +0 -1
  748. package/dist/utils/expect-defined.js.map +0 -7
  749. package/dist/utils/glob-expand.d.ts.map +0 -1
  750. package/dist/utils/glob-match.d.ts.map +0 -1
  751. package/dist/utils/heap-watchdog-types.d.ts.map +0 -1
  752. package/dist/utils/heap-watchdog.d.ts.map +0 -1
  753. package/dist/utils/heap-watchdog.js.map +0 -7
  754. package/dist/utils/incoming-images.d.ts.map +0 -1
  755. package/dist/utils/index.d.ts.map +0 -1
  756. package/dist/utils/index.js.map +0 -7
  757. package/dist/utils/instruction-file.d.ts.map +0 -1
  758. package/dist/utils/ip-guard.d.ts.map +0 -1
  759. package/dist/utils/json-repair.d.ts.map +0 -1
  760. package/dist/utils/json-schema-validate.d.ts.map +0 -1
  761. package/dist/utils/lru-cache.d.ts.map +0 -1
  762. package/dist/utils/memory-flight-recorder.d.ts.map +0 -1
  763. package/dist/utils/merge-custom-models.d.ts.map +0 -1
  764. package/dist/utils/merge-models-payload.d.ts.map +0 -1
  765. package/dist/utils/message-invariants.d.ts.map +0 -1
  766. package/dist/utils/newline-normalize.d.ts.map +0 -1
  767. package/dist/utils/perf-profile.d.ts.map +0 -1
  768. package/dist/utils/pid.d.ts.map +0 -1
  769. package/dist/utils/project-identity.d.ts.map +0 -1
  770. package/dist/utils/project-watch.d.ts.map +0 -1
  771. package/dist/utils/regex-guard.d.ts.map +0 -1
  772. package/dist/utils/safe-json.d.ts.map +0 -1
  773. package/dist/utils/sage-output-block.d.ts.map +0 -1
  774. package/dist/utils/session-scoped-path.d.ts.map +0 -1
  775. package/dist/utils/sleep.d.ts.map +0 -1
  776. package/dist/utils/slug.d.ts.map +0 -1
  777. package/dist/utils/socket-path.d.ts.map +0 -1
  778. package/dist/utils/sqlite-warning.d.ts.map +0 -1
  779. package/dist/utils/string.d.ts.map +0 -1
  780. package/dist/utils/task-format.d.ts.map +0 -1
  781. package/dist/utils/term.d.ts.map +0 -1
  782. package/dist/utils/todos-format.d.ts.map +0 -1
  783. package/dist/utils/token-estimate.d.ts.map +0 -1
  784. package/dist/utils/tool-description-mode.d.ts.map +0 -1
  785. package/dist/utils/tool-name.d.ts.map +0 -1
  786. package/dist/utils/tool-output-serializer.d.ts.map +0 -1
  787. package/dist/utils/tool-result-render-mode.d.ts.map +0 -1
  788. package/dist/utils/tool-subject.d.ts.map +0 -1
  789. package/dist/utils/tool-wire-compact.d.ts.map +0 -1
  790. package/dist/utils/tree-kill.d.ts.map +0 -1
  791. package/dist/utils/tree-kill.js.map +0 -7
  792. package/dist/utils/ulid.d.ts.map +0 -1
  793. package/dist/utils/walk-ignore.d.ts.map +0 -1
  794. package/dist/utils/wstack-paths.d.ts.map +0 -1
  795. package/dist/worktree/index.d.ts.map +0 -1
  796. package/dist/worktree/index.js.map +0 -7
  797. package/dist/worktree/worktree-git.d.ts.map +0 -1
  798. package/dist/worktree/worktree-managed-ops.d.ts.map +0 -1
  799. package/dist/worktree/worktree-manager.d.ts.map +0 -1
  800. package/dist/worktree/worktree-types.d.ts.map +0 -1
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/core/agent.ts", "../../src/utils/expect-defined.ts", "../../src/utils/error.ts", "../../src/types/errors.ts", "../../src/extension/registry.ts", "../../src/kernel/run-controller.ts", "../../src/kernel/tokens.ts", "../../src/coordination/global-mailbox-paths.ts", "../../src/utils/wstack-paths.ts", "../../src/coordination/remote-mailbox.ts", "../../src/coordination/mailbox-constants.ts", "../../src/coordination/mailbox-project-server-client.ts", "../../src/coordination/mailbox-project-server-endpoint.ts", "../../src/coordination/mailbox-project-server-protocol.ts", "../../src/coordination/mailbox-type-properties.ts", "../../src/coordination/mailbox-types.ts", "../../src/coordination/sqlite-mailbox.ts", "../../src/hq/factory.ts", "../../src/utils/project-identity.ts", "../../src/utils/ulid.ts", "../../src/hq/auth-store.ts", "../../src/hq/publisher.ts", "../../src/security/secret-scrubber.ts", "../../src/hq/protocol/tool.ts", "../../src/hq/protocol/core.ts", "../../src/hq/redaction.ts", "../../src/hq/mailbox-mapper.ts", "../../src/coordination/mailbox-tool.ts", "../../src/core/mailbox-loop.ts", "../../src/core/btw.ts", "../../src/core/fleet-pulse.ts", "../../src/mailbox-attach.ts", "../../src/types/blocks.ts", "../../src/utils/string.ts", "../../src/types/quota-regex.ts", "../../src/types/provider.ts", "../../src/utils/context-evidence.ts", "../../src/utils/tool-wire-compact.ts", "../../src/utils/token-estimate.ts", "../../src/core/context.ts", "../../src/core/conversation-state.ts", "../../src/core/continue-to-next-iteration.ts", "../../src/core/iteration-limit.ts", "../../src/core/streaming-response-builder.ts", "../../src/utils/json-repair.ts", "../../src/chronicle/prompt-manifest.ts", "../../src/observability/network-telemetry.ts", "../../src/core/provider-runner.ts", "../../src/core/queued-messages.ts", "../../src/core/request-provider-binding.ts", "../../src/core/agent-loop.ts", "../../src/utils/cache-key.ts", "../../src/utils/message-invariants.ts", "../../src/core/agent-response.ts", "../../src/utils/sage-output-block.ts", "../../src/utils/tool-output-serializer.ts", "../../src/core/agent-tools.ts", "../../src/kernel/pipeline.ts", "../../src/core/agent-types.ts", "../../src/core/input-builder.ts", "../../src/utils/todos-format.ts", "../../src/core/continue-intent.ts", "../../src/core/model-ref.ts", "../../src/core/model-availability-calendar.ts", "../../src/core/fallback-profile-manager.ts", "../../src/core/fallback-model.ts", "../../src/types/config/runtime.ts", "../../src/types/system-prompt.ts", "../../src/core/instruction-bundle.ts", "../../src/core/modes/default.ts", "../../src/core/system-prompt-blocks.ts", "../../src/core/system-prompt-environment.ts", "../../src/core/system-prompt-environment-probes.ts", "../../src/utils/child-env.ts", "../../src/core/system-prompt-shell.ts", "../../src/skills/limits.ts", "../../src/core/system-prompt-skill-text.ts", "../../src/core/system-prompt-skill-bodies.ts", "../../src/core/system-prompt-memory-skills.ts", "../../src/core/system-prompt-plan.ts", "../../src/core/system-prompt-builder.ts"],
4
- "sourcesContent": ["import { createHash } from 'node:crypto';\nimport { ExtensionRegistry } from '../extension/registry.js';\nimport type { Container } from '../kernel/container.js';\nimport type { EventBus } from '../kernel/events.js';\nimport { RunController } from '../kernel/run-controller.js';\nimport { TOKENS } from '../kernel/tokens.js';\nimport type { ProviderRegistry } from '../registry/provider-registry.js';\nimport type { ToolRegistry } from '../registry/tool-registry.js';\nimport type { ErrorHandler } from '../types/error-handler.js';\nimport { AgentError, toWrongStackError } from '../types/errors.js';\nimport type { Logger } from '../types/logger.js';\nimport type { Tracer } from '../types/observability.js';\nimport type { PermissionPolicy } from '../types/permission.js';\nimport type { Plugin, PluginAPI } from '../types/plugin.js';\nimport type { Renderer } from '../types/renderer.js';\nimport type { RetryPolicy } from '../types/retry-policy.js';\nimport type { Tool } from '../types/tool.js';\nimport type { ToolExecutorLike } from '../types/tool-executor.js';\nimport { type AgentLoopHandler, createAgentLoopHandler, signalAbortReason } from './agent-loop.js';\nimport { type AgentResponseHandler, createAgentResponseHandler } from './agent-response.js';\nimport { type AgentToolHandler, createAgentToolHandler } from './agent-tools.js';\nimport {\n type AgentInit,\n type AgentInput,\n type AgentPipelines,\n DEFAULT_MAX_ITERATIONS,\n normalizeInput,\n type ResolvedLoopDetectionConfig,\n type RunResult,\n resolveLoopDetection,\n} from './agent-types.js';\nimport type { Context, RunOptions } from './context.js';\n\n// Re-export types and utilities from agent-types.ts for backward compatibility\nexport {\n type AgentInit,\n type AgentInput,\n type AgentPipelines,\n createDefaultPipelines,\n DEFAULT_MAX_ITERATIONS,\n normalizeInput,\n type ResolvedLoopDetectionConfig,\n type RunResult,\n resolveLoopDetection,\n type ToolCallPipelinePayload,\n type UserInputPayload,\n} from './agent-types.js';\n\nexport class Agent {\n readonly container: Container;\n readonly tools: ToolRegistry;\n readonly providers: ProviderRegistry;\n readonly events: EventBus;\n readonly pipelines: AgentPipelines;\n readonly ctx: Context;\n /** Max agent-loop iterations per run. Mutable so the TUI `/settings` picker\n * can apply a new value to the live session (takes effect next run). */\n maxIterations: number;\n readonly executionStrategy: 'parallel' | 'sequential' | 'smart';\n readonly perIterationOutputCapBytes: number;\n private readonly plugins: { plugin: Plugin; api: PluginAPI }[] = [];\n readonly toolExecutor: ToolExecutorLike;\n readonly autoExtendLimit: boolean;\n /** Resolved loop-detector settings (see `tools.loopDetection`). */\n readonly loopDetection: ResolvedLoopDetectionConfig;\n private readonly autonomousContinue: boolean;\n readonly tracer: Tracer | undefined;\n readonly extensions: ExtensionRegistry;\n private readonly _toolHandler: AgentToolHandler;\n private readonly _responseHandler: AgentResponseHandler;\n private readonly _loopHandler: AgentLoopHandler;\n private readonly _logger: Logger;\n\n /**\n * Guards against concurrent `run()` calls on the same Agent instance.\n * `run()` mutates shared state (`ctx.signal`, `ctx.messages`, token\n * bookkeeping, compaction state) and a second concurrent call would\n * interleave those mutations with the first, producing an invalid\n * conversation or racing abort signals.\n */\n private _runInProgress = false;\n /** SHA-256 of the last submitted input content \u2014 prevents duplicate runs. */\n private _lastInputHash: string | undefined;\n\n constructor(init: AgentInit) {\n this.container = init.container;\n this.tools = init.tools;\n this.providers = init.providers;\n this.events = init.events;\n this.pipelines = init.pipelines;\n this.ctx = init.context;\n this.maxIterations = init.maxIterations ?? DEFAULT_MAX_ITERATIONS;\n this.executionStrategy = init.executionStrategy ?? 'smart';\n this.perIterationOutputCapBytes = init.perIterationOutputCapBytes ?? 100_000;\n this.autoExtendLimit = init.autoExtendLimit ?? true;\n this.loopDetection = resolveLoopDetection(init.loopDetection);\n this.autonomousContinue = init.autonomousContinue ?? false;\n this.tracer = init.tracer;\n this.extensions = init.extensions ?? new ExtensionRegistry();\n // Create a child logger that auto-carries the session ID so every\n // log entry from provider calls, stream handling, and tool execution\n // is correlated to its session without any call-site plumbing.\n this._logger = this.container.resolve(TOKENS.Logger).child({ sessionId: this.ctx.session.id });\n this.extensions.setLogger(this._logger);\n this.toolExecutor = init.toolExecutor;\n this._toolHandler = createAgentToolHandler(this);\n this._responseHandler = createAgentResponseHandler(this);\n this._loopHandler = createAgentLoopHandler(this, {\n tools: this._toolHandler,\n response: this._responseHandler,\n });\n }\n\n get logger(): Logger {\n return this._logger;\n }\n get retry(): RetryPolicy {\n return this.container.resolve(TOKENS.RetryPolicy);\n }\n get errorHandler(): ErrorHandler {\n return this.container.resolve(TOKENS.ErrorHandler);\n }\n get permission(): PermissionPolicy {\n return this.container.resolve(TOKENS.PermissionPolicy);\n }\n get renderer(): Renderer | undefined {\n return this.container.safeResolve(TOKENS.Renderer);\n }\n\n disableInteractiveConfirmation(): void {\n this.toolExecutor.clearConfirmAwaiter();\n if (typeof this.permission.setPromptDelegate === 'function') {\n this.permission.setPromptDelegate(undefined);\n }\n }\n\n register(tool: Tool): void {\n this.tools.register(tool);\n }\n\n async use(plugin: Plugin, api: PluginAPI): Promise<void> {\n await plugin.setup(api);\n this.plugins.push({ plugin, api });\n }\n\n async teardown(): Promise<void> {\n const errors: unknown[] = [];\n for (const { plugin, api } of this.plugins.toReversed()) {\n if (typeof plugin.teardown !== 'function') continue;\n try {\n await plugin.teardown(api);\n } catch (err) {\n errors.push(err);\n }\n }\n this.plugins.length = 0;\n // Drain agent-lifetime hooks (mailbox heartbeat, awareness, HQ publisher,\n // auto-compaction) that persist across runs. Do this AFTER plugin teardown\n // so plugins can still interact with mailbox/HQ during their own shutdown.\n try {\n await this.ctx.drainAgentHooks();\n } catch {\n // best-effort \u2014 individual hook errors already swallowed by drainAgentHooks\n }\n if (errors.length > 0) {\n throw new AgentError({\n message: `Agent teardown failed: ${errors.map(String).join('; ')}`,\n code: 'AGENT_RUN_FAILED',\n context: { failures: errors.length, phase: 'plugin-teardown' },\n // Preserve the FIRST underlying failure as the cause so consumers can\n // pull type/code off it via `instanceof` checks. The full list is\n // flattened into the message; we don't keep the array on the error\n // because WrongStackError.context is Record<string, unknown> and\n // arrays of unknown Errors would lose their structured fields.\n cause: errors[0],\n });\n }\n }\n\n async run(userInput: AgentInput, opts: RunOptions = {}): Promise<RunResult> {\n // Reject concurrent runs: shared mutable state (ctx.signal, messages,\n // session, token bookkeeping, compaction) would race between two\n // simultaneous runs.\n if (this._runInProgress) {\n throw new AgentError({\n message:\n 'Agent.run() is already in progress on this instance. Concurrent runs are not supported.',\n code: 'AGENT_RUN_FAILED',\n context: { phase: 'concurrency-guard' },\n });\n }\n // Dedup: silently skip a run when the input text is byte-identical to\n // the immediately preceding submission. Prevents terminal \\r\\n\n // re-entrancy, stuck-key bursts, and client-side resubmission loops\n // from firing duplicate runs back-to-back.\n const inputText =\n typeof userInput === 'string'\n ? userInput\n : ((userInput as { prompt?: string })?.prompt ?? '');\n if (inputText.length > 0) {\n const hash = createHash('sha256').update(inputText).digest('hex');\n if (hash === this._lastInputHash) {\n return {\n status: 'done' as const,\n iterations: 0,\n };\n }\n this._lastInputHash = hash;\n }\n\n this._runInProgress = true;\n const controller = new RunController({ parentSignal: opts.signal });\n const signal = controller.signal;\n this.ctx.signal = signal;\n // Pin this run's writer and id BEFORE any async hook runs. Hosts (WebUI)\n // can swap ctx.session on session.new/resume while this run is still in\n // flight; every event and persistence call from here on \u2014 including from\n // beforeRun extensions and late provider streams \u2014 must stay on the\n // session that started the run.\n const sessionWriter = this.ctx.session;\n const sessionId = sessionWriter.id;\n this.ctx.activeRunSessionWriter = sessionWriter;\n this.ctx.activeRunSessionId = sessionId;\n controller.onAbort(() => this.ctx.drainAbortHooks());\n // Abort durability: drain the buffered session writer the moment the run\n // is cancelled. The loop's `finally` clears the in-flight marker, but the\n // buffered JSONL events would otherwise sit in memory until the next\n // periodic flush \u2014 a hard exit right after Ctrl+C would lose them.\n controller.onAbort(async () => {\n await sessionWriter.flush().catch(() => {\n /* best-effort \u2014 close()/checkpoint flush remains the backstop */\n });\n });\n\n // Refresh the live context's tool mirror from the registry. The provider\n // request reads `this.tools.list()` directly, but `ctx.tools` is a separate\n // convenience snapshot \u2014 the one tools introspect (tool_search, tool-help,\n // vision adapters) and request-token estimation reads. The Context is\n // constructed before MCP / plugin / fleet tools register, so without this\n // refresh `ctx.tools` stays empty and tool_search reports zero tools.\n // Using the agent's own registry keeps filtered subagent rosters correct.\n this.ctx.tools = this.tools.list();\n\n const span = this.tracer?.startSpan('agent.run', {\n 'agent.model': opts.model ?? this.ctx.model,\n 'agent.executionStrategy': opts.executionStrategy ?? this.executionStrategy,\n });\n\n const { blocks, text } = normalizeInput(userInput);\n const inputPayload = { content: blocks, text, ctx: this.ctx };\n\n await this.extensions.runBeforeRun(this.ctx, inputPayload);\n const runStartedAt = Date.now();\n const runStartedIso = new Date(runStartedAt).toISOString();\n\n try {\n this.events.emit('agent.run.started', {\n sessionId,\n ctx: this.ctx,\n model: opts.model ?? this.ctx.model,\n at: runStartedIso,\n inputText: text,\n });\n const autonomousContinue = opts.autonomousContinue ?? this.autonomousContinue;\n const result = await this._loopHandler.runInner(\n inputPayload,\n opts,\n controller,\n autonomousContinue,\n );\n span?.setAttribute('agent.status', result.status);\n span?.setAttribute('agent.iterations', result.iterations);\n await this.extensions.runAfterRun(this.ctx, result);\n this.events.emit('agent.run.completed', {\n sessionId,\n ctx: this.ctx,\n status: result.status,\n iterations: result.iterations,\n at: new Date().toISOString(),\n durationMs: Date.now() - runStartedAt,\n });\n return result;\n } catch (err) {\n const wse = err instanceof AgentError ? err : toWrongStackError(err);\n const safeError = err instanceof Error ? new Error(err.message) : new Error(String(err));\n this.events.emit('error', {\n sessionId,\n err: safeError,\n phase: 'agent',\n _original: err instanceof Error ? err : undefined,\n });\n if (err instanceof Error) span?.recordError(err);\n span?.setAttribute('agent.status', 'failed');\n const result: RunResult = {\n status: signal.aborted ? 'aborted' : 'failed',\n iterations: 0,\n error: wse,\n abortReason: signal.aborted ? signalAbortReason(signal) : undefined,\n };\n await this.extensions.runAfterRun(this.ctx, result);\n if (result.status === 'failed') {\n this.events.emit('agent.run.error', {\n sessionId,\n ctx: this.ctx,\n err: safeError,\n at: new Date().toISOString(),\n durationMs: Date.now() - runStartedAt,\n });\n }\n this.events.emit('agent.run.completed', {\n sessionId,\n ctx: this.ctx,\n status: result.status,\n iterations: result.iterations,\n at: new Date().toISOString(),\n durationMs: Date.now() - runStartedAt,\n });\n return result;\n } finally {\n span?.end();\n // Keep the run guard and pinned session pair intact through controller\n // disposal so teardown events cannot be attributed or persisted to a\n // newly-selected session, and no next run can overwrite the pins early.\n try {\n await controller.dispose();\n } finally {\n this.ctx.activeRunSessionId = undefined;\n this.ctx.activeRunSessionWriter = undefined;\n this._runInProgress = false;\n }\n }\n }\n\n // \u2500\u2500 Tool + response execution handled by AgentToolHandler / AgentResponseHandler \u2500\u2500\n}\n", "/** Assert a value is neither null nor undefined. Throws if it is.\n * Useful after optional chaining and indexed access when the\n * control flow guarantees the value exists but TypeScript can't\n * prove it (e.g. after a check on a related field). */\nexport function expectDefined<T>(value: T | null | undefined, label?: string): T {\n if (value === null || value === undefined) {\n const err = new Error(label ? `Expected ${label} to be defined` : 'Expected value to be defined');\n err.name = 'ExpectDefinedError';\n throw err;\n }\n return value;\n}\n", "/**\n * Converts an unknown error value to a human-readable string.\n * Used in 40+ files across the codebase to normalize error messaging.\n */\nexport function toErrorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n", "import { toErrorMessage } from '../utils/error.js';\n\n/**\n * WrongStack error hierarchy.\n *\n * Every error thrown by the framework is a `WrongStackError` with a\n * machine-readable `code`, a `subsystem` tag, and a `severity` level.\n * This lets consumers (CLI, TUI, plugins, tests) branch on structured\n * data instead of parsing error messages.\n */\n\n// \u2500\u2500 Error codes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Machine-readable error codes as frozen constants.\n *\n * Use `ERROR_CODES.X` instead of raw string literals for:\n * - IDE autocomplete and compile-time validation\n * - Safe refactoring (rename updates all usages)\n * - Plugin extensibility (extend the object to add custom codes)\n *\n * The `ErrorCode` type is derived from this object, so adding a new\n * code here automatically updates the type without extra changes.\n */\nexport const ERROR_CODES = {\n // Provider\n PROVIDER_RATE_LIMITED: 'PROVIDER_RATE_LIMITED',\n PROVIDER_AUTH_FAILED: 'PROVIDER_AUTH_FAILED',\n PROVIDER_OVERLOADED: 'PROVIDER_OVERLOADED',\n PROVIDER_INVALID_REQUEST: 'PROVIDER_INVALID_REQUEST',\n PROVIDER_SERVER_ERROR: 'PROVIDER_SERVER_ERROR',\n PROVIDER_NETWORK_ERROR: 'PROVIDER_NETWORK_ERROR',\n PROVIDER_CONTEXT_OVERFLOW: 'PROVIDER_CONTEXT_OVERFLOW',\n // Tool\n TOOL_NOT_FOUND: 'TOOL_NOT_FOUND',\n TOOL_PERMISSION_DENIED: 'TOOL_PERMISSION_DENIED',\n TOOL_EXECUTION_FAILED: 'TOOL_EXECUTION_FAILED',\n TOOL_TIMEOUT: 'TOOL_TIMEOUT',\n TOOL_INPUT_INVALID: 'TOOL_INPUT_INVALID',\n // Config\n CONFIG_INVALID: 'CONFIG_INVALID',\n CONFIG_NOT_FOUND: 'CONFIG_NOT_FOUND',\n CONFIG_PARSE_FAILED: 'CONFIG_PARSE_FAILED',\n CONFIG_MIGRATION_NEEDED: 'CONFIG_MIGRATION_NEEDED',\n // Plugin\n PLUGIN_LOAD_FAILED: 'PLUGIN_LOAD_FAILED',\n PLUGIN_API_MISMATCH: 'PLUGIN_API_MISMATCH',\n PLUGIN_MISSING_DEPENDENCY: 'PLUGIN_MISSING_DEPENDENCY',\n // Agent\n AGENT_ITERATION_LIMIT: 'AGENT_ITERATION_LIMIT',\n AGENT_CONTEXT_OVERFLOW: 'AGENT_CONTEXT_OVERFLOW',\n AGENT_ABORTED: 'AGENT_ABORTED',\n AGENT_RUN_FAILED: 'AGENT_RUN_FAILED',\n // Session\n SESSION_NOT_FOUND: 'SESSION_NOT_FOUND',\n SESSION_CORRUPTED: 'SESSION_CORRUPTED',\n SESSION_WRITE_FAILED: 'SESSION_WRITE_FAILED',\n // Container / Registry\n CONTAINER_TOKEN_ALREADY_BOUND: 'CONTAINER_TOKEN_ALREADY_BOUND',\n CONTAINER_TOKEN_NOT_BOUND: 'CONTAINER_TOKEN_NOT_BOUND',\n CONTAINER_CIRCULAR_DEPENDENCY: 'CONTAINER_CIRCULAR_DEPENDENCY',\n REGISTRY_DUPLICATE: 'REGISTRY_DUPLICATE',\n REGISTRY_NOT_FOUND: 'REGISTRY_NOT_FOUND',\n REGISTRY_INVALID: 'REGISTRY_INVALID',\n // File system\n FS_READ_FAILED: 'FS_READ_FAILED',\n FS_WRITE_FAILED: 'FS_WRITE_FAILED',\n FS_MKDIR_FAILED: 'FS_MKDIR_FAILED',\n FS_DELETE_FAILED: 'FS_DELETE_FAILED',\n FS_ATOMIC_WRITE_FAILED: 'FS_ATOMIC_WRITE_FAILED',\n // SDD (Spec-Driven Development)\n SDD_VALIDATION_FAILED: 'SDD_VALIDATION_FAILED',\n SDD_PARSE_FAILED: 'SDD_PARSE_FAILED',\n SDD_INVALID_STATE: 'SDD_INVALID_STATE',\n SDD_NOT_READY: 'SDD_NOT_READY',\n // General\n VALIDATION_ERROR: 'VALIDATION_ERROR',\n PARSE_FAILED: 'PARSE_FAILED',\n UNKNOWN: 'UNKNOWN',\n} as const;\n\n/**\n * Union type derived from `ERROR_CODES`. Using `typeof ERROR_CODES[keyof typeof ERROR_CODES]`\n * instead of a string literal union means TypeScript auto-updates the type whenever\n * a new code is added to `ERROR_CODES` \u2014 no need to keep two lists in sync.\n */\nexport type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];\n\nexport type ErrorSubsystem =\n | 'provider'\n | 'tool'\n | 'config'\n | 'plugin'\n | 'agent'\n | 'session'\n | 'sdd'\n | 'container'\n | 'fs'\n | 'general';\nexport type ErrorSeverity = 'fatal' | 'error' | 'warning';\n\n// \u2500\u2500 Base error class \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class WrongStackError extends Error {\n readonly code: ErrorCode;\n readonly subsystem: ErrorSubsystem;\n readonly severity: ErrorSeverity;\n readonly recoverable: boolean;\n readonly context?: Record<string, unknown> | undefined;\n\n constructor(opts: {\n message: string;\n code: ErrorCode;\n subsystem: ErrorSubsystem;\n severity?: ErrorSeverity | undefined;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super(opts.message, { cause: opts.cause });\n this.name = 'WrongStackError';\n this.code = opts.code;\n this.subsystem = opts.subsystem;\n this.severity = opts.severity ?? 'error';\n this.recoverable = opts.recoverable ?? false;\n this.context = opts.context;\n }\n\n /**\n * Render a one-line user-facing description.\n * Subclasses should override for domain-specific formatting.\n */\n describe(): string {\n const ctx = this.context ? ` ${formatContext(this.context)}` : '';\n return `${this.code}: ${this.message}${ctx}`;\n }\n}\n\nfunction formatContext(ctx: Record<string, unknown>): string {\n const parts = Object.entries(ctx)\n .filter(([, v]) => v !== undefined)\n .slice(0, 3)\n .map(([k, v]) => `${k}=${String(v)}`);\n return parts.length > 0 ? `[${parts.join(' ')}]` : '';\n}\n\n// \u2500\u2500 Specific error classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Tool execution errors \u2014 thrown by ToolExecutor and individual tools.\n */\nexport class ToolError extends WrongStackError {\n readonly toolName: string;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n | 'TOOL_NOT_FOUND'\n | 'TOOL_PERMISSION_DENIED'\n | 'TOOL_EXECUTION_FAILED'\n | 'TOOL_TIMEOUT'\n | 'TOOL_INPUT_INVALID'\n >;\n toolName: string;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'tool',\n recoverable: opts.recoverable,\n context: { tool: opts.toolName, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ToolError';\n this.toolName = opts.toolName;\n }\n}\n\n/**\n * Config loading / validation errors.\n */\nexport class ConfigError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'CONFIG_INVALID' | 'CONFIG_NOT_FOUND' | 'CONFIG_PARSE_FAILED' | 'CONFIG_MIGRATION_NEEDED'\n >;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'config',\n severity: 'fatal',\n recoverable: false,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'ConfigError';\n }\n}\n\n/**\n * Plugin loading / lifecycle errors.\n */\nexport class PluginError extends WrongStackError {\n readonly pluginName: string;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'PLUGIN_LOAD_FAILED' | 'PLUGIN_API_MISMATCH' | 'PLUGIN_MISSING_DEPENDENCY'\n >;\n pluginName: string;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'plugin',\n severity: 'error',\n recoverable: opts.code === ERROR_CODES.PLUGIN_MISSING_DEPENDENCY,\n context: { plugin: opts.pluginName, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'PluginError';\n this.pluginName = opts.pluginName;\n }\n}\n\n/**\n * Agent runtime errors \u2014 thrown by Agent.run when a non-WrongStackError\n * escapes the inner loop, so callers always see a structured error.\n */\nexport class AgentError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'AGENT_ITERATION_LIMIT' | 'AGENT_CONTEXT_OVERFLOW' | 'AGENT_ABORTED' | 'AGENT_RUN_FAILED'\n >;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'agent',\n severity: opts.code === ERROR_CODES.AGENT_ABORTED ? 'warning' : 'error',\n recoverable: opts.recoverable ?? opts.code === ERROR_CODES.AGENT_ITERATION_LIMIT,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'AgentError';\n }\n}\n\n/**\n * Wrap an arbitrary thrown value into a `WrongStackError` so the caller\n * always gets a structured error. Pass-throughs WrongStackError instances\n * unchanged; raw `Error`s and primitives get an `AGENT_RUN_FAILED` wrapper\n * with the original preserved as `cause`.\n */\nexport function toWrongStackError(\n err: unknown,\n code: Extract<ErrorCode, 'AGENT_RUN_FAILED' | 'AGENT_ABORTED' | 'UNKNOWN'> = ERROR_CODES.AGENT_RUN_FAILED,\n): WrongStackError {\n if (err instanceof WrongStackError) return err;\n const message = toErrorMessage(err);\n return new AgentError({\n message,\n code: code === 'UNKNOWN' ? ERROR_CODES.AGENT_RUN_FAILED : code,\n cause: err,\n });\n}\n\n/**\n * Session storage errors.\n */\nexport class SessionError extends WrongStackError {\n readonly sessionId?: string | undefined;\n\n constructor(opts: {\n message: string;\n code: Extract<ErrorCode, 'SESSION_NOT_FOUND' | 'SESSION_CORRUPTED' | 'SESSION_WRITE_FAILED'>;\n sessionId?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'session',\n severity: opts.code === ERROR_CODES.SESSION_WRITE_FAILED ? 'error' : 'warning',\n recoverable: opts.code !== ERROR_CODES.SESSION_CORRUPTED,\n context: { sessionId: opts.sessionId, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'SessionError';\n this.sessionId = opts.sessionId;\n }\n}\n\n/**\n * SDD (Spec-Driven Development) errors \u2014 spec validation, parsing, and\n * state machine violations in the AISpecBuilder, TaskFlow, and TaskTracker.\n */\nexport class SddError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'SDD_VALIDATION_FAILED' | 'SDD_PARSE_FAILED' | 'SDD_INVALID_STATE' | 'SDD_NOT_READY'\n >;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'sdd',\n severity: opts.code === ERROR_CODES.SDD_PARSE_FAILED ? 'warning' : 'error',\n recoverable: opts.code === ERROR_CODES.SDD_NOT_READY,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'SddError';\n }\n}\n\n/**\n * File system operation errors.\n */\nexport class FsError extends WrongStackError {\n readonly path?: string | undefined;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'FS_READ_FAILED' | 'FS_WRITE_FAILED' | 'FS_MKDIR_FAILED' | 'FS_DELETE_FAILED' | 'FS_ATOMIC_WRITE_FAILED'\n >;\n path?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'fs',\n severity: 'error',\n recoverable: opts.code !== ERROR_CODES.FS_READ_FAILED,\n context: { path: opts.path, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'FsError';\n this.path = opts.path;\n }\n}\n\n/**\n * HTTP fetch error \u2014 thrown when a network request returns a non-OK status.\n * Carries the response status so {@link classifyToolError} can branch on it\n * (429 \u2192 transient, 404 \u2192 not_found, 401 \u2192 permission) without duck-typing\n * the error via `'response' in err`.\n *\n * P3 #18 (before-release.md): the previous `'response' in err` check caught\n * any Error with a `response` property, including custom errors, proxy\n * objects, or mocked errors in tests. `instanceof FetchError` is reliable.\n *\n * Tools and providers that make HTTP requests and need the executor to\n * classify their failures should throw `new FetchError({ status, message })`\n * instead of a bare `Error` with an ad-hoc `response` field.\n */\nexport class FetchError extends WrongStackError {\n readonly status: number;\n\n constructor(opts: {\n message: string;\n status: number;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n severity: 'error',\n recoverable: opts.status === 429 || opts.status >= 500,\n context: { status: opts.status, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'FetchError';\n this.status = opts.status;\n }\n}\n\n/**\n * Tool input validation error \u2014 thrown when a tool's input fails a validation\n * check that the JSON Schema cannot express (e.g. `old_string === new_string`\n * in edit, or a cross-field invariant). Use this instead of a bare\n * `throw new Error('...validation...')` so {@link classifyToolError} can\n * match on `instanceof` rather than a locale-dependent message substring.\n *\n * P2 #6 (before-release.md): the previous `err.message.includes('validation')`\n * check misclassified any error whose message happened to contain \"validation\"\n * (e.g. a third-party \"input validation timeout\") as a VALIDATION error.\n *\n * Named `ToolValidationError` (not `ValidationError`) to avoid colliding with\n * the existing `ValidationError` interface exported by json-schema-validate.ts\n * (a validation-result shape, not an Error subclass).\n */\nexport class ToolValidationError extends WrongStackError {\n constructor(opts: {\n message: string;\n /** Field path or tool name that failed validation, for diagnostics. */\n field?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n severity: 'error',\n recoverable: false,\n context: { field: opts.field, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ToolValidationError';\n }\n}\n\n/**\n * Response / payload parse error \u2014 thrown when an upstream HTTP response,\n * file, or data structure is well-formed at the transport layer (HTTP 200,\n * valid JSON) but is missing required fields or has an unexpected shape.\n *\n * Distinct from `ConfigError(CONFIG_PARSE_FAILED)` (which is specifically\n * for config-file parsing) and `FetchError` (which covers HTTP non-OK\n * responses). `ParseError` fills the gap: the request succeeded but the\n * response body couldn't be interpreted.\n *\n * Common sites: OAuth token responses missing `access_token`, device-code\n * responses missing `device_code`, registry responses with unexpected\n * schemas.\n */\nexport class ParseError extends WrongStackError {\n readonly source?: string | undefined;\n\n constructor(opts: {\n message: string;\n /**\n * What was being parsed \u2014 e.g. `'oauth-token-response'`,\n * `'device-code-response'`. Lets consumers distinguish parse failures\n * from different upstream APIs without parsing the message.\n */\n source?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.PARSE_FAILED,\n subsystem: 'general',\n severity: 'error',\n recoverable: false,\n context: { source: opts.source, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ParseError';\n this.source = opts.source;\n }\n}\n\n// \u2500\u2500 Type guards \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function isWrongStackError(err: unknown): err is WrongStackError {\n return err instanceof WrongStackError;\n}\n\nexport function isToolError(err: unknown): err is ToolError {\n return err instanceof ToolError;\n}\n\nexport function isConfigError(err: unknown): err is ConfigError {\n return err instanceof ConfigError;\n}\n\nexport function isPluginError(err: unknown): err is PluginError {\n return err instanceof PluginError;\n}\n\nexport function isSessionError(err: unknown): err is SessionError {\n return err instanceof SessionError;\n}\n\nexport function isAgentError(err: unknown): err is AgentError {\n return err instanceof AgentError;\n}\n\nexport function isFsError(err: unknown): err is FsError {\n return err instanceof FsError;\n}\n\nexport function isToolValidationError(err: unknown): err is ToolValidationError {\n return err instanceof ToolValidationError;\n}\n\nexport function isFetchError(err: unknown): err is FetchError {\n return err instanceof FetchError;\n}\n\nexport function isParseError(err: unknown): err is ParseError {\n return err instanceof ParseError;\n}\n\nexport function isSddError(err: unknown): err is SddError {\n return err instanceof SddError;\n}\n", "import { expectDefined } from '../utils/expect-defined.js';\n/**\n * ExtensionRegistry \u2014 manages AgentExtension registrations.\n *\n * Extensions are called in registration order at each lifecycle phase.\n * Each extension hook failure is caught and logged independently so\n * one bad extension can't take down the agent.\n */\n\nimport type { TextBlock } from '../types/blocks.js';\nimport { WrongStackError, ERROR_CODES } from '../types/errors.js';\nimport type { Logger } from '../types/logger.js';\nimport type { SystemPromptContributor } from '../types/system-prompt-contributor.js';\nimport type {\n AfterIterationHook,\n AfterRunHook,\n AfterToolExecutionHook,\n AgentExtension,\n BeforeIterationHook,\n BeforeRunHook,\n BeforeToolExecutionHook,\n OnErrorHook,\n ProviderRunnerFn,\n} from './extension-points.js';\nexport class ExtensionRegistry {\n private readonly extensions: AgentExtension[] = [];\n private readonly promptContributors: SystemPromptContributor[] = [];\n private log: Logger | undefined;\n\n setLogger(log: Logger): void {\n this.log = log;\n }\n\n /**\n * Register a system prompt contributor. Returns an unregister function.\n * Contributors are called on every system prompt build in registration\n * order. Their output blocks are inserted after the core environment\n * block, before the mode and plan blocks.\n */\n registerSystemPromptContributor(c: SystemPromptContributor): () => void {\n this.promptContributors.push(c);\n return () => {\n const idx = this.promptContributors.indexOf(c);\n if (idx >= 0) this.promptContributors.splice(idx, 1);\n };\n }\n\n /**\n * Build all registered system prompt contributions.\n * Failures are caught and logged \u2014 one bad contributor doesn't\n * break the prompt assembly.\n */\n async buildSystemPromptContributions(\n ctx: Parameters<SystemPromptContributor>[0],\n ): Promise<TextBlock[]> {\n const blocks: TextBlock[] = [];\n // Snapshot before iterating so mid-iteration registration doesn't cause\n // skipped or duplicate contributor invocations during this phase.\n const snapshot = [...this.promptContributors];\n for (const c of snapshot) {\n try {\n const contributed = await c(ctx);\n blocks.push(...contributed);\n } catch (err) {\n this.log?.error('SystemPromptContributor failed', err);\n }\n }\n return blocks;\n }\n\n /**\n * Returns the live array of contributors (readonly snapshot for\n * passing to DefaultSystemPromptBuilder at build time).\n */\n listSystemPromptContributors(): readonly SystemPromptContributor[] {\n return this.promptContributors;\n }\n\n /**\n * Register an extension. Duplicate names are rejected.\n * Returns an unregister function.\n */\n register(ext: AgentExtension): () => void {\n if (this.extensions.some((e) => e.name === ext.name)) {\n throw new WrongStackError({\n message: `Extension \"${ext.name}\" already registered`,\n code: ERROR_CODES.REGISTRY_DUPLICATE,\n subsystem: 'container',\n context: { extension: ext.name },\n });\n }\n this.extensions.push(ext);\n return () => this.unregister(ext.name);\n }\n\n /**\n * Register an extension, silently replacing any previous registration\n * with the same name. Use this when overriding a default extension.\n */\n registerOrReplace(ext: AgentExtension): () => void {\n const idx = this.extensions.findIndex((e) => e.name === ext.name);\n if (idx >= 0) this.extensions.splice(idx, 1);\n return this.register(ext);\n }\n\n /**\n * Unregister an extension by name. Returns true if found.\n */\n unregister(name: string): boolean {\n const idx = this.extensions.findIndex((e) => e.name === name);\n if (idx === -1) return false;\n this.extensions.splice(idx, 1);\n return true;\n }\n\n /**\n * List registered extension names in order.\n */\n list(): readonly string[] {\n return this.extensions.map((e) => e.name);\n }\n\n /**\n * Check if an extension with the given name is registered.\n */\n has(name: string): boolean {\n return this.extensions.some((e) => e.name === name);\n }\n\n /**\n * Remove all registered extensions and contributors.\n */\n clear(): void {\n this.extensions.length = 0;\n this.promptContributors.length = 0;\n }\n\n // \u2500\u2500 Hook runners \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async runBeforeRun(...args: Parameters<BeforeRunHook>): Promise<void> {\n const snapshot = [...this.extensions];\n for (const ext of snapshot) {\n if (!ext.beforeRun) continue;\n try {\n await ext.beforeRun(...args);\n } catch (err) {\n this.log?.error(`Extension \"${ext.name}\" beforeRun hook failed`, err);\n }\n }\n }\n\n async runAfterRun(...args: Parameters<AfterRunHook>): Promise<void> {\n const snapshot = [...this.extensions];\n for (const ext of snapshot) {\n if (!ext.afterRun) continue;\n try {\n await ext.afterRun(...args);\n } catch (err) {\n this.log?.error(`Extension \"${ext.name}\" afterRun hook failed`, err);\n }\n }\n }\n\n async runBeforeIteration(...args: Parameters<BeforeIterationHook>): Promise<void> {\n const snapshot = [...this.extensions];\n for (const ext of snapshot) {\n if (!ext.beforeIteration) continue;\n try {\n await ext.beforeIteration(...args);\n } catch (err) {\n this.log?.error(`Extension \"${ext.name}\" beforeIteration hook failed`, err);\n }\n }\n }\n\n async runAfterIteration(...args: Parameters<AfterIterationHook>): Promise<void> {\n const snapshot = [...this.extensions];\n for (const ext of snapshot) {\n if (!ext.afterIteration) continue;\n try {\n await ext.afterIteration(...args);\n } catch (err) {\n this.log?.error(`Extension \"${ext.name}\" afterIteration hook failed`, err);\n }\n }\n }\n\n /**\n * Run onError hooks in order. The first hook that returns a non-void\n * result wins; subsequent hooks are skipped.\n */\n async runOnError(\n ...args: Parameters<OnErrorHook>\n ): Promise<\n { action: 'retry'; model?: string | undefined } | { action: 'fail' } | { action: 'continue' } | void\n > {\n const snapshot = [...this.extensions];\n for (const ext of snapshot) {\n if (!ext.onError) continue;\n try {\n const result = await ext.onError(...args);\n if (result) return result;\n } catch (err) {\n this.log?.error(`Extension \"${ext.name}\" onError hook failed`, err);\n }\n }\n }\n\n /**\n * Build a composed provider runner. Extensions with `wrapProviderRunner`\n * form a middleware-style chain: the innermost extension wraps the\n * default runner, each subsequent wrapper wraps the previous.\n */\n wrapProviderRunner(inner: ProviderRunnerFn): ProviderRunnerFn {\n const wrappers = this.extensions\n .filter((e) => e.wrapProviderRunner)\n .map((e) => ({ name: e.name, wrap: expectDefined(e.wrapProviderRunner) }));\n\n if (wrappers.length === 0) return inner;\n\n // Build chain from innermost to outermost\n let composed: ProviderRunnerFn = inner;\n for (let i = wrappers.length - 1; i >= 0; i--) {\n const wrapper = wrappers[i];\n if (!wrapper) continue;\n const next = composed;\n composed = async (ctx, req) => {\n try {\n return await wrapper.wrap(ctx, req, next);\n } catch (err) {\n this.log?.error(`Extension \"${wrapper.name}\" wrapProviderRunner failed`, err);\n throw err;\n }\n };\n }\n return composed;\n }\n\n async runBeforeToolExecution(\n ...args: Parameters<BeforeToolExecutionHook>\n ): Promise<Parameters<BeforeToolExecutionHook>[1]> {\n let toolUses = args[1];\n const snapshot = [...this.extensions];\n for (const ext of snapshot) {\n if (!ext.beforeToolExecution) continue;\n try {\n toolUses = await ext.beforeToolExecution(args[0], toolUses);\n } catch (err) {\n this.log?.error(`Extension \"${ext.name}\" beforeToolExecution hook failed`, err);\n }\n }\n return toolUses;\n }\n\n async runAfterToolExecution(...args: Parameters<AfterToolExecutionHook>): Promise<void> {\n const snapshot = [...this.extensions];\n for (const ext of snapshot) {\n if (!ext.afterToolExecution) continue;\n try {\n await ext.afterToolExecution(...args);\n } catch (err) {\n this.log?.error(`Extension \"${ext.name}\" afterToolExecution hook failed`, err);\n }\n }\n }\n}\n", "import { toErrorMessage } from '../utils/error.js';\n/**\n * RunController centralises abort + cleanup for a single agent run. It\n * wraps a single AbortController and exposes a registry of teardown\n * hooks that fire (LIFO, exactly once) when the run aborts OR ends\n * normally. Anyone holding the controller can:\n *\n * - read `signal` to bail out cooperatively\n * - call `abort(reason?)` to abort the run\n * - call `onAbort(fn)` to register a cleanup hook\n * - call `dispose()` when the run ends normally \u2014 this fires the\n * hooks too, so cleanup runs regardless of outcome\n *\n * Hooks must be idempotent and synchronous-or-quick. Errors thrown\n * inside hooks are caught and surfaced through `errorSink` (or the\n * console as a last resort) so one bad hook can't block the others.\n */\nexport interface RunControllerOptions {\n /** Optional parent signal \u2014 abort propagates from parent \u2192 this. */\n parentSignal?: AbortSignal | undefined;\n /** Receives errors thrown by cleanup hooks. Defaults to console.warn. */\n errorSink?: (err: unknown, where: string) => void;\n}\n\nexport class RunController {\n private readonly ctrl = new AbortController();\n private readonly hooks: Array<() => void | Promise<void>> = [];\n private disposed = false;\n private hooksDrained = false;\n private readonly errorSink: (err: unknown, where: string) => void;\n /**\n * Shared promise for the in-flight `runHooks()` call. Set by the abort\n * signal handler or by `dispose()`, whichever fires first. Both callers\n * await the same promise so abort-triggered async cleanup (session flush,\n * socket close) completes before `dispose()` resolves.\n */\n private _hooksPromise: Promise<void> | null = null;\n\n constructor(opts: RunControllerOptions = {}) {\n this.errorSink =\n opts.errorSink ??\n ((err, where) => {\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'run.cleanup_hook_failed',\n where,\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }));\n });\n if (opts.parentSignal) {\n const parent = opts.parentSignal;\n if (parent.aborted) {\n this.ctrl.abort(parent.reason);\n // Aborting this signal before attaching the abort listener means\n // the listener (registered below) will not fire \u2014 the WHATWG spec\n // only delivers abort events on the transition from un-aborted to\n // aborted, not for late listeners on already-aborted signals. So\n // drive the hook pipeline directly. We defer with queueMicrotask\n // so any synchronous `onAbort()` calls between `new RunController(\u2026)`\n // returning and the next microtask checkpoint are captured by the\n // hook array before runHooks() snapshots it.\n queueMicrotask(() => {\n void this.runHooks();\n });\n } else {\n const onParentAbort = () => this.ctrl.abort(parent.reason);\n parent.addEventListener('abort', onParentAbort, { once: true });\n // When this run finishes normally, stop listening on the parent.\n this.onAbort(() => parent.removeEventListener('abort', onParentAbort));\n }\n }\n this.ctrl.signal.addEventListener(\n 'abort',\n () => {\n this.ensureHooksRun();\n },\n { once: true },\n );\n }\n\n get signal(): AbortSignal {\n return this.ctrl.signal;\n }\n\n get aborted(): boolean {\n return this.ctrl.signal.aborted;\n }\n\n abort(reason?: unknown): void {\n if (this.ctrl.signal.aborted) return;\n this.ctrl.abort(reason);\n }\n\n /**\n * Register a teardown hook. Returns an unsubscribe function so callers\n * can opt out before the hook fires (e.g. when a tool finishes cleanly\n * before abort happens).\n *\n * If the controller has already drained its hooks (a prior abort() or\n * dispose() ran), the new hook is fired immediately on a best-effort\n * basis \u2014 otherwise a hook registered after teardown would be silently\n * dropped and the resource it cleans up would leak. The returned\n * unsubscribe is a no-op in that case (the hook has already run). Errors\n * from the immediate run are routed through `errorSink` like any other\n * cleanup failure.\n */\n onAbort(fn: () => void | Promise<void>): () => void {\n if (this.hooksDrained) {\n void (async () => {\n try {\n await fn();\n } catch (err) {\n this.errorSink(err, 'RunController.onAbort(post-drain)');\n }\n })();\n return () => {};\n }\n this.hooks.push(fn);\n return () => {\n const idx = this.hooks.indexOf(fn);\n if (idx !== -1) this.hooks.splice(idx, 1);\n };\n }\n\n /**\n * Fire cleanup hooks and tear down listeners \u2014 called when the run\n * ends *normally* so cleanup happens regardless of outcome. Subsequent\n * aborts become no-ops.\n */\n async dispose(): Promise<void> {\n if (this.disposed) return;\n this.disposed = true;\n await this.ensureHooksRun();\n }\n\n /**\n * Start running hooks (or wait for an already-in-flight run) and return\n * a promise that settles when all hooks complete. Both the abort signal\n * handler and `dispose()` call this so they share the same underlying\n * promise \u2014 abort-triggered async cleanup (session flush, socket close)\n * is guaranteed to finish before `dispose()` resolves.\n */\n private ensureHooksRun(): Promise<void> {\n if (!this._hooksPromise) {\n this._hooksPromise = this.runHooks();\n }\n return this._hooksPromise;\n }\n\n private async runHooks(): Promise<void> {\n if (this.hooksDrained) return;\n this.hooksDrained = true;\n // Snapshot + clear so hooks added during cleanup don't re-fire.\n // The contract says hooks are independent and one bad hook must not\n // block the others, so we fire them in parallel rather than awaiting\n // serially. The snapshot's iteration order still determines the START\n // order (LIFO), so synchronous hooks that push to a shared array keep\n // the LIFO observation. Async hooks may complete out of order \u2014 the\n // previous serial behavior is preserved only for synchronous hooks,\n // and no test asserts async completion ordering.\n const snapshot = this.hooks.splice(0, this.hooks.length).reverse();\n if (snapshot.length === 0) return;\n await Promise.allSettled(\n snapshot.map((hook) =>\n Promise.resolve()\n .then(() => hook())\n .catch((err: unknown) => {\n this.errorSink(err, 'RunController.dispose');\n }),\n ),\n );\n }\n}\n", "import type { BrainArbiter } from '../coordination/brain.js';\nimport type { FallbackProfileManager } from '../core/fallback-profile-manager.js';\nimport type { ProviderModelStatusTracker } from '../coordination/provider-status-tracker.js';\nimport type { HookRegistry } from '../hooks/registry.js';\nimport type { Compactor } from '../types/compactor.js';\nimport type { ConfigLoader, ConfigStore } from '../types/config.js';\nimport type { ErrorHandler } from '../types/error-handler.js';\nimport type { InputReader } from '../types/input-reader.js';\nimport type { Logger } from '../types/logger.js';\nimport type { MemoryPort } from '../types/memory.js';\nimport type { ModeStore } from '../types/mode.js';\nimport type { ModelsRegistry } from '../types/models-registry.js';\nimport type { PathResolver } from '../types/path-resolver.js';\nimport type { PermissionPolicy } from '../types/permission.js';\nimport type { PromptLoader } from '../types/prompt.js';\nimport type { ProviderRunner } from '../types/provider-runner.js';\nimport type { Renderer } from '../types/renderer.js';\nimport type { RetryPolicy } from '../types/retry-policy.js';\nimport type { SecretScrubber } from '../types/secret-scrubber.js';\nimport type { SessionStore } from '../types/session.js';\nimport type { SkillLoader } from '../types/skill.js';\nimport type { SystemPromptBuilder } from '../types/system-prompt.js';\nimport type { TokenCounter } from '../types/token-counter.js';\nimport type { WorktreeManager } from '../worktree/worktree-manager.js';\nimport type { Token } from './container.js';\n\n// Tokens use the GLOBAL symbol registry (`Symbol.for`) rather than unique\n// per-call `Symbol()`s. If `@wrongstack/core` is ever evaluated twice in one\n// process \u2014 e.g. Node loads it under two path casings on a case-insensitive\n// filesystem (`D:\\Codebox\\\u2026` vs `D:\\codebox\\\u2026`), or a bundler inlines a second\n// copy \u2014 `Symbol()` would mint distinct tokens per instance, so a binding made\n// via one copy's `TOKENS.ConfigStore` could never be resolved via the other's,\n// surfacing as `Container: token \"ConfigStore\" not bound`. `Symbol.for(key)`\n// returns the same symbol for the same key across every module instance in the\n// process, making DI resilient to accidental duplication. The key is namespaced\n// to avoid colliding with unrelated global symbols; `.description` (used in\n// container error messages) stays human-readable.\nconst t = <T>(name: string): Token<T> => Symbol.for(`@wrongstack/core/kernel#${name}`) as Token<T>;\n\nexport const TOKENS = {\n Logger: t<Logger>('Logger'),\n TokenCounter: t<TokenCounter>('TokenCounter'),\n SessionStore: t<SessionStore>('SessionStore'),\n /**\n * @deprecated Token name retained for compatibility.\n * The resolved value IS a `MemoryPort`, NOT the legacy `MemoryStore` interface.\n * Callers that cast or destructure as `MemoryStore` will lose `getCapability`,\n * `health`, `dispose`, and the narrowed `withTraceId(): MemoryPort` return type.\n * Port implementations are opaque \u2014 query optional features via `getCapability`.\n * Use `TOKENS.MemoryPort` instead.\n */\n MemoryStore: t<MemoryPort>('MemoryStore'),\n /** Production memory backend. Use instead of the deprecated `MemoryStore` token. */\n MemoryPort: t<MemoryPort>('MemoryPort'),\n PermissionPolicy: t<PermissionPolicy>('PermissionPolicy'),\n Compactor: t<Compactor>('Compactor'),\n PathResolver: t<PathResolver>('PathResolver'),\n ConfigLoader: t<ConfigLoader>('ConfigLoader'),\n ConfigStore: t<ConfigStore>('ConfigStore'),\n FallbackProfileManager: t<FallbackProfileManager>('FallbackProfileManager'),\n /** Shared (provider, model) health tracker; fallback extensions read/write it. */\n ProviderModelStatusTracker: t<ProviderModelStatusTracker>('ProviderModelStatusTracker'),\n Renderer: t<Renderer>('Renderer'),\n InputReader: t<InputReader>('InputReader'),\n ErrorHandler: t<ErrorHandler>('ErrorHandler'),\n RetryPolicy: t<RetryPolicy>('RetryPolicy'),\n SkillLoader: t<SkillLoader>('SkillLoader'),\n PromptLoader: t<PromptLoader>('PromptLoader'),\n SystemPromptBuilder: t<SystemPromptBuilder>('SystemPromptBuilder'),\n SecretScrubber: t<SecretScrubber>('SecretScrubber'),\n ModelsRegistry: t<ModelsRegistry>('ModelsRegistry'),\n ModeStore: t<ModeStore>('ModeStore'),\n /** Replaces the entire provider call layer \u2014 retry, streaming, tracing. */\n ProviderRunner: t<ProviderRunner>('ProviderRunner'),\n /** Optional git-worktree lifecycle manager (per-phase isolation in Goal). */\n WorktreeManager: t<WorktreeManager>('WorktreeManager'),\n /** Optional global Brain arbiter for policy/decision escalation. */\n BrainArbiter: t<BrainArbiter>('BrainArbiter'),\n /** Lifecycle hook registry (shell + in-process hooks). */\n HookRegistry: t<HookRegistry>('HookRegistry'),\n} as const;\n", "import * as path from 'node:path';\nimport { projectSlug } from '../utils/wstack-paths.js';\n\nexport const GLOBAL_MAILBOX_FILE = '_mailbox.jsonl';\nexport const GLOBAL_MAILBOX_CLIENT_REGISTRY_FILE = '_mailbox.clients.json';\n\n/**\n * Derive the project-level mailbox directory path.\n *\n * Delegates to the canonical projectSlug() from wstack-paths so every surface\n * lands in the same ~/.wrongstack/projects/<slug>/ directory.\n */\nexport function resolveProjectDir(projectRoot: string, globalRoot: string): string {\n return path.join(globalRoot, 'projects', projectSlug(projectRoot));\n}\n", "import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\n\n/**\n * Path layout. All developer-level state lives in ~/.wrongstack/.\n * Per-project state is keyed by the canonical project root under\n * ~/.wrongstack/projects/<slug>/. Linked Git worktrees resolve to their main\n * checkout so coordination and durable state are shared across worktrees.\n *\n * The ONLY thing inside the project tree is the optional\n * .wrongstack/AGENTS.md (committed) and .wrongstack/skills/ (committed).\n */\n\nexport interface WstackPaths {\n /** ~/.wrongstack \u2014 global root. */\n globalRoot: string;\n /** Active profile name resolved from the bootstrap config. */\n profileName: string;\n /** ~/.wrongstack/profiles/<activeProfile> \u2014 active user-profile root. */\n profileDir: string;\n /** Absolute project root. */\n projectRoot: string;\n /** Home directory (~) \u2014 base for foreign tool state (~/.codex, ~/.agents, \u2026). */\n homeDir: string;\n /**\n * ~/.wrongstack/profiles/<activeProfile> \u2014 directory for profile-scoped\n * user state (mode.json, statusline.json, custom-context-modes.json, \u2026).\n */\n configDir: string;\n /** ~/.wrongstack/config.json \u2014 bootstrap config (activeProfile + version). */\n globalConfig: string;\n /**\n * ~/.wrongstack/profiles \u2014 directory containing per-profile configs.\n * Each profile has its own subdirectory with a config.json.\n */\n profilesDir: string;\n /**\n * Resolve the config path for a named profile.\n * Returns ~/.wrongstack/profiles/<name>/config.json.\n */\n profileConfig: (name: string) => string;\n /** Resolve ~/.wrongstack/profiles/<name>/statusline.json */\n profileStatuslineConfig: (name: string) => string;\n /** Resolve ~/.wrongstack/profiles/<name>/mode.json */\n profileModeConfig: (name: string) => string;\n /** Resolve ~/.wrongstack/profiles/<name>/provider-status.json */\n profileProviderStatus: (name: string) => string;\n /** Resolve ~/.wrongstack/profiles/<name>/update-cache.json */\n profileUpdateCache: (name: string) => string;\n /** ~/.wrongstack/.key \u2014 32 random bytes, mode 0600, AES-GCM key for the secret vault. */\n secretsKey: string;\n /** ~/.wrongstack/profiles/<activeProfile>/memory.md \u2014 profile memory. */\n globalMemory: string;\n /** ~/.wrongstack/profiles/<activeProfile>/skills \u2014 profile skills. */\n globalSkills: string;\n /** ~/.claude/skills \u2014 user-global skills from foreign coding agents (Claude Code, Codex, \u2026). Read-only. */\n globalClaudeSkills: string;\n /** ~/.wrongstack/profiles/<activeProfile>/design-kits \u2014 profile Design Studio kits. */\n globalDesignKits: string;\n /** ~/.wrongstack/profiles/<activeProfile>/prompts \u2014 profile prompt library. */\n globalPrompts: string;\n /** ~/.wrongstack/profiles/<activeProfile>/instructions \u2014 profile instruction overrides. */\n globalInstructions: string;\n /** ~/.wrongstack/profiles/<activeProfile>/prompt-usage.json \u2014 prompt usage. */\n promptUsage: string;\n /** ~/.wrongstack/cache \u2014 fetched data (models.dev, etc.). */\n cacheDir: string;\n /** ~/.wrongstack/cache/models.dev.json */\n modelsCache: string;\n /** ~/.wrongstack/cache/models-overlay.json \u2014 cached curated overlay. */\n modelsOverlayCache: string;\n /**\n * Per-project codebase symbol index (SQLite). Lives under the global project\n * dir \u2014 NOT inside the repo \u2014 so it never clutters the working tree or needs\n * gitignoring. `~/.wrongstack/projects/<hash>/codebase-index`.\n */\n projectCodebaseIndex: string;\n /** ~/.wrongstack/profiles/<activeProfile>/history \u2014 REPL line history. */\n historyFile: string;\n /** ~/.wrongstack/logs/wrongstack.log */\n logFile: string;\n /** ~/.wrongstack/projects/<hash> */\n projectDir: string;\n /** ~/.wrongstack/projects/<hash>/memory.md */\n projectMemory: string;\n /** ~/.wrongstack/projects/<hash>/sessions */\n projectSessions: string;\n /** ~/.wrongstack/projects/<hash>/trust.json */\n projectTrust: string;\n /** ~/.wrongstack/projects/<hash>/meta.json */\n projectMeta: string;\n /** ~/.wrongstack/projects/<hash>/config.local.json \u2014 optional override */\n projectLocalConfig: string;\n /** <project>/.wrongstack/config.json \u2014 per-project settings (safe fields only).\n * This lives inside the project root so it can be gitignored or shared. */\n inProjectConfig: string;\n /** <project>/.wrongstack/AGENTS.md \u2014 committed project memory. */\n inProjectAgentsFile: string;\n /** <project>/.wrongstack/skills \u2014 committed project skills. */\n inProjectSkills: string;\n /** <project>/.claude/skills \u2014 project skills authored for foreign coding agents (Claude Code, \u2026). Read-only. */\n inProjectClaudeSkills: string;\n /** <project>/.wrongstack/prompts \u2014 committed project prompt library. */\n inProjectPrompts: string;\n /** <project>/.wrongstack/instructions \u2014 committed project instruction overrides. */\n inProjectInstructions: string;\n /** <project>/.wrongstack/design-kits \u2014 committed project Design Studio kits. */\n inProjectDesignKits: string;\n /** <project>/.wrongstack/worktrees \u2014 git worktrees for per-phase isolation (gitignored). */\n inProjectWorktrees: string;\n /** Stable hash for the canonical project root (shared by linked Git worktrees). */\n projectHash: string;\n /** Human-readable canonical project slug, shared by linked Git worktrees. */\n projectSlug: string;\n /** ~/.wrongstack/projects/<hash>/goal.json \u2014 goal persistence */\n projectGoal: string;\n /** ~/.wrongstack/projects/<hash>/input-history.json \u2014 TUI prompt input history */\n projectInputHistory: string;\n /** ~/.wrongstack/projects/<hash>/specs \u2014 SDD spec files */\n projectSpecs: string;\n /** ~/.wrongstack/projects/<hash>/task-graphs \u2014 SDD task graphs */\n projectTaskGraphs: string;\n /** ~/.wrongstack/projects/<hash>/sdd-session.json \u2014 SDD session state */\n projectSddSession: string;\n /** ~/.wrongstack/projects/<hash>/plan.json \u2014 plan persistence */\n projectPlan: string;\n /** ~/.wrongstack/projects/<hash>/autophase \u2014 Goal phase-graph JSON files (dir name kept for backward compat) */\n projectAutophase: string;\n /** ~/.wrongstack/projects/<hash>/sdd-boards \u2014 live SDD board snapshots + JSONL event logs */\n projectSddBoards: string;\n /** ~/.wrongstack/profiles/<activeProfile>/sync.json \u2014 CloudSync configuration */\n syncConfig: string;\n /** ~/.wrongstack/config-history \u2014 timestamped backups on every config write */\n configHistoryDir: string;\n /** Function to get the status.json path for a project given its hash. */\n projectStatus: (projectHash: string) => string;\n}\n\n/**\n * Resolve the stable project identity root used by global WrongStack state.\n *\n * A linked Git worktree has its own checkout path and a `.git` *file* that\n * points into `<main>/.git/worktrees/<name>`. Its `commondir` points back to\n * the main checkout's `.git` directory. Treating the linked checkout path as\n * the project identity would split one repository into multiple session,\n * registry, and mailbox directories \u2014 agents in different worktrees would be\n * unable to see or message each other.\n *\n * Project-local paths still use the caller's actual checkout. Only global\n * state identity is canonicalized. Non-Git projects, normal checkouts, Git\n * submodules, and separate-git-dir layouts keep their existing identity.\n */\nexport function canonicalProjectRoot(absRoot: string): string {\n const checkoutRoot = path.resolve(absRoot);\n const dotGit = path.join(checkoutRoot, '.git');\n\n try {\n if (!fs.statSync(dotGit).isFile()) return checkoutRoot;\n\n const gitDirLine = fs.readFileSync(dotGit, 'utf8').trim();\n const match = /^gitdir:\\s*(.+)$/i.exec(gitDirLine);\n if (!match?.[1]) return checkoutRoot;\n\n const gitDir = path.resolve(checkoutRoot, match[1].trim());\n const commonDirFile = path.join(gitDir, 'commondir');\n if (!fs.statSync(commonDirFile).isFile()) return checkoutRoot;\n\n const commonDir = path.resolve(gitDir, fs.readFileSync(commonDirFile, 'utf8').trim());\n // Linked worktrees created by Git share the main checkout's `.git` dir.\n // A submodule or --separate-git-dir layout may point elsewhere; do not\n // guess a working-tree root for those shapes.\n if (path.basename(commonDir).toLowerCase() !== '.git') return checkoutRoot;\n return path.dirname(commonDir);\n } catch {\n // Missing/malformed administrative files must never make path resolution\n // fail. Falling back preserves the pre-canonicalization behavior.\n return checkoutRoot;\n }\n}\n\nexport function projectHash(absRoot: string): string {\n return createHash('sha256').update(canonicalProjectRoot(absRoot)).digest('hex').slice(0, 12);\n}\n\n/**\n * Human-readable project directory name: slugified folder name + short hash\n * suffix for uniqueness. e.g. `wrongstack-a1b2c3` instead of `3024e5e6fa58`.\n */\nexport function projectSlug(absRoot: string): string {\n const identityRoot = canonicalProjectRoot(absRoot);\n const base = slugify(path.basename(identityRoot));\n const hash = createHash('sha256').update(identityRoot).digest('hex').slice(0, 6);\n return `${base}-${hash}`;\n}\n\n/** Turn a folder name into a filesystem-safe lowercase slug. */\nfunction slugify(name: string): string {\n return (\n name\n .toLowerCase()\n // Collapse any run of non-alphanumeric chars into a single hyphen.\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 40) || 'project'\n );\n}\n\nexport interface WstackPathOptions {\n userHome?: string | undefined;\n projectRoot: string;\n /** Override the global root (e.g. for tests). Default: `${userHome}/.wrongstack`. */\n globalRoot?: string | undefined;\n /** Explicit profile override. Otherwise read from the root bootstrap config. */\n profileName?: string | undefined;\n}\n\n/** Make an untrusted profile name safe for use as one path segment. */\nexport function safeProfileName(name: string | undefined): string {\n const safe = (name ?? '').replace(/[/\\\\:]/g, '_').replace(/\\.\\./g, '_').trim();\n return safe || 'default';\n}\n\n/**\n * Resolve the selected profile from ~/.wrongstack/config.json. The root file\n * is bootstrap metadata only; a missing/corrupt bootstrap selects `default`.\n */\nexport function activeProfileName(globalRoot: string): string {\n try {\n const parsed = JSON.parse(fs.readFileSync(path.join(globalRoot, 'config.json'), 'utf8')) as {\n activeProfile?: unknown;\n };\n return safeProfileName(typeof parsed.activeProfile === 'string' ? parsed.activeProfile : undefined);\n } catch {\n return 'default';\n }\n}\n\n/**\n * The global `~/.wrongstack` root, honoring the `WRONGSTACK_HOME` env\n * override. The override exists so tests (and sandboxed runs) can redirect\n * ALL global state \u2014 config, secrets, logs, projects/, mailboxes \u2014 away from\n * the real user home. Before it existed, `pnpm test` booted runtimes against\n * the real `~/.wrongstack`: it read the user's real config.json (starting a\n * second live Telegram poller), appended to the real wrongstack.log, and left\n * ~20k orphaned fixture dirs under projects/.\n *\n * Every code path that wants the global dir must come through here (or\n * through `resolveWstackPaths`) instead of `path.join(os.homedir(), '.wrongstack')`.\n */\nexport function wstackGlobalRoot(): string {\n const fromEnv = process.env['WRONGSTACK_HOME'];\n if (fromEnv && fromEnv.trim().length > 0) return path.resolve(fromEnv);\n return path.join(os.homedir(), '.wrongstack');\n}\n\nexport function resolveWstackPaths(opts: WstackPathOptions): WstackPaths {\n // Precedence: explicit globalRoot > explicit userHome (callers/tests that\n // pass one expect paths under it) > WRONGSTACK_HOME env > real home dir.\n const globalRoot =\n opts.globalRoot ?? (opts.userHome ? path.join(opts.userHome, '.wrongstack') : wstackGlobalRoot());\n // Home dir for FOREIGN tool state (Claude Code's ~/.claude). Independent of\n // WRONGSTACK_HOME, which redirects only WrongStack state: a real user's\n // Claude skills live in their real home, but tests pass `userHome` to keep\n // both `.wrongstack` and `.claude` under a temp dir.\n const homeDir = opts.userHome ?? os.homedir();\n const profileName = safeProfileName(opts.profileName ?? activeProfileName(globalRoot));\n const profileDir = path.join(globalRoot, 'profiles', profileName);\n const hash = projectHash(opts.projectRoot);\n const slug = projectSlug(opts.projectRoot);\n const projectDir = path.join(globalRoot, 'projects', slug);\n return {\n globalRoot,\n profileName,\n profileDir,\n projectRoot: opts.projectRoot,\n homeDir,\n configDir: profileDir,\n globalConfig: path.join(globalRoot, 'config.json'),\n profilesDir: path.join(globalRoot, 'profiles'),\n profileConfig: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'config.json');\n },\n profileStatuslineConfig: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'statusline.json');\n },\n profileModeConfig: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'mode.json');\n },\n profileProviderStatus: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'provider-status.json');\n },\n profileUpdateCache: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'update-cache.json');\n },\n secretsKey: path.join(globalRoot, '.key'),\n globalMemory: path.join(profileDir, 'memory.md'),\n globalSkills: path.join(profileDir, 'skills'),\n globalClaudeSkills: path.join(homeDir, '.claude', 'skills'),\n globalDesignKits: path.join(profileDir, 'design-kits'),\n globalPrompts: path.join(profileDir, 'prompts'),\n globalInstructions: path.join(profileDir, 'instructions'),\n promptUsage: path.join(profileDir, 'prompt-usage.json'),\n cacheDir: path.join(globalRoot, 'cache'),\n modelsCache: path.join(globalRoot, 'cache', 'models.dev.json'),\n modelsOverlayCache: path.join(globalRoot, 'cache', 'models-overlay.json'),\n historyFile: path.join(profileDir, 'history'),\n logFile: path.join(globalRoot, 'logs', 'wrongstack.log'),\n projectDir,\n projectCodebaseIndex: path.join(projectDir, 'codebase-index'),\n projectMemory: path.join(projectDir, 'memory.md'),\n projectSessions: path.join(projectDir, 'sessions'),\n projectTrust: path.join(projectDir, 'trust.json'),\n projectMeta: path.join(projectDir, 'meta.json'),\n projectLocalConfig: path.join(projectDir, 'config.local.json'),\n inProjectConfig: path.join(opts.projectRoot, '.wrongstack', 'config.json'),\n inProjectAgentsFile: path.join(opts.projectRoot, '.wrongstack', 'AGENTS.md'),\n inProjectSkills: path.join(opts.projectRoot, '.wrongstack', 'skills'),\n inProjectClaudeSkills: path.join(opts.projectRoot, '.claude', 'skills'),\n inProjectPrompts: path.join(opts.projectRoot, '.wrongstack', 'prompts'),\n inProjectInstructions: path.join(opts.projectRoot, '.wrongstack', 'instructions'),\n inProjectDesignKits: path.join(opts.projectRoot, '.wrongstack', 'design-kits'),\n inProjectWorktrees: path.join(opts.projectRoot, '.wrongstack', 'worktrees'),\n projectHash: hash,\n projectSlug: slug,\n projectGoal: path.join(projectDir, 'goal.json'),\n projectInputHistory: path.join(projectDir, 'input-history.json'),\n projectSpecs: path.join(projectDir, 'specs'),\n projectTaskGraphs: path.join(projectDir, 'task-graphs'),\n projectSddSession: path.join(projectDir, 'sdd-session.json'),\n projectPlan: path.join(projectDir, 'plan.json'),\n projectAutophase: path.join(projectDir, 'autophase'),\n projectSddBoards: path.join(projectDir, 'sdd-boards'),\n syncConfig: path.join(profileDir, 'sync.json'),\n configHistoryDir: path.join(globalRoot, 'config-history'),\n projectStatus: (projectHash: string) => path.join(globalRoot, 'projects', projectHash, 'status.json'),\n };\n}\n", "import * as path from 'node:path';\nimport type { HqPublisher } from '../hq/publisher.js';\nimport type { EventBus } from '../kernel/events.js';\nimport { HQ_MAILBOX_SNAPSHOT_MIN_INTERVAL_MS } from './mailbox-constants.js';\nimport type {\n CredentialValidation,\n IssueCredentialOptions,\n MailboxCredential,\n} from './mailbox-credential-store.js';\nimport type { MailboxEvent, MailboxEventEmitter } from './mailbox-events.js';\nimport {\n MailboxProjectServerConnection,\n type MailboxProjectServerConnectionState,\n} from './mailbox-project-server-client.js';\nimport type {\n AgentHeartbeatInput,\n AgentRegistrationInput,\n AutoCompactOptions,\n AutoCompactResult,\n ClientHeartbeatInput,\n ClientRegistrationInput,\n ClientStatus,\n Mailbox,\n MailboxAckBatchInput,\n MailboxAckInput,\n MailboxAgentStatus,\n MailboxMessage,\n MailboxQuery,\n MailboxSendInput,\n PurgeOptions,\n PurgeResult,\n} from './mailbox-types.js';\nimport { SQLITE_MAILBOX_FILE } from './sqlite-mailbox.js';\n\ntype HqPublisherRef = HqPublisher | (() => HqPublisher | undefined);\nconst HQ_MAILBOX_EVENT_MAX_PENDING = 256;\n\nexport interface ProjectMailboxOptions {\n projectDir: string;\n events?: EventBus | undefined;\n hqPublisher?: HqPublisherRef | undefined;\n eventEmitter?: MailboxEventEmitter | undefined;\n /** Tests/diagnostics only: bypass the normal one-connection-per-process cache. */\n isolatedConnection?: boolean | undefined;\n}\n\ntype RemoteDependencyCache = {\n withoutPublisher?: RemoteMailbox;\n readonly byPublisher: WeakMap<object, RemoteMailbox>;\n};\n\ntype RemoteProjectCache = {\n readonly withoutEvents: RemoteDependencyCache;\n readonly byEvents: WeakMap<object, RemoteDependencyCache>;\n};\n\nconst sharedRemoteMailboxes = new Map<string, RemoteProjectCache>();\nconst sharedProjectConnections = new Map<\n string,\n { connection: MailboxProjectServerConnection; references: number }\n>();\n\nfunction dependencyCache(): RemoteDependencyCache {\n return { byPublisher: new WeakMap() };\n}\n\n/**\n * The project mailbox, as seen by every process that is not the owner.\n *\n * There is no second mode. One detached server per project owns the only\n * SQLite handle, and every CLI/TUI/WebUI/HQ/bridge process reaches it over\n * the deterministic IPC endpoint. If that server cannot be reached the\n * operation fails \u2014 it does not quietly become a private local store, which\n * is how the agent loop once spent a whole migration talking to a\n * `_mailbox.jsonl` nobody else read.\n */\nexport class RemoteMailbox implements Mailbox {\n readonly projectDir: string;\n readonly messagePath: string;\n readonly registryPath: string;\n readonly clientRegistryPath: string;\n private readonly connection: MailboxProjectServerConnection;\n private readonly ownsConnection: boolean;\n private readonly sharedConnectionKey?: string | undefined;\n private readonly events?: EventBus | undefined;\n private readonly hqPublisherRef?: HqPublisherRef | undefined;\n private readonly eventEmitter?: MailboxEventEmitter | undefined;\n private readonly unsubscribeEvent: () => void;\n private readonly unsubscribeMailboxEvent: () => void;\n private cacheEviction: (() => void) | undefined;\n private closed = false;\n /** Pending coalesced HQ snapshot; see {@link scheduleHqSnapshot}. */\n private hqSnapshotTimer: ReturnType<typeof setTimeout> | undefined;\n private hqSnapshotLastAt = 0;\n /** At most one full snapshot may query/map/serialize mailbox state at a time. */\n private hqSnapshotInFlight: Promise<void> | undefined;\n /** Latest scope requested while a timer or snapshot is already active. */\n private hqSnapshotPendingMailboxId: string | undefined;\n /** Message deltas are serialized so a burst cannot launch one full mailbox\n * query per event concurrently. Newer updates for the same message replace\n * older pending ones; the periodic snapshot remains the lossless rollup. */\n private readonly hqEventPending = new Map<string, MailboxEvent>();\n private hqEventInFlight: Promise<void> | undefined;\n private hqEventCoalesced = 0;\n private hqEventDropped = 0;\n\n constructor(\n optionsOrProjectDir: ProjectMailboxOptions | string,\n events?: EventBus,\n hqPublisher?: HqPublisherRef,\n eventEmitter?: MailboxEventEmitter,\n ) {\n const options =\n typeof optionsOrProjectDir === 'string'\n ? {\n projectDir: optionsOrProjectDir,\n events,\n hqPublisher,\n eventEmitter,\n }\n : optionsOrProjectDir;\n this.projectDir = path.resolve(options.projectDir);\n this.messagePath = path.join(this.projectDir, SQLITE_MAILBOX_FILE);\n this.registryPath = this.messagePath;\n this.clientRegistryPath = this.messagePath;\n this.events = options.events;\n this.hqPublisherRef = options.hqPublisher;\n this.eventEmitter = options.eventEmitter;\n // Escape hatch \u2014 must be REQUESTED, never entered by accident. Sniffing\n // VITEST/NODE_ENV here used to put the whole test suite (and anything that\n // happened to set NODE_ENV=test) on a private in-process store, which is\n // precisely the silent \"one store per process\" failure the project-daemon\n // invariant forbids. Matches the sibling daemons: sage, chronicle and\n // codebase-index all gate on their own `WRONGSTACK_*_INLINE` and nothing\n // else. See tests/architecture/project-daemon-boundary.test.ts.\n if (options.isolatedConnection) {\n this.connection = new MailboxProjectServerConnection(this.projectDir);\n this.ownsConnection = true;\n } else {\n let entry = sharedProjectConnections.get(this.projectDir);\n if (!entry) {\n entry = {\n connection: new MailboxProjectServerConnection(this.projectDir),\n references: 0,\n };\n sharedProjectConnections.set(this.projectDir, entry);\n }\n entry.references++;\n this.connection = entry.connection;\n this.sharedConnectionKey = this.projectDir;\n this.ownsConnection = false;\n }\n this.unsubscribeEvent = this.connection.onEvent((event, payload) => {\n this.events?.emitCustom(event, payload);\n this.publishHqRegistryEvent(event, payload);\n });\n this.unsubscribeMailboxEvent = this.connection.onMailboxEvent((event) => {\n this.eventEmitter?.emit(event);\n this.publishHqEvent(event);\n });\n // Eagerly start the detached mailbox IPC server so the first client for\n // this project has a server running without waiting for mail to be sent\n // or received. The connection is idempotent \u2014 if a concurrent\n // initialize() or operation arrives, ensureConnected deduplicates on the\n // in-flight promise. Fire-and-forget: failures are retried lazily on the\n // next real operation.\n void this.connection.connect().catch(() => {\n // Swallowed intentionally; the next mailbox operation will retry.\n });\n }\n\n getConnectionState(): MailboxProjectServerConnectionState {\n return this.connection.getState();\n }\n\n onConnectionStateChange(\n listener: (state: MailboxProjectServerConnectionState) => void,\n ): () => void {\n return this.connection.onStateChange(listener);\n }\n\n async initialize(): Promise<void> {\n await this.connection.connect();\n await this.connection.status();\n }\n\n async status() {\n return this.connection.status();\n }\n\n send(input: MailboxSendInput): Promise<MailboxMessage> {\n return this.connection.call('send', { input });\n }\n\n sendRuntimeControl(\n input: Omit<MailboxSendInput, 'type'> & { type?: 'control' },\n ): Promise<MailboxMessage> {\n return this.connection.call('sendRuntimeControl', { input });\n }\n\n query(query: MailboxQuery): Promise<MailboxMessage[]> {\n return this.connection.call('query', { query });\n }\n\n ack(input: MailboxAckInput): Promise<MailboxMessage | null> {\n return this.connection.call('ack', { input });\n }\n\n ackMany(input: MailboxAckBatchInput): Promise<MailboxMessage[]> {\n return this.connection.call('ackMany', { input });\n }\n\n unreadCount(forAgentId: string, sessionId?: string): Promise<number> {\n return this.connection.call('unreadCount', { forAgentId, sessionId });\n }\n\n softDelete(mailId: string, by: string): Promise<MailboxMessage | null> {\n return this.connection.call('softDelete', { mailId, by });\n }\n\n restore(mailId: string): Promise<MailboxMessage | null> {\n return this.connection.call('restore', { mailId });\n }\n\n registerAgent(input: AgentRegistrationInput): Promise<void> {\n return this.connection.call('registerAgent', { input });\n }\n\n deregisterAgent(agentId: string): Promise<void> {\n return this.connection.call('deregisterAgent', { agentId });\n }\n\n heartbeat(input: AgentHeartbeatInput): Promise<void> {\n return this.connection.call('heartbeat', { input });\n }\n\n getAgentStatuses(): Promise<MailboxAgentStatus[]> {\n return this.connection.call('getAgentStatuses', {});\n }\n\n getOnlineAgents(): Promise<MailboxAgentStatus[]> {\n return this.connection.call('getOnlineAgents', {});\n }\n\n purgeAgents(maxAgeMs?: number): Promise<number> {\n return this.connection.call('purgeAgents', { maxAgeMs });\n }\n\n registerClient(input: ClientRegistrationInput): Promise<void> {\n return this.connection.call('registerClient', { input });\n }\n\n deregisterClient(clientId: string): Promise<void> {\n return this.connection.call('deregisterClient', { clientId });\n }\n\n clientHeartbeat(input: ClientHeartbeatInput): Promise<void> {\n return this.connection.call('clientHeartbeat', { input });\n }\n\n getClientStatuses(): Promise<ClientStatus[]> {\n return this.connection.call('getClientStatuses', {});\n }\n\n purgeClients(): Promise<number> {\n return this.connection.call('purgeClients', {});\n }\n\n clearAll(): Promise<void> {\n return this.connection.call('clearAll', {});\n }\n\n purgeStale(options?: PurgeOptions): Promise<PurgeResult> {\n return this.connection.call('purgeStale', { options });\n }\n\n autoCompact(options?: AutoCompactOptions): Promise<AutoCompactResult> {\n return this.connection.call('autoCompact', { options }, { timeoutMs: 2 * 60_000 });\n }\n\n credentialIssue(\n options: IssueCredentialOptions,\n ): Promise<{ credential: MailboxCredential; secret: string }> {\n return this.connection.call('credentialIssue', { options });\n }\n\n credentialVerify(credentialId: string, secret: string): Promise<CredentialValidation> {\n return this.connection.call('credentialVerify', { credentialId, secret });\n }\n\n credentialRevoke(credentialId: string, reason?: string, by?: string): Promise<boolean> {\n return this.connection.call('credentialRevoke', { credentialId, reason, by });\n }\n\n credentialRotate(\n credentialId: string,\n options?: Partial<IssueCredentialOptions>,\n ): Promise<{ credential: MailboxCredential; secret: string } | null> {\n return this.connection.call('credentialRotate', { credentialId, options });\n }\n\n credentialGet(credentialId: string): Promise<MailboxCredential | null> {\n return this.connection.call('credentialGet', { credentialId });\n }\n\n credentialList(): Promise<MailboxCredential[]> {\n return this.connection.call('credentialList', {});\n }\n\n credentialStatusCounts(): Promise<Record<string, number>> {\n return this.connection.call('credentialStatusCounts', {});\n }\n\n startAutoCompactTimer(_options?: AutoCompactOptions): () => void {\n // The detached owner runs exactly one compaction timer for the project;\n // clients must never start their own.\n return () => {};\n }\n\n async close(): Promise<void> {\n if (this.closed) return;\n this.closed = true;\n if (this.hqSnapshotTimer !== undefined) {\n clearTimeout(this.hqSnapshotTimer);\n this.hqSnapshotTimer = undefined;\n }\n this.hqSnapshotPendingMailboxId = undefined;\n this.hqEventPending.clear();\n this.cacheEviction?.();\n this.cacheEviction = undefined;\n this.unsubscribeEvent();\n this.unsubscribeMailboxEvent();\n if (this.ownsConnection) {\n this.connection.close();\n return;\n }\n if (this.sharedConnectionKey !== undefined) {\n const entry = sharedProjectConnections.get(this.sharedConnectionKey);\n if (entry?.connection === this.connection) {\n entry.references = Math.max(0, entry.references - 1);\n if (entry.references === 0) {\n entry.connection.close();\n sharedProjectConnections.delete(this.sharedConnectionKey);\n }\n }\n }\n }\n\n /** @internal Remove a process-shared wrapper from its cache when explicitly closed. */\n setCacheEviction(evict: () => void): void {\n this.cacheEviction = evict;\n }\n\n /** Lightweight diagnostics for the process memory flight recorder. */\n getHqSnapshotStats(): {\n inFlight: boolean;\n pending: boolean;\n timerScheduled: boolean;\n eventInFlight: boolean;\n pendingEvents: number;\n coalescedEvents: number;\n droppedEvents: number;\n } {\n return {\n inFlight: this.hqSnapshotInFlight !== undefined,\n pending: this.hqSnapshotPendingMailboxId !== undefined,\n timerScheduled: this.hqSnapshotTimer !== undefined,\n eventInFlight: this.hqEventInFlight !== undefined,\n pendingEvents: this.hqEventPending.size,\n coalescedEvents: this.hqEventCoalesced,\n droppedEvents: this.hqEventDropped,\n };\n }\n\n private get hqPublisher(): HqPublisher | undefined {\n return typeof this.hqPublisherRef === 'function' ? this.hqPublisherRef() : this.hqPublisherRef;\n }\n\n /**\n * Publish a full HQ mailbox snapshot, at most once per\n * {@link HQ_MAILBOX_SNAPSHOT_MIN_INTERVAL_MS}.\n *\n * Trailing-edge: the first caller after the interval schedules one, and\n * every caller in the window folds into it. The snapshot is a rollup of\n * current state, so a coalesced publish carries strictly more up-to-date\n * information than the ones it replaced \u2014 dropping them loses nothing.\n */\n private scheduleHqSnapshot(mailboxId: string): void {\n if (this.closed) return;\n this.hqSnapshotPendingMailboxId = mailboxId;\n if (this.hqSnapshotTimer !== undefined || this.hqSnapshotInFlight !== undefined) return;\n const elapsed = Date.now() - this.hqSnapshotLastAt;\n const delay = Math.max(0, HQ_MAILBOX_SNAPSHOT_MIN_INTERVAL_MS - elapsed);\n this.hqSnapshotTimer = setTimeout(() => {\n this.hqSnapshotTimer = undefined;\n const pendingMailboxId = this.hqSnapshotPendingMailboxId;\n this.hqSnapshotPendingMailboxId = undefined;\n const publisher = this.hqPublisher;\n if (this.closed || !publisher || pendingMailboxId === undefined) return;\n this.hqSnapshotLastAt = Date.now();\n const inFlight = (async () => {\n try {\n await publisher.publishMailboxSnapshot(this, { mailboxId: pendingMailboxId });\n } catch {\n // HQ telemetry remains best-effort.\n } finally {\n this.hqSnapshotInFlight = undefined;\n const nextMailboxId = this.hqSnapshotPendingMailboxId;\n if (!this.closed && nextMailboxId !== undefined) {\n this.scheduleHqSnapshot(nextMailboxId);\n }\n }\n })();\n this.hqSnapshotInFlight = inFlight;\n }, delay);\n // Never hold the process open for a telemetry rollup.\n this.hqSnapshotTimer.unref?.();\n }\n\n private publishHqEvent(event: MailboxEvent): void {\n if (!this.hqPublisher || this.closed) return;\n if (this.hqEventPending.has(event.messageId)) {\n this.hqEventCoalesced += 1;\n } else if (this.hqEventPending.size >= HQ_MAILBOX_EVENT_MAX_PENDING) {\n const oldest = this.hqEventPending.keys().next().value;\n if (oldest !== undefined) this.hqEventPending.delete(oldest);\n this.hqEventDropped += 1;\n }\n this.hqEventPending.set(event.messageId, event);\n this.drainHqEvents();\n }\n\n private drainHqEvents(): void {\n if (this.closed || this.hqEventInFlight !== undefined) return;\n const next = this.hqEventPending.entries().next().value as [string, MailboxEvent] | undefined;\n if (!next) return;\n const [messageId, event] = next;\n this.hqEventPending.delete(messageId);\n const publisher = this.hqPublisher;\n if (!publisher) {\n this.hqEventPending.clear();\n return;\n }\n const mailboxId = `${path.basename(this.projectDir)}:mailbox`;\n const inFlight = this.query({ includeDeleted: true, limit: 100 })\n .then((messages) => {\n const message = messages.find((candidate) => candidate.id === event.messageId);\n const action = event.type === 'message.sent' ? 'message.sent' : 'message.updated';\n publisher.publishMailboxEvent({\n mailboxId,\n action,\n ...(message ? { message } : {}),\n timestamp: event.timestamp,\n });\n this.scheduleHqSnapshot(mailboxId);\n })\n .catch(() => {\n // HQ telemetry remains best-effort.\n })\n .finally(() => {\n this.hqEventInFlight = undefined;\n this.drainHqEvents();\n });\n this.hqEventInFlight = inFlight;\n }\n\n private publishHqRegistryEvent(event: string, payload: unknown): void {\n const publisher = this.hqPublisher;\n if (\n !publisher ||\n (!event.startsWith('mailbox.agent_') && !event.startsWith('mailbox.client_'))\n ) {\n return;\n }\n const mailboxId = `${path.basename(this.projectDir)}:mailbox`;\n const record =\n typeof payload === 'object' && payload !== null ? (payload as Record<string, unknown>) : {};\n const agentId = typeof record['agentId'] === 'string' ? record['agentId'] : undefined;\n const action =\n event === 'mailbox.agent_registered'\n ? 'agent.registered'\n : event === 'mailbox.agent_heartbeat'\n ? 'agent.heartbeat'\n : event === 'mailbox.agent_deregistered'\n ? 'agent.deregistered'\n : undefined;\n void this.getAgentStatuses()\n .then((statuses) => {\n const agent = agentId\n ? statuses.find((candidate) => candidate.agentId === agentId)\n : undefined;\n if (action) {\n publisher.publishMailboxEvent({\n mailboxId,\n action,\n ...(agent ? { agent } : {}),\n ...(agentId ? { summary: agentId } : {}),\n });\n }\n // A heartbeat only refreshes one agent's `lastSeen` \u2014 it changes no\n // roster membership and no message state, so the snapshot rollup it\n // used to trigger was pure duplication of the delta just published.\n // With one heartbeat per agent per 30s, that path alone accounted for\n // most of the snapshot volume. Registration and deregistration do\n // move the roster, so those still schedule a (coalesced) snapshot.\n if (action !== 'agent.heartbeat') this.scheduleHqSnapshot(mailboxId);\n })\n .catch(() => {\n // HQ telemetry remains best-effort.\n });\n }\n}\n\nexport function createProjectMailbox(options: ProjectMailboxOptions): RemoteMailbox {\n return new RemoteMailbox(options);\n}\n\nexport function getSharedProjectMailbox(\n projectDir: string,\n events?: EventBus,\n hqPublisher?: HqPublisherRef,\n): RemoteMailbox {\n const key = path.resolve(projectDir);\n let projectCache = sharedRemoteMailboxes.get(key);\n if (!projectCache) {\n projectCache = {\n withoutEvents: dependencyCache(),\n byEvents: new WeakMap(),\n };\n sharedRemoteMailboxes.set(key, projectCache);\n }\n let dependencies = projectCache.withoutEvents;\n if (events) {\n dependencies = projectCache.byEvents.get(events) ?? dependencyCache();\n projectCache.byEvents.set(events, dependencies);\n }\n if (!hqPublisher) {\n if (!dependencies.withoutPublisher) {\n const mailbox = new RemoteMailbox(key, events);\n dependencies.withoutPublisher = mailbox;\n mailbox.setCacheEviction(() => {\n if (dependencies.withoutPublisher === mailbox) {\n delete dependencies.withoutPublisher;\n }\n });\n }\n return dependencies.withoutPublisher;\n }\n const publisherKey = Object(hqPublisher);\n const existing = dependencies.byPublisher.get(publisherKey);\n if (existing) return existing;\n const mailbox = new RemoteMailbox(key, events, hqPublisher);\n dependencies.byPublisher.set(publisherKey, mailbox);\n mailbox.setCacheEviction(() => {\n if (dependencies.byPublisher.get(publisherKey) === mailbox) {\n dependencies.byPublisher.delete(publisherKey);\n }\n });\n return mailbox;\n}\n", "/**\n * Centralized constants for the mailbox system.\n *\n * Previously these magic numbers were scattered across global-mailbox.ts,\n * mailbox-attach.ts, mailbox-hooks.ts, and mailbox-health.ts. Keeping them\n * in one place ensures every surface agrees on timeouts, intervals, and\n * thresholds \u2014 and makes tuning a single-file change.\n *\n * @module mailbox-constants\n */\n\n/**\n * Agents without a heartbeat for this long are no longer live and are removed\n * from the registry. Presence registries are not history stores: retaining an\n * offline row makes dead agents and shadow workers look actionable in HQ.\n */\nexport const AGENT_STALE_MS = 60_000;\n\n/** Clients without a heartbeat for this long are considered offline. */\nexport const CLIENT_STALE_MS = 60_000;\n\n/** Heartbeat updates are throttled to at most this interval (per agent/client). */\nexport const HEARTBEAT_THROTTLE_MS = 5_000;\n\n/**\n * How long a read may be served from the in-process registry cache before\n * re-reading the shared file. Kept well below HEARTBEAT_THROTTLE_MS so\n * cross-process registrations become visible promptly.\n */\nexport const REGISTRY_CACHE_TTL_MS = 2_000;\n\n/** JSONL line separator. */\nexport const LINE_SEPARATOR = '\\n';\n\n/**\n * Soft cap on the in-memory message cache. The cache mirrors the JSONL\n * message file; under normal load it stays well under this. If a pathological\n * mailbox exceeds the cap we fall back to reading from disk rather than\n * holding an unbounded buffer in memory.\n */\nexport const MESSAGE_CACHE_MAX_ENTRIES = 10_000;\n\n// \u2500\u2500 Polling / heartbeat intervals (used by mailbox-attach.ts) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Background mailbox awareness polling interval (cross-process fallback). */\nexport const MAILBOX_AWARENESS_INTERVAL_MS = 30_000;\n\n/** Agent heartbeat interval in the attach layer. */\nexport const MAILBOX_HEARTBEAT_INTERVAL_MS = 30_000;\n\n/**\n * Floor on how often a full HQ mailbox snapshot may be published.\n *\n * The snapshot is a rollup (50 messages + every agent status, ~30 KB) that\n * exists so the HQ dashboard's counters are authoritative. It used to be\n * published after *every* message mutation and *every* agent heartbeat, which\n * made it the single largest thing HQ persists: 14,053 snapshots totalling\n * 415 MB in one measured `events.jsonl`, next to 8.3 MB for the 12,445\n * `mailbox.event` deltas that already carried the same information.\n *\n * Snapshots are now coalesced behind this interval \u2014 the dashboard converges\n * within a few seconds instead of on every keystroke-scale event, and the\n * deltas keep the live feed exact in between.\n */\nexport const HQ_MAILBOX_SNAPSHOT_MIN_INTERVAL_MS = 10_000;\n\n/** Min interval between registry reads for the fleet pulse digest. */\nexport const PULSE_MIN_READ_INTERVAL_MS = 30_000;\n\n/**\n * Floor on how often the pre-tool hook actually reads the mailbox.\n *\n * `beforeTool` fires once per tool call, and a busy turn issues dozens. Each\n * call stats the shared message file and, whenever another session has written\n * to it, pays a read. Collapsing bursts to one check per second keeps steer\n * messages effectively immediate (no tool completes fast enough for a human to\n * notice the difference) while removing the per-tool file churn. Set the hook's\n * `unreadCheckIntervalMs` to 0 to check on every call.\n */\nexport const UNREAD_CHECK_MIN_INTERVAL_MS = 1_000;\n\n// \u2500\u2500 Auto-cleanup / compaction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Interval at which the background auto-compaction sweep runs.\n * Default: every 5 minutes.\n */\nexport const AUTO_COMPACT_INTERVAL_MS = 300_000;\n\n/**\n * Messages that have been read by ALL currently-online agents are eligible\n * for auto-removal after this many milliseconds since the last read.\n * Default: 10 minutes.\n */\nexport const AUTO_COMPACT_READ_MAX_AGE_MS = 600_000;\n\n/**\n * Messages whose TTL (time-to-live) has expired are eligible for auto-removal.\n * When a message has `expiresAt` set and that timestamp is in the past, the\n * next compaction sweep drops it. Default TTL for messages without an explicit\n * `expiresAt`: 24 hours.\n */\nexport const AUTO_COMPACT_DEFAULT_TTL_MS = 86_400_000; // 24h\n\n/**\n * Per-type TTL overrides for message classes that are pure live-awareness\n * chatter, applied when the message carries no explicit `expiresAt`.\n *\n * `status` is broadcast by the fleet supervisor, host supervisor, mailbox\n * health probe and handoff plugin purely so peers can see who is doing what\n * *right now*; nothing reads it back as history. Under the 24h default it\n * dominated the shared file \u2014 on a real project mailbox, 1807 of 2766 lines\n * and 1.5 MB of 3 MB \u2014 and every reader pays for that on any cache miss.\n * Half an hour is far longer than any consumer's interest window.\n *\n * Keyed by `MailboxMessageType`; unlisted types keep\n * {@link AUTO_COMPACT_DEFAULT_TTL_MS}.\n */\nexport const AUTO_COMPACT_TYPE_TTL_MS: Readonly<Record<string, number>> = {\n status: 1_800_000, // 30 min\n};\n\n// \u2500\u2500 HTTP bridge rate limiting \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Maximum requests per minute from a single external agent (bearer token). */\nexport const HTTP_RATE_LIMIT_PER_MINUTE = 120;\n\n/** Window size for the sliding-window rate limiter. */\nexport const HTTP_RATE_LIMIT_WINDOW_MS = 60_000;\n", "import { spawn } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as net from 'node:net';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { MailboxEvent } from './mailbox-events.js';\nimport { mailboxProjectServerEndpoint } from './mailbox-project-server-endpoint.js';\nimport {\n encodeMailboxProjectServerMessage,\n isMailboxProjectServerMessage,\n MAILBOX_PROJECT_SERVER_MAX_FRAME_CHARS,\n MAILBOX_PROJECT_SERVER_PROTOCOL_VERSION,\n type MailboxProjectServerInfo,\n type MailboxProjectServerMessage,\n type MailboxProjectServerStatus,\n type MailboxServerOperationName,\n type MailboxServerOperations,\n} from './mailbox-project-server-protocol.js';\n\nconst CONNECT_ATTEMPT_TIMEOUT_MS = 750;\nconst SERVER_START_TIMEOUT_MS = 10_000;\nconst DEFAULT_CALL_TIMEOUT_MS = 30_000;\nconst DEFAULT_HEARTBEAT_INTERVAL_MS = 10_000;\n\ninterface PendingRequest {\n resolve(value: unknown): void;\n reject(error: unknown): void;\n timer: ReturnType<typeof setTimeout>;\n}\n\nexport type MailboxProjectServerConnectionStatus =\n | 'offline'\n | 'connecting'\n | 'connected'\n | 'error'\n | 'stopping'\n | 'unavailable';\n\nexport interface MailboxProjectServerConnectionState {\n status: MailboxProjectServerConnectionStatus;\n connected: boolean;\n projectDir: string;\n endpoint: string;\n pid?: number | undefined;\n lastError?: string | undefined;\n}\n\nfunction normalizePath(value: string): string {\n const resolved = path.resolve(value);\n return process.platform === 'win32' ? resolved.toLowerCase() : resolved;\n}\n\n/**\n * Locate the built project-server entrypoint.\n *\n * There is deliberately no env var that turns the server off. The mailbox has\n * exactly one mode \u2014 one detached owner per project, reached over IPC \u2014 so the\n * only reason this returns null is a missing build, and that is an error, not\n * a fallback. `WRONGSTACK_MAILBOX_INLINE` / `WRONGSTACK_MAILBOX_SERVER=0` used\n * to select an in-process store here; they are gone. Do not reintroduce them:\n * the moment a client can quietly open its own store, \"one mailbox per\n * project\" becomes \"one mailbox per process\" with no visible symptom.\n */\nfunction resolveProjectServerUrl(): URL | null {\n for (const relative of [\n './mailbox-project-server.js',\n '../../dist/coordination/mailbox-project-server.js',\n ]) {\n try {\n const url = new URL(relative, import.meta.url);\n if (url.protocol === 'file:' && fs.existsSync(fileURLToPath(url))) return url;\n } catch {\n // Try the next supported build layout.\n }\n }\n return null;\n}\n\nexport function isMailboxProjectServerAvailable(): boolean {\n return resolveProjectServerUrl() !== null;\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport class MailboxProjectServerConnection {\n readonly endpoint: string;\n private socket: net.Socket | null = null;\n private info: MailboxProjectServerInfo | null = null;\n private buffer = '';\n private connecting: Promise<void> | null = null;\n private connectResolve: (() => void) | null = null;\n private connectReject: ((error: unknown) => void) | null = null;\n private nextId = 1;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private readonly pending = new Map<number, PendingRequest>();\n private readonly eventListeners = new Set<(event: string, payload: unknown) => void>();\n private readonly mailboxEventListeners = new Set<(event: MailboxEvent) => void>();\n private readonly stateListeners = new Set<(state: MailboxProjectServerConnectionState) => void>();\n private state: MailboxProjectServerConnectionState;\n\n constructor(readonly projectDir: string) {\n this.projectDir = path.resolve(projectDir);\n this.endpoint = mailboxProjectServerEndpoint(this.projectDir);\n this.state = {\n status: isMailboxProjectServerAvailable() ? 'offline' : 'unavailable',\n connected: false,\n projectDir: this.projectDir,\n endpoint: this.endpoint,\n };\n }\n\n getState(): MailboxProjectServerConnectionState {\n return { ...this.state };\n }\n\n onStateChange(listener: (state: MailboxProjectServerConnectionState) => void): () => void {\n this.stateListeners.add(listener);\n return () => this.stateListeners.delete(listener);\n }\n\n onEvent(listener: (event: string, payload: unknown) => void): () => void {\n this.eventListeners.add(listener);\n return () => this.eventListeners.delete(listener);\n }\n\n onMailboxEvent(listener: (event: MailboxEvent) => void): () => void {\n this.mailboxEventListeners.add(listener);\n return () => this.mailboxEventListeners.delete(listener);\n }\n\n async connect(): Promise<void> {\n await this.ensureConnected(true);\n }\n\n async status(): Promise<MailboxProjectServerStatus> {\n return this.call('ping', {}, { timeoutMs: 3_000 });\n }\n\n /**\n * Inspect an existing project server without starting one.\n * Returns null when no server is running (ECONNREFUSED / timeout).\n * Mirrors the SAGE `status()` probe pattern.\n */\n async probeStatus(): Promise<MailboxProjectServerStatus | null> {\n try {\n await this.ensureConnected(false);\n return await this.request<MailboxProjectServerStatus>(\n { type: 'request', op: 'ping', args: {} },\n 3_000,\n );\n } catch {\n this.close();\n return null;\n }\n }\n\n async call<O extends MailboxServerOperationName>(\n op: O,\n args: MailboxServerOperations[O]['args'],\n options: { timeoutMs?: number | undefined } = {},\n ): Promise<MailboxServerOperations[O]['result']> {\n await this.ensureConnected(true);\n return this.request<MailboxServerOperations[O]['result']>(\n { type: 'request', op, args },\n options.timeoutMs ?? DEFAULT_CALL_TIMEOUT_MS,\n );\n }\n\n async shutdown(reason?: string): Promise<{ stopped: boolean; pid?: number; reason?: string }> {\n try {\n await this.ensureConnected(false);\n } catch {\n return { stopped: false, reason: 'offline' };\n }\n const pid = this.info?.pid;\n const result = await this.request<{ stopped: boolean; pid?: number; reason?: string }>(\n { type: 'shutdown', reason },\n 5_000,\n );\n return { ...result, ...(pid !== undefined && result.pid === undefined ? { pid } : {}) };\n }\n\n close(): void {\n this.stopHeartbeat();\n const socket = this.socket;\n this.socket = null;\n this.info = null;\n socket?.destroy();\n this.rejectPending(new Error('Mailbox project server connection closed'));\n this.transition('offline');\n }\n\n private transition(status: MailboxProjectServerConnectionStatus, error?: unknown): void {\n this.state = {\n status,\n connected: status === 'connected',\n projectDir: this.projectDir,\n endpoint: this.endpoint,\n ...(status === 'connected' && this.info ? { pid: this.info.pid } : {}),\n ...(error !== undefined\n ? { lastError: error instanceof Error ? error.message : String(error) }\n : {}),\n };\n for (const listener of [...this.stateListeners]) listener({ ...this.state });\n }\n\n private async ensureConnected(spawnIfMissing: boolean): Promise<void> {\n if (this.socket && !this.socket.destroyed && this.info) return;\n if (this.connecting) return this.connecting;\n if (!isMailboxProjectServerAvailable()) {\n this.transition('unavailable');\n throw new Error(\n 'Built mailbox project server is unavailable. Run `pnpm --filter @wrongstack/core build`. ' +\n 'The mailbox has no in-process mode: there is no env var to fall back to, by design.',\n );\n }\n this.transition('connecting');\n this.connecting = this.connectWithElection(spawnIfMissing)\n .catch((error) => {\n this.transition('error', error);\n throw error;\n })\n .finally(() => {\n this.connecting = null;\n });\n return this.connecting;\n }\n\n private async connectWithElection(spawnIfMissing: boolean): Promise<void> {\n const deadline =\n Date.now() + (spawnIfMissing ? SERVER_START_TIMEOUT_MS : CONNECT_ATTEMPT_TIMEOUT_MS);\n let spawned = false;\n let lastError: unknown = new Error('Mailbox project server unavailable');\n while (Date.now() < deadline) {\n try {\n await this.connectOnce();\n return;\n } catch (error) {\n lastError = error;\n }\n if (!spawnIfMissing) break;\n if (!spawned) {\n this.spawnDetachedServer();\n spawned = true;\n }\n await delay(75);\n }\n throw lastError;\n }\n\n private connectOnce(): Promise<void> {\n this.socket?.destroy();\n this.socket = null;\n this.info = null;\n this.buffer = '';\n return new Promise<void>((resolve, reject) => {\n const socket = net.createConnection(this.endpoint);\n this.socket = socket;\n socket.setEncoding('utf8');\n const timer = setTimeout(() => {\n this.connectReject?.(new Error('Mailbox project server handshake timed out'));\n socket.destroy();\n }, CONNECT_ATTEMPT_TIMEOUT_MS);\n timer.unref?.();\n this.connectResolve = () => {\n clearTimeout(timer);\n this.connectResolve = null;\n this.connectReject = null;\n this.startHeartbeat();\n this.transition('connected');\n resolve();\n };\n this.connectReject = (error) => {\n clearTimeout(timer);\n this.connectResolve = null;\n this.connectReject = null;\n reject(error);\n };\n socket.on('data', (chunk: string) => this.onData(socket, chunk));\n socket.on('error', (error) => {\n if (!this.info) this.connectReject?.(error);\n });\n socket.on('close', () => this.onClose(socket));\n });\n }\n\n private request<T>(\n message:\n | { type: 'request'; op: MailboxServerOperationName; args: unknown }\n | { type: 'shutdown'; reason?: string | undefined },\n timeoutMs: number,\n ): Promise<T> {\n const socket = this.socket;\n if (!socket || socket.destroyed) {\n return Promise.reject(new Error('Mailbox project server connection is unavailable'));\n }\n const id = this.nextId++;\n const encoded = encodeMailboxProjectServerMessage({ ...message, id });\n if (encoded.length > MAILBOX_PROJECT_SERVER_MAX_FRAME_CHARS) {\n return Promise.reject(new Error('Mailbox project server request exceeded frame limit'));\n }\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n const pending = this.pending.get(id);\n if (!pending) return;\n this.pending.delete(id);\n pending.reject(new Error(`Mailbox ${message.type} exceeded its ${timeoutMs}ms timeout`));\n }, timeoutMs);\n timer.unref?.();\n this.pending.set(id, { resolve, reject, timer });\n socket.write(encoded);\n });\n }\n\n private onData(socket: net.Socket, chunk: string): void {\n if (socket !== this.socket) return;\n this.buffer += chunk;\n while (true) {\n const newline = this.buffer.indexOf('\\n');\n if (newline < 0) {\n if (this.buffer.length > MAILBOX_PROJECT_SERVER_MAX_FRAME_CHARS) {\n socket.destroy(new Error('Mailbox project server response exceeded frame limit'));\n }\n return;\n }\n if (newline > MAILBOX_PROJECT_SERVER_MAX_FRAME_CHARS) {\n socket.destroy(new Error('Mailbox project server response exceeded frame limit'));\n return;\n }\n const line = this.buffer.slice(0, newline);\n this.buffer = this.buffer.slice(newline + 1);\n if (!line) continue;\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n socket.destroy(new Error('Invalid mailbox project server response'));\n return;\n }\n if (!isMailboxProjectServerMessage(parsed)) {\n socket.destroy(new Error('Invalid mailbox project server response'));\n return;\n }\n this.onMessage(parsed);\n }\n }\n\n private onMessage(message: MailboxProjectServerMessage): void {\n if (message.type === 'hello') {\n if (message.protocolVersion !== MAILBOX_PROJECT_SERVER_PROTOCOL_VERSION) {\n this.connectReject?.(\n new Error(\n `Mailbox protocol mismatch: client=${MAILBOX_PROJECT_SERVER_PROTOCOL_VERSION}, server=${message.protocolVersion}`,\n ),\n );\n this.socket?.destroy();\n return;\n }\n if (normalizePath(message.projectDir) !== normalizePath(this.projectDir)) {\n this.connectReject?.(new Error('Mailbox project server identity mismatch'));\n this.socket?.destroy();\n return;\n }\n this.info = message;\n this.connectResolve?.();\n return;\n }\n if (message.type === 'event') {\n for (const listener of [...this.eventListeners]) listener(message.event, message.payload);\n return;\n }\n if (message.type === 'mailbox-event') {\n for (const listener of [...this.mailboxEventListeners]) listener(message.event);\n return;\n }\n const pending = this.pending.get(message.id);\n if (!pending) return;\n this.pending.delete(message.id);\n clearTimeout(pending.timer);\n if (message.ok) pending.resolve(message.result);\n else {\n const error = new Error(message.error);\n if (message.errorName) error.name = message.errorName;\n pending.reject(error);\n }\n }\n\n private onClose(socket: net.Socket): void {\n if (socket !== this.socket) return;\n this.socket = null;\n this.info = null;\n this.stopHeartbeat();\n const error = new Error('Mailbox project server connection closed');\n this.connectReject?.(error);\n this.connectResolve = null;\n this.connectReject = null;\n this.rejectPending(error);\n this.transition('offline');\n }\n\n private rejectPending(error: Error): void {\n const pending = [...this.pending.values()];\n this.pending.clear();\n for (const item of pending) {\n clearTimeout(item.timer);\n item.reject(error);\n }\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat();\n const configured = Number(process.env['WRONGSTACK_MAILBOX_CLIENT_HEARTBEAT_MS']);\n const intervalMs =\n Number.isFinite(configured) && configured >= 50 ? configured : DEFAULT_HEARTBEAT_INTERVAL_MS;\n this.heartbeatTimer = setInterval(() => {\n const socket = this.socket;\n if (socket && !socket.destroyed) {\n socket.write(encodeMailboxProjectServerMessage({ type: 'heartbeat' }));\n }\n }, intervalMs);\n this.heartbeatTimer.unref?.();\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n\n private spawnDetachedServer(): void {\n const url = resolveProjectServerUrl();\n if (!url) throw new Error('Mailbox project server entrypoint is unavailable');\n // The mailbox may be the first project-scoped service touched during a\n // lightweight TUI/WebUI launch. Ensure the spawn cwd exists before the\n // detached owner is created; the owner remains the only SQLite opener.\n fs.mkdirSync(this.projectDir, { recursive: true });\n const child = spawn(process.execPath, [fileURLToPath(url), '--project-dir', this.projectDir], {\n cwd: this.projectDir,\n detached: process.platform !== 'win32',\n stdio: 'ignore',\n windowsHide: true,\n env: process.env,\n });\n child.unref();\n }\n}\n", "import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { assertUnixSocketPathWithinLimit } from '../utils/socket-path.js';\nimport { MAILBOX_PROJECT_SERVER_PROTOCOL_VERSION } from './mailbox-project-server-protocol.js';\n\nexport const MAILBOX_PROJECT_SERVER_METADATA_FILE = '.mailbox-server.json';\n\nfunction normalizeLocalPath(value: string): string {\n const resolved = path.resolve(value);\n return process.platform === 'win32' ? resolved.toLowerCase() : resolved;\n}\n\nexport function mailboxProjectServerKey(projectDir: string): string {\n return createHash('sha256')\n .update(normalizeLocalPath(projectDir))\n .digest('hex')\n .slice(0, 24);\n}\n\n/**\n * Deterministic per-project mailbox IPC endpoint.\n *\n * The Unix subdirectory is the short `wsmb-v<V>/` (was\n * `wrongstack-mailbox-v<V>/`, which left only 3 bytes of macOS `sun_path`\n * headroom under the ~48-byte per-user TMPDIR \u2014 see the codebase-index macOS\n * incident and `@wrongstack/persistence` socket-path helpers). ~86 bytes\n * worst-case macOS now.\n *\n * Migration: the protocol version stays embedded in the path, so this rename\n * behaves exactly like a protocol bump \u2014 old daemons keep listening on the old\n * `wrongstack-mailbox-v<V>/` path, are never contacted again, and exit on\n * their idle timeout. No coexistence window: a client build always talks only\n * to the endpoint scheme it derives. Bump\n * `MAILBOX_PROJECT_SERVER_PROTOCOL_VERSION` for wire changes as before; the\n * prefix itself must not grow without re-checking the byte budget.\n * The Windows pipe name keeps the long prefix \u2014 named pipes have no\n * `sun_path` limit.\n */\nexport function mailboxProjectServerEndpoint(projectDir: string): string {\n const key = mailboxProjectServerKey(projectDir);\n if (process.platform === 'win32') {\n return `\\\\\\\\.\\\\pipe\\\\wrongstack-mailbox-v${MAILBOX_PROJECT_SERVER_PROTOCOL_VERSION}-${key}`;\n }\n return path.join(\n os.tmpdir(),\n `wsmb-v${MAILBOX_PROJECT_SERVER_PROTOCOL_VERSION}`,\n `${key}.sock`,\n );\n}\n\nexport function mailboxProjectServerMetadataPath(projectDir: string): string {\n return path.join(path.resolve(projectDir), MAILBOX_PROJECT_SERVER_METADATA_FILE);\n}\n\nexport function ensureMailboxProjectServerSocketDirectory(endpoint: string): void {\n if (process.platform !== 'win32') {\n // ~86 bytes under a canonical macOS TMPDIR since the wsmb-v1/ rename.\n // Assert so growth fails loudly instead of as a silent bind error in the\n // detached daemon (see the codebase-index macOS incident).\n assertUnixSocketPathWithinLimit(endpoint, 'mailbox');\n fs.mkdirSync(path.dirname(endpoint), { recursive: true, mode: 0o700 });\n }\n}\n", "import type { MailboxEvent } from './mailbox-events.js';\nimport type {\n CredentialValidation,\n IssueCredentialOptions,\n MailboxCredential,\n} from './mailbox-credential-store.js';\nimport type {\n AgentHeartbeatInput,\n AgentRegistrationInput,\n AutoCompactOptions,\n AutoCompactResult,\n ClientHeartbeatInput,\n ClientRegistrationInput,\n ClientStatus,\n MailboxAckBatchInput,\n MailboxAckInput,\n MailboxAgentStatus,\n MailboxMessage,\n MailboxQuery,\n MailboxSendInput,\n PurgeOptions,\n PurgeResult,\n} from './mailbox-types.js';\n\nexport const MAILBOX_PROJECT_SERVER_PROTOCOL_VERSION = 3;\nexport const MAILBOX_PROJECT_SERVER_MAX_FRAME_CHARS = 16 * 1024 * 1024;\n\nexport interface MailboxProjectServerInfo {\n protocolVersion: number;\n pid: number;\n projectDir: string;\n endpoint: string;\n startedAt: string;\n}\n\nexport interface MailboxProjectServerStatus extends MailboxProjectServerInfo {\n clients: number;\n pendingRequests: number;\n /** Compatibility alias; points to databasePath for protocol v2+. */\n messagePath: string;\n databasePath: string;\n storageKind: 'sqlite' | 'legacy-test-adapter';\n}\n\nexport interface MailboxServerOperations {\n ping: { args: Record<string, never>; result: MailboxProjectServerStatus };\n send: { args: { input: MailboxSendInput }; result: MailboxMessage };\n sendRuntimeControl: {\n args: { input: Omit<MailboxSendInput, 'type'> & { type?: 'control' } };\n result: MailboxMessage;\n };\n query: { args: { query: MailboxQuery }; result: MailboxMessage[] };\n ack: { args: { input: MailboxAckInput }; result: MailboxMessage | null };\n ackMany: { args: { input: MailboxAckBatchInput }; result: MailboxMessage[] };\n unreadCount: {\n args: { forAgentId: string; sessionId?: string | undefined };\n result: number;\n };\n softDelete: {\n args: { mailId: string; by: string };\n result: MailboxMessage | null;\n };\n restore: { args: { mailId: string }; result: MailboxMessage | null };\n registerAgent: { args: { input: AgentRegistrationInput }; result: void };\n deregisterAgent: { args: { agentId: string }; result: void };\n heartbeat: { args: { input: AgentHeartbeatInput }; result: void };\n getAgentStatuses: { args: Record<string, never>; result: MailboxAgentStatus[] };\n getOnlineAgents: { args: Record<string, never>; result: MailboxAgentStatus[] };\n purgeAgents: { args: { maxAgeMs?: number | undefined }; result: number };\n registerClient: { args: { input: ClientRegistrationInput }; result: void };\n deregisterClient: { args: { clientId: string }; result: void };\n clientHeartbeat: { args: { input: ClientHeartbeatInput }; result: void };\n getClientStatuses: { args: Record<string, never>; result: ClientStatus[] };\n purgeClients: { args: Record<string, never>; result: number };\n clearAll: { args: Record<string, never>; result: void };\n purgeStale: { args: { options?: PurgeOptions | undefined }; result: PurgeResult };\n autoCompact: {\n args: { options?: AutoCompactOptions | undefined };\n result: AutoCompactResult;\n };\n credentialIssue: {\n args: { options: IssueCredentialOptions };\n result: { credential: MailboxCredential; secret: string };\n };\n credentialVerify: {\n args: { credentialId: string; secret: string };\n result: CredentialValidation;\n };\n credentialRevoke: {\n args: { credentialId: string; reason?: string | undefined; by?: string | undefined };\n result: boolean;\n };\n credentialRotate: {\n args: { credentialId: string; options?: Partial<IssueCredentialOptions> | undefined };\n result: { credential: MailboxCredential; secret: string } | null;\n };\n credentialGet: {\n args: { credentialId: string };\n result: MailboxCredential | null;\n };\n credentialList: {\n args: Record<string, never>;\n result: MailboxCredential[];\n };\n credentialStatusCounts: {\n args: Record<string, never>;\n result: Record<string, number>;\n };\n}\n\nexport type MailboxServerOperationName = keyof MailboxServerOperations;\n\nexport type MailboxProjectServerClientMessage =\n | {\n type: 'request';\n id: number;\n op: MailboxServerOperationName;\n args: unknown;\n }\n | { type: 'heartbeat' }\n | { type: 'shutdown'; id: number; reason?: string | undefined };\n\nconst MAILBOX_SERVER_OPERATION_NAMES: Readonly<Record<MailboxServerOperationName, true>> = {\n ping: true,\n send: true,\n sendRuntimeControl: true,\n query: true,\n ack: true,\n ackMany: true,\n unreadCount: true,\n softDelete: true,\n restore: true,\n registerAgent: true,\n deregisterAgent: true,\n heartbeat: true,\n getAgentStatuses: true,\n getOnlineAgents: true,\n purgeAgents: true,\n registerClient: true,\n deregisterClient: true,\n clientHeartbeat: true,\n getClientStatuses: true,\n purgeClients: true,\n clearAll: true,\n purgeStale: true,\n autoCompact: true,\n credentialIssue: true,\n credentialVerify: true,\n credentialRevoke: true,\n credentialRotate: true,\n credentialGet: true,\n credentialList: true,\n credentialStatusCounts: true,\n};\n\nfunction isRequestId(value: unknown): value is number {\n return Number.isSafeInteger(value) && (value as number) >= 0;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction hasString(record: Record<string, unknown>, key: string): boolean {\n return typeof record[key] === 'string' && (record[key] as string).length > 0;\n}\n\nfunction hasRecord(record: Record<string, unknown>, key: string): boolean {\n return isRecord(record[key]);\n}\n\nfunction isMailboxServerOperationArgs(\n op: MailboxServerOperationName,\n value: unknown,\n): boolean {\n if (!isRecord(value)) return false;\n switch (op) {\n case 'ping':\n case 'getAgentStatuses':\n case 'getOnlineAgents':\n case 'getClientStatuses':\n case 'purgeClients':\n case 'clearAll':\n case 'credentialList':\n case 'credentialStatusCounts':\n return true;\n case 'send':\n case 'sendRuntimeControl':\n case 'ack':\n case 'ackMany':\n case 'registerAgent':\n case 'heartbeat':\n case 'registerClient':\n case 'clientHeartbeat':\n return hasRecord(value, 'input');\n case 'query':\n return hasRecord(value, 'query');\n case 'unreadCount':\n return hasString(value, 'forAgentId');\n case 'softDelete':\n return hasString(value, 'mailId') && hasString(value, 'by');\n case 'restore':\n return hasString(value, 'mailId');\n case 'deregisterAgent':\n return hasString(value, 'agentId');\n case 'purgeAgents':\n case 'purgeStale':\n case 'autoCompact':\n return true;\n case 'deregisterClient':\n return hasString(value, 'clientId');\n case 'credentialIssue':\n return hasRecord(value, 'options');\n case 'credentialVerify':\n return hasString(value, 'credentialId') && hasString(value, 'secret');\n case 'credentialRevoke':\n case 'credentialRotate':\n case 'credentialGet':\n return hasString(value, 'credentialId');\n }\n}\n\n/** Runtime boundary guard for untrusted newline-delimited IPC frames. */\nexport function isMailboxProjectServerClientMessage(\n value: unknown,\n): value is MailboxProjectServerClientMessage {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const message = value as Record<string, unknown>;\n if (message['type'] === 'heartbeat') return true;\n if (message['type'] === 'shutdown') {\n return (\n isRequestId(message['id']) &&\n (message['reason'] === undefined || typeof message['reason'] === 'string')\n );\n }\n if (message['type'] !== 'request' || !isRequestId(message['id'])) return false;\n const op = message['op'];\n return (\n typeof op === 'string' &&\n Object.hasOwn(MAILBOX_SERVER_OPERATION_NAMES, op) &&\n isMailboxServerOperationArgs(op as MailboxServerOperationName, message['args'])\n );\n}\n\nexport type MailboxProjectServerMessage =\n | ({ type: 'hello' } & MailboxProjectServerInfo)\n | { type: 'mailbox-event'; event: MailboxEvent }\n | { type: 'event'; event: string; payload: unknown }\n | { type: 'response'; id: number; ok: true; result: unknown }\n | {\n type: 'response';\n id: number;\n ok: false;\n error: string;\n errorName?: string | undefined;\n };\n\n/** Runtime guard for server frames before the client touches discriminants. */\nexport function isMailboxProjectServerMessage(\n value: unknown,\n): value is MailboxProjectServerMessage {\n if (!isRecord(value) || typeof value['type'] !== 'string') return false;\n if (value['type'] === 'hello') {\n return (\n Number.isInteger(value['protocolVersion']) &&\n Number.isInteger(value['pid']) &&\n hasString(value, 'projectDir') &&\n hasString(value, 'endpoint') &&\n hasString(value, 'startedAt')\n );\n }\n if (value['type'] === 'event') return hasString(value, 'event');\n if (value['type'] === 'mailbox-event') return isRecord(value['event']);\n if (value['type'] !== 'response' || !isRequestId(value['id'])) return false;\n if (value['ok'] === true) return Object.hasOwn(value, 'result');\n return value['ok'] === false && typeof value['error'] === 'string';\n}\n\nexport function encodeMailboxProjectServerMessage(message: object): string {\n return `${JSON.stringify(message)}\\n`;\n}\n", "export type MailboxMessageType =\n | 'note'\n | 'ask'\n | 'assign'\n | 'steer'\n | 'btw'\n | 'broadcast'\n | 'status'\n | 'result'\n | 'review'\n | 'control';\n\n/**\n * Semantic category a mail type belongs to - determines its handling\n * priority, delivery guarantees, and interaction with the agent loop.\n */\nexport type MailboxTypeCategory =\n /** Requires a substantive response from the recipient. */\n | 'actionable'\n /** Consumed for context; no action required. */\n | 'informational'\n /** Multi-recipient envelope - routing metadata only. */\n | 'routing'\n /** Out-of-band signal handled by the runtime, not the agent. */\n | 'control_signal';\n\n/**\n * Explicit per-type properties used for programmatic dispatch decisions.\n * This is the single source of truth - every type in the union appears\n * here, so adding a new type requires a corresponding entry.\n */\nexport const MAILBOX_TYPE_PROPERTIES: Record<MailboxMessageType, {\n category: MailboxTypeCategory;\n /** Is the sender expected to get a substantive response? */\n expectsReply: boolean;\n /**\n * Should this message type trigger the \"Action required\" acknowledgement\n * footer in the rendered mailbox block?\n *\n * This is SEPARATE from `expectsReply`:\n * - `review` expects no reply but still requires inspection -> `requiresAction: true`\n * - `ask` requires both a reply AND action -> `requiresAction: true, expectsReply: true`\n * - `result` provides evidence but expects nothing back -> both false\n */\n requiresAction: boolean;\n /** Should this type be injected inline in background delivery mode? */\n backgroundEligible: boolean;\n /** Should this type be excluded from the folded conversation block? */\n outOfBand: boolean;\n /** Render priority (lower = rendered first). */\n renderPriority: number;\n /** Human-readable description of the recipient's obligation. */\n recipientObligation: string;\n /** Human-readable description of when a sender should use this type. */\n senderGuidance: string;\n}> = {\n note: {\n category: 'informational',\n expectsReply: false,\n requiresAction: false,\n backgroundEligible: false,\n outOfBand: false,\n renderPriority: 20,\n recipientObligation: 'Read for context; no reply needed.',\n senderGuidance: 'General-purpose FYI. Use when no more specific type applies.',\n },\n ask: {\n category: 'actionable',\n expectsReply: true,\n requiresAction: true,\n backgroundEligible: true,\n outOfBand: false,\n renderPriority: 10,\n recipientObligation: 'Answer as soon as possible \u2014 the sender is waiting.',\n senderGuidance: 'Blocking question. Only use when you need an answer to proceed.',\n },\n assign: {\n category: 'actionable',\n expectsReply: false,\n requiresAction: true,\n backgroundEligible: true,\n outOfBand: false,\n renderPriority: 10,\n recipientObligation: 'Accept or decline; act on it when current operation allows.',\n senderGuidance: 'Task delegation. Must be directed to a specific recipient (not \"*\").',\n },\n steer: {\n category: 'actionable',\n expectsReply: false,\n requiresAction: true,\n backgroundEligible: true,\n outOfBand: false,\n renderPriority: 0, // Always rendered first\n recipientObligation: 'Pause current approach, adjust per instruction, then resume.',\n senderGuidance: 'Mid-task direction change. The recipient is already working on something.',\n },\n btw: {\n category: 'informational',\n expectsReply: false,\n requiresAction: false,\n backgroundEligible: false,\n outOfBand: false,\n renderPriority: 30,\n recipientObligation: 'Absorb the information and stay on current task; no reply needed.',\n senderGuidance: 'Low-priority aside. Non-urgent info that can wait.',\n },\n broadcast: {\n category: 'routing',\n expectsReply: false,\n requiresAction: false,\n backgroundEligible: false,\n outOfBand: false,\n renderPriority: 20,\n recipientObligation: 'Read if addressed to you (direct recipient, alias, or \"*\").',\n senderGuidance: 'Multi-recipient envelope. Auto-selected when to is \"*\" or \"@session\".',\n },\n status: {\n category: 'informational',\n expectsReply: false,\n requiresAction: false,\n backgroundEligible: false,\n outOfBand: false,\n renderPriority: 40,\n recipientObligation: 'Use to avoid redundant work; never act on as a task or question.',\n senderGuidance: 'Agent/system status update. Machine-generated, not for human-originated messages.',\n },\n result: {\n category: 'informational',\n expectsReply: false,\n requiresAction: false,\n backgroundEligible: true,\n outOfBand: false,\n renderPriority: 10,\n recipientObligation: 'Factor into next decision; treat as evidence, not a new task.',\n senderGuidance: 'Task completion notice. Share the outcome of finished work.',\n },\n review: {\n category: 'actionable',\n expectsReply: false,\n requiresAction: true,\n backgroundEligible: true,\n outOfBand: false,\n renderPriority: 10,\n recipientObligation: 'Inspect when convenient; no immediate reply required.',\n senderGuidance: 'Passive review request (code/doc/PR). No reply required.',\n },\n control: {\n category: 'control_signal',\n expectsReply: false,\n requiresAction: false,\n backgroundEligible: false,\n outOfBand: true,\n renderPriority: 999, // Never rendered\n recipientObligation: 'Handled by the agent loop, NOT folded into conversation. \"interrupt\" causes cooperative halt.',\n senderGuidance: 'RESERVED for runtime use. Agents must NOT send control messages.',\n },\n};\n", "/**\n * Mailbox \u2014 persistent inter-agent messaging system with cross-session support.\n *\n * Agents can leave notes for specific agents or broadcast to all. Each agent\n * periodically checks the mailbox or retrieves messages via tool calls.\n *\n * ## Cross-session communication\n *\n * The mailbox is stored at **project level** (`~/.wrongstack/projects/<slug>/_mailbox.sqlite`, owned by one detached\n * project server and reached over IPC),\n * so agents in different terminal sessions / WebUI tabs working on the same\n * canonical project can communicate live, even when they run in different\n * processes, clients, branches, or linked Git worktrees.\n *\n * ## Agent registration\n *\n * Every agent that uses the mailbox registers itself with a heartbeat.\n * Other agents can discover online agents via `getOnlineAgents()`.\n * Stale agents (no heartbeat > 60s) are pruned automatically.\n *\n * ## Read receipts\n *\n * Each message tracks per-recipient read status via a `readBy` map:\n * `{ \"agentId\": \"ISO8601\" }`. When agent X reads a message, its entry\n * is added. The WebUI shows who read what and when.\n *\n * @module mailbox-types\n */\n\nimport {\n MAILBOX_TYPE_PROPERTIES,\n type MailboxMessageType,\n} from './mailbox-type-properties.js';\nexport {\n MAILBOX_TYPE_PROPERTIES,\n type MailboxMessageType,\n type MailboxTypeCategory,\n} from './mailbox-type-properties.js';\n\n// \u2500\u2500 Message type discriminator \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * The ten mail types each carry a distinct **semantic category**, a **sender\n * contract** (when the sender must use it), and a **recipient contract** (how\n * the runtime dispatches it and what the recipient agent must do).\n *\n * \u2500\u2500\u2500\u2500\u2500 Type semantics \u2014 decision matrix for senders \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * ## Categories\n *\n * | Category | Types | Purpose |\n * |--------------|---------------------------------------|--------------------------------|\n * | Actionable | `ask`, `assign`, `steer`, `review` | Require a substantive response |\n * | Informational| `note`, `btw`, `result`, `status` | Consume for context, no action |\n * | Routing | `broadcast` | Multi-recipient envelope |\n * | Control | `control` | Out-of-band signal (no render) |\n *\n * ## Per-type contract\n *\n * ### Actionable types\n *\n * | Type | When to send | Recipient must |\n * |----------|-----------------------------------------------------|----------------------------------------------------|\n * | `ask` | Blocking question \u2014 you need an answer to proceed | Answer as soon as possible; the sender is waiting. |\n * | `assign` | Delegating a task | Accept or decline; act on it when current op allows. |\n * | `steer` | Mid-task direction change \u2014 the recipient is | Pause current approach, adjust per instruction, |\n * | | already working on something and you need them | then resume. Rendered first in the mailbox block. |\n * | | to change course NOW | |\n * | `review` | Requesting a code/doc/PR review (passive) | Inspect when convenient; no immediate reply needed.|\n *\n * ### Informational types\n *\n * | Type | When to send | Recipient must |\n * |----------|-----------------------------------------------------|----------------------------------------------------|\n * | `note` | General-purpose FYI \u2014 a message that isn't any | Read for context; no reply needed. The untyped |\n * | | of the more specific types | default for directed messages. |\n * | `btw` | Low-priority aside \u2014 \"by the way\" | Absorb the information and stay on current task; |\n * | | | no reply needed. Injected via BTW block (separate |\n * | | | from the main mailbox fold) to minimise disruption.|\n * | `result` | Subagent/task completion notice \u2014 share the | Factor into next decision; treat as evidence, not |\n * | | outcome of finished work | a new task. |\n * | `status` | Agent or system status update (heartbeat, spawn, | Use to avoid redundant work; never act on it as |\n * | | task progress, error). Machine-generated. | a task or question. |\n * | `broadcast` | Multi-recipient envelope \u2014 the same message for | Read if addressed to you (direct, alias, session, |\n * | | every agent on the project. Auto-selected when | or `*`). The `*` recipient means \"everyone\". |\n * | | `to` is `\"*\"` or `\"@session\"` in `mail_send`. | |\n *\n * ### Control type\n *\n * | Type | When to send | Recipient must |\n * |----------|-----------------------------------------------------|----------------------------------------------------|\n * | `control`| Out-of-band signal (interrupt, halt, redirect). | NEVER folded into conversation content. The agent |\n * | | Machine-generated by the runtime, not by agents. | loop intercepts it separately. `control:interrupt` |\n * | | | causes a cooperative halt at the next iteration |\n * | | | boundary. |\n *\n * \u2500\u2500\u2500\u2500\u2500 Dispatch behavior (runtime contract) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * The mailbox system enforces these dispatch rules:\n *\n * 1. **Send-side**: `mail_send` auto-defaults the type: `broadcast` when\n * `to` is `\"*\"` or `\"@session::...\"`, otherwise `note`.\n * 2. **Send-side validation**: `assign` always requires a specific `to`\n * (not `\"*\"`). `control` is reserved for runtime use \u2014 agents passing it\n * via the tool surface will be rejected.\n * 3. **Render-order guarantee**: `steer` messages are ALWAYS rendered first\n * in `buildMailboxBlock()`, before any other type, to ensure mid-task\n * direction changes are seen before other action items.\n * 4. **Control isolation**: `control`-type messages are filtered by\n * `injectPendingMailboxMessages()` and NEVER enter the folded\n * conversation block \u2014 they are out-of-band signals only.\n * 5. **Background routing**: in `background` delivery mode, only\n * `ACTIONABLE_BACKGROUND_TYPES` (`steer`, `ask`, `assign`, `result`,\n * `review`) are escalated; `note`, `btw`, `status`, and `broadcast`\n * are suppressed to minimise disruption during tool work.\n * 6. **Awareness polling**: `btw` messages intercepted by background\n * polling are queued via `setBtwNote()` for injection at a safe loop\n * boundary, not folded inline.\n * 7. **Agent registry**: `getAgentStatuses()` reads the dedicated agent\n * registry (`_mailbox.registry.json`), not mailbox message content. The\n * registry is populated by agent heartbeat calls (not by `status`-type\n * messages). `Mailbox.getAgentStatuses()` derives\n * a registry snapshot from `status`-type messages as a fallback when no\n * shared registry file exists.\n * 8. **Request-scoped context**: delivered raw mailbox blocks are removed\n * after one successful provider evaluation. Durable assistant/tool/task\n * consequences remain; routine mail does not occupy later requests.\n *\n * When a type is missing from any dispatch table, the fallback is:\n * - Render with `\uD83D\uDCE8 <TYPE>` label (generic emoji prefix)\n * - Route inline (not background)\n * - No special instruction added\n */\n\n/**\n * Which class of agent may consume a mailbox message.\n *\n * `leaders` is a delivery boundary, not merely a UI hint: agent-loop and\n * inbox readers must exclude these messages for subagents. The optional\n * persisted field keeps older JSONL records backwards-compatible (`all`).\n */\nexport type MailboxAudience = 'all' | 'leaders';\n\n/** Return the stable base portion of a session-qualified mailbox identity. */\nexport function mailboxIdentityBase(agentId: string): string {\n return agentId.split(/[@#]/, 1)[0]!.trim().toLowerCase();\n}\n\n/** Whether a mailbox identity belongs to the session's main/leader agent. */\nexport function isMailboxLeader(agentId: string, role?: string): boolean {\n return mailboxIdentityBase(agentId) === 'leader' || role?.trim().toLowerCase() === 'leader';\n}\n\n/** Whether a message may be consumed by the supplied agent identity. */\nexport function isMailboxMessageVisibleTo(\n message: Pick<MailboxMessage, 'audience'>,\n agentId: string,\n role?: string,\n): boolean {\n return message.audience !== 'leaders' || isMailboxLeader(agentId, role);\n}\n\n/** Category + expectsReply are provided by MAILBOX_TYPE_PROPERTIES directly. */\n\n/**\n * Validate that a given (type, to) pair is internally consistent.\n * Throws when the combination breaks a fundamental rule.\n */\nexport function validateSendType(type: MailboxMessageType, to: string): void {\n if (type === 'control') {\n throw new TypeError(\n 'Type \"control\" is reserved for runtime use and cannot be set by agents',\n );\n }\n const isMultiRecipient = to === '*' || to.startsWith('@session:');\n if (type === 'assign' && isMultiRecipient) {\n throw new TypeError(\n `Type \"assign\" requires a specific recipient \u2014 multi-recipient target \"${to}\" is ambiguous`,\n );\n }\n if (type === 'steer' && isMultiRecipient) {\n throw new TypeError(\n `Type \"steer\" requires a specific recipient \u2014 multi-recipient target \"${to}\" is ambiguous`,\n );\n }\n}\n\n// \u2500\u2500 Read receipt \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Per-recipient read status. `readBy` maps agentId \u2192 ISO8601 timestamp of\n * when that agent first read the message. An empty map means unread by all.\n */\nexport interface ReadReceipts {\n [agentId: string]: string; // ISO8601 timestamp\n}\n\n// \u2500\u2500 Core message \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface MailboxMessage {\n /** Unique message id (UUID). */\n id: string;\n /** Sender agent id. */\n from: string;\n /** Recipient agent id, or '*' for broadcast. */\n to: string;\n /** Message category. */\n type: MailboxMessageType;\n /** Delivery audience. Omitted legacy values mean `all`. */\n audience?: MailboxAudience | undefined;\n /** Short subject line \u2014 one sentence. */\n subject: string;\n /** Full message content. */\n body: string;\n /** Priority \u2014 high priority messages surface first. */\n priority: 'low' | 'normal' | 'high';\n /**\n * Per-recipient read receipts. agentId \u2192 ISO8601 when they first read it.\n * Replaces the old single `read: boolean` + `readAt` fields.\n */\n readBy: ReadReceipts;\n /** Has any recipient acted on / completed this? */\n completed: boolean;\n /** Who completed it (agentId). */\n completedBy?: string | undefined;\n /** Optional summary of what happened after handling. */\n outcome?: string | undefined;\n /** ISO8601 \u2014 when the message was sent. */\n timestamp: string;\n /** ISO8601 \u2014 when the message was marked complete. */\n completedAt?: string | undefined;\n /**\n * ISO8601 \u2014 when the message was soft-deleted. When present, the\n * default `Mailbox.query()` filter excludes the message from the\n * normal inbox view; {@link Mailbox.restore} clears the\n * field to undo the delete. Hard deletes (removing the line from\n * the JSONL) are reserved for the CLI and never happen via the\n * server route handlers.\n */\n deletedAt?: string | undefined;\n /** When the soft-delete happened, the agentId that issued it. */\n deletedBy?: string | undefined;\n /** If this is a reply, the id of the parent message. */\n replyTo?: string | undefined;\n /** For assign-type messages \u2014 task context for agent discovery. */\n taskContext?: MailboxTaskContext | undefined;\n /** Session id of the sender. Enables cross-session communication. */\n senderSessionId?: string | undefined;\n /**\n * ISO8601 \u2014 when the message expires. Set at send time from `ttlMs`\n * (default: 24h via AUTO_COMPACT_DEFAULT_TTL_MS). The auto-compaction\n * sweep removes messages whose `expiresAt` is in the past. When\n * undefined, the compaction sweep uses the default TTL from the\n * caller's options.\n */\n expiresAt?: string | undefined;\n}\n\n// \u2500\u2500 Task context for agent discovery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface MailboxTaskContext {\n /** The role that should handle this task (e.g. \"tech-stack\", \"audit-log\"). */\n agentRole?: string | undefined;\n /** Human-readable agent name (e.g. \"Tesla (Executor)\"). */\n agentName?: string | undefined;\n /** Task id if already assigned via coordinator. */\n taskId?: string | undefined;\n /** Current task status. */\n status?: 'pending' | 'in_progress' | 'completed' | 'failed' | undefined;\n}\n\n// \u2500\u2500 Agent registration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface RegisteredAgent {\n /** Unique agent id. */\n agentId: string;\n /** Session id this agent belongs to. */\n sessionId: string;\n /** Human-readable name. */\n name: string;\n /** Role (e.g. \"leader\", \"tech-stack\", \"bug-hunter\"). */\n role?: string | undefined;\n /** Current status. */\n status: 'idle' | 'running' | 'streaming' | 'waiting_user' | 'error';\n /** Current tool being executed, if any. */\n currentTool?: string | undefined;\n /** Current task description. */\n currentTask?: string | undefined;\n /** Iteration count so far. */\n iterations: number;\n /** Tool calls so far. */\n toolCalls: number;\n /** ISO8601 \u2014 registered at. */\n registeredAt: string;\n /** ISO8601 \u2014 last heartbeat (updated on every mailbox op). */\n lastSeenAt: string;\n /** Which process registered this agent (PID). */\n pid: number;\n /** Where the agent is running (e.g. \"cli\", \"webui\"). */\n source?: 'cli' | 'webui' | 'mcp' | 'acp' | 'http' | undefined;\n}\n\n// \u2500\u2500 Agent status entry (for discovery) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface MailboxAgentStatus {\n /** Agent id. */\n agentId: string;\n /** Human-readable name. */\n name: string;\n /** Role. */\n role?: string | undefined;\n /** Session id. */\n sessionId: string;\n /** Current status. */\n status: 'idle' | 'running' | 'streaming' | 'waiting_user' | 'error' | 'offline';\n /** Current tool being executed, if any. */\n currentTool?: string | undefined;\n /** Current task description. */\n currentTask?: string | undefined;\n /** Iteration count so far. */\n iterations: number;\n /** Tool calls so far. */\n toolCalls: number;\n /** ISO8601 \u2014 last activity timestamp. */\n lastActivityAt: string;\n /** ISO8601 \u2014 last heartbeat. */\n lastSeenAt: string;\n /** Whether this agent is currently online (heartbeat within threshold). */\n online: boolean;\n /** Which process. */\n pid: number;\n /** Source. */\n source?: 'cli' | 'webui' | 'mcp' | 'acp' | 'http' | undefined;\n}\n\n// \u2500\u2500 Mailbox query \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface MailboxQuery {\n /** Filter by recipient agent id. */\n to?: string | undefined;\n /** Filter by sender agent id. */\n from?: string | undefined;\n /** Only messages unread by this agent. */\n unreadBy?: string | undefined;\n /** Trusted caller role used with `unreadBy` for audience filtering. */\n readerRole?: string | undefined;\n /** Only incomplete messages. */\n incompleteOnly?: boolean | undefined;\n /**\n * Internal trusted-read option: retain folded per-actor receipt state so a\n * boundary can derive an actor-safe projection. Untrusted query codecs must\n * never accept this field from request payloads.\n */\n includeReceiptState?: boolean | undefined;\n /** Filter by message type. */\n type?: MailboxMessageType | undefined;\n /** Filter by priority (>= this level). */\n minPriority?: 'low' | 'normal' | 'high' | undefined;\n /** Maximum number of messages to return. */\n limit?: number | undefined;\n /** ISO8601 \u2014 only messages after this timestamp. */\n since?: string | undefined;\n /** Filter by the sender's session id (`MailboxMessage.senderSessionId`). */\n sessionId?: string | undefined;\n /**\n * Include soft-deleted messages (where `deletedAt` is set). When\n * `false` (the default), soft-deleted messages are filtered out so\n * the normal inbox view stays clean. The \"trash\" view passes\n * `true` to surface them.\n */\n includeDeleted?: boolean | undefined;\n /**\n * Filter by replyTo parent message id (UUID). When set, only messages\n * whose `replyTo` exactly matches this value are returned. An empty\n * string matches nothing \u2014 empty strings are technically allowed by\n * `send()` (it passes through `MailboxSendInput.replyTo` directly with\n * no normalization), but are never produced by chimera/execution callers.\n * The query filter is exact-match.\n * Useful for polling the response to a specific `ask` message.\n */\n replyTo?: string | undefined;\n}\n\n// \u2500\u2500 Mailbox operations \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Canonical prefix for mail addressed to every agent in one session. */\nexport const SESSION_RECIPIENT_PREFIX = '@session:';\n\n/** Build the canonical recipient address for a session-scoped broadcast. */\nexport function sessionRecipient(sessionId: string): string {\n const normalizedSessionId = sessionId.trim();\n if (!normalizedSessionId) {\n throw new TypeError('sessionId is required for the \"@session\" recipient');\n }\n return `${SESSION_RECIPIENT_PREFIX}${normalizedSessionId}`;\n}\n\n/**\n * Normalize a recipient address.\n *\n * - `\"all\"` (any casing) is canonicalized to `'*'`.\n * - `\"@session\"` (any casing) is canonicalized to\n * `\"@session:<sessionId>\"`; callers must provide the sender's session id.\n * - Already-canonical `\"@session:<sessionId>\"` addresses are preserved.\n */\nexport function normalizeRecipient(to: string, sessionId?: string): string {\n const trimmed = to.trim();\n const normalized = trimmed.toLowerCase();\n if (normalized === 'all') return '*';\n if (normalized === '@session') return sessionRecipient(sessionId ?? '');\n return trimmed;\n}\n\nexport interface MailboxSendInput {\n /** Sender agent id. */\n from: string;\n /** Recipient agent id, '*' / \"all\" for project broadcast, or \"@session\" for the sender's session. */\n to: string;\n /** Message category. */\n type: MailboxMessageType;\n /** Restrict consumption to main/leader agents. Default: `all`. */\n audience?: MailboxAudience | undefined;\n /** Short subject line. */\n subject: string;\n /** Full message content. */\n body: string;\n /** Priority. Default: 'normal'. */\n priority?: 'low' | 'normal' | 'high' | undefined;\n /** If replying, the id of the parent message. */\n replyTo?: string | undefined;\n /** Task context for assign-type messages. */\n taskContext?: MailboxTaskContext | undefined;\n /** Sender session id. Required when `to` is the `\"@session\"` alias. */\n senderSessionId?: string | undefined;\n /**\n * Time-to-live in milliseconds. When set, the message's `expiresAt` is\n * computed as `now + ttlMs` at send time. The auto-compaction sweep\n * removes expired messages. Default: none (use compaction sweep default).\n */\n ttlMs?: number | undefined;\n}\n\n/**\n * Append-only ack record stored in the JSONL alongside messages.\n *\n * Instead of rewriting the entire mailbox file to mark a message as read or\n * completed, we append a small ack record. At read time, ack records are\n * folded into their target messages. The `__ack` discriminator distinguishes\n * ack records from regular messages.\n *\n * Compaction (autoCompact / purgeStale) folds these into the messages and\n * removes the ack lines from the file, keeping the file bounded.\n */\nexport interface AckRecord {\n /** Discriminator \u2014 always `true` to distinguish from MailboxMessage. */\n __ack: true;\n /** The message this ack applies to. */\n messageId: string;\n /** Agent acknowledging the message. */\n readerId: string;\n /** ISO8601 timestamp of the ack. */\n timestamp: string;\n /** Was the message read? */\n read: boolean;\n /** Was the message marked completed? */\n completed?: boolean | undefined;\n /** Who completed it (when completed === true). */\n completedBy?: string | undefined;\n /** Optional outcome summary. */\n outcome?: string | undefined;\n /**\n * Soft-delete or restore the target message.\n * - `true`: set `deletedAt`/`deletedBy` on the message\n * - `false`: clear `deletedAt`/`deletedBy` on the message\n * - `undefined`: not a delete/restore operation (backward-compat default)\n *\n * When `deleted` is `true`, `deletedBy` records who performed the delete.\n */\n deleted?: boolean | undefined;\n /** Who deleted the message (set when `deleted === true`). */\n deletedBy?: string | undefined;\n}\n\nexport interface MailboxAckInput {\n /** Message id to acknowledge. */\n messageId: string;\n /** Agent id of who is reading/acking. */\n readerId: string;\n /** Mark as read by this agent? Defaults to true if not specified. */\n read?: boolean | undefined;\n /** Mark as completed? */\n completed?: boolean | undefined;\n /** Optional outcome summary. */\n outcome?: string | undefined;\n}\n\n/**\n * Batch acknowledgment input \u2014 applies a batch of acks under a single file\n * lock + single file rewrite. Each entry has the same shape as\n * {@link MailboxAckInput} minus the per-batch defaults documented on\n * `ackMany`. Use this when an agent is acking several fresh messages at\n * once (the common case in the mailbox loop) \u2014 it collapses N full-file\n * rewrites into one.\n */\nexport interface MailboxAckBatchInput {\n /** Ack entries to apply. */\n acks: MailboxAckInput[];\n}\n\n// \u2500\u2500 Agent registration input \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface AgentRegistrationInput {\n agentId: string;\n sessionId: string;\n name: string;\n role?: string | undefined;\n pid?: number | undefined;\n source?: 'cli' | 'webui' | 'mcp' | 'acp' | 'http' | undefined;\n}\n\n// \u2500\u2500 Client (REPL/TUI/WebUI) registration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type ClientSource = 'repl' | 'tui' | 'webui' | 'http';\n\nexport interface RegisteredClient {\n /** Unique client id. */\n clientId: string;\n /** Session/project context id. */\n sessionId: string;\n /** Human-readable name (e.g. \"TUI [main]\", \"WebUI [chrome]\"). */\n name: string;\n /** Client type. */\n source: ClientSource;\n /** ISO8601 \u2014 registered at. */\n registeredAt: string;\n /** ISO8601 \u2014 last heartbeat. */\n lastSeenAt: string;\n /** Which process. */\n pid: number;\n}\n\nexport interface ClientStatus {\n /** Client id. */\n clientId: string;\n /** Human-readable name. */\n name: string;\n /** Client type. */\n source: ClientSource;\n /** Session id. */\n sessionId: string;\n /** ISO8601 \u2014 last activity timestamp. */\n lastSeenAt: string;\n /** Whether this client is currently online (heartbeat within threshold). */\n online: boolean;\n /** Which process. */\n pid: number;\n}\n\nexport interface ClientRegistrationInput {\n clientId: string;\n sessionId: string;\n name: string;\n source: ClientSource;\n pid?: number | undefined;\n}\n\nexport interface ClientHeartbeatInput {\n clientId: string;\n /** Active session id for this client. When present, updates the registry entry. */\n sessionId?: string | undefined;\n}\n\n// \u2500\u2500 Agent heartbeat input \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface AgentHeartbeatInput {\n agentId: string;\n status?: RegisteredAgent['status'] | undefined;\n currentTool?: string | undefined;\n currentTask?: string | undefined;\n iterations?: number | undefined;\n toolCalls?: number | undefined;\n}\n\n// \u2500\u2500 Purge options & result \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface PurgeOptions {\n /**\n * Purge completed messages older than this many milliseconds.\n * Default: 1 day (86_400_000 ms)\n */\n completedMaxAgeMs?: number | undefined;\n /**\n * Purge incomplete messages older than this many milliseconds.\n * Default: 7 days (604_800_000 ms)\n */\n incompleteMaxAgeMs?: number | undefined;\n}\n\nexport interface PurgeResult {\n /** Messages removed because they were completed and too old. */\n completedPurged: number;\n /** Messages removed because they were incomplete and too old. */\n incompletePurged: number;\n /** Total messages removed. */\n totalPurged: number;\n /** Messages remaining in the mailbox after purge. */\n remaining: number;\n}\n\n// \u2500\u2500 Auto-compact options & result \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface AutoCompactOptions {\n /**\n * Remove messages read by ALL currently-online agents that are older\n * than this many milliseconds since the last read receipt was stamped.\n * Default: 10 minutes (AUTO_COMPACT_READ_MAX_AGE_MS).\n */\n readMaxAgeMs?: number | undefined;\n /**\n * Default TTL for messages without an explicit `expiresAt`. Messages\n * whose `timestamp` is older than `now - defaultTtlMs` are removed.\n * Default: 24 hours (AUTO_COMPACT_DEFAULT_TTL_MS).\n */\n defaultTtlMs?: number | undefined;\n /**\n * Per-message-type TTL overrides, consulted before `defaultTtlMs` for\n * messages with no explicit `expiresAt`. Keyed by `MailboxMessageType`.\n * Default: {@link AUTO_COMPACT_TYPE_TTL_MS} (transient `status` chatter\n * expires in 30 minutes instead of 24 hours).\n */\n typeTtlMs?: Readonly<Record<string, number>> | undefined;\n /**\n * Also run `purgeStale` logic in the same pass \u2014 purge completed\n * messages older than this many ms. Default: 1 day.\n */\n completedMaxAgeMs?: number | undefined;\n /**\n * Also run `purgeStale` logic in the same pass \u2014 purge incomplete\n * messages older than this many ms. Default: 7 days.\n */\n incompleteMaxAgeMs?: number | undefined;\n /**\n * Interval for the background auto-compact timer.\n * Default: 5 minutes (AUTO_COMPACT_INTERVAL_MS).\n */\n intervalMs?: number | undefined;\n /**\n * Also run `purgeStale` logic in the same pass (completed > 1 day,\n * incomplete > 7 days). Default: true.\n */\n includePurgeStale?: boolean | undefined;\n}\n\nexport interface AutoCompactResult {\n /** Messages removed because they were read by all online agents. */\n readByAllRemoved: number;\n /** Messages removed because their TTL expired (explicit or default). */\n expiredRemoved: number;\n /** Messages removed by the purgeStale pass (if enabled). */\n stalePurged: number;\n /** Total messages removed. */\n totalRemoved: number;\n /** Messages remaining in the mailbox after compaction. */\n remaining: number;\n}\n\n// \u2500\u2500 Mailbox interface \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface Mailbox {\n /** Send a message. Returns the created message. */\n send(input: MailboxSendInput): Promise<MailboxMessage>;\n\n /** Query messages matching criteria. */\n query(query: MailboxQuery): Promise<MailboxMessage[]>;\n\n /** Acknowledge a message (read/complete). Returns updated message. */\n ack(input: MailboxAckInput): Promise<MailboxMessage | null>;\n\n /**\n * Acknowledge many messages in one shot. Acquires the file lock once and\n * rewrites the message file once, regardless of how many acks are in the\n * batch. Returns the messages that were actually updated (messages whose\n * ids are not in the file are skipped silently).\n *\n * This is the preferred path when an agent has multiple fresh messages\n * to receipt at once \u2014 the per-message {@link ack} path does a full\n * read-modify-rewrite of the mailbox file for every call.\n */\n ackMany(input: MailboxAckBatchInput): Promise<MailboxMessage[]>;\n\n /**\n * Soft-delete a message. Sets `deletedAt` to the current timestamp\n * and records the acting agent in `deletedBy`. Reversible via\n * {@link restore}. The default `query()` filter hides the message\n * once `deletedAt` is set; pass `includeDeleted: true` to see the\n * trash.\n */\n softDelete(mailId: string, by: string): Promise<MailboxMessage | null>;\n\n /**\n * Undo a {@link softDelete}. Clears `deletedAt` and `deletedBy` on\n * the message. No-op (returns the message as-is) if the message is\n * not soft-deleted.\n */\n restore(mailId: string): Promise<MailboxMessage | null>;\n\n /** Get a snapshot of online/offline agents and their current tasks. */\n getAgentStatuses(): Promise<MailboxAgentStatus[]>;\n\n /**\n * Get only online agents (heartbeat within 60s).\n * Useful for \"who can I talk to right now?\" queries.\n */\n getOnlineAgents(): Promise<MailboxAgentStatus[]>;\n\n /**\n * Register an agent. Called once per agent on first mailbox use.\n * Subsequent calls are idempotent \u2014 they update lastSeenAt.\n */\n registerAgent(input: AgentRegistrationInput): Promise<void>;\n /** Remove an agent from the registry entirely. Called on session shutdown. */\n deregisterAgent(agentId: string): Promise<void>;\n\n /**\n * Update agent heartbeat and optional status fields.\n * Called periodically (every tool call / iteration).\n */\n heartbeat(input: AgentHeartbeatInput): Promise<void>;\n\n /**\n * Count unread messages for a specific agent.\n * Used for \"new mail\" notifications without pulling full message bodies.\n */\n unreadCount(forAgentId: string, sessionId?: string): Promise<number>;\n\n /** Close and flush any pending writes. */\n close(): Promise<void>;\n\n /**\n * Delete all messages from the mailbox file.\n * Agents and read receipts are preserved; only messages are cleared.\n */\n clearAll(): Promise<void>;\n\n /**\n * Purge orphaned and stale messages from the mailbox.\n *\n * Stale messages are:\n * - Completed messages older than `completedMaxAgeMs` (default: 1 day)\n * - Incomplete messages older than `incompleteMaxAgeMs` (default: 7 days)\n *\n * This does NOT touch agent registrations or client registry.\n */\n purgeStale(opts?: PurgeOptions): Promise<PurgeResult>;\n\n /**\n * Auto-compact: remove messages that are no longer needed.\n *\n * Two cleanup passes run in a single file rewrite:\n * 1. **Read-by-all**: Messages read by every currently-online agent,\n * older than `readMaxAgeMs` (default 10 min).\n * 2. **Expired**: Messages whose `expiresAt` is in the past, or whose\n * `timestamp` is older than `defaultTtlMs` (default 24h) when no\n * explicit `expiresAt` is set.\n *\n * Also runs `purgeStale` logic (completed > 1 day, incomplete > 7 days)\n * in the same pass to avoid a second rewrite.\n */\n autoCompact(opts?: AutoCompactOptions): Promise<AutoCompactResult>;\n\n /**\n * Start a background timer that periodically calls `autoCompact`.\n * Returns a dispose function that stops the timer. Idempotent \u2014\n * calling start twice replaces the prior timer.\n */\n startAutoCompactTimer(opts?: AutoCompactOptions): () => void;\n\n // \u2500\u2500 Client (REPL/TUI/WebUI) registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Register a client (REPL/TUI/WebUI). Called once per client on startup.\n * Subsequent calls are idempotent \u2014 they update lastSeenAt.\n */\n registerClient(input: ClientRegistrationInput): Promise<void>;\n\n /**\n * Update client heartbeat. Called periodically (every 15s for clients).\n */\n clientHeartbeat(input: ClientHeartbeatInput): Promise<void>;\n\n /** Remove a client immediately on clean shutdown. */\n deregisterClient(clientId: string): Promise<void>;\n\n /**\n * Get snapshot of online/offline clients and their last activity.\n */\n getClientStatuses(): Promise<ClientStatus[]>;\n\n /**\n * Explicitly purge stale clients from the registry.\n * Removes client entries whose lastSeenAt is older than CLIENT_STALE_MS.\n * Returns the number of entries purged.\n */\n purgeClients(): Promise<number>;\n}\n\nexport {\n expandMailboxCapabilities,\n hasMailboxCapability,\n MAILBOX_CAPABILITY_IMPLICATIONS,\n type MailboxActorContext,\n type MailboxAuthMode,\n type MailboxCapability,\n type MailboxPrincipalKind,\n} from './mailbox-auth-types.js';\n\n// \u2500\u2500 Recipient-scoped receipt state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Per-recipient delivery/action state for a single message.\n *\n * Keyed by actor ID. Each entry tracks when the actor read, completed,\n * or otherwise interacted with the message \u2014 independently of other actors.\n */\nexport interface MailboxRecipientState {\n /** Actor ID this state belongs to. */\n actorId: string;\n /** ISO8601 \u2014 when this actor first read the message. */\n readAt?: string | undefined;\n /** ISO8601 \u2014 when this actor completed the message. */\n completedAt?: string | undefined;\n /** Who recorded the completion (usually same as actorId). */\n completedBy?: string | undefined;\n /** Optional outcome summary recorded by this actor. */\n outcome?: string | undefined;\n}\n\n/**\n * V2 JSONL receipt record. Appended alongside messages and v1 ack records.\n *\n * Has an explicit `__mailboxReceipt: 2` discriminator so:\n * 1. The v2 reader folds these into per-actor `MailboxRecipientState`.\n * 2. A v1 reader ignores the unknown JSON line (no `__ack` field).\n *\n * Fold algebra (applied during materialization):\n * - Keyed by `(messageId, actorId)`.\n * - `read`: first-write-wins (earliest read timestamp is preserved).\n * - `completed`: monotonic upward (once `true`, cannot revert unless an\n * explicit reopen record with `completed: false` is appended).\n * - `outcome`: last-write-wins.\n * - Duplicate records (same messageId, actorId, timestamp): idempotent no-ops.\n */\nexport interface MailboxReceiptRecordV2 {\n /** Discriminator \u2014 always `2` to distinguish from messages and v1 acks. */\n __mailboxReceipt: 2;\n /** Target message this receipt applies to. */\n messageId: string;\n /** Actor this receipt belongs to. */\n actorId: string;\n /** ISO8601 \u2014 when the receipt event occurred. */\n timestamp: string;\n /** Was the message read by this actor? */\n read?: boolean | undefined;\n /** Was the message completed by this actor? */\n completed?: boolean | undefined;\n /** Optional outcome summary. */\n outcome?: string | undefined;\n}\n\n/**\n * Check if a parsed JSONL value is a v2 receipt record.\n * Validates the discriminator AND required structural fields.\n */\nexport function isMailboxReceiptRecordV2(value: unknown): value is MailboxReceiptRecordV2 {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const v = value as Record<string, unknown>;\n if (v['__mailboxReceipt'] !== 2) return false;\n if (typeof v['messageId'] !== 'string' || v['messageId'].length === 0) return false;\n if (typeof v['actorId'] !== 'string' || v['actorId'].length === 0) return false;\n if (typeof v['timestamp'] !== 'string' || v['timestamp'].length === 0) return false;\n // Validate optional fields when present \u2014 prevents malformed JSONL records\n // from entering typed receipt-folding code (e.g. completed:\"false\" truthy string).\n if ('read' in v && typeof v['read'] !== 'boolean') return false;\n if ('completed' in v && typeof v['completed'] !== 'boolean') return false;\n if ('outcome' in v && v['outcome'] !== undefined && typeof v['outcome'] !== 'string') return false;\n return true;\n}\n\n// \u2500\u2500 Message projections \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Materialized message with per-actor recipient state.\n *\n * This is the internal representation after folding all v1 acks and v2\n * receipt records. It carries both the legacy fields (for backward\n * compatibility) and the new actor-specific state map.\n *\n * `legacyGlobalCompletion` is set ONLY for historical v1 fan-out messages\n * that were globally completed. It is never set for new v2 writes.\n */\nexport interface MailboxMessageProjection extends MailboxMessage {\n /** Per-actor delivery/action state, keyed by actorId. */\n recipientState: Readonly<Record<string, MailboxRecipientState>>;\n /**\n * True ONLY for historical v1 fan-out messages that were globally completed\n * (completed before the v2 migration). These remain globally suppressed to\n * prevent upgrade re-delivery. New v2 writes NEVER set this.\n */\n legacyGlobalCompletion?: boolean | undefined;\n}\n\n/**\n * Self-facing message \u2014 what a specific actor sees.\n *\n * This does NOT extend `MailboxMessage` because self-facing responses must NOT\n * contain aggregate receipt metadata (`readBy`, `completedBy`, `completedAt`,\n * `outcome`) that would leak other actors' activity. Only actor-specific\n * derived fields are added on top of the non-sensitive message fields.\n */\nexport interface ActorMailboxMessage\n extends Omit<MailboxMessage, 'readBy' | 'completed' | 'completedBy' | 'completedAt' | 'outcome'> {\n /** Has this actor read the message? */\n readByMe: boolean;\n /** Has this actor completed the message? */\n completedByMe: boolean;\n /** Does this message require action from this actor? */\n actionRequiredForMe: boolean;\n /** This actor's outcome, if any. */\n myOutcome?: string | undefined;\n /**\n * True for historical v1 fan-out messages that were globally completed.\n * Lets the UI distinguish \"completed by me\" from \"completed globally\n * before migration.\"\n */\n legacyGlobalCompletion?: boolean | undefined;\n}\n\n/**\n * Derive `actionRequiredForMe` from the canonical type properties and actor state.\n *\n * Defined as:\n * `MAILBOX_TYPE_PROPERTIES[type].requiresAction && visible && !completedByMe && !deleted && !legacyGlobalCompletion`\n *\n * For historical legacy-global messages, `actionRequiredForMe` is always false\n * because the message is suppressed and should not re-enter any actor's flow.\n */\nexport function isActionRequiredForActor(\n message: Pick<MailboxMessage, 'type' | 'deletedAt' | 'completed'>,\n projection: Pick<ActorMailboxMessage, 'completedByMe' | 'legacyGlobalCompletion'>,\n): boolean {\n if (projection.legacyGlobalCompletion) return false;\n if (message.deletedAt !== undefined) return false;\n if (projection.completedByMe) return false;\n return MAILBOX_TYPE_PROPERTIES[message.type]?.requiresAction === true;\n}\n", "import { randomUUID } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { DatabaseSync } from 'node:sqlite';\n\nimport type { EventBus } from '../kernel/events.js';\nimport {\n AGENT_STALE_MS,\n AUTO_COMPACT_INTERVAL_MS,\n CLIENT_STALE_MS,\n HEARTBEAT_THROTTLE_MS,\n} from './mailbox-constants.js';\nimport type {\n CredentialValidation,\n IssueCredentialOptions,\n MailboxCredential,\n} from './mailbox-credential-store.js';\nimport type { MailboxEventEmitter } from './mailbox-events.js';\nimport { isMessageCompletedForActor } from './global-mailbox-completion.js';\nimport { isFanOutRecipient } from './mailbox-receipt-folding.js';\nimport {\n projectMailboxCompletion,\n} from './mailbox-retention-state.js';\nimport { mapRegisteredAgentsToStatuses, mapRegisteredClientsToStatuses } from './mailbox-status-mappers.js';\nimport type {\n AgentHeartbeatInput,\n AgentRegistrationInput,\n AutoCompactOptions,\n AutoCompactResult,\n ClientHeartbeatInput,\n ClientRegistrationInput,\n ClientStatus,\n Mailbox,\n MailboxAckBatchInput,\n MailboxAckInput,\n MailboxAgentStatus,\n MailboxMessage,\n MailboxMessageProjection,\n MailboxQuery,\n MailboxRecipientState,\n MailboxSendInput,\n PurgeOptions,\n PurgeResult,\n RegisteredAgent,\n RegisteredClient,\n} from './mailbox-types.js';\nimport {\n isMailboxMessageVisibleTo,\n normalizeRecipient,\n sessionRecipient,\n validateSendType,\n} from './mailbox-types.js';\nimport { normalizeMailboxMessageType } from './mailbox-message-codec.js';\nimport {\n autoCompact,\n type CompactionContext,\n purgeStale,\n} from './sqlite-mailbox-compaction.js';\nimport {\n credentialGet,\n credentialIssue,\n credentialList,\n credentialRevoke,\n credentialRotate,\n credentialStatusCounts,\n credentialVerify,\n} from './sqlite-mailbox-credentials.js';\nimport {\n deleteMessages,\n materializeMessageRows,\n type MessageRow,\n type SqliteStatement,\n persistAgent,\n persistClient,\n persistMessage,\n persistReceipt,\n pruneAgents,\n pruneClients,\n readAgents,\n readClients,\n withoutAggregateCompletion,\n} from './sqlite-mailbox-rows.js';\nimport {\n initializeSchema,\n loadDatabaseSync,\n migrateLegacyFiles,\n type SchemaContext,\n} from './sqlite-mailbox-schema.js';\nexport const SQLITE_MAILBOX_FILE = '_mailbox.sqlite';\n/**\n * Server-owned project mailbox persistence.\n *\n * Production callers must reach this store through RemoteMailbox. The detached\n * project server is the only process that opens the database connection.\n */\n/**\n * Bounds for the in-memory heartbeat throttle maps. The sweep only runs once a\n * map is over the entry cap, so the steady state costs nothing.\n */\nconst HEARTBEAT_TRACKING_MAX_ENTRIES = 512;\nconst HEARTBEAT_TRACKING_TTL_MS = 30 * 60_000;\n\nexport class SqliteMailbox implements Mailbox {\n readonly databasePath: string;\n /** Compatibility alias used by project-server health/status consumers. */\n readonly messagePath: string;\n readonly eventEmitter?: MailboxEventEmitter | undefined;\n\n private readonly db: DatabaseSync;\n private readonly events?: EventBus | undefined;\n private readonly lastHeartbeat = new Map<string, number>();\n private readonly lastClientHeartbeat = new Map<string, number>();\n private autoCompactTimer: NodeJS.Timeout | null = null;\n private closed = false;\n\n constructor(\n readonly projectDir: string,\n events?: EventBus,\n eventEmitter?: MailboxEventEmitter,\n ) {\n fs.mkdirSync(projectDir, { recursive: true });\n this.databasePath = path.join(projectDir, SQLITE_MAILBOX_FILE);\n this.messagePath = this.databasePath;\n this.events = events;\n this.eventEmitter = eventEmitter;\n const Database = loadDatabaseSync();\n this.db = new Database(this.databasePath);\n this.db.exec('PRAGMA journal_mode = WAL');\n this.db.exec('PRAGMA synchronous = NORMAL');\n this.db.exec('PRAGMA foreign_keys = ON');\n this.db.exec('PRAGMA busy_timeout = 5000');\n initializeSchema(this.schemaCtx());\n migrateLegacyFiles(this.schemaCtx());\n }\n\n private stmt(sql: string): SqliteStatement {\n return this.db.prepare(sql);\n }\n\n private transaction<T>(run: () => T): T {\n this.db.exec('BEGIN IMMEDIATE');\n try {\n const result = run();\n this.db.exec('COMMIT');\n return result;\n } catch (error) {\n this.db.exec('ROLLBACK');\n throw error;\n }\n }\n\n /** Bundle of store state the schema/migration module operates on. */\n private schemaCtx(): SchemaContext {\n return {\n db: this.db,\n projectDir: this.projectDir,\n transaction: (run) => this.transaction(run),\n };\n }\n\n private persistMessage(message: MailboxMessage, legacyGlobalCompletion = false): void {\n persistMessage(this.db, message, legacyGlobalCompletion);\n }\n\n private persistReceipt(messageId: string, state: MailboxRecipientState): void {\n persistReceipt(this.db, messageId, state);\n }\n\n private materializeMessageRows(rows: readonly MessageRow[]): MailboxMessageProjection[] {\n return materializeMessageRows(this.db, rows);\n }\n\n private readMessages(): MailboxMessageProjection[] {\n const rows = this.stmt(\n 'SELECT id, data, legacy_global_completion FROM messages',\n ).all() as unknown as MessageRow[];\n return this.materializeMessageRows(rows);\n }\n\n private findMessage(messageId: string): MailboxMessageProjection | undefined {\n const row = this.stmt(\n 'SELECT id, data, legacy_global_completion FROM messages WHERE id = ?',\n ).get(messageId) as MessageRow | undefined;\n return row === undefined ? undefined : this.materializeMessageRows([row])[0];\n }\n\n async send(input: MailboxSendInput): Promise<MailboxMessage> {\n return this.sendMessage(input, false);\n }\n\n async sendRuntimeControl(\n input: Omit<MailboxSendInput, 'type'> & { type?: 'control' },\n ): Promise<MailboxMessage> {\n return this.sendMessage({ ...input, type: 'control' }, true);\n }\n\n private async sendMessage(\n input: MailboxSendInput,\n allowRuntimeControl: boolean,\n ): Promise<MailboxMessage> {\n const type = normalizeMailboxMessageType(input.type);\n const to = normalizeRecipient(input.to, input.senderSessionId);\n if (!(allowRuntimeControl && type === 'control')) validateSendType(type, to);\n const timestamp = new Date().toISOString();\n const message: MailboxMessage = {\n id: randomUUID(),\n from: input.from,\n to,\n type,\n ...(input.audience !== undefined && input.audience !== 'all'\n ? { audience: input.audience }\n : {}),\n subject: input.subject,\n body: input.body,\n priority: input.priority ?? 'normal',\n readBy: {},\n completed: false,\n timestamp,\n ...(input.replyTo !== undefined ? { replyTo: input.replyTo } : {}),\n ...(input.taskContext !== undefined ? { taskContext: input.taskContext } : {}),\n ...(input.senderSessionId !== undefined ? { senderSessionId: input.senderSessionId } : {}),\n ...(input.ttlMs !== undefined\n ? { expiresAt: new Date(Date.now() + input.ttlMs).toISOString() }\n : {}),\n };\n this.persistMessage(message);\n this.events?.emitCustom('mailbox.message_sent', {\n messageId: message.id,\n from: message.from,\n to: message.to,\n type: message.type,\n subject: message.subject,\n });\n this.eventEmitter?.emit({\n type: 'message.sent',\n messageId: message.id,\n from: message.from,\n to: message.to,\n audience: message.audience,\n timestamp,\n });\n return message;\n }\n\n async query(query: MailboxQuery): Promise<MailboxMessage[]> {\n const type = query.type === undefined ? undefined : normalizeMailboxMessageType(query.type);\n const priorityRank = { low: 0, normal: 1, high: 2 } as const;\n const minimumRank = query.minPriority === undefined ? 0 : priorityRank[query.minPriority];\n const statuses =\n query.unreadBy === undefined ? await this.getAgentStatuses() : undefined;\n const where: string[] = [];\n const params: Array<string | number> = [];\n if (query.to !== undefined) {\n where.push('(to_id = ? OR to_id = ?)');\n params.push(query.to, '*');\n }\n if (query.from !== undefined) {\n where.push('from_id = ?');\n params.push(query.from);\n }\n if (query.sessionId !== undefined) {\n where.push('sender_session_id = ?');\n params.push(query.sessionId);\n }\n if (type !== undefined) {\n where.push('type = ?');\n params.push(type);\n }\n if (query.minPriority !== undefined) {\n // Unrecognized priorities rank as `normal`, matching the JSONL reader\n // this store replaced: an unknown value must not silently drop a\n // message out of a `minPriority: 'normal'` query. Only an explicit\n // 'low' ranks below normal.\n where.push(`CASE priority WHEN 'high' THEN 2 WHEN 'low' THEN 0 ELSE 1 END >= ?`);\n params.push(minimumRank);\n }\n if (query.since !== undefined) {\n where.push('timestamp > ?');\n params.push(query.since);\n }\n if (!query.includeDeleted) where.push('deleted_at IS NULL');\n if (query.replyTo !== undefined) {\n where.push('reply_to = ?');\n params.push(query.replyTo);\n }\n const canPreLimit = query.unreadBy === undefined && !query.incompleteOnly;\n let sql = 'SELECT id, data, legacy_global_completion FROM messages';\n if (where.length > 0) sql += ` WHERE ${where.join(' AND ')}`;\n // `rowid DESC` breaks ties: two sends can land in the same millisecond and\n // ISO timestamps have no finer resolution. Without it SQLite is free to\n // return same-millisecond messages in any order, and \"newest first\"\n // becomes a coin flip. Insertion order is stable \u2014 `persistMessage`\n // upserts, so an ack never moves a message's rowid.\n sql += ' ORDER BY timestamp DESC, rowid DESC';\n if (canPreLimit) {\n sql += ' LIMIT ?';\n params.push(query.limit ?? 50);\n }\n const rows = this.stmt(sql).all(...params) as unknown as MessageRow[];\n const messages = this.materializeMessageRows(rows).filter((message) => {\n if (query.to !== undefined && message.to !== query.to && message.to !== '*') return false;\n if (query.from !== undefined && message.from !== query.from) return false;\n if (query.sessionId !== undefined && message.senderSessionId !== query.sessionId) return false;\n if (\n query.unreadBy !== undefined &&\n !isMailboxMessageVisibleTo(message, query.unreadBy, query.readerRole)\n ) return false;\n if (\n !query.incompleteOnly &&\n query.unreadBy !== undefined &&\n query.unreadBy in message.readBy\n ) return false;\n if (\n query.incompleteOnly &&\n (query.unreadBy === undefined\n ? projectMailboxCompletion(message, undefined, statuses).completed\n : isMessageCompletedForActor(message, query.unreadBy))\n ) return false;\n if (type !== undefined && message.type !== type) return false;\n if (priorityRank[message.priority] < minimumRank) return false;\n if (query.since !== undefined && message.timestamp <= query.since) return false;\n if (!query.includeDeleted && message.deletedAt !== undefined) return false;\n if (query.replyTo !== undefined && message.replyTo !== query.replyTo) return false;\n return true;\n });\n messages.sort((left, right) => right.timestamp.localeCompare(left.timestamp));\n return messages.slice(0, query.limit ?? 50).map((message) => {\n const copy = {\n ...projectMailboxCompletion(message, query.unreadBy, statuses),\n readBy: { ...message.readBy },\n };\n if (!query.includeReceiptState) {\n delete (copy as Partial<MailboxMessageProjection>).recipientState;\n delete (copy as Partial<MailboxMessageProjection>).legacyGlobalCompletion;\n }\n return copy;\n });\n }\n\n async ack(input: MailboxAckInput): Promise<MailboxMessage | null> {\n const results = await this.ackMany({ acks: [input] });\n return results[0] ?? null;\n }\n\n async ackMany(input: MailboxAckBatchInput): Promise<MailboxMessage[]> {\n if (input.acks.length === 0) return [];\n const timestamp = new Date().toISOString();\n const changed = new Set<string>();\n const updated = this.transaction(() => {\n const results: MailboxMessage[] = [];\n for (const ack of input.acks) {\n const message = this.findMessage(ack.messageId);\n if (message === undefined) continue;\n const current = message.recipientState[ack.readerId] ?? { actorId: ack.readerId };\n const state: MailboxRecipientState = { ...current };\n let didChange = false;\n\n if (ack.read !== false && state.readAt === undefined) {\n state.readAt = timestamp;\n message.readBy[ack.readerId] = timestamp;\n didChange = true;\n }\n if (\n ack.completed === true &&\n state.completedAt === undefined &&\n message.legacyGlobalCompletion !== true\n ) {\n state.completedAt = timestamp;\n state.completedBy = ack.readerId;\n didChange = true;\n }\n if (ack.read === false && ack.completed === false && state.completedAt !== undefined) {\n delete state.completedAt;\n delete state.completedBy;\n didChange = true;\n }\n if (ack.outcome !== undefined && state.outcome !== ack.outcome) {\n state.outcome = ack.outcome;\n didChange = true;\n }\n\n message.recipientState = {\n ...message.recipientState,\n [ack.readerId]: state,\n };\n const actorCompleted = state.completedAt !== undefined;\n message.completed = message.legacyGlobalCompletion === true || actorCompleted;\n if (actorCompleted) {\n message.completedBy = state.completedBy ?? ack.readerId;\n message.completedAt = state.completedAt;\n } else if (message.legacyGlobalCompletion !== true) {\n delete message.completedBy;\n delete message.completedAt;\n }\n message.outcome = state.outcome;\n\n if (didChange) {\n this.persistReceipt(message.id, state);\n // Aggregate completion is STORED only for a message with a single\n // addressee. One actor finishing a fan-out (`*`, `@session:`, a bare\n // role alias) must not mark it done for everyone else \u2014 that is what\n // the per-actor receipt model exists to prevent, and\n // `legacyGlobalCompletion` marks the historical v1 messages that\n // predate it. The value returned to the caller below still reports\n // that actor's own completion.\n this.persistMessage(\n isFanOutRecipient(message.to) ? withoutAggregateCompletion(message) : message,\n message.legacyGlobalCompletion === true,\n );\n changed.add(message.id);\n }\n results.push({ ...message, readBy: { ...message.readBy } });\n }\n return results;\n });\n\n for (const message of updated) {\n if (!changed.has(message.id)) continue;\n this.eventEmitter?.emit({\n type: 'message.acked',\n messageId: message.id,\n from: message.from,\n to: message.to,\n audience: message.audience,\n timestamp,\n });\n }\n return updated;\n }\n\n async unreadCount(forAgentId: string, sessionId?: string): Promise<number> {\n const sessionAddress = sessionId === undefined ? undefined : sessionRecipient(sessionId);\n return this.readMessages().filter(\n (message) =>\n (message.to === forAgentId || message.to === '*' || message.to === sessionAddress) &&\n isMailboxMessageVisibleTo(message, forAgentId) &&\n !(forAgentId in message.readBy) &&\n !isMessageCompletedForActor(message, forAgentId) &&\n message.deletedAt === undefined,\n ).length;\n }\n\n async softDelete(mailId: string, by: string): Promise<MailboxMessage | null> {\n const message = this.findMessage(mailId);\n if (message === undefined) return null;\n if (message.deletedAt !== undefined) return { ...message, readBy: { ...message.readBy } };\n const timestamp = new Date().toISOString();\n message.deletedAt = timestamp;\n message.deletedBy = by;\n const previousState = message.recipientState[by] ?? { actorId: by };\n const state = {\n ...previousState,\n readAt: previousState.readAt ?? timestamp,\n };\n message.readBy[by] = state.readAt;\n message.recipientState = { ...message.recipientState, [by]: state };\n this.transaction(() => {\n this.persistReceipt(message.id, state);\n this.persistMessage(message, message.legacyGlobalCompletion === true);\n });\n this.eventEmitter?.emit({\n type: 'message.deleted',\n messageId: message.id,\n from: message.from,\n to: message.to,\n audience: message.audience,\n timestamp,\n });\n return { ...message, readBy: { ...message.readBy } };\n }\n\n async restore(mailId: string): Promise<MailboxMessage | null> {\n const message = this.findMessage(mailId);\n if (message === undefined) return null;\n if (message.deletedAt === undefined && message.deletedBy === undefined) {\n return { ...message, readBy: { ...message.readBy } };\n }\n delete message.deletedAt;\n delete message.deletedBy;\n this.persistMessage(message, message.legacyGlobalCompletion === true);\n const timestamp = new Date().toISOString();\n this.eventEmitter?.emit({\n type: 'message.restored',\n messageId: message.id,\n from: message.from,\n to: message.to,\n audience: message.audience,\n timestamp,\n });\n return { ...message, readBy: { ...message.readBy } };\n }\n\n private persistAgent(agent: RegisteredAgent): void {\n persistAgent(this.db, agent);\n }\n\n private readAgents(): Map<string, RegisteredAgent> {\n return readAgents(this.db);\n }\n\n private pruneAgents(maxAgeMs = AGENT_STALE_MS): number {\n return pruneAgents(this.db, maxAgeMs);\n }\n\n async registerAgent(input: AgentRegistrationInput): Promise<void> {\n this.pruneAgents();\n const now = new Date().toISOString();\n this.persistAgent({\n agentId: input.agentId,\n sessionId: input.sessionId,\n name: input.name,\n ...(input.role !== undefined ? { role: input.role } : {}),\n status: 'idle',\n iterations: 0,\n toolCalls: 0,\n registeredAt: now,\n lastSeenAt: now,\n pid: input.pid ?? process.pid,\n ...(input.source !== undefined ? { source: input.source } : {}),\n });\n this.events?.emitCustom('mailbox.agent_registered', {\n agentId: input.agentId,\n sessionId: input.sessionId,\n name: input.name,\n role: input.role,\n source: input.source,\n });\n }\n\n /**\n * Throttle bookkeeping only: `agentId`/`clientId` -> last accepted heartbeat.\n *\n * Entries are deleted on a clean deregister, but a crashed or forcibly killed\n * peer never deregisters, so over a long-lived daemon's life these maps grew\n * with every distinct id ever seen. Dropping a stale entry is free: the next\n * heartbeat from that id simply is not throttled and writes once more.\n */\n private pruneHeartbeats(map: Map<string, number>, nowMs: number): void {\n if (map.size <= HEARTBEAT_TRACKING_MAX_ENTRIES) return;\n for (const [id, at] of map) {\n if (nowMs - at > HEARTBEAT_TRACKING_TTL_MS) map.delete(id);\n }\n }\n\n async deregisterAgent(agentId: string): Promise<void> {\n this.stmt('DELETE FROM agents WHERE agent_id = ?').run(agentId);\n this.lastHeartbeat.delete(agentId);\n this.events?.emitCustom('mailbox.agent_deregistered', { agentId });\n }\n\n async heartbeat(input: AgentHeartbeatInput): Promise<void> {\n const nowMs = Date.now();\n if (nowMs - (this.lastHeartbeat.get(input.agentId) ?? 0) < HEARTBEAT_THROTTLE_MS) return;\n this.lastHeartbeat.set(input.agentId, nowMs);\n this.pruneHeartbeats(this.lastHeartbeat, nowMs);\n this.pruneAgents();\n const agent = this.readAgents().get(input.agentId);\n if (agent !== undefined) {\n agent.lastSeenAt = new Date(nowMs).toISOString();\n if (input.status !== undefined) agent.status = input.status;\n if (input.currentTool !== undefined) agent.currentTool = input.currentTool;\n if (input.currentTask !== undefined) agent.currentTask = input.currentTask;\n if (input.iterations !== undefined) agent.iterations = input.iterations;\n if (input.toolCalls !== undefined) agent.toolCalls = input.toolCalls;\n this.persistAgent(agent);\n }\n this.events?.emitCustom('mailbox.agent_heartbeat', {\n agentId: input.agentId,\n status: input.status,\n currentTool: input.currentTool,\n currentTask: input.currentTask,\n });\n }\n\n async getAgentStatuses(): Promise<MailboxAgentStatus[]> {\n this.pruneAgents();\n return mapRegisteredAgentsToStatuses(this.readAgents(), Date.now(), AGENT_STALE_MS);\n }\n\n async purgeAgents(maxAgeMs = AGENT_STALE_MS): Promise<number> {\n return this.pruneAgents(maxAgeMs);\n }\n\n async getOnlineAgents(): Promise<MailboxAgentStatus[]> {\n return (await this.getAgentStatuses()).filter((agent) => agent.online);\n }\n\n private persistClient(client: RegisteredClient): void {\n persistClient(this.db, client);\n }\n\n private readClients(): Map<string, RegisteredClient> {\n return readClients(this.db);\n }\n\n private pruneClientsInPlace(): number {\n return pruneClients(this.db);\n }\n\n async registerClient(input: ClientRegistrationInput): Promise<void> {\n this.pruneClientsInPlace();\n const now = new Date().toISOString();\n this.persistClient({\n clientId: input.clientId,\n sessionId: input.sessionId,\n name: input.name,\n source: input.source,\n registeredAt: now,\n lastSeenAt: now,\n pid: input.pid ?? process.pid,\n });\n this.events?.emitCustom('mailbox.client_registered', {\n clientId: input.clientId,\n sessionId: input.sessionId,\n name: input.name,\n source: input.source,\n });\n }\n\n async deregisterClient(clientId: string): Promise<void> {\n this.stmt('DELETE FROM clients WHERE client_id = ?').run(clientId);\n this.lastClientHeartbeat.delete(clientId);\n this.events?.emitCustom('mailbox.client_deregistered', { clientId });\n }\n\n async clientHeartbeat(input: ClientHeartbeatInput): Promise<void> {\n const nowMs = Date.now();\n if (\n nowMs - (this.lastClientHeartbeat.get(input.clientId) ?? 0) <\n HEARTBEAT_THROTTLE_MS\n ) return;\n this.lastClientHeartbeat.set(input.clientId, nowMs);\n this.pruneHeartbeats(this.lastClientHeartbeat, nowMs);\n this.pruneClientsInPlace();\n const client = this.readClients().get(input.clientId);\n if (client !== undefined) {\n client.lastSeenAt = new Date(nowMs).toISOString();\n if (input.sessionId) client.sessionId = input.sessionId;\n this.persistClient(client);\n }\n this.events?.emitCustom('mailbox.client_heartbeat', {\n clientId: input.clientId,\n ...(input.sessionId ? { sessionId: input.sessionId } : {}),\n });\n }\n\n async getClientStatuses(): Promise<ClientStatus[]> {\n this.pruneClientsInPlace();\n return mapRegisteredClientsToStatuses(this.readClients(), Date.now(), CLIENT_STALE_MS);\n }\n\n async purgeClients(): Promise<number> {\n return this.pruneClientsInPlace();\n }\n\n async clearAll(): Promise<void> {\n this.stmt('DELETE FROM messages').run();\n }\n\n async purgeStale(options?: PurgeOptions): Promise<PurgeResult> {\n return purgeStale(this.compactionCtx(), options);\n }\n\n async autoCompact(options?: AutoCompactOptions): Promise<AutoCompactResult> {\n return autoCompact(this.compactionCtx(), options);\n }\n\n /** Bundle of store operations the retention sweeps drive. */\n private compactionCtx(): CompactionContext {\n return {\n getAgentStatuses: () => this.getAgentStatuses(),\n readMessages: () => this.readMessages(),\n deleteMessages: (ids) => this.deleteMessages(ids),\n };\n }\n\n private deleteMessages(ids: readonly string[]): void {\n if (ids.length === 0) return;\n this.transaction(() => deleteMessages(this.db, ids));\n }\n\n credentialGet(credentialId: string): MailboxCredential | null {\n return credentialGet(this.db, credentialId);\n }\n\n credentialList(): MailboxCredential[] {\n return credentialList(this.db);\n }\n\n credentialStatusCounts(): Record<string, number> {\n return credentialStatusCounts(this.db);\n }\n\n credentialIssue(\n options: IssueCredentialOptions,\n ): { credential: MailboxCredential; secret: string } {\n return credentialIssue(this.db, (run) => this.transaction(run), options);\n }\n\n credentialVerify(credentialId: string, secret: string): CredentialValidation {\n return credentialVerify(this.db, credentialId, secret);\n }\n\n credentialRevoke(credentialId: string, reason?: string, by?: string): boolean {\n return credentialRevoke(this.db, credentialId, reason, by);\n }\n\n credentialRotate(\n credentialId: string,\n options?: Partial<IssueCredentialOptions>,\n ): { credential: MailboxCredential; secret: string } | null {\n return credentialRotate(this.db, (run) => this.transaction(run), credentialId, options);\n }\n\n startAutoCompactTimer(options?: AutoCompactOptions): () => void {\n if (this.autoCompactTimer !== null) clearInterval(this.autoCompactTimer);\n const timer = setInterval(() => {\n void this.autoCompact(options).catch(() => {});\n }, options?.intervalMs ?? AUTO_COMPACT_INTERVAL_MS);\n timer.unref?.();\n this.autoCompactTimer = timer;\n return () => {\n clearInterval(timer);\n if (this.autoCompactTimer === timer) this.autoCompactTimer = null;\n };\n }\n\n async close(): Promise<void> {\n if (this.closed) return;\n this.closed = true;\n if (this.autoCompactTimer !== null) clearInterval(this.autoCompactTimer);\n this.autoCompactTimer = null;\n this.db.close();\n }\n}\n", "import { createHash, randomUUID } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport { hostname } from 'node:os';\nimport { basename } from 'node:path';\nimport { readProjectIdentitySync } from '../utils/project-identity.js';\nimport type { HqClientConfig } from '../types/config.js';\nimport type { Logger } from '../types/logger.js';\nimport {\n type HqAuthFile,\n hqAuthFilePath,\n readHqRuntimeFileSync,\n resolveHqDataDir,\n} from './auth-store.js';\nimport type {\n HqClientCapability,\n HqClientIdentity,\n HqProjectIdentity,\n HqRedactionPolicy,\n} from './protocol.js';\nimport {\n HqPublisher,\n type HqPublisherCommandHandler,\n type HqPublisherOptions,\n type HqSocketFactory,\n} from './publisher.js';\n\nexport interface HqPublisherEnvConfig {\n url: string;\n token?: string;\n enabled?: boolean;\n rawContent?: boolean;\n projectAlias?: string;\n /**\n * Same-machine auto-discovery mode: no explicit URL was configured, so the\n * publisher should re-resolve the endpoint from `<dataDir>/runtime.json`\n * (+ the first client token in `auth.json`) before every connect attempt.\n * This lets every client on the machine attach to a `wstack --hq` that is\n * already running, starts later, or restarts on a different port.\n */\n discover?: boolean;\n /** Resolved HQ data dir the discovery reads from. */\n dataDir?: string;\n}\n\n/**\n * Discover a locally running `wstack --hq` endpoint: reads the runtime\n * marker (pid-liveness-checked) and the first client token. Returns\n * `undefined` when no live HQ is advertised on this machine.\n */\nexport function discoverLocalHqEndpoint(options: {\n dataDir?: string | undefined;\n env?: NodeJS.ProcessEnv | undefined;\n} = {}): { url: string; token?: string | undefined } | undefined {\n const dataDir = resolveHqDataDir(options.dataDir, options.env ?? process.env);\n const runtime = readHqRuntimeFileSync(dataDir);\n if (runtime === undefined) return undefined;\n const token = readFirstClientTokenFromAuthFile(dataDir);\n return { url: runtime.url, ...(token ? { token } : {}) };\n}\n\nfunction readFirstClientTokenFromAuthFile(dataDir: string): string | undefined {\n try {\n const raw = fs.readFileSync(hqAuthFilePath(dataDir), 'utf8');\n const parsed = JSON.parse(raw) as HqAuthFile;\n return parsed.clientTokens?.find((t) => t.token.trim().length > 0)?.token;\n } catch {\n return undefined;\n }\n}\n\n/**\n * True when an explicit HQ URL targets this machine. Falling back to the\n * LOCAL auth.json client token is only valid for same-machine servers \u2014 a\n * remote HQ has its own auth.json, and sending the local token would put the\n * publisher into a silent 401 reconnect loop.\n */\nfunction isLoopbackHqUrl(url: string): boolean {\n try {\n const host = new URL(url).hostname.toLowerCase();\n return host === '127.0.0.1' || host === 'localhost' || host === '::1' || host === '[::1]' || host === '0.0.0.0';\n } catch {\n return false;\n }\n}\n\nexport function resolveHqConfigFromEnv(env: NodeJS.ProcessEnv = process.env): HqPublisherEnvConfig | undefined {\n return resolveHqConfig({ env });\n}\n\nexport function resolveHqConfig(options: {\n env?: NodeJS.ProcessEnv | undefined;\n config?: HqClientConfig | undefined;\n} = {}): HqPublisherEnvConfig | undefined {\n const env = options.env ?? process.env;\n const fileConfig = options.config;\n const envUrl = env['WRONGSTACK_HQ_URL']?.trim();\n const envToken = env['WRONGSTACK_HQ_TOKEN']?.trim();\n const configUrl = fileConfig?.url?.trim();\n const configToken = fileConfig?.token?.trim();\n const envEnabledRaw = env['WRONGSTACK_HQ_ENABLED']?.trim();\n const enabled = envEnabledRaw !== undefined && envEnabledRaw.length > 0\n ? envEnabledRaw !== '0'\n : fileConfig?.enabled;\n const dataDir = resolveHqDataDir(fileConfig?.dataDir, env);\n const explicitToken = envToken || configToken;\n const runtimeUrl = readHqRuntimeFileSync(dataDir)?.url.trim();\n const url = envUrl || configUrl;\n // The local auth.json client token is only a valid fallback for\n // same-machine endpoints (discovery, or an explicit loopback URL). For a\n // remote URL without an explicit token, send NO token \u2014 the server's 401\n // is then an honest signal instead of a guaranteed-wrong local token.\n const localFallbackToken =\n !url || isLoopbackHqUrl(url) ? readFirstClientTokenFromAuthFile(dataDir) : undefined;\n const token = explicitToken || localFallbackToken;\n\n const rawContentEnv = env['WRONGSTACK_HQ_RAW_CONTENT']?.trim();\n const explicitRawContent = rawContentEnv ? rawContentEnv === '1' : fileConfig?.rawContent;\n const projectAliasEnv = env['WRONGSTACK_HQ_PROJECT_ALIAS']?.trim();\n const projectAlias = projectAliasEnv || fileConfig?.projectAlias;\n\n if (!url) {\n if (enabled === false) return undefined;\n // No explicit endpoint \u2192 same-machine auto-discovery (default ON).\n // The publisher re-resolves runtime.json + auth.json before every\n // connect attempt, so an HQ started AFTER this client \u2014 or restarted on\n // another port \u2014 is attached to automatically. While no HQ is running\n // the publisher stays dormant (bounded queue, cheap file poll).\n // Opt out with WRONGSTACK_HQ_ENABLED=0 or config `hq.enabled: false`.\n //\n // Same-machine HQ defaults to RAW content: the data never leaves this\n // machine and the operator watching HQ is the same user running the\n // sessions \u2014 a redacted chat history there is useless. Opt out with\n // WRONGSTACK_HQ_RAW_CONTENT=0 or `hq.rawContent: false` (/hq raw off).\n // Secret scrubbing + sensitive-field masking still always apply.\n return {\n url: runtimeUrl || 'http://127.0.0.1:3499',\n enabled: true,\n discover: true,\n dataDir,\n rawContent: explicitRawContent ?? true,\n ...(token ? { token } : {}),\n ...(projectAlias ? { projectAlias } : {}),\n };\n }\n\n // Explicit URL: raw content is the default for every HQ target. Operators\n // can still opt out with WRONGSTACK_HQ_RAW_CONTENT=0 or hq.rawContent=false,\n // and the HQ server can clamp disclosure with auth.json redactionPolicy.\n const rawContent = explicitRawContent ?? true;\n return {\n url,\n ...(token ? { token } : {}),\n ...(enabled !== undefined ? { enabled } : {}),\n ...(rawContent !== undefined ? { rawContent } : {}),\n ...(projectAlias ? { projectAlias } : {}),\n };\n}\n\nfunction stableMachineId(): string {\n // Stable per *physical machine*, NOT per process \u2014 every terminal on the\n // same computer must share one machineId so HQ groups them under a single\n // machine node. (Process identity already lives in clientId via the pid.)\n return createHash('sha256').update(hostname()).digest('hex').slice(0, 12);\n}\n\nexport function deriveHqProjectId(projectRoot: string, projectAlias?: string): string {\n const projectIdentity = readProjectIdentitySync(projectRoot);\n if (projectIdentity) return projectIdentity.projectId;\n const alias = projectAlias?.trim();\n if (!alias && projectRoot.startsWith('alias:')) {\n throw new Error('projectRoot must not use the reserved \"alias:\" HQ identity prefix');\n }\n const identity = alias ? `alias:${alias}` : projectRoot;\n return createHash('sha256').update(identity).digest('hex').slice(0, 12);\n}\n\nexport interface CreateHqPublisherOptions {\n clientKind: HqClientIdentity['kind'];\n projectRoot: string;\n projectName?: string;\n machineId?: string;\n hostnameOverride?: string;\n socketFactory?: HqSocketFactory;\n config?: HqPublisherEnvConfig;\n appConfig?: { hq?: HqClientConfig | undefined } | undefined;\n redactionPolicy?: Partial<HqRedactionPolicy>;\n /** Forwarded to the HqPublisher constructor (Phase 4 control plane). */\n capabilities?: readonly HqClientCapability[];\n /** Bound offline telemetry retained by this client. */\n maxQueuedMessages?: number;\n /** Forwarded to the HqPublisher constructor (Phase 4 control plane). */\n onCommand?: HqPublisherCommandHandler;\n /** Receives the latest merged Kanban snapshot from HQ. */\n onKanbanSnapshot?: HqPublisherOptions['onKanbanSnapshot'];\n /** Dormant discovery re-check interval override (tests / tight loops). */\n discoveryPollMs?: number;\n /** Logger for structured connect-failure diagnostics. */\n logger?: Logger | undefined;\n}\n\nexport function createHqPublisherFromEnv(options: CreateHqPublisherOptions): HqPublisher | undefined {\n const config = options.config ?? resolveHqConfig({ config: options.appConfig?.hq });\n if (!config || config.enabled === false) return undefined;\n\n const machineId = options.machineId ?? stableMachineId();\n const host = options.hostnameOverride ?? hostname();\n const projectAlias = config.projectAlias?.trim() || undefined;\n const projectName = projectAlias ?? options.projectName ?? (basename(options.projectRoot) || 'unknown');\n\n const client: HqClientIdentity = {\n clientId: `${machineId}:${options.clientKind}:${process.pid}:${randomUUID().slice(0, 8)}`,\n kind: options.clientKind,\n machineId,\n ...(host ? { hostname: host } : {}),\n pid: process.pid,\n startedAt: new Date().toISOString(),\n };\n\n const project: HqProjectIdentity = {\n projectId: deriveHqProjectId(options.projectRoot, projectAlias),\n projectRoot: options.projectRoot,\n projectName,\n machineId,\n workspaceKind: 'git',\n };\n\n const redactionPolicy: Partial<HqRedactionPolicy> | undefined =\n options.redactionPolicy || config.rawContent !== undefined\n ? {\n ...(config.rawContent !== undefined ? { rawContent: config.rawContent } : {}),\n ...(options.redactionPolicy ?? {}),\n }\n : undefined;\n\n const discoveryDataDir = config.dataDir;\n return new HqPublisher({\n url: config.url,\n ...(config.token ? { token: config.token } : {}),\n client,\n project,\n ...(options.socketFactory ? { socketFactory: options.socketFactory } : {}),\n ...(redactionPolicy !== undefined ? { redactionPolicy } : {}),\n ...(options.capabilities !== undefined ? { capabilities: options.capabilities } : {}),\n ...(options.maxQueuedMessages !== undefined\n ? { maxQueuedMessages: options.maxQueuedMessages }\n : {}),\n ...(options.onCommand !== undefined ? { onCommand: options.onCommand } : {}),\n ...(options.onKanbanSnapshot !== undefined\n ? { onKanbanSnapshot: options.onKanbanSnapshot }\n : {}),\n // Auto-discovery: re-read the local HQ runtime marker + client token on\n // every connect attempt so late-started/restarted HQs are picked up.\n ...(config.discover\n ? { resolveEndpoint: () => discoverLocalHqEndpoint({ dataDir: discoveryDataDir }) }\n : {}),\n ...(options.discoveryPollMs !== undefined ? { discoveryPollMs: options.discoveryPollMs } : {}),\n ...(options.logger !== undefined ? { logger: options.logger } : {}),\n });\n}\n", "import * as fs from 'node:fs';\nimport * as fsPromises from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { atomicWrite } from './atomic-write.js';\nimport { isUlid, ulid } from './ulid.js';\n\nexport const PROJECT_IDENTITY_VERSION = 1 as const;\nexport const PROJECT_ID_PREFIX = 'proj_';\nexport const PROJECT_IDENTITY_RELATIVE_PATH = path.join('.wrongstack', 'project.json');\n\nexport interface ProjectIdentityFile {\n version: typeof PROJECT_IDENTITY_VERSION;\n projectId: string;\n}\n\nexport interface EnsureProjectIdentityResult {\n identity: ProjectIdentityFile;\n created: boolean;\n}\n\nexport interface RekeyProjectIdentityResult {\n previous?: ProjectIdentityFile | undefined;\n identity: ProjectIdentityFile;\n}\n\nconst PROJECT_GITIGNORE_RULES = [\n '.wrongstack/',\n '!/.wrongstack/',\n '/.wrongstack/*',\n '!/.wrongstack/project.json',\n] as const;\n\nexport function projectIdentityPath(projectRoot: string): string {\n return path.join(projectRoot, PROJECT_IDENTITY_RELATIVE_PATH);\n}\n\nexport function createProjectId(seedTime: number = Date.now()): string {\n return `${PROJECT_ID_PREFIX}${ulid(seedTime)}`;\n}\n\nexport function isProjectId(value: string): boolean {\n return value.startsWith(PROJECT_ID_PREFIX) && isUlid(value.slice(PROJECT_ID_PREFIX.length));\n}\n\nexport function readProjectIdentitySync(projectRoot: string): ProjectIdentityFile | undefined {\n const filePath = projectIdentityPath(projectRoot);\n try {\n return parseProjectIdentity(fs.readFileSync(filePath, 'utf8'), filePath);\n } catch (error) {\n if (isMissingFileError(error)) return undefined;\n throw error;\n }\n}\n\nexport async function readProjectIdentity(\n projectRoot: string,\n): Promise<ProjectIdentityFile | undefined> {\n const filePath = projectIdentityPath(projectRoot);\n try {\n return parseProjectIdentity(await fsPromises.readFile(filePath, 'utf8'), filePath);\n } catch (error) {\n if (isMissingFileError(error)) return undefined;\n throw error;\n }\n}\n\nexport async function ensureProjectIdentity(\n projectRoot: string,\n idFactory: () => string = createProjectId,\n): Promise<EnsureProjectIdentityResult> {\n const existing = await readProjectIdentity(projectRoot);\n if (existing) return { identity: existing, created: false };\n\n const filePath = projectIdentityPath(projectRoot);\n const identity = makeIdentity(idFactory());\n await fsPromises.mkdir(path.dirname(filePath), { recursive: true });\n\n try {\n await fsPromises.writeFile(filePath, serializeProjectIdentity(identity), {\n encoding: 'utf8',\n flag: 'wx',\n });\n return { identity, created: true };\n } catch (error) {\n if (!isAlreadyExistsError(error)) throw error;\n const winner = await readProjectIdentity(projectRoot);\n if (!winner) throw error;\n return { identity: winner, created: false };\n }\n}\n\nexport async function rekeyProjectIdentity(\n projectRoot: string,\n idFactory: () => string = createProjectId,\n): Promise<RekeyProjectIdentityResult> {\n const previous = await readProjectIdentity(projectRoot);\n const identity = makeIdentity(idFactory());\n const filePath = projectIdentityPath(projectRoot);\n await fsPromises.mkdir(path.dirname(filePath), { recursive: true });\n await atomicWrite(filePath, serializeProjectIdentity(identity));\n return { previous, identity };\n}\n\n/**\n * Keep runtime state ignored while allowing the small, explicitly shared\n * WrongStack project contract to travel with the repository.\n */\nexport async function ensureProjectGitignore(projectRoot: string): Promise<void> {\n const filePath = path.join(projectRoot, '.gitignore');\n let content = '';\n try {\n content = await fsPromises.readFile(filePath, 'utf8');\n } catch (error) {\n if (!isMissingFileError(error)) throw error;\n }\n\n const hadTrailingNewline = content.endsWith('\\n');\n const lines = content.length === 0 ? [] : content.split(/\\r?\\n/);\n if (hadTrailingNewline) lines.pop();\n\n let changed = false;\n for (let index = 0; index < lines.length; index++) {\n if (lines[index]?.trim() === '.wrongstack/*') {\n lines[index] = '.wrongstack/';\n changed = true;\n }\n }\n\n for (const entry of PROJECT_GITIGNORE_RULES) {\n if (!lines.some((line) => line.trim() === entry)) {\n if (entry === '.wrongstack/' && lines.length > 0 && lines.at(-1) !== '') lines.push('');\n lines.push(entry);\n changed = true;\n }\n }\n\n if (!changed) return;\n await fsPromises.writeFile(filePath, `${lines.join('\\n')}\\n`, 'utf8');\n}\n\nfunction makeIdentity(projectId: string): ProjectIdentityFile {\n if (!isProjectId(projectId)) {\n throw new Error(`Invalid WrongStack project id: ${projectId}`);\n }\n return { version: PROJECT_IDENTITY_VERSION, projectId };\n}\n\nfunction parseProjectIdentity(raw: string, filePath: string): ProjectIdentityFile {\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch {\n throw new Error(`Invalid JSON in WrongStack project identity file: ${filePath}`);\n }\n if (typeof value !== 'object' || value === null) {\n throw new Error(`Invalid WrongStack project identity file: ${filePath}`);\n }\n const record = value as Record<string, unknown>;\n if (record['version'] !== PROJECT_IDENTITY_VERSION) {\n throw new Error(`Unsupported WrongStack project identity version in ${filePath}`);\n }\n if (typeof record['projectId'] !== 'string' || !isProjectId(record['projectId'])) {\n throw new Error(`Invalid projectId in WrongStack project identity file: ${filePath}`);\n }\n return { version: PROJECT_IDENTITY_VERSION, projectId: record['projectId'] };\n}\n\nfunction serializeProjectIdentity(identity: ProjectIdentityFile): string {\n return `${JSON.stringify(identity, null, 2)}\\n`;\n}\n\nfunction isMissingFileError(error: unknown): boolean {\n return (error as NodeJS.ErrnoException | undefined)?.code === 'ENOENT';\n}\n\nfunction isAlreadyExistsError(error: unknown): boolean {\n return (error as NodeJS.ErrnoException | undefined)?.code === 'EEXIST';\n}\n", "import { randomBytes } from 'node:crypto';\n\n/**\n * Crockford base32 alphabet (excludes I, L, O, U to avoid ambiguity).\n */\nconst ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';\nconst ENCODING_LEN = ENCODING.length;\nconst TIME_LEN = 10;\nconst RANDOM_LEN = 16;\n\nfunction encodeTime(now: number, len: number): string {\n let mod: number;\n let str = '';\n for (let i = len - 1; i >= 0; i--) {\n mod = now % ENCODING_LEN;\n str = ENCODING[mod] + str;\n now = (now - mod) / ENCODING_LEN;\n }\n return str;\n}\n\nfunction encodeRandom(len: number): string {\n const bytes = randomBytes(len);\n let str = '';\n for (let i = 0; i < len; i++) {\n str += ENCODING[(bytes[i] as number) % ENCODING_LEN];\n }\n return str;\n}\n\n/**\n * Generate a ULID \u2014 a 26-char Crockford-base32 identifier whose first 10 chars\n * encode the millisecond timestamp (so IDs sort lexicographically by creation\n * time) followed by 16 chars of randomness. Zero runtime dependencies.\n *\n * The codebase convention is \"IDs are ULIDs\"; use this for any new store key.\n */\nexport function ulid(seedTime: number = Date.now()): string {\n return encodeTime(seedTime, TIME_LEN) + encodeRandom(RANDOM_LEN);\n}\n\n/** True for a well-formed 26-char Crockford-base32 ULID. */\nexport function isUlid(value: string): boolean {\n if (value.length !== TIME_LEN + RANDOM_LEN) return false;\n for (const ch of value) {\n if (!ENCODING.includes(ch)) return false;\n }\n return true;\n}\n", "/**\n * HQ auth-store \u2014 persistent `auth.json` for the HQ command center.\n *\n * Holds:\n * - Operator-configured redaction policy override (applied server-side\n * even when a publisher claims rawContent:true).\n * - Browser tokens + client tokens. Separate lists so a browser-only token\n * cannot be replayed on /ws/client and vice versa.\n * - Operator-configured alert-rule thresholds (`alertRules`), live-reloaded.\n * - Live reload hook: callers can `watchHqAuthFile()` to re-read on change.\n *\n * Storage layout (under the HQ data directory, default `~/.wrongstack/hq/`):\n * <dataDir>/auth.json \u2014 this file (atomic write, mode 0o600)\n * <dataDir>/events.jsonl \u2014 persistent event log (rotated)\n * <dataDir>/snapshot.json \u2014 persisted latest snapshot (cache)\n *\n * The file is written atomically (tmp + rename) with mode 0o600 so a\n * shared host cannot read issued tokens or the redaction policy. Reads\n * are lenient: a missing file yields an empty document; a corrupt file\n * yields an empty document plus a warning so the operator can recover.\n *\n * @module hq/auth-store\n */\nimport { createHash, randomBytes, randomUUID, scrypt, timingSafeEqual } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as syncFs from 'node:fs';\nimport * as path from 'node:path';\n\nimport { atomicWrite } from '../utils/atomic-write.js';\nimport { wstackGlobalRoot } from '../utils/wstack-paths.js';\nimport type { HqAlertRuleConfig } from './alerts.js';\nimport { logHqAuthAudit } from './auth-audit.js';\nimport type { HqRedactionPolicy } from './protocol.js';\n\n/** Current auth-file schema version. Bump on breaking shape changes. */\nexport const HQ_AUTH_FILE_VERSION = 1 as const;\n\n/** Default HQ data directory: `~/.wrongstack/hq` (honors WRONGSTACK_HOME). */\nexport function defaultHqDataDir(): string {\n return path.join(wstackGlobalRoot(), 'hq');\n}\n\n/**\n * Resolve an HQ data directory from an optional override.\n *\n * Resolution order:\n * 1. Explicit `override` (from `--data-dir`) \u2014 resolved against\n * `process.cwd()` if relative.\n * 2. `WRONGSTACK_HQ_DATA_DIR` env var (same resolution rules).\n * 3. `defaultHqDataDir()` \u2014 `~/.wrongstack/hq`.\n *\n * The env var exists so tests (and sandboxed runs) can redirect HQ state\n * away from the real user home without threading a CLI flag everywhere.\n */\nexport function resolveHqDataDir(override?: string, env: NodeJS.ProcessEnv = process.env): string {\n const raw = override ?? env['WRONGSTACK_HQ_DATA_DIR']?.trim();\n if (!raw) return defaultHqDataDir();\n return path.isAbsolute(raw) ? path.resolve(raw) : path.resolve(process.cwd(), raw);\n}\n\n/**\n * A generic HQ-issued token. Used for both browser tokens (validated on\n * `/ws/browser`) and client tokens (validated on `/ws/client`). The two\n * are stored in separate lists so a browser-only token cannot be replayed\n * against the client channel and vice versa.\n *\n * `capabilities` scopes what a token may do. When absent the token is\n * unrestricted (backward-compat with tokens minted before Phase 3). Known\n * capability strings:\n * - `control.enqueue` \u2014 browser token may enqueue commands to clients\n * - `control.execute` \u2014 client token may execute `run-command` commands\n * - `telemetry.publish` \u2014 client token may publish telemetry\n */\nexport interface HqToken {\n id: string;\n token: string;\n label?: string;\n createdAt: string;\n lastUsedAt?: string;\n /**\n * Optional capability scope. When absent, the token is unrestricted\n * (backward-compat). When present, only the listed capabilities are\n * granted.\n */\n capabilities?: string[];\n /**\n * Optional ISO timestamp after which the token is refused. When absent\n * (the pre-TTL default), the token never expires. The HQ server rejects\n * an expired token at both the HTTP and the WS-upgrade auth boundary,\n * so TTL rotation is enforced even for long-lived browser sessions.\n *\n * The timestamp is wall-clock (`new Date().toISOString()`). Clock skew\n * between the issuing HQ and the client is handled by passing a\n * `clockSkewMs` tolerance to {@link isTokenExpired} and\n * {@link tokenHasCapability} \u2014 callers that fetch tokens from a remote\n * HQ should use the server's clock (e.g. `Date.parse(expiresAt)`)\n * rather than the local wall clock.\n */\n expiresAt?: string;\n}\n\n/**\n * True when a token has a wall-clock expiry that has already passed.\n * Returns `false` when `expiresAt` is absent (the pre-TTL default).\n *\n * The check is fail-open for malformed values: an unparseable timestamp\n * is treated as \"no expiry\" rather than \"already expired\", because the\n * latter would lock the operator out of their own HQ on a bad file edit.\n * Use {@link tokenHasCapability} at the auth boundary to also deny\n * capabilities for expired tokens.\n *\n * @param at - epoch milliseconds; defaults to `Date.now()`. Exposed so\n * tests can inject a fixed clock.\n * @param clockSkewMs - tolerance in milliseconds for clock skew between\n * the issuing node and the verifying node. When set, a token that has\n * technically expired by up to `clockSkewMs` is still accepted, so a\n * verifier whose clock is slightly ahead of the issuer does not\n * prematurely reject valid tokens. Defaults to 0 (no tolerance).\n */\nexport function isTokenExpired(\n token: Pick<HqToken, 'expiresAt'> | undefined,\n at: number = Date.now(),\n clockSkewMs: number = 0,\n): boolean {\n if (token === undefined) return false;\n const expiresAt = token.expiresAt;\n if (expiresAt === undefined) return false;\n const parsed = Date.parse(expiresAt);\n if (!Number.isFinite(parsed)) return false;\n return at >= parsed - Math.max(0, clockSkewMs);\n}\n\n/**\n * Check whether a token grants a capability. A token with no `capabilities`\n * field is unrestricted (backward-compat). Otherwise the capability must be\n * explicitly listed. **Expired tokens are refused regardless of capability**\n * \u2014 call this at the auth boundary so TTL rotation is enforced uniformly.\n *\n * @param clockSkewMs - passed through to {@link isTokenExpired}. When set, a\n * token that has expired by up to `clockSkewMs` is still accepted. Defaults\n * to 0.\n */\nexport function tokenHasCapability(\n token: HqToken | undefined,\n capability: string,\n clockSkewMs: number = 0,\n): boolean {\n if (token === undefined) return false;\n if (isTokenExpired(token, Date.now(), clockSkewMs)) return false;\n if (token.capabilities === undefined) return true;\n return token.capabilities.includes(capability);\n}\n\n/**\n * Alias kept for backward-compat with Phase 3 callers/tests. New code\n * should prefer `HqToken`.\n */\nexport type HqBrowserToken = HqToken;\n\n/** On-disk shape of `<dataDir>/auth.json`. */\nexport interface HqRuntimeFile {\n url: string;\n updatedAt: string;\n pid?: number;\n}\n\nexport interface HqAuthFile {\n version: typeof HQ_AUTH_FILE_VERSION;\n updatedAt: string;\n /**\n * Operator-configured redaction policy override. When present, the HQ\n * server applies these settings AFTER any publisher-declared policy \u2014\n * i.e. the operator can always tighten, never loosen.\n */\n redactionPolicy?: Partial<HqRedactionPolicy>;\n /** Browser tokens \u2014 validated on `/ws/browser` upgrades (Phase 3). */\n browserTokens?: HqToken[];\n /** Client tokens \u2014 validated on `/ws/client` upgrades (Phase 4). */\n clientTokens?: HqToken[];\n /** scrypt hash of the optional browser password login. */\n passwordHash?: string;\n /** Secret used to sign browser session cookies. */\n cookieSecret?: string;\n /**\n * Operator-configured alert-rule thresholds. When present, these override\n * the built-in defaults for the alert engine (cost ceiling, stale-machine\n * window, concurrency limit). Live-reloaded with the rest of the file.\n */\n alertRules?: HqAlertRuleConfig;\n}\n\n/** An empty auth file \u2014 what a brand-new HQ install starts with. */\nexport function emptyHqAuthFile(): HqAuthFile {\n return {\n version: HQ_AUTH_FILE_VERSION,\n updatedAt: new Date().toISOString(),\n };\n}\n\n/**\n * Sentinel value `hqAuthContentHash` substitutes for every raw secret\n * (`HqToken.token`, `HqAuthFile.passwordHash`, `HqAuthFile.cookieSecret`)\n * before hashing. Exported so downstream consumers of the audit log can\n * recognize the redaction shape without hardcoding the literal \u2014 e.g. a\n * forensic tool that re-derives a `contentHash` from a known on-disk\n * `auth.json` can substitute this same sentinel and compare.\n */\nexport const HQ_AUTH_CONTENT_HASH_REDACTED = '<redacted>';\n\n/**\n * Compute a SHA-256 content hash over a *redacted* projection of an\n * `HqAuthFile`. The projection replaces every raw token string, the\n * `passwordHash`, and the `cookieSecret` with constant sentinels, so:\n *\n * - the audit log never holds derivable token material (a hash of a\n * redacted projection can't be reversed to recover the originals),\n * - two files that differ only in their secrets hash identically\n * (reissuing a token without changing its id/label/expiry does not\n * change the hash), and\n * - the hash still flips whenever the structural state the operator\n * cares about (version, token ids/labels/capabilities/expiries,\n * alert rules, redaction policy) changes.\n *\n * Returns `undefined` when hashing or serialization throws (e.g. a\n * future schema addition that isn't JSON-serializable) \u2014 callers\n * should pass that through as an absent `contentHash` field rather\n * than failing the audit append, matching the audit module's\n * best-effort contract.\n */\nexport function hqAuthContentHash(file: HqAuthFile): string | undefined {\n const REDACTED = HQ_AUTH_CONTENT_HASH_REDACTED;\n const redactToken = (t: HqToken): HqToken => ({ ...t, token: REDACTED });\n try {\n // `exactOptionalPropertyTypes: true` means optional fields can't be\n // assigned `undefined` explicitly \u2014 preserve absence via conditional\n // spreads so the projection stays a valid `HqAuthFile`.\n const projection: HqAuthFile = {\n version: file.version,\n updatedAt: file.updatedAt,\n ...(file.redactionPolicy !== undefined ? { redactionPolicy: file.redactionPolicy } : {}),\n ...(file.browserTokens !== undefined\n ? { browserTokens: file.browserTokens.map(redactToken) }\n : {}),\n ...(file.clientTokens !== undefined\n ? { clientTokens: file.clientTokens.map(redactToken) }\n : {}),\n ...(file.passwordHash !== undefined ? { passwordHash: REDACTED } : {}),\n ...(file.cookieSecret !== undefined ? { cookieSecret: REDACTED } : {}),\n ...(file.alertRules !== undefined ? { alertRules: file.alertRules } : {}),\n };\n // Stable key ordering \u2014 the projection above has a fixed key order, so\n // the serialized form is deterministic across runs for the same\n // structural state.\n const payload = JSON.stringify(projection);\n return createHash('sha256').update(payload).digest('hex');\n } catch {\n return undefined;\n }\n}\n\n/** Path to `auth.json` under the given data directory. */\nexport function hqAuthFilePath(dataDir: string): string {\n return path.join(dataDir, 'auth.json');\n}\n\n/** Path to the best-effort runtime endpoint marker under the given data directory. */\nexport function hqRuntimeFilePath(dataDir: string): string {\n return path.join(dataDir, 'runtime.json');\n}\n\nexport async function writeHqRuntimeFile(dataDir: string, file: Omit<HqRuntimeFile, 'updatedAt'>): Promise<void> {\n const payload: HqRuntimeFile = {\n ...file,\n updatedAt: new Date().toISOString(),\n };\n await atomicWrite(hqRuntimeFilePath(dataDir), `${JSON.stringify(payload, null, 2)}\\n`, { mode: 0o600 });\n}\n\nfunction isProcessAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function readHqRuntimeFileSync(dataDir: string): HqRuntimeFile | undefined {\n try {\n const parsed = JSON.parse(syncFs.readFileSync(hqRuntimeFilePath(dataDir), 'utf8')) as Partial<HqRuntimeFile>;\n if (typeof parsed.url !== 'string' || parsed.url.trim().length === 0) return undefined;\n if (typeof parsed.pid === 'number' && !isProcessAlive(parsed.pid)) return undefined;\n return {\n url: parsed.url,\n updatedAt: typeof parsed.updatedAt === 'string' ? parsed.updatedAt : '',\n ...(typeof parsed.pid === 'number' ? { pid: parsed.pid } : {}),\n };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Read `auth.json` from disk. Returns `emptyHqAuthFile()` when the file does\n * NOT exist (ENOENT) \u2014 the only case treated as intentional open mode.\n *\n * Throws for all other read failures (EACCES, EIO, etc.), malformed JSON,\n * and unsupported schema versions. A corrupt or unreadable auth file must\n * never silently open the server.\n *\n * Callers that want to handle errors gracefully (e.g. the live-reload\n * watcher which should preserve the last-known-good state) should catch\n * the thrown error.\n */\nexport async function readHqAuthFile(\n dataDir: string,\n _opts: { warn?: (msg: string) => void } = {},\n): Promise<HqAuthFile> {\n const file = hqAuthFilePath(dataDir);\n let raw: string;\n try {\n raw = await fs.readFile(file, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return emptyHqAuthFile();\n // Non-ENOENT (EACCES, EIO, \u2026) \u2014 fail closed.\n throw new Error(\n `HQ auth file at ${file} cannot be read: ${(err as Error).message}. ` +\n 'Fix the file permissions or delete it to start with an empty auth state.',\n );\n }\n let parsed: HqAuthFile;\n try {\n parsed = JSON.parse(raw) as HqAuthFile;\n } catch (err) {\n throw new Error(\n `HQ auth file at ${file} is not valid JSON: ${(err as Error).message}. ` +\n 'Fix the file or delete it to start with an empty auth state.',\n );\n }\n if (parsed.version !== HQ_AUTH_FILE_VERSION) {\n throw new Error(\n `HQ auth file at ${file} has unsupported version ${String(parsed.version)} ` +\n `(expected ${String(HQ_AUTH_FILE_VERSION)}). ` +\n 'Remove or update the file to match the current schema version.',\n );\n }\n return parsed;\n}\n\n/**\n * Write `auth.json` atomically with mode 0o600. Creates the data directory\n * if needed. Throws on I/O failure \u2014 callers (CLI commands) should surface\n * the error to the operator.\n */\nexport async function writeHqAuthFile(dataDir: string, file: HqAuthFile): Promise<void> {\n const target = hqAuthFilePath(dataDir);\n const payload: HqAuthFile = {\n ...file,\n version: HQ_AUTH_FILE_VERSION,\n updatedAt: new Date().toISOString(),\n };\n await atomicWrite(target, `${JSON.stringify(payload, null, 2)}\\n`, { mode: 0o600 });\n}\n\nexport interface EnsureHqFirstRunAuthOptions {\n warn?: (msg: string) => void;\n /** Optional browser password login. Hashed with scrypt before storage. */\n password?: string;\n /**\n * Optional time-to-live (milliseconds) stamped on the first-run browser\n * and client tokens. When set, both tokens carry an `expiresAt` and the\n * HQ server will refuse them once it passes. Default: no expiry.\n *\n * Only affects tokens minted by THIS call (the first run). Tokens added\n * later via `wstack hq token create` choose their own TTL.\n */\n tokenTtlMs?: number | undefined;\n /**\n * Optional `actor` string recorded in `auth-audit.jsonl` for the two\n * `first-run` entries this function emits (one per minted token). The\n * CLI fills this with `user@host`; when omitted the entry carries no\n * `actor` field. Never contains the token string.\n */\n actor?: string | undefined;\n}\n\nexport interface EnsureHqFirstRunAuthResult {\n authFile: HqAuthFile;\n created: boolean;\n browserToken?: HqToken;\n clientToken?: HqToken;\n}\n\n/**\n * Ensure a brand-new HQ data directory has the auth required for safe\n * first-run operation. Only a missing auth.json is bootstrapped; an existing\n * file, including one with empty token arrays, is treated as operator intent.\n *\n * Caller surface: the sole production caller is `startHqServer` in\n * `packages/cli/src/hq-server.ts`, which threads `actor: resolveAuditActor()`\n * so both first-run audit entries carry `user@host`. Test callers live under\n * `packages/core/tests/hq/` (token-ttl, first-run-audit, auth-store). Any\n * new production caller MUST pass `actor` for the audit log to carry\n * forensic identity \u2014 see `EnsureHqFirstRunAuthOptions.actor`.\n */\nexport async function ensureHqFirstRunAuthFile(\n dataDir: string,\n opts: EnsureHqFirstRunAuthOptions = {},\n): Promise<EnsureHqFirstRunAuthResult> {\n const file = hqAuthFilePath(dataDir);\n try {\n await fs.access(file);\n const existing = await readHqAuthFile(dataDir, opts);\n if (opts.password) {\n const passwordUnchanged =\n existing.passwordHash !== undefined &&\n (await verifyHqPassword(opts.password, existing.passwordHash));\n if (!passwordUnchanged) {\n const authFile: HqAuthFile = {\n ...existing,\n passwordHash: await hashHqPassword(opts.password),\n // Rotating the cookie secret invalidates sessions created with the\n // previous password. This matters when --password is used to\n // recover or deliberately change an existing HQ installation.\n cookieSecret: mintHqCookieSecret(),\n };\n await writeHqAuthFile(dataDir, authFile);\n // Re-read so the hash reflects exactly what landed on disk \u2014\n // `writeHqAuthFile` re-stamps `updatedAt` internally, so hashing\n // the in-memory `authFile` would diverge from the persisted state\n // an operator can independently inspect.\n const persisted = await readHqAuthFile(dataDir, opts);\n const hash = hqAuthContentHash(persisted);\n const actorField = opts.actor ? { actor: opts.actor } : {};\n logHqAuthAudit(\n dataDir,\n {\n kind: 'password-rotate',\n scope: 'browser',\n tokenId: '(password-rotation)',\n ...(hash !== undefined ? { contentHash: hash } : {}),\n ...actorField,\n },\n {\n onError: (err) =>\n opts.warn?.(`HQ password-rotate audit write failed: ${(err as Error).message}`),\n },\n );\n return { authFile: persisted, created: false };\n }\n }\n return { authFile: existing, created: false };\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n opts.warn?.(`HQ auth file access failed at ${file}: ${(err as Error).message}`);\n return { authFile: await readHqAuthFile(dataDir, opts), created: false };\n }\n }\n\n // First-run credentials are deliberately least-privilege. Operators can\n // mint an execution-capable client token explicitly when remote command\n // execution is required; a freshly started HQ must never grant it by\n // accident.\n const browserToken = {\n ...mintHqToken({ label: 'first-run browser', ttlMs: opts.tokenTtlMs }),\n capabilities: ['control.enqueue'],\n };\n const clientToken = {\n ...mintHqToken({ label: 'first-run client', ttlMs: opts.tokenTtlMs }),\n capabilities: ['telemetry.publish'],\n };\n const authFile: HqAuthFile = {\n version: HQ_AUTH_FILE_VERSION,\n updatedAt: new Date().toISOString(),\n browserTokens: [browserToken],\n clientTokens: [clientToken],\n };\n if (opts.password) {\n authFile.passwordHash = await hashHqPassword(opts.password);\n authFile.cookieSecret = mintHqCookieSecret();\n }\n await writeHqAuthFile(dataDir, authFile);\n\n // Re-read so the audit hash + the returned `authFile` reflect exactly\n // what landed on disk. `writeHqAuthFile` re-stamps `updatedAt` (and\n // could normalize other fields in the future); hashing the in-memory\n // `authFile` would diverge from the persisted state an operator can\n // independently inspect, defeating the forensic-tie-back purpose.\n const persisted = await readHqAuthFile(dataDir, opts);\n\n // Record both first-run mints in auth-audit.jsonl. Best-effort: a failed\n // append must never roll back the fresh auth.json we just wrote. The two\n // entries use the same `kind: 'first-run'` discriminator the audit\n // schema reserves for this bootstrap path. Both carry the content hash of\n // the persisted file so an operator reviewing the log can tie them back\n // to the exact on-disk state without the log holding secrets.\n const hash = hqAuthContentHash(persisted);\n const hashField = hash !== undefined ? { contentHash: hash } : {};\n const actorField = opts.actor ? { actor: opts.actor } : {};\n for (const [scope, token] of [\n ['browser', browserToken],\n ['client', clientToken],\n ] as const) {\n logHqAuthAudit(\n dataDir,\n {\n kind: 'first-run',\n scope,\n tokenId: token.id,\n ...hashField,\n ...(token.label ? { label: token.label } : {}),\n capabilities: token.capabilities,\n ...(token.expiresAt ? { expiresAt: token.expiresAt } : {}),\n ...actorField,\n },\n {\n onError: (err) =>\n opts.warn?.(`HQ first-run audit write failed: ${(err as Error).message}`),\n },\n );\n }\n\n return { authFile: persisted, created: true, browserToken, clientToken };\n}\n\n/**\n * Load \u2192 mutate \u2192 write. The mutator receives the current file (or an empty\n * one) and returns the next file. Use this for any read-modify-write cycle\n * to avoid clobbering concurrent edits from another CLI invocation.\n *\n * Note: this does NOT take a file lock. HQ auth edits are rare (operator\n * running `wstack --hq-token add` etc.) and the atomic rename protects\n * against torn writes; a race between two concurrent edits would be\n * last-write-wins, which is acceptable for this low-frequency file.\n */\nexport async function mutateHqAuthFile(\n dataDir: string,\n mutator: (current: HqAuthFile) => HqAuthFile | Promise<HqAuthFile>,\n opts: { warn?: (msg: string) => void } = {},\n): Promise<HqAuthFile> {\n const current = await readHqAuthFile(dataDir, opts);\n const next = await mutator(current);\n await writeHqAuthFile(dataDir, next);\n return next;\n}\n\nconst HQ_PASSWORD_SALT_BYTES = 16;\nconst HQ_PASSWORD_HASH_BYTES = 32;\nconst HQ_PASSWORD_SCRYPT_PARAMS = { N: 16384, r: 8, p: 1 };\n\n/**\n * Hash a browser password for storage in `auth.json`. Uses scrypt with a\n * random salt; the returned string is `scrypt$<salt>$<hash>` in base64url.\n */\nexport function hashHqPassword(password: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const salt = randomBytes(HQ_PASSWORD_SALT_BYTES);\n scrypt(password, salt, HQ_PASSWORD_HASH_BYTES, HQ_PASSWORD_SCRYPT_PARAMS, (err, derivedKey) => {\n if (err) return reject(err);\n const payload = `scrypt$${salt.toString('base64url')}$${derivedKey.toString('base64url')}`;\n resolve(payload);\n });\n });\n}\n\n/**\n * Verify a browser password against a stored scrypt hash.\n */\nexport async function verifyHqPassword(password: string, hash: string): Promise<boolean> {\n const parts = hash.split('$');\n if (parts.length !== 3 || parts[0] !== 'scrypt' || !parts[1] || !parts[2]) return false;\n let salt: Buffer;\n let expected: Buffer;\n try {\n salt = Buffer.from(parts[1], 'base64url');\n expected = Buffer.from(parts[2], 'base64url');\n } catch {\n return false;\n }\n if (salt.length === 0 || expected.length === 0) return false;\n const derived = await new Promise<Buffer>((resolve, reject) => {\n scrypt(password, salt, expected.length, HQ_PASSWORD_SCRYPT_PARAMS, (err, key) => {\n if (err) reject(err);\n else resolve(key);\n });\n });\n return timingSafeEqual(derived, expected);\n}\n\n/** Mint a secret used to sign browser session cookies. */\nexport function mintHqCookieSecret(): string {\n return randomBytes(32).toString('base64url');\n}\n\n/**\n * Options for {@link mintHqToken}.\n *\n * - `label` \u2014 human-readable identifier persisted alongside the token.\n * - `ttlMs` \u2014 when set, the token is stamped with `expiresAt = now + ttlMs`.\n * Absent (the default) means the token never expires, preserving the\n * pre-TTL contract.\n * - `now` \u2014 epoch milliseconds override for deterministic tests.\n */\nexport interface MintHqTokenOptions {\n label?: string | undefined;\n ttlMs?: number | undefined;\n now?: number | undefined;\n}\n\n/**\n * Mint a fresh token. Used for both browser and client tokens; the caller\n * decides which list to append to.\n *\n * Pass an options object to stamp an `expiresAt`; the bare-string overload\n * (`mintHqToken('my-label')`) is preserved for backward-compat.\n */\nexport function mintHqToken(labelOrOptions?: string | MintHqTokenOptions): HqToken {\n const opts: MintHqTokenOptions =\n typeof labelOrOptions === 'string' ? { label: labelOrOptions } : (labelOrOptions ?? {});\n const at = opts.now ?? Date.now();\n const createdAtIso = new Date(at).toISOString();\n return {\n id: randomUUID(),\n token: randomUUID().replace(/-/g, '') + randomUUID().replace(/-/g, ''),\n createdAt: createdAtIso,\n ...(opts.label ? { label: opts.label } : {}),\n ...(opts.ttlMs !== undefined && Number.isFinite(opts.ttlMs) && opts.ttlMs > 0\n ? { expiresAt: new Date(at + opts.ttlMs).toISOString() }\n : {}),\n };\n}\n\n/**\n * Backward-compat alias for `mintHqToken`. Phase 3 callers/tests use this.\n */\nexport const mintHqBrowserToken = mintHqToken;\n\n/**\n * Watch `auth.json` for changes and invoke `onChange` with the freshly-read\n * file. Returns a `close()` function that stops watching.\n *\n * The watcher debounces events (default 200ms) because most editors do a\n * tmp+rename dance that emits multiple events. On any read failure (file\n * deleted, corrupt, etc.) the `warn` callback is invoked with the same\n * semantics as `readHqAuthFile`; the watcher stays active so a future\n * valid write re-triggers the callback.\n *\n * Notes:\n * - `fs.watch` is best-effort across platforms. On some network\n * filesystems events may not fire; the operator must restart the server\n * to pick up changes in that case.\n * - The watcher polls the parent directory (not the file itself) so that\n * atomic rename events surface reliably.\n */\nexport function watchHqAuthFile(\n dataDir: string,\n onChange: (file: HqAuthFile) => void,\n opts: { warn?: (msg: string) => void; debounceMs?: number } = {},\n): { close: () => void } {\n const file = hqAuthFilePath(dataDir);\n const debounceMs = opts.debounceMs ?? 200;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let closed = false;\n\n let watcher: syncFs.FSWatcher;\n try {\n // Watch the directory (not the file) so atomic-rename events surface\n // reliably. `fs.watch` is best-effort across platforms \u2014 on some\n // network filesystems events may not fire; the operator must restart\n // the server in that case.\n watcher = syncFs.watch(path.dirname(file), { recursive: false });\n } catch (err) {\n opts.warn?.(`HQ auth watcher could not start: ${(err as Error).message}`);\n return { close: () => {} };\n }\n\n const trigger = (): void => {\n if (closed) return;\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = undefined;\n const readOpts = opts.warn ? { warn: opts.warn } : {};\n void readHqAuthFile(dataDir, readOpts).then(\n (next) => {\n if (!closed) onChange(next);\n },\n () => {\n // readHqAuthFile never throws for routine I/O \u2014 this is a\n // belt-and-braces guard.\n },\n );\n }, debounceMs);\n };\n\n // Without a listener an FSWatcher 'error' event is an uncaught exception\n // (Windows emits transient EPERMs on dir churn). Degrade to \"no watcher\" \u2014\n // same as the creation-failure path above.\n watcher.on('error', (err: Error) => {\n opts.warn?.(`HQ auth watcher error: ${err.message}`);\n try {\n watcher.close();\n } catch {\n /* already closed */\n }\n });\n\n watcher.on('change', (eventType: string, filename: string | Buffer | null) => {\n const name = typeof filename === 'string' ? filename : '';\n // Only react to events that touch auth.json (rename, change).\n if (eventType === 'rename' || eventType === 'change') {\n if (!name || name === 'auth.json' || name === path.basename(file)) {\n trigger();\n }\n }\n });\n\n watcher.on('error', (err: Error) => {\n opts.warn?.(`HQ auth watcher error: ${err.message}`);\n });\n\n return {\n close: () => {\n closed = true;\n if (timer) clearTimeout(timer);\n watcher.close();\n },\n };\n}\n", "import { randomUUID } from 'node:crypto';\nimport * as v8 from 'node:v8';\nimport type { Mailbox, MailboxAgentStatus, MailboxMessage } from '../coordination/mailbox-types.js';\nimport type { Logger } from '../types/logger.js';\nimport {\n createMailboxEventPayload,\n createMailboxSnapshotPayloadFromMailbox,\n type HqMailboxEventAction,\n type HqMailboxSnapshotOptions,\n} from './mailbox-mapper.js';\nimport {\n createHqEventEnvelope,\n HQ_PROTOCOL_VERSION,\n HQ_TRANSCRIPT_TEXT_CAP,\n type HqClientCapability,\n type HqClientCommandAckMessage,\n type HqClientCommandPollMessage,\n type HqClientEventMessage,\n type HqClientHelloMessage,\n type HqClientIdentity,\n type HqEventEnvelope,\n type HqEventType,\n type HqFleetSnapshotPayload,\n type HqKanbanSnapshotPayload,\n type HqMailboxEventPayload,\n type HqMailboxSnapshotPayload,\n type HqProjectIdentity,\n type HqQueuedCommand,\n type HqRedactionPolicy,\n type HqServerCommandBatchMessage,\n type HqServerKanbanSnapshotMessage,\n type HqSessionEndedPayload,\n type HqSessionSnapshotPayload,\n type HqTranscriptAppendPayload,\n} from './protocol.js';\nimport { redactHqEvent, resolveHqRedactionPolicy } from './redaction.js';\n\nexport interface HqSocketLike {\n readyState: number;\n send(data: string): void;\n close(code?: number, reason?: string): void;\n addEventListener?(\n type: 'open' | 'close' | 'error' | 'message',\n listener: (event: unknown) => void,\n ): void;\n removeEventListener?(\n type: 'open' | 'close' | 'error' | 'message',\n listener: (event: unknown) => void,\n ): void;\n on?(type: 'open' | 'close' | 'error' | 'message', listener: (event: unknown) => void): void;\n off?(type: 'open' | 'close' | 'error' | 'message', listener: (event: unknown) => void): void;\n}\n\nexport type HqSocketFactory = (url: string, init: { token?: string }) => HqSocketLike;\n\nexport interface HqPublisherCommandResult {\n commandId: string;\n status: 'accepted' | 'completed' | 'failed' | 'rejected';\n message?: string;\n}\n\nexport type HqPublisherCommandHandler = (\n command: HqQueuedCommand,\n) => void | HqPublisherCommandResult | Promise<void | HqPublisherCommandResult>;\n\nexport interface HqPublisherOptions {\n url: string;\n token?: string;\n client: HqClientIdentity;\n project: HqProjectIdentity;\n capabilities?: readonly HqClientCapability[];\n socketFactory?: HqSocketFactory;\n now?: () => string;\n idFactory?: () => string;\n reconnect?: boolean;\n reconnectBaseMs?: number;\n reconnectMaxMs?: number;\n maxQueuedMessages?: number;\n /** Hard byte cap on the outbound queue (prevents RAM blow-up when HQ is\n * offline). Older frames are dropped oldest-first when exceeded. The default\n * is heap-relative: `min(16 MiB, heap_limit * 0.10)` \u2014 see `DEFAULT_MAX_QUEUED_BYTES`. */\n maxQueuedBytes?: number;\n redactionPolicy?: Partial<HqRedactionPolicy>;\n commandPollIntervalMs?: number;\n commandPollLimit?: number;\n onCommand?: HqPublisherCommandHandler;\n /** Called whenever HQ sends the merged Kanban state for this project. */\n onKanbanSnapshot?: (snapshot: HqKanbanSnapshotPayload) => void | Promise<void>;\n /**\n * Local auto-discovery hook: re-resolve the HQ endpoint before EVERY\n * connect attempt (e.g. by reading `<hq dataDir>/runtime.json`). Returning\n * `undefined` means no HQ is currently discoverable \u2014 the publisher stays\n * dormant (events keep queueing, bounded) and re-checks every\n * {@link HqPublisherOptions.discoveryPollMs}. Because the endpoint is\n * re-resolved per attempt, an HQ started AFTER this client \u2014 or restarted\n * on a different port, or one that minted its first client token on boot \u2014\n * is picked up automatically.\n */\n resolveEndpoint?: () => { url: string; token?: string | undefined } | undefined;\n /** Dormant re-check interval while `resolveEndpoint` yields nothing. Default 5s. */\n discoveryPollMs?: number;\n /**\n * Application-level heartbeat interval for the `/ws/client` connection.\n * The HQ server evicts silent sockets, so this must be comfortably below\n * the server-side client TTL even when no command handler is installed.\n */\n heartbeatIntervalMs?: number;\n /**\n * Diagnostic sink for the one-time consecutive-connect-failure warning.\n * The publisher is otherwise deliberately silent (dormant queueing), which\n * made auth failures invisible: a token the server rejects \u2014 e.g. a wrong\n * `WRONGSTACK_HQ_TOKEN` against a remote HQ \u2014 looked exactly like \"HQ not\n * running\". Defaults to a single structured `console.warn` line.\n */\n warn?: (message: string) => void;\n /** Logger for structured events. When provided, the `warn` callback is derived from it. */\n logger?: Logger | undefined;\n}\n\nexport interface HqPublishEventOptions {\n type: HqEventType | (string & {});\n payload: unknown;\n sessionId?: string;\n runId?: string;\n timestamp?: string;\n /**\n * Per-string redaction cap override. Defaults to the generic 500-char\n * summary cap; chat-transcript event types (`session.transcript`,\n * `agent.message`) automatically get {@link HQ_TRANSCRIPT_TEXT_CAP} so\n * full chat history survives when `rawContent` is enabled.\n */\n maxSummaryLength?: number;\n}\n\n/** Event types that carry full chat turns rather than telemetry summaries. */\nconst TRANSCRIPT_EVENT_TYPES = new Set<string>(['session.transcript', 'agent.message']);\n\nconst OPEN_STATE = 1;\n/**\n * After this many consecutive failed connects (never reaching `open`), emit\n * ONE diagnostic warning. The WS handshake gives the browser-style socket no\n * HTTP status, so a 401 (token mismatch) is indistinguishable from a dead\n * server at this layer \u2014 the warning names both possibilities.\n */\nconst CONNECT_WARN_AFTER_FAILURES = 5;\nconst DEFAULT_RECONNECT_BASE_MS = 1_000;\nconst DEFAULT_RECONNECT_MAX_MS = 30_000;\nconst DEFAULT_DISCOVERY_POLL_MS = 5_000;\nconst DEFAULT_MAX_QUEUED_MESSAGES = 2000;\n/**\n * Hard byte cap on the enqueue to prevent unbounded RAM growth when HQ is offline.\n *\n * Heap-relative: `min(16 MiB, heap_limit * 0.10)`. The lower bound keeps the cap\n * small in typical V8 configurations (e.g. ~512 MiB limit \u2192 16 MiB cap), while\n * the upper bound prevents the cap from exceeding 10 % of the V8 heap limit in\n * small-container or `--max-old-space-size` scenarios. Operators can override\n * via the `maxQueuedBytes` option \u2014 the override takes precedence over this\n * default and is the right escape hatch for long offline periods.\n */\nconst DEFAULT_MAX_QUEUED_BYTES = Math.min(\n 16 * 1024 * 1024,\n Math.floor(v8.getHeapStatistics().heap_size_limit * 0.1),\n);\n// Commands originate from an interactive operator console. Keep delivery\n// close to WebSocket-real-time while retaining the existing bounded poll\n// protocol (which also provides replay after a brief disconnect).\nconst DEFAULT_COMMAND_POLL_INTERVAL_MS = 500;\nconst DEFAULT_COMMAND_POLL_LIMIT = 25;\nconst DEFAULT_HEARTBEAT_INTERVAL_MS = 25_000;\n\ninterface QueuedFrame {\n serialized: string;\n bytes: number;\n /**\n * State snapshots are rollups: while offline, only the newest snapshot for\n * a scope has value. Event/transcript frames intentionally have no key and\n * retain FIFO semantics.\n */\n coalesceKey?: string | undefined;\n}\n\nfunction queuedFrameCoalesceKey(\n frame:\n | HqClientHelloMessage\n | HqClientEventMessage\n | HqClientCommandPollMessage\n | HqClientCommandAckMessage,\n): string | undefined {\n if (frame.type !== 'client.event' || !frame.event.type.endsWith('.snapshot')) {\n return undefined;\n }\n return [frame.event.type, frame.event.sessionId ?? '', frame.event.runId ?? ''].join('|');\n}\n\nfunction defaultSocketFactory(url: string): HqSocketLike {\n const WebSocketCtor = globalThis.WebSocket;\n if (WebSocketCtor === undefined) {\n throw new Error(\n 'No global WebSocket implementation is available; provide HqPublisherOptions.socketFactory.',\n );\n }\n return new WebSocketCtor(url) as HqSocketLike;\n}\n\nfunction toClientUrl(baseUrl: string, token: string | undefined): string {\n const url = new URL(baseUrl);\n url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';\n if (url.pathname === '/' || url.pathname === '') url.pathname = '/ws/client';\n if (token !== undefined && token.length > 0) url.searchParams.set('token', token);\n return url.toString();\n}\n\nfunction addSocketListener(\n socket: HqSocketLike,\n type: 'open' | 'close' | 'error' | 'message',\n listener: (event: unknown) => void,\n): void {\n if (socket.addEventListener !== undefined) {\n socket.addEventListener(type, listener);\n return;\n }\n socket.on?.(type, listener);\n}\n\nfunction removeSocketListener(\n socket: HqSocketLike,\n type: 'open' | 'close' | 'error' | 'message',\n listener: (event: unknown) => void,\n): void {\n if (socket.removeEventListener !== undefined) {\n socket.removeEventListener(type, listener);\n return;\n }\n socket.off?.(type, listener);\n}\n\nexport class HqPublisher {\n private readonly socketFactory: HqSocketFactory;\n private readonly now: () => string;\n private readonly idFactory: () => string;\n private readonly capabilities: readonly HqClientCapability[];\n private readonly reconnect: boolean;\n private readonly reconnectBaseMs: number;\n private readonly reconnectMaxMs: number;\n private readonly maxQueuedMessages: number;\n private readonly maxQueuedBytes: number;\n private readonly resolvedRedactionPolicy: HqRedactionPolicy;\n private readonly logger: Logger | undefined;\n private socket: HqSocketLike | null = null;\n private seq = 0;\n private queue: QueuedFrame[] = [];\n private queueBytes = 0;\n /**\n * Cumulative count of frames dropped by the bounded outbound queue when the\n * count/byte cap is exceeded while HQ is unreachable. Lifetime statistic \u2014\n * intentionally NOT reset on close()/reconnect, so it reflects total\n * telemetry loss to overflow for this publisher instance.\n */\n private droppedFrames = 0;\n /** Cumulative UTF-8 bytes of frames dropped on overflow (see droppedFrames). */\n private droppedBytes = 0;\n /** Obsolete state snapshots replaced in-place while HQ was unreachable. */\n private coalescedFrames = 0;\n /** UTF-8 bytes released by snapshot coalescing. */\n private coalescedBytes = 0;\n private stopped = false;\n private reconnectAttempt = 0;\n private connectWarningEmitted = false;\n private lastAttempt: { url: string; hadToken: boolean } | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private commandPollTimer: ReturnType<typeof setInterval> | null = null;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private lastCommandId: string | undefined;\n\n constructor(private readonly options: HqPublisherOptions) {\n this.socketFactory = options.socketFactory ?? defaultSocketFactory;\n this.now = options.now ?? (() => new Date().toISOString());\n this.idFactory = options.idFactory ?? randomUUID;\n this.capabilities = options.capabilities ?? [\n 'telemetry.publish',\n 'mailbox.summary',\n 'fleet.summary',\n 'session.summary',\n ];\n this.reconnect = options.reconnect ?? true;\n this.reconnectBaseMs = options.reconnectBaseMs ?? DEFAULT_RECONNECT_BASE_MS;\n this.reconnectMaxMs = options.reconnectMaxMs ?? DEFAULT_RECONNECT_MAX_MS;\n this.maxQueuedMessages = options.maxQueuedMessages ?? DEFAULT_MAX_QUEUED_MESSAGES;\n this.maxQueuedBytes = options.maxQueuedBytes ?? DEFAULT_MAX_QUEUED_BYTES;\n this.resolvedRedactionPolicy = resolveHqRedactionPolicy(options.redactionPolicy);\n this.logger = options.logger;\n }\n\n connect(): void {\n if (this.socket !== null || this.stopped) return;\n // A retry / discovery poll is already scheduled \u2014 let it fire instead of\n // dialing (and re-resolving the endpoint) on every publish while offline.\n if (this.reconnectTimer !== null) return;\n\n let url = this.options.url;\n let token = this.options.token;\n if (this.options.resolveEndpoint !== undefined) {\n const endpoint = this.options.resolveEndpoint();\n if (endpoint === undefined) {\n this.scheduleDiscoveryPoll();\n return;\n }\n url = endpoint.url;\n token = endpoint.token ?? token;\n }\n this.lastAttempt = { url, hadToken: token !== undefined };\n\n let socket: HqSocketLike;\n try {\n socket = this.socketFactory(toClientUrl(url, token), {\n ...(token !== undefined ? { token } : {}),\n });\n } catch {\n this.scheduleReconnect();\n return;\n }\n this.socket = socket;\n\n const onOpen = () => {\n this.reconnectAttempt = 0;\n this.sendHelloNow();\n this.flushQueue();\n this.startHeartbeat();\n if (this.options.onCommand !== undefined) {\n this.startCommandPolling();\n this.pollCommands();\n }\n };\n const onMessage = (event: unknown) => {\n // HQ traffic is best-effort telemetry: a failed message (e.g. transient\n // Windows EPERM while a kanban board is being renamed under a reader)\n // must degrade to a warning, never an unhandled rejection that kills\n // the host process.\n this.handleServerMessage(event).catch((error: unknown) => {\n const message = `WrongStack HQ publisher: server message handling failed: ${\n error instanceof Error ? error.message : String(error)\n }`;\n if (this.logger) {\n this.logger.warn(message, { event: 'hq.publisher.message_failed' });\n return;\n }\n process.emitWarning(message, { code: 'WRONGSTACK_HQ_MESSAGE_FAILED' });\n });\n };\n const onCloseOrError = () => {\n removeSocketListener(socket, 'open', onOpen);\n removeSocketListener(socket, 'message', onMessage);\n removeSocketListener(socket, 'close', onCloseOrError);\n removeSocketListener(socket, 'error', onCloseOrError);\n this.stopCommandPolling();\n this.stopHeartbeat();\n if (this.socket === socket) this.socket = null;\n this.scheduleReconnect();\n };\n\n addSocketListener(socket, 'open', onOpen);\n addSocketListener(socket, 'message', onMessage);\n addSocketListener(socket, 'close', onCloseOrError);\n addSocketListener(socket, 'error', onCloseOrError);\n\n if (socket.readyState === OPEN_STATE) onOpen();\n }\n\n close(): void {\n this.stopped = true;\n if (this.reconnectTimer !== null) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n this.stopCommandPolling();\n this.stopHeartbeat();\n this.queue = [];\n this.queueBytes = 0;\n const socket = this.socket;\n this.socket = null;\n socket?.close(1000, 'hq publisher closed');\n }\n\n publishEvent<TPayload>(\n options: HqPublishEventOptions & { payload: TPayload },\n ): HqEventEnvelope<TPayload> {\n const event = createHqEventEnvelope({\n id: this.idFactory(),\n type: options.type,\n timestamp: options.timestamp ?? this.now(),\n clientId: this.options.client.clientId,\n projectId: this.options.project.projectId,\n seq: ++this.seq,\n payload: options.payload,\n ...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),\n ...(options.runId !== undefined ? { runId: options.runId } : {}),\n });\n const maxSummaryLength =\n options.maxSummaryLength ??\n (TRANSCRIPT_EVENT_TYPES.has(options.type) ? HQ_TRANSCRIPT_TEXT_CAP : undefined);\n const redacted = redactHqEvent(event, {\n policy: this.resolvedRedactionPolicy,\n projectRoot: this.options.project.projectRoot,\n ...(maxSummaryLength !== undefined ? { maxSummaryLength } : {}),\n }).value;\n this.sendFrame({ type: 'client.event', event: redacted });\n return redacted;\n }\n\n async publishMailboxSnapshot(\n mailbox: Pick<Mailbox, 'query' | 'getAgentStatuses'>,\n options: Omit<HqMailboxSnapshotOptions, 'redactionPolicy'> & {\n sessionId?: string;\n timestamp?: string;\n },\n ): Promise<HqEventEnvelope<HqMailboxSnapshotPayload>> {\n const payload = await createMailboxSnapshotPayloadFromMailbox(mailbox, {\n ...options,\n redactionPolicy: this.resolvedRedactionPolicy,\n });\n return this.publishEvent({\n type: 'mailbox.snapshot',\n payload,\n ...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),\n ...(options.timestamp !== undefined ? { timestamp: options.timestamp } : {}),\n });\n }\n\n publishMailboxEvent(input: {\n mailboxId: string;\n action: HqMailboxEventAction;\n message?: MailboxMessage;\n agent?: MailboxAgentStatus;\n summary?: string;\n previewLength?: number;\n sessionId?: string;\n timestamp?: string;\n }): HqEventEnvelope<HqMailboxEventPayload> {\n const payload = createMailboxEventPayload({\n mailboxId: input.mailboxId,\n action: input.action,\n ...(input.message !== undefined ? { message: input.message } : {}),\n ...(input.agent !== undefined ? { agent: input.agent } : {}),\n ...(input.summary !== undefined ? { summary: input.summary } : {}),\n ...(input.previewLength !== undefined ? { previewLength: input.previewLength } : {}),\n redactionPolicy: this.resolvedRedactionPolicy,\n });\n return this.publishEvent({\n type: 'mailbox.event',\n payload,\n ...(input.sessionId !== undefined ? { sessionId: input.sessionId } : {}),\n ...(input.timestamp !== undefined ? { timestamp: input.timestamp } : {}),\n });\n }\n\n /** The client identity this publisher announced (clientId, kind, machineId, \u2026). */\n get identity(): HqClientIdentity {\n return this.options.client;\n }\n\n /** The project identity this publisher is bound to. */\n get project(): HqProjectIdentity {\n return this.options.project;\n }\n\n /** Effective publisher-side policy applied before any event leaves this process. */\n get redactionPolicy(): HqRedactionPolicy {\n return this.resolvedRedactionPolicy;\n }\n\n /** Current outbound queue pressure \u2014 useful for flow control in telemetry bridges. */\n getQueueStats(): {\n entries: number;\n bytes: number;\n maxBytes: number;\n droppedFrames: number;\n droppedBytes: number;\n coalescedFrames: number;\n coalescedBytes: number;\n } {\n return {\n entries: this.queue.length,\n bytes: this.queueBytes,\n maxBytes: this.maxQueuedBytes,\n droppedFrames: this.droppedFrames,\n droppedBytes: this.droppedBytes,\n coalescedFrames: this.coalescedFrames,\n coalescedBytes: this.coalescedBytes,\n };\n }\n\n /** Publish a live session/terminal snapshot (state + agents). */\n publishSessionSnapshot(\n payload: HqSessionSnapshotPayload,\n opts?: { timestamp?: string },\n ): HqEventEnvelope<HqSessionSnapshotPayload> {\n return this.publishEvent({\n type: 'session.snapshot',\n payload,\n sessionId: payload.sessionId,\n ...(opts?.timestamp !== undefined ? { timestamp: opts.timestamp } : {}),\n });\n }\n\n /** Publish an incremental batch of transcript turns for a session. */\n publishTranscriptAppend(\n payload: HqTranscriptAppendPayload,\n opts?: { timestamp?: string },\n ): HqEventEnvelope<HqTranscriptAppendPayload> {\n return this.publishEvent({\n type: 'session.transcript',\n payload,\n sessionId: payload.sessionId,\n ...(opts?.timestamp !== undefined ? { timestamp: opts.timestamp } : {}),\n });\n }\n\n /** Mark a session/terminal as ended. */\n publishSessionEnded(\n payload: HqSessionEndedPayload,\n opts?: { timestamp?: string },\n ): HqEventEnvelope<HqSessionEndedPayload> {\n return this.publishEvent({\n type: 'session.ended',\n payload,\n sessionId: payload.sessionId,\n ...(opts?.timestamp !== undefined ? { timestamp: opts.timestamp } : {}),\n });\n }\n\n /** Publish a fleet (multi-agent coordinator) snapshot. */\n publishFleetSnapshot(\n payload: HqFleetSnapshotPayload,\n opts?: { sessionId?: string; timestamp?: string },\n ): HqEventEnvelope<HqFleetSnapshotPayload> {\n return this.publishEvent({\n type: 'fleet.snapshot',\n payload,\n runId: payload.runId,\n ...(opts?.sessionId !== undefined ? { sessionId: opts.sessionId } : {}),\n ...(opts?.timestamp !== undefined ? { timestamp: opts.timestamp } : {}),\n });\n }\n\n pollCommands(): void {\n this.sendFrame({\n type: 'client.command_poll',\n clientId: this.options.client.clientId,\n projectId: this.options.project.projectId,\n ...(this.lastCommandId !== undefined ? { afterCommandId: this.lastCommandId } : {}),\n limit: this.options.commandPollLimit ?? DEFAULT_COMMAND_POLL_LIMIT,\n });\n }\n\n ackCommand(result: HqPublisherCommandResult): void {\n this.sendFrame({\n type: 'client.command_ack',\n clientId: this.options.client.clientId,\n projectId: this.options.project.projectId,\n commandId: result.commandId,\n status: result.status,\n ...(result.message !== undefined ? { message: result.message } : {}),\n });\n }\n\n private createHelloFrame(): HqClientHelloMessage {\n return {\n type: 'client.hello',\n payload: {\n protocolVersion: HQ_PROTOCOL_VERSION,\n client: this.options.client,\n project: this.options.project,\n capabilities: this.capabilities,\n redactionPolicy: this.resolvedRedactionPolicy,\n },\n };\n }\n\n private sendHelloNow(): void {\n const socket = this.socket;\n if (socket?.readyState !== OPEN_STATE) {\n this.sendFrame(this.createHelloFrame());\n return;\n }\n socket.send(JSON.stringify(this.createHelloFrame()));\n }\n\n private sendFrame(\n frame:\n | HqClientHelloMessage\n | HqClientEventMessage\n | HqClientCommandPollMessage\n | HqClientCommandAckMessage,\n ): void {\n const serialized = JSON.stringify(frame);\n const socket = this.socket;\n // Fast path: socket is open and nothing queued \u2014 send immediately.\n if (socket?.readyState === OPEN_STATE && this.queue.length === 0) {\n socket.send(serialized);\n return;\n }\n // Slow path: socket offline or queue already has pending frames \u2014 enqueue.\n this.enqueue(serialized, queuedFrameCoalesceKey(frame));\n this.connect();\n }\n\n private enqueue(serialized: string, coalesceKey?: string): void {\n const bytes = Buffer.byteLength(serialized, 'utf8');\n // A single pathological snapshot must not bypass the total byte cap just\n // because the queue is empty. It is telemetry, so fail closed and let the\n // next (usually smaller) rollup supersede it.\n if (bytes > this.maxQueuedBytes) {\n this.droppedFrames += 1;\n this.droppedBytes += bytes;\n return;\n }\n\n if (coalesceKey !== undefined) {\n let existingIndex = -1;\n for (let index = this.queue.length - 1; index >= 0; index -= 1) {\n if (this.queue[index]?.coalesceKey === coalesceKey) {\n existingIndex = index;\n break;\n }\n }\n if (existingIndex !== -1) {\n const [obsolete] = this.queue.splice(existingIndex, 1);\n if (obsolete !== undefined) {\n this.queueBytes -= obsolete.bytes;\n this.coalescedFrames += 1;\n this.coalescedBytes += obsolete.bytes;\n }\n }\n }\n\n // Drop oldest frames when either the count cap or the byte cap is\n // exceeded. The byte cap prevents unbounded RAM growth during extended\n // HQ outages while the count cap limits per-frame overhead.\n while (\n (this.queue.length >= this.maxQueuedMessages ||\n this.queueBytes + bytes > this.maxQueuedBytes) &&\n this.queue.length > 0\n ) {\n const dropped = this.queue.shift();\n if (dropped !== undefined) {\n this.queueBytes -= dropped.bytes;\n this.droppedFrames += 1;\n this.droppedBytes += dropped.bytes;\n }\n }\n this.queue.push({ serialized, bytes, coalesceKey });\n this.queueBytes += bytes;\n }\n\n /** Batch-dequeue up to 50 frames at a time, yielding to the microtask\n * queue between batches so we don't starve the event loop on reconnect. */\n private flushQueue(): void {\n const socket = this.socket;\n if (socket?.readyState !== OPEN_STATE || this.queue.length === 0) return;\n const batch = this.queue.splice(0, 50);\n for (const frame of batch) {\n socket.send(frame.serialized);\n this.queueBytes -= frame.bytes;\n }\n this.queueBytes = Math.max(0, this.queueBytes);\n if (this.queue.length > 0) setImmediate(() => this.flushQueue());\n }\n\n private startCommandPolling(): void {\n if (this.options.onCommand === undefined || this.commandPollTimer !== null) return;\n this.commandPollTimer = setInterval(\n () => this.pollCommands(),\n this.options.commandPollIntervalMs ?? DEFAULT_COMMAND_POLL_INTERVAL_MS,\n );\n this.commandPollTimer.unref?.();\n }\n\n private stopCommandPolling(): void {\n if (this.commandPollTimer === null) return;\n clearInterval(this.commandPollTimer);\n this.commandPollTimer = null;\n }\n\n private startHeartbeat(): void {\n if (this.heartbeatTimer !== null) return;\n this.heartbeatTimer = setInterval(\n () => this.publishHeartbeat(),\n this.options.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS,\n );\n this.heartbeatTimer.unref?.();\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer === null) return;\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n\n private publishHeartbeat(): void {\n const startedAt = Date.parse(this.options.client.startedAt);\n const now = Date.parse(this.now());\n this.publishEvent({\n type: 'client.heartbeat',\n payload: {\n uptimeMs:\n Number.isFinite(startedAt) && Number.isFinite(now) ? Math.max(0, now - startedAt) : 0,\n status: 'idle',\n },\n });\n }\n\n private async handleServerMessage(event: unknown): Promise<void> {\n const message = this.parseServerMessage(event);\n if (message?.type === 'hq.command_batch') {\n await this.handleCommandBatch(message);\n return;\n }\n if (message?.type === 'hq.kanban_snapshot') {\n await this.options.onKanbanSnapshot?.(message.payload);\n }\n }\n\n private parseServerMessage(\n event: unknown,\n ): HqServerCommandBatchMessage | HqServerKanbanSnapshotMessage | null {\n const data = this.extractMessageData(event);\n if (data === null) return null;\n try {\n const parsed = JSON.parse(data) as\n | Partial<HqServerCommandBatchMessage>\n | Partial<HqServerKanbanSnapshotMessage>;\n if (parsed.type === 'hq.command_batch' && Array.isArray(parsed.commands)) {\n return parsed as HqServerCommandBatchMessage;\n }\n if (parsed.type === 'hq.kanban_snapshot') {\n const payload = (parsed as Partial<HqServerKanbanSnapshotMessage>).payload;\n if (\n payload !== undefined &&\n typeof payload === 'object' &&\n typeof payload.projectId === 'string' &&\n payload.projectId === this.options.project.projectId &&\n Array.isArray(payload.boards) &&\n Array.isArray(payload.tombstones)\n ) {\n return parsed as HqServerKanbanSnapshotMessage;\n }\n }\n return null;\n } catch {\n return null;\n }\n }\n\n private extractMessageData(event: unknown): string | null {\n const value =\n typeof event === 'object' && event !== null && 'data' in event\n ? (event as { data?: unknown }).data\n : event;\n if (typeof value === 'string') return value;\n if (value instanceof ArrayBuffer) return new TextDecoder().decode(value);\n if (ArrayBuffer.isView(value)) {\n const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n return new TextDecoder().decode(bytes);\n }\n return null;\n }\n\n private async handleCommandBatch(message: HqServerCommandBatchMessage): Promise<void> {\n const handler = this.options.onCommand;\n if (handler === undefined) return;\n\n for (const command of message.commands) {\n try {\n const result = await handler(command);\n if (result !== undefined) this.ackCommand(result);\n else if (command.requiresAck)\n this.ackCommand({ commandId: command.commandId, status: 'accepted' });\n } catch (err) {\n this.ackCommand({\n commandId: command.commandId,\n status: 'failed',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n // Advance the poll cursor only AFTER the command is handled and acked.\n // Advancing it before `await handler` meant a socket flap mid-handler\n // left the next command_poll asking for commands AFTER this one \u2014 so an\n // operator command (steer/abort/broadcast) that never ran was silently\n // skipped and never re-fetched. At-least-once (a possible duplicate on\n // reconnect, which these commands tolerate) beats losing one outright.\n this.lastCommandId = command.commandId;\n }\n }\n\n private scheduleReconnect(): void {\n if (this.stopped || !this.reconnect || this.reconnectTimer !== null) return;\n const delay = Math.min(this.reconnectMaxMs, this.reconnectBaseMs * 2 ** this.reconnectAttempt);\n this.reconnectAttempt += 1;\n // One-time visibility for persistent failures. `reconnectAttempt` resets\n // on every successful open, so reaching the threshold means the endpoint\n // has NEVER accepted us in this streak \u2014 dead server or rejected token.\n if (!this.connectWarningEmitted && this.reconnectAttempt >= CONNECT_WARN_AFTER_FAILURES) {\n this.connectWarningEmitted = true;\n this.emitConnectWarning();\n }\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, delay);\n this.reconnectTimer.unref?.();\n }\n\n private emitConnectWarning(): void {\n const attempt = this.lastAttempt;\n const message =\n `WrongStack HQ publisher: ${this.reconnectAttempt} consecutive connection failures` +\n `${attempt !== null ? ` to ${attempt.url} (client token ${attempt.hadToken ? 'present' : 'absent'})` : ''}. ` +\n 'Either the HQ server is unreachable or it rejected the token (401). ' +\n 'If HQ runs in client-token mode, verify WRONGSTACK_HQ_TOKEN / auth.json. Retries continue with backoff.';\n if (this.logger) {\n this.logger.warn(message, { event: 'hq.publisher.connect_failed' });\n return;\n }\n const warn =\n this.options.warn ??\n ((msg: string) =>\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'hq.publisher.connect_failed',\n message: msg,\n timestamp: this.now(),\n }),\n ));\n try {\n warn(message);\n } catch {\n /* diagnostics must never break publishing */\n }\n }\n\n /**\n * Dormant re-check while no HQ endpoint is discoverable. Uses a FIXED\n * interval (not the exponential reconnect backoff): the check is a cheap\n * local file read, and backing off would delay attaching to an HQ the\n * user just started \u2014 the whole point of auto-discovery.\n */\n private scheduleDiscoveryPoll(): void {\n if (this.stopped || !this.reconnect || this.reconnectTimer !== null) return;\n this.reconnectAttempt = 0;\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, this.options.discoveryPollMs ?? DEFAULT_DISCOVERY_POLL_MS);\n this.reconnectTimer.unref?.();\n }\n}\n", "import type { SecretScrubber } from '../types/secret-scrubber.js';\n\ninterface Pattern {\n type: string;\n regex: RegExp;\n}\n\nconst PATTERNS: Pattern[] = [\n // Anchored at the start where possible so partial matches inside larger\n // strings don't trigger false positives.\n {\n type: 'anthropic_key',\n regex: /(?<![A-Za-z0-9])sk-ant-api\\d+-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g,\n },\n { type: 'openai_key', regex: /(?<![A-Za-z0-9])sk-(?:proj-)?[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g },\n { type: 'github_pat', regex: /(?<![A-Za-z0-9])ghp_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g },\n { type: 'github_pat_v2', regex: /(?<![A-Za-z0-9])github_pat_[A-Za-z0-9_]{50,}(?![A-Za-z0-9])/g },\n { type: 'aws_access_key', regex: /(?<![A-Za-z0-9])AKIA[0-9A-Z]{16}(?![A-Za-z0-9])/g },\n { type: 'gcp_key', regex: /(?<![A-Za-z0-9])AIza[0-9A-Za-z_-]{35}(?![A-Za-z0-9])/g },\n { type: 'slack_token', regex: /(?<![A-Za-z0-9-])xox[abpos]-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g },\n {\n type: 'stripe_key',\n regex: /(?<![A-Za-z0-9])sk_(?:live|test)_[A-Za-z0-9]{24,}(?![A-Za-z0-9])/g,\n },\n {\n type: 'twilio_sid', regex: /(?<![A-Za-z0-9])AC[a-f0-9]{32}(?![A-Za-z0-9])/g,\n },\n {\n type: 'telegram_bot_token',\n // Telegram tokens are of the form bot<digits>:<alphanum> in URL paths\n regex: /\\/bot\\d+:[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,\n },\n {\n type: 'jwt',\n // Anchored: look for literal \"eyJ\" which is unambiguous for JWT header\n regex:\n /(?<![A-Za-z0-9/+=])eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}(?![A-Za-z0-9/+=])/g,\n },\n {\n type: 'private_key',\n // Anchored: start must be BEGIN, end must be END with no extra dashes after END\n regex:\n /(?:^|\\n)-----BEGIN (?:RSA|EC|OPENSSH|DSA|PGP)? ?PRIVATE KEY-----[\\s\\S]*?-----END[^-]*-----(?:\\n|$)/g,\n },\n { type: 'mongodb_uri', regex: /mongodb(?:\\+srv)?:\\/\\/[^\\s\"'`]+/g },\n { type: 'postgres_uri', regex: /postgres(?:ql)?:\\/\\/[^\\s\"'`]+/g },\n { type: 'mysql_uri', regex: /mysql:\\/\\/[^\\s\"'`]+/g },\n { type: 'redis_uri', regex: /redis:\\/\\/[^\\s\"'`]+/g },\n // AI/ML provider keys \u2014 modern LLM services with well-known prefixes\n {\n type: 'huggingface_token',\n // HuggingFace tokens: hf_ followed by 34 alphanumeric chars\n regex: /(?<![A-Za-z0-9])hf_[A-Za-z0-9]{34}(?![A-Za-z0-9])/g,\n },\n {\n type: 'replicate_token',\n // Replicate tokens: r8_ followed by 40+ alphanumeric chars\n regex: /(?<![A-Za-z0-9])r8_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,\n },\n {\n type: 'perplexity_key',\n // Perplexity API keys: pplx- followed by 40+ alphanumeric chars\n regex: /(?<![A-Za-z0-9])pplx-[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,\n },\n {\n type: 'groq_key',\n // Groq API keys: gsk_ followed by 40+ alphanumeric chars\n regex: /(?<![A-Za-z0-9])gsk_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,\n },\n {\n type: 'bearer_token',\n // Anchored with alternation instead of negative lookahead \u2014 avoids V8\n // backtracking risk on adversarial input. Bounded at 512 chars.\n // Min 12 chars: some OAuth providers issue shorter-lived tokens (< 20\n // chars). A 12-char base64 string has ~71 bits of entropy \u2014 above the\n // threshold where random strings are unlikely to produce false matches.\n // The trailing boundary is a NON-consuming lookahead: two adjacent bearer\n // tokens sharing a single delimiter (`Bearer a\u2026 Bearer b\u2026`) must both be\n // redacted. A consuming trailing delimiter would eat the separator the\n // next match needs for its leading anchor, leaking the second token.\n regex: /(?:^|[^A-Za-z0-9_.~+/-])Bearer\\s+[A-Za-z0-9._~+/-]{12,512}=*(?=$|[^A-Za-z0-9_.~+/-])/g,\n },\n {\n type: 'high_entropy_env',\n // Anchored with alternation instead of lookbehind to avoid backtracking.\n // Value bounded at 512 chars.\n // The trailing boundary is a NON-consuming lookahead so two secrets\n // separated by a single delimiter (one space OR one newline, e.g.\n // `printenv` / `.env` dumps: `API_KEY=\u2026 \\n SESSION_TOKEN=\u2026`) are BOTH\n // redacted. A consuming trailing `\\s` would swallow the separator the\n // next match needs for its leading anchor, so every other secret would\n // leak in plaintext.\n // The leading delimiter is CAPTURED (group 1) and re-emitted by the\n // replacement so the separator between adjacent secrets is preserved\n // rather than collapsed. Capture groups are therefore: 1=leading\n // delimiter, 2=key name, 3=value.\n regex: /(^|\\s)([A-Z_]{4,}(?:KEY|TOKEN|SECRET|PASSWORD|PWD))\\s*[:=]\\s*['\"]?([A-Za-z0-9_/+=-]{20,512})['\"]?(?=\\s|$)/g,\n },\n];\n\n/**\n * `high_entropy_env` is the one pattern that needs special replacement logic\n * (it preserves the key name), so it runs in its own pass. Every other pattern\n * is folded into a single combined regex. Derive the split by type rather than\n * by hard-coded indices so adding/removing a pattern can't silently drop one.\n */\nconst SIMPLE_PATTERNS = PATTERNS.filter((p) => p.type !== 'high_entropy_env');\n\n/**\n * Combined single-pass regex for all simple patterns. Each alternative is a\n * capturing group so the callback can determine which original pattern fired\n * (only one group is non-undefined at match time). Order matches SIMPLE_PATTERNS\n * (longer/more-specific prefixes first). Relies on each simple pattern source\n * containing no internal capturing groups \u2014 only `(?:...)` and lookarounds.\n */\nconst COMBINED_REGEX = new RegExp(SIMPLE_PATTERNS.map((p) => `(${p.regex.source})`).join('|'), 'g');\n\n/** Separate pattern for high_entropy_env (different replacement logic). */\nconst HIGH_ENTROPY_REGEX = PATTERNS.find((p) => p.type === 'high_entropy_env')!.regex;\n\n/**\n * Replacements for the combined patterns, parallel to SIMPLE_PATTERNS. The\n * combined-regex callback indexes into this with the matched group's position.\n */\nconst COMBINED_REPLACEMENTS = SIMPLE_PATTERNS.map((p) => `[REDACTED:${p.type}]`);\n\n/**\n * Per-chunk cap. Splits long inputs into 64 KB chunks to keep scrub() memory\n * bounded. Real scrub() inputs (LLM responses, tool outputs) are typically\n * much smaller; this cap handles edge cases without impacting normal usage.\n */\nconst SCRUB_CHUNK_BYTES = 64 * 1024;\n\n/**\n * Overlap window used to nudge a chunk boundary onto a safe separator so a\n * secret straddling the 64 KB cut isn't split in half (which would leave\n * neither half matching, leaking the secret verbatim).\n *\n * Sized above the longest BOUNDED credential pattern: `high_entropy_env`\n * caps its value at 512 chars (+ key name + quotes \u2248 560) and `bearer_token`\n * at 512; every prefix-keyed pattern is far shorter. Because all of these\n * patterns are whitespace-free, the first whitespace at/after the nominal cut\n * is guaranteed to sit *past the end* of any such secret \u2014 so snapping the\n * boundary forward to it keeps every bounded secret wholly inside one chunk.\n * 1 KB gives comfortable headroom over the 560-char worst case.\n */\nconst SCRUB_OVERLAP_BYTES = 1024;\n\n/**\n * Quick pre-scan: check if the text contains any substring that MUST be\n * present for a credential pattern to match. If none are found, the text\n * is guaranteed clean \u2014 skip all regex passes (2 total: 16-pattern combined + high_entropy_env).\n *\n * Each anchor is the shortest unique substring from the corresponding pattern.\n * V8's `String.includes()` is hand-tuned C++ \u2014 O(n) with near-zero overhead\n * for typical tool-output lengths (100\u20135000 chars). A single combined regex\n * via `text.search()` is consistently slower for this many alternatives.\n */\nfunction hasCredentialAnchors(text: string): boolean {\n return (\n text.includes('-----BEGIN') || // Private keys (most unique \u2192 cheap reject)\n text.includes('sk-') || // Anthropic + OpenAI keys\n text.includes('sk_') || // Stripe live/test keys\n text.includes('ghp_') || // GitHub PAT v1\n text.includes('github_pat_') || // GitHub PAT v2\n text.includes('eyJ') || // JWT\n text.includes('AKIA') || // AWS access key\n text.includes('AIza') || // GCP service key\n text.includes('xox') || // Slack token (xoxa/xoxb/xoxp/xoxo/xoxs)\n text.includes('Bearer ') || // Bearer token (space suffix reduces false positives)\n text.includes('/bot') || // Telegram bot token (URL path pattern)\n text.includes('hf_') || // HuggingFace token\n text.includes('r8_') || // Replicate token\n text.includes('pplx-') || // Perplexity API key\n text.includes('gsk_') || // Groq API key\n text.includes('_KEY=') || // High-entropy env vars: API_KEY=, SECRET_KEY=, ...\n text.includes('_TOKEN=') || // ACCESS_TOKEN=, AUTH_TOKEN=, ...\n text.includes('_SECRET=') || // API_SECRET=, CLIENT_SECRET=, ...\n text.includes('_PASSWORD=') || // DB_PASSWORD=, ROOT_PASSWORD=, ...\n text.includes('mongodb://') ||\n text.includes('mongodb+srv://') ||\n text.includes('postgres://') ||\n text.includes('postgresql://') ||\n text.includes('mysql://') ||\n text.includes('redis://') ||\n // JSON-style credential keys: tool outputs often serialise objects as\n // raw JSON strings rather than parsed objects. The value may not start\n // with a recognisable prefix (sk-, ghp_, etc.), so we anchor on common\n // key names. The `\"` prefix avoids matching prose that happens to mention\n // these words \u2014 JSON serialisation always quotes string keys.\n text.includes('\"apiKey\"') ||\n text.includes('\"api_key\"') ||\n text.includes('\"token\"') ||\n text.includes('\"secret\"') ||\n text.includes('\"password\"') ||\n text.includes('\"authorization\"') ||\n text.includes('\"bearer\"') ||\n text.includes('\"private_key\"') ||\n text.includes('\"access_token\"') ||\n text.includes('\"refresh_token\"') ||\n text.includes('\"client_secret\"')\n );\n}\n\nexport class DefaultSecretScrubber implements SecretScrubber {\n scrub(text: string): string {\n if (!text) return text;\n\n // Fast path: if no credential anchor substrings exist in the text,\n // none of the 17 regex patterns can match. Skip all regex work.\n // This covers the vast majority of tool outputs (~95% of calls on\n // typical sessions are file paths, status messages, diffs, etc.).\n if (!hasCredentialAnchors(text)) return text;\n\n // For oversize inputs, scrub in fixed chunks to keep memory bounded.\n // The boundary is snapped FORWARD to the next whitespace within an\n // overlap window so a secret straddling the nominal 64 KB cut is never\n // split in half. Every bounded credential pattern is whitespace-free, so\n // the next whitespace at/after the cut necessarily falls past the end of\n // any such secret \u2014 guaranteeing it stays wholly inside the current chunk.\n if (text.length <= SCRUB_CHUNK_BYTES) {\n return this.scrubOne(text);\n }\n const out: string[] = [];\n let i = 0;\n while (i < text.length) {\n let end = Math.min(i + SCRUB_CHUNK_BYTES, text.length);\n if (end < text.length) {\n // Look for the first whitespace at/after the nominal cut, bounded by\n // the overlap window. Extending forward (not backward) ensures any\n // secret that began before `end` finishes before the new boundary.\n const limit = Math.min(end + SCRUB_OVERLAP_BYTES, text.length);\n let safe = -1;\n for (let j = end; j < limit; j++) {\n const ch = text.charCodeAt(j);\n // space, \\t, \\n, \\r\n if (ch === 32 || ch === 9 || ch === 10 || ch === 13) {\n safe = j;\n break;\n }\n }\n // Snap onto the whitespace if found; otherwise fall back to the hard\n // cut (an unbroken >1 KB run with no whitespace can't be a bounded\n // secret anyway \u2014 those are all \u2264 ~560 chars and whitespace-free).\n end = safe === -1 ? end : safe + 1;\n }\n out.push(this.scrubOne(text.slice(i, end)));\n i = end;\n }\n return out.join('');\n }\n\n private scrubOne(text: string): string {\n // Redundant guard: if we reached scrubOne via the chunked path, the\n // chunk may have been small enough to anchor-skip independently.\n if (!hasCredentialAnchors(text)) return text;\n\n // Pass 1: combined single-pass regex for all simple patterns. Each\n // alternative is a capturing group; only the group that matched is\n // non-undefined. The trailing offset/string args replace() appends are\n // always defined, so the matched group (which precedes them) is found first.\n let out = text.replace(\n COMBINED_REGEX,\n (match, ...groups) => {\n // groups[i] corresponds to SIMPLE_PATTERNS[i]; find which one fired.\n const idx = groups.findIndex((g) => g !== undefined);\n if (idx < 0) return match;\n const replacement = COMBINED_REPLACEMENTS[idx];\n return replacement !== undefined ? replacement : match;\n },\n );\n\n // Pass 2: high_entropy_env needs special handling \u2014 preserve the key name.\n // Groups: 1=leading delimiter (re-emitted so adjacent-secret separators\n // aren't collapsed), 2=key name, 3=value (redacted).\n out = out.replace(HIGH_ENTROPY_REGEX, (_match, lead, key, _value) => {\n return `${lead}${key}=[REDACTED:high_entropy_env]`;\n });\n\n return out;\n }\n\n /**\n * Recursively scrub every string value in an object/array graph. Secrets can\n * appear under any key \u2014 a URL query param, an `authorization` header, an\n * arbitrarily-named nested field \u2014 so we don't gate recursion on key names.\n * The per-string `scrub()` fast-path (anchor pre-scan) keeps this cheap: any\n * value without a credential anchor returns immediately without regex work.\n */\n scrubObject<T>(obj: T): T {\n const seen = new WeakSet();\n const visit = (v: unknown): unknown => {\n if (typeof v === 'string') return this.scrub(v);\n if (v === null || typeof v !== 'object') return v;\n if (seen.has(v as object)) return v;\n seen.add(v as object);\n if (Array.isArray(v)) return v.map(visit);\n const out: Record<string, unknown> = {};\n for (const [k, val] of Object.entries(v as Record<string, unknown>)) {\n out[k] = visit(val);\n }\n return out;\n };\n return visit(obj) as T;\n }\n}\n", "import type { HqPathPolicy } from './project.js';\n\nexport type HqToolArgsPolicy = 'none' | 'summary' | 'redacted' | 'full';\n\nexport interface HqRedactionPolicy {\n rawContent: boolean;\n toolArgs: HqToolArgsPolicy;\n paths: HqPathPolicy;\n}\n\nexport const DEFAULT_HQ_REDACTION_POLICY: HqRedactionPolicy = {\n rawContent: true,\n toolArgs: 'full',\n paths: 'full',\n};\n\n/**\n * Per-string cap applied when redacting chat-transcript events\n * (`session.transcript` / `agent.message`). The generic 500-char summary cap\n * is right for telemetry rollups but would mangle full chat-history rendering\n * in the HQ Console once `rawContent` is enabled \u2014 messages and tool outputs\n * routinely exceed it. Applied publisher-side AND at the server's re-redaction\n * so both hops agree.\n */\nexport const HQ_TRANSCRIPT_TEXT_CAP = 16_000;\n\nexport interface HqToolStartedPayload {\n toolName: string;\n capabilities?: readonly string[];\n risk?: string;\n inputSummary?: unknown;\n}\n\nexport interface HqToolCompletedPayload {\n toolName: string;\n status: 'success' | 'error' | 'timeout' | 'cancelled';\n durationMs: number;\n outputSummary?: unknown;\n errorClass?: string;\n}\n", "import type {\n HqClientCapability,\n HqClientCommandAckMessage,\n HqClientCommandPollMessage,\n HqClientHelloPayload,\n HqClientHeartbeatPayload,\n HqClientIdentity,\n HqClientKind,\n HqClientMessage,\n HqClientResumeMessage,\n} from './client.js';\nimport type { HqBrainEventPayload } from './brain.js';\nimport type {\n HqFleetEventPayload,\n HqFleetSnapshotPayload,\n HqQueuedCommand,\n HqWorktreeEventPayload,\n} from './fleet.js';\nimport type {\n HqMailboxAgentSummary,\n HqMailboxEventPayload,\n HqMailboxMessageSummary,\n HqMailboxSnapshotPayload,\n} from './mailbox.js';\nimport type {\n HqMcpFailureCounts,\n HqMcpHealthCheck,\n HqMcpHealthSnapshotPayload,\n HqMcpLatencySummary,\n HqMcpOperationPayload,\n HqMcpServerHealth,\n} from './mcp.js';\nimport { isHqKanbanSnapshotPayload, type HqServerKanbanSnapshotMessage } from './kanban.js';\nimport { isHqPeerLostPayload, isHqPeerRehydratePayload } from './peer.js';\nimport type { HqResumeMessage } from './resume.js';\nimport type { HqProjectIdentity, HqWorkspaceKind } from './project.js';\nimport type {\n HqSessionAgentSummary,\n HqSessionEndedPayload,\n HqSessionSnapshotPayload,\n HqSubagentSummary,\n HqTranscriptAppendPayload,\n HqTranscriptEntry,\n} from './session.js';\nimport type {\n HqRedactionPolicy,\n HqToolCompletedPayload,\n HqToolStartedPayload,\n} from './tool.js';\n\nexport const HQ_PROTOCOL_VERSION = 1 as const;\n\nexport type HqProtocolVersion = typeof HQ_PROTOCOL_VERSION;\n\nexport interface HqWelcomePayload {\n type: 'hq.welcome';\n protocolVersion: HqProtocolVersion;\n serverTime: string;\n acceptedCapabilities: readonly HqClientCapability[];\n redactionPolicy: HqRedactionPolicy;\n}\n\nexport interface HqEventEnvelope<TPayload = unknown> {\n id: string;\n type: HqEventType | (string & {});\n schemaVersion: HqProtocolVersion;\n timestamp: string;\n clientId: string;\n projectId: string;\n sessionId?: string;\n runId?: string;\n seq: number;\n payload: TPayload;\n}\n\nexport type HqEventType =\n | 'client.hello'\n | 'client.heartbeat'\n | 'session.started'\n | 'session.status'\n | 'session.usage'\n | 'tool.started'\n | 'tool.completed'\n | 'fleet.snapshot'\n | 'fleet.event'\n | 'mailbox.snapshot'\n | 'mailbox.event'\n | 'kanban.snapshot'\n | 'worklist.snapshot'\n | 'git.snapshot'\n | 'agent.message'\n | 'agent.status'\n | 'session.snapshot'\n | 'session.transcript'\n | 'session.ended'\n | 'brain.event'\n | 'worktree.event'\n | 'mcp.health.snapshot'\n | 'mcp.operation'\n | 'peer.rehydrate'\n | 'peer.lost';\n\nexport interface HqUsagePayload {\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n costUsd?: number;\n durationMs?: number;\n /** Provider id that produced this usage (e.g. 'anthropic'), when known. */\n provider?: string;\n /** Model id the cost was priced against, when known. */\n model?: string;\n /** Cache-read (prompt-cache hit) tokens, when reported. */\n cacheRead?: number;\n /** Cache-write tokens, when reported. */\n cacheWrite?: number;\n}\n\n/** A physical machine, aggregated by HQ from connected clients' machineId. */\nexport interface HqMachineRecord {\n machineId: string;\n hostname?: string;\n clientCount: number;\n sessionCount: number;\n agentCount: number;\n projectIds: readonly string[];\n lastActivityAt: string;\n}\n\nexport interface HqGitSnapshotPayload {\n branch?: string;\n dirtyFiles?: number;\n stagedFiles?: number;\n ahead?: number;\n behind?: number;\n}\n\nexport interface HqAlertMessage {\n type: 'hq.alert';\n severity: 'info' | 'warn' | 'error';\n message: string;\n timestamp: string;\n}\n\nexport interface HqHeartbeatMessage {\n type: 'hq.heartbeat';\n serverTime: string;\n}\n\nexport interface HqServerCommandBatchMessage {\n type: 'hq.command_batch';\n commands: readonly HqQueuedCommand[];\n}\n\nexport type HqServerMessage =\n | HqServerCommandBatchMessage\n | HqServerKanbanSnapshotMessage\n | HqWelcomePayload\n | HqResumeMessage;\n\n/**\n * Discriminated parse result for {@link parseHqFrame}. The `reason` field\n * is only present when `ok` is `false`; consumers should narrow on `ok`\n * before accessing `frame` or `reason`.\n */\nexport type HqParseResult =\n | { ok: true; frame: HqClientMessage }\n | { ok: false; reason: 'invalid-json' | 'unknown-type' | 'malformed' };\n\n/** Known client \u2192 server frame `type` discriminators. */\nconst KNOWN_HQ_CLIENT_FRAME_TYPES = new Set<HqClientMessage['type']>([\n 'client.hello',\n 'client.event',\n 'client.command_poll',\n 'client.command_ack',\n 'client.resume',\n]);\n\nconst HQ_CLIENT_KINDS = new Set<HqClientKind>([\n 'tui',\n 'repl',\n 'webui',\n 'cli',\n 'mailbox',\n 'unknown',\n]);\nconst HQ_WORKSPACE_KINDS = new Set<HqWorkspaceKind>(['git', 'directory', 'unknown']);\nconst HQ_CLIENT_CAPABILITIES = new Set<HqClientCapability>([\n 'telemetry.publish',\n 'session.summary',\n 'fleet.summary',\n 'mailbox.summary',\n 'mailbox.serve',\n 'control.receive',\n]);\nconst HQ_COMMAND_ACK_STATUSES = new Set<HqClientCommandAckMessage['status']>([\n 'accepted',\n 'completed',\n 'failed',\n 'rejected',\n]);\n\n/** Top-level object + string `type` guard. */\nfunction hasStringType(x: unknown): x is { type: string } {\n return typeof x === 'object' && x !== null && typeof (x as { type?: unknown }).type === 'string';\n}\n\nfunction isHqClientIdentity(x: unknown): x is HqClientIdentity {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.clientId === 'string' &&\n typeof v.kind === 'string' &&\n HQ_CLIENT_KINDS.has(v.kind as HqClientKind) &&\n typeof v.machineId === 'string' &&\n typeof v.startedAt === 'string'\n );\n}\n\nfunction isHqProjectIdentity(x: unknown): x is HqProjectIdentity {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.projectId === 'string' &&\n typeof v.projectRoot === 'string' &&\n typeof v.projectName === 'string' &&\n typeof v.machineId === 'string' &&\n typeof v.workspaceKind === 'string' &&\n HQ_WORKSPACE_KINDS.has(v.workspaceKind as HqWorkspaceKind)\n );\n}\n\nfunction isHqRedactionPolicy(x: unknown): x is HqRedactionPolicy {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.rawContent === 'boolean' &&\n (v.toolArgs === 'none' || v.toolArgs === 'summary' || v.toolArgs === 'redacted' || v.toolArgs === 'full') &&\n (v.paths === 'none' ||\n v.paths === 'project-relative' ||\n v.paths === 'redacted' ||\n v.paths === 'full')\n );\n}\n\nfunction isHqClientHelloPayload(x: unknown): x is HqClientHelloPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.protocolVersion === 'number' &&\n isHqClientIdentity(v.client) &&\n isHqProjectIdentity(v.project) &&\n Array.isArray(v.capabilities) &&\n v.capabilities.every(\n (capability) =>\n typeof capability === 'string' &&\n HQ_CLIENT_CAPABILITIES.has(capability as HqClientCapability),\n ) &&\n (v.redactionPolicy === undefined || isHqRedactionPolicy(v.redactionPolicy))\n );\n}\n\nfunction isHqEventEnvelope(x: unknown): x is HqEventEnvelope {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.id === 'string' &&\n typeof v.type === 'string' &&\n v.schemaVersion === HQ_PROTOCOL_VERSION &&\n typeof v.timestamp === 'string' &&\n typeof v.clientId === 'string' &&\n typeof v.projectId === 'string' &&\n Number.isSafeInteger(v.seq) &&\n (v.seq as number) >= 0 &&\n Object.hasOwn(v, 'payload')\n );\n}\n\nfunction isHqClientCommandPollMessage(x: unknown): x is HqClientCommandPollMessage {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.clientId === 'string' &&\n typeof v.projectId === 'string' &&\n (v.afterCommandId === undefined || typeof v.afterCommandId === 'string') &&\n (v.limit === undefined ||\n (Number.isSafeInteger(v.limit) && (v.limit as number) > 0 && (v.limit as number) <= 200))\n );\n}\n\nfunction isHqClientCommandAckMessage(x: unknown): x is HqClientCommandAckMessage {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.clientId === 'string' &&\n typeof v.projectId === 'string' &&\n typeof v.commandId === 'string' &&\n typeof v.status === 'string' &&\n HQ_COMMAND_ACK_STATUSES.has(v.status as HqClientCommandAckMessage['status']) &&\n (v.message === undefined || typeof v.message === 'string')\n );\n}\n\nfunction isHqClientResumeMessage(x: unknown): x is HqClientResumeMessage {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.type === 'string' &&\n v.type === 'client.resume' &&\n Number.isSafeInteger(v.lastSeqSeen) &&\n (v.lastSeqSeen as number) >= 0 &&\n (v.clientId === undefined || typeof v.clientId === 'string') &&\n (v.projectId === undefined || typeof v.projectId === 'string')\n );\n}\n\n/**\n * Strictly parse a raw client \u2192 server frame into a {@link HqParseResult}.\n *\n * Validates, in order:\n * 1. JSON syntax (`invalid-json` on failure)\n * 2. Top-level object with string `type` discriminator\n * 3. `type` is one of {@link HqClientMessage} union members (`unknown-type`)\n * 4. Per-type field-shape presence checks (`malformed` on failure)\n *\n * On success, `frame` is narrowed to {@link HqClientMessage} and consumers\n * can switch on `frame.type` for type-safe access to per-union-member\n * fields without `as` casts.\n */\nexport function parseHqFrame(raw: string | Buffer): HqParseResult {\n let parsed: unknown;\n try {\n parsed = JSON.parse(typeof raw === 'string' ? raw : raw.toString('utf8'));\n } catch {\n return { ok: false, reason: 'invalid-json' };\n }\n\n if (!hasStringType(parsed)) {\n return { ok: false, reason: 'malformed' };\n }\n const obj = parsed as { type: string } & Record<string, unknown>;\n\n if (!KNOWN_HQ_CLIENT_FRAME_TYPES.has(obj.type as HqClientMessage['type'])) {\n return { ok: false, reason: 'unknown-type' };\n }\n\n switch (obj.type as HqClientMessage['type']) {\n case 'client.hello':\n if (!isHqClientHelloPayload(obj.payload)) {\n return { ok: false, reason: 'malformed' };\n }\n return { ok: true, frame: { type: 'client.hello', payload: obj.payload } };\n case 'client.event':\n if (!isHqEventEnvelope(obj.event)) {\n return { ok: false, reason: 'malformed' };\n }\n return { ok: true, frame: { type: 'client.event', event: obj.event } };\n case 'client.command_poll':\n if (!isHqClientCommandPollMessage(obj)) {\n return { ok: false, reason: 'malformed' };\n }\n return {\n ok: true,\n frame: {\n type: 'client.command_poll',\n clientId: obj.clientId,\n projectId: obj.projectId,\n ...(typeof obj.afterCommandId === 'string'\n ? { afterCommandId: obj.afterCommandId }\n : {}),\n ...(typeof obj.limit === 'number' ? { limit: obj.limit } : {}),\n },\n };\n case 'client.command_ack':\n if (!isHqClientCommandAckMessage(obj)) {\n return { ok: false, reason: 'malformed' };\n }\n return {\n ok: true,\n frame: {\n type: 'client.command_ack',\n clientId: obj.clientId,\n projectId: obj.projectId,\n commandId: obj.commandId,\n status: obj.status as HqClientCommandAckMessage['status'],\n ...(typeof obj.message === 'string' ? { message: obj.message } : {}),\n },\n };\n case 'client.resume':\n if (!isHqClientResumeMessage(obj)) {\n return { ok: false, reason: 'malformed' };\n }\n return {\n ok: true,\n frame: {\n type: 'client.resume',\n lastSeqSeen: obj.lastSeqSeen,\n ...(typeof obj.clientId === 'string' ? { clientId: obj.clientId } : {}),\n ...(typeof obj.projectId === 'string' ? { projectId: obj.projectId } : {}),\n },\n };\n default: {\n // Unreachable: KNOWN_HQ_CLIENT_FRAME_TYPES membership guarantees\n // `obj.type` is one of the cases above. Return `unknown-type` defensively\n // to satisfy the return type if a future HqClientMessage union member\n // is added without updating this switch.\n const _exhaustive: never = obj.type as never;\n return _exhaustive;\n }\n }\n}\n\n/** Known `client.event` envelope event types whose payload shape we validate. */\nconst KNOWN_HQ_EVENT_PAYLOAD_TYPES = new Set<string>([\n 'mailbox.snapshot',\n 'mailbox.event',\n 'kanban.snapshot',\n 'session.snapshot',\n 'session.transcript',\n 'session.ended',\n 'fleet.snapshot',\n 'fleet.event',\n 'brain.event',\n 'worktree.event',\n 'tool.started',\n 'tool.completed',\n 'session.usage',\n 'client.heartbeat',\n 'mcp.health.snapshot',\n 'mcp.operation',\n 'peer.rehydrate',\n 'peer.lost',\n]);\n\nfunction isHqMcpLatencySummary(x: unknown): x is HqMcpLatencySummary {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.count === 'number' &&\n (v.lastMs === undefined || typeof v.lastMs === 'number') &&\n (v.minMs === undefined || typeof v.minMs === 'number') &&\n (v.maxMs === undefined || typeof v.maxMs === 'number') &&\n (v.p50Ms === undefined || typeof v.p50Ms === 'number') &&\n (v.p95Ms === undefined || typeof v.p95Ms === 'number')\n );\n}\n\nfunction isHqMcpFailureCounts(x: unknown): x is HqMcpFailureCounts {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.transport === 'number' &&\n typeof v.protocol === 'number' &&\n typeof v.tool === 'number'\n );\n}\n\nfunction isHqMcpHealthCheck(x: unknown): x is HqMcpHealthCheck {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.name === 'string' &&\n typeof v.passed === 'boolean' &&\n (v.value === undefined || typeof v.value === 'number') &&\n (v.threshold === undefined || typeof v.threshold === 'number')\n );\n}\n\nconst HQ_MCP_HEALTH_STATES = new Set<string>([\n 'disabled',\n 'dormant',\n 'connecting',\n 'healthy',\n 'degraded',\n 'failed',\n]);\n\nconst HQ_MCP_CONNECTION_STATES = new Set<string>([\n 'idle',\n 'dormant',\n 'connecting',\n 'connected',\n 'reconnecting',\n 'disconnected',\n 'failed',\n]);\n\nfunction isHqMcpServerHealth(x: unknown): x is HqMcpServerHealth {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.name === 'string' &&\n typeof v.projectId === 'string' &&\n typeof v.clientId === 'string' &&\n typeof v.connectionState === 'string' &&\n HQ_MCP_CONNECTION_STATES.has(v.connectionState) &&\n typeof v.healthState === 'string' &&\n HQ_MCP_HEALTH_STATES.has(v.healthState) &&\n (v.lastSuccessAt === undefined || typeof v.lastSuccessAt === 'string') &&\n (v.lastFailureAt === undefined || typeof v.lastFailureAt === 'string') &&\n (v.lastFailureKind === undefined ||\n v.lastFailureKind === 'transport' ||\n v.lastFailureKind === 'protocol' ||\n v.lastFailureKind === 'tool') &&\n typeof v.consecutiveFailures === 'number' &&\n isHqMcpFailureCounts(v.failures) &&\n typeof v.reconnectCount === 'number' &&\n typeof v.wakeCount === 'number' &&\n typeof v.sleepCount === 'number' &&\n typeof v.restartCount === 'number' &&\n isHqMcpLatencySummary(v.connectionLatency) &&\n isHqMcpLatencySummary(v.discoveryLatency) &&\n isHqMcpLatencySummary(v.callLatency) &&\n typeof v.inFlightCalls === 'number' &&\n typeof v.peakInFlightCalls === 'number' &&\n Array.isArray(v.healthChecks) &&\n v.healthChecks.every(isHqMcpHealthCheck)\n );\n}\n\nfunction isHqMcpHealthSnapshotPayload(x: unknown): x is HqMcpHealthSnapshotPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return Array.isArray(v.servers) && v.servers.every(isHqMcpServerHealth);\n}\n\nfunction isHqMcpOperationPayload(x: unknown): x is HqMcpOperationPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.operation === 'object' &&\n v.operation !== null &&\n Array.isArray(v.servers) &&\n v.servers.every(isHqMcpServerHealth)\n );\n}\n\nfunction isHqMailboxMessageSummary(x: unknown): x is HqMailboxMessageSummary {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.messageId === 'string' &&\n typeof v.from === 'string' &&\n typeof v.to === 'string' &&\n typeof v.subject === 'string' &&\n typeof v.priority === 'string' &&\n typeof v.timestamp === 'string' &&\n typeof v.completed === 'boolean' &&\n typeof v.hasBody === 'boolean'\n );\n}\n\nfunction isHqMailboxAgentSummary(x: unknown): x is HqMailboxAgentSummary {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.agentId === 'string' &&\n typeof v.name === 'string' &&\n typeof v.sessionId === 'string' &&\n typeof v.status === 'string' &&\n typeof v.iterations === 'number' &&\n typeof v.toolCalls === 'number' &&\n typeof v.lastActivityAt === 'string' &&\n typeof v.lastSeenAt === 'string' &&\n typeof v.online === 'boolean'\n );\n}\n\nfunction isHqMailboxSnapshotPayload(x: unknown): x is HqMailboxSnapshotPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (\n typeof v.mailboxId !== 'string' ||\n (v.scope !== 'project' && v.scope !== 'global') ||\n !Array.isArray(v.messages) ||\n !Array.isArray(v.agents) ||\n typeof v.totals !== 'object' ||\n v.totals === null\n ) {\n return false;\n }\n const totals = v.totals as Record<string, unknown>;\n if (\n typeof totals.messages !== 'number' ||\n typeof totals.unread !== 'number' ||\n typeof totals.incomplete !== 'number' ||\n typeof totals.highPriority !== 'number' ||\n typeof totals.onlineAgents !== 'number'\n ) {\n return false;\n }\n for (const message of v.messages) {\n if (!isHqMailboxMessageSummary(message)) return false;\n }\n for (const agent of v.agents) {\n if (!isHqMailboxAgentSummary(agent)) return false;\n }\n return true;\n}\n\nconst HQ_MAILBOX_EVENT_ACTIONS = new Set<string>([\n 'message.sent',\n 'message.read',\n 'message.completed',\n 'message.updated',\n 'agent.registered',\n 'agent.heartbeat',\n 'agent.offline',\n 'agent.deregistered',\n]);\n\nfunction isHqMailboxEventPayload(x: unknown): x is HqMailboxEventPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (typeof v.mailboxId !== 'string') return false;\n if (typeof v.action !== 'string' || !HQ_MAILBOX_EVENT_ACTIONS.has(v.action)) return false;\n // `message` and `agent` are optional but, when present, must satisfy\n // their respective shape guard so a downstream consumer can rely on\n // the typed fields.\n if (v.message !== undefined && !isHqMailboxMessageSummary(v.message)) return false;\n if (v.agent !== undefined && !isHqMailboxAgentSummary(v.agent)) return false;\n return true;\n}\n\nconst HQ_SESSION_AGENT_STATUSES = new Set<string>([\n 'idle',\n 'running',\n 'streaming',\n 'waiting_user',\n 'error',\n]);\n\nfunction isHqSessionAgentSummary(x: unknown): x is HqSessionAgentSummary {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.id === 'string' &&\n typeof v.name === 'string' &&\n typeof v.status === 'string' &&\n HQ_SESSION_AGENT_STATUSES.has(v.status) &&\n typeof v.iterations === 'number' &&\n typeof v.toolCalls === 'number' &&\n typeof v.lastActivityAt === 'string'\n );\n}\n\nconst HQ_SESSION_STATUSES = new Set<string>(['active', 'idle', 'closing', 'stale']);\n\nfunction isHqSessionSnapshotPayload(x: unknown): x is HqSessionSnapshotPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (\n typeof v.sessionId !== 'string' ||\n typeof v.clientKind !== 'string' ||\n typeof v.machineId !== 'string' ||\n typeof v.projectId !== 'string' ||\n typeof v.projectName !== 'string' ||\n typeof v.projectRoot !== 'string' ||\n typeof v.status !== 'string' ||\n !HQ_SESSION_STATUSES.has(v.status) ||\n typeof v.startedAt !== 'string' ||\n typeof v.lastActivityAt !== 'string' ||\n typeof v.agentCount !== 'number' ||\n !Array.isArray(v.agents)\n ) {\n return false;\n }\n for (const agent of v.agents) {\n if (!isHqSessionAgentSummary(agent)) return false;\n }\n return true;\n}\n\nconst HQ_TRANSCRIPT_ROLES = new Set<string>([\n 'user',\n 'assistant',\n 'thinking',\n 'tool',\n 'system',\n 'error',\n]);\n\nfunction isHqTranscriptEntry(x: unknown): x is HqTranscriptEntry {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.ts === 'string' &&\n typeof v.role === 'string' &&\n HQ_TRANSCRIPT_ROLES.has(v.role) &&\n typeof v.text === 'string'\n );\n}\n\nfunction isHqTranscriptAppendPayload(x: unknown): x is HqTranscriptAppendPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (\n typeof v.sessionId !== 'string' ||\n typeof v.fromSeq !== 'number' ||\n !Array.isArray(v.entries)\n ) {\n return false;\n }\n for (const entry of v.entries) {\n if (!isHqTranscriptEntry(entry)) return false;\n }\n return true;\n}\n\nfunction isHqSessionEndedPayload(x: unknown): x is HqSessionEndedPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return typeof v.sessionId === 'string' && typeof v.endedAt === 'string';\n}\n\nconst HQ_FLEET_SUBAGENT_STATUS = new Set<string>([\n 'pending',\n 'running',\n 'idle',\n 'completed',\n 'failed',\n 'stopped',\n]);\n\nfunction isHqSubagentSummary(x: unknown): x is HqSubagentSummary {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.subagentId === 'string' &&\n typeof v.status === 'string' &&\n HQ_FLEET_SUBAGENT_STATUS.has(v.status)\n );\n}\n\nfunction isHqFleetSnapshotPayload(x: unknown): x is HqFleetSnapshotPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (\n typeof v.runId !== 'string' ||\n typeof v.activeSubagents !== 'number' ||\n typeof v.queuedTasks !== 'number' ||\n typeof v.completedTasks !== 'number' ||\n typeof v.failedTasks !== 'number' ||\n !Array.isArray(v.subagents)\n ) {\n return false;\n }\n for (const s of v.subagents) {\n if (!isHqSubagentSummary(s)) return false;\n }\n return true;\n}\n\nfunction isHqFleetEventPayload(x: unknown): x is HqFleetEventPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return typeof v.runId === 'string' && typeof v.event === 'string';\n}\n\nconst HQ_BRAIN_EVENT_KINDS = new Set<string>([\n 'decision_requested',\n 'decision_answered',\n 'decision_ask_human',\n 'human_answered',\n 'decision_denied',\n 'intervention',\n]);\n\nfunction isHqBrainEventPayload(x: unknown): x is HqBrainEventPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (typeof v.kind !== 'string' || !HQ_BRAIN_EVENT_KINDS.has(v.kind)) return false;\n if (typeof v.at !== 'number') return false;\n return true;\n}\n\nconst HQ_WORKTREE_EVENT_KINDS = new Set<string>([\n 'allocated',\n 'committed',\n 'merged',\n 'conflict',\n 'released',\n 'failed',\n]);\n\nfunction isHqWorktreeEventPayload(x: unknown): x is HqWorktreeEventPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (typeof v.kind !== 'string' || !HQ_WORKTREE_EVENT_KINDS.has(v.kind)) return false;\n if (typeof v.handleId !== 'string' || typeof v.ownerId !== 'string') return false;\n return true;\n}\n\nfunction isHqToolStartedPayload(x: unknown): x is HqToolStartedPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return typeof v.toolName === 'string';\n}\n\nfunction isHqToolCompletedPayload(x: unknown): x is HqToolCompletedPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.toolName === 'string' &&\n typeof v.status === 'string' &&\n typeof v.durationMs === 'number'\n );\n}\n\nfunction isHqUsagePayload(x: unknown): x is HqUsagePayload {\n if (typeof x !== 'object' || x === null) return false;\n // HqUsagePayload has all-optional numeric fields; accept any object so the\n // cost signal is never dropped on a partial payload, but require it be a\n // plain object (not array/null) to keep the downstream typed.\n return !Array.isArray(x);\n}\n\nfunction isHqClientHeartbeatPayload(x: unknown): x is HqClientHeartbeatPayload {\n if (typeof x !== 'object' || x === null || Array.isArray(x)) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.uptimeMs === 'number' &&\n (v.activeSessionId === undefined || typeof v.activeSessionId === 'string') &&\n (v.activeRunId === undefined || typeof v.activeRunId === 'string') &&\n typeof v.status === 'string' &&\n (v.status === 'active' ||\n v.status === 'idle' ||\n v.status === 'stale' ||\n v.status === 'error') &&\n (v.activeSubagents === undefined || typeof v.activeSubagents === 'number') &&\n (v.queuedTasks === undefined || typeof v.queuedTasks === 'number')\n );\n}\n\n/**\n * Validate the `payload` field of a {@link HqEventEnvelope} for known\n * event types. Returns `{ ok: true, payload }` with a narrowed payload\n * type when the event type has a registered shape guard and the payload\n * matches it; `{ ok: true, payload: unknown }` for event types that the\n * server does not yet validate; or `{ ok: false, reason }` when the\n * payload fails the registered guard.\n *\n * Use this after {@link parseHqFrame} has produced a valid frame, when\n * the frame is `client.event` and the server is about to consume the\n * event payload.\n */\nexport type HqEventPayloadResult<T> =\n | { ok: true; payload: T }\n | { ok: false; reason: 'unknown-event-type' | 'malformed-payload' };\n\nexport function parseHqEventPayload(\n eventType: string,\n payload: unknown,\n): HqEventPayloadResult<unknown> {\n if (!KNOWN_HQ_EVENT_PAYLOAD_TYPES.has(eventType)) {\n // Server does not validate this event type yet \u2014 pass it through\n // untyped so the publish pipeline is not blocked. Future events\n // can opt-in by adding their type + guard here.\n return { ok: true, payload };\n }\n switch (eventType) {\n case 'mailbox.snapshot':\n return isHqMailboxSnapshotPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'mailbox.event':\n return isHqMailboxEventPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'kanban.snapshot':\n return isHqKanbanSnapshotPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'session.snapshot':\n return isHqSessionSnapshotPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'session.transcript':\n return isHqTranscriptAppendPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'session.ended':\n return isHqSessionEndedPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'fleet.snapshot':\n return isHqFleetSnapshotPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'fleet.event':\n return isHqFleetEventPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'brain.event':\n return isHqBrainEventPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'worktree.event':\n return isHqWorktreeEventPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'tool.started':\n return isHqToolStartedPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'tool.completed':\n return isHqToolCompletedPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'session.usage':\n return isHqUsagePayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'client.heartbeat':\n return isHqClientHeartbeatPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'mcp.health.snapshot':\n return isHqMcpHealthSnapshotPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'mcp.operation':\n return isHqMcpOperationPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'peer.rehydrate':\n return isHqPeerRehydratePayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'peer.lost':\n return isHqPeerLostPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n default: {\n const _exhaustive: never = eventType as never;\n return _exhaustive;\n }\n }\n}\n\nexport function createHqEventEnvelope<TPayload>(input: {\n id: string;\n type: HqEventType | (string & {});\n timestamp: string;\n clientId: string;\n projectId: string;\n seq: number;\n payload: TPayload;\n sessionId?: string;\n runId?: string;\n}): HqEventEnvelope<TPayload> {\n return {\n id: input.id,\n type: input.type,\n schemaVersion: HQ_PROTOCOL_VERSION,\n timestamp: input.timestamp,\n clientId: input.clientId,\n projectId: input.projectId,\n seq: input.seq,\n payload: input.payload,\n ...(input.sessionId !== undefined ? { sessionId: input.sessionId } : {}),\n ...(input.runId !== undefined ? { runId: input.runId } : {}),\n };\n}\n", "import { DefaultSecretScrubber } from '../security/secret-scrubber.js';\nimport {\n DEFAULT_HQ_REDACTION_POLICY,\n type HqEventEnvelope,\n type HqRedactionPolicy,\n} from './protocol.js';\n\nconst RAW_CONTENT_REPLACEMENT = '[REDACTED:hq_raw_content]';\nconst SENSITIVE_FIELD_REPLACEMENT = '[REDACTED:hq_sensitive_field]';\nconst REDACTED_PATH_REPLACEMENT = '[REDACTED:hq_path]';\n\nconst RAW_CONTENT_KEYS = new Set([\n 'content',\n 'contents',\n 'raw',\n 'rawContent',\n 'body',\n 'message',\n 'messages',\n 'prompt',\n 'prompts',\n 'completion',\n 'response',\n 'text',\n 'partialText',\n 'assistantMessage',\n 'userMessage',\n 'stdout',\n 'stderr',\n 'output',\n 'toolInput',\n 'toolOutput',\n 'outputSummary',\n 'body',\n 'mailboxBody',\n 'messageBody',\n 'outcome',\n 'fileContent',\n 'diff',\n 'patch',\n 'transcript',\n 'logs',\n]);\n\n// Kanban records are an explicitly configured project-state synchronization\n// channel, not telemetry summaries. Their user-authored fields must round-trip\n// intact; sensitive-key and secret-pattern scrubbing still applies recursively.\nconst HQ_PROJECT_STATE_EVENT_TYPES = new Set(['kanban.snapshot']);\n\nconst SENSITIVE_KEYS = new Set([\n 'authorization',\n 'cookie',\n 'password',\n 'passwd',\n 'pwd',\n 'secret',\n 'token',\n 'accessToken',\n 'refreshToken',\n 'apiKey',\n 'apikey',\n 'clientSecret',\n 'privateKey',\n]);\n\nconst PATH_KEYS = new Set([\n 'path',\n 'paths',\n 'file',\n 'files',\n 'filepath',\n 'filePath',\n 'filename',\n 'projectRoot',\n 'projectRootDisplay',\n 'cwd',\n 'workingDir',\n 'workingDirectory',\n]);\n\nexport interface HqRedactOptions {\n policy?: Partial<HqRedactionPolicy>;\n projectRoot?: string;\n maxSummaryLength?: number;\n}\n\nexport interface HqRedactionResult<T> {\n value: T;\n redacted: boolean;\n}\n\nconst defaultScrubber = new DefaultSecretScrubber();\n\nexport function resolveHqRedactionPolicy(\n policy?: Partial<HqRedactionPolicy>,\n): HqRedactionPolicy {\n return {\n ...DEFAULT_HQ_REDACTION_POLICY,\n ...policy,\n };\n}\n\n/**\n * Apply an operator policy as a one-way privacy clamp. An override can make a\n * publisher policy stricter, but can never enable raw content or broader path\n * / tool-argument disclosure than the publisher selected.\n */\nexport function tightenHqRedactionPolicy(\n publisherPolicy: HqRedactionPolicy,\n operatorPolicy?: Partial<HqRedactionPolicy>,\n): HqRedactionPolicy {\n if (operatorPolicy === undefined) return publisherPolicy;\n const toolRank: Record<HqRedactionPolicy['toolArgs'], number> = {\n none: 0,\n summary: 1,\n redacted: 2,\n full: 3,\n };\n const pathRank: Record<HqRedactionPolicy['paths'], number> = {\n none: 0,\n redacted: 0,\n 'project-relative': 1,\n full: 2,\n };\n const requestedToolArgs = operatorPolicy.toolArgs;\n const requestedPaths = operatorPolicy.paths;\n return {\n rawContent:\n publisherPolicy.rawContent &&\n (operatorPolicy.rawContent === undefined || operatorPolicy.rawContent),\n toolArgs:\n requestedToolArgs !== undefined &&\n toolRank[requestedToolArgs] < toolRank[publisherPolicy.toolArgs]\n ? requestedToolArgs\n : publisherPolicy.toolArgs,\n paths:\n requestedPaths !== undefined && pathRank[requestedPaths] < pathRank[publisherPolicy.paths]\n ? requestedPaths\n : publisherPolicy.paths,\n };\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return Object.prototype.toString.call(value) === '[object Object]';\n}\n\nfunction isSensitiveKey(key: string): boolean {\n const lower = key.toLowerCase();\n return (\n SENSITIVE_KEYS.has(key) ||\n lower.includes('authorization') ||\n lower.includes('password') ||\n lower.includes('secret') ||\n lower.endsWith('token') ||\n lower.endsWith('apikey') ||\n lower.endsWith('api_key')\n );\n}\n\nfunction isRawContentKey(key: string): boolean {\n return RAW_CONTENT_KEYS.has(key) || RAW_CONTENT_KEYS.has(key.toLowerCase());\n}\n\nfunction isPathKey(key: string): boolean {\n return PATH_KEYS.has(key) || PATH_KEYS.has(key.toLowerCase());\n}\n\nfunction normalizePathForCompare(value: string): string {\n return value.replace(/\\\\/g, '/').replace(/\\/+$/g, '');\n}\n\nfunction redactPath(\n value: string,\n projectRoot: string | undefined,\n policy: HqRedactionPolicy,\n): string {\n if (policy.paths === 'full') return value;\n if (policy.paths === 'none' || policy.paths === 'redacted') return REDACTED_PATH_REPLACEMENT;\n\n const normalizedValue = normalizePathForCompare(value);\n if (!projectRoot) return normalizedValue.split('/').at(-1) ?? REDACTED_PATH_REPLACEMENT;\n\n const normalizedRoot = normalizePathForCompare(projectRoot);\n if (normalizedValue === normalizedRoot) return '.';\n if (normalizedValue.startsWith(`${normalizedRoot}/`)) {\n return normalizedValue.slice(normalizedRoot.length + 1) || '.';\n }\n return normalizedValue.split('/').at(-1) ?? REDACTED_PATH_REPLACEMENT;\n}\n\nfunction summarizeString(value: string, maxSummaryLength: number, scrub: boolean): string {\n const scrubbed = scrub ? defaultScrubber.scrub(value) : value;\n if (scrubbed.length <= maxSummaryLength) return scrubbed;\n return `${scrubbed.slice(0, maxSummaryLength)}\u2026[truncated:${scrubbed.length - maxSummaryLength}]`;\n}\n\n/**\n * Scrub a free-text preview field and truncate it to a maximum length so\n * it is safe to embed in HQ event envelopes and broadcast to browsers\n * without leaking secrets or running away on unbounded input.\n *\n * Returns `undefined` when the input is empty or non-string. Truncation\n * suffix is `\"\u2026[truncated:N]\"` where N is the number of dropped chars.\n */\nexport function scrubAndTruncateHqPreview(\n value: unknown,\n maxLength: number = 280,\n): string | undefined {\n if (typeof value !== 'string' || value.length === 0) return undefined;\n return summarizeString(value, maxLength, true);\n}\n\nfunction visitValue(\n value: unknown,\n options: {\n policy: HqRedactionPolicy;\n projectRoot?: string;\n maxSummaryLength: number;\n preserveRawContentKeys?: boolean;\n seen: WeakSet<object>;\n },\n key?: string,\n): { value: unknown; redacted: boolean } {\n if (!options.policy.rawContent && key !== undefined && isSensitiveKey(key)) {\n return { value: SENSITIVE_FIELD_REPLACEMENT, redacted: true };\n }\n\n if (typeof value === 'string') {\n if (key !== undefined && isPathKey(key)) {\n const redactedPath = redactPath(value, options.projectRoot, options.policy);\n return { value: redactedPath, redacted: redactedPath !== value };\n }\n\n if (\n !options.preserveRawContentKeys &&\n !options.policy.rawContent &&\n key !== undefined &&\n isRawContentKey(key)\n ) {\n return { value: RAW_CONTENT_REPLACEMENT, redacted: true };\n }\n\n const scrubbed = summarizeString(value, options.maxSummaryLength, !options.policy.rawContent);\n return { value: scrubbed, redacted: scrubbed !== value };\n }\n\n if (value === null || typeof value !== 'object') return { value, redacted: false };\n\n if (options.seen.has(value)) return { value: '[REDACTED:hq_circular]', redacted: true };\n options.seen.add(value);\n\n if (Array.isArray(value)) {\n let redacted = false;\n const out = value.map((item) => {\n const next = visitValue(item, options, key);\n redacted ||= next.redacted;\n return next.value;\n });\n return { value: out, redacted };\n }\n\n if (!isPlainObject(value)) return { value: String(value), redacted: true };\n\n let redacted = false;\n const out: Record<string, unknown> = {};\n for (const [childKey, childValue] of Object.entries(value)) {\n const next = visitValue(childValue, options, childKey);\n redacted ||= next.redacted;\n out[childKey] = next.value;\n }\n return { value: out, redacted };\n}\n\nfunction redactHqValueInternal<T>(\n value: T,\n options: HqRedactOptions,\n preserveRawContentKeys: boolean,\n): HqRedactionResult<T> {\n const result = visitValue(value, {\n policy: resolveHqRedactionPolicy(options.policy),\n ...(options.projectRoot !== undefined ? { projectRoot: options.projectRoot } : {}),\n maxSummaryLength: options.maxSummaryLength ?? 500,\n preserveRawContentKeys,\n seen: new WeakSet<object>(),\n });\n return { value: result.value as T, redacted: result.redacted };\n}\n\nexport function redactHqValue<T>(\n value: T,\n options: HqRedactOptions = {},\n): HqRedactionResult<T> {\n return redactHqValueInternal(value, options, false);\n}\n\nexport function redactHqEvent<TPayload>(\n event: HqEventEnvelope<TPayload>,\n options: HqRedactOptions = {},\n): HqRedactionResult<HqEventEnvelope<TPayload>> {\n const payload = redactHqValueInternal(\n event.payload,\n options,\n HQ_PROJECT_STATE_EVENT_TYPES.has(event.type),\n );\n const nextEvent = {\n ...event,\n payload: payload.value,\n };\n return { value: nextEvent, redacted: payload.redacted };\n}\n\nexport function summarizeHqToolArgs(value: unknown, options: HqRedactOptions = {}): unknown {\n const policy = resolveHqRedactionPolicy(options.policy);\n if (policy.toolArgs === 'full') return value;\n if (policy.toolArgs === 'none') return '[REDACTED:hq_tool_args]';\n if (policy.toolArgs === 'redacted') return redactHqValue(value, options).value;\n\n if (value === null || typeof value !== 'object') return redactHqValue(value, options).value;\n if (Array.isArray(value)) return `[array:${value.length}]`;\n\n const entries = Object.entries(value as Record<string, unknown>);\n const summary: Record<string, unknown> = {};\n for (const [key, item] of entries.slice(0, 20)) {\n if (isSensitiveKey(key)) {\n summary[key] = SENSITIVE_FIELD_REPLACEMENT;\n } else if (typeof item === 'string') {\n summary[key] = isPathKey(key)\n ? redactPath(item, options.projectRoot, policy)\n : summarizeString(item, 120, true);\n } else if (Array.isArray(item)) {\n summary[key] = `[array:${item.length}]`;\n } else if (item !== null && typeof item === 'object') {\n summary[key] = '[object]';\n } else {\n summary[key] = item;\n }\n }\n if (entries.length > 20) summary.__truncatedKeys = entries.length - 20;\n return summary;\n}\n", "import type { Mailbox, MailboxAgentStatus, MailboxMessage } from '../coordination/mailbox-types.js';\nimport { SESSION_RECIPIENT_PREFIX } from '../coordination/mailbox-types.js';\nimport type {\n HqMailboxAgentSummary,\n HqMailboxEventPayload,\n HqMailboxMessageScope,\n HqMailboxMessageSummary,\n HqMailboxSnapshotPayload,\n HqRedactionPolicy,\n} from './protocol.js';\nimport { scrubAndTruncateHqPreview } from './redaction.js';\n\nexport interface HqMailboxMappingOptions {\n mailboxId: string;\n scope?: 'project' | 'global';\n limit?: number;\n previewLength?: number;\n redactionPolicy?: Partial<HqRedactionPolicy>;\n}\n\nexport interface HqMailboxSnapshotOptions extends HqMailboxMappingOptions {\n includeCompleted?: boolean;\n}\n\nexport type HqMailboxEventAction = HqMailboxEventPayload['action'];\n\nfunction previewText(value: string | undefined, maxLength: number, policy?: Partial<HqRedactionPolicy>): string | undefined {\n if (value === undefined || value.length === 0) return undefined;\n if (policy?.rawContent === false) return '[REDACTED:hq_raw_content]';\n if (policy?.rawContent === true) {\n if (value.length <= maxLength) return value;\n return `${value.slice(0, maxLength)}\u2026`;\n }\n return scrubAndTruncateHqPreview(value, maxLength);\n}\n\nfunction readCount(message: MailboxMessage): number {\n return Object.keys(message.readBy).length;\n}\n\n/**\n * Classify a mailbox recipient address for UI labeling.\n *\n * - `'*'` (project broadcast) \u2192 `'project'`\n * - `@session:<id>` \u2192 `'session'` (returns the session id)\n * - everything else \u2192 `'agent'`\n */\nexport interface HqMailboxRecipientScope {\n scope: HqMailboxMessageScope;\n recipientSessionId?: string;\n}\n\nexport function classifyMailboxRecipient(to: string): HqMailboxRecipientScope {\n if (to === '*' || to === 'all') return { scope: 'project' };\n if (to.startsWith(SESSION_RECIPIENT_PREFIX)) {\n const recipientSessionId = to.slice(SESSION_RECIPIENT_PREFIX.length);\n if (recipientSessionId.length === 0) return { scope: 'agent' };\n return { scope: 'session', recipientSessionId };\n }\n return { scope: 'agent' };\n}\n\nfunction taskSummary(message: MailboxMessage): HqMailboxMessageSummary['task'] {\n if (message.taskContext === undefined) return undefined;\n const task = {\n ...(message.taskContext.taskId !== undefined ? { taskId: message.taskContext.taskId } : {}),\n ...(message.taskContext.agentRole !== undefined ? { agentRole: message.taskContext.agentRole } : {}),\n ...(message.taskContext.agentName !== undefined ? { agentName: message.taskContext.agentName } : {}),\n ...(message.taskContext.status !== undefined ? { status: message.taskContext.status } : {}),\n } satisfies HqMailboxMessageSummary['task'];\n return Object.keys(task).length > 0 ? task : undefined;\n}\n\nexport function mapMailboxMessageToHqSummary(\n message: MailboxMessage,\n options: Pick<HqMailboxMappingOptions, 'previewLength' | 'redactionPolicy'> = {},\n): HqMailboxMessageSummary {\n const previewLength = options.previewLength ?? 500;\n const bodyPreview = previewText(message.body, previewLength, options.redactionPolicy);\n const outcomePreview = previewText(message.outcome, previewLength, options.redactionPolicy);\n const task = taskSummary(message);\n const recipient = classifyMailboxRecipient(message.to);\n\n return {\n mailId: message.id, // unique UUID per message record, used for deduplication\n messageId: message.id,\n from: message.from,\n to: message.to,\n scope: recipient.scope,\n ...(recipient.recipientSessionId !== undefined ? { recipientSessionId: recipient.recipientSessionId } : {}),\n type: message.type,\n ...(message.audience !== undefined ? { audience: message.audience } : {}),\n subject: previewText(message.subject, previewLength, options.redactionPolicy) ?? '',\n priority: message.priority,\n timestamp: message.timestamp,\n ...(message.replyTo !== undefined ? { replyTo: message.replyTo } : {}),\n ...(message.senderSessionId !== undefined ? { senderSessionId: message.senderSessionId } : {}),\n completed: message.completed,\n ...(message.completedBy !== undefined ? { completedBy: message.completedBy } : {}),\n ...(message.completedAt !== undefined ? { completedAt: message.completedAt } : {}),\n readCount: readCount(message),\n hasBody: message.body.length > 0,\n ...(bodyPreview !== undefined ? { bodyPreview } : {}),\n ...(outcomePreview !== undefined ? { outcomePreview } : {}),\n ...(task !== undefined ? { task } : {}),\n };\n}\n\nexport function mapMailboxAgentToHqSummary(agent: MailboxAgentStatus): HqMailboxAgentSummary {\n return {\n agentId: agent.agentId,\n name: agent.name,\n ...(agent.role !== undefined ? { role: agent.role } : {}),\n sessionId: agent.sessionId,\n status: agent.status,\n ...(agent.currentTool !== undefined ? { currentTool: agent.currentTool } : {}),\n ...(agent.currentTask !== undefined ? { currentTask: agent.currentTask } : {}),\n iterations: agent.iterations,\n toolCalls: agent.toolCalls,\n lastActivityAt: agent.lastActivityAt,\n lastSeenAt: agent.lastSeenAt,\n online: agent.online,\n ...(agent.source !== undefined ? { source: agent.source } : {}),\n };\n}\n\nexport function createMailboxSnapshotPayload(\n messages: readonly MailboxMessage[],\n agents: readonly MailboxAgentStatus[],\n options: HqMailboxSnapshotOptions,\n): HqMailboxSnapshotPayload {\n const includeCompleted = options.includeCompleted ?? true;\n const filteredMessages = includeCompleted ? messages : messages.filter((message) => !message.completed);\n const limit = options.limit ?? 50;\n const sortedMessages = [...filteredMessages].sort((a, b) => b.timestamp.localeCompare(a.timestamp)).slice(0, limit);\n const summaries = sortedMessages.map((message) => mapMailboxMessageToHqSummary(message, options));\n const agentSummaries = agents.map(mapMailboxAgentToHqSummary);\n\n return {\n mailboxId: options.mailboxId,\n scope: options.scope ?? 'project',\n messages: summaries,\n agents: agentSummaries,\n totals: {\n messages: messages.length,\n unread: messages.filter((message) => !message.completed && readCount(message) === 0).length,\n incomplete: messages.filter((message) => !message.completed).length,\n highPriority: messages.filter((message) => message.priority === 'high').length,\n onlineAgents: agents.filter((agent) => agent.online).length,\n },\n };\n}\n\nexport async function createMailboxSnapshotPayloadFromMailbox(\n mailbox: Pick<Mailbox, 'query' | 'getAgentStatuses'>,\n options: HqMailboxSnapshotOptions,\n): Promise<HqMailboxSnapshotPayload> {\n const limit = options.limit ?? 50;\n const [messages, agents] = await Promise.all([\n mailbox.query({ limit }),\n mailbox.getAgentStatuses(),\n ]);\n return createMailboxSnapshotPayload(messages, agents, options);\n}\n\nexport function createMailboxEventPayload(input: {\n mailboxId: string;\n action: HqMailboxEventAction;\n message?: MailboxMessage;\n agent?: MailboxAgentStatus;\n summary?: string;\n previewLength?: number;\n redactionPolicy?: Partial<HqRedactionPolicy>;\n}): HqMailboxEventPayload {\n const summaryOptions: Pick<HqMailboxMappingOptions, 'previewLength' | 'redactionPolicy'> = {\n ...(input.previewLength !== undefined ? { previewLength: input.previewLength } : {}),\n ...(input.redactionPolicy !== undefined ? { redactionPolicy: input.redactionPolicy } : {}),\n };\n\n return {\n mailboxId: input.mailboxId,\n action: input.action,\n ...(input.message !== undefined ? { message: mapMailboxMessageToHqSummary(input.message, summaryOptions) } : {}),\n ...(input.agent !== undefined ? { agent: mapMailboxAgentToHqSummary(input.agent) } : {}),\n ...(input.summary !== undefined\n ? { summary: previewText(input.summary, input.previewLength ?? 160, input.redactionPolicy) ?? '' }\n : {}),\n };\n}\n", "/**\n * mailbox-tool \u2014 Tool that exposes the inter-agent mailbox to agents.\n *\n * Sub-commands: check, send, ack, query, status, online, unread\n *\n * Uses the server-backed project mailbox for cross-session communication.\n * Agents are auto-registered on first use with heartbeat tracking.\n * Read receipts track who read each message and when.\n *\n * @module mailbox-tool\n */\n\nimport { createHash } from 'node:crypto';\nimport type { EventBus } from '../kernel/events.js';\nimport type { Context } from '../core/context.js';\nimport type { Tool } from '../types/tool.js';\nimport { ToolCapabilities } from '../security/capabilities.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport { wstackGlobalRoot } from '../utils/wstack-paths.js';\nimport { resolveProjectDir } from './global-mailbox-paths.js';\nimport { getSharedProjectMailbox } from './remote-mailbox.js';\nimport { resolveSendTypeSafe } from './mailbox-message-codec.js';\nimport {\n isMailboxMessageVisibleTo,\n normalizeRecipient,\n type Mailbox,\n type MailboxAudience,\n type MailboxMessage,\n type MailboxMessageType,\n} from './mailbox-types.js';\n\nexport type MailboxResolver = (ctx: Context) => Mailbox;\n\nexport interface MailboxToolOptions {\n /**\n * How to obtain a Mailbox instance given the execution Context.\n * Default: derives the project dir and connects to its mailbox owner.\n */\n resolveMailbox?: MailboxResolver | undefined;\n /**\n * Agent id of the caller \u2014 used as default \"from\" on send.\n * Default: 'leader' for the main agent, or derived from ctx.meta.\n */\n agentId?: string | undefined;\n /** Session id for cross-session communication. Default: derived from ctx. */\n sessionId?: string | undefined;\n /**\n * Project directory where the mailbox is stored.\n * Default: derived from ctx.projectRoot (may differ from wpaths.projectDir).\n * For correct cross-session sharing, pass `wpaths.projectDir` from the caller.\n */\n projectDir?: string | undefined;\n /**\n * EventBus for emitting mailbox.agent_registered and mailbox.agent_heartbeat\n * events so the TUI/WebUI can update the online agent count in the status bar.\n * When omitted, events are not emitted and the status bar count stays at 0.\n */\n events?: EventBus | undefined;\n}\n\nexport function defaultResolveProjectDir(ctx: Context): string {\n return resolveProjectDir(ctx.projectRoot, wstackGlobalRoot());\n}\n\n/**\n * Compact, deterministic tag for a session id \u2014 8 hex chars of its sha256.\n * Session ids are date-sharded paths (\"2026-06-11/sess_<ULID>\");\n * the tag keeps mailbox identities short, filesystem-safe, and stable for\n * the lifetime of the session (including across process restarts/resumes).\n */\nexport function mailboxSessionTag(sessionId: string): string {\n return createHash('sha256').update(sessionId).digest('hex').slice(0, 8);\n}\n\n/**\n * Resolve the caller's mailbox identity from the execution Context.\n *\n * Shared by the `mailbox` power-tool, the thin `mail_send`/`mail_inbox`\n * tools, the agent-loop checker, and the /mailbox slash command so every\n * surface agrees on who is talking:\n * - base id: ctx.meta.agentId \u2192 ctx.agentId field (subagents) \u2192 fallback\n * - unique id: `<base>@<sessionTag>` \u2014 SESSION-bound, not pid-bound. Every\n * session has its own id, so two leader sessions on the same project\n * never collide (pids can be recycled by the OS), and a resumed session\n * keeps its identity: read state survives a restart instead of\n * re-flooding old broadcasts. Derived LIVE from ctx.session.id so an\n * in-process session swap (resume / session.new / project switch) moves\n * the identity with it. `ctx.meta.globalAgentId` remains an explicit\n * override for hosts that manage identity themselves.\n */\nexport function resolveMailboxIdentity(\n ctx: Context,\n fallbackBase = 'leader',\n): { baseId: string; callerId: string; name: string; role?: string | undefined; sessionId: string } {\n const fieldId =\n ctx.agentId && ctx.agentId !== 'unknown' ? ctx.agentId : undefined;\n const baseId = (ctx.meta['agentId'] as string | undefined) ?? fieldId ?? fallbackBase;\n const sessionId = (ctx.meta['sessionId'] as string | undefined) ?? ctx.session?.id ?? 'default';\n const callerId =\n (ctx.meta['globalAgentId'] as string | undefined) ??\n `${baseId}@${mailboxSessionTag(sessionId)}`;\n const fieldName =\n ctx.agentName && ctx.agentName !== 'Unknown Agent' ? ctx.agentName : undefined;\n const name = (ctx.meta['agentName'] as string | undefined) ?? fieldName ?? baseId;\n const role = ctx.meta['agentRole'] as string | undefined;\n return { baseId, callerId, name, role, sessionId };\n}\n\n/**\n * Apply sender-specific delivery restrictions before a message is persisted.\n * Chimera workers report only to main agents; enforcing that here keeps the\n * invariant intact even if a model requests a peer or project broadcast.\n */\nexport function applyMailboxSendPolicy(\n ctx: Context,\n identity: Pick<ReturnType<typeof resolveMailboxIdentity>, 'baseId' | 'name'>,\n requestedTo: string,\n requestedAudience?: MailboxAudience,\n): { to: string; audience?: MailboxAudience } {\n const policy = ctx.meta['mailboxSendPolicy'];\n const isChimeraIdentity = (value: string) => {\n const normalized = value.trim().toLowerCase();\n return normalized === 'chimera' || normalized.startsWith('chimera-');\n };\n const chimeraSender =\n isChimeraIdentity(identity.baseId) || isChimeraIdentity(identity.name);\n if (policy === 'leaders-only' || chimeraSender) {\n return { to: 'leader', audience: 'leaders' };\n }\n return {\n to: requestedTo,\n ...(requestedAudience !== undefined ? { audience: requestedAudience } : {}),\n };\n}\n\nexport function makeMailboxTool(opts: MailboxToolOptions = {}): Tool {\n const resolveMailbox = opts.resolveMailbox ?? ((ctx: Context) => {\n const dir = opts.projectDir ?? defaultResolveProjectDir(ctx);\n return getSharedProjectMailbox(dir, opts.events);\n });\n const agentId = opts.agentId ?? 'leader';\n const sessionId = opts.sessionId ?? 'default';\n\n const shortHint =\n 'Sub-commands: check (unread), send (exact/base/@session/project broadcast), ack (read/complete), query (filter), status (all agents), online (active only), unread (count).';\n\n return {\n name: 'mailbox',\n description:\n 'Low-level inter-agent mailbox with 7 actions (check, send, ack, query, status, online, unread). ' +\n 'For most use cases, prefer the simpler `mail_send` and `mail_inbox` tools \u2014 they cover the ' +\n 'common send/read operations with a cleaner interface. This tool is for advanced queries ' +\n '(filter by sender, sender session, priority, since-timestamp), agent status/online lists, and message ack/control. ' +\n 'Use to=\"@session\" only for session-local coordination; use \"*\" or a base alias when another session may be affected.',\n usageHint: shortHint + ' For simple send/read, use mail_send / mail_inbox instead.',\n category: 'Coordination',\n permission: 'auto',\n mutating: true,\n capabilities: [ToolCapabilities.COORDINATION_MAIL],\n inputSchema: {\n type: 'object',\n properties: {\n action: {\n type: 'string',\n enum: ['check', 'send', 'ack', 'query', 'status', 'online', 'unread'],\n description: 'Which mailbox operation to perform.',\n },\n to: { type: 'string', description: \"Recipient agent id, base alias, '@session' for the sender's session, or '*' / 'all' for project broadcast.\" },\n type: { type: 'string', enum: ['note', 'ask', 'assign', 'steer', 'btw', 'broadcast', 'status', 'result', 'review', 'control'], description: 'Required message intent. Actionable: ask (blocking question), assign (task delegation, must have specific to), steer (mid-course direction), review (passive ask). Informational: note (general FYI), btw (low-priority aside), result (completion notice), status (system update). Routing: broadcast (multi-recipient). Reserved: control (runtime only, agents cannot send).' },\n subject: { type: 'string', description: 'Short subject line.' },\n body: { type: 'string', description: 'Full message content.' },\n priority: { type: 'string', enum: ['low', 'normal', 'high'] },\n audience: { type: 'string', enum: ['all', 'leaders'], description: 'Delivery audience. \"leaders\" prevents subagent consumption.' },\n replyTo: { type: 'string', description: 'Reply to a specific message id.' },\n messageId: { type: 'string', description: \"Message id to acknowledge. Required for 'ack'.\" },\n read: { type: 'boolean', description: 'Mark as read (adds read receipt).' },\n markRead: { type: 'boolean', description: 'For action=check, add read receipts for returned messages (default true).' },\n completed: { type: 'boolean', description: 'Mark as completed. For action=check, completes every returned message.' },\n outcome: { type: 'string', description: 'Outcome summary when marking complete.' },\n unreadBy: { type: 'string', description: \"Filter messages unread by this agent. Used by 'check'.\" },\n incompleteOnly: { type: 'boolean', description: 'Only incomplete messages.' },\n from: { type: 'string', description: \"Filter by sender.\" },\n minPriority: { type: 'string', enum: ['low', 'normal', 'high'] },\n since: { type: 'string', description: 'ISO8601 timestamp \u2014 only messages after this.' },\n sessionId: { type: 'string', description: 'Filter query results by sender session id.' },\n limit: { type: 'number', description: 'Max messages to return.' },\n },\n required: ['action'],\n },\n async execute(input: unknown, ctx: Context) {\n const mb = resolveMailbox(ctx);\n const i = (input ?? {}) as Record<string, unknown>;\n const action = i.action as string | undefined;\n // Prefer the process-unique identity set by attachMailboxChecker\n // (`leader#<pid>`) so registration/receipts/sends agree with the\n // agent-loop checker. The bare base id stays addressable as an alias.\n const identity = resolveMailboxIdentity(ctx, agentId);\n const baseCallerId = identity.baseId;\n const callerId = identity.callerId;\n const callerSessionId =\n (ctx.meta['sessionId'] as string) ?? (ctx.session?.id ?? sessionId);\n\n // Auto-register this agent on first use (idempotent)\n try {\n await mb.registerAgent({\n agentId: callerId,\n sessionId: callerSessionId,\n name: identity.name,\n role: identity.role,\n pid: process.pid,\n source: (ctx.meta['source'] as 'cli' | 'webui' | undefined) ?? 'cli',\n });\n } catch { /* best-effort */ }\n\n // Update heartbeat\n try {\n await mb.heartbeat({ agentId: callerId });\n } catch { /* best-effort */ }\n\n switch (action) {\n case 'check':\n return executeCheck(mb, callerId, callerSessionId, [baseCallerId], identity.role, i);\n case 'send':\n return executeSend(mb, identity, callerSessionId, i, ctx);\n case 'ack':\n return executeAck(mb, callerId, i);\n case 'query':\n return executeQuery(mb, callerId, identity.role, i);\n case 'status':\n return executeStatus(mb);\n case 'online':\n return executeOnline(mb);\n case 'unread':\n return executeUnread(mb, callerId, callerSessionId, [baseCallerId], identity.role);\n default:\n return { ok: false, error: `Unknown action: \"${action}\". Use check, send, ack, query, status, online, or unread.` };\n }\n },\n };\n}\n\n// \u2500\u2500 Action handlers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function executeCheck(\n mb: Mailbox,\n agentId: string,\n sessionId: string,\n aliases: string[],\n role: string | undefined,\n i: Record<string, unknown>,\n) {\n const limit = (i.limit as number) ?? 20;\n const markRead = (i.markRead as boolean | undefined) ?? true;\n const completed = (i.completed as boolean | undefined) ?? false;\n const outcome = i.outcome as string | undefined;\n // Check unique id + base aliases + same-session broadcast. Project\n // broadcasts match every query and are deduped by message id below.\n const targets = [\n agentId,\n ...aliases.filter((al) => al && al !== agentId),\n `@session:${sessionId}`,\n ];\n const batches = await Promise.all(\n targets.map((to) =>\n mb.query({ to, unreadBy: agentId, readerRole: role, limit, minPriority: 'low' }).catch(() => []),\n ),\n );\n const seen = new Set<string>();\n const messages = batches.flat().filter((m) => {\n if (seen.has(m.id)) return false;\n if (!isMailboxMessageVisibleTo(m, agentId, role)) return false;\n seen.add(m.id);\n return true;\n });\n\n // Auto-read: add read receipts for each message by default. Use the batch\n // path so catch-up checks perform one locked rewrite instead of N rewrites.\n // Return the post-ack snapshots so readByMe/completed reflect this call.\n const acked = markRead || completed\n ? await mb\n .ackMany({\n acks: messages.map((m) => ({\n messageId: m.id,\n readerId: agentId,\n read: markRead,\n completed,\n outcome: completed ? outcome : undefined,\n })),\n })\n .catch(() => messages)\n : messages;\n\n return {\n ok: true,\n count: acked.length,\n messages: acked.map((m) => formatMessage(m, agentId)),\n summary: acked.length === 0 ? 'No unread messages.' : `${acked.length} unread message(s)${markRead ? ' (marked read)' : ''}${completed ? ' (completed)' : ''}.`,\n };\n}\n\nasync function executeSend(\n mb: Mailbox,\n identity: ReturnType<typeof resolveMailboxIdentity>,\n sessionId: string,\n i: Record<string, unknown>,\n ctx: Context,\n) {\n const to = i.to as string | undefined;\n const tp = i.type as string | undefined;\n const subject = i.subject as string | undefined;\n const body = i.body as string | undefined;\n const audience = i.audience as MailboxAudience | undefined;\n\n if (!to) return { ok: false, error: '\"to\" is required.' };\n if (!tp) return { ok: false, error: '\"type\" is required.' };\n if (!subject) return { ok: false, error: '\"subject\" is required.' };\n // Empty string is a legitimate body (e.g. subject-only status pings) \u2014\n // only reject when the field is genuinely absent.\n if (body === undefined || body === null) return { ok: false, error: '\"body\" is required.' };\n if (audience !== undefined && audience !== 'all' && audience !== 'leaders') {\n return { ok: false, error: '\"audience\" must be \"all\" or \"leaders\".' };\n }\n\n // Resolve and validate the (type, to) pair using the canonical helper.\n // This enforces: control is reserved, assign/steer to \"*\" is rejected.\n let normalizedTo: string;\n try {\n normalizedTo = normalizeRecipient(to, sessionId);\n } catch (err) {\n return { ok: false, error: `\"to\" is invalid: ${toErrorMessage(err)}` };\n }\n const delivery = applyMailboxSendPolicy(ctx, identity, normalizedTo, audience);\n const typeResult = resolveSendTypeSafe(tp as MailboxMessageType, delivery.to);\n if (!typeResult.ok) return { ok: false, error: `\"type\" is invalid: ${typeResult.error}` };\n\n const msg = await mb.send({\n from: identity.callerId,\n to: delivery.to, type: typeResult.type, subject, body,\n audience: delivery.audience,\n priority: (i.priority as 'low' | 'normal' | 'high') ?? 'normal',\n replyTo: i.replyTo as string | undefined,\n senderSessionId: sessionId,\n });\n\n return {\n ok: true, messageId: msg.id, to: msg.to, type: msg.type, timestamp: msg.timestamp,\n summary: `Message sent to ${msg.to === '*' ? 'all agents' : msg.to}. Id: ${msg.id}`,\n };\n}\n\nasync function executeAck(mb: Mailbox, agentId: string, i: Record<string, unknown>) {\n const messageId = i.messageId as string | undefined;\n if (!messageId) return { ok: false, error: '\"messageId\" is required.' };\n\n const updated = await mb.ack({\n messageId,\n readerId: agentId,\n read: i.read as boolean | undefined,\n completed: i.completed as boolean | undefined,\n outcome: i.outcome as string | undefined,\n });\n\n if (!updated) return { ok: false, error: `Message \"${messageId}\" not found.` };\n\n return {\n ok: true, messageId: updated.id,\n readBy: Object.keys(updated.readBy),\n readByCount: Object.keys(updated.readBy).length,\n completed: updated.completed,\n completedBy: updated.completedBy,\n outcome: updated.outcome,\n summary: `Message ${messageId} acknowledged. Read by ${Object.keys(updated.readBy).length} agent(s), Completed: ${updated.completed}.`,\n };\n}\n\nasync function executeQuery(\n mb: Mailbox,\n agentId: string,\n role: string | undefined,\n i: Record<string, unknown>,\n) {\n const limit = (i.limit as number) ?? 50;\n const messages = await mb.query({\n to: i.to as string | undefined,\n from: i.from as string | undefined,\n unreadBy: i.unreadBy as string | undefined,\n incompleteOnly: i.incompleteOnly as boolean | undefined,\n type: i.type as MailboxMessageType | undefined,\n minPriority: i.minPriority as 'low' | 'normal' | 'high' | undefined,\n since: i.since as string | undefined,\n sessionId: i.sessionId as string | undefined,\n limit,\n });\n const visible = messages.filter((message) => isMailboxMessageVisibleTo(message, agentId, role));\n return { ok: true, count: visible.length, messages: visible, summary: `${visible.length} message(s).` };\n}\n\nasync function executeStatus(mb: Mailbox) {\n const agents = await mb.getAgentStatuses();\n return {\n ok: true, count: agents.length,\n agents: agents.map((a) => ({\n agentId: a.agentId, name: a.name, role: a.role, sessionId: a.sessionId,\n status: a.status, currentTool: a.currentTool, currentTask: a.currentTask,\n iterations: a.iterations, toolCalls: a.toolCalls,\n lastSeenAt: a.lastSeenAt, online: a.online, pid: a.pid, source: a.source,\n })),\n summary: `${agents.filter((a) => a.online).length} online, ${agents.length} total.`,\n };\n}\n\nasync function executeOnline(mb: Mailbox) {\n const agents = await mb.getOnlineAgents();\n return {\n ok: true, count: agents.length,\n agents: agents.map((a) => ({\n agentId: a.agentId, name: a.name, role: a.role, sessionId: a.sessionId,\n status: a.status, currentTool: a.currentTool, currentTask: a.currentTask,\n lastSeenAt: a.lastSeenAt, source: a.source,\n })),\n summary: `${agents.length} online agent(s).`,\n };\n}\n\nasync function executeUnread(\n mb: Mailbox,\n agentId: string,\n sessionId: string,\n aliases: string[] = [],\n role?: string,\n) {\n // Count unique id + base aliases + same-session broadcast; project\n // broadcasts match every query and are deduped by id.\n const targets = [\n agentId,\n ...aliases.filter((al) => al && al !== agentId),\n `@session:${sessionId}`,\n ];\n const batches = await Promise.all(\n targets.map((to) => mb.query({ to, unreadBy: agentId, readerRole: role, limit: 200 }).catch(() => [])),\n );\n const ids = new Set(\n batches.flat().filter((m) => isMailboxMessageVisibleTo(m, agentId, role)).map((m) => m.id),\n );\n return { ok: true, count: ids.size, summary: `${ids.size} unread message(s) for you.` };\n}\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction formatMessage(m: MailboxMessage, readerId: string) {\n const maxBody = 2000;\n const truncated = m.body.length > maxBody ? `${m.body.slice(0, maxBody)}\u2026 [truncated]` : m.body;\n return {\n id: m.id, from: m.from, to: m.to, type: m.type, audience: m.audience ?? 'all',\n subject: m.subject, body: truncated, priority: m.priority,\n readByMe: readerId in m.readBy,\n readByCount: Object.keys(m.readBy).length,\n readBy: m.readBy,\n completed: m.completed, completedBy: m.completedBy,\n outcome: m.outcome, timestamp: m.timestamp,\n replyTo: m.replyTo, senderSessionId: m.senderSessionId,\n };\n}\n", "/**\n * mailbox-loop \u2014 Agent-loop integration for mailbox checking.\n *\n * Integrates the inter-agent mailbox into the agent's iteration cycle.\n * Before each LLM call, checks for unread messages from subagents and other\n * agents. Normal surfaces inject message content inline. Minimal surfaces may\n * use background delivery: routine chatter remains telemetry-only, while\n * actionable asks/results/steers still reach the agent.\n *\n * Uses the project-level mailbox (one detached owner, reached over IPC) for\n * cross-session communication.\n *\n * ## Type-based dispatch\n *\n * The dispatch logic in this file is the **receive-side** of the type\n * semantics contract (the send-side lives in `mailbox-message-codec.ts`).\n *\n * Every type must have explicit handling. The contract is enforced by\n * `MAILBOX_TYPE_PROPERTIES` in mailbox-types.ts: adding a new type to the\n * `MailboxMessageType` union requires a corresponding entry.\n *\n * @module mailbox-loop\n */\n\nimport type { Mailbox, MailboxMessage, MailboxMessageType } from '../coordination/mailbox-types.js';\nimport type { TextBlock } from '../types/blocks.js';\nimport type { Message } from '../types/messages.js';\nimport { toErrorMessage } from '../utils/error.js';\n\nexport interface MailboxLoopOptions {\n /**\n * The mailbox instance, or a getter that returns the current mailbox.\n * A getter is used when the agent may switch projects at runtime \u2014\n * the mailbox resolves from the current `ctx.projectRoot` on each\n * check rather than being captured at construction time.\n */\n mailbox: Mailbox | (() => Mailbox);\n /**\n * The agent's globally unique mailbox identity (e.g. `leader@a1b2c3d4`,\n * session-bound). Read receipts are recorded under this id, so two\n * sessions whose leaders share a base name never consume each other's\n * receipts. Pass a GETTER when the identity can change at runtime (an\n * in-process session swap moves the leader onto a new session tag).\n */\n agentId: string | (() => string);\n /** Current roster role, used by leader-only delivery filtering. */\n role?: string | (() => string | undefined) | undefined;\n /**\n * Additional addresses this agent also answers to \u2014 typically the bare\n * base id (`leader`). Lets other agents (and humans) address \"leader\"\n * without knowing the session tag; every live leader session receives it.\n */\n aliases?: string[] | undefined;\n /** Optional delivery predicate applied before dedup/read receipts. */\n include?: ((message: MailboxMessage) => boolean) | undefined;\n /**\n * Current session id. When provided, mail addressed to `@session:<id>` is\n * delivered alongside direct, alias, and project-broadcast mail.\n */\n sessionId?: string | (() => string) | undefined;\n /** Mark returned messages as read. Defaults to true for normal delivery. */\n ack?: boolean | undefined;\n /**\n * ISO timestamp below which project-wide broadcasts (`to: '*'`) are ignored.\n * Defaults to the moment this checker is constructed \u2014 i.e. a broadcast is\n * delivered only to sessions that were live when it was sent.\n *\n * Without this floor, every NEW session replayed the whole retained\n * broadcast backlog. Read receipts are keyed by `agentId`, which is derived\n * from the session id (`base@sha256(sessionId)`), so a new session gets an\n * identity that appears in no existing `readBy` map and `unreadBy` matches\n * everything within the 24h retention window. Observed in the wild: 630\n * messages carrying 26,406 ack records \u2014 240 distinct reader identities,\n * single messages acked up to 61 times \u2014 with leaders repeatedly reasoning\n * about \"peer noise\" from work that had already been committed.\n *\n * Scoped to broadcasts on purpose. Directed mail (unique id, base alias,\n * `@session:` scope) was addressed deliberately and must still be delivered\n * even if it was sent before this session existed; a human running\n * `wstack mailbox send --to leader` and then starting a session expects it\n * to arrive. Broadcasts are ambient announcements (\"X joined the fleet\",\n * \"task success\") and were 619 of those 630 messages.\n */\n broadcastFloor?: string | undefined;\n}\n\nexport function createMailboxChecker(\n opts: MailboxLoopOptions,\n): () => Promise<MailboxMessage[]> {\n const getMailbox = typeof opts.mailbox === 'function' ? opts.mailbox : () => opts.mailbox as Mailbox;\n const currentId = typeof opts.agentId === 'function' ? opts.agentId : () => opts.agentId as string;\n const currentSessionId =\n typeof opts.sessionId === 'function' ? opts.sessionId : () => opts.sessionId;\n const currentRole: () => string | undefined =\n typeof opts.role === 'function' ? opts.role : () => opts.role as string | undefined;\n\n const injectedIds = new Set<string>();\n const broadcastFloor = opts.broadcastFloor ?? new Date().toISOString();\n\n return async (): Promise<MailboxMessage[]> => {\n try {\n const mailbox = getMailbox();\n const agentId = currentId();\n const role = currentRole();\n const sessionId = currentSessionId();\n const targets = [\n agentId,\n ...(opts.aliases ?? []).filter((al) => al && al !== agentId),\n ...(sessionId ? [`@session:${sessionId}`] : []),\n ];\n // Query ALL unread messages across every address this agent answers\n // to (unique id, base-id aliases, session scope; '*' broadcasts match\n // each query and are deduped below). Receipts always use the unique id.\n const batches = await Promise.all(\n targets.map((to) =>\n mailbox.query({ to, unreadBy: agentId, readerRole: role, limit: 10 }).catch(() => [] as MailboxMessage[]),\n ),\n );\n const seen = new Set<string>();\n const messages: MailboxMessage[] = [];\n for (const batch of batches) {\n for (const m of batch) {\n if (seen.has(m.id)) continue;\n // Pre-existing broadcasts are dropped WITHOUT an ack. Acking them\n // would stamp this session's identity onto the entire retained\n // backlog on first check \u2014 the exact write amplification that\n // produced 26k ack records against 630 messages. Left unread they\n // simply age out with the 24h retention sweep, and they cannot\n // starve new mail: query sorts newest-first before applying `limit`.\n if (m.to === '*' && m.timestamp < broadcastFloor) continue;\n if (opts.include && !opts.include(m)) continue;\n seen.add(m.id);\n messages.push(m);\n }\n }\n\n // Filter out already-injected and completed messages\n const fresh = messages.filter(\n (m) => !injectedIds.has(m.id) && !m.completed,\n );\n\n // Track as injected\n for (const m of fresh) {\n injectedIds.add(m.id);\n }\n\n // Auto-read all fresh messages (adds read receipt) in a single batched\n // call. The previous per-message ack() did a full read-modify-rewrite\n // of the mailbox file for every fresh message \u2014 N fresh messages\n // meant N full-file rewrites in a row on every iteration.\n if (fresh.length > 0 && opts.ack !== false) {\n void mailbox\n .ackMany({\n acks: fresh.map((m) => ({\n messageId: m.id,\n readerId: agentId,\n read: true,\n })),\n })\n .catch(() => {});\n }\n\n // GC\n if (injectedIds.size > 1000) {\n const recent = new Set([...injectedIds].slice(-500));\n injectedIds.clear();\n for (const id of recent) injectedIds.add(id);\n }\n\n return fresh;\n } catch {\n return [];\n }\n };\n}\n\n/**\n * Human-readable emoji prefix for each message type. Types not in this map\n * fall through to a generic `\uD83D\uDCE8 <TYPE>` prefix so a newly-added MailboxMessageType\n * still renders sensibly without needing an immediate code change here.\n */\nconst TYPE_LABEL: Partial<Record<MailboxMessage['type'], string>> = {\n steer: '\uD83D\uDD04 STEER',\n btw: '\uD83D\uDCAC BTW',\n ask: '\u2753 ASK',\n assign: '\uD83D\uDCCB ASSIGN',\n result: '\u2705 RESULT',\n review: '\uD83D\uDD0D REVIEW',\n status: '\uD83D\uDCE8 STATUS',\n note: '\uD83D\uDCE8 NOTE',\n broadcast: '\uD83D\uDCE2 BROADCAST',\n control: '\u2699 CONTROL',\n};\n\n/**\n * Lookup table: maps each MailboxMessageType to the guidance text appended\n * after the message body in `buildMailboxBlock()`. Every type gets explicit\n * guidance \u2014 no fallthrough to an empty string.\n */\nconst TYPE_GUIDANCE: Record<MailboxMessageType, string> = {\n steer: 'After your current operation reaches a stopping point, adjust your approach per the instruction above.',\n ask: 'This agent is waiting for your answer. Reply directly or use mailbox action=send to respond.',\n assign: 'This is a task assignment. Act on it when your current operation allows.',\n result: 'A subagent has completed its work. Factor this result into your next decision.',\n btw: 'FYI only \u2014 absorb the information and stay on your current task; no reply needed.',\n status: 'Peer status update \u2014 use it to avoid duplicate or conflicting work; no reply needed.',\n review: 'This is a review request. Inspect the referenced code/doc/PR when convenient; an immediate reply is not required.',\n note: 'Read for context; no reply needed.',\n broadcast: 'Broadcast message. Read for context; no reply needed.',\n control: '', // control never reaches this rendering path \u2014 see injectPendingMailboxMessages\n};\n\n// Keep receive-side dispatch policy in the core layer. Importing the\n// coordination layer's runtime policy table here creates a core \u2194 coordination\n// dependency cycle; the message union remains a type-only contract.\nconst ACTION_FOOTER_TYPES = new Set<MailboxMessageType>([\n 'ask',\n 'assign',\n 'result',\n 'review',\n]);\nconst BACKGROUND_DELIVERY_TYPES = new Set<MailboxMessageType>([\n 'steer',\n 'ask',\n 'assign',\n 'result',\n 'review',\n]);\nconst OUT_OF_BAND_TYPES = new Set<MailboxMessageType>(['control']);\n\nexport function buildMailboxBtwAwarenessBlock(messages: MailboxMessage[]): { type: 'text'; text: string } {\n if (messages.length === 0) throw new Error('buildMailboxBtwAwarenessBlock called with empty messages');\n\n const parts: string[] = [];\n parts.push('[MAILBOX BTW] Mailbox awareness update:');\n parts.push('');\n parts.push(\n 'Disclaimer: an agent just sent mail to everyone or to you. Do not stop your current work to look at it; this is only for awareness. This notification came from the WrongStack mailbox system.',\n );\n parts.push('');\n\n for (const m of messages) {\n const typeLabel = TYPE_LABEL[m.type] ?? `\uD83D\uDCE8 ${m.type.toUpperCase()}`;\n const scope = m.to === '*' ? 'broadcast to everyone' : `addressed to ${m.to}`;\n parts.push(`--- ${typeLabel} from ${m.from} (${scope}) ---`);\n parts.push(`Subject: ${m.subject}`);\n parts.push('');\n parts.push(m.body);\n parts.push('');\n }\n\n parts.push('This raw awareness block is request-scoped; absorb it once without quoting or restating it.');\n parts.push('');\n parts.push('[END MAILBOX BTW]');\n return { type: 'text', text: parts.join('\\n') };\n}\n\nexport function buildMailboxBlock(messages: MailboxMessage[]): { type: 'text'; text: string } {\n if (messages.length === 0) throw new Error('buildMailboxBlock called with empty messages');\n\n const parts: string[] = [];\n parts.push('[MAILBOX] New message(s) from other agents:');\n parts.push('');\n\n // Steers alter the current approach inline, but do not require a separate\n // mailbox acknowledgement footer. Ask/assign/result/review messages do.\n const hasActionable = messages.some((m) => ACTION_FOOTER_TYPES.has(m.type));\n\n // Steer messages always come first \u2014 they are mid-task behavior changes\n // and the model must see them before any other action items, otherwise\n // it can finish an ask/assign/result before adjusting course. We do NOT\n // mutate `messages` itself (the caller still owns it for dedup) \u2014 we\n // build a local render order via a single-pass partition.\n const steers: MailboxMessage[] = [];\n const rest: MailboxMessage[] = [];\n for (const m of messages) {\n if (m.type === 'steer') steers.push(m);\n else rest.push(m);\n }\n const ordered = [...steers, ...rest];\n\n for (const m of ordered) {\n const typeLabel = TYPE_LABEL[m.type] ?? `\uD83D\uDCE8 ${m.type.toUpperCase()}`;\n parts.push(`--- ${typeLabel} from ${m.from} ---`);\n parts.push(`Subject: ${m.subject}`);\n parts.push('');\n parts.push(m.body);\n parts.push('');\n // Every type gets explicit guidance via the TYPE_GUIDANCE lookup.\n // control messages never reach this path (filtered upstream).\n const guidance = TYPE_GUIDANCE[m.type];\n if (guidance) {\n parts.push(`${guidance}`);\n parts.push('');\n }\n }\n\n if (hasActionable) {\n parts.push('Action required: address the items above. When done, use `mailbox action=ack messageId=<id> completed=true` to mark them complete.');\n parts.push('');\n }\n\n parts.push(\n 'Context policy: this raw mailbox block is request-scoped and will be removed after you evaluate it. Do not quote or restate the mail. If it has a durable consequence, retain only one concise conclusion/action in your response, task state, or tool output; otherwise acknowledge it internally and continue.',\n );\n parts.push('');\n\n parts.push('[END MAILBOX]');\n return { type: 'text', text: parts.join('\\n') };\n}\n\n/**\n * Remove request-scoped mailbox blocks after the provider has evaluated them.\n *\n * Mail is folded into a user message before request construction so normal\n * context-window accounting and provider role alternation still work. Keeping\n * the raw block after that request, however, makes every later request pay for\n * and reconsider the same mail. This helper removes only the exact text blocks\n * injected by the current run. Any assistant response, tool call/result, todo,\n * or other durable consequence remains in the conversation.\n */\nexport function removeInjectedMailboxBlocks(\n messages: readonly Message[],\n injectedBlocks: readonly TextBlock[],\n): { messages: Message[]; changed: boolean } {\n if (injectedBlocks.length === 0) {\n return { messages: messages as Message[], changed: false };\n }\n\n const blockRefs = new Set<TextBlock>(injectedBlocks);\n const blockTexts = new Set(injectedBlocks.map((block) => block.text));\n const next: Message[] = [];\n let changed = false;\n\n for (const message of messages) {\n if (!Array.isArray(message.content)) {\n next.push(message);\n continue;\n }\n\n const content = message.content.filter((block) => {\n if (block.type !== 'text') return true;\n const isInjected = blockRefs.has(block) || blockTexts.has(block.text);\n if (isInjected) changed = true;\n return !isInjected;\n });\n\n if (content.length === message.content.length) {\n next.push(message);\n continue;\n }\n if (content.length === 0) continue;\n\n // The cached estimate belongs to the pre-removal content.\n const { _estTokens: _staleEstimate, ...rest } = message;\n next.push({ ...rest, content });\n }\n\n return changed ? { messages: next, changed: true } : { messages: messages as Message[], changed: false };\n}\n\n// \u2500\u2500 Integration hooks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// attachMailboxChecker (which resolves the concrete project mailbox) lives\n// in ../mailbox-attach.ts \u2014 the composition layer \u2014 so this file stays free\n// of runtime coordination/ imports (architecture Rule 3).\n\n/** Result of an inject pass \u2014 signals an out-of-band control request. */\ninterface MailboxInjectResult {\n /** A fresh `control:interrupt` message asked this agent to stop. */\n interrupt: boolean;\n /** Operator-supplied reason for the interrupt, if any. */\n interruptReason?: string | undefined;\n}\n\nexport type MailboxDeliveryMode = 'inline' | 'background';\n\nexport async function injectPendingMailboxMessages(\n checkMailbox: () => Promise<MailboxMessage[]>,\n foldFn: (block: { type: 'text'; text: string }) => void,\n a: { events: { emit: (type: string, payload: unknown) => void }; logger: { debug?: (...args: unknown[]) => void } },\n deliveryMode: MailboxDeliveryMode = 'inline',\n): Promise<MailboxInjectResult> {\n let messages: MailboxMessage[];\n try {\n messages = await checkMailbox();\n } catch {\n return { interrupt: false };\n }\n\n // Emit events for all found messages\n for (const m of messages) {\n a.events.emit('mailbox.received', {\n messageId: m.id,\n from: m.from,\n to: m.to,\n type: m.type,\n audience: m.audience ?? 'all',\n subject: m.subject,\n });\n }\n\n if (messages.length === 0) return { interrupt: false };\n\n // out-of-band messages (e.g. `control`) are out-of-band signals handled\n // by the runtime, NOT conversation content \u2014 keep them out of the folded\n // block so they never pollute the transcript. The canonical\n const outOfBand = messages.filter((m) => OUT_OF_BAND_TYPES.has(m.type));\n const content = messages.filter((m) => !OUT_OF_BAND_TYPES.has(m.type));\n const deliveredContent =\n deliveryMode === 'background'\n ? content.filter((message) => BACKGROUND_DELIVERY_TYPES.has(message.type))\n : content;\n\n if (deliveredContent.length > 0) {\n try { foldFn(buildMailboxBlock(deliveredContent)); } catch (err) {\n (a.logger.debug ?? console.debug)?.(\n `mailbox: failed to fold messages: ${toErrorMessage(err)}`,\n );\n }\n }\n\n // An interrupt control message (subject/body naming a stop) asks the loop to\n // halt cooperatively at the next iteration boundary.\n const interruptMsg = outOfBand.find(\n (m) => /\\b(interrupt|stop|halt|abort|cancel)\\b/i.test(`${m.subject} ${m.body}`),\n );\n return interruptMsg\n ? { interrupt: true, interruptReason: interruptMsg.body || interruptMsg.subject || 'operator interrupt' }\n : { interrupt: false };\n}\n", "/**\n * `/btw` \u2014 non-aborting mid-run steering (\"by the way\").\n *\n * Unlike `/steer` (which aborts the current iteration and prepends a heavy\n * STEERING preamble), `/btw` stashes a short note on the live `Context` and\n * lets the agent pick it up at the NEXT iteration boundary \u2014 between tool\n * batches \u2014 without tearing down in-flight work.\n *\n * Flow:\n * 1. The `/btw <text>` slash command calls `setBtwNote(ctx, text)` on the\n * live run context. Multiple notes accumulate in order.\n * 2. At the top of each agent iteration (before the request is built),\n * `Agent` drains the queue via `consumeBtwNotes(ctx)` and folds the\n * notes into the conversation as a user-visible block.\n *\n * The notes live in `ctx.meta` so the slash command and the agent loop share\n * one source of truth, the same way `_autonomousContinue` is plumbed in\n * {@link ./continue-to-next-iteration.ts}.\n */\nimport type { Context } from './context.js';\n\n/** Meta key holding the pending `/btw` notes (FIFO). */\nconst META_KEY = '_btwNotes';\n\n/** Cap on queued notes so a runaway loop can't grow `ctx.meta` unbounded. */\nconst MAX_PENDING = 20;\n\nfunction readQueue(ctx: Context): string[] {\n const raw = ctx.meta[META_KEY];\n return Array.isArray(raw) ? (raw as string[]) : [];\n}\n\n/**\n * Stash a \"by the way\" note on the context. The agent surfaces it at the\n * start of its next iteration. Blank notes are ignored. Returns the number\n * of notes now pending.\n */\nexport function setBtwNote(ctx: Context, text: string): number {\n const trimmed = text.trim();\n if (!trimmed) return readQueue(ctx).length;\n const next = [...readQueue(ctx), trimmed].slice(-MAX_PENDING);\n ctx.meta[META_KEY] = next;\n return next.length;\n}\n\n/** Number of notes currently waiting to be delivered. */\nexport function pendingBtwCount(ctx: Context): number {\n return readQueue(ctx).length;\n}\n\n/**\n * Read and clear all pending notes in one call. Returns them in the order\n * they were added (empty array when none).\n */\nexport function consumeBtwNotes(ctx: Context): string[] {\n const notes = readQueue(ctx);\n if (notes.length > 0) delete ctx.meta[META_KEY];\n return notes;\n}\n\n/**\n * Format pending notes as the text the agent reads. Kept deliberately light\n * (no \"I interrupted you\" framing) so the model folds the note into its\n * current work rather than restarting.\n */\nexport function buildBtwBlock(notes: string[]): string {\n const body = notes.map((n) => `- ${n}`).join('\\n');\n return [\n '[BY THE WAY \u2014 the user added this while you were working. Fold it into',\n 'your current task; do not restart from scratch unless it contradicts the',\n 'goal:',\n '',\n body,\n ']',\n ].join('\\n');\n}\n", "/**\n * fleet-pulse \u2014 pure formatter for the periodic peer-status digest.\n *\n * Every agent on a project (leader and fleet subagents alike) periodically\n * gets a compact \"[FLEET PULSE]\" block folded into its conversation so it\n * knows what its peers are doing \u2014 who is running what task, who went\n * idle, who finished. This is the push half of peer awareness (the pull\n * half is the `fleet_status` tool).\n *\n * This module is data-in/text-out only: it never touches the mailbox or\n * the filesystem, so core/ stays free of runtime coordination/ imports\n * (architecture Rule 3 \u2014 same posture as mailbox-loop.ts). The composition\n * glue that feeds it live `MailboxAgentStatus[]` lives in\n * ../mailbox-attach.ts (`attachFleetPulse`).\n *\n * @module fleet-pulse\n */\n\nimport type { MailboxAgentStatus } from '../coordination/mailbox-types.js';\n\ninterface FleetPulseOptions {\n /** This agent's own mailbox id \u2014 excluded from the digest. */\n selfId: string;\n /** Max peers listed (rest summarized as \"+N more\"). Default 15. */\n maxAgents?: number | undefined;\n /** Hard cap on total digest characters. Default 900. */\n maxChars?: number | undefined;\n}\n\nconst DEFAULT_MAX_AGENTS = 15;\nconst DEFAULT_MAX_CHARS = 900;\nconst TASK_SNIPPET_CHARS = 60;\n\n/**\n * Stable signature over the fields that matter to a reader \u2014 used by the\n * caller to skip re-injection when nothing meaningful changed since the\n * last pulse. Deliberately excludes counters (iterations/toolCalls) and\n * timestamps: those tick constantly and would defeat the dedup.\n */\nexport function fleetPulseSignature(statuses: MailboxAgentStatus[]): string {\n return statuses\n .map((s) => `${s.agentId}|${s.status}|${s.currentTask ?? ''}`)\n .sort()\n .join('\\n');\n}\n\nfunction peerLine(s: MailboxAgentStatus): string {\n const role = s.role && s.role !== s.name ? ` (${s.role})` : '';\n const parts = [`\u2022 ${s.name}${role} \u2014 ${s.status}`];\n if (s.currentTask) {\n const task =\n s.currentTask.length > TASK_SNIPPET_CHARS\n ? `${s.currentTask.slice(0, TASK_SNIPPET_CHARS)}\u2026`\n : s.currentTask;\n parts.push(`\"${task}\"`);\n }\n if (s.currentTool) parts.push(`tool: ${s.currentTool}`);\n if (s.toolCalls > 0) parts.push(`${s.toolCalls} tools`);\n return parts.join(' \u2014 ');\n}\n\n/**\n * Build the digest block, or `null` when there is nothing worth saying\n * (no online peers besides self). The caller owns cadence and dedup.\n */\nexport function buildFleetPulseBlock(\n statuses: MailboxAgentStatus[],\n opts: FleetPulseOptions,\n): { type: 'text'; text: string } | null {\n const maxAgents = opts.maxAgents ?? DEFAULT_MAX_AGENTS;\n const maxChars = opts.maxChars ?? DEFAULT_MAX_CHARS;\n const peers = statuses.filter((s) => s.online && s.agentId !== opts.selfId);\n if (peers.length === 0) return null;\n\n // Running peers first \u2014 they are what a reader coordinates around.\n const order: Record<string, number> = { running: 0, streaming: 0, waiting_user: 1, idle: 2, error: 3, offline: 4 };\n const sorted = [...peers].sort(\n (x, y) => (order[x.status] ?? 5) - (order[y.status] ?? 5) || x.name.localeCompare(y.name),\n );\n const shown = sorted.slice(0, maxAgents);\n const hidden = sorted.length - shown.length;\n\n const parts: string[] = [];\n parts.push(`[FLEET PULSE] ${peers.length} peer${peers.length === 1 ? '' : 's'} online:`);\n for (const s of shown) parts.push(peerLine(s));\n if (hidden > 0) parts.push(`\u2026 +${hidden} more`);\n parts.push(\n '[END FLEET PULSE] (FYI \u2014 coordinate via mail_send; avoid duplicating peers\\' work)',\n );\n\n let text = parts.join('\\n');\n if (text.length > maxChars) {\n // Trim from the peer list, never the header/footer.\n while (parts.length > 3 && parts.join('\\n').length > maxChars) {\n parts.splice(parts.length - 2, 1);\n }\n text = parts.join('\\n');\n if (text.length > maxChars) text = `${text.slice(0, maxChars - 1)}\u2026`;\n }\n return { type: 'text', text };\n}\n", "/**\n * mailbox-attach \u2014 composition glue for the agent-loop mailbox checker.\n *\n * Lives at the src root (composition layer) because it resolves the concrete\n * project mailbox from coordination/ and hands the resulting checker to\n * core/ \u2014 core/ itself may only depend on the Mailbox interface\n * (architecture Rule 3, see tests/architecture/package-boundaries.test.ts).\n *\n * The mailbox it resolves is the *server-backed* one: the detached project\n * owner holds the only SQLite handle and every surface reaches it over IPC.\n * This module used to construct a direct-filesystem `GlobalMailbox`, which\n * put the agent loop \u2014 registration, heartbeat, delivery, ack \u2014 on a private\n * `_mailbox.jsonl` while every UI read `_mailbox.sqlite`. That split is the\n * exact failure the project-daemon invariant exists to prevent.\n *\n * @module mailbox-attach\n */\n\nimport { resolveProjectDir } from './coordination/global-mailbox-paths.js';\nimport { getSharedProjectMailbox } from './coordination/remote-mailbox.js';\nimport { createHqPublisherFromEnv } from './hq/factory.js';\nimport { wstackGlobalRoot } from './utils/wstack-paths.js';\nimport { toErrorMessage } from './utils/error.js';\nimport {\n MAILBOX_AWARENESS_INTERVAL_MS,\n MAILBOX_HEARTBEAT_INTERVAL_MS,\n PULSE_MIN_READ_INTERVAL_MS,\n} from './coordination/mailbox-constants.js';\nimport { mailboxSessionTag, resolveMailboxIdentity } from './coordination/mailbox-tool.js';\nimport type { Mailbox, MailboxMessage } from './coordination/mailbox-types.js';\nimport { MAILBOX_TYPE_PROPERTIES } from './coordination/mailbox-types.js';\nimport type { FleetConfig } from './types/config.js';\nimport type { AgentInternals } from './core/agent-internals.js';\nimport { buildMailboxBtwAwarenessBlock, createMailboxChecker } from './core/mailbox-loop.js';\nimport { setBtwNote } from './core/btw.js';\nimport { buildFleetPulseBlock, fleetPulseSignature } from './core/fleet-pulse.js';\n\nexport function attachMailboxChecker(\n a: AgentInternals,\n source?: 'cli' | 'webui',\n): () => Promise<MailboxMessage[]> {\n // Mailbox integration is best-effort \u2014 it must NEVER be the reason Agent\n // construction fails. Ephemeral/test contexts without a projectRoot get a\n // no-op checker, and any setup error degrades to the same.\n if (!a.ctx.projectRoot) {\n return async () => [];\n }\n try {\n return attachMailboxCheckerInner(a, source);\n } catch {\n return async () => [];\n }\n}\n\nfunction attachMailboxCheckerInner(\n a: AgentInternals,\n source?: 'cli' | 'webui',\n): () => Promise<MailboxMessage[]> {\n // Lazy mailbox getter: re-derives projectRoot on every call so that\n // an in-process project switch (which mutates a.ctx.projectRoot) is\n // picked up automatically without re-creating the loop handler.\n const getMailbox = (): Mailbox => {\n const projectDir = resolveProjectDir(a.ctx.projectRoot, wstackGlobalRoot());\n return getSharedProjectMailbox(projectDir, a.events, hqPublisher);\n };\n // Pass the agent's EventBus so the mailbox can re-emit the project owner's\n // real-time events (agent_registered, agent_heartbeat, etc.) for TUI/WebUI\n // display.\n // This socket only carries mailbox telemetry. Declaring the default\n // capability set (which includes `session.summary`) would make HQ treat it\n // as a terminal surface: it would render as a phantom \"waiting for session\n // telemetry\" node and get orphan-evicted (terminate \u2192 reconnect churn)\n // because it never publishes session snapshots.\n const hqPublisher = createHqPublisherFromEnv({\n clientKind: source ?? 'cli',\n projectRoot: a.ctx.projectRoot,\n logger: a.logger,\n capabilities: ['telemetry.publish', 'mailbox.summary'],\n });\n hqPublisher?.connect();\n if (hqPublisher) {\n // Agent-level hook: the HQ publisher lives across runs, not per-run.\n a.ctx.registerAgentHook(() => hqPublisher.close());\n }\n const surface = source ?? ((a.ctx.meta['source'] as 'cli' | 'webui' | undefined) ?? 'cli');\n if (!a.ctx.meta['source']) a.ctx.meta['source'] = surface;\n\n // SESSION-bound unique identity (`<base>@<sessionTag>`): every session\n // has its own id, so two leader sessions on the same project never\n // collide \u2014 and the identity is re-derived LIVE so an in-process session\n // swap (resume / session.new / project switch) moves the agent onto the\n // new session's identity automatically. ctx.meta.globalAgentId is kept\n // fresh for the tools and the /mailbox command.\n const baseIdOf = (): string => {\n const fieldId = a.ctx.agentId && a.ctx.agentId !== 'unknown' ? a.ctx.agentId : undefined;\n return (a.ctx.meta['agentId'] as string | undefined) ?? fieldId ?? 'leader';\n };\n let registeredAs = '';\n const ensureRegistered = (): string => {\n // Clear a stale explicit override from a previous session so the\n // resolver re-derives from the CURRENT session id.\n const derived = `${baseIdOf()}@${mailboxSessionTag(a.ctx.session.id)}`;\n if ((a.ctx.meta['globalAgentId'] as string | undefined) !== derived) {\n a.ctx.meta['globalAgentId'] = derived;\n }\n if (registeredAs !== derived) {\n registeredAs = derived;\n const identity = resolveMailboxIdentity(a.ctx);\n getMailbox()\n .registerAgent({\n agentId: derived,\n name: `${identity.name} [${surface}]`,\n role: identity.role,\n sessionId: a.ctx.session.id,\n pid: process.pid,\n source: surface,\n })\n .catch((err: unknown) => {\n // Log but don't fail - registration errors shouldn't crash the agent\n a.logger.debug(`Failed to register agent ${derived}`, {\n agentId: derived,\n err: toErrorMessage(err),\n });\n });\n }\n return derived;\n };\n ensureRegistered();\n\n // Heartbeat keeps the registration alive (every 30 seconds) and follows\n // identity changes \u2014 after a session swap the new identity registers and\n // the old one simply goes stale (60s timeout).\n const HEARTBEAT_INTERVAL_MS = MAILBOX_HEARTBEAT_INTERVAL_MS;\n const heartbeatTimer = setInterval(() => {\n const id = ensureRegistered();\n getMailbox().heartbeat({ agentId: id }).catch(() => {\n // Silently ignore - heartbeat failures are expected during shutdown\n });\n }, HEARTBEAT_INTERVAL_MS);\n heartbeatTimer.unref?.();\n\n // Register cleanup to stop heartbeat on agent teardown. Note: there's no\n // unregisterAgent method \u2014 agents are considered offline after their heartbeat\n // expires (60s timeout). Agent-level: the heartbeat runs across runs.\n a.ctx.registerAgentHook(() => {\n clearInterval(heartbeatTimer);\n });\n\n // Receive on the unique id AND the bare base id (plus '*' broadcasts) \u2014\n // \"send to leader\" reaches every live leader session on the project.\n // Getter form: each check re-derives identity from the CURRENT session.\n const mailboxCheckerOptions = {\n mailbox: getMailbox,\n agentId: () => ensureRegistered(),\n role: () => resolveMailboxIdentity(a.ctx).role,\n aliases: [baseIdOf()],\n sessionId: () => a.ctx.session.id,\n };\n const checkMailbox = createMailboxChecker(mailboxCheckerOptions);\n const checkMailboxAwareness = createMailboxChecker({\n ...mailboxCheckerOptions,\n // Exclude out-of-band types (control) from awareness polling.\n // Uses the canonical MAILBOX_TYPE_PROPERTIES outOfBand flag instead\n // of a hardcoded type string, so a newly-added out-of-band type is\n // automatically excluded.\n include: (m) => !MAILBOX_TYPE_PROPERTIES[m.type]?.outOfBand,\n ack: false,\n });\n\n // Background mailbox awareness: poll while tools or long provider calls are\n // in flight, but queue the result as a BTW note so the agent only consumes it\n // at the next safe loop boundary. This is the important separation: polling\n // is continuous, conversation mutation remains serialized by the agent loop.\n //\n // PUSH-NOTIFICATION SHORT-CIRCUIT: the project owner emits\n // 'mailbox.message_sent' on every send() and broadcasts it to every\n // connected client, which re-emits it on this agent's EventBus. We\n // subscribe to that event and trigger an immediate (debounced) awareness\n // poll \u2014 so a message surfaces in <500ms instead of waiting up to the full\n // poll interval. Since the owner is shared, this now covers cross-process\n // sends too; the 30s interval remains as a fallback for a dropped socket.\n const AWARENESS_FALLBACK_INTERVAL_MS = MAILBOX_AWARENESS_INTERVAL_MS; // cross-process fallback\n const AWARENESS_PUSH_DEBOUNCE_MS = 500; // collapse bursts from the same sender\n let pollInFlight = false;\n let awarenessDisposed = false;\n let pushDebounceTimer: NodeJS.Timeout | null = null;\n\n const pollMailboxAwareness = async () => {\n if (awarenessDisposed || pollInFlight) return;\n pollInFlight = true;\n try {\n const messages = await checkMailboxAwareness();\n if (\n !awarenessDisposed &&\n messages.length > 0 &&\n a.ctx.meta['coordinationContextMode'] !== 'background'\n ) {\n setBtwNote(a.ctx, buildMailboxBtwAwarenessBlock(messages).text);\n }\n } catch {\n // Best-effort awareness only \u2014 a broken mailbox must not disturb work.\n } finally {\n pollInFlight = false;\n }\n };\n\n // Push-triggered poll: debounce so a rapid burst of messages (e.g. a\n // subagent sending 5 results) collapses into a single poll after 500ms\n // rather than firing 5 polls.\n const triggerPushPoll = () => {\n if (awarenessDisposed) return;\n if (pushDebounceTimer !== null) clearTimeout(pushDebounceTimer);\n pushDebounceTimer = setTimeout(() => {\n pushDebounceTimer = null;\n void pollMailboxAwareness();\n }, AWARENESS_PUSH_DEBOUNCE_MS);\n };\n\n // Subscribe to 'mailbox.message_sent' for push-based awareness. The project\n // owner emits it on every send(); the local connection re-emits it here.\n let pushUnsub: (() => void) | null = null;\n if (a.events && typeof a.events.onPattern === 'function') {\n pushUnsub = a.events.onPattern('mailbox.message_sent', () => {\n triggerPushPoll();\n });\n }\n\n // Fallback polling for cross-process messages (other terminal sessions,\n // external agents via the HTTP bridge). These don't trigger the in-process\n // EventBus event, so we still need periodic polling \u2014 just less frequently.\n const awarenessTimer = setInterval(() => {\n void pollMailboxAwareness();\n }, AWARENESS_FALLBACK_INTERVAL_MS);\n awarenessTimer.unref?.();\n a.ctx.registerAgentHook(() => {\n awarenessDisposed = true;\n clearInterval(awarenessTimer);\n if (pushDebounceTimer !== null) clearTimeout(pushDebounceTimer);\n pushUnsub?.();\n });\n\n // Auto-compaction (drop messages read by every online agent, expired TTLs,\n // stale completed/incomplete records) is NOT started here: the detached\n // project owner runs exactly one compaction timer for the whole project\n // (`mailbox-project-server.ts` \u2192 `startAutoCompactTimer`). Starting a\n // per-agent timer would have N sessions compacting the same store.\n\n return checkMailbox;\n}\n\n/**\n * Fleet-pulse provider: returns a fresh \"[FLEET PULSE]\" digest block when\n * (a) the read throttle allows, (b) at least one online peer exists, and\n * (c) the peer picture actually changed since the last injected pulse.\n * Otherwise `null`. Same best-effort posture as the mailbox checker \u2014 any\n * failure degrades to \"no pulse\", never to a thrown error.\n */\nexport function attachFleetPulse(\n a: AgentInternals,\n cfg?: FleetConfig['pulse'],\n): () => Promise<{ type: 'text'; text: string } | null> {\n if (!a.ctx.projectRoot || cfg?.enabled === false) {\n return async () => null;\n }\n try {\n const projectDir = resolveProjectDir(a.ctx.projectRoot, wstackGlobalRoot());\n // No EventBus/HQ publisher here \u2014 the pulse is a read-only registry\n // consumer; the checker's mailbox instance already owns event emission.\n const mailbox: Mailbox = getSharedProjectMailbox(projectDir);\n let lastReadAt = 0;\n let lastSignature = '';\n return async () => {\n try {\n const now = Date.now();\n if (now - lastReadAt < PULSE_MIN_READ_INTERVAL_MS) return null;\n lastReadAt = now;\n const statuses = await mailbox.getAgentStatuses();\n const selfId =\n (a.ctx.meta['globalAgentId'] as string | undefined) ??\n `${a.ctx.agentId ?? 'leader'}@${mailboxSessionTag(a.ctx.session.id)}`;\n const online = statuses.filter((s) => s.online && s.agentId !== selfId);\n const signature = fleetPulseSignature(online);\n if (online.length === 0 || signature === lastSignature) return null;\n const block = buildFleetPulseBlock(statuses, {\n selfId,\n maxAgents: cfg?.maxAgents,\n maxChars: cfg?.maxChars,\n });\n if (block) lastSignature = signature;\n return block;\n } catch {\n return null;\n }\n };\n } catch {\n return async () => null;\n }\n}\n", "export interface TextBlock {\n type: 'text';\n text: string;\n cache_control?: { type: 'ephemeral' | undefined };\n}\n\nexport interface ToolUseBlock {\n type: 'tool_use';\n id: string;\n name: string;\n input: Record<string, unknown>;\n /**\n * Provider-specific opaque metadata captured from the wire response.\n * Echoed back verbatim in the next request so providers that bind\n * extra state to function calls keep working. Example: Gemini's\n * `thoughtSignature` \u2014 required for tool-use turns with thinking\n * models, otherwise the next request fails with 400 \"Function call\n * is missing a thought_signature in functionCall parts\".\n *\n * Keys are namespaced by intent so multiple wires can coexist:\n * - `google.thoughtSignature` \u2014 Gemini signed-thought blob\n * Other providers can add their own keys without colliding.\n */\n providerMeta?: Record<string, unknown>;\n}\n\nexport interface ToolResultBlock {\n type: 'tool_result';\n tool_use_id: string;\n /**\n * The original tool name. Useful for providers like Google Gemini that\n * need the tool name in `functionResponse.name` \u2014 the tool_use_id is\n * only a session-local identifier and is not stable across replays.\n * Always set by ToolExecutor; may be absent on manually-constructed blocks.\n */\n name?: string | undefined;\n content: string;\n is_error?: boolean | undefined;\n}\n\nexport interface ImageBlock {\n type: 'image';\n source: {\n type: 'base64' | 'url';\n media_type?: string | undefined;\n data?: string | undefined;\n url?: string | undefined;\n };\n}\n\n/**\n * Chain-of-thought / extended-thinking content emitted by the model.\n *\n * Both Anthropic extended thinking (`{type:'thinking', thinking, signature}`)\n * and DeepSeek reasoning mode (top-level `reasoning_content` on the assistant\n * message) require this content to be echoed back verbatim on the next\n * request, otherwise the provider returns 400:\n * - Anthropic: \"The `content[].thinking` in the thinking mode must be passed back\"\n * - DeepSeek: \"The `reasoning_content` in the thinking mode must be passed back\"\n *\n * `signature` is Anthropic-specific (an opaque integrity blob). DeepSeek\n * doesn't issue a signature \u2014 the field is absent for that provider.\n *\n * Per Anthropic, thinking blocks MUST appear before any text/tool_use blocks\n * in an assistant message. Stream builders preserve that order.\n */\nexport interface ThinkingBlock {\n type: 'thinking';\n thinking: string;\n signature?: string | undefined;\n providerMeta?: Record<string, unknown>;\n}\n\nexport type ContentBlock = TextBlock | ToolUseBlock | ToolResultBlock | ImageBlock | ThinkingBlock;\n\nexport function isTextBlock(b: ContentBlock): b is TextBlock {\n return b.type === 'text';\n}\nexport function isToolUseBlock(b: ContentBlock): b is ToolUseBlock {\n return b.type === 'tool_use';\n}\nexport function isToolResultBlock(b: ContentBlock): b is ToolResultBlock {\n return b.type === 'tool_result';\n}\nexport function isImageBlock(b: ContentBlock): b is ImageBlock {\n return b.type === 'image';\n}\n", "/**\n * String utilities shared across the WrongStack codebase.\n */\n\n/**\n * Truncate a string to at most `max` characters, appending an ellipsis if it\n * was longer. Returns the original string unchanged when it fits.\n */\nexport function truncate(s: string, max: number): string {\n return s.length <= max ? s : `${s.slice(0, max - 1)}\u2026`;\n}\n", "/**\n * Shared regex literals for classifying provider error messages as\n * account/plan-level quota exhaustion vs. per-request rate limiting.\n *\n * ## Why this module exists\n *\n * The same regex used by `classifyProviderError` (`packages/core/src/types/provider.ts`)\n * is also used by `isQuotaExhausted` in `provider-status-tracker.ts`. Hand-maintained\n * duplicates of a regex literal that mutates every release cycle (new provider\n * message shapes) silently drift \u2014 the two paths classify messages\n * inconsistently. Centralising the literal here makes a single edit take\n * effect on every caller.\n *\n * Callers MUST NOT re-declare these regexes locally. Import from this module.\n *\n * @module types/quota-regex\n */\n\nexport const QUOTA_EXHAUSTED_RE =\n /(?:insufficient|exhausted|depleted|exceeded|no|not enough)[-_\\s]*(?:quota|credit|balance)|(?:quota|credit|balance)(?:\\s+(?:has|have))?(?:\\s+been)?[-_\\s]*(?:exhausted|depleted|exceeded|insufficient)|billing[_\\s-]*(?:hard[_\\s-]*)?limit|payment required|spending limit|plan limit|usage[-_\\s]*limit[-_\\s]*(?:reached|exceeded)/i;\n\nexport const ROUTE_SCOPED_QUOTA_RE =\n /\\b(?:for|on)\\s+(?:(?:this|the)\\s+)?(?:route|model)\\b|\\b(?:route|model)(?:[-_\\s]+[\\w.-]+)?[-_\\s]*(?:quota|limit)\\b|\\b(?:quota|limit).{0,24}\\b(?:for|on)\\s+(?:(?:this|the)\\s+)?(?:route|model)\\b/i;\n", "import { truncate } from '../utils/string.js';\nimport type { ContentBlock, TextBlock } from './blocks.js';\nimport type { ErrorCode } from './errors.js';\nimport { ERROR_CODES, WrongStackError } from './errors.js';\nimport type { Message } from './messages.js';\nimport { QUOTA_EXHAUSTED_RE } from './quota-regex.js';\nimport type { Tool } from './tool.js';\n\n/**\n * Token usage for a single provider call, normalized across providers.\n *\n * Disjoint semantics: the four fields never overlap. `input` is the count\n * of FRESH input tokens (billed at the full input rate); `cacheRead` and\n * `cacheWrite` are separate cached subsets each priced at their own rate.\n * The total context the model loaded for this turn is\n * `input + (cacheRead ?? 0) + (cacheWrite ?? 0)`.\n *\n * Provider quirks normalized at the adapter layer:\n * - Anthropic: returns `input_tokens` already disjoint from cache fields.\n * - OpenAI / OpenAI-compatible: `prompt_tokens` is the TOTAL including\n * cached portion; the adapter subtracts `cached_tokens` to stay disjoint.\n * - Google: `promptTokenCount` likewise includes cache; adapter subtracts\n * `cachedContentTokenCount`.\n *\n * Cost math and the context-fullness chip both depend on the disjoint\n * invariant \u2014 a TOTAL `input` plus a separate `cacheRead` count would bill\n * cached tokens twice and skew cache-hit-ratio reporting.\n */\nexport type ReasoningEffort = 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';\nexport type CacheTtl = '5m' | '1h';\n\n/**\n * Provider-agnostic response-format directive.\n *\n * - `{ type: 'text' }` \u2014 free-form text (default).\n * - `{ type: 'json_object' }` \u2014 valid JSON without a schema constraint.\n * - `{ type: 'json_schema', jsonSchema: { name, schema, strict? } }` \u2014 JSON\n * constrained to the supplied JSON Schema. The `strict` flag is\n * OpenAI-specific; Gemini ignores it in favour of `responseMimeType`.\n *\n * Each provider adapter maps this into its own wire format:\n * OpenAI \u2192 `response_format`\n * Gemini \u2192 `responseMimeType` + `responseSchema`\n * Anthropic \u2192 (not yet supported; uses tools for structured output)\n */\nexport interface JsonSchemaSpec {\n name: string;\n /** OpenAI-specific: enable strict schema adherence. */\n strict?: boolean | undefined;\n /** The JSON Schema object describing the expected shape. */\n schema: Record<string, unknown>;\n /** Optional human-readable description (OpenAI). */\n description?: string | undefined;\n}\n\nexport type ResponseFormat =\n | { type: 'text' }\n | { type: 'json_object' }\n | { type: 'json_schema'; jsonSchema: JsonSchemaSpec };\n\n/**\n * Safety category threshold pair used by Google Gemini's `safetySettings`.\n *\n * Categories: `HARM_CATEGORY_HARASSMENT`, `HARM_CATEGORY_HATE_SPEECH`,\n * `HARM_CATEGORY_SEXUALLY_EXPLICIT`, `HARM_CATEGORY_DANGEROUS_CONTENT`.\n *\n * Thresholds: `BLOCK_NONE`, `BLOCK_ONLY_HIGH`, `BLOCK_MEDIUM_AND_ABOVE`,\n * `BLOCK_LOW_AND_ABOVE`.\n */\nexport interface SafetySetting {\n category: string;\n threshold: string;\n}\n\nexport interface Usage {\n input: number;\n output: number;\n cacheRead?: number | undefined;\n /** Back-compat aggregate of all cache-write tokens. Prefer TTL-specific fields when present. */\n cacheWrite?: number | undefined;\n cacheWrite5m?: number | undefined;\n cacheWrite1h?: number | undefined;\n}\n\n/**\n * Effective prompt tokens loaded by the model for one request.\n *\n * Provider adapters normalize `Usage` to disjoint fields: `input` is fresh\n * full-rate tokens, `cacheRead` is cached prefix tokens, and `cacheWrite` is\n * the cache-written prefix segment. Context-window pressure cares about the\n * full prompt the model saw, not only the bill-at-full-rate slice.\n */\nexport function effectiveInputTokens(usage: Usage): number {\n return usage.input + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0);\n}\n\nexport interface ReasoningRequest {\n enabled?: boolean | undefined;\n effort?: ReasoningEffort | undefined;\n preserve?: boolean | undefined;\n display?: 'summarized' | 'omitted' | undefined;\n}\n\nexport interface RequestCacheControl {\n ttl?: CacheTtl | undefined;\n /**\n * Provider-agnostic cache-partition key. A stable hash of the cacheable\n * system-prompt prefix (see `deriveCachePrefixKey`); requests sharing a prefix\n * share a key so provider backends route them to the same automatic-cache\n * partition. Consumed by OpenAI-family wires as `prompt_cache_key`; ignored by\n * Anthropic (which uses `ttl` + explicit `cache_control` markers).\n */\n key?: string | undefined;\n /**\n * Opt-in flag (from `ModelRuntimeCacheConfig.geminiExplicit`) telling the\n * Google provider to use explicit `cachedContents` for this request. Ignored\n * by other providers.\n */\n geminiExplicit?: boolean | undefined;\n /**\n * Resolved Gemini `cachedContents/*` resource name, injected by\n * `GoogleProvider.stream()` after it creates/reuses the cache. When present,\n * the Google wire sends `cachedContent` and OMITS the (now-cached) system\n * instruction + tool defs from the live body. Internal \u2014 never set by callers.\n */\n geminiCachedContentName?: string | undefined;\n}\n\nexport interface ReasoningConfig {\n default: 'enabled' | 'disabled' | 'adaptive' | 'always_on';\n disableSupported: boolean;\n effortSupported: boolean;\n effortLevels: ReasoningEffort[];\n preserveThinking: 'unsupported' | 'optional' | 'always_on';\n}\n\nexport interface Capabilities {\n tools: boolean;\n parallelTools: boolean;\n vision: boolean;\n streaming: boolean;\n promptCache: boolean;\n systemPrompt: boolean;\n jsonMode: boolean;\n reasoning: boolean;\n maxContext: number;\n /**\n * Maximum output tokens the model can produce in a single response.\n * Used as the default for `Request.maxTokens` when the caller doesn't\n * supply an explicit value \u2014 letting subagents run up to the model's\n * native ceiling instead of a fixed 8192 cap. Omit (undefined) to fall\n * back to a conservative default; populate per family in\n * `family-capabilities.ts` once you know the spec.\n */\n maxOutput?: number | undefined;\n cacheControl: 'native' | 'auto' | 'none';\n\n // \u2500\u2500 Extended parameter support (optional; family defaults in CAPABILITIES_BY_FAMILY) \u2500\u2500\n\n /** Model accepts `top_k` / `topK` sampling parameter. */\n topK?: boolean | undefined;\n /** Model accepts `frequency_penalty` / `frequencyPenalty` parameter. */\n frequencyPenalty?: boolean | undefined;\n /** Model accepts `presence_penalty` / `presencePenalty` parameter. */\n presencePenalty?: boolean | undefined;\n /** Model accepts `seed` parameter for deterministic generation. */\n seed?: boolean | undefined;\n /**\n * Model accepts JSON Schema / structured-output constraints\n * (OpenAI `response_format.json_schema`, Gemini `responseMimeType`+`responseSchema`).\n * Distinct from `jsonMode` (which is just a system-prompt hint).\n */\n structuredOutput?: boolean | undefined;\n /** Model supports log-probability output (`logprobs`, `top_logprobs`). */\n logprobs?: boolean | undefined;\n /** Model supports audio input/output modality. */\n audio?: boolean | undefined;\n /** Model supports the `n` parameter for multiple completions. */\n multipleCompletions?: boolean | undefined;\n}\n\nexport interface Request {\n model: string;\n system?: TextBlock[] | undefined;\n messages: Message[];\n tools?: Tool[] | undefined;\n /**\n * Cap on output tokens for this single response. Optional \u2014 when\n * omitted, the provider adapter falls back to its own\n * `capabilities.maxOutput` (which the catalog populates from\n * `ModelsDevModel.limit.output`). If neither is available, the\n * adapter applies a conservative 8192 safety net. Letting this stay\n * undefined at the call site means callers like Chimera can hand the\n * model its native output ceiling without hard-coding a number.\n */\n maxTokens?: number | undefined;\n temperature?: number | undefined;\n topP?: number | undefined;\n topK?: number | undefined;\n frequencyPenalty?: number | undefined;\n presencePenalty?: number | undefined;\n seed?: number | undefined;\n /**\n * End-user identifier for abuse monitoring and per-user rate limiting.\n * - Anthropic \u2192 `metadata.user_id`\n * - OpenAI \u2192 `user`\n * - Gemini \u2192 (not supported)\n */\n user?: string | undefined;\n /**\n * Number of response candidates to generate. Google Gemini supports\n * this via `generationConfig.candidateCount`. OpenAI does not have\n * an equivalent (`n` is conceptually similar but distinct).\n */\n candidateCount?: number | undefined;\n /**\n * Whether to return log probabilities for output tokens.\n * - OpenAI \u2192 `logprobs: boolean` (+ `topLogprobs: number`)\n * - Gemini \u2192 `generationConfig.logprobs: number` (how many top candidates)\n * Default undefined = no logprobs requested.\n */\n logprobs?: boolean | undefined;\n /**\n * Number of most probable tokens to return log probabilities for\n * (OpenAI `top_logprobs`). Only meaningful when `logprobs` is true.\n * Range: 0-20. Gemini ignores this (uses `logprobs` as the count).\n */\n topLogprobs?: number | undefined;\n stopSequences?: string[] | undefined;\n toolChoice?: 'auto' | 'required' | 'none' | { type: 'tool' | undefined; name: string };\n reasoning?: ReasoningRequest | undefined;\n cache?: RequestCacheControl | undefined;\n /**\n * Structured-output / response-format directive.\n * When set, the provider adapter maps this to its native response-format\n * parameter (OpenAI `response_format`, Gemini `responseMimeType`, etc.).\n * The model must advertise `capabilities.structuredOutput` for this to be\n * honoured; unsupported models will likely 400 or ignore it.\n */\n responseFormat?: ResponseFormat | undefined;\n /**\n * Safety category thresholds for filtering harmful content.\n * - Gemini \u2192 top-level `safetySettings` array with `{ category, threshold }`\n * - OpenAI \u2192 not supported (uses server-side moderation)\n * - Anthropic \u2192 not supported\n */\n safetySettings?: SafetySetting[] | undefined;\n}\n\nexport type StopReason = 'end_turn' | 'tool_use' | 'max_tokens' | 'stop_sequence' | 'refusal';\n\nexport interface Response {\n content: ContentBlock[];\n stopReason: StopReason;\n usage: Usage;\n model: string;\n}\n\nexport type StreamEvent =\n | { type: 'message_start'; model: string }\n | {\n type: 'content_block_start';\n kind: 'text' | 'tool_use' | 'thinking';\n id?: string | undefined;\n name?: string | undefined;\n }\n | { type: 'content_block_stop'; index: number }\n | { type: 'text_delta'; text: string }\n | { type: 'tool_use_start'; id: string; name: string }\n | { type: 'tool_use_input_delta'; id: string; partial: string }\n | { type: 'tool_use_stop'; id: string; input: unknown; providerMeta?: Record<string, unknown> }\n | { type: 'thinking_start'; providerMeta?: Record<string, unknown> }\n | { type: 'thinking_delta'; text: string }\n | { type: 'thinking_signature'; signature: string }\n | { type: 'thinking_stop' }\n | { type: 'message_stop'; stopReason: StopReason; usage: Usage };\n\nexport interface Provider {\n readonly id: string;\n readonly capabilities: Capabilities;\n /** Canonical streaming entry point. `complete()` defaults to a wrapper that\n * aggregates this stream \u2014 providers may override for non-streaming wires. */\n stream(req: Request, opts: { signal: AbortSignal }): AsyncIterable<StreamEvent>;\n complete(req: Request, opts: { signal: AbortSignal }): Promise<Response>;\n}\n\n/**\n * Structured body parsed from a provider's HTTP error response. Populated\n * best-effort: providers return JSON shaped differently (Anthropic uses\n * `{error: {type, message}}`, OpenAI uses `{error: {message, code}}`,\n * Google uses `{error: {status, message}}`), so the fields here are the\n * intersection that's usable for rendering and routing.\n */\nexport interface ProviderErrorBody {\n /** Provider-specific kind, e.g. \"overloaded_error\", \"rate_limit_error\", \"invalid_request_error\". */\n type?: string | undefined;\n /** Human-readable explanation from the provider. */\n message?: string | undefined;\n /** Provider request id, when present in the body or headers. */\n requestId?: string | undefined;\n /** Parsed Retry-After header (or equivalent body hint) in milliseconds. */\n retryAfterMs?: number | undefined;\n /** The raw response body (truncated to ~2 KB), kept for debugging. */\n raw?: string | undefined;\n /** True when `raw` was truncated; check `rawLength` for the original size. */\n truncated?: boolean | undefined;\n /** Original length of the response body in bytes, when `truncated` is true. */\n rawLength?: number | undefined;\n}\n\n/**\n * Canonical provider-failure taxonomy. Computed ONCE at error-construction\n * time (`classifyProviderError`) and carried on `ProviderError.kind` so\n * every downstream consumer \u2014 retry policy, cross-provider fallback,\n * recovery strategies, the subagent error classifier \u2014 branches on the\n * same classification instead of re-deriving it from status codes and\n * message regexes. When a new provider's error format needs special\n * handling, this module is the only place to teach it.\n */\nexport type ProviderErrorKind =\n | 'rate_limit' // 429 / rate_limit_error \u2014 back off (honour Retry-After), then failover\n | 'quota_exhausted' // credits/plan depleted \u2014 do not retry same route; fail over immediately\n | 'overloaded' // 529 / overloaded_error \u2014 retry with backoff, then failover\n | 'server' // other 5xx \u2014 retry same provider\n | 'timeout' // 408 request timeout\n | 'network' // status 0 \u2014 connection/DNS failure before a response arrived\n | 'stream_hang' // 599 sentinel \u2014 stream stalled mid-response (StreamHangError)\n | 'auth' // 401/403 \u2014 key invalid/expired; retrying without action is pointless\n | 'context_overflow' // 413 or an overflow-shaped 4xx \u2014 compact, don't retry as-is\n | 'content_filter' // provider refused on policy grounds \u2014 a sibling model may pass, but the `content_filter_reroute` recovery strategy owns that hop, NOT the fallback engine (which surfaces this kind)\n | 'invalid_request' // other 4xx \u2014 request is malformed; retrying won't help\n | 'unknown';\n\n/**\n * Overflow-shaped provider messages. Union of the patterns previously\n * scattered across `error-handler.ts` and `coordinator/error-classifier.ts`\n * (which had drifted apart) \u2014 keep additions here, nowhere else.\n */\nconst CONTEXT_OVERFLOW_RE =\n /context.length|context.window|maximum context|max.*tokens?.*exceeded|prompt is too long|too long|exceeds the context|\\btokens\\b.*exceed|too many tokens|reduce the length|resulted in \\d+ tokens|input.{0,12}too (?:large|long)|context_length_exceeded/i;\n\n/** Content-policy refusals surfaced as HTTP errors (Azure/OpenAI `content_filter`, etc.). */\nconst CONTENT_FILTER_RE = /content.(filter|policy|moderation)|safety (system|filter)/i;\n/** \"rate limit exceeded\" pattern \u2014 checked against body.message only, NOT the\n * raw JSON text, because OpenAI's `\"code\":\"rate_limit_exceeded\"` field would\n * produce a false positive in the combined-text regex. */\nconst RATE_LIMIT_EXCEEDED_RE = /rate[-_\\s]*limit[-_\\s]*exceeded/i;\n\n/**\n * Classify a provider HTTP failure into the canonical taxonomy from its\n * status code plus the parsed error body (and, for message-only errors\n * without a structured body, the error message itself). Pure and total \u2014\n * always returns a kind, never throws.\n */\nexport function classifyProviderError(\n status: number,\n body?: ProviderErrorBody,\n message?: string,\n): ProviderErrorKind {\n const type = body?.type;\n const text = [message, body?.message, type, body?.raw].filter(Boolean).join('\\n');\n if (status === 0) return 'network';\n if (status === 408) return 'timeout';\n if (status === 599) return 'stream_hang';\n if (status === 402 || QUOTA_EXHAUSTED_RE.test(text)) return 'quota_exhausted';\n // Check body.message separately for \"rate limit exceeded\" \u2014 this pattern\n // should NOT match against body.raw because OpenAI's error response\n // includes `\"code\":\"rate_limit_exceeded\"` in the JSON, which would be a\n // false positive (it's a transient burst, not a hard limit).\n if (status === 429 && body?.message && RATE_LIMIT_EXCEEDED_RE.test(body.message)) {\n return 'quota_exhausted';\n }\n if (type === 'rate_limit_error' || status === 429) return 'rate_limit';\n if (type === 'overloaded_error' || status === 529) return 'overloaded';\n if (status >= 500) return 'server';\n if (\n type === 'authentication_error' ||\n type === 'permission_error' ||\n status === 401 ||\n status === 403\n ) {\n return 'auth';\n }\n if (type === 'content_filter' || CONTENT_FILTER_RE.test(text)) return 'content_filter';\n if (status === 413 || (status >= 400 && CONTEXT_OVERFLOW_RE.test(text))) {\n return 'context_overflow';\n }\n if (status >= 400) return 'invalid_request';\n return 'unknown';\n}\n\n// \u2500\u2500 Prose reset-hint parsing \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Many providers answer an exhausted hourly/daily/weekly/monthly budget with\n// a 429/402 whose *message prose* says when the limit resets \u2014 e.g.\n// \"Please try again in 6h12m\" (OpenAI, Go durations)\n// \"usage limit reached; resets in 2 hours\" (plan-cap notices)\n// \"Your usage limit resets at 2026-07-28T00:00:00Z\" (weekly caps)\n// When no structured `Retry-After` header was captured into\n// `ProviderErrorBody.retryAfterMs`, the waiting room should still honor the\n// provider-published reset instead of falling back to a fixed default block\n// (which probes a weekly cap every 15 minutes).\n//\n// `parseResetHintMs` extracts that hint. It is deliberately conservative:\n// only text following an explicit lead-in (\"try again in\", \"retry after\",\n// \"reset(s) in/at/on\", \"available in\") is parsed, garbage yields `undefined`,\n// and any parsed delay is clamped to `MAX_RESET_HINT_MS` so a corrupt or\n// absurd message cannot park a model forever (manual `retryNow()` and the\n// periodic sweep remain the escape hatches).\n\n/** Upper bound for any prose-parsed reset delay: 7 days. */\nexport const MAX_RESET_HINT_MS = 7 * 24 * 60 * 60 * 1_000;\n\nconst RESET_HINT_LEAD_RE =\n /(?:try again|retry|resets?|resetting|available|returns?|back online|usable again)\\s+(?:in|after)\\s+/i;\nconst RESET_AT_LEAD_RE = /resets?\\s+(?:at|on)\\s+/i;\n\n/** Longest-unit-first so `minutes` wins over `m`; `(?![a-z])` keeps `12m0.5s` compound durations intact. */\nconst DURATION_TOKEN_RE =\n /(\\d+(?:\\.\\d+)?)\\s*(ms|secs?|seconds?|s|mins?|minutes?|m|hrs?|hours?|h|days?|d)(?![a-z])/gi;\n\nconst UNIT_MS: Record<string, number> = {\n ms: 1,\n s: 1_000,\n m: 60_000,\n h: 3_600_000,\n d: 86_400_000,\n};\n\nfunction unitMs(unit: string): number {\n const u = unit.toLowerCase();\n if (u === 'ms') return 1;\n if (u.startsWith('s')) return UNIT_MS['s']!;\n if (u.startsWith('m')) return UNIT_MS['m']!;\n if (u.startsWith('h')) return UNIT_MS['h']!;\n return UNIT_MS['d']!;\n}\n\nconst ISO_TIMESTAMP_RE =\n /(\\d{4}-\\d{2}-\\d{2}(?:[T ]\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?(?:\\s*(?:Z|[+-]\\d{2}:?\\d{2}|UTC|GMT))?)?)/i;\n\n/**\n * Parse a prose reset/retry hint from a provider error message into\n * milliseconds-from-`now`. Returns `undefined` when no usable hint exists.\n *\n * @param message - Provider error message (body.message / error text).\n * @param now - Reference timestamp (ms epoch); injectable for tests.\n */\nexport function parseResetHintMs(message: string, now: number = Date.now()): number | undefined {\n if (!message) return undefined;\n\n // 1. Relative duration: \"try again in 6h12m\", \"retry after 90 seconds\",\n // \"resets in 2 hours\", \"available in 1 day\".\n const lead = RESET_HINT_LEAD_RE.exec(message);\n if (lead) {\n const window = message.slice(lead.index + lead[0].length, lead.index + lead[0].length + 80);\n let total = 0;\n let matched = false;\n DURATION_TOKEN_RE.lastIndex = 0;\n for (let m = DURATION_TOKEN_RE.exec(window); m; m = DURATION_TOKEN_RE.exec(window)) {\n const value = Number.parseFloat(m[1]!);\n if (Number.isFinite(value) && value > 0) {\n total += value * unitMs(m[2]!);\n matched = true;\n }\n }\n // Bare-word units: \"try again in an hour\" / \"retry after a minute\".\n if (!matched) {\n const bare = /^(?:an?\\s+)?(second|minute|hour|day)\\b/i.exec(window.trim());\n if (bare) {\n total = unitMs(bare[1]!);\n matched = true;\n }\n }\n if (matched && total > 0) {\n return Math.min(total, MAX_RESET_HINT_MS);\n }\n }\n\n // 2. Absolute timestamp: \"resets at 2026-07-28T00:00:00Z\",\n // \"reset on 2026-08-01 00:00 UTC\".\n const atLead = RESET_AT_LEAD_RE.exec(message);\n if (atLead) {\n const window = message.slice(atLead.index + atLead[0].length);\n const iso = ISO_TIMESTAMP_RE.exec(window);\n if (iso) {\n // Normalize \"2026-08-01 00:00 UTC\" \u2192 \"2026-08-01T00:00Z\" so Date.parse\n // is deterministic across JS engines.\n const normalized = iso[1]!\n .replace(/^(\\d{4}-\\d{2}-\\d{2}) (\\d{2}:\\d{2})/, '$1T$2')\n .replace(/\\s*(UTC|GMT)$/i, 'Z');\n const ts = Date.parse(normalized);\n if (Number.isFinite(ts) && ts > now) {\n return Math.min(ts - now, MAX_RESET_HINT_MS);\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Whether a kind is worth retrying against the SAME provider/model.\n * `context_overflow` is deliberately false \u2014 the request must shrink first;\n * `auth`/`invalid_request`/`content_filter` won't improve on replay.\n *\n * Exhaustive by construction (`Record<ProviderErrorKind, \u2026>`): adding a new\n * kind refuses to compile until it is classified here. Every kind\u2192X mapping\n * in the codebase follows this drift-guard pattern \u2014 see also KIND_TO_CODE\n * below, DefaultRetryPolicy.maxAttempts, fallback-model shouldFallback, and\n * the coordinator's providerErrorToSubagentError.\n */\nexport function isRetryableKind(kind: ProviderErrorKind): boolean {\n return RETRYABLE_BY_KIND[kind];\n}\n\nconst RETRYABLE_BY_KIND: Record<ProviderErrorKind, boolean> = {\n rate_limit: true,\n quota_exhausted: false,\n overloaded: true,\n server: true,\n timeout: true,\n network: true,\n stream_hang: true,\n auth: false,\n context_overflow: false,\n content_filter: false,\n invalid_request: false,\n unknown: false,\n};\n\n/**\n * Whether a kind is worth HOPPING to a different provider/model \u2014 the gate for\n * the cross-provider fallback engine (agent-loop extension AND the one-shot\n * orchestrator both branch on this ONE table, so their behavior can't drift).\n *\n * A distinct question from {@link isRetryableKind} (retry the SAME model):\n * a hop only helps for capacity/transport failures. Request-shaped failures\n * surface instead \u2014 `context_overflow` needs compaction, `content_filter` is\n * owned by the `content_filter_reroute` recovery strategy, and `auth` /\n * `invalid_request` are user-actionable and would fail identically on a hop.\n * The value set is currently identical to the retryable set, but it is kept as\n * its own table on purpose: the two answer different questions and may diverge.\n *\n * Exhaustive by construction (`Record<ProviderErrorKind, \u2026>`) \u2014 a new kind\n * refuses to compile until it is classified here.\n */\nexport function isFallbackWorthy(kind: ProviderErrorKind): boolean {\n return FALLBACK_WORTHY_BY_KIND[kind];\n}\n\nconst FALLBACK_WORTHY_BY_KIND: Record<ProviderErrorKind, boolean> = {\n rate_limit: true,\n quota_exhausted: true,\n overloaded: true,\n server: true,\n timeout: true,\n network: true,\n stream_hang: true,\n auth: false,\n context_overflow: false,\n content_filter: false,\n invalid_request: false,\n unknown: false,\n};\n\nexport class ProviderError extends WrongStackError {\n public readonly status: number;\n public readonly retryable: boolean;\n public readonly providerId: string;\n /** Canonical failure classification \u2014 see {@link ProviderErrorKind}. */\n public readonly kind: ProviderErrorKind;\n public readonly body?: ProviderErrorBody | undefined;\n\n /**\n * Duck-type guard: checks whether an unknown value *looks like* a\n * ProviderError by probing for its structural properties. Use this\n * anywhere the constructor identity might cross a package boundary\n * (e.g. `@wrongstack/providers` creates the error, but the runner in\n * `@wrongstack/core` checks it). A plain `instanceof ProviderError`\n * can fail when npm hoists duplicate copies of `@wrongstack/core`,\n * each with its own class identity.\n *\n * The check tests for the four invariant properties defined in the\n * constructor: `name === 'ProviderError'`, `status` (number),\n * `retryable` (boolean), and `kind` (string). This tolerates both\n * true `ProviderError` instances and cross-boundary copies.\n */\n static isProviderError(err: unknown): err is ProviderError {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n // Accept both ProviderError and its subclasses (e.g. StreamHangError) by\n // checking for the structural invariant properties defined in the\n // constructor. The `name` check accepts 'ProviderError' and any subclass\n // name that ends with 'Error' \u2014 this tolerates both true instances and\n // cross-boundary copies where instanceof may fail due to npm hoisting.\n const name = e.name;\n if (typeof name !== 'string' || !name.endsWith('Error')) return false;\n return (\n typeof e.status === 'number' &&\n typeof e.retryable === 'boolean' &&\n typeof e.kind === 'string'\n );\n }\n\n constructor(\n message: string,\n status: number,\n retryable: boolean,\n providerId: string,\n opts: {\n body?: ProviderErrorBody | undefined;\n cause?: unknown | undefined;\n /** Override the computed classification (rarely needed \u2014 tests, custom wires). */\n kind?: ProviderErrorKind | undefined;\n } = {},\n ) {\n const kind = opts.kind ?? classifyProviderError(status, opts.body, message);\n super({\n message,\n code: kindToCode(kind),\n subsystem: 'provider',\n severity: status >= 500 ? 'error' : 'warning',\n recoverable: retryable,\n context: { providerId, status },\n cause: opts.cause,\n });\n this.name = 'ProviderError';\n this.status = status;\n this.retryable = retryable;\n this.providerId = providerId;\n this.kind = kind;\n this.body = opts.body;\n }\n\n /**\n * Render a one-line, user-facing description. Designed for the CLI/TUI\n * status line and the agent's retry warning. Avoids dumping raw JSON\n * (which is what users see today when a 529 lands and the log message\n * includes the full `{\"type\":\"error\",...}` body).\n *\n * Examples:\n * \"minimax-coding-plan overloaded (529): High traffic detected. Upgrade for highspeed model. [req 06534785201de9c0\u2026]\"\n * \"openai rate limited (429): Retry after 12s\"\n * \"anthropic invalid request (400): messages.0.role must be one of 'user'|'assistant'\"\n * \"groq HTTP 500 (server error)\"\n */\n override describe(): string {\n const kind = describeStatus(this.status, this.body?.type);\n const head = `${this.providerId} ${kind}`;\n const detail = this.body?.message?.trim();\n const reqId = this.body?.requestId\n ? ` [req ${this.body.requestId.slice(0, 16)}${this.body.requestId.length > 16 ? '\u2026' : ''}]`\n : '';\n if (detail && detail.length > 0) {\n return `${head}: ${truncate(detail, 240)}${reqId}`;\n }\n return `${head}${reqId}`;\n }\n}\n\n/**\n * Belt-and-suspenders overflow detection for the recovery layer. Returns true\n * when a `ProviderError` is *shaped* like a context overflow even if its `kind`\n * says otherwise \u2014 an HTTP 413, or an overflow phrase anywhere in its message /\n * body. Gateways and proxies sometimes relabel an overflow as a generic\n * `invalid_request`/400 (or a caller constructs the error with an explicit\n * wrong `kind`); the `context_overflow_reduce` strategy uses this so those\n * still trigger compact-and-retry instead of failing terminally.\n */\nexport function isContextOverflowShaped(err: unknown): boolean {\n if (!(err instanceof ProviderError) && !ProviderError.isProviderError(err)) return false;\n const providerErr = err as ProviderError;\n if (providerErr.kind === 'context_overflow' || providerErr.status === 413) return true;\n if (providerErr.status < 400) return false;\n const text = [providerErr.message, providerErr.body?.message, providerErr.body?.type, providerErr.body?.raw]\n .filter(Boolean)\n .join('\\n');\n return CONTEXT_OVERFLOW_RE.test(text);\n}\n\nfunction describeStatus(status: number, type?: string): string {\n if (status === 0) return 'network error';\n if (status === 599) return `stream hang (${status})`;\n if (type === 'overloaded_error' || status === 529) return `overloaded (${status})`;\n if (type === 'rate_limit_error' || status === 429) return `rate limited (${status})`;\n if (type === 'authentication_error' || status === 401) return `auth failed (${status})`;\n if (type === 'permission_error' || status === 403) return `forbidden (${status})`;\n if (type === 'not_found_error' || status === 404) return `not found (${status})`;\n if (type === 'content_filter') return `content filtered (${status})`;\n if (type === 'invalid_request_error' || status === 400) return `invalid request (${status})`;\n if (status === 408) return `timeout (${status})`;\n if (status >= 500 && status < 600) return `HTTP ${status} (server error)`;\n if (type) return `${type} (${status})`;\n return `HTTP ${status}`;\n}\n\n/**\n * Thrown when the provider stream stops delivering data mid-response.\n * This is distinct from a network error (TCP reset, DNS failure) \u2014 the\n * connection is established and the response started, but chunks stopped\n * arriving before the stream completed.\n *\n * Status 599 is used as a sentinel to distinguish stream hangs from\n * regular HTTP errors while still flowing through ProviderError-based\n * retry and fallback infrastructure.\n */\nexport class StreamHangError extends ProviderError {\n /** Name of the provider that hung, e.g. \"zai\", \"anthropic\". */\n public readonly hungProviderId: string;\n /** Model that was being called when the hang occurred. */\n public readonly hungModel: string;\n /** How long (ms) we waited for the next chunk before declaring a hang. */\n public readonly hangTimeoutMs: number;\n /** How many bytes were received before the hang. */\n public readonly bytesReceived: number;\n /** Elapsed time (ms) from the start of the stream until the hang. */\n public readonly elapsedMs: number;\n\n constructor(opts: {\n providerId: string;\n model: string;\n hangTimeoutMs: number;\n bytesReceived: number;\n elapsedMs: number;\n cause?: unknown | undefined;\n }) {\n super(\n `Stream hang: ${opts.providerId}/${opts.model} \u2014 no data for ${opts.hangTimeoutMs}ms after ${opts.bytesReceived} bytes (${opts.elapsedMs}ms elapsed)`,\n 599,\n true, // always retryable\n opts.providerId,\n {\n body: {\n message: `Stream stalled after ${opts.elapsedMs}ms, ${opts.bytesReceived} bytes received`,\n },\n cause: opts.cause,\n },\n );\n this.name = 'StreamHangError';\n this.hungProviderId = opts.providerId;\n this.hungModel = opts.model;\n this.hangTimeoutMs = opts.hangTimeoutMs;\n this.bytesReceived = opts.bytesReceived;\n this.elapsedMs = opts.elapsedMs;\n }\n}\n\n/** Exhaustive kind \u2192 ErrorCode mapping \u2014 new kinds must be added here or the\n * file stops compiling (same drift-guard pattern as RETRYABLE_BY_KIND). */\nconst KIND_TO_CODE: Record<ProviderErrorKind, ErrorCode> = {\n network: ERROR_CODES.PROVIDER_NETWORK_ERROR,\n timeout: ERROR_CODES.PROVIDER_NETWORK_ERROR,\n rate_limit: ERROR_CODES.PROVIDER_RATE_LIMITED,\n quota_exhausted: ERROR_CODES.PROVIDER_RATE_LIMITED,\n auth: ERROR_CODES.PROVIDER_AUTH_FAILED,\n overloaded: ERROR_CODES.PROVIDER_OVERLOADED,\n context_overflow: ERROR_CODES.PROVIDER_CONTEXT_OVERFLOW,\n server: ERROR_CODES.PROVIDER_SERVER_ERROR,\n stream_hang: ERROR_CODES.PROVIDER_SERVER_ERROR,\n content_filter: ERROR_CODES.PROVIDER_INVALID_REQUEST,\n invalid_request: ERROR_CODES.PROVIDER_INVALID_REQUEST,\n unknown: ERROR_CODES.PROVIDER_INVALID_REQUEST,\n};\n\nfunction kindToCode(kind: ProviderErrorKind): ErrorCode {\n return KIND_TO_CODE[kind];\n}\n", "import * as path from 'node:path';\nimport type { Context } from '../core/context.js';\nimport type { TextBlock } from '../types/blocks.js';\nimport type { CompactReport } from '../types/compactor.js';\nimport type {\n CompletedWorkEvidence,\n CompletedWorkSource,\n ContextEvidenceState,\n ToolOutputMetadata,\n} from '../types/context-evidence.js';\nimport type { Message } from '../types/messages.js';\n\nconst MAX_TOOL_CALLS = 80;\nconst MAX_FACTS = 40;\nconst MAX_ERRORS = 20;\nconst MAX_DIGEST_CHARS = 4_000;\n/** Cap for the per-iteration reference scan \u2014 see markAssistantReferencedEvidence. */\nconst RECENT_TOOL_CALL_SCAN_LIMIT = 20;\n/** Cap content fed to file/symbol regex extractors (first N chars). */\nconst EXTRACT_CONTENT_CAP_CHARS = 10_000;\n/** Only scan the last N lines for error patterns \u2014 errors surface at the bottom. */\nconst EXTRACT_ERROR_TAIL_LINES = 200;\n\nconst WRITE_TOOLS = new Set(['edit', 'write', 'replace', 'patch']);\nconst READ_TOOLS = new Set(['read', 'grep', 'glob', 'ls', 'tree']);\n\nexport function createContextEvidenceState(): ContextEvidenceState {\n return {\n sessionGoals: [],\n implicitFacts: [],\n activeErrors: [],\n toolCalls: [],\n fileGraph: {},\n repeatedReads: [],\n completedWork: [],\n updatedAt: Date.now(),\n };\n}\n\nexport interface RecordToolOutputEvidenceInput {\n toolUseId: string;\n toolName: string;\n input: unknown;\n content: string;\n ok: boolean;\n outputBytes?: number | undefined;\n outputTokens?: number | undefined;\n outputLines?: number | undefined;\n}\n\nexport function recordUserIntentEvidence(ctx: Context, text: string): void {\n const intent = normalizeWhitespace(text).slice(0, 700);\n if (!intent) return;\n const state = ensureEvidence(ctx);\n state.currentIntent = { text: intent, updatedAt: Date.now() };\n if (state.sessionGoals.length === 0 || isGoalish(intent)) {\n pushUniqueBounded(state.sessionGoals, intent, 8);\n }\n state.updatedAt = Date.now();\n}\n\nexport function recordToolOutputEvidence(\n ctx: Context,\n input: RecordToolOutputEvidenceInput,\n): ToolOutputMetadata {\n const state = ensureEvidence(ctx);\n // Cap content for regex extraction. File paths and symbol declarations\n // appear near the top of tool output (import blocks, function definitions),\n // so the first 10KB captures them. Without this cap, matchAll() runs over\n // the full output \u2014 e.g. a 50KB file read triggers ~100KB of regex scanning\n // across two patterns in extractSymbols plus the extractFiles pass.\n const scanContent = input.content.length > EXTRACT_CONTENT_CAP_CHARS\n ? input.content.slice(0, EXTRACT_CONTENT_CAP_CHARS)\n : input.content;\n const files = extractFiles(ctx, input.toolName, input.input, scanContent);\n const symbols = extractSymbols(scanContent, input.input);\n const commands = extractCommands(input.toolName, input.input);\n const errors = extractErrors(input.content);\n const summary = summarizeToolOutput(input.toolName, input.input, input.content, {\n files,\n symbols,\n errors,\n ok: input.ok,\n });\n\n const metadata: ToolOutputMetadata = {\n toolUseId: input.toolUseId,\n toolName: input.toolName,\n ok: input.ok,\n inputSummary: summarizeInput(input.input),\n summary,\n files,\n symbols,\n commands,\n errors,\n status: 'seen',\n referenceCount: 0,\n seenAt: Date.now(),\n outputBytes: input.outputBytes,\n outputTokens: input.outputTokens,\n outputLines: input.outputLines,\n };\n\n state.toolCalls.push(metadata);\n if (state.toolCalls.length > MAX_TOOL_CALLS) {\n state.toolCalls.splice(0, state.toolCalls.length - MAX_TOOL_CALLS);\n }\n\n updateFileGraph(state, metadata);\n updateRepeatedReadSignals(state, metadata);\n if (errors.length > 0) {\n for (const err of errors) pushUniqueBounded(state.activeErrors, err, MAX_ERRORS);\n }\n const fact = implicitFactFor(metadata);\n if (fact) pushUniqueBounded(state.implicitFacts, fact, MAX_FACTS);\n state.updatedAt = Date.now();\n return metadata;\n}\n\nexport function markAssistantReferencedEvidence(ctx: Context, text: string): void {\n const state = ensureEvidence(ctx);\n const haystack = text.toLowerCase();\n if (!haystack.trim()) return;\n\n // Only scan the most recent tool calls. The assistant almost always\n // references the files/symbols it just worked on \u2014 older entries are\n // rarely re-referenced. Scanning the full list (up to 80 entries) means\n // worst case: 80 \u00D7 (files + symbols) includes() calls per iteration,\n // each O(responseText.length), which degrades as the conversation grows.\n // The last 20 captures the realistic reference window at \u00BC the cost.\n const recent = state.toolCalls.length > RECENT_TOOL_CALL_SCAN_LIMIT\n ? state.toolCalls.slice(-RECENT_TOOL_CALL_SCAN_LIMIT)\n : state.toolCalls;\n for (const tool of recent) {\n if (!metadataReferencedByText(tool, haystack)) continue;\n tool.status = 'referenced';\n tool.referenceCount++;\n tool.referencedAt = Date.now();\n for (const file of tool.files) {\n const node = state.fileGraph[file];\n if (node) node.referenced = true;\n }\n }\n state.updatedAt = Date.now();\n}\n\nexport function buildContextEvidenceDigest(ctx: Context): string {\n const state = ensureEvidence(ctx);\n const lines: string[] = [];\n\n if (state.currentIntent?.text) {\n lines.push(`intent: ${state.currentIntent.text}`);\n }\n\n const goals = state.sessionGoals.slice(-3);\n if (goals.length > 0) {\n lines.push('session_goals:');\n for (const goal of goals) lines.push(`- ${goal}`);\n }\n\n const activeErrors = state.activeErrors.slice(-5);\n if (activeErrors.length > 0) {\n lines.push('active_errors:');\n for (const err of activeErrors) lines.push(`- ${err}`);\n }\n\n const files = Object.values(state.fileGraph)\n .sort((a, b) => (b.writes - a.writes) || (b.reads - a.reads) || a.path.localeCompare(b.path))\n .slice(0, 12);\n if (files.length > 0) {\n lines.push('dependency_graph:');\n for (const file of files) {\n const actions = [\n file.reads > 0 ? `read ${file.reads}x` : '',\n file.writes > 0 ? `write ${file.writes}x` : '',\n ].filter(Boolean).join(', ');\n const refs = file.referenced ? '; referenced by assistant' : '';\n const via = file.lastToolUseId ? `; last via ${file.lastToolUseId}` : '';\n lines.push(`- ${file.path} (${actions || 'seen'}${refs}${via})`);\n }\n }\n\n const referenced = state.toolCalls\n .filter((tool) => tool.status === 'referenced')\n .slice(-10);\n const recentSeen = state.toolCalls\n .filter((tool) => tool.status === 'seen')\n .slice(-5);\n const trail = [...referenced, ...recentSeen];\n if (trail.length > 0) {\n lines.push('tool_trail:');\n for (const tool of trail) {\n const size = tool.outputTokens ? `; ~${tool.outputTokens} tokens` : '';\n const filesText = tool.files.length > 0 ? `; files=${tool.files.slice(0, 4).join(', ')}` : '';\n const symbolsText = tool.symbols.length > 0 ? `; symbols=${tool.symbols.slice(0, 4).join(', ')}` : '';\n lines.push(\n `- ${tool.toolUseId} ${tool.toolName} ${tool.status}: ${tool.summary}${filesText}${symbolsText}${size}`,\n );\n }\n }\n\n const facts = state.implicitFacts.slice(-8);\n if (facts.length > 0) {\n lines.push('implicit_facts:');\n for (const fact of facts) lines.push(`- ${fact}`);\n }\n\n const digest = lines.join('\\n');\n if (digest.length <= MAX_DIGEST_CHARS) return digest;\n return `${digest.slice(0, MAX_DIGEST_CHARS)}... [+${digest.length - MAX_DIGEST_CHARS} chars]`;\n}\n\nexport function repeatedReadPressure(ctx: Context): number {\n return ensureEvidence(ctx).repeatedReads.reduce((max, item) => Math.max(max, item.count), 0);\n}\n\n/** Marker prefixing the forced evidence-floor system message (also its dedupe key). */\nconst CONTEXT_STATE_MARKER = '[context_state]';\n\n/**\n * Stable issue keys emitted by `checkCompactionQuality` and consumed by\n * `injectEvidenceFloor`. Using typed consts instead of raw string literals\n * ensures the producer/consumer contract is typechecker-enforced \u2014 any new\n * issue key must be added here and both sides will be updated together.\n */\nconst QUALITY_ISSUE = {\n missingIntent: 'missing intent anchor',\n missingPathTrail: 'missing tool/path trail',\n} as const;\n\n/**\n * Deterministic post-compaction sanity check. Cheap and local: records whether\n * the compacted context still carries an intent anchor and a tool/path trail.\n * Shared across all compactors so they report quality the same way (previously\n * only HybridCompactor did). Advisory on its own \u2014 pair with\n * `injectEvidenceFloor` to actually repair a flagged loss.\n */\nexport function checkCompactionQuality(\n ctx: Context,\n opts: {\n collapsedDigest?: string | undefined;\n evidenceDigest?: string | undefined;\n reduced: boolean;\n },\n): CompactReport['quality'] {\n const evidence = ctx.contextEvidence;\n const digest = `${opts.collapsedDigest ?? ''}\\n${opts.evidenceDigest ?? ''}`;\n const hasIntent = Boolean(\n evidence?.currentIntent?.text ||\n /\\b(intent|goal|session_goals|hedef|amac|istiyorum|gerekiyor)\\b/i.test(digest),\n );\n const hasPathTrail = Boolean(\n Object.keys(evidence?.fileGraph ?? {}).length > 0 ||\n (evidence?.toolCalls.length ?? 0) > 0 ||\n /\\b(dependency_graph|tool_trail|files=)\\b/i.test(digest),\n );\n const issues: string[] = [];\n if (opts.reduced && !hasIntent) issues.push(QUALITY_ISSUE.missingIntent);\n if (opts.reduced && !hasPathTrail) issues.push(QUALITY_ISSUE.missingPathTrail);\n return { ok: issues.length === 0, hasIntent, hasPathTrail, issues };\n}\n\n/**\n * Enforce an evidence floor: when `checkCompactionQuality` flags that\n * compaction dropped the intent anchor or tool/path trail, prepend a compact\n * `[context_state]` system message rebuilt from the live evidence state so the\n * session goal is never silently lost. Idempotent (won't double-inject) and a\n * no-op when quality is fine or there is no evidence to inject. Returns true\n * when it injected a block (so the caller re-estimates tokens).\n */\nexport function injectEvidenceFloor(\n ctx: Context,\n quality: CompactReport['quality'] | undefined,\n): boolean {\n if (!quality || quality.ok) return false;\n const needsRepair =\n quality.issues.includes(QUALITY_ISSUE.missingIntent) ||\n quality.issues.includes(QUALITY_ISSUE.missingPathTrail);\n if (!needsRepair) return false;\n\n const digest = buildContextEvidenceDigest(ctx);\n if (!digest.trim()) return false;\n\n const already = ctx.messages.some(\n (m) => typeof m.content === 'string' && m.content.startsWith(CONTEXT_STATE_MARKER),\n );\n if (already) return false;\n\n const block: Message = { role: 'system', content: `${CONTEXT_STATE_MARKER}\\n${digest}` };\n ctx.state.replaceMessages([block, ...ctx.messages]);\n return true;\n}\n\nfunction ensureEvidence(ctx: Context): ContextEvidenceState {\n if (!ctx.contextEvidence) {\n (ctx as never as { contextEvidence: ContextEvidenceState }).contextEvidence =\n createContextEvidenceState();\n }\n // States restored from sessions persisted before the completed-work\n // ledger existed lack the array \u2014 heal in place so recorders can push.\n ctx.contextEvidence.completedWork ??= [];\n return ctx.contextEvidence;\n}\n\n// \u2500\u2500 Completed-work ledger \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Bound on retained ledger entries \u2014 oldest are dropped first. */\nconst MAX_COMPLETED_WORK = 50;\n/** How many (newest) entries render into the system-prompt block. */\nconst LEDGER_BLOCK_ITEMS = 20;\n\n/** Marker prefixing the ledger's system-prompt block (also used to find/replace it). */\nexport const COMPLETED_WORK_LEDGER_MARKER = '[completed_work_ledger]';\n\nexport interface RecordCompletedWorkInput {\n /** Stable dedupe key, e.g. `task:<id>` \u2014 re-completion updates in place. */\n key: string;\n source: CompletedWorkSource;\n summary: string;\n /** Optional pointer to proof (test run, commit hash, file path). */\n evidence?: string | undefined;\n /** Epoch ms; defaults to now. */\n completedAt?: number | undefined;\n}\n\n/**\n * Append one finished unit of work to the session ledger. The provider request\n * composer renders this state as a volatile tail block; the stable system-prompt\n * prefix is never mutated here.\n */\nexport function recordCompletedWorkEvidence(\n ctx: Context,\n input: RecordCompletedWorkInput,\n): CompletedWorkEvidence {\n const state = ensureEvidence(ctx);\n const entry: CompletedWorkEvidence = {\n key: input.key,\n source: input.source,\n summary: normalizeWhitespace(input.summary).slice(0, 300),\n completedAt: input.completedAt ?? Date.now(),\n ...(input.evidence !== undefined && { evidence: input.evidence }),\n };\n const existing = state.completedWork.findIndex((item) => item.key === entry.key);\n if (existing >= 0) state.completedWork.splice(existing, 1);\n state.completedWork.push(entry);\n if (state.completedWork.length > MAX_COMPLETED_WORK) {\n state.completedWork.splice(0, state.completedWork.length - MAX_COMPLETED_WORK);\n }\n state.updatedAt = Date.now();\n return entry;\n}\n\n/** Render the ledger's system-prompt block text (marker + newest entries). */\nexport function formatCompletedWorkLedger(items: readonly CompletedWorkEvidence[]): string {\n const lines = items\n .slice(-LEDGER_BLOCK_ITEMS)\n .map(\n (item) =>\n `- [${item.source}] ${item.summary}${item.evidence ? ` (evidence: ${item.evidence})` : ''}`,\n );\n return (\n `${COMPLETED_WORK_LEDGER_MARKER}\\n` +\n 'Work already completed this session \u2014 do not redo it; build on it:\\n' +\n lines.join('\\n')\n );\n}\n\n/** Build the current volatile completed-work block without mutating the prompt. */\nexport function buildCompletedWorkLedgerBlock(ctx: Context): TextBlock | undefined {\n const items = ensureEvidence(ctx).completedWork;\n if (items.length === 0) return undefined;\n return {\n type: 'text',\n text: formatCompletedWorkLedger(items),\n cache_control: { type: 'ephemeral' },\n };\n}\n\n/**\n * @deprecated Volatile state must be composed at request time. Kept as a\n * compatibility no-op for embedders importing the old helper.\n */\nexport function syncCompletedWorkLedgerBlock(_ctx: Context): void {\n // Intentionally empty. Mutating ctx.systemPrompt invalidates provider prefix caches.\n}\n\nfunction isGoalish(text: string): boolean {\n return /\\b(goal|objective|task|need|want|implement|fix|improve|refactor|add|remove|hedef|amac|istiyorum|gerekiyor|iyilestir|duzelt|ekle|kaldir)\\b/i.test(text);\n}\n\nfunction normalizeWhitespace(text: string): string {\n return text.replace(/\\s+/g, ' ').trim();\n}\n\nfunction pushUniqueBounded(list: string[], value: string, max: number): void {\n const normalized = normalizeWhitespace(value);\n /* v8 ignore next -- unreachable: every caller passes already-normalized non-empty text */\n if (!normalized) return;\n const existing = list.findIndex((item) => item.toLowerCase() === normalized.toLowerCase());\n if (existing >= 0) list.splice(existing, 1);\n list.push(normalized);\n if (list.length > max) list.splice(0, list.length - max);\n}\n\nfunction extractFiles(\n ctx: Context,\n toolName: string,\n input: unknown,\n content: string,\n): string[] {\n const out = new Set<string>();\n for (const value of inputPathValues(input)) addPath(ctx, out, value);\n\n if (toolName === 'grep' || toolName === 'glob' || toolName === 'bash') {\n const re = /(?:(?:[A-Za-z]:)?[./\\\\]?[\\w@.-]+(?:[\\\\/][\\w@(). -]+)+\\.[A-Za-z0-9]{1,12})/g;\n for (const match of content.matchAll(re)) addPath(ctx, out, match[0]);\n }\n\n return [...out].slice(0, 30);\n}\n\nfunction inputPathValues(input: unknown): string[] {\n const values: string[] = [];\n const visit = (value: unknown, key?: string): void => {\n if (typeof value === 'string') {\n if (key && /^(path|file|files|fromFile|toFile|dir|cwd)$/i.test(key)) values.push(value);\n return;\n }\n if (Array.isArray(value)) {\n for (const item of value) visit(item, key);\n return;\n }\n if (!value || typeof value !== 'object') return;\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) visit(v, k);\n };\n visit(input);\n return values;\n}\n\nfunction addPath(ctx: Context, out: Set<string>, raw: string): void {\n const clean = raw.trim().replace(/^[\"'`]+|[\"'`),;:]+$/g, '');\n if (!clean || clean.length > 260) return;\n let normalized = clean.replace(/\\\\/g, '/');\n try {\n const abs = path.isAbsolute(clean) ? path.resolve(clean) : null;\n if (abs) {\n const rel = path.relative(ctx.projectRoot, abs);\n if (!rel.startsWith('..') && !path.isAbsolute(rel)) {\n normalized = rel.replace(/\\\\/g, '/');\n }\n }\n } catch {\n // Keep the best-effort normalized string.\n }\n if (normalized.length > 0) out.add(normalized);\n}\n\nfunction extractSymbols(content: string, input: unknown): string[] {\n const out = new Set<string>();\n const patterns = [\n /\\b(?:function|class|interface|type|enum|const|let|var|def|fn|struct)\\s+([A-Za-z_$][\\w$]*)/g,\n /\\b(?:export\\s+)?(?:async\\s+)?function\\s+([A-Za-z_$][\\w$]*)/g,\n ];\n for (const re of patterns) {\n for (const match of content.matchAll(re)) {\n if (match[1]) out.add(match[1]);\n if (out.size >= 30) break;\n }\n }\n\n const pattern = input && typeof input === 'object'\n ? (input as Record<string, unknown>)['pattern']\n : undefined;\n if (typeof pattern === 'string' && /^[A-Za-z_$][\\w$]*$/.test(pattern)) {\n out.add(pattern);\n }\n\n return [...out].slice(0, 30);\n}\n\nfunction extractCommands(toolName: string, input: unknown): string[] {\n if (toolName !== 'bash' && toolName !== 'exec' && toolName !== 'shell') return [];\n if (!input || typeof input !== 'object') return [];\n const command = (input as Record<string, unknown>)['command'];\n if (typeof command !== 'string') return [];\n return [command.slice(0, 220)];\n}\n\nfunction extractErrors(content: string): string[] {\n const allLines = content.split(/\\r?\\n/);\n // Only scan the last N lines \u2014 errors and stack traces surface at the\n // bottom of tool output. Scanning all lines means one regex test per line,\n // so a 2000-line file read costs 2000 regex evaluations for no gain since\n // the interesting errors are always at the tail.\n const lines = allLines.length > EXTRACT_ERROR_TAIL_LINES\n ? allLines.slice(-EXTRACT_ERROR_TAIL_LINES)\n : allLines;\n const errors: string[] = [];\n for (const line of lines) {\n if (!/\\b(error|exception|failed|failure|fatal|panic|timeout|denied|enoent|eacces|eperm|typeerror|syntaxerror)\\b/i.test(line)) continue;\n errors.push(normalizeWhitespace(line).slice(0, 260));\n if (errors.length >= 5) break;\n }\n return errors;\n}\n\nfunction summarizeInput(input: unknown): string | undefined {\n if (!input || typeof input !== 'object') return undefined;\n const obj = input as Record<string, unknown>;\n const parts: string[] = [];\n for (const key of ['path', 'file', 'pattern', 'glob', 'command']) {\n const value = obj[key];\n if (typeof value === 'string') parts.push(`${key}=${value.slice(0, 160)}`);\n }\n return parts.length > 0 ? parts.join(', ') : undefined;\n}\n\nfunction summarizeToolOutput(\n toolName: string,\n input: unknown,\n content: string,\n opts: { files: string[]; symbols: string[]; errors: string[]; ok: boolean },\n): string {\n if (!opts.ok && opts.errors.length > 0) return opts.errors[0] ?? `${toolName} failed`;\n if (toolName === 'read' && opts.files[0]) return `read ${opts.files[0]}`;\n if (toolName === 'grep') {\n const pattern = input && typeof input === 'object'\n ? (input as Record<string, unknown>)['pattern']\n : undefined;\n return `searched ${typeof pattern === 'string' ? pattern : 'pattern'} (${opts.files.length} file hint(s))`;\n }\n if ((toolName === 'edit' || toolName === 'write') && opts.files[0]) {\n return `${toolName === 'write' ? 'wrote' : 'edited'} ${opts.files[0]}`;\n }\n const firstLine = normalizeWhitespace(content.split(/\\r?\\n/).find((line) => line.trim()) ?? '');\n return firstLine ? firstLine.slice(0, 220) : `${toolName} returned no text`;\n}\n\nfunction updateFileGraph(state: ContextEvidenceState, metadata: ToolOutputMetadata): void {\n const writes = WRITE_TOOLS.has(metadata.toolName) ? 1 : 0;\n const reads = writes === 0 && (READ_TOOLS.has(metadata.toolName) || metadata.files.length > 0)\n ? 1\n : 0;\n for (const file of metadata.files) {\n const existing = state.fileGraph[file] ?? {\n path: file,\n reads: 0,\n writes: 0,\n tools: [],\n referenced: false,\n };\n existing.reads += reads;\n existing.writes += writes;\n existing.lastToolUseId = metadata.toolUseId;\n pushUniqueBounded(existing.tools, `${metadata.toolName}#${metadata.toolUseId}`, 8);\n state.fileGraph[file] = existing;\n }\n}\n\nfunction updateRepeatedReadSignals(state: ContextEvidenceState, metadata: ToolOutputMetadata): void {\n if (metadata.toolName !== 'read' || metadata.files.length === 0) {\n state.lastReadPath = undefined;\n return;\n }\n const file = metadata.files[0] as string;\n if (state.lastReadPath === file) {\n const existing = state.repeatedReads.find((item) => item.file === file);\n if (existing) {\n existing.count++;\n existing.lastToolUseId = metadata.toolUseId;\n } else {\n state.repeatedReads.push({ file, count: 2, lastToolUseId: metadata.toolUseId });\n }\n if (state.repeatedReads.length > 10) state.repeatedReads.shift();\n }\n state.lastReadPath = file;\n}\n\nfunction implicitFactFor(metadata: ToolOutputMetadata): string | undefined {\n if (metadata.errors.length > 0) return `${metadata.toolName}#${metadata.toolUseId} exposed error: ${metadata.errors[0]}`;\n if (metadata.toolName === 'read' && metadata.files[0]) {\n const size = metadata.outputLines ? ` (${metadata.outputLines} line(s) returned)` : '';\n return `read ${metadata.files[0]}${size}`;\n }\n if ((metadata.toolName === 'edit' || metadata.toolName === 'write') && metadata.files[0]) {\n return `${metadata.toolName} changed ${metadata.files[0]}`;\n }\n if (metadata.status === 'referenced') return `${metadata.toolName}#${metadata.toolUseId} was referenced`;\n return undefined;\n}\n\nfunction metadataReferencedByText(metadata: ToolOutputMetadata, haystack: string): boolean {\n for (const file of metadata.files) {\n const f = file.toLowerCase();\n const base = path.basename(file).toLowerCase();\n if (f && haystack.includes(f)) return true;\n if (base && haystack.includes(base)) return true;\n }\n for (const symbol of metadata.symbols) {\n if (symbol.length >= 3 && haystack.includes(symbol.toLowerCase())) return true;\n }\n for (const err of metadata.errors) {\n const head = err.slice(0, 80).toLowerCase();\n if (head.length >= 12 && haystack.includes(head)) return true;\n }\n return false;\n}\n", "import type { JSONSchema } from '../types/tool.js';\n\nexport interface ToolWireDefinitionLike {\n name: string;\n description?: string | undefined;\n inputSchema: unknown;\n}\n\nexport interface CompactToolDefinitionForWireOptions {\n /** Top-level tool description budget. */\n descriptionMaxChars?: number | undefined;\n /** Per-JSON-Schema `description` annotation budget. */\n schemaDescriptionMaxChars?: number | undefined;\n}\n\nexport interface CompactWireToolDefinition {\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n}\n\nconst TOOL_DESCRIPTION_MAX_CHARS = 400;\nconst SCHEMA_DESCRIPTION_MAX_CHARS = 120;\n\nconst compactCache = new WeakMap<object, CompactWireToolDefinition>();\n\n/**\n * Return the provider-wire version of a tool definition.\n *\n * Tool schemas remain structurally intact: validation keywords, property\n * names, required fields, enum values, and nested shapes are preserved. The\n * only reduction is on human prose annotations (`description`), which are the\n * largest repeated cost in provider tool declarations.\n */\nexport function compactToolDefinitionForWire(\n tool: ToolWireDefinitionLike,\n opts: CompactToolDefinitionForWireOptions = {},\n): CompactWireToolDefinition {\n const useDefaultOptions =\n opts.descriptionMaxChars === undefined && opts.schemaDescriptionMaxChars === undefined;\n if (useDefaultOptions && typeof tool === 'object' && tool !== null) {\n const cached = compactCache.get(tool);\n if (cached) return cached;\n }\n\n const compact: CompactWireToolDefinition = {\n name: tool.name,\n description: compactDescription(\n tool.description ?? '',\n opts.descriptionMaxChars ?? TOOL_DESCRIPTION_MAX_CHARS,\n ),\n inputSchema: normalizeTopLevelToolSchema(\n compactSchemaDescriptions(\n tool.inputSchema,\n opts.schemaDescriptionMaxChars ?? SCHEMA_DESCRIPTION_MAX_CHARS,\n ),\n ),\n };\n\n if (useDefaultOptions && typeof tool === 'object' && tool !== null) {\n compactCache.set(tool, compact);\n }\n return compact;\n}\n\n/**\n * Tool inputs are always JSON objects, but dynamically supplied MCP/plugin\n * schemas sometimes express that object as a top-level oneOf/anyOf/allOf.\n * Anthropic-family endpoints reject those combinators at the input_schema\n * root (including when reached through an OpenAI-compatible gateway such as\n * OmniRoute). Keep nested combinators intact and flatten only the root.\n * Runtime validation still uses the tool's original schema.\n */\nexport function normalizeTopLevelToolSchema(\n schema: Record<string, unknown>,\n): Record<string, unknown> {\n const combinators = (['oneOf', 'anyOf', 'allOf'] as const)\n .map((keyword) => ({ keyword, branches: schema[keyword] }))\n .filter((entry): entry is { keyword: 'oneOf' | 'anyOf' | 'allOf'; branches: unknown[] } =>\n Array.isArray(entry.branches),\n );\n if (combinators.length === 0) return schema;\n\n const out: Record<string, unknown> = { ...schema, type: 'object' };\n delete out['oneOf'];\n delete out['anyOf'];\n delete out['allOf'];\n\n const properties: Record<string, unknown> = isRecord(schema['properties'])\n ? { ...schema['properties'] }\n : {};\n let required = stringSet(schema['required']);\n\n for (const { keyword, branches } of combinators) {\n const objectBranches = branches.filter(isRecord);\n for (const branch of objectBranches) {\n if (isRecord(branch['properties'])) Object.assign(properties, branch['properties']);\n }\n\n const branchRequired = objectBranches.map((branch) => stringSet(branch['required']));\n if (keyword === 'allOf') {\n for (const fields of branchRequired) for (const field of fields) required.add(field);\n } else if (branchRequired.length > 0) {\n const common = new Set(\n [...branchRequired[0]!].filter((field) =>\n branchRequired.slice(1).every((fields) => fields.has(field)),\n ),\n );\n required = new Set([...required, ...common]);\n }\n }\n\n out['properties'] = properties;\n if (required.size > 0) out['required'] = [...required];\n else delete out['required'];\n return out;\n}\n\nfunction stringSet(value: unknown): Set<string> {\n return new Set(\n Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : [],\n );\n}\n\nexport function compactSchemaDescriptions(\n schema: unknown,\n maxDescriptionChars = SCHEMA_DESCRIPTION_MAX_CHARS,\n): Record<string, unknown> {\n const compact = compactSchemaNode(schema, maxDescriptionChars);\n return isRecord(compact) ? compact : { type: 'object', properties: {} };\n}\n\nfunction compactSchemaNode(node: unknown, maxDescriptionChars: number): unknown {\n if (Array.isArray(node)) {\n return node.map((item) => compactSchemaNode(item, maxDescriptionChars));\n }\n if (!isRecord(node)) return node;\n\n const out: JSONSchema = {};\n for (const [key, value] of Object.entries(node)) {\n if (key === 'description' && typeof value === 'string') {\n out[key] = compactDescription(value, maxDescriptionChars);\n } else {\n out[key] = compactSchemaNode(value, maxDescriptionChars);\n }\n }\n return out;\n}\n\nexport function compactDescription(text: string, maxChars: number): string {\n const normalized = text.replace(/\\s+/g, ' ').trim();\n if (normalized.length <= maxChars) return normalized;\n if (maxChars <= 20) return normalized.slice(0, maxChars);\n\n const hardLimit = maxChars - 12;\n const boundary = findSemanticBoundary(normalized, hardLimit);\n const head = normalized.slice(0, boundary > 0 ? boundary : hardLimit).trimEnd();\n return `${head} ...`;\n}\n\nexport function findSemanticBoundary(text: string, limit: number): number {\n const punctuation = Math.max(\n text.lastIndexOf('. ', limit),\n text.lastIndexOf('; ', limit),\n text.lastIndexOf(': ', limit),\n );\n if (punctuation >= Math.floor(limit * 0.45)) return punctuation + 1;\n\n const comma = text.lastIndexOf(', ', limit);\n if (comma >= Math.floor(limit * 0.6)) return comma + 1;\n\n const space = text.lastIndexOf(' ', limit);\n return space >= Math.floor(limit * 0.6) ? space : limit;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n", "import type { Message } from '../types/messages.js';\nimport { compactToolDefinitionForWire } from './tool-wire-compact.js';\n\n/**\n * Shared token estimation with JSON.stringify caching.\n * Avoids repeated stringification of tool input objects.\n *\n * ## Calibration\n *\n * `estimateRequestTokens` uses a fixed 3.5 chars/token heuristic \u2014 a\n * conservative overestimate that prevents underestimation but reduces\n * accuracy. After each API call, call `recordActualUsage()` with the\n * provider-authoritative effective prompt tokens (`input + cacheRead +\n * cacheWrite` after adapter normalization). The module maintains a rolling\n * average of `actual / estimated` ratio (EWM, \u03B1=0.3) and applies it to\n * subsequent calls via `estimateRequestTokensCalibrated`.\n *\n * Calibration is per-module (shared across all callers), which is\n * sufficient: the chars/token ratio is a property of the tokenizer,\n * not the model. Uncalibrated calls (before any samples, or when\n * `recordActualUsage` is not called) fall back to the uncalibrated\n * estimate so nothing breaks.\n */\n\nconst RoughTokenEstimate = (text: string, charsPerToken = 3.5): number =>\n Math.max(1, Math.ceil(text.length / charsPerToken));\n\n/** Calibration state: actual/estimated ratio via exponential weighted moving average. */\ninterface CalState {\n ratio: number; // current calibration multiplier (actual / estimated)\n count: number; // number of samples recorded\n prevEst: number; // estimated tokens from the most recent estimateRequestTokens call\n}\n\n/** EWM \u03B1 \u2014 higher = faster adaptation, more volatile. */\nconst CAL_ALPHA = 0.3;\n\n/**\n * Calibration is keyed so that, in a multi-agent / model-switching process,\n * each (provider, model) tokenizer gets its own ratio instead of all of them\n * collapsing onto one shared number. Callers that don't pass a key use the\n * shared `__global__` bucket \u2014 that preserves the original single-session\n * behavior and keeps all existing call sites working unchanged.\n */\nconst CALIBRATION_GLOBAL_KEY = '__global__';\nconst _cals = new Map<string, CalState>();\n\nfunction calState(key: string): CalState {\n let state = _cals.get(key);\n if (!state) {\n state = { ratio: 1.0, count: 0, prevEst: 0 };\n _cals.set(key, state);\n }\n return state;\n}\n\nconst MIN_SAMPLES_FOR_CALIBRATION = 3;\n\n/**\n * Fallback chars/token ratios per model family for providers that don't return\n * usage data. Used when `recordActualUsage` receives zero/negative tokens and\n * we have enough samples to trust the fallback. Keys are lowercase prefixes.\n */\nconst MODEL_FAMILY_RATIO: Record<string, number> = {\n // Anthropic: ~3.8-4.0 chars/token depending on model\n claude: 3.8,\n // OpenAI: ~4.0 chars/token\n 'gpt-4': 4.0,\n 'gpt-3.5': 4.0,\n // Google: ~3.5 chars/token\n gemini: 3.5,\n // DeepSeek: ~3.5 chars/token\n deepseek: 3.5,\n};\n\n/**\n * Cache of computed estimates keyed by a compact HASH of the stringified input \u2014\n * NOT the stringified input itself. The estimator is called per tool_use and per\n * tool_result on every context-window check, and the source strings are full tool\n * payloads (file reads, command output). Keying the Map by those strings meant the\n * cache retained up to 50 000 full payloads \u2014 hundreds of MB \u2014 for a value that is\n * a single number. We now key by `\"<len>:<djb2>\"` (\u224815 chars) and never retain the\n * payload. A hash collision (same length AND djb2) at worst returns a slightly-off\n * heuristic token estimate, which only nudges compaction timing \u2014 never correctness.\n */\nconst ESTIMATE_CACHE = new Map<string, number>();\n/** Insertion-order queue for O(1) LRU eviction: shift from front on overcapacity. */\nconst _estimateCacheOrder: string[] = [];\n\nconst ESTIMATE_CACHE_MAX_SIZE = 50_000;\n\n/** Compact collision-resistant key: length prefix + 32-bit DJB2 of the source. */\nfunction estimateCacheKey(source: string): string {\n let h = 5381;\n for (let i = 0; i < source.length; i++) {\n h = ((h << 5) + h + source.charCodeAt(i)) | 0;\n }\n return `${source.length}:${h >>> 0}`;\n}\n\nfunction getCachedEstimate(source: string, compute: (source: string) => number): number {\n const key = estimateCacheKey(source);\n const existing = ESTIMATE_CACHE.get(key);\n if (existing !== undefined) return existing;\n if (ESTIMATE_CACHE.size >= ESTIMATE_CACHE_MAX_SIZE) {\n // Evict oldest half \u2014 O(1) per eviction (array shift + Map.delete) instead\n // of O(n) iteration over all 50 000 keys in the Map.\n while (ESTIMATE_CACHE.size > Math.floor(ESTIMATE_CACHE_MAX_SIZE / 2)) {\n const oldest = _estimateCacheOrder.shift();\n if (oldest !== undefined) ESTIMATE_CACHE.delete(oldest);\n }\n }\n // Compute on the full source (never retained); only the hash key + number stay.\n const estimate = compute(source);\n ESTIMATE_CACHE.set(key, estimate);\n _estimateCacheOrder.push(key);\n return estimate;\n}\n\n/**\n * Estimate tokens for a tool_use block input.\n * Caches the stringified result keyed by the stable string representation\n * to avoid repeated JSON.stringify calls during context window checks.\n */\nexport function estimateToolInputTokens(input: unknown): number {\n if (typeof input === 'string') return RoughTokenEstimate(input);\n if (input === null || typeof input !== 'object') {\n return RoughTokenEstimate(String(input));\n }\n // JSON.stringify is called once to form the cache key; RoughTokenEstimate\n // is deferred only on cache miss (compute callback), not wrapped unnecessarily.\n return getCachedEstimate(JSON.stringify(input), (key) => RoughTokenEstimate(key));\n}\n\n/**\n * Estimate tokens for a tool_result content.\n */\nexport function estimateToolResultTokens(content: string | unknown): number {\n if (typeof content === 'string') return RoughTokenEstimate(content);\n return getCachedEstimate(JSON.stringify(content), (key) => RoughTokenEstimate(key));\n}\n\n/**\n * Estimate tokens for a text block.\n */\nexport function estimateTextTokens(text: string): number {\n return RoughTokenEstimate(text);\n}\n\n/**\n * Compute and cache the token estimate for a single message. This is the\n * canonical per-message estimator \u2014 called once by ConversationState on\n * append/replace so the O(n\u00B7m) content-block walk happens at mutation time,\n * not on every context-pressure check.\n */\nexport function computeMessageTokens(msg: Message): number {\n if (typeof msg.content === 'string') return estimateTextTokens(msg.content);\n let total = 0;\n for (const b of msg.content) {\n if (b.type === 'text') total += estimateTextTokens(b.text);\n else if (b.type === 'tool_use') total += estimateToolInputTokens(b.input);\n else if (b.type === 'tool_result') total += estimateToolResultTokens(b.content);\n else total += RoughTokenEstimate(JSON.stringify(b));\n }\n return total;\n}\n\n/**\n * Estimate tokens for an array of messages (text + tool I/O), using the shared\n * 3.5 chars/token basis. This is the single canonical message-array estimator \u2014\n * compactors, the context_manager tool, and the `/context` display all route\n * through it so the number a user sees matches the number compaction decides on.\n *\n * When a message carries a pre-computed `_estTokens` field (set by\n * ConversationState on append/replace), it is used directly instead of\n * re-walking the content blocks \u2014 turning the O(n\u00B7m) scan into an O(n)\n * sum for fully-cached arrays.\n */\nexport function estimateMessageTokens(messages: readonly Message[]): number {\n let total = 0;\n for (const m of messages) {\n if (typeof m._estTokens === 'number' && m._estTokens > 0) {\n total += m._estTokens;\n continue;\n }\n total += computeMessageTokens(m);\n }\n return total;\n}\n\n/**\n * Real-usage-anchored input-token count. Given the provider's authoritative\n * prompt-token count from the last response (`anchorTokens`, a REAL number) and\n * the `messages.length` of the request that produced it (`anchorMsgCount`),\n * returns `anchorTokens + estimate(messages appended since)` \u2014 so everything up\n * to the last turn is exact and only the newest, not-yet-sent messages are\n * estimated. This is deliberately NOT calibrated: the base is already real, and\n * on the next response the whole thing re-anchors to the new real count.\n *\n * Returns `null` when there is no usable anchor (no response yet, or the\n * message array shrank below the anchor \u2014 e.g. after compaction \u2014 in which case\n * the caller falls back to a full estimate until the next response re-anchors).\n */\nexport function realAnchoredInputTokens(\n messages: readonly Message[],\n anchorTokens: number | undefined,\n anchorMsgCount: number | undefined,\n): number | null {\n if (typeof anchorTokens !== 'number' || anchorTokens <= 0) return null;\n if (typeof anchorMsgCount !== 'number' || anchorMsgCount < 0) return null;\n if (messages.length < anchorMsgCount) return null;\n const delta = anchorMsgCount === messages.length ? 0 : estimateMessageTokens(messages.slice(anchorMsgCount));\n return anchorTokens + delta;\n}\n\n/**\n * Rough estimate of tokens in a tool definition (name + description + schema).\n * Accounts for the JSON-serialized inputSchema which is sent to the API\n * but NOT included in roughEstimate(content).\n */\nexport function estimateToolDefTokens(tool: {\n name: string;\n description?: string | undefined;\n inputSchema: unknown;\n}): number {\n // Fast path: pre-computed by ToolRegistry at registration time.\n const cached = (tool as { _estDefTokens?: number | undefined })._estDefTokens;\n if (typeof cached === 'number' && cached > 0) return cached;\n\n const compact = compactToolDefinitionForWire(tool);\n return (\n RoughTokenEstimate(tool.name) +\n RoughTokenEstimate(compact.description) +\n RoughTokenEstimate(JSON.stringify(compact.inputSchema))\n );\n}\n\n/**\n * Estimate the total API request token count: system prompt + tool definitions\n * + conversation messages. Use this for context-window bar calculations\n * instead of roughEstimate (which only counts messages).\n *\n * The overhead ratio (overhead / messages) varies by conversation length:\n * - Short conversations (< 10 messages): ~30-50% overhead (large system+tools)\n * - Medium (10-50 messages): ~15-30%\n * - Long (> 50 messages): ~5-15%\n *\n * Returns { messages, systemPrompt, tools, total } for debugging display.\n */\nexport interface RequestTokenBreakdown {\n messages: number;\n systemPrompt: number;\n tools: number;\n total: number;\n}\n\nexport function estimateRequestTokens(\n messages: unknown,\n systemPrompt: unknown,\n tools: { name: string; description?: string | undefined; inputSchema: unknown }[],\n calibrationKey: string = CALIBRATION_GLOBAL_KEY,\n): RequestTokenBreakdown {\n // Messages: apply the same logic as roughEstimate\n let messagesTokens = 0;\n if (typeof messages === 'string') {\n messagesTokens = RoughTokenEstimate(messages);\n } else if (Array.isArray(messages)) {\n for (const m of messages) {\n if (typeof m === 'object' && m !== null && 'content' in m) {\n // Fast path: pre-computed per-message token estimate (set by\n // ConversationState on append/replace). Skips the O(m) content-block\n // walk entirely for cached messages.\n const cached = (m as { _estTokens?: number | undefined })._estTokens;\n if (typeof cached === 'number' && cached > 0) {\n messagesTokens += cached;\n continue;\n }\n const content = (m as { content: unknown }).content;\n if (typeof content === 'string') {\n messagesTokens += RoughTokenEstimate(content);\n } else if (Array.isArray(content)) {\n for (const b of content) {\n if (typeof b === 'object' && b !== null) {\n if ((b as { type?: string | undefined }).type === 'text') {\n messagesTokens += RoughTokenEstimate((b as { text: string }).text);\n } else {\n messagesTokens += RoughTokenEstimate(JSON.stringify(b));\n }\n }\n }\n }\n }\n }\n }\n\n // System prompt\n let systemTokens = 0;\n if (typeof systemPrompt === 'string') {\n systemTokens = RoughTokenEstimate(systemPrompt);\n } else if (Array.isArray(systemPrompt)) {\n for (const b of systemPrompt) {\n if (\n typeof b === 'object' &&\n b !== null &&\n (b as { type?: string | undefined }).type === 'text'\n ) {\n systemTokens += RoughTokenEstimate((b as { text: string }).text);\n }\n }\n }\n\n // Tool definitions\n let toolsTokens = 0;\n for (const t of tools) {\n toolsTokens += estimateToolDefTokens(t);\n }\n\n const total = messagesTokens + systemTokens + toolsTokens;\n\n // Record the raw estimate for calibration: the next recordActualUsage()\n // call will pair this against the actual API usage so the rolling ratio\n // stays in sync with the real chars/token ratio of the content.\n calState(calibrationKey).prevEst = total;\n\n return {\n messages: messagesTokens,\n systemPrompt: systemTokens,\n tools: toolsTokens,\n total,\n };\n}\n\n/**\n * Record the actual API input token count after a provider call so\n * `estimateRequestTokensCalibrated` can self-correct on subsequent calls.\n *\n * Prefer passing `estimatedInputTokens` explicitly (the calibrated pre-flight\n * estimate from the middleware) \u2014 this avoids race conditions when other code\n * also calls `estimateRequestTokens` between the pre-flight and this call\n * (e.g. audit logging in agent.ts).\n *\n * When `estimatedInputTokens` is omitted, falls back to the keyed bucket's\n * `prevEst` for backward compatibility with callers that don't have the\n * pre-flight value. `calibrationKey` selects the per-(provider,model) bucket\n * (defaults to the shared global bucket).\n */\nexport function recordActualUsage(\n actualInputTokens: number,\n estimatedInputTokens?: number,\n calibrationKey: string = CALIBRATION_GLOBAL_KEY,\n): void {\n if (actualInputTokens <= 0) return;\n const cal = calState(calibrationKey);\n const est = estimatedInputTokens ?? cal.prevEst;\n if (est <= 0) return;\n\n const sampleRatio = actualInputTokens / est;\n if (cal.count === 0) {\n cal.ratio = sampleRatio;\n } else {\n // EWM: new = \u03B1 * sample + (1-\u03B1) * old \u2192 \u03B1=0.3 = fast initial converge\n cal.ratio = CAL_ALPHA * sampleRatio + (1 - CAL_ALPHA) * cal.ratio;\n }\n // Sanity bound: keep the rolling ratio within [0.5, 1.5] so a sequence\n // of bad samples can't blow up the calibration for everyone.\n cal.ratio = Math.min(1.5, Math.max(0.5, cal.ratio));\n cal.count++;\n}\n\n/**\n * Returns the current calibration state for a bucket. Exposed for debugging\n * and tests \u2014 not needed by normal callers.\n */\nexport function getCalibrationState(calibrationKey: string = CALIBRATION_GLOBAL_KEY): {\n ratio: number;\n count: number;\n calibrated: boolean;\n} {\n const cal = calState(calibrationKey);\n return {\n ratio: cal.ratio,\n count: cal.count,\n calibrated: cal.count >= MIN_SAMPLES_FOR_CALIBRATION,\n };\n}\n\n/**\n * Like `estimateRequestTokens` but applies the rolling calibration factor\n * so context pressure readings converge on reality within a few iterations.\n *\n * Before any `recordActualUsage` samples are collected, returns the same\n * result as `estimateRequestTokens` (ratio = 1.0, no distortion).\n * After `MIN_SAMPLES_FOR_CALIBRATION` samples, applies the calibrated\n * multiplier capped to the range [0.5, 1.5] as a sanity bound.\n */\nexport function estimateRequestTokensCalibrated(\n messages: unknown,\n systemPrompt: unknown,\n tools: { name: string; description?: string | undefined; inputSchema: unknown }[],\n calibrationKey: string = CALIBRATION_GLOBAL_KEY,\n): RequestTokenBreakdown {\n const result = estimateRequestTokens(messages, systemPrompt, tools, calibrationKey);\n const cal = calState(calibrationKey);\n\n if (cal.count >= MIN_SAMPLES_FOR_CALIBRATION) {\n const safeRatio = Math.min(1.5, Math.max(0.5, cal.ratio));\n return {\n messages: Math.round(result.messages * safeRatio),\n systemPrompt: Math.round(result.systemPrompt * safeRatio),\n tools: Math.round(result.tools * safeRatio),\n total: Math.round(result.total * safeRatio),\n };\n }\n\n // No calibration samples yet \u2014 fall back to model-family ratio if available,\n // otherwise use the uncalibrated estimate (ratio = 1.0).\n const fallbackRatio = getModelFamilyRatio(calibrationKey);\n if (fallbackRatio !== null) {\n return {\n messages: Math.round(result.messages * fallbackRatio),\n systemPrompt: Math.round(result.systemPrompt * fallbackRatio),\n tools: Math.round(result.tools * fallbackRatio),\n total: Math.round(result.total * fallbackRatio),\n };\n }\n\n return result;\n}\n\n/** Per-block sample cap for the density scan \u2014 bounds work on giant blocks. */\nconst DENSITY_SAMPLE_PER_BLOCK = 4_096;\n/** Hard cap on total sampled chars so the density scan stays cheap. */\nconst DENSITY_SAMPLE_TOTAL_CAP = 2_000_000;\n\n/**\n * Estimate a **token-density multiplier** for content that the flat 3.5\n * chars/token basis under-counts. The basis is tuned for ASCII English\n * (~4 chars/token); CJK, and other high-codepoint scripts tokenize at ~1.5-2\n * chars/token, so a message that is mostly CJK carries up to ~2.3\u00D7 the tokens\n * the flat basis predicts. Long unbroken ASCII runs (base64, minified blobs)\n * pack slightly denser too. This scans a bounded sample and returns a\n * multiplier in [1, 2.5] \u2014 always \u2265 1, so it can only push the estimate UP,\n * never down. Used only by the send-time overflow guard, never for display.\n */\nfunction textDensityMultiplier(messages: readonly Message[]): number {\n let sampled = 0;\n let nonAscii = 0;\n let maxRun = 0;\n const consider = (s: string): void => {\n const n = Math.min(s.length, DENSITY_SAMPLE_PER_BLOCK);\n let run = 0;\n for (let i = 0; i < n; i++) {\n const c = s.charCodeAt(i);\n if (c > 127) nonAscii++;\n if (c === 32 || c === 9 || c === 10 || c === 13) {\n if (run > maxRun) maxRun = run;\n run = 0;\n } else {\n run++;\n }\n }\n if (run > maxRun) maxRun = run;\n sampled += n;\n };\n\n for (const m of messages) {\n if (typeof m.content === 'string') {\n consider(m.content);\n } else if (Array.isArray(m.content)) {\n for (const b of m.content) {\n if (b.type === 'text') consider(b.text);\n else if (b.type === 'tool_result' && typeof b.content === 'string') consider(b.content);\n else if (b.type === 'thinking') consider(b.thinking);\n }\n }\n if (sampled >= DENSITY_SAMPLE_TOTAL_CAP) break;\n }\n\n if (sampled === 0) return 1;\n const nonAsciiRatio = nonAscii / sampled;\n // 3.5 chars/token at 0% non-ASCII \u2192 1.5 at 100% (heavy CJK).\n let charsPerToken = 3.5 - 2.0 * nonAsciiRatio;\n // A very long unbroken ASCII run (base64/minified) packs a little denser.\n if (maxRun > 2_000 && nonAsciiRatio < 0.1) charsPerToken = Math.min(charsPerToken, 3.0);\n const multiplier = 3.5 / Math.max(1.4, charsPerToken);\n return Math.min(2.5, Math.max(1, multiplier));\n}\n\n/**\n * Never-undercount upper bound for the request token total, for the **send\n * guard** only. Takes the flat estimate and scales it up by the greater of the\n * content-density multiplier and the calibration ceiling, so the guarded value\n * satisfies `real \u2264 upperBound`. The context bar and `/context` keep using the\n * calibrated estimate \u2014 this deliberately over-counts, which is only ever safe\n * for the \"must this be trimmed before sending?\" decision.\n */\nexport function estimateRequestTokensUpperBound(\n messages: unknown,\n systemPrompt: unknown,\n tools: { name: string; description?: string | undefined; inputSchema: unknown }[],\n calibrationKey: string = CALIBRATION_GLOBAL_KEY,\n): RequestTokenBreakdown {\n const base = estimateRequestTokens(messages, systemPrompt, tools, calibrationKey);\n const density = Array.isArray(messages)\n ? textDensityMultiplier(messages as readonly Message[])\n : 1;\n const cal = calState(calibrationKey);\n const calCeiling =\n cal.count >= MIN_SAMPLES_FOR_CALIBRATION ? Math.min(1.5, Math.max(1, cal.ratio)) : 1;\n const mult = Math.max(density, calCeiling);\n if (mult <= 1) return base;\n return {\n messages: Math.ceil(base.messages * mult),\n systemPrompt: Math.ceil(base.systemPrompt * mult),\n tools: Math.ceil(base.tools * mult),\n total: Math.ceil(base.total * mult),\n };\n}\n\n/** Look up the fallback chars/token ratio for a calibration key (e.g. \"provider/model\"). */\nfunction getModelFamilyRatio(calibrationKey: string): number | null {\n const lower = calibrationKey.toLowerCase();\n for (const [family, ratio] of Object.entries(MODEL_FAMILY_RATIO)) {\n if (lower.includes(family)) return ratio / 3.5; // MODEL_FAMILY_RATIO is chars/token, we need multiplier\n }\n return null;\n}\n\n/**\n * Resets calibration state. Primarily for tests that run in the same\n * process and need a clean slate between suites. With no argument it clears\n * every bucket (including the global one); pass a key to reset just that bucket.\n */\nexport function resetCalibration(calibrationKey?: string): void {\n if (calibrationKey === undefined) {\n _cals.clear();\n return;\n }\n _cals.delete(calibrationKey);\n}\n", "import * as path from 'node:path';\nimport type { TextBlock } from '../types/blocks.js';\nimport type { ContextEvidenceState } from '../types/context-evidence.js';\nimport type { FileEventRecord } from '../types/file-event-record.js';\nimport type { Message } from '../types/messages.js';\nimport type { Provider, Usage } from '../types/provider.js';\nimport type { SessionEvent, SessionWriter } from '../types/session.js';\nimport type { TokenCounter } from '../types/token-counter.js';\nimport type { Tool } from '../types/tool.js';\nimport { createContextEvidenceState } from '../utils/context-evidence.js';\nimport { ConversationState } from './conversation-state.js';\nimport type { RunEnv } from './run-env.js';\n\nexport interface TodoItem {\n id: string;\n content: string;\n status: 'pending' | 'in_progress' | 'completed';\n activeForm?: string | undefined;\n /** When promoted from a plan item, stores the plan item's id. */\n promotedFromPlan?: string | undefined;\n /** When promoted from a task, stores the task's id. */\n promotedFromTask?: string | undefined;\n}\n\nexport interface RunOptions {\n signal?: AbortSignal | undefined;\n model?: string | undefined;\n executionStrategy?: 'parallel' | 'sequential' | 'smart' | undefined;\n maxIterations?: number | undefined;\n /**\n * Enable autonomous continue for this specific run. When true, the agent\n * loop re-runs on `[continue]`/`[next step]`/`[proceed]` markers or\n * `continue_to_next_iteration()` tool calls instead of returning.\n * Overrides `AgentInit.autonomousContinue` for this call only.\n */\n autonomousContinue?: boolean | undefined;\n}\n\nexport interface ContextInit {\n systemPrompt: TextBlock[];\n provider: Provider;\n session: SessionWriter;\n signal: AbortSignal;\n tokenCounter: TokenCounter;\n cwd: string;\n projectRoot: string;\n /** Mutable working directory. Defaults to `cwd`. Must stay within `projectRoot`. */\n workingDir?: string | undefined;\n /**\n * When false, file tools and `setWorkingDir()` are confined to `projectRoot`.\n * Defaults to `false` (restrictive) when omitted so directly-constructed\n * contexts (tests, embedded callers) keep the safe behavior; the runtime\n * passes the config-derived value (default `true` \u2014 permissive) explicitly.\n */\n allowOutsideProjectRoot?: boolean | undefined;\n model: string;\n tools?: Tool[] | undefined;\n /** Agent id performing this run (e.g. 'leader', 'executor', 'tech-stack'). */\n agentId?: string | undefined;\n /** Human-readable agent name. */\n agentName?: string | undefined;\n /**\n * Session-level trace ID for correlating storage events with agent\n * iterations in observability pipelines. Stored on the SessionWriter\n * so that storage operations can emit it in `storage.*` events.\n * When set, the Context constructor propagates it to\n * `session.traceId` automatically.\n */\n traceId?: string | undefined;\n}\n\n/**\n * L1-A: `Context` is the live agent-run object. Its read-only environment\n * shape is exposed by the `RunEnv` interface (every field below the\n * conversation state) and its mutable shape by `ConversationState` (the\n * `state` accessor). New code should declare the narrower type at its\n * parameter \u2014 pass `ctx` for it. Existing tools that accept `Context`\n * still work because `Context` structurally satisfies both.\n *\n * The single source of truth for the project directory is `projectRoot`.\n * All tools (read/write/bash/exec) resolve paths relative to this.\n * Sessions, config, memory, and logs are also stored under this root.\n *\n * There IS a mutable `workingDir` (separate from `projectRoot`) that can be\n * changed at runtime via `setWorkingDir()`. It starts as `cwd` and allows\n * the agent and user to navigate within the project without spawning a new\n * process. All changes must stay inside `projectRoot`.\n */\nexport class Context implements RunEnv {\n messages: Message[] = [];\n /**\n * Maximum number of messages retained in the conversation history.\n * Past this limit, the oldest messages are dropped. Compaction passes\n * should reduce messages below this threshold \u2014 this cap is a safety\n * net to prevent unbounded growth when compaction is not running\n * (e.g., during a /rewind, provider error storm, or custom embedder).\n * Set to 0 for unlimited (legacy/test behaviour).\n */\n static readonly MAX_MESSAGES = 1_000;\n /**\n * Companion size cap on the same history, in estimated tokens.\n *\n * `MAX_MESSAGES` bounds the message *count*, which does not bound memory:\n * message size spans four orders of magnitude, and a tool result may be up\n * to `exec`'s 200 KB output cap. 2,000 of those is ~400 MB of live\n * conversation, reached without ever tripping the count cap. Both caps guard\n * the same failure \u2014 compaction not running \u2014 so both belong here.\n *\n * 1M tokens is roughly 4M characters, i.e. ~8 MB of UTF-16 text before JS\n * object overhead. That is still 5x a full 200k-token context window, so normal\n * compaction runs first; a broken compactor cannot retain tens of millions of characters.\n * Set to 0 for unlimited (legacy/test behaviour).\n */\n static readonly MAX_MESSAGE_TOKENS = 1_000_000;\n /**\n * Hard cap on distinct tracked-file paths retained in memory per session.\n * Past this limit the oldest (least-recently-entered) path is dropped.\n * Prevents unbounded growth on very large repos in long sessions.\n * Affects readFiles, writtenFiles, fileMtimes, and fileHashes.\n */\n static readonly MAX_TRACKED_FILES = 5_000;\n todos: TodoItem[] = [];\n /**\n * Files whose content the **user / model has explicitly seen** via the\n * `read` tool (or an edit's auto-read, which surfaces the content to the\n * model). This is the set the permission policy's write-smart-bypass\n * (step 7) checks \u2014 writing a file the model has already read is treated\n * as \"no new content to approve\". It must NEVER contain files only touched\n * by `edit`/`write`, otherwise the model could repeatedly overwrite a file\n * whose content the user never saw (P1 #1, before-release.md).\n *\n * Tool-driven mutations record via `writtenFiles` + `recordRead(..., 'write')`\n * so mtime tracking still works without widening the bypass.\n *\n * Bounded at MAX_TRACKED_FILES with oldest-first eviction to prevent\n * unbounded growth in long-running sessions over large codebases.\n */\n readFiles = new Set<string>();\n /**\n * Files written by `edit`/`write` in this session. Tracked for observability\n * and to keep `readFiles` (the permission-bypass source of truth) clean.\n * `recordRead(path, mtime, 'write')` adds here instead of `readFiles`.\n *\n * Bounded at MAX_TRACKED_FILES with oldest-first eviction.\n */\n writtenFiles = new Set<string>();\n /**\n * Last-known mtime for each tracked file path. Used by the permission\n * policy and edit-staleness checks.\n *\n * Bounded at MAX_TRACKED_FILES with oldest-first eviction to prevent\n * unbounded growth in long-running sessions.\n */\n fileMtimes = new Map<string, number>();\n /**\n * sha-256 (hex) of file content at the last recorded read/write, when the\n * recording tool had the content in hand. Used by `edit` as the authoritative\n * staleness arbiter: mtime comparison has a 2 s tolerance window on Windows\n * (FAT/NTFS granularity) during which an external modification is invisible,\n * and conversely a bare `touch` bumps mtime without changing content. Hash\n * equality resolves both cases exactly. Entries are dropped whenever a\n * hash-less `recordRead` observes a *different* mtime (content may have\n * changed under us \u2014 fall back to the mtime heuristic rather than trust a\n * stale hash).\n *\n * Bounded at MAX_TRACKED_FILES with oldest-first eviction.\n */\n fileHashes = new Map<string, string>();\n /**\n * Structured side-effect records accumulated during the current run\n * (P2 #5). Populated by `recordSideEffect()` \u2014 read by /diag for an\n * in-memory audit trail without parsing the JSONL file. Cleared by\n * `clearFileTracking()` alongside read/written-file tracking.\n *\n * Bounded at MAX_SIDE_EFFECTS (500) with oldest-first splice.\n */\n sideEffects: import('../types/side-effect.js').SideEffect[] = [];\n /**\n * Tracked file events for the current session. Populated by\n * `recordFileEvent()` \u2014 used for in-memory audit and real-time\n * subscription (EventBus `file.event`). Also persisted to session\n * JSONL as `file_event` events for durable storage.\n *\n * Bounded at MAX_FILE_EVENTS (1000) with oldest-first slice.\n */\n fileEvents: FileEventRecord[] = [];\n contextEvidence: ContextEvidenceState = createContextEvidenceState();\n systemPrompt: TextBlock[];\n provider: Provider;\n session: SessionWriter;\n signal: AbortSignal;\n tokenCounter: TokenCounter;\n cwd: string;\n projectRoot: string;\n /** Mutable working directory \u2014 starts as `cwd`. Change via `setWorkingDir()`. */\n workingDir: string;\n /**\n * When true, file tools (via `_util.ts`) and `setWorkingDir()` reject paths\n * outside `projectRoot`. When false, those boundary checks are bypassed so\n * tools may reach paths outside the project (still gated by permission\n * tiers). Mutable so `/settings` can toggle it live on the running session.\n */\n allowOutsideProjectRoot: boolean;\n model: string;\n tools: Tool[] = [];\n meta: Record<string, unknown> = {};\n /** Agent id performing this run (e.g. 'leader', 'executor'). */\n agentId: string;\n /** Human-readable agent name. */\n agentName: string;\n /**\n * Current kanban task ID, set by the agent/coordinator when working\n * on a specific kanban task. Tools use this via `recordFileEvent()`\n * to associate file operations with the active task.\n */\n currentKanbanTaskId: string | undefined = undefined;\n /**\n * Current kanban board ID, paired with `currentKanbanTaskId`.\n */\n currentKanbanBoardId: string | undefined = undefined;\n /**\n * Session-level trace ID for correlating storage events with agent\n * iterations. Stored here and also propagated to `session.traceId`\n * so storage operations can include it in `storage.*` events.\n */\n traceId: string | undefined;\n\n /**\n * Session id pinned to the currently-executing run. Set by `Agent.run()`\n * at run start and cleared when the run ends. Event-emission sites must\n * prefer this over `session.id` (via {@link eventSessionId}) because the\n * WebUI can swap `ctx.session` (session.new / resume) while a slow\n * provider stream from the previous session is still in flight \u2014 a live\n * `session.id` read would stamp the old run's late events with the NEW\n * session id and leak them into the new session's chat.\n */\n activeRunSessionId: string | undefined = undefined;\n /**\n * Writer pinned alongside `activeRunSessionId`. Persistence sites that stamp\n * a run-pinned session id must append through this writer; otherwise a\n * host-side `ctx.session` swap can put an old-session event in the new\n * session's JSONL.\n */\n activeRunSessionWriter: SessionWriter | undefined = undefined;\n\n /**\n * Session id that events of the in-flight run must be stamped with: the\n * run-pinned id when a run is active, otherwise the live session id.\n */\n eventSessionId(): string {\n return resolveEventSessionId(this);\n }\n\n /** Callbacks fired when `setWorkingDir()` changes the working directory. */\n private _onWorkingDirChanged: Array<(newDir: string, oldDir: string) => void> = [];\n /**\n * Serializes externally requested provider/model changes. Request creation\n * waits on this barrier so an automatic continuation cannot capture the old\n * model while a user-triggered switch is still building its provider.\n */\n private _modelTransition: Promise<void> = Promise.resolve();\n\n runModelTransition<T>(transition: () => T | Promise<T>): Promise<T> {\n const result = this._modelTransition.then(transition, transition);\n this._modelTransition = result.then(\n () => undefined,\n () => undefined,\n );\n return result;\n }\n\n async waitForModelTransition(): Promise<void> {\n await this._modelTransition;\n }\n\n /**\n * Set to true when the conversation gains new tool_use or tool_result\n * blocks \u2014 the only time repairToolUseAdjacency() can find new issues.\n * buildAndRunRequestPipeline() checks this flag to skip an O(n) scan\n * on iterations where no tool content was added (pure text responses).\n */\n toolAdjacencyDirty = false;\n\n /**\n * Pending PostToolUse hook context text accumulated during tool execution\n * when `contextAs === 'separate'`. Instead of appending a standalone user\n * message (which would break tool-use/tool-result adjacency), the tool\n * executor stores the text here and agent-tools merges it as a leading\n * text block in the same user message that carries the tool_results.\n * Cleared after being consumed by agent-tools.\n */\n pendingPostToolContext: string | undefined = undefined;\n\n /**\n * H1: pre-computed total-request token estimate from the most recent\n * `estimateRequestTokens()` call in the agent loop's pre-flight step.\n * The middleware that decides when to compact, the `emitContextPct`\n * helper that drives the live context-fill bar, and the pre-flight\n * itself all need this number; previously each one walked the same\n * messages/system/tools arrays independently. Stashing it here lets\n * the three call sites share a single compute per iteration.\n *\n * The value is the **uncalibrated** total. Callers that want the\n * calibrated number apply the per-(provider,model) ratio themselves.\n */\n lastRequestTokens: number | undefined = undefined;\n\n /**\n * The provider's **authoritative** prompt-token count from the most recent\n * response \u2014 `effectiveInputTokens(usage)` = `input + cacheRead + cacheWrite`.\n * This is a REAL number, not an estimate. Paired with\n * `meta.realAnchorMsgCount` (the `messages.length` of the request that\n * produced it), it anchors the live context figure: the true count of\n * everything sent last turn, plus only an estimate of the messages appended\n * since. Undefined before the first response. See `realAnchoredInputTokens`.\n */\n lastRealInputTokens: number | undefined = undefined;\n\n constructor(init: ContextInit) {\n this.systemPrompt = init.systemPrompt;\n this.provider = init.provider;\n this.session = init.session;\n this.signal = init.signal;\n this.tokenCounter = init.tokenCounter;\n this.cwd = init.cwd;\n this.projectRoot = init.projectRoot;\n this.workingDir = init.workingDir ?? init.cwd;\n this.allowOutsideProjectRoot = init.allowOutsideProjectRoot ?? false;\n this.model = init.model;\n this.tools = init.tools ?? [];\n this.agentId = init.agentId ?? 'unknown';\n this.agentName = init.agentName ?? 'Unknown Agent';\n this.traceId = init.traceId;\n this.allowOutsideProjectRoot = init.allowOutsideProjectRoot ?? false;\n // Propagate traceId to the SessionWriter so storage operations\n // can read it without needing a direct handle on the Context.\n this.session.traceId = init.traceId;\n }\n\n /**\n * Observable wrapper over the mutable conversation state. Lazy so\n * subsystems that don't subscribe pay nothing. Mutations made directly\n * on `ctx.messages` / `ctx.todos` are still visible through this\n * wrapper's read API (it holds a reference, not a copy) but only\n * mutations that go through `state.appendMessage()` etc. fire\n * `onChange`. New code should prefer the wrapper API.\n */\n private _state: ConversationState | null = null;\n private readonly _conversationJournalQueue: Array<{\n event: SessionEvent;\n bytes: number;\n writer: SessionWriter;\n }> = [];\n private _conversationJournalBytes = 0;\n private _conversationJournalDrain: Promise<void> | null = null;\n private static readonly CONVERSATION_JOURNAL_MAX_EVENTS = 256;\n private static readonly CONVERSATION_JOURNAL_MAX_BYTES = 4 * 1024 * 1024;\n private static readonly MAX_FILE_EVENTS = 1000;\n private static readonly MAX_SIDE_EFFECTS = 500;\n\n /** Wait until every exact conversation-state event queued so far is in the writer buffer. */\n async flushConversationJournal(): Promise<void> {\n for (;;) {\n if (this._conversationJournalQueue.length > 0) this.startConversationJournalDrain();\n const drain = this._conversationJournalDrain;\n if (!drain) break;\n await drain;\n }\n // After the drain completes, forcefully clear the queue to release\n // references to the old session's SessionEvent objects. The drain\n // above processed every event, but the array slot references may\n // still be held by V8's internal representation. Explicit nulling\n // here makes the old objects unreachable immediately.\n this._conversationJournalQueue.length = 0;\n this._conversationJournalBytes = 0;\n }\n\n private conversationJournalBytes(event: SessionEvent): number {\n try {\n return Buffer.byteLength(JSON.stringify(event), 'utf8');\n } catch {\n return Context.CONVERSATION_JOURNAL_MAX_BYTES + 1;\n }\n }\n\n private enqueueConversationJournal(event: SessionEvent, writer: SessionWriter): void {\n const bytes = this.conversationJournalBytes(event);\n const shouldSnapshot =\n event.type === 'messages_replaced' ||\n this._conversationJournalQueue.length >= Context.CONVERSATION_JOURNAL_MAX_EVENTS ||\n this._conversationJournalBytes + bytes > Context.CONVERSATION_JOURNAL_MAX_BYTES;\n\n if (shouldSnapshot) {\n const snapshot: SessionEvent =\n event.type === 'messages_replaced'\n ? event\n : {\n type: 'messages_replaced',\n ts: new Date().toISOString(),\n version: 1,\n messages: [...this.messages],\n };\n const snapshotBytes = this.conversationJournalBytes(snapshot);\n for (let index = this._conversationJournalQueue.length - 1; index >= 0; index -= 1) {\n const queued = this._conversationJournalQueue[index];\n if (queued?.writer !== writer) continue;\n this._conversationJournalBytes = Math.max(0, this._conversationJournalBytes - queued.bytes);\n this._conversationJournalQueue.splice(index, 1);\n }\n if (snapshotBytes <= Context.CONVERSATION_JOURNAL_MAX_BYTES) {\n this._conversationJournalQueue.push({ event: snapshot, bytes: snapshotBytes, writer });\n this._conversationJournalBytes += snapshotBytes;\n }\n } else {\n this._conversationJournalQueue.push({ event, bytes, writer });\n this._conversationJournalBytes += bytes;\n }\n while (\n this._conversationJournalQueue.length > Context.CONVERSATION_JOURNAL_MAX_EVENTS ||\n this._conversationJournalBytes > Context.CONVERSATION_JOURNAL_MAX_BYTES\n ) {\n const dropped = this._conversationJournalQueue.shift();\n if (!dropped) break;\n this._conversationJournalBytes = Math.max(0, this._conversationJournalBytes - dropped.bytes);\n }\n this.startConversationJournalDrain();\n }\n\n private startConversationJournalDrain(): void {\n if (this._conversationJournalDrain) return;\n const drain = (async () => {\n while (this._conversationJournalQueue.length > 0) {\n const queued = this._conversationJournalQueue.shift();\n if (!queued) continue;\n this._conversationJournalBytes = Math.max(0, this._conversationJournalBytes - queued.bytes);\n await queued.writer.append(queued.event).catch(() => {\n // Session persistence is best-effort. FileSessionWriter separately\n // bounds and retries its durable buffer.\n });\n }\n })().finally(() => {\n if (this._conversationJournalDrain === drain) this._conversationJournalDrain = null;\n if (this._conversationJournalQueue.length > 0) this.startConversationJournalDrain();\n });\n this._conversationJournalDrain = drain;\n }\n\n get state(): ConversationState {\n if (!this._state) {\n this._state = new ConversationState(this);\n this._state.onChange((change) => {\n const ts = new Date().toISOString();\n const event: SessionEvent | null =\n change.kind === 'message_appended'\n ? {\n type: 'message_appended',\n ts,\n version: 1,\n message: change.message,\n }\n : change.kind === 'message_updated'\n ? {\n type: 'message_updated',\n ts,\n version: 1,\n index: change.index,\n message: change.message,\n }\n : change.kind === 'messages_replaced'\n ? {\n type: 'messages_replaced',\n ts,\n version: 1,\n messages: [...change.messages],\n }\n : null;\n if (!event) return;\n this.enqueueConversationJournal(event, this.session);\n });\n }\n return this._state;\n }\n\n /**\n * Register a teardown hook tied to the current run's abort signal.\n * Hooks registered before a run starts are stored and fired when the\n * next run ends; there is no immediate fire when no run is active.\n *\n * **Scope:** these hooks fire on the **whole agent run's** abort, not on\n * an individual tool call. For per-tool teardown of resources owned by\n * the tool author (child processes, handles), prefer `Tool.cleanup` \u2014\n * see its JSDoc for the full rule.\n *\n * For hooks that must survive across run boundaries (mailbox heartbeat,\n * awareness polling, HQ publisher), prefer `registerAgentHook` instead.\n */\n private abortHooks = new Set<() => void | Promise<void>>();\n registerAbortHook(fn: () => void | Promise<void>): () => void {\n this.abortHooks.add(fn);\n return () => this.abortHooks.delete(fn);\n }\n async drainAbortHooks(): Promise<void> {\n const snapshot = [...this.abortHooks].reverse();\n // Clear before running so new hooks registered during iteration\n // fire on the next abort cycle (not the current one \u2014 hook chains\n // are intentionally not supported).\n this.abortHooks.clear();\n for (const fn of snapshot) {\n try {\n await fn();\n } catch {\n // hooks must be best-effort; swallow so siblings still fire\n }\n }\n }\n\n /**\n * Register a teardown hook that persists across individual run boundaries.\n * These hooks are NOT drained by `drainAbortHooks()` (which fires on every\n * run end). They are only released by `drainAgentHooks()`, intended to be\n * called during Agent teardown / process shutdown.\n *\n * Used for long-lived resources such as the mailbox heartbeat timer,\n * awareness polling interval, HQ publisher connection, and auto-compaction\n * timer \u2014 resources that must survive from the first run to the last.\n */\n private agentHooks = new Set<() => void | Promise<void>>();\n registerAgentHook(fn: () => void | Promise<void>): () => void {\n this.agentHooks.add(fn);\n return () => this.agentHooks.delete(fn);\n }\n async drainAgentHooks(): Promise<void> {\n const snapshot = [...this.agentHooks].reverse();\n this.agentHooks.clear();\n for (const fn of snapshot) {\n try {\n await fn();\n } catch {\n // hooks must be best-effort; swallow so siblings still fire\n }\n }\n }\n\n /**\n * Record that a file's content was seen / mtime was observed.\n *\n * `source` controls which tracking set is populated \u2014 and therefore whether\n * the permission policy's write-smart-bypass (step 7) will auto-approve a\n * subsequent `write` to this path:\n *\n * - `'user'` (default): the model/user saw the content (via `read`, or an\n * edit's auto-read that surfaced it). Adds to `readFiles` \u2192 bypass applies.\n * - `'write'`: a tool wrote the file (`edit`/`write`) and is recording the\n * new mtime so subsequent edits detect external modification. Adds to\n * `writtenFiles` only \u2014 the bypass does NOT apply, because the user never\n * approved the new content (P1 #1, before-release.md).\n *\n * `fileMtimes` is updated in both cases so mtime-based staleness checks work.\n *\n * `contentHash` (sha-256 hex of the exact content seen) is optional so\n * existing callers keep working. When provided it is stored in `fileHashes`\n * and becomes the authoritative staleness arbiter for later edits. When\n * omitted, a previously stored hash survives only if the observed mtime is\n * unchanged \u2014 a different mtime with no fresh hash means the content may\n * have changed, so the stale hash is dropped and staleness checks fall back\n * to mtime comparison.\n */\n recordRead(\n absPath: string,\n mtimeMs: number,\n source: 'user' | 'write' = 'user',\n contentHash?: string,\n ): void {\n if (contentHash !== undefined) {\n this.fileHashes.set(absPath, contentHash);\n } else {\n const prevMtime = this.fileMtimes.get(absPath);\n if (prevMtime !== mtimeMs) this.fileHashes.delete(absPath);\n }\n this.fileMtimes.set(absPath, mtimeMs);\n if (contentHash !== undefined) {\n this.session.recordFileObservation?.({\n path: absPath,\n hash: contentHash,\n mtimeMs,\n source,\n });\n }\n if (source === 'write') {\n this.writtenFiles.add(absPath);\n } else {\n this.readFiles.add(absPath);\n }\n this.trimTrackedFiles();\n }\n\n /**\n * Enforce MAX_TRACKED_FILES cap on all four file-tracking structures.\n * Evicts the oldest entries (insertion order = oldest-first in Set/Map)\n * when the cap is exceeded. This prevents unbounded memory growth in\n * long-running sessions over very large codebases where the agent\n * touches thousands of distinct files.\n *\n * The order of eviction across structures is not synchronized (each\n * structure independently drops its oldest), so after trimming the\n * sets may reference paths whose mtime/hash have been evicted from the\n * maps, and vice-versa. This is safe: paths in a Set are just strings\n * (4-8 bytes per char in the heap), and a stale lookup in fileMtimes\n * returns undefined, which `read`/`edit` treat as \"first access\" \u2014\n * the tool will re-stat the file and re-populate the entry. The agent\n * never fails or misbehaves; it just pays one extra stat call.\n */\n private trimTrackedFiles(): void {\n Context.trimSet(this.readFiles, Context.MAX_TRACKED_FILES);\n Context.trimSet(this.writtenFiles, Context.MAX_TRACKED_FILES);\n Context.trimMap(this.fileMtimes, Context.MAX_TRACKED_FILES);\n Context.trimMap(this.fileHashes, Context.MAX_TRACKED_FILES);\n }\n\n private static trimSet(set: Set<string>, max: number): void {\n while (set.size > max) {\n const oldest = set.values().next().value;\n if (oldest === undefined) break;\n set.delete(oldest);\n }\n }\n\n private static trimMap(map: Map<string, unknown>, max: number): void {\n while (map.size > max) {\n const oldest = map.keys().next().value;\n if (oldest === undefined) break;\n map.delete(oldest);\n }\n }\n\n /** Clear accumulated file-read metadata after compaction or at boundaries\n * where stale read history could cause tools to skip legitimate re-reads.\n * The agent re-populates this naturally on the next file access. */\n clearFileTracking(): void {\n this.readFiles.clear();\n this.writtenFiles.clear();\n this.fileMtimes.clear();\n this.fileHashes.clear();\n this.sideEffects = [];\n this.fileEvents = [];\n }\n\n /**\n * Record a structured side effect for the audit trail (P2 #5).\n * Called by tools that perform non-filesystem mutations (bash, install,\n * fetch) so /diag and session replay can show what the agent did beyond\n * file edits.\n *\n * Unlike recordFileChange(), this does NOT support undo \u2014 it is purely\n * for observability and audit. The event is appended to the session\n * JSONL fire-and-forget; errors are swallowed so recording never blocks\n * tool execution.\n */\n recordSideEffect(sideEffect: import('../types/side-effect.js').SideEffect): void {\n this.sideEffects.push(sideEffect);\n if (this.sideEffects.length > Context.MAX_SIDE_EFFECTS) {\n this.sideEffects.splice(0, this.sideEffects.length - Context.MAX_SIDE_EFFECTS);\n }\n // Persist through the writer pinned to this run (if active) so a\n // host-side session swap cannot route side effects into the new\n // session's JSONL \u2014 same invariant as recordFileEvent.\n const sessionWriter = this.activeRunSessionWriter ?? this.session;\n sessionWriter\n .append({\n type: 'side_effect',\n ts: sideEffect.ts,\n toolUseId: sideEffect.toolUseId,\n toolName: sideEffect.toolName,\n input: sideEffect.input,\n outcome: sideEffect.outcome,\n risk: sideEffect.risk,\n })\n .catch(() => {\n /* best-effort \u2014 never block tool execution */\n });\n }\n\n /**\n * Set the current kanban task context for subsequent file operations.\n * Tools call this (or the agent loop sets it) so that `recordFileEvent()`\n * can associate operations with the active kanban task.\n *\n * Pass `undefined` for both to clear the task association.\n */\n setCurrentKanbanTask(taskId: string | undefined, boardId?: string | undefined): void {\n this.currentKanbanTaskId = taskId;\n this.currentKanbanBoardId = boardId;\n }\n\n /**\n * Record a comprehensive file event for the audit trail.\n * Persists the event as a `file_event` session JSONL event.\n * Consumers that need `file.event` EventBus events should subscribe\n * at the executor level (see `ToolExecutor`'s auto-emission).\n *\n * The `scope` field is auto-derived from `currentKanbanTaskId`:\n * - When a kanban task is set, scope = `'task'` and `taskId`/`boardId`\n * are populated from `currentKanbanTaskId`/`currentKanbanBoardId`.\n * - Otherwise scope = `'session'`.\n *\n * Fire-and-forget: errors are swallowed so recording never blocks\n * tool execution.\n */\n recordFileEvent(input: {\n operation: 'create' | 'read' | 'update' | 'delete' | 'rename';\n filePath: string;\n absPath: string;\n toolName: string;\n toolUseId: string;\n durationMs?: number | undefined;\n fileSize?: number | undefined;\n lines?: number | undefined;\n bytes?: number | undefined;\n }): void {\n const scope = this.currentKanbanTaskId ? 'task' : 'session';\n const ts = new Date().toISOString();\n const record: FileEventRecord = {\n operation: input.operation,\n filePath: input.filePath,\n absPath: input.absPath,\n sessionId: this.eventSessionId(),\n agentId: this.agentId,\n agentName: this.agentName,\n provider:\n typeof this.provider === 'object'\n ? (this.provider as { id: string }).id\n : String(this.provider),\n model: this.model,\n toolName: input.toolName,\n toolUseId: input.toolUseId,\n scope,\n taskId: this.currentKanbanTaskId,\n boardId: this.currentKanbanBoardId,\n timestamp: ts,\n durationMs: input.durationMs,\n fileSize: input.fileSize,\n lines: input.lines,\n bytes: input.bytes,\n };\n\n this.fileEvents.push(record);\n if (this.fileEvents.length > Context.MAX_FILE_EVENTS) {\n this.fileEvents.splice(0, this.fileEvents.length - Context.MAX_FILE_EVENTS);\n }\n\n // Persist through the writer pinned to this run. The WebUI may replace\n // `this.session` while a late tool operation is completing; pairing the\n // writer with the already-pinned id keeps both JSONL routing and metadata\n // on the session that started the run.\n const sessionWriter = this.activeRunSessionWriter ?? this.session;\n sessionWriter\n .append({\n type: 'file_event',\n ts,\n operation: input.operation,\n filePath: input.filePath,\n absPath: input.absPath,\n sessionId: record.sessionId,\n agentId: this.agentId,\n agentName: this.agentName,\n provider: record.provider,\n model: record.model,\n toolName: input.toolName,\n toolUseId: input.toolUseId,\n scope,\n taskId: this.currentKanbanTaskId,\n boardId: this.currentKanbanBoardId,\n durationMs: input.durationMs,\n fileSize: input.fileSize,\n lines: input.lines,\n bytes: input.bytes,\n })\n .catch(() => {\n /* best-effort \u2014 never block tool execution */\n });\n }\n\n /**\n * True if the model/user has explicitly seen this file's content via `read`\n * (or an edit auto-read). Tool-only writes (`source: 'write'`) do NOT count\n * \u2014 this is the source of truth for the permission policy's write bypass.\n */\n hasRead(absPath: string): boolean {\n return this.readFiles.has(absPath);\n }\n\n /** True if `edit`/`write` wrote this file in the current session. */\n hasWritten(absPath: string): boolean {\n return this.writtenFiles.has(absPath);\n }\n\n lastReadMtime(absPath: string): number | undefined {\n return this.fileMtimes.get(absPath);\n }\n\n /** sha-256 (hex) of the content at the last recorded read/write, if the\n * recording tool supplied one. See `fileHashes` for drop semantics. */\n lastReadHash(absPath: string): string | undefined {\n return this.fileHashes.get(absPath);\n }\n\n /**\n * Change the working directory for path resolution. Resolves relative paths\n * against `projectRoot` and validates the result is within the project root.\n * Fires all registered `onWorkingDirChanged` callbacks.\n * Returns the resolved absolute path.\n */\n setWorkingDir(dir: string): string {\n const resolved = path.isAbsolute(dir) ? path.resolve(dir) : path.resolve(this.projectRoot, dir);\n\n // Validate containment within projectRoot \u2014 unless filesystem access is\n // unrestricted, in which case the working dir may leave the project root.\n if (!this.allowOutsideProjectRoot) {\n const root = path.resolve(this.projectRoot);\n const rel = path.relative(root, resolved);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw new Error(`Working directory \"${resolved}\" is outside project root \"${root}\"`);\n }\n }\n\n const old = this.workingDir;\n this.workingDir = resolved;\n // Fire callbacks (catch errors so one bad listener doesn't break others)\n for (const cb of this._onWorkingDirChanged) {\n try {\n cb(resolved, old);\n } catch {\n /* best-effort */\n }\n }\n return resolved;\n }\n\n /**\n * Register a callback that fires when the working directory changes.\n * Returns an unsubscribe function. Callbacks are fired synchronously\n * inside `setWorkingDir()` \u2014 errors in callbacks are swallowed so one\n * bad listener doesn't prevent others from executing.\n */\n onWorkingDirChanged(cb: (newDir: string, oldDir: string) => void): () => void {\n this._onWorkingDirChanged.push(cb);\n return () => {\n const idx = this._onWorkingDirChanged.indexOf(cb);\n if (idx >= 0) this._onWorkingDirChanged.splice(idx, 1);\n };\n }\n\n usage(): Usage {\n return this.tokenCounter.total();\n }\n}\n\n/**\n * Session id that events of the in-flight run must be stamped with: the\n * run-pinned id (`Context.activeRunSessionId`) when a run is active,\n * otherwise the live session id. Reads properties defensively because\n * tests and lightweight embedders stub Context with partial objects whose\n * `session` may be missing despite the non-optional type.\n */\nexport function resolveEventSessionId(ctx: Context): string {\n if (ctx.activeRunSessionId) return ctx.activeRunSessionId;\n const session: SessionWriter | undefined = ctx.session;\n return session?.id ?? '';\n}\n", "import type { ContentBlock } from '../types/blocks.js';\nimport type { Message } from '../types/messages.js';\nimport { computeMessageTokens } from '../utils/token-estimate.js';\nimport type { TodoItem } from './context.js';\nimport { Context } from './context.js';\n\n/**\n * Observable wrapper for mutable conversation state. Production code should\n * mutate messages, todos, and meta through this API so subscribers see a\n * deterministic change stream. The underlying Context arrays are still\n * exposed for read compatibility and legacy tests.\n *\n * L1-A invariant: direct mutations of `ctx.messages` / `ctx.todos` bypass\n * the observer layer. Prefer `ctx.state.appendMessage()` etc. to keep\n * subscribers in sync. The compatibility arrays exist so existing code\n * that reads `ctx.messages` directly still works \u2014 they are NOT safe for\n * external writes.\n */\nexport type StateChange =\n | { kind: 'message_appended'; message: Message }\n | { kind: 'messages_replaced'; messages: readonly Message[] }\n | { kind: 'message_updated'; index: number; message: Message }\n | {\n kind: 'todos_replaced';\n todos: readonly TodoItem[];\n /**\n * Final all-completed snapshot when the tactical list auto-clears.\n * Observational mirrors use this to move cards to Done instead of\n * interpreting the empty active list as \"the work vanished\".\n */\n completedSnapshot?: readonly TodoItem[] | undefined;\n }\n | { kind: 'meta_set'; key: string; value: unknown }\n | { kind: 'meta_deleted'; key: string }\n | { kind: 'meta_cleared' };\n\nexport type StateChangeHandler = (change: StateChange, state: ConversationState) => void;\n\nexport interface ReadonlyConversationState {\n readonly messages: readonly Message[];\n readonly todos: readonly TodoItem[];\n readonly meta: Readonly<Record<string, unknown>>;\n}\n\nexport class ConversationState {\n private readonly ctx: Context;\n private readonly listeners = new Set<StateChangeHandler>();\n private _revision = 0;\n\n constructor(ctx: Context) {\n this.ctx = ctx;\n }\n\n get messages(): readonly Message[] {\n return this.ctx.messages;\n }\n\n get todos(): readonly TodoItem[] {\n return this.ctx.todos;\n }\n\n get meta(): Readonly<Record<string, unknown>> {\n return this.ctx.meta;\n }\n\n /** Monotonic mutation counter for consumers that need to detect rewrites. */\n get revision(): number {\n return this._revision;\n }\n\n /**\n * Cheap immutable snapshot. Useful for tests and for compaction passes\n * that need a stable view across an async boundary.\n *\n * Uses shallow-freeze instead of deep-freeze: only the wrapper object\n * and the three content arrays are frozen. Individual message/todo\n * objects are NOT recursively frozen \u2014 they are reconstructed via\n * spread copies and are immutable by convention. This cuts the freeze\n * count from O(n\u00B7m\u00B7d) (n=messages, m=content blocks, d=depth) to O(1).\n */\n snapshot(): ReadonlyConversationState {\n const snap = {\n messages: [...this.ctx.messages],\n todos: [...this.ctx.todos],\n meta: { ...this.ctx.meta },\n };\n Object.freeze(snap.messages);\n Object.freeze(snap.todos);\n Object.freeze(snap.meta);\n return Object.freeze(snap) as ReadonlyConversationState;\n }\n\n appendMessage(message: Message): void {\n // Pre-compute token estimate once at mutation time so every downstream\n // estimateMessageTokens / estimateRequestTokens call is an O(1) sum\n // instead of re-walking the content blocks on every invocation.\n if (message._estTokens === undefined) {\n message._estTokens = computeMessageTokens(message);\n }\n this.ctx.messages.splice(this.ctx.messages.length, 0, message);\n // Cap messages to prevent unbounded growth when compaction does not\n // run (provider error storms, rewinds, custom embedders). Oldest\n // messages are dropped first \u2014 the compaction digest lives at index 0\n // and is dropped with them.\n const overflow = this.overflowCount(this.ctx.messages);\n if (overflow > 0) {\n this.ctx.messages.splice(0, overflow);\n // Dropping messages may orphan a tool_use or tool_result, breaking\n // strict-provider adjacency rules. Force a repair scan on the next\n // request pipeline run.\n this.ctx.toolAdjacencyDirty = true;\n // Emit a full snapshot so journal replay does not reconstruct an\n // array larger than live state after truncation.\n this.emit({ kind: 'messages_replaced', messages: [...this.ctx.messages] });\n } else {\n this.emit({ kind: 'message_appended', message });\n }\n }\n\n /**\n * How many of the oldest messages must be dropped to satisfy both retention\n * caps \u2014 count ({@link Context.MAX_MESSAGES}) and size\n * ({@link Context.MAX_MESSAGE_TOKENS}). Returns 0 when the history already\n * fits, which is the overwhelmingly common case.\n *\n * The size pass reads the per-message `_estTokens` cache populated at\n * mutation time, so it is a sum over numbers rather than a re-walk of\n * content blocks. It runs whenever the token cap is enabled; the count\n * cap determines the starting index for the sum but does not gate it.\n */\n private overflowCount(arr: readonly Message[]): number {\n let drop = Context.MAX_MESSAGES > 0 ? Math.max(0, arr.length - Context.MAX_MESSAGES) : 0;\n if (Context.MAX_MESSAGE_TOKENS <= 0) return drop;\n\n let total = 0;\n for (let i = drop; i < arr.length; i++) total += arr[i]?._estTokens ?? 0;\n if (total <= Context.MAX_MESSAGE_TOKENS) return drop;\n // Walk forward dropping the oldest survivors until the remainder fits.\n // Always keep the newest message: dropping the one just appended would\n // silently discard the turn the caller is in the middle of.\n while (drop < arr.length - 1 && total > Context.MAX_MESSAGE_TOKENS) {\n total -= arr[drop]?._estTokens ?? 0;\n drop++;\n }\n return drop;\n }\n\n /**\n * Append a content block to the trailing user message's content array.\n * Mutates only that one message (a single indexed assignment) \u2014 avoids\n * the O(n) array copy + token-cache re-walk that `replaceMessages()`\n * would do for a single-message edit. Used by the agent loop to fold\n * btw-notes / queued-mailbox blocks into the conversation.\n *\n * The block is folded only into a *user* message (preserves\n * user/assistant alternation between tool batches). Returns false when\n * there is no trailing user message to fold into \u2014 callers should\n * `appendMessage({ role: 'user', content: [block] })` instead.\n */\n appendBlockToLastUserMessage(block: ContentBlock): boolean {\n const arr = this.ctx.messages;\n const last = arr[arr.length - 1];\n if (last?.role !== 'user') return false;\n const content: ContentBlock[] =\n typeof last.content === 'string'\n ? [{ type: 'text', text: last.content }, block]\n : [...last.content, block];\n // Replace only the trailing message object \u2014 O(1), no full-array copy.\n // Recompute the token estimate for the one changed message; everything\n // else in the array is untouched and its cache stays valid.\n const updated: Message = {\n ...last,\n content,\n _estTokens: computeMessageTokens({ ...last, content }),\n };\n arr[arr.length - 1] = updated;\n // Text/informational blocks never carry tool_use/tool_result, so\n // toolAdjacencyDirty is unaffected \u2014 no need to set it here.\n this.emit({ kind: 'message_updated', index: arr.length - 1, message: updated });\n return true;\n }\n\n replaceMessages(messages: Message[]): void {\n // M1 (combined with the existing _estTokens loop): single pass over the\n // replacement messages that handles per-message token estimation AND\n // tool-block detection for the adjacency-dirty flag. The previous\n // implementation did a separate `messages.some(m => m.content.some(...))`\n // walk \u2014 a second O(n\u00B7m) pass that the first loop can absorb with a\n // tiny amount of extra state. For 200 messages with a 5-block average\n // this halves the work done here.\n let hasToolBlock = false;\n for (const m of messages) {\n if (m._estTokens === undefined) {\n m._estTokens = computeMessageTokens(m);\n }\n // Cached messages still need the adjacency scan. Resume/rewind commonly\n // replaces state with messages carrying `_estTokens`; gating this scan\n // on cache misses silently skipped tool repair for exactly those paths.\n if (!hasToolBlock && Array.isArray(m.content)) {\n for (const b of m.content) {\n if (b.type === 'tool_use' || b.type === 'tool_result') {\n hasToolBlock = true;\n break;\n }\n }\n }\n }\n\n // `replaceMessages()` is used by resume, rewind, WebUI context editing and\n // compaction. It must enforce the same safety boundary as appendMessage;\n // otherwise a large journal/context replacement bypasses retention in one\n // call and remains live until the process exits.\n const overflow = this.overflowCount(messages);\n const retained = overflow > 0 ? messages.slice(overflow) : messages;\n if (overflow > 0) this.ctx.toolAdjacencyDirty = true;\n\n // In-place replacement without array spread to avoid a temporary\n // allocation of 200+ elements on large compaction rewrites.\n // When messages.length > arr.length, JavaScript auto-extends the array\n // on indexed assignment (arr[i] = val where i >= arr.length sets\n // arr.length = i + 1 per ECMAScript \u00A79.4.2.1).\n const arr = this.ctx.messages;\n if (retained.length < arr.length) {\n arr.length = retained.length;\n }\n for (let i = 0; i < retained.length; i++) {\n arr[i] = retained[i]!;\n }\n\n // Mark adjacency dirty when the replacement contains tool-use\n // blocks \u2014 the next request pipeline must re-check adjacency.\n // Without this, replaceMessages() can silently skip repair when\n // it introduces or modifies tool_use/tool_result pairs (e.g. test\n // setup, agent-loop content rewrite).\n if (hasToolBlock) {\n this.ctx.toolAdjacencyDirty = true;\n }\n\n this.emit({ kind: 'messages_replaced', messages: [...retained] });\n }\n\n replaceTodos(todos: TodoItem[]): void {\n // Auto-clear: when every item is completed and the list is non-empty,\n // the board has served its purpose. Treat it as a clear signal so the\n // user doesn't have to manually `/todos clear` after each task.\n const allDone = todos.length > 0 && todos.every((t) => t.status === 'completed');\n const effective = allDone ? [] : todos;\n\n this.ctx.todos.length = 0;\n this.ctx.todos.splice(0, 0, ...effective);\n this.emit({\n kind: 'todos_replaced',\n todos: [...effective],\n ...(allDone ? { completedSnapshot: [...todos] } : {}),\n });\n }\n\n setMeta(key: string, value: unknown): void {\n this.ctx.meta[key] = value;\n this.emit({ kind: 'meta_set', key, value });\n }\n\n deleteMeta(key: string): void {\n if (!(key in this.ctx.meta)) return;\n delete this.ctx.meta[key];\n this.emit({ kind: 'meta_deleted', key });\n }\n\n clearMeta(): void {\n const keys = Object.keys(this.ctx.meta);\n if (keys.length === 0) return;\n for (const key of keys) delete this.ctx.meta[key];\n this.emit({ kind: 'meta_cleared' });\n }\n\n /**\n * Subscribe to mutations that go through this wrapper. Direct mutations of\n * the compatibility arrays are intentionally not observed.\n */\n onChange(listener: StateChangeHandler): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n private emit(change: StateChange): void {\n this._revision++;\n for (const h of this.listeners) {\n try {\n h(change, this);\n } catch {\n // Listeners are observational only; one bad subscriber must not\n // prevent state mutation or block sibling listeners.\n }\n }\n }\n}\n\n/**\n * Convenience constructor. The wrapper holds a reference, not a copy.\n */\nexport function wrapAsState(ctx: Context): ConversationState {\n return new ConversationState(ctx);\n}\n", "/**\n * L1-E: Autonomous continue \u2014 model-driven self-iteration continuation.\n *\n * In autonomous mode the model can signal \"keep going without waiting for\n * user input\" by either:\n *\n * 1. **Tool call** \u2014 call `continue_to_next_iteration()` with no args.\n * The tool returns `{ continue: true }` and sets\n * `ctx.meta._autonomousContinue = true`. The agent loop detects this\n * flag and re-runs the iteration instead of returning.\n *\n * 2. **Text marker** \u2014 include one of the below markers on its own line\n * in the final text output (no tool call required):\n *\n * - `[continue]` \u2014 same as calling the tool; next iteration\n * - `[next step]` \u2014 synonym for `[continue]`\n * - `[proceed]` \u2014 synonym for `[continue]`\n * - `[done]` \u2014 stop iterating; return to caller\n *\n * The parser matches `^\\s*(?:\\[continue\\]|\\[next step\\]|\\[proceed\\]|\\[done\\])\\s*$`\n * so the marker must occupy its own line (possibly indented).\n *\n * Text markers are checked in `processResponse()` BEFORE the loop exit\n * condition, so the model can emit `[continue]` as part of its final text\n * block and the loop re-runs seamlessly.\n *\n * The `_autonomousContinue` flag lives in `ctx.meta` \u2014 it is cleared at\n * the start of each iteration so a stale flag from a prior run cannot\n * cause spurious continuation.\n *\n * @example\n * ```typescript\n * // Enable autonomous continuation on the Agent\n * const agent = new Agent({\n * // ... other options\n * autonomousContinue: true, // enable text-marker parsing\n * });\n *\n * // The model can now end a response with:\n * // [continue]\n * // and the agent will immediately start the next iteration without\n * // returning to the caller.\n * ```\n */\nimport type { Context } from './context.js';\nimport type { JSONSchema } from '../types/tool.js';\nimport type { Tool } from '../types/tool.js';\n\n/**\n * Directive emitted by the model to control the autonomous loop.\n *\n * `continue` \u2014 halt the current agent.run() and signal to the outer\n * runner (e.g. AutonomousRunner) that it should re-invoke\n * agent.run() immediately with a fresh continuation prompt.\n *\n * `stop` \u2014 halt and signal the outer runner to NOT continue.\n * The agent.run() returns `{ status: 'done' }` as normal.\n *\n * `none` \u2014 no directive present; outer runner uses its own\n * `doneCondition` to decide.\n */\nexport type ContinueDirective = 'continue' | 'stop' | 'none';\n\n/**\n * Parse a `ContinueDirective` from raw assistant text.\n *\n * Matches markers on their own line (with optional leading/trailing\n * whitespace). Case-insensitive. Returns `'none'` when no marker found.\n *\n * The marker must be on its own line to avoid false positives \u2014 e.g.\n * \"remember to use [continue] in your next email\" does NOT trigger it.\n */\nexport function parseContinueDirective(text: string): ContinueDirective {\n // Strict: marker must be the only significant content on its line.\n // This regex uses a look-ahead to ensure the line contains nothing\n // meaningful besides the marker itself.\n const LINE_MARKERS =\n /^\\s*\\[(continue|next step|proceed|done)\\]\\s*$/gim;\n\n // M3: in practice the directive lives at the very end of the response \u2014\n // models append `[continue]` or `[done]` as the last line. Scanning the\n // whole `text` string runs the regex's state machine across every char\n // even when no marker exists. For a 4 KB response the regex engine\n // walks ~4 KB of input. Restricting to the last ~2 KB cuts the scan\n // work by ~50% on typical long responses, with no functional change:\n // a marker anywhere in the last 2 KB will still be detected, and a\n // marker *before* that range is by definition not the directive\n // (the model is supposed to end its response with the marker).\n const tail =\n text.length <= DIRECTIVE_SCAN_WINDOW\n ? text\n : text.slice(text.length - DIRECTIVE_SCAN_WINDOW);\n\n let match: RegExpExecArray | null;\n let lastDirective: ContinueDirective = 'none';\n\n // biome-ignore lint/suspicious/noAssignInExpressions: while-loop condition requires assignment\n while ((match = LINE_MARKERS.exec(tail)) !== null) {\n const value = (match[1] ?? '').toLowerCase();\n if (value === 'continue' || value === 'next step' || value === 'proceed') {\n lastDirective = 'continue';\n } else if (value === 'done') {\n lastDirective = 'stop';\n }\n // Keep scanning \u2014 if multiple markers appear, rightmost wins\n // (e.g. model emits \"[continue]\\n[dONE]\" accidentally; stop takes priority)\n }\n\n return lastDirective;\n}\n\n/**\n * How many characters from the end of the response to scan for\n * `[continue]` / `[done]` markers. Models are trained to put the\n * directive on its own line at the very end, so a tail-restricted\n * scan misses nothing in practice.\n */\nconst DIRECTIVE_SCAN_WINDOW = 2_048;\n\n/** Meta key used to communicate the directive from tool \u2192 agent loop. */\nconst META_KEY = '_autonomousContinue';\n\n/**\n * Set the autonomous continue flag in the context.\n * Called by `makeContinueToNextIterationTool` when the model invokes it.\n */\nexport function setAutonomousContinue(ctx: Context): void {\n ctx.meta[META_KEY] = true;\n}\n\n/**\n * Clear the autonomous continue flag at the start of each iteration.\n * Called from `Agent.run()` before the loop body.\n */\nexport function clearAutonomousContinue(ctx: Context): void {\n delete ctx.meta[META_KEY];\n}\n\n/**\n * Read and clear the autonomous continue flag in one call.\n * Returns `true` if the flag was set; `false` otherwise.\n */\nexport function consumeAutonomousContinue(ctx: Context): boolean {\n const val = ctx.meta[META_KEY] === true;\n delete ctx.meta[META_KEY];\n return val;\n}\n\n/**\n * Built-in tool that lets the model explicitly request the next iteration.\n *\n * When called, the agent loop detects the flag and re-runs instead of\n * returning to the caller. This is the explicit counterpart to the\n * `[continue]` text marker.\n *\n * The tool has no side effects and returns `{ continue: true }`.\n */\nexport function makeContinueToNextIterationTool(): Tool {\n const inputSchema: JSONSchema = {\n type: 'object',\n properties: {},\n required: [],\n description:\n 'Signal that the agent should continue to the next iteration immediately, without waiting for user input. Use this when you have completed a step and want to proceed automatically to the next step in your plan.',\n };\n\n return {\n name: 'continue_to_next_iteration',\n description:\n 'Continue to the next iteration without returning to the user. Call this when you have finished a step and want to keep working autonomously.',\n permission: 'auto',\n mutating: false,\n inputSchema,\n async execute(_input: unknown, ctx: Context) {\n setAutonomousContinue(ctx);\n return { continue: true };\n },\n };\n}\n", "import type { EventBus } from '../kernel/events.js';\n\ninterface RequestLimitExtensionOptions {\n events: EventBus;\n sessionId?: string | undefined;\n currentIterations: number;\n currentLimit: number;\n /** When true (default), auto-grant 100 extra after giving listeners a tick to deny. */\n autoExtend: boolean;\n /** Timeout in ms before falling back to \"0 extra\" if no listener responds. */\n timeoutMs?: number | undefined;\n}\n\n/**\n * Emit `iteration.limit_reached` and wait for a listener to grant or\n * deny. Resolves with the number of extra iterations to grant (0 = stop).\n * When `autoExtend` is true the listener gets a `setImmediate` window to\n * react; otherwise the resolution stays open until the timer fires.\n *\n * Listener contract \u2014 **important for `autoExtend: true` callers**:\n *\n * - `grant(extra)` and `deny()` must be invoked **synchronously** from\n * the event listener (or earlier than the next `setImmediate` tick).\n * The auto-grant path resolves to 100 inside `setImmediate`, so any\n * async work between receiving the event and calling grant/deny will\n * lose the race and the auto-grant wins.\n *\n * - If you need to make an async decision (await a confirm dialog,\n * query a remote policy), pass `autoExtend: false`. The promise will\n * stay pending until the listener calls grant/deny or `timeoutMs`\n * fires (default 30s).\n *\n * - Multiple listeners are allowed but the first to call grant/deny\n * wins; subsequent calls are no-ops.\n */\nexport function requestLimitExtension(opts: RequestLimitExtensionOptions): Promise<number> {\n const { events, sessionId, currentIterations, currentLimit, autoExtend, timeoutMs = 30_000 } = opts;\n return new Promise((resolve) => {\n let resolved = false;\n // Shared flag so setImmediate knows when timer already resolved.\n const timerFired = () => {\n if (!resolved) {\n resolved = true;\n resolve(0);\n }\n };\n const timer = setTimeout(timerFired, timeoutMs);\n timer.unref(); // Don't keep event loop alive past timeout\n const deny = () => {\n if (!resolved) {\n resolved = true;\n clearTimeout(timer);\n resolve(0);\n }\n };\n const grant = (extra: number) => {\n if (!resolved) {\n resolved = true;\n clearTimeout(timer);\n resolve(Math.max(0, extra));\n }\n };\n events.emit('iteration.limit_reached', {\n sessionId,\n currentIterations,\n currentLimit,\n grant,\n deny,\n });\n if (autoExtend) {\n // Give listeners a tick to deny synchronously; otherwise auto-grant 100.\n setImmediate(() => {\n // Only act if timer hasn't already fired \u2014 prevents a wasted microtask\n // when the timeout resolved before this tick.\n if (!resolved) {\n resolved = true;\n clearTimeout(timer);\n resolve(100);\n }\n });\n }\n });\n}\n", "import { randomUUID } from 'node:crypto';\nimport type { EventBus } from '../kernel/events.js';\nimport type { Logger } from '../types/logger.js';\nimport type { ContentBlock, ThinkingBlock, ToolUseBlock } from '../types/blocks.js';\nimport type { Provider, Request, Response } from '../types/provider.js';\nimport { type Context, resolveEventSessionId } from './context.js';\nimport { completePartialObject } from '../utils/json-repair.js';\n\nconst STREAM_DRAIN_TIMEOUT_MS = 500;\n\ninterface ThinkingEntry {\n textBuf: string;\n signature?: string | undefined;\n providerMeta?: Record<string, unknown>;\n}\n\ninterface StreamingState {\n model: string;\n stopReason: Response['stopReason'];\n usage: Response['usage'];\n textBuffers: string[];\n currentTextIndex: number;\n tools: Map<\n string,\n {\n name: string;\n partial: string;\n input?: unknown | undefined;\n providerMeta?: Record<string, unknown>;\n }\n >;\n thinking: ThinkingEntry[];\n currentThinkingIndex: number;\n blockOrder: Array<\n { kind: 'text'; idx: number } | { kind: 'tool'; id: string } | { kind: 'thinking'; idx: number }\n >;\n}\n\nexport function buildResponse(state: StreamingState): Response {\n const content: ContentBlock[] = [];\n for (const b of state.blockOrder) {\n if (b.kind === 'text') {\n const txt = state.textBuffers[b.idx] ?? '';\n if (txt) content.push({ type: 'text', text: txt });\n } else if (b.kind === 'thinking') {\n const t = state.thinking[b.idx];\n // Skip blocks with no thinking text AND no signature \u2014 emitting an\n // empty {type:'thinking', thinking:''} block makes Anthropic 400\n // (\"content[].thinking.thinking: cannot be empty\").\n if (!t) continue;\n if (!t.textBuf && !t.signature) continue;\n const block: ThinkingBlock = { type: 'thinking', thinking: t.textBuf };\n if (t.signature) block.signature = t.signature;\n if (t.providerMeta && Object.keys(t.providerMeta).length > 0) {\n block.providerMeta = t.providerMeta;\n }\n content.push(block);\n } else {\n const tb = state.tools.get(b.id);\n if (tb) {\n const block: ToolUseBlock = {\n type: 'tool_use',\n id: b.id,\n name: tb.name,\n input: (tb.input as Record<string, unknown>) ?? {},\n };\n if (tb.providerMeta && Object.keys(tb.providerMeta).length > 0) {\n block.providerMeta = tb.providerMeta;\n }\n content.push(block);\n }\n }\n }\n if (content.length === 0) content.push({ type: 'text', text: '' });\n return { content, stopReason: state.stopReason, usage: state.usage, model: state.model };\n}\n\nexport function createStreamingState(model: string): StreamingState {\n return {\n model,\n stopReason: 'end_turn',\n usage: { input: 0, output: 0 },\n textBuffers: [],\n currentTextIndex: -1,\n tools: new Map(),\n thinking: [],\n currentThinkingIndex: -1,\n blockOrder: [],\n };\n}\n\nexport function handleMessageStart(state: StreamingState, model: string): void {\n state.model = model;\n}\n\nexport function handleContentBlockStart(\n state: StreamingState,\n ev: {\n kind?: string | undefined;\n id?: string | undefined;\n name?: string | undefined;\n providerMeta?: Record<string, unknown>;\n },\n): void {\n const kind = ev.kind ?? 'text';\n if (kind === 'text') {\n state.currentTextIndex = state.textBuffers.length;\n state.textBuffers.push('');\n state.blockOrder.push({ kind: 'text', idx: state.currentTextIndex });\n } else if (kind === 'tool_use') {\n const id = ev.id ?? randomUUID();\n state.tools.set(id, { name: ev.name ?? 'unknown', partial: '' });\n state.blockOrder.push({ kind: 'tool', id });\n state.currentTextIndex = -1;\n } else if (kind === 'thinking') {\n state.currentThinkingIndex = state.thinking.length;\n state.thinking.push({\n textBuf: '',\n ...(ev.providerMeta ? { providerMeta: ev.providerMeta } : {}),\n });\n state.blockOrder.push({ kind: 'thinking', idx: state.currentThinkingIndex });\n state.currentTextIndex = -1;\n }\n}\n\nexport function handleContentBlockStop(\n state: StreamingState,\n ev: { index?: number | undefined },\n): void {\n // Currently no provider adapter sends stop-only metadata.\n // (e.g. tool use result, thinking signature). Currently a no-op \u2014 every\n // content_block_stop event is consumed but produces no side effects.\n void state;\n void ev;\n}\n\nexport function handleTextDelta(state: StreamingState, text: string): void {\n if (state.currentTextIndex === -1) {\n // No open text block \u2014 create one and track it.\n state.currentTextIndex = state.textBuffers.length;\n state.textBuffers.push('');\n state.blockOrder.push({ kind: 'text', idx: state.currentTextIndex });\n }\n state.textBuffers[state.currentTextIndex] =\n (state.textBuffers[state.currentTextIndex] ?? '') + text;\n}\n\nexport function handleToolUseStart(state: StreamingState, ev: { id: string; name: string }): void {\n state.currentTextIndex = -1;\n state.tools.set(ev.id, { name: ev.name, partial: '' });\n state.blockOrder.push({ kind: 'tool', id: ev.id });\n}\n\nexport function handleToolUseInputDelta(\n state: StreamingState,\n ev: { id: string; partial: string },\n): void {\n const t = state.tools.get(ev.id);\n if (t) t.partial += ev.partial;\n}\n\nexport function safeJsonOrRaw(s: string): unknown {\n if (!s) return {};\n try {\n return JSON.parse(s);\n } catch {\n // Attempt to repair a truncated streaming JSON blob by auto-closing\n // unclosed braces and string values before giving up.\n const repaired = completePartialObject(s);\n try {\n return JSON.parse(repaired);\n } catch {\n return { _raw: repaired };\n }\n }\n}\n\nexport function handleToolUseStop(\n state: StreamingState,\n ev: { id: string; input?: unknown | undefined; providerMeta?: Record<string, unknown> },\n): void {\n const t = state.tools.get(ev.id);\n if (t) {\n t.input = ev.input !== undefined ? ev.input : safeJsonOrRaw(t.partial);\n if (ev.providerMeta) t.providerMeta = ev.providerMeta;\n }\n state.currentTextIndex = -1;\n}\n\n/**\n * Open a fresh thinking block. Providers that don't pre-announce blocks\n * (e.g. OpenAI/DeepSeek) can call this lazily on the first reasoning delta.\n */\nexport function handleThinkingStart(\n state: StreamingState,\n ev: { providerMeta?: Record<string, unknown> },\n): void {\n state.currentThinkingIndex = state.thinking.length;\n state.thinking.push({\n textBuf: '',\n ...(ev.providerMeta ? { providerMeta: ev.providerMeta } : {}),\n });\n state.blockOrder.push({ kind: 'thinking', idx: state.currentThinkingIndex });\n state.currentTextIndex = -1;\n}\n\nexport function handleThinkingDelta(state: StreamingState, text: string): void {\n if (state.currentThinkingIndex === -1) {\n handleThinkingStart(state, {});\n }\n const t = state.thinking[state.currentThinkingIndex];\n if (t) t.textBuf += text;\n}\n\nexport function handleThinkingSignature(state: StreamingState, signature: string): void {\n if (state.currentThinkingIndex === -1) {\n handleThinkingStart(state, {});\n }\n const t = state.thinking[state.currentThinkingIndex];\n if (t) t.signature = signature;\n}\n\nexport function handleThinkingStop(state: StreamingState): void {\n state.currentThinkingIndex = -1;\n}\n\nexport function handleMessageStop(\n state: StreamingState,\n ev: { stopReason?: Response['stopReason'] | undefined; usage?: Response['usage'] | undefined },\n): void {\n state.stopReason = ev.stopReason ?? 'end_turn';\n state.usage = ev.usage ?? { input: 0, output: 0 };\n}\n\nexport async function streamProviderToResponse(\n provider: Provider,\n req: Request,\n signal: AbortSignal,\n ctx: Context,\n events: EventBus,\n logger: Logger,\n): Promise<Response> {\n const state = createStreamingState(req.model);\n const sessionId = resolveEventSessionId(ctx);\n logger.debug('Stream started', { providerId: provider.id, model: req.model });\n\n // Batch text_delta EventBus emissions to cut fan-out ~4\u00D7. Subscribers\n // treat `text` as an appendable chunk, so concatenating deltas before\n // emitting is semantically identical. Flush before any non-text event\n // and at stream end to preserve ordering.\n const TEXT_BATCH_SIZE = 4;\n let pendingText = '';\n let pendingCount = 0;\n const flushText = (): void => {\n if (pendingCount > 0) {\n events.emit('provider.text_delta', { sessionId, ctx, text: pendingText });\n pendingText = '';\n pendingCount = 0;\n }\n };\n\n const iter = provider.stream(req, { signal })[Symbol.asyncIterator]();\n try {\n for (;;) {\n const next = await iter.next();\n if (next.done) break;\n const ev = next.value;\n try {\n switch (ev.type) {\n case 'message_start':\n handleMessageStart(state, ev.model);\n break;\n case 'content_block_start':\n handleContentBlockStart(state, ev as Parameters<typeof handleContentBlockStart>[1]);\n break;\n case 'content_block_stop':\n handleContentBlockStop(state, ev as Parameters<typeof handleContentBlockStop>[1]);\n break;\n case 'text_delta':\n handleTextDelta(state, ev.text);\n pendingText += ev.text;\n pendingCount++;\n if (pendingCount >= TEXT_BATCH_SIZE) flushText();\n break;\n case 'tool_use_start': {\n flushText();\n const idVal = ev.id;\n const nameVal = ev.name;\n handleToolUseStart(state, { id: idVal, name: nameVal });\n const emittedPayload = { sessionId, ctx, id: idVal ?? 'unknown', name: nameVal ?? 'unknown' };\n events.emit('provider.tool_use_start', emittedPayload);\n break;\n }\n case 'tool_use_input_delta':\n handleToolUseInputDelta(state, ev as Parameters<typeof handleToolUseInputDelta>[1]);\n break;\n case 'tool_use_stop': {\n flushText();\n const stoppedName = state.tools.get(ev.id)?.name ?? 'unknown';\n handleToolUseStop(state, ev as Parameters<typeof handleToolUseStop>[1]);\n events.emit('provider.tool_use_stop', { sessionId, ctx, id: ev.id, name: stoppedName });\n break;\n }\n case 'thinking_start':\n handleThinkingStart(state, ev as Parameters<typeof handleThinkingStart>[1]);\n break;\n case 'thinking_delta':\n flushText();\n handleThinkingDelta(state, ev.text);\n events.emit('provider.thinking_delta', { sessionId, ctx, text: ev.text });\n break;\n case 'thinking_signature':\n handleThinkingSignature(state, ev.signature);\n break;\n case 'thinking_stop':\n handleThinkingStop(state);\n break;\n case 'message_stop':\n handleMessageStop(state, ev as Parameters<typeof handleMessageStop>[1]);\n break;\n default: {\n // Unknown SSE event type \u2014 log for observability\n const unknownEv = ev as { type: unknown };\n logger.warn(`Stream received unknown event type: \"${String(unknownEv.type)}\"`, {\n providerId: provider.id,\n model: req.model,\n eventType: String(unknownEv.type),\n });\n break;\n }\n }\n } catch (handlerErr) {\n // Best-effort: a single malformed event should not abort the entire\n // stream. The partial response built from earlier events is preserved.\n const errMsg = handlerErr instanceof Error ? handlerErr.message : String(handlerErr);\n const evAny = ev as { type: unknown };\n logger.warn(`Stream handler error for event type \"${String(evAny.type)}\": ${errMsg}`, {\n providerId: provider.id,\n model: req.model,\n eventType: String(evAny.type),\n errorMessage: errMsg,\n });\n flushText();\n events.emit('provider.stream_error', {\n sessionId,\n ctx,\n eventType: String(evAny.type),\n msg: errMsg,\n });\n }\n }\n } catch (err) {\n if (signal.aborted) {\n // Preserve partial state so the agent can persist what was already\n // streamed before honoring the abort. The agent's outer loop checks\n // `controller.signal.aborted` after consuming this response and\n // returns `status: 'aborted'` with the finalText we built here.\n //\n // The stop reason `end_turn` is the most accurate of the available\n // StopReason values \u2014 the stream simply ended early, it was NOT a\n // token-budget hit (the previous code mis-attributed this as\n // `max_tokens`, which corrupted telemetry and broke retry logic\n // that branches on max_tokens specifically).\n state.stopReason = 'end_turn';\n flushText();\n logger.debug('Stream aborted \u2014 returning partial state', {\n providerId: provider.id,\n model: req.model,\n textBlockCount: state.textBuffers.length,\n toolBlockCount: state.tools.size,\n thinkingBlockCount: state.thinking.length,\n });\n return buildResponse(state);\n }\n throw err;\n } finally {\n try {\n // Race the drain against a short deadline so a non-cooperative\n // provider stream can't pin shutdown. 500ms is long enough for\n // cooperative SDK iterators to release network resources without\n // making abort/exit paths feel stuck.\n let drainTimer: ReturnType<typeof setTimeout> | null = null;\n try {\n // Attach a noop catch to the loser so a rejected iter.return()\n // doesn't become an unhandled promise rejection when the timeout wins.\n const drainPromise = Promise.resolve(iter.return?.()).catch(() => {\n // best-effort \u2014 iter.return() may reject on abrupt stream close\n });\n await Promise.race([\n drainPromise,\n new Promise<void>((resolve) => {\n drainTimer = setTimeout(resolve, STREAM_DRAIN_TIMEOUT_MS);\n }),\n ]);\n } finally {\n if (drainTimer) clearTimeout(drainTimer);\n }\n } catch {\n // best-effort\n }\n }\n flushText();\n logger.debug('Stream completed', {\n providerId: provider.id,\n model: req.model,\n stopReason: state.stopReason,\n textBlockCount: state.textBuffers.length,\n toolBlockCount: state.tools.size,\n thinkingBlockCount: state.thinking.length,\n usageInput: state.usage.input,\n usageOutput: state.usage.output,\n });\n return buildResponse(state);\n}\n", "import { expectDefined } from './expect-defined.js';\n\n/**\n * Attempt to close an incomplete JSON object string by auto-closing braces\n * and completing any unclosed double-quoted string values.\n *\n * Strategy:\n * 1. Compute origOpen from the ORIGINAL input (how many braces are unclosed).\n * 2. Add that many closing braces. If result is now valid JSON \u2192 return it.\n * 3. If still invalid: trim trailing whitespace, strip trailing backslash.\n * 4. Walk backwards to detect an unclosed string value.\n * - Quote followed by `:` \u2192 key-name, skip\n * - Quote followed by `,` `}` or end-of-string \u2192 toggle in/out of string\n * 5. If we end INSIDE a string (unclosed opening `\"`), append `\"` + origOpen `}`.\n *\n * Known limitations:\n * - Strings whose content ends with a `\"` character cannot be repaired\n * (algorithm can't distinguish content-`\"` from string-terminator `\"`).\n * - Input ending in bare `:` (incomplete value expression) can't be meaningfully repaired.\n * - Bare `{` returns unchanged.\n * - If origOpen=0 (braces balanced) but string is unclosed, repair is skipped\n * (the input would be valid JSON per JSON.parse, so it's returned as-is).\n */\nexport function completePartialObject(s: string): string {\n if (!s.trim().startsWith('{')) return s;\n if (tryParse(s).ok) return s;\n return repairTruncated(s);\n}\n\nfunction repairTruncated(s: string): string {\n // Single forward scan capturing the structural state at the truncation point:\n // the open-container stack, whether we are inside a string, a dangling escape,\n // and where the last significant (non-trailing-whitespace) character sits.\n const stack: ('{' | '[')[] = [];\n let inString = false;\n let escaped = false;\n let sawKey = false; // have we seen any string (i.e. real content) yet?\n let prevSig = ''; // last significant char seen outside of a string\n let contentEnd = 0; // index just past the last significant char\n // Count unbalanced `{` accumulated *inside* the currently-open string value,\n // so a truncation mid-string like `\"a{` can be balanced before closing it.\n let stringBraceDepth = 0;\n\n for (let i = 0; i < s.length; i++) {\n const ch = expectDefined(s[i]);\n if (inString) {\n contentEnd = i + 1;\n if (escaped) {\n escaped = false;\n continue;\n }\n if (ch === '\\\\') {\n escaped = true;\n continue;\n }\n if (ch === '\"') {\n inString = false;\n prevSig = '\"';\n stringBraceDepth = 0;\n continue;\n }\n if (ch === '{') stringBraceDepth++;\n else if (ch === '}' && stringBraceDepth > 0) stringBraceDepth--;\n continue;\n }\n if (ch === ' ' || ch === '\\t' || ch === '\\n' || ch === '\\r') continue;\n contentEnd = i + 1;\n if (ch === '\"') {\n inString = true;\n sawKey = true;\n stringBraceDepth = 0;\n prevSig = '\"';\n } else if (ch === '{' || ch === '[') {\n stack.push(ch);\n prevSig = ch;\n } else if (ch === '}' || ch === ']') {\n stack.pop();\n prevSig = ch;\n } else {\n prevSig = ch;\n }\n }\n\n // A lone open brace (or anything with no key/content) can't be meaningfully\n // completed \u2014 return it untouched.\n if (!sawKey && !inString) return s;\n\n // Drop trailing whitespace that sits outside any string.\n let result = s.slice(0, contentEnd);\n\n if (inString) {\n // A dangling lone backslash can't begin a valid escape \u2014 drop it.\n if (escaped) {\n result = result.slice(0, -1);\n } else if (endsWithInvalidEscape(result)) {\n // A trailing invalid escape (e.g. `\\}`) can't be completed into valid\n // JSON \u2014 strip the backslash and its bogus escapee.\n result = result.slice(0, -2);\n }\n // Balance braces opened inside the truncated string before closing it.\n if (stringBraceDepth > 0) result += '}'.repeat(stringBraceDepth);\n result += '\"';\n } else if (prevSig === ':') {\n // A key with no value (e.g. `{\"k\":`) \u2014 complete it to null.\n result += 'null';\n }\n\n // Close any still-open containers in reverse order.\n for (let k = stack.length - 1; k >= 0; k--) {\n result += stack[k] === '{' ? '}' : ']';\n }\n\n // Last resort: an empty value sitting before an existing close (`{\"k\":}`)\n // leaves invalid JSON \u2014 fill it with null.\n if (!tryParse(result).ok) {\n const patched = result.replace(/:(\\s*)([}\\]])/g, ':null$2');\n if (tryParse(patched).ok) result = patched;\n }\n\n return result;\n}\n\nconst VALID_ESCAPE = new Set(['\"', '\\\\', '/', 'b', 'f', 'n', 'r', 't', 'u']);\n\n/** True when `str` ends with a backslash escape that JSON does not allow. */\nfunction endsWithInvalidEscape(str: string): boolean {\n const last = str[str.length - 1];\n if (str[str.length - 2] !== '\\\\' || last === undefined) return false;\n if (VALID_ESCAPE.has(last)) return false;\n // The backslash must itself be unescaped (odd run of backslashes before it).\n let backslashes = 0;\n for (let k = str.length - 2; k >= 0 && str[k] === '\\\\'; k--) backslashes++;\n return backslashes % 2 === 1;\n}\n\nfunction tryParse(s: string): { ok: true; value: unknown } | { ok: false } {\n try {\n return { ok: true, value: JSON.parse(s) };\n } catch {\n return { ok: false };\n }\n}\n", "import { createHash } from 'node:crypto';\nimport type { ContentBlock } from '../types/blocks.js';\nimport type { Message } from '../types/messages.js';\nimport type { Request } from '../types/provider.js';\n\nexport interface ChroniclePromptManifest {\n manifestId: string;\n messageCount: number; estimatedMessageTokens: number; contentBytes: number;\n roleCounts: Record<string, number>; blockCounts: Record<string, number>;\n system: { blockCount: number; bytes: number; hash: string };\n messages: Array<{ index: number; role: string; bytes: number; estimatedTokens?: number; hash: string; blocks: Record<string, number> }>;\n tools: { count: number; estimatedDefinitionTokens: number; manifestHash: string; names: string[]; mutating: number; destructive: number };\n request: Record<string, unknown>;\n}\n\n/** Content-addressed prompt composition manifest; raw prompt/tool prose never leaves this function. */\nexport function createChroniclePromptManifest(request: Request): ChroniclePromptManifest {\n const roleCounts: Record<string, number> = {}, blockCounts: Record<string, number> = {};\n const messages = request.messages.map((message, index) => messageSummary(message, index, roleCounts, blockCounts));\n const systemText = (request.system ?? []).map((block) => block.text).join('\\n');\n const toolRecords = (request.tools ?? []).map((tool) => ({ name: tool.name, schemaHash: hash(stable(tool.inputSchema)),\n permission: tool.permission, mutating: tool.mutating, riskTier: tool.riskTier, capabilities: tool.capabilities,\n estimatedTokens: tool._estDefTokens ?? 0 }));\n const core = { systemHash: hash(systemText), messages: messages.map(({ hash: contentHash, ...rest }) => ({ ...rest, contentHash })), tools: toolRecords,\n model: request.model, maxTokens: request.maxTokens, temperature: request.temperature, topP: request.topP,\n topK: request.topK, seed: request.seed, toolChoice: request.toolChoice, reasoning: request.reasoning,\n cache: request.cache, responseFormat: request.responseFormat?.type };\n return {\n manifestId: `prompt_${hash(stable(core))}`,\n messageCount: messages.length,\n estimatedMessageTokens: messages.reduce((sum, message) => sum + (message.estimatedTokens ?? 0), 0),\n contentBytes: messages.reduce((sum, message) => sum + message.bytes, 0) + Buffer.byteLength(systemText),\n roleCounts, blockCounts,\n system: { blockCount: request.system?.length ?? 0, bytes: Buffer.byteLength(systemText), hash: hash(systemText) },\n messages,\n tools: { count: toolRecords.length, estimatedDefinitionTokens: toolRecords.reduce((sum, tool) => sum + tool.estimatedTokens, 0),\n manifestHash: hash(stable(toolRecords)), names: toolRecords.map((tool) => tool.name),\n mutating: toolRecords.filter((tool) => tool.mutating).length,\n destructive: toolRecords.filter((tool) => tool.riskTier === 'destructive').length },\n request: { maxTokens: request.maxTokens, temperature: request.temperature, topP: request.topP, topK: request.topK,\n frequencyPenalty: request.frequencyPenalty, presencePenalty: request.presencePenalty, seed: request.seed,\n candidateCount: request.candidateCount, logprobs: request.logprobs, topLogprobs: request.topLogprobs,\n stopSequenceCount: request.stopSequences?.length ?? 0, toolChoice: request.toolChoice,\n reasoning: request.reasoning, cache: request.cache, responseFormat: request.responseFormat?.type,\n safetySettingCount: request.safetySettings?.length ?? 0, userHash: request.user ? hash(request.user) : undefined },\n };\n}\n\nfunction messageSummary(message: Message, index: number, roles: Record<string, number>, totals: Record<string, number>) {\n roles[message.role] = (roles[message.role] ?? 0) + 1;\n const blocks = typeof message.content === 'string' ? { text: 1 } : countBlocks(message.content);\n for (const [type, count] of Object.entries(blocks)) totals[type] = (totals[type] ?? 0) + count;\n const content = contentIdentity(message.content);\n return { index, role: message.role, bytes: content.bytes,\n ...(message._estTokens !== undefined ? { estimatedTokens: message._estTokens } : {}), hash: content.hash, blocks };\n}\nfunction countBlocks(blocks: ContentBlock[]): Record<string, number> {\n const counts: Record<string, number> = {};\n for (const block of blocks) counts[block.type] = (counts[block.type] ?? 0) + 1;\n return counts;\n}\nfunction hash(value: string): string { return createHash('sha256').update(value).digest('hex'); }\nfunction contentIdentity(content: Message['content']): { hash: string; bytes: number } {\n if (typeof content === 'string') return { hash: hash(content), bytes: Buffer.byteLength(content) };\n const digest = createHash('sha256'); let bytes = 0;\n const add = (value: string | undefined) => { if (!value) return; digest.update(value); bytes += Buffer.byteLength(value); };\n for (const block of content) {\n add(block.type);\n if (block.type === 'text') add(block.text);\n else if (block.type === 'thinking') { add(block.thinking); add(block.signature); }\n else if (block.type === 'tool_use') { add(block.id); add(block.name); add(stable(block.input)); }\n else if (block.type === 'tool_result') { add(block.tool_use_id); add(block.name); add(block.content); add(String(block.is_error ?? false)); }\n else if (block.type === 'image') { add(block.source.type); add(block.source.media_type); add(block.source.url); add(block.source.data); }\n }\n return { hash: digest.digest('hex'), bytes };\n}\nfunction stable(value: unknown): string {\n if (value === undefined) return 'undefined';\n if (value === null || typeof value !== 'object') return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(stable).join(',')}]`;\n return `{${Object.entries(value as Record<string, unknown>).sort(([a], [b]) => a.localeCompare(b)).map(([key, child]) => `${JSON.stringify(key)}:${stable(child)}`).join(',')}}`;\n}\n", "import { AsyncLocalStorage } from 'node:async_hooks';\nimport { createHash, randomUUID } from 'node:crypto';\nimport { channel } from 'node:diagnostics_channel';\nimport type { EventBus } from '../kernel/events.js';\n\nexport interface NetworkTelemetryContext {\n events: EventBus; sessionId: string; traceId?: string; agentId?: string;\n toolCallId?: string; attemptId?: string; initiator: 'provider' | 'tool'; operationName: string;\n}\ninterface RequestState extends Omit<NetworkTelemetryContext, 'events'> {\n events: EventBus; requestId: string; method: string; scheme: string; serverAddress: string;\n serverPort?: number; pathHash: string; requestBytes?: number; startedAt: string; startedNs: bigint;\n}\nconst storage = new AsyncLocalStorage<NetworkTelemetryContext>();\nconst requests = new WeakMap<object, RequestState>();\nlet users = 0;\nlet unsubscribe: (() => void) | undefined;\n\nexport function runWithNetworkTelemetry<T>(context: NetworkTelemetryContext, run: () => T): T {\n return storage.run(context, run);\n}\n\n/** Installs one process-wide undici/fetch diagnostics observer, reference counted across runtimes. */\nexport function startNetworkTelemetryMonitor(): () => void {\n users++;\n if (!unsubscribe) unsubscribe = subscribe();\n let stopped = false;\n return () => { if (stopped) return; stopped = true; users--; if (users <= 0) { unsubscribe?.(); unsubscribe = undefined; users = 0; } };\n}\n\nfunction subscribe(): () => void {\n const create = channel('undici:request:create');\n const headers = channel('undici:request:headers');\n const error = channel('undici:request:error');\n const onCreate = (message: unknown) => {\n const context = storage.getStore(); const request = objectField(message, 'request');\n if (!context || !request) return;\n const target = safeTarget(request); const startedAt = new Date().toISOString();\n const requestBytes = numberField(request, 'contentLength');\n const state: RequestState = { ...context, requestId: randomUUID(), ...target,\n ...(requestBytes !== undefined ? { requestBytes } : {}), startedAt, startedNs: process.hrtime.bigint() };\n requests.set(request, state);\n context.events.emit('network.request.started', { ...identity(state), requestId: state.requestId,\n method: state.method, scheme: state.scheme, serverAddress: state.serverAddress,\n ...(state.serverPort !== undefined ? { serverPort: state.serverPort } : {}), pathHash: state.pathHash,\n queryKeys: queryKeys(request), ...(state.requestBytes !== undefined ? { requestBytes: state.requestBytes } : {}), startedAt });\n };\n const onHeaders = (message: unknown) => {\n const request = objectField(message, 'request'); if (!request) return;\n const state = requests.get(request); if (!state) return; requests.delete(request);\n const response = objectField(message, 'response');\n const responseBytes = contentLength(response);\n state.events.emit('network.request.completed', { ...identity(state), requestId: state.requestId,\n method: state.method, scheme: state.scheme, serverAddress: state.serverAddress,\n ...(state.serverPort !== undefined ? { serverPort: state.serverPort } : {}), pathHash: state.pathHash,\n statusCode: numberField(response, 'statusCode') ?? 0, durationMs: elapsed(state.startedNs),\n ...(state.requestBytes !== undefined ? { requestBytes: state.requestBytes } : {}),\n ...(responseBytes !== undefined ? { responseBytes } : {}), completedAt: new Date().toISOString() });\n };\n const onError = (message: unknown) => {\n const request = objectField(message, 'request'); if (!request) return;\n const state = requests.get(request); if (!state) return; requests.delete(request);\n const err = objectField(message, 'error');\n const errorCode = stringField(err, 'code');\n state.events.emit('network.request.failed', { ...identity(state), requestId: state.requestId,\n method: state.method, scheme: state.scheme, serverAddress: state.serverAddress,\n ...(state.serverPort !== undefined ? { serverPort: state.serverPort } : {}), pathHash: state.pathHash,\n durationMs: elapsed(state.startedNs), errorName: stringField(err, 'name') ?? 'Error',\n ...(errorCode ? { errorCode } : {}), failedAt: new Date().toISOString() });\n };\n create.subscribe(onCreate); headers.subscribe(onHeaders); error.subscribe(onError);\n return () => { create.unsubscribe(onCreate); headers.unsubscribe(onHeaders); error.unsubscribe(onError); };\n}\n\nfunction identity(state: RequestState) { return { sessionId: state.sessionId, ...(state.traceId ? { traceId: state.traceId } : {}),\n ...(state.agentId ? { agentId: state.agentId } : {}), ...(state.toolCallId ? { toolCallId: state.toolCallId } : {}),\n ...(state.attemptId ? { attemptId: state.attemptId } : {}), initiator: state.initiator, operationName: state.operationName }; }\nfunction safeTarget(request: Record<string, unknown>) {\n const origin = String(request.origin ?? ''); const path = String(request.path ?? '');\n let url: URL; try { url = new URL(path, origin); } catch { url = new URL('http://invalid.local/'); }\n return { method: String(request.method ?? 'GET').toUpperCase(), scheme: url.protocol.replace(':', ''),\n serverAddress: url.hostname, ...(url.port ? { serverPort: Number(url.port) } : {}), pathHash: hash(url.pathname) };\n}\nfunction queryKeys(request: Record<string, unknown>): string[] { try { return [...new URL(String(request.path ?? ''), String(request.origin ?? '')).searchParams.keys()].filter((v, i, a) => a.indexOf(v) === i).slice(0, 50); } catch { return []; } }\nfunction contentLength(response: Record<string, unknown> | undefined): number | undefined {\n const raw = response?.headers; if (!Array.isArray(raw)) return undefined;\n for (let index = 0; index < raw.length - 1; index += 2) if (String(raw[index]).toLowerCase() === 'content-length') { const value = Number(String(raw[index + 1])); return Number.isFinite(value) ? value : undefined; }\n return undefined;\n}\nfunction objectField(value: unknown, key: string): Record<string, unknown> | undefined { return value && typeof value === 'object' && (value as Record<string, unknown>)[key] && typeof (value as Record<string, unknown>)[key] === 'object' ? (value as Record<string, Record<string, unknown>>)[key] : undefined; }\nfunction stringField(value: Record<string, unknown> | undefined, key: string): string | undefined { return typeof value?.[key] === 'string' ? value[key] as string : undefined; }\nfunction numberField(value: Record<string, unknown> | undefined, key: string): number | undefined { return typeof value?.[key] === 'number' ? value[key] as number : undefined; }\nfunction elapsed(start: bigint): number { return Number(process.hrtime.bigint() - start) / 1e6; }\nfunction hash(value: string): string { return createHash('sha256').update(value).digest('hex'); }\n", "import type { EventBus } from '../kernel/events.js';\nimport type { Logger } from '../types/logger.js';\nimport type { Tracer } from '../types/observability.js';\nimport type { Provider, Request, Response } from '../types/provider.js';\nimport { ProviderError } from '../types/provider.js';\nimport { toWrongStackError } from '../types/errors.js';\nimport type { RetryPolicy } from '../types/retry-policy.js';\nimport { type Context, resolveEventSessionId } from './context.js';\nimport { streamProviderToResponse } from './streaming-response-builder.js';\nimport { createChroniclePromptManifest } from '../chronicle/prompt-manifest.js';\nimport { runWithNetworkTelemetry } from '../observability/network-telemetry.js';\n\n/** Fields worth including in every provider-run log for cross-correlation. */\nfunction providerLogCtx(p: Provider, r: Request): Record<string, unknown> {\n return {\n providerId: p.id,\n model: r.model,\n streaming: p.capabilities.streaming,\n msgCount: r.messages.length,\n toolCount: r.tools?.length ?? 0,\n };\n}\n\nexport interface RunProviderOptions {\n provider: Provider;\n request: Request;\n signal: AbortSignal;\n ctx: Context;\n events: EventBus;\n retry: RetryPolicy;\n logger: Logger;\n tracer?: Tracer | undefined;\n}\n\n/**\n * Call a provider with the retry policy applied. Emits `provider.retry`\n * before each retry and `provider.error` once when the retries are\n * exhausted. Streaming providers route through the streaming-response\n * builder so deltas reach the renderer.\n */\nexport async function runProviderWithRetry(opts: RunProviderOptions): Promise<Response> {\n const { provider, request, signal, ctx, events, retry, logger, tracer } = opts;\n const logicalRequestId = randomUUID();\n const promptManifest = createChroniclePromptManifest(request);\n let attempt = 0;\n for (;;) {\n const attemptId = randomUUID();\n const startedAt = new Date().toISOString();\n const startedNs = process.hrtime.bigint();\n const correlation = {\n sessionId: resolveEventSessionId(ctx),\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}),\n ...(ctx.agentId ? { agentId: ctx.agentId } : {}),\n logicalRequestId,\n attemptId,\n attempt,\n providerId: provider.id,\n model: request.model,\n taskId: ctx.currentKanbanTaskId,\n boardId: ctx.currentKanbanBoardId,\n };\n events.emit('provider.attempt.started', {\n ...correlation,\n streaming: provider.capabilities.streaming,\n messageCount: request.messages.length,\n toolCount: request.tools?.length ?? 0,\n promptManifest,\n startedAt,\n });\n const span = tracer?.startSpan('provider.complete', {\n 'provider.id': provider.id,\n 'provider.model': request.model,\n 'provider.streaming': provider.capabilities.streaming,\n 'provider.attempt': attempt,\n });\n logger.debug(`Provider attempt ${attempt + 1} starting`, providerLogCtx(provider, request));\n try {\n const res = await runWithNetworkTelemetry({ events, sessionId: resolveEventSessionId(ctx),\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}), ...(ctx.agentId ? { agentId: ctx.agentId } : {}),\n attemptId, initiator: 'provider', operationName: `${provider.id}.complete` }, () =>\n provider.capabilities.streaming\n ? streamProviderToResponse(provider, request, signal, ctx, events, logger)\n : provider.complete(request, { signal }));\n span?.setAttribute('provider.stopReason', res.stopReason);\n span?.setAttribute('provider.usage_in', res.usage.input);\n span?.setAttribute('provider.usage_out', res.usage.output);\n span?.end();\n events.emit('provider.attempt.completed', {\n ...correlation,\n startedAt,\n endedAt: new Date().toISOString(),\n durationMs: elapsedMs(startedNs),\n stopReason: res.stopReason,\n usage: res.usage,\n });\n logger.debug('Provider call succeeded', {\n ...providerLogCtx(provider, request),\n stopReason: res.stopReason,\n usageInput: res.usage.input,\n usageOutput: res.usage.output,\n cacheRead: res.usage.cacheRead,\n cacheWrite: res.usage.cacheWrite,\n attempts: attempt + 1,\n });\n return res;\n } catch (err) {\n if (err instanceof Error) span?.recordError(err);\n span?.end();\n if (signal.aborted) throw err;\n const isProviderErr = err instanceof ProviderError || ProviderError.isProviderError(err);\n const errAsErr = err instanceof Error ? err : new Error(String(err));\n const canRetry = retry.shouldRetry(isProviderErr ? err : errAsErr, attempt);\n const description = isProviderErr ? (err as ProviderError).describe() : errAsErr.message;\n const delay = canRetry\n ? Math.round(retry.delayMs(attempt, isProviderErr ? (err as ProviderError) : errAsErr))\n : undefined;\n events.emit('provider.attempt.failed', {\n ...correlation,\n startedAt,\n endedAt: new Date().toISOString(),\n durationMs: elapsedMs(startedNs),\n status: isProviderErr ? err.status : 0,\n failureKind: isProviderErr ? err.kind : 'unknown',\n description,\n retryable: canRetry,\n retryScheduled: canRetry,\n ...(delay !== undefined ? { retryDelayMs: delay } : {}),\n ...(isProviderErr && err.body?.requestId ? { providerRequestId: err.body.requestId } : {}),\n });\n if (!canRetry) {\n events.emit('provider.error', {\n sessionId: resolveEventSessionId(ctx),\n providerId: isProviderErr ? err.providerId : provider.id,\n status: isProviderErr ? err.status : 0,\n description,\n retryable: false,\n });\n logger.error(`Provider call failed after ${attempt + 1} attempt(s) \u2014 ${description}`, {\n ...providerLogCtx(provider, request),\n attempts: attempt + 1,\n errorDescription: description,\n status: isProviderErr ? (err as ProviderError).status : undefined,\n errorName: err instanceof Error ? err.name : undefined,\n errorStack:\n err instanceof Error ? err.stack?.split('\\n').slice(0, 3).join('\\n') : undefined,\n });\n // ProviderError already extends WrongStackError \u2014 passes through unchanged.\n // Raw Errors (network, timeout) get wrapped so callers can branch on .code\n // instead of parsing error messages.\n throw toWrongStackError(err);\n }\n const attemptNum = attempt + 1;\n const maxAttempts = retry.maxAttempts(isProviderErr ? (err as ProviderError) : errAsErr);\n logger.warn(`Provider retry ${attemptNum}/${maxAttempts} in ${delay}ms \u2014 ${description}`, {\n ...providerLogCtx(provider, request),\n attempt: attemptNum,\n maxAttempts,\n delayMs: delay,\n errorDescription: description,\n status: isProviderErr ? (err as ProviderError).status : undefined,\n });\n events.emit('provider.retry', {\n sessionId: resolveEventSessionId(ctx),\n providerId: isProviderErr ? err.providerId : provider.id,\n attempt: attemptNum,\n delayMs: delay!,\n status: isProviderErr ? err.status : 0,\n description,\n });\n await new Promise<void>((resolve, reject) => {\n let settled = false;\n // Single teardown for both outcomes (timer fires OR signal aborts) so\n // the two branches can't drift: always clear the pending timer AND\n // remove the abort listener. removeEventListener is a no-op once the\n // listener has fired, but calling it unconditionally guarantees no\n // listener survives the wait \u2014 even on the abort-wins path \u2014 which is\n // what prevents abort listeners from accumulating across retries on a\n // long-lived signal.\n const cleanup = () => {\n clearTimeout(t);\n signal.removeEventListener('abort', onAbort);\n };\n const onAbort = () => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(new Error('aborted'));\n };\n const t = setTimeout(() => {\n if (settled) return;\n settled = true;\n cleanup();\n resolve();\n }, delay!);\n if (signal.aborted) {\n onAbort();\n return;\n }\n signal.addEventListener('abort', onAbort);\n });\n attempt++;\n }\n }\n}\n\nfunction elapsedMs(startedNs: bigint): number {\n return Number(process.hrtime.bigint() - startedNs) / 1_000_000;\n}\nimport { randomUUID } from 'node:crypto';\n", "/**\n * Queue awareness \u2014 let the running agent *see* messages the user typed\n * while it was busy, without delivering them early.\n *\n * The TUI queues plain messages typed mid-run and replays them as real user\n * turns after the run finishes (the queue drainer in app.tsx). That keeps\n * turn-taking clean, but the model is blind to the backlog: a queued message\n * may invalidate the current approach, add a constraint, or just be a\n * \"by the way\" note the user expected the agent to notice.\n *\n * Unlike `/btw` (a consume-once note channel, {@link ./btw.ts}), this is a\n * SNAPSHOT channel: the host mirrors the queue's current contents onto the\n * live `Context` on every queue mutation (enqueue, /queue delete, /queue\n * clear, dequeue-for-delivery). At each iteration boundary the agent loop\n * asks \"did the snapshot change since the model last saw it?\" and, if so,\n * injects an informational block listing the pending messages. The queue\n * itself is untouched \u2014 every queued message still arrives later as its own\n * user turn.\n *\n * Deliberate quietness: when the queue transitions to empty (cleared by the\n * user, drained between runs, or dropped by steering/abort) the snapshot is\n * marked seen WITHOUT injecting a \"queue is now empty\" block. The empty\n * transition usually happens at run boundaries where such a notice is stale\n * noise; the cost is that a mid-run `/queue clear` isn't announced, which is\n * safe because the block's framing already tells the model the queue may\n * change and the authoritative messages arrive as future turns.\n */\nimport type { Context } from './context.js';\n\n/** Meta key holding the queue-awareness snapshot. */\nconst META_KEY = '_queuedMessagesAwareness';\n\n/** Cap on listed messages so a paste-storm can't bloat the injected block. */\nconst MAX_ITEMS = 20;\n\n/** Per-message preview cap \u2014 the full text arrives later as a real turn. */\nconst MAX_PREVIEW_CHARS = 500;\n\ninterface AwarenessState {\n /** Current queue contents (truncated previews, head first). */\n items: string[];\n /** What the model was last shown. Injection fires only on a diff. */\n seen: string[];\n}\n\nfunction read(ctx: Context): AwarenessState | undefined {\n const raw = ctx.meta[META_KEY];\n if (!raw || typeof raw !== 'object') return undefined;\n const s = raw as AwarenessState;\n return Array.isArray(s.items) && Array.isArray(s.seen) ? s : undefined;\n}\n\nfunction sameList(a: string[], b: string[]): boolean {\n return a.length === b.length && a.every((v, i) => v === b[i]);\n}\n\nfunction toPreview(text: string): string {\n const trimmed = text.trim();\n if (trimmed.length <= MAX_PREVIEW_CHARS) return trimmed;\n return `${trimmed.slice(0, MAX_PREVIEW_CHARS - 1)}\u2026`;\n}\n\n/**\n * Mirror the host's pending-message queue onto the context. Call on every\n * queue mutation with the FULL current queue (head first) \u2014 not a delta.\n * Blank entries are dropped; the head-most {@link MAX_ITEMS} are kept since\n * the head is what arrives first.\n */\nexport function setQueuedMessagesSnapshot(ctx: Context, texts: string[]): void {\n const items = texts.map(toPreview).filter((t) => t.length > 0).slice(0, MAX_ITEMS);\n const prev = read(ctx);\n if (items.length === 0 && (!prev || prev.seen.length === 0)) {\n // Nothing pending and the model never saw anything \u2014 keep meta clean.\n if (prev) delete ctx.meta[META_KEY];\n return;\n }\n ctx.meta[META_KEY] = { items, seen: prev?.seen ?? [] } satisfies AwarenessState;\n}\n\n/** Current snapshot (previews), without affecting seen-state. */\nexport function peekQueuedMessages(ctx: Context): string[] {\n return read(ctx)?.items ?? [];\n}\n\n/**\n * Called by the agent loop at each iteration boundary. Returns the queued\n * messages to surface when the snapshot changed since the model last saw it,\n * or `null` when there is nothing new to say. Marks the snapshot seen either\n * way, so the same state is never injected twice. An empty snapshot is\n * acknowledged silently (see module comment).\n */\nexport function consumeQueuedMessagesUpdate(ctx: Context): string[] | null {\n const s = read(ctx);\n if (!s) return null;\n if (sameList(s.items, s.seen)) return null;\n if (s.items.length === 0) {\n delete ctx.meta[META_KEY];\n return null;\n }\n ctx.meta[META_KEY] = { items: s.items, seen: s.items } satisfies AwarenessState;\n return s.items;\n}\n\n/**\n * Format the awareness block. Framing goals: (1) the model must NOT treat\n * the listed messages as instructions to execute now \u2014 they each arrive as\n * their own turn later; (2) it SHOULD let them influence in-flight decisions\n * (a queued message may invalidate the current approach or be a /btw-style\n * note); (3) the list is a full replacement of any earlier notice, so a\n * shrunken list implicitly communicates deletions.\n */\nexport function buildQueuedMessagesBlock(items: string[]): string {\n const body = items.map((t, i) => `${i + 1}. ${t}`).join('\\n');\n return [\n '[QUEUED MESSAGES \u2014 the user typed these while you were working. They are',\n 'waiting in the input queue and each will be delivered as its own turn',\n 'after you finish, so do NOT answer or act on them as new tasks now. Read',\n 'them as a heads-up: if one changes what you should be doing right now',\n '(new constraint, invalidated approach), adapt your current work; if one',\n 'is just an FYI, fold it in. The queue may still change before delivery.',\n 'This notice replaces any earlier one \u2014 the queue now holds exactly:',\n '',\n body,\n ']',\n ].join('\\n');\n}\n", "import type { Provider, Request } from '../types/provider.js';\n\n/**\n * Provider identity owned by one concrete LLM request.\n *\n * Live model switches replace Context.provider, but an already-built request\n * must keep the provider it started with. Fallback is the deliberate\n * exception: it rebinds the same request before retrying it elsewhere.\n */\nconst requestProviders = new WeakMap<Request, Provider>();\n\nexport function bindRequestProvider(request: Request, provider: Provider): void {\n requestProviders.set(request, provider);\n}\n\nexport function providerBoundToRequest(request: Request): Provider | undefined {\n return requestProviders.get(request);\n}\n", "import type { RunController } from '../kernel/run-controller.js';\nimport { TOKENS } from '../kernel/tokens.js';\nimport { attachFleetPulse, attachMailboxChecker } from '../mailbox-attach.js';\nimport type { ContentBlock, TextBlock } from '../types/blocks.js';\nimport { isTextBlock, isToolUseBlock } from '../types/blocks.js';\nimport { toWrongStackError } from '../types/errors.js';\nimport type { Request, Response } from '../types/provider.js';\nimport { effectiveInputTokens } from '../types/provider.js';\nimport { recordUserIntentEvidence } from '../utils/context-evidence.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport {\n estimateMessageTokens,\n estimateRequestTokens,\n getCalibrationState,\n type RequestTokenBreakdown,\n realAnchoredInputTokens,\n recordActualUsage,\n} from '../utils/token-estimate.js';\nimport type { AgentInternals } from './agent-internals.js';\nimport type { AgentResponseHandler } from './agent-response.js';\nimport type { AgentToolHandler } from './agent-tools.js';\nimport type { RunResult, UserInputPayload } from './agent-types.js';\nimport { buildBtwBlock, consumeBtwNotes } from './btw.js';\nimport { resolveEventSessionId, type RunOptions } from './context.js';\nimport { consumeAutonomousContinue } from './continue-to-next-iteration.js';\nimport { requestLimitExtension } from './iteration-limit.js';\nimport { injectPendingMailboxMessages, removeInjectedMailboxBlocks } from './mailbox-loop.js';\nimport { runProviderWithRetry } from './provider-runner.js';\nimport { buildQueuedMessagesBlock, consumeQueuedMessagesUpdate } from './queued-messages.js';\nimport { providerBoundToRequest } from './request-provider-binding.js';\n\nfunction toError(err: unknown): Error {\n return err instanceof Error ? err : new Error(String(err));\n}\n\nexport function signalAbortReason(signal: AbortSignal): string {\n const r = signal.reason;\n if (r instanceof Error) return r.message || r.name;\n if (typeof r === 'string' && r.length > 0) return r;\n return 'aborted';\n}\n\ninterface LoopHandlers {\n tools: AgentToolHandler;\n response: AgentResponseHandler;\n}\n\nexport interface AgentLoopHandler {\n runInner(\n inputPayload: UserInputPayload,\n opts: RunOptions,\n controller: RunController,\n autonomousContinue: boolean,\n ): Promise<RunResult>;\n}\n\nexport function createAgentLoopHandler(\n a: AgentInternals,\n handlers: LoopHandlers,\n): AgentLoopHandler {\n const checkMailbox = attachMailboxChecker(a);\n\n const fleetPulseCfg = (() => {\n try {\n return typeof a.container?.has === 'function' && a.container.has(TOKENS.ConfigStore)\n ? a.container.resolve(TOKENS.ConfigStore).get().fleet?.pulse\n : undefined;\n } catch {\n return undefined;\n }\n })();\n const getFleetPulse = attachFleetPulse(a, fleetPulseCfg);\n const pulseEveryN = Math.max(1, fleetPulseCfg?.everyNIterations ?? 5);\n const backgroundCoordination = () => a.ctx.meta['coordinationContextMode'] === 'background';\n\n async function compactContextIfNeeded(): Promise<boolean> {\n const msgCount = a.ctx.messages.length;\n const maxContext = currentMaxContext();\n const revision = a.ctx.state.revision;\n const toolsRef = a.ctx.tools;\n const systemRef = a.ctx.systemPrompt;\n const requestTokens = a.ctx.lastRequestTokens;\n if (\n _lastCompactionMsgCount === msgCount &&\n _lastCompactionRevision === revision &&\n _lastCompactionToolsRef === toolsRef &&\n _lastCompactionSystemRef === systemRef &&\n _lastCompactionRequestTokens === requestTokens &&\n _lastCompactionWasNoop &&\n _lastCompactionMaxContext === maxContext &&\n maxContext > 0\n ) {\n return false;\n }\n const beforeMessages = a.ctx.messages;\n const beforeMsgCount = a.ctx.messages.length;\n await a.pipelines.contextWindow.run(a.ctx);\n _lastCompactionMsgCount = a.ctx.messages.length;\n _lastCompactionRevision = a.ctx.state.revision;\n _lastCompactionToolsRef = a.ctx.tools;\n _lastCompactionSystemRef = a.ctx.systemPrompt;\n _lastCompactionMaxContext = maxContext;\n const changed = a.ctx.messages !== beforeMessages || a.ctx.messages.length !== beforeMsgCount;\n const tokens = refreshContextRequestTokenStash({ force: changed });\n _lastCompactionRequestTokens = tokens;\n const load = maxContext > 0 ? tokens / maxContext : 0;\n _lastCompactionWasNoop = tokens > 0 && load < 0.5;\n if (changed) {\n _lastEmittedMsgCount = -1;\n _lastEmittedToolCount = -1;\n _lastEmittedMaxContext = -1;\n }\n return changed;\n }\n\n const calibrationKey = (model: string = a.ctx.model): string =>\n `${a.ctx.provider?.id ?? 'unknown'}/${model}`;\n\n let _cachedSysRef: unknown = null;\n let _cachedToolsRef: readonly unknown[] | null = null;\n let _cachedOverheadTokens = 0;\n\n function systemAndToolsOverhead(): number {\n const sysRef = a.ctx.systemPrompt;\n const toolsRef = a.ctx.tools;\n if (sysRef === _cachedSysRef && toolsRef === _cachedToolsRef && _cachedOverheadTokens > 0) {\n return _cachedOverheadTokens;\n }\n const breakdown = estimateRequestTokens([], sysRef, toolsRef ?? [], calibrationKey());\n _cachedSysRef = sysRef;\n _cachedToolsRef = toolsRef;\n _cachedOverheadTokens = breakdown.systemPrompt + breakdown.tools;\n return _cachedOverheadTokens;\n }\n\n function stashRequestTokens(req: Request): RequestTokenBreakdown {\n const preFlight = estimateRequestTokens(\n req.messages,\n req.system,\n req.tools ?? [],\n calibrationKey(req.model),\n );\n\n a.ctx.lastRequestTokens = preFlight.total;\n _lastPreFlightMsgCount = req.messages.length;\n _cachedSysRef = req.system;\n _cachedToolsRef = req.tools ?? [];\n _cachedOverheadTokens = preFlight.systemPrompt + preFlight.tools;\n a.ctx.meta['lastRequestTokensAt'] = {\n msgCount: req.messages.length,\n toolCount: (req.tools ?? []).length,\n };\n\n return preFlight;\n }\n\n function refreshContextRequestTokenStash(opts: { force?: boolean | undefined } = {}): number {\n const msgCount = a.ctx.messages.length;\n const toolCount = (a.ctx.tools ?? []).length;\n const stashed = a.ctx.lastRequestTokens;\n const stashedAt = a.ctx.meta?.['lastRequestTokensAt'];\n if (\n !opts.force &&\n typeof stashed === 'number' &&\n stashed > 0 &&\n typeof stashedAt === 'object' &&\n stashedAt !== null\n ) {\n const meta = stashedAt as { msgCount?: unknown; toolCount?: unknown };\n if (\n meta.msgCount === msgCount &&\n (typeof meta.toolCount !== 'number' || meta.toolCount === toolCount)\n ) {\n return stashed;\n }\n }\n\n const refreshed = estimateMessageTokens(a.ctx.messages) + systemAndToolsOverhead();\n a.ctx.lastRequestTokens = refreshed;\n _lastPreFlightMsgCount = msgCount;\n a.ctx.meta['lastRequestTokensAt'] = { msgCount, toolCount };\n return refreshed;\n }\n\n async function buildRequestWithPreflightCompaction(opts: RunOptions): Promise<{\n req: Request;\n provider: import('../types/provider.js').Provider;\n preFlight: RequestTokenBreakdown;\n }> {\n let prepared = await handlers.response.buildAndRunRequestPipeline(opts);\n let req = prepared.request;\n let preFlight = stashRequestTokens(req);\n\n if (await compactContextIfNeeded()) {\n prepared = await handlers.response.buildAndRunRequestPipeline(opts);\n req = prepared.request;\n preFlight = stashRequestTokens(req);\n }\n\n return { req, provider: prepared.provider, preFlight };\n }\n\n function emitContextPct(): void {\n const msgCount = a.ctx.messages.length;\n const toolCount = (a.ctx.tools ?? []).length;\n const maxContext = currentMaxContext();\n const revision = a.ctx.state.revision;\n if (\n msgCount === _lastEmittedMsgCount &&\n toolCount === _lastEmittedToolCount &&\n revision === _lastEmittedRevision &&\n maxContext === _lastEmittedMaxContext &&\n maxContext > 0\n ) {\n return;\n }\n _lastEmittedMsgCount = msgCount;\n _lastEmittedToolCount = toolCount;\n _lastEmittedRevision = revision;\n _lastEmittedMaxContext = maxContext;\n\n if (msgCount !== _lastPreFlightMsgCount) {\n const stashed = a.ctx.lastRequestTokens;\n if (\n typeof stashed === 'number' &&\n stashed > 0 &&\n _lastPreFlightMsgCount >= 0 &&\n _lastPreFlightMsgCount < msgCount\n ) {\n const delta = estimateMessageTokens(a.ctx.messages.slice(_lastPreFlightMsgCount));\n a.ctx.lastRequestTokens = stashed + delta;\n } else {\n a.ctx.lastRequestTokens = estimateMessageTokens(a.ctx.messages) + systemAndToolsOverhead();\n }\n _lastPreFlightMsgCount = msgCount;\n a.ctx.meta['lastRequestTokensAt'] = { msgCount, toolCount };\n }\n\n let total: number;\n const anchored = realAnchoredInputTokens(\n a.ctx.messages,\n a.ctx.lastRealInputTokens,\n typeof a.ctx.meta?.['realAnchorMsgCount'] === 'number'\n ? (a.ctx.meta['realAnchorMsgCount'] as number)\n : undefined,\n );\n const stashed = a.ctx.lastRequestTokens;\n if (anchored !== null) {\n total = anchored;\n } else if (typeof stashed === 'number' && stashed > 0) {\n const cal = getCalibrationState(calibrationKey());\n total = cal.calibrated\n ? Math.round(stashed * Math.min(1.5, Math.max(0.5, cal.ratio)))\n : stashed;\n } else {\n const raw = estimateMessageTokens(a.ctx.messages) + systemAndToolsOverhead();\n a.ctx.lastRequestTokens = raw;\n _lastPreFlightMsgCount = msgCount;\n const cal = getCalibrationState(calibrationKey());\n total = cal.calibrated ? Math.round(raw * Math.min(1.5, Math.max(0.5, cal.ratio))) : raw;\n }\n const rawLoad = maxContext > 0 ? total / maxContext : 0;\n const load = Math.max(0, Math.min(1, rawLoad));\n a.events.emit('ctx.pct', {\n sessionId: resolveEventSessionId(a.ctx),\n load,\n rawLoad,\n tokens: total,\n maxContext,\n });\n }\n\n function currentMaxContext(): number {\n const metaLimit = a.ctx.meta?.['effectiveMaxContext'];\n const providerMax = a.ctx.provider.capabilities.maxContext;\n return typeof metaLimit === 'number' && metaLimit > 0\n ? metaLimit\n : typeof providerMax === 'number' && providerMax > 0\n ? providerMax\n : 200_000;\n }\n\n let _lastEmittedMsgCount = -1;\n let _lastEmittedToolCount = -1;\n let _lastEmittedRevision = -1;\n let _lastEmittedMaxContext = -1;\n let _lastPreFlightMsgCount = -1;\n let _lastCompactionMsgCount = -1;\n let _lastCompactionRevision = -1;\n let _lastCompactionToolsRef: unknown = null;\n let _lastCompactionSystemRef: unknown = null;\n let _lastCompactionRequestTokens: number | undefined;\n let _lastCompactionMaxContext = -1;\n let _lastCompactionWasNoop = false;\n\n function foldBlockIntoConversation(block: TextBlock): void {\n if (!a.ctx.state.appendBlockToLastUserMessage(block)) {\n a.ctx.state.appendMessage({ role: 'user', content: [block] });\n }\n }\n\n function iterationFingerprint(blocks: ContentBlock[]): string {\n const toolUses = blocks.filter(isToolUseBlock);\n const texts = blocks.filter(isTextBlock);\n\n const toolNameSet = Array.from(new Set(toolUses.map((u) => u.name))).sort();\n const firstInputHash = toolUses[0] ? hashSmall(stableStringify(toolUses[0].input ?? {})) : '';\n const textBlob = texts\n .map((t) => t.text)\n .join('')\n .slice(0, 512);\n\n const hasContent = toolNameSet.length > 0 || textBlob.length > 0;\n if (!hasContent) return '__empty__';\n\n return [\n `tools=${toolNameSet.join('+') || '-'}`,\n `in0=${firstInputHash}`,\n `txt=${textBlob}`,\n ].join('\\n');\n }\n\n function stableStringify(value: unknown): string {\n return JSON.stringify(canonicalize(value));\n }\n\n function canonicalize(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(canonicalize);\n if (value && typeof value === 'object') {\n const src = value as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const k of Object.keys(src).sort()) out[k] = canonicalize(src[k]);\n return out;\n }\n return value;\n }\n\n function hashSmall(s: string): string {\n let h = 0x811c9dc5;\n for (let i = 0; i < s.length; i++) {\n h ^= s.charCodeAt(i);\n h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;\n }\n return h.toString(36);\n }\n\n function injectPendingBtwNotes(onMailboxBlock?: (block: TextBlock) => void): void {\n const notes = consumeBtwNotes(a.ctx);\n if (notes.length === 0) return;\n const mailboxNotes = notes.filter((note) => note.startsWith('[MAILBOX BTW]'));\n const regularNotes = notes.filter((note) => !note.startsWith('[MAILBOX BTW]'));\n if (regularNotes.length > 0) {\n foldBlockIntoConversation({ type: 'text', text: buildBtwBlock(regularNotes) });\n }\n if (mailboxNotes.length > 0) {\n const block: TextBlock = { type: 'text', text: buildBtwBlock(mailboxNotes) };\n foldBlockIntoConversation(block);\n onMailboxBlock?.(block);\n }\n }\n\n function injectQueueAwareness(): void {\n const items = consumeQueuedMessagesUpdate(a.ctx);\n if (!items) return;\n foldBlockIntoConversation({ type: 'text', text: buildQueuedMessagesBlock(items) });\n }\n\n async function checkIterationLimit(\n iterationIndex: number,\n limit: number,\n hasHardLimit: boolean,\n currentIterations: number,\n delegateSummaries: Array<{ summary: string; ok: boolean }>,\n ): Promise<{ limit: number; exit?: RunResult | undefined }> {\n if (hasHardLimit && iterationIndex >= limit) {\n const extendBy = await requestLimitExtension({\n events: a.events,\n sessionId: resolveEventSessionId(a.ctx),\n currentIterations,\n currentLimit: limit,\n autoExtend: a.autoExtendLimit,\n });\n if (extendBy > 0) {\n const newLimit = limit + extendBy;\n a.logger.info(`Iteration limit extended by ${extendBy} (new limit: ${newLimit})`);\n return { limit: newLimit };\n }\n return {\n limit,\n exit: { status: 'max_iterations', iterations: currentIterations, delegateSummaries },\n };\n }\n return { limit };\n }\n\n async function runInner(\n inputPayload: UserInputPayload,\n opts: RunOptions,\n controller: RunController,\n autonomousContinue: boolean,\n ): Promise<RunResult> {\n await a.pipelines.userInput.run(inputPayload);\n recordUserIntentEvidence(a.ctx, inputPayload.text);\n await a.ctx.session.append({\n type: 'user_input',\n ts: new Date().toISOString(),\n content: inputPayload.content,\n });\n a.ctx.state.appendMessage({ role: 'user', content: inputPayload.content });\n const promptIndex = a.ctx.messages.filter((m) => m.role === 'user').length - 1;\n const preview = inputPayload.text.slice(0, 80) + (inputPayload.text.length > 80 ? '\u2026' : '');\n await a.ctx.session.writeCheckpoint(promptIndex, preview);\n try {\n await a.ctx.flushConversationJournal();\n await a.ctx.session.flush();\n } catch (err) {\n (a.logger.debug ?? a.logger.warn)?.(`session boundary flush failed: ${toErrorMessage(err)}`);\n }\n\n let finalText = '';\n let iterations = 0;\n const delegateSummaries: Array<{ summary: string; ok: boolean }> = [];\n let effectiveLimit = opts.maxIterations ?? a.maxIterations;\n const hasHardLimit = effectiveLimit > 0 && Number.isFinite(effectiveLimit);\n let recoveryRetries = 0;\n const pendingMailboxBlocks: TextBlock[] = [];\n\n function clearEvaluatedMailboxBlocks(): void {\n if (pendingMailboxBlocks.length === 0) return;\n const cleaned = removeInjectedMailboxBlocks(a.ctx.messages, pendingMailboxBlocks);\n pendingMailboxBlocks.length = 0;\n if (cleaned.changed) {\n a.ctx.state.replaceMessages(cleaned.messages);\n a.ctx.lastRealInputTokens = undefined;\n delete a.ctx.meta['realAnchorMsgCount'];\n refreshContextRequestTokenStash({ force: true });\n }\n }\n\n const loopCfg = a.loopDetection;\n let lastToolSignature = '';\n let toolLoopCount = 0;\n let iterationSteerDone = false;\n const recentCallKeys: string[] = [];\n const steeredCallKeys = new Set<string>();\n let pendingLoopSteer: string | null = null;\n\n function queueLoopSteer(text: string): void {\n pendingLoopSteer = pendingLoopSteer ? `${pendingLoopSteer}\\n${text}` : text;\n }\n\n const onSubagentDone = ({ summary, ok }: { summary: string; ok: boolean }) => {\n delegateSummaries.push({ summary, ok });\n };\n const offSubagentDone = a.events.on('subagent.done', onSubagentDone);\n\n const diRunner = a.container.has(TOKENS.ProviderRunner)\n ? a.container.resolve(TOKENS.ProviderRunner)\n : null;\n const baseRunner = diRunner\n ? (ctx: typeof a.ctx, req: Request) =>\n diRunner.run({\n provider: providerBoundToRequest(req) ?? ctx.provider,\n request: req,\n signal: controller.signal,\n ctx,\n events: a.events,\n retry: a.retry,\n logger: a.logger,\n tracer: a.tracer,\n })\n : async (ctx: typeof a.ctx, req: Request) =>\n runProviderWithRetry({\n provider: providerBoundToRequest(req) ?? ctx.provider,\n request: req,\n signal: controller.signal,\n ctx,\n events: a.events,\n retry: a.retry,\n logger: a.logger,\n tracer: a.tracer,\n });\n\n const customRunner = a.extensions.wrapProviderRunner(baseRunner);\n\n try {\n for (let i = 0; ; i++) {\n iterations = i + 1;\n if (controller.signal.aborted) {\n return {\n status: 'aborted',\n iterations,\n abortReason: signalAbortReason(controller.signal),\n };\n }\n\n try {\n await a.ctx.session.writeInFlightMarker(`iteration ${i} / max ${a.maxIterations}`);\n await a.ctx.session.flush();\n } catch (err) {\n (a.logger.debug ?? a.logger.warn)?.(\n `in-flight marker write failed: ${toErrorMessage(err)}`,\n );\n }\n\n if (autonomousContinue) {\n consumeAutonomousContinue(a.ctx);\n }\n\n const limitCheck = await checkIterationLimit(\n i,\n effectiveLimit,\n hasHardLimit,\n iterations,\n delegateSummaries,\n );\n effectiveLimit = limitCheck.limit;\n if (limitCheck.exit) {\n return { ...limitCheck.exit, finalText };\n }\n\n await a.extensions.runBeforeIteration(a.ctx, i);\n a.events.emit('iteration.started', { sessionId: resolveEventSessionId(a.ctx), ctx: a.ctx, index: i });\n\n injectPendingBtwNotes((block) => pendingMailboxBlocks.push(block));\n injectQueueAwareness();\n\n if (pendingLoopSteer) {\n foldBlockIntoConversation({ type: 'text', text: pendingLoopSteer });\n pendingLoopSteer = null;\n }\n\n if (!backgroundCoordination() && (i % pulseEveryN === 1 || pulseEveryN === 1)) {\n try {\n const pulse = await getFleetPulse();\n if (pulse) foldBlockIntoConversation(pulse);\n } catch {}\n }\n\n const mailboxResult = await injectPendingMailboxMessages(\n checkMailbox,\n (block) => {\n foldBlockIntoConversation(block);\n pendingMailboxBlocks.push(block);\n },\n {\n events: {\n emit: (type, payload) => {\n a.events.emit(type as never, payload as never);\n },\n },\n logger: a.logger as never as { debug?: (...args: unknown[]) => void },\n },\n backgroundCoordination() ? 'background' : 'inline',\n );\n if (mailboxResult.interrupt) {\n const reason = `interrupted: ${mailboxResult.interruptReason ?? 'operator request'}`;\n return { status: 'aborted', iterations, abortReason: reason, finalText };\n }\n\n const {\n req,\n provider: requestProvider,\n preFlight,\n } = await buildRequestWithPreflightCompaction(opts);\n await a.ctx.session\n .append({\n type: 'llm_request',\n ts: new Date().toISOString(),\n model: req.model,\n messageCount: req.messages.length,\n estimatedInputTokens: preFlight.total,\n toolCount: (req.tools ?? []).length,\n })\n .catch(() => {});\n\n let res: Response;\n try {\n res = await customRunner(a.ctx, req);\n const key = calibrationKey(req.model);\n const cal = getCalibrationState(key);\n const calibratedTotal = cal.calibrated\n ? Math.round(preFlight.total * Math.min(1.5, Math.max(0.5, cal.ratio)))\n : preFlight.total;\n const realInputTokens = effectiveInputTokens(res.usage);\n recordActualUsage(realInputTokens, calibratedTotal, key);\n const previousRealInput = a.ctx.lastRealInputTokens;\n const previousAnchorMsgCount =\n typeof a.ctx.meta?.['realAnchorMsgCount'] === 'number'\n ? (a.ctx.meta['realAnchorMsgCount'] as number)\n : undefined;\n const anchorIsPlausible = realInputTokens >= calibratedTotal * 0.5;\n const anchorAdvanced =\n previousRealInput === undefined ||\n realInputTokens > previousRealInput ||\n (previousAnchorMsgCount !== undefined &&\n _lastPreFlightMsgCount < previousAnchorMsgCount);\n if (realInputTokens > 0 && anchorIsPlausible && anchorAdvanced) {\n a.ctx.lastRealInputTokens = realInputTokens;\n a.ctx.meta['realAnchorMsgCount'] = _lastPreFlightMsgCount;\n }\n recoveryRetries = 0;\n } catch (err) {\n if (controller.signal.aborted) {\n a.events.emit('error', {\n sessionId: resolveEventSessionId(a.ctx),\n err: toError(err),\n phase: 'provider',\n });\n return {\n status: 'aborted',\n iterations,\n error: toWrongStackError(err, 'AGENT_ABORTED'),\n abortReason: signalAbortReason(controller.signal),\n };\n }\n\n const extDecision = await a.extensions.runOnError(a.ctx, err, 'provider', i);\n if (extDecision) {\n if (extDecision.action === 'fail') {\n a.events.emit('error', {\n sessionId: resolveEventSessionId(a.ctx),\n err: toError(err),\n phase: 'provider',\n });\n return {\n status: 'failed',\n iterations,\n error: toWrongStackError(err),\n delegateSummaries,\n };\n }\n if (extDecision.action === 'continue') {\n await a.extensions.runAfterIteration(a.ctx, i);\n continue;\n }\n if (extDecision.action === 'retry') {\n recoveryRetries++;\n if (recoveryRetries > 2) {\n a.events.emit('error', {\n sessionId: resolveEventSessionId(a.ctx),\n err: toError(err),\n phase: 'provider',\n });\n return {\n status: 'failed',\n iterations,\n error: toWrongStackError(err),\n delegateSummaries,\n };\n }\n if (extDecision.model) a.ctx.model = extDecision.model;\n a.logger.info('Extension requested retry; retrying turn');\n continue;\n }\n }\n\n const recovered = await a.errorHandler.recover(err, a.ctx);\n if (!recovered || recovered.action === 'fail') {\n a.events.emit('error', {\n sessionId: resolveEventSessionId(a.ctx),\n err: toError(err),\n phase: 'provider',\n });\n return {\n status: 'failed',\n iterations,\n error: toWrongStackError(recovered?.error ?? err),\n delegateSummaries,\n };\n }\n if (recovered.action === 'retry') {\n recoveryRetries++;\n if (recoveryRetries > 2) {\n a.events.emit('error', {\n sessionId: resolveEventSessionId(a.ctx),\n err: toError(err),\n phase: 'provider',\n });\n return { status: 'failed', iterations, error: toWrongStackError(err) };\n }\n if (recovered.model) a.ctx.model = recovered.model;\n a.logger.info(`Recovered provider error via ${recovered.reason}; retrying turn`);\n continue;\n }\n recoveryRetries = 0;\n res = recovered.response;\n }\n\n clearEvaluatedMailboxBlocks();\n\n const responseResult = await handlers.response.processResponse(\n res,\n req,\n providerBoundToRequest(req) ?? requestProvider,\n );\n if (responseResult.aborted) {\n return {\n status: 'aborted',\n iterations,\n finalText: responseResult.finalText,\n delegateSummaries,\n abortReason: signalAbortReason(controller.signal),\n };\n }\n if (responseResult.done) {\n return {\n status: 'done',\n iterations,\n finalText: responseResult.finalText,\n delegateSummaries,\n };\n }\n\n finalText = responseResult.finalText;\n\n const toolUses = res.content.filter(isToolUseBlock);\n\n if (loopCfg.mode !== 'off') {\n const sig = iterationFingerprint(res.content);\n if (sig !== '__empty__') {\n if (sig === lastToolSignature) {\n toolLoopCount++;\n } else {\n lastToolSignature = sig;\n toolLoopCount = 1;\n iterationSteerDone = false;\n }\n\n const names = toolUses.map((t) => t.name).join(', ');\n const hasText = res.content.some(isTextBlock);\n const kind: 'tool' | 'message' | 'mixed' =\n toolUses.length > 0 && hasText ? 'mixed' : toolUses.length > 0 ? 'tool' : 'message';\n const observationRepeat =\n loopCfg.mode === 'steer-then-cut' &&\n toolUses.length > 0 &&\n toolUses.every((use) => {\n const tool = a.tools.get(use.name);\n return (\n tool?.mutating === false &&\n (tool.riskTier === 'safe' || (tool.capabilities?.length ?? 0) > 0)\n );\n });\n const repeatMultiplier = observationRepeat ? 2 : 1;\n const detail =\n kind === 'tool'\n ? `\"${names}\" called with effectively identical inputs ${toolLoopCount} times in a row`\n : kind === 'mixed'\n ? `\"${names}\" + same text repeated ${toolLoopCount} times in a row`\n : `same assistant text repeated ${toolLoopCount} times in a row`;\n\n const cutAt =\n (loopCfg.mode === 'cut' ? loopCfg.steerThreshold : loopCfg.cutThreshold) *\n repeatMultiplier;\n if (toolLoopCount >= cutAt) {\n a.logger.warn(`Loop detected: ${detail} \u2014 stopping to prevent infinite loop.`);\n a.events.emit('tool.loop_detected', {\n sessionId: resolveEventSessionId(a.ctx),\n ctx: a.ctx,\n tools: names,\n repeatCount: toolLoopCount,\n iteration: i,\n kind,\n action: 'cut',\n scope: 'iteration',\n });\n const summary =\n kind === 'message'\n ? `[Loop detected: same assistant message repeated ${toolLoopCount}\u00D7 \u2014 stopping to prevent infinite repetition.]`\n : `[Loop detected: ${detail} \u2014 stopping to prevent infinite repetition.]`;\n return {\n status: 'max_iterations',\n iterations,\n finalText: finalText || summary,\n delegateSummaries,\n };\n }\n\n if (\n loopCfg.mode === 'steer-then-cut' &&\n toolLoopCount >= loopCfg.steerThreshold * repeatMultiplier &&\n !iterationSteerDone\n ) {\n iterationSteerDone = true;\n a.logger.warn(`Loop detected: ${detail} \u2014 steering the model to change approach.`);\n a.events.emit('tool.loop_detected', {\n sessionId: resolveEventSessionId(a.ctx),\n ctx: a.ctx,\n tools: names,\n repeatCount: toolLoopCount,\n iteration: i,\n kind,\n action: 'steer',\n scope: 'iteration',\n });\n queueLoopSteer(\n `[loop-detector] Your last ${toolLoopCount} responses were effectively identical (${detail}). ` +\n 'This approach is not working. Change strategy: use a different tool, different arguments, ' +\n 'or a different plan \u2014 or explain what is blocking you and stop. ' +\n `Repeating the same response ${cutAt - toolLoopCount} more time(s) will terminate the turn.`,\n );\n }\n } else {\n lastToolSignature = '';\n toolLoopCount = 0;\n iterationSteerDone = false;\n }\n\n if (loopCfg.mode === 'steer-then-cut') {\n for (const u of toolUses) {\n const key = `${u.name}:${hashSmall(stableStringify(u.input ?? {}))}`;\n recentCallKeys.push(key);\n if (recentCallKeys.length > loopCfg.windowSize) recentCallKeys.shift();\n if (steeredCallKeys.has(key)) continue;\n let count = 0;\n for (const k of recentCallKeys) if (k === key) count++;\n const tool = a.tools.get(u.name);\n const observationThreshold =\n tool?.mutating === false &&\n (tool.riskTier === 'safe' || (tool.capabilities?.length ?? 0) > 0)\n ? loopCfg.callRepeatThreshold * 2\n : loopCfg.callRepeatThreshold;\n if (count < observationThreshold) continue;\n steeredCallKeys.add(key);\n const preview = JSON.stringify(u.input ?? {}).slice(0, 160);\n a.logger.warn(\n `Loop detected: \"${u.name}\" called with identical arguments ${count}\u00D7 within the last ${loopCfg.windowSize} tool calls \u2014 steering the model to change approach.`,\n );\n a.events.emit('tool.loop_detected', {\n sessionId: resolveEventSessionId(a.ctx),\n ctx: a.ctx,\n tools: u.name,\n repeatCount: count,\n iteration: i,\n kind: 'tool',\n action: 'steer',\n scope: 'call',\n });\n queueLoopSteer(\n `[loop-detector] You have called ${u.name}(${preview}) ${count} times with identical arguments ` +\n `within the last ${loopCfg.windowSize} tool calls. The result will not change. Do not repeat ` +\n 'this call \u2014 use what you already know, try a different approach, or explain the blocker.',\n );\n }\n }\n }\n\n if (toolUses.length === 0) {\n await compactContextIfNeeded();\n emitContextPct();\n a.events.emit('iteration.completed', {\n sessionId: resolveEventSessionId(a.ctx),\n ctx: a.ctx,\n index: i,\n });\n if (autonomousContinue && responseResult.directive === 'continue') {\n await a.extensions.runAfterIteration(a.ctx, i);\n continue;\n }\n if (autonomousContinue && responseResult.directive === 'stop') {\n return { status: 'done', iterations, finalText, delegateSummaries };\n }\n return { status: 'done', iterations, finalText, delegateSummaries };\n }\n\n try {\n await handlers.tools.executeTools(toolUses);\n } catch (toolErr) {\n if (controller.signal.aborted) {\n return {\n status: 'aborted',\n iterations,\n finalText,\n delegateSummaries,\n abortReason: signalAbortReason(controller.signal),\n };\n }\n throw toolErr;\n }\n\n if (autonomousContinue && consumeAutonomousContinue(a.ctx)) {\n await compactContextIfNeeded();\n emitContextPct();\n a.events.emit('iteration.completed', {\n sessionId: resolveEventSessionId(a.ctx),\n ctx: a.ctx,\n index: i,\n });\n await a.extensions.runAfterIteration(a.ctx, i);\n continue;\n }\n\n await compactContextIfNeeded();\n emitContextPct();\n a.events.emit('iteration.completed', { sessionId: resolveEventSessionId(a.ctx), ctx: a.ctx, index: i });\n await a.extensions.runAfterIteration(a.ctx, i);\n\n if (autonomousContinue && responseResult.directive === 'continue') {\n continue;\n }\n if (autonomousContinue && responseResult.directive === 'stop') {\n return { status: 'done', iterations, finalText, delegateSummaries };\n }\n }\n } finally {\n clearEvaluatedMailboxBlocks();\n offSubagentDone();\n const reason: 'clean' | 'aborted' = controller.signal.aborted ? 'aborted' : 'clean';\n try {\n await a.ctx.session.clearInFlightMarker(reason);\n await a.ctx.session.flush();\n } catch (err) {\n (a.logger.debug ?? a.logger.warn)?.(\n `in-flight marker clear failed: ${toErrorMessage(err)}`,\n );\n }\n }\n }\n\n return { runInner };\n}\n", "import { createHash } from 'node:crypto';\nimport type { TextBlock } from '../types/blocks.js';\n\nconst keyCache = new WeakMap<readonly TextBlock[], string>();\n\n/**\n * Derive a stable, provider-agnostic cache-partition key from a frozen\n * system-prompt epoch. Requests that share the same stable prefix produce the\n * same key, so provider backends route them to the same automatic-cache\n * partition \u2014 this is what OpenAI's `prompt_cache_key` (and Gemini implicit\n * routing) needs to actually hit the cache on load-balanced deployments.\n *\n * Keyed off the volatile-free `ctx.systemPrompt` epoch array (the per-turn\n * ledger/next-steps blocks are appended AFTER this array, so they never enter\n * the key). Cached by array identity in a WeakMap \u2014 the sha-256 runs once per\n * epoch (a new array = a new epoch, e.g. on mode switch), not per request.\n *\n * Anthropic ignores this field (it uses `ttl` + `cache_control` markers), so\n * setting it is harmless there; only the wires that read `req.cache.key` act on\n * it, gated by their own capability flags.\n */\nexport function deriveCachePrefixKey(systemPrompt: readonly TextBlock[]): string {\n const cached = keyCache.get(systemPrompt);\n if (cached !== undefined) return cached;\n const h = createHash('sha256');\n for (const block of systemPrompt) h.update(block.text).update('\u0000');\n // 128 bits of hex is ample collision resistance for a routing key and keeps\n // the value short enough for provider length limits (OpenAI caps at 128 chars).\n const key = `ws-${h.digest('hex').slice(0, 32)}`;\n keyCache.set(systemPrompt, key);\n return key;\n}\n", "import type { ContentBlock, ToolResultBlock, ToolUseBlock } from '../types/blocks.js';\nimport type { Message } from '../types/messages.js';\nimport { expectDefined } from './expect-defined.js';\nexport interface MessageRepairReport {\n changed: boolean;\n removedToolUses: string[];\n removedToolResults: string[];\n removedMessages: number;\n}\n\nexport interface MessageRepairResult {\n messages: Message[];\n report: MessageRepairReport;\n}\n\n/**\n * Repair provider-level tool-call adjacency invariants.\n *\n * Anthropic requires every assistant `tool_use` block to have a matching\n * `tool_result` block in the immediately following user message. Manual\n * context surgery (summary/prune) can cut through the middle of such an\n * exchange. This function removes only the now-orphaned protocol blocks,\n * preserving surrounding text/images/thinking blocks where possible.\n */\nexport function repairToolUseAdjacency(messages: Message[]): MessageRepairResult {\n const removedToolUses: string[] = [];\n const removedToolResults: string[] = [];\n let removedMessages = 0;\n let changed = false;\n const out: Message[] = [];\n\n for (let i = 0; i < messages.length; i++) {\n const original = expectDefined(messages[i]);\n let msg = original;\n\n if (hasToolUse(msg)) {\n const nextIds = toolResultIds(messages[i + 1]);\n const filtered = mapContent(msg, (blocks) => {\n const next: ContentBlock[] = [];\n for (const block of blocks) {\n if (block.type === 'tool_use' && !nextIds.has(block.id)) {\n removedToolUses.push(block.id);\n changed = true;\n continue;\n }\n next.push(block);\n }\n return next;\n });\n msg = filtered ?? msg;\n }\n\n if (hasToolResult(msg)) {\n const allowed = toolUseIds(out[out.length - 1]);\n const filtered = mapContent(msg, (blocks) => {\n const next: ContentBlock[] = [];\n for (const block of blocks) {\n if (block.type === 'tool_result' && !allowed.has(block.tool_use_id)) {\n removedToolResults.push(block.tool_use_id);\n changed = true;\n continue;\n }\n next.push(block);\n }\n return next;\n });\n msg = filtered ?? msg;\n }\n\n if (isEmptyMessage(msg)) {\n removedMessages++;\n changed = true;\n continue;\n }\n out.push(msg);\n }\n\n return {\n messages: changed ? out : messages,\n report: { changed, removedToolUses, removedToolResults, removedMessages },\n };\n}\n\nfunction hasToolUse(msg: Message | undefined): boolean {\n return contentBlocks(msg).some((b): b is ToolUseBlock => b.type === 'tool_use');\n}\n\nfunction hasToolResult(msg: Message | undefined): boolean {\n return contentBlocks(msg).some((b): b is ToolResultBlock => b.type === 'tool_result');\n}\n\nfunction toolUseIds(msg: Message | undefined): Set<string> {\n const ids = new Set<string>();\n if (msg?.role !== 'assistant') return ids;\n for (const block of contentBlocks(msg)) {\n if (block.type === 'tool_use') ids.add(block.id);\n }\n return ids;\n}\n\nfunction toolResultIds(msg: Message | undefined): Set<string> {\n const ids = new Set<string>();\n if (msg?.role !== 'user') return ids;\n for (const block of contentBlocks(msg)) {\n if (block.type === 'tool_result') ids.add(block.tool_use_id);\n }\n return ids;\n}\n\nfunction contentBlocks(msg: Message | undefined): ContentBlock[] {\n return msg && Array.isArray(msg.content) ? msg.content : [];\n}\n\nfunction mapContent(msg: Message, fn: (blocks: ContentBlock[]) => ContentBlock[]): Message | null {\n if (!Array.isArray(msg.content)) return msg;\n const next = fn(msg.content);\n if (next.length === msg.content.length && next.every((b, idx) => b === msg.content[idx])) {\n return msg;\n }\n return { ...msg, content: next };\n}\n\n/**\n * True when a message content payload carries meaningful information for\n * the provider: non-whitespace text, a tool call/result, thinking with\n * text or a signature, or any other block type.\n *\n * False for empty strings/arrays and for arrays whose only blocks are\n * empty or whitespace-only text \u2014 the shape persisted when a stream is\n * interrupted before the first meaningful delta (issue #271). Strict\n * providers reject such assistant turns, so repair and replay paths must\n * treat them as empty.\n */\nexport function hasMeaningfulContent(content: Message['content']): boolean {\n if (typeof content === 'string') return content.trim().length > 0;\n for (const block of content) {\n if (block.type === 'text') {\n if (block.text.trim().length > 0) return true;\n continue;\n }\n if (block.type === 'thinking') {\n // Signature-only thinking blocks are valid and required for replay;\n // blocks with neither text nor signature are provider-rejected noise.\n if (block.thinking.trim().length > 0 || block.signature) return true;\n continue;\n }\n // tool_use, tool_result, image, redacted_thinking, \u2026 \u2014 always meaningful.\n return true;\n }\n return false;\n}\n\nfunction isEmptyMessage(msg: Message): boolean {\n return !hasMeaningfulContent(msg.content);\n}\n", "/**\n * Response processing handler \u2014 extracted from Agent class.\n * Handles provider response pipeline, event emission, session\n * persistence, text rendering, and autonomous continuation parsing.\n */\n\nimport { isTextBlock, type TextBlock } from '../types/blocks.js';\nimport type { Provider, Request, Response } from '../types/provider.js';\nimport { deriveCachePrefixKey } from '../utils/cache-key.js';\nimport {\n buildCompletedWorkLedgerBlock,\n markAssistantReferencedEvidence,\n} from '../utils/context-evidence.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport { hasMeaningfulContent, repairToolUseAdjacency } from '../utils/message-invariants.js';\nimport type { AgentInternals } from './agent-internals.js';\nimport { type Context, resolveEventSessionId, type RunOptions } from './context.js';\nimport { type ContinueDirective, parseContinueDirective } from './continue-to-next-iteration.js';\nimport { bindRequestProvider } from './request-provider-binding.js';\n\ninterface ProcessResponseResult {\n finalText: string;\n aborted: boolean;\n done: boolean;\n directive?: ContinueDirective | undefined;\n}\n\nexport interface AgentResponseHandler {\n buildAndRunRequestPipeline(opts: RunOptions): Promise<{ request: Request; provider: Provider }>;\n processResponse(\n raw: Response,\n req: Request,\n requestProvider?: Provider,\n ): Promise<ProcessResponseResult>;\n}\n\nconst MAX_TODO_SNAPSHOT_ITEMS = 10;\nconst MAX_TODO_SNAPSHOT_CONTENT = 180;\n\n/**\n * Build the leader-only, per-request decision gate for `<nextsteps>`.\n *\n * The base system prompt is intentionally frozen for provider caching, while\n * todos change during tool execution. Keeping this block volatile makes the\n * final-response contract follow the live todo state on every iteration.\n */\nexport function buildLiveNextStepsGateBlock(\n ctx: Pick<Context, 'agentId' | 'todos'>,\n): TextBlock | undefined {\n if (ctx.agentId !== 'leader') return undefined;\n\n const openTodos = ctx.todos.filter(\n (todo) => todo.status === 'pending' || todo.status === 'in_progress',\n );\n\n if (openTodos.length === 0) {\n return {\n type: 'text',\n text: [\n '[nextsteps_gate]',\n 'Authoritative live state for this request: open todos = 0.',\n 'On the final response, you MUST take exactly one branch:',\n '1. If at least one genuinely useful follow-on action exists, include a balanced <nextsteps> block containing 1-4 exact prompt messages that can be submitted back to you through the current TUI or WebUI input.',\n 'Every item must ask the agent to perform work. Never put a human-only chore or an instruction addressed to the user inside <nextsteps>; natural-language agent-directed imperatives are valid and need not be shell commands.',\n '2. If no useful follow-on action truly exists, omit <nextsteps> and explicitly tell the user in normal prose that no further steps are needed for this task.',\n 'Silently omitting both is invalid. Do not decide by chance, tone, or response length, and do not invent filler suggestions.',\n '[/nextsteps_gate]',\n ].join('\\n'),\n cache_control: { type: 'ephemeral' },\n };\n }\n\n const todoSnapshot = openTodos.slice(0, MAX_TODO_SNAPSHOT_ITEMS).map((todo) => {\n const normalized = todo.content.replace(/\\s+/g, ' ').trim();\n const content =\n normalized.length > MAX_TODO_SNAPSHOT_CONTENT\n ? `${normalized.slice(0, MAX_TODO_SNAPSHOT_CONTENT - 1)}\u2026`\n : normalized;\n return `- [${todo.status}] ${content}`;\n });\n const omitted = openTodos.length - todoSnapshot.length;\n if (omitted > 0) todoSnapshot.push(`- \u2026and ${omitted} more open todo(s)`);\n\n return {\n type: 'text',\n text: [\n '[nextsteps_gate]',\n `Authoritative live state for this request: open todos = ${openTodos.length}.`,\n 'You MUST omit <nextsteps> entirely while these todos remain open. Continue or finish the tracked work; do not propose unrelated follow-on work.',\n 'Open todo snapshot:',\n ...todoSnapshot,\n '[/nextsteps_gate]',\n ].join('\\n'),\n cache_control: { type: 'ephemeral' },\n };\n}\n\nexport function createAgentResponseHandler(a: AgentInternals): AgentResponseHandler {\n // Each assigned prompt array is one explicit cache epoch. Freeze it at the\n // first request boundary so turn-time code cannot silently invalidate the\n // provider prefix by pushing/replacing blocks in place. Lifecycle actions\n // such as a mode switch may assign a new array, which becomes a new epoch.\n const stabilizedPromptEpochs = new WeakSet<TextBlock[]>();\n\n function stabilizePromptEpoch(): void {\n const prompt = a.ctx.systemPrompt;\n if (stabilizedPromptEpochs.has(prompt)) return;\n for (const block of prompt) {\n if (block.cache_control) Object.freeze(block.cache_control);\n Object.freeze(block);\n }\n Object.freeze(prompt);\n stabilizedPromptEpochs.add(prompt);\n }\n\n async function buildAndRunRequestPipeline(\n opts: RunOptions,\n ): Promise<{ request: Request; provider: Provider }> {\n // Only scan for tool-use adjacency issues when tool content has been\n // added since the last scan. Pure text responses and iterations without\n // tool calls don't introduce new adjacency problems \u2014 skipping the O(n)\n // message-array walk saves ~1-3ms per iteration on large contexts.\n if (a.ctx.toolAdjacencyDirty) {\n const repaired = repairToolUseAdjacency(a.ctx.messages);\n a.ctx.toolAdjacencyDirty = false;\n if (repaired.report.changed) {\n a.ctx.state.replaceMessages(repaired.messages);\n a.events.emit('context.repaired', {\n sessionId: resolveEventSessionId(a.ctx),\n ctx: a.ctx,\n ...repaired.report,\n });\n a.logger.warn(\n `Repaired context tool adjacency: removed ${repaired.report.removedToolUses.length} tool_use block(s), ` +\n `${repaired.report.removedToolResults.length} tool_result block(s), ` +\n `${repaired.report.removedMessages} empty message(s)`,\n );\n }\n }\n stabilizePromptEpoch();\n const volatileLedger = buildCompletedWorkLedgerBlock(a.ctx);\n const liveNextStepsGate = buildLiveNextStepsGateBlock(a.ctx);\n const volatileBlocks = [volatileLedger, liveNextStepsGate].filter(\n (block): block is TextBlock => block !== undefined,\n );\n const system =\n volatileBlocks.length > 0 ? [...a.ctx.systemPrompt, ...volatileBlocks] : a.ctx.systemPrompt;\n // A picker/WebUI switch can still be building a provider while\n // auto-continue prepares the next iteration. Wait immediately before\n // capturing the request identity so that iteration cannot retain the old\n // model by racing the switch.\n await a.ctx.waitForModelTransition();\n // Capture provider and model as one request identity. A live /model switch\n // may replace ctx.provider while the async request pipeline or provider\n // call is pending; this request must still finish under the identity it\n // started with.\n const provider = a.ctx.provider;\n const baseReq: Request = {\n model: opts.model ?? a.ctx.model,\n system,\n messages: a.ctx.messages,\n tools: a.tools.list(),\n // `maxTokens` is deliberately NOT set here. The provider adapter\n // resolves the ceiling from the catalog entry for the model in\n // `req.model`, which is the only source that stays correct across a\n // `/model` switch, a fallback hop, or a subagent on a model-matrix\n // entry \u2014 `provider.capabilities` is resolved once, for the model the\n // session booted on, and pinning it here would override the accurate\n // per-request value with a stale one. Callers that genuinely want a\n // smaller response (one-shot LLM helpers, compaction, the brain) still\n // set `maxTokens` on their own Request and keep priority over the\n // catalog.\n // Provider-agnostic cache-partition key from the stable prompt epoch.\n // Wires that support prompt caching (OpenAI `prompt_cache_key`) read it;\n // the config `ttl` is merged over this by the ModelRuntime middleware.\n cache: { key: deriveCachePrefixKey(a.ctx.systemPrompt) },\n };\n const request = await a.pipelines.request.run(baseReq);\n bindRequestProvider(request, provider);\n return { request, provider };\n }\n\n async function processResponse(\n raw: Response,\n req: Request,\n requestProvider: Provider = a.ctx.provider,\n ): Promise<ProcessResponseResult> {\n let res = raw;\n res = await a.pipelines.response.run(res);\n a.events.emit('provider.response', {\n sessionId: resolveEventSessionId(a.ctx),\n ctx: a.ctx,\n model: req.model,\n content: res.content,\n usage: res.usage,\n stopReason: res.stopReason,\n });\n a.ctx.tokenCounter.account(res.usage, req.model, requestProvider.id);\n\n // Issue #271: never append or persist a semantically empty assistant\n // response (e.g. a stream interrupted before the first meaningful delta,\n // which the response builders represent as a single empty text block).\n // Strict providers reject empty assistant turns on the next request, and\n // once journaled, the malformed turn survived every repair path. Partial\n // text, tool calls, and thinking content remain meaningful and are kept.\n if (hasMeaningfulContent(res.content)) {\n // Persist the semantic provider response before its exact-state\n // projection. The conversation journal drains independently, so state\n // mutation first can race `message_appended` ahead of `llm_response`.\n await a.ctx.session.append({\n type: 'llm_response',\n ts: new Date().toISOString(),\n content: res.content,\n stopReason: res.stopReason,\n usage: res.usage,\n });\n a.ctx.state.appendMessage({ role: 'assistant', content: res.content });\n // If the assistant emitted tool_use blocks, mark the message adjacency\n // as potentially needing repair before the next provider request.\n if (!a.ctx.toolAdjacencyDirty) {\n for (const block of res.content) {\n if (block.type === 'tool_use') {\n a.ctx.toolAdjacencyDirty = true;\n break;\n }\n }\n }\n // Tool execution is a side-effect boundary: ensure the response containing\n // its tool_use blocks has reached the session writer before any tool runs.\n // FileSessionWriter keeps failed batches queued for retry; alternate\n // writers may reject, which is logged without masking the provider result.\n try {\n await a.ctx.flushConversationJournal();\n await a.ctx.session.flush();\n } catch (err) {\n (a.logger.debug ?? a.logger.warn)?.(`LLM response flush failed: ${toErrorMessage(err)}`);\n }\n } else {\n a.logger.warn('Empty assistant response \u2014 not appended to context or session', {\n model: req.model,\n stopReason: res.stopReason,\n aborted: a.ctx.signal.aborted,\n });\n }\n\n if (a.ctx.signal.aborted) {\n // M3: collect into an array and join at the end. `finalText += block.text`\n // is O(n\u00B2) on V8 for many concatenations because each `+=` may allocate\n // a new backing string. For a typical 4-block response this is moot,\n // but the streaming-text path concatenates the *full* response in chunks\n // \u2014 and long autonomous loops with verbose reasoning can hit dozens of\n // chunks, making the cost visible. `Array.push` + single `join('')` is\n // amortized O(n).\n const parts: string[] = [];\n for (const block of res.content) {\n if (isTextBlock(block)) parts.push(block.text);\n }\n return { finalText: parts.join(''), aborted: true, done: false };\n }\n\n const parts: string[] = [];\n const streamed = requestProvider.capabilities.streaming;\n for (const block of res.content) {\n if (isTextBlock(block)) {\n const rendered = await a.pipelines.assistantOutput.run(block);\n parts.push(rendered.text);\n if (!streamed) a.renderer?.write(rendered);\n }\n }\n const finalText = parts.join('');\n markAssistantReferencedEvidence(a.ctx, finalText);\n\n let directive: ContinueDirective = 'none';\n if (finalText) {\n directive = parseContinueDirective(finalText);\n }\n\n return { finalText, aborted: false, done: false, directive };\n }\n\n return { buildAndRunRequestPipeline, processResponse };\n}\n", "/**\n * sage-output-block \u2014 split the SAGE Memory Injector suffix off a tool result.\n *\n * The SAGE middleware (`packages/sage/src/middleware/tool-call-memory.ts`)\n * appends a `--- SAGE: \u2026 (Memory Injector) ---` block to the tool result\n * content the model sees. That block is *memory*, not tool output, and every\n * surface renders it as its own card (TUI `SageMemoryBlock`, WebUI\n * `SageMemoryCard`).\n *\n * Surfaces used to recover the block by re-parsing the `tool.executed` event\n * `output` string \u2014 which is a ~400-char preview. When a tool's own output was\n * short (glob/grep/tree hits), the cut landed *inside* the appended memory\n * line: the `</memory>` fence was gone, the memory-line regex rejected the\n * candidate, and the whole block fell through to the plain tool-output\n * renderer. The result was raw `--- SAGE: \u2026 ---` text dumped into the chat.\n *\n * So the split happens HERE, at the emit site, before any truncation:\n * `tool.executed.output` carries tool text only and the block travels\n * separately in `tool.executed.sage`. Surfaces that don't know about SAGE show\n * clean tool output instead of leaking the block, and surfaces that do render\n * a card from structured lines instead of a regex over a truncated string.\n *\n * The headings and the memory-line shape mirror\n * `packages/tui/src/components/history/sage-output-format.ts` and\n * `packages/webui/src/lib/sage-block.ts`. Those two keep their own copies\n * because they also parse *replayed* sessions, where the block is still inline\n * in the persisted `tool_result` content. All three must agree.\n */\n\nexport interface SageOutputSplit {\n /** Tool result text with the SAGE block removed (trailing whitespace trimmed). */\n body: string;\n /**\n * The SAGE block including its `--- SAGE: \u2026` header line, or empty when the\n * input has no terminal SAGE suffix. Trailing blank lines are excluded.\n */\n sageLines: string[];\n}\n\n/** Exact heading lines emitted by `formatMemoryHintsDetailed()`. */\nexport const SAGE_INJECTOR_HEADINGS: ReadonlySet<string> = new Set([\n '--- SAGE: task-aware project knowledge (Memory Injector) ---',\n '--- SAGE: related project knowledge (Memory Injector) ---',\n]);\n\n/**\n * A complete memory line, as produced by `formatMemoryHintsDetailed()` in\n * `packages/sage/src/retrieval/format.ts`:\n *\n * `- [kind][priority] <memory id=\"\u2026\">escaped text</memory> (anchor) [relation=\u2026; tags=\u2026]`\n *\n * The `(anchor)` / `[relation=\u2026]` trailers are optional.\n */\nconst SAGE_MEMORY_LINE = /^- \\[[^\\]]+\\](?:\\[[^\\]]+\\])* <memory id=\"[^\"]+\">.*<\\/memory>(?: .*)?$/;\n\n/**\n * A memory line whose tail was cut by an upstream character cap (the `\u2026`\n * marker `truncateForEvent` and the fleet/HQ bridges append). Accepted only as\n * the LAST line of a candidate block: the `- [labels] <memory id=\"\u2026\">` prefix\n * is specific enough that no ordinary tool output produces it, so recognising\n * the fragment keeps a truncated block rendering as memory rather than\n * decaying into raw tool text. Anything after such a fragment disqualifies the\n * candidate, exactly as an unmatched line would.\n */\nconst SAGE_MEMORY_LINE_TRUNCATED = /^- \\[[^\\]]+\\](?:\\[[^\\]]+\\])* <memory id=\"[^\"]+\">.*\u2026$/;\n\n/**\n * Find the last SAGE suffix in `output` and split it away from the tool text.\n *\n * - Scans from the end, so a `--- SAGE:` string inside the tool body never\n * steals the real trailing block.\n * - Every non-blank line after the header must be a memory line (the last one\n * may be a truncated fragment); otherwise the candidate is rejected and the\n * header is treated as ordinary tool output.\n * - Trailing blank lines are tolerated but excluded from `sageLines`.\n */\nexport function splitSageOutputBlock(output: string): SageOutputSplit {\n if (!output.includes('--- SAGE: ')) return { body: output, sageLines: [] };\n const lines = output.split('\\n');\n for (let sageIdx = lines.length - 1; sageIdx >= 0; sageIdx--) {\n if (!SAGE_INJECTOR_HEADINGS.has(lines[sageIdx] ?? '')) continue;\n const candidate = lines.slice(sageIdx);\n if (candidate.length < 2) continue;\n const memoryLines = candidate.slice(1).filter((line) => line.trim().length > 0);\n if (memoryLines.length === 0) continue;\n const bodyOk = memoryLines.every(\n (line, index) =>\n SAGE_MEMORY_LINE.test(line) ||\n (index === memoryLines.length - 1 && SAGE_MEMORY_LINE_TRUNCATED.test(line)),\n );\n if (!bodyOk) continue;\n let end = candidate.length;\n while (end > 1 && candidate[end - 1]!.trim().length === 0) end--;\n return {\n body: lines.slice(0, sageIdx).join('\\n').trimEnd(),\n sageLines: candidate.slice(0, end),\n };\n }\n return { body: output, sageLines: [] };\n}\n\n/**\n * Trim a SAGE block to `maxChars` by dropping WHOLE memory lines from the end.\n *\n * Never slices inside a line: a half-line loses its `</memory>` fence and\n * every downstream parser would stop recognising the block \u2014 the exact failure\n * this module exists to prevent. Returns `[]` when not even the header plus one\n * memory line fits, since a header alone renders as an empty card.\n */\nexport function capSageLines(sageLines: readonly string[], maxChars: number): string[] {\n if (sageLines.length < 2) return [];\n const header = sageLines[0]!;\n if (header.length >= maxChars) return [];\n const out = [header];\n let used = header.length;\n for (const line of sageLines.slice(1)) {\n if (used + 1 + line.length > maxChars) break;\n out.push(line);\n used += 1 + line.length;\n }\n return out.length > 1 ? out : [];\n}\n", "/**\n * Tool output serialization utilities.\n * Extracted from Agent.executeTools to allow reuse and consistent output handling.\n */\n\nexport interface ToolOutputSerializerOptions {\n perIterationOutputCapBytes?: number | undefined;\n estimator?: ((text: string) => number) | undefined;\n}\n\nexport interface ToolOutputSerializeContext {\n toolName?: string | undefined;\n input?: unknown;\n /**\n * Optional reference to the Tool object. When present and the tool defines\n * a `serialize()` method, the serializer delegates to it instead of the\n * central `renderToolObject()` switch (P3 #21).\n */\n tool?: { serialize?: (output: unknown, input: unknown) => string } | undefined;\n}\n\ntype RecordValue = Record<string, unknown>;\n\nconst DEFAULT_LIST_LIMIT = 500;\nconst LOG_ENTRY_LIMIT = 200;\nconst INLINE_LIMIT = 240;\nconst GREP_FILE_LIMIT = 80;\nconst GREP_MATCHES_PER_FILE = 3;\nconst DIFF_INLINE_LINE_LIMIT = 260;\nconst DIFF_HUNK_LIMIT = 8;\nconst DIFF_HUNK_CONTEXT = 14;\n\n// Pre-compiled regex \u2014 used in parseGrepContentLine() for every grep match line.\n// Compiling once at module load avoids repeated RegExp construction overhead.\nconst GREP_LINE_RE = /^(.+?):(\\d+):(.*)$/;\n\nexport function createToolOutputSerializer(opts: ToolOutputSerializerOptions = {}) {\n const capBytes = opts.perIterationOutputCapBytes ?? 100_000;\n\n function serialize(value: unknown, context: ToolOutputSerializeContext = {}): string {\n if (typeof value === 'string') return value;\n if (value === null || value === undefined) return '';\n if (typeof value === 'object') {\n if (Array.isArray(value)) return value.map((item) => serialize(item)).join('\\n');\n // P3 #21 (before-release.md): prefer the tool's own serialize() method\n // when it defines one \u2014 lets tools own their output formatting without\n // adding a branch to the central renderToolObject() god function.\n if (context.tool?.serialize) {\n try {\n return context.tool.serialize(value, context.input);\n } catch {\n // Fall through to the central renderer if the tool's serializer\n // throws \u2014 never let a formatting error break the tool result.\n }\n }\n if (context.toolName) {\n const compact = renderToolObject(context.toolName, value as RecordValue, context.input);\n if (compact !== undefined) return compact;\n return renderGenericToolObject(context.toolName, value as RecordValue);\n }\n if ('text' in (value as Record<string, unknown>)) {\n const t = (value as Record<string, unknown>).text;\n return typeof t === 'string' ? t : JSON.stringify(value, null, 2);\n }\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n }\n return String(value);\n }\n\n function enforceCap(text: string, remainingBudget: number): { text: string; newBudget: number } {\n if (remainingBudget <= 0) {\n return { text: '[truncated: iteration output cap exceeded]', newBudget: 0 };\n }\n const textBytes = Buffer.byteLength(text, 'utf8');\n if (textBytes <= remainingBudget) {\n return { text, newBudget: remainingBudget - textBytes };\n }\n const marker = `\\n\u2026[truncated ${textBytes - remainingBudget} bytes]\u2026\\n`;\n const markerBytes = Buffer.byteLength(marker, 'utf8');\n const available = remainingBudget - markerBytes;\n if (available <= 0) {\n return { text: '[truncated: iteration output cap exceeded]', newBudget: 0 };\n }\n const half = Math.floor(available / 2);\n const first = text.slice(0, half);\n const second = text.slice(text.length - half);\n return { text: `${first}${marker}${second}`, newBudget: 0 };\n }\n\n return { serialize, enforceCap, capBytes };\n}\n\nfunction renderToolObject(toolName: string, obj: RecordValue, input: unknown): string | undefined {\n if (toolName === 'read' && typeof obj['text'] === 'string') {\n return joinSections([\n renderHeader(\n `read: ${stringFromInput(input, 'path') ?? stringField(obj, 'path') ?? '<unknown>'}`,\n {\n offset: numberFromInput(input, 'offset'),\n limit: numberFromInput(input, 'limit'),\n total_lines: obj['total_lines'],\n encoding: obj['encoding'],\n truncated: obj['truncated'],\n cached: obj['cached'],\n note: obj['note'],\n },\n ),\n obj['text'],\n ]);\n }\n\n if (toolName === 'grep' && Array.isArray(obj['matches'])) {\n const matches = stringArrayField(obj, 'matches');\n return joinSections([\n renderHeader(`grep: ${stringFromInput(input, 'pattern') ?? '<pattern>'}`, {\n path: stringFromInput(input, 'path'),\n glob: stringFromInput(input, 'glob'),\n mode: stringFromInput(input, 'output_mode'),\n count: obj['count'],\n shown: matches.length,\n truncated: obj['truncated'],\n used: obj['used'],\n }),\n renderGrepMatches(matches, stringFromInput(input, 'output_mode')),\n ]);\n }\n\n if (toolName === 'patch' && Array.isArray(obj['files'])) {\n const files = stringArrayField(obj, 'files');\n return joinSections([\n renderHeader('patch', {\n applied: obj['applied'],\n rejected: obj['rejected'],\n files: files.length,\n dry_run: obj['dry_run'],\n }),\n typeof obj['message'] === 'string' ? `message:\\n${obj['message']}` : undefined,\n files.length > 0 ? `files:\\n${renderStringList(files)}` : undefined,\n ]);\n }\n\n if (toolName === 'glob' && Array.isArray(obj['files'])) {\n const files = stringArrayField(obj, 'files');\n return joinSections([\n renderHeader(\n `${toolName}: ${stringFromInput(input, 'pattern') ?? stringFromInput(input, 'files') ?? stringFromInput(input, 'path') ?? ''}`.trim(),\n {\n path: stringFromInput(input, 'path'),\n files: files.length,\n truncated: obj['truncated'],\n },\n ),\n renderStringList(files, '(no files)'),\n ]);\n }\n\n if (toolName === 'tree' && typeof obj['tree'] === 'string') {\n return joinSections([\n renderHeader(\n `tree: ${stringField(obj, 'path') ?? stringFromInput(input, 'path') ?? '<cwd>'}`,\n {\n total_files: obj['total_files'],\n total_dirs: obj['total_dirs'],\n truncated: obj['truncated'],\n },\n ),\n obj['tree'],\n ]);\n }\n\n if (toolName === 'fetch' && typeof obj['content'] === 'string') {\n return joinSections([\n renderHeader(\n `fetch: ${stringField(obj, 'url') ?? stringFromInput(input, 'url') ?? '<url>'}`,\n {\n status: obj['status'],\n content_type: obj['content_type'],\n },\n ),\n obj['content'],\n ]);\n }\n\n if (toolName === 'replace' && Array.isArray(obj['results'])) {\n const results = obj['results'].filter(isRecord);\n const sections: Array<string | undefined> = [\n renderHeader('replace', {\n files_modified: obj['files_modified'],\n total_replacements: obj['total_replacements'],\n dry_run: obj['dry_run'],\n }),\n ];\n for (const r of results.slice(0, DEFAULT_LIST_LIMIT)) {\n sections.push(\n joinSections([\n renderHeader(`file: ${stringField(r, 'path') ?? '<unknown>'}`, {\n replacements: r['replacements'],\n }),\n typeof r['diff'] === 'string' ? r['diff'] : undefined,\n ]),\n );\n }\n if (results.length > DEFAULT_LIST_LIMIT) {\n sections.push(`[serializer omitted ${results.length - DEFAULT_LIST_LIMIT} result item(s)]`);\n }\n return joinSections(sections);\n }\n\n if (typeof obj['diff'] === 'string') {\n const diff = obj['diff'];\n // matched_by: 'exact' is the default and carries no information \u2014 only\n // surface the field when a fallback tier actually fired.\n const matchedBy =\n typeof obj['matched_by'] === 'string' && obj['matched_by'] !== 'exact'\n ? obj['matched_by']\n : undefined;\n const syntaxErrors = Array.isArray(obj['syntax_errors'])\n ? obj['syntax_errors'].filter((e): e is string => typeof e === 'string')\n : [];\n return joinSections([\n renderHeader(toolName, {\n path: obj['path'],\n replacements: obj['replacements'],\n bytes_written: obj['bytes_written'],\n created: obj['created'],\n matched_by: matchedBy,\n note: obj['note'],\n files: Array.isArray(obj['files']) ? obj['files'].length : undefined,\n truncated: obj['truncated'],\n mode: obj['mode'],\n }),\n compactDiff(diff),\n syntaxErrors.length > 0 ? `syntax_errors:\\n${renderStringList(syntaxErrors)}` : undefined,\n ]);\n }\n\n if (toolName === 'test' && typeof obj['output'] === 'string') {\n return renderTestOutput(obj, input);\n }\n\n if (\n (toolName === 'typecheck' || toolName === 'lint' || toolName === 'format') &&\n typeof obj['output'] === 'string'\n ) {\n return renderVerifierOutput(toolName, obj, input);\n }\n\n if (hasCommandOutputShape(obj)) {\n return renderCommandOutput(toolName, obj, input);\n }\n\n if (toolName === 'json' && typeof obj['formatted'] === 'string') {\n return joinSections([\n renderHeader('json', {\n type: obj['type'],\n keys: Array.isArray(obj['keys']) ? obj['keys'].length : undefined,\n query: stringFromInput(input, 'query'),\n error: obj['error'],\n }),\n obj['formatted'],\n ]);\n }\n\n if (toolName === 'logs' && Array.isArray(obj['entries'])) {\n const entries = obj['entries'].filter(isRecord);\n const lines = entries.slice(0, LOG_ENTRY_LIMIT).map((entry) => {\n const ts = stringField(entry, 'timestamp') ?? '';\n const level = stringField(entry, 'level') ?? 'info';\n const message = stringField(entry, 'message') ?? '';\n const source = stringField(entry, 'source');\n return [ts, level, source, message].filter(Boolean).join(' ');\n });\n if (entries.length > LOG_ENTRY_LIMIT) {\n lines.push(`[serializer omitted ${entries.length - LOG_ENTRY_LIMIT} log entry item(s)]`);\n }\n return joinSections([\n renderHeader(`logs: ${stringField(obj, 'source') ?? '<source>'}`, {\n total: obj['total'],\n shown: Math.min(entries.length, LOG_ENTRY_LIMIT),\n truncated: obj['truncated'],\n stream_mode: obj['stream_mode'],\n }),\n lines.length > 0 ? lines.join('\\n') : '(no log entries)',\n ]);\n }\n\n if (toolName === 'audit' && Array.isArray(obj['vulnerabilities'])) {\n const vulns = obj['vulnerabilities'].filter(isRecord);\n const lines = vulns.slice(0, DEFAULT_LIST_LIMIT).map((v) => {\n const severity = stringField(v, 'severity') ?? 'unknown';\n const pkg = stringField(v, 'package') ?? '<package>';\n const title = stringField(v, 'title') ?? '';\n const url = stringField(v, 'url');\n return [severity, pkg, title, url].filter(Boolean).join(' | ');\n });\n if (vulns.length > DEFAULT_LIST_LIMIT) {\n lines.push(`[serializer omitted ${vulns.length - DEFAULT_LIST_LIMIT} vulnerability item(s)]`);\n }\n return joinSections([\n renderHeader('audit', {\n exit_code: obj['exit_code'],\n total: obj['total'],\n summary: obj['summary'],\n truncated: obj['truncated'],\n }),\n lines.length > 0 ? lines.join('\\n') : stringField(obj, 'output'),\n ]);\n }\n\n if (toolName === 'outdated' && Array.isArray(obj['packages'])) {\n const packages = obj['packages'].filter(isRecord);\n const lines = packages\n .slice(0, DEFAULT_LIST_LIMIT)\n .map((p) =>\n [\n stringField(p, 'name') ?? '<package>',\n `current=${stringField(p, 'current') ?? 'unknown'}`,\n `wanted=${stringField(p, 'wanted') ?? 'unknown'}`,\n `latest=${stringField(p, 'latest') ?? 'unknown'}`,\n stringField(p, 'type'),\n ]\n .filter(Boolean)\n .join(' | '),\n );\n if (packages.length > DEFAULT_LIST_LIMIT) {\n lines.push(`[serializer omitted ${packages.length - DEFAULT_LIST_LIMIT} package item(s)]`);\n }\n return joinSections([\n renderHeader('outdated', {\n exit_code: obj['exit_code'],\n total: obj['total'],\n truncated: obj['truncated'],\n }),\n lines.length > 0 ? lines.join('\\n') : stringField(obj, 'output'),\n ]);\n }\n\n return undefined;\n}\n\nfunction renderTestOutput(obj: RecordValue, input: unknown): string {\n const exitCode = numberField(obj, 'exit_code') ?? 0;\n const failed = numberField(obj, 'failed') ?? 0;\n const output = stringField(obj, 'output') ?? '';\n const header = renderHeader(`test: ${stringField(obj, 'runner') ?? 'runner'}`, {\n exit_code: obj['exit_code'],\n tests_run: obj['tests_run'],\n passed: obj['passed'],\n failed: obj['failed'],\n duration_ms: obj['duration_ms'],\n truncated: obj['truncated'],\n files: inputListSummary(input, 'files'),\n grep: stringFromInput(input, 'grep'),\n });\n\n if (exitCode === 0 && failed === 0) {\n return joinSections([\n header,\n joinSections([\n 'report:',\n `status=passed`,\n `tests_run=${obj['tests_run'] ?? 0}`,\n `passed=${obj['passed'] ?? 0}`,\n `failed=${obj['failed'] ?? 0}`,\n `duration_ms=${obj['duration_ms'] ?? 0}`,\n extractSpoolNote(output),\n ]),\n ]);\n }\n\n return joinSections([\n header,\n `error_context:\\n${compactFailureOutput(output || '(no runner output)')}`,\n ]);\n}\n\nfunction renderVerifierOutput(toolName: string, obj: RecordValue, input: unknown): string {\n const exitCode = numberField(obj, 'exit_code') ?? 0;\n const errors = numberField(obj, 'errors') ?? 0;\n const warnings = numberField(obj, 'warnings') ?? 0;\n const output = stringField(obj, 'output') ?? '';\n const changed = numberField(obj, 'files_changed') ?? 0;\n const header = renderHeader(toolName, {\n exit_code: obj['exit_code'],\n errors: obj['errors'],\n warnings: obj['warnings'],\n files_checked: obj['files_checked'],\n files_changed: obj['files_changed'],\n fix_applied: obj['fix_applied'],\n fixer: obj['fixer'],\n linter: obj['linter'],\n project: obj['project'],\n truncated: obj['truncated'],\n files: inputListSummary(input, 'files'),\n cwd: stringFromInput(input, 'cwd'),\n });\n\n if (exitCode === 0 && errors === 0 && (toolName !== 'format' || changed === 0)) {\n return joinSections([\n header,\n joinSections([\n 'report:',\n 'status=passed',\n `errors=${errors}`,\n `warnings=${warnings}`,\n toolName === 'format' ? `files_changed=${changed}` : undefined,\n extractSpoolNote(output),\n ]),\n ]);\n }\n\n if (exitCode === 0 && toolName === 'format') {\n return joinSections([\n header,\n joinSections([\n 'report:',\n 'status=changed',\n `files_changed=${changed}`,\n extractSpoolNote(output),\n ]),\n ]);\n }\n\n return joinSections([\n header,\n `error_context:\\n${compactFailureOutput(output || '(no verifier output)')}`,\n ]);\n}\n\nfunction renderGrepMatches(matches: string[], mode: string | undefined): string {\n if (matches.length === 0) return '(no matches)';\n if (mode === 'files_with_matches') return renderStringList(matches, '(no files)');\n if (mode === 'count') return renderStringList(matches, '(no counts)');\n\n const groups = new Map<string, string[]>();\n const passthrough: string[] = [];\n for (const match of matches) {\n const parsed = parseGrepContentLine(match);\n if (!parsed) {\n passthrough.push(match);\n continue;\n }\n const list = groups.get(parsed.file) ?? [];\n list.push(`${parsed.line}:${parsed.text}`);\n groups.set(parsed.file, list);\n }\n\n if (groups.size === 0) return renderStringList(matches, '(no matches)');\n\n const sections: string[] = [];\n let fileIndex = 0;\n for (const [file, lines] of groups) {\n fileIndex++;\n if (fileIndex > GREP_FILE_LIMIT) break;\n const shown = lines.slice(0, GREP_MATCHES_PER_FILE);\n sections.push(\n `${file} (${lines.length} match(es), showing ${shown.length})\\n${shown.join('\\n')}`,\n );\n }\n if (groups.size > GREP_FILE_LIMIT) {\n sections.push(`[serializer omitted ${groups.size - GREP_FILE_LIMIT} file group(s)]`);\n }\n if (passthrough.length > 0) {\n sections.push(`ungrouped:\\n${renderStringList(passthrough, '', 50)}`);\n }\n return sections.join('\\n');\n}\n\nfunction parseGrepContentLine(\n line: string,\n): { file: string; line: string; text: string } | undefined {\n const match = GREP_LINE_RE.exec(line);\n if (!match?.[1] || !match[2]) return undefined;\n return { file: match[1], line: match[2], text: match[3] ?? '' };\n}\n\nfunction compactDiff(diff: string): string {\n const lines = diff.split(/\\r?\\n/);\n if (lines.length <= DIFF_INLINE_LINE_LIMIT) return diff;\n\n const fileCount = Math.max(\n new Set(\n lines\n .map(\n (line) => /^diff --git\\s+a\\/(.+?)\\s+b\\//.exec(line)?.[1] ?? /^---\\s+(.+)/.exec(line)?.[1],\n )\n .filter(Boolean),\n ).size,\n 0,\n );\n const hunks = lines.filter((line) => line.startsWith('@@')).length;\n const added = lines.filter((line) => line.startsWith('+') && !line.startsWith('+++')).length;\n const removed = lines.filter((line) => line.startsWith('-') && !line.startsWith('---')).length;\n\n // Collect [start, end] intervals as we scan lines sequentially.\n // Intervals are naturally ordered by line index \u2014 no sort needed.\n const intervals: Array<[number, number]> = [];\n let hunkCount = 0;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? '';\n if (line.startsWith('diff --git') || line.startsWith('--- ') || line.startsWith('+++ ')) {\n intervals.push([i, i]);\n continue;\n }\n if (!line.startsWith('@@')) continue;\n if (hunkCount >= DIFF_HUNK_LIMIT) continue;\n hunkCount++;\n intervals.push([i, Math.min(lines.length - 1, i + DIFF_HUNK_CONTEXT)]);\n }\n\n if (intervals.length === 0) {\n return joinSections([\n renderHeader('diff_summary', {\n files: fileCount,\n hunks,\n added,\n removed,\n lines: lines.length,\n }),\n lines.slice(0, DIFF_INLINE_LINE_LIMIT).join('\\n'),\n `[serializer omitted ${Math.max(0, lines.length - DIFF_INLINE_LINE_LIMIT)} diff line(s)]`,\n ]);\n }\n\n // Merge overlapping / adjacent intervals in a single O(n) pass.\n // Intervals are already in ascending order from the sequential scan.\n const merged: Array<[number, number]> = [intervals[0]!];\n for (let i = 1; i < intervals.length; i++) {\n const last = merged[merged.length - 1]!;\n const current = intervals[i]!;\n if (current[0] <= last[1] + 1) {\n last[1] = Math.max(last[1], current[1]);\n } else {\n merged.push(current);\n }\n }\n\n // Build excerpt from merged intervals \u2014 O(n), no sort.\n const excerpt: string[] = [];\n let prevLine = -1;\n for (const [start, end] of merged) {\n if (start > prevLine + 1) {\n const omitted = prevLine === -1 ? start : start - prevLine - 1;\n excerpt.push(`[serializer omitted ${omitted} diff line(s)]`);\n }\n for (let j = start; j <= end; j++) {\n excerpt.push(lines[j] ?? '');\n }\n prevLine = end;\n }\n\n const trailing = lines.length - prevLine - 1;\n if (trailing > 0) excerpt.push(`[serializer omitted ${trailing} trailing diff line(s)]`);\n\n return joinSections([\n renderHeader('diff_summary', {\n files: fileCount,\n hunks,\n shown_hunks: Math.min(hunks, DIFF_HUNK_LIMIT),\n added,\n removed,\n lines: lines.length,\n }),\n excerpt.join('\\n'),\n ]);\n}\n\nfunction compactFailureOutput(output: string): string {\n const lines = output.split(/\\r?\\n/);\n if (lines.length <= 260) return output.trimEnd();\n\n const selected = new Set<number>();\n const marker =\n /\\b(fail|failed|failure|error|exception|assertionerror|expected|received|actual|timeout|stack)\\b/i;\n let markerHits = 0;\n for (let i = 0; i < lines.length; i++) {\n if (!marker.test(lines[i] ?? '')) continue;\n markerHits++;\n for (let j = Math.max(0, i - 4); j <= Math.min(lines.length - 1, i + 10); j++) {\n selected.add(j);\n }\n }\n\n if (markerHits === 0) {\n return lines.slice(-220).join('\\n').trimEnd();\n }\n\n const ordered = [...selected].sort((a, b) => a - b);\n const out: string[] = [];\n let previous = -1;\n for (const index of ordered) {\n if (index > previous + 1) {\n const omitted = previous === -1 ? index : index - previous - 1;\n out.push(`[serializer omitted ${omitted} line(s)]`);\n }\n out.push(lines[index] ?? '');\n previous = index;\n }\n return out.join('\\n').trimEnd();\n}\n\nfunction extractSpoolNote(output: string): string | undefined {\n return output\n .split(/\\r?\\n/)\n .find((line) => line.startsWith('[output truncated') && line.includes('full'));\n}\n\nfunction hasCommandOutputShape(obj: RecordValue): boolean {\n return (\n typeof obj['stdout'] === 'string' ||\n typeof obj['stderr'] === 'string' ||\n typeof obj['output'] === 'string' ||\n typeof obj['exitCode'] === 'number' ||\n typeof obj['exit_code'] === 'number'\n );\n}\n\nfunction renderCommandOutput(toolName: string, obj: RecordValue, input: unknown): string {\n const command = stringField(obj, 'command') ?? stringFromInput(input, 'command');\n const args = stringArrayField(obj, 'args');\n const commandLine = command ? [command, ...args].join(' ') : undefined;\n const output = stringField(obj, 'output');\n const stdout = stringField(obj, 'stdout');\n const stderr = stringField(obj, 'stderr');\n return joinSections([\n renderHeader(commandLine ? `${toolName}: ${commandLine}` : toolName, {\n exit_code: obj['exit_code'] ?? obj['exitCode'],\n timed_out: obj['timed_out'],\n pid: obj['pid'],\n allowed: obj['allowed'],\n truncated: obj['truncated'],\n runner: obj['runner'],\n linter: obj['linter'],\n fixer: obj['fixer'],\n project: obj['project'],\n tests_run: obj['tests_run'],\n passed: obj['passed'],\n failed: obj['failed'],\n duration_ms: obj['duration_ms'],\n errors: obj['errors'],\n warnings: obj['warnings'],\n files_checked: obj['files_checked'],\n files_changed: obj['files_changed'],\n fix_applied: obj['fix_applied'],\n }),\n stringField(obj, 'error') ? `error:\\n${stringField(obj, 'error')}` : undefined,\n output ? `output:\\n${output}` : undefined,\n stdout ? `stdout:\\n${stdout}` : undefined,\n stderr ? `stderr:\\n${stderr}` : undefined,\n ]);\n}\n\nfunction renderGenericToolObject(toolName: string, obj: RecordValue): string {\n const scalars: RecordValue = {};\n const blocks: string[] = [];\n for (const [key, value] of Object.entries(obj)) {\n if (value === undefined) continue;\n if (isScalar(value)) {\n const inline = String(value);\n if (inline.length <= INLINE_LIMIT && !inline.includes('\\n')) {\n scalars[key] = value;\n } else {\n blocks.push(`${key}:\\n${inline}`);\n }\n continue;\n }\n if (Array.isArray(value)) {\n if (value.every((item) => typeof item === 'string')) {\n blocks.push(`${key}:\\n${renderStringList(value as string[])}`);\n } else {\n blocks.push(`${key}:\\n${renderUnknownList(value)}`);\n }\n continue;\n }\n blocks.push(`${key}: ${clipInline(oneLineJson(value))}`);\n }\n return joinSections([renderHeader(toolName, scalars), ...blocks]);\n}\n\nfunction renderHeader(label: string, fields: RecordValue): string {\n const parts = Object.entries(fields)\n .filter(([, value]) => value !== undefined && value !== null && value !== '')\n .map(([key, value]) => `${key}=${clipInline(formatInlineValue(value))}`);\n return parts.length > 0 ? `${label} (${parts.join(' ')})` : label;\n}\n\nfunction renderStringList(items: string[], empty = '', limit = DEFAULT_LIST_LIMIT): string {\n if (items.length === 0) return empty;\n const shown = items.slice(0, limit);\n const omitted = items.length - shown.length;\n return [\n ...shown,\n ...(omitted > 0\n ? [`[serializer omitted ${omitted} item(s); narrow the request for more]`]\n : []),\n ].join('\\n');\n}\n\nfunction renderUnknownList(items: unknown[], limit = DEFAULT_LIST_LIMIT): string {\n const shown = items.slice(0, limit).map((item) => clipInline(oneLineJson(item), 1_000));\n const omitted = items.length - shown.length;\n if (omitted > 0)\n shown.push(`[serializer omitted ${omitted} item(s); narrow the request for more]`);\n return shown.join('\\n');\n}\n\nfunction joinSections(sections: Array<string | undefined>): string {\n return sections\n .map((section) => (typeof section === 'string' ? section.trimEnd() : undefined))\n .filter((section): section is string => !!section)\n .join('\\n');\n}\n\nfunction formatInlineValue(value: unknown): string {\n /* v8 ignore next -- no renderHeader field is ever an array (all callers pass scalars) */\n if (Array.isArray(value)) return `[${value.map(formatInlineValue).join(',')}]`;\n if (isScalar(value)) return String(value);\n return oneLineJson(value);\n}\n\nfunction clipInline(value: string, max = INLINE_LIMIT): string {\n const compact = value.replace(/\\s+/g, ' ').trim();\n return compact.length <= max\n ? compact\n : `${compact.slice(0, max - 15)}...(${compact.length} chars)`;\n}\n\nfunction oneLineJson(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nfunction stringField(obj: RecordValue, key: string): string | undefined {\n const value = obj[key];\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction numberField(obj: RecordValue, key: string): number | undefined {\n const value = obj[key];\n return typeof value === 'number' ? value : undefined;\n}\n\nfunction stringArrayField(obj: RecordValue, key: string): string[] {\n const value = obj[key];\n return Array.isArray(value)\n ? value.filter((item): item is string => typeof item === 'string')\n : [];\n}\n\nfunction stringFromInput(input: unknown, key: string): string | undefined {\n if (!isRecord(input)) return undefined;\n const value = input[key];\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction numberFromInput(input: unknown, key: string): number | undefined {\n if (!isRecord(input)) return undefined;\n const value = input[key];\n return typeof value === 'number' ? value : undefined;\n}\n\nfunction inputListSummary(input: unknown, key: string): string | undefined {\n if (!isRecord(input)) return undefined;\n const value = input[key];\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) return value.filter((item) => typeof item === 'string').join(',');\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is RecordValue {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isScalar(value: unknown): value is string | number | boolean | null {\n return value === null || ['string', 'number', 'boolean'].includes(typeof value);\n}\n\n/**\n * Render a tool result body for inclusion in the `tool.executed` event.\n * Tool outputs can be large (file dumps, command output); UIs only want a\n * preview line, so cap at ~400 chars with an ellipsis marker.\n */\nexport function truncateForEvent(content: string, max = 400): string {\n if (!content) return '';\n return content.length <= max ? content : `${content.slice(0, max - 1)}\u2026`;\n}\n\n/**\n * Derive size signals (bytes / tokens / lines) for the chip rendered beside\n * each tool result. Computed once over the FULL `content` BEFORE the\n * 400-char event preview is taken.\n *\n * - bytes: UTF-8 byte length (multi-byte aware).\n * - tokens: standard ~3.5 chars/token heuristic.\n * - lines: read prefixes lines with `<n>\u2192`; for shell/grep/logs we fall\n * back to a newline count. Undefined for tools without a line notion.\n */\nconst READ_LINE_PREFIX_RE = /^\\s*\\d+\u2192/gm;\n\nexport function sizeSignals(\n toolName: string | undefined,\n content: string,\n): { outputBytes: number; outputTokens: number; outputLines: number | undefined } {\n if (!content || content.length === 0) {\n return { outputBytes: 0, outputTokens: 0, outputLines: undefined };\n }\n const outputBytes = Buffer.byteLength(content, 'utf8');\n const outputTokens = Math.max(1, Math.round(outputBytes / 3.5));\n let outputLines: number | undefined;\n if (toolName === 'read') {\n READ_LINE_PREFIX_RE.lastIndex = 0;\n let count = 0;\n while (READ_LINE_PREFIX_RE.exec(content) !== null) count++;\n if (count > 0) outputLines = count;\n } else if (\n toolName === 'bash' ||\n toolName === 'shell' ||\n toolName === 'grep' ||\n toolName === 'logs'\n ) {\n let nl = 0;\n for (let i = 0; i < content.length; i++) if (content.charCodeAt(i) === 10) nl++;\n outputLines = nl + (content.endsWith('\\n') ? 0 : 1);\n }\n return { outputBytes, outputTokens, outputLines };\n}\n", "/**\n * Tool execution handler \u2014 extracted from Agent class for testability.\n * Handles batch tool execution, confirmation flow, and post-execution\n * pipeline/session/event emission.\n */\nimport type { ContentBlock, ToolResultBlock, ToolUseBlock } from '../types/blocks.js';\nimport type { SessionEvent } from '../types/session.js';\nimport type { Tool } from '../types/tool.js';\nimport { recordToolOutputEvidence } from '../utils/context-evidence.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport { capSageLines, splitSageOutputBlock } from '../utils/sage-output-block.js';\nimport { sizeSignals, truncateForEvent } from '../utils/tool-output-serializer.js';\nimport type { AgentInternals } from './agent-internals.js';\nimport { resolveEventSessionId } from './context.js';\n\n/**\n * Tools whose serialized output is a unified diff that UIs render as a\n * colored diff block (TUI `DiffBlock`, WebUI `DiffView`). The default\n * 400-char event-preview cap slices the last visible diff line mid-word\n * (a stray `\u2026`), so these tools get a much larger budget. The serializer\n * already compacts large diffs (\u2264260 lines via `compactDiff`) and the\n * renderers cap the number of visible rows, so this only needs to be big\n * enough that the shown hunk survives intact.\n */\nconst DIFF_TOOL_NAMES = new Set(['edit', 'write', 'replace', 'patch', 'diff']);\nconst DIFF_TOOL_EVENT_PREVIEW_MAX = 16_000;\n\n/**\n * Budget for the SAGE memory block travelling in `tool.executed.sage`. It is\n * kept OUT of the `output` preview budget on purpose: the block is memory, not\n * tool output, and sharing one cap is what used to cut a memory line in half\n * and leak the fragment into the tool body (see `utils/sage-output-block.ts`).\n * The injector itself caps a block at 2800 chars, so this only trims the\n * largest blocks \u2014 always by whole memory lines.\n */\nconst SAGE_EVENT_MAX = 2_000;\n\nexport interface AgentToolHandler {\n executeTools(toolUses: ToolUseBlock[]): Promise<ToolResultBlock[]>;\n executeSingleWithDecision(\n tool: Tool,\n use: { id: string; name: string; input: unknown },\n ): Promise<{ result: ToolResultBlock; durationMs: number }>;\n}\n\nexport function createAgentToolHandler(a: AgentInternals): AgentToolHandler {\n async function executeSingleWithDecision(\n tool: Tool,\n use: { id: string; name: string; input: unknown },\n ): Promise<{ result: ToolResultBlock; durationMs: number }> {\n const start = Date.now();\n try {\n // The provider always sends properly typed tool_use blocks through\n // JSON deserialization. The executor needs the `type: 'tool_use'`\n // discriminant and `input: Record<string, unknown>`, so we construct\n // the full shape explicitly rather than using a blind `as ToolUseBlock`\n // cast that would silence a missing `type` field.\n const result = await a.toolExecutor.executeTool(\n tool,\n {\n type: 'tool_use' as const,\n id: use.id,\n name: use.name,\n input: use.input as Record<string, unknown>,\n },\n a.ctx,\n a.perIterationOutputCapBytes,\n );\n // H2: `result` is now { block, bytes }. The executeTools caller\n // gets the block; the `bytes` field is for budget accounting\n // (caller of *this* function already has the budget, so we\n // surface `block` only here and let it handle the bytes).\n return { result: result.block, durationMs: Date.now() - start };\n } catch (err) {\n const msg = toErrorMessage(err);\n return {\n result: {\n type: 'tool_result',\n tool_use_id: use.id,\n content: `Tool \"${tool.name}\" threw: ${msg}`,\n is_error: true,\n },\n durationMs: Date.now() - start,\n };\n }\n }\n\n function waitForConfirm(info: {\n tool: Tool;\n input: unknown;\n toolUseId: string;\n suggestedPattern: string;\n decisionSource?: import('../types/permission.js').PermissionDecision['source'] | undefined;\n riskTier?: import('../types/tool.js').RiskTier | undefined;\n boundaryReason?: string | undefined;\n }): Promise<'yes' | 'no' | 'always' | 'deny' | 'abort'> {\n // Headless deadlock guard (P1 #4, before-release.md): if no UI layer has\n // subscribed to `tool.confirm_needed`, emitting the event leaves the\n // resolver promise pending forever \u2014 the tool neither executes nor fails\n // and the agent appears stuck. This happens in headless/CI/test runs that\n // construct a minimal agent without wiring a TUI/WebUI confirm handler.\n // Fall back to `deny` so the tool surfaces an error the model can react\n // to, instead of hanging silently.\n if (a.events.listenerCount('tool.confirm_needed') === 0) {\n // Structured warning to stdout \u2014 matches the observability skill's JSON\n // log convention. Kept off the session store to avoid coupling the\n // permission fallback to SessionWriter availability.\n console.log(\n JSON.stringify({\n level: 'warn',\n event: 'confirm.headless_fallback',\n tool: info.tool.name,\n toolUseId: info.toolUseId,\n message: `No tool.confirm_needed listener \u2014 auto-denying \"${info.tool.name}\" to avoid headless deadlock.`,\n }),\n );\n return Promise.resolve('deny' as const);\n }\n return new Promise((resolve) => {\n // Abort-awareness: /interrupt, Esc, or a parent abort must not leave the\n // run blocked on a confirmation nobody will answer. Resolve as 'abort'\n // \u2014 NOT 'no' \u2014 so the caller skips the denyOnce side effect (a\n // session-scoped deny minted by an interrupt would silently block this\n // tool+pattern for the rest of the session). Resolving twice is a\n // harmless no-op, so a late UI answer after abort is safely ignored.\n const signal = a.ctx.signal;\n const onAbort = () => resolve('abort');\n if (signal.aborted) {\n resolve('abort');\n return;\n }\n signal.addEventListener('abort', onAbort, { once: true });\n a.events.emit('tool.confirm_needed', {\n sessionId: resolveEventSessionId(a.ctx),\n tool: info.tool,\n input: info.input,\n toolUseId: info.toolUseId,\n suggestedPattern: info.suggestedPattern,\n decisionSource: info.decisionSource,\n riskTier: info.riskTier,\n boundaryReason: info.boundaryReason,\n resolve: (choice) => {\n signal.removeEventListener('abort', onAbort);\n resolve(choice);\n },\n });\n });\n }\n\n function emitToolExecuted(\n toolUseId: string,\n toolName: string,\n durationMs: number,\n ok: boolean,\n input: unknown,\n content: string,\n ): void {\n const sig = sizeSignals(toolName, content);\n // Memory the SAGE middleware appended to the result travels in its own\n // field. `output` keeps tool text only, so a short tool result can no\n // longer have the preview cap land inside a memory line \u2014 and surfaces\n // without a SAGE renderer never print the block as tool output.\n // Size signals stay computed over the full `content`: the model does see\n // the injected block and pays tokens for it.\n const { body, sageLines } = splitSageOutputBlock(content);\n const sage = capSageLines(sageLines, SAGE_EVENT_MAX);\n const metadata = recordToolOutputEvidence(a.ctx, {\n toolUseId,\n toolName,\n input,\n content,\n ok,\n outputBytes: sig.outputBytes,\n outputTokens: sig.outputTokens,\n outputLines: sig.outputLines,\n });\n a.events.emit('tool.executed', {\n sessionId: resolveEventSessionId(a.ctx),\n ...(a.ctx.traceId ? { traceId: a.ctx.traceId } : {}),\n agentId: a.ctx.agentId,\n agentName: a.ctx.agentName,\n id: toolUseId,\n name: toolName,\n durationMs,\n ok,\n input,\n output: truncateForEvent(\n body,\n DIFF_TOOL_NAMES.has(toolName) ? DIFF_TOOL_EVENT_PREVIEW_MAX : undefined,\n ),\n ...(sage.length > 0 ? { sage } : {}),\n outputBytes: sig.outputBytes,\n outputTokens: sig.outputTokens,\n outputLines: sig.outputLines,\n metadata,\n taskId: a.ctx.currentKanbanTaskId,\n boardId: a.ctx.currentKanbanBoardId,\n ...(typeof a.ctx.provider === 'object'\n ? { provider: (a.ctx.provider as { id: string }).id }\n : {}),\n ...(a.ctx.model ? { model: a.ctx.model } : {}),\n });\n }\n\n async function executeTools(toolUses: ToolUseBlock[]): Promise<ToolResultBlock[]> {\n const selectedToolUses = await a.extensions.runBeforeToolExecution(a.ctx, toolUses);\n\n const { outputs } = await a.toolExecutor.executeBatch(\n selectedToolUses,\n a.ctx,\n a.executionStrategy,\n );\n\n const useById = new Map(selectedToolUses.map((u) => [u.id, u]));\n const resultsForMessage: ToolResultBlock[] = [];\n const sessionEvents: SessionEvent[] = [];\n\n for (const { result, tool, durationMs } of outputs) {\n if (result.type === 'tool_confirm_pending' && tool) {\n const decision = await waitForConfirm({\n tool: tool,\n input: result.input,\n toolUseId: result.toolUseId,\n suggestedPattern: result.suggestedPattern,\n decisionSource: result.decisionSource,\n riskTier: result.riskTier,\n boundaryReason: result.boundaryReason,\n });\n\n // Persist trust/deny rules\n if (decision === 'always') {\n try {\n await a.permission.trust({ tool: tool.name, pattern: result.suggestedPattern });\n a.events.emit('trust.persisted', {\n sessionId: resolveEventSessionId(a.ctx),\n tool: tool.name,\n pattern: result.suggestedPattern,\n decision,\n });\n } catch {\n /* best-effort */\n }\n } else if (decision === 'deny') {\n try {\n await a.permission.deny({ tool: tool.name, pattern: result.suggestedPattern });\n a.events.emit('trust.persisted', {\n sessionId: resolveEventSessionId(a.ctx),\n tool: tool.name,\n pattern: result.suggestedPattern,\n decision,\n });\n } catch {\n /* best-effort */\n }\n }\n\n // Soft allow/deny for session-scoped retry prevention\n if (decision === 'yes') {\n const p = a.permission as never as {\n allowOnce?(r: { tool: string; pattern: string }): void;\n };\n p.allowOnce?.({ tool: tool.name, pattern: result.suggestedPattern });\n } else if (decision === 'no') {\n const p = a.permission as never as {\n denyOnce?(r: { tool: string; pattern: string }): void;\n };\n p.denyOnce?.({ tool: tool.name, pattern: result.suggestedPattern });\n }\n\n const reRunResult =\n decision === 'yes' || decision === 'always'\n ? await executeSingleWithDecision(tool, {\n id: result.toolUseId,\n name: tool.name,\n input: result.input,\n })\n : {\n result: {\n type: 'tool_result' as const,\n tool_use_id: result.toolUseId,\n content:\n decision === 'abort'\n ? `Tool \"${tool.name}\" was not executed \u2014 the run was aborted while awaiting confirmation.`\n : decision === 'deny'\n ? `Tool \"${tool.name}\" denied and blocked for this pattern.`\n : `Tool \"${tool.name}\" denied by user.`,\n is_error: true,\n },\n durationMs: 0,\n };\n\n const use = useById.get(reRunResult.result.tool_use_id);\n if (use) {\n await a.pipelines.toolCall.run({\n toolUse: use,\n result: reRunResult.result,\n ctx: a.ctx,\n tool,\n });\n sessionEvents.push({\n type: 'tool_result',\n ts: new Date().toISOString(),\n id: reRunResult.result.tool_use_id,\n content: reRunResult.result.content,\n isError: !!reRunResult.result.is_error,\n });\n emitToolExecuted(\n reRunResult.result.tool_use_id,\n tool.name,\n reRunResult.durationMs,\n !reRunResult.result.is_error,\n result.input,\n reRunResult.result.content,\n );\n }\n resultsForMessage.push(reRunResult.result);\n continue;\n }\n\n // Non-pending: already a resolved tool_result\n if (result.type !== 'tool_result') continue;\n resultsForMessage.push(result);\n const use = useById.get(result.tool_use_id);\n if (!use) continue;\n await a.pipelines.toolCall.run({ toolUse: use, result, ctx: a.ctx, tool: tool ?? undefined });\n sessionEvents.push({\n type: 'tool_result',\n ts: new Date().toISOString(),\n id: result.tool_use_id,\n content: result.content,\n isError: !!result.is_error,\n });\n emitToolExecuted(\n result.tool_use_id,\n use.name,\n durationMs,\n !result.is_error,\n use.input,\n result.content,\n );\n }\n\n // Batch-append all tool_result events to the session log in one call.\n // This replaces N sequential append() calls (one per tool result) with a\n // single batch write, avoiding N-1 function calls, scrub/observe cycles,\n // and timer rescheduling overhead.\n if (sessionEvents.length > 0) {\n await a.ctx.session.appendBatch(sessionEvents);\n }\n\n // Merge any pending PostToolUse separate context as a leading text block\n // in the same user message as the tool results \u2014 this keeps tool-use/\n // tool-result adjacency intact. The context text was stored on ctx by\n // the tool executor when a PostToolUse hook returned contextAs='separate'.\n const pendingContext = a.ctx.pendingPostToolContext;\n a.ctx.pendingPostToolContext = undefined;\n const contentBlocks: ContentBlock[] = pendingContext\n ? [{ type: 'text', text: pendingContext }, ...resultsForMessage]\n : resultsForMessage;\n a.ctx.state.appendMessage({ role: 'user', content: contentBlocks });\n // Tool results were added \u2014 mark adjacency as potentially needing repair\n // before the next provider request.\n if (contentBlocks.length > 0) {\n a.ctx.toolAdjacencyDirty = true;\n }\n // A completed tool may already have changed the filesystem. Persist the\n // legacy tool_result records AND the exact combined user message (including\n // PostToolUse context) before another provider call or crash can observe a\n // half-journaled conversation.\n try {\n await a.ctx.flushConversationJournal();\n await a.ctx.session.flush();\n } catch (err) {\n (a.logger.debug ?? a.logger.warn)?.(\n `tool result boundary flush failed: ${toErrorMessage(err)}`,\n );\n }\n await a.extensions.runAfterToolExecution(a.ctx, outputs);\n return resultsForMessage;\n }\n\n return { executeTools, executeSingleWithDecision };\n}\n", "/**\n * Pipeline \u2014 Koa-style middleware chain with named middleware\n * and position-aware insertion. Generic over input type T.\n */\n\nimport { WrongStackError, ERROR_CODES } from '../types/errors.js';\n\nexport type NextFn<T> = (value: T) => Promise<T>;\nexport type MiddlewareHandler<T> = (value: T, next: NextFn<T>) => Promise<T>;\n\n/**\n * Called when a middleware crashes (throws or rejects). Used by the\n * Pipeline's error boundary to log the offender without aborting the run.\n *\n * Return `'rethrow'` to propagate the error (default for core middleware),\n * or `'swallow'` to abort descent into the crashing middleware: its caller's\n * `await next()` resolves with the value that was about to flow into the\n * crashed middleware. The crashed middleware AND every middleware after it in\n * the chain are skipped (they never run); UPSTREAM middleware, already paused\n * at their own `await next()`, resume their post-`next()` work normally. It\n * does NOT continue at the next sibling middleware. Plugin middleware should\n * usually be swallowed so one bad plugin can't kill an agent run.\n */\nexport type PipelineErrorPolicy = 'rethrow' | 'swallow';\n\nexport interface PipelineErrorEvent {\n middleware: string;\n owner?: string | undefined;\n err: unknown;\n}\n\nexport type PipelineErrorHandler = (\n ev: PipelineErrorEvent,\n) => PipelineErrorPolicy | Promise<PipelineErrorPolicy>;\n\nexport interface Middleware<T> {\n name: string;\n handler: MiddlewareHandler<T>;\n owner?: string | undefined;\n}\n\nexport interface PipelineOptions {\n /** When true and the target middleware is not found, operations silently no-op instead of throwing. */\n optional?: boolean | undefined;\n}\n\n/**\n * Read-only view of a pipeline. Returned to consumers (plugins, hooks)\n * so they can inspect but not mutate the chain.\n */\nexport interface ReadonlyPipeline<T> {\n readonly size: number;\n list(): readonly string[];\n run(input: T): Promise<T>;\n}\n\nexport class Pipeline<T> {\n private readonly chain: Middleware<T>[] = [];\n private errorHandler?: PipelineErrorHandler | undefined;\n /**\n * Optional operational logger. When set, the `swallow` error-boundary path\n * emits a structured warning so a swallowed middleware crash is never\n * completely silent (P2 #7, before-release.md). Without a logger, the\n * swallow path still works but the crash is invisible \u2014 host code should\n * always wire one.\n */\n private logger?: { warn: (msg: string, ctx?: unknown) => void | undefined } | undefined;\n\n /**\n * Install an error boundary. When a middleware throws or rejects, the\n * handler is called and decides whether to swallow (continue with the\n * pre-handler value) or rethrow. Without a handler, errors propagate.\n *\n * Wire one per pipeline at boot \u2014 the host CLI typically installs a\n * single boundary that logs to the operational log and emits a\n * `pipeline.error` event for /diag.\n */\n setErrorHandler(handler: PipelineErrorHandler | undefined): this {\n this.errorHandler = handler;\n return this;\n }\n\n /**\n * Set the operational logger used by the swallow error-boundary path.\n * Without this, a swallowed middleware crash is completely silent.\n */\n setLogger(\n logger: { warn: (msg: string, ctx?: unknown) => void | undefined } | undefined,\n ): this {\n this.logger = logger;\n return this;\n }\n\n use(mw: Middleware<T> | Middleware<unknown>): this {\n this.ensureUnique(mw.name);\n this.chain.push(mw as Middleware<T>);\n return this;\n }\n\n prepend(mw: Middleware<T>): this {\n this.ensureUnique(mw.name);\n this.chain.unshift(mw);\n return this;\n }\n\n /**\n * Insert middleware at an explicit index. Out-of-range indices are clamped.\n * Use this when insertBefore/insertAfter are insufficient (e.g. to place\n * a middleware at a known position regardless of named targets).\n */\n insertAt(index: number, mw: Middleware<T>): this {\n this.ensureUnique(mw.name);\n const idx = Math.max(0, Math.min(index, this.chain.length));\n this.chain.splice(idx, 0, mw);\n return this;\n }\n\n /**\n * Insert mw immediately before the first occurrence of target.\n * If called multiple times with the same target, each call inserts\n * before the target's current position \u2014 so after insertBefore('B', X)\n * then insertBefore('B', Y), the order is Y \u2192 X \u2192 B.\n */\n insertBefore(target: string, mw: Middleware<T>, opts?: PipelineOptions): this {\n this.ensureUnique(mw.name);\n const idx = this.indexOf(target, opts?.optional);\n if (idx === -1) return this;\n this.chain.splice(idx, 0, mw);\n return this;\n }\n\n /**\n * Insert mw immediately after the first occurrence of target.\n * If called multiple times with the same target, each call inserts\n * after the target's current position \u2014 so after insertAfter('B', X)\n * then insertAfter('B', Y), the order is B \u2192 X \u2192 Y.\n */\n insertAfter(target: string, mw: Middleware<T>, opts?: PipelineOptions): this {\n this.ensureUnique(mw.name);\n const idx = this.indexOf(target, opts?.optional);\n if (idx === -1) return this;\n this.chain.splice(idx + 1, 0, mw);\n return this;\n }\n\n replace(target: string, mw: Middleware<T>, opts?: PipelineOptions): this {\n if (mw.name !== target) this.ensureUnique(mw.name);\n const idx = this.indexOf(target, opts?.optional);\n if (idx === -1) return this;\n this.chain[idx] = mw;\n return this;\n }\n\n remove(name: string, opts?: PipelineOptions): this {\n const idx = this.indexOf(name, opts?.optional);\n if (idx === -1) return this;\n this.chain.splice(idx, 1);\n return this;\n }\n\n list(): readonly string[] {\n return this.chain.map((m) => m.name);\n }\n\n size(): number {\n return this.chain.length;\n }\n\n /** Return a read-only view suitable for passing to plugins. */\n asReadonly(): ReadonlyPipeline<T> {\n // The returned object's methods close over `this`, so it always sees the\n // live chain. `list()` freezes its result so plugin code can't mutate\n // the chain names; subsequent calls produce fresh frozen snapshots.\n const self = this;\n const view: ReadonlyPipeline<T> = Object.freeze({\n get size(): number {\n return self.chain.length;\n },\n list(): readonly string[] {\n return Object.freeze(self.chain.map((m) => m.name));\n },\n run(input: T): Promise<T> {\n return self.run(input);\n },\n });\n return view;\n }\n\n async run(input: T): Promise<T> {\n let index = -1;\n const chain = this.chain;\n const errorHandler = this.errorHandler;\n\n const dispatch = async (i: number, value: T): Promise<T> => {\n if (i <= index) {\n const offender = chain[index]?.name;\n throw new WrongStackError({\n message: `Pipeline: next() called multiple times in \"${offender}\"`,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'container',\n context: { middleware: offender },\n });\n }\n index = i;\n const mw = chain[i];\n if (!mw) return value;\n try {\n return await mw.handler(value, (v) => dispatch(i + 1, v));\n } catch (err) {\n if (!errorHandler) throw err;\n const policy = await errorHandler({ middleware: mw.name, owner: mw.owner, err });\n if (policy === 'rethrow') throw err;\n // Swallow: resolve THIS dispatch with the value that was about to flow\n // into the crashed middleware. Because we return instead of recursing,\n // the crashed middleware and everything downstream of it never run; the\n // upstream caller's `await next()` resolves with `value` and its\n // post-next() logic continues. Net effect: the broken layer and the\n // rest of the chain below it are short-circuited, while already-entered\n // upstream layers unwind normally.\n // P2 #7 (before-release.md): emit a structured warning so a swallowed\n // crash is never completely silent. Plugin authors debugging a\n // short-circuited middleware would otherwise have no signal.\n this.logger?.warn('pipeline.error', {\n middleware: mw.name,\n owner: mw.owner,\n error: err instanceof Error ? err.message : String(err),\n });\n return value;\n }\n };\n\n return dispatch(0, input);\n }\n\n private indexOf(name: string, optional = false): number {\n const idx = this.chain.findIndex((m) => m.name === name);\n if (idx === -1 && !optional) {\n throw new WrongStackError({\n message: `Pipeline: middleware \"${name}\" not found`,\n code: ERROR_CODES.REGISTRY_NOT_FOUND,\n subsystem: 'container',\n context: { middleware: name },\n });\n }\n return idx;\n }\n\n private ensureUnique(name: string): void {\n if (this.chain.some((m) => m.name === name)) {\n throw new WrongStackError({\n message: `Pipeline: middleware \"${name}\" already registered`,\n code: ERROR_CODES.REGISTRY_DUPLICATE,\n subsystem: 'container',\n context: { middleware: name },\n });\n }\n }\n}\n", "/**\n * Agent type definitions \u2014 extracted from agent.ts to break circular\n * dependencies and keep the Agent class focused on runtime logic.\n */\nimport { Pipeline } from '../kernel/pipeline.js';\nimport type { ExtensionRegistry } from '../extension/registry.js';\nimport type { Container } from '../kernel/container.js';\nimport type { EventBus } from '../kernel/events.js';\nimport type { ProviderRegistry } from '../registry/provider-registry.js';\nimport type { ToolRegistry } from '../registry/tool-registry.js';\nimport type { ContentBlock, TextBlock, ToolResultBlock, ToolUseBlock } from '../types/blocks.js';\nimport { isTextBlock } from '../types/blocks.js';\nimport type { WrongStackError } from '../types/errors.js';\nimport type { Tracer } from '../types/observability.js';\nimport type { PermissionPolicy } from '../types/permission.js';\nimport type { LoopDetectionConfig } from '../types/config.js';\nimport type { Request, Response } from '../types/provider.js';\nimport type { Tool } from '../types/tool.js';\nimport type { ToolExecutorLike } from '../types/tool-executor.js';\nimport type { Context } from './context.js';\n\n/** Default iteration cap. Use 0 or Infinity via config to disable. */\nexport const DEFAULT_MAX_ITERATIONS = 100;\n\nexport interface RunResult {\n status: 'done' | 'failed' | 'max_iterations' | 'aborted';\n error?: WrongStackError | undefined;\n finalText?: string | undefined;\n iterations: number;\n delegateSummaries?: Array<{ summary: string | undefined; ok: boolean }>;\n /** Human-readable reason for abort (e.g. \"user interrupt\", \"tool timeout\", \"stream hang\"). */\n abortReason?: string | undefined;\n}\n\nexport interface AgentInit {\n container: Container;\n tools: ToolRegistry;\n providers: ProviderRegistry;\n events: EventBus;\n pipelines: AgentPipelines;\n context: Context;\n maxIterations?: number | undefined;\n iterationTimeoutMs?: number | undefined;\n executionStrategy?: 'parallel' | 'sequential' | 'smart' | undefined;\n perIterationOutputCapBytes?: number | undefined;\n autoExtendLimit?: boolean | undefined;\n autonomousContinue?: boolean | undefined;\n confirmAwaiter?: import('../types/tool-executor.js').ConfirmAwaiter | undefined;\n permissionPolicy?: PermissionPolicy | undefined;\n tracer?: Tracer | undefined;\n extensions?: ExtensionRegistry | undefined;\n toolExecutor: ToolExecutorLike;\n /** Loop-detector tuning (`tools.loopDetection`). Omitted fields use defaults. */\n loopDetection?: LoopDetectionConfig | undefined;\n}\n\n/** Fully-resolved loop-detector settings (defaults applied, bounds clamped). */\nexport interface ResolvedLoopDetectionConfig {\n mode: 'steer-then-cut' | 'cut' | 'off';\n steerThreshold: number;\n cutThreshold: number;\n windowSize: number;\n callRepeatThreshold: number;\n}\n\n/**\n * Apply defaults and sanity bounds to a (possibly partial) loop-detection\n * config. Clamping keeps a bad config from disabling the safety valve by\n * accident: the cut threshold always sits strictly above the steer\n * threshold so 'steer-then-cut' can never cut before it has steered.\n */\nexport function resolveLoopDetection(cfg?: LoopDetectionConfig): ResolvedLoopDetectionConfig {\n const steerThreshold = Math.max(2, cfg?.steerThreshold ?? 3);\n return {\n mode: cfg?.mode ?? 'steer-then-cut',\n steerThreshold,\n cutThreshold: Math.max(steerThreshold + 1, cfg?.cutThreshold ?? steerThreshold + 2),\n windowSize: Math.max(4, cfg?.windowSize ?? 12),\n callRepeatThreshold: Math.max(2, cfg?.callRepeatThreshold ?? 4),\n };\n}\n\nexport interface AgentPipelines {\n request: Pipeline<Request>;\n response: Pipeline<Response>;\n toolCall: Pipeline<ToolCallPipelinePayload>;\n userInput: Pipeline<UserInputPayload>;\n assistantOutput: Pipeline<TextBlock>;\n contextWindow: Pipeline<Context>;\n}\n\nexport interface UserInputPayload {\n content: ContentBlock[];\n text: string;\n ctx: Context;\n}\n\nexport type AgentInput = string | ContentBlock[];\n\nexport function normalizeInput(input: AgentInput): { blocks: ContentBlock[]; text: string } {\n if (typeof input === 'string') {\n return { blocks: [{ type: 'text', text: input }], text: input };\n }\n const text = input.filter(isTextBlock).map((b) => b.text).join('');\n return { blocks: input, text };\n}\n\nexport interface ToolCallPipelinePayload {\n toolUse: ToolUseBlock;\n result: ToolResultBlock;\n ctx: Context;\n tool?: Tool | undefined;\n}\n\nexport function createDefaultPipelines(): AgentPipelines {\n return {\n request: new Pipeline<Request>(),\n response: new Pipeline<Response>(),\n toolCall: new Pipeline<ToolCallPipelinePayload>(),\n userInput: new Pipeline<UserInputPayload>(),\n assistantOutput: new Pipeline<TextBlock>(),\n contextWindow: new Pipeline<Context>(),\n };\n}\n", "import type { AddAttachmentInput, AttachmentRef, AttachmentStore } from '../types/attachment.js';\nimport type { ContentBlock } from '../types/blocks.js';\n\nexport interface InputBuilderOptions {\n store: AttachmentStore;\n /**\n * Pastes \u2265 this many lines collapse to a `[pasted #N]` placeholder.\n * Default: 8 lines.\n */\n pasteLineThreshold?: number | undefined;\n /**\n * Pastes \u2265 this many characters collapse to a placeholder regardless of\n * line count. Default: 2000 chars.\n */\n pasteCharThreshold?: number | undefined;\n}\n\nexport interface InputBuilderEvent {\n /** Current display string (with placeholders, before submit). */\n display: string;\n refs: AttachmentRef[];\n}\n\n/**\n * UI-agnostic accumulator for user input. The frontend (CLI/TUI) feeds in:\n * - typed text via `appendText()`\n * - large pastes via `appendPaste()` \u2192 returns placeholder string\n * - image paste via `appendImage()` \u2192 returns placeholder string\n * - file refs (`@path`) via `appendFile()` \u2192 returns placeholder string\n *\n * On `submit()` the builder runs the display string through AttachmentStore.expand()\n * and returns the final ContentBlock[] ready for `agent.run()`.\n *\n * The builder does not know what a \"line\" or \"key\" is \u2014 that is the\n * frontend's job. It only operates on strings and byte payloads.\n */\nexport class InputBuilder {\n private readonly store: AttachmentStore;\n private readonly pasteLineThreshold: number;\n private readonly pasteCharThreshold: number;\n private display = '';\n private readonly refs: AttachmentRef[] = [];\n\n constructor(opts: InputBuilderOptions) {\n this.store = opts.store;\n this.pasteLineThreshold = opts.pasteLineThreshold ?? 8;\n this.pasteCharThreshold = opts.pasteCharThreshold ?? 2000;\n }\n\n get text(): string {\n return this.display;\n }\n\n get attachments(): AttachmentRef[] {\n return [...this.refs];\n }\n\n get isEmpty(): boolean {\n return this.display.trim().length === 0;\n }\n\n appendText(text: string): void {\n this.display += text;\n }\n\n /**\n * Decide whether a chunk of pasted text is \"big\" enough to collapse.\n * If yes, store it and append a placeholder. If no, inline it.\n * Returns the placeholder string actually appended (or `null` if inlined).\n */\n async appendPaste(text: string): Promise<string | null> {\n if (this.shouldCollapse(text)) {\n const ref = await this.store.add({\n kind: 'text',\n data: text,\n meta: { label: paragraphLabel(text) },\n });\n const placeholder = `[pasted #${ref.seq}]`;\n this.display += placeholder;\n this.refs.push(ref);\n return placeholder;\n }\n this.display += text;\n return null;\n }\n\n /**\n * Always collapses to `[image #N]` \u2014 images are never inlined.\n * `dataBase64` is the raw base64 payload (no data: prefix).\n */\n async appendImage(dataBase64: string, mediaType: string): Promise<string> {\n const ref = await this.store.add({\n kind: 'image',\n data: dataBase64,\n meta: { mediaType, label: `${mediaType.split('/')[1]?.toUpperCase() ?? 'IMG'}` },\n });\n const placeholder = `[image #${ref.seq}]`;\n this.display += placeholder;\n this.refs.push(ref);\n return placeholder;\n }\n\n async appendFile(input: AddAttachmentInput): Promise<string> {\n const ref = await this.store.add({ ...input, kind: 'file' });\n const placeholder = `[file #${ref.seq}]`;\n this.display += placeholder;\n this.refs.push(ref);\n return placeholder;\n }\n\n /**\n * Register-only variant of `appendPaste`. Always stores the paste and\n * returns the inline `[pasted #N, L lines]` token WITHOUT mutating\n * `display` \u2014 the caller (TUI) owns its own editable buffer as the single\n * source of truth, inserts the token there, and expands the buffer at\n * submit. The collapse decision is the caller's (it gates this call); use\n * `wouldCollapse()` for that.\n */\n async registerPaste(text: string): Promise<string> {\n const ref = await this.store.add({\n kind: 'text',\n data: text,\n meta: { label: paragraphLabel(text) },\n });\n this.refs.push(ref);\n // Split on \\r\\n, \\r, or \\n \u2014 Windows terminals often send \\r-only\n // line separators in bracketed-paste mode (e.g. pasted from cmd.exe).\n const lines = text.split(/\\r?\\n|\\r/).length;\n return `[pasted #${ref.seq}, ${lines} lines]`;\n }\n\n /**\n * Register-only variant of `appendImage` \u2014 see `registerPaste`. Returns a\n * seq-keyed `[image #N, LABEL]` token; does not touch `display`.\n */\n async registerImage(dataBase64: string, mediaType: string): Promise<string> {\n const label = `${mediaType.split('/')[1]?.toUpperCase() ?? 'IMG'}`;\n const ref = await this.store.add({\n kind: 'image',\n data: dataBase64,\n meta: { mediaType, label },\n });\n this.refs.push(ref);\n return `[image #${ref.seq}, ${label}]`;\n }\n\n /**\n * Register-only variant of `appendFile` \u2014 see `registerPaste`. Returns a\n * path-keyed `[file:<path>]` token (resolved by path at expand time); does\n * not touch `display`. The path is read from `meta.filename` (falling back\n * to `meta.label`).\n */\n async registerFile(input: AddAttachmentInput): Promise<string> {\n const ref = await this.store.add({ ...input, kind: 'file' });\n this.refs.push(ref);\n const path = ref.meta.filename ?? ref.meta.label ?? String(ref.seq);\n return `[file:${path}]`;\n }\n\n /**\n * Whether `appendPaste(text)` would collapse the text to a placeholder\n * (rather than inlining it). Lets a frontend decide where to route a paste\n * \u2014 e.g. collapsed pastes become a pill, while inlined ones can be shown\n * in the editable input row \u2014 without calling `appendPaste` first (which\n * mutates the display buffer).\n */\n wouldCollapse(text: string): boolean {\n return this.shouldCollapse(text);\n }\n\n /** Reset display and ref list. Does NOT clear the store itself. */\n reset(): void {\n this.display = '';\n this.refs.length = 0;\n }\n\n /**\n * Resolve the current display string into ContentBlock[]. Empty\n * input returns an empty array \u2014 caller decides what to do.\n */\n async submit(): Promise<ContentBlock[]> {\n const text = this.display;\n this.reset();\n return text ? this.store.expand(text) : [];\n }\n\n private shouldCollapse(text: string): boolean {\n if (text.length >= this.pasteCharThreshold) return true;\n let lines = 1;\n for (let i = 0; i < text.length; i++) {\n const c = text.charCodeAt(i);\n // \\n (10) is always a line break.\n // \\r (13) is a line break only when NOT followed by \\n (Mac-style).\n // \\r\\n sequences are counted once by the \\n check on the next iteration.\n if (c === 10) lines++;\n else if (c === 13 && text.charCodeAt(i + 1) !== 10) lines++;\n if (lines >= this.pasteLineThreshold) return true;\n }\n return false;\n }\n}\n\nfunction paragraphLabel(text: string): string {\n // Split on \\r\\n, \\r, or \\n \u2014 handles Windows (\\r\\n), Unix (\\n), and\n // legacy Mac / bracketed-paste \\r-only separators.\n const lines = text.split(/\\r?\\n|\\r/).length;\n const bytes = Buffer.byteLength(text, 'utf8');\n if (bytes < 1024) return `${lines} lines, ${bytes} B`;\n return `${lines} lines, ${(bytes / 1024).toFixed(1)} KB`;\n}\n", "import type { TodoItem } from '../core/context.js';\nimport { color } from './color.js';\n\n/**\n * Canonical text rendering of the live todo list, shared by the CLI's\n * `/todos` slash command and the TUI's auto-echo (which prints the same\n * snapshot to chat history each time the `todo` tool mutates the list).\n *\n * Layout: a header line with the `done/total done` count, then one row\n * per item \u2014 `[ ]` pending, `[~]` in-progress, `[x]` completed. In-\n * progress rows prefer `activeForm` (\"Building the project\") over the\n * imperative `content` (\"Build the project\") when present.\n *\n * Returned as a single newline-joined string so callers can hand it\n * straight to a history dispatcher or stdout.\n */\nexport function formatTodosList(todos: TodoItem[]): string {\n if (todos.length === 0) return 'No todos.';\n const lines: string[] = [];\n const done = todos.filter((t) => t.status === 'completed').length;\n lines.push(color.dim(`Todos (${done}/${todos.length} done):`));\n todos.forEach((t, i) => {\n const mark =\n t.status === 'completed'\n ? color.green('[x]')\n : t.status === 'in_progress'\n ? color.yellow('[~]')\n : color.dim('[ ]');\n const text = t.status === 'in_progress' && t.activeForm ? t.activeForm : t.content;\n const label = t.status === 'completed' ? color.dim(text) : text;\n lines.push(` ${color.dim(String(i + 1).padStart(2))}. ${mark} ${label}`);\n });\n return lines.join('\\n');\n}\n\n/**\n * True when the todos list still has at least one unfinished item \u2014 either\n * `pending` (not started) or `in_progress` (underway). The REPL and other\n * post-turn handlers call this to decide whether to surface `<nextsteps>`\n * suggestions to the user: as long as the agent has open todos, finishing\n * them takes priority over offering new prompt options. Surfacing\n * `<nextsteps>` mid-task is what causes YOLO+auto mode and the autonomy\n * 'auto' loop to prematurely pivot away from the in-flight todo list.\n *\n * Returns false for an empty / undefined list (nothing pending, nothing to\n * block on) and false for an all-completed list. Treats any non-array input\n * (legacy contexts, mocks) as \"no todos\" rather than throwing.\n */\nexport function hasOpenTodos(todos: readonly TodoItem[] | undefined | null): boolean {\n if (!Array.isArray(todos) || todos.length === 0) return false;\n return todos.some((t) => t.status === 'pending' || t.status === 'in_progress');\n}\n", "/**\n * Continue-intent detection + continuation resolution.\n *\n * ## Problem\n *\n * Users frequently type a bare \"continue\" (or \"devam\", \"go on\", \"keep going\")\n * to nudge the agent forward without supplying any new instruction. On its own\n * that word carries no information about *what* to continue \u2014 the model has to\n * re-derive \"what was next\" from history, which drifts as the context window is\n * compacted. Left unanchored, a run of \"continue \u2026 continue \u2026 continue\" turns\n * into an ever-vaguer manual loop: the model repeats work, declares completion\n * prematurely, or wanders.\n *\n * ## Approach\n *\n * A bare \"continue\" is not new information \u2014 it points at an *existing* goal.\n * So instead of asking the model to remember a hidden per-message marker, we\n * resolve the continuation against the state we already keep:\n *\n * 1. **Open todos** \u2014 the strongest, most durable anchor. Survives context\n * compaction (todos are re-injected each turn) and goal.json persistence.\n * \"continue\" = resume the next open todo.\n * 2. **Parsed `<nextsteps>` suggestions** \u2014 the menu surfaced after the last\n * completed turn (already extracted and stored by the surface's\n * suggestion store). \"continue\" = do suggestion #1.\n * 3. **Open continuation** \u2014 no explicit task is queued, but the user still\n * wants work to proceed. We inject an instruction that tells the model to\n * pick the single most valuable next step itself and carry it out \u2014 while\n * explicitly forbidding fabricated busywork. This is what keeps \"continue\"\n * from ever dead-ending.\n *\n * This module is pure and surface-agnostic: detection takes the raw string,\n * resolution takes already-collected data (todos + parsed suggestion strings).\n * The REPL and TUI wire it in at the point where a user message becomes an\n * agent run, *before* prompt refinement \u2014 a bare \"continue\" has nothing\n * meaningful to refine, and refining it would only add latency and drift.\n *\n * The three triggers of the same continuation machinery \u2014 the user typing\n * \"continue\", the model emitting the `[continue]` marker (see\n * {@link parseContinueDirective}), and an autonomy tick \u2014 all ultimately want\n * the same thing: advance the plan. This module is the manual-trigger path.\n */\n\nimport { hasOpenTodos } from '../utils/todos-format.js';\nimport type { TodoItem } from './context.js';\n\n// \u2500\u2500 Detection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Normalized phrases that mean \"just keep going\" on their own. Matched by\n * exact equality after {@link normalizeContinueInput}, which is deliberately\n * strict: a message is a bare-continue only when it is *nothing but* one of\n * these phrases (plus optional trailing politeness / punctuation). This makes\n * false positives structurally impossible \u2014 \"continue with the auth refactor\"\n * normalizes to a longer string that is not in the set, so it falls through to\n * normal handling.\n *\n * Coverage skews to the two languages this project's users type in (English,\n * Turkish) with a handful of common Latin-script others. Add sparingly \u2014 every\n * entry is a phrase we promise carries no other meaning in an agent prompt.\n */\nconst CONTINUE_PHRASES: ReadonlySet<string> = new Set([\n // \u2500\u2500 English \u2500\u2500\n 'continue',\n 'cont',\n 'continue continue',\n 'continue working',\n 'keep going',\n 'keep it going',\n 'keep going on',\n 'keep working',\n 'keep on',\n 'carry on',\n 'go on',\n 'goon',\n 'go ahead',\n 'proceed',\n 'proceed further',\n 'onward',\n 'onwards',\n 'next',\n 'next step',\n 'more',\n 'resume',\n 'and continue',\n 'yes continue',\n 'ok continue',\n // \u2500\u2500 Turkish \u2500\u2500\n 'devam',\n 'devam et',\n 'devam et bakalim',\n 'devam edelim',\n 'devam edin',\n 'devam etsene',\n 'devam etsenize',\n 'devam ediyoruz',\n 'devam et lutfen',\n 'surdur',\n 'devam etsen',\n 'devam et hadi',\n 'hadi devam',\n // \u2500\u2500 Other Latin-script (light coverage) \u2500\u2500\n 'weiter', // de\n 'mach weiter', // de\n 'continuar', // es/pt\n 'continua', // es/it/pt\n 'continuer', // fr\n 'continue por favor', // pt/es\n]);\n\n/**\n * Trailing politeness / filler tokens stripped before matching, so\n * \"continue please\" and \"devam et l\u00FCtfen\" resolve to their base phrase.\n * (Turkish diacritics are folded to ASCII first, so \"l\u00FCtfen\" \u2192 \"lutfen\".)\n */\nconst POLITENESS_SUFFIXES: readonly string[] = [\n 'please',\n 'pls',\n 'plz',\n 'lutfen',\n 'thanks',\n 'thank you',\n 'thx',\n 'ty',\n];\n\n/** Fold the handful of Turkish diacritics we care about to ASCII. */\nfunction foldDiacritics(s: string): string {\n return s\n .replace(/\u00FC/g, 'u')\n .replace(/\u00F6/g, 'o')\n .replace(/\u00E7/g, 'c')\n .replace(/\u015F/g, 's')\n .replace(/\u011F/g, 'g')\n .replace(/\u0131/g, 'i')\n .replace(/\u0130/g, 'i')\n .replace(/\u00E2/g, 'a')\n .replace(/\u00EE/g, 'i')\n .replace(/\u00FB/g, 'u');\n}\n\n/**\n * Normalize a raw user message for bare-continue matching:\n * lowercase \u2192 fold diacritics \u2192 strip wrapping quotes/backticks \u2192 strip\n * surrounding punctuation \u2192 collapse internal whitespace \u2192 drop one trailing\n * politeness token. Returns the normalized string (possibly empty).\n */\nfunction normalizeContinueInput(raw: string): string {\n let s = raw.trim().toLowerCase();\n s = foldDiacritics(s);\n // Strip a single layer of wrapping quotes/backticks.\n s = s.replace(/^[\"'`]+/, '').replace(/[\"'`]+$/, '');\n // Strip leading/trailing punctuation and whitespace runs.\n s = s.replace(/^[\\s.!?,;:\u2026]+/, '').replace(/[\\s.!?,;:\u2026]+$/, '');\n // Collapse internal whitespace.\n s = s.replace(/\\s+/g, ' ').trim();\n // Drop one trailing politeness token (e.g. \"continue please\" \u2192 \"continue\").\n for (const suffix of POLITENESS_SUFFIXES) {\n if (s === suffix) break; // a bare \"please\" is not a continue\n if (s.endsWith(` ${suffix}`)) {\n s = s.slice(0, s.length - suffix.length - 1).trim();\n break;\n }\n }\n return s;\n}\n\n/** Longest phrase in the set, in words \u2014 a cheap upper bound for the guard. */\nconst MAX_CONTINUE_WORDS = 4;\n\n/**\n * True when `raw` is a bare \"continue\"-style nudge and nothing else.\n *\n * Strict by construction: the message must normalize to exactly one of\n * {@link CONTINUE_PHRASES}. Anything with additional substance (\"continue but\n * skip tests\", \"go on to the next file and commit\") normalizes to a string\n * outside the set and returns false, so it is handled as an ordinary message.\n */\nexport function detectContinueIntent(raw: string): boolean {\n if (!raw) return false;\n // Fast length guard \u2014 bare-continue phrases are short. Avoids normalizing\n // large pastes.\n if (raw.length > 40) return false;\n const normalized = normalizeContinueInput(raw);\n if (!normalized) return false;\n if (normalized.split(' ').length > MAX_CONTINUE_WORDS) return false;\n return CONTINUE_PHRASES.has(normalized);\n}\n\n// \u2500\u2500 Resolution \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Where the resolved continuation came from:\n * - `todo` \u2014 resumed the next open todo (strongest anchor)\n * - `suggestion` \u2014 took the top parsed `<nextsteps>` suggestion\n * - `open` \u2014 no explicit task queued; model self-determines the step\n */\nexport type ContinuationSource = 'todo' | 'suggestion' | 'open';\n\nexport interface ContinuationInput {\n /** Live todo list (`ctx.todos`). */\n todos?: readonly TodoItem[] | undefined;\n /** Already-parsed `<nextsteps>` suggestion strings from the surface store. */\n suggestions?: readonly string[] | undefined;\n}\n\nexport interface ResolvedContinuation {\n source: ContinuationSource;\n /**\n * The concrete instruction injected as the next user turn in place of the\n * bare \"continue\". Written for the model, not the human.\n */\n text: string;\n /**\n * Short one-line label for the surface to echo (dim) so the human sees what\n * \"continue\" resolved to without the full injected paragraph.\n */\n label: string;\n}\n\n/** Truncate a string to `max` chars with an ellipsis, for labels. */\nfunction ellipsize(s: string, max = 72): string {\n const flat = s.replace(/\\s+/g, ' ').trim();\n return flat.length <= max ? flat : `${flat.slice(0, max - 1)}\u2026`;\n}\n\n/**\n * Resolve what a bare \"continue\" should do, given the current run state.\n *\n * The ladder \u2014 first match wins:\n * 1. an open todo (in-progress preferred, else the first pending),\n * 2. the top stored suggestion,\n * 3. an open continuation that never dead-ends.\n *\n * Always returns a usable {@link ResolvedContinuation}; the `open` branch is\n * the guaranteed fallback so \"continue\" keeps work moving even with no todos\n * and no suggestions.\n */\nexport function resolveContinuation(input: ContinuationInput): ResolvedContinuation {\n const todos = Array.isArray(input.todos) ? input.todos : [];\n const suggestions = (Array.isArray(input.suggestions) ? input.suggestions : []).filter(\n (s): s is string => typeof s === 'string' && s.trim().length > 0,\n );\n\n // 1 \u2500\u2500 Open todos: the durable anchor.\n if (hasOpenTodos(todos)) {\n const inProgress = todos.find((t) => t.status === 'in_progress');\n const next = inProgress ?? todos.find((t) => t.status === 'pending');\n if (next) {\n const total = todos.length;\n const done = todos.filter((t) => t.status === 'completed').length;\n const item =\n next.status === 'in_progress' && next.activeForm ? next.activeForm : next.content;\n // Embed the full board snapshot (not just the next item). Two reasons:\n // - the model gets the complete plan state every continuation instead\n // of a single line, so multi-turn work stays grounded;\n // - the continuation text changes whenever ANY board state changes,\n // so the auto-proceed repetition guard only sees identical prompts\n // when the board is genuinely frozen across whole turns \u2014 real\n // progress (items completed, added, re-ordered, re-statused) never\n // trips it.\n // Cap displayed rows so the prompt doesn't balloon. 20 rows keeps the\n // board readable for both small and large todo lists without crowding\n // the continuation prompt with hundreds of items.\n const BOARD_MAX_ROWS = 20;\n const board = todos.slice(0, BOARD_MAX_ROWS).map((t) => {\n const mark = t.status === 'completed' ? '[x]' : t.status === 'in_progress' ? '[~]' : '[ ]';\n // Flatten newlines so multi-line todo content doesn't break the\n // board's structured layout \u2014 each row is exactly one line.\n const flatContent = t.content.replace(/\\n|\\r/g, ' ');\n return ` ${mark} ${flatContent}`;\n });\n if (todos.length > BOARD_MAX_ROWS) {\n board.push(` \u2026 ${todos.length - BOARD_MAX_ROWS} more`);\n }\n const text = [\n 'Continue with the plan. Resume work on the next open todo:',\n '',\n ` ${item}`,\n '',\n `Current todo board (${done}/${total} todos complete.):`,\n ...board,\n '',\n 'If this item is already done, mark it complete and move to the next open todo. Keep the board honest as you work \u2014 mark finished items completed and split items that need more than one turn. When every todo is complete, stop and give a short summary \u2014 do not invent new work.',\n ].join('\\n');\n return { source: 'todo', text, label: `\u25B6 Continue \u2192 todo: ${ellipsize(item)}` };\n }\n }\n\n // 2 \u2500\u2500 Top parsed suggestion.\n const top = suggestions[0];\n if (top) {\n const text = [\n 'Continue. Proceed with this next step:',\n '',\n ` ${top}`,\n '',\n 'Carry it out now. When it is done, briefly report the result.',\n ].join('\\n');\n return { source: 'suggestion', text, label: `\u25B6 Continue \u2192 ${ellipsize(top)}` };\n }\n\n // 3 \u2500\u2500 Open continuation: no queued task, but keep working.\n const text = [\n 'Continue working.',\n '',\n 'There is no explicit pending task queued, so decide the single most valuable next step yourself based on our conversation so far and the current state of the project, then carry it out.',\n '',\n 'Prefer finishing, verifying, or hardening work already in progress over starting something unrelated. If the work is genuinely complete and nothing sensible remains, say so plainly in one or two sentences and propose a direction \u2014 do not fabricate busywork.',\n ].join('\\n');\n return { source: 'open', text, label: '\u25B6 Continue \u2192 (no pending task \u2014 choosing next step)' };\n}\n", "/** A provider-qualified or provider-relative model reference. */\nexport interface ModelRef {\n provider?: string | undefined;\n model: string;\n}\n\n/** Parse `model`, `provider/model`, or `provider model`. */\nexport function parseModelRef(ref: string): ModelRef {\n const trimmed = ref.trim();\n const slash = trimmed.indexOf('/');\n if (slash !== -1) {\n return {\n provider: trimmed.slice(0, slash) || undefined,\n model: trimmed.slice(slash + 1).trim(),\n };\n }\n const parts = trimmed.split(/\\s+/);\n if (parts.length >= 2) {\n return { provider: parts[0], model: parts.slice(1).join(' ') };\n }\n return { model: trimmed };\n}\n\nexport function formatModelRef(ref: ModelRef, defaultProvider?: string | undefined): string {\n const provider = ref.provider ?? defaultProvider;\n return provider ? `${provider}/${ref.model}` : ref.model;\n}\n\nexport function normalizeModelRef(ref: string, defaultProvider?: string | undefined): string {\n return formatModelRef(parseModelRef(ref), defaultProvider);\n}\n", "export interface ModelBlackoutRule {\n id: string;\n enabled?: boolean | undefined;\n provider?: string | undefined;\n model?: string | undefined;\n /** JavaScript weekday numbers: Sunday=0 \u2026 Saturday=6. Empty means every day. */\n days?: number[] | undefined;\n /** Inclusive local start, HH:mm. */\n start: string;\n /** Exclusive local end, HH:mm. Equal to start means all day. */\n end: string;\n /** IANA timezone. Defaults to the host timezone. */\n timezone?: string | undefined;\n label?: string | undefined;\n /** `blackout`: deny inside. `allow_only`: deny outside all matching allow windows. */\n mode?: 'blackout' | 'allow_only' | undefined;\n}\n\nexport interface ModelCalendarDecision {\n allowed: boolean;\n rule?: ModelBlackoutRule | undefined;\n}\n\nexport function logicalCalendarTarget(\n providerId: string,\n model: string,\n): {\n providerId: string;\n model: string;\n} {\n if (providerId !== 'omniroute') return { providerId, model };\n const slash = model.indexOf('/');\n return slash > 0 && slash < model.length - 1\n ? { providerId: model.slice(0, slash), model: model.slice(slash + 1) }\n : { providerId, model };\n}\n\nconst WEEKDAYS: Record<string, number> = {\n Sun: 0,\n Mon: 1,\n Tue: 2,\n Wed: 3,\n Thu: 4,\n Fri: 5,\n Sat: 6,\n};\n\nfunction minuteOfDay(value: string): number | undefined {\n const match = /^(\\d{2}):(\\d{2})$/.exec(value);\n if (!match) return undefined;\n const hour = Number(match[1]);\n const minute = Number(match[2]);\n if (hour > 23 || minute > 59) return undefined;\n return hour * 60 + minute;\n}\n\nfunction clockAt(date: Date, timezone?: string): { day: number; minute: number } | undefined {\n try {\n const parts = new Intl.DateTimeFormat('en-US', {\n timeZone: timezone,\n weekday: 'short',\n hour: '2-digit',\n minute: '2-digit',\n hourCycle: 'h23',\n }).formatToParts(date);\n const weekday = parts.find((part) => part.type === 'weekday')?.value;\n const hour = Number(parts.find((part) => part.type === 'hour')?.value);\n const minute = Number(parts.find((part) => part.type === 'minute')?.value);\n if (!weekday || WEEKDAYS[weekday] === undefined || !Number.isFinite(hour + minute))\n return undefined;\n return { day: WEEKDAYS[weekday], minute: hour * 60 + minute };\n } catch {\n return undefined;\n }\n}\n\nfunction targetMatches(rule: ModelBlackoutRule, providerId: string, model: string): boolean {\n if (rule.provider && rule.provider !== providerId) return false;\n if (rule.model && rule.model !== model) return false;\n return Boolean(rule.provider || rule.model);\n}\n\nfunction timeMatches(rule: ModelBlackoutRule, day: number, minute: number): boolean {\n const start = minuteOfDay(rule.start);\n const end = minuteOfDay(rule.end);\n if (start === undefined || end === undefined) return false;\n const days = rule.days?.length ? new Set(rule.days) : undefined;\n if (start === end) return !days || days.has(day);\n if (start < end) return (!days || days.has(day)) && minute >= start && minute < end;\n // Overnight: Monday 22:00\u201307:00 includes early Tuesday morning.\n if (minute >= start) return !days || days.has(day);\n const previousDay = (day + 6) % 7;\n return minute < end && (!days || days.has(previousDay));\n}\n\nexport function evaluateModelCalendar(\n rules: readonly ModelBlackoutRule[] | undefined,\n providerId: string,\n model: string,\n at = new Date(),\n): ModelCalendarDecision {\n ({ providerId, model } = logicalCalendarTarget(providerId, model));\n const allowRules: ModelBlackoutRule[] = [];\n let allowMatched = false;\n for (const rule of rules ?? []) {\n if (rule.enabled === false || !targetMatches(rule, providerId, model)) continue;\n const clock = clockAt(at, rule.timezone);\n if (!clock || minuteOfDay(rule.start) === undefined || minuteOfDay(rule.end) === undefined)\n continue;\n if (rule.mode === 'allow_only') {\n allowRules.push(rule);\n if (timeMatches(rule, clock.day, clock.minute)) allowMatched = true;\n } else if (timeMatches(rule, clock.day, clock.minute)) {\n return { allowed: false, rule };\n }\n }\n if (allowRules.length > 0 && !allowMatched) return { allowed: false, rule: allowRules[0] };\n return { allowed: true };\n}\n", "/**\n * FallbackProfileManager \u2014 centralized, decoupled fallback profile resolution.\n *\n * Every consumer (fallback-model, council orchestrator, one-shot LLM, plugins)\n * resolves its fallback chain through this single manager instead of parsing\n * config.fallbackProfiles independently. This guarantees consistent resolution,\n * provider-health filtering, and a single reload point on config changes.\n *\n * Design:\n * - Stable service identity: `reload()` atomically replaces the manager's\n * immutable config/profile snapshot so injected consumers stay live.\n * - Immutable outputs: every resolved chain is frozen.\n * - Provider-aware: each profile entry is checked against live provider config\n * (has API key?) before inclusion.\n * - Zero coupling: consumers only see `readonly FallbackChainEntry[]` \u2014\n * no awareness of profile names, config shape, or provider internals.\n */\n\nimport type { ProviderModelStatusTracker } from '../coordination/provider-status-tracker.js';\nimport type { Config, ProviderConfig } from '../types/config.js';\nimport { parseModelRef } from './model-ref.js';\nimport { evaluateModelCalendar } from './model-availability-calendar.js';\n\n// \u2500\u2500 Public types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** One resolved entry in a fallback chain. */\nexport interface FallbackChainEntry {\n /** Resolved provider id. */\n readonly providerId: string;\n /** Resolved model id. */\n readonly model: string;\n /** Whether this entry uses a different provider than the primary. */\n readonly providerSwitched: boolean;\n}\n\n/** Immutable fallback chain returned by the manager. */\nexport type FallbackChain = readonly FallbackChainEntry[];\n\n/**\n * Configuration-level provider health used while resolving fallback chains.\n *\n * This deliberately answers whether the runtime has enough configuration to\n * construct the provider; it does not perform a network probe. Keyless\n * self-hosted endpoints are usable when they declare a `baseUrl`.\n */\nexport interface ProviderHealth {\n readonly providerId: string;\n readonly hasKey: boolean;\n readonly hasEndpoint: boolean;\n readonly hasModels: boolean;\n readonly usable: boolean;\n}\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction hasText(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\nfunction providerHasKey(entry: ProviderConfig | undefined): boolean {\n if (!entry) return false;\n if (hasText(entry.apiKey)) return true;\n if (Array.isArray(entry.apiKeys) && entry.apiKeys.some((k) => hasText(k?.apiKey))) return true;\n if (Array.isArray(entry.envVars) && entry.envVars.some((v) => hasText(process.env[v])))\n return true;\n return false;\n}\n\nfunction visibleProviderModels(\n config: Config,\n providerId: string,\n providerModels: string[],\n): string[] {\n const entry = config.providers?.[providerId];\n return entry?.models !== undefined ? [...entry.models] : providerModels;\n}\n\nfunction buildProfiles(config: Config): ReadonlyMap<string, readonly string[]> {\n const entries = new Map<string, readonly string[]>();\n for (const [name, chain] of Object.entries(config.fallbackProfiles ?? {})) {\n if (Array.isArray(chain) && chain.length > 0) {\n entries.set(name, Object.freeze([...chain]));\n }\n }\n return entries;\n}\n\n// \u2500\u2500 Manager \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class FallbackProfileManager {\n /** Immutable snapshot of config.fallbackProfiles for the active config. */\n private profiles: ReadonlyMap<string, readonly string[]>;\n /** Active frozen config snapshot for provider lookups. */\n private config: Config;\n /** Optional shared runtime status tracker. */\n private statusTracker: ProviderModelStatusTracker | undefined;\n\n constructor(config: Config, opts?: { statusTracker?: ProviderModelStatusTracker | undefined }) {\n this.config = config;\n this.profiles = buildProfiles(config);\n this.statusTracker = opts?.statusTracker;\n }\n\n /**\n * Bind (or replace) the shared runtime status tracker.\n * Called by the boot path after the tracker is created.\n */\n setStatusTracker(tracker: ProviderModelStatusTracker | undefined): void {\n this.statusTracker = tracker;\n }\n\n // \u2500\u2500 Profile existence \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n hasProfile(name: string): boolean {\n return this.profiles.has(name);\n }\n\n listProfiles(): readonly string[] {\n return Object.freeze([...this.profiles.keys()]);\n }\n\n // \u2500\u2500 Resolution \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Resolve a named fallback profile to a validated, provider-filtered chain.\n *\n * Returns an empty chain when:\n * - The profile doesn't exist.\n * - Every entry's provider is missing, has no key, or has no matching model.\n *\n * @param name - Profile name from config.fallbackProfiles.\n * @param defaultProvider - Used when an entry has no explicit provider.\n * @param exclude - Optional { providerId, model } to skip (avoid self-fallback).\n */\n resolve(\n name: string,\n opts: {\n defaultProvider?: string | undefined;\n exclude?: { providerId: string; model: string } | undefined;\n } = {},\n ): FallbackChain {\n const defaultProvider = opts.defaultProvider ?? this.config.provider;\n const chain = this.profiles.get(name);\n if (!chain) return FREEZER_EMPTY;\n\n const excludeKey = opts.exclude\n ? `${opts.exclude.providerId}/${opts.exclude.model}`\n : undefined;\n\n const resolved: FallbackChainEntry[] = [];\n const seen = new Set<string>();\n\n for (const ref of chain) {\n const parsed = parseModelRef(ref);\n if (!parsed.model) continue;\n\n const providerId = parsed.provider ?? defaultProvider;\n const key = `${providerId}/${parsed.model}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n // Skip self-reference\n if (excludeKey && key === excludeKey) continue;\n\n const health = this.checkProvider(providerId);\n if (!health.usable) continue;\n\n // Skip entries that are blocked by the runtime status tracker\n if (this.statusTracker && !this.statusTracker.isAvailable(providerId, parsed.model)) continue;\n if (\n !evaluateModelCalendar(this.config.modelAvailabilitySchedule, providerId, parsed.model)\n .allowed\n )\n continue;\n\n // Skip entries whose provider has no matching model in its allow-list\n // (provider may restrict which models are available).\n const allowedModels = this.config.providers?.[providerId]?.models;\n if (allowedModels && !allowedModels.includes(parsed.model)) continue;\n\n resolved.push({\n providerId,\n model: parsed.model,\n providerSwitched: providerId !== (opts.exclude?.providerId ?? this.config.provider),\n });\n }\n\n return Object.freeze(resolved);\n }\n\n /**\n * Resolve the effective fallback chain for a session: explicit fallbackModels\n * first, then named profile, then smart default (unless disabled).\n *\n * Mirrors the previous `effectiveFallbackChain()` logic but centralized.\n */\n resolveEffective(\n opts: {\n fallbackModels?: readonly string[] | undefined;\n fallbackProfile?: string | undefined;\n fallbackAuto?: boolean | undefined;\n exclude?: { providerId: string; model: string } | undefined;\n } = {},\n ): FallbackChain {\n // 1. Explicit fallbackModels (already resolved refs)\n // Only return if non-empty; empty chain falls through to next source.\n if (opts.fallbackModels && opts.fallbackModels.length > 0) {\n const resolved = this.resolveRefs(opts.fallbackModels, opts.exclude);\n if (resolved.length > 0) return resolved;\n }\n\n // 2. Named profile \u2014 only return if non-empty\n if (opts.fallbackProfile) {\n const resolved = this.resolve(opts.fallbackProfile, { exclude: opts.exclude });\n if (resolved.length > 0) return resolved;\n }\n\n // 3. Smart default\n if (opts.fallbackAuto !== false) {\n return this.smartDefault(opts.exclude);\n }\n\n return FREEZER_EMPTY;\n }\n\n // \u2500\u2500 Provider availability (read-only) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n checkProvider(providerId: string): ProviderHealth {\n const entry = this.config.providers?.[providerId];\n const isPrimary = providerId === this.config.provider;\n const hasKey = providerHasKey(entry) || (isPrimary && hasText(this.config.apiKey));\n const hasEndpoint = hasText(entry?.baseUrl) || (isPrimary && hasText(this.config.baseUrl));\n const hasModels =\n (Array.isArray(entry?.models) && entry.models.length > 0) ||\n (isPrimary && hasText(this.config.model));\n return Object.freeze({\n providerId,\n hasKey,\n hasEndpoint,\n hasModels,\n usable: hasKey || hasEndpoint,\n });\n }\n\n // \u2500\u2500 Rebuild on config change \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Atomically replace the active immutable snapshot while preserving this\n * service identity for every injected consumer.\n */\n reload(newConfig: Config): void {\n this.config = newConfig;\n this.profiles = buildProfiles(newConfig);\n }\n\n // \u2500\u2500 Internal helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Resolve an array of model ref strings (from explicit fallbackModels config).\n * Public so consumers like one-shot-llm can use it directly.\n */\n resolveRefs(\n refs: readonly string[],\n exclude?: { providerId: string; model: string },\n ): FallbackChain {\n const excludeKey = exclude ? `${exclude.providerId}/${exclude.model}` : undefined;\n const resolved: FallbackChainEntry[] = [];\n const seen = new Set<string>();\n\n for (const ref of refs) {\n const parsed = parseModelRef(ref);\n if (!parsed.model) continue;\n\n const providerId = parsed.provider ?? this.config.provider;\n const key = `${providerId}/${parsed.model}`;\n if (seen.has(key)) continue;\n seen.add(key);\n if (excludeKey && key === excludeKey) continue;\n\n // Skip entries blocked by the runtime status tracker\n if (this.statusTracker && !this.statusTracker.isAvailable(providerId, parsed.model)) continue;\n if (\n !evaluateModelCalendar(this.config.modelAvailabilitySchedule, providerId, parsed.model)\n .allowed\n )\n continue;\n\n resolved.push({\n providerId,\n model: parsed.model,\n providerSwitched: providerId !== (exclude?.providerId ?? this.config.provider),\n });\n }\n\n return Object.freeze(resolved);\n }\n\n /**\n * Derive a smart default chain from configured providers when nothing\n * explicit is set. Same-provider alternatives first, then cross-provider.\n * Limited to 4 entries to avoid burning through models on a transient blip.\n */\n private smartDefault(exclude?: { providerId: string; model: string }): FallbackChain {\n const leaderProvider = this.config.provider;\n const leaderModel = this.config.model;\n const providers = this.config.providers ?? {};\n const favoriteSet = new Set(\n (this.config.favoriteModels ?? []).map((ref) => {\n const p = parseModelRef(ref);\n return `${p.provider ?? leaderProvider}/${p.model}`;\n }),\n );\n const hasFavorites = favoriteSet.size > 0;\n const favoritesOnly = this.config.favoriteModelsOnly === true;\n const seen = new Set<string>();\n const favorites: string[] = [];\n const sameProvider: string[] = [];\n const crossProvider: string[] = [];\n\n const excludeKey = exclude ? `${exclude.providerId}/${exclude.model}` : undefined;\n\n const ids = Object.keys(providers).sort((a, b) =>\n a === leaderProvider ? -1 : b === leaderProvider ? 1 : a.localeCompare(b),\n );\n\n for (const id of ids) {\n const entry = providers[id];\n if (!this.checkProvider(id).usable) continue;\n // Skip the entire provider if it's blocked at the provider level\n // (all its models would be blocked too, but we check per-model below)\n const models = visibleProviderModels(this.config, id, entry?.models ?? []);\n for (const model of models) {\n if (id === leaderProvider && model === leaderModel) continue;\n const ref = `${id}/${model}`;\n if (seen.has(ref)) continue;\n seen.add(ref);\n if (excludeKey && ref === excludeKey) continue;\n // Skip models blocked by the runtime status tracker\n if (this.statusTracker && !this.statusTracker.isAvailable(id, model)) continue;\n if (!evaluateModelCalendar(this.config.modelAvailabilitySchedule, id, model).allowed)\n continue;\n if (favoriteSet.has(ref)) {\n favorites.push(ref);\n continue;\n }\n if (favoritesOnly && hasFavorites) continue;\n (id === leaderProvider ? sameProvider : crossProvider).push(ref);\n }\n }\n\n const MAX = 4;\n const all = [...favorites, ...sameProvider, ...crossProvider].slice(0, MAX);\n return Object.freeze(\n all.map((ref) => {\n const p = parseModelRef(ref);\n return {\n providerId: p.provider ?? leaderProvider,\n model: p.model,\n providerSwitched:\n (p.provider ?? leaderProvider) !== (exclude?.providerId ?? leaderProvider),\n } satisfies FallbackChainEntry;\n }),\n );\n }\n}\n\nconst FREEZER_EMPTY: FallbackChain = Object.freeze([]);\n", "/**\n * Cross-provider fallback model extension.\n *\n * Lives in core so EVERY agent surface can reuse it: the CLI leader, the CLI\n * director/host subagent factory, and the runtime light subagent factory (used\n * by standalone SDD runs). It wraps the provider runner and, when the active\n * model 429s / overloads / stream-hangs, rotates through a fallback chain. The\n * chain is recomputed from live config every turn, so changes take effect\n * without a restart; an empty chain makes the wrapper a no-op.\n *\n * Moved here from `@wrongstack/cli` (it only ever depended on core types) so the\n * runtime light factory can wire fallbacks for SDD worker subagents.\n */\n\nimport type { ProviderModelStatusTracker } from '../coordination/provider-status-tracker.js';\nimport type { AgentExtension } from '../extension/extension-points.js';\nimport type { EventBus } from '../kernel/events.js';\nimport { isTextBlock, isToolUseBlock } from '../types/blocks.js';\nimport type { Config } from '../types/config.js';\nimport type { Logger } from '../types/logger.js';\nimport {\n isFallbackWorthy,\n type Provider,\n ProviderError,\n type Response,\n} from '../types/provider.js';\nimport { resolveEventSessionId } from './context.js';\nimport type { FallbackChain, FallbackChainEntry } from './fallback-profile-manager.js';\nimport { FallbackProfileManager } from './fallback-profile-manager.js';\nimport { evaluateModelCalendar, logicalCalendarTarget } from './model-availability-calendar.js';\nimport { bindRequestProvider } from './request-provider-binding.js';\n\nexport type { ModelRef } from './model-ref.js';\n// Compatibility: the canonical leaf implementation lives in model-ref.ts.\nexport { formatModelRef, normalizeModelRef, parseModelRef } from './model-ref.js';\n\nexport interface FallbackModelDeps {\n /** Returns the live config (re-read each turn so `/model` switches are honored). */\n getConfig: () => Config;\n /** Shared live manager from the runtime container. */\n fallbackProfileManager?: FallbackProfileManager | undefined;\n /** Live named profile selected for this worker (for example by `/setmodel`). */\n getFallbackProfile?: (() => string | undefined) | undefined;\n /** Live task/role-specific chain. Explicit task fallbacks may return a stable list. */\n getFallbackModels?: (() => readonly string[] | undefined) | undefined;\n /** Worker-local primary; prevents a subagent fallback from restoring the leader model. */\n getPrimaryTarget?: (() => { providerId: string; model: string } | undefined) | undefined;\n /** When true, only the explicitly supplied fallback chain may be attempted. */\n isClosedWorld?: (() => boolean) | undefined;\n /**\n * Builds a credential-resolved Provider for a provider id (alias-resolved),\n * WITHOUT persisting anything to config/configStore. Supplied by the boot\n * path, which shares this with the `/model` switch logic. May be async \u2014 the\n * subagent host resolves a provider's real context window asynchronously.\n */\n buildProvider: (providerId: string, modelId?: string | undefined) => Provider | Promise<Provider>;\n /**\n * Called after the active model changes (a fallback hop or the primary\n * restore) so the host can refresh the auto-compaction / context-window\n * denominator \u2014 important when a fallback crosses to a smaller-window model.\n */\n onModelSwitch?: (providerId: string, modelId: string) => void | Promise<void>;\n events: EventBus;\n /** Optional \u2014 warnings about un-buildable fallback providers. */\n logger?: Logger | undefined;\n /**\n * Base cooldown after the configured primary fails with a fallback-worthy\n * error. While active, `beforeRun` leaves the context on the working fallback\n * instead of retrying the primary at the start of every turn. Default: 60s.\n * Set 0 to preserve the legacy \"probe primary every turn\" behavior.\n */\n primaryCooldownMs?: number | undefined;\n /**\n * Maximum exponential cooldown for repeated failed primary probes. Default:\n * 10 minutes. Ignored when `primaryCooldownMs` is 0.\n */\n primaryCooldownMaxMs?: number | undefined;\n /**\n * Number of consecutive primary successes required to fully reset the\n * failure ladder after a cooldown expiry. Set 1 for the legacy \"one\n * success fully resets\" behavior; higher values prevent an\n * intermittently-available primary from causing model bouncing \u2014 the\n * streak is retained across a single success so the next failure\n * continues the exponential backoff instead of restarting at 1.\n * Default: 2.\n */\n primaryRecoverySuccesses?: number | undefined;\n /**\n * Minimum number of turns to dwell on a working fallback before the\n * primary becomes eligible for a half-open probe \u2014 even if the cooldown\n * timer has already expired. Default: 0 (timer alone governs).\n * Set to e.g. 3 to require three full turns on the fallback before the\n * system risks switching back to the primary.\n */\n stickyFallbackTurns?: number | undefined;\n /** Test hook for deterministic cooldown assertions. */\n now?: (() => number) | undefined;\n /**\n * Shared provider/model status tracker. When set, the extension records\n * failures and successes in the tracker, and skips blocked entries in\n * the fallback chain.\n */\n statusTracker?: ProviderModelStatusTracker | undefined;\n}\n\nexport function fallbackProfileChain(config: Config, profileName: string | undefined): string[] {\n if (!profileName) return [];\n const mgr = new FallbackProfileManager(config);\n return mgr.resolve(profileName).map((e) => `${e.providerId}/${e.model}`);\n}\n\n/**\n * Check if an error should trigger a fallback. Returns the status for\n * logging, or null if the error doesn't warrant a fallback attempt.\n *\n * Branches on the canonical `ProviderError.kind`: capacity/availability\n * failures (rate limit, overload, server error, stream hang, timeout,\n * network) are worth trying on another provider; request-shaped failures\n * (auth, invalid request, context overflow, content filter) would fail\n * identically anywhere \u2014 or need a different remedy (compaction, key fix) \u2014\n * so they surface instead.\n */\nfunction shouldFallback(err: unknown): number | null {\n if (!(err instanceof ProviderError) && !ProviderError.isProviderError(err)) return null;\n const kind = (err as ProviderError).kind;\n return isFallbackWorthy(kind) ? (err as ProviderError).status : null;\n}\n\nfunction isUsableModelResponse(response: Response): boolean | undefined {\n if (!response?.content) return undefined;\n return response.content.some(\n (block) => isToolUseBlock(block) || (isTextBlock(block) && block.text.trim().length > 0),\n );\n}\n\nfunction ensureUsableModelResponse(\n response: Response,\n providerId: string,\n model: string,\n): Response {\n const usable = isUsableModelResponse(response);\n // undefined content means the caller didn't provide a content field (e.g. test mocks) \u2014 let it through\n if (usable !== false) return response;\n throw new ProviderError(\n `Empty response from ${providerId}/${model}; trying the next configured model`,\n 503,\n true,\n providerId,\n { kind: 'overloaded' },\n );\n}\n\nexport function smartDefaultFallbackChain(config: Config): string[] {\n const mgr = new FallbackProfileManager(config);\n return mgr.resolveEffective({ fallbackAuto: true }).map((e) => `${e.providerId}/${e.model}`);\n}\n\n/**\n * The effective fallback chain for a turn: the explicit `fallbackModels` list\n * when non-empty, otherwise the smart default (unless `fallbackAuto` is off).\n */\nexport function effectiveFallbackChain(config: Config): string[] {\n const mgr = new FallbackProfileManager(config);\n return mgr\n .resolveEffective({\n fallbackModels: config.fallbackModels,\n fallbackAuto: config.fallbackAuto,\n })\n .map((e) => `${e.providerId}/${e.model}`);\n}\n\nconst DEFAULT_PRIMARY_COOLDOWN_MS = 60_000;\nconst DEFAULT_PRIMARY_COOLDOWN_MAX_MS = 10 * 60_000;\nconst DEFAULT_PRIMARY_RECOVERY_SUCCESSES = 2;\n\nfunction sameTarget(\n a: { providerId: string; model: string } | undefined,\n b: { providerId: string; model: string },\n): boolean {\n return !!a && a.providerId === b.providerId && a.model === b.model;\n}\n\nfunction fallbackCandidates(\n config: Config,\n current: { providerId: string; model: string },\n opts: {\n fallbackModels?: readonly string[] | undefined;\n fallbackProfile?: string | undefined;\n sharedManager?: FallbackProfileManager | undefined;\n primary?: { providerId: string; model: string } | undefined;\n closedWorld?: boolean | undefined;\n } = {},\n): FallbackChain {\n const mgr = opts.sharedManager ?? new FallbackProfileManager(config);\n const configuredPrimary = opts.primary ?? primaryTarget(config);\n // The effective fallbackAuto: honour the config explicitly, fall back to\n // !closedWorld only when config.fallbackAuto is undefined/null.\n const configFallbackAuto = config.fallbackAuto;\n const effectiveFallbackAuto =\n configFallbackAuto !== undefined && configFallbackAuto !== null\n ? configFallbackAuto\n : !opts.closedWorld;\n const selectedChain = mgr.resolveEffective({\n fallbackModels: opts.fallbackModels ?? config.fallbackModels,\n fallbackProfile: opts.fallbackProfile,\n fallbackAuto: effectiveFallbackAuto,\n exclude: current,\n });\n const candidates: FallbackChainEntry[] = [];\n\n // A model allowlist is a permission boundary. Never append the session\n // model, default profile, or auto-discovered providers outside that boundary.\n if (opts.closedWorld) {\n candidates.push(...selectedChain);\n const seen = new Set<string>();\n return Object.freeze(\n candidates.filter((entry) => {\n const key = `${entry.providerId}/${entry.model}`;\n if (key === `${current.providerId}/${current.model}` || seen.has(key)) return false;\n seen.add(key);\n return true;\n }),\n );\n }\n\n // 1. A live config or role-selected primary is the user's current model\n // choice, so try it before any fallback entries when the active context\n // is still on an older model.\n if (!sameTarget(configuredPrimary, current)) {\n candidates.push({\n providerId: configuredPrimary.providerId,\n model: configuredPrimary.model,\n providerSwitched: configuredPrimary.providerId !== current.providerId,\n });\n }\n\n // 2. Preserve the exact order of the user's explicit / role-selected chain.\n candidates.push(...selectedChain);\n\n // 3. The default profile is additional fallback depth (unless we already\n // resolved it as the selected chain above).\n if (opts.fallbackProfile !== 'default') {\n candidates.push(...mgr.resolve('default', { exclude: current }));\n }\n\n // 4. Every other configured provider as a last resort \u2014 but only\n // when fallbackAuto is actually enabled.\n if (effectiveFallbackAuto) {\n const smartDefaults = mgr.resolveEffective({ fallbackAuto: true, exclude: current });\n candidates.push(...smartDefaults);\n }\n\n const seen = new Set<string>();\n return Object.freeze(\n candidates.filter((entry) => {\n const key = `${entry.providerId}/${entry.model}`;\n if (key === `${current.providerId}/${current.model}` || seen.has(key)) return false;\n seen.add(key);\n return true;\n }),\n );\n}\n\nconst primaryTarget = (cfg: Config) => ({ providerId: cfg.provider, model: cfg.model });\n\nfunction maxContextOf(provider: Provider): number {\n const max = provider.capabilities.maxContext;\n return typeof max === 'number' && Number.isFinite(max) ? max : 0;\n}\n\nfunction contextWindowWarning(\n currentProvider: Provider,\n nextProvider: Provider,\n currentTokens: unknown,\n):\n | { fromMaxContext: number; toMaxContext: number; currentTokens?: number | undefined }\n | undefined {\n const fromMaxContext = maxContextOf(currentProvider);\n const toMaxContext = maxContextOf(nextProvider);\n if (fromMaxContext <= 0 || toMaxContext <= 0 || toMaxContext >= fromMaxContext) return undefined;\n return {\n fromMaxContext,\n toMaxContext,\n ...(typeof currentTokens === 'number' && currentTokens > 0 ? { currentTokens } : {}),\n };\n}\n\n/**\n * Build the cross-provider fallback extension. Always returns an extension \u2014\n * the effective chain (`effectiveFallbackChain`) is recomputed every turn from\n * the live config, so a chain that is empty at boot but populated later (via\n * `/fallback add` or the smart default kicking in once a key is added) takes\n * effect WITHOUT a restart. An empty chain makes the wrapper a no-op (it just\n * rethrows the original error).\n *\n * Mechanism (see plan): wraps the provider runner. The inner runner already\n * applies the per-model retry policy (backoff, up to 5 tries for 429), so the\n * fallback only engages AFTER the active model's own retries are exhausted.\n * Because the wrapper resolves within a single provider call, it does not\n * consume the agent loop's `recoveryRetries` budget \u2014 chains longer than two\n * entries work. `beforeRun` keeps the last working fallback while the primary\n * is cooling down, then restores the configured primary for a half-open probe.\n */\nexport function createFallbackModelExtension(deps: FallbackModelDeps): AgentExtension {\n // True when a prior turn left the live context on a fallback model.\n let dirty = false;\n let primaryFailureStreak = 0;\n let primaryRecoveryHits = 0;\n let stickyTurnsElapsed = 0;\n // Remembers the last fallback model that succeeded so the chain can\n // front-load it on subsequent primary failures \u2014 avoiding a full\n // re-traversal through flaky entries that were already tried.\n let lastWorkingFallback: { providerId: string; model: string } | undefined;\n let blockedPrimary: { providerId: string; model: string } | undefined;\n let primaryBlockedUntil = 0;\n\n const now = () => deps.now?.() ?? Date.now();\n const cooldownBase = () => Math.max(0, deps.primaryCooldownMs ?? DEFAULT_PRIMARY_COOLDOWN_MS);\n const cooldownMax = () =>\n Math.max(cooldownBase(), deps.primaryCooldownMaxMs ?? DEFAULT_PRIMARY_COOLDOWN_MAX_MS);\n const selectedPrimary = (cfg: Config) => deps.getPrimaryTarget?.() ?? primaryTarget(cfg);\n const primaryInCooldown = (cfg: Config) =>\n sameTarget(blockedPrimary, selectedPrimary(cfg)) && now() < primaryBlockedUntil;\n\n const markPrimaryFailure = (cfg: Config) => {\n const primary = selectedPrimary(cfg);\n primaryFailureStreak = sameTarget(blockedPrimary, primary) ? primaryFailureStreak + 1 : 1;\n // A failure breaks any in-progress recovery chain.\n primaryRecoveryHits = 0;\n // A new fallback hop starts the sticky-dwell window from zero.\n stickyTurnsElapsed = 0;\n blockedPrimary = primary;\n const base = cooldownBase();\n if (base <= 0) {\n primaryBlockedUntil = 0;\n return;\n }\n const multiplier = 2 ** Math.max(0, primaryFailureStreak - 1);\n primaryBlockedUntil = now() + Math.min(cooldownMax(), base * multiplier);\n };\n\n const recoveryTarget = () =>\n Math.max(1, deps.primaryRecoverySuccesses ?? DEFAULT_PRIMARY_RECOVERY_SUCCESSES);\n\n const stickyTarget = () => Math.max(0, deps.stickyFallbackTurns ?? 0);\n\n /** Whether the mandatory fallback dwell period is still in effect. */\n const inStickyWindow = () => stickyTurnsElapsed < stickyTarget();\n\n /**\n * Graduated primary recovery: a single success does NOT fully reset the\n * failure ladder. The streak is retained so the next failure continues\n * the exponential backoff instead of restarting at 1 \u2014 preventing an\n * intermittently-available primary from causing endless model bouncing.\n * Only after `recoveryTarget()` consecutive successes is the ladder\n * fully cleared.\n */\n const onPrimarySuccess = (cfg: Config) => {\n if (!sameTarget(blockedPrimary, selectedPrimary(cfg))) return;\n primaryRecoveryHits += 1;\n if (primaryRecoveryHits >= recoveryTarget()) {\n // Enough consecutive successes \u2014 fully clear the ladder.\n primaryFailureStreak = 0;\n primaryRecoveryHits = 0;\n stickyTurnsElapsed = 0;\n lastWorkingFallback = undefined;\n blockedPrimary = undefined;\n primaryBlockedUntil = 0;\n } else {\n // Partial recovery: allow probing next turn but retain the streak\n // so a subsequent failure continues the exponential backoff.\n primaryBlockedUntil = 0;\n }\n };\n\n return {\n name: 'fallback-model',\n\n beforeRun: async (ctx) => {\n if (!dirty) return;\n const cfg = deps.getConfig();\n const primary = selectedPrimary(cfg);\n\n // \u2500\u2500 Sticky fallback dwell \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Count this turn as one completed turn on the working fallback.\n // If we haven't yet dwelled for `stickyTarget()` turns, stay on\n // the fallback even if the cooldown timer has expired.\n stickyTurnsElapsed += 1;\n if (inStickyWindow()) return;\n\n if (primaryInCooldown(cfg)) return;\n if (\n !evaluateModelCalendar(cfg.modelAvailabilitySchedule, primary.providerId, primary.model)\n .allowed ||\n (deps.statusTracker && !deps.statusTracker.isAvailable(primary.providerId, primary.model))\n )\n return;\n try {\n ctx.provider = await deps.buildProvider(primary.providerId, primary.model);\n ctx.model = primary.model;\n await deps.onModelSwitch?.(primary.providerId, primary.model);\n // The next provider call is the half-open primary probe. If it\n // succeeds, onPrimarySuccess will either partially clear (allowing\n // another probe) or fully reset the ladder (after recoveryTarget\n // consecutive successes). If it fails, the catch path marks a\n // longer cooldown and rotates back through the chain.\n primaryBlockedUntil = 0;\n } catch (err) {\n deps.logger?.warn(\n `fallback-model: could not restore primary \"${primary.providerId}/${primary.model}\": ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n markPrimaryFailure(cfg);\n return;\n }\n dirty = false;\n },\n\n wrapProviderRunner: async (ctx, request, inner) => {\n // \u2500\u2500 Before calling, check if the current provider/model is blocked \u2500\u2500\n const tracker = deps.statusTracker;\n const calendar = evaluateModelCalendar(\n deps.getConfig().modelAvailabilitySchedule,\n ctx.provider.id,\n ctx.model,\n );\n const trackerBlocked = tracker ? !tracker.isAvailable(ctx.provider.id, ctx.model) : false;\n if (trackerBlocked || !calendar.allowed) {\n deps.logger?.warn(\n `provider-status: \"${ctx.provider.id}/${ctx.model}\" is blocked \u2014 trying fallback chain`,\n );\n // Emit active_blocked so the UI can surface a prominent warning\n const status = tracker?.getStatus(ctx.provider.id, ctx.model);\n const logical =\n tracker?.logicalIdentity(ctx.provider.id, ctx.model) ??\n logicalCalendarTarget(ctx.provider.id, ctx.model);\n deps.events.emit('provider.active_blocked', {\n providerId: logical.providerId,\n model: logical.model,\n state: 'blocked',\n fallbackProviderId: '',\n fallbackModel: '',\n lastError:\n calendar.rule?.label ??\n (calendar.rule ? 'Blocked by model availability calendar' : undefined) ??\n status?.lastErrorMessage ??\n 'Rate limit or repeated failures',\n sessionId: resolveEventSessionId(ctx),\n timestamp: Date.now(),\n });\n // Skipping the blocked primary \u2014 simulate a fallback-worthy error\n const skipErr = new ProviderError(\n `Skipping unavailable \"${ctx.provider.id}/${ctx.model}\" \u2014 try fallback`,\n 429,\n true,\n ctx.provider.id,\n { kind: 'rate_limit' },\n );\n return runFallbackChain(ctx, request, inner, skipErr, true);\n }\n\n try {\n const response = ensureUsableModelResponse(\n await inner(ctx, request),\n ctx.provider.id,\n ctx.model,\n );\n // Record success in the tracker\n tracker?.recordSuccess(ctx.provider.id, ctx.model, {\n sessionId: resolveEventSessionId(ctx),\n agentId: ctx.agentId,\n });\n const cfg = deps.getConfig();\n const primary = selectedPrimary(cfg);\n if (ctx.provider.id === primary.providerId && ctx.model === primary.model) {\n onPrimarySuccess(cfg);\n }\n return response;\n } catch (firstErr) {\n return runFallbackChain(ctx, request, inner, firstErr);\n }\n\n // \u2500\u2500 Shared fallback-chain runner with tracker integration \u2500\u2500\n async function runFallbackChain(\n ctx_: typeof ctx,\n request_: typeof request,\n inner_: typeof inner,\n firstErr_: unknown,\n alreadyTracked = false,\n ): Promise<Response> {\n let lastErr: unknown = firstErr_;\n const cfg = deps.getConfig();\n const current = { providerId: ctx_.provider.id, model: ctx_.model };\n\n // Record the failure in the tracker (real ProviderError, not our synthetic skip)\n const firstErrIsProvider = firstErr_ instanceof ProviderError || ProviderError.isProviderError(firstErr_);\n if (!alreadyTracked && firstErrIsProvider && tracker) {\n tracker.recordFailure(\n ctx_.provider.id,\n ctx_.model,\n (firstErr_ as ProviderError).kind,\n (firstErr_ as ProviderError).status,\n (firstErr_ as ProviderError).describe(),\n {\n sessionId: resolveEventSessionId(ctx_),\n agentId: ctx_.agentId,\n retryAfterMs: firstErr_.body?.retryAfterMs,\n },\n );\n }\n\n const chain = fallbackCandidates(cfg, current, {\n fallbackModels: deps.getFallbackModels?.(),\n fallbackProfile: deps.getFallbackProfile?.(),\n sharedManager: deps.fallbackProfileManager,\n primary: selectedPrimary(cfg),\n closedWorld: deps.isClosedWorld?.() ?? false,\n });\n\n // Filter blocked entries from the chain via the tracker\n let usableChain = tracker\n ? chain.filter((e) => tracker.isAvailable(e.providerId, e.model))\n : chain;\n\n // \u2500\u2500 Last-working-fallback prioritization \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // If a prior turn found a model that worked, move it to the front\n // of the chain so we don't re-traverse flaky entries that already\n // failed. The dedup filter in fallbackCandidates already removed\n // duplicates, so this is a stable re-order, not a duplication.\n if (\n lastWorkingFallback &&\n usableChain.length > 1 &&\n // Don't front-load if the last-working is the current model\n // (we're already on it) or if it's now blocked.\n !(lastWorkingFallback.providerId === current.providerId &&\n lastWorkingFallback.model === current.model) &&\n !(tracker && !tracker.isAvailable(lastWorkingFallback.providerId, lastWorkingFallback.model))\n ) {\n const lwfKey = `${lastWorkingFallback.providerId}/${lastWorkingFallback.model}`;\n const lwfEntry = usableChain.find(\n (e) => `${e.providerId}/${e.model}` === lwfKey,\n );\n if (lwfEntry) {\n usableChain = [\n lwfEntry,\n ...usableChain.filter((e) => `${e.providerId}/${e.model}` !== lwfKey),\n ];\n }\n }\n\n if (\n !alreadyTracked &&\n shouldFallback(firstErr_) !== null &&\n sameTarget(selectedPrimary(cfg), current)\n ) {\n markPrimaryFailure(cfg);\n }\n\n // Gate ONCE, on the error that TRIGGERED the fallback \u2014 not per entry\n // on `lastErr`.\n //\n // `lastErr` is reassigned by every failed attempt below, so the old\n // per-entry check let ONE bad candidate abort the whole chain: a model\n // id that no longer exists on its provider answers 404, which\n // classifies as `invalid_request` (not fallback-worthy), and the next\n // iteration hit `break`. Every healthy entry after it went untried and\n // the turn died with \"model not found\" while a working fallback sat\n // one slot down. Stale entries are easy to acquire \u2014 `resolveRefs`\n // never validates `fallbackModels` against the provider's model list,\n // `buildProvider` ignores the model argument entirely, and\n // `config.providers[].models` is an unrefreshed snapshot.\n //\n // A per-entry failure now just moves to the next candidate; only the\n // triggering error decides whether we fall back at all.\n const status = shouldFallback(firstErr_);\n if (status === null) throw firstErr_; // not a fallback-worthy error\n\n for (const entry of usableChain) {\n if (\n !evaluateModelCalendar(cfg.modelAvailabilitySchedule, entry.providerId, entry.model)\n .allowed\n )\n continue;\n\n // Re-check tracker availability right before attempting this entry.\n // The chain was computed from a snapshot of `isAvailable`, but an\n // intervening failure \u2014 from a concurrent subagent, a prior entry\n // in this loop, or a race with the one-shot LLM helper \u2014 may have\n // pushed this (providerId, model) into the waiting room since then.\n // A stale-chain call would waste time and burn rate-limit budget.\n if (tracker && !tracker.isAvailable(entry.providerId, entry.model)) {\n deps.logger?.warn(\n `provider-status: \"${entry.providerId}/${entry.model}\" entered the waiting room` +\n ` since the chain was computed \u2014 skipping`,\n );\n continue;\n }\n\n const targetProviderId = entry.providerId;\n const targetModel = entry.model;\n if (targetProviderId === ctx_.provider.id && targetModel === ctx_.model) continue;\n if (\n primaryInCooldown(cfg) &&\n sameTarget(selectedPrimary(cfg), {\n providerId: targetProviderId,\n model: targetModel,\n })\n ) {\n continue;\n }\n\n const from = { providerId: ctx_.provider.id, model: ctx_.model };\n const logicalFrom = tracker?.logicalIdentity(from.providerId, from.model) ?? from;\n\n let nextProvider: Provider;\n try {\n nextProvider = await deps.buildProvider(targetProviderId, targetModel);\n } catch (err) {\n deps.logger?.warn(\n `fallback-model: skipping \"${targetProviderId}/${targetModel}\" \u2014 cannot build provider \"${targetProviderId}\": ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n continue;\n }\n\n // Pre-filter: if we know the current request's token count and this\n // fallback model's context window is provably too small, skip it\n // instead of dispatching a call that will fail with context_overflow\n // (which is NOT fallback-worthy and would surface as an error to the\n // user). The check is conservative: only skips when the INPUT alone\n // exceeds the window \u2014 if input fits, the call may still succeed.\n const entryMaxContext = maxContextOf(nextProvider);\n const currentTokens = ctx_.lastRequestTokens;\n if (\n entryMaxContext > 0 &&\n typeof currentTokens === 'number' &&\n currentTokens > 0 &&\n currentTokens > entryMaxContext\n ) {\n deps.logger?.warn(\n `fallback-model: skipping \"${targetProviderId}/${targetModel}\" \u2014 context window ` +\n `(${entryMaxContext}) is smaller than current request tokens (${currentTokens})`,\n );\n continue;\n }\n\n const providerSwitched = nextProvider.id !== from.providerId;\n const warning = contextWindowWarning(ctx_.provider, nextProvider, ctx_.lastRequestTokens);\n ctx_.provider = nextProvider;\n ctx_.model = targetModel;\n request_.model = targetModel;\n bindRequestProvider(request_, nextProvider);\n dirty = true;\n await deps.onModelSwitch?.(targetProviderId, targetModel);\n\n deps.events.emit('provider.fallback', {\n sessionId: resolveEventSessionId(ctx_),\n from: logicalFrom,\n to: tracker?.logicalIdentity(nextProvider.id, targetModel) ?? {\n providerId: nextProvider.id,\n model: targetModel,\n },\n status,\n providerSwitched,\n ...(warning ? { contextWindowWarning: warning } : {}),\n });\n\n try {\n const response = ensureUsableModelResponse(\n await inner_(ctx_, request_),\n ctx_.provider.id,\n ctx_.model,\n );\n tracker?.recordSuccess(nextProvider.id, targetModel, {\n sessionId: resolveEventSessionId(ctx_),\n agentId: ctx_.agentId,\n });\n // Remember this model so the next chain traversal front-loads it.\n lastWorkingFallback = { providerId: nextProvider.id, model: targetModel };\n return response;\n } catch (err) {\n // Record fallback failure too\n if ((err instanceof ProviderError || ProviderError.isProviderError(err)) && tracker) {\n tracker.recordFailure(\n nextProvider.id,\n targetModel,\n (err as ProviderError).kind,\n (err as ProviderError).status,\n (err as ProviderError).describe(),\n {\n sessionId: resolveEventSessionId(ctx_),\n agentId: ctx_.agentId,\n retryAfterMs: err.body?.retryAfterMs,\n },\n );\n }\n lastErr = err;\n }\n }\n\n throw lastErr;\n }\n },\n };\n}\n", "import type { CacheTtl, ReasoningEffort } from '../provider.js';\n\nexport interface ModelRuntimeReasoningConfig {\n /**\n * Whether to send explicit reasoning enable/disable.\n * - 'auto' \u2192 do not send explicit fields; provider/model default wins\n * - 'on' \u2192 send `reasoning.enabled = true`\n * - 'off' \u2192 send `reasoning.enabled = false` only when the model supports disable\n */\n mode?: 'auto' | 'on' | 'off' | undefined;\n /** Reasoning effort. Only sent when the model advertises `effortSupported`. */\n effort?: ReasoningEffort | undefined;\n /** Preserve thinking across turns. Only sent when `preserveThinking !== 'unsupported'`. */\n preserve?: boolean | undefined;\n}\n\n/**\n * Runtime prompt-cache controls mapped into `Request.cache`. Currently only the\n * Anthropic TTL toggle (5m vs 1h) is exposed; other providers ignore it.\n */\nexport interface ModelRuntimeCacheConfig {\n ttl?: CacheTtl | undefined;\n /**\n * Opt-in explicit Gemini context caching. When true, the Google provider\n * creates a server-side `cachedContents` resource for the stable system\n * prefix (system instruction + tool defs) and references it by name instead\n * of resending it every turn. Default false: Gemini's automatic *implicit*\n * caching already covers a byte-stable prefix with no setup. Ignored by every\n * non-Google provider. Any failure in the create flow falls back to the\n * normal inline request, so enabling it can never break a request.\n */\n geminiExplicit?: boolean | undefined;\n}\n\n/**\n * Shared runtime controls applied to every provider request, regardless of host\n * (REPL / TUI / WebUI). The CLI installs a single request-pipeline middleware\n * that reads these and mutates the outgoing `Request`.\n */\nexport interface ModelRuntimeConfig {\n reasoning?: ModelRuntimeReasoningConfig | undefined;\n cache?: ModelRuntimeCacheConfig | undefined;\n /**\n * Generic generation parameters mapped directly onto `Request` fields.\n * Only sent when the active model's `Capabilities` advertise support.\n */\n parameters?: ModelRuntimeParametersConfig | undefined;\n}\n\n/**\n * Selects which built-in/base system identity prompt file is used when building\n * the host system prompt. Surfaces keep `default` unless explicitly told to use\n * the lite or pro prompt.\n */\nexport interface SystemPromptConfig {\n variant?: 'default' | 'lite' | 'pro' | undefined;\n}\n\n/**\n * Generic generation parameters the user can set per-session / per-project.\n * Each field maps to a `Request` field of the same name and is gated by the\n * corresponding `Capabilities` flag so unsupported models don't receive\n * parameters they'd reject.\n */\nexport interface ModelRuntimeParametersConfig {\n /** Top-K sampling (Anthropic, Gemini). Gated by `capabilities.topK`. */\n topK?: number | undefined;\n /** Frequency penalty (OpenAI, Gemini). Gated by `capabilities.frequencyPenalty`. */\n frequencyPenalty?: number | undefined;\n /** Presence penalty (OpenAI, Gemini). Gated by `capabilities.presencePenalty`. */\n presencePenalty?: number | undefined;\n /** Random seed (OpenAI, Gemini). Gated by `capabilities.seed`. */\n seed?: number | undefined;\n /** End-user identifier for abuse monitoring. */\n user?: string | undefined;\n /** Log probabilities (OpenAI, Gemini). Gated by `capabilities.logprobs`. */\n logprobs?: boolean | undefined;\n /** Number of top logprobs to return (OpenAI). Only when `logprobs` is true. */\n topLogprobs?: number | undefined;\n}\n\n/**\n * HQ client connection settings. Same-machine clients can auto-discover the\n * local HQ auth file; remote clients use this config-backed URL/token pair.\n */\nexport interface HqClientConfig {\n /** Enable HQ publishing. Env WRONGSTACK_HQ_ENABLED still overrides at runtime. */\n enabled?: boolean | undefined;\n /** HQ HTTP base URL, e.g. http://host:3499. */\n url?: string | undefined;\n /** Client token for /ws/client. Stored encrypted by SecretVault when persisted. */\n token?: string | undefined;\n /** Optional HQ data dir for same-machine auth.json discovery. */\n dataDir?: string | undefined;\n /** Send raw content previews to HQ instead of redacted previews. */\n rawContent?: boolean | undefined;\n /** Override project display name in HQ. */\n projectAlias?: string | undefined;\n}\n\n/**\n * Token-saving mode tier levels. Controls how aggressively the system prompt\n * is compacted to reduce per-request token consumption.\n *\n * - 'off' \u2014 Full prompt, all tools, complete guidance (no reduction)\n * - 'minimal' \u2014 TIER1 tools (13, including codebase index lifecycle), stripped guidance\n * - 'light' \u2014 Same Tier 1 tool surface, common patterns, minimal guidance\n * - 'medium' \u2014 TIER1 + TIER2 development tools, some guidance (default when `true`)\n * - 'aggressive' \u2014 Maximum savings before tools become unusable (~4-5k tokens saved)\n */\n/**\n * Prompt token-saving tiers. `'auto'` is an INPUT-only sentinel meaning \"pick a\n * concrete tier from the model's context window\" \u2014 it is resolved to one of the\n * concrete tiers by {@link resolveTokenSavingTier} before reaching the prompt\n * builder (which never sees `'auto'`; if it somehow does, it behaves as `'off'`,\n * i.e. the full prompt \u2014 the safe fallback).\n */\nexport type TokenSavingTier = 'off' | 'auto' | 'minimal' | 'light' | 'medium' | 'aggressive';\n\n/** Concrete tiers the prompt builder actually consumes ('auto' excluded). */\nexport type ConcreteTokenSavingTier = Exclude<TokenSavingTier, 'auto'>;\n\n/**\n * Normalize a TokenSavingTier value, handling backward-compatible boolean inputs.\n * - `true` \u2192 'medium' (existing behavior)\n * - `false` \u2192 'off'\n * - `'auto'` \u2192 `'off'` \u2014 the `'auto'` sentinel is window-dependent, so EVERY\n * consumer that isn't the prompt builder (tool selection, lazy-load gate, TUI\n * display) must treat it as the safe no-op `'off'`: it must NOT reduce the\n * registered tool set or enable lazy loading on its own. Only the prompt\n * builder expands `'auto'` \u2014 via {@link resolveTokenSavingTier} \u2014 and only for\n * the (cache-stable) prompt prose. This keeps auto-tiering capability-neutral.\n * - other valid strings are returned as-is; `undefined`/invalid \u2192 'off'\n */\nexport function normalizeTokenSavingTier(val?: TokenSavingTier | boolean): ConcreteTokenSavingTier {\n if (val === undefined) return 'off';\n if (typeof val === 'boolean') return val ? 'medium' : 'off';\n const validTiers = new Set<ConcreteTokenSavingTier>([\n 'off',\n 'minimal',\n 'light',\n 'medium',\n 'aggressive',\n ]);\n // 'auto' is deliberately absent \u2192 collapses to 'off' for non-prompt consumers.\n return validTiers.has(val as ConcreteTokenSavingTier) ? (val as ConcreteTokenSavingTier) : 'off';\n}\n\n/**\n * Resolve the effective (concrete) token-saving tier for the **prompt builder**,\n * expanding the `'auto'` sentinel from the model's context window. This is\n * **cache-safe**: the window is stable for a session, so it resolves to the same\n * tier every turn \u2014 the system-prompt prefix stays byte-stable and the provider\n * prompt cache is never busted by a shifting tier (unlike a per-turn\n * pressure-driven tier). It re-resolves only on `/model` switch, which busts the\n * cache anyway.\n *\n * Modern threshold mapping \u2014 the system prompt (~12K tokens) is roughly the same\n * size regardless of context window; paying full price for it on every turn when\n * there is abundant headroom is wasteful. The tiers apply minimal trimming first,\n * escalating only when the window is genuinely tight:\n * - `< 32k` \u2192 `'medium'` (tiny window: identity + tool prose is a big fraction)\n * - `< 128k` \u2192 `'light'` (tight window: GPT-4 base class models)\n * - `>= 128k` \u2192 `'minimal'` (modern models: GPT-4o, Sonnet, DeepSeek, Qwen 3, Gemini 1M, Qwen 1M)\n * - unknown window \u2192 `'off'` (never guess a lean prompt without evidence)\n *\n * Explicit concrete tiers (a user who set `'medium'`, `'off'`, \u2026) are always\n * respected verbatim \u2014 `'auto'` is the only value that consults the window.\n */\nexport function resolveTokenSavingTier(\n val: TokenSavingTier | boolean | undefined,\n maxContext: number | undefined,\n): ConcreteTokenSavingTier {\n if (val === 'auto') {\n if (typeof maxContext !== 'number' || !Number.isFinite(maxContext) || maxContext <= 0) {\n return 'off';\n }\n if (maxContext < 32_000) return 'medium';\n if (maxContext < 128_000) return 'light';\n return 'minimal';\n }\n return normalizeTokenSavingTier(val);\n}\n\n// FleetChatVerbosity, FLEET_CHAT_VERBOSITY_VALUES, and resolveFleetChatVerbosity\n// were moved to the dependency-free leaf module ./fleet-chat.ts to avoid a\n// type-level import cycle with ./autonomy.ts. They are surfaced through the\n// config barrel (../config.ts) which re-exports ./config/fleet-chat.js directly.\n\nexport const DEFAULT_TUI_THINKING_WORD = 'thinking';\nexport const MAX_TUI_THINKING_WORD_LENGTH = 16;\n\n/**\n * Normalize the configurable statusline word shown while the TUI is working.\n * The value must be a single short word; invalid values fall back to the default.\n */\nexport function normalizeTuiThinkingWord(value: unknown): string {\n if (typeof value !== 'string') return DEFAULT_TUI_THINKING_WORD;\n const word = value.trim();\n if (word.length === 0 || word.length > MAX_TUI_THINKING_WORD_LENGTH) {\n return DEFAULT_TUI_THINKING_WORD;\n }\n if (!/^[\\p{L}\\p{N}_-]+$/u.test(word)) return DEFAULT_TUI_THINKING_WORD;\n return word;\n}\n", "import type { TextBlock } from './blocks.js';\nimport type { Tool } from './tool.js';\nimport type { MailboxAgentStatus } from '../coordination/mailbox-types.js';\n\n/** Model capabilities relevant to prompt composition. */\nexport interface ModelCapabilities {\n maxContextTokens: number;\n supportsTools: boolean;\n supportsVision: boolean;\n supportsReasoning: boolean;\n}\n\nexport interface BuildContext {\n cwd: string;\n projectRoot: string;\n tools: Tool[];\n /** Provider id (e.g. \"anthropic\", \"minimax-coding-plan\"). */\n provider?: string | undefined;\n /** Model id (e.g. \"configured-model\", \"MiniMax-M2.7\"). */\n model?: string | undefined;\n /**\n * True when the prompt is being built for a SUBAGENT, not the host\n * agent. Subagents are scoped to a single task \u2014 they should NOT see\n * the host's strategic plan board (which is anchoring the host across\n * turns, not steering individual subtasks). The plan-injection\n * layer short-circuits when this flag is set.\n */\n subagent?: boolean | undefined;\n /**\n * List of currently online agents in the shared mailbox system.\n * Includes agents from all clients, processes, sessions, branches, and\n * linked Git worktrees in the same canonical project.\n */\n onlineAgents?: MailboxAgentStatus[] | undefined;\n}\n\n/**\n * Stability regions for the system prompt.\n *\n * `core` and `session` form the provider-cache prefix and must remain byte-for-byte\n * stable after the first request in a session. `volatile` is appended at request\n * time and may change between turns without rewriting that prefix.\n */\nexport interface SystemPromptRegions {\n readonly core: readonly TextBlock[];\n readonly session: readonly TextBlock[];\n readonly volatile: readonly TextBlock[];\n}\n\nexport function flattenSystemPromptRegions(regions: SystemPromptRegions): TextBlock[] {\n return [...regions.core, ...regions.session, ...regions.volatile];\n}\n\nexport interface SystemPromptBuilder {\n build(ctx: BuildContext): Promise<TextBlock[]>;\n /** Region-aware build used by hosts that enforce prompt-prefix stability. */\n buildRegions?(ctx: BuildContext): Promise<SystemPromptRegions>;\n}\n", "import { statSync } from 'node:fs';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nexport interface SystemInstructionBundle {\n identity?: string | undefined;\n leaderAfterTask?: string | undefined;\n}\n\nexport interface InstructionBundle {\n version?: number | undefined;\n system?: SystemInstructionBundle | undefined;\n sections?: Record<string, string> | undefined;\n}\n\nexport type SystemInstructionVariant = 'default' | 'lite' | 'pro';\n\nexport interface InstructionBundlePaths {\n /** Bundled instruction directory. Defaults to `<@wrongstack/core>/instructions`. */\n bundledDir?: string | undefined;\n /** Profile override directory, e.g. `~/.wrongstack/profiles/<name>/instructions`. */\n globalDir?: string | undefined;\n /** Project override directory, e.g. `<project>/.wrongstack/instructions`. */\n projectDir?: string | undefined;\n /**\n * Selects the markdown file used for the system identity layer.\n * Defaults to `system.md`; `lite` reads `system-lite.md` and `pro` reads\n * `system-pro.md` from the same bundled/global/project instruction directories.\n */\n systemVariant?: SystemInstructionVariant | undefined;\n /**\n * Direct markdown filename for the system identity layer, for callers that\n * need an explicit file such as `system-pro.md` without introducing another\n * variant. Path separators are rejected so selection stays within each\n * instruction directory.\n */\n systemFile?: string | undefined;\n /** Extra override JSON files applied after projectDir, in order. */\n files?: readonly string[] | undefined;\n}\n\nexport async function loadInstructionBundle(\n paths: InstructionBundlePaths | undefined,\n): Promise<InstructionBundle> {\n let bundle: InstructionBundle = {};\n const systemFile = resolveSystemInstructionFile(paths);\n const dirs = [\n paths?.bundledDir ?? defaultBundledInstructionDir(),\n paths?.globalDir,\n paths?.projectDir,\n ].filter((p): p is string => typeof p === 'string' && p.trim().length > 0);\n\n for (const dir of dirs) {\n bundle = mergeInstructionBundle(bundle, await readInstructionDir(dir, { systemFile }));\n }\n for (const file of paths?.files ?? []) {\n bundle = mergeInstructionBundle(bundle, await readInstructionJson(file));\n }\n return bundle;\n}\n\nexport function mergeInstructionBundle(\n base: InstructionBundle,\n override: InstructionBundle,\n): InstructionBundle {\n return {\n ...base,\n ...definedPick(override, ['version']),\n system: {\n ...(base.system ?? {}),\n ...(override.system ?? {}),\n },\n sections: {\n ...(base.sections ?? {}),\n ...(override.sections ?? {}),\n },\n };\n}\n\nfunction resolveSystemInstructionFile(paths: InstructionBundlePaths | undefined): string {\n if (paths?.systemFile !== undefined) return sanitizeSystemInstructionFile(paths.systemFile);\n if (paths?.systemVariant === 'lite') return 'system-lite.md';\n if (paths?.systemVariant === 'pro') return 'system-pro.md';\n return 'system.md';\n}\n\nfunction sanitizeSystemInstructionFile(file: string): string {\n const trimmed = file.trim();\n if (\n trimmed.length === 0 ||\n trimmed !== path.basename(trimmed) ||\n path.extname(trimmed).toLowerCase() !== '.md'\n ) {\n throw new Error(`Invalid system instruction file: ${file}`);\n }\n return trimmed;\n}\n\nasync function readInstructionDir(\n dir: string,\n options: { systemFile: string },\n): Promise<InstructionBundle> {\n const [json, identity, leaderAfterTask, sections] = await Promise.all([\n readInstructionJson(path.join(dir, 'instructions.json')),\n readOptionalText(path.join(dir, options.systemFile)),\n readOptionalText(path.join(dir, 'leader-after-task.md')),\n readSections(path.join(dir, 'sections')),\n ]);\n const fromMarkdown: InstructionBundle = {\n system: {\n ...(identity !== undefined ? { identity } : {}),\n ...(leaderAfterTask !== undefined ? { leaderAfterTask } : {}),\n },\n sections,\n };\n return mergeInstructionBundle(json, fromMarkdown);\n}\n\nasync function readSections(root: string): Promise<Record<string, string>> {\n const out: Record<string, string> = {};\n await readSectionsInto(root, root, out);\n return out;\n}\n\nasync function readSectionsInto(\n root: string,\n dir: string,\n out: Record<string, string>,\n): Promise<void> {\n let entries: Array<import('node:fs').Dirent>;\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n await Promise.all(\n entries.map(async (entry) => {\n const file = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n await readSectionsInto(root, file, out);\n return;\n }\n if (!entry.isFile() || !entry.name.endsWith('.md')) return;\n const text = await readOptionalText(file);\n if (text === undefined) return;\n const rel = path.relative(root, file).replace(/\\\\/g, '/').replace(/\\.md$/i, '');\n const key = rel.split('/').join('.').replace(/-/g, '.');\n out[key] = text;\n }),\n );\n}\n\nasync function readInstructionJson(file: string): Promise<InstructionBundle> {\n let raw: string;\n try {\n raw = await fs.readFile(file, 'utf8');\n } catch {\n return {};\n }\n try {\n return normalizeInstructionBundle(JSON.parse(raw));\n } catch {\n return {};\n }\n}\n\nfunction normalizeInstructionBundle(value: unknown): InstructionBundle {\n if (!value || typeof value !== 'object') return {};\n const input = value as {\n version?: unknown;\n system?: unknown;\n sections?: unknown;\n };\n const system =\n input.system && typeof input.system === 'object'\n ? (input.system as { identity?: unknown; leaderAfterTask?: unknown })\n : undefined;\n const sections =\n input.sections && typeof input.sections === 'object'\n ? Object.fromEntries(\n Object.entries(input.sections as Record<string, unknown>).filter(\n (entry): entry is [string, string] => typeof entry[1] === 'string',\n ),\n )\n : undefined;\n return {\n ...(typeof input.version === 'number' ? { version: input.version } : {}),\n ...(system\n ? {\n system: {\n ...(typeof system.identity === 'string' ? { identity: system.identity } : {}),\n ...(typeof system.leaderAfterTask === 'string'\n ? { leaderAfterTask: system.leaderAfterTask }\n : {}),\n },\n }\n : {}),\n ...(sections ? { sections } : {}),\n };\n}\n\nasync function readOptionalText(file: string): Promise<string | undefined> {\n try {\n const text = await fs.readFile(file, 'utf8');\n return text.trimEnd();\n } catch {\n return undefined;\n }\n}\n\nfunction defaultBundledInstructionDir(): string {\n const here = path.dirname(fileURLToPath(import.meta.url));\n return firstExistingDirSync([\n path.resolve(here, '../../instructions'),\n path.resolve(here, '../instructions'),\n path.resolve(here, 'instructions'),\n ]);\n}\n\nfunction definedPick<T extends object, K extends keyof T>(obj: T, keys: readonly K[]): Partial<T> {\n const out: Partial<T> = {};\n for (const key of keys) {\n if (obj[key] !== undefined) out[key] = obj[key];\n }\n return out;\n}\n\nfunction firstExistingDirSync(candidates: readonly string[]): string {\n for (const candidate of candidates) {\n try {\n const stat = statSync(candidate);\n if (stat.isDirectory()) return candidate;\n } catch {\n // try next candidate\n }\n }\n return candidates[0] ?? '';\n}\n", "import { readFileSync, statSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nexport const PROMPT = readBundledInstructionFile('system.md');\n\n/**\n * Leader-only after-task affordances. The full text lives in\n * `packages/core/instructions/leader-after-task.md` so prompt wording can be\n * overridden without editing TypeScript.\n */\nexport const LEADER_AFTER_TASK_PROMPT = readBundledInstructionFile('leader-after-task.md');\n\nfunction readBundledInstructionFile(name: string): string {\n for (const dir of bundledInstructionDirCandidates()) {\n const file = path.join(dir, name);\n try {\n return readFileSync(file, 'utf8').trimEnd();\n } catch {\n // try next candidate\n }\n }\n return '';\n}\n\nfunction bundledInstructionDirCandidates(): string[] {\n const here = path.dirname(fileURLToPath(import.meta.url));\n const candidates = [\n path.resolve(here, '../../../instructions'),\n path.resolve(here, '../../instructions'),\n path.resolve(here, '../instructions'),\n path.resolve(here, 'instructions'),\n ];\n return candidates.sort((a, b) => Number(!isDirectory(a)) - Number(!isDirectory(b)));\n}\n\nfunction isDirectory(candidate: string): boolean {\n try {\n return statSync(candidate).isDirectory();\n } catch {\n return false;\n }\n}\n", "/**\n * Block provenance and the stateless render helpers of the system-prompt build.\n *\n * Split out of `system-prompt-builder.ts`. Everything here is pure: it depends\n * only on its arguments, so it moved out of the builder class unchanged.\n * `SystemBlockSource` / `SYSTEM_BLOCK_SOURCE` keep their re-export from\n * `system-prompt-builder.ts`, which remains the public import site.\n *\n * @module core/system-prompt-blocks\n */\nimport type { MailboxAgentStatus } from '../coordination/mailbox-types.js';\nimport type { TextBlock } from '../types/blocks.js';\nimport type { Tool } from '../types/tool.js';\nimport type { InstructionBundle } from './instruction-bundle.js';\n\n/**\n * The section of the system prompt a given TextBlock originated from. Used by\n * `getContextBreakdown()` to attribute real token counts per category in the\n * `/context` display.\n */\nexport type SystemBlockSource =\n | 'identity' // layer1 \u2014 instructions/system.md\n | 'tool-usage' // layer2 \u2014 tool prose summary\n | 'environment' // layer3 \u2014 OS/git/date/skills-in-scope\n | 'skills' // layer4 \u2014 Active Skills bodies (+ memory when injectMemory)\n | 'mode' // layer5 mode prompt + mode-skill hint\n | 'plan' // layer6 \u2014 active plan\n | 'leader-after-task' // leader-only after-task affordances\n | 'contributor' // plugin-contributed volatile blocks\n | 'ledger' // volatile completed-work ledger (request-time)\n | 'nextsteps'; // volatile next-steps gate (request-time)\n\n/**\n * Side-table mapping each system-prompt TextBlock to the section it came from.\n * Kept as a WeakMap rather than a field on TextBlock so the label never reaches\n * the wire: the provider adapters spread blocks verbatim (Anthropic non-ttl\n * `: b`, OpenAI `stripCacheControl` rest-spread), so any extra field would leak.\n * Block identities survive `flattenSystemPromptRegions` into `ctx.systemPrompt`,\n * so a later read of `ctx.systemPrompt` resolves the same entries.\n */\nexport const SYSTEM_BLOCK_SOURCE = new WeakMap<TextBlock, SystemBlockSource>();\n\n/** Tag a freshly-built block with its origin, returning the same reference. */\nexport function tagBlock(block: TextBlock, source: SystemBlockSource): TextBlock {\n SYSTEM_BLOCK_SOURCE.set(block, source);\n return block;\n}\n\nexport function shortSessionId(sessionId: string): string {\n const leaf = sessionId.split('/').pop() ?? sessionId;\n return leaf.length > 12 ? `${leaf.slice(0, 12)}\u2026` : leaf;\n}\n\nexport function instructionSection(\n bundle: InstructionBundle,\n key: string,\n vars: Record<string, string | number> = {},\n): string {\n const template = bundle.sections?.[key];\n if (!template) return '';\n return template.replace(/\\{\\{\\s*([a-zA-Z0-9_.-]+)\\s*\\}\\}/g, (match, name: string) => {\n const value = vars[name];\n return value === undefined ? match : String(value);\n });\n}\n\nexport function renderToolSelectionBoundary(tool: Tool): string {\n const selection = tool.selection;\n if (!selection?.doNotUseWhen.trim()) return '';\n const alternatives = selection.useInstead?.filter(Boolean) ?? [];\n const instead =\n alternatives.length > 0\n ? ` Use ${alternatives.map((name) => `\\`${name}\\``).join(' or ')} instead.`\n : '';\n return `Do not use when ${selection.doNotUseWhen.trim()}${instead}`;\n}\n\n/**\n * Cheap content fingerprint of the online agents array. The mailbox\n * rebuilds the array as a fresh object on every status check, so caching\n * by reference always misses \u2014 this lets the renderOnlineAgents and\n * buildToolUsage caches detect rendered identity/status/task/tool changes\n * instead.\n *\n * O(n) over every field rendered in the peer snapshot. This matters because\n * status/task/tool changes should invalidate the prompt just like joins and\n * leaves do. Uses FNV-1a over character codes; a collision would only leave a\n * stale cosmetic snapshot in the prompt.\n */\nexport function agentsFingerprint(agents: readonly MailboxAgentStatus[] | undefined): string {\n if (!agents || agents.length === 0) return '0';\n let h = 0x811c9dc5;\n for (const a of agents) {\n const fields = [\n a.agentId,\n a.name,\n a.source,\n a.sessionId,\n a.status,\n a.currentTask,\n a.currentTool,\n a.online ? '1' : '0',\n ];\n for (const field of fields) {\n const value = field ?? '';\n for (let i = 0; i < value.length; i++) {\n h ^= value.charCodeAt(i);\n h = Math.imul(h, 0x01000193) >>> 0;\n }\n h ^= 0xff;\n h = Math.imul(h, 0x01000193) >>> 0;\n }\n }\n return `${agents.length}:${h.toString(36)}`;\n}\n", "/**\n * The `## Environment` section of the system prompt \u2014 OS, shell, git, detected\n * languages, model capabilities, and the skills-in-scope footer.\n *\n * Split out of `system-prompt-builder.ts`. The builder passes the pieces of its\n * own state this section reads; `envCacheByRoot` is the builder's Map, mutated\n * here by reference exactly as before.\n *\n * @module core/system-prompt-environment\n */\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { ConcreteTokenSavingTier } from '../types/config.js';\nimport type { BuildContext, ModelCapabilities } from '../types/system-prompt.js';\nimport { detectLanguages, dirExists, gitStatus } from './system-prompt-environment-probes.js';\nimport { effectiveShell, SHELL_DISPLAY, shellGuidanceBlock } from './system-prompt-shell.js';\n\n/** The builder state this section reads. */\nexport interface EnvironmentSectionContext {\n tier: ConcreteTokenSavingTier;\n isCompact: boolean;\n modelCapabilities: ModelCapabilities | undefined;\n /** Builder's per-projectRoot cache \u2014 read and written by reference. */\n envCacheByRoot: Map<string, string>;\n skillCache: string | undefined;\n todayIso: string | undefined;\n modeId: string | undefined;\n skillMode: string | undefined;\n}\n\nexport async function buildEnvironment(\n ctx: BuildContext,\n env: EnvironmentSectionContext,\n): Promise<string> {\n const modelCapabilities = env.modelCapabilities;\n const cacheKey = [\n ctx.projectRoot,\n ctx.provider ?? '',\n ctx.model ?? '',\n modelCapabilities?.maxContextTokens ?? 0,\n modelCapabilities?.supportsTools ? 1 : 0,\n modelCapabilities?.supportsVision ? 1 : 0,\n modelCapabilities?.supportsReasoning ? 1 : 0,\n ].join('\\0');\n const cached = env.envCacheByRoot.get(cacheKey);\n if (cached) return cached;\n const today = env.todayIso ?? new Date().toISOString().slice(0, 10);\n const platform = `${os.platform()} ${os.release()}`;\n // The bash tool's effective shell, pinned at boot via WRONGSTACK_SHELL.\n // On POSIX we keep reporting the raw $SHELL; on Windows we report the\n // resolved shell + a \"write X syntax\" nudge, and append a syntax guidance\n // sub-block below so the model doesn't default to bash/POSIX idioms.\n const effShell = effectiveShell(os.platform(), process.env['WRONGSTACK_SHELL']);\n const shell =\n effShell === 'posix'\n ? (process.env.SHELL ?? process.env.ComSpec ?? 'unknown')\n : SHELL_DISPLAY[effShell];\n const node = process.version;\n const isGit = await dirExists(path.join(ctx.projectRoot, '.git'));\n // Fan out the per-root probes so the prompt build doesn't serialize\n // ~12 fs.access calls plus the git status spawn back-to-back. On a\n // cold cache (CI / first turn) this trims hundreds of ms.\n const [git, langs] = await Promise.all([\n isGit ? gitStatus(ctx.projectRoot) : Promise.resolve('not a git repo'),\n detectLanguages(ctx.projectRoot),\n ]);\n\n // Tier-aware environment block content.\n // - 'off': Full \u2014 all fields\n // - 'minimal': Compact single line \u2014 git + date only\n // - 'light': +platform\n // - 'medium': +languages\n // - 'aggressive': +capabilities (context window, provider/model)\n const tier = env.tier;\n const lines: string[] = ['## Environment'];\n\n if (tier === 'minimal') {\n // Single compact line\n lines.push(`- Git: ${git} | Date: ${today}`);\n } else {\n lines.push(`- Operating system: ${platform}`);\n if (tier !== 'light') {\n lines.push(`- Shell: ${shell}`);\n lines.push(`- Node.js: ${node}`);\n }\n // Languages appear in the full ('off') block and the richer trimming\n // tiers; only 'minimal' (single line) and 'light' (platform only) omit\n // them. 'off' is the most complete tier (no token saving), per the\n // toolDescLimit ordering off=80 > aggressive=70 > \u2026 > minimal=40.\n if (tier === 'off' || tier === 'medium' || tier === 'aggressive') {\n lines.push(`- Detected languages: ${langs}`);\n }\n lines.push(`- Git status: ${git}`);\n lines.push(`- Today's date: ${today}`);\n if (tier === 'aggressive') {\n if (ctx.provider || ctx.model) {\n lines.push(\n `- Running on: ${ctx.provider ?? '<unknown provider>'}/${ctx.model ?? '<unknown model>'}`,\n );\n }\n if (modelCapabilities) {\n lines.push(\n `- Context window: ${modelCapabilities.maxContextTokens.toLocaleString()} tokens max`,\n );\n }\n }\n if (tier !== 'aggressive' && modelCapabilities) {\n lines.push(\n `- Context window: ${modelCapabilities.maxContextTokens.toLocaleString()} tokens max`,\n );\n }\n if (tier !== 'aggressive' && (ctx.provider || ctx.model)) {\n lines.push(\n `- Running on: ${ctx.provider ?? '<unknown provider>'}/${ctx.model ?? '<unknown model>'}`,\n );\n }\n if (tier !== 'aggressive' && env.modeId && env.modeId !== 'default') {\n lines.push(`- Mode: ${env.modeId}`);\n }\n }\n\n // Shell syntax guidance \u2014 only meaningful on Windows, where the model must\n // not fall back to bash/POSIX idioms. Tier-gated: full for off/medium/\n // aggressive, a one-liner for light, omitted for minimal. POSIX returns ''.\n if (effShell !== 'posix' && tier !== 'minimal') {\n const guide = shellGuidanceBlock(effShell, tier === 'light' ? 'short' : 'full');\n if (guide) lines.push('', guide);\n }\n\n if (env.skillCache) {\n lines.push(\n '',\n '## Skills in scope for this session',\n env.skillCache,\n '',\n env.skillMode === 'progressive'\n ? 'Skill names and triggers are injected below; load full instructions deterministically with the `skill` tool before relying on one.'\n : env.isCompact\n ? 'Compact skill instructions are injected in the Active Skills block below (Overview + Rules only).'\n : 'Skill bodies are injected below up to the eager budget; overflow remains listed by name and trigger for deterministic loading with the `skill` tool.',\n );\n }\n const text = lines.join('\\n');\n env.envCacheByRoot.set(cacheKey, text);\n return text;\n}\n", "import { spawn } from 'node:child_process';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { buildChildEnv } from '../utils/child-env.js';\n\nexport async function dirExists(p: string): Promise<boolean> {\n try {\n const stat = await fs.stat(p);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function gitStatus(root: string): Promise<string> {\n return new Promise((resolve) => {\n let settled = false;\n const finish = (s: string): void => {\n if (settled) return;\n settled = true;\n resolve(s);\n };\n let proc: ReturnType<typeof spawn> | undefined;\n // 2 s ceiling: a hung git status must not stall prompt construction.\n const timer = setTimeout(() => {\n proc?.kill('SIGKILL');\n finish('git timeout');\n }, 2000);\n try {\n proc = spawn('git', ['status', '--porcelain=v1', '--branch'], {\n cwd: root,\n env: buildChildEnv(),\n stdio: ['ignore', 'pipe', 'ignore'],\n windowsHide: true,\n });\n let buf = '';\n proc.stdout?.on('data', (c) => {\n buf += c.toString();\n });\n proc.on('error', () => {\n clearTimeout(timer);\n finish('git error');\n });\n proc.on('close', () => {\n clearTimeout(timer);\n const lines = buf.split('\\n').filter(Boolean);\n const branchLine = lines[0] ?? '';\n const branchMatch = branchLine.match(/## ([^\\s.]+)/);\n const branch = branchMatch?.[1] ?? 'detached';\n const dirty = lines.slice(1);\n const staged = dirty.filter((l) => /^[MARCD]/.test(l)).length;\n const modified = dirty.length - staged;\n finish(`branch=${branch}, ${modified} modified, ${staged} staged`);\n });\n } catch {\n clearTimeout(timer);\n finish('git unavailable');\n }\n });\n}\n\nexport async function detectLanguages(root: string): Promise<string> {\n const checks: Array<[string, string]> = [\n ['package.json', 'JavaScript/TypeScript'],\n ['tsconfig.json', 'TypeScript'],\n ['go.mod', 'Go'],\n ['Cargo.toml', 'Rust'],\n ['pyproject.toml', 'Python'],\n ['requirements.txt', 'Python'],\n ['Gemfile', 'Ruby'],\n ['pom.xml', 'Java'],\n ['build.gradle', 'Java/Kotlin'],\n ['composer.json', 'PHP'],\n ['mix.exs', 'Elixir'],\n ];\n const hits = await Promise.all(\n checks.map(async ([marker, lang]) => {\n try {\n await fs.access(path.join(root, marker));\n return lang;\n } catch {\n return null;\n }\n }),\n );\n const langs = new Set(hits.filter((l): l is string => l !== null));\n return langs.size === 0 ? 'unknown' : Array.from(langs).join(', ');\n}\n", "/**\n * Build a sanitized child-process environment.\n *\n * The bash/exec tools and MCP stdio transports execute LLM-generated or\n * configured commands. The parent process carries provider API keys\n * (ANTHROPIC_API_KEY, OPENAI_API_KEY, ...), VCS tokens (GITHUB_TOKEN),\n * and cloud credentials. Forwarding those to a child is an exfiltration\n * vector even with `permission: 'confirm'` \u2014 a compromised MCP server\n * or a cleverly composed shell pipeline can leak secrets.\n *\n * Strategy: copy a small, explicit allowlist of variables that real builds\n * need, then copy anything else that does NOT look secret-bearing. This\n * preserves user-friendly behavior (locale, terminal, npm config) while\n * blocking the obvious leak channels. Two value-side guards back up the\n * name-based filter:\n * - any value carrying an embedded URI credential (`scheme://user:pass@host`,\n * e.g. `DATABASE_URL`/`REDIS_URL`/`*_DSN`) is dropped (WS-01);\n * - `NODE_OPTIONS` is forwarded but with module-preload directives\n * (`--require`/`--import`/`--loader`) stripped so a parent-set value can't\n * inject code into node children (WS-02).\n *\n * Override with `WRONGSTACK_CHILD_ENV_PASSTHROUGH=1` to forward the full\n * parent environment unchanged (opt-in for advanced users who understand\n * the risk).\n */\n\nconst ALLOWED_KEYS = new Set<string>([\n 'PATH',\n 'HOME',\n 'USER',\n 'USERNAME',\n 'LOGNAME',\n 'SHELL',\n 'LANG',\n 'LC_ALL',\n 'LC_CTYPE',\n 'TERM',\n 'TZ',\n 'TMPDIR',\n 'TEMP',\n 'TMP',\n 'PWD',\n 'OLDPWD',\n 'COMSPEC',\n 'SYSTEMROOT',\n 'SYSTEMDRIVE',\n 'WINDIR',\n 'PROGRAMFILES',\n 'PROGRAMFILES(X86)',\n 'PROGRAMDATA',\n 'APPDATA',\n 'LOCALAPPDATA',\n 'USERPROFILE',\n 'PUBLIC',\n 'PATHEXT',\n]);\n\n// Substring match against env-var names (case-insensitive). Bias toward\n// false-positives \u2014 a missing var is recoverable, an exfiltrated key is not.\n// Only consulted for vars NOT on the curated allowlist; PWD/PASSWD-style\n// false positives there are avoided by checking allowlist first.\nconst SECRET_NAME_PARTS = [\n 'TOKEN',\n 'SECRET',\n 'PASSWORD',\n 'PASSWD',\n 'AUTH',\n 'CRED',\n 'BEARER',\n 'COOKIE',\n 'PRIVATE',\n];\n\nfunction looksSecret(name: string): boolean {\n const upper = name.toUpperCase();\n for (const p of SECRET_NAME_PARTS) {\n if (upper.includes(p)) return true;\n }\n // KEY is tricky \u2014 PUBLIC_KEY is fine to forward but most _KEY vars are\n // secrets. Require word boundary so KEYBOARD_LAYOUT etc. are not flagged.\n if (/(?:^|_)KEY(?:$|_|S$)/i.test(upper)) return true;\n if (/API[_-]?KEY/i.test(upper)) return true;\n if (/ACCESS[_-]?KEY/i.test(upper)) return true;\n if (/SESSION[_-]?ID/i.test(upper) === false && /SESSION/i.test(upper)) {\n // SESSION_ID is metadata (we set our own); other SESSION_* often holds\n // session cookies. Be conservative.\n return true;\n }\n return false;\n}\n\n/**\n * Value-side secret detection (WS-01). The name-based `looksSecret` filter\n * misses connection-string variables whose NAME is innocuous but whose VALUE\n * embeds a password \u2014 e.g. `DATABASE_URL=postgres://user:pass@host`,\n * `REDIS_URL=redis://:pass@host`, `MONGO_URI`, `AMQP_URL`, `*_DSN`. Forwarding\n * these to a child (bash/exec/MCP server) leaks the embedded credential.\n *\n * Matches a URI userinfo component that contains a password, i.e.\n * `scheme://[user]:<password>@host`. Deliberately precise: a credential-free\n * URL (`https://api.example.com`, `https://user@host` with no password) is NOT\n * matched, so non-secret `*_URL` knobs (registries, endpoints) still forward.\n */\nfunction valueHasEmbeddedCredential(value: string): boolean {\n // scheme:// then optional user, a ':' , a non-empty password, then '@'.\n // Userinfo chars stop at '/', whitespace, ':' (separator) and '@'.\n return /\\b[a-z][a-z0-9+.-]*:\\/\\/[^/\\s:@]*:[^/\\s@]+@/i.test(value);\n}\n\n/**\n * Code-injection directives that turn `NODE_OPTIONS` into an RCE channel by\n * preloading an arbitrary module into every node child process (WS-02).\n */\nconst NODE_OPTIONS_INJECTION_FLAG =\n /^(?:--require|-r|--import|--loader|--experimental-loader)$/;\nconst NODE_OPTIONS_INJECTION_FLAG_EQ =\n /^(?:--require|-r|--import|--loader|--experimental-loader)=/;\n\n/**\n * Strip module-preload directives from a `NODE_OPTIONS` value while preserving\n * benign flags (`--no-warnings`, `--max-old-space-size=\u2026`, etc.). Handles both\n * the `--require=./x.js` and space-separated `--require ./x.js` forms. Returns\n * the sanitized string (possibly empty).\n */\nexport function sanitizeNodeOptions(value: string): string {\n const tokens = value.split(/\\s+/).filter(Boolean);\n const kept: string[] = [];\n for (let i = 0; i < tokens.length; i++) {\n const tok = tokens[i] as string;\n if (NODE_OPTIONS_INJECTION_FLAG_EQ.test(tok)) continue; // --require=./x\n if (NODE_OPTIONS_INJECTION_FLAG.test(tok)) {\n i++; // also drop the following path token (--require ./x)\n continue;\n }\n kept.push(tok);\n }\n return kept.join(' ');\n}\n\nexport interface BuildChildEnvOptions {\n /** Session ID to inject as WRONGSTACK_SESSION_ID. */\n sessionId?: string | undefined;\n /** Additional env vars to merge (takes priority over filtered parent env). */\n extra?: NodeJS.ProcessEnv | undefined;\n}\n\n/**\n * Commit identity applied to every git-touching child process via the\n * `GIT_AUTHOR_*` / `GIT_COMMITTER_*` env vars. Env-var identity outranks\n * every `git config` layer (repo/global/system), so commits made by any\n * tool (git tool, bash/exec, worktree manager, plugins) carry this\n * name/email without touching the user's git config \u2014 hand-made commits\n * in a normal terminal are unaffected.\n */\nexport interface GitIdentity {\n name?: string | undefined;\n email?: string | undefined;\n}\n\nlet gitIdentity: GitIdentity | null = null;\n\n/**\n * Set (or clear with `null`) the git commit identity injected by\n * `buildChildEnv()`. Wired at boot from the user-level `config.git.identity`\n * (the config loader strips `git` from repo-committed in-project configs \u2014\n * identity spoofing must not be repo-controllable) and re-applied at runtime\n * by the `/gitid` slash command.\n */\nexport function configureChildEnvGitIdentity(identity: GitIdentity | null | undefined): void {\n const name = identity?.name?.trim();\n const email = identity?.email?.trim();\n gitIdentity = name || email ? { name: name || undefined, email: email || undefined } : null;\n}\n\n/** Current configured git identity, or null when none is set. */\nexport function getChildEnvGitIdentity(): Readonly<GitIdentity> | null {\n return gitIdentity;\n}\n\n/**\n * Build a filtered child-process environment suitable for bash, exec, and\n * MCP server subprocesses. Strips API keys, tokens, and other credentials\n * while preserving system/tooling variables.\n */\nexport function buildChildEnv(optsOrSessionId?: BuildChildEnvOptions | string): NodeJS.ProcessEnv {\n const opts: BuildChildEnvOptions =\n typeof optsOrSessionId === 'string'\n ? { sessionId: optsOrSessionId }\n : (optsOrSessionId ?? {});\n\n // WRONGSTACK_CHILD_ENV_PASSTHROUGH may NOT be set via config file.\n // It is a privileged override that opt-outs the entire credential filter\n // and must only be set by the operator's shell environment (real env var,\n // not something a config file injects into process.env). Config-file\n // sources do NOT go through process.env \u2014 only the actual shell environment\n // does \u2014 so checking Object.prototype.hasOwnProperty.call(process.env, ...)\n // is sufficient to exclude config-driven values.\n const hasOwn = Object.hasOwn(process.env, 'WRONGSTACK_CHILD_ENV_PASSTHROUGH');\n const legacyHasOwn = Object.hasOwn(process.env, 'WRONGSTACK_BASH_ENV_PASSTHROUGH');\n const passthrough = (hasOwn && process.env['WRONGSTACK_CHILD_ENV_PASSTHROUGH'] === '1')\n || (legacyHasOwn && process.env['WRONGSTACK_BASH_ENV_PASSTHROUGH'] === '1');\n if (passthrough && !process.env['CI']) {\n console.warn(\n '[agent] WARNING: WRONGSTACK_*_ENV_PASSTHROUGH=1 is active \u2014\\n' +\n ' all parent env vars (including API keys) forwarded to child processes.\\n' +\n ' Do not use on shared or multi-tenant systems.'\n );\n }\n const out: NodeJS.ProcessEnv = {};\n\n // The CLI entry defaults NODE_ENV=production (so React/Ink resolve their\n // production builds \u2014 see cli-main) and marks the injection with this\n // flag. The injected value must NOT reach children: NODE_ENV=production\n // makes `pnpm install` skip devDependencies and flips test-runner\n // behavior. Strip both vars whenever the flag says wrongstack set them \u2014\n // a NODE_ENV genuinely exported by the operator's shell (flag absent)\n // is forwarded unchanged. Applies in passthrough mode too: passthrough\n // means \"the operator's real environment\", which this value is not.\n const nodeEnvDefaulted = process.env['WRONGSTACK_NODE_ENV_DEFAULTED'] === '1';\n\n for (const [k, v] of Object.entries(process.env)) {\n if (v === undefined) continue;\n if (nodeEnvDefaulted && (k === 'NODE_ENV' || k === 'WRONGSTACK_NODE_ENV_DEFAULTED')) continue;\n if (passthrough) {\n out[k] = v;\n continue;\n }\n const upper = k.toUpperCase();\n // 0. Strip any value with an embedded URI credential (user:pass@host),\n // regardless of the variable name (WS-01). Applied before the allowlist\n // so even a \"system\" name carrying a connection string is caught.\n if (valueHasEmbeddedCredential(v)) continue;\n // 1. Forward names on the explicit allowlist \u2014 these are well-known\n // non-secret system variables (PATH, HOME, LANG, ...).\n if (ALLOWED_KEYS.has(upper)) {\n out[k] = v;\n continue;\n }\n // 2. Strip anything that looks like a secret.\n if (looksSecret(upper)) continue;\n // NODE_OPTIONS is forwarded (builds rely on flags like --no-warnings) but\n // module-preload directives (--require/--import/--loader) are stripped \u2014\n // they would let a parent-set NODE_OPTIONS inject code into every node\n // child (WS-02 defense-in-depth).\n if (upper === 'NODE_OPTIONS') {\n const sanitized = sanitizeNodeOptions(v);\n if (sanitized) out[k] = sanitized;\n continue;\n }\n // 3. Forward tooling-prefixed vars that builds commonly need, unless\n // they already failed the secret check above.\n if (\n upper.startsWith('NODE_') ||\n upper.startsWith('NPM_') ||\n upper.startsWith('PNPM_') ||\n upper.startsWith('YARN_') ||\n upper.startsWith('GIT_') ||\n upper.startsWith('CI') ||\n upper.startsWith('XDG_') ||\n // Our own non-secret knobs (WRONGSTACK_HOME, WRONGSTACK_SESSION_ID, \u2026).\n // Secrets never live in WRONGSTACK_* env vars (they're in the encrypted\n // vault). Forwarding keeps child wstack processes \u2014 e.g. ones spawned\n // by the test suite \u2014 inside the same redirected global root.\n upper.startsWith('WRONGSTACK_') ||\n upper === 'EDITOR' ||\n upper === 'VISUAL' ||\n upper === 'PAGER'\n ) {\n out[k] = v;\n }\n }\n\n // Configured commit identity. Applied in passthrough mode too \u2014 it is the\n // operator's explicit intent, not a parent-env leak. Placed BEFORE the\n // extras merge so a caller-provided GIT_* override still wins.\n if (gitIdentity) {\n if (gitIdentity.name) {\n out['GIT_AUTHOR_NAME'] = gitIdentity.name;\n out['GIT_COMMITTER_NAME'] = gitIdentity.name;\n }\n if (gitIdentity.email) {\n out['GIT_AUTHOR_EMAIL'] = gitIdentity.email;\n out['GIT_COMMITTER_EMAIL'] = gitIdentity.email;\n }\n }\n\n // Merge explicit extras AFTER filtering. Callers MUST treat `opts.extra`\n // as a small, user-authored allowlist (e.g. MCP server tokens, LSP env\n // overrides from config). Do NOT pass `process.env` or any object derived\n // from it \u2014 that would defeat the parent-env scrub above. The secret\n // filter is intentionally skipped here so legitimate secret-bearing\n // tokens the user explicitly configured can still reach the child.\n if (opts.extra) {\n Object.assign(out, opts.extra);\n }\n\n if (opts.sessionId) out['WRONGSTACK_SESSION_ID'] = opts.sessionId;\n return out;\n}\n", "/** Canonical shell the `bash` tool targets \u2014 drives the Environment Shell line\n * and the syntax-guidance sub-block. */\nexport type EffectiveShell = 'pwsh' | 'powershell' | 'cmd' | 'posix';\n\n/**\n * Derive the shell the `bash` tool will use from `os.platform()` + the pinned\n * `WRONGSTACK_SHELL` value (set at boot by `ensureSessionShell` in\n * @wrongstack/tools). On POSIX this is always `'posix'` and the caller shows the\n * raw `$SHELL`. On Windows with no pinned value (boot didn't run \u2014 tests /\n * embeddings) we report `'cmd'`, matching `bash.ts`'s default for\n * non-PowerShell-looking commands.\n */\nexport function effectiveShell(\n platform: NodeJS.Platform,\n wrongstackShell: string | undefined,\n): EffectiveShell {\n if (platform !== 'win32') return 'posix';\n const v = wrongstackShell?.trim().toLowerCase();\n if (v === 'powershell' || v === 'powershell.exe') return 'powershell';\n if (v === 'pwsh' || v === 'pwsh.exe') return 'pwsh';\n if (v === 'cmd' || v === 'cmd.exe') return 'cmd';\n return 'cmd';\n}\n\nexport const SHELL_DISPLAY: Record<Exclude<EffectiveShell, 'posix'>, string> = {\n pwsh: 'pwsh (PowerShell 7+) \u2014 write PowerShell syntax, not bash',\n powershell: 'powershell (Windows PowerShell 5.1) \u2014 write PowerShell syntax, not bash',\n cmd: 'cmd.exe (Command Prompt) \u2014 write cmd syntax, not bash',\n};\n\n/**\n * Shell-specific syntax guidance for the Environment block. Returns `''` for\n * POSIX (the model writes bash natively, so no nudge is needed). `detail:\n * 'short'` is the light-tier one-liner; `'full'` is the complete cheat-sheet.\n * The `&&`/`||` note branches on the PowerShell edition (only pwsh 7 supports\n * them).\n */\nexport function shellGuidanceBlock(shell: EffectiveShell, detail: 'full' | 'short'): string {\n if (shell === 'posix') return '';\n if (shell === 'cmd') {\n if (detail === 'short') {\n return '- Shell syntax: cmd.exe \u2014 use `%VAR%`, `2>nul`, `dir`/`type`/`del`/`where` (NOT bash `$VAR`, `/dev/null`, `ls`/`cat`/`rm`).';\n }\n return [\n '## Shell \u2014 cmd.exe',\n 'The `bash` tool runs **cmd.exe** on this machine. Write cmd syntax, not bash/POSIX:',\n '- Env vars: `%NAME%` (NOT `$NAME`); set with `set NAME=value`.',\n '- Discard output: `2>nul` / `>nul` (NOT `2>/dev/null`).',\n '- No `ls`/`cat`/`rm`/`which`/`head` \u2014 use `dir`/`type`/`del`/`where` and `more`.',\n '- Chain with `&&` / `||` / `&`. Prefer the dedicated read/grep/glob tools over shell file ops.',\n ].join('\\n');\n }\n // pwsh or powershell\n if (detail === 'short') {\n return '- Shell syntax: PowerShell \u2014 use `$env:VAR`, `2>$null`, `Get-Content`/`Select-Object` (NOT bash `$VAR`, `/dev/null`, `cat`/`head`).';\n }\n const chain =\n shell === 'pwsh'\n ? '- Chain with `&&` / `||` (supported in PowerShell 7).'\n : '- `&&` / `||` are NOT available in Windows PowerShell 5.1 \u2014 separate commands with `;` (and check `$LASTEXITCODE`).';\n return [\n `## Shell \u2014 PowerShell${shell === 'pwsh' ? ' 7+ (pwsh)' : ' 5.1 (powershell)'}`,\n 'The `bash` tool runs **PowerShell** on this machine. Write PowerShell syntax, not bash/POSIX:',\n \"- Env vars: read `$env:NAME`, set `$env:NAME = 'value'` (NOT `$NAME`, `%NAME%`, or `export`).\",\n '- Discard output: `... 2>$null` or `$null = ...` (NOT `2>/dev/null`).',\n '- No bash builtins \u2014 use cmdlets: `head -n N`\u2192`Select-Object -First N`, `tail`\u2192`-Last N`, `cat`\u2192`Get-Content`, `which x`\u2192`Get-Command x`, `rm -rf p`\u2192`Remove-Item -Recurse -Force p`, `touch f`\u2192`New-Item -ItemType File f`. Prefer the grep/glob tools over `Select-String`.',\n '- Read a line window of a file: `Get-Content path | Select-Object -Skip N -First M` (the `sed -n` / `head|tail` equivalent).',\n '- Pipes work normally; `rg`/`git`/`node` and other native exes run as-is \u2014 only the *shell builtins* differ. (`rg --files src | rg pattern` is fine.)',\n '- Call exes whose path has spaces via the call operator: `& \"C:\\\\Program Files\\\\app.exe\" args`.',\n \"- Multi-line literals: single-quoted here-string `@'\u2026'@` with the closing `'@` at column 0.\",\n '- Non-interactive only: no `Read-Host`/`Get-Credential`/`pause`; add `-Confirm:$false` to destructive cmdlets.',\n chain,\n ].join('\\n');\n}\n", "/**\n * Centralized skill system limits.\n *\n * Before this file existed, the magic numbers below were scattered across five\n * modules (`skill-installer`, `github-fetcher`, `skill` tool, system-prompt\n * builder, skill-loader), sometimes duplicated (e.g. per-skill body cap was\n * defined independently in the builder and the tool). Centralizing them here\n * keeps the budget model coherent \u2014 change one, change everywhere \u2014 and makes\n * the trade-offs visible in one place.\n *\n * Values are frozen at their pre-centralization defaults so this is a pure\n * refactor (no behavior change).\n */\nexport const SKILL_LIMITS = {\n /**\n * Per-skill body cap when injecting a full skill body into the system prompt\n * (eager mode), and when returning a skill body from the `skill` tool.\n * ~4k tokens. Oversized bodies are truncated at a paragraph boundary.\n *\n * Consumers: `system-prompt-builder.capSkillBody`, `skill` tool body return.\n */\n MAX_SKILL_BODY_CHARS: 16_000,\n\n /**\n * Per-resource cap when the `skill` tool loads a bundled file\n * (`scripts/`, `references/`, `assets/`). ~8k tokens.\n *\n * Consumer: `skill` tool `loadResource`.\n */\n MAX_RESOURCE_CHARS: 32_000,\n\n /**\n * Maximum number of bundled resource paths the `skill` tool lists in one\n * response. Caps a pathological skill (huge `assets/` tree) from blowing up\n * the tool result.\n *\n * Consumer: `skill` tool resource listing.\n */\n MAX_LISTED_RESOURCES: 100,\n\n /**\n * Max size of a single installed skill file (SKILL.md or a bundled resource).\n * Guards against a malicious registry skill shipping a multi-MB blob that\n * then flows into the prompt. 100KB.\n *\n * Consumer: `SkillInstaller.install` / `importFromDir`.\n */\n MAX_SKILL_FILE_SIZE: 100 * 1024,\n\n /**\n * Max size of a GitHub tarball downloaded by the skill installer. Guards\n * against a repo accidentally (or maliciously) shipping a giant tarball that\n * would be extracted into a temp dir. 50MB.\n *\n * Consumer: `downloadGitHubTarball`.\n */\n MAX_TARBALL_SIZE: 50 * 1024 * 1024,\n\n /**\n * Default total char budget for skill bodies injected in eager mode when\n * `config.skills.eagerMaxChars` is unset. ~6k tokens. Skills are injected\n * highest-priority first; once the budget is exhausted the remaining skills\n * are listed as a manifest the agent loads via the `skill` tool. Set very\n * high to effectively disable budgeting.\n *\n * Consumer: `DefaultSystemPromptBuilder.buildMemoryAndSkills` (default for\n * `skillEagerMaxChars`).\n */\n EAGER_DEFAULT_MAX_CHARS: 24_000,\n\n /**\n * Auto-compact body limits (the token-saving fallback used when a skill has\n * no hand-crafted `SKILL.save.md`). The Overview and Rules sections are\n * extracted and trimmed to these char budgets, then the total is capped.\n *\n * Consumer: `DefaultSkillLoader.compactSkillBody`.\n */\n COMPACT_OVERVIEW_MAX: 200,\n COMPACT_RULES_MAX: 350,\n COMPACT_TOTAL_MAX: 450,\n\n /**\n * Max length of a skill name (agentskills.io spec). Enforced by the\n * frontmatter validator's format regex plus this length bound.\n *\n * Consumer: `isValidSkillNameFormat`.\n */\n SKILL_NAME_MAX_LEN: 64,\n\n /**\n * Soft line limit for a SKILL.md body, per the bundled `skill-creator` rule.\n * Not enforced in code (a skill can exceed it) \u2014 surfaced by `/skill-gen\n * validate` and the `skill-creator` skill as guidance to move deep material\n * into `references/`.\n *\n * Consumer: `skill-creator` skill, `/skill-gen validate` advisory.\n */\n SKILL_BODY_LINE_LIMIT: 500,\n} as const;\n", "import { SKILL_LIMITS } from '../skills/limits.js';\n\n/** Strip YAML frontmatter from a SKILL.md file, returning only the body. */\nexport function stripFrontmatter(raw: string): string {\n if (!raw.startsWith('---')) return raw;\n const end = raw.indexOf('\\n---', 4);\n if (end === -1) return raw;\n // Skip past the closing `---` and the following newline\n let body = raw.slice(end + 4);\n if (body.startsWith('\\n')) body = body.slice(1);\n return body;\n}\n\n/**\n * Cap a skill body at `SKILL_LIMITS.MAX_SKILL_BODY_CHARS`, truncating at a\n * paragraph boundary when possible to preserve readability. Appends an\n * ellipsis marker when truncated so the model can detect the cap.\n */\nexport function capSkillBody(body: string): string {\n const max = SKILL_LIMITS.MAX_SKILL_BODY_CHARS;\n if (body.length <= max) return body;\n // Try to cut at the last paragraph break (`\\n\\n`) within the\n // budget so the truncated body ends cleanly. Fall back to a\n // hard cut if no paragraph break exists.\n const budget = max - 1; // reserve 1 char for ellipsis\n const cut = body.lastIndexOf('\\n\\n', budget);\n const truncated = cut > budget / 2 ? body.slice(0, cut) : body.slice(0, budget);\n return truncated + '\u2026';\n}\n\n/**\n * Compact a skill trigger description into a short label.\n * \"Use this skill when scanning source code for bugs...\"\n * -> \"scanning source code for bugs, anti-patterns, code smells\"\n */\nexport function compactTrigger(trigger: string): string {\n // Strip common prefixes\n let s = trigger\n .replace(/^Use this skill when /i, '')\n .replace(/^Use this skill for /i, '')\n .replace(/^Use when /i, '')\n .replace(/\\.$/, '');\n // Truncate to ~72 chars at a word boundary\n if (s.length > 72) {\n const cut = s.lastIndexOf(' ', 68);\n s = cut > 50 ? s.slice(0, cut) + '\u2026' : s.slice(0, 68) + '\u2026';\n }\n return s;\n}\n", "import { SKILL_LIMITS } from '../skills/limits.js';\nimport type { SkillLoader } from '../types/skill.js';\nimport { capSkillBody, stripFrontmatter } from './system-prompt-skill-text.js';\n\nexport async function buildProgressiveSkillManifestText(loader: SkillLoader): Promise<string> {\n try {\n const entries = await loader.listEntries();\n if (entries.length === 0) return '';\n const lines = [\n 'Call the `skill` tool to load a skill before relying on it.',\n '',\n '| Skill | Use when |',\n '|---|---|',\n ];\n for (const e of entries) {\n const trigger = (e.trigger ?? '').replace(/\\|/g, '\\\\|').replace(/\\n+/g, ' ').trim();\n lines.push(`| \\`${e.name}\\` | ${trigger} |`);\n }\n return lines.join('\\n');\n } catch {\n return '';\n }\n}\n\nexport async function buildFullSkillBodiesText(\n loader: SkillLoader,\n budget: number = SKILL_LIMITS.EAGER_DEFAULT_MAX_CHARS,\n): Promise<string> {\n try {\n const skills = await loader.list();\n if (skills.length === 0) return '';\n const bodies: string[] = [];\n const overflow: string[] = [];\n let used = 0;\n for (const s of skills) {\n try {\n const raw = await loader.readBody(s.name);\n const trimmed = stripFrontmatter(raw).trim();\n if (!trimmed) continue;\n const entry = `## Skill: ${s.name}\\n\\n${capSkillBody(trimmed)}`;\n if (used + entry.length <= budget) {\n bodies.push(entry);\n used += entry.length;\n } else {\n overflow.push(`- ${s.name}`);\n }\n } catch {\n // skip unreadable skill\n }\n }\n let out = bodies.join('\\n\\n---\\n\\n');\n if (overflow.length > 0) {\n const note =\n overflow.length === skills.length\n ? '## Available skills (load with the `skill` tool)'\n : '## Other available skills (not injected \u2014 load with the `skill` tool)';\n out += `${out ? '\\n\\n---\\n\\n' : ''}${note}\\n${overflow.join('\\n')}`;\n }\n return out;\n } catch {\n return '';\n }\n}\n\nexport async function buildCompactSkillBodiesText(loader: SkillLoader): Promise<string> {\n try {\n const skills = await loader.list();\n if (skills.length === 0) return '';\n const bodies: string[] = [];\n for (const s of skills) {\n try {\n const saveBody = await loader.readSaveBody(s.name);\n const clean = stripFrontmatter(saveBody);\n if (clean.trim()) {\n bodies.push(`## Skill: ${s.name}\\n\\n${clean.trim()}`);\n }\n } catch {\n // skip unreadable skill\n }\n }\n return bodies.length > 0 ? bodies.join('\\n\\n---\\n\\n') : '';\n } catch {\n return '';\n }\n}\n", "/**\n * The relevant-memory and active-skill-bodies sections of the system prompt,\n * plus the cached online-peer snapshot rendered into the tool-usage block.\n *\n * Split out of `system-prompt-builder.ts`. Both functions used to mutate a\n * builder field for their cache; here the cache is taken as an argument and\n * handed back, so the builder assigns it at the single call site instead.\n *\n * @module core/system-prompt-memory-skills\n */\nimport type { MailboxAgentStatus } from '../coordination/mailbox-types.js';\nimport type { ConcreteTokenSavingTier } from '../types/config.js';\nimport type { MemoryStore } from '../types/memory.js';\nimport type { SkillLoader } from '../types/skill.js';\nimport type { Tool } from '../types/tool.js';\nimport { agentsFingerprint, shortSessionId } from './system-prompt-blocks.js';\nimport {\n buildCompactSkillBodiesText,\n buildFullSkillBodiesText,\n buildProgressiveSkillManifestText,\n} from './system-prompt-skill-bodies.js';\n\n/** Rendered peer snapshot, cached by content fingerprint. */\nexport interface OnlineAgentsCache {\n hash: string;\n text: string;\n}\n\n/**\n * Render the online agents list, cached by content fingerprint. The agents\n * list changes at join/leave pace (seconds to minutes), not every prompt\n * build turn (hundreds of ms). The fingerprint detects membership changes\n * without holding the array reference \u2014 the mailbox rebuilds the array as\n * a fresh object on every status check, so reference equality always misses.\n *\n * Tier behaviour:\n * - 'off' / 'medium' / 'aggressive' \u2192 full list with names, sessions, sources\n * - 'minimal' / 'light' \u2192 count only (no list)\n *\n * Returns the (possibly updated) cache alongside the text; the caller stores it.\n */\nexport function renderOnlineAgents(\n agents: readonly MailboxAgentStatus[] | undefined,\n tier: ConcreteTokenSavingTier,\n cache: OnlineAgentsCache | undefined,\n): { text: string; cache: OnlineAgentsCache | undefined } {\n if (!agents || agents.length === 0) return { text: '', cache };\n\n // Content fingerprint: detects membership changes without holding the\n // array reference, which is rebuilt as a fresh object on every status check.\n const hash = agentsFingerprint(agents);\n if (cache?.hash === hash) {\n return { text: cache.text, cache };\n }\n\n const totalCount = agents.length;\n // minimal / light tiers: count only, no list\n if (tier === 'minimal' || tier === 'light') {\n const text = ` (${totalCount} agent${totalCount !== 1 ? 's' : ''} online)`;\n return { text, cache: { hash, text } };\n }\n\n const inlineData = (value: string, max = 120): string =>\n value.replace(/[`\\r\\n]+/g, ' ').replace(/\\s+/g, ' ').trim().slice(0, max);\n const agentList = agents\n .map((a) => {\n const details = [\n `id: \\`${inlineData(a.agentId ?? a.name, 96)}\\``,\n `client: ${inlineData(a.source ?? 'unknown', 32)}`,\n a.status ? `status: ${inlineData(a.status, 32)}` : undefined,\n a.currentTask ? `task: \\`${inlineData(a.currentTask)}\\`` : undefined,\n a.currentTool ? `tool: \\`${inlineData(a.currentTool, 64)}\\`` : undefined,\n a.sessionId ? `session: ${shortSessionId(inlineData(a.sessionId, 96))}` : undefined,\n ].filter((part): part is string => part !== undefined);\n return `- **${inlineData(a.name, 96)}** \u2014 ${details.join('; ')}`;\n })\n .join('\\n');\n const text = `\\n\\n**Currently online (${totalCount} agent${totalCount !== 1 ? 's' : ''}):**\\n${agentList}`;\n return { text, cache: { hash, text } };\n}\n\n/** The builder state the memory + skills section reads. */\nexport interface MemorySkillsContext {\n tier: ConcreteTokenSavingTier;\n isCompact: boolean;\n memoryStore: MemoryStore | undefined;\n injectMemory: boolean | undefined;\n skillLoader: SkillLoader | undefined;\n skillMode: string | undefined;\n skillEagerMaxChars: number | undefined;\n /** Tools from the last build \u2014 used for memory relevance scoring. */\n lastBuildTools: Tool[] | undefined;\n skillBodyCache: string | undefined;\n}\n\n/**\n * Returns the section text plus the (possibly refreshed) skill-body cache; the\n * caller stores the cache back on the builder.\n */\nexport async function buildMemoryAndSkills(\n mem: MemorySkillsContext,\n): Promise<{ text: string; skillBodyCache: string | undefined }> {\n const parts: string[] = [];\n let skillBodyCache = mem.skillBodyCache;\n // Memory injection count per tier: off=5, minimal=3, light=5, medium=5, aggressive=5\n const memoryCount = mem.tier === 'minimal' || mem.tier === 'light' ? 3 : 5;\n const compactMemory = mem.tier === 'minimal'; // compact = text only, no badges/tags\n // When a per-turn memory retriever owns injection (SAGE turn\n // middleware), skip the static prompt section so memory flows through a\n // single channel \u2014 no double injection.\n if (mem.memoryStore && mem.injectMemory !== false) {\n try {\n // Use relevance scoring when available, fall back to full dump.\n if (mem.memoryStore.scoreRelevant) {\n const toolNames = mem.lastBuildTools?.map((t) => t.name) ?? [];\n const scored = await mem.memoryStore.scoreRelevant(\n {\n currentTask: '',\n toolNames,\n },\n 'project-memory',\n memoryCount,\n );\n if (scored.length > 0) {\n const lines: string[] = ['# Relevant Memory'];\n for (const e of scored) {\n if (compactMemory) {\n lines.push(`- ${e.text}`);\n } else {\n const badge = e.type ? `[\\`${e.type.replace('_', '-')}\\`] ` : '';\n const priorityMark =\n e.priority === 'critical' ? '\u26A1' : e.priority === 'high' ? '\u25B2' : '';\n lines.push(\n `- ${priorityMark}${badge}${e.text}${e.tags ? ` \\`#${e.tags.join(' #')}\\`` : ''}`,\n );\n }\n }\n parts.push(lines.join('\\n'));\n }\n } else {\n const memText = await mem.memoryStore.readAll();\n if (memText.trim()) parts.push(`# Project Memory\\n\\n${memText}`);\n }\n } catch {\n // skip\n }\n }\n // Skill bodies \u2014 re-read on every build so newly created/edited skills\n // are picked up. The SkillLoader caches disk I/O internally (list/body\n // caches), so re-calling its methods here is cheap: the loader returns\n // cached data unless invalidateCache() was called, which happens when\n // skills are created, edited, installed, or removed.\n // Skills are listed by name+trigger in buildEnvironment (envCache);\n // here we inject the full body content so the model has the actual\n // domain instructions, not just a trigger hint.\n // In token-saving mode, skill bodies are compacted to save tokens:\n // only the Overview and Rules sections (~400 chars max per skill).\n if (mem.skillLoader) {\n if (mem.skillMode === 'progressive') {\n skillBodyCache = await buildProgressiveSkillManifestText(mem.skillLoader);\n } else if (mem.isCompact) {\n skillBodyCache = await buildCompactSkillBodiesText(mem.skillLoader);\n } else {\n skillBodyCache = await buildFullSkillBodiesText(mem.skillLoader, mem.skillEagerMaxChars);\n }\n }\n if (skillBodyCache) {\n parts.push(`# Active Skills\\n\\n${skillBodyCache}`);\n }\n return { text: parts.join('\\n\\n'), skillBodyCache };\n}\n", "import * as fs from 'node:fs/promises';\n\nexport interface ActivePlanCache {\n path: string;\n mtimeMs: number;\n text: string;\n}\n\nexport async function readActivePlanBlock(args: {\n planPath: string | undefined;\n cache: ActivePlanCache | undefined;\n}): Promise<{ text: string; cache: ActivePlanCache | undefined }> {\n const { planPath, cache } = args;\n if (!planPath) return { text: '', cache };\n\n try {\n const stat = await fs.stat(planPath);\n if (cache && cache.path === planPath && cache.mtimeMs === stat.mtimeMs) {\n return { text: cache.text, cache };\n }\n const raw = await fs.readFile(planPath, 'utf8');\n const text = formatActivePlan(raw);\n return { text, cache: { path: planPath, mtimeMs: stat.mtimeMs, text } };\n } catch {\n return { text: '', cache: undefined };\n }\n}\n\nfunction formatActivePlan(raw: string): string {\n let parsed: {\n items?: Array<{ status?: string | undefined; title?: string | undefined }>;\n title?: string | undefined;\n };\n try {\n parsed = JSON.parse(raw);\n } catch {\n return '';\n }\n if (!Array.isArray(parsed.items) || parsed.items.length === 0) return '';\n const open = parsed.items.filter((i) => i?.status !== 'done');\n if (open.length === 0) return '';\n const lines = ['## Active plan'];\n if (parsed.title) lines.push(`*${parsed.title}*`, '');\n parsed.items.forEach((it, idx) => {\n const mark = it?.status === 'done' ? '[x]' : it?.status === 'in_progress' ? '[~]' : '[ ]';\n lines.push(`${idx + 1}. ${mark} ${it?.title ?? '(untitled)'}`);\n });\n lines.push(\n '',\n 'Use `/plan` (user) or the `plan` tool to update status as you progress. The roadmap survives session resume.',\n );\n return lines.join('\\n');\n}\n", "import type { MailboxAgentStatus } from '../coordination/mailbox-types.js';\nimport type { TextBlock } from '../types/blocks.js';\nimport type { ConcreteTokenSavingTier, TokenSavingTier } from '../types/config.js';\nimport { resolveTokenSavingTier } from '../types/config.js';\nimport type { MemoryStore } from '../types/memory.js';\nimport type { ModeStore } from '../types/mode.js';\nimport type { SkillLoader } from '../types/skill.js';\nimport type {\n BuildContext,\n ModelCapabilities,\n SystemPromptBuilder,\n SystemPromptRegions,\n} from '../types/system-prompt.js';\nimport { flattenSystemPromptRegions } from '../types/system-prompt.js';\nimport type { SystemPromptContributor } from '../types/system-prompt-contributor.js';\nimport type { Tool } from '../types/tool.js';\nimport {\n type InstructionBundle,\n type InstructionBundlePaths,\n loadInstructionBundle,\n mergeInstructionBundle,\n} from './instruction-bundle.js';\nimport { PROMPT as DEFAULT_PROMPT, LEADER_AFTER_TASK_PROMPT } from './modes/default.js';\nimport {\n agentsFingerprint,\n instructionSection,\n renderToolSelectionBoundary,\n tagBlock,\n} from './system-prompt-blocks.js';\nimport { buildEnvironment } from './system-prompt-environment.js';\nimport { buildMemoryAndSkills, renderOnlineAgents } from './system-prompt-memory-skills.js';\nimport { compactTrigger } from './system-prompt-skill-text.js';\nimport { type ActivePlanCache, readActivePlanBlock } from './system-prompt-plan.js';\nexport { effectiveShell, shellGuidanceBlock, type EffectiveShell } from './system-prompt-shell.js';\n\nexport const LAYER_1_IDENTITY = DEFAULT_PROMPT;\n\n// Provenance side-table and the stateless render helpers now live in their own\n// module; re-exported here so this file stays the public import site.\nexport type { SystemBlockSource } from './system-prompt-blocks.js';\nexport { SYSTEM_BLOCK_SOURCE } from './system-prompt-blocks.js';\n\nexport interface DefaultSystemPromptBuilderOptions {\n memoryStore?: MemoryStore | undefined;\n /**\n * Inject a static \"# Relevant Memory\" section into the built prompt from\n * `memoryStore`. Default: true. Set to false when a dedicated per-turn memory\n * retriever (the SAGE turn middleware) is the single injection\n * channel \u2014 this avoids double-injecting the same memories and keeps all\n * memory context flowing through one system.\n */\n injectMemory?: boolean | undefined;\n skillLoader?: SkillLoader | undefined;\n /**\n * How skill bodies reach the prompt. `'eager'` (default) injects every\n * discovered skill body; `'progressive'` injects only a name+trigger manifest\n * and relies on the agent calling the `skill` tool to load a body on demand\n * (the agentskills.io progressive-disclosure model).\n */\n skillMode?: 'eager' | 'progressive' | undefined;\n /**\n * In eager mode, cap the total chars of injected skill bodies (highest-priority\n * skills first); the rest become a load-on-demand manifest. Bounds prompt\n * cost when many skills are discovered. Default ~24k chars.\n */\n skillEagerMaxChars?: number | undefined;\n modeStore?: ModeStore | undefined;\n /** Pre-resolved active mode id \u2014 shown in environment block. */\n modeId?: string | undefined;\n /** Pre-resolved mode prompt \u2014 avoids redundant modeStore.getActiveMode() call. */\n modePrompt?: string | undefined;\n /** Model capabilities \u2014 object snapshot or lazy getter for live model switches. */\n modelCapabilities?: ModelCapabilities | (() => ModelCapabilities | undefined) | undefined;\n todayIso?: string | undefined;\n /**\n * Path to the session's plan JSON, or a getter that returns it. When\n * set, the builder reads the file on every `build()` call and injects\n * an \"Active plan\" block listing open items, so the LLM is anchored to\n * the strategic roadmap every turn \u2014 not just at resume. The block is\n * tagged `ephemeral` so a plan edit on turn N doesn't invalidate the\n * provider's prefix cache for earlier turns.\n *\n * The function form lets callers bind the builder before the session\n * id is known (e.g. DI containers that resolve the builder lazily) \u2014\n * the getter is called at build-time, after the session has been\n * created.\n */\n planPath?: string | (() => string | undefined);\n /**\n * System prompt contributors \u2014 called on every `build()` to inject\n * additional TextBlocks. Use `ExtensionRegistry.listSystemPromptContributors()`\n * or pass a plain array. Contributors are called in order; a throwing\n * contributor is caught and logged without aborting the build.\n */\n contributors?: readonly SystemPromptContributor[] | undefined;\n /**\n * Token-saving mode tier. Controls how aggressively the system prompt is\n * compacted: skill bodies are omitted/trimmed, tool hints are shortened,\n * and optional guidance sections (delegation, mailbox, context management)\n * use minimal versions to reduce per-request tokens.\n *\n * - 'off' \u2014 Full guidance (no reduction)\n * - 'minimal' \u2014 TIER1 tools, stripped guidance\n * - 'light' \u2014 TIER1 + memory tools, minimal patterns\n * - 'medium' \u2014 TIER1 + TIER2 tools, some guidance\n * - 'aggressive' \u2014 Maximum reduction before tools become unusable\n *\n * Boolean values are accepted for backward compatibility:\n * - `true` \u2192 'medium'\n * - `false` \u2192 'off'\n */\n tokenSavingMode?: TokenSavingTier | boolean | undefined;\n /**\n * File-backed instruction layers. Builtins are loaded first, then global\n * overrides, then project overrides, then explicit files. This lets durable\n * system instructions live outside TypeScript while keeping the builder API\n * stable for embedded runtimes.\n */\n instructionPaths?: InstructionBundlePaths | undefined;\n /**\n * Last-mile in-memory overrides, applied after instructionPaths. Useful for\n * tests, embedders, and plugin-provided prompt experiments.\n */\n instructionBundle?: InstructionBundle | undefined;\n}\n\nexport class DefaultSystemPromptBuilder implements SystemPromptBuilder {\n /**\n * Cached environment block, keyed by projectRoot. A single builder\n * instance is normally reused across turns of the same agent run, but\n * tests and library consumers may reuse it across runs with different\n * roots; keying the cache prevents leaking the first call's project\n * state into a later call against an unrelated project.\n */\n private envCacheByRoot = new Map<string, string>();\n private skillCache?: string | undefined;\n /** Cached full skill bodies (after frontmatter), built once per session. */\n private skillBodyCache?: string | undefined;\n /** Tools from last build \u2014 used for memory relevance scoring. */\n private _lastBuildTools?: Tool[] | undefined;\n /** Cached rendered online agents string, keyed by content fingerprint. */\n private _lastOnlineAgents?: { hash: string; text: string } | undefined;\n /** Cached full buildToolUsage output \u2014 keyed by tools array ref + agents fingerprint + tier. */\n private _toolsUsageCache?:\n | { toolsRef: readonly Tool[]; agentsHash: string; tier: string; text: string }\n | undefined;\n private _instructionBundle?: Promise<InstructionBundle> | undefined;\n constructor(private readonly opts: DefaultSystemPromptBuilderOptions = {}) {}\n\n /**\n * Normalizes `tokenSavingMode` to a boolean for backward-compatible boolean checks.\n * - `undefined` / `false` / `'off'` \u2192 false\n * - `true` / any tier string other than `'off'` \u2192 true\n *\n * Note: invalid tier strings (e.g. \"MINIMAL\") are coerced to 'off'\n * by `normalizeTokenSavingTier` via the `tier` getter, so isCompact\n * correctly returns false for them \u2014 preventing isCompact/tier\n * disagreement on bad input.\n */\n private get isCompact(): boolean {\n return this.tier !== 'off';\n }\n\n /** Exposes the effective (concrete) `TokenSavingTier` for tier-aware guidance\n * decisions. Invalid strings coerce to 'off'; the `'auto'` sentinel expands\n * from the model's context window (cache-safe \u2014 the window is stable per\n * session, so the resolved tier and therefore the prompt prefix stay stable).\n * See packages/core/src/types/config.ts. */\n private get tier(): ConcreteTokenSavingTier {\n return resolveTokenSavingTier(\n this.opts.tokenSavingMode,\n this.modelCapabilities()?.maxContextTokens,\n );\n }\n\n /**\n * Returns the max tool description length for the current tier.\n * Per the design doc: off=80, minimal=40, light=50, medium=60, aggressive=70.\n */\n private toolDescLimit(): number {\n switch (this.tier) {\n case 'minimal':\n return 30;\n case 'light':\n return 40;\n case 'medium':\n return 50;\n case 'aggressive':\n return 60;\n default:\n return 70;\n }\n }\n\n async build(ctx: BuildContext): Promise<TextBlock[]> {\n return flattenSystemPromptRegions(await this.buildRegions(ctx));\n }\n\n async buildRegions(ctx: BuildContext): Promise<SystemPromptRegions> {\n this._lastBuildTools = ctx.tools;\n // Re-read skill entries on every build so newly created/edited skills\n // (which call SkillLoader.invalidateCache()) are picked up without a\n // process restart. The SkillLoader itself caches disk I/O, so this is\n // cheap \u2014 only string formatting, no filesystem reads for cached data.\n if (this.opts.skillLoader) {\n try {\n const entries = await this.opts.skillLoader.listEntries();\n if (entries.length > 0) {\n const lines: string[] = [];\n for (const e of entries) {\n // Compact format: name + shortened trigger (full body in Active Skills)\n const shortTrigger = compactTrigger(e.trigger);\n lines.push(`- **${e.name}** (${shortTrigger})`);\n }\n this.skillCache = lines.join('\\n');\n } else {\n this.skillCache = '';\n }\n } catch {\n this.skillCache = '';\n }\n } else {\n this.skillCache = '';\n }\n\n const instructions = await this.instructions();\n const layer1 = instructions.system?.identity ?? LAYER_1_IDENTITY;\n const layer2 = await this.buildToolUsage(ctx.tools, ctx);\n const layer3 = await this.buildEnvironment(ctx);\n const layer3WithDir = `${layer3}\\n- Project root: ${ctx.projectRoot}`;\n const layer4 = await this.buildMemoryAndSkills();\n const layer5 = await this.buildMode();\n // Plans anchor the HOST agent across turns. Subagents run one\n // narrow task and shouldn't carry the host's strategic context \u2014\n // it just bloats their prompt and risks them mutating a plan\n // they weren't supposed to touch.\n const layer6 = ctx.subagent ? '' : await this.buildActivePlan();\n\n const core: TextBlock[] = [\n tagBlock(\n { type: 'text', text: layer1, cache_control: { type: 'ephemeral' } },\n 'identity',\n ),\n tagBlock(\n { type: 'text', text: layer2, cache_control: { type: 'ephemeral' } },\n 'tool-usage',\n ),\n ];\n const session: TextBlock[] = [\n tagBlock(\n { type: 'text', text: layer3WithDir, cache_control: { type: 'ephemeral' } },\n 'environment',\n ),\n ];\n const volatile: TextBlock[] = [];\n\n if (layer4.trim()) {\n session.push(\n tagBlock(\n { type: 'text', text: layer4, cache_control: { type: 'ephemeral' } },\n 'skills',\n ),\n );\n }\n\n if (layer5.trim()) {\n session.push(\n tagBlock(\n { type: 'text', text: layer5, cache_control: { type: 'ephemeral' } },\n 'mode',\n ),\n );\n }\n\n // Suggested skills for the active mode \u2014 helps the model know which\n // domain instructions to prioritize when multiple skills are loaded.\n if (this.opts.modeStore && this.opts.skillLoader) {\n try {\n const activeMode = await this.opts.modeStore.getActiveMode();\n if (activeMode?.suggestedSkills && activeMode.suggestedSkills.length > 0) {\n const skills = await this.opts.skillLoader.list();\n const loadedNames = new Set(skills.map((s) => s.name));\n const available = activeMode.suggestedSkills.filter((n) => loadedNames.has(n));\n if (available.length > 0) {\n session.push(\n tagBlock(\n {\n type: 'text',\n text: `Mode \"${activeMode.id}\" works best with these skills: ${available.join(', ')}. Their full instructions are in the Active Skills block above.`,\n cache_control: { type: 'ephemeral' },\n },\n 'mode',\n ),\n );\n }\n }\n } catch {\n // skip \u2014 non-critical hint\n }\n }\n\n if (layer6.trim()) {\n volatile.push(\n tagBlock(\n { type: 'text', text: layer6, cache_control: { type: 'ephemeral' } },\n 'plan',\n ),\n );\n }\n\n // System prompt contributors \u2014 plugins inject ephemeral context here.\n if (this.opts.contributors && this.opts.contributors.length > 0) {\n for (const c of this.opts.contributors) {\n try {\n const contributed = await c(ctx);\n for (const b of contributed) tagBlock(b, 'contributor');\n volatile.push(...contributed);\n } catch {\n // Contributor errors are swallowed \u2014 a bad plugin shouldn't\n // break the system prompt assembly.\n }\n }\n }\n\n // Leader-only after-task affordances (the `<nextsteps>` block + post-task\n // mailbox update). Host-only and appended last: subagents are headless\n // workers whose output is parsed (SDD spec/plan/task JSON) or rolled up by\n // the parent, so a `<nextsteps>` tag there is just noise that leaks into\n // specs/plans. Lives outside layer1 so the host keeps it in EVERY mode while\n // no subagent ever receives it.\n if (!ctx.subagent) {\n session.push(\n tagBlock(\n {\n type: 'text',\n text: instructions.system?.leaderAfterTask ?? LEADER_AFTER_TASK_PROMPT,\n },\n 'leader-after-task',\n ),\n );\n }\n\n return { core, session, volatile };\n }\n\n private async instructions(): Promise<InstructionBundle> {\n if (!this._instructionBundle) {\n this._instructionBundle = loadInstructionBundle(this.opts.instructionPaths).then((bundle) =>\n this.opts.instructionBundle\n ? mergeInstructionBundle(bundle, this.opts.instructionBundle)\n : bundle,\n );\n }\n return this._instructionBundle;\n }\n\n /**\n * Cached plan content keyed by (planPath, mtimeMs). The plan is read\n * once per system-prompt build; most turns don't change the plan, so\n * this avoids a blocking fs.readFile + JSON.parse on every iteration.\n * Cleared when the file's mtime changes (the `/plan` tool mutated it).\n */\n private _planCache?: ActivePlanCache | undefined;\n\n /**\n * Reads the session-scoped plan sidecar (when configured) and produces\n * a short \"Active plan\" block listing open items so the model is\n * anchored to the strategic roadmap every turn. Reads on every `build()`\n * so a plan edit (via `/plan` or the `plan` tool) reflects on the next\n * turn without restarting the session.\n */\n private async buildActivePlan(): Promise<string> {\n const planPath =\n typeof this.opts.planPath === 'function' ? this.opts.planPath() : this.opts.planPath;\n const result = await readActivePlanBlock({\n planPath,\n cache: this._planCache,\n });\n this._planCache = result.cache;\n return result.text;\n }\n\n private async buildToolUsage(tools: Tool[], ctx: BuildContext): Promise<string> {\n if (tools.length === 0) return '## Tool usage\\n\\nNo tools registered.';\n const instructions = await this.instructions();\n\n // Cache: tools array is stable (same reference) until a registry mutation\n // thanks to B2 (ToolRegistry snapshot). Online agents are keyed by content\n // fingerprint \u2014 the mailbox rebuilds the array on every status check, so\n // reference equality would always miss. When all three keys match the\n // previous build, the full output is identical \u2014 return the cached\n // string. Including `tier` in the key ensures that mutating\n // `opts.tokenSavingMode` between builds (rare but supported via the\n // `private readonly opts` design) recomputes the prompt with the\n // new tier's truncation limits and tier-gated content.\n const agentsHash = agentsFingerprint(ctx.onlineAgents);\n const tier = this.tier;\n if (\n this._toolsUsageCache?.toolsRef === tools &&\n this._toolsUsageCache?.agentsHash === agentsHash &&\n this._toolsUsageCache?.tier === tier\n ) {\n return this._toolsUsageCache.text;\n }\n\n // Group tools by category for a cleaner listing when categories are used.\n const byCat = new Map<string, Tool[]>();\n const uncategorized: Tool[] = [];\n for (const t of tools) {\n if (t.category) {\n let group = byCat.get(t.category);\n if (!group) {\n group = [];\n byCat.set(t.category, group);\n }\n group.push(t);\n } else {\n uncategorized.push(t);\n }\n }\n\n const lines = ['## Tool usage'];\n const descLimit = this.toolDescLimit();\n\n // Categorized tools\n for (const [cat, catTools] of byCat) {\n lines.push(`\\n### ${cat}`);\n for (const t of catTools) {\n const hint = t.usageHint ?? t.description;\n // Trim to the tier-specific limit, preferring sentence boundaries.\n const desc =\n hint.length > descLimit\n ? hint.slice(0, hint.indexOf('.', 20) + 1 || descLimit) +\n (hint.length > descLimit ? '\u2026' : '')\n : hint.trim();\n lines.push(`- **${t.name}** \u2014 ${desc}`);\n const boundary = renderToolSelectionBoundary(t);\n if (boundary) lines.push(` ${boundary}`);\n }\n }\n\n // Uncategorized tools\n if (uncategorized.length > 0) {\n if (byCat.size > 0) lines.push('');\n for (const t of uncategorized) {\n const hint = t.usageHint ?? t.description;\n lines.push(`\\n### ${t.name}\\n${hint.trim()}`);\n const boundary = renderToolSelectionBoundary(t);\n if (boundary) lines.push(boundary);\n }\n }\n\n // Common tool chain patterns \u2014 teaches model how to compose tools effectively.\n // Skipped in minimal and aggressive tiers \u2014 model already knows these patterns\n // and aggressive users are under context pressure.\n if (this.tier !== 'minimal' && this.tier !== 'aggressive') {\n const commonPatterns = instructionSection(instructions, 'tool.common.patterns');\n if (commonPatterns) lines.push(commonPatterns);\n }\n\n // Delegation guidance \u2014 included when the `delegate` tool is present.\n // Without this block the model doesn't know that multi-agent work is\n // even an option, and `delegate` sits unused while the host agent\n // tries to do everything in one expensive context.\n // Tier behaviour:\n // - 'off' / 'medium' / 'aggressive' \u2192 full block\n // - 'light' \u2192 minimal one-liner\n // - 'minimal' \u2192 skipped\n const hasDelegate = tools.some((t) => t.name === 'delegate');\n if (hasDelegate) {\n const delegateTool = tools.find((t) => t.name === 'delegate');\n const enumValues = (() => {\n const role = (\n delegateTool?.inputSchema as\n | { properties?: { role?: { enum?: unknown | undefined } } }\n | undefined\n )?.properties?.role?.enum;\n return Array.isArray(role) ? (role.filter((r) => typeof r === 'string') as string[]) : [];\n })();\n const roleList = enumValues.length > 0 ? enumValues.join(', ') : '(no roster configured)';\n if (this.tier === 'minimal') {\n // Skip \u2014 don't emit any delegation guidance\n } else if (this.tier === 'light' || this.tier === 'medium' || this.tier === 'aggressive') {\n // Token-saving tiers get the compact one-liner instead of the full\n // multi-paragraph guidance. `aggressive` joins the compact group \u2014\n // a user under context pressure doesn't need a 600-token essay on\n // subagent scoping.\n const delegation = instructionSection(instructions, 'tool.delegation.compact', {\n roleList,\n });\n if (delegation) lines.push(delegation);\n } else {\n const delegation = instructionSection(instructions, 'tool.delegation.full', {\n roleList,\n });\n if (delegation) lines.push(delegation);\n }\n }\n\n // Mailbox guidance \u2014 included when any mailbox tool is present.\n // Tier behaviour:\n // - 'off' \u2192 full block\n // - every token-saving tier \u2192 compact project-wide contract\n //\n // Note: 'aggressive' was previously listed with 'off' for the\n // full block, but per the parallel-session decision (Option H,\n // `leader@1b68eb14`): at aggressive, the 400-token mailbox essay\n // is the largest single guidance section and users under context\n // pressure don't need it. The compact one-liner is enough.\n const hasMailbox = tools.some(\n (t) => t.name === 'mailbox' || t.name === 'mail_send' || t.name === 'mail_inbox',\n );\n if (hasMailbox) {\n // Build online-agent info \u2014 cached by a rendered-field fingerprint so\n // joins/leaves and live status/task/tool changes invalidate it.\n const onlineAgentsInfo = this.renderOnlineAgents(ctx.onlineAgents);\n const hasMailboxPowerTool = tools.some((t) => t.name === 'mailbox');\n const mailStatusCommand = tools.some((t) => t.name === 'fleet_status')\n ? '`fleet_status`'\n : hasMailboxPowerTool\n ? '`mailbox action=status` or `mailbox action=online`'\n : 'the online-agent list above';\n const mailInboxCommand = tools.some((t) => t.name === 'mail_inbox')\n ? '`mail_inbox`'\n : '`mailbox action=check`';\n const mailSendCommand = tools.some((t) => t.name === 'mail_send')\n ? '`mail_send`'\n : '`mailbox action=send`';\n const mailboxVars = {\n onlineAgentsInfo,\n mailStatusCommand,\n mailInboxCommand,\n mailSendCommand,\n };\n if (this.tier !== 'off') {\n // Minimal: keep just the header and agent count.\n // `aggressive` joins `light`/`medium` \u2014 the 400-token mailbox essay\n // is the largest single guidance section; users under context pressure\n // don't need it.\n const mailbox = instructionSection(\n instructions,\n 'tool.mailbox.compact',\n mailboxVars,\n );\n if (mailbox) lines.push(mailbox);\n } else {\n const mailbox = instructionSection(instructions, 'tool.mailbox.full', mailboxVars);\n if (mailbox) lines.push(mailbox);\n }\n }\n\n // Commit hygiene \u2014 shown whenever the structured `git` tool is available.\n // Other agents (or a separate wrongstack process, or a human) may be\n // editing the SAME working tree at the same time; a blanket commit captures\n // their half-done work and there is no clean way to undo a shared commit.\n const hasGitTool = tools.some((t) => t.name === 'git');\n if (hasGitTool && this.tier !== 'minimal' && this.tier !== 'light') {\n const commitHygiene = instructionSection(instructions, 'tool.commit.hygiene');\n if (commitHygiene) lines.push(commitHygiene);\n }\n\n // MCP lazy-loading guidance \u2014 shown whenever mcp_control is registered.\n // Tier behaviour:\n // - 'off' / 'medium' \u2192 full guidance block\n // - 'minimal' / 'light' / 'aggressive' \u2192 minimal one-liner\n //\n // Note: 'aggressive' was previously listed with 'off' for the\n // full block, but per the parallel-session decision (Option H):\n // at aggressive, the full MCP workflow (activate \u2192 use \u2192\n // deactivate) is documented elsewhere and the meta-tool\n // `mcp_use` is sufficient. The one-liner is enough.\n const hasMcpControl = tools.some((t) => t.name === 'mcp_control');\n const hasMcpUse = tools.some((t) => t.name === 'mcp_use');\n if (hasMcpControl) {\n if (this.tier === 'minimal' || this.tier === 'light' || this.tier === 'aggressive') {\n // Minimal one-liner \u2014 `aggressive` joins `minimal`/`light`. The full\n // MCP workflow (activate \u2192 use \u2192 deactivate) is documented elsewhere\n // and the meta-tool `mcp_use` is sufficient at any tier that has it.\n const mcp = instructionSection(\n instructions,\n hasMcpUse ? 'tool.mcp.compact.use' : 'tool.mcp.compact.control',\n );\n if (mcp) lines.push(mcp);\n } else {\n // Full block\n const mcp = instructionSection(\n instructions,\n hasMcpUse ? 'tool.mcp.full.use' : 'tool.mcp.full.control',\n );\n if (mcp) lines.push(mcp);\n }\n }\n\n // Context management guidance \u2014 shown when context_manager is registered.\n // Tier behaviour:\n // - 'off' / 'aggressive' \u2192 full block\n // - 'medium' \u2192 minimal one-liner\n // - 'minimal' / 'light' \u2192 skipped\n const hasContextManager = tools.some((t) => t.name === 'context_manager');\n if (hasContextManager) {\n if (this.tier === 'minimal' || this.tier === 'light') {\n // Skip\n } else if (this.tier === 'medium') {\n const contextManagement = instructionSection(\n instructions,\n 'tool.context.management.compact',\n );\n if (contextManagement) lines.push(contextManagement);\n } else {\n // Adaptive threshold based on model context window size.\n // Small context (<=32k) \u2192 trigger earlier; large context (>32k) \u2192 more relaxed.\n // Fallback to 0 when unknown \u2192 conservative compaction (50 % threshold).\n const maxCtx = this.modelCapabilities()?.maxContextTokens ?? 0;\n const threshold = maxCtx <= 32000 ? '50' : '70';\n const contextManagement = instructionSection(\n instructions,\n 'tool.context.management.full',\n { threshold },\n );\n if (contextManagement) lines.push(contextManagement);\n }\n }\n\n // Store cache \u2014 keyed by tools reference (B2 snapshot) + agents content\n // fingerprint + tier, so it auto-invalidates when tools change, agents\n // join/leave, or the token-saving tier changes.\n const text = lines.join('\\n');\n this._toolsUsageCache = { toolsRef: tools, agentsHash, tier, text };\n return text;\n }\n\n private renderOnlineAgents(agents: readonly MailboxAgentStatus[] | undefined): string {\n const result = renderOnlineAgents(agents, this.tier, this._lastOnlineAgents);\n this._lastOnlineAgents = result.cache;\n return result.text;\n }\n\n private async buildEnvironment(ctx: BuildContext): Promise<string> {\n return buildEnvironment(ctx, {\n tier: this.tier,\n isCompact: this.isCompact,\n modelCapabilities: this.modelCapabilities(),\n envCacheByRoot: this.envCacheByRoot,\n skillCache: this.skillCache,\n todayIso: this.opts.todayIso,\n modeId: this.opts.modeId,\n skillMode: this.opts.skillMode,\n });\n }\n\n private modelCapabilities(): ModelCapabilities | undefined {\n const caps = this.opts.modelCapabilities;\n return typeof caps === 'function' ? caps() : caps;\n }\n\n private async buildMemoryAndSkills(): Promise<string> {\n const result = await buildMemoryAndSkills({\n tier: this.tier,\n isCompact: this.isCompact,\n memoryStore: this.opts.memoryStore,\n injectMemory: this.opts.injectMemory,\n skillLoader: this.opts.skillLoader,\n skillMode: this.opts.skillMode,\n skillEagerMaxChars: this.opts.skillEagerMaxChars,\n lastBuildTools: this._lastBuildTools,\n skillBodyCache: this.skillBodyCache,\n });\n this.skillBodyCache = result.skillBodyCache;\n return result.text;\n }\n\n private async buildMode(): Promise<string> {\n // Use pre-resolved modePrompt if available (avoids redundant async call).\n if (this.opts.modePrompt) return this.opts.modePrompt;\n if (!this.opts.modeStore) return '';\n const mode = await this.opts.modeStore.getActiveMode();\n if (!mode?.prompt) return '';\n return mode.prompt;\n }\n\n}\n"],
5
- "mappings": "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",
6
- "names": ["createHash", "path", "hash", "path", "fs", "path", "createHash", "os", "path", "createHash", "relative", "resolve", "delay", "mailbox", "createHash", "randomUUID", "fs", "basename", "fs", "path", "path", "redacted", "out", "DEFAULT_HEARTBEAT_INTERVAL_MS", "delay", "t", "createHash", "basename", "randomUUID", "createHash", "createHash", "path", "isRecord", "t", "path", "t", "META_KEY", "META_KEY", "resolve", "randomUUID", "t", "randomUUID", "resolve", "createHash", "randomUUID", "delay", "resolve", "t", "META_KEY", "t", "META_KEY", "t", "stashed", "t", "hasText", "preview", "createHash", "parts", "resolve", "use", "contentBlocks", "hash", "createHash", "path", "t", "t", "text", "seen", "statSync", "fs", "path", "fileURLToPath", "stat", "readFileSync", "statSync", "path", "fileURLToPath", "os", "path", "spawn", "fs", "path", "stat", "resolve", "spawn", "platform", "platform", "hash", "text", "t", "fs", "stat", "t"]
7
- }