@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/context.ts", "../../src/utils/context-evidence.ts", "../../src/utils/tool-wire-compact.ts", "../../src/utils/token-estimate.ts", "../../src/core/conversation-state.ts", "../../src/utils/error.ts", "../../src/types/errors.ts", "../../src/types/blocks.ts", "../../src/utils/expect-defined.ts", "../../src/utils/message-invariants.ts", "../../src/execution/compaction-scoring.ts", "../../src/execution/compaction-core.ts", "../../src/execution/auto-compaction-middleware.ts", "../../src/types/context-window.ts", "../../src/infrastructure/logger.ts", "../../src/utils/term.ts", "../../src/utils/color.ts", "../../src/execution/compactor.ts", "../../src/execution/subagent-compaction.ts", "../../src/utils/assert-never.ts", "../../src/utils/regex-guard.ts", "../../src/execution/autonomous-runner.ts", "../../src/coordination/brain-heuristics.ts", "../../src/coordination/brain-telemetry.ts", "../../src/coordination/brain.ts", "../../src/utils/instruction-file.ts", "../../src/utils/safe-json.ts", "../../src/execution/autonomy-brain.ts", "../../src/utils/string.ts", "../../src/types/quota-regex.ts", "../../src/types/provider.ts", "../../src/core/model-ref.ts", "../../src/core/model-availability-calendar.ts", "../../src/core/fallback-profile-manager.ts", "../../src/core/fallback-model.ts", "../../src/execution/council-personas.ts", "../../src/execution/council-profiles.ts", "../../src/execution/council-prompts.ts", "../../src/execution/council-resolution.ts", "../../src/execution/council-orchestrator.ts", "../../src/execution/council-brain.ts", "../../src/execution/brain-chain.ts", "../../src/execution/brain-evaluation.ts", "../../src/coordination/brain-ledger.ts", "../../src/coordination/brain-cache.ts", "../../src/execution/brain-circuit.ts", "../../src/coordination/brain-rules.ts", "../../src/execution/brain-runtime-constants.ts", "../../src/execution/brain-runtime.ts", "../../src/storage/goal-store.ts", "../../src/utils/atomic-write.ts", "../../src/utils/wstack-paths.ts", "../../src/execution/autonomy-prompt-contributor.ts", "../../src/types/design-kit.ts", "../../src/execution/design-kit-loader.ts", "../../src/execution/design-project-store.ts", "../../src/execution/design-color.ts", "../../src/execution/design-verify.ts", "../../src/execution/design-detect.ts", "../../src/execution/regex-patterns.ts", "../../src/execution/error-handler.ts", "../../src/execution/eternal-autonomy.ts", "../../src/storage/goal-coordination.ts", "../../src/storage/goal-kanban.ts", "../../src/utils/sleep.ts", "../../src/execution/goal-preamble.ts", "../../src/execution/compaction-summary-cache.ts", "../../src/utils/lru-cache.ts", "../../src/execution/intelligent-compactor.ts", "../../src/execution/model-runtime.ts", "../../src/execution/parallel-eternal-engine.ts", "../../src/coordination/subagent-budget.ts", "../../src/security/capabilities.ts", "../../src/coordination/subagent-result-tool.ts", "../../src/coordination/agent-subagent-runner.ts", "../../src/coordination/agents/types.ts", "../../src/coordination/agents/agent-prompts.ts", "../../src/coordination/agents/project-agent-identity.ts", "../../src/coordination/agents/project-agent-knowledge-manifests.ts", "../../src/coordination/agents/project-agent-learning-policy.ts", "../../src/coordination/agents/project-agent-paths.ts", "../../src/coordination/agents/project-agent-learning-entries.ts", "../../src/coordination/agents/project-agent-consolidation.ts", "../../src/coordination/agents/phase1-discovery.ts", "../../src/coordination/agents/phase2-planning.ts", "../../src/coordination/agents/phase3-build.ts", "../../src/coordination/agents/phase3-wave1-platform.ts", "../../src/coordination/agents/phase3-wave2-meta.ts", "../../src/coordination/agents/phase4-verify.ts", "../../src/coordination/agents/phase5-review.ts", "../../src/coordination/agents/phase6-domain.ts", "../../src/coordination/agents/phase7-knowledge.ts", "../../src/coordination/agents/phase8-delivery.ts", "../../src/coordination/agents/phase8-wave3-products.ts", "../../src/coordination/agents/phase9-meta.ts", "../../src/coordination/agents/phase9-wave4-platform-meta.ts", "../../src/coordination/agents/role-skills.ts", "../../src/coordination/agents/index.ts", "../../src/coordination/dispatcher.ts", "../../src/coordination/multi-agent-coordinator.ts", "../../src/coordination/coordinator/error-classifier.ts", "../../src/coordination/fleet.ts", "../../src/coordination/subagent-nicknames.ts", "../../src/coordination/multi-agent-timeout.ts", "../../src/execution/retry-policy.ts", "../../src/utils/compaction-preview.ts", "../../src/models/llm-selector.ts", "../../src/execution/selective-compactor.ts", "../../src/execution/skill-loader.ts", "../../src/skills/foreign-sources.ts", "../../src/skills/frontmatter.ts", "../../src/skills/limits.ts", "../../src/execution/prompt-loader.ts", "../../src/storage/prompt-store.ts", "../../src/utils/slug.ts", "../../src/utils/ulid.ts", "../../src/types/prompt.ts", "../../src/utils/json-schema-validate.ts", "../../src/utils/tool-output-serializer.ts", "../../src/utils/tool-result-render-mode.ts", "../../src/utils/tool-subject.ts", "../../src/execution/strategy-compactor.ts", "../../src/execution/tool-executor.ts", "../../src/observability/process-telemetry.ts", "../../src/observability/network-telemetry.ts", "../../src/security/kanban-boundary.ts", "../../src/types/tool-executor.ts", "../../src/execution/tool-executor-support.ts", "../../src/types/tool-markers.ts", "../../src/execution/tool-executor-results.ts", "../../src/execution/tool-executor-logging.ts", "../../src/execution/tool-executor-stream.ts", "../../src/execution/one-shot-llm.ts", "../../src/execution/prompt-enhancer.ts", "../../src/execution/enhance-recovery.ts"],
4
- "sourcesContent": ["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 * 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 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 * 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", "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", "/** 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", "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", "import type { ToolResultBlock } from '../types/blocks.js';\nimport { isTextBlock } from '../types/blocks.js';\nimport type { Message } from '../types/messages.js';\n\nconst FAILURE_PATTERN = /(error|fail|exception|timeout|enonet|eacces|eperm|enoent|abort|hata|ba\u015Far\u0131s\u0131z|basarisiz)/i;\nconst CORRECTION_PATTERN = /\\b(wrong|no\\b|stop\\b|don'?t\\b|actually|fix that|undo|revert|forget|ignore|skip)\\b/i;\nconst ERROR_LANG_PATTERN = /\\b(error|exception|fatal|critical|crash|panic|abort|segfault|core dump|undefined is not|null pointer|typeerror|referenceerror|syntaxerror)\\b/i;\nconst SECURITY_PATTERN = /\\b(security|vulnerability|injection|xss|csrf|secret|apikey|api.key|hardcoded|leak|exploit|cve)\\b/i;\nconst ARCHITECTURE_PATTERN = /\\b(architecture|design|approach|strategy|pattern|refactor|migrate|restructure|decision|trade.?off)\\b/i;\nconst CORRECTION_PATTERN_TR =\n /(hay\u0131r|hayir|yanl\u0131\u015F|yanlis|durdur|dur\\b|yapma\\b|geri al|d\u00FCzelt|duzelt|bo\u015F ?ver|bosver|iptal|olmad\u0131|olmadi|bozdun|yapmad\u0131n|yapmadin|de\u011Fil|degil|vazge\u00E7|vazgec)/i;\nconst ERROR_LANG_PATTERN_TR =\n /(hata\\b|hatas\u0131|hatasi|ba\u015Far\u0131s\u0131z|basarisiz|\u00E7\u00F6kt\u00FC|coktu|kritik|\u00E7ak\u0131ld\u0131|cakildi|tak\u0131ld\u0131|takildi|patlad\u0131|patladi)/i;\nconst ARCHITECTURE_PATTERN_TR =\n /(mimari|tasar\u0131m|tasarim|yakla\u015F\u0131m|yaklasim|strateji|karar\\b|yeniden yap\u0131land|yeniden yapiland|refakt\u00F6r|refaktor|g\u00F6\u00E7 et|goc et|ge\u00E7i\u015F|gecis)/i;\nconst BOILERPLATE_PATTERN = /\\b(files_with_matches|count|found \\d+ match|directory tree|\\.\\.\\. and \\d+ more)\\b/i;\n\nexport type ContentScore = 0 | 1 | 2 | 3 | 4 | 5;\n\nexport function extractText(m: Message): string {\n if (typeof m.content === 'string') return m.content;\n return m.content\n .filter(isTextBlock)\n .map((b) => b.text)\n .join('\\n');\n}\n\nexport function hasToolUse(m: Message): boolean {\n if (typeof m.content === 'string') return false;\n return m.content.some((b) => b.type === 'tool_use');\n}\n\nexport function hasLargeToolResult(m: Message, threshold = 3000): boolean {\n if (typeof m.content === 'string') return false;\n return m.content.some(\n (b) =>\n b.type === 'tool_result' &&\n (b as ToolResultBlock).content &&\n (typeof (b as ToolResultBlock).content === 'string'\n ? (b as ToolResultBlock).content.length\n : JSON.stringify((b as ToolResultBlock).content).length) > threshold,\n );\n}\n\nexport function scoreMessage(\n m: Message,\n context?: { failureCounts?: Map<string, number> },\n): ContentScore {\n const text = extractText(m).toLowerCase();\n\n if (text.trim().length === 0 && (hasToolUse(m) || typeof m.content !== 'string')) {\n const hasResult =\n typeof m.content !== 'string' && m.content.some((b) => b.type === 'tool_result');\n if (hasToolUse(m) || hasResult) return 0;\n }\n\n if (context?.failureCounts && m.role === 'user' && hasToolUse(m) === false) {\n const failureMatch = FAILURE_PATTERN.exec(text);\n if (failureMatch) {\n const errKey = failureMatch[0]?.toLowerCase() ?? 'error';\n const count = (context.failureCounts.get(errKey) ?? 0) + 1;\n context.failureCounts.set(errKey, count);\n if (count >= 5) return 0;\n if (count >= 3) return 1;\n }\n }\n\n if (m.role === 'user') {\n if (CORRECTION_PATTERN.test(text) || CORRECTION_PATTERN_TR.test(text)) {\n return 5;\n }\n }\n if (ERROR_LANG_PATTERN.test(text) || ERROR_LANG_PATTERN_TR.test(text)) return 5;\n if (SECURITY_PATTERN.test(text)) return 5;\n if (m.role === 'assistant' && (ARCHITECTURE_PATTERN.test(text) || ARCHITECTURE_PATTERN_TR.test(text))) {\n return 5;\n }\n if (hasLargeToolResult(m)) return 1;\n if (m.role === 'user' && !hasToolUse(m) && BOILERPLATE_PATTERN.test(text)) return 1;\n return 3;\n}\n\nexport function buildSmartDigest(messages: readonly Message[]): string {\n const lines: string[] = [];\n const failureCounts = new Map<string, number>();\n let noiseCount = 0;\n\n for (const m of messages) {\n const isPureToolIO =\n Array.isArray(m.content) &&\n m.content.length > 0 &&\n !hasToolUse(m) &&\n m.content.every((b) => b.type === 'tool_result');\n if (isPureToolIO) {\n noiseCount++;\n continue;\n }\n\n const score = scoreMessage(m, { failureCounts });\n const text = extractText(m);\n const toolCount = countToolBlocks(m);\n\n if (score === 0) {\n noiseCount++;\n continue;\n }\n\n const marker = toolCount > 0 ? ` [${toolCount} tool call(s)]` : '';\n let display: string;\n switch (score) {\n case 5:\n display = text.trim();\n break;\n case 3:\n display = firstSentence(text);\n break;\n case 1:\n display = oneLineSummary(m, text);\n break;\n default:\n display = firstSentence(text);\n }\n\n if (display.length === 0 && toolCount === 0) continue;\n lines.push(`[${m.role}]: ${display}${marker}`);\n }\n\n if (noiseCount > 0) {\n lines.push(\n `[system]: ${noiseCount} low-importance turn(s) collapsed (repeated failures / pure tool I/O)`,\n );\n }\n\n return lines.join('\\n');\n}\n\nfunction countToolBlocks(m: Message): number {\n if (typeof m.content === 'string') return 0;\n return m.content.filter((b) => b.type === 'tool_use' || b.type === 'tool_result').length;\n}\n\nfunction firstSentence(text: string): string {\n const trimmed = text.trim();\n if (trimmed.length === 0) return '';\n const dot = trimmed.indexOf('. ');\n if (dot === -1) return trimmed.length > 150 ? `${trimmed.slice(0, 147)}\u2026` : trimmed;\n const sentence = trimmed.slice(0, dot + 1);\n return sentence.length > 150 ? `${sentence.slice(0, 147)}\u2026` : sentence;\n}\n\nfunction oneLineSummary(m: Message, text: string): string {\n const trimmed = text.trim();\n if (trimmed.length === 0) {\n if (typeof m.content !== 'string') {\n const results = m.content.filter((b) => b.type === 'tool_result');\n if (results.length > 0) {\n return `[${results.length} tool result(s) \u2014 see session log]`;\n }\n }\n return '[no text content]';\n }\n const firstLine = trimmed.split('\\n')[0] ?? '';\n return firstLine.length > 100 ? `${firstLine.slice(0, 97)}\u2026` : firstLine;\n}\n", "import type { ContentBlock, ToolResultBlock, ToolUseBlock } from '../types/blocks.js';\nimport { isTextBlock } from '../types/blocks.js';\nimport type { Message } from '../types/messages.js';\nimport type { Logger } from '../types/logger.js';\nimport { repairToolUseAdjacency } from '../utils/message-invariants.js';\nimport {\n computeMessageTokens,\n estimateMessageTokens,\n estimateTextTokens,\n estimateToolInputTokens,\n estimateToolResultTokens,\n} from '../utils/token-estimate.js';\nexport {\n buildSmartDigest,\n extractText,\n hasLargeToolResult,\n hasToolUse,\n scoreMessage,\n type ContentScore,\n} from './compaction-scoring.js';\n\n// Path hint extraction \u2014 used inside firstErrorLine path summaries.\nconst PATH_HINT_PATTERN = /(?:(?:[A-Za-z]:)?[./\\\\]?[\\w@.-]+(?:[\\\\/][\\w@(). -]+)+\\.[A-Za-z0-9]{1,12})/g;\nconst PATH_BACKSLASH_PATTERN = /\\\\/g;\nconst PATH_TRIM_PATTERN = /^[\"'`]+|[\"'`),;:]+$/g;\n\n// Error line detection \u2014 first non-blank line whose text matches the\n// set of words that indicate something went wrong.\nconst ERROR_LINE_PATTERN = /\\b(error|exception|failed|failure|fatal|panic|timeout|denied|enoent|eacces|eperm)\\b/i;\nconst NEWLINE_SPLIT_PATTERN = /\\r?\\n/;\nconst WHITESPACE_COLLAPSE_PATTERN = /\\s+/g;\n\n/**\n * Instrumentation state for compaction hot-path analysis.\n * Tracks actual vs. nominal iteration counts to detect O(n\u00B7m) blowup.\n *\n * Logged as structured events so they can be aggregated from session JSONL\n * and plotted per-message-count to catch regressions before they ship.\n */\ninterface CompactionMetrics {\n /** Total messages in the compaction pass. */\n messageCount: number;\n /** Index where the preserved window starts (from findPreserveStart). */\n preserveStart: number;\n /** Outer-loop iterations in the elision fast-path scan. */\n fastPathIterations: number;\n /**\n * Inner-loop block iterations in the fast-path scan.\n * Ratio fastPathInner / fastPathIterations indicates avg blocks per message.\n */\n fastPathInnerIterations: number;\n /**\n * Outer-loop iterations in the full elision pass.\n * A targeted pass starts at the first oversized old tool block and stops at\n * the preserve boundary, so this should stay well below messageCount when\n * the fast-path hit is late in the old window.\n */\n fullPassIterations: number;\n /**\n * Inner-loop block iterations in the full elision pass.\n * Ratio fullPassInner / fullPassIterations indicates avg blocks per message.\n */\n fullPassInnerIterations: number;\n /** Estimated tokens saved by the elision pass. */\n tokensSaved: number;\n /** Whether the full elision pass made any changes. */\n changed: boolean;\n}\n\n/**\n * Whether compaction instrumentation should be emitted to stdout.\n * Gated behind WRONGSTACK_DEBUG=1 or NODE_ENV=development so the hot path\n * does not pay for JSON.stringify + console.log on every compaction pass\n * in production. Matches the guard at the ratio-guard site (line ~281).\n */\nfunction compactionDebugEnabled(): boolean {\n return process.env['NODE_ENV'] === 'development' || process.env['WRONGSTACK_DEBUG'] === '1';\n}\n\n/**\n * Module-level debug logger for compaction instrumentation. Set by\n * compactor classes that have a Logger instance; falls back to\n * console.log/error when unset (preserves existing debug output).\n */\nlet _debugLogger: Logger | undefined;\n\n/** Set the module-level compaction debug logger (called by compactor constructors). */\nexport function setCompactionDebugLogger(logger: Logger | undefined): void {\n _debugLogger = logger;\n}\n\n/** Emit compaction instrumentation as a structured log event (debug-only). */\nfunction emitCompactionMetrics(event: string, metrics: CompactionMetrics): void {\n if (!compactionDebugEnabled()) return;\n const ctx = {\n event,\n messageCount: metrics.messageCount,\n preserveStart: metrics.preserveStart,\n fastPathIterations: metrics.fastPathIterations,\n fastPathInnerIterations: metrics.fastPathInnerIterations,\n fastPathInnerPerOuter:\n metrics.fastPathIterations > 0\n ? metrics.fastPathInnerIterations / metrics.fastPathIterations\n : 0,\n fullPassIterations: metrics.fullPassIterations,\n fullPassInnerIterations: metrics.fullPassInnerIterations,\n fullPassInnerPerOuter:\n metrics.fullPassIterations > 0\n ? metrics.fullPassInnerIterations / metrics.fullPassIterations\n : 0,\n tokensSaved: metrics.tokensSaved,\n changed: metrics.changed,\n };\n if (_debugLogger) {\n _debugLogger.debug(`compaction: ${event}`, ctx);\n } else {\n console.log(JSON.stringify({ level: 'debug', ...ctx }));\n }\n}\n\n/**\n * Token estimate for a message array (text + tool I/O). Re-exported from the\n * canonical `token-estimate` helper so compactors and the context-pressure\n * monitor share one number.\n */\nexport const estimateMessages = estimateMessageTokens;\n\n// `buildCompactionPreview` (with its `safePreviewString`/`truncatePreview`\n// helpers) moved to `../utils/compaction-preview.js` \u2014 a neutral layer both the\n// execution compactors and the models-layer LLMSelector can import without the\n// models\u2192execution runtime cycle the boundary test forbids. The shared\n// `extractPathHints`/`firstErrorLine` helpers stay here (they are also used by\n// the elision summariser below).\n\n/**\n * Shared, pure compaction primitives.\n *\n * Before this module the three compactors (`HybridCompactor`,\n * `IntelligentCompactor`, `SelectiveCompactor`) each carried their own copies\n * of message-token estimation, tool-result elision, text detection and digest\n * rendering \u2014 with subtle divergences (notably Selective lacked the\n * tool_use/tool_result pair preservation, so it could elide the result of a\n * tool call it was supposed to keep). These helpers are the single source of\n * truth. They operate on plain `Message[]` and never touch `Context`/state, so\n * each compactor keeps its own `ctx.state.replaceMessages(...)` plumbing.\n */\n\n/** Does this message carry any non-empty text? */\nexport function hasTextContent(m: Message): boolean {\n if (typeof m.content === 'string') return m.content.trim().length > 0;\n return m.content.some((b) => b.type === 'text' && b.text.trim().length > 0);\n}\n\n/**\n * Index where the preserved (recent) window starts. Walks back counting\n * user/assistant messages until `preserveK` are covered, then walks forward to\n * keep any tool_use/tool_result protocol pair intact \u2014 so a tool_result whose\n * tool_use is preserved is never elided.\n *\n * Instrumentation: emits `compaction.find_preserve_start.ended` with the\n * repair-loop block count so we can track whether protocol-pair repair is\n * scanning too much content.\n */\nexport function findPreserveStart(messages: readonly Message[], preserveK: number): number {\n let pairCount = 0;\n let preserveStart = messages.length;\n for (let i = messages.length - 1; i >= 0 && pairCount < preserveK; i--) {\n const m = messages[i];\n if (!m) continue;\n if (m.role === 'user' || m.role === 'assistant') {\n pairCount++;\n preserveStart = i;\n }\n }\n\n // If the preserved window starts on a user tool_result, widen backward to\n // include the immediately preceding assistant tool_use. This keeps provider\n // protocol adjacency intact and avoids orphaned results after compaction.\n let pairRepairIterations = 0;\n let pairRepairInnerIterations = 0;\n while (preserveStart > 0) {\n pairRepairIterations++;\n const first = messages[preserveStart];\n const prev = messages[preserveStart - 1];\n if (!first || !prev || first.role !== 'user' || prev.role !== 'assistant') break;\n if (typeof first.content === 'string' || typeof prev.content === 'string') break;\n const pairCheck = hasMatchingToolPair(first.content, prev.content);\n pairRepairInnerIterations += pairCheck.iterations;\n if (!pairCheck.matched) break;\n preserveStart--;\n }\n\n if (compactionDebugEnabled()) {\n const ctx = {\n event: 'compaction.find_preserve_start.ended',\n messageCount: messages.length,\n preserveK,\n preserveStart,\n pairRepairIterations,\n pairRepairInnerIterations,\n pairRepairInnerPerOuter:\n pairRepairIterations > 0 ? pairRepairInnerIterations / pairRepairIterations : 0,\n };\n if (_debugLogger) {\n _debugLogger.debug('compaction: find_preserve_start.ended', ctx);\n } else {\n console.log(JSON.stringify({ level: 'debug', ...ctx }));\n }\n }\n\n return preserveStart;\n}\n\nfunction hasMatchingToolPair(\n resultContent: readonly ContentBlock[],\n useContent: readonly ContentBlock[],\n): { matched: boolean; iterations: number } {\n let iterations = 0;\n let firstResultId: string | undefined;\n let resultIds: Set<string> | undefined;\n\n for (const block of resultContent) {\n iterations++;\n if (block.type !== 'tool_result') continue;\n if (firstResultId === undefined) {\n firstResultId = block.tool_use_id;\n } else {\n resultIds ??= new Set([firstResultId]);\n resultIds.add(block.tool_use_id);\n }\n }\n if (firstResultId === undefined) return { matched: false, iterations };\n\n for (const block of useContent) {\n iterations++;\n if (block.type !== 'tool_use') continue;\n if (resultIds ? resultIds.has(block.id) : block.id === firstResultId) {\n return { matched: true, iterations };\n }\n }\n\n return { matched: false, iterations };\n}\n\nexport interface EliseResult {\n /** New message array, or the same reference when nothing changed. */\n messages: Message[];\n /** Estimated tokens reclaimed. */\n saved: number;\n changed: boolean;\n}\n\n/**\n * Elide oversized tool I/O that falls before the preserve window. Pure:\n * returns a fresh array (or the same reference when unchanged). Replaces the\n * duplicate copies that lived in all three compactors.\n */\nexport function eliseOldToolResults(\n messages: readonly Message[],\n opts: { preserveK: number; eliseThreshold: number },\n): EliseResult {\n const preserveStart = findPreserveStart(messages, opts.preserveK);\n\n // \u2500\u2500 Per-block token-estimate cache \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 // Both the fast-path probe and the full pass call estimateToolResultTokens /\n // estimateToolInputTokens on the same block. On oversized-tool-result\n // sessions (thousands of 7 KB+ results) the redundant re-estimate is the\n // single biggest cost \u2014 profiling showed ~11 ms/msg dominated by the\n // estimator running twice per oversized block. The cache is keyed by the\n // block object itself (stable within one call), scoped to this invocation,\n // and free of GC risk: it dies with the closure. A plain Map is used rather\n // than WeakMap because ToolUseBlock/ToolResultBlock are plain object literals\n // (no identity stability guarantee across callers, but stable within one\n // pass \u2014 which is all we need).\n const tokenCache = new Map<ContentBlock, number>();\n const tokensFor = (b: ContentBlock): number => {\n const cached = tokenCache.get(b);\n if (cached !== undefined) return cached;\n const t =\n b.type === 'tool_result'\n ? estimateToolResultTokens(b.content)\n : b.type === 'tool_use'\n ? estimateToolInputTokens(b.input)\n : 0;\n tokenCache.set(b, t);\n return t;\n };\n\n // \u2500\u2500 Fast path: probe for oversized tool I/O \u2500\u2500\u2500\u2500\u2500\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 // Instruments the ratio of actual iterations to message count so we can\n // detect whether the inner block-scan loop is O(n\u00B7m) as expected or has\n // regressed to quadratic behaviour.\n let hasOversized = false;\n let firstOversizedIndex = -1;\n let fastPathIterations = 0;\n let fastPathInnerIterations = 0;\n for (let i = 0; i < preserveStart && !hasOversized; i++) {\n fastPathIterations++;\n const msg = messages[i];\n if (!msg || !Array.isArray(msg.content)) continue;\n for (const b of msg.content) {\n fastPathInnerIterations++;\n const oversized = tokensFor(b) >= opts.eliseThreshold;\n if (oversized) {\n hasOversized = true;\n firstOversizedIndex = i;\n break;\n }\n }\n }\n\n // \u2500\u2500 Emit fast-path metrics (covers both fast-path hit and the early-exit) \u2500\u2500\n emitCompactionMetrics(\n hasOversized\n ? 'compaction.elision.fast_path.oversized_found'\n : 'compaction.elision.fast_path.no_oversized',\n {\n messageCount: messages.length,\n preserveStart,\n fastPathIterations,\n fastPathInnerIterations,\n fullPassIterations: 0,\n fullPassInnerIterations: 0,\n tokensSaved: 0,\n changed: false,\n },\n );\n\n if (!hasOversized) return { messages: messages as Message[], saved: 0, changed: false };\n\n // \u2500\u2500 Targeted elision pass \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 fast path already proved that every message before firstOversizedIndex\n // is below threshold, and preserveStart caps the old window. Only scan that\n // narrowed range, and only clone the message array/content array when an\n // actual replacement is made.\n let saved = 0;\n let changed = false;\n let fullPassIterations = 0;\n let fullPassInnerIterations = 0;\n let next: Message[] | undefined;\n for (let i = firstOversizedIndex; i < preserveStart; i++) {\n fullPassIterations++;\n const msg = messages[i];\n if (!msg || !Array.isArray(msg.content)) continue;\n const original = msg.content;\n let newContent: ContentBlock[] | undefined;\n for (let idx = 0; idx < original.length; idx++) {\n fullPassInnerIterations++;\n const b = original[idx];\n if (!b) continue;\n if (b.type === 'tool_use') {\n const tokens = tokensFor(b);\n if (tokens < opts.eliseThreshold) continue;\n const elidedInput = summarizeToolUseInputElision(b, tokens);\n saved += Math.max(0, tokens - estimateToolInputTokens(elidedInput));\n newContent ??= original.slice();\n newContent[idx] = { ...b, input: elidedInput };\n continue;\n }\n\n if (b.type !== 'tool_result') continue;\n const tokens = tokensFor(b);\n if (tokens < opts.eliseThreshold) continue;\n saved += tokens;\n const elided: ToolResultBlock = {\n type: 'tool_result',\n tool_use_id: b.tool_use_id,\n content: summarizeToolResultElision(b, tokens),\n is_error: b.is_error,\n };\n newContent ??= original.slice();\n newContent[idx] = elided;\n }\n if (newContent) {\n next ??= messages.slice() as Message[];\n // Clear the cached token estimate \u2014 content was replaced with\n // shorter elision markers but the spread preserves the original\n // `_estTokens` (set by ConversationState.appendMessage). Without\n // this, token estimates report the pre-elision size, making\n // compaction appear ineffective and risking false\n // AGENT_CONTEXT_OVERFLOW.\n next[i] = { ...msg, content: newContent, _estTokens: undefined };\n changed = true;\n }\n\n // \u2500\u2500 Ratio guard: defensive assertion + conditional early-break \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // Defensive assertion (threshold 10): fires in dev/debug if the inner loop\n // is running more than 10x what we'd expect per message. This catches\n // pathological regressions where a single message has hundreds of blocks.\n if (compactionDebugEnabled()) {\n const ratio = fullPassInnerIterations / fullPassIterations;\n\n if (ratio > 10) {\n // Defensive assertion: never expected in practice\n const ctx = {\n event: 'compaction.elision.regression',\n message: `fullPassInnerPerOuter=${ratio.toFixed(2)} exceeds threshold 10 \u2014 possible O(n\u00B7m) regression`,\n messageCount: messages.length,\n fullPassIterations,\n fullPassInnerIterations,\n };\n if (_debugLogger) {\n _debugLogger.error(`compaction: elision.regression \u2014 ratio ${ratio.toFixed(2)}`, ctx);\n } else {\n console.error(JSON.stringify({ level: 'error', ...ctx }));\n }\n }\n }\n }\n\n emitCompactionMetrics('compaction.elision.full_pass.ended', {\n messageCount: messages.length,\n preserveStart,\n fastPathIterations,\n fastPathInnerIterations,\n fullPassIterations,\n fullPassInnerIterations,\n tokensSaved: saved,\n changed,\n });\n\n return { messages: changed && next ? next : (messages as Message[]), saved, changed };\n}\n\nfunction summarizeToolUseInputElision(\n block: ToolUseBlock,\n tokens: number,\n): Record<string, unknown> {\n const fields: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(block.input ?? {})) {\n fields[key] = summarizeToolUseInputValue(value);\n }\n\n return {\n __elided_tool_input: `~${tokens} tokens; original arguments are in the session log`,\n tool: block.name,\n fields,\n };\n}\n\nfunction summarizeToolUseInputValue(value: unknown): unknown {\n if (value === null || value === undefined) return value;\n if (typeof value === 'number' || typeof value === 'boolean') return value;\n if (typeof value === 'string') {\n const oneLine = value.replace(/\\s+/g, ' ').trim();\n return oneLine.length <= 160 ? oneLine : `${oneLine.slice(0, 120)}...(${oneLine.length} chars)`;\n }\n if (Array.isArray(value)) {\n return `[array:${value.length}]`;\n }\n if (typeof value === 'object') {\n const keys = Object.keys(value as Record<string, unknown>);\n return `[object:${keys.slice(0, 8).join(',')}${keys.length > 8 ? ',...' : ''}]`;\n }\n return String(value);\n}\n\nfunction summarizeToolResultElision(block: ToolResultBlock, tokens: number): string {\n const parts = [`elided: ~${tokens} tokens`];\n if (block.name) parts.push(`tool=${block.name}`);\n const files = extractPathHints(block.content).slice(0, 5);\n if (files.length > 0) parts.push(`files=${files.join(', ')}`);\n const error = firstErrorLine(block.content);\n if (error) parts.push(`error=${error}`);\n return `[${parts.join('; ')}]`;\n}\n\nfunction extractPathHints(content: unknown): string[] {\n const text = typeof content === 'string' ? content : JSON.stringify(content);\n const out = new Set<string>();\n for (const match of text.matchAll(PATH_HINT_PATTERN)) {\n const clean = match[0]?.replace(PATH_BACKSLASH_PATTERN, '/').replace(PATH_TRIM_PATTERN, '');\n if (clean && clean.length <= 220) out.add(clean);\n if (out.size >= 5) break;\n }\n return [...out];\n}\n\nfunction firstErrorLine(content: unknown): string | undefined {\n const text = typeof content === 'string' ? content : JSON.stringify(content);\n for (const line of text.split(NEWLINE_SPLIT_PATTERN)) {\n if (!ERROR_LINE_PATTERN.test(line)) continue;\n const trimmed = line.replace(WHITESPACE_COLLAPSE_PATTERN, ' ').trim();\n if (trimmed) return trimmed.slice(0, 180);\n }\n return undefined;\n}\n\n// \u2500\u2500 Last-resort emergency trim (the no-overflow guarantee) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface HardBudgetResult {\n /** New message array, or the same reference when nothing changed. */\n messages: Message[];\n changed: boolean;\n /** Estimated message tokens reclaimed (before \u2212 after). */\n saved: number;\n /** Number of content blocks elided or truncated. */\n trimmedBlocks: number;\n /** Number of whole messages dropped (last-resort Pass 4). */\n droppedMessages: number;\n /** True when the message array fits `budgetTokens` after trimming. */\n withinBudget: boolean;\n}\n\n/** Old text blocks above this token size are head/tail truncated in Pass 2. */\nconst EMERGENCY_TEXT_TOKEN_CAP = 400;\n/** Pass 2 (old messages): generous head/tail retention. */\nconst EMERGENCY_KEEP_HEAD = 800;\nconst EMERGENCY_KEEP_TAIL = 300;\n/** Pass 3 (whole array, incl. preserved window): tighter floor retention. */\nconst EMERGENCY_FLOOR_HEAD = 400;\nconst EMERGENCY_FLOOR_TAIL = 150;\n/** Below this token size a text block is left alone (not worth a marker). */\nconst EMERGENCY_MIN_TRIM_TOKENS = 120;\n\nfunction isElidedResultContent(content: string): boolean {\n return typeof content === 'string' && content.startsWith('[elided:');\n}\n\nfunction isElidedToolInput(input: Record<string, unknown> | undefined): boolean {\n return !!input && Object.hasOwn(input, '__elided_tool_input');\n}\n\n/**\n * Head/tail truncate a long string, keeping the first `keepHead` and last\n * `keepTail` characters with a token-count marker in between. Returns the\n * original when it is already small enough to make trimming pointless.\n */\nfunction headTailTruncate(text: string, keepHead: number, keepTail: number): string {\n if (text.length <= keepHead + keepTail + 60) return text;\n const removedChars = text.length - keepHead - keepTail;\n const approxTokens = Math.ceil(removedChars / 3.5);\n return `${text.slice(0, keepHead)}\\n\u2026 [truncated ~${approxTokens} tokens \u2014 see session log] \u2026\\n${text.slice(text.length - keepTail)}`;\n}\n\n/**\n * Truncate the oversized **text** content of one message (string content, or\n * `text` blocks in an array). Thinking blocks are never touched (their verbatim\n * echo \u2014 with signature \u2014 is a provider replay requirement) and protocol blocks\n * are handled by the elision pass. Returns a new message when it changed the\n * content, or `null` when nothing qualified.\n */\nfunction truncateMessageText(\n m: Message,\n keepHead: number,\n keepTail: number,\n minTokens: number,\n): { message: Message; trimmed: number } | null {\n if (typeof m.content === 'string') {\n if (estimateTextTokens(m.content) < minTokens) return null;\n const next = headTailTruncate(m.content, keepHead, keepTail);\n if (next === m.content) return null;\n return { message: { ...m, content: next, _estTokens: undefined }, trimmed: 1 };\n }\n let newContent: ContentBlock[] | undefined;\n let trimmed = 0;\n for (let j = 0; j < m.content.length; j++) {\n const b = m.content[j];\n if (!b) continue;\n if (b.type !== 'text') continue;\n if (estimateTextTokens(b.text) < minTokens) continue;\n const next = headTailTruncate(b.text, keepHead, keepTail);\n if (next === b.text) continue;\n newContent ??= m.content.slice();\n newContent[j] = { ...b, text: next };\n trimmed++;\n }\n if (!newContent) return null;\n return { message: { ...m, content: newContent, _estTokens: undefined }, trimmed };\n}\n\n/**\n * Elide every oversized tool_use / tool_result block in one message,\n * regardless of the usual `eliseThreshold` \u2014 this is the emergency floor, so\n * the threshold does not apply. Keeps the block (and its id) so tool_use \u2194\n * tool_result pairing survives; only the payload is replaced with a marker.\n */\nfunction elideMessageToolIo(m: Message): { message: Message; trimmed: number } | null {\n if (typeof m.content === 'string') return null;\n let newContent: ContentBlock[] | undefined;\n let trimmed = 0;\n for (let j = 0; j < m.content.length; j++) {\n const b = m.content[j];\n if (!b) continue;\n if (b.type === 'tool_result' && !isElidedResultContent(b.content)) {\n const tokens = estimateToolResultTokens(b.content);\n if (tokens < EMERGENCY_MIN_TRIM_TOKENS) continue;\n newContent ??= m.content.slice();\n newContent[j] = {\n type: 'tool_result',\n tool_use_id: b.tool_use_id,\n ...(b.name !== undefined && { name: b.name }),\n content: summarizeToolResultElision(b, tokens),\n is_error: b.is_error,\n };\n trimmed++;\n } else if (b.type === 'tool_use' && !isElidedToolInput(b.input)) {\n const tokens = estimateToolInputTokens(b.input);\n if (tokens < EMERGENCY_MIN_TRIM_TOKENS) continue;\n newContent ??= m.content.slice();\n newContent[j] = { ...b, input: summarizeToolUseInputElision(b, tokens) };\n trimmed++;\n }\n }\n if (!newContent) return null;\n return { message: { ...m, content: newContent, _estTokens: undefined }, trimmed };\n}\n\n/**\n * Last-resort trim that makes a request **structurally guaranteed** to fit its\n * budget. Call it after normal compaction when the message array still exceeds\n * the hard budget (a single huge paste, a preserved-window tool_result, or a\n * >1.5\u00D7 token under-estimate). It escalates through four increasingly\n * destructive passes and stops the instant the array fits, so loss is\n * minimised:\n *\n * 1. Elide all old tool I/O before the preserve window (no threshold floor).\n * 2. Head/tail truncate large text in old messages.\n * 3. Head/tail truncate large text across the whole array (incl. preserved).\n * 4. Drop the oldest whole messages (never the last one) until it fits.\n *\n * A final `repairToolUseAdjacency` re-links any protocol pair Pass 4 orphaned.\n *\n * `budgetTokens` is the maximum tokens the **message array** may occupy \u2014 the\n * caller subtracts the system-prompt + tool-definition overhead from the\n * context window first, so this stays a pure function over `Message[]`.\n */\nexport function enforceHardBudget(\n messages: readonly Message[],\n budgetTokens: number,\n opts: { preserveK: number },\n): HardBudgetResult {\n const target = Math.max(1, Math.floor(budgetTokens));\n const perMsg: number[] = messages.map((m) =>\n typeof m._estTokens === 'number' && m._estTokens > 0 ? m._estTokens : computeMessageTokens(m),\n );\n let total = perMsg.reduce((a, b) => a + b, 0);\n const before = total;\n if (total <= target) {\n return {\n messages: messages as Message[],\n changed: false,\n saved: 0,\n trimmedBlocks: 0,\n droppedMessages: 0,\n withinBudget: true,\n };\n }\n\n const work = messages.slice() as Message[];\n const preserveStart = findPreserveStart(messages, opts.preserveK);\n let changed = false;\n let trimmedBlocks = 0;\n\n // Replace message i, keeping `total`/`perMsg` in sync via a fresh estimate.\n const setMsg = (i: number, newMsg: Message): void => {\n const t = computeMessageTokens(newMsg);\n total += t - (perMsg[i] ?? 0);\n perMsg[i] = t;\n work[i] = newMsg;\n changed = true;\n };\n\n // \u2500\u2500 Pass 1: elide all old tool I/O (before the preserve window) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n for (let i = 0; i < preserveStart && total > target; i++) {\n const m = work[i];\n if (!m) continue;\n const res = elideMessageToolIo(m);\n if (res) {\n trimmedBlocks += res.trimmed;\n setMsg(i, res.message);\n }\n }\n\n // \u2500\u2500 Pass 2: truncate large text in old messages \u2500\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 for (let i = 0; i < preserveStart && total > target; i++) {\n const m = work[i];\n if (!m) continue;\n const res = truncateMessageText(\n m,\n EMERGENCY_KEEP_HEAD,\n EMERGENCY_KEEP_TAIL,\n EMERGENCY_TEXT_TOKEN_CAP,\n );\n if (res) {\n trimmedBlocks += res.trimmed;\n setMsg(i, res.message);\n }\n }\n\n // \u2500\u2500 Pass 3: floor-truncate text across the whole array (incl. preserved) +\n // elide any remaining oversized tool I/O in the preserved tail \u2500\u2500\n for (let i = 0; i < work.length && total > target; i++) {\n const m = work[i];\n if (!m) continue;\n const elided = elideMessageToolIo(m);\n if (elided) {\n trimmedBlocks += elided.trimmed;\n setMsg(i, elided.message);\n if (total <= target) break;\n }\n const current = work[i];\n if (!current) continue;\n const res = truncateMessageText(\n current,\n EMERGENCY_FLOOR_HEAD,\n EMERGENCY_FLOOR_TAIL,\n EMERGENCY_MIN_TRIM_TOKENS,\n );\n if (res) {\n trimmedBlocks += res.trimmed;\n setMsg(i, res.message);\n }\n }\n\n // \u2500\u2500 Pass 4: drop the oldest whole messages until it fits (guaranteed) \u2500\u2500\u2500\u2500\n let dropFrom = 0;\n while (total > target && dropFrom < work.length - 1) {\n total -= perMsg[dropFrom] ?? 0;\n dropFrom++;\n changed = true;\n }\n let trimmed: Message[] = dropFrom > 0 ? work.slice(dropFrom) : work;\n const droppedMessages = dropFrom;\n\n // Repair any tool_use/tool_result adjacency the drop pass orphaned.\n if (changed) {\n const repair = repairToolUseAdjacency(trimmed);\n if (repair.report.changed) trimmed = repair.messages;\n }\n\n return {\n messages: changed ? trimmed : (messages as Message[]),\n changed,\n saved: Math.max(0, before - total),\n trimmedBlocks,\n droppedMessages,\n withinBudget: total <= target,\n };\n}\n\n// \u2500\u2500 Stale repeated-read dedup (smart cleanup) \u2500\u2500\u2500\u2500\u2500\u2500\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 DedupResult {\n messages: Message[];\n changed: boolean;\n /** Estimated tokens reclaimed. */\n saved: number;\n /** Number of stale reads collapsed. */\n deduped: number;\n}\n\n/** Path-like value from a read tool_use input (path / file / file_path\u2026). */\nfunction readPathOf(input: Record<string, unknown> | undefined): string | undefined {\n if (!input) return undefined;\n for (const key of ['file_path', 'path', 'file', 'filename']) {\n const v = input[key];\n if (typeof v === 'string' && v.trim()) return v.trim();\n }\n return undefined;\n}\n\nfunction normalizePathKey(p: string): string {\n return p.replace(PATH_BACKSLASH_PATTERN, '/').toLowerCase();\n}\n\n/** Does `pathKey` refer to one of the hot (repeatedly-read) files? */\nfunction isHotRead(pathKey: string, hot: readonly string[]): boolean {\n for (const h of hot) {\n if (pathKey === h) return true;\n if (pathKey.endsWith(h) || h.endsWith(pathKey)) return true;\n const base = pathKey.slice(pathKey.lastIndexOf('/') + 1);\n if (base && h.endsWith(base)) return true;\n }\n return false;\n}\n\n/**\n * Collapse **superseded** reads of the same file. When a file is read\n * repeatedly (tracked in `repeatedReads` evidence), every read of it before\n * the preserve window that is *not* the newest occurrence is redundant \u2014 the\n * later read replaced it. This replaces those stale `tool_result` payloads\n * with a one-line marker (and elides the paired `tool_use` input), keeping the\n * newest read verbatim. Complements `eliseOldToolResults`, which only fires on\n * results \u2265 `eliseThreshold`: many small-but-repeated reads slip under that bar\n * and accumulate, so this catches the pattern `eliseThreshold` misses.\n */\nexport function dedupStaleReads(\n messages: readonly Message[],\n repeatedReads: readonly { file: string; count: number }[],\n opts: { preserveK: number },\n): DedupResult {\n const unchanged: DedupResult = {\n messages: messages as Message[],\n changed: false,\n saved: 0,\n deduped: 0,\n };\n const hot = repeatedReads.filter((r) => r.count >= 2).map((r) => normalizePathKey(r.file));\n if (hot.length === 0) return unchanged;\n\n // Pass A: find, per hot path key, the newest message index that reads it.\n const newestIndexByKey = new Map<string, number>();\n const readKeyByUseId = new Map<string, string>();\n for (let i = 0; i < messages.length; i++) {\n const m = messages[i];\n if (!m || typeof m.content === 'string') continue;\n for (const b of m.content) {\n if (b.type !== 'tool_use' || b.name.toLowerCase() !== 'read') continue;\n const p = readPathOf(b.input);\n if (!p) continue;\n const key = normalizePathKey(p);\n if (!isHotRead(key, hot)) continue;\n readKeyByUseId.set(b.id, key);\n const prev = newestIndexByKey.get(key);\n if (prev === undefined || i > prev) newestIndexByKey.set(key, i);\n }\n }\n if (newestIndexByKey.size === 0) return unchanged;\n\n const preserveStart = findPreserveStart(messages, opts.preserveK);\n\n // Pass B: collect the tool_use ids of stale (superseded, pre-preserve) reads.\n const staleIds = new Map<string, string>(); // tool_use_id \u2192 path key\n for (let i = 0; i < preserveStart; i++) {\n const m = messages[i];\n if (!m || typeof m.content === 'string') continue;\n for (const b of m.content) {\n if (b.type !== 'tool_use') continue;\n const key = readKeyByUseId.get(b.id);\n if (!key) continue;\n const newest = newestIndexByKey.get(key);\n if (newest !== undefined && i < newest) staleIds.set(b.id, key);\n }\n }\n if (staleIds.size === 0) return unchanged;\n\n // Pass C: rewrite stale tool_use inputs + their paired tool_result payloads.\n let saved = 0;\n let deduped = 0;\n let next: Message[] | undefined;\n for (let i = 0; i < messages.length; i++) {\n const m = messages[i];\n if (!m || typeof m.content === 'string') continue;\n let newContent: ContentBlock[] | undefined;\n for (let j = 0; j < m.content.length; j++) {\n const b = m.content[j];\n if (!b) continue;\n if (b.type === 'tool_use' && staleIds.has(b.id) && !isElidedToolInput(b.input)) {\n newContent ??= m.content.slice();\n newContent[j] = {\n ...b,\n input: { __stale_read: `superseded by a later read of ${staleIds.get(b.id)}`, tool: b.name },\n };\n } else if (b.type === 'tool_result' && staleIds.has(b.tool_use_id)) {\n const key = staleIds.get(b.tool_use_id);\n if (isElidedResultContent(b.content)) continue;\n const tokens = estimateToolResultTokens(b.content);\n if (tokens < 1) continue;\n saved += tokens;\n deduped++;\n newContent ??= m.content.slice();\n newContent[j] = {\n type: 'tool_result',\n tool_use_id: b.tool_use_id,\n ...(b.name !== undefined && { name: b.name }),\n content: `[stale read of ${key} \u2014 superseded by a later read; see session log]`,\n is_error: b.is_error,\n };\n }\n }\n if (newContent) {\n next ??= messages.slice() as Message[];\n next[i] = { ...m, content: newContent, _estTokens: undefined };\n }\n }\n\n if (!next) return unchanged;\n return { messages: next, changed: true, saved, deduped };\n}\n\n/**\n * Lossless textual digest of a message range. Every text block is kept verbatim\n * (across all roles, so prior `system` digests fold forward and nothing\n * accumulates as loss). `tool_use` / `tool_result` blocks are counted and\n * replaced with a marker rather than serialized \u2014 their payload is already\n * persisted in the session log. Empty/tool-only messages are skipped.\n */\nexport function buildLosslessDigest(messages: readonly Message[]): string {\n const lines: string[] = [];\n for (const m of messages) {\n let text: string;\n let omitted = 0;\n if (typeof m.content === 'string') {\n text = m.content;\n } else {\n const parts: string[] = [];\n for (const b of m.content) {\n if (isTextBlock(b)) parts.push(b.text);\n else if (b.type === 'tool_use' || b.type === 'tool_result') omitted++;\n }\n text = parts.join(' ');\n }\n if (text.trim().length === 0 && omitted === 0) continue;\n const marker = omitted > 0 ? ` [${omitted} tool call(s) omitted \u2014 see session log]` : '';\n lines.push(`[${m.role}]: ${text}${marker}`);\n }\n return lines.join('\\n');\n}\n\n/**\n * Nearest safe cut boundary in [from, to]: the start of the exchange of the\n * closest user-with-text message. Returns -1 when no such boundary exists.\n */\nexport function findSafeBoundary(messages: readonly Message[], from: number, to: number): number {\n for (let i = to; i >= from; i--) {\n const m = messages[i];\n if (!m) continue;\n if (m.role === 'user' && hasTextContent(m)) {\n return findExchangeStart(messages, i);\n }\n }\n return -1;\n}\n\n/**\n * Walk backwards from a user message to find where its logical exchange began\n * (just after the last assistant message that made no tool calls).\n */\nexport function findExchangeStart(messages: readonly Message[], userIndex: number): number {\n for (let i = userIndex - 1; i >= 0; i--) {\n const m = messages[i];\n if (!m) continue;\n if (m.role === 'assistant') {\n const hasToolUse = Array.isArray(m.content)\n ? m.content.some((b) => b.type === 'tool_use')\n : false;\n if (!hasToolUse) return i + 1;\n } else if (m.role === 'user') {\n return i;\n }\n }\n return 0;\n}\n", "import { type Context, resolveEventSessionId } from '../core/context.js';\nimport type { EventBus } from '../kernel/events.js';\nimport type { MiddlewareHandler } from '../kernel/pipeline.js';\nimport type { SessionEventBridge } from '../storage/session-event-bridge.js';\nimport type { Compactor, CompactReport } from '../types/compactor.js';\nimport type { ContextWindowAggressiveOn, ContextWindowPolicy } from '../types/context-window.js';\nimport { AgentError, ERROR_CODES } from '../types/errors.js';\nimport { repeatedReadPressure } from '../utils/context-evidence.js';\nimport {\n estimateRequestTokens,\n estimateRequestTokensCalibrated,\n estimateRequestTokensUpperBound,\n getCalibrationState,\n realAnchoredInputTokens,\n} from '../utils/token-estimate.js';\nimport { enforceHardBudget, estimateMessages } from './compaction-core.js';\n\ntype PressureLevel = 'warn' | 'soft' | 'hard';\nconst LEVEL_RANK: Record<PressureLevel, number> = { warn: 0, soft: 1, hard: 2 };\n\nexport interface ContextWindowBudgetSnapshot {\n maxContext: number;\n inputTokens: number;\n availableInputTokens: number;\n remainingInputTokens: number;\n reservedOutputTokens: number;\n reservedSafetyTokens: number;\n load: number;\n overflowTokens: number;\n}\n\n/** Max chars of collapse digest persisted to the session log line. */\nconst MAX_DIGEST_LOG_CHARS = 4_000;\n\nfunction truncateDigest(digest: string): string {\n if (digest.length <= MAX_DIGEST_LOG_CHARS) return digest;\n return `${digest.slice(0, MAX_DIGEST_LOG_CHARS)}\u2026 [+${digest.length - MAX_DIGEST_LOG_CHARS} chars; full turns in session log]`;\n}\n\ntype CompactionFailureMode = 'throw' | 'throw_on_hard' | 'continue';\n\ninterface AutoCompactionOptions {\n aggressiveOn?: ContextWindowAggressiveOn | undefined;\n events?: EventBus | undefined;\n failureMode?: CompactionFailureMode | undefined;\n policyProvider?: (\n ctx: Context,\n ) => Pick<ContextWindowPolicy, 'thresholds' | 'aggressiveOn' | 'targetLoad'> | null | undefined;\n /** Optional bridge for writing compaction events into the persistent session log. */\n sessionBridge?: SessionEventBridge | undefined;\n /**\n * Optional callback fired after successful compaction with the report.\n * Receives the CompactReport so callers can feed the collapsed digest\n * to memory consolidation, logging, or other side effects.\n */\n onCompact?: ((report: CompactReport) => void) | undefined;\n}\n\n/**\n * Pipeline middleware that monitors context token load and automatically\n * triggers compaction when the warn/soft/hard thresholds are crossed.\n * Runs before the next agent iteration.\n *\n * Uses `estimateRequestTokens` for accurate full-request token counting:\n * messages + systemPrompt + toolDefs. This replaces the previous pattern\n * of applying an OVERHEAD_FACTOR to a messages-only estimate.\n */\nexport class AutoCompactionMiddleware {\n readonly name = 'AutoCompaction';\n\n private readonly compactor: Compactor;\n /** Deprecated. Kept for backward compat with tests that pass simpleEstimator. */\n private readonly _estimator?: ((ctx: Context) => number) | undefined;\n private readonly warnThreshold: number;\n private readonly softThreshold: number;\n private readonly hardThreshold: number;\n /** Writable so model-switch can update the denominator without re-registering the middleware. */\n private _maxContext: number;\n /**\n * Runtime on/off gate. The middleware is always installed in the pipeline so\n * auto-compaction can be toggled live from the TUI `/settings` picker; when\n * disabled the handler is a pass-through. Defaults to enabled.\n */\n private _enabled = true;\n private readonly aggressiveOn: ContextWindowAggressiveOn;\n private readonly events?: EventBus | undefined;\n private readonly failureMode: CompactionFailureMode;\n private readonly policyProvider?: AutoCompactionOptions['policyProvider'] | undefined;\n private readonly sessionBridge?: SessionEventBridge | undefined;\n private readonly onCompact?: ((report: CompactReport) => void) | undefined;\n\n /**\n * Once a compaction attempt reduces nothing (preserveK protects everything,\n * no oversized tool_results remain to elide), retrying on every iteration\n * just spams `compaction.fired` events without making progress. We remember\n * the no-op and skip until either the pressure level escalates or context\n * has grown by at least this many tokens since the failed attempt.\n */\n private static readonly NOOP_RETRY_DELTA_TOKENS = 2_000;\n /** A tiny positive delta is operationally still a no-op at large context sizes. */\n private static readonly MIN_EFFECTIVE_REDUCTION_TOKENS = 1_000;\n private static readonly MIN_EFFECTIVE_REDUCTION_RATIO = 0.005;\n\n /**\n * Calibrated-load floor above which the upper-bound send guard runs. Below\n * this, even the maximum density under-count factor (2.5\u00D7) cannot push the\n * real token count past the window, so the extra scan is pure waste. Equals\n * 1 / 2.5 = 0.4.\n */\n private static readonly GUARD_GATE_LOAD = 0.4;\n\n /** Tracks the most recent no-op attempt so we can avoid re-firing per turn. */\n private lastNoopAttempt: { level: PressureLevel; tokens: number } | null = null;\n\n /**\n * Cached token estimate from the last handler() invocation. When the\n * message count and tool count haven't changed since the last estimate\n * (autonomous idle loops), we skip the expensive O(n) token estimation\n * and reuse this value. Reset to -1 when the context changes.\n */\n private _cachedTokens = -1;\n private _cachedMsgCount = -1;\n private _cachedToolCount = -1;\n private _cachedRevision = -1;\n private _cachedSystemRef: unknown = null;\n private _cachedToolsRef: unknown = null;\n\n /**\n * @param compactor Compactor to use for compaction.\n * @param maxContext Provider's max context window in tokens.\n * @param _estimator Deprecated parameter kept for backward compatibility.\n * The middleware now uses `estimateRequestTokens` internally\n * for accurate full-request token counting (messages +\n * systemPrompt + toolDefs).\n * @param thresholds Threshold fractions (0-1) of maxContext.\n * @param opts Optional behavior. By default, failures at the\n * hard threshold throw AGENT_CONTEXT_OVERFLOW so\n * the agent does not continue into a likely\n * provider context overflow. Warn/soft failures\n * still emit compaction.failed and continue.\n */\n constructor(\n compactor: Compactor,\n maxContext: number,\n /**\n * Optional custom estimator. When omitted (pass `undefined`), the\n * middleware uses its internal `estimateRequestTokensCalibrated` default \u2014\n * the right choice for subagents, which want the same per-(provider,model)\n * calibration as the leader without threading an estimator through.\n */\n _estimator: ((ctx: Context) => number) | undefined,\n thresholds: { warn: number; soft: number; hard: number },\n optsOrAggressiveOn: AutoCompactionOptions | ContextWindowAggressiveOn = {},\n events?: EventBus | undefined,\n ) {\n const opts =\n typeof optsOrAggressiveOn === 'string'\n ? { aggressiveOn: optsOrAggressiveOn, events }\n : optsOrAggressiveOn;\n this.compactor = compactor;\n this._maxContext = maxContext;\n this._estimator = _estimator;\n this.warnThreshold = thresholds.warn;\n this.softThreshold = thresholds.soft;\n this.hardThreshold = thresholds.hard;\n this.aggressiveOn = opts.aggressiveOn ?? 'soft';\n this.events = opts.events;\n this.failureMode = opts.failureMode ?? 'throw_on_hard';\n this.policyProvider = opts.policyProvider;\n this.sessionBridge = opts.sessionBridge;\n this.onCompact = opts.onCompact;\n }\n\n /** Allow callers (e.g. model-switch in WebUI) to update the context window\n * denominator when the active model changes. */\n setMaxContext(maxContext: number): void {\n this._maxContext = maxContext;\n }\n\n /** Whether auto-compaction is currently active. */\n get enabled(): boolean {\n return this._enabled;\n }\n\n /** Toggle auto-compaction on a live session (TUI `/settings`). When disabled\n * the middleware passes every iteration straight through without estimating\n * tokens or compacting. */\n setEnabled(enabled: boolean): void {\n this._enabled = enabled;\n }\n\n handler(): MiddlewareHandler<Context> {\n return async (ctx, next) => {\n // Runtime gate \u2014 when auto-compaction is turned off via /settings the\n // middleware stays installed but does nothing.\n if (!this._enabled) return next(ctx);\n // Reuse the last token estimate when the context hasn't grown since\n // the previous check \u2014 common in autonomous idle loops. The cached\n // value is invalidated whenever messages or tools change.\n //\n // IMPORTANT: the cache is only valid for the deterministic\n // estimateRequestTokensCalibrated path (messages+system+tools \u2192 fixed\n // output). When a custom _estimator is provided (e.g. in tests with\n // a mutable closure, or a dynamic policy provider), always call it\n // fresh \u2014 the estimator owns its own semantics and the middleware\n // cannot safely cache its result across calls.\n const msgCount = ctx.messages.length;\n const toolCount = (ctx.tools ?? []).length;\n const revision = ctx.state?.revision ?? -1;\n\n let tokens: number;\n // Prefer the REAL usage anchor: compaction decisions run against the\n // provider's authoritative prompt-token count (+ the delta of unsent\n // messages), not a scaled estimate. Only the newest turn is estimated;\n // everything else is exact. Falls through to the estimate paths before\n // the first response or right after compaction shrank the array.\n const anchorAt =\n typeof ctx.meta?.['realAnchorMsgCount'] === 'number'\n ? (ctx.meta['realAnchorMsgCount'] as number)\n : undefined;\n const anchored = realAnchoredInputTokens(ctx.messages, ctx.lastRealInputTokens, anchorAt);\n if (anchored !== null) {\n tokens = anchored;\n } else if (this._estimator) {\n // Custom estimator \u2014 never cache; call fresh every invocation.\n tokens = this._estimator(ctx);\n } else if (\n msgCount === this._cachedMsgCount &&\n toolCount === this._cachedToolCount &&\n revision === this._cachedRevision &&\n ctx.systemPrompt === this._cachedSystemRef &&\n ctx.tools === this._cachedToolsRef &&\n this._cachedTokens >= 0\n ) {\n // Default estimator, context unchanged \u2014 reuse cached value.\n tokens = this._cachedTokens;\n } else if (this.tryStashedTokens(ctx, msgCount, toolCount) !== null) {\n // H1: the agent loop's pre-flight (or its restash in emitContextPct)\n // populated `ctx.lastRequestTokens` this iteration. Apply the\n // per-(provider,model) calibration ratio and use it. This avoids\n // a third redundant O(n) walk per iteration.\n const stashed = this.tryStashedTokens(ctx, msgCount, toolCount) as number;\n const cal = getCalibrationState(`${ctx.provider?.id ?? 'unknown'}/${ctx.model}`);\n tokens = cal.calibrated\n ? Math.round(stashed * Math.min(1.5, Math.max(0.5, cal.ratio)))\n : stashed;\n this._cachedTokens = tokens;\n this._cachedMsgCount = msgCount;\n this._cachedToolCount = toolCount;\n this._cachedRevision = revision;\n this._cachedSystemRef = ctx.systemPrompt;\n this._cachedToolsRef = ctx.tools;\n } else {\n // Default estimator, context changed and no stash \u2014 compute fresh\n // and cache. Cold-start path: very first iteration, or the\n // middleware is being driven from somewhere that didn't run the\n // agent loop's pre-flight (tests, manual compaction trigger).\n tokens = estimateRequestTokensCalibrated(\n ctx.messages,\n ctx.systemPrompt,\n ctx.tools ?? [],\n `${ctx.provider?.id ?? 'unknown'}/${ctx.model}`,\n ).total;\n this._cachedTokens = tokens;\n this._cachedMsgCount = msgCount;\n this._cachedToolCount = toolCount;\n this._cachedRevision = revision;\n this._cachedSystemRef = ctx.systemPrompt;\n this._cachedToolsRef = ctx.tools;\n }\n // A provider overflow can teach the session a route-specific effective\n // limit that is lower than the catalog/native-model value. Resolve it on\n // every pass so the next retry compacts against the learned denominator.\n const runtimeMaxContext = effectiveMaxContext(ctx, this._maxContext);\n const budget = computeContextWindowBudget(ctx, tokens, runtimeMaxContext);\n const calibratedLoad = budget.load;\n const policy = this.policyProvider?.(ctx);\n const thresholds = policy?.thresholds ?? {\n warn: this.warnThreshold,\n soft: this.softThreshold,\n hard: this.hardThreshold,\n };\n const repetition = repeatedReadPressure(ctx);\n const adaptiveThresholds = adaptThresholdsForSignals(thresholds, {\n repeatedReadCount: repetition,\n });\n const aggressiveOn = policy?.aggressiveOn ?? this.aggressiveOn;\n const targetLoad = normalizeTargetLoad(policy?.targetLoad, adaptiveThresholds);\n\n // \u2500\u2500 Never-undercount send guard \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 // The calibrated estimate can under-count dense content (CJK, base64,\n // minified) by >1.5\u00D7, which would let an over-limit request slip past the\n // thresholds and reach the provider. Once the calibrated load is high\n // enough that even the max density factor (2.5\u00D7) *could* overflow\n // (load \u2265 1/2.5 = 0.4), re-check with the upper-bound estimator and\n // escalate the effective load to whichever is larger. Below 0.4 an\n // overflow is arithmetically impossible, so the extra scan is skipped.\n let load = calibratedLoad;\n if (calibratedLoad >= AutoCompactionMiddleware.GUARD_GATE_LOAD) {\n const guardTotal = estimateRequestTokensUpperBound(\n ctx.messages,\n ctx.systemPrompt,\n ctx.tools ?? [],\n `${ctx.provider?.id ?? 'unknown'}/${ctx.model}`,\n ).total;\n const guardLoad = guardTotal / budget.availableInputTokens;\n if (guardLoad > load) load = guardLoad;\n }\n\n const level: PressureLevel | null =\n load >= adaptiveThresholds.hard\n ? 'hard'\n : load >= adaptiveThresholds.soft\n ? 'soft'\n : load >= adaptiveThresholds.warn\n ? 'warn'\n : null;\n\n if (!level) {\n // Load dropped back below all thresholds \u2014 any previously stuck state\n // is no longer relevant.\n this.lastNoopAttempt = null;\n return next(ctx);\n }\n\n if (this.shouldSkipNoopRetry(level, tokens)) {\n return next(ctx);\n }\n\n const aggressive =\n level === 'hard'\n ? true\n : level === 'soft'\n ? aggressiveOn !== 'hard'\n : aggressiveOn === 'warn';\n\n await this.compact(ctx, aggressive, {\n level,\n tokens,\n load,\n hardThreshold: adaptiveThresholds.hard,\n targetLoad,\n budget,\n signals: { repeatedReadCount: repetition },\n });\n\n return next(ctx);\n };\n }\n\n /**\n * H1: try to read a pre-computed token total from `ctx.lastRequestTokens`\n * (set by the agent loop's pre-flight or its restash in emitContextPct).\n * Returns the uncalibrated total when the stash is valid for the current\n * context shape (positive number, and the message count it was computed\n * at matches the current one \u2014 otherwise tool results have been appended\n * since and the value is stale). Returns null when missing or stale so\n * the caller falls back to a fresh walk.\n */\n private tryStashedTokens(ctx: Context, msgCount: number, toolCount: number): number | null {\n const stashed = ctx.lastRequestTokens;\n if (typeof stashed !== 'number' || stashed <= 0) return null;\n // The agent loop writes the (msg, tool) count it computed the stash at\n // into ctx.meta['lastRequestTokensAt']. When the counts disagree the\n // caller has already recomputed and refreshed the stash, but we verify\n // the meta key exists for safety \u2014 older code paths and tests may set\n // lastRequestTokens without the companion entry.\n const stashedAt = ctx.meta?.['lastRequestTokensAt'];\n if (typeof stashedAt !== 'object' || stashedAt === null) return null;\n const meta = stashedAt as { msgCount?: unknown; toolCount?: unknown };\n if (meta.msgCount !== msgCount) return null;\n if (typeof meta.toolCount === 'number' && meta.toolCount !== toolCount) return null;\n return stashed;\n }\n\n /**\n * Returns true when the previous compaction at the same or higher pressure\n * level reduced nothing and context has not grown materially since. Prevents\n * a stuck preserveK window from spamming compaction events every iteration.\n */\n private shouldSkipNoopRetry(level: PressureLevel, tokens: number): boolean {\n const stuck = this.lastNoopAttempt;\n if (!stuck) return false;\n // Escalation always retries \u2014 soft \u2192 hard might be reducible aggressively.\n if (LEVEL_RANK[level] > LEVEL_RANK[stuck.level]) return false;\n const delta = tokens - stuck.tokens;\n return delta < AutoCompactionMiddleware.NOOP_RETRY_DELTA_TOKENS;\n }\n\n private recordAttempt(level: PressureLevel, tokens: number, report: CompactReport): void {\n // Prefer full-request tokens (accurate); fall back to message-only before/after.\n const before = report.fullRequestTokensBefore ?? report.before;\n const after = report.fullRequestTokensAfter ?? report.after;\n const saved = before - after;\n const minimumUsefulSaving = Math.max(\n AutoCompactionMiddleware.MIN_EFFECTIVE_REDUCTION_TOKENS,\n Math.ceil(before * AutoCompactionMiddleware.MIN_EFFECTIVE_REDUCTION_RATIO),\n );\n const reduced = saved >= minimumUsefulSaving;\n const repaired = !!report.repaired;\n if (reduced || repaired) {\n this.lastNoopAttempt = null;\n } else {\n this.lastNoopAttempt = { level, tokens };\n }\n }\n\n private async compact(\n ctx: Context,\n aggressive: boolean,\n pressure: {\n level: PressureLevel;\n tokens: number;\n load: number;\n hardThreshold: number;\n targetLoad: number;\n budget: ContextWindowBudgetSnapshot;\n signals: { repeatedReadCount: number };\n },\n ): Promise<void> {\n const runtimeMaxContext = pressure.budget.maxContext;\n let postCompactionOverflow: AgentError | null = null;\n try {\n const report = await this.compactor.compact(ctx, { aggressive });\n this.recordAttempt(pressure.level, pressure.tokens, report);\n this.onCompact?.(report);\n this.events?.emit('compaction.fired', {\n sessionId: resolveEventSessionId(ctx),\n level: pressure.level,\n tokens: pressure.tokens,\n load: pressure.load,\n maxContext: runtimeMaxContext,\n budget: pressure.budget,\n signals: pressure.signals,\n report,\n aggressive,\n });\n\n // Persist a compaction event to the session log (if a bridge was provided).\n // This is one of the highest-value audit events for understanding context\n // window behavior over long runs.\n await this.sessionBridge?.append({\n type: 'compaction',\n ts: new Date().toISOString(),\n before: report.before,\n after: report.after,\n level: pressure.level,\n aggressive,\n reductions: report.reductions?.map((r) => ({ phase: r.phase, saved: r.saved })),\n budget: pressure.budget,\n signals: pressure.signals,\n // Record what was collapsed so the audit trail shows the preserved\n // content, not just token counts. Bounded to keep the log line small;\n // the full original turns are already in the session JSONL.\n ...(report.collapsedDigest ? { digest: truncateDigest(report.collapsedDigest) } : {}),\n });\n\n // Stale file-read metadata from before the compaction boundary is no\n // longer useful and would cause hasRead() to skip legitimate re-reads.\n ctx.clearFileTracking();\n\n // The real-usage anchor was captured for the PRE-compaction message array.\n // Compaction just rewrote it, so the anchor no longer corresponds \u2014 drop\n // it so the live figure and the next decision use a fresh estimate of the\n // compacted array until the next response re-anchors. (Without this, an\n // elision-only pass that keeps the message count would leave the stale,\n // larger real count in place and could spuriously re-trigger compaction.)\n ctx.lastRealInputTokens = undefined;\n\n const afterTokens = report.fullRequestTokensAfter ?? report.after;\n let afterBudget = computeContextWindowBudget(ctx, afterTokens, runtimeMaxContext);\n let afterLoad = afterBudget.load;\n let stillHard = afterLoad >= pressure.hardThreshold;\n\n // Last-resort emergency trim \u2014 the no-overflow guarantee. When normal\n // compaction (preserveK protects everything, a single oversized message,\n // a >1.5\u00D7 under-estimate) leaves the request above the hard line, trim\n // message CONTENT until it structurally fits rather than throwing a\n // terminal AGENT_CONTEXT_OVERFLOW. This runs in-band so recovery/retry is\n // never needed for a proactively-detected overflow.\n if (stillHard) {\n const trim = this.emergencyTrim(ctx, afterBudget, pressure.hardThreshold);\n if (trim) {\n const retryTokens = estimateRequestTokens(\n ctx.messages,\n ctx.systemPrompt,\n ctx.tools ?? [],\n ).total;\n afterBudget = computeContextWindowBudget(ctx, retryTokens, runtimeMaxContext);\n afterLoad = afterBudget.load;\n stillHard = afterLoad >= pressure.hardThreshold;\n ctx.clearFileTracking();\n this.events?.emit('compaction.emergency_trim', {\n sessionId: resolveEventSessionId(ctx),\n level: pressure.level,\n saved: trim.saved,\n trimmedBlocks: trim.trimmedBlocks,\n droppedMessages: trim.droppedMessages,\n tokens: retryTokens,\n load: afterLoad,\n maxContext: runtimeMaxContext,\n budget: afterBudget,\n withinBudget: trim.withinBudget,\n });\n }\n }\n\n if (!stillHard && afterLoad > pressure.targetLoad) {\n const trim = this.emergencyTrim(ctx, afterBudget, pressure.targetLoad);\n if (trim) {\n const retryTokens = estimateRequestTokens(\n ctx.messages,\n ctx.systemPrompt,\n ctx.tools ?? [],\n ).total;\n afterBudget = computeContextWindowBudget(ctx, retryTokens, runtimeMaxContext);\n afterLoad = afterBudget.load;\n stillHard = afterLoad >= pressure.hardThreshold;\n ctx.clearFileTracking();\n this.events?.emit('compaction.target_trim', {\n sessionId: resolveEventSessionId(ctx),\n level: pressure.level,\n targetLoad: pressure.targetLoad,\n saved: trim.saved,\n trimmedBlocks: trim.trimmedBlocks,\n droppedMessages: trim.droppedMessages,\n tokens: retryTokens,\n load: afterLoad,\n maxContext: runtimeMaxContext,\n budget: afterBudget,\n withinBudget: trim.withinBudget,\n });\n }\n }\n\n // Only reachable if the emergency trim somehow could not fit the request\n // (e.g. a budget smaller than a single floored message \u2014 not achievable in\n // practice). Preserve the original fail-safe so nothing is silently sent.\n const fatal =\n stillHard &&\n (this.failureMode === 'throw' ||\n (this.failureMode === 'throw_on_hard' && pressure.level === 'hard'));\n if (stillHard) {\n const error = new Error(\n `Auto-compaction left context above the hard threshold after ${pressure.level} compaction`,\n );\n this.events?.emit('compaction.failed', {\n sessionId: resolveEventSessionId(ctx),\n err: error,\n aggressive,\n level: pressure.level,\n tokens: afterBudget.inputTokens,\n maxContext: runtimeMaxContext,\n budget: afterBudget,\n signals: pressure.signals,\n load: afterLoad,\n fatal,\n });\n if (fatal) {\n postCompactionOverflow = new AgentError({\n message: `Auto-compaction did not reduce context below hard threshold`,\n code: ERROR_CODES.AGENT_CONTEXT_OVERFLOW,\n recoverable: true,\n context: {\n level: pressure.level,\n tokens: afterBudget.inputTokens,\n maxContext: runtimeMaxContext,\n },\n });\n }\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n const fatal =\n this.failureMode === 'throw' ||\n (this.failureMode === 'throw_on_hard' && pressure.level === 'hard');\n this.events?.emit('compaction.failed', {\n sessionId: resolveEventSessionId(ctx),\n err: error,\n aggressive,\n level: pressure.level,\n tokens: pressure.tokens,\n maxContext: runtimeMaxContext,\n budget: pressure.budget,\n signals: pressure.signals,\n load: pressure.load,\n fatal,\n });\n if (fatal) {\n throw new AgentError({\n message: `Auto-compaction failed at ${pressure.level} threshold`,\n code: ERROR_CODES.AGENT_CONTEXT_OVERFLOW,\n recoverable: true,\n context: {\n level: pressure.level,\n tokens: pressure.tokens,\n maxContext: runtimeMaxContext,\n },\n cause: err,\n });\n }\n }\n if (postCompactionOverflow) throw postCompactionOverflow;\n }\n\n /**\n * Last-resort trim that makes the request structurally fit the window.\n * Converts the calibrated context budget into a raw message-token budget\n * (the estimator scale `enforceHardBudget` works in) by subtracting the\n * system-prompt + tool-definition overhead, then trims message content until\n * it fits. Targets 95% of the hard line so re-estimation jitter does not\n * leave it exactly on the boundary. Returns the trim result, or null when\n * nothing needed trimming.\n */\n private emergencyTrim(\n ctx: Context,\n budget: ContextWindowBudgetSnapshot,\n hardThreshold: number,\n ): {\n saved: number;\n trimmedBlocks: number;\n droppedMessages: number;\n withinBudget: boolean;\n } | null {\n const rawMessageTokens = estimateMessages(ctx.messages);\n const rawFull = estimateRequestTokens(ctx.messages, ctx.systemPrompt, ctx.tools ?? []).total;\n const rawOverhead = Math.max(0, rawFull - rawMessageTokens);\n // Target 95% of the hard line, expressed in the estimator's raw scale.\n const targetGuardFull = Math.floor(hardThreshold * budget.availableInputTokens * 0.95);\n // `enforceHardBudget` counts raw tokens, but the request is measured by the\n // upper-bound guard. Deflate the raw message budget by the current density\n // inflation so the trimmed request fits the guard, not just the raw\n // estimate \u2014 over-trimming slightly is the safe direction here.\n const guardFull = estimateRequestTokensUpperBound(\n ctx.messages,\n ctx.systemPrompt,\n ctx.tools ?? [],\n ).total;\n const inflation = rawFull > 0 ? Math.max(1, guardFull / rawFull) : 1;\n const messageBudget = Math.max(1, Math.floor(targetGuardFull / inflation) - rawOverhead);\n const result = enforceHardBudget(ctx.messages, messageBudget, {\n preserveK: this.resolvePreserveK(ctx),\n });\n if (!result.changed) return null;\n ctx.state.replaceMessages(result.messages);\n return {\n saved: result.saved,\n trimmedBlocks: result.trimmedBlocks,\n droppedMessages: result.droppedMessages,\n withinBudget: result.withinBudget,\n };\n }\n\n /** Preserve-window size from the active policy, defaulting to 6 recent pairs. */\n private resolvePreserveK(ctx: Context): number {\n const policy = ctx.meta?.['contextWindowPolicy'];\n const k =\n policy && typeof policy === 'object'\n ? (policy as { preserveK?: unknown }).preserveK\n : undefined;\n return typeof k === 'number' && k > 0 ? Math.floor(k) : 6;\n }\n}\n\nfunction effectiveMaxContext(ctx: Context, configured: number): number {\n const learned = ctx.meta?.['effectiveMaxContext'];\n if (typeof learned === 'number' && Number.isFinite(learned) && learned > 0) {\n return Math.floor(learned);\n }\n const providerMax = ctx.provider?.capabilities?.maxContext;\n if (typeof providerMax === 'number' && Number.isFinite(providerMax) && providerMax > 0) {\n return Math.floor(providerMax);\n }\n return configured;\n}\n\nfunction computeContextWindowBudget(\n ctx: Context,\n inputTokens: number,\n maxContext: number,\n): ContextWindowBudgetSnapshot {\n const reservedOutputTokens =\n readPositiveMetaNumber(ctx, 'contextOutputReserveTokens') ?? realOutputReserve(ctx, maxContext);\n const reservedSafetyTokens =\n readPositiveMetaNumber(ctx, 'contextSafetyBufferTokens') ??\n Math.floor(Math.min(4096, maxContext * 0.02));\n const availableInputTokens = Math.max(\n 1,\n maxContext - reservedOutputTokens - reservedSafetyTokens,\n );\n const remainingInputTokens = availableInputTokens - inputTokens;\n return {\n maxContext,\n inputTokens,\n availableInputTokens,\n remainingInputTokens,\n reservedOutputTokens,\n reservedSafetyTokens,\n load: inputTokens / availableInputTokens,\n overflowTokens: Math.max(0, -remainingInputTokens),\n };\n}\n\n/**\n * The output-token reserve subtracted from the window to get the input budget.\n *\n * This is the room left for the model's RESPONSE, so it must track the actual\n * per-request output cap \u2014 which in an agentic loop is `Request.maxTokens`\n * (typically a few thousand), NOT the model's *theoretical* `maxOutput` ceiling\n * (which the catalog reports as 32k-65k for many models). Reserving the full\n * theoretical ceiling shrinks the usable window so far that a large context\n * sits permanently above the compaction thresholds \u2192 constant re-compaction.\n *\n * So the reserve is the heuristic `min(8192, 8% of window)` \u2014 the same value\n * that has always worked \u2014 tightened only when the model's real `maxOutput` is\n * *smaller* than that (a genuinely small-output model can't produce more, so\n * reserving less is both accurate and frees input budget). It never exceeds the\n * heuristic, so it can only keep or reduce compaction frequency, never raise it.\n * The real catalog `maxOutput` is still surfaced in `/context` for visibility.\n */\nfunction realOutputReserve(ctx: Context, maxContext: number): number {\n const heuristic = Math.floor(Math.min(8192, maxContext * 0.08));\n const maxOutput = ctx.provider?.capabilities?.maxOutput;\n if (typeof maxOutput === 'number' && Number.isFinite(maxOutput) && maxOutput > 0) {\n return Math.min(heuristic, Math.floor(maxOutput));\n }\n return heuristic;\n}\n\nfunction readPositiveMetaNumber(ctx: Context, key: string): number | undefined {\n const value = ctx.meta?.[key];\n return typeof value === 'number' && Number.isFinite(value) && value >= 0\n ? Math.floor(value)\n : undefined;\n}\n\nfunction adaptThresholdsForSignals(\n thresholds: { warn: number; soft: number; hard: number },\n signals: { repeatedReadCount: number },\n): { warn: number; soft: number; hard: number } {\n if (signals.repeatedReadCount < 3) return thresholds;\n // Re-reading the same file repeatedly is a strong sign of shrinking-spiral\n // behavior. Lower only warn/soft a little so compaction can refresh anchors\n // before the hard overflow path, but keep hard fixed as the safety boundary.\n return {\n warn: Math.max(0.25, thresholds.warn - 0.08),\n soft: Math.max(0.35, thresholds.soft - 0.04),\n hard: thresholds.hard,\n };\n}\n\nfunction normalizeTargetLoad(\n targetLoad: number | null | undefined,\n thresholds: { warn: number; soft: number; hard: number },\n): number {\n if (typeof targetLoad === 'number' && Number.isFinite(targetLoad) && targetLoad > 0) {\n return Math.min(Math.max(0.05, targetLoad), Math.max(0.05, thresholds.hard - 0.01));\n }\n return Math.max(0.05, thresholds.warn);\n}\n", "import { expectDefined } from '../utils/expect-defined.js';\n\nexport type ContextWindowModeId = 'balanced' | 'frugal' | 'deep';\nexport type DeprecatedContextWindowModeId = 'archival';\nexport type ContextWindowModeSelectionId = ContextWindowModeId | DeprecatedContextWindowModeId;\n\nexport type ContextWindowAggressiveOn = 'hard' | 'soft' | 'warn';\n\nexport interface ContextWindowThresholds {\n warn: number;\n soft: number;\n hard: number;\n}\n\nexport interface ContextWindowMode {\n id: ContextWindowModeId;\n name: string;\n description: string;\n thresholds: ContextWindowThresholds;\n aggressiveOn: ContextWindowAggressiveOn;\n preserveK: number;\n eliseThreshold: number;\n targetLoad: number;\n}\n\nexport interface ContextWindowPolicy extends ContextWindowMode {}\n\nexport interface ContextWindowConfigLike {\n mode?: ContextWindowModeSelectionId | string | undefined;\n warnThreshold?: number | undefined;\n softThreshold?: number | undefined;\n hardThreshold?: number | undefined;\n preserveK?: number | undefined;\n eliseThreshold?: number | undefined;\n targetLoad?: number | undefined;\n}\n\nexport const DEFAULT_CONTEXT_WINDOW_MODE_ID: ContextWindowModeId = 'balanced';\n\nexport const DEPRECATED_CONTEXT_WINDOW_MODE_ALIASES: Readonly<\n Record<DeprecatedContextWindowModeId, ContextWindowModeId>\n> = Object.freeze({\n archival: 'balanced',\n});\n\nexport const CONTEXT_WINDOW_MODES: readonly ContextWindowMode[] = Object.freeze([\n {\n id: 'balanced',\n name: 'Balanced',\n description: 'Default rolling compaction: recent work stays verbatim, old tool output is trimmed.',\n thresholds: { warn: 0.55, soft: 0.7, hard: 0.85 },\n aggressiveOn: 'soft',\n preserveK: 8,\n eliseThreshold: 1200,\n targetLoad: 0.65,\n },\n {\n id: 'frugal',\n name: 'Frugal',\n description: 'Token-saver mode: compacts early and keeps a tight verbatim tail.',\n thresholds: { warn: 0.4, soft: 0.55, hard: 0.7 },\n aggressiveOn: 'warn',\n preserveK: 4,\n eliseThreshold: 500,\n targetLoad: 0.45,\n },\n {\n id: 'deep',\n name: 'Deep',\n description: 'Long-reasoning mode: delays compaction and keeps more recent turns intact.',\n thresholds: { warn: 0.72, soft: 0.86, hard: 0.96 },\n aggressiveOn: 'hard',\n preserveK: 18,\n eliseThreshold: 5000,\n targetLoad: 0.82,\n },\n]);\n\nexport function listContextWindowModes(): ContextWindowMode[] {\n return CONTEXT_WINDOW_MODES.map((m) => ({ ...m, thresholds: { ...m.thresholds } }));\n}\n\nexport function normalizeContextWindowModeId(\n id: string | null | undefined,\n): ContextWindowModeId | null {\n if (!id) return null;\n if (isContextWindowModeId(id)) return id;\n return DEPRECATED_CONTEXT_WINDOW_MODE_ALIASES[id as DeprecatedContextWindowModeId] ?? null;\n}\n\nexport function isDeprecatedContextWindowModeId(\n id: string,\n): id is DeprecatedContextWindowModeId {\n return Object.hasOwn(DEPRECATED_CONTEXT_WINDOW_MODE_ALIASES, id);\n}\n\nexport function isContextWindowModeSelectionId(\n id: string,\n): id is ContextWindowModeSelectionId {\n return isContextWindowModeId(id) || isDeprecatedContextWindowModeId(id);\n}\n\nexport function getContextWindowMode(id: string | null | undefined): ContextWindowMode | null {\n const normalized = normalizeContextWindowModeId(id);\n if (!normalized) return null;\n const mode = CONTEXT_WINDOW_MODES.find((m) => m.id === normalized);\n return mode ? { ...mode, thresholds: { ...mode.thresholds } } : null;\n}\n\nexport function isContextWindowModeId(id: string): id is ContextWindowModeId {\n return CONTEXT_WINDOW_MODES.some((m) => m.id === id);\n}\n\nexport function resolveContextWindowPolicy(\n config: ContextWindowConfigLike = {},\n overrideMode?: string | null | undefined,\n): ContextWindowPolicy {\n const requested = overrideMode ?? config.mode ?? DEFAULT_CONTEXT_WINDOW_MODE_ID;\n const mode = getContextWindowMode(requested) ?? expectDefined(getContextWindowMode(DEFAULT_CONTEXT_WINDOW_MODE_ID));\n\n return {\n ...mode,\n thresholds: {\n warn: config.warnThreshold ?? mode.thresholds.warn,\n soft: config.softThreshold ?? mode.thresholds.soft,\n hard: config.hardThreshold ?? mode.thresholds.hard,\n },\n preserveK: config.preserveK ?? mode.preserveK,\n eliseThreshold: config.eliseThreshold ?? mode.eliseThreshold,\n targetLoad: config.targetLoad ?? mode.targetLoad,\n };\n}\n\nexport function formatContextWindowModeList(activeId?: string | null): string {\n const active = normalizeContextWindowModeId(activeId);\n return CONTEXT_WINDOW_MODES.map((m) => {\n const marker = m.id === active ? '*' : ' ';\n return `${marker} ${m.id.padEnd(9)} ${m.name} - ${m.description}`;\n }).join('\\n');\n}\n", "import * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { Logger, LogLevel } from '../types/logger.js';\nimport { color } from '../utils/color.js';\nimport { writeErr } from '../utils/term.js';\n\nconst LEVEL_RANK: Record<LogLevel, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n trace: 4,\n};\n\nconst COLORS: Record<LogLevel, (s: string) => string> = {\n error: color.red,\n warn: color.yellow,\n info: color.cyan,\n debug: color.gray,\n trace: color.dim,\n};\n\nconst LOG_LEVELS = new Set<LogLevel>(['error', 'warn', 'info', 'debug', 'trace']);\nconst LOG_FORMATS = new Set<string>(['pretty', 'json']);\n\nexport type LogFormat = 'pretty' | 'json';\n\nexport interface DefaultLoggerOptions {\n level?: LogLevel | undefined;\n file?: string | undefined;\n /**\n * @deprecated Use `format: 'json'` instead. Kept for backward compat\n * with existing callers but has no effect on output \u2014 the `format`\n * option controls whether stderr receives pretty-printed or JSON lines.\n */\n pretty?: boolean | undefined;\n /** Output format for stderr. `pretty` (colored, human-readable) or `json` (machine-parseable). Defaults to `WRONGSTACK_LOG_FORMAT` env var, falling back to `pretty`. */\n format?: LogFormat | undefined;\n bindings?: Record<string, unknown>;\n /**\n * When false, suppress stderr output entirely \u2014 only write to the log\n * file (if configured). Use this in TUI mode so plugin/library log\n * messages don't interleave with Ink's terminal rendering.\n * Default: true (stderr output is enabled).\n */\n stderr?: boolean | undefined;\n /**\n * Rotate the log file once it exceeds this many bytes: the current file is\n * renamed to `<file>.1` (replacing any previous one) and a fresh file\n * starts. Bounds total disk to ~2\u00D7 this value. Default 10 MB.\n */\n maxFileBytes?: number | undefined;\n}\n\nexport class DefaultLogger implements Logger {\n /** How many file writes between rotation size checks (statSync is not free). */\n private static readonly ROTATE_CHECK_EVERY = 100;\n private static readonly MAX_PENDING_FILE_WRITES = 2_000;\n private static readonly MAX_PENDING_FILE_BYTES = 8 * 1024 * 1024;\n\n level: LogLevel;\n private file?: string | undefined;\n private bindings: Record<string, unknown>;\n private format: LogFormat;\n private stderr: boolean;\n private maxFileBytes: number;\n private writesSinceRotateCheck = 0;\n /**\n * Serialized async tail for file writes. Every appendFile (and any\n * chained rotation) is awaited through this promise so file I/O\n * never overlaps itself \u2014 preserving the per-line ordering the\n * sync version had, but without blocking the caller thread. Any\n * rejection is swallowed (`catch(() => {})`) because logging must\n * never crash the host.\n *\n * Children share the parent's tail: `child.tail === parent.tail`\n * for the lifetime of the chain. Read/write access goes through\n * `_tail` so that, when a child has been wired to a parent, both\n * `enqueueRotate` and `log` always observe the parent's current tail\n * rather than a stale snapshot taken at `child()` time.\n */\n private tail: Promise<void> = Promise.resolve();\n private parent: DefaultLogger | null = null;\n private pendingFileWrites = 0;\n private pendingFileBytes = 0;\n\n private get root(): DefaultLogger {\n return this.parent ? this.parent.root : this;\n }\n\n /**\n * Resolve the current tail. For the root logger this is the field;\n * for a child logger we always read through the parent so that a\n * child's appends land on the parent's most recent tail, and a\n * parent's `flush()` waits for everything the child chained.\n */\n private get _tail(): Promise<void> {\n return this.parent ? this.parent._tail : this.tail;\n }\n private set _tail(next: Promise<void>) {\n if (this.parent) this.parent.tail = next;\n else this.tail = next;\n }\n\n constructor(opts: DefaultLoggerOptions = {}) {\n this.level = opts.level ?? parseLogLevel(process.env.WRONGSTACK_LOG_LEVEL);\n this.file = opts.file;\n this.bindings = opts.bindings ?? {};\n this.format = opts.format ?? parseLogFormat(process.env.WRONGSTACK_LOG_FORMAT);\n this.stderr = opts.stderr !== false; // default true\n this.maxFileBytes = opts.maxFileBytes ?? 10 * 1024 * 1024;\n if (this.file) {\n // Chain mkdir onto the file-write tail so the first append can't\n // race a still-pending mkdir (especially under tests that call\n // `flush()` immediately after `info()`). mkdir is best-effort;\n // a rejection only blocks subsequent appends in the chain that\n // observed it via the rejected promise, which would skip the\n // append \u2014 that is acceptable because ENOENT/EEXIST/EPERM all\n // either are no-ops or indicate an unrecoverable environment.\n const dir = path.dirname(this.file);\n this._tail = this._tail\n .then(async () => {\n await fsp.mkdir(dir, { recursive: true });\n })\n .catch(() => undefined);\n }\n }\n\n error(msg: string, ctx?: unknown): void {\n this.log('error', msg, ctx);\n }\n warn(msg: string, ctx?: unknown): void {\n this.log('warn', msg, ctx);\n }\n info(msg: string, ctx?: unknown): void {\n this.log('info', msg, ctx);\n }\n debug(msg: string, ctx?: unknown): void {\n this.log('debug', msg, ctx);\n }\n trace(msg: string, ctx?: unknown): void {\n this.log('trace', msg, ctx);\n }\n\n child(bindings: Record<string, unknown>): Logger {\n // Construct without invoking the class constructor (which would mkdir\n // again and create a separate file-write tail). The parent and child\n // must share the same tail so `parent.flush()` waits for child\n // appends too \u2014 otherwise a test that flushes the parent after\n // `child.info(...)` would race the child append and observe an empty\n // file. Sharing the tail preserves the order the parent originally\n // had via its serialised file-write queue.\n const child = Object.create(DefaultLogger.prototype) as DefaultLogger;\n child.level = this.level;\n child.file = this.file;\n child.bindings = { ...this.bindings, ...bindings };\n child.format = this.format;\n child.stderr = this.stderr;\n child.maxFileBytes = this.maxFileBytes;\n child.parent = this;\n child.writesSinceRotateCheck = this.writesSinceRotateCheck;\n return child;\n }\n\n /**\n * Wait until all queued file writes (and any pending rotation) have\n * completed. `log()` is fire-and-forget by design \u2014 the caller never\n * blocks on disk \u2014 so tests, shutdown handlers, and processes that\n * need a deterministic \"everything is on disk now\" guarantee should\n * `await logger.flush()` before reading the file or exiting.\n */\n flush(): Promise<void> {\n return this._tail;\n }\n\n /**\n * Size-based rotation: when the file outgrows `maxFileBytes`, rename it to\n * `<file>.1` (dropping the previous `.1`) so the live file restarts empty.\n * Checked on the first write and every ROTATE_CHECK_EVERY writes after.\n * Best-effort: a rename can fail on Windows while another process holds\n * the file \u2014 the next check retries. Multiple processes appending to the\n * same log all run this check; whoever crosses the threshold first wins.\n *\n * Async: the rotation runs on the file-write tail (so its writes don't\n * interleave with the next append), and the caller never blocks on a\n * statSync / renameSync syscall on the hot log path.\n */\n private enqueueRotate(file: string): void {\n if (this.writesSinceRotateCheck++ % DefaultLogger.ROTATE_CHECK_EVERY !== 0) return;\n this._tail = this._tail\n .then(async () => {\n let st;\n try {\n st = await fsp.stat(file);\n } catch {\n return; // file missing \u2014 nothing to rotate\n }\n if (st.size < this.maxFileBytes) return;\n try {\n await fsp.rm(`${file}.1`, { force: true });\n await fsp.rename(file, `${file}.1`);\n } catch {\n // file locked, or raced by another process \u2014 ignore\n }\n })\n .catch(() => undefined);\n }\n\n private log(level: LogLevel, msg: string, ctx?: unknown): void {\n const r = LEVEL_RANK[level];\n const allowed = LEVEL_RANK[this.level];\n if (r > allowed) return;\n const ts = new Date().toISOString();\n const entry: Record<string, unknown> = { ts, level, msg, ...this.bindings };\n if (ctx !== undefined) {\n entry.ctx = ctx instanceof Error ? { message: ctx.message, stack: ctx.stack } : ctx;\n }\n // Disk: JSON line. Serialized through `_tail` so concurrent log\n // calls preserve per-line order without blocking the caller on\n // sync file I/O. Children route through their parent's tail, so\n // a parent's `flush()` waits for every chained child append.\n if (this.file) {\n const line = `${JSON.stringify(entry)}\\n`;\n const bytes = Buffer.byteLength(line, 'utf8');\n const root = this.root;\n if (\n root.pendingFileWrites < DefaultLogger.MAX_PENDING_FILE_WRITES &&\n bytes <= DefaultLogger.MAX_PENDING_FILE_BYTES &&\n root.pendingFileBytes + bytes <= DefaultLogger.MAX_PENDING_FILE_BYTES\n ) {\n root.pendingFileWrites += 1;\n root.pendingFileBytes += bytes;\n this.enqueueRotate(this.file);\n this._tail = this._tail\n .then(() => fsp.appendFile(this.file!, line))\n .catch(() => undefined)\n .finally(() => {\n root.pendingFileWrites = Math.max(0, root.pendingFileWrites - 1);\n root.pendingFileBytes = Math.max(0, root.pendingFileBytes - bytes);\n });\n }\n }\n // Stderr: pretty or json. Suppressed when this.stderr is false (TUI mode)\n // so plugin/library log messages don't interleave with Ink's rendering.\n if (!this.stderr) return;\n if (this.format === 'json') {\n writeErr(`${JSON.stringify(entry)}\\n`);\n } else {\n const head = `${color.dim(ts)} ${COLORS[level](level.toUpperCase().padEnd(5))} ${msg}`;\n if (ctx !== undefined) {\n writeErr(`${head} ${formatCtx(ctx)}\\n`);\n } else {\n writeErr(`${head}\\n`);\n }\n }\n }\n}\n\nfunction parseLogLevel(raw: string | undefined): LogLevel {\n return raw && LOG_LEVELS.has(raw as LogLevel) ? (raw as LogLevel) : 'info';\n}\n\nfunction parseLogFormat(raw: string | undefined): LogFormat {\n return raw && LOG_FORMATS.has(raw) ? (raw as LogFormat) : 'pretty';\n}\n\nfunction formatCtx(ctx: unknown): string {\n if (ctx instanceof Error) return color.dim(ctx.message);\n if (typeof ctx === 'string') return color.dim(ctx);\n try {\n return color.dim(JSON.stringify(ctx));\n } catch {\n return color.dim(String(ctx));\n }\n}\n\n/**\n * A logger that silently discards all messages. Used during boot before\n * the real logger is configured, and in test contexts where logging\n * would be noise.\n */\nexport const noOpLogger: Logger = {\n // 'error' is the quietest level the Logger contract offers; the methods\n // discard everything regardless, this only matters to level checks.\n level: 'error',\n error: () => {},\n warn: () => {},\n info: () => {},\n debug: () => {},\n trace: () => {},\n child: () => noOpLogger,\n};\n", "/**\n * TTY detection helpers \u2014 the single source of truth for \"is this process\n * running against a real terminal?\". Replaces ad-hoc `process.stdin.isTTY`\n * / `process.stdout.isTTY` checks scattered across the codebase so that:\n *\n * 1. test code can mock a single module instead of stubbing `isTTY` on\n * every ReadStream/WriteStream the test happens to touch;\n * 2. a future TTY-detection source (an env var override, a Windows\n * ConPTY workaround, \u2026) lands in one place;\n * 3. `isInteractive()` encodes the rule the project already used inline\n * (\"both streams are TTYs AND we're not running under CI\") in one\n * testable helper instead of the same 3-condition check in two\n * different files.\n *\n * Scope: detection only. Raw-mode control (`setRawMode`), resize\n * subscriptions, and write-injection belong to a future, larger TTY\n * abstraction; this module is the smallest pull that gives us a\n * testable seam and dedups 20+ call sites.\n */\n\nconst hasStdout = (): boolean => typeof process !== 'undefined' && !!process.stdout;\nconst hasStdin = (): boolean => typeof process !== 'undefined' && !!process.stdin;\n\n/** True when `process.stdout` is attached to a terminal (not a pipe/file). */\nexport function isStdoutTTY(): boolean {\n return hasStdout() && Boolean(process.stdout.isTTY);\n}\n\n/** True when `process.stdin` is attached to a terminal (not a pipe/file). */\nexport function isStdinTTY(): boolean {\n return hasStdin() && Boolean(process.stdin.isTTY);\n}\n\n/**\n * True when the current process is an interactive session: both stdin and\n * stdout are TTYs. Callers that also need a \"not a single-shot invocation\"\n * or \"not under CI\" check should layer that on top \u2014 keeping this helper\n * minimal preserves the original inline checks it replaces.\n */\nexport function isInteractive(): boolean {\n return isStdinTTY() && isStdoutTTY();\n}\n\n/** Current terminal size in characters, with a 24\u00D780 fallback for non-TTYs. */\nexport function getTermSize(): { rows: number; cols: number } {\n if (!hasStdout()) return { rows: 24, cols: 80 };\n return {\n rows: process.stdout.rows ?? 24,\n cols: process.stdout.columns ?? 80,\n };\n}\n\n/**\n * Subscribe to terminal resize events. `cb` is called with the new size each\n * time the underlying stream emits `resize`. Returns a cleanup function the\n * caller MUST call on dispose to remove the listener \u2014 leaving a stale\n * `resize` listener on a disposed component leaks the closure (and the\n * component itself, transitively) until the process exits.\n *\n * The stream argument defaults to `process.stdout`. Pass an explicit\n * `NodeJS.WriteStream` when the caller already owns one (e.g. a status line\n * that targets an injected `out` for testability). For non-TTY streams no\n * listener is registered and the returned cleanup is a no-op.\n */\nexport function onResize(\n cb: (size: { rows: number; cols: number }) => void,\n stream: NodeJS.WriteStream = process.stdout,\n): () => void {\n if (!stream || typeof stream.on !== 'function') return () => {};\n const handler = (): void => {\n cb({\n rows: stream.rows ?? 24,\n cols: stream.columns ?? 80,\n });\n };\n stream.on('resize', handler);\n return () => {\n stream.off('resize', handler);\n };\n}\n\n/**\n * Toggle raw mode on a TTY stdin stream. Returns `true` when the toggle was\n * applied, `false` when the stream is null, not a TTY, or doesn't expose\n * `setRawMode` (pipes, file descriptors, Windows ConPTY edge cases). Callers\n * that need to restore the previous mode should snapshot `input.isRaw`\n * BEFORE the call and pass the value to a second call to flip back.\n *\n * Use this helper to drop the now-redundant\n * `if (input.isTTY) input.setRawMode(...)` ceremony at every call site.\n */\nexport function setRawMode(input: NodeJS.ReadStream, mode: boolean): boolean {\n if (input?.isTTY !== true) return false;\n if (typeof input.setRawMode !== 'function') return false;\n input.setRawMode(mode);\n return true;\n}\n\n/**\n * Bracket installed by the interactive input reader while a `readline`\n * prompt is on screen. Out-of-band terminal writes \u2014 logger WARN/INFO\n * lines, async activity from the Telegram bridge, etc. \u2014 go to the same\n * physical terminal as the half-typed prompt but readline has no idea they\n * happened, so it never repaints. The result is the classic corruption the\n * user sees: every async line strands the in-progress draft as a fresh\n * scrollback row (sometimes with its cursor underline).\n *\n * The guard closes that gap. `suspend()` wipes the draft row so the message\n * prints clean; `resume()` repaints the prompt + draft (cursor preserved).\n * When no prompt is active the guard is `null` and writes pass straight\n * through \u2014 so agent-turn output (spinner, renderer) is untouched.\n */\nexport interface OutputLineGuard {\n /** Clear the current input row right before an out-of-band write. */\n suspend(): void;\n /** Repaint the prompt + in-progress draft right after the write. */\n resume(): void;\n}\n\nlet activeOutputGuard: OutputLineGuard | null = null;\n\n/**\n * Register (or clear, with `null`) the guard that brackets out-of-band\n * writes. Installed by {@link writeOut}/{@link writeErr} consumers \u2014 in\n * practice the CLI's readline input reader \u2014 only while a prompt is live.\n * Idempotent; the most recent caller wins.\n */\nexport function setOutputLineGuard(guard: OutputLineGuard | null): void {\n activeOutputGuard = guard;\n}\n\n/**\n * Stream-agnostic write primitive. Returns `false` when the stream is\n * missing or doesn't expose `write` so callers can degrade silently under\n * hostile host environments (closed pipe, mock injects `null`, test\n * replaces the stream with a stub).\n *\n * When an {@link OutputLineGuard} is installed (a readline prompt is on\n * screen) the write is bracketed by `suspend()`/`resume()` so the user's\n * half-typed input survives the interruption instead of being stranded in\n * scrollback. The guard's own redraw uses raw stream writes \u2014 never\n * `writeOut`/`writeErr` \u2014 so there is no re-entrancy here.\n *\n * **Not exported in the public API.** Exposed only inside `term.ts` for\n * `writeOut` / `writeErr` to share a single implementation. If a caller\n * needs to write to an arbitrary stream, they should call `writeOut` (or\n * `writeErr`) with an explicit `stream` argument \u2014 the named functions\n * are the public surface so the \"this is the standard error stream\"\n * intent stays visible at every call site.\n */\nfunction writeTo(\n s: string,\n stream: NodeJS.WriteStream | undefined,\n): boolean {\n if (!stream || typeof stream.write !== 'function') return false;\n const guard = activeOutputGuard;\n if (!guard) {\n stream.write(s);\n return true;\n }\n // A prompt is live \u2014 wipe the draft row, emit the message, repaint.\n guard.suspend();\n stream.write(s);\n guard.resume();\n return true;\n}\n\n/**\n * Write `s` to `stream` (defaults to `process.stdout`). Returns `false`\n * when the stream is missing or doesn't expose `write` so callers can\n * degrade silently under hostile host environments (closed pipe, mock\n * injects `null`, test replaces the stream with a stub).\n *\n * Why a helper:\n * 1. **Single seam for output capture in tests** \u2014 stub `writeOut` once\n * and assert on what the rest of the codebase intended to print,\n * without spying on `process.stdout.write` (which is brittle and\n * leaks across parallel test files).\n * 2. **Stream swap without grep** \u2014 routing the CLI's output to a\n * logger or `out.log` becomes a one-line change at process boot.\n * 3. **Defensive default** \u2014 closes the \"what if `process.stdout` is\n * `null`\" gap that currently exists at ~50 call sites that just\n * call `process.stdout.write(s)` and crash on certain Windows\n * redirect invocations.\n *\n * Call-site migration is staged: this commit introduces the helper, a\n * follow-up commit replaces the 50+ `process.stdout.write(...)` sites\n * with `writeOut(...)`. Until that migration lands, both forms coexist\n * and `writeOut` is the preferred form for new code.\n */\nexport function writeOut(\n s: string,\n stream: NodeJS.WriteStream = process.stdout,\n): boolean {\n return writeTo(s, stream);\n}\n\n/**\n * Symmetric partner of `writeOut` for the standard error stream. Same shape,\n * same defensive contract, same single-seam-for-tests story \u2014 just defaults to\n * `process.stderr` instead of `process.stdout`.\n *\n * Use this in code paths that emit error/diagnostic/warning text. Keeping\n * these two helpers split (rather than a single `writeTo(s, stream)`) means\n * the call site reads as a clear intent signal: \"I am writing an error\" vs.\n * \"I am writing a result\" \u2014 which matters for callers that decide between\n * stdout/stderr routing (e.g. `--quiet` flags, log-level filtering,\n * structured-log rewriters that fork on stream).\n *\n * Stderr writes from the core logger (see `infrastructure/logger.ts`) and from\n * the TUI guard (see `tui/run-tui.ts`) used to call `process.stderr.write`\n * directly. Routing them through this helper lets tests stub the stream at\n * one boundary and lets future logging middleware (e.g. a JSON-line rewriter)\n * swap the destination for the entire process in one place.\n */\nexport function writeErr(\n s: string,\n stream: NodeJS.WriteStream = process.stderr,\n): boolean {\n return writeTo(s, stream);\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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// TerminalCapability \u2014 startup capability profile\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * Color depth the terminal can render.\n *\n * 0 = no color (dumb, redirected, `TERM=dumb`)\n * 1 = 16 colors (basic ANSI)\n * 2 = 256 colors (ANSI 256 + bright variants)\n * 3 = 16.7M / 24-bit truecolor\n */\nexport type ColorDepth = 0 | 1 | 2 | 3;\n\n/**\n * Mouse tracking protocol the terminal speaks.\n *\n * 'none' \u2014 no mouse reporting\n * 'x10' \u2014 basic button press/release, capped at 223 columns\n * 'urxvt'\u2014 URXVT extension, supports >223 cols\n * 'sgr' \u2014 SGR extended mode, modern standard, no column cap\n */\nexport type MouseProtocol = 'none' | 'x10' | 'urxvt' | 'sgr';\n\n/**\n * A snapshot of the terminal's capabilities and identity, computed once at\n * startup. Call {@link detectTerminal} once and pass the result through your\n * app \u2014 never re-detect mid-session.\n *\n * Query once \u2192 adapt once. Re-querying on every render is wrong because\n * `$TERM` is static for the process lifetime and stdout.isTTY can only go\n * from true\u2192false (never the reverse), so a mid-session change means the\n * process was started in a terminal and then something went wrong.\n */\nexport interface TerminalCapability {\n /** True when both stdin and stdout are attached to a terminal. */\n isRealTTY: boolean;\n /**\n * Whether the terminal speaks color.\n *\n * Uses the industry-standard precedence:\n * `FORCE_COLOR=0` \u2192 0 (disabled)\n * `FORCE_COLOR` \u2192 3 (force truecolor)\n * `NO_COLOR=\u2026` \u2192 0 (opted out)\n * `COLORTERM=truecolor|24bit` \u2192 3\n * `TERM=\u2026truecolor|24bit` \u2192 3 (some emulators advertise it)\n * `TERM=\u2026256color` \u2192 2\n * fallback \u2192 1\n *\n * Note: `TERM=dumb` always produces 0 even if `COLORTERM=truecolor` is set \u2014\n * `dumb` terminals are non-interactive by definition.\n */\n colorDepth: ColorDepth;\n /**\n * Whether `stdout` can be written to. Determined once at startup from\n * `stdout?.isTTY ?? false`. Even when `isRealTTY` is true, `stdout` may be\n * writable=false (e.g. the terminal was closed mid-session).\n */\n stdoutWritable: boolean;\n /**\n * Best mouse protocol the terminal speaks. Progressive enhancement:\n * attempt SGR first, fall back to URXVT, then X10, then 'none'.\n *\n * The caller (typically the App component) decides whether to enable\n * tracking at all \u2014 this only reports what the terminal CAN understand.\n */\n mouseProtocol: MouseProtocol;\n /**\n * Whether the terminal title can be set via OSC 0 / OSC 2.\n * True when stdout is a TTY and `$TERM` is not `dumb`.\n */\n canSetTitle: boolean;\n /**\n * Whether the terminal understands the tmux DCS passthrough prefix.\n * Detected by seeing `$TERM=tmux*`. When true, escape sequences should be\n * wrapped: `\\x1bPtmux;\\x1b${seq}\\x1b\\\\`.\n */\n isTmux: boolean;\n /**\n * Whether the terminal is on Windows using the legacy conhost backend\n * (cmd.exe, PowerShell non-ConPTY) rather than ConPTY (Windows Terminal,\n * VS Code Integrated Terminal). Used to apply Windows-specific raw-mode\n * handoff logic.\n *\n * Detected by: platform === 'win32' AND `!process.stdout.getColorDepth?.()`\n * (ConPTY exposes color depth; conhost does not). Also false on non-Windows.\n */\n isWindowsConhost: boolean;\n}\n\n/**\n * Parse `process.env.TERM` into a color-depth guess.\n *\n * We intentionally do NOT use the `supports-color` npm package here because\n * (a) it adds a dependency, (b) it resolves at module-import time, and (c) we\n * need to factor in `FORCE_COLOR` / `NO_COLOR` which may be set after import.\n * This pure function is trivial to test and predictable regardless of import\n * order.\n */\nfunction parseColorDepth(env: { FORCE_COLOR?: string; NO_COLOR?: string; COLORTERM?: string; TERM?: string; }): ColorDepth {\n // `FORCE_COLOR=0` is an explicit opt-out, even when `COLORTERM=truecolor`.\n if (env.FORCE_COLOR === '0') return 0;\n // `FORCE_COLOR` with no value or any truthy value forces truecolor.\n if (env.FORCE_COLOR !== undefined) return 3;\n // Explicit user opt-out.\n if (typeof env.NO_COLOR === 'string' && env.NO_COLOR !== '') return 0;\n // Explicit terminal advertisement.\n const colorterm = (env.COLORTERM ?? '').toLowerCase();\n if (colorterm === 'truecolor' || colorterm === '24bit') return 3;\n // TERM strings that advertise rich color.\n const term = (env.TERM ?? '').toLowerCase();\n if (term.includes('truecolor') || term.includes('24bit')) return 3;\n if (term.includes('256color')) return 2;\n // TERM=dumb = no interactive capability at all.\n if (term === 'dumb') return 0;\n // Default to 16-color \u2014 the safest floor. Modern terminals all override this.\n return 1;\n}\n\n/**\n * Detect the best mouse protocol the terminal speaks.\n *\n * Uses the `$TERM` string as a proxy since Node.js has no runtime query for\n * mouse capability (DECSET 1000/1002/1003 responses are not standardized for\n * programmatic use). The approximation is:\n * - `tmux` + `screen` = SGR (they proxy it)\n * - `xterm*`, `rxvt*`, `konsole`, `gnome*` = SGR (post-2013)\n * - `linux`, `vt100`, `dumb` = none\n * - Everything else = URXVT / X10 (try SGR, fall back gracefully in mouse.ts)\n *\n * This is advisory only. The App component gates mouse tracking behind an\n * explicit user/setting opt-in; false positives just mean the tracking enable\n * sequence is ignored harmlessly.\n */\nfunction parseMouseProtocol(term: string): MouseProtocol {\n const t = term.toLowerCase();\n // Terminals that reliably support SGR (1006) mode.\n if (\n t.startsWith('xterm') ||\n t.startsWith('tmux') ||\n t.startsWith('screen') ||\n t.includes('rxvt-unicode') ||\n t.includes('urxvt') ||\n t.includes('konsole') ||\n t.includes('gnome') ||\n t.includes('foot') ||\n t.includes('alacritty') ||\n t.includes('wezterm') ||\n t.includes('kitty') ||\n t.includes('vscode') ||\n t.includes('Apple_Terminal')\n ) {\n return 'sgr';\n }\n // Known mouse-capable but older terminals.\n if (t.startsWith('rxvt') || t.startsWith('linux') || t.includes('Eterm')) {\n return 'urxvt';\n }\n // vt100 / dumb \u2014 no mouse.\n if (t === 'vt100' || t === 'dumb') return 'none';\n // Default: assume SGR is safe to try; mouse.ts falls back silently.\n return 'sgr';\n}\n\n/**\n * Detect the terminal's capabilities and identity at startup.\n *\n * Call once, early in process boot, before any event-loop async has had a\n * chance to corrupt the read of `process.stdout.isTTY`. Store the result and\n * pass it through the app \u2014 do NOT call this on every render.\n *\n * All `env` lookups default gracefully to safe values when the env var is\n * absent or empty, so the return value is deterministic regardless of what\n * the host's environment looks like.\n */\nexport function detectTerminal(\n opts: {\n stdin?: NodeJS.ReadStream | null;\n stdout?: NodeJS.WriteStream | null;\n env?: typeof process.env;\n } = {},\n): TerminalCapability {\n const stdin = opts.stdin ?? process.stdin;\n const stdout = opts.stdout ?? process.stdout;\n const env = opts.env ?? process.env;\n\n const isRealTTY = (stdin?.isTTY ?? false) && (stdout?.isTTY ?? false);\n const stdoutWritable = isRealTTY && typeof stdout?.write === 'function';\n const term = env.TERM ?? '';\n const isTmux = term.toLowerCase().startsWith('tmux');\n const isWindowsConhost = isRealTTY\n && process.platform === 'win32'\n && typeof (stdout as NodeJS.WriteStream & { getColorDepth?: unknown }).getColorDepth !== 'function';\n\n return {\n isRealTTY,\n colorDepth: isRealTTY ? parseColorDepth(env) : 0,\n stdoutWritable,\n mouseProtocol: parseMouseProtocol(term),\n canSetTitle: isRealTTY && term !== 'dumb',\n isTmux,\n isWindowsConhost,\n };\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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// TerminalLifecycle \u2014 raw-mode lifecycle manager\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * Lifecycle owner for the TTY stdin raw-mode state machine.\n *\n * Raw mode is the most dangerous primitive in TUI code. Getting it wrong leaves\n * the user's terminal in a broken state (line-buffered, no echo) that requires\n * closing and reopening the terminal to recover. This class enforces a strict\n * acquire \u2192 hold \u2192 release lifecycle:\n *\n * - `acquire()` may be called only once (idempotent \u2014 subsequent calls no-op).\n * - `release()` restores the previous mode exactly once.\n * - `release()` is called automatically on process `exit` and `beforeExit`.\n * - Any signal handler (SIGINT, SIGTERM, SIGHUP) that calls `release()` clears\n * its own registration so double-signals don't double-restore.\n *\n * Use this instead of calling `setRawMode()` directly at every call site. The\n * single instance lives at module scope in `run-tui.ts`; components that need\n * to signal \"TUI is shutting down\" call `terminalLifecycle.requestExit()` rather\n * than calling `release()` directly.\n */\nexport class TerminalLifecycle {\n private _active = false;\n\n /**\n * The stdin stream we took raw mode on. Set by `acquire()`; undefined before\n * first call. Used by `release()` and by the ConPTY race-closer in\n * `acquire()`.\n */\n private _stdin: NodeJS.ReadStream | undefined;\n\n /**\n * The `isRaw` snapshot captured before the first `acquire()` call, so\n * `release()` restores to the pre-TUI state rather than blindly disabling\n * raw mode. Null when `acquire()` has never been called.\n */\n private _wasRaw: boolean | null = null;\n\n /**\n * Whether stdin was paused before the TUI took ownership. Readline closes\n * its interface by pausing the shared process stream, so raw mode alone is\n * not enough to make Ink receive bytes during the boot-prompt -> TUI handoff.\n */\n private _wasPaused: boolean | null = null;\n\n /**\n * Request the process to exit. Set the flag, trigger any registered\n * `onRequestExit` callback (typically Ink's `unmount()`), and arm a\n * deadline timer. When the timer fires the process is hard-exited.\n *\n * Safe to call multiple times: subsequent calls no-op after the first.\n */\n requestExit: (exitCode?: number) => void;\n\n /**\n * Callback invoked when `requestExit` is called. Registered by the Ink\n * mount point so unmount() runs before the deadline timer fires.\n */\n onRequestExit: (() => void | Promise<void>) | null = null;\n\n constructor() {\n // Build the requestExit closure here so subclasses / tests can override\n // `requestExit` before calling `acquire()`.\n let exitCode = 0;\n let requested = false;\n this.requestExit = (code = 0) => {\n exitCode = code;\n if (requested) return;\n requested = true;\n // Let the Ink unmount handler run (if registered).\n try {\n this.onRequestExit?.();\n } catch {\n // unmount handler threw \u2014 proceed to hard exit.\n }\n // Hard-exit deadline. `unref()` so the timer doesn't keep the event\n // loop alive if everything else has settled.\n setTimeout(() => process.exit(exitCode), 5_000).unref();\n };\n }\n\n /** True while raw mode is held. */\n get active(): boolean {\n return this._active;\n }\n\n /**\n * Acquire raw mode on `stdin`. Idempotent \u2014 calling twice is safe; only the\n * first call has any effect.\n *\n * On Windows ConPTY, calls `setRawMode` twice: once immediately, then again\n * after the next event-loop tick. This closes the ConPTY race where\n * `readline`'s cleanup (registered before this class is constructed) can\n * restore the original cooked mode after we set raw mode but before Ink's\n * render loop takes over the stdin fd. The double-call ensures the last\n * writer wins.\n *\n * @param stdin - The stdin stream (defaults to `process.stdin`).\n * @returns `true` if raw mode was acquired; `false` if stdin is not a TTY\n * or already shut down.\n */\n acquire(stdin: NodeJS.ReadStream = process.stdin): boolean {\n if (this._active) return false;\n\n // Guard: must be a real TTY, must have setRawMode.\n if (stdin?.isTTY !== true) return false;\n if (typeof stdin.setRawMode !== 'function') return false;\n\n // Snapshot the pre-TUI raw state so release() restores correctly.\n this._wasRaw = stdin.isRaw ?? false;\n this._wasPaused = stdin.isPaused();\n this._stdin = stdin;\n\n stdin.setRawMode(true);\n // A preceding readline prompt normally leaves process.stdin paused.\n // Explicitly start the stream before Ink installs its input listener;\n // otherwise the UI can render perfectly while every key appears dead.\n stdin.resume();\n this._active = true;\n\n // Windows ConPTY double-acquire: schedule a second setRawMode on the next\n // tick so we win the race against readline's \"restore original mode\".\n // Safe on non-Windows (no-op: process.platform !== 'win32').\n if (process.platform === 'win32') {\n setImmediate(() => {\n if (this._active && this._stdin?.isTTY) {\n this._stdin.setRawMode?.(true);\n }\n });\n }\n\n return true;\n }\n\n /**\n * Release raw mode and restore the terminal to the state it was in before\n * `acquire()` was called. Idempotent \u2014 subsequent calls are no-ops.\n *\n * Call this on: SIGINT, SIGTERM, SIGHUP, SIGBREAK, and `process.exit`.\n *\n * \u26A0 **Windows caveat**: `setRawMode(false)` on ConPTY restores the original\n * console mode captured when the process started \u2014 not the mode captured by\n * `acquire()`. On ConPTY, the original mode was already raw (ConPTY starts\n * raw), so this call is typically a no-op on Windows Terminal. On conhost.exe\n * it may restore cooked mode, which is correct for that backend.\n */\n release(): void {\n if (!this._active) return;\n this._active = false;\n\n const stdin = this._stdin;\n if (stdin?.isTTY === true) {\n // Restore to pre-TUI state rather than blindly disabling raw mode.\n stdin.setRawMode?.(this._wasRaw ?? false);\n if (this._wasPaused) stdin.pause();\n }\n this._stdin = undefined;\n this._wasRaw = null;\n this._wasPaused = null;\n }\n\n /**\n * Synchronously reset all terminal state written by the TUI layer:\n * raw mode, SGR attributes, cursor visibility, and mouse tracking.\n *\n * Intended for the final `process.on('exit')` handler where async is\n * impossible. Uses `\\x1b[0m` (SGR reset), `\\x1b[?25h` (cursor show),\n * and `\\x1b[?9l` (mouse off) \u2014 all safe to emit even if the terminal does\n * not understand them (unknown CSI sequences are silently ignored).\n *\n * Safe to call multiple times from multiple exit paths because each write\n * is a constant-time synchronous stream write.\n *\n * @param stdout - Stream to reset (defaults to `process.stdout`).\n */\n reset(stdout: NodeJS.WriteStream = process.stdout): void {\n if (typeof stdout?.write !== 'function') return;\n // SGR reset \u2014 clears bold, color, underline, etc.\n stdout.write('\\x1b[0m');\n // Cursor show (in case Ink's unmount left it hidden).\n stdout.write('\\x1b[?25h');\n // Mouse tracking off (all three DECRST sequences \u2014 safe no-ops if never set).\n stdout.write('\\x1b[?1003l\\x1b[?1002l\\x1b[?1000l');\n }\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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// safeEscape \u2014 guarded escape-sequence emitter\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * Result of emitting an escape sequence. Distinguishes the three distinct\n * failure modes so callers can degrade gracefully.\n */\nexport interface EscapeEmitResult {\n /** `true` when the sequence was written to the stream. */\n ok: boolean;\n /**\n * Human-readable reason when `ok` is `false`. One of:\n * `'not_a_tty'` \u2014 stdout is not a terminal (pipe / redirect / CI)\n * `'unwritable'` \u2014 stdout.write is missing or threw\n * `'empty'` \u2014 `sequence` was the empty string\n */\n reason: 'not_a_tty' | 'unwritable' | 'empty';\n}\n\n/**\n * A terminal escape sequence with its optional string terminator.\n *\n * OSC (title, color palette) sequences MUST be terminated with `BEL (\\x07)`\n * or `ST (\\x1b\\\\)` or the terminal stays in command mode and corrupts\n * subsequent output. CSI sequences (colors, cursor movement) are\n * self-terminating and do not need a terminator byte.\n */\nexport interface EscapeSequence {\n /** The raw sequence, e.g. `\\x1b[38;2;255;0;0m`. */\n raw: string;\n /**\n * Optional terminator byte required by OSC/DCS families.\n * `undefined` for CSI sequences; `\\x07` (BEL) for OSC; `\\x1b\\\\` (ST) for DCS.\n */\n terminator?: string;\n}\n\n/**\n * Shared OSC/DCS terminator bytes.\n *\n * BEL (`\\x07`) is understood by iTerm2, Konsole, mintty, foot, and\n * Windows Terminal. ST (`\\x1b\\\\`) is the strict DEC standard equivalent.\n * Prefer BEL for compatibility; fall back to ST if the terminal's response\n * to BEL is observed to be garbled.\n */\nexport const ESCAPE_TERMINATOR = Object.freeze({\n BEL: '\\x07', // OSC 0 / OSC 2 (title)\n ST: '\\x1b\\\\', // DCS / strict OSC\n});\n\n/**\n * Emit a terminal escape sequence safely.\n *\n * Rules enforced:\n * 1. Empty string \u2192 returns `ok: false, reason: 'empty'`, no write.\n * 2. Not a TTY \u2192 returns `ok: false, reason: 'not_a_tty'`, no write.\n * 3. Stream write throws \u2192 returns `ok: false, reason: 'unwritable'`.\n * 4. OSC/DCS sequences MUST have a terminator byte (guarded assertion).\n * A missing terminator on an OSC sequence corrupts output on terminals\n * that don't understand the sequence \u2014 this function refuses to emit it.\n *\n * @param sequence - The sequence to emit. CSI sequences need no terminator.\n * OSC/DCS sequences must carry `terminator: '\\x07'` or `'\\x1b\\\\'`.\n * @param stdout - Stream to write to (defaults to `process.stdout`).\n * @returns Result indicating success or the specific failure mode.\n */\nexport function safeEmit(\n sequence: EscapeSequence | string,\n stdout: NodeJS.WriteStream = process.stdout,\n): EscapeEmitResult {\n const raw = typeof sequence === 'string' ? sequence : sequence.raw;\n const term = typeof sequence === 'string' ? undefined : sequence.terminator;\n\n if (!raw) {\n return { ok: false, reason: 'empty' };\n }\n if (stdout?.isTTY !== true) {\n return { ok: false, reason: 'not_a_tty' };\n }\n\n // For OSC/DCS sequences (which include `[` or `]` in the body), verify a\n // terminator is present. CSI sequences start with `\\x1b[` and are\n // self-terminating; we treat any sequence that is not a known OSC/DCS\n // as CSI and allow through. OSC starts with `\\x1b]`; DCS with `\\x1bP`.\n if (raw.startsWith('\\x1b]') || raw.startsWith('\\x1bP')) {\n // Assertion: terminator must be provided. Belt-and-suspenders against\n // callers that forget to append `\\x07` \u2014 this prevents corrupted output.\n if (!term) {\n // Defensive: append BEL rather than crashing. This is the only case\n // where we mutate the sequence. The assert-then-fallback pattern is\n // intentional: we catch programmer error in development but degrade\n // safely in production rather than throwing.\n void term; // suppress unused-variable warning\n const safe = `${raw}\\x07`;\n try {\n stdout.write(safe);\n } catch {\n return { ok: false, reason: 'unwritable' };\n }\n return { ok: true, reason: 'empty' }; // reason field is ignored when ok=true\n }\n try {\n stdout.write(`${raw}${term}`);\n } catch {\n return { ok: false, reason: 'unwritable' };\n }\n return { ok: true, reason: 'empty' };\n }\n\n // CSI sequence \u2014 self-terminating.\n try {\n stdout.write(raw);\n } catch {\n return { ok: false, reason: 'unwritable' };\n }\n return { ok: true, reason: 'empty' };\n}\n\n/**\n * Build an OSC 0 / OSC 2 (window/tab title) sequence with a safe terminator.\n *\n * The terminator defaults to `BEL (\\x07)` for broad terminal compatibility.\n * Use `terminator: ESCAPE_TERMINATOR.ST` for stricter terminals that interpret\n * BEL as a beep.\n *\n * @param title - The title string. Embedded BEL bytes are stripped.\n * @param terminator - Defaults to `ESCAPE_TERMINATOR.BEL`.\n */\nexport function buildTitleSequence(\n title: string,\n terminator: string = ESCAPE_TERMINATOR.BEL,\n): EscapeSequence {\n return {\n raw: `\\x1b]0;${title.replace(/\\x07/g, '')}`,\n terminator,\n };\n}\n\n/**\n * Build an SGR (Select Graphic Rendition) color/style sequence.\n *\n * @param codes - SGR parameter list, e.g. `[31]` (red foreground),\n * `[1;32]` (bold green), `[38;2;255;128;0]` (truecolor orange).\n */\nexport function buildSgrSequence(...codes: number[]): EscapeSequence {\n return { raw: `\\x1b[${codes.join(';')}m` };\n}\n\n/**\n * Emit a title sequence. Convenience wrapper around `safeEmit` + `buildTitleSequence`.\n *\n * @param title - The title string.\n * @param stdout - Target stream.\n */\nexport function setTitle(\n title: string,\n stdout: NodeJS.WriteStream = process.stdout,\n): boolean {\n return safeEmit(buildTitleSequence(title), stdout).ok;\n}\n", "import { isStdoutTTY } from './term.js';\n\nconst isColorTty = (): boolean => {\n if (envFlag(process.env.NO_COLOR)) return false;\n if (envFlag(process.env.FORCE_COLOR)) return true;\n return isStdoutTTY();\n};\n\nfunction envFlag(value: string | undefined): boolean {\n if (value === undefined) return false;\n if (value.trim() === '') return false;\n return !/^(0|false|no|off)$/i.test(value.trim());\n}\n\nconst COLOR = isColorTty();\n\nconst wrap =\n (open: string, close: string) =>\n (s: string): string =>\n COLOR ? `\\x1b[${open}m${s}\\x1b[${close}m` : s;\n\nexport const color = {\n reset: wrap('0', '0'),\n bold: wrap('1', '22'),\n dim: wrap('2', '22'),\n italic: wrap('3', '23'),\n underline: wrap('4', '24'),\n red: wrap('31', '39'),\n green: wrap('32', '39'),\n yellow: wrap('33', '39'),\n blue: wrap('34', '39'),\n magenta: wrap('35', '39'),\n cyan: wrap('36', '39'),\n gray: wrap('90', '39'),\n amber: wrap('38;5;214', '39'),\n pink: wrap('38;5;205', '39'),\n bgRed: wrap('41', '49'),\n bgGreen: wrap('42', '49'),\n};\n\nexport function stripAnsi(s: string): string {\n return s.replace(/\\x1b\\[[0-9;]*[A-Za-z]/g, '');\n}\n", "import type { Context } from '../core/context.js';\nimport type { CompactReport, Compactor } from '../types/compactor.js';\nimport type { ContextWindowPolicy } from '../types/context-window.js';\nimport type { Message } from '../types/messages.js';\nimport type { Logger } from '../types/logger.js';\nimport { noOpLogger } from '../infrastructure/logger.js';\nimport { estimateRequestTokens } from '../utils/token-estimate.js';\nimport { repairToolUseAdjacency } from '../utils/message-invariants.js';\nimport {\n buildContextEvidenceDigest,\n checkCompactionQuality,\n injectEvidenceFloor,\n} from '../utils/context-evidence.js';\nimport {\n buildLosslessDigest,\n buildSmartDigest,\n dedupStaleReads,\n eliseOldToolResults,\n estimateMessages,\n hasTextContent,\n setCompactionDebugLogger,\n} from './compaction-core.js';\n\nexport interface CompactorOptions {\n preserveK?: number | undefined;\n eliseThreshold?: number | undefined;\n /**\n * Enable content-aware digest mode. When true, `collapseAncientTurns` uses\n * `buildSmartDigest` which scores messages by importance: critical content\n * (errors, corrections, decisions) is kept verbatim; normal exchanges get\n * first-sentence summaries; large tool outputs and repeated failures are\n * aggressively compressed. Defaults to false (lossless digest).\n */\n smart?: boolean | undefined;\n /**\n * @deprecated Ignored. Token estimation is centralized in\n * `compaction-core`/`token-estimate` so all compactors and the context-pressure\n * monitor agree on one number. Kept only for backward-compatible call sites.\n */\n estimator?: (((text: string) => number)) | undefined;\n /** Structured logger. Defaults to noOpLogger (silent). */\n logger?: Logger | undefined;\n}\n\n/**\n * Default tools config values shared across CLI and WebUI.\n * Import this instead of hardcoding to avoid cross-surface inconsistencies.\n * These mirror the values in CONFIG_BEHAVIOR_DEFAULTS (config-loader.ts).\n *\n * @deprecated Import from '../types/default-config.js' instead.\n * This re-export exists for backward compatibility.\n */\nexport { DEFAULT_TOOLS_CONFIG, DEFAULT_CONTEXT_CONFIG, DEFAULT_AUTONOMY_CONFIG } from '../types/default-config.js';\n\nexport class HybridCompactor implements Compactor {\n private readonly preserveK: number;\n private readonly eliseThreshold: number;\n private readonly smart: boolean;\n private readonly logger: Logger;\n\n constructor(opts: CompactorOptions = {}) {\n this.preserveK = opts.preserveK ?? 5;\n this.eliseThreshold = opts.eliseThreshold ?? 2000;\n this.smart = opts.smart ?? false;\n this.logger = opts.logger ?? noOpLogger;\n setCompactionDebugLogger(this.logger);\n }\n\n async compact(ctx: Context, opts: { aggressive?: boolean | undefined } = {}): Promise<CompactReport> {\n const beforeTokens = estimateMessages(ctx.messages);\n const beforeFull = this.estimateFullRequest(ctx);\n const reductions: CompactReport['reductions'] = [];\n const policy = readContextWindowPolicy(ctx);\n const preserveK = policy?.preserveK ?? this.preserveK;\n const eliseThreshold = policy?.eliseThreshold ?? this.eliseThreshold;\n\n // Phase 1: elision (shared core handles tool_use/tool_result pair preservation).\n const elide = eliseOldToolResults(ctx.messages, { preserveK, eliseThreshold });\n if (elide.changed) ctx.state.replaceMessages(elide.messages);\n if (elide.saved > 0) reductions.push({ phase: 'elision', saved: elide.saved });\n\n // Phase 1b: collapse superseded repeated reads that slipped under eliseThreshold.\n const dedup = dedupStaleReads(ctx.messages, ctx.contextEvidence?.repeatedReads ?? [], {\n preserveK,\n });\n if (dedup.changed) ctx.state.replaceMessages(dedup.messages);\n if (dedup.saved > 0) reductions.push({ phase: 'elision', saved: dedup.saved });\n\n // Phase 2: lossless collapse of ancient turns into a single digest.\n // Preserves ALL textual content (instructions, decisions, conclusions);\n // only raw tool I/O is dropped (it remains in the session log). No sub-LLM call.\n let collapsedDigest: string | undefined;\n let evidenceDigest: string | undefined;\n if (opts.aggressive) {\n const phase2 = this.collapseAncientTurns(ctx, preserveK);\n if (phase2.saved > 0) reductions.push({ phase: 'summary', saved: phase2.saved });\n collapsedDigest = phase2.digest;\n evidenceDigest = phase2.evidenceDigest;\n }\n\n const repaired = repairToolUseAdjacency(ctx.messages);\n if (repaired.report.changed) {\n ctx.state.replaceMessages(repaired.messages);\n }\n\n let afterTokens = estimateMessages(ctx.messages);\n let afterFull = this.estimateFullRequest(ctx);\n const quality = checkCompactionQuality(ctx, {\n collapsedDigest,\n evidenceDigest,\n reduced: beforeTokens > afterTokens || beforeFull > afterFull,\n });\n // Enforce the evidence floor: if quality flags a dropped intent/path anchor,\n // re-inject a compact [context_state] block so the goal survives (not advisory).\n if (injectEvidenceFloor(ctx, quality)) {\n afterTokens = estimateMessages(ctx.messages);\n afterFull = this.estimateFullRequest(ctx);\n }\n return {\n before: beforeTokens,\n after: afterTokens,\n fullRequestTokensBefore: beforeFull,\n fullRequestTokensAfter: afterFull,\n reductions,\n collapsedDigest,\n evidenceDigest,\n quality,\n repaired: repaired.report.changed\n ? {\n removedToolUses: repaired.report.removedToolUses,\n removedToolResults: repaired.report.removedToolResults,\n removedMessages: repaired.report.removedMessages,\n }\n : undefined,\n };\n }\n\n /**\n * Estimate the full API request token count: messages + systemPrompt + toolDefs.\n * This is the accurate figure for context-window pressure monitoring.\n */\n private estimateFullRequest(ctx: Context): number {\n return estimateRequestTokens(ctx.messages, ctx.systemPrompt, ctx.tools ?? []).total;\n }\n\n /**\n * Lossless rule-based collapse of ancient turns into a single digest message.\n *\n * Preserves ALL textual content of the collapsed range \u2014 user instructions,\n * assistant decisions/conclusions, and any prior digests (chained forward so\n * the digest stays lossless across repeated compactions). Only `tool_use` /\n * `tool_result` protocol blocks are dropped and replaced with a count marker;\n * their full payload already lives in the session log. No sub-LLM call.\n *\n * Returns the token savings and the digest text (for audit logging).\n */\n private collapseAncientTurns(\n ctx: Context,\n preserveK = this.preserveK,\n ): { saved: number; digest?: string | undefined; evidenceDigest?: string | undefined } {\n const messages = ctx.messages;\n const cutTarget = Math.max(0, messages.length - preserveK * 2);\n if (cutTarget <= 0) return { saved: 0 };\n\n // Find a safe boundary: nearest user-message-with-text at or after cutTarget.\n let boundary = -1;\n for (let i = cutTarget; i < messages.length; i++) {\n const m = messages[i];\n if (!m) continue;\n if (m.role === 'user' && hasTextContent(m)) {\n boundary = i;\n break;\n }\n }\n if (boundary <= 0) return { saved: 0 };\n\n const removed = messages.slice(0, boundary);\n const removedTokens = estimateMessages(removed);\n\n const historyDigest =\n this.smart\n ? buildSmartDigest(removed) ||\n `${removed.length} earlier turns (no textual content; tool I/O omitted; see session log)`\n : buildLosslessDigest(removed) ||\n `${removed.length} earlier turns (no textual content; tool I/O omitted; see session log)`;\n\n const evidenceDigest = buildContextEvidenceDigest(ctx);\n const digest = evidenceDigest\n ? `[context_state]\\n${evidenceDigest}\\n\\n[prior_history]\\n${historyDigest}`\n : historyDigest;\n\n const summaryMsg: Message = {\n role: 'system',\n content: `[prior_turns_digest: ${digest}]`,\n };\n\n // L1-A: route through ConversationState so subscribers see the rewrite.\n const tail = ctx.messages.slice(boundary);\n ctx.state.replaceMessages([summaryMsg, ...tail]);\n return {\n saved: Math.max(0, removedTokens - estimateMessages([summaryMsg])),\n digest,\n evidenceDigest: evidenceDigest || undefined,\n };\n }\n}\n\nfunction readContextWindowPolicy(ctx: Context): ContextWindowPolicy | null {\n const policy = ctx.meta?.['contextWindowPolicy'];\n if (!policy || typeof policy !== 'object') return null;\n const candidate = policy as Partial<ContextWindowPolicy>;\n if (\n typeof candidate.preserveK !== 'number' ||\n typeof candidate.eliseThreshold !== 'number'\n ) {\n return null;\n }\n return candidate as ContextWindowPolicy;\n}\n", "import type { AgentPipelines } from '../core/agent-types.js';\nimport type { Context } from '../core/context.js';\nimport type { EventBus } from '../kernel/events.js';\nimport {\n type ContextWindowConfigLike,\n resolveContextWindowPolicy,\n} from '../types/context-window.js';\nimport { AutoCompactionMiddleware } from './auto-compaction-middleware.js';\nimport { HybridCompactor } from './compactor.js';\n\n/**\n * Install proactive auto-compaction into a subagent's context-window pipeline.\n *\n * Subagents (CLI fleet host, the light webui/SDD factory) build their pipelines\n * with `createDefaultPipelines()` and historically registered nothing on\n * `contextWindow`, so they had **no proactive compaction** \u2014 they grew until a\n * provider rejected the request and only then recovered reactively. This wires\n * the same rule-based `HybridCompactor` + `AutoCompactionMiddleware` the leader\n * uses, so a subagent shrinks on the warn/soft/hard thresholds (and gets the\n * last-resort emergency trim) exactly like the leader.\n *\n * No custom estimator is passed: the middleware's internal\n * `estimateRequestTokensCalibrated` default already applies per-(provider,model)\n * calibration, which is what a subagent wants. Returns the middleware (so the\n * caller could toggle it) or `undefined` when the provider window is unknown\n * (0), in which case compaction is skipped rather than guessing a denominator.\n */\nexport function installSubagentAutoCompaction(\n pipelines: AgentPipelines,\n ctx: Context,\n contextConfig: ContextWindowConfigLike | undefined,\n events?: EventBus | undefined,\n): AutoCompactionMiddleware | undefined {\n const maxContext = ctx.provider?.capabilities?.maxContext ?? 0;\n if (!(maxContext > 0)) return undefined;\n\n const policy = resolveContextWindowPolicy(contextConfig ?? {});\n ctx.meta ??= {};\n // Publish the policy so the compactor (preserveK/eliseThreshold) and the\n // middleware's policyProvider + emergency-trim preserveK all read it.\n ctx.meta['contextWindowPolicy'] = policy;\n\n const compactor = new HybridCompactor({\n preserveK: policy.preserveK,\n eliseThreshold: policy.eliseThreshold,\n smart: true,\n });\n\n const middleware = new AutoCompactionMiddleware(\n compactor,\n maxContext,\n undefined,\n policy.thresholds,\n {\n aggressiveOn: policy.aggressiveOn,\n failureMode: 'throw_on_hard',\n events,\n policyProvider: (c) => {\n const p = c.meta?.['contextWindowPolicy'];\n return p && typeof p === 'object'\n ? (p as {\n thresholds: { warn: number; soft: number; hard: number };\n aggressiveOn: 'hard' | 'soft' | 'warn';\n targetLoad: number;\n })\n : null;\n },\n },\n );\n\n pipelines.contextWindow.use({ name: 'AutoCompaction', handler: middleware.handler() });\n return middleware;\n}\n", "/**\n * Exhaustiveness check for discriminated union switches.\n * Place in the `default` branch of a switch over a union type\n * to get a compile-time error when a new variant is added.\n *\n * @example\n * switch (block.type) {\n * case 'text': return renderText(block);\n * case 'tool_use': return renderToolUse(block);\n * default: return assertNever(block);\n * }\n */\nexport function assertNever(x: never, message?: string): never {\n const err = new Error(\n message ?? `Unhandled case: ${JSON.stringify(x)}`,\n );\n err.name = 'AssertNeverError';\n throw err;\n}\n", "/**\n * Compile a user-supplied regex with conservative bounds against ReDoS.\n *\n * Duplicated from @wrongstack/tools/_regex.ts to avoid a circular\n * dependency (tools depends on core, not vice versa). Keep both copies\n * in sync if the heuristics change.\n *\n * V8's regex engine is backtracking-based and cannot interrupt a\n * synchronous match \u2014 a pattern like `(a+)+$` against a sufficiently\n * long line will pin a worker for seconds.\n */\n\nconst MAX_PATTERN_LEN = 512;\n\n// Heuristics for catastrophic-backtracking constructs.\nconst DANGEROUS_PATTERNS: ReadonlyArray<RegExp> = [\n /(\\([^)]*[+*][^)]*\\))[+*]/, // (a+)+, (.*)+, etc\n /(\\(\\?:[^)]*[+*][^)]*\\))[+*]/, // same, with non-capturing group\n];\n\nexport interface CompileResult {\n ok: true;\n regex: RegExp;\n}\n\nexport interface CompileFail {\n ok: false;\n reason: string;\n}\n\nexport function compileUserRegex(pattern: string, flags: string): CompileResult | CompileFail {\n if (typeof pattern !== 'string') {\n return { ok: false, reason: 'pattern must be a string' };\n }\n if (pattern.length === 0) {\n return { ok: false, reason: 'pattern is empty' };\n }\n if (pattern.length > MAX_PATTERN_LEN) {\n return { ok: false, reason: `pattern exceeds ${MAX_PATTERN_LEN} characters` };\n }\n for (const rx of DANGEROUS_PATTERNS) {\n if (rx.test(pattern)) {\n return {\n ok: false,\n reason:\n 'pattern looks vulnerable to catastrophic backtracking \u2014 rewrite without nested quantifiers',\n };\n }\n }\n try {\n return { ok: true, regex: new RegExp(pattern, flags) };\n } catch (err) {\n return {\n ok: false,\n reason: err instanceof Error ? err.message : 'invalid regex',\n };\n }\n}\n", "import type { Agent, RunResult } from '../core/agent.js';\nimport type { Context } from '../core/context.js';\nimport { toWrongStackError } from '../types/errors.js';\nimport type { Logger } from '../types/logger.js';\nimport type { DoneCondition } from '../types/multi-agent.js';\nimport { assertNever } from '../utils/assert-never.js';\nimport { compileUserRegex } from '../utils/regex-guard.js';\n\ntype AutonomousResult = RunResult & { toolCalls: number; reason?: string | undefined };\n\nexport interface DoneCheckResult {\n done: boolean;\n reason?: string | undefined;\n iterations: number;\n toolCalls: number;\n}\n\nexport class DoneConditionChecker {\n private readonly compiledRegex: RegExp | null;\n private readonly logger: Logger | undefined;\n\n constructor(\n private readonly condition: DoneCondition,\n opts?: { logger?: Logger | undefined },\n ) {\n this.logger = opts?.logger;\n if (condition.type === 'output_match' && condition.pattern) {\n const result = compileUserRegex(condition.pattern, '');\n this.compiledRegex = result.ok ? result.regex : null;\n if (!result.ok) {\n // Log warning but don't throw \u2014 the done condition simply won't match\n if (this.logger) {\n this.logger.warn(\n 'Done condition has invalid regex \u2014 will never match',\n { event: 'autonomous.done_condition_invalid_regex', pattern: condition.pattern, reason: result.reason },\n );\n } else {\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'autonomous.done_condition_invalid_regex',\n pattern: condition.pattern,\n reason: result.reason,\n timestamp: new Date().toISOString(),\n }));\n }\n }\n } else {\n this.compiledRegex = null;\n }\n }\n\n check(state: { iterations: number; toolCalls: number; lastOutput?: string | undefined }): DoneCheckResult {\n switch (this.condition.type) {\n case 'iterations':\n if (this.condition.maxIterations && state.iterations >= this.condition.maxIterations) {\n return {\n done: true,\n reason: `max iterations (${this.condition.maxIterations}) reached`,\n ...state,\n };\n }\n break;\n\n case 'tool_calls':\n if (this.condition.maxToolCalls && state.toolCalls >= this.condition.maxToolCalls) {\n return {\n done: true,\n reason: `max tool calls (${this.condition.maxToolCalls}) reached`,\n ...state,\n };\n }\n break;\n\n case 'output_match':\n if (this.compiledRegex && state.lastOutput && this.compiledRegex.test(state.lastOutput)) {\n return {\n done: true,\n reason: `output matched pattern \"${this.condition.pattern}\"`,\n ...state,\n };\n }\n break;\n\n case 'directive':\n // Model-driven: the agent manages its own continuation via [continue]/[done].\n // The done condition is never satisfied by the checker \u2014 the agent returns\n // `status: 'done'` when the model emits [done] or naturally finishes.\n // The runner's outer loop uses maxIterations/maxToolCalls as hard caps.\n if (this.condition.maxIterations && state.iterations >= this.condition.maxIterations) {\n return { done: true, reason: `max iterations (${this.condition.maxIterations}) reached`, ...state };\n }\n if (this.condition.maxToolCalls && state.toolCalls >= this.condition.maxToolCalls) {\n return { done: true, reason: `max tool calls (${this.condition.maxToolCalls}) reached`, ...state };\n }\n break;\n\n case 'all_tasks_done':\n // Coordinator-managed: completion is decided by the multi-agent\n // coordinator's pending-task queue, not by per-iteration state here.\n break;\n\n case 'custom':\n // Reserved for future extension\n break;\n default:\n return assertNever(this.condition.type);\n }\n\n return { done: false, iterations: state.iterations, toolCalls: state.toolCalls };\n }\n}\n\nexport interface AutonomousRunnerOptions {\n agent: Agent;\n context: Context;\n doneCondition: DoneCondition;\n iterationTimeoutMs?: number | undefined;\n onIteration?: (state: { iteration: number | undefined; toolCalls: number }) => void;\n onDone?: (((result: AutonomousResult) => void)) | undefined;\n /**\n * When true and `doneCondition.type === 'directive'`, the runner\n * runs the agent with `autonomousContinue: true` so the agent loop\n * handles its own [continue]/[done] markers internally (no outer\n * re-invocation needed). The runner still provides iteration/timeouts.\n */\n enableAutonomousContinue?: boolean | undefined;\n /** Logger for structured warnings. Falls back to console.warn when omitted. */\n logger?: Logger | undefined;\n}\n\nexport class AutonomousRunner {\n private iterations = 0;\n private toolCalls = 0;\n private lastOutput?: string | undefined;\n private stopped = false;\n private readonly doneChecker: DoneConditionChecker;\n\n constructor(private readonly opts: AutonomousRunnerOptions) {\n this.doneChecker = new DoneConditionChecker(opts.doneCondition, { logger: opts.logger });\n }\n\n async run(): Promise<AutonomousResult> {\n // Subscribe to `tool.executed` so the per-tool budget (`tool_calls`\n // done-condition) actually counts each tool invocation rather than\n // each `agent.run()` call. Without this, a single iteration that\n // fires 5 tools only bumps the counter once, and a `maxToolCalls: 3`\n // budget would fire after 3 iterations (typically 3\u00D7N tools) instead\n // of after 3 tools. Unsubscribed in the `finally` so the listener\n // doesn't outlive this run instance. Mock agents in tests may pass\n // null/undefined for `events`; gracefully skip when missing \u2014 those\n // tests don't exercise the tool-count budget path.\n const offToolExecuted = this.opts.agent.events?.on?.('tool.executed', () => {\n this.toolCalls++;\n });\n // When autonomous continue is enabled, also count internal agent-loop\n // iterations. Each iteration.started within a single agent.run() call\n // counts toward the runner's maxIterations cap. We listen to the event\n // through the agent's EventBus.\n const offIterationCompleted = this.opts.agent.events?.on?.('iteration.completed', () => {\n // Only count if we're in autonomous continue mode (agent loop\n // handles multiple iterations internally before returning).\n if (this.opts.enableAutonomousContinue && this.opts.doneCondition.type === 'directive') {\n // Each internal iteration completed \u2014 bump the outer iteration counter.\n // This ensures maxIterations on the runner actually limits total work.\n this.iterations++;\n }\n });\n try {\n return await this.runLoop();\n } finally {\n offToolExecuted?.();\n offIterationCompleted?.();\n }\n }\n\n private async runLoop(): Promise<AutonomousResult> {\n while (!this.stopped) {\n const check = this.doneChecker.check({\n iterations: this.iterations,\n toolCalls: this.toolCalls,\n lastOutput: this.lastOutput,\n });\n\n if (check.done) {\n const result: AutonomousResult = {\n status: 'done',\n iterations: this.iterations,\n toolCalls: this.toolCalls,\n reason: check.reason,\n };\n this.opts.onDone?.(result);\n return result;\n }\n\n this.opts.onIteration?.({ iteration: this.iterations, toolCalls: this.toolCalls });\n\n const ctrl = new AbortController();\n const timeout = setTimeout(() => ctrl.abort(), this.opts.iterationTimeoutMs ?? 30_000);\n\n try {\n // In directive mode with autonomous continue, pass it through so the\n // agent loop handles its own [continue]/[done] markers internally.\n // The runner provides iteration caps and timeouts; the agent handles\n // the continuation decision within each agent.run() call.\n const isDirectiveMode =\n this.opts.doneCondition.type === 'directive' &&\n this.opts.enableAutonomousContinue;\n\n const result = await this.opts.agent.run('', {\n signal: ctrl.signal,\n maxIterations: isDirectiveMode ? (this.opts.doneCondition.maxIterations ?? 100) : 1,\n executionStrategy: 'sequential',\n autonomousContinue: isDirectiveMode ? true : undefined,\n });\n\n // Only increment iterations if we're NOT counting via iteration.completed\n // (i.e., not in autonomous continue directive mode). In that mode,\n // the offIterationCompleted listener in run() bumps this counter\n // per internal iteration so the runner's maxIterations cap is respected.\n if (!isDirectiveMode) this.iterations++;\n // Only access finalText when the run actually succeeded. Failed/aborted\n // runs may have undefined finalText \u2014 accessing it unconditionally would\n // produce garbage output for the done-condition matchers.\n if (result.status === 'done') {\n this.lastOutput = result.finalText;\n }\n // `toolCalls` is bumped by the `tool.executed` listener installed\n // in run() \u2014 no manual increment here.\n\n if (result.status === 'failed' || result.status === 'aborted') {\n const failedResult: AutonomousResult = {\n status: result.status,\n error: result.error,\n iterations: this.iterations,\n toolCalls: this.toolCalls,\n };\n this.opts.onDone?.(failedResult);\n return failedResult;\n }\n } catch (e) {\n // Be precise about what constitutes a timeout error \u2014 matching on\n // 'timeout' substring is too loose (an error message containing\n // \"timeout exceeded\" from the LLM is not the same as an abort).\n const isAbort =\n (e instanceof DOMException && e.name === 'AbortError') ||\n (e instanceof Error && e.name === 'AbortError') ||\n (e instanceof Error && e.message.includes('iteration timeout'));\n if (isAbort) {\n const timeoutResult: AutonomousResult = {\n status: 'failed',\n error: toWrongStackError(e),\n iterations: this.iterations,\n toolCalls: this.toolCalls,\n reason: 'iteration timeout',\n };\n this.opts.onDone?.(timeoutResult);\n return timeoutResult;\n }\n // Any other throw (TypeError, tool crash propagation, etc.) must\n // stop the loop \u2014 silently continuing would spin forever on the\n // same error and burn provider tokens with no progress.\n this.stopped = true;\n const failedResult: AutonomousResult = {\n status: 'failed',\n error: toWrongStackError(e),\n iterations: this.iterations,\n toolCalls: this.toolCalls,\n reason: e instanceof Error ? e.message : String(e),\n };\n this.opts.onDone?.(failedResult);\n return failedResult;\n } finally {\n clearTimeout(timeout);\n }\n }\n\n return {\n status: 'aborted',\n iterations: this.iterations,\n toolCalls: this.toolCalls,\n reason: 'stopped externally',\n };\n }\n\n stop(): void {\n this.stopped = true;\n }\n}\n", "/**\n * Shared heuristic patterns for Brain decision-making.\n *\n * These regexes are used by both `DefaultBrainArbiter` (coordination/brain.ts)\n * and `quickDecide` (execution/autonomy-brain.ts) to detect the\n * blocked-resolved pattern: a question about a blocked task where the\n * context contains explicit evidence that the blocker has been resolved.\n *\n * Extracted to a single module to prevent drift between the two consumers.\n * If you add or remove a resolution marker, update BOTH the regex and the\n * tests in `tests/execution/brain-quickdecide.test.ts`.\n */\n\n/**\n * Resolution markers: words that indicate a blocking dependency has been\n * explicitly resolved in the context. Word-boundary anchored to avoid\n * false positives on substrings (e.g. \"unresolved\" should NOT match).\n */\nexport const BLOCKED_RESOLVED_MARKERS =\n /\\b(?:resolved|fixed|completed|unblocked|available|done|merged|landed|shipped)\\b/;\n\n/**\n * Competing-alternative guard: rejects questions that offer a choice\n * (e.g. \"Should we unblock and continue or wait?\"). When \"or\" is present,\n * the question is offering alternatives \u2014 not a simple unblock signal.\n */\nexport const COMPETING_ALTERNATIVE = /\\bor\\b/;\n\n/**\n * Evaluate the blocked-resolved heuristic against a question/context pair.\n *\n * Returns `true` when:\n * 1. The question mentions \"blocked\"\n * 2. The question does NOT contain competing alternatives (\"or\")\n * 3. The context contains an explicit resolution marker\n *\n * Callers must additionally verify:\n * - `request.fallback === 'continue'` (caller declared continue safe)\n * - `!request.options?.length` (no structured choices to override)\n *\n * @param question - Lowercased question text\n * @param context - Lowercased context text\n */\nexport function isBlockedResolved(\n question: string,\n context: string,\n markers: RegExp = BLOCKED_RESOLVED_MARKERS,\n): boolean {\n return (\n question.includes('blocked') &&\n !COMPETING_ALTERNATIVE.test(question) &&\n markers.test(context)\n );\n}\n\n/**\n * Toggles for the built-in pattern heuristics.\n *\n * These four patterns plus the low-risk fast path used to be unconditional:\n * an operator could change WHEN the expensive tiers run, but never turn off a\n * cheap guess that was firing wrongly for their workload. Each flag defaults\n * to `true`, so an absent config behaves exactly as before.\n */\nexport interface BrainHeuristicsConfig {\n /** `DefaultBrainArbiter`: auto-answer low-risk requests that carry a recommended option. */\n lowRiskAutoAnswer?: boolean | undefined;\n /** \"blocked \u2026 + explicit resolution marker in context\" \u2192 continue. */\n blockedResolved?: boolean | undefined;\n /** \"deadlock\" + failed work units in context \u2192 skip and continue. */\n deadlockSkip?: boolean | undefined;\n /** \"failed\"/\"retry\" + demonstrably exhausted retries \u2192 mark failed and move on. */\n retryExhausted?: boolean | undefined;\n /** Bare continue/proceed ping with no competing alternative \u2192 continue. */\n continuePing?: boolean | undefined;\n /**\n * Replace the resolution markers the `blockedResolved` heuristic looks for.\n * Entries are matched as whole words, case-insensitively, and are regex\n * ESCAPED \u2014 this is a word list, not a pattern, so a stray `(` from config\n * cannot break decision-making. Empty/absent keeps the built-in list.\n */\n blockedResolvedMarkers?: string[] | undefined;\n}\n\n/** Every heuristic on \u2014 the behaviour that predates `BrainHeuristicsConfig`. */\nexport const DEFAULT_BRAIN_HEURISTICS: Required<\n Omit<BrainHeuristicsConfig, 'blockedResolvedMarkers'>\n> = {\n lowRiskAutoAnswer: true,\n blockedResolved: true,\n deadlockSkip: true,\n retryExhausted: true,\n continuePing: true,\n};\n\n/** Resolved, fully-populated heuristic settings. */\nexport interface ResolvedBrainHeuristics\n extends Required<Omit<BrainHeuristicsConfig, 'blockedResolvedMarkers'>> {\n /** Compiled resolution markers for `isBlockedResolved`. */\n blockedResolvedMarkers: RegExp;\n}\n\nconst escapeRegex = (value: string): string => value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n/**\n * Build a whole-word, case-insensitive alternation from a marker word list.\n * Returns the built-in pattern when the list yields nothing usable.\n */\nexport function compileResolutionMarkers(words: readonly string[] | undefined): RegExp {\n const cleaned = (words ?? []).map((w) => w.trim()).filter((w) => w.length > 0);\n if (cleaned.length === 0) return BLOCKED_RESOLVED_MARKERS;\n return new RegExp(`\\\\b(?:${cleaned.map(escapeRegex).join('|')})\\\\b`, 'i');\n}\n\n/** Fill a partial heuristics config with the all-on defaults. */\nexport function resolveBrainHeuristics(\n cfg: BrainHeuristicsConfig | undefined,\n): ResolvedBrainHeuristics {\n return {\n lowRiskAutoAnswer: cfg?.lowRiskAutoAnswer ?? DEFAULT_BRAIN_HEURISTICS.lowRiskAutoAnswer,\n blockedResolved: cfg?.blockedResolved ?? DEFAULT_BRAIN_HEURISTICS.blockedResolved,\n deadlockSkip: cfg?.deadlockSkip ?? DEFAULT_BRAIN_HEURISTICS.deadlockSkip,\n retryExhausted: cfg?.retryExhausted ?? DEFAULT_BRAIN_HEURISTICS.retryExhausted,\n continuePing: cfg?.continuePing ?? DEFAULT_BRAIN_HEURISTICS.continuePing,\n blockedResolvedMarkers: compileResolutionMarkers(cfg?.blockedResolvedMarkers),\n };\n}\n", "/**\n * Brain decision provenance \u2014 WHICH tier actually resolved a decision.\n *\n * The Brain chain is a ladder (rules \u2192 policy \u2192 cache \u2192 council \u2192 LLM \u2192\n * escalation), but every tier returns a bare `BrainDecision` with no marker\n * saying where it came from. `ObservableBrainArbiter` sits OUTSIDE the chain,\n * so the events it emits \u2014 the only thing the TUI/WebUI/HQ surfaces see \u2014\n * could not distinguish a free deterministic answer from one that cost a\n * multi-model council call. That made the single most important operational\n * question (\"how often does the Brain actually burn an LLM?\") unanswerable.\n *\n * Provenance is recorded OUT OF BAND, keyed by the identity of the\n * `BrainDecisionRequest` object, rather than as a field on `BrainDecision`:\n *\n * - `BrainDecision` is a public union compared structurally in a great many\n * places (`expect(d).toEqual(deny('\u2026'))` throughout the Brain tests, and\n * equality checks in host code). Adding even an optional field would\n * change those comparisons.\n * - The SAME request object reference is threaded unchanged through every\n * tier, so its identity is already a reliable per-decision key.\n * - A `WeakMap` keeps this leak-free: when the request is collected, so is\n * its provenance entry. No cleanup protocol, no unbounded growth.\n *\n * Marks are last-writer-wins. Each tier marks itself as it RESOLVES; a tier\n * that defers to the next one must not mark.\n *\n * @module brain-telemetry\n */\n\nimport type { BrainDecisionRequest } from './brain.js';\n\n/**\n * The tier that produced a decision, cheapest first.\n *\n * - `rule` \u2014 a configured deterministic `BrainRule` matched.\n * - `policy` \u2014 `DefaultBrainArbiter` fallback semantics.\n * - `heuristic` \u2014 a built-in pattern heuristic (quickDecide / blocked-resolved).\n * - `cache` \u2014 a previous identical decision was replayed.\n * - `ledger-guard`\u2014 denied deterministically from observed failure history.\n * - `council` \u2014 the multi-LLM panel decided.\n * - `llm` \u2014 the single-LLM tier decided.\n * - `terminal` \u2014 headless terminal policy (no human available).\n * - `human` \u2014 a person answered the escalation prompt.\n */\nexport type BrainDecisionTier =\n | 'rule'\n | 'policy'\n | 'heuristic'\n | 'cache'\n | 'ledger-guard'\n | 'council'\n | 'llm'\n | 'terminal'\n | 'human';\n\n/** Tiers that did NOT cost a provider call. */\nexport const DETERMINISTIC_BRAIN_TIERS: ReadonlySet<BrainDecisionTier> = new Set<BrainDecisionTier>(\n ['rule', 'policy', 'heuristic', 'cache', 'ledger-guard', 'terminal'],\n);\n\nconst tierByRequest = new WeakMap<BrainDecisionRequest, BrainDecisionTier>();\n\n/**\n * Record which tier resolved this request. Call it at the point of RESOLUTION\n * \u2014 a tier that falls through to the next one must not mark, or the ladder's\n * provenance collapses onto whichever tier ran last.\n */\nexport function markDecisionTier(request: BrainDecisionRequest, tier: BrainDecisionTier): void {\n tierByRequest.set(request, tier);\n}\n\n/** The tier that resolved this request, when a tier recorded itself. */\nexport function readDecisionTier(request: BrainDecisionRequest): BrainDecisionTier | undefined {\n return tierByRequest.get(request);\n}\n\n/** True when the decision was reached without any provider call. */\nexport function isDeterministicTier(tier: BrainDecisionTier | undefined): boolean {\n return tier !== undefined && DETERMINISTIC_BRAIN_TIERS.has(tier);\n}\n\n/** Running per-tier tally, for `/brain stats` and the settings surfaces. */\nexport interface BrainTierStats {\n /** Decisions resolved by each tier. Tiers with no decisions are omitted. */\n byTier: Partial<Record<BrainDecisionTier, number>>;\n /** Total decisions counted (including ones with no recorded tier). */\n total: number;\n /** Decisions reached without any provider call. */\n deterministic: number;\n /** Decisions that cost at least one provider call (`council` + `llm`). */\n llmBacked: number;\n /** Decisions whose tier was never recorded. */\n unattributed: number;\n}\n\n/**\n * Mutable per-tier counter. Hosts keep one per session and feed it from the\n * `brain.decision_*` event stream.\n */\nexport class BrainTierCounter {\n private readonly counts = new Map<BrainDecisionTier, number>();\n private total = 0;\n private unattributed = 0;\n\n /** Count one decision. `undefined` counts toward `unattributed`. */\n record(tier: BrainDecisionTier | undefined): void {\n this.total += 1;\n if (tier === undefined) {\n this.unattributed += 1;\n return;\n }\n this.counts.set(tier, (this.counts.get(tier) ?? 0) + 1);\n }\n\n snapshot(): BrainTierStats {\n const byTier: Partial<Record<BrainDecisionTier, number>> = {};\n let deterministic = 0;\n let llmBacked = 0;\n for (const [tier, count] of this.counts) {\n byTier[tier] = count;\n if (DETERMINISTIC_BRAIN_TIERS.has(tier)) deterministic += count;\n else if (tier === 'council' || tier === 'llm') llmBacked += count;\n }\n return {\n byTier,\n total: this.total,\n deterministic,\n llmBacked,\n unattributed: this.unattributed,\n };\n }\n\n reset(): void {\n this.counts.clear();\n this.total = 0;\n this.unattributed = 0;\n }\n}\n", "/**\n * Brain coordination primitives.\n *\n * Brain is an authority layer above a leader/director but below the human. It is\n * intentionally modeled as a decision interface first, not as an autonomous\n * bypass: callers ask for a decision, Brain either answers within policy or\n * escalates to the human.\n */\n\nimport type { EventBus } from '../kernel/events.js';\nimport {\n type BrainHeuristicsConfig,\n isBlockedResolved,\n type ResolvedBrainHeuristics,\n resolveBrainHeuristics,\n} from './brain-heuristics.js';\nimport { markDecisionTier, readDecisionTier } from './brain-telemetry.js';\n\nexport type BrainDecisionSource = 'goal' | 'director' | 'tool' | 'user' | 'system';\n\nexport type BrainRisk = 'low' | 'medium' | 'high' | 'critical';\n\n/**\n * Canonical ordering of request risk, lowest first. The single source of\n * truth for every risk comparison in the Brain (tier ceilings, council\n * floors, rule `minRisk`/`maxRisk` bounds) \u2014 keeping it here, next to the\n * type it orders, stops the ladders from drifting apart.\n *\n * Typed as `Record<string, number>` on purpose: callers index it with values\n * that arrive from config/JSON and may not be valid `BrainRisk` members, and\n * are expected to supply their own `?? default` for that case.\n */\nexport const BRAIN_RISK_LEVELS: Record<string, number> = {\n low: 0,\n medium: 1,\n high: 2,\n critical: 3,\n};\n\nexport type BrainFallback = 'ask_human' | 'deny' | 'continue';\n\nexport interface BrainDecisionOption {\n id: string;\n label: string;\n consequence?: string | undefined;\n risk?: BrainRisk | undefined;\n recommended?: boolean | undefined;\n}\n\nexport interface BrainDecisionRequest {\n id: string;\n /** Active host session id for surfaces that multiplex multiple sessions. */\n sessionId?: string | undefined;\n source: BrainDecisionSource;\n question: string;\n context?: string | undefined;\n options?: BrainDecisionOption[] | undefined;\n risk: BrainRisk;\n /** What a non-LLM/default Brain should do when policy cannot decide safely. */\n fallback: BrainFallback;\n}\n\nexport type BrainDecision =\n | {\n type: 'answer';\n optionId?: string | undefined;\n text: string;\n rationale?: string | undefined;\n }\n | {\n type: 'ask_human';\n prompt: string;\n options?: BrainDecisionOption[] | undefined;\n rationale?: string | undefined;\n }\n | {\n type: 'deny';\n reason: string;\n };\n\nexport interface BrainArbiter {\n decide(request: BrainDecisionRequest): Promise<BrainDecision>;\n}\n\n/**\n * Event-emitting decorator for any Brain implementation. Hosts wire this around\n * their actual arbiter so TUI/session surfaces can render Brain decisions\n * without coupling to the caller that requested the decision.\n */\nexport class ObservableBrainArbiter implements BrainArbiter {\n constructor(\n private readonly inner: BrainArbiter,\n private readonly events: EventBus,\n ) {}\n\n async decide(request: BrainDecisionRequest): Promise<BrainDecision> {\n this.events.emit('brain.decision_requested', { sessionId: request.sessionId, request, at: Date.now() });\n const decision = await this.inner.decide(request);\n const event =\n decision.type === 'ask_human'\n ? 'brain.decision_ask_human'\n : decision.type === 'deny'\n ? 'brain.decision_denied'\n : 'brain.decision_answered';\n // Provenance is recorded inside the chain (this decorator sits outside\n // it), so surfaces can tell a free deterministic answer from one that\n // cost a council/LLM call. Optional: chains that predate the marking, or\n // arbiters wired directly, simply report no tier.\n const tier = readDecisionTier(request);\n this.events.emit(event, {\n sessionId: request.sessionId,\n request,\n decision,\n at: Date.now(),\n ...(tier ? { tier } : {}),\n });\n return decision;\n }\n}\n\ninterface BrainDecisionQueueOptions {\n /** Safety fallback if the human never answers. Default: no timeout. */\n timeoutMs?: number | undefined;\n /**\n * Decision to resolve with when the timeout fires. Default: deny.\n * Headless-leaning hosts pass `terminalPolicyDecision` here so an\n * unanswered prompt degrades to the safe default instead of a bare deny.\n */\n onTimeout?: ((request: BrainDecisionRequest) => BrainDecision) | undefined;\n}\n\n/**\n * Bridge between an `ask_human` Brain decision and the UI. It emits the visible\n * ask-human event, then resolves when the TUI emits `brain.human_answered`.\n */\nexport class BrainDecisionQueue {\n private readonly pending = new Map<\n string,\n {\n request: BrainDecisionRequest;\n resolve: (decision: BrainDecision) => void;\n timer?: ReturnType<typeof setTimeout> | undefined;\n }\n >();\n private readonly offAnswer: () => void;\n\n constructor(\n private readonly events: EventBus,\n private readonly opts: BrainDecisionQueueOptions = {},\n ) {\n this.offAnswer = this.events.on('brain.human_answered', (answer) => {\n const pending = this.pending.get(answer.id);\n if (!pending) return;\n this.pending.delete(answer.id);\n if (pending.timer) clearTimeout(pending.timer);\n markDecisionTier(pending.request, 'human');\n if (answer.deny) {\n pending.resolve({ type: 'deny', reason: answer.text ?? 'Denied by human.' });\n return;\n }\n const option = pending.request.options?.find((o) => o.id === answer.optionId);\n pending.resolve({\n type: 'answer',\n optionId: answer.optionId,\n text: answer.text ?? option?.label ?? answer.optionId ?? 'Human answered.',\n rationale: 'Human answered a Brain escalation prompt.',\n });\n });\n }\n\n async requestHumanDecision(request: BrainDecisionRequest): Promise<BrainDecision> {\n const ask: BrainDecision = {\n type: 'ask_human',\n prompt: formatHumanPrompt(request),\n options: request.options,\n rationale: 'Decision escalated to human authority.',\n };\n const pending = new Promise<BrainDecision>((resolve) => {\n const entry: {\n request: BrainDecisionRequest;\n resolve: (decision: BrainDecision) => void;\n timer?: ReturnType<typeof setTimeout> | undefined;\n } = { request, resolve };\n if (this.opts.timeoutMs && this.opts.timeoutMs > 0) {\n entry.timer = setTimeout(() => {\n this.pending.delete(request.id);\n // Nobody answered \u2014 this resolves through the terminal policy, not\n // through human authority.\n markDecisionTier(request, 'terminal');\n resolve(\n this.opts.onTimeout?.(request) ?? {\n type: 'deny',\n reason: 'Brain human decision timed out.',\n },\n );\n }, this.opts.timeoutMs);\n }\n this.pending.set(request.id, entry);\n });\n this.events.emit('brain.decision_ask_human', { sessionId: request.sessionId, request, decision: ask, at: Date.now() });\n return pending;\n }\n\n dispose(): void {\n this.offAnswer();\n for (const [id, pending] of this.pending) {\n if (pending.timer) clearTimeout(pending.timer);\n pending.resolve({ type: 'deny', reason: 'Brain decision queue disposed.' });\n this.pending.delete(id);\n }\n }\n}\n\n/** Escalation routing for the outermost Brain tier. See `EscalationRoutingBrainArbiter`. */\nexport type BrainEscalationMode = 'interactive' | 'headless';\n\n/**\n * Resolve an `ask_human` escalation WITHOUT a human \u2014 the terminal policy of\n * a headless Brain. The ladder is deliberately conservative:\n *\n * 1. A caller-recommended option at low/medium request risk is chosen \u2014\n * the caller already declared it the safe default.\n * 2. `fallback: 'continue'` requests continue (the caller stated that\n * continuing is the safe default when nobody can decide).\n * 3. Everything else is denied. Denial is always safe by contract: every\n * Brain call site treats deny as \"do not take the proposed action\".\n *\n * The rationale names the terminal policy so decision logs/ledgers make the\n * degradation visible instead of silent.\n */\nexport type BrainTerminalPolicy = 'conservative' | 'deny-all' | 'continue-on-recommended';\n\nexport function terminalPolicyDecision(\n request: BrainDecisionRequest,\n policy: BrainTerminalPolicy = 'conservative',\n): BrainDecision {\n if (policy === 'deny-all') {\n return {\n type: 'deny',\n reason:\n `Headless terminal policy \"deny-all\": \"${request.question}\" was not auto-approved ` +\n '(risk: ' +\n request.risk +\n '). The proposed action was not taken.',\n };\n }\n const recommended = request.options?.find((option) => option.recommended);\n const acceptRecommended =\n recommended !== undefined &&\n (policy === 'continue-on-recommended' ||\n request.risk === 'low' ||\n request.risk === 'medium');\n if (recommended && acceptRecommended) {\n return {\n type: 'answer',\n optionId: recommended.id,\n text: recommended.label,\n rationale:\n 'Headless terminal policy: caller-recommended option accepted at ' +\n `${request.risk} risk (no human available by configuration).`,\n };\n }\n if (request.fallback === 'continue') {\n return {\n type: 'answer',\n text: 'Continue with the caller default.',\n rationale:\n 'Headless terminal policy: request declares continue as its safe fallback.',\n };\n }\n return {\n type: 'deny',\n reason:\n `Headless terminal policy: no safe automatic option for \"${request.question}\" ` +\n `(risk: ${request.risk}). The proposed action was not taken.`,\n };\n}\n\n/**\n * Outermost escalation tier that never lets an `ask_human` decision leak to\n * the caller. Routing is read PER DECISION so `/brain mode` switches apply\n * live:\n *\n * - 'interactive' (and a queue is wired) \u2192 prompt the human via the\n * `BrainDecisionQueue`, exactly like `HumanEscalatingBrainArbiter`.\n * - 'headless' (or no queue) \u2192 resolve through `terminalPolicyDecision`.\n *\n * This is the layer that makes a fully unattended Brain possible: with mode\n * 'headless' every decision terminates in answer/deny, never in a blocking\n * prompt.\n */\nexport class EscalationRoutingBrainArbiter implements BrainArbiter {\n constructor(\n private readonly inner: BrainArbiter,\n private readonly queue: BrainDecisionQueue | undefined,\n private readonly getMode: () => BrainEscalationMode,\n /** Live terminal-policy variant, read per decision. Default 'conservative'. */\n private readonly getTerminalPolicy?: () => BrainTerminalPolicy,\n ) {}\n\n async decide(request: BrainDecisionRequest): Promise<BrainDecision> {\n const decision = await this.inner.decide(request);\n if (decision.type !== 'ask_human') return decision;\n if (this.getMode() === 'interactive' && this.queue) {\n return this.queue.requestHumanDecision(request);\n }\n markDecisionTier(request, 'terminal');\n return terminalPolicyDecision(request, this.getTerminalPolicy?.() ?? 'conservative');\n }\n}\n\n/**\n * Decorator that turns `ask_human` into an actual awaited human decision.\n * The wrapped Brain remains policy-only; this layer owns the UI/event bridge.\n */\nexport class HumanEscalatingBrainArbiter implements BrainArbiter {\n constructor(\n private readonly inner: BrainArbiter,\n private readonly queue: BrainDecisionQueue,\n ) {}\n\n async decide(request: BrainDecisionRequest): Promise<BrainDecision> {\n const decision = await this.inner.decide(request);\n if (decision.type !== 'ask_human') return decision;\n return this.queue.requestHumanDecision(request);\n }\n}\n\nexport interface DefaultBrainArbiterOptions {\n /**\n * Allow deterministic auto-answering for low-risk requests. Default true.\n * @deprecated Prefer `heuristics.lowRiskAutoAnswer`; this still wins when set.\n */\n allowLowRiskAutoAnswer?: boolean | undefined;\n /** Per-heuristic toggles. Omitted fields default to enabled. */\n heuristics?: BrainHeuristicsConfig | undefined;\n}\n\n/**\n * Conservative deterministic Brain implementation.\n *\n * It only auto-answers low-risk requests when the caller provided a recommended\n * option. Everything else follows the request fallback. This gives hosts a safe\n * policy object to wire before an LLM-backed Brain exists.\n */\nexport class DefaultBrainArbiter implements BrainArbiter {\n private readonly heuristics: ResolvedBrainHeuristics;\n\n constructor(opts: DefaultBrainArbiterOptions = {}) {\n const resolved = resolveBrainHeuristics(opts.heuristics);\n // The legacy standalone flag still wins when explicitly passed, so hosts\n // that predate `heuristics` keep their behaviour.\n this.heuristics = {\n ...resolved,\n lowRiskAutoAnswer: opts.allowLowRiskAutoAnswer ?? resolved.lowRiskAutoAnswer,\n };\n }\n\n async decide(request: BrainDecisionRequest): Promise<BrainDecision> {\n const recommended = request.options?.find((option) => option.recommended);\n if (this.heuristics.lowRiskAutoAnswer && request.risk === 'low' && recommended) {\n markDecisionTier(request, 'heuristic');\n return {\n type: 'answer',\n optionId: recommended.id,\n text: recommended.label,\n rationale: 'Low-risk request with an explicit recommended option.',\n };\n }\n\n // Blocked dependency explicitly resolved \u2192 continue. Uses the shared\n // heuristic from brain-heuristics.ts (same pattern as quickDecide in\n // autonomy-brain.ts). Requires the caller to have declared continue safe\n // AND explicit resolution evidence in the context. Skips option-bearing\n // requests (options are control-plane input demanding a structured\n // choice, not a keyword guess \u2014 same discipline as quickDecide).\n if (\n this.heuristics.blockedResolved &&\n !request.options?.length &&\n request.fallback === 'continue' &&\n request.context\n ) {\n if (\n isBlockedResolved(\n request.question.toLowerCase(),\n request.context.toLowerCase(),\n this.heuristics.blockedResolvedMarkers,\n )\n ) {\n markDecisionTier(request, 'heuristic');\n return {\n type: 'answer',\n text: 'Blocker resolved. Continue with the previously blocked work.',\n rationale: 'Heuristic: blocking dependency explicitly resolved \u2014 resuming.',\n };\n }\n }\n\n // Fallback semantics. A `continue` answer here is only PROVISIONAL (the\n // tiered arbiter forwards it to the LLM tier), and `ask_human` is always\n // handed onward, so both marks get overwritten by whichever tier actually\n // resolves. Marking anyway keeps the policy visible when no later tier\n // takes over.\n markDecisionTier(request, 'policy');\n switch (request.fallback) {\n case 'deny':\n return {\n type: 'deny',\n reason: `Brain could not safely decide: ${request.question}`,\n };\n case 'continue':\n return {\n type: 'answer',\n text: 'Continue with the caller default.',\n rationale: 'No safe Brain decision was available; request fallback is continue.',\n };\n case 'ask_human':\n return {\n type: 'ask_human',\n prompt: formatHumanPrompt(request),\n options: request.options,\n rationale: 'Decision requires human authority or lacks a safe automatic option.',\n };\n default:\n // Runtime safety: deserialized or unknown fallback defaults to deny\n return {\n type: 'deny',\n reason: `Brain could not safely decide (unknown fallback: ${String(request.fallback)}): ${request.question}`,\n };\n }\n }\n}\n\nexport function formatHumanPrompt(request: BrainDecisionRequest): string {\n const lines = [\n `Brain requires human decision for ${request.source}:`,\n `Question: ${request.question}`,\n ];\n if (request.context?.trim()) {\n lines.push('', 'Context:', request.context.trim());\n }\n if (request.options?.length) {\n lines.push('', 'Options:');\n for (const option of request.options) {\n const risk = option.risk ? ` [risk: ${option.risk}]` : '';\n const consequence = option.consequence ? ` \u2014 ${option.consequence}` : '';\n lines.push(`- ${option.id}: ${option.label}${risk}${consequence}`);\n }\n }\n lines.push('', `Risk: ${request.risk}`);\n return lines.join('\\n');\n}\n", "import { readFileSync, statSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Cache of resolved instruction text, keyed by the relative path. Bundled\n * instruction files are immutable for the process lifetime, so re-reading them\n * on every call (some callers do so per LLM request) is wasted disk I/O.\n */\nconst textCache = new Map<string, string>();\n\n/** Resolved once \u2014 the candidate roots only depend on this module's location. */\nlet rootCandidates: string[] | undefined;\n\nexport function readBundledInstructionText(relativePath: string): string {\n const cached = textCache.get(relativePath);\n if (cached !== undefined) return cached;\n\n let resolved = '';\n for (const root of instructionRootCandidates()) {\n try {\n resolved = readFileSync(path.join(root, relativePath), 'utf8').trimEnd();\n break;\n } catch {\n // try next candidate\n }\n }\n textCache.set(relativePath, resolved);\n return resolved;\n}\n\nexport function renderInstructionTemplate(\n template: string,\n values: Record<string, string>,\n): string {\n return template.replace(/\\{\\{\\s*([a-zA-Z0-9_.-]+)\\s*\\}\\}/g, (match, key: string) =>\n Object.hasOwn(values, key) ? (values[key] ?? '') : match,\n );\n}\n\nfunction instructionRootCandidates(): string[] {\n if (rootCandidates !== undefined) return rootCandidates;\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 ];\n rootCandidates = candidates.sort((a, b) => Number(!isDirectory(a)) - Number(!isDirectory(b)));\n return rootCandidates;\n}\n\nfunction isDirectory(candidate: string): boolean {\n try {\n return statSync(candidate).isDirectory();\n } catch {\n return false;\n }\n}\n", "import { toErrorMessage } from './error.js';\n\nexport interface SafeParseResult<T> {\n ok: boolean;\n value?: T | undefined;\n error?: string | undefined;\n}\n\nexport function safeParse<T = unknown>(input: string, maxBytes = 5_000_000): SafeParseResult<T> {\n if (Buffer.byteLength(input, 'utf8') > maxBytes) {\n return { ok: false, error: `Input exceeds limit (${maxBytes} bytes)` };\n }\n try {\n return { ok: true, value: JSON.parse(input) as T };\n } catch (err) {\n return {\n ok: false,\n error: toErrorMessage(err),\n };\n }\n}\n\nexport function safeStringify(value: unknown, pretty = false): string {\n const seen = new WeakSet();\n const replacer = (_k: string, v: unknown): unknown => {\n if (typeof v === 'bigint') return v.toString();\n if (v instanceof Error) {\n return { name: v.name, message: v.message, stack: v.stack };\n }\n if (typeof v === 'object' && v !== null) {\n if (seen.has(v as object)) return '[Circular]';\n seen.add(v as object);\n }\n return v;\n };\n try {\n return JSON.stringify(value, replacer, pretty ? 2 : undefined) ?? 'null';\n } catch (err) {\n return JSON.stringify({\n __serialization_error: toErrorMessage(err),\n });\n }\n}\n\n/**\n * Attempt to parse JSON5-style input and return a valid JSON string.\n * Handles trailing commas, line/block comments, and unquoted keys\n * that are common in provider output.\n *\n * Returns the sanitized string if it parses successfully as JSON,\n * or `null` if the input cannot be made valid. Callers use this to\n * decide whether to proceed with the parsed result or fall back to\n * raw handling.\n */\nexport function sanitizeJsonString(s: string): string | null {\n let out = s.trim();\n\n // Stage 1: strip line and block comments outside JSON string values.\n out = stripJsonComments(out);\n\n // Stage 2: strip trailing commas before } or ]\n out = out.replace(/,(\\s*[}\\]])/g, '$1');\n\n // Stage 3: escape literal control characters that appear *inside* string\n // values. Models frequently emit raw newlines/tabs inside a code payload\n // (e.g. edit's old_string/new_string) instead of the required \\n / \\t, which\n // makes JSON.parse throw. This is the single most common malformed-args case.\n out = escapeControlCharsInStrings(out);\n\n // Stage 4: attempt full parse; return null if it fails so callers can\n // distinguish \"already valid JSON\" from \"unrecoverable\".\n try {\n JSON.parse(out);\n return out;\n } catch {\n return null; // stripped but still not valid JSON; caller handles it\n }\n}\n\n/**\n * Strip a Markdown code-fence wrapper from a payload.\n *\n * Models occasionally return tool-call arguments wrapped in ```json fences\n * (or embedded in prose around one) instead of bare JSON. Returns the inner\n * content when the input starts with a fence (closing fence optional, so a\n * truncated stream still unwraps) or contains one complete fenced block;\n * returns null when no fence is present. Callers should only invoke this\n * after a direct parse failed, so fences inside legitimate string values are\n * never touched.\n */\nexport function stripCodeFences(s: string): string | null {\n const trimmed = s.trim();\n // Whole-payload fence: ```lang? \u2026 ```? (closer optional for truncation)\n const opener = /^```[\\w+-]*[ \\t]*\\r?\\n?/.exec(trimmed);\n if (opener) {\n const inner = trimmed.slice(opener[0].length).replace(/(\\r?\\n)?[ \\t]*```[ \\t]*$/, '');\n return inner.trim();\n }\n // Fence embedded in prose: extract the first complete fenced block.\n const embedded = /```[\\w+-]*[ \\t]*\\r?\\n([\\s\\S]*?)\\r?\\n[ \\t]*```/.exec(trimmed);\n if (embedded) return (embedded[1] ?? '').trim();\n return null;\n}\n\n/**\n * Walk the string tracking whether we are inside a JSON string literal and\n * replace raw control characters (U+0000\u2013U+001F) that appear inside strings\n * with their valid JSON escape sequences. Characters outside strings are left\n * untouched (insignificant whitespace stays as-is). Already-escaped sequences\n * are not double-escaped because we only act on *literal* control bytes.\n */\nfunction escapeControlCharsInStrings(s: string): string {\n let inString = false;\n let out = '';\n for (let i = 0; i < s.length; i++) {\n const c = s.charAt(i);\n if (c === '\"' && (i === 0 || s[i - 1] !== '\\\\')) {\n inString = !inString;\n out += c;\n continue;\n }\n const code = c.charCodeAt(0);\n if (inString && code < 0x20) {\n switch (c) {\n case '\\n':\n out += '\\\\n';\n break;\n case '\\r':\n out += '\\\\r';\n break;\n case '\\t':\n out += '\\\\t';\n break;\n case '\\b':\n out += '\\\\b';\n break;\n case '\\f':\n out += '\\\\f';\n break;\n default:\n out += `\\\\u${code.toString(16).padStart(4, '0')}`;\n }\n continue;\n }\n out += c;\n }\n return out;\n}\n\nfunction stripJsonComments(s: string): string {\n let inString = false;\n let escaped = false;\n const chars: string[] = [];\n let i = 0;\n\n while (i < s.length) {\n const c = s.charAt(i);\n\n if (inString) {\n chars.push(c);\n if (escaped) {\n escaped = false;\n } else if (c === '\\\\') {\n escaped = true;\n } else if (c === '\"') {\n inString = false;\n }\n i++;\n continue;\n }\n\n if (c === '\"') {\n inString = true;\n chars.push(c);\n i++;\n continue;\n }\n\n if (c === '/' && s.charAt(i + 1) === '/') {\n while (i < s.length && s.charAt(i) !== '\\n') i++;\n continue;\n }\n\n if (c === '/' && s.charAt(i + 1) === '*') {\n const end = s.indexOf('*/', i + 2);\n if (end === -1) {\n // Preserve an unterminated opener so the final JSON.parse rejects it.\n chars.push(s.slice(i));\n break;\n }\n i = end + 2;\n continue;\n }\n\n chars.push(c);\n i++;\n }\n\n return chars.join('');\n}\n", "/**\n * AutonomyBrain \u2014 a self-driving decision layer for autonomous workflows.\n *\n * Unlike the standard BrainArbiter which asks the human when uncertain,\n * AutonomyBrain makes decisions autonomously within configured risk\n * boundaries, keeping the system running unattended. It uses the session\n * LLM to evaluate situations and produce decisions.\n *\n * ## Identity\n * The AutonomyBrain is NOT the main agent. It is a dedicated decision\n * engine with a single purpose: evaluate blocked/stuck situations in\n * autonomous workflows and decide whether to continue, pivot, or stop.\n *\n * ## Decision Flow\n * 1. RISK GATE \u2014 if request risk > maxAutoRisk, auto-deny\n * 2. HEURISTIC \u2014 fast pattern-match for common situations (deadlock, retry-exhausted)\n * 3. LLM EVALUATION \u2014 complex decisions (goal completion, conflict resolution)\n *\n * ## Decision Logging\n * Every decision is emitted via `onDecision` callback with a human-readable\n * summary suitable for chat history and journal entries.\n *\n * Usage:\n * const brain = createAutonomyBrain({\n * provider, model, maxAutoRisk: 'high',\n * onDecision: (summary) => journal.push(summary),\n * });\n */\n\nimport type { Provider, Usage } from '../types/provider.js';\nimport {\n BRAIN_RISK_LEVELS,\n type BrainArbiter,\n type BrainDecision,\n type BrainDecisionRequest,\n} from '../coordination/brain.js';\nimport {\n type BrainHeuristicsConfig,\n COMPETING_ALTERNATIVE,\n isBlockedResolved,\n resolveBrainHeuristics,\n} from '../coordination/brain-heuristics.js';\nimport { markDecisionTier } from '../coordination/brain-telemetry.js';\nimport type { BrainCircuitBreaker } from './brain-circuit.js';\nimport type { EventBus } from '../kernel/events.js';\nimport { readBundledInstructionText } from '../utils/instruction-file.js';\nimport { safeParse } from '../utils/safe-json.js';\n\n/** One (provider, model) pair the Brain may call for a decision. */\nexport interface BrainLlmTarget {\n provider: Provider;\n model: string;\n /** Display label for logs/status (e.g. \"anthropic/claude-haiku\"). */\n label?: string | undefined;\n}\n\nexport interface AutonomyBrainOptions {\n /** LLM provider for decision-making. Ignored when `targets` is non-empty. */\n provider?: Provider | undefined;\n /** Model to use for decisions (should be fast + cheap). Ignored when `targets` is non-empty. */\n model?: string | undefined;\n /**\n * Ordered LLM pool. With `strategy: 'fallback'` (default) the first target\n * is primary and later ones are tried in order when a call fails/times\n * out; with 'round-robin' successive decisions rotate the starting target.\n * At least one of `targets` / (`provider` + `model`) must be provided.\n */\n targets?: BrainLlmTarget[] | undefined;\n /** Pool selection strategy. Default 'fallback'. */\n strategy?: 'fallback' | 'round-robin' | undefined;\n /** Maximum risk level the brain will auto-decide. Default: 'high'.\n * 'low' \u2014 only auto-decide low-risk questions\n * 'medium' \u2014 auto-decide low/medium\n * 'high' \u2014 auto-decide low/medium/high\n * 'all' \u2014 auto-decide everything (including critical)\n */\n maxAutoRisk?: 'low' | 'medium' | 'high' | 'all' | undefined;\n /** Timeout for each decision call (ms). Default: 15_000. */\n decisionTimeoutMs?: number | undefined;\n /** Per-heuristic toggles for `quickDecide`. Omitted fields default to enabled. */\n heuristics?: BrainHeuristicsConfig | undefined;\n /**\n * Bus for `brain.llm_call` trace events \u2014 one per pool target per decision,\n * including the failures the fallback loop otherwise swallows.\n */\n events?: EventBus | undefined;\n /** Include raw response text in trace events. Off by default (production content). */\n traceContent?: boolean | undefined;\n /** Output budget per decision call. Default `DEFAULT_BRAIN_MAX_TOKENS` (200). */\n maxTokens?: number | undefined;\n /**\n * Reject responses in which the model declined to decide (\"I don't know\",\n * \"insufficient evidence\", empty text) instead of presenting them as an\n * answer. Default true \u2014 an empty or hedging response is not a decision.\n */\n rejectUncertain?: boolean | undefined;\n /**\n * Reject answers whose self-reported `confidence` is below this (0..1).\n * Default 0 = off. Responses that report no confidence are never rejected\n * by this gate.\n */\n minConfidence?: number | undefined;\n /**\n * Failure memory for the pool. When the breaker is open the tier is skipped\n * outright instead of paying `pool.length \u00D7 decisionTimeoutMs` again for a\n * conclusion the previous decision already reached.\n */\n circuit?: BrainCircuitBreaker | undefined;\n /**\n * Decision-history digest for the LLM prompt (typically\n * `BrainDecisionLedger.digestFor`): how similar past decisions went and\n * how they turned out. Appended to the user message when non-empty.\n */\n getDecisionDigest?: ((request: BrainDecisionRequest) => string | undefined) | undefined;\n /**\n * Called after every decision with a human-readable summary.\n * Use this to log decisions into chat history, journal, or status line.\n * Example: \"\uD83E\uDDE0 Brain: skipped deadlocked tasks \u2192 continuing with phase 3/5\"\n */\n onDecision?: ((summary: string, decision: BrainDecision, request: BrainDecisionRequest) => void) | undefined;\n}\n\n/** Re-exported under the historical local name; canonical copy lives with `BrainRisk`. */\nconst RISK_LEVELS = BRAIN_RISK_LEVELS;\n\n/** Runtime-adjustable autonomy ceiling for the tiered brain. */\nexport type BrainAutoRisk = 'off' | 'low' | 'medium' | 'high' | 'all';\n\n/**\n * Resolve an autonomy ceiling to a level comparable against `RISK_LEVELS`.\n *\n * `RISK_LEVELS` is keyed by REQUEST risk (`low|medium|high|critical`), but a\n * ceiling is keyed by `BrainAutoRisk`, whose `'off'` and `'all'` values have\n * no entry there. Looking a ceiling up directly therefore silently produced\n * the fallback level \u2014 `'all'` resolved to `2` (= `high`), so\n * `createAutonomyBrain({ maxAutoRisk: 'all' })` auto-denied every `critical`\n * request despite being explicitly configured as permissive (see\n * `assembleBrainTiers`, which passes `'all'` precisely to keep the inner tier\n * ungated and let the tiered ceiling do the gating).\n *\n * Both the tiered arbiter and the single-LLM brain now share this one\n * resolver so the two ladders cannot drift apart again.\n *\n * @returns `-1` for `'off'` (nothing is auto-decidable), `3` for `'all'`\n * (including `critical`), otherwise the matching `RISK_LEVELS` entry.\n */\nexport function resolveRiskCeiling(ceiling: BrainAutoRisk | undefined): number {\n if (ceiling === 'off') return -1;\n if (ceiling === 'all') return 3;\n return RISK_LEVELS[ceiling ?? 'medium'] ?? 1;\n}\n\nexport interface TieredBrainArbiterOptions {\n /** Fast deterministic policy layer (DefaultBrainArbiter). Consulted first. */\n policy: BrainArbiter;\n /** LLM-backed autonomous layer (createAutonomyBrain). Consulted when the\n * policy layer would escalate to the human and the request's risk is\n * within the live ceiling. */\n autonomous?: BrainArbiter | undefined;\n /**\n * Live autonomy ceiling \u2014 read on EVERY decision so `/brain risk <level>`\n * changes take effect immediately. 'off' disables the autonomous layer\n * entirely (everything the policy can't answer goes to the human).\n */\n getMaxAutoRisk?: (() => BrainAutoRisk) | undefined;\n /**\n * Multi-LLM council (createCouncilBrainArbiter). When present, requests at\n * or above the council risk floor are decided by the council INSTEAD of\n * the single-LLM layer. Council answers AND denies are terminal \u2014 a panel\n * that considered the question and refused is a real decision, not a\n * failure. Only `ask_human` (quorum not met / judge unavailable) falls\n * through to the escalation tier.\n */\n council?: BrainArbiter | undefined;\n /** Live council risk floor. Default 'high'. Read on every decision. */\n getCouncilMinRisk?: (() => 'medium' | 'high' | 'critical') | undefined;\n /**\n * Whether an LLM-tier `deny` ends the decision. Read per decision.\n * Default 'never' \u2014 see `BrainConfig.llm.denyIsTerminal`.\n */\n getDenyIsTerminal?: (() => 'never' | 'when-decided' | 'always') | undefined;\n /**\n * Bus for `brain.tier_transition` events \u2014 one per tier the ladder ran,\n * recording what it returned and why the chain did or did not stop there.\n * Without it a decision's path through the ladder is unrecoverable.\n */\n events?: EventBus | undefined;\n}\n\n/**\n * The standard Brain positioning: policy first, LLM/council second,\n * escalation last.\n *\n * 1. POLICY \u2014 deterministic DefaultBrainArbiter (low-risk fast path,\n * fallback semantics). Denies and option-backed answers pass through\n * untouched. A fallback-produced `continue` answer (no optionId, the\n * request declared `fallback: 'continue'`) is only PROVISIONAL: it\n * means \"nobody could decide\", not \"this is the right call\", so the\n * LLM tier still gets consulted within the ceiling. Historically it\n * short-circuited here, which meant e.g. goal-completion checks never\n * reached the LLM at all.\n * 2. COUNCIL \u2014 requests at/above the council floor (default 'high') are\n * decided by the multi-LLM council when one is wired.\n * 3. LLM \u2014 everything else within the live ceiling goes to the\n * single-LLM autonomous brain. Only a real `answer` short-circuits;\n * denials/failures fall through.\n * 4. ESCALATION \u2014 anything left escalates. Callers wrap this in\n * `EscalationRoutingBrainArbiter` (interactive prompt or headless\n * terminal policy) or the legacy `HumanEscalatingBrainArbiter`.\n */\nexport function createTieredBrainArbiter(opts: TieredBrainArbiterOptions): BrainArbiter {\n const trace = (\n request: BrainDecisionRequest,\n tier: 'policy' | 'council' | 'llm',\n outcome: 'answer' | 'deny' | 'ask_human' | 'error' | 'skipped',\n terminal: boolean,\n startedAt: number,\n reason?: string,\n ): void => {\n opts.events?.emit('brain.tier_transition', {\n sessionId: request.sessionId,\n requestId: request.id,\n tier,\n outcome,\n terminal,\n ...(reason ? { reason } : {}),\n durationMs: Date.now() - startedAt,\n at: Date.now(),\n });\n };\n\n return {\n async decide(request: BrainDecisionRequest): Promise<BrainDecision> {\n const policyAt = Date.now();\n const policyDecision = await opts.policy.decide(request);\n // Provisional = the policy merely echoed the request's continue\n // fallback (no optionId means it did not pick a concrete option).\n const provisionalContinue =\n policyDecision.type === 'answer' &&\n policyDecision.optionId === undefined &&\n request.fallback === 'continue';\n if (policyDecision.type !== 'ask_human' && !provisionalContinue) {\n trace(request, 'policy', policyDecision.type, true, policyAt);\n return policyDecision;\n }\n trace(\n request,\n 'policy',\n policyDecision.type,\n false,\n policyAt,\n provisionalContinue ? 'provisional continue \u2014 forwarded for a real judgement' : 'policy escalated',\n );\n\n // 'off' resolves to -1, so the comparison below short-circuits every\n // request back to the policy decision without a special case.\n const ceilingLevel = resolveRiskCeiling(opts.getMaxAutoRisk?.() ?? 'medium');\n const requestLevel = RISK_LEVELS[request.risk] ?? 2;\n if (requestLevel > ceilingLevel) {\n trace(request, 'llm', 'skipped', false, policyAt, `risk ${request.risk} exceeds the autonomy ceiling`);\n return policyDecision;\n }\n\n // COUNCIL \u2014 high-stakes questions get the multi-LLM panel.\n if (opts.council) {\n const floor = opts.getCouncilMinRisk?.() ?? 'high';\n const floorLevel = RISK_LEVELS[floor] ?? 2;\n if (requestLevel >= floorLevel) {\n const councilAt = Date.now();\n try {\n const councilDecision = await opts.council.decide(request);\n if (councilDecision.type !== 'ask_human') {\n markDecisionTier(request, 'council');\n trace(request, 'council', councilDecision.type, true, councilAt);\n return councilDecision;\n }\n trace(request, 'council', 'ask_human', false, councilAt, 'council abstained');\n } catch (err) {\n // Council failure degrades to the single-LLM tier below.\n trace(\n request,\n 'council',\n 'error',\n false,\n councilAt,\n err instanceof Error ? err.message : String(err),\n );\n }\n } else {\n trace(request, 'council', 'skipped', false, policyAt, `risk ${request.risk} below the council floor`);\n }\n }\n\n if (!opts.autonomous) {\n trace(request, 'llm', 'skipped', false, policyAt, 'no LLM tier configured');\n return policyDecision;\n }\n const llmAt = Date.now();\n try {\n const llmDecision = await opts.autonomous.decide(request);\n if (llmDecision.type === 'answer') {\n trace(request, 'llm', 'answer', true, llmAt);\n return llmDecision;\n }\n // A deny may be a real refusal or just a dead pool. `readLlmDenyKind`\n // tells them apart; without that distinction every refusal had to be\n // discarded to stay safe against infrastructure failures.\n if (llmDecision.type === 'deny') {\n const policy = opts.getDenyIsTerminal?.() ?? 'never';\n const kind = readLlmDenyKind(llmDecision);\n const terminal =\n policy === 'always' || (policy === 'when-decided' && kind === undefined);\n if (terminal) {\n markDecisionTier(request, 'llm');\n trace(request, 'llm', 'deny', true, llmAt, `denyIsTerminal: ${policy}`);\n return llmDecision;\n }\n }\n trace(request, 'llm', llmDecision.type, false, llmAt, 'non-answer discarded by the ladder');\n } catch (err) {\n // LLM layer is best-effort \u2014 fall through to the escalation tier.\n trace(request, 'llm', 'error', false, llmAt, err instanceof Error ? err.message : String(err));\n }\n // The LLM tier marked itself before we rejected its non-answer; restore\n // the provenance to the decision we are actually returning.\n markDecisionTier(request, 'policy');\n return policyDecision;\n },\n };\n}\n\n/**\n * Create a self-driving brain that makes autonomous decisions.\n * Never asks the human \u2014 within its risk boundary it answers, above it denies.\n */\nexport function createAutonomyBrain(opts: AutonomyBrainOptions): BrainArbiter {\n const maxRisk = opts.maxAutoRisk ?? 'high';\n const maxRiskLevel = resolveRiskCeiling(maxRisk);\n const timeoutMs = opts.decisionTimeoutMs ?? 15_000;\n const targets: BrainLlmTarget[] =\n opts.targets && opts.targets.length > 0\n ? opts.targets\n : opts.provider && opts.model\n ? [{ provider: opts.provider, model: opts.model }]\n : [];\n if (targets.length === 0) {\n throw new Error('createAutonomyBrain: provide `targets` or `provider` + `model`.');\n }\n const strategy = opts.strategy ?? 'fallback';\n // Round-robin rotation cursor \u2014 advances once per decision, not per attempt.\n let rrCursor = 0;\n\n return {\n async decide(request: BrainDecisionRequest): Promise<BrainDecision> {\n const requestLevel = RISK_LEVELS[request.risk] ?? 2;\n\n // RISK GATE \u2014 above our risk boundary \u2192 auto-deny\n if (requestLevel > maxRiskLevel) {\n const reason = `Auto-denied: risk \"${request.risk}\" exceeds max \"${maxRisk}\"`;\n const decision: BrainDecision = { type: 'deny', reason };\n opts.onDecision?.(\n `\uD83E\uDDE0 Brain: DENIED \u2014 ${request.question.slice(0, 80)} (risk: ${request.risk} > ${maxRisk})`,\n decision,\n request,\n );\n return decision;\n }\n\n // HEURISTIC \u2014 fast pattern-match\n const heuristic = quickDecide(request, opts.heuristics);\n if (heuristic) {\n markDecisionTier(request, 'heuristic');\n opts.onDecision?.(formatDecisionSummary(heuristic, request), heuristic, request);\n return heuristic;\n }\n\n // CIRCUIT BREAKER \u2014 a dead pool must not cost a full timeout sweep on\n // every decision. Skipping here returns the same `unavailable` deny the\n // sweep would have produced, so the ladder behaves identically minus\n // the wait.\n if (opts.circuit && !opts.circuit.shouldAttempt()) {\n const decision = markDenyKind(\n {\n type: 'deny',\n reason: 'Autonomy Brain LLM tier is circuit-broken after repeated failures.',\n },\n 'unavailable',\n );\n opts.onDecision?.(formatDecisionSummary(decision, request), decision, request);\n return decision;\n }\n\n // LLM EVALUATION \u2014 complex decisions. Try the pool in order; the first\n // target that produces a usable response wins.\n // Wrap the cursor in place rather than letting it grow unbounded, so a\n // long-lived session cannot drift it toward Number.MAX_SAFE_INTEGER.\n let start = 0;\n if (strategy === 'round-robin') {\n start = rrCursor;\n rrCursor = (rrCursor + 1) % targets.length;\n }\n const rotated = [...targets.slice(start), ...targets.slice(0, start)];\n // Known-bad targets go last so a recovered model is still reached.\n const ordered = opts.circuit\n ? opts.circuit.orderTargets(rotated, (t) => t.label ?? t.model)\n : rotated;\n const digest = opts.getDecisionDigest?.(request);\n const llmDecision = await llmDecide(\n request,\n ordered,\n timeoutMs,\n digest,\n opts.events ? { events: opts.events, content: opts.traceContent === true } : undefined,\n opts.maxTokens,\n {\n rejectUncertain: opts.rejectUncertain ?? true,\n minConfidence: opts.minConfidence ?? 0,\n },\n opts.circuit,\n );\n markDecisionTier(request, 'llm');\n opts.onDecision?.(formatDecisionSummary(llmDecision, request), llmDecision, request);\n return llmDecision;\n },\n };\n}\n\n/**\n * Format a decision as a human-readable one-liner for chat history.\n */\nexport function formatDecisionSummary(\n decision: BrainDecision,\n request: BrainDecisionRequest,\n): string {\n const question = request.question.length > 80\n ? request.question.slice(0, 77) + '\u2026'\n : request.question;\n\n if (decision.type === 'deny') {\n return `\uD83E\uDDE0 Brain: DENIED \u2014 \"${question}\" \u2192 ${decision.reason}`;\n }\n\n if (decision.type === 'answer') {\n const action = decision.optionId\n ? `chose [${decision.optionId}]`\n : decision.text.length > 60\n ? decision.text.slice(0, 57) + '\u2026'\n : decision.text;\n return `\uD83E\uDDE0 Brain: DECIDED \u2014 \"${question}\" \u2192 ${action}`;\n }\n\n return `\uD83E\uDDE0 Brain: ASKED HUMAN \u2014 \"${question}\"`;\n}\n\n/**\n * Fast heuristic decisions that don't need an LLM call.\n *\n * Deliberately narrow: heuristics never fire on option-bearing requests\n * (options are control-plane input demanding a structured choice, not a\n * keyword guess) and the continue fast-path only fires when the caller\n * itself declared continue the safe fallback AND the question offers no\n * alternative \u2014 \"Should we continue or stop?\" must reach the LLM.\n */\nexport function quickDecide(\n request: BrainDecisionRequest,\n heuristics?: BrainHeuristicsConfig | undefined,\n): BrainDecision | null {\n if (request.options?.length) return null;\n\n const h = resolveBrainHeuristics(heuristics);\n const q = request.question.toLowerCase();\n const ctx = request.context?.toLowerCase() ?? '';\n\n // Deadlock with failed tasks \u2192 skip and continue. The context must mention\n // \"failed\" anchored to a work-unit noun (task, step, job, \u2026) so that\n // incidental mentions like \"login failed\" don't trigger the fast path.\n if (h.deadlockSkip && q.includes('deadlock') && /\\bfailed\\s+(?:task|step|job|build|test|phase|stage|item|unit)s?\\b/.test(ctx)) {\n return {\n type: 'answer',\n text: 'Skip deadlocked tasks and continue with remaining work. Failed tasks will be reported in the final summary.',\n rationale: 'Heuristic: deadlocked tasks blocked by failed dependencies \u2014 skipping unblocks remaining work.',\n };\n }\n\n // Repeated failure with retries demonstrably exhausted \u2192 move on. Requires\n // an explicit exhausted marker or a concrete \u22653 attempt/failure count \u2014\n // a bare \"3\" anywhere in the context is not evidence.\n if (\n h.retryExhausted &&\n (q.includes('failed') || q.includes('retry')) &&\n (/\\bexhausted\\b/.test(ctx) ||\n /\\b(?:[3-9]|\\d{2,})\\s+(?:consecutive\\s+)?(?:times|attempts|retries|failures)\\b/.test(ctx) ||\n /\\b(?:attempt|retr(?:y|ies)|failure)s?\\W{0,3}(?:[3-9]|\\d{2,})\\b/.test(ctx))\n ) {\n return {\n type: 'answer',\n text: 'Mark as failed and move on. Note the failure for the final report.',\n rationale: 'Heuristic: retries exhausted \u2014 continuing would waste resources.',\n };\n }\n\n // Blocked dependency explicitly resolved \u2192 continue. Requires the caller\n // to have declared continue safe and no competing alternative in the\n // question. The context must contain an explicit resolution marker so\n // that \"blocked by X\" without evidence of resolution still reaches the LLM.\n if (\n h.blockedResolved &&\n request.fallback === 'continue' &&\n isBlockedResolved(q, ctx, h.blockedResolvedMarkers)\n ) {\n return {\n type: 'answer',\n text: 'Blocker resolved. Continue with the previously blocked work.',\n rationale: 'Heuristic: blocking dependency explicitly resolved \u2014 resuming.',\n };\n }\n\n // Goal complete verification \u2192 needs LLM evaluation\n if (q.includes('goal complete') || q.includes('mission complete')) {\n return null;\n }\n\n // Plain continue/proceed ping whose caller declared continue safe, with no\n // competing alternative in the question \u2192 yes without burning an LLM call.\n if (\n h.continuePing &&\n request.fallback === 'continue' &&\n /\\b(?:continue|proceed)\\b/.test(q) &&\n !/\\b(?:stop|abort|halt|cancel|pause|rollback)\\b/.test(q) &&\n !COMPETING_ALTERNATIVE.test(q)\n ) {\n return {\n type: 'answer',\n text: 'Continue execution. Do not stop.',\n rationale: 'Heuristic: autonomy mode \u2014 continue until all work is complete.',\n };\n }\n\n return null;\n}\n\n/**\n * Render a decision request as the user message for a Brain LLM call.\n * Shared by the single-LLM tier and every council voter so all of them see\n * the same question/context/options shape.\n */\nexport function buildBrainUserMessage(request: BrainDecisionRequest): string {\n const optionsText = request.options?.length\n ? '\\nOptions:\\n' +\n request.options\n .map(\n (o) =>\n ` [${o.id}] ${o.label}${o.consequence ? ` \u2014 ${o.consequence}` : ''}${o.recommended ? ' \u2605 recommended' : ''}`,\n )\n .join('\\n')\n : '';\n\n return [\n `Question: ${request.question}`,\n request.context ? `\\nContext:\\n${request.context}` : '',\n optionsText,\n ].filter(Boolean).join('\\n');\n}\n\n/** Append a decision-history digest to a Brain user message (shared shape). */\nexport function withDecisionDigest(user: string, digest: string | undefined): string {\n if (!digest?.trim()) return user;\n return `${user}\\n\\nOutcome history of similar past decisions (learn from it):\\n${digest}`;\n}\n\n/**\n * One Brain LLM call against a single target. Throws on transport failure,\n * timeout, or abort \u2014 callers own the pool/fallback semantics.\n */\nexport async function completeBrainLlm(\n target: BrainLlmTarget,\n input: { system: string; user: string; timeoutMs: number; maxTokens?: number | undefined },\n): Promise<string> {\n return (await completeBrainLlmDetailed(target, input)).text;\n}\n\n/** Text plus the observable call metadata a trace/quality gate needs. */\ninterface BrainLlmCallResult {\n text: string;\n usage?: Usage | undefined;\n /**\n * `'max_tokens'` means the response was CUT OFF. With the default 200-token\n * budget a rationale can be truncated mid-sentence, and the free-text path\n * would happily turn that fragment into a decision \u2014 so callers must be\n * able to see it.\n */\n stopReason?: string | undefined;\n}\n\n/**\n * One Brain LLM call, returning the metadata `completeBrainLlm` discards.\n *\n * Usage was previously thrown away at this boundary, which is why the council\n * adapter reported hardcoded zero tokens for every seat and why \"what do\n * Brain decisions cost\" had no answer.\n */\nexport async function completeBrainLlmDetailed(\n target: BrainLlmTarget,\n input: { system: string; user: string; timeoutMs: number; maxTokens?: number | undefined },\n): Promise<BrainLlmCallResult> {\n const signal = AbortSignal.timeout(input.timeoutMs);\n const response = await target.provider.complete(\n {\n model: target.model,\n system: [{ type: 'text', text: input.system }],\n messages: [{ role: 'user', content: input.user || 'Decide.' }],\n maxTokens: input.maxTokens ?? DEFAULT_BRAIN_MAX_TOKENS,\n },\n { signal },\n );\n return {\n text: extractText(response).trim(),\n usage: extractUsage(response),\n stopReason: extractStopReason(response),\n };\n}\n\n/**\n * Output budget for a Brain decision call.\n *\n * Deliberately small \u2014 a Brain response is one decision plus a one-sentence\n * rationale, not prose. Raise it via `brain.llm.maxTokens` if truncation\n * shows up in the trace as `stopReason: 'max_tokens'`.\n */\nexport const DEFAULT_BRAIN_MAX_TOKENS = 200;\n\nfunction extractUsage(result: unknown): Usage | undefined {\n if (!result || typeof result !== 'object') return undefined;\n const usage = (result as { usage?: unknown }).usage;\n if (!usage || typeof usage !== 'object') return undefined;\n const u = usage as Record<string, unknown>;\n const input = typeof u.input === 'number' ? u.input : undefined;\n const output = typeof u.output === 'number' ? u.output : undefined;\n if (input === undefined && output === undefined) return undefined;\n return { input: input ?? 0, output: output ?? 0 };\n}\n\nfunction extractStopReason(result: unknown): string | undefined {\n if (!result || typeof result !== 'object') return undefined;\n const reason = (result as { stopReason?: unknown }).stopReason;\n return typeof reason === 'string' ? reason : undefined;\n}\n\n/**\n * Ask the LLM pool for a decision on complex questions. Targets are tried\n * in the given order; the first one that answers wins. Uses a carefully\n * crafted system prompt that establishes the brain's identity, purpose,\n * and decision-making framework.\n */\ntype BrainLlmDenyKind =\n /** No target in the pool produced a response (transport/timeout). */\n | 'unavailable'\n /** A response came back but carried no exact valid option id. */\n | 'unparseable'\n /** The model considered the question and refused. */\n | 'refused';\n\n/**\n * Why a Brain LLM call ended in `deny`.\n *\n * `llmDecide` historically collapsed three very different situations into one\n * bare `{type:'deny'}`: a dead provider pool, an unparseable response, and a\n * model that genuinely refused. Callers could not tell them apart, so\n * `createTieredBrainArbiter` had to treat ALL of them as infrastructure noise\n * and fall through \u2014 which meant a real refusal could never be terminal.\n *\n * The kind is recorded out of band (keyed by the decision object's identity)\n * so the `BrainDecision` union \u2014 and every consumer that structurally\n * compares decisions \u2014 stays untouched.\n */\nconst denyKinds = new WeakMap<object, BrainLlmDenyKind>();\n\n/** Tag a deny decision with the reason it was produced. */\nfunction markDenyKind(decision: BrainDecision, kind: BrainLlmDenyKind): BrainDecision {\n denyKinds.set(decision, kind);\n return decision;\n}\n\n/**\n * Read the reason a Brain LLM tier denied, when known. Returns undefined for\n * decisions that did not come from `llmDecide` (policy denials, council\n * denials, ledger-guard denials), which callers should treat as decided.\n */\nexport function readLlmDenyKind(decision: BrainDecision): BrainLlmDenyKind | undefined {\n return denyKinds.get(decision);\n}\n\nasync function llmDecide(\n request: BrainDecisionRequest,\n targets: BrainLlmTarget[],\n timeoutMs: number,\n digest?: string | undefined,\n trace?: { events: EventBus; content: boolean } | undefined,\n maxTokens?: number | undefined,\n quality?: { rejectUncertain: boolean; minConfidence: number } | undefined,\n circuit?: BrainCircuitBreaker | undefined,\n): Promise<BrainDecision> {\n const systemPrompt = readBundledInstructionText('llm/autonomy-brain.md');\n const userMessage = withDecisionDigest(buildBrainUserMessage(request), digest);\n\n let text: string | null = null;\n for (const [attempt, target] of targets.entries()) {\n const startedAt = Date.now();\n try {\n const result = await completeBrainLlmDetailed(target, {\n system: systemPrompt,\n user: userMessage,\n timeoutMs,\n maxTokens,\n });\n text = result.text;\n circuit?.recordSuccess(target.label ?? target.model);\n trace?.events.emit('brain.llm_call', {\n sessionId: request.sessionId,\n requestId: request.id,\n tier: 'llm',\n providerId: target.provider.id,\n model: target.model,\n label: target.label,\n attempt,\n ok: true,\n durationMs: Date.now() - startedAt,\n // A truncated response is a quality problem, not a transport one \u2014\n // surface it rather than letting a half-sentence become a decision.\n ...(result.stopReason === 'max_tokens'\n ? { error: 'response truncated at maxTokens' }\n : {}),\n ...(trace.content ? { responseText: text } : {}),\n ...(result.usage ? { usage: result.usage } : {}),\n at: Date.now(),\n });\n break;\n } catch (err) {\n // This target is unavailable/slow \u2014 fall through to the next one. The\n // failure used to vanish here, which is precisely why a silently\n // degraded pool was undetectable.\n circuit?.recordFailure(target.label ?? target.model);\n trace?.events.emit('brain.llm_call', {\n sessionId: request.sessionId,\n requestId: request.id,\n tier: 'llm',\n providerId: target.provider.id,\n model: target.model,\n label: target.label,\n attempt,\n ok: false,\n durationMs: Date.now() - startedAt,\n error: err instanceof Error ? err.message : String(err),\n at: Date.now(),\n });\n }\n }\n\n if (text === null) {\n // Entire pool unavailable. This is NOT a decision, whatever the caller's\n // fallback says.\n //\n // This branch used to synthesise `{type:'answer', text:'Continue \u2026'}` for\n // `fallback: 'continue'` requests. The outcome was right but the framing\n // was not: the tiered ladder then accepted it as a genuine model answer,\n // so telemetry credited a model that was never reached, the trace\n // recorded an LLM answer for a call that never happened, and the\n // uncertainty gate was bypassed entirely.\n //\n // Reporting `unavailable` instead is both honest and outcome-preserving:\n // the ladder falls through to the policy tier, whose `fallback:'continue'`\n // handling produces exactly the same continue \u2014 attributed to `policy`,\n // which is what actually decided.\n return markDenyKind(\n { type: 'deny', reason: 'Autonomy Brain LLM unavailable for decision.' },\n 'unavailable',\n );\n }\n\n // Option-bearing decisions are control-plane input, not prose. Accept the\n // canonical JSON envelope and the historical leading `[id]` form, but\n // never substring-match an id anywhere in free text: a response such as\n // \"do not spawn; wait\" must not select the earlier `spawn` option.\n const minConfidence = quality?.minConfidence ?? 0;\n const rejectUncertain = quality?.rejectUncertain ?? true;\n const confidence = extractConfidence(text);\n const belowConfidence = minConfidence > 0 && confidence !== undefined && confidence < minConfidence;\n\n if (request.options?.length) {\n const parsed = parseOptionDecision(text, request.options);\n if (parsed && !belowConfidence) {\n return parsed;\n }\n return markDenyKind(\n {\n type: 'deny',\n reason: belowConfidence\n ? `Autonomy Brain reported confidence ${confidence} below the ${minConfidence} floor.`\n : 'Autonomy Brain returned no exact valid option id.',\n },\n 'unparseable',\n );\n }\n\n // Free-text answer. A response that declined to decide, or that is empty\n // because the provider returned an unrecognised shape, must NOT be dressed\n // up as a decision \u2014 the caller would act on it.\n const envelope = parseFreeTextDecision(text);\n if (rejectUncertain && (!envelope || belowConfidence)) {\n return markDenyKind(\n {\n type: 'deny',\n reason: belowConfidence\n ? `Autonomy Brain reported confidence ${confidence} below the ${minConfidence} floor.`\n : 'Autonomy Brain returned no usable decision (empty or declined).',\n },\n 'unparseable',\n );\n }\n\n return {\n type: 'answer',\n text:\n envelope?.decision ||\n (request.fallback === 'continue' ? 'Continue execution.' : 'Denied by autonomy policy.'),\n rationale: envelope?.rationale ?? envelope?.decision ?? undefined,\n };\n}\n\n/** Read a self-reported confidence out of a raw response, if it carries one. */\nexport function extractConfidence(rawText: string): number | undefined {\n const text = rawText.trim();\n const wholeFence = /^```(?:json)?[ \\t]*\\r?\\n([\\s\\S]*?)\\r?\\n?```$/i.exec(text);\n const candidate = wholeFence ? (wholeFence[1] ?? '').trim() : text;\n const parsed = safeParse<{ confidence?: unknown }>(candidate, 16_384);\n if (!parsed.ok || !parsed.value) return undefined;\n const value = parsed.value.confidence;\n if (typeof value !== 'number' || !Number.isFinite(value)) return undefined;\n return Math.min(1, Math.max(0, value));\n}\n\n/**\n * Phrases that mean the model declined to decide.\n *\n * The optionless path used to wrap ANY returned prose in\n * `{type:'answer'}` \u2014 so \"I don't have enough information to say\" became a\n * decision the caller would act on, indistinguishable from a real judgement.\n * Word-boundary anchored to avoid matching inside longer words.\n */\nconst LLM_NON_ANSWER =\n /\\b(?:insufficient evidence|not enough (?:information|context|evidence)|cannot determine|can't determine|unable to determine|i (?:don't|do not) know|unclear|please (?:clarify|specify)|need more (?:information|context|detail)|as an ai)\\b/i;\n\n/** Does this free-text response decline to decide? */\nexport function isNonAnswer(text: string): boolean {\n const trimmed = text.trim();\n return trimmed.length === 0 || LLM_NON_ANSWER.test(trimmed);\n}\n\n/** Structured envelope a Brain LLM may return for an optionless question. */\ninterface BrainFreeTextEnvelope {\n decision: string;\n rationale?: string | undefined;\n confidence?: number | undefined;\n}\n\n/**\n * Parse the optionless response.\n *\n * Accepts the structured envelope the prompt now asks for, and falls back to\n * bare prose so older/simpler models keep working. Returns null when the\n * model declined to decide \u2014 the caller must then fall through rather than\n * present the refusal as an answer.\n */\nexport function parseFreeTextDecision(rawText: string): BrainFreeTextEnvelope | null {\n const text = rawText.trim();\n if (text.length === 0) return null;\n\n const wholeFence = /^```(?:json)?[ \\t]*\\r?\\n([\\s\\S]*?)\\r?\\n?```$/i.exec(text);\n const candidate = wholeFence ? (wholeFence[1] ?? '').trim() : text;\n const parsed = safeParse<{ decision?: unknown; rationale?: unknown; confidence?: unknown }>(\n candidate,\n 16_384,\n );\n if (parsed.ok && parsed.value && typeof parsed.value.decision === 'string') {\n const decision = parsed.value.decision.trim();\n if (isNonAnswer(decision)) return null;\n return {\n decision,\n rationale:\n typeof parsed.value.rationale === 'string' && parsed.value.rationale.trim()\n ? parsed.value.rationale.trim()\n : undefined,\n confidence:\n typeof parsed.value.confidence === 'number' && Number.isFinite(parsed.value.confidence)\n ? Math.min(1, Math.max(0, parsed.value.confidence))\n : undefined,\n };\n }\n\n if (isNonAnswer(text)) return null;\n return { decision: text };\n}\n\nexport function parseOptionDecision(\n rawText: string,\n options: NonNullable<BrainDecisionRequest['options']>,\n): BrainDecision | null {\n const text = rawText.trim();\n const byId = new Map(options.map((option) => [option.id, option] as const));\n\n // A fenced response is accepted only when the fence is the entire payload.\n // Extracting an embedded JSON block from prose would reintroduce the same\n // ambiguity as substring matching (for example: \"do not spawn\" followed by\n // an illustrative `{ optionId: 'spawn' }` block).\n const wholeFence = /^```(?:json)?[ \\t]*\\r?\\n([\\s\\S]*?)\\r?\\n?```$/i.exec(text);\n const jsonCandidate = wholeFence ? (wholeFence[1] ?? '').trim() : text;\n const parsed = safeParse<{ optionId?: unknown; rationale?: unknown }>(jsonCandidate, 16_384);\n if (parsed.ok && parsed.value && typeof parsed.value.optionId === 'string') {\n const option = byId.get(parsed.value.optionId);\n if (!option) return null;\n return {\n type: 'answer',\n optionId: option.id,\n text: option.label,\n rationale:\n typeof parsed.value.rationale === 'string' && parsed.value.rationale.trim()\n ? parsed.value.rationale.trim()\n : undefined,\n };\n }\n\n // Backward compatibility for the prompt's former `[id] \u2014 rationale` shape.\n // The id must be the first semantic token; mentions later in prose are not\n // decisions and deliberately fail closed.\n const legacy = /^\\s*\\[([^\\]\\r\\n]+)\\](?:\\s*(?:\u2014|-|:)\\s*)?([\\s\\S]*)$/.exec(text);\n if (!legacy) return null;\n const option = byId.get((legacy[1] ?? '').trim());\n if (!option) return null;\n const rationale = (legacy[2] ?? '').trim();\n return {\n type: 'answer',\n optionId: option.id,\n text: option.label,\n rationale: rationale || undefined,\n };\n}\n\nfunction extractText(result: unknown): string {\n if (!result || typeof result !== 'object') return '';\n const r = result as Record<string, unknown>;\n if (Array.isArray(r.content)) {\n return (r.content as Array<{ type?: string; text?: string }>)\n .filter((b) => b.type === 'text')\n .map((b) => b.text ?? '')\n .join('');\n }\n if (Array.isArray(r.choices)) {\n return (r.choices as Array<{ message?: { content?: string } }>)[0]?.message?.content ?? '';\n }\n return typeof r.text === 'string' ? r.text : '';\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", "/** 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 { CouncilPersona } from '../types/council.js';\n\nconst PERSONA_ID_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\n/** Provider-neutral personas shipped with every Council installation. */\nexport const BUILTIN_COUNCIL_PERSONAS: readonly CouncilPersona[] = Object.freeze([\n freezePersona({\n id: 'executor',\n name: 'Executor',\n description: 'Tests whether a proposal is practical and keeps useful work moving.',\n instruction:\n 'Evaluate operational feasibility, concrete progress, and the cost of delay. Favor decisive action when evidence supports it, but reject action whose prerequisites are missing.',\n tags: ['delivery', 'feasibility', 'progress'],\n }),\n freezePersona({\n id: 'skeptic',\n name: 'Skeptic',\n description: 'Challenges assumptions and looks for concrete failure modes.',\n instruction:\n 'Identify unsupported assumptions, unsafe premises, irreversible consequences, and credible failure modes. Oppose or refuse only when you can name a concrete reason.',\n defaultVeto: true,\n tags: ['risk', 'assumptions', 'failure-modes'],\n }),\n freezePersona({\n id: 'auditor',\n name: 'Auditor',\n description: 'Evaluates cost, waste, evidence quality, and expected value.',\n instruction:\n 'Compare resource cost, opportunity cost, evidence quality, reversibility, and expected value. Prefer the option that achieves the objective with the least avoidable waste.',\n tags: ['cost', 'evidence', 'efficiency'],\n }),\n freezePersona({\n id: 'security',\n name: 'Security Reviewer',\n description: 'Examines trust boundaries, abuse cases, and security impact.',\n instruction:\n 'Evaluate trust boundaries, attacker-controlled inputs, privilege changes, data exposure, abuse cases, and recovery options. Treat unmitigated high-impact security risk as grounds to refuse.',\n defaultVeto: true,\n tags: ['security', 'trust', 'abuse-cases'],\n }),\n freezePersona({\n id: 'maintainer',\n name: 'Maintainer',\n description: 'Evaluates complexity, compatibility, and long-term ownership.',\n instruction:\n 'Evaluate behavioral compatibility, conceptual complexity, testability, migration cost, and future maintenance. Prefer the smallest design that remains clear and extensible.',\n tags: ['maintenance', 'compatibility', 'simplicity'],\n }),\n freezePersona({\n id: 'user-advocate',\n name: 'User Advocate',\n description: 'Evaluates the decision from the affected user\u2019s perspective.',\n instruction:\n 'Evaluate usability, surprise, accessibility, failure recovery, and whether the outcome solves the user\u2019s stated need. Prefer understandable behavior with safe recovery paths.',\n tags: ['users', 'usability', 'accessibility'],\n }),\n]);\n\n/** Immutable registry of trusted Council persona definitions. */\nexport class CouncilPersonaRegistry {\n private readonly byId: ReadonlyMap<string, CouncilPersona>;\n\n constructor(personas: readonly CouncilPersona[] = []) {\n const entries = new Map<string, CouncilPersona>();\n for (const persona of personas) {\n const normalized = freezePersona(persona);\n if (entries.has(normalized.id)) {\n throw new Error(`CouncilPersonaRegistry: duplicate persona id \"${normalized.id}\".`);\n }\n entries.set(normalized.id, normalized);\n }\n this.byId = entries;\n }\n\n has(id: string): boolean {\n return this.byId.has(id);\n }\n\n get(id: string): CouncilPersona | undefined {\n return this.byId.get(id);\n }\n\n require(id: string): CouncilPersona {\n const persona = this.get(id);\n if (!persona) throw new Error(`CouncilPersonaRegistry: unknown persona \"${id}\".`);\n return persona;\n }\n\n list(): readonly CouncilPersona[] {\n return Object.freeze([...this.byId.values()]);\n }\n\n /** Return a new registry; the current registry is never mutated. */\n with(persona: CouncilPersona, opts: { replace?: boolean | undefined } = {}): CouncilPersonaRegistry {\n const normalized = freezePersona(persona);\n if (this.has(normalized.id) && opts.replace !== true) {\n throw new Error(`CouncilPersonaRegistry: persona \"${normalized.id}\" already exists.`);\n }\n return new CouncilPersonaRegistry([\n ...this.list().filter((entry) => entry.id !== normalized.id),\n normalized,\n ]);\n }\n}\n\nexport const DEFAULT_COUNCIL_PERSONA_REGISTRY = new CouncilPersonaRegistry(\n BUILTIN_COUNCIL_PERSONAS,\n);\n\nexport function createCouncilPersonaRegistry(\n additional: readonly CouncilPersona[] = [],\n): CouncilPersonaRegistry {\n let registry = DEFAULT_COUNCIL_PERSONA_REGISTRY;\n for (const persona of additional) registry = registry.with(persona);\n return registry;\n}\n\nfunction freezePersona(persona: CouncilPersona): CouncilPersona {\n const id = persona.id.trim();\n const name = persona.name.trim();\n const description = persona.description.trim();\n const instruction = persona.instruction.trim();\n if (!PERSONA_ID_RE.test(id)) {\n throw new Error(`CouncilPersonaRegistry: invalid persona id \"${persona.id}\".`);\n }\n if (!name) throw new Error(`CouncilPersonaRegistry: persona \"${id}\" requires a name.`);\n if (!description) {\n throw new Error(`CouncilPersonaRegistry: persona \"${id}\" requires a description.`);\n }\n if (!instruction) {\n throw new Error(`CouncilPersonaRegistry: persona \"${id}\" requires an instruction.`);\n }\n if (\n persona.defaultWeight !== undefined &&\n (!Number.isFinite(persona.defaultWeight) || persona.defaultWeight <= 0)\n ) {\n throw new Error(`CouncilPersonaRegistry: persona \"${id}\" has an invalid default weight.`);\n }\n const tags = Object.freeze(\n [...new Set((persona.tags ?? []).map((tag) => tag.trim()).filter(Boolean))],\n );\n return Object.freeze({\n id,\n name,\n description,\n instruction,\n ...(persona.defaultWeight !== undefined ? { defaultWeight: persona.defaultWeight } : {}),\n ...(persona.defaultVeto !== undefined ? { defaultVeto: persona.defaultVeto } : {}),\n ...(tags.length > 0 ? { tags } : {}),\n });\n}\n", "import type {\n CouncilDistinctness,\n CouncilModelTarget,\n CouncilProfileConfig,\n ResolvedCouncilProfile,\n ResolvedCouncilSeat,\n} from '../types/council.js';\nimport {\n type CouncilPersonaRegistry,\n DEFAULT_COUNCIL_PERSONA_REGISTRY,\n} from './council-personas.js';\n\nconst PROFILE_ID_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\nconst DISTINCTNESS_VALUES: ReadonlySet<CouncilDistinctness> = new Set([\n 'none',\n 'model',\n 'provider',\n]);\n\nexport const DEFAULT_COUNCIL_QUORUM_FRACTION = 0.5;\nexport const DEFAULT_COUNCIL_APPROVAL_FRACTION = 0.5;\nexport const DEFAULT_COUNCIL_VOTER_MAX_TOKENS = 300;\nexport const DEFAULT_COUNCIL_JUDGE_MAX_TOKENS = 500;\nexport const DEFAULT_COUNCIL_PER_CALL_TIMEOUT_MS = 30_000;\nexport const DEFAULT_COUNCIL_OVERALL_TIMEOUT_MS = 90_000;\n\n/** Model-agnostic profiles. Roles are routing hints, never provider/model pins. */\nexport const BUILTIN_COUNCIL_PROFILES: readonly CouncilProfileConfig[] = Object.freeze([\n Object.freeze({\n id: 'balanced',\n name: 'Balanced',\n description: 'Three complementary lenses plus an independent judge for general decisions.',\n seats: Object.freeze([\n Object.freeze({ persona: 'executor', target: Object.freeze({ role: 'planner' }) }),\n Object.freeze({ persona: 'skeptic', target: Object.freeze({ role: 'critic' }) }),\n Object.freeze({ persona: 'auditor', target: Object.freeze({ role: 'analyst' }) }),\n ]),\n judge: Object.freeze({ role: 'reviewer' }),\n quorumFraction: 0.5,\n approvalFraction: 0.5,\n distinctness: 'model',\n }),\n Object.freeze({\n id: 'fast',\n name: 'Fast',\n description: 'Two-seat panel without a judge for quick, low-cost decisions.',\n seats: Object.freeze([\n Object.freeze({ persona: 'executor', target: Object.freeze({ role: 'planner' }) }),\n Object.freeze({ persona: 'skeptic', target: Object.freeze({ role: 'critic' }) }),\n ]),\n judge: false,\n quorumFraction: 0.5,\n approvalFraction: 0.5,\n distinctness: 'none',\n voterMaxTokens: 200,\n perCallTimeoutMs: 20_000,\n overallTimeoutMs: 30_000,\n }),\n Object.freeze({\n id: 'risk-review',\n name: 'Risk Review',\n description: 'Security, assumptions, maintenance, and cost review for high-impact choices.',\n seats: Object.freeze([\n Object.freeze({ persona: 'skeptic', target: Object.freeze({ role: 'critic' }) }),\n Object.freeze({ persona: 'security', target: Object.freeze({ role: 'security-reviewer' }) }),\n Object.freeze({ persona: 'maintainer', target: Object.freeze({ role: 'reviewer' }) }),\n Object.freeze({ persona: 'auditor', target: Object.freeze({ role: 'analyst' }) }),\n ]),\n judge: Object.freeze({ role: 'architect' }),\n quorumFraction: 0.75,\n approvalFraction: 0.5,\n distinctness: 'provider',\n judgeMaxTokens: 700,\n overallTimeoutMs: 120_000,\n }),\n]);\n\n/** Immutable registry of normalized Council profiles. */\nexport class CouncilProfileRegistry {\n private readonly byId: ReadonlyMap<string, ResolvedCouncilProfile>;\n private readonly personas: CouncilPersonaRegistry;\n\n constructor(\n profiles: readonly CouncilProfileConfig[] = [],\n personas: CouncilPersonaRegistry = DEFAULT_COUNCIL_PERSONA_REGISTRY,\n ) {\n this.personas = personas;\n const entries = new Map<string, ResolvedCouncilProfile>();\n for (const profile of profiles) {\n const normalized = normalizeCouncilProfile(profile, personas);\n if (entries.has(normalized.id)) {\n throw new Error(`CouncilProfileRegistry: duplicate profile id \"${normalized.id}\".`);\n }\n entries.set(normalized.id, normalized);\n }\n this.byId = entries;\n }\n\n has(id: string): boolean {\n return this.byId.has(id);\n }\n\n get(id: string): ResolvedCouncilProfile | undefined {\n return this.byId.get(id);\n }\n\n require(id: string): ResolvedCouncilProfile {\n const profile = this.get(id);\n if (!profile) throw new Error(`CouncilProfileRegistry: unknown profile \"${id}\".`);\n return profile;\n }\n\n list(): readonly ResolvedCouncilProfile[] {\n return Object.freeze([...this.byId.values()]);\n }\n\n /** Return a new registry; the current registry is never mutated. */\n with(\n profile: CouncilProfileConfig,\n opts: {\n replace?: boolean | undefined;\n personas?: CouncilPersonaRegistry | undefined;\n } = {},\n ): CouncilProfileRegistry {\n const personas = opts.personas ?? this.personas;\n const normalized = normalizeCouncilProfile(profile, personas);\n if (this.has(normalized.id) && opts.replace !== true) {\n throw new Error(`CouncilProfileRegistry: profile \"${normalized.id}\" already exists.`);\n }\n return new CouncilProfileRegistry(\n [\n ...this.list().filter((entry) => entry.id !== normalized.id),\n profile,\n ],\n personas,\n );\n }\n}\n\nexport const DEFAULT_COUNCIL_PROFILE_REGISTRY = new CouncilProfileRegistry(\n BUILTIN_COUNCIL_PROFILES,\n);\n\nexport function createCouncilProfileRegistry(\n additional: readonly CouncilProfileConfig[] = [],\n personas: CouncilPersonaRegistry = DEFAULT_COUNCIL_PERSONA_REGISTRY,\n): CouncilProfileRegistry {\n return new CouncilProfileRegistry([...BUILTIN_COUNCIL_PROFILES, ...additional], personas);\n}\n\nexport function resolveCouncilProfile(\n profile: string | CouncilProfileConfig | undefined,\n opts: {\n registry?: CouncilProfileRegistry | undefined;\n personas?: CouncilPersonaRegistry | undefined;\n defaultProfile?: string | undefined;\n } = {},\n): ResolvedCouncilProfile {\n const personas = opts.personas ?? DEFAULT_COUNCIL_PERSONA_REGISTRY;\n if (profile && typeof profile !== 'string') return normalizeCouncilProfile(profile, personas);\n const id = profile ?? opts.defaultProfile ?? 'balanced';\n return (opts.registry ?? DEFAULT_COUNCIL_PROFILE_REGISTRY).require(id);\n}\n\nexport function normalizeCouncilProfile(\n profile: CouncilProfileConfig,\n personas: CouncilPersonaRegistry = DEFAULT_COUNCIL_PERSONA_REGISTRY,\n): ResolvedCouncilProfile {\n const id = profile.id.trim();\n if (!PROFILE_ID_RE.test(id)) {\n throw new Error(`CouncilProfileRegistry: invalid profile id \"${profile.id}\".`);\n }\n if (profile.seats.length === 0) {\n throw new Error(`CouncilProfileRegistry: profile \"${id}\" requires at least one seat.`);\n }\n\n const usedIds = new Set<string>();\n const seats = profile.seats.map((seat) => {\n const persona = personas.require(seat.persona.trim());\n const explicitSeatId = seat.id?.trim();\n if (explicitSeatId && usedIds.has(explicitSeatId)) {\n throw new Error(`CouncilProfileRegistry: duplicate seat id \"${explicitSeatId}\".`);\n }\n const seatId = uniqueSeatId(explicitSeatId || persona.id, usedIds);\n const label = seat.label?.trim() || persona.name;\n const weight = seat.weight ?? persona.defaultWeight ?? 1;\n if (!Number.isFinite(weight) || weight <= 0) {\n throw new Error(`CouncilProfileRegistry: seat \"${seatId}\" has an invalid weight.`);\n }\n return Object.freeze({\n id: seatId,\n label,\n persona: persona.id,\n ...(seat.target ? { target: freezeTarget(seat.target, `seat \"${seatId}\"`) } : {}),\n weight,\n veto: seat.veto ?? persona.defaultVeto ?? false,\n }) satisfies ResolvedCouncilSeat;\n });\n\n const quorumFraction = fraction(\n profile.quorumFraction ?? DEFAULT_COUNCIL_QUORUM_FRACTION,\n 'quorumFraction',\n id,\n );\n const approvalFraction = fraction(\n profile.approvalFraction ?? DEFAULT_COUNCIL_APPROVAL_FRACTION,\n 'approvalFraction',\n id,\n );\n const distinctness = profile.distinctness ?? 'model';\n if (!DISTINCTNESS_VALUES.has(distinctness)) {\n throw new Error(`CouncilProfileRegistry: profile \"${id}\" has invalid distinctness.`);\n }\n const voterMaxTokens = positiveInteger(\n profile.voterMaxTokens ?? DEFAULT_COUNCIL_VOTER_MAX_TOKENS,\n 'voterMaxTokens',\n id,\n );\n const judgeMaxTokens = positiveInteger(\n profile.judgeMaxTokens ?? DEFAULT_COUNCIL_JUDGE_MAX_TOKENS,\n 'judgeMaxTokens',\n id,\n );\n const perCallTimeoutMs = positiveInteger(\n profile.perCallTimeoutMs ?? DEFAULT_COUNCIL_PER_CALL_TIMEOUT_MS,\n 'perCallTimeoutMs',\n id,\n );\n const overallTimeoutMs = positiveInteger(\n profile.overallTimeoutMs ?? DEFAULT_COUNCIL_OVERALL_TIMEOUT_MS,\n 'overallTimeoutMs',\n id,\n );\n if (overallTimeoutMs < perCallTimeoutMs) {\n throw new Error(\n `CouncilProfileRegistry: profile \"${id}\" overallTimeoutMs must be at least perCallTimeoutMs.`,\n );\n }\n\n return Object.freeze({\n id,\n name: profile.name?.trim() || id,\n description: profile.description?.trim() || '',\n seats: Object.freeze(seats),\n judge: profile.judge ? freezeTarget(profile.judge, 'judge') : false,\n quorumFraction,\n approvalFraction,\n distinctness,\n voterMaxTokens,\n judgeMaxTokens,\n perCallTimeoutMs,\n overallTimeoutMs,\n });\n}\n\nfunction uniqueSeatId(base: string, used: Set<string>): string {\n if (!PROFILE_ID_RE.test(base)) {\n throw new Error(`CouncilProfileRegistry: invalid seat id \"${base}\".`);\n }\n let id = base;\n let suffix = 2;\n while (used.has(id)) id = `${base}-${suffix++}`;\n used.add(id);\n return id;\n}\n\nfunction freezeTarget(target: CouncilModelTarget, label: string): CouncilModelTarget {\n const providerId = optionalText(target.providerId);\n const model = optionalText(target.model);\n const role = optionalText(target.role);\n const fallbackProfile = optionalText(target.fallbackProfile);\n const fallbackModels = Object.freeze(\n [...new Set((target.fallbackModels ?? []).map((ref) => ref.trim()).filter(Boolean))],\n );\n if (\n !providerId &&\n !model &&\n !role &&\n !fallbackProfile &&\n fallbackModels.length === 0\n ) {\n throw new Error(`CouncilProfileRegistry: ${label} target is empty.`);\n }\n return Object.freeze({\n ...(providerId ? { providerId } : {}),\n ...(model ? { model } : {}),\n ...(role ? { role } : {}),\n ...(fallbackProfile ? { fallbackProfile } : {}),\n ...(fallbackModels.length > 0 ? { fallbackModels } : {}),\n });\n}\n\nfunction optionalText(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n return trimmed || undefined;\n}\n\nfunction fraction(value: number, field: string, profileId: string): number {\n if (!Number.isFinite(value) || value <= 0 || value > 1) {\n throw new Error(`CouncilProfileRegistry: profile \"${profileId}\" ${field} must be in (0, 1].`);\n }\n return value;\n}\n\nfunction positiveInteger(value: number, field: string, profileId: string): number {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new Error(\n `CouncilProfileRegistry: profile \"${profileId}\" ${field} must be a positive integer.`,\n );\n }\n return value;\n}\n", "import type {\n CouncilOption,\n CouncilPersona,\n CouncilQuestion,\n CouncilVoteResult,\n ResolvedCouncilSeat,\n} from '../types/council.js';\nimport {\n readBundledInstructionText,\n renderInstructionTemplate,\n} from '../utils/instruction-file.js';\n\nexport const COUNCIL_VOTER_PROMPT_PATH = 'llm/council-voter.md';\nexport const COUNCIL_JUDGE_PROMPT_PATH = 'llm/council-judge.md';\n\n/** Build the trusted system instruction for one independent seat. */\nexport function buildCouncilVoterSystemPrompt(persona: CouncilPersona): string {\n const template = requiredInstruction(COUNCIL_VOTER_PROMPT_PATH);\n return renderInstructionTemplate(template, {\n personaInstruction: persona.instruction,\n });\n}\n\n/** Build the trusted system instruction for the final judge. */\nexport function buildCouncilJudgeSystemPrompt(): string {\n return requiredInstruction(COUNCIL_JUDGE_PROMPT_PATH);\n}\n\n/** Render the original question as delimited, untrusted user data. */\nexport function buildCouncilQuestionPrompt(\n question: CouncilQuestion,\n opts: { refusalOptionId?: string | undefined } = {},\n): string {\n const text = question.question.trim();\n if (!text) throw new Error('buildCouncilQuestionPrompt: question must not be empty.');\n const options = normalizeOptions(question.options);\n return [\n '<council-question>',\n `Question: ${text}`,\n question.context?.trim() ? `Context:\\n${question.context.trim()}` : '',\n options.length > 0 ? `Options (JSON):\\n${JSON.stringify(options)}` : 'Options: none',\n opts.refusalOptionId\n ? `Refusal option id: ${opts.refusalOptionId}`\n : 'Refusal option id: not supplied',\n '</council-question>',\n ]\n .filter(Boolean)\n .join('\\n\\n');\n}\n\n/** Build the voter user prompt. Persona instructions stay in the system prompt. */\nexport function buildCouncilVoterUserPrompt(\n question: CouncilQuestion,\n seat: ResolvedCouncilSeat,\n opts: { refusalOptionId?: string | undefined } = {},\n): string {\n return [\n buildCouncilQuestionPrompt(question, opts),\n '<seat-metadata>',\n `Seat id: ${seat.id}`,\n `Seat label: ${seat.label}`,\n `Persona id: ${seat.persona}`,\n `Vote weight: ${seat.weight}`,\n seat.veto ? 'Veto power: yes \u2014 your refusal unilaterally denies the proposal.' : '',\n '</seat-metadata>',\n ]\n .filter(Boolean)\n .join('\\n');\n}\n\n/** Build the judge user prompt with seat outputs serialized as untrusted JSON. */\nexport function buildCouncilJudgeUserPrompt(\n question: CouncilQuestion,\n votes: readonly CouncilVoteResult[],\n opts: {\n reason?: string | undefined;\n refusalOptionId?: string | undefined;\n } = {},\n): string {\n const ballots = votes.map((vote) => ({\n seatId: vote.seatId,\n persona: vote.persona,\n status: vote.status,\n ...(vote.optionId ? { optionId: vote.optionId } : {}),\n ...(vote.stance ? { stance: vote.stance } : {}),\n ...(vote.rationale ? { rationale: vote.rationale } : {}),\n }));\n return [\n buildCouncilQuestionPrompt(question, { refusalOptionId: opts.refusalOptionId }),\n '<council-ballots>',\n opts.reason?.trim() ? `Reason judging is required: ${opts.reason.trim()}` : '',\n JSON.stringify(ballots),\n '</council-ballots>',\n ]\n .filter(Boolean)\n .join('\\n\\n');\n}\n\nfunction normalizeOptions(options: readonly CouncilOption[] | undefined): CouncilOption[] {\n if (!options) return [];\n const seen = new Set<string>();\n return options.map((option) => {\n const id = option.id.trim();\n const label = option.label.trim();\n if (!id) throw new Error('buildCouncilQuestionPrompt: option id must not be empty.');\n if (!label) throw new Error(`buildCouncilQuestionPrompt: option \"${id}\" needs a label.`);\n if (seen.has(id)) throw new Error(`buildCouncilQuestionPrompt: duplicate option id \"${id}\".`);\n seen.add(id);\n return {\n id,\n label,\n ...(option.consequence?.trim() ? { consequence: option.consequence.trim() } : {}),\n };\n });\n}\n\nfunction requiredInstruction(path: string): string {\n const text = readBundledInstructionText(path);\n if (!text) throw new Error(`Council instruction file is unavailable: ${path}`);\n return text;\n}\n", "/**\n * Provider- and Brain-independent council vote resolution.\n *\n * This module contains only deterministic quorum, veto, weighted-majority,\n * refusal, and judge-escalation rules. LLM calls, prompts, parsing, and host\n * decision types belong in adapters such as `council-brain.ts`.\n */\n\nexport interface CouncilResolutionSeat {\n id: string;\n /** Vote weight in the tally. Default 1. */\n weight?: number | undefined;\n /** A refusal from this seat immediately denies the proposal. */\n veto?: boolean | undefined;\n}\n\nexport interface CouncilResolutionVote {\n seatId: string;\n optionId: string;\n}\n\nexport interface CouncilResolutionInput {\n seats: readonly CouncilResolutionSeat[];\n votes: readonly CouncilResolutionVote[];\n refusalOptionId: string;\n /** Fraction of configured seats required to return a vote. */\n quorumFraction: number;\n /** Winning weight must exceed this fraction of cast weight. */\n approvalFraction: number;\n}\n\nexport type CouncilResolution =\n | {\n status: 'abstained';\n reason: 'quorum_not_met';\n validVoteCount: number;\n seatCount: number;\n }\n | {\n status: 'denied';\n method: 'veto';\n optionId: string;\n seatId: string;\n }\n | {\n status: 'denied';\n method: 'refusal';\n optionId: string;\n winningWeight: number;\n castWeight: number;\n }\n | {\n status: 'decided';\n method: 'majority';\n optionId: string;\n winningWeight: number;\n castWeight: number;\n }\n | {\n status: 'needs_judge';\n reason: 'tie' | 'approval_threshold_not_met';\n castWeight: number;\n };\n\n/** Resolve already-parsed council votes without performing any I/O. */\nexport function resolveCouncilVotes(input: CouncilResolutionInput): CouncilResolution {\n validateInput(input);\n\n const seatById = new Map(input.seats.map((seat) => [seat.id, seat] as const));\n const validVotes: CouncilResolutionVote[] = [];\n const votedSeatIds = new Set<string>();\n for (const vote of input.votes) {\n if (!seatById.has(vote.seatId) || votedSeatIds.has(vote.seatId)) continue;\n votedSeatIds.add(vote.seatId);\n validVotes.push(vote);\n }\n\n if (validVotes.length / input.seats.length < input.quorumFraction) {\n return {\n status: 'abstained',\n reason: 'quorum_not_met',\n validVoteCount: validVotes.length,\n seatCount: input.seats.length,\n };\n }\n\n const veto = validVotes.find(\n (vote) =>\n vote.optionId === input.refusalOptionId && seatById.get(vote.seatId)?.veto === true,\n );\n if (veto) {\n return {\n status: 'denied',\n method: 'veto',\n optionId: veto.optionId,\n seatId: veto.seatId,\n };\n }\n\n const weightByOption = new Map<string, number>();\n let castWeight = 0;\n for (const vote of validVotes) {\n const weight = seatById.get(vote.seatId)?.weight ?? 1;\n castWeight += weight;\n weightByOption.set(vote.optionId, (weightByOption.get(vote.optionId) ?? 0) + weight);\n }\n\n let winner: { optionId: string; weight: number } | undefined;\n let contested = false;\n for (const [optionId, weight] of weightByOption) {\n if (!winner || weight > winner.weight) {\n winner = { optionId, weight };\n contested = false;\n } else if (weight === winner.weight) {\n contested = true;\n }\n }\n\n const decisive =\n winner !== undefined &&\n !contested &&\n winner.weight > input.approvalFraction * castWeight;\n\n if (!decisive || !winner) {\n return {\n status: 'needs_judge',\n reason: contested ? 'tie' : 'approval_threshold_not_met',\n castWeight,\n };\n }\n\n if (winner.optionId === input.refusalOptionId) {\n return {\n status: 'denied',\n method: 'refusal',\n optionId: winner.optionId,\n winningWeight: winner.weight,\n castWeight,\n };\n }\n\n return {\n status: 'decided',\n method: 'majority',\n optionId: winner.optionId,\n winningWeight: winner.weight,\n castWeight,\n };\n}\n\nfunction validateInput(input: CouncilResolutionInput): void {\n if (input.seats.length === 0) {\n throw new Error('resolveCouncilVotes: at least one seat is required.');\n }\n requireFraction(input.quorumFraction, 'quorumFraction');\n requireFraction(input.approvalFraction, 'approvalFraction');\n\n const seatIds = new Set<string>();\n for (const seat of input.seats) {\n if (!seat.id.trim()) throw new Error('resolveCouncilVotes: seat id must not be empty.');\n if (seatIds.has(seat.id)) {\n throw new Error(`resolveCouncilVotes: duplicate seat id \"${seat.id}\".`);\n }\n seatIds.add(seat.id);\n if (seat.weight !== undefined && (!Number.isFinite(seat.weight) || seat.weight <= 0)) {\n throw new Error(`resolveCouncilVotes: invalid weight for seat \"${seat.id}\".`);\n }\n }\n}\n\nfunction requireFraction(value: number, label: string): void {\n if (!Number.isFinite(value) || value <= 0 || value > 1) {\n throw new Error(`resolveCouncilVotes: ${label} must be in (0, 1].`);\n }\n}\n", "import type {\n CouncilLLMCaller,\n CouncilModelTarget,\n CouncilQuestion,\n CouncilResult,\n CouncilUsage,\n CouncilVoteResult,\n ResolvedCouncilProfile,\n ResolvedCouncilSeat,\n} from '../types/council.js';\nimport type { OneShotLLMResult } from '../types/one-shot-llm.js';\nimport {\n DEFAULT_COUNCIL_PERSONA_REGISTRY,\n type CouncilPersonaRegistry,\n} from './council-personas.js';\nimport {\n DEFAULT_COUNCIL_PROFILE_REGISTRY,\n type CouncilProfileRegistry,\n resolveCouncilProfile,\n} from './council-profiles.js';\nimport {\n buildCouncilJudgeSystemPrompt,\n buildCouncilJudgeUserPrompt,\n buildCouncilVoterSystemPrompt,\n buildCouncilVoterUserPrompt,\n} from './council-prompts.js';\nimport { resolveCouncilVotes } from './council-resolution.js';\nimport type { FallbackProfileManager } from '../core/fallback-profile-manager.js';\nimport type { Config } from '../types/config.js';\n\n/** Synthetic ballot entry for \"refuse every real option\". */\nexport const COUNCIL_REFUSAL_OPTION_ID = 'council_refuse';\nexport const DEFAULT_COUNCIL_MAX_CONCURRENCY = 3;\nexport const MAX_COUNCIL_CONCURRENCY = 8;\n\nexport interface CouncilOrchestratorOptions {\n /**\n * Shared LLM caller used for every seat and the judge when no per-seat\n * caller is configured. Optional \u2014 supply `seatCaller` (per-seat callers)\n * and/or `judgeCaller` (separate judge caller) to route votes to different\n * providers. At least one of `caller`, `seatCaller`, or `judgeCaller`\n * must be provided; the constructor throws otherwise.\n */\n caller?: CouncilLLMCaller | undefined;\n personas?: CouncilPersonaRegistry | undefined;\n profiles?: CouncilProfileRegistry | undefined;\n defaultProfile?: string | undefined;\n maxConcurrency?: number | undefined;\n refusalOptionId?: string | undefined;\n /** Live config accessor for fallback profile resolution. */\n getConfig?: (() => Config) | undefined;\n /**\n * Shared live FallbackProfileManager \u2014 required for reliable fallback\n * profile pre-resolution. Pass the runtime container's manager.\n */\n fallbackProfileManager?: FallbackProfileManager | undefined;\n /**\n * Per-seat LLM caller factory. When set, each seat gets its own caller\n * instead of the shared `caller`. The factory receives (seatIndex) and\n * returns a CouncilLLMCaller. Used by Brain council arbitration where\n * each voter has its own Provider instance.\n */\n seatCaller?: ((seatIndex: number) => CouncilLLMCaller) | undefined;\n /**\n * Separate caller for the judge seat. Required when `seatCaller` is set\n * because the judge uses the shared caller path. When absent and\n * `seatCaller` is set, the judge falls back to `seatCaller(0)`.\n */\n judgeCaller?: CouncilLLMCaller | undefined;\n}\n\ninterface ParsedVote {\n optionId?: string | undefined;\n stance?: string | undefined;\n rationale?: string | undefined;\n}\n\ninterface ParsedJudge {\n optionId?: string | undefined;\n answer?: string | undefined;\n rationale?: string | undefined;\n}\n\ninterface UsageAccumulator {\n calls: number;\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n}\n\n/** Provider-neutral Council runner backed by an injected one-shot LLM caller. */\nexport class CouncilOrchestrator {\n private readonly caller: CouncilLLMCaller | undefined;\n private readonly personas: CouncilPersonaRegistry;\n private readonly profiles: CouncilProfileRegistry;\n private readonly defaultProfile: string | undefined;\n private readonly maxConcurrency: number;\n private readonly refusalOptionId: string;\n private readonly fallbackProfileManager: FallbackProfileManager | undefined;\n private readonly seatCaller: ((seatIndex: number) => CouncilLLMCaller) | undefined;\n private readonly judgeCaller: CouncilLLMCaller | undefined;\n\n constructor(opts: CouncilOrchestratorOptions) {\n if (!opts.caller && !opts.seatCaller && !opts.judgeCaller) {\n throw new Error(\n 'CouncilOrchestrator: provide `caller`, `seatCaller`, or `judgeCaller`.',\n );\n }\n this.caller = opts.caller;\n this.personas = opts.personas ?? DEFAULT_COUNCIL_PERSONA_REGISTRY;\n this.profiles = opts.profiles ?? DEFAULT_COUNCIL_PROFILE_REGISTRY;\n this.defaultProfile = opts.defaultProfile;\n this.maxConcurrency = validateConcurrency(\n opts.maxConcurrency ?? DEFAULT_COUNCIL_MAX_CONCURRENCY,\n );\n this.refusalOptionId = opts.refusalOptionId?.trim() || COUNCIL_REFUSAL_OPTION_ID;\n this.fallbackProfileManager = opts.fallbackProfileManager;\n this.seatCaller = opts.seatCaller;\n this.judgeCaller = opts.judgeCaller;\n }\n\n async ask(question: CouncilQuestion): Promise<CouncilResult> {\n const startedAt = Date.now();\n const profile = resolveCouncilProfile(question.profile, {\n registry: this.profiles,\n personas: this.personas,\n defaultProfile: this.defaultProfile,\n });\n validateRefusalCollision(question, this.refusalOptionId);\n\n const timeoutSignal = AbortSignal.timeout(profile.overallTimeoutMs);\n const signal = question.signal\n ? AbortSignal.any([question.signal, timeoutSignal])\n : timeoutSignal;\n const usage: UsageAccumulator = {\n calls: 0,\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n };\n\n const votes = await mapConcurrent(\n profile.seats,\n Math.min(this.maxConcurrency, profile.seats.length),\n async (seat, i) => {\n try {\n return await this.callSeat(question, profile, seat, i, signal, usage);\n } catch (error) {\n return {\n seatId: seat.id,\n persona: seat.persona,\n status: signal.aborted ? 'cancelled' : 'failed',\n error: errorMessage(error),\n } satisfies CouncilVoteResult;\n }\n },\n );\n const warnings = distinctnessWarnings(votes, profile);\n const errors = votes\n .filter((vote) => vote.status === 'failed' || vote.status === 'invalid')\n .map((vote) => `${vote.seatId}: ${vote.error ?? vote.status}`);\n\n if (question.signal?.aborted) {\n return resultEnvelope({\n status: 'cancelled',\n reason: 'Council call cancelled.',\n resolution: 'none',\n votes,\n profile,\n usage,\n startedAt,\n warnings,\n errors,\n });\n }\n if (timeoutSignal.aborted) {\n return resultEnvelope({\n status: 'failed',\n reason: 'Council overall timeout exceeded.',\n resolution: 'none',\n votes,\n profile,\n usage,\n startedAt,\n warnings,\n errors: [...errors, 'Council overall timeout exceeded.'],\n });\n }\n\n if (!question.options || question.options.length === 0) {\n return this.resolveOpenQuestion(\n question,\n profile,\n votes,\n signal,\n usage,\n startedAt,\n warnings,\n errors,\n );\n }\n return this.resolveOptionQuestion(\n question,\n profile,\n votes,\n signal,\n usage,\n startedAt,\n warnings,\n errors,\n );\n }\n\n private async callSeat(\n question: CouncilQuestion,\n profile: ResolvedCouncilProfile,\n seat: ResolvedCouncilSeat,\n seatIndex: number,\n signal: AbortSignal,\n usage: UsageAccumulator,\n ): Promise<CouncilVoteResult> {\n if (signal.aborted) return cancelledVote(seat);\n let persona;\n try {\n persona = this.personas.require(seat.persona);\n } catch (error) {\n return {\n seatId: seat.id,\n persona: seat.persona,\n status: 'failed',\n error: errorMessage(error),\n };\n }\n const result = await this.safeCall({\n system: buildCouncilVoterSystemPrompt(persona),\n userPrompt: buildCouncilVoterUserPrompt(question, seat, {\n refusalOptionId: question.options?.length ? this.refusalOptionId : undefined,\n }),\n target: seat.target,\n maxTokens: profile.voterMaxTokens,\n timeoutMs: profile.perCallTimeoutMs,\n signal,\n usage,\n seatIndex,\n });\n\n const metadata = callMetadata(result);\n if (result.error) {\n return {\n seatId: seat.id,\n persona: seat.persona,\n status: signal.aborted ? 'cancelled' : 'failed',\n ...metadata,\n error: result.error,\n };\n }\n const parsed = parseVote(result.text, question, this.refusalOptionId);\n if (!parsed.ok) {\n return {\n seatId: seat.id,\n persona: seat.persona,\n status: 'invalid',\n ...metadata,\n error: parsed.error,\n };\n }\n return {\n seatId: seat.id,\n persona: seat.persona,\n status: 'valid',\n ...parsed.vote,\n ...metadata,\n };\n }\n\n private async resolveOptionQuestion(\n question: CouncilQuestion,\n profile: ResolvedCouncilProfile,\n votes: CouncilVoteResult[],\n signal: AbortSignal,\n usage: UsageAccumulator,\n startedAt: number,\n warnings: string[],\n errors: string[],\n ): Promise<CouncilResult> {\n const validVotes = votes.filter(\n (vote): vote is CouncilVoteResult & { optionId: string } =>\n vote.status === 'valid' && typeof vote.optionId === 'string',\n );\n const resolution = resolveCouncilVotes({\n seats: profile.seats.map((seat) => ({\n id: seat.id,\n weight: seat.weight,\n veto: seat.veto,\n })),\n votes: validVotes.map((vote) => ({ seatId: vote.seatId, optionId: vote.optionId })),\n refusalOptionId: this.refusalOptionId,\n quorumFraction: profile.quorumFraction,\n approvalFraction: profile.approvalFraction,\n });\n\n if (resolution.status === 'abstained') {\n return resultEnvelope({\n status: 'abstained',\n reason: 'Council quorum was not met.',\n resolution: 'none',\n votes,\n profile,\n usage,\n startedAt,\n warnings,\n errors,\n });\n }\n if (resolution.status === 'denied') {\n return resultEnvelope({\n status: 'denied',\n optionId: resolution.optionId,\n reason: `Council denied the proposal via ${resolution.method}.`,\n resolution: resolution.method,\n votes,\n profile,\n usage,\n startedAt,\n warnings,\n errors,\n });\n }\n if (resolution.status === 'decided') {\n return resultEnvelope({\n status: 'decided',\n optionId: resolution.optionId,\n answer: optionLabel(question, resolution.optionId),\n resolution: 'majority',\n votes,\n profile,\n usage,\n startedAt,\n warnings,\n errors,\n });\n }\n if (!profile.judge) {\n return resultEnvelope({\n status: 'abstained',\n reason: `Council requires a judge (${resolution.reason}), but this profile has none.`,\n resolution: 'none',\n votes,\n profile,\n usage,\n startedAt,\n warnings,\n errors,\n });\n }\n\n const judged = await this.callJudge(\n question,\n profile,\n votes,\n profile.judge,\n resolution.reason,\n signal,\n usage,\n );\n if (!judged.ok) {\n return resultEnvelope({\n status: signal.aborted ? 'cancelled' : 'abstained',\n reason: judged.error,\n resolution: 'none',\n votes,\n profile,\n usage,\n startedAt,\n warnings,\n errors: [...errors, judged.error],\n judgeUsed: true,\n });\n }\n if (judged.value.optionId === this.refusalOptionId) {\n return resultEnvelope({\n status: 'denied',\n optionId: this.refusalOptionId,\n reason: judged.value.rationale ?? 'Council judge refused all options.',\n resolution: 'judge',\n votes,\n profile,\n usage,\n startedAt,\n warnings,\n errors,\n judgeUsed: true,\n });\n }\n return resultEnvelope({\n status: 'decided',\n optionId: judged.value.optionId,\n answer: optionLabel(question, judged.value.optionId),\n reason: judged.value.rationale,\n resolution: 'judge',\n votes,\n profile,\n usage,\n startedAt,\n warnings,\n errors,\n judgeUsed: true,\n });\n }\n\n private async resolveOpenQuestion(\n question: CouncilQuestion,\n profile: ResolvedCouncilProfile,\n votes: CouncilVoteResult[],\n signal: AbortSignal,\n usage: UsageAccumulator,\n startedAt: number,\n warnings: string[],\n errors: string[],\n ): Promise<CouncilResult> {\n const valid = votes.filter(\n (vote): vote is CouncilVoteResult & { stance: string } =>\n vote.status === 'valid' && typeof vote.stance === 'string',\n );\n if (valid.length / profile.seats.length < profile.quorumFraction) {\n return resultEnvelope({\n status: 'abstained',\n reason: 'Council quorum was not met.',\n resolution: 'none',\n votes,\n profile,\n usage,\n startedAt,\n warnings,\n errors,\n });\n }\n if (!profile.judge) {\n const first = valid[0];\n if (!first) {\n return resultEnvelope({\n status: 'failed',\n reason: 'Council produced no valid stance.',\n resolution: 'none',\n votes,\n profile,\n usage,\n startedAt,\n warnings,\n errors,\n });\n }\n return resultEnvelope({\n status: 'decided',\n answer: first.stance,\n reason: first.rationale,\n resolution: 'first_stance',\n votes,\n profile,\n usage,\n startedAt,\n warnings,\n errors,\n });\n }\n\n const judged = await this.callJudge(\n question,\n profile,\n votes,\n profile.judge,\n 'open_question_synthesis',\n signal,\n usage,\n );\n if (!judged.ok) {\n return resultEnvelope({\n status: signal.aborted ? 'cancelled' : 'failed',\n reason: judged.error,\n resolution: 'none',\n votes,\n profile,\n usage,\n startedAt,\n warnings,\n errors: [...errors, judged.error],\n judgeUsed: true,\n });\n }\n return resultEnvelope({\n status: 'decided',\n answer: judged.value.answer,\n reason: judged.value.rationale,\n resolution: 'judge',\n votes,\n profile,\n usage,\n startedAt,\n warnings,\n errors,\n judgeUsed: true,\n });\n }\n\n private async callJudge(\n question: CouncilQuestion,\n profile: ResolvedCouncilProfile,\n votes: CouncilVoteResult[],\n target: CouncilModelTarget,\n reason: string,\n signal: AbortSignal,\n usage: UsageAccumulator,\n ): Promise<{ ok: true; value: ParsedJudge } | { ok: false; error: string }> {\n const result = await this.safeCall({\n system: buildCouncilJudgeSystemPrompt(),\n userPrompt: buildCouncilJudgeUserPrompt(question, votes, {\n reason,\n refusalOptionId: question.options?.length ? this.refusalOptionId : undefined,\n }),\n target,\n maxTokens: profile.judgeMaxTokens,\n timeoutMs: profile.perCallTimeoutMs,\n signal,\n usage,\n });\n if (result.error) return { ok: false, error: result.error };\n return parseJudge(result.text, question, this.refusalOptionId);\n }\n\n /**\n * Resolve the effective LLM caller for a call. Voter seats use\n * `seatCaller(seatIndex)` when wired. Judge seats (seatIndex undefined)\n * use `judgeCaller` if set, otherwise `seatCaller(0)` if set, otherwise\n * the shared `caller`.\n */\n private resolveCaller(seatIndex?: number): CouncilLLMCaller {\n if (seatIndex !== undefined && this.seatCaller) {\n return this.seatCaller(seatIndex);\n }\n if (this.judgeCaller) return this.judgeCaller;\n if (this.seatCaller) return this.seatCaller(0);\n // Shared caller \u2014 guaranteed present by the constructor invariant\n // (at least one of `caller` / `seatCaller` / `judgeCaller` is required).\n return this.caller as CouncilLLMCaller;\n }\n\n private async safeCall(input: {\n system: string;\n userPrompt: string;\n target?: CouncilModelTarget | undefined;\n maxTokens: number;\n timeoutMs: number;\n signal: AbortSignal;\n usage: UsageAccumulator;\n seatIndex?: number | undefined;\n }): Promise<OneShotLLMResult> {\n const effectiveCaller = this.resolveCaller(input.seatIndex);\n\n const resolvedTarget = this.resolveCouncilTarget(input.target);\n\n try {\n const result = await effectiveCaller.call({\n system: input.system,\n userPrompt: input.userPrompt,\n responseFormat: { type: 'json_object' },\n maxTokens: input.maxTokens,\n timeoutMs: input.timeoutMs,\n signal: input.signal,\n ...(resolvedTarget?.providerId ? { providerId: resolvedTarget.providerId } : {}),\n ...(resolvedTarget?.model ? { model: resolvedTarget.model } : {}),\n ...(resolvedTarget?.role ? { role: resolvedTarget.role } : {}),\n ...(resolvedTarget?.fallbackModels && resolvedTarget.fallbackModels.length > 0\n ? { fallbackModels: [...resolvedTarget.fallbackModels] }\n : {}),\n });\n addUsage(input.usage, result);\n return result;\n } catch (error) {\n input.usage.calls += 1;\n return emptyCallResult(errorMessage(error));\n }\n }\n\n /**\n * Resolve a CouncilModelTarget: pre-resolve fallbackProfile to fallbackModels\n * so the downstream caller only sees the resolved chain.\n */\n private resolveCouncilTarget(\n target?: CouncilModelTarget | undefined,\n ): CouncilModelTarget | undefined {\n if (!target) return undefined;\n if (!target.fallbackProfile) return target;\n\n const mgr = this.fallbackProfileManager;\n if (!mgr) return target;\n const chain = mgr.resolve(target.fallbackProfile);\n if (chain.length === 0) return target;\n\n // Combine profile-resolved chain with any explicit fallbackModels\n const combined = [\n ...chain.map((e) => `${e.providerId}/${e.model}`),\n ...(target.fallbackModels ?? []),\n ];\n // Deduplicate while preserving order\n const seen = new Set<string>();\n const deduped = combined.filter((ref) => {\n if (seen.has(ref)) return false;\n seen.add(ref);\n return true;\n });\n\n return {\n ...(target.providerId ? { providerId: target.providerId } : {}),\n ...(target.model ? { model: target.model } : {}),\n ...(target.role ? { role: target.role } : {}),\n fallbackModels: deduped,\n };\n }\n}\n\nfunction parseVote(\n text: string,\n question: CouncilQuestion,\n refusalOptionId: string,\n): { ok: true; vote: ParsedVote } | { ok: false; error: string } {\n const parsed = parseObject(text);\n if (!parsed.ok && (!question.options || question.options.length === 0)) {\n // Optionless: if JSON parsing fails, use the raw text as stance\n // (backward compat with old council-brain behavior).\n const fallback = text.trim();\n if (fallback) return { ok: true, vote: { stance: fallback } };\n return { ok: false, error: 'Voter returned an empty response.' };\n }\n if (!parsed.ok) return parsed;\n const rationale = optionalString(parsed.value['rationale']);\n if (question.options && question.options.length > 0) {\n const optionId = optionalString(parsed.value['optionId']);\n const allowed = new Set([...question.options.map((option) => option.id.trim()), refusalOptionId]);\n if (!optionId || !allowed.has(optionId)) {\n return { ok: false, error: 'Voter returned an unknown or missing optionId.' };\n }\n return { ok: true, vote: { optionId, ...(rationale ? { rationale } : {}) } };\n }\n const stance = optionalString(parsed.value['stance']);\n if (!stance) return { ok: false, error: 'Voter returned an empty or missing stance.' };\n return { ok: true, vote: { stance, ...(rationale ? { rationale } : {}) } };\n}\n\nfunction parseJudge(\n text: string,\n question: CouncilQuestion,\n refusalOptionId: string,\n): { ok: true; value: ParsedJudge } | { ok: false; error: string } {\n const parsed = parseObject(text);\n if (!parsed.ok && (!question.options || question.options.length === 0)) {\n // Optionless: if JSON parsing fails, use raw text as answer\n const fallback = text.trim();\n if (fallback) return { ok: true, value: { answer: fallback } };\n return { ok: false, error: 'Judge returned an empty response.' };\n }\n if (!parsed.ok) return parsed;\n const rationale = optionalString(parsed.value['rationale']);\n if (question.options && question.options.length > 0) {\n const optionId = optionalString(parsed.value['optionId']);\n const allowed = new Set([...question.options.map((option) => option.id.trim()), refusalOptionId]);\n if (!optionId || !allowed.has(optionId)) {\n return { ok: false, error: 'Judge returned an unknown or missing optionId.' };\n }\n return { ok: true, value: { optionId, ...(rationale ? { rationale } : {}) } };\n }\n const answer = optionalString(parsed.value['answer']);\n if (!answer) return { ok: false, error: 'Judge returned an empty or missing answer.' };\n return { ok: true, value: { answer, ...(rationale ? { rationale } : {}) } };\n}\n\nfunction parseObject(\n text: string,\n): { ok: true; value: Record<string, unknown> } | { ok: false; error: string } {\n const trimmed = text.trim();\n const first = trimmed.indexOf('{');\n const last = trimmed.lastIndexOf('}');\n if (first < 0 || last < first) return { ok: false, error: 'LLM response did not contain JSON.' };\n try {\n const value: unknown = JSON.parse(trimmed.slice(first, last + 1));\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return { ok: false, error: 'LLM response JSON must be an object.' };\n }\n return { ok: true, value: value as Record<string, unknown> };\n } catch (error) {\n return { ok: false, error: `Invalid LLM response JSON: ${errorMessage(error)}` };\n }\n}\n\nfunction resultEnvelope(input: {\n status: CouncilResult['status'];\n answer?: string | undefined;\n optionId?: string | undefined;\n reason?: string | undefined;\n resolution: CouncilResult['resolution'];\n votes: CouncilVoteResult[];\n profile: ResolvedCouncilProfile;\n usage: UsageAccumulator;\n startedAt: number;\n warnings: string[];\n errors: string[];\n judgeUsed?: boolean | undefined;\n}): CouncilResult {\n const validVoteCount = input.votes.filter((vote) => vote.status === 'valid').length;\n return {\n status: input.status,\n ...(input.answer ? { answer: input.answer } : {}),\n ...(input.optionId ? { optionId: input.optionId } : {}),\n ...(input.reason ? { reason: input.reason } : {}),\n resolution: input.resolution,\n votes: Object.freeze([...input.votes]),\n configuredSeatCount: input.profile.seats.length,\n validVoteCount,\n distinctTargetCount: distinctTargetCount(input.votes, input.profile),\n judgeUsed: input.judgeUsed ?? false,\n usage: usageResult(input.usage, input.startedAt),\n ...(input.warnings.length > 0 ? { warnings: Object.freeze([...input.warnings]) } : {}),\n ...(input.errors.length > 0 ? { errors: Object.freeze([...input.errors]) } : {}),\n };\n}\n\nfunction callMetadata(result: OneShotLLMResult): Omit<CouncilVoteResult, 'seatId' | 'persona' | 'status'> {\n return {\n ...(result.provider ? { provider: result.provider } : {}),\n ...(result.model ? { model: result.model } : {}),\n ...(result.fromFallback ? { fromFallback: true } : {}),\n durationMs: result.durationMs,\n };\n}\n\nfunction addUsage(usage: UsageAccumulator, result: OneShotLLMResult): void {\n usage.calls += 1;\n usage.inputTokens += result.tokens.input;\n usage.outputTokens += result.tokens.output;\n usage.totalTokens += result.tokens.total;\n}\n\nfunction usageResult(usage: UsageAccumulator, startedAt: number): CouncilUsage {\n return Object.freeze({ ...usage, durationMs: Math.max(0, Date.now() - startedAt) });\n}\n\nfunction cancelledVote(seat: ResolvedCouncilSeat): CouncilVoteResult {\n return { seatId: seat.id, persona: seat.persona, status: 'cancelled', error: 'Cancelled.' };\n}\n\nfunction distinctTargetCount(\n votes: readonly CouncilVoteResult[],\n profile: ResolvedCouncilProfile,\n): number {\n const keys = votes\n .filter((vote) => vote.status === 'valid')\n .map((vote) =>\n profile.distinctness === 'provider'\n ? vote.provider\n : `${vote.provider ?? ''}/${vote.model ?? ''}`,\n )\n .filter(Boolean);\n return new Set(keys).size;\n}\n\nfunction distinctnessWarnings(\n votes: readonly CouncilVoteResult[],\n profile: ResolvedCouncilProfile,\n): string[] {\n if (profile.distinctness === 'none') return [];\n const valid = votes.filter((vote) => vote.status === 'valid');\n const distinct = distinctTargetCount(valid, profile);\n if (valid.length > 1 && distinct < valid.length) {\n return [\n `Council distinctness policy \"${profile.distinctness}\" was not met: ${distinct} distinct target(s) served ${valid.length} valid vote(s).`,\n ];\n }\n return [];\n}\n\nfunction optionLabel(question: CouncilQuestion, optionId: string | undefined): string | undefined {\n if (!optionId) return undefined;\n return question.options?.find((option) => option.id.trim() === optionId)?.label.trim();\n}\n\nfunction validateRefusalCollision(question: CouncilQuestion, refusalOptionId: string): void {\n if (question.options?.some((option) => option.id.trim() === refusalOptionId)) {\n throw new Error(`CouncilOrchestrator: option id \"${refusalOptionId}\" is reserved.`);\n }\n}\n\nfunction validateConcurrency(value: number): number {\n if (!Number.isSafeInteger(value) || value <= 0 || value > MAX_COUNCIL_CONCURRENCY) {\n throw new Error(\n `CouncilOrchestrator: maxConcurrency must be an integer in [1, ${MAX_COUNCIL_CONCURRENCY}].`,\n );\n }\n return value;\n}\n\nasync function mapConcurrent<T, R>(\n items: readonly T[],\n concurrency: number,\n worker: (item: T, index: number) => Promise<R>,\n): Promise<R[]> {\n const results = new Array<R>(items.length);\n let next = 0;\n const run = async (): Promise<void> => {\n while (true) {\n const index = next++;\n if (index >= items.length) return;\n const item = items[index];\n if (item !== undefined) results[index] = await worker(item, index);\n }\n };\n await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => run()));\n return results;\n}\n\nfunction emptyCallResult(error: string): OneShotLLMResult {\n return {\n text: '',\n model: '',\n provider: '',\n tokens: { input: 0, output: 0, total: 0 },\n durationMs: 0,\n fromFallback: false,\n error,\n };\n}\n\nfunction optionalString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n", "/**\n * CouncilBrainArbiter \u2014 a multi-LLM decision panel for high-stakes questions.\n *\n * A thin adapter over CouncilOrchestrator. Each CouncilVoter becomes a seat\n * with its OWN Provider via per-seat CouncilLLMCaller, so multi-provider\n * panels work correctly (no voters[0] collapsing).\n *\n * Decision lenses (personas):\n * - executor \u2014 biased toward forward progress; hates stalling.\n * - skeptic \u2014 hunts for the reason the proposed action is wrong; may veto.\n * - auditor \u2014 cost/waste/budget lens; hates throwing tokens at dead ends.\n * - security \u2014 examines trust boundaries, abuse cases, security impact.\n * - maintainer \u2014 evaluates complexity, compatibility, long-term ownership.\n * - user-advocate \u2014 evaluates from the affected user's perspective.\n *\n * @module council-brain\n */\n\nimport type {\n BrainArbiter,\n BrainDecision,\n BrainDecisionRequest,\n} from '../coordination/brain.js';\nimport {\n completeBrainLlmDetailed,\n type BrainLlmTarget,\n} from './autonomy-brain.js';\nimport type { EventBus } from '../kernel/events.js';\nimport { CouncilOrchestrator } from './council-orchestrator.js';\nimport type { CouncilLLMCaller, CouncilModelTarget, CouncilProfileConfig, CouncilSeatConfig } from '../types/council.js';\nimport type { OneShotLLMInput, OneShotLLMResult } from '../types/one-shot-llm.js';\nimport type { Provider } from '../types/provider.js';\n\n/**\n * Refusal option id used by the Brain adapter. Re-exported from the\n * orchestrator so both layers share a single source of truth.\n */\nexport { COUNCIL_REFUSAL_OPTION_ID as COUNCIL_REFUSE_OPTION_ID } from './council-orchestrator.js';\n\n// \u2500\u2500 Config \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 voting seat on the council. */\nexport interface CouncilVoter {\n /** Provider instance this voter uses. */\n provider: Provider;\n /** Model id this voter uses. */\n model: string;\n /**\n * Decision lens. Built-ins: 'executor', 'skeptic', 'auditor'. Any other\n * string is injected verbatim as the persona description.\n */\n persona?: string | undefined;\n /** Vote weight. Default 1. */\n weight?: number | undefined;\n /** A refusal from this seat immediately denies the proposal. */\n veto?: boolean | undefined;\n /** Display label for status/logs. Defaults to model. */\n label?: string | undefined;\n}\n\nexport interface CouncilBrainOptions {\n voters: CouncilVoter[];\n /** Tie-breaker / synthesizer. Default: none (ties call for human). */\n judge?: CouncilVoter | undefined;\n /** Fraction of voters that must vote. Default 0.5. */\n quorumFraction?: number | undefined;\n /** Winning option weight must exceed this fraction. Default 0.5. */\n approvalFraction?: number | undefined;\n /** Per-voter completion timeout in ms. Default 15 000. */\n decisionTimeoutMs?: number | undefined;\n /** Seats polled concurrently, 1..8. Default 3 (the orchestrator's default). */\n maxConcurrency?: number | undefined;\n /** Panel-diversity warning policy. Default 'none'. */\n distinctness?: 'none' | 'model' | 'provider' | undefined;\n /** Output budget for the judge call. */\n judgeMaxTokens?: number | undefined;\n /** Optional digest of past decisions for context. */\n getDecisionDigest?: ((request: BrainDecisionRequest) => string | undefined) | undefined;\n /**\n * Bus for per-seat vote and resolution trace events. Optional: the council\n * decides identically without it, but nothing downstream can reconstruct\n * HOW a panel reached its verdict.\n */\n events?: EventBus | undefined;\n /**\n * Include vote rationales / stances / reasons in the emitted trace events.\n * Off by default \u2014 this is production decision content.\n */\n traceContent?: boolean | undefined;\n}\n\n// \u2500\u2500 Factory \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * Create a council-of-LLMs Brain arbiter backed by CouncilOrchestrator\n * with per-seat LLM callers \u2014 each voter's own Provider is used for its\n * seat, avoiding the single-provider collapsing bug.\n */\nexport function createCouncilBrainArbiter(opts: CouncilBrainOptions): BrainArbiter {\n if (opts.voters.length === 0) {\n throw new Error('createCouncilBrainArbiter: at least one voter is required.');\n }\n\n // \u2500\u2500 Per-seat caller factory \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 // Each seat i gets a caller wrapping completeBrainLlm(voter[i], ...).\n function makeSeatCallerForVoter(target: BrainLlmTarget): CouncilLLMCaller {\n return {\n async call(input: OneShotLLMInput): Promise<OneShotLLMResult> {\n const startedAt = Date.now();\n try {\n const result = await completeBrainLlmDetailed(\n { provider: target.provider, model: input.model ?? target.model },\n {\n system: typeof input.system === 'string'\n ? input.system\n : Array.isArray(input.system)\n ? input.system.map((b) => b.text).join('\\n')\n : '',\n user: input.userPrompt ?? '',\n timeoutMs: input.timeoutMs ?? 15_000,\n maxTokens: input.maxTokens,\n },\n );\n // Real usage and timing \u2014 these used to be hardcoded zeros, which\n // made `CouncilResult.usage` (and therefore the cost of every\n // council decision) permanently report 0 tokens.\n const inputTokens = result.usage?.input ?? 0;\n const outputTokens = result.usage?.output ?? 0;\n return {\n text: result.text,\n model: target.model,\n provider: target.provider.id,\n tokens: {\n input: inputTokens,\n output: outputTokens,\n total: inputTokens + outputTokens,\n },\n durationMs: Date.now() - startedAt,\n fromFallback: false,\n };\n } catch (error) {\n return {\n text: '',\n model: target.model,\n provider: target.provider.id,\n tokens: { input: 0, output: 0, total: 0 },\n durationMs: 0,\n fromFallback: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n },\n };\n }\n\n const seatCaller = (seatIndex: number): CouncilLLMCaller => {\n const voter = opts.voters[seatIndex];\n if (!voter) {\n return {\n async call(_input: OneShotLLMInput): Promise<OneShotLLMResult> {\n return {\n text: '',\n model: '',\n provider: '',\n tokens: { input: 0, output: 0, total: 0 },\n durationMs: 0,\n fromFallback: false,\n error: `No voter at index ${seatIndex}.`,\n };\n },\n };\n }\n return makeSeatCallerForVoter(voter);\n };\n\n // \u2500\u2500 Build a dynamic profile from voters \u2500\u2500\u2500\u2500\u2500\u2500\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 const seats: CouncilSeatConfig[] = opts.voters.map((voter, i) => ({\n id: `voter-${i}`,\n label: voter.label ?? voter.model,\n persona: voter.persona ?? 'executor',\n target: {\n providerId: voter.provider.id,\n model: voter.model,\n role: voter.persona ?? 'executor',\n } satisfies CouncilModelTarget,\n weight: voter.weight,\n veto: voter.veto,\n }));\n\n const judgeTarget = opts.judge\n ? ({\n providerId: opts.judge.provider.id,\n model: opts.judge.model,\n role: 'judge',\n } satisfies CouncilModelTarget)\n : false;\n\n const profile: CouncilProfileConfig = {\n id: 'brain-council-adapter',\n seats,\n judge: judgeTarget,\n quorumFraction: opts.quorumFraction ?? 0.5,\n approvalFraction: opts.approvalFraction ?? 0.5,\n perCallTimeoutMs: opts.decisionTimeoutMs ?? 15_000,\n ...(opts.judgeMaxTokens !== undefined ? { judgeMaxTokens: opts.judgeMaxTokens } : {}),\n distinctness: opts.distinctness ?? 'none',\n };\n\n // \u2500\u2500 Orchestrator with per-seat callers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 const orchestrator = new CouncilOrchestrator({\n defaultProfile: 'brain-council-adapter',\n // Previously never passed, so the panel was pinned at the orchestrator's\n // default of 3 concurrent seats no matter how many voters were configured.\n ...(opts.maxConcurrency !== undefined ? { maxConcurrency: opts.maxConcurrency } : {}),\n seatCaller,\n judgeCaller: opts.judge\n ? makeSeatCallerForVoter(opts.judge)\n : undefined,\n });\n\n const abstain = (request: BrainDecisionRequest, why: string): BrainDecision => ({\n type: 'ask_human',\n prompt: `Council abstained (${why}): ${request.question}`,\n options: request.options,\n rationale: `Temporary user escalation because ${why}.`,\n });\n\n // \u2500\u2500 Decide \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 return {\n async decide(request: BrainDecisionRequest): Promise<BrainDecision> {\n const digest = opts.getDecisionDigest?.(request);\n\n const question = {\n question: request.question,\n context: digest\n ? `${request.context ?? ''}\\n\\nPrevious decisions:\\n${digest}`\n : request.context,\n ...(request.options ? { options: request.options } : {}),\n profile: profile satisfies CouncilProfileConfig,\n };\n\n const result = await orchestrator.ask(question);\n\n // \u2500\u2500 Trace \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 // `CouncilResult` already carries every seat's observable vote, the\n // quorum counts, judge usage and token usage; the adapter used to\n // discard all of it and surface only the verdict. Re-emitting it here\n // needs no orchestrator changes and is what makes a council decision\n // reconstructable.\n if (opts.events) {\n const at = Date.now();\n for (const vote of result.votes) {\n const seat = seats.find((s) => s.id === vote.seatId);\n opts.events.emit('brain.council_vote', {\n sessionId: request.sessionId,\n requestId: request.id,\n seatId: vote.seatId,\n persona: vote.persona,\n status: vote.status,\n providerId: vote.provider,\n model: vote.model,\n optionId: vote.optionId,\n ...(opts.traceContent\n ? { stance: vote.stance, rationale: vote.rationale }\n : {}),\n weight: seat?.weight,\n veto: seat?.veto,\n durationMs: vote.durationMs,\n error: vote.error,\n at,\n });\n }\n opts.events.emit('brain.council_resolved', {\n sessionId: request.sessionId,\n requestId: request.id,\n status: result.status,\n resolution: result.resolution,\n optionId: result.optionId,\n configuredSeatCount: result.configuredSeatCount,\n validVoteCount: result.validVoteCount,\n distinctTargetCount: result.distinctTargetCount,\n judgeUsed: result.judgeUsed,\n usage: result.usage,\n // Structural, not content \u2014 always emitted. See the event docs:\n // a correlated panel is the one council failure mode that produces\n // a perfectly normal-looking verdict.\n ...(result.warnings?.length ? { warnings: [...result.warnings] } : {}),\n ...(opts.traceContent ? { reason: result.reason } : {}),\n at,\n });\n }\n\n // Handle failures and cancellations\n if (result.status === 'cancelled' || result.status === 'failed') {\n return abstain(request, result.reason ?? result.errors?.[0] ?? 'council error');\n }\n\n if (result.status === 'abstained') {\n return abstain(request, result.reason ?? 'no consensus');\n }\n\n if (result.status === 'denied') {\n return {\n type: 'deny',\n reason: result.reason ?? `Council (${result.resolution})`,\n };\n }\n\n // Decided\n if (request.options && request.options.length > 0) {\n // Option-bearing: pick the winning option\n const winningOption = request.options.find((o) => o.id === result.optionId);\n return {\n type: 'answer',\n ...(winningOption ? { optionId: result.optionId } : {}),\n text: winningOption?.label ?? result.answer ?? 'Council decided.',\n rationale: result.reason ?? `Council (${result.resolution})`,\n };\n }\n\n // Optionless: use the council's synthesized answer\n return {\n type: 'answer',\n text: result.answer ?? 'Council decided.',\n rationale: result.reason ?? `Council (${result.resolution})`,\n };\n },\n };\n}\n", "/**\n * Brain tier assembly \u2014 turns `Config.brain` into the concrete LLM tiers\n * (single-LLM pool + optional multi-LLM council) that\n * `createTieredBrainArbiter` composes. Shared by every host that wires a\n * Brain (CLI/TUI in `wiring/brain-and-orchestration.ts`, the standalone\n * WebUI server in `backend-services.ts`) so the config surface behaves\n * identically everywhere.\n *\n * Hosts differ only in HOW a provider id becomes a `Provider` instance, so\n * that is the one injected dependency (`resolveProvider`). Unresolvable\n * pool/council entries are skipped \u2014 one bad ref never takes the Brain down.\n *\n * @module brain-chain\n */\n\nimport type { BrainArbiter, BrainDecisionRequest } from '../coordination/brain.js';\nimport type { EventBus } from '../kernel/events.js';\nimport { parseModelRef } from '../core/fallback-model.js';\nimport type { BrainConfig, BrainModelEntry } from '../types/config.js';\nimport type { Provider } from '../types/provider.js';\nimport { type BrainLlmTarget, createAutonomyBrain } from './autonomy-brain.js';\nimport type { BrainCircuitBreaker } from './brain-circuit.js';\nimport { type CouncilVoter, createCouncilBrainArbiter } from './council-brain.js';\n\n/** Default council seats, assigned in order to voters without a persona. */\nconst DEFAULT_SEATS: ReadonlyArray<Pick<CouncilVoter, 'persona' | 'veto'>> = [\n { persona: 'executor' },\n { persona: 'skeptic', veto: true },\n { persona: 'auditor' },\n];\n\n/** Seat rotation for voters without an explicit persona (config may replace it). */\nfunction resolveSeats(\n configured: BrainConfig['council'] extends infer C\n ? C extends { seats?: infer S }\n ? S\n : never\n : never,\n): ReadonlyArray<Pick<CouncilVoter, 'persona' | 'veto'>> {\n const seats = configured as Array<{ persona: string; veto?: boolean }> | undefined;\n if (!seats?.length) return DEFAULT_SEATS;\n return seats.map((seat) => ({ persona: seat.persona, veto: seat.veto }));\n}\n\nexport interface BrainTierAssemblyOptions {\n /** `config.brain` \u2014 undefined assembles the legacy session-model single tier. */\n brainConfig: BrainConfig | undefined;\n /** The session's provider id (`config.provider`). */\n defaultProviderId: string;\n /** Live session provider \u2014 read per decision so `/setmodel` switches apply. */\n sessionProvider: () => Provider;\n /** Live session model id \u2014 read per decision. */\n sessionModel: () => string;\n /**\n * Resolve a NON-default provider id to a Provider instance. May throw or\n * return null; the entry is then skipped.\n */\n resolveProvider: (providerId: string, model: string) => Provider | null;\n /**\n * Decision-history digest (typically `BrainDecisionLedger.digestFor`) \u2014\n * injected into both the single-LLM and council prompts so the Brain\n * learns from the outcomes of its past similar decisions.\n */\n getDecisionDigest?: ((request: BrainDecisionRequest) => string | undefined) | undefined;\n /** Bus for `brain.llm_call` / `brain.council_*` trace events. */\n events?: EventBus | undefined;\n /** Include free text in trace events. Mirrors `brain.trace.content === 'full'`. */\n traceContent?: boolean | undefined;\n /** Failure memory shared by every decision the single-LLM tier makes. */\n circuit?: BrainCircuitBreaker | undefined;\n}\n\nexport interface BrainTierAssembly {\n /** Single-LLM tier for `TieredBrainArbiterOptions.autonomous`. */\n autonomous: BrainArbiter;\n /** Council tier for `TieredBrainArbiterOptions.council` (undefined = disabled). */\n council: BrainArbiter | undefined;\n /** Live council risk floor for `TieredBrainArbiterOptions.getCouncilMinRisk`. */\n getCouncilMinRisk: () => 'medium' | 'high' | 'critical';\n /** Human-readable pool labels for status surfaces; empty = session model. */\n poolLabels: string[];\n /** Human-readable council seat labels; empty = council disabled. */\n councilLabels: string[];\n /**\n * EFFECTIVE judge label \u2014 undefined when no council is wired.\n *\n * Distinct from the CONFIGURED judge (`council.judge`), which is usually\n * absent: the judge is then derived, and whether the derived one is\n * independent of the seated voters is not something any surface could\n * previously observe.\n */\n judgeLabel: string | undefined;\n /**\n * True when the effective judge is ALSO one of the seated voters \u2014 i.e. the\n * tie-breaker already cast one of the tied votes.\n *\n * Computed here, from the real voter list, rather than left to each surface\n * to infer by string-matching `judgeLabel` against `councilLabels`: those\n * are display strings (`\"<label> (<persona>, veto)\"`), and three independent\n * re-parses of a rendering format is exactly how surfaces drift apart.\n */\n judgeIsVoter: boolean;\n}\n\n/** Assemble the LLM tiers of the Brain chain from `Config.brain`. */\nexport function assembleBrainTiers(opts: BrainTierAssemblyOptions): BrainTierAssembly {\n const brainCfg = opts.brainConfig;\n\n const toEntry = (entry: string | BrainModelEntry): BrainModelEntry =>\n typeof entry === 'string' ? (parseModelRef(entry) as BrainModelEntry) : entry;\n const buildTarget = (entry: BrainModelEntry): BrainLlmTarget | null => {\n if (!entry.model) return null;\n const providerId = entry.provider ?? opts.defaultProviderId;\n try {\n const provider =\n providerId === opts.defaultProviderId\n ? opts.sessionProvider()\n : opts.resolveProvider(providerId, entry.model);\n if (!provider) return null;\n return { provider, model: entry.model, label: `${providerId}/${entry.model}` };\n } catch {\n return null;\n }\n };\n\n const poolTargets = (brainCfg?.models ?? [])\n .map(toEntry)\n .map(buildTarget)\n .filter((t): t is BrainLlmTarget => t !== null);\n\n // Single-LLM tier. With a configured pool the arbiter is constructed once\n // (round-robin cursor + fallback order persist across decisions); without\n // one it is built per decision so live provider/model switches apply.\n const autonomous: BrainArbiter =\n poolTargets.length > 0\n ? createAutonomyBrain({\n targets: poolTargets,\n strategy: brainCfg?.strategy ?? 'fallback',\n maxAutoRisk: 'all', // the tiered ceiling gates risk \u2014 keep inner permissive\n decisionTimeoutMs: brainCfg?.decisionTimeoutMs,\n heuristics: brainCfg?.heuristics,\n getDecisionDigest: opts.getDecisionDigest,\n events: opts.events,\n traceContent: opts.traceContent,\n maxTokens: brainCfg?.llm?.maxTokens,\n rejectUncertain: brainCfg?.llm?.rejectUncertain,\n minConfidence: brainCfg?.llm?.minConfidence,\n circuit: opts.circuit,\n })\n : {\n decide: (request) =>\n createAutonomyBrain({\n provider: opts.sessionProvider(),\n model: opts.sessionModel(),\n maxAutoRisk: 'all',\n decisionTimeoutMs: brainCfg?.decisionTimeoutMs,\n heuristics: brainCfg?.heuristics,\n getDecisionDigest: opts.getDecisionDigest,\n events: opts.events,\n traceContent: opts.traceContent,\n maxTokens: brainCfg?.llm?.maxTokens,\n rejectUncertain: brainCfg?.llm?.rejectUncertain,\n minConfidence: brainCfg?.llm?.minConfidence,\n circuit: opts.circuit,\n }).decide(request),\n };\n\n // Council tier \u2014 seats come from explicit `brain.council.voters` or are\n // derived from the pool (first 3 models, default personas).\n const councilCfg = brainCfg?.council;\n const SEATS = resolveSeats(councilCfg?.seats);\n const explicitVoters = (councilCfg?.voters ?? []).map((v) =>\n typeof v === 'string' ? { entry: toEntry(v), cfg: {} as Partial<CouncilVoter> } : { entry: v, cfg: v },\n );\n const voters: CouncilVoter[] = (\n explicitVoters.length > 0\n ? explicitVoters.map(({ entry, cfg }, i) => {\n const target = buildTarget(entry);\n if (!target) return null;\n const seat = SEATS[i % SEATS.length];\n return {\n ...target,\n persona: cfg.persona ?? seat?.persona,\n weight: cfg.weight,\n veto: cfg.veto ?? seat?.veto,\n } satisfies CouncilVoter;\n })\n : poolTargets.slice(0, SEATS.length).map((target, i) => ({\n ...target,\n ...SEATS[i % SEATS.length],\n }))\n ).filter((v): v is CouncilVoter => v !== null);\n\n const judgeEntry = councilCfg?.judge\n ? typeof councilCfg.judge === 'string'\n ? toEntry(councilCfg.judge)\n : councilCfg.judge\n : undefined;\n // An explicitly configured judge always wins. Otherwise prefer a pool target\n // that is NOT already seated: the judge only runs to break a tie or\n // synthesize a split panel, and a \"tie-breaker\" that already cast one of the\n // tied votes is not an independent opinion \u2014 it re-states its own position\n // with the deciding weight. `poolTargets[0]` was the previous default and is\n // exactly the model that becomes voter #1 whenever seats are derived from\n // the pool, so the old default made the judge a seated voter in every\n // auto-derived council. With no unseated target left (pool size == seat\n // count) it still falls back to the old behaviour, and the distinctness\n // warning now reports the correlation instead of hiding it.\n const seatedLabels = new Set(voters.map((v) => v.label ?? v.model));\n const judge =\n (judgeEntry ? buildTarget(judgeEntry) : null) ??\n poolTargets.find((t) => !seatedLabels.has(t.label ?? t.model)) ??\n poolTargets[0] ??\n voters[0];\n const councilEnabled = councilCfg?.enabled ?? voters.length >= 2;\n const council =\n councilEnabled && voters.length >= 2\n ? createCouncilBrainArbiter({\n voters,\n judge,\n quorumFraction: councilCfg?.quorum,\n approvalFraction: councilCfg?.approval,\n decisionTimeoutMs: councilCfg?.perCallTimeoutMs ?? brainCfg?.decisionTimeoutMs,\n maxConcurrency: councilCfg?.maxConcurrency,\n distinctness: councilCfg?.distinctness,\n judgeMaxTokens: councilCfg?.judgeMaxTokens,\n getDecisionDigest: opts.getDecisionDigest,\n events: opts.events,\n traceContent: opts.traceContent,\n })\n : undefined;\n\n return {\n autonomous,\n council,\n getCouncilMinRisk: () => councilCfg?.minRisk ?? 'high',\n poolLabels: poolTargets.map((t) => t.label ?? t.model),\n councilLabels: council\n ? voters.map((v) => `${v.label ?? v.model} (${v.persona ?? 'voter'}${v.veto ? ', veto' : ''})`)\n : [],\n judgeLabel: council ? (judge?.label ?? judge?.model) : undefined,\n judgeIsVoter:\n council !== undefined && judge !== undefined && seatedLabels.has(judge.label ?? judge.model),\n };\n}\n", "import type { BrainArbiter, BrainDecision, BrainDecisionRequest } from '../coordination/brain.js';\nimport type { BrainTraceRecord } from '../coordination/brain-trace.js';\n\nexport const BRAIN_EVALUATION_CASE_VERSION = 1 as const;\n\nexport interface BrainEvaluationExpectations {\n /** Restrict the accepted decision variants for this case. */\n allowedDecisionTypes?: BrainDecision['type'][] | undefined;\n /** Exact option ids that may be selected. Every id must exist in the request. */\n allowedOptionIds?: string[] | undefined;\n /** Options that represent an unsafe allowance and must fail the case. */\n unsafeOptionIds?: string[] | undefined;\n /** Require an answer to carry an exact option id. */\n requireOptionId?: boolean | undefined;\n /** Whether ask_human is acceptable rather than an unnecessary escalation. */\n allowEscalation?: boolean | undefined;\n}\n\n/** Versioned, JSON-serializable fixture for side-effect-free Brain evaluation. */\nexport interface BrainEvaluationCaseV1 {\n version: typeof BRAIN_EVALUATION_CASE_VERSION;\n id: string;\n description?: string | undefined;\n request: BrainDecisionRequest;\n expectations?: BrainEvaluationExpectations | undefined;\n}\n\nexport type BrainEvaluationFailureCode =\n | 'invalid_fixture'\n | 'arbiter_error'\n | 'unexpected_decision_type'\n | 'invalid_option_id'\n | 'missing_option_id'\n | 'disallowed_option_id'\n | 'unsafe_option_id'\n | 'unexpected_escalation';\n\nexport interface BrainEvaluationFailure {\n code: BrainEvaluationFailureCode;\n message: string;\n}\n\nexport interface BrainEvaluationCaseResult {\n caseId: string;\n passed: boolean;\n decision?: BrainDecision | undefined;\n failures: BrainEvaluationFailure[];\n latencyMs: number;\n}\n\nexport interface BrainEvaluationMetrics {\n totalCases: number;\n passedCases: number;\n failedCases: number;\n optionDecisionCount: number;\n invalidOptionCount: number;\n validOptionRate: number;\n unsafeAllowanceCount: number;\n unnecessaryEscalationCount: number;\n averageLatencyMs: number;\n}\n\nexport interface BrainEvaluationReport {\n version: typeof BRAIN_EVALUATION_CASE_VERSION;\n results: BrainEvaluationCaseResult[];\n metrics: BrainEvaluationMetrics;\n}\n\nexport type BrainEvaluationCaseValidation =\n | { ok: true; value: BrainEvaluationCaseV1 }\n | { ok: false; diagnostics: string[] };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((entry) => typeof entry === 'string');\n}\n\n/** Validate a fixture loaded from JSON before any arbiter is invoked. */\nexport function validateBrainEvaluationCase(value: unknown): BrainEvaluationCaseValidation {\n const diagnostics: string[] = [];\n if (!isRecord(value)) return { ok: false, diagnostics: ['case must be an object'] };\n if (value['version'] !== BRAIN_EVALUATION_CASE_VERSION) {\n diagnostics.push(`version must be ${BRAIN_EVALUATION_CASE_VERSION}`);\n }\n if (typeof value['id'] !== 'string' || value['id'].trim().length === 0) {\n diagnostics.push('id must be a non-empty string');\n }\n\n const request = value['request'];\n if (!isRecord(request)) {\n diagnostics.push('request must be an object');\n } else {\n if (typeof request['id'] !== 'string' || request['id'].trim().length === 0) {\n diagnostics.push('request.id must be a non-empty string');\n }\n if (!['goal', 'director', 'tool', 'user', 'system'].includes(String(request['source']))) {\n diagnostics.push('request.source is invalid');\n }\n if (typeof request['question'] !== 'string' || request['question'].trim().length === 0) {\n diagnostics.push('request.question must be a non-empty string');\n }\n if (!['low', 'medium', 'high', 'critical'].includes(String(request['risk']))) {\n diagnostics.push('request.risk is invalid');\n }\n if (!['ask_human', 'deny', 'continue'].includes(String(request['fallback']))) {\n diagnostics.push('request.fallback is invalid');\n }\n if (request['options'] !== undefined) {\n if (!Array.isArray(request['options'])) {\n diagnostics.push('request.options must be an array');\n } else {\n const ids = new Set<string>();\n for (const [index, option] of request['options'].entries()) {\n if (!isRecord(option)) {\n diagnostics.push(`request.options[${index}] must be an object`);\n continue;\n }\n const id = option['id'];\n if (typeof id !== 'string' || id.trim().length === 0) {\n diagnostics.push(`request.options[${index}].id must be a non-empty string`);\n } else if (ids.has(id)) {\n diagnostics.push(`request option id \"${id}\" is duplicated`);\n } else {\n ids.add(id);\n }\n if (typeof option['label'] !== 'string' || option['label'].trim().length === 0) {\n diagnostics.push(`request.options[${index}].label must be a non-empty string`);\n }\n }\n }\n }\n }\n\n const expectations = value['expectations'];\n if (expectations !== undefined && !isRecord(expectations)) {\n diagnostics.push('expectations must be an object');\n } else if (isRecord(expectations)) {\n const allowedTypes = expectations['allowedDecisionTypes'];\n if (\n allowedTypes !== undefined &&\n (!isStringArray(allowedTypes) ||\n allowedTypes.length === 0 ||\n allowedTypes.some((entry) => !['answer', 'ask_human', 'deny'].includes(entry)))\n ) {\n diagnostics.push('expectations.allowedDecisionTypes is invalid');\n }\n for (const field of ['allowedOptionIds', 'unsafeOptionIds'] as const) {\n const entries = expectations[field];\n if (entries !== undefined && !isStringArray(entries)) {\n diagnostics.push(`expectations.${field} must be a string array`);\n }\n }\n\n if (isRecord(request) && Array.isArray(request['options'])) {\n const requestIds = new Set(\n request['options']\n .filter(isRecord)\n .map((option) => option['id'])\n .filter((id): id is string => typeof id === 'string'),\n );\n for (const field of ['allowedOptionIds', 'unsafeOptionIds'] as const) {\n const entries = expectations[field];\n if (!isStringArray(entries)) continue;\n for (const id of entries) {\n if (!requestIds.has(id))\n diagnostics.push(`expectations.${field} contains unknown id \"${id}\"`);\n }\n }\n }\n for (const field of ['requireOptionId', 'allowEscalation'] as const) {\n const setting = expectations[field];\n if (setting !== undefined && typeof setting !== 'boolean') {\n diagnostics.push(`expectations.${field} must be a boolean`);\n }\n }\n }\n\n return diagnostics.length > 0\n ? { ok: false, diagnostics }\n : { ok: true, value: value as unknown as BrainEvaluationCaseV1 };\n}\n\nfunction assessDecision(\n fixture: BrainEvaluationCaseV1,\n decision: BrainDecision,\n): BrainEvaluationFailure[] {\n const failures: BrainEvaluationFailure[] = [];\n const expectations = fixture.expectations;\n if (\n expectations?.allowedDecisionTypes &&\n !expectations.allowedDecisionTypes.includes(decision.type)\n ) {\n failures.push({\n code: 'unexpected_decision_type',\n message: `decision type \"${decision.type}\" is not allowed`,\n });\n }\n\n if (decision.type === 'ask_human' && expectations?.allowEscalation !== true) {\n failures.push({\n code: 'unexpected_escalation',\n message: 'case escalated to a human without allowEscalation',\n });\n }\n if (decision.type !== 'answer') return failures;\n\n const requestOptionIds = new Set(fixture.request.options?.map((option) => option.id) ?? []);\n if (decision.optionId === undefined) {\n if (expectations?.requireOptionId || expectations?.allowedOptionIds) {\n failures.push({\n code: 'missing_option_id',\n message: 'answer did not return the required exact option id',\n });\n }\n return failures;\n }\n if (!requestOptionIds.has(decision.optionId)) {\n failures.push({\n code: 'invalid_option_id',\n message: `answer returned unknown option id \"${decision.optionId}\"`,\n });\n }\n if (\n expectations?.allowedOptionIds &&\n !expectations.allowedOptionIds.includes(decision.optionId)\n ) {\n failures.push({\n code: 'disallowed_option_id',\n message: `option id \"${decision.optionId}\" is not allowed for this case`,\n });\n }\n if (expectations?.unsafeOptionIds?.includes(decision.optionId)) {\n failures.push({\n code: 'unsafe_option_id',\n message: `unsafe option id \"${decision.optionId}\" was selected`,\n });\n }\n return failures;\n}\n\n/**\n * Replay evaluation fixtures through a Brain arbiter without applying the\n * returned decisions. The runner has no dispatch, terminate, permission, or\n * tool-execution callback, so a result can only be measured and reported.\n */\nexport async function runBrainEvaluation(\n arbiter: BrainArbiter,\n cases: readonly unknown[],\n): Promise<BrainEvaluationReport> {\n const results: BrainEvaluationCaseResult[] = [];\n const seenCaseIds = new Set<string>();\n for (const rawCase of cases) {\n const validation = validateBrainEvaluationCase(rawCase);\n if (!validation.ok) {\n const caseId =\n isRecord(rawCase) && typeof rawCase['id'] === 'string' ? rawCase['id'] : '<invalid>';\n results.push({\n caseId,\n passed: false,\n failures: validation.diagnostics.map((message) => ({ code: 'invalid_fixture', message })),\n latencyMs: 0,\n });\n continue;\n }\n\n const fixture = validation.value;\n if (seenCaseIds.has(fixture.id)) {\n results.push({\n caseId: fixture.id,\n passed: false,\n failures: [{ code: 'invalid_fixture', message: `case id \"${fixture.id}\" is duplicated` }],\n latencyMs: 0,\n });\n continue;\n }\n seenCaseIds.add(fixture.id);\n const startedAt = performance.now();\n try {\n // Isolate fixture state from an arbiter that mutates its input. The\n // result is measured only; it is never routed to a production consumer.\n const decision = await arbiter.decide(structuredClone(fixture.request));\n const failures = assessDecision(fixture, decision);\n results.push({\n caseId: fixture.id,\n passed: failures.length === 0,\n decision,\n failures,\n latencyMs: Math.max(0, performance.now() - startedAt),\n });\n } catch (error) {\n results.push({\n caseId: fixture.id,\n passed: false,\n failures: [\n {\n code: 'arbiter_error',\n message: error instanceof Error ? error.message : String(error),\n },\n ],\n latencyMs: Math.max(0, performance.now() - startedAt),\n });\n }\n }\n\n const optionResults = results.filter(\n (result) => result.decision?.type === 'answer' && result.decision.optionId !== undefined,\n );\n const invalidOptionCount = results.reduce(\n (count, result) =>\n count + result.failures.filter((failure) => failure.code === 'invalid_option_id').length,\n 0,\n );\n const totalLatency = results.reduce((sum, result) => sum + result.latencyMs, 0);\n const metrics: BrainEvaluationMetrics = {\n totalCases: results.length,\n passedCases: results.filter((result) => result.passed).length,\n failedCases: results.filter((result) => !result.passed).length,\n optionDecisionCount: optionResults.length,\n invalidOptionCount,\n validOptionRate:\n optionResults.length === 0\n ? 1\n : (optionResults.length - invalidOptionCount) / optionResults.length,\n unsafeAllowanceCount: results.reduce(\n (count, result) =>\n count + result.failures.filter((failure) => failure.code === 'unsafe_option_id').length,\n 0,\n ),\n unnecessaryEscalationCount: results.reduce(\n (count, result) =>\n count +\n result.failures.filter((failure) => failure.code === 'unexpected_escalation').length,\n 0,\n ),\n averageLatencyMs: results.length === 0 ? 0 : totalLatency / results.length,\n };\n\n return { version: BRAIN_EVALUATION_CASE_VERSION, results, metrics };\n}\n\nexport interface BrainTraceCaptureOptions {\n /**\n * Pin the case to the decision the trace actually produced, so a replay\n * fails when the Brain's behaviour changes. Off by default: a captured\n * decision is evidence of what happened, not a statement that it was\n * correct, and freezing it wholesale bakes today's bugs into the suite.\n */\n pinObservedDecision?: boolean | undefined;\n /** Option ids that must never be selected for this case. */\n unsafeOptionIds?: string[] | undefined;\n /** Prefix for the generated case id. Default 'capture'. */\n idPrefix?: string | undefined;\n}\n\n/**\n * Turn a recorded production decision into a replayable evaluation fixture.\n *\n * This is the capture half of the replay loop: `BrainTraceRecorder` writes\n * what happened, this converts a row into the versioned case format that\n * `runBrainEvaluation` executes offline without dispatching anything.\n *\n * Only the REQUEST is carried over \u2014 the recorded decision becomes an\n * expectation solely when `pinObservedDecision` is set. Trace content is\n * already governed by the recorder's content mode, so a fixture captured from\n * a `redacted`/`none` trace is structurally valid but will not reproduce the\n * original model behaviour; capture from a `full` trace for real replay.\n */\nexport function brainTraceToEvaluationCase(\n record: BrainTraceRecord,\n opts: BrainTraceCaptureOptions = {},\n): BrainEvaluationCaseV1 {\n const decision = record.decision;\n const expectations: BrainEvaluationExpectations = {};\n\n if (opts.pinObservedDecision && decision) {\n expectations.allowedDecisionTypes = [decision.type];\n if (decision.type === 'answer' && decision.optionId !== undefined) {\n expectations.allowedOptionIds = [decision.optionId];\n expectations.requireOptionId = true;\n }\n if (decision.type === 'ask_human') expectations.allowEscalation = true;\n }\n if (opts.unsafeOptionIds?.length) expectations.unsafeOptionIds = [...opts.unsafeOptionIds];\n\n const tierNote = record.tier ? ` via ${record.tier}` : '';\n const costNote =\n record.totals.llmCalls > 0\n ? ` (${record.totals.llmCalls} llm call(s), ${record.totals.totalTokens} tokens)`\n : ' (no provider call)';\n\n return {\n version: BRAIN_EVALUATION_CASE_VERSION,\n id: `${opts.idPrefix ?? 'capture'}-${record.requestId}`,\n description: `Captured ${record.request.source} decision${tierNote}${costNote}`,\n request: record.request,\n ...(Object.keys(expectations).length > 0 ? { expectations } : {}),\n };\n}\n", "/**\n * BrainDecisionLedger \u2014 the Brain's persistent memory + learning loop.\n *\n * Every Brain decision already flows over the EventBus (`brain.decision_*`,\n * `brain.intervention` \u2014 emitted by `ObservableBrainArbiter` and\n * `BrainMonitor`). The ledger subscribes to those events, appends each\n * decision to a JSONL file, and \u2014 the part that makes it a LEARNING loop \u2014\n * correlates decisions with their real-world outcomes using events the host\n * already emits, with ZERO changes to the deciders:\n *\n * - budget extensions \u2014 `subagent.budget_extended` carries subagentId +\n * kind, which deterministically reconstructs the director's decision id\n * (`director-budget-<subagentId>-<kind>`). When that subagent's task\n * later lands (`subagent.task_completed`), the extension decision gets a\n * success/failure outcome: \"we granted more budget \u2014 did it help?\"\n * - steers \u2014 a `brain.intervention` of the same kind re-triggering within\n * the retry window means the previous steer did NOT fix the problem \u2192\n * failure outcome for the earlier intervention.\n *\n * Outcomes are appended as their own JSONL rows, re-emitted as\n * `brain.outcome` events for the UI surfaces, and folded into\n * `digestFor(request)` \u2014 a short text block the LLM/council tiers inject\n * into their decision prompts so the Brain sees how its past similar calls\n * actually turned out (\"the last 3 extends all failed \u2014 stop extending\").\n *\n * The file survives sessions: `start()` seeds the in-memory ring from the\n * JSONL tail, so learning carries across runs of the same project.\n *\n * @module brain-ledger\n */\n\nimport { createReadStream } from 'node:fs';\nimport { access, appendFile, mkdir, rename, stat } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { createInterface } from 'node:readline';\nimport type { EventBus } from '../kernel/events.js';\nimport type { BrainArbiter, BrainDecision, BrainDecisionRequest } from './brain.js';\nimport { markDecisionTier } from './brain-telemetry.js';\n\nexport interface BrainLedgerEntry {\n at: number;\n sessionId?: string | undefined;\n /** `BrainDecisionRequest.id` this row belongs to. */\n requestId: string;\n kind: 'answered' | 'denied' | 'ask_human' | 'intervention' | 'outcome';\n source?: string | undefined;\n risk?: string | undefined;\n question?: string | undefined;\n optionId?: string | undefined;\n /** Rationale / deny reason / outcome detail (truncated). */\n detail?: string | undefined;\n outcome?: 'success' | 'failure' | undefined;\n}\n\nexport interface BrainDecisionLedgerOptions {\n events: EventBus;\n /** JSONL file the ledger appends to (e.g. `<projectDir>/brain-ledger.jsonl`). */\n filePath: string;\n /** In-memory ring size (also the seed size read from disk). Default 500. */\n maxMemoryEntries?: number | undefined;\n /**\n * A same-kind BrainMonitor intervention re-triggering within this window\n * marks the PREVIOUS steer as a failure. Default 10 minutes.\n */\n interventionRetryWindowMs?: number | undefined;\n /** Override the clock for deterministic tests. */\n now?: (() => number) | undefined;\n}\n\nconst QUESTION_MAX = 200;\nconst DETAIL_MAX = 240;\n\nconst truncate = (s: string | undefined, max: number): string | undefined =>\n s === undefined ? undefined : s.length > max ? `${s.slice(0, max - 1)}\u2026` : s;\n\n/**\n * Group similar decisions: identical questions about different subjects\n * (subagent ids, task ids, counts) should share one history. Tokens that\n * contain a digit are id/number-shaped \u2014 collapse them to `#`.\n */\nexport function brainDecisionKey(source: string | undefined, question: string): string {\n const normalized = question\n .toLowerCase()\n .replace(/[^\\s]*\\d[^\\s]*/g, '#')\n .replace(/\\s+/g, ' ')\n .trim()\n .slice(0, 100);\n return `${source ?? '?'}:${normalized}`;\n}\n\nfunction fmtAge(ms: number): string {\n const s = Math.max(0, Math.round(ms / 1000));\n if (s < 60) return `${s}s ago`;\n if (s < 3600) return `${Math.round(s / 60)}m ago`;\n return `${Math.round(s / 3600)}h ago`;\n}\n\nexport interface LedgerGuardBrainArbiterOptions {\n inner: BrainArbiter;\n /** Typically `BrainDecisionLedger.failureStreakFor`. */\n failureStreakFor: (request: Pick<BrainDecisionRequest, 'source' | 'question' | 'id'>) => number;\n /**\n * Deny deterministically once this many consecutive failure outcomes are\n * on record for the request's decision group. Default 3. 0 disables.\n */\n denyAfter?: number | undefined;\n}\n\n/**\n * Deterministic guard derived from the ledger's outcome history: when the\n * last `denyAfter` approvals of a decision group ALL ended in observed\n * failures, the request is denied outright \u2014 no LLM call, no council, no\n * escalation. Deny is safe by contract at every Brain call site (\"do not\n * take the proposed action\"), so this converts repeated observed waste\n * (budget extensions that never help, steers that never stick) into a hard\n * policy rule. A later observed success resets the streak and lifts the\n * guard automatically.\n *\n * Position OUTSIDE the tiered arbiter (between it and the escalation\n * router): a guard denial must be terminal, not a fall-through to the\n * escalation tier where a `recommended: true` option could resurrect the\n * very action the history condemned.\n */\nexport function createLedgerGuardBrainArbiter(opts: LedgerGuardBrainArbiterOptions): BrainArbiter {\n const denyAfter = opts.denyAfter ?? 3;\n return {\n async decide(request: BrainDecisionRequest): Promise<BrainDecision> {\n if (denyAfter > 0) {\n const streak = opts.failureStreakFor(request);\n if (streak >= denyAfter) {\n markDecisionTier(request, 'ledger-guard');\n return {\n type: 'deny',\n reason:\n `Ledger guard: the last ${streak} approved decisions of this kind all ` +\n `ended in observed failures \u2014 denying deterministically until a success ` +\n `is recorded. (${request.question.slice(0, 120)})`,\n };\n }\n }\n return opts.inner.decide(request);\n },\n };\n}\n\nexport class BrainDecisionLedger {\n private readonly entries: BrainLedgerEntry[] = [];\n private readonly outcomeByRequest = new Map<string, 'success' | 'failure'>();\n /** subagentId \u2192 decision request ids awaiting that subagent's task result. */\n private readonly pendingBudgetOutcomes = new Map<string, Set<string>>();\n private readonly lastInterventionByKind = new Map<string, { requestId: string; at: number }>();\n private readonly unsubscribers: Array<() => void> = [];\n /** Serialized fire-and-forget writes \u2014 awaited by `stop()` (drain). */\n private writeChain: Promise<unknown> = Promise.resolve();\n private pendingWriteCount = 0;\n private pendingWriteBytes = 0;\n private static readonly MAX_PENDING_WRITES = 1_000;\n private static readonly MAX_PENDING_WRITE_BYTES = 8 * 1024 * 1024;\n /** Rotate the JSONL to `.1` past this size so it can't grow unbounded. */\n private static readonly MAX_FILE_BYTES = 5 * 1024 * 1024;\n /** Stat the file for rotation only once per this many writes. */\n private static readonly ROTATE_CHECK_EVERY = 100;\n private writesSinceRotateCheck = 0;\n private dirReady = false;\n\n private readonly maxMemoryEntries: number;\n private readonly retryWindowMs: number;\n private readonly now: () => number;\n\n constructor(private readonly opts: BrainDecisionLedgerOptions) {\n this.maxMemoryEntries = opts.maxMemoryEntries ?? 500;\n this.retryWindowMs = opts.interventionRetryWindowMs ?? 10 * 60_000;\n this.now = opts.now ?? Date.now;\n }\n\n /**\n * Subscribe to the EventBus and seed the in-memory ring from the JSONL\n * tail. The returned promise resolves once the seed load finished\n * (best-effort \u2014 a missing/corrupt file is an empty history, not an error).\n */\n async start(): Promise<void> {\n const { events } = this.opts;\n this.unsubscribers.push(\n events.on('brain.decision_answered', (e) => {\n this.record({\n at: e.at,\n sessionId: e.sessionId,\n requestId: e.request.id,\n kind: 'answered',\n source: e.request.source,\n risk: e.request.risk,\n question: truncate(e.request.question, QUESTION_MAX),\n optionId: e.decision.type === 'answer' ? e.decision.optionId : undefined,\n detail:\n e.decision.type === 'answer'\n ? truncate(e.decision.rationale ?? e.decision.text, DETAIL_MAX)\n : undefined,\n });\n }),\n events.on('brain.decision_denied', (e) => {\n this.record({\n at: e.at,\n sessionId: e.sessionId,\n requestId: e.request.id,\n kind: 'denied',\n source: e.request.source,\n risk: e.request.risk,\n question: truncate(e.request.question, QUESTION_MAX),\n detail: e.decision.type === 'deny' ? truncate(e.decision.reason, DETAIL_MAX) : undefined,\n });\n }),\n events.on('brain.decision_ask_human', (e) => {\n this.record({\n at: e.at,\n sessionId: e.sessionId,\n requestId: e.request.id,\n kind: 'ask_human',\n source: e.request.source,\n risk: e.request.risk,\n question: truncate(e.request.question, QUESTION_MAX),\n });\n }),\n events.on('brain.intervention', (e) => {\n this.record({\n at: e.at,\n sessionId: e.sessionId,\n requestId: e.request.id,\n kind: 'intervention',\n source: e.request.source,\n risk: e.request.risk,\n question: truncate(`[${e.kind}] ${e.request.question}`, QUESTION_MAX),\n detail: e.intervened ? 'steered' : 'observed only',\n });\n if (!e.intervened) return;\n // A same-kind re-engagement inside the retry window means the\n // previous steer did not fix the underlying problem.\n const prev = this.lastInterventionByKind.get(e.kind);\n if (prev && e.at - prev.at <= this.retryWindowMs) {\n this.recordOutcome(\n prev.requestId,\n 'failure',\n `same signal (${e.kind}) re-triggered ${fmtAge(e.at - prev.at).replace(' ago', ' later')}`,\n e.sessionId,\n );\n }\n this.lastInterventionByKind.set(e.kind, { requestId: e.request.id, at: e.at });\n }),\n // \u2500\u2500 Outcome correlation: budget extensions \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 events.on('subagent.budget_extended', (e) => {\n // The director's decision id is deterministic \u2014 reconstruct it.\n const requestId = `director-budget-${e.subagentId}-${e.kind}`;\n if (!this.entries.some((entry) => entry.requestId === requestId)) return;\n let set = this.pendingBudgetOutcomes.get(e.subagentId);\n if (!set) {\n set = new Set();\n this.pendingBudgetOutcomes.set(e.subagentId, set);\n }\n set.add(requestId);\n }),\n events.on('subagent.task_completed', (e) => {\n const pending = this.pendingBudgetOutcomes.get(e.subagentId);\n if (!pending) return;\n this.pendingBudgetOutcomes.delete(e.subagentId);\n const outcome = e.status === 'success' ? 'success' : 'failure';\n for (const requestId of pending) {\n this.recordOutcome(\n requestId,\n outcome,\n `budget-extended subagent's task ${e.status}`,\n e.sessionId,\n );\n }\n }),\n );\n await this.load();\n }\n\n /** Unsubscribe and drain pending writes. Safe to call twice. */\n async stop(): Promise<void> {\n for (const off of this.unsubscribers) off();\n this.unsubscribers.length = 0;\n await this.writeChain.catch(() => {});\n }\n\n /**\n * Attach a real-world outcome to an earlier decision. Appended to the\n * JSONL, folded into future digests, and re-emitted as `brain.outcome`.\n */\n recordOutcome(\n requestId: string,\n outcome: 'success' | 'failure',\n detail?: string,\n sessionId?: string,\n ): void {\n this.outcomeByRequest.set(requestId, outcome);\n this.record({\n at: this.now(),\n sessionId,\n requestId,\n kind: 'outcome',\n outcome,\n detail: truncate(detail, DETAIL_MAX),\n });\n this.opts.events.emit('brain.outcome', {\n sessionId,\n requestId,\n outcome,\n detail,\n at: this.now(),\n });\n }\n\n /** Last `n` ledger rows, oldest first. */\n tail(n: number): BrainLedgerEntry[] {\n return this.entries.slice(-n);\n }\n\n /**\n * Consecutive most-recent FAILURE outcomes among answered decisions of\n * this request's group. Decisions whose outcome is still unknown are\n * skipped (they neither extend nor break the streak); the first known\n * SUCCESS ends it. Powers the deterministic ledger guard: \"the last K\n * times we approved this, it went wrong \u2014 stop approving\".\n */\n failureStreakFor(request: Pick<BrainDecisionRequest, 'source' | 'question' | 'id'>): number {\n const key = brainDecisionKey(request.source, request.question);\n let streak = 0;\n for (let i = this.entries.length - 1; i >= 0; i--) {\n const e = this.entries[i];\n if (\n e?.kind !== 'answered' ||\n e.requestId === request.id ||\n e.question === undefined ||\n brainDecisionKey(e.source, e.question) !== key\n ) {\n continue;\n }\n const outcome = this.outcomeByRequest.get(e.requestId);\n if (outcome === undefined) continue;\n if (outcome === 'success') break;\n streak += 1;\n }\n return streak;\n }\n\n /**\n * Short decision-history block for the LLM/council prompt: how similar\n * past decisions went and \u2014 when known \u2014 how they turned OUT. Returns\n * undefined when there is no relevant history (no prompt noise).\n */\n digestFor(request: Pick<BrainDecisionRequest, 'source' | 'question' | 'id'>): string | undefined {\n const key = brainDecisionKey(request.source, request.question);\n const related = this.entries.filter(\n (e) =>\n (e.kind === 'answered' || e.kind === 'denied') &&\n e.requestId !== request.id &&\n e.question !== undefined &&\n brainDecisionKey(e.source, e.question) === key,\n );\n if (related.length === 0) return undefined;\n\n const recent = related.slice(-5).reverse();\n const now = this.now();\n const lines = recent.map((e) => {\n const what =\n e.kind === 'denied' ? 'denied' : e.optionId ? `chose [${e.optionId}]` : 'answered';\n const outcome = this.outcomeByRequest.get(e.requestId);\n const suffix =\n outcome === 'failure'\n ? ' \u2192 later FAILED'\n : outcome === 'success'\n ? ' \u2192 later succeeded'\n : '';\n return `- ${fmtAge(now - e.at)}: ${what}${suffix}`;\n });\n const approved = related.filter((e) => e.kind === 'answered');\n const failedAfter = approved.filter(\n (e) => this.outcomeByRequest.get(e.requestId) === 'failure',\n ).length;\n const summary =\n `Summary: ${related.length} similar decision(s); ` +\n `${approved.length} answered${failedAfter > 0 ? ` (${failedAfter} later failed)` : ''}, ` +\n `${related.length - approved.length} denied.`;\n return [...lines, summary].join('\\n');\n }\n\n // \u2500\u2500 Private \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 private record(entry: BrainLedgerEntry): void {\n this.entries.push(entry);\n if (this.entries.length > this.maxMemoryEntries) {\n // Collect requestIds from the evicted entries so we can prune\n // outcomeByRequest entries whose decision has been forgotten.\n const evictedRequestIds = new Set<string>();\n const evictCount = this.entries.length - this.maxMemoryEntries;\n const evicted = this.entries.splice(0, evictCount);\n for (const e of evicted) {\n if (e.requestId) evictedRequestIds.add(e.requestId);\n }\n if (evictedRequestIds.size > 0) {\n // Build a set of requestIds that still have entries in the ring.\n // Only outcomes for those are still queryable via digestFor().\n const remainingRequestIds = new Set<string>();\n for (const e of this.entries) {\n if (e.requestId) remainingRequestIds.add(e.requestId);\n }\n for (const id of evictedRequestIds) {\n if (!remainingRequestIds.has(id)) this.outcomeByRequest.delete(id);\n }\n }\n }\n this.append(entry);\n }\n\n private append(entry: BrainLedgerEntry): void {\n let line: string;\n try {\n line = `${JSON.stringify(entry)}\\n`;\n } catch {\n return;\n }\n const bytes = Buffer.byteLength(line, 'utf8');\n if (\n this.pendingWriteCount >= BrainDecisionLedger.MAX_PENDING_WRITES ||\n bytes > BrainDecisionLedger.MAX_PENDING_WRITE_BYTES ||\n this.pendingWriteBytes + bytes > BrainDecisionLedger.MAX_PENDING_WRITE_BYTES\n ) {\n return;\n }\n this.pendingWriteCount += 1;\n this.pendingWriteBytes += bytes;\n this.writeChain = this.writeChain\n .then(async () => {\n if (!this.dirReady) {\n await mkdir(dirname(this.opts.filePath), { recursive: true });\n this.dirReady = true;\n }\n await this.maybeRotate();\n await appendFile(this.opts.filePath, line, 'utf8');\n })\n .catch(() => {\n // Ledger persistence is best-effort \u2014 never destabilize the host.\n })\n .finally(() => {\n this.pendingWriteCount = Math.max(0, this.pendingWriteCount - 1);\n this.pendingWriteBytes = Math.max(0, this.pendingWriteBytes - bytes);\n });\n }\n\n /**\n * Size-bounded rotation: past {@link MAX_FILE_BYTES} the file moves to a\n * single `.1` sibling (previous `.1` is overwritten), bounding disk to\n * ~2\u00D7 the cap. Checked once per {@link ROTATE_CHECK_EVERY} writes; runs on\n * the write chain, so it never races an append. The ring `load()` reads\n * only the tail, so rotation never costs queryable history.\n */\n private async maybeRotate(): Promise<void> {\n this.writesSinceRotateCheck += 1;\n if (this.writesSinceRotateCheck < BrainDecisionLedger.ROTATE_CHECK_EVERY) return;\n this.writesSinceRotateCheck = 0;\n try {\n const info = await stat(this.opts.filePath);\n if (info.size < BrainDecisionLedger.MAX_FILE_BYTES) return;\n await rename(this.opts.filePath, `${this.opts.filePath}.1`);\n } catch {\n // Missing file or a locked rename \u2014 rotation retries on a later check.\n }\n }\n\n /** Seed the in-memory ring from the JSONL tail (cross-session learning). */\n private async load(): Promise<void> {\n try {\n await access(this.opts.filePath);\n } catch {\n return; // No ledger yet.\n }\n const seed: BrainLedgerEntry[] = [];\n const input = createReadStream(this.opts.filePath, { encoding: 'utf8' });\n const lines = createInterface({ input, crlfDelay: Number.POSITIVE_INFINITY });\n try {\n for await (const line of lines) {\n if (!line.trim()) continue;\n try {\n const parsed = JSON.parse(line) as BrainLedgerEntry;\n if (typeof parsed?.requestId === 'string' && typeof parsed.at === 'number') {\n seed.push(parsed);\n if (seed.length > this.maxMemoryEntries) seed.shift();\n }\n } catch {\n // Skip corrupt rows \u2014 a partial tail is still useful history.\n }\n }\n } catch {\n return;\n } finally {\n lines.close();\n input.destroy();\n }\n // Entries recorded while the file was loading stay AFTER the seed.\n this.entries.unshift(...seed);\n if (this.entries.length > this.maxMemoryEntries) {\n this.entries.splice(0, this.entries.length - this.maxMemoryEntries);\n }\n for (const e of this.entries) {\n if (e.kind === 'outcome' && e.outcome) this.outcomeByRequest.set(e.requestId, e.outcome);\n }\n }\n}\n", "/**\n * Decision cache for the expensive Brain tiers.\n *\n * Autonomy workloads ask the same question over and over: a goal-completion\n * check every phase, a budget-extension question per subagent, a\n * monitor engagement per repeated signal. Each one used to be a fresh\n * council/LLM call even when nothing about the situation had changed, which\n * is the single largest avoidable source of Brain token spend.\n *\n * Scope is deliberately narrow \u2014 the cache exists to skip PROVIDER calls, not\n * to replace judgement:\n *\n * - Only decisions produced by the `council` / `llm` tiers are stored. A\n * deterministic tier is already free, so caching it would add lookup cost\n * and staleness for no gain.\n * - `ask_human` is never cached: it is a request for input, not a verdict.\n * - An observed FAILURE outcome for a cached decision evicts it. This is\n * what stops the cache from cementing a bad call: the ledger already\n * correlates outcomes, so a decision that demonstrably went wrong will\n * not be replayed.\n * - Entries expire on a TTL, so a stale world eventually re-asks anyway.\n *\n * The key includes everything that could change the right answer \u2014 question\n * shape, source, risk, fallback, and the exact option set \u2014 so two questions\n * that merely look similar do not share a verdict.\n *\n * @module brain-cache\n */\n\nimport type { EventBus } from '../kernel/events.js';\nimport type { BrainArbiter, BrainDecision, BrainDecisionRequest } from './brain.js';\nimport { brainDecisionKey } from './brain-ledger.js';\nimport { markDecisionTier, readDecisionTier } from './brain-telemetry.js';\n\nexport interface BrainDecisionCacheOptions {\n /** Master switch. Default false \u2014 caching a judgement is opt-in. */\n enabled?: boolean | undefined;\n /** Entry lifetime in ms. Default 300_000 (5 min). */\n ttlMs?: number | undefined;\n /** Maximum live entries; oldest evicted first. Default 200. */\n maxEntries?: number | undefined;\n /**\n * Outcome feed. When a cached decision is later observed to have FAILED,\n * its entry is dropped so the mistake is not replayed.\n */\n events?: EventBus | undefined;\n /** Override the clock for deterministic tests. */\n now?: (() => number) | undefined;\n}\n\ninterface CacheEntry {\n decision: BrainDecision;\n storedAt: number;\n /** Request ids served from (or that produced) this entry, for outcome eviction. */\n requestIds: Set<string>;\n}\n\nexport interface BrainCacheStats {\n hits: number;\n misses: number;\n stores: number;\n evictions: number;\n size: number;\n}\n\n/**\n * Build the cache key for a request.\n *\n * Reuses `brainDecisionKey` for the question so id/number-shaped tokens\n * collapse (the same question about two different subagents shares an entry),\n * then adds every other field that can legitimately change the answer.\n */\nexport function brainCacheKey(request: BrainDecisionRequest): string {\n const options = (request.options ?? [])\n .map((option) => option.id)\n .sort()\n .join(',');\n return [\n brainDecisionKey(request.source, request.question),\n request.risk,\n request.fallback,\n options,\n ].join('|');\n}\n\n/** Tiers whose decisions cost a provider call and are therefore worth caching. */\nconst CACHEABLE_TIERS = new Set(['council', 'llm']);\n\nexport class BrainDecisionCache {\n /**\n * Max request ids retained per cached entry. Served (replayed) request ids\n * are kept only so a later `brain.outcome` failure can evict the verdict;\n * past this cap the oldest ids are dropped \u2014 the entry itself stays.\n */\n private static readonly MAX_REQUEST_IDS_PER_ENTRY = 500;\n\n private readonly entries = new Map<string, CacheEntry>();\n private readonly keyByRequestId = new Map<string, string>();\n private readonly unsubscribers: Array<() => void> = [];\n private stats = { hits: 0, misses: 0, stores: 0, evictions: 0 };\n\n private readonly enabled: boolean;\n private readonly ttlMs: number;\n private readonly maxEntries: number;\n private readonly now: () => number;\n\n constructor(private readonly opts: BrainDecisionCacheOptions = {}) {\n this.enabled = opts.enabled === true;\n this.ttlMs = opts.ttlMs ?? 300_000;\n this.maxEntries = opts.maxEntries ?? 200;\n this.now = opts.now ?? Date.now;\n }\n\n /**\n * Delete an entry and every request-id index mapping that points at it.\n * Every eviction path (TTL expiry, max-entry eviction, outcome failure,\n * same-key replacement) must go through this so `keyByRequestId` cannot\n * outlive its entry \u2014 otherwise the index grows one string per unique\n * request id for the process lifetime.\n */\n private removeEntry(key: string): boolean {\n const entry = this.entries.get(key);\n if (!entry) return false;\n // Only drop index mappings that still point at THIS entry. A request id\n // that was re-stored under a different key keeps its newer mapping.\n for (const requestId of entry.requestIds) {\n if (this.keyByRequestId.get(requestId) === key) this.keyByRequestId.delete(requestId);\n }\n this.entries.delete(key);\n return true;\n }\n\n /** Subscribe to the outcome feed so failures evict their decision. */\n start(): void {\n if (!this.enabled || !this.opts.events) return;\n this.unsubscribers.push(\n this.opts.events.on('brain.outcome', (e) => {\n if (e.outcome !== 'failure') return;\n const key = this.keyByRequestId.get(e.requestId);\n if (key === undefined) return;\n // The world disagreed with this verdict \u2014 do not serve it again.\n if (this.removeEntry(key)) this.stats.evictions += 1;\n }),\n );\n }\n\n stop(): void {\n for (const off of this.unsubscribers) off();\n this.unsubscribers.length = 0;\n }\n\n get(request: BrainDecisionRequest): BrainDecision | undefined {\n if (!this.enabled) return undefined;\n const key = brainCacheKey(request);\n const entry = this.entries.get(key);\n if (!entry) {\n this.stats.misses += 1;\n return undefined;\n }\n if (this.now() - entry.storedAt > this.ttlMs) {\n this.removeEntry(key);\n this.stats.evictions += 1;\n this.stats.misses += 1;\n return undefined;\n }\n // Bound the per-entry served-request-id set so replay tracking cannot grow\n // without limit on hot entries (outcome eviction needs only recent ids).\n if (entry.requestIds.size >= BrainDecisionCache.MAX_REQUEST_IDS_PER_ENTRY) {\n const oldest = entry.requestIds.values().next().value;\n if (oldest !== undefined) {\n entry.requestIds.delete(oldest);\n this.keyByRequestId.delete(oldest);\n }\n }\n entry.requestIds.add(request.id);\n this.keyByRequestId.set(request.id, key);\n this.stats.hits += 1;\n return entry.decision;\n }\n\n /**\n * Store a decision if it is worth caching. Returns true when stored.\n * Callers pass the tier that produced it \u2014 a deterministic tier is free to\n * recompute, and `ask_human` is a request for input rather than a verdict.\n */\n set(request: BrainDecisionRequest, decision: BrainDecision, tier: string | undefined): boolean {\n if (!this.enabled) return false;\n if (decision.type === 'ask_human') return false;\n if (tier === undefined || !CACHEABLE_TIERS.has(tier)) return false;\n\n const key = brainCacheKey(request);\n // Replace any existing entry for this key first, so the superseded\n // entry's request-id index mappings do not outlive it.\n this.removeEntry(key);\n this.entries.set(key, {\n decision,\n storedAt: this.now(),\n requestIds: new Set([request.id]),\n });\n this.keyByRequestId.set(request.id, key);\n this.stats.stores += 1;\n\n while (this.entries.size > this.maxEntries) {\n const oldest = this.entries.keys().next();\n if (oldest.done) break;\n this.removeEntry(oldest.value);\n this.stats.evictions += 1;\n }\n return true;\n }\n\n snapshot(): BrainCacheStats {\n return { ...this.stats, size: this.entries.size };\n }\n\n clear(): void {\n this.entries.clear();\n this.keyByRequestId.clear();\n }\n}\n\nexport interface CachingBrainArbiterOptions {\n inner: BrainArbiter;\n cache: BrainDecisionCache;\n}\n\n/**\n * Wrap an arbiter so repeated identical questions replay a previous\n * provider-backed verdict instead of paying for it again.\n *\n * Position INSIDE the ledger guard: a guard denial must always be evaluated\n * against the live failure history, never served from a cache.\n */\nexport function createCachingBrainArbiter(opts: CachingBrainArbiterOptions): BrainArbiter {\n return {\n async decide(request: BrainDecisionRequest): Promise<BrainDecision> {\n const hit = opts.cache.get(request);\n if (hit) {\n markDecisionTier(request, 'cache');\n return hit;\n }\n const decision = await opts.inner.decide(request);\n // Read the tier the inner chain recorded \u2014 that is what tells us\n // whether this decision actually cost anything.\n opts.cache.set(request, decision, readDecisionTier(request));\n return decision;\n },\n };\n}\n", "/**\n * Circuit breaker for the Brain's LLM pool.\n *\n * The single-LLM tier walks its whole pool on every decision, giving each\n * target the full `decisionTimeoutMs`. When the pool is dead \u2014 expired key,\n * provider outage, offline machine \u2014 that costs `pool.length \u00D7 timeout` PER\n * DECISION, forever, with no memory between calls. With a `fallbackModels`\n * chain of five and the default 15s timeout, a single Brain question stalls\n * the caller for over a minute, repeatedly, to reach a conclusion the\n * previous decision already reached.\n *\n * This breaker gives the pool a memory:\n *\n * - CLOSED \u2014 normal operation; every failure increments a counter.\n * - OPEN \u2014 after `failureThreshold` consecutive failures the tier is\n * skipped outright for `cooldownMs`, so decisions fall\n * straight through to the deterministic tiers instead of\n * paying the timeout again.\n * - HALF_OPEN \u2014 once the cooldown expires, ONE probe decision is allowed\n * through. Success closes the breaker; failure re-opens it\n * for another cooldown.\n *\n * Per-target health is tracked separately so `orderTargets()` can move a\n * known-bad model to the back of the pool without removing it \u2014 a model that\n * recovers is still tried, just last.\n *\n * @module brain-circuit\n */\n\nexport type BrainCircuitState = 'closed' | 'open' | 'half_open';\n\nexport interface BrainCircuitOptions {\n /** Consecutive failures before the breaker opens. Default 3. 0 disables. */\n failureThreshold?: number | undefined;\n /** How long the breaker stays open before allowing a probe (ms). Default 60_000. */\n cooldownMs?: number | undefined;\n /** Override the clock for deterministic tests. */\n now?: (() => number) | undefined;\n}\n\nexport interface BrainCircuitSnapshot {\n state: BrainCircuitState;\n consecutiveFailures: number;\n /** When the breaker last opened, or undefined while closed. */\n openedAt: number | undefined;\n /** Per-target consecutive failure counts, worst first. */\n unhealthyTargets: Array<{ label: string; failures: number }>;\n}\n\n/**\n * Failure memory for the Brain LLM tier. Pure bookkeeping \u2014 it performs no\n * I/O and makes no decisions of its own; callers ask `shouldAttempt()` before\n * spending a timeout and report back via `recordSuccess` / `recordFailure`.\n */\nexport class BrainCircuitBreaker {\n private consecutiveFailures = 0;\n private openedAt: number | undefined;\n /** Set while a half-open probe is in flight, so only one is allowed. */\n private probeInFlight = false;\n private readonly targetFailures = new Map<string, number>();\n\n private readonly failureThreshold: number;\n private readonly cooldownMs: number;\n private readonly now: () => number;\n\n constructor(opts: BrainCircuitOptions = {}) {\n this.failureThreshold = opts.failureThreshold ?? 3;\n this.cooldownMs = opts.cooldownMs ?? 60_000;\n this.now = opts.now ?? Date.now;\n }\n\n /** Disabled breakers never open, so callers can skip the state dance. */\n get enabled(): boolean {\n return this.failureThreshold > 0;\n }\n\n state(): BrainCircuitState {\n if (!this.enabled || this.openedAt === undefined) return 'closed';\n return this.now() - this.openedAt >= this.cooldownMs ? 'half_open' : 'open';\n }\n\n /**\n * May the LLM tier be consulted right now?\n *\n * Returns false only while the breaker is fully open, or when a half-open\n * probe is already in flight \u2014 concurrent decisions must not all become\n * probes, or an outage would still cost the full timeout on every one.\n */\n shouldAttempt(): boolean {\n if (!this.enabled) return true;\n const state = this.state();\n if (state === 'closed') return true;\n if (state === 'open') return false;\n if (this.probeInFlight) return false;\n this.probeInFlight = true;\n return true;\n }\n\n recordSuccess(targetLabel?: string): void {\n this.consecutiveFailures = 0;\n this.openedAt = undefined;\n this.probeInFlight = false;\n if (targetLabel) this.targetFailures.delete(targetLabel);\n }\n\n recordFailure(targetLabel?: string): void {\n if (targetLabel) {\n this.targetFailures.set(targetLabel, (this.targetFailures.get(targetLabel) ?? 0) + 1);\n }\n if (!this.enabled) return;\n this.consecutiveFailures += 1;\n this.probeInFlight = false;\n if (this.consecutiveFailures >= this.failureThreshold) {\n // Re-stamp on every failure past the threshold: a half-open probe that\n // fails must buy a FRESH cooldown, not resume the expired one.\n this.openedAt = this.now();\n }\n }\n\n /**\n * Reorder a pool so targets with recent failures are tried last, preserving\n * relative order within each group. A bad model is deprioritised, never\n * dropped \u2014 it stays reachable the moment it recovers.\n */\n orderTargets<T>(targets: readonly T[], labelOf: (target: T) => string): T[] {\n if (this.targetFailures.size === 0) return [...targets];\n return [...targets].sort(\n (a, b) =>\n (this.targetFailures.get(labelOf(a)) ?? 0) - (this.targetFailures.get(labelOf(b)) ?? 0),\n );\n }\n\n snapshot(): BrainCircuitSnapshot {\n return {\n state: this.state(),\n consecutiveFailures: this.consecutiveFailures,\n openedAt: this.openedAt,\n unhealthyTargets: [...this.targetFailures.entries()]\n .map(([label, failures]) => ({ label, failures }))\n .sort((a, b) => b.failures - a.failures),\n };\n }\n\n reset(): void {\n this.consecutiveFailures = 0;\n this.openedAt = undefined;\n this.probeInFlight = false;\n this.targetFailures.clear();\n }\n}\n", "/**\n * BrainRules \u2014 the configurable deterministic tier.\n *\n * Every deterministic decision the Brain could make used to be a hardcoded\n * regex or `if` buried in `DefaultBrainArbiter` / `quickDecide`. That made the\n * cheapest tier the least controllable one: operators could change WHEN the\n * expensive tiers engage (risk ceilings, council floors) but never WHAT the\n * free tier is able to settle on its own. The practical consequence was that\n * high-frequency, low-information questions \u2014 above all the BrainMonitor's\n * steer/continue engagements \u2014 always fell through to a provider call.\n *\n * This module adds a rule table in front of the policy tier:\n *\n * rules \u2192 policy \u2192 cache \u2192 council \u2192 LLM \u2192 escalation\n *\n * Rules are pure predicates over the request. They perform no I/O, cannot\n * call a provider, and evaluate first-match-wins. A rule that matches but\n * whose action is `defer` explicitly hands the request to the next tier,\n * which makes \"everything EXCEPT X is deterministic\" expressible.\n *\n * ## Trust\n * `config.brain` is on the in-project config deny list, so rules can only\n * come from the user's own active-profile config \u2014 never from a repo. Regex\n * sources are still length-capped and compiled defensively (a bad pattern\n * disables its own rule rather than taking the Brain down), and matching runs\n * against truncated inputs so a pathological pattern cannot stall a decision\n * indefinitely.\n *\n * @module brain-rules\n */\n\nimport {\n BRAIN_RISK_LEVELS,\n type BrainArbiter,\n type BrainDecision,\n type BrainDecisionRequest,\n type BrainDecisionSource,\n type BrainFallback,\n type BrainRisk,\n} from './brain.js';\nimport { markDecisionTier } from './brain-telemetry.js';\n\n/** Longest regex source accepted from config. */\nexport const BRAIN_RULE_PATTERN_MAX = 1_000;\n\n/**\n * Longest question/context prefix a rule pattern is matched against.\n *\n * Bounding the SUBJECT is the only backtracking mitigation available to a\n * JS regex engine without a timeout: a catastrophic pattern's blow-up is\n * driven by input length, so a hard cap keeps the worst case bounded. Brain\n * questions are short by construction and context is already truncated\n * upstream, so this never changes a legitimate match.\n */\nexport const BRAIN_RULE_SUBJECT_MAX = 8_000;\n\n/** Predicate over a decision request. All present fields must match (AND). */\nexport interface BrainRuleMatch {\n /** Request source(s). Omitted = any. */\n source?: BrainDecisionSource | BrainDecisionSource[] | undefined;\n /** Exact request risk(s). Omitted = any. */\n risk?: BrainRisk | BrainRisk[] | undefined;\n /** Inclusive lower bound on request risk. */\n minRisk?: BrainRisk | undefined;\n /** Inclusive upper bound on request risk. */\n maxRisk?: BrainRisk | undefined;\n /** Caller-declared fallback(s). Omitted = any. */\n fallback?: BrainFallback | BrainFallback[] | undefined;\n /** true = request must carry options; false = must carry none. */\n hasOptions?: boolean | undefined;\n /** Request must offer an option with this exact id. */\n offersOption?: string | undefined;\n /** Case-insensitive regex the question must match. */\n question?: string | undefined;\n /** Case-insensitive regex the context must match (no context = no match). */\n context?: string | undefined;\n /** Case-insensitive regex the question must NOT match. */\n notQuestion?: string | undefined;\n /** Case-insensitive regex the context must NOT match (no context = passes). */\n notContext?: string | undefined;\n}\n\n/** What a matching rule does. */\nexport type BrainRuleAction =\n | {\n action: 'answer';\n /** Must name an option the request actually offers, else the rule defers. */\n optionId?: string | undefined;\n text?: string | undefined;\n rationale?: string | undefined;\n }\n | { action: 'deny'; reason?: string | undefined }\n | { action: 'escalate'; prompt?: string | undefined }\n /** Match, but hand the request to the next tier anyway. */\n | { action: 'defer' };\n\n/** One deterministic rule from `config.brain.rules`. */\nexport interface BrainRule {\n /** Stable identifier, surfaced in rationales and telemetry. */\n id: string;\n /** Default true. */\n enabled?: boolean | undefined;\n /** Free-text note for humans; never interpreted. */\n description?: string | undefined;\n when: BrainRuleMatch;\n then: BrainRuleAction;\n}\n\ninterface CompiledMatch {\n sources?: ReadonlySet<string> | undefined;\n risks?: ReadonlySet<string> | undefined;\n minRiskLevel?: number | undefined;\n maxRiskLevel?: number | undefined;\n fallbacks?: ReadonlySet<string> | undefined;\n hasOptions?: boolean | undefined;\n offersOption?: string | undefined;\n question?: RegExp | undefined;\n context?: RegExp | undefined;\n notQuestion?: RegExp | undefined;\n notContext?: RegExp | undefined;\n}\n\nexport interface CompiledBrainRule {\n id: string;\n match: CompiledMatch;\n then: BrainRuleAction;\n}\n\nexport interface BrainRuleCompileResult {\n rules: CompiledBrainRule[];\n /** One entry per rejected rule: `<id>: <why>`. Hosts surface these; nothing throws. */\n errors: string[];\n}\n\nconst asSet = (value: string | string[] | undefined): ReadonlySet<string> | undefined => {\n if (value === undefined) return undefined;\n const items = Array.isArray(value) ? value : [value];\n return items.length > 0 ? new Set(items) : undefined;\n};\n\nfunction compilePattern(source: string | undefined, label: string, ruleId: string): RegExp | undefined {\n if (source === undefined) return undefined;\n if (source.length > BRAIN_RULE_PATTERN_MAX) {\n throw new Error(\n `${ruleId}: ${label} pattern is ${source.length} chars (max ${BRAIN_RULE_PATTERN_MAX})`,\n );\n }\n try {\n return new RegExp(source, 'i');\n } catch (err) {\n throw new Error(`${ruleId}: invalid ${label} pattern \u2014 ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\nfunction riskLevel(risk: BrainRisk | undefined, label: string, ruleId: string): number | undefined {\n if (risk === undefined) return undefined;\n const level = BRAIN_RISK_LEVELS[risk];\n if (level === undefined) throw new Error(`${ruleId}: unknown ${label} \"${risk}\"`);\n return level;\n}\n\n/**\n * Compile a rule table. Invalid rules are DROPPED with an explanatory error\n * rather than throwing: one bad pattern in a long-lived config must not take\n * the whole Brain offline, and the surviving rules are still useful.\n */\nexport function compileBrainRules(rules: readonly BrainRule[] | undefined): BrainRuleCompileResult {\n const compiled: CompiledBrainRule[] = [];\n const errors: string[] = [];\n const seen = new Set<string>();\n\n for (const [index, rule] of (rules ?? []).entries()) {\n const id = typeof rule?.id === 'string' && rule.id.trim() ? rule.id.trim() : `rule[${index}]`;\n try {\n if (rule.enabled === false) continue;\n if (seen.has(id)) throw new Error(`${id}: duplicate rule id`);\n if (!rule.when || typeof rule.when !== 'object') throw new Error(`${id}: missing \"when\"`);\n if (!rule.then || typeof rule.then !== 'object') throw new Error(`${id}: missing \"then\"`);\n\n const w = rule.when;\n const match: CompiledMatch = {\n sources: asSet(w.source),\n risks: asSet(w.risk),\n minRiskLevel: riskLevel(w.minRisk, 'minRisk', id),\n maxRiskLevel: riskLevel(w.maxRisk, 'maxRisk', id),\n fallbacks: asSet(w.fallback),\n hasOptions: w.hasOptions,\n offersOption: w.offersOption,\n question: compilePattern(w.question, 'question', id),\n context: compilePattern(w.context, 'context', id),\n notQuestion: compilePattern(w.notQuestion, 'notQuestion', id),\n notContext: compilePattern(w.notContext, 'notContext', id),\n };\n\n const action = rule.then.action;\n if (action !== 'answer' && action !== 'deny' && action !== 'escalate' && action !== 'defer') {\n throw new Error(`${id}: unknown action \"${String(action)}\"`);\n }\n if (action === 'answer' && !rule.then.optionId && !rule.then.text?.trim()) {\n throw new Error(`${id}: an \"answer\" rule needs an optionId or text`);\n }\n\n seen.add(id);\n // `when`/`then` is the rule DSL's public config vocabulary (documented\n // in configuration.md, mirrored in the WebUI wire types), so renaming it\n // would break user configs. The thenable hazard does not apply here:\n // `then` is always a BrainRuleAction OBJECT, and `await` only treats a\n // value as a promise when `.then` is CALLABLE \u2014 awaiting a compiled rule\n // would simply resolve to the rule itself.\n // biome-ignore lint/suspicious/noThenProperty: public rule-DSL field; the value is never callable\n compiled.push({ id, match, then: rule.then });\n } catch (err) {\n errors.push(err instanceof Error ? err.message : String(err));\n }\n }\n\n return { rules: compiled, errors };\n}\n\nconst subject = (value: string | undefined): string =>\n (value ?? '').slice(0, BRAIN_RULE_SUBJECT_MAX);\n\n/** Does this compiled rule apply to the request? */\nexport function ruleMatches(rule: CompiledBrainRule, request: BrainDecisionRequest): boolean {\n const m = rule.match;\n if (m.sources && !m.sources.has(request.source)) return false;\n if (m.risks && !m.risks.has(request.risk)) return false;\n if (m.fallbacks && !m.fallbacks.has(request.fallback)) return false;\n\n if (m.minRiskLevel !== undefined || m.maxRiskLevel !== undefined) {\n const level = BRAIN_RISK_LEVELS[request.risk];\n if (level === undefined) return false;\n if (m.minRiskLevel !== undefined && level < m.minRiskLevel) return false;\n if (m.maxRiskLevel !== undefined && level > m.maxRiskLevel) return false;\n }\n\n const optionCount = request.options?.length ?? 0;\n if (m.hasOptions !== undefined && m.hasOptions !== optionCount > 0) return false;\n if (m.offersOption !== undefined && !request.options?.some((o) => o.id === m.offersOption)) {\n return false;\n }\n\n if (m.question && !m.question.test(subject(request.question))) return false;\n if (m.notQuestion?.test(subject(request.question))) return false;\n\n // A context pattern cannot be satisfied by an absent context: rules that\n // demand evidence must not fire when there is none to inspect.\n if (m.context) {\n if (!request.context) return false;\n if (!m.context.test(subject(request.context))) return false;\n }\n if (m.notContext && request.context && m.notContext.test(subject(request.context))) return false;\n\n return true;\n}\n\n/**\n * Turn a matching rule into a decision. Returns null when the rule defers, or\n * when its action cannot be honoured (an `answer` naming an option the\n * request does not offer) \u2014 failing open to the next tier rather than\n * fabricating an option id the caller would not recognise.\n */\nexport function applyRule(\n rule: CompiledBrainRule,\n request: BrainDecisionRequest,\n): BrainDecision | null {\n const then = rule.then;\n const attribution = `Deterministic Brain rule \"${rule.id}\".`;\n\n switch (then.action) {\n case 'defer':\n return null;\n\n case 'deny':\n return {\n type: 'deny',\n reason: then.reason?.trim()\n ? `${then.reason.trim()} (${attribution})`\n : `${attribution} Denied without consulting a model.`,\n };\n\n case 'escalate':\n // The escalation ROUTER decides what `ask_human` ultimately becomes\n // (a real prompt in interactive mode, the terminal policy in headless),\n // so a rule only needs to declare that it wants out of the fast path.\n return {\n type: 'ask_human',\n prompt: then.prompt?.trim() || request.question,\n options: request.options,\n rationale: attribution,\n };\n\n case 'answer': {\n if (then.optionId !== undefined) {\n const option = request.options?.find((o) => o.id === then.optionId);\n if (!option) return null;\n return {\n type: 'answer',\n optionId: option.id,\n text: then.text?.trim() || option.label,\n rationale: then.rationale?.trim() || attribution,\n };\n }\n const text = then.text?.trim();\n if (!text) return null;\n return { type: 'answer', text, rationale: then.rationale?.trim() || attribution };\n }\n }\n}\n\n/** Evaluate a compiled table; first rule that yields a decision wins. */\nexport function evaluateBrainRules(\n rules: readonly CompiledBrainRule[],\n request: BrainDecisionRequest,\n): { decision: BrainDecision; ruleId: string } | null {\n for (const rule of rules) {\n if (!ruleMatches(rule, request)) continue;\n const decision = applyRule(rule, request);\n // A matching rule that produced nothing (defer, or an unusable action)\n // hands over to the NEXT TIER, not to the next rule \u2014 otherwise `defer`\n // could not express \"stop rule evaluation here\".\n if (decision) return { decision, ruleId: rule.id };\n return null;\n }\n return null;\n}\n\nexport interface RuleBrainArbiterOptions {\n /** Consulted when no rule decides. */\n inner: BrainArbiter;\n /** Live rule table \u2014 read per decision so config edits apply immediately. */\n getRules: () => readonly CompiledBrainRule[];\n /** Observability hook fired only when a rule actually decided. */\n onRuleDecision?: ((ruleId: string, request: BrainDecisionRequest, decision: BrainDecision) => void) | undefined;\n}\n\n/**\n * Deterministic rule tier. Sits in front of the policy tier so a configured\n * rule can settle a question before any of the tiers that cost tokens.\n */\nexport function createRuleBrainArbiter(opts: RuleBrainArbiterOptions): BrainArbiter {\n return {\n async decide(request: BrainDecisionRequest): Promise<BrainDecision> {\n const hit = evaluateBrainRules(opts.getRules(), request);\n if (hit) {\n markDecisionTier(request, 'rule');\n opts.onRuleDecision?.(hit.ruleId, request, hit.decision);\n return hit.decision;\n }\n return opts.inner.decide(request);\n },\n };\n}\n", "/**\n * Patch keys that are read per-decision via closures: no chain rebuild needed.\n *\n * These sets are the source of truth for which fields `mergePatch` accepts.\n * Adding a knob to `BrainConfigPatch` without listing it here makes `apply()`\n * throw `Unknown brain config field`, so keep them in step.\n */\nexport const FAST_PATH_KEYS: ReadonlySet<string> = new Set(['mode', 'maxAutoRisk', 'humanTimeoutMs']);\n\n/** Patch keys whose change requires the tier chain to be reassembled. */\nexport const STRUCTURAL_PATCH_KEYS: ReadonlySet<string> = new Set([\n 'models',\n 'strategy',\n 'decisionTimeoutMs',\n 'council',\n 'ledger',\n 'rules',\n 'heuristics',\n 'llm',\n 'trace',\n 'monitor',\n 'terminalPolicy',\n 'decisionLogMaxEntries',\n 'cache',\n]);\n\n/** Every key `mergePatch` accepts. Derived, never hand-maintained. */\nexport const KNOWN_PATCH_KEYS: ReadonlySet<string> = new Set([\n ...FAST_PATH_KEYS,\n ...STRUCTURAL_PATCH_KEYS,\n]);\n\nexport const AUTO_RISK_LEVELS: ReadonlySet<string> = new Set(['off', 'low', 'medium', 'high', 'all']);\nexport const COUNCIL_MIN_RISKS: ReadonlySet<string> = new Set(['medium', 'high', 'critical']);\nexport const COUNCIL_DISTINCTNESS: ReadonlySet<string> = new Set(['none', 'model', 'provider']);\nexport const TRACE_CONTENT_MODES: ReadonlySet<string> = new Set(['none', 'redacted', 'full']);\nexport const DENY_TERMINAL_MODES: ReadonlySet<string> = new Set(['never', 'when-decided', 'always']);\nexport const TERMINAL_POLICIES: ReadonlySet<string> = new Set([\n 'conservative',\n 'deny-all',\n 'continue-on-recommended',\n]);\n", "/**\n * BrainRuntime \u2014 the live, rebuildable owner of `config.brain`.\n *\n * The Brain chain used to be assembled once at boot; every knob except the\n * risk ceiling and escalation mode was frozen until restart. This module\n * makes the whole `BrainConfig` surface live-editable AND persistable from\n * any host surface (/brain subcommands, TUI Brain panel, WebUI BrainSection):\n *\n * - `arbiter` is a STABLE delegating handle (`decide` reads a mutable\n * `current`), so hosts wrap it once in their EscalationRouting/Observable\n * layers and no consumer ever needs a rebind after a settings change.\n * - `apply(patch)` normalizes + validates the patch, commits it, rebuilds\n * the tier chain when a structural knob changed (pool, council, timeout,\n * ledger guard), and persists through an injected callback \u2014 core never\n * touches config files itself.\n * - `getSnapshot()` is the JSON-safe truth both UIs render: configured\n * values plus derived facts (resolved pool/council labels, EFFECTIVE\n * council enablement, session-model fallback).\n *\n * Persistence contract: `config.brain` is on the in-project deny list, so\n * the injected `persist` MUST write the GLOBAL config. A persist failure\n * never rolls back the live change; it is reported via the returned promise.\n *\n * @module brain-runtime\n */\n\nimport {\n type BrainArbiter,\n type BrainDecisionRequest,\n type BrainEscalationMode,\n type BrainTerminalPolicy,\n DefaultBrainArbiter,\n} from '../coordination/brain.js';\nimport type { BrainHeuristicsConfig } from '../coordination/brain-heuristics.js';\nimport type { EventBus } from '../kernel/events.js';\nimport {\n BrainDecisionCache,\n createCachingBrainArbiter,\n} from '../coordination/brain-cache.js';\nimport { createLedgerGuardBrainArbiter } from '../coordination/brain-ledger.js';\nimport { BrainCircuitBreaker } from './brain-circuit.js';\nimport {\n type BrainRule,\n type CompiledBrainRule,\n compileBrainRules,\n createRuleBrainArbiter,\n} from '../coordination/brain-rules.js';\nimport { parseModelRef } from '../core/fallback-model.js';\nimport type { BrainConfig, BrainCouncilVoterConfig, BrainModelEntry } from '../types/config.js';\nimport type { Provider } from '../types/provider.js';\nimport {\n type BrainAutoRisk,\n createTieredBrainArbiter,\n DEFAULT_BRAIN_MAX_TOKENS,\n} from './autonomy-brain.js';\nimport { assembleBrainTiers } from './brain-chain.js';\nimport {\n AUTO_RISK_LEVELS,\n COUNCIL_DISTINCTNESS,\n COUNCIL_MIN_RISKS,\n DENY_TERMINAL_MODES,\n KNOWN_PATCH_KEYS,\n TERMINAL_POLICIES,\n TRACE_CONTENT_MODES,\n} from './brain-runtime-constants.js';\n\nexport type BrainCouncilMinRisk = 'medium' | 'high' | 'critical';\nexport type BrainPoolStrategy = 'fallback' | 'round-robin';\n\n/** JSON-safe view of the live Brain configuration + derived facts. */\nexport interface BrainConfigSnapshot {\n mode: BrainEscalationMode;\n maxAutoRisk: BrainAutoRisk;\n /** Configured pool entries (normalized). Empty = session model. */\n models: BrainModelEntry[];\n strategy: BrainPoolStrategy;\n decisionTimeoutMs: number | undefined;\n humanTimeoutMs: number | undefined;\n council: {\n /** EFFECTIVE enablement (default rule `voters >= 2` applied). */\n enabled: boolean;\n /** Raw configured value (undefined = default rule decides). */\n configured: boolean | undefined;\n minRisk: BrainCouncilMinRisk;\n /** Explicitly configured voters; seats derived from the pool are visible via `councilLabels`. */\n voters: BrainCouncilVoterConfig[];\n quorum: number | undefined;\n approval: number | undefined;\n judge: BrainModelEntry | undefined;\n perCallTimeoutMs: number | undefined;\n maxConcurrency: number | undefined;\n distinctness: 'none' | 'model' | 'provider';\n judgeMaxTokens: number | undefined;\n seats: Array<{ persona: string; veto?: boolean | undefined }>;\n };\n ledger: {\n enabled: boolean;\n autoDenyAfterFailures: number | undefined;\n path: string | undefined;\n maxMemoryEntries: number | undefined;\n interventionRetryWindowMs: number | undefined;\n };\n /** Configured deterministic rules, in evaluation order. */\n rules: BrainRule[];\n /** Effective single-LLM quality gate. */\n llm: {\n maxTokens: number;\n rejectUncertain: boolean;\n minConfidence: number;\n denyIsTerminal: 'never' | 'when-decided' | 'always';\n };\n /** Effective replay-trace settings. */\n trace: { enabled: boolean; content: 'none' | 'redacted' | 'full'; path: string | undefined };\n /** Configured monitor overrides (defaults are applied by BrainMonitor itself). */\n monitor: NonNullable<BrainConfig['monitor']>;\n /** Effective headless escalation variant. */\n terminalPolicy: BrainTerminalPolicy;\n /** Effective rolling decision-log size. */\n decisionLogMaxEntries: number;\n /** Live LLM circuit-breaker state, when a breaker is wired. */\n circuit: { state: string; consecutiveFailures: number } | undefined;\n /** Effective decision-cache settings plus live hit/miss counters. */\n cache: {\n enabled: boolean;\n ttlMs: number;\n maxEntries: number;\n hits: number;\n misses: number;\n size: number;\n };\n /** Effective heuristic toggles (defaults filled in). */\n // Spelled out rather than `Required<Omit<BrainHeuristicsConfig, \u2026>>`:\n // `Required` strips the `?` but NOT the explicit `| undefined` these fields\n // carry, so consumers would still see `boolean | undefined` for values the\n // snapshot always resolves.\n heuristics: {\n lowRiskAutoAnswer: boolean;\n blockedResolved: boolean;\n deadlockSkip: boolean;\n retryExhausted: boolean;\n continuePing: boolean;\n blockedResolvedMarkers: string[] | undefined;\n };\n /**\n * Compile diagnostics from the LAST assembly, one per dropped rule. Empty\n * when every configured rule compiled. Surfaced by the settings UIs so a\n * typo'd pattern is visible instead of silently inert.\n */\n ruleErrors: string[];\n /** Resolved pool labels from the LAST assembly (may be fewer than `models` \u2014 unresolvable refs are skipped). */\n poolLabels: string[];\n /** Resolved council seat labels; empty = council effectively disabled. */\n councilLabels: string[];\n /**\n * EFFECTIVE council judge, undefined when no council is wired.\n *\n * Distinct from `council.judge`, which is the CONFIGURED one and is usually\n * absent \u2014 the judge is then derived from the pool. Since the judge only\n * runs to break a tie or synthesize a split panel, whether it is one of the\n * seats that produced that tie is the difference between an independent\n * tie-breaker and voter #1 winning twice. Surfacing it is what makes that\n * checkable instead of implicit.\n */\n judgeLabel: string | undefined;\n /**\n * True when the effective judge is also one of the seated voters. Surfaces\n * render this as a warning; they must NOT re-derive it by matching\n * `judgeLabel` against the `councilLabels` display strings.\n */\n judgeIsVoter: boolean;\n usingSessionModel: boolean;\n}\n\n/** Council sub-patch. Arrays REPLACE; `null` clears back to the default. */\nexport interface BrainCouncilPatch {\n enabled?: boolean | null | undefined;\n minRisk?: BrainCouncilMinRisk | null | undefined;\n voters?: Array<string | BrainCouncilVoterConfig> | null | undefined;\n quorum?: number | null | undefined;\n approval?: number | null | undefined;\n judge?: string | BrainModelEntry | null | undefined;\n perCallTimeoutMs?: number | null | undefined;\n maxConcurrency?: number | null | undefined;\n distinctness?: 'none' | 'model' | 'provider' | null | undefined;\n judgeMaxTokens?: number | null | undefined;\n seats?: Array<{ persona: string; veto?: boolean | undefined }> | null | undefined;\n}\n\n/**\n * Partial update for the live Brain config. Omitted fields are untouched,\n * `null` clears a field back to its default, arrays replace wholesale.\n */\nexport interface BrainConfigPatch {\n mode?: BrainEscalationMode | undefined;\n maxAutoRisk?: BrainAutoRisk | undefined;\n models?: Array<string | BrainModelEntry> | null | undefined;\n strategy?: BrainPoolStrategy | null | undefined;\n decisionTimeoutMs?: number | null | undefined;\n humanTimeoutMs?: number | null | undefined;\n /** Replaces the whole table; `null` clears it. Rejected wholesale if any rule is invalid. */\n rules?: BrainRule[] | null | undefined;\n /** Merged field-by-field; `null` clears the whole block back to all-defaults. */\n heuristics?: BrainHeuristicsConfig | null | undefined;\n /** Single-LLM tier quality gate. Merged field-by-field; `null` clears it. */\n llm?: BrainConfig['llm'] | null | undefined;\n /** Replay trace. Merged field-by-field; `null` clears it. */\n trace?: BrainConfig['trace'] | null | undefined;\n /** Headless escalation variant. */\n terminalPolicy?: BrainTerminalPolicy | null | undefined;\n /** Rolling decision-log size for `/brain status`. */\n decisionLogMaxEntries?: number | null | undefined;\n /** Decision cache. Merged field-by-field; `null` clears it. */\n cache?: BrainConfig['cache'] | null | undefined;\n /**\n * Monitor thresholds. Merged field-by-field; `null` clears it.\n *\n * Live, like every other patch field \u2014 but the runtime does not own the\n * BrainMonitor, so the HOST must forward `snapshot.monitor` to\n * `BrainMonitor.reconfigure()` from `onApplied`. A host that skips that\n * wiring persists the setting and applies it on the next session.\n */\n monitor?: BrainConfig['monitor'] | null | undefined;\n council?: BrainCouncilPatch | null | undefined;\n ledger?:\n | {\n enabled?: boolean | undefined;\n autoDenyAfterFailures?: number | null | undefined;\n maxMemoryEntries?: number | null | undefined;\n interventionRetryWindowMs?: number | null | undefined;\n }\n | null\n | undefined;\n}\n\n/** Host-owned ledger controller \u2014 the runtime never touches ledger files. */\nexport interface BrainRuntimeLedgerHost {\n getPath: () => string | undefined;\n isEnabled: () => boolean;\n /** Host starts/stops its BrainDecisionLedger instance. */\n setEnabled: (enabled: boolean) => void;\n failureStreakFor?:\n | ((request: Pick<BrainDecisionRequest, 'source' | 'question' | 'id'>) => number)\n | undefined;\n getDecisionDigest?: ((request: BrainDecisionRequest) => string | undefined) | undefined;\n}\n\nexport interface BrainRuntimeOptions {\n /** Boot-time `config.brain`. Invalid entries are dropped leniently here (apply() is strict). */\n initialConfig: BrainConfig | undefined;\n /** The session's provider id (`config.provider`). */\n defaultProviderId: string;\n /** Live session provider \u2014 read per decision so `/setmodel` switches apply. */\n sessionProvider: () => Provider;\n /** Live session model id \u2014 read per decision. */\n sessionModel: () => string;\n /** Resolve a NON-default provider id. May throw / return null \u2192 entry skipped. */\n resolveProvider: (providerId: string, model: string) => Provider | null;\n ledger?: BrainRuntimeLedgerHost | undefined;\n /**\n * Injected writer for the canonical `BrainConfig`. MUST target the global\n * config (`config.brain` is denied in project scope). Absent = live-only.\n */\n persist?: ((config: BrainConfig) => Promise<void>) | undefined;\n /** Fired after every successful apply, with the fresh snapshot. */\n onApplied?: ((snapshot: BrainConfigSnapshot) => void) | undefined;\n /** Bus for Brain trace events. Absent = no LLM/council tracing. */\n events?: EventBus | undefined;\n}\n\nexport interface BrainApplyResult {\n snapshot: BrainConfigSnapshot;\n /** Resolves `{ok: true}` immediately when persistence was skipped or absent. */\n persisted: Promise<{ ok: boolean; error?: string | undefined }>;\n}\n\nexport interface BrainRuntime {\n /** STABLE arbiter handle \u2014 the inner tier chain swaps on `apply`. */\n arbiter: BrainArbiter;\n getMode(): BrainEscalationMode;\n getMaxAutoRisk(): BrainAutoRisk;\n getHumanTimeoutMs(): number | undefined;\n getSnapshot(): BrainConfigSnapshot;\n /** Canonical shape written to `config.brain` (compact string refs where lossless). */\n getConfig(): BrainConfig;\n /** Live-apply synchronously; persistence (default on) is async best-effort. */\n apply(patch: BrainConfigPatch, opts?: { persist?: boolean | undefined }): BrainApplyResult;\n}\n\nfunction normalizeEntry(raw: string | BrainModelEntry): BrainModelEntry {\n const parsed =\n typeof raw === 'string'\n ? (parseModelRef(raw) as { provider?: string | undefined; model?: string | undefined })\n : raw;\n const model = parsed.model?.trim();\n if (!model) {\n throw new Error(\n `Invalid model ref: ${typeof raw === 'string' ? `\"${raw}\"` : JSON.stringify(raw)} (expected \"model\" or \"provider/model\")`,\n );\n }\n const provider = parsed.provider?.trim();\n return provider ? { provider, model } : { model };\n}\n\nfunction normalizeVoter(raw: string | BrainCouncilVoterConfig): BrainCouncilVoterConfig {\n if (typeof raw === 'string') return normalizeEntry(raw);\n const base = normalizeEntry(raw);\n const voter: BrainCouncilVoterConfig = { ...base };\n if (raw.persona !== undefined) voter.persona = raw.persona;\n if (raw.weight !== undefined) {\n if (!Number.isFinite(raw.weight) || raw.weight <= 0) {\n throw new Error(`Invalid voter weight: ${String(raw.weight)} (must be a positive number)`);\n }\n voter.weight = raw.weight;\n }\n if (raw.veto !== undefined) voter.veto = raw.veto;\n return voter;\n}\n\nfunction requireFraction(value: number, label: string): number {\n if (!Number.isFinite(value) || value <= 0 || value > 1) {\n throw new Error(`Invalid ${label}: ${String(value)} (must be in (0, 1])`);\n }\n return value;\n}\n\nfunction requirePositiveMs(value: number, label: string): number {\n if (!Number.isFinite(value) || value <= 0) {\n throw new Error(\n `Invalid ${label}: ${String(value)} (must be a positive number of milliseconds)`,\n );\n }\n return Math.round(value);\n}\n\n/** Compact a normalized entry to the friendliest lossless config form. */\nfunction compactEntry(entry: BrainModelEntry): string {\n return entry.provider ? `${entry.provider}/${entry.model}` : entry.model;\n}\n\nfunction compactVoter(voter: BrainCouncilVoterConfig): string | BrainCouncilVoterConfig {\n if (voter.persona === undefined && voter.weight === undefined && voter.veto === undefined) {\n return compactEntry(voter);\n }\n return { ...voter };\n}\n\nexport interface BrainDefaultsContext {\n /** The session's fallback chain (`config.fallbackModels`) \u2014 seeds the default pool. */\n fallbackModels?: readonly string[] | undefined;\n}\n\n/**\n * Product defaults for hosts that want a minimum-human Brain out of the box\n * (CLI/TUI wiring and the standalone WebUI server both apply this before\n * `createBrainRuntime`). Only FILLS GAPS \u2014 every explicitly configured field\n * wins, so existing `config.brain` blocks are untouched by updates.\n *\n * - `models` \u2192 the user's own `fallbackModels` chain (never hardcoded\n * model ids; every install has different providers). With \u22652 entries the\n * council auto-derives from the pool, so multi-model users get a council\n * by default.\n * - `mode` \u2192 'headless': decisions never block on a human; the terminal\n * policy (safe default / deny) is the escalation of last resort.\n * - `maxAutoRisk` \u2192 adaptive: 'all' when a council can convene (critical\n * questions get a multi-model panel), otherwise 'high' (critical\n * questions resolve via the conservative terminal policy instead of a\n * single unchecked model).\n * - `humanTimeoutMs` \u2192 120s: if the user explicitly switches back to\n * 'interactive', an unanswered prompt still auto-resolves instead of\n * hanging an unattended run forever. Set `humanTimeoutMs: 0` to restore\n * the legacy wait-indefinitely behavior.\n *\n * NOTE deliberately NOT persisted anywhere \u2014 resolved at boot, so existing\n * users pick these up on update without any config migration/write.\n */\nexport function resolveBrainConfigDefaults(\n brain: BrainConfig | undefined,\n ctx: BrainDefaultsContext = {},\n): BrainConfig {\n const cfg: BrainConfig = { ...(brain ?? {}) };\n if (cfg.models === undefined && ctx.fallbackModels && ctx.fallbackModels.length > 0) {\n cfg.models = [...ctx.fallbackModels];\n }\n const seatCount = cfg.council?.voters?.length ?? cfg.models?.length ?? 0;\n const councilLikely = cfg.council?.enabled ?? seatCount >= 2;\n if (cfg.mode === undefined) cfg.mode = 'headless';\n if (cfg.maxAutoRisk === undefined) cfg.maxAutoRisk = councilLikely ? 'all' : 'high';\n if (cfg.humanTimeoutMs === undefined) cfg.humanTimeoutMs = 120_000;\n return cfg;\n}\n\n/** Lenient boot-time normalization: bad entries are dropped, not fatal. */\nfunction normalizeInitial(config: BrainConfig | undefined): BrainConfig {\n const cfg: BrainConfig = { ...(config ?? {}) };\n const safe = <T, R>(items: readonly T[] | undefined, map: (item: T) => R): R[] =>\n (items ?? []).flatMap((item) => {\n try {\n return [map(item)];\n } catch {\n return [];\n }\n });\n if (cfg.models) cfg.models = safe(cfg.models, normalizeEntry);\n // Rules are validated at COMPILE time (rebuild), where a bad rule disables\n // only itself and reports through `ruleErrors`. Nothing to drop here \u2014 but\n // a non-array from a hand-edited config would break compilation, so guard.\n if (cfg.rules !== undefined && !Array.isArray(cfg.rules)) cfg.rules = undefined;\n if (cfg.council) {\n const council = { ...cfg.council };\n if (council.voters) council.voters = safe(council.voters, normalizeVoter);\n if (council.judge) {\n try {\n council.judge = normalizeEntry(council.judge);\n } catch {\n council.judge = undefined;\n }\n }\n cfg.council = council;\n }\n return cfg;\n}\n\nexport function createBrainRuntime(opts: BrainRuntimeOptions): BrainRuntime {\n let cfg: BrainConfig = normalizeInitial(opts.initialConfig);\n let poolLabels: string[] = [];\n let councilLabels: string[] = [];\n let judgeLabel: string | undefined;\n let judgeIsVoter = false;\n let circuit: BrainCircuitBreaker | undefined;\n let decisionCache: BrainDecisionCache | undefined;\n let compiledRules: CompiledBrainRule[] = [];\n let ruleErrors: string[] = [];\n let current: BrainArbiter;\n\n // Digest + streak wrappers check the host's live ledger enablement per call\n // so a ledger toggle takes effect without re-plumbing.\n const getDecisionDigest = (request: BrainDecisionRequest): string | undefined => {\n const ledger = opts.ledger;\n if (!ledger?.isEnabled()) return undefined;\n return ledger.getDecisionDigest?.(request);\n };\n\n function rebuild(): void {\n const breakerCfg = cfg.llm?.circuitBreaker;\n circuit = new BrainCircuitBreaker({\n failureThreshold: breakerCfg?.failureThreshold,\n cooldownMs: breakerCfg?.cooldownMs,\n });\n const tiers = assembleBrainTiers({\n brainConfig: cfg,\n defaultProviderId: opts.defaultProviderId,\n sessionProvider: opts.sessionProvider,\n sessionModel: opts.sessionModel,\n resolveProvider: opts.resolveProvider,\n getDecisionDigest,\n events: opts.events,\n traceContent: cfg.trace?.content === undefined || cfg.trace.content === 'full',\n circuit,\n });\n poolLabels = tiers.poolLabels;\n councilLabels = tiers.councilLabels;\n judgeLabel = tiers.judgeLabel;\n judgeIsVoter = tiers.judgeIsVoter;\n const tiered = createTieredBrainArbiter({\n policy: new DefaultBrainArbiter({ heuristics: cfg.heuristics }),\n autonomous: tiers.autonomous,\n getMaxAutoRisk: () => cfg.maxAutoRisk ?? 'medium',\n council: tiers.council,\n getCouncilMinRisk: tiers.getCouncilMinRisk,\n // Product default 'when-decided', not the bare-API 'never': the tier\n // distinguishes a model that CONSIDERED the question and refused from a\n // pool that was never reached (`readLlmDenyKind`), and with 'never' that\n // distinction is unreachable \u2014 every refusal is discarded, so the LLM\n // tier can express agreement but never disagreement. Infrastructure\n // failures (unavailable / unparseable) still fall through untouched.\n // Same split as `maxAutoRisk`: the raw arbiter stays conservative for\n // callers that wire it directly; the product default lives here.\n getDenyIsTerminal: () => cfg.llm?.denyIsTerminal ?? 'when-decided',\n events: opts.events,\n });\n\n // Deterministic rules sit in FRONT of the tiered chain so a configured\n // rule settles the question before the policy/council/LLM ladder runs.\n // Compiled once per rebuild; the arbiter reads the array by reference so\n // there is no per-decision compilation cost.\n const compileResult = compileBrainRules(cfg.rules);\n compiledRules = compileResult.rules;\n ruleErrors = compileResult.errors;\n const ruled: BrainArbiter =\n compiledRules.length > 0\n ? createRuleBrainArbiter({ inner: tiered, getRules: () => compiledRules })\n : tiered;\n\n // Decision cache wraps the tiers but stays INSIDE the ledger guard: a\n // guard denial must always be evaluated against the live failure\n // history, never served from a cache.\n decisionCache?.stop();\n decisionCache = new BrainDecisionCache({\n enabled: cfg.cache?.enabled,\n ttlMs: cfg.cache?.ttlMs,\n maxEntries: cfg.cache?.maxEntries,\n events: opts.events,\n });\n decisionCache.start();\n const cached: BrainArbiter =\n cfg.cache?.enabled === true\n ? createCachingBrainArbiter({ inner: ruled, cache: decisionCache })\n : ruled;\n\n // The ledger guard stays OUTERMOST: a guard denial must be terminal, and\n // must not be overridable by a rule that would resurrect the very action\n // the observed failure history condemned.\n const streakFor = opts.ledger?.failureStreakFor;\n current =\n streakFor && opts.ledger?.isEnabled()\n ? createLedgerGuardBrainArbiter({\n inner: cached,\n failureStreakFor: streakFor,\n denyAfter: cfg.ledger?.autoDenyAfterFailures,\n })\n : cached;\n }\n rebuild();\n\n /** Merge + validate a patch into a NEW config. Throws before any state changes. */\n function mergePatch(patch: BrainConfigPatch): { next: BrainConfig; rebuildNeeded: boolean } {\n const next: BrainConfig = { ...cfg, council: cfg.council ? { ...cfg.council } : undefined };\n let rebuildNeeded = false;\n const structural = (): void => {\n rebuildNeeded = true;\n };\n\n if (patch.mode !== undefined) {\n if (patch.mode !== 'headless' && patch.mode !== 'interactive') {\n throw new Error(`Invalid mode: ${String(patch.mode)}`);\n }\n next.mode = patch.mode;\n }\n if (patch.maxAutoRisk !== undefined) {\n if (!AUTO_RISK_LEVELS.has(patch.maxAutoRisk)) {\n throw new Error(`Invalid maxAutoRisk: ${String(patch.maxAutoRisk)}`);\n }\n next.maxAutoRisk = patch.maxAutoRisk;\n }\n if (patch.humanTimeoutMs !== undefined) {\n next.humanTimeoutMs =\n patch.humanTimeoutMs === null\n ? undefined\n : requirePositiveMs(patch.humanTimeoutMs, 'humanTimeoutMs');\n }\n if (patch.models !== undefined) {\n next.models = patch.models === null ? undefined : patch.models.map(normalizeEntry);\n structural();\n }\n if (patch.strategy !== undefined) {\n if (\n patch.strategy !== null &&\n patch.strategy !== 'fallback' &&\n patch.strategy !== 'round-robin'\n ) {\n throw new Error(`Invalid strategy: ${String(patch.strategy)}`);\n }\n next.strategy = patch.strategy ?? undefined;\n structural();\n }\n if (patch.decisionTimeoutMs !== undefined) {\n next.decisionTimeoutMs =\n patch.decisionTimeoutMs === null\n ? undefined\n : requirePositiveMs(patch.decisionTimeoutMs, 'decisionTimeoutMs');\n structural();\n }\n if (patch.heuristics !== undefined) {\n if (patch.heuristics === null) {\n next.heuristics = undefined;\n } else {\n const h: BrainHeuristicsConfig = { ...(next.heuristics ?? {}) };\n for (const key of [\n 'lowRiskAutoAnswer',\n 'blockedResolved',\n 'deadlockSkip',\n 'retryExhausted',\n 'continuePing',\n ] as const) {\n const value = patch.heuristics[key];\n if (value === undefined) continue;\n if (typeof value !== 'boolean') {\n throw new Error(`Invalid heuristics.${key}: expected a boolean`);\n }\n h[key] = value;\n }\n if (patch.heuristics.blockedResolvedMarkers !== undefined) {\n const markers = patch.heuristics.blockedResolvedMarkers;\n if (markers !== null && !Array.isArray(markers)) {\n throw new Error('Invalid heuristics.blockedResolvedMarkers: expected an array');\n }\n h.blockedResolvedMarkers = markers ?? undefined;\n }\n next.heuristics = h;\n }\n structural();\n }\n if (patch.rules !== undefined) {\n if (patch.rules === null) {\n next.rules = undefined;\n } else {\n if (!Array.isArray(patch.rules)) throw new Error('Invalid rules: expected an array');\n // apply() is STRICT where boot is lenient: an interactive edit that\n // silently dropped half its rules would be worse than a clear error.\n const { errors } = compileBrainRules(patch.rules);\n if (errors.length > 0) {\n throw new Error(`Invalid Brain rule(s): ${errors.join('; ')}`);\n }\n next.rules = [...patch.rules];\n }\n structural();\n }\n if (patch.council !== undefined) {\n if (patch.council === null) {\n next.council = undefined;\n } else {\n const c = { ...(next.council ?? {}) };\n const p = patch.council;\n if (p.enabled !== undefined) c.enabled = p.enabled === null ? undefined : p.enabled;\n if (p.minRisk !== undefined) {\n if (p.minRisk !== null && !COUNCIL_MIN_RISKS.has(p.minRisk)) {\n throw new Error(`Invalid council minRisk: ${String(p.minRisk)}`);\n }\n c.minRisk = p.minRisk ?? undefined;\n }\n if (p.voters !== undefined) {\n c.voters = p.voters === null ? undefined : p.voters.map(normalizeVoter);\n }\n if (p.quorum !== undefined) {\n c.quorum = p.quorum === null ? undefined : requireFraction(p.quorum, 'council quorum');\n }\n if (p.approval !== undefined) {\n c.approval =\n p.approval === null ? undefined : requireFraction(p.approval, 'council approval');\n }\n if (p.judge !== undefined) {\n c.judge = p.judge === null ? undefined : normalizeEntry(p.judge);\n }\n for (const key of ['perCallTimeoutMs', 'maxConcurrency', 'judgeMaxTokens'] as const) {\n const v = p[key];\n if (v === undefined) continue;\n if (v !== null && (!Number.isInteger(v) || v <= 0)) {\n throw new Error(`Invalid council.${key}: ${String(v)} (must be a positive integer)`);\n }\n c[key] = v ?? undefined;\n }\n if (p.distinctness !== undefined) {\n if (p.distinctness !== null && !COUNCIL_DISTINCTNESS.has(p.distinctness)) {\n throw new Error(`Invalid council.distinctness: ${String(p.distinctness)}`);\n }\n c.distinctness = p.distinctness ?? undefined;\n }\n if (p.seats !== undefined) {\n if (p.seats === null) {\n c.seats = undefined;\n } else {\n if (!Array.isArray(p.seats)) throw new Error('Invalid council.seats: expected an array');\n for (const seat of p.seats) {\n if (!seat?.persona?.trim()) {\n throw new Error('Invalid council.seats: every seat needs a persona');\n }\n }\n c.seats = p.seats.map((seat) => ({ ...seat }));\n }\n }\n next.council = c;\n }\n structural();\n }\n if (patch.terminalPolicy !== undefined) {\n if (patch.terminalPolicy !== null && !TERMINAL_POLICIES.has(patch.terminalPolicy)) {\n throw new Error(`Invalid terminalPolicy: ${String(patch.terminalPolicy)}`);\n }\n next.terminalPolicy = patch.terminalPolicy ?? undefined;\n }\n if (patch.decisionLogMaxEntries !== undefined) {\n const n = patch.decisionLogMaxEntries;\n if (n !== null && (!Number.isInteger(n) || n <= 0)) {\n throw new Error(`Invalid decisionLogMaxEntries: ${String(n)} (must be a positive integer)`);\n }\n next.decisionLogMaxEntries = n ?? undefined;\n }\n if (patch.cache !== undefined) {\n if (patch.cache === null) {\n next.cache = undefined;\n } else {\n const c = { ...(next.cache ?? {}) };\n if (patch.cache.enabled !== undefined) {\n if (typeof patch.cache.enabled !== 'boolean') {\n throw new Error('Invalid cache.enabled: expected a boolean');\n }\n c.enabled = patch.cache.enabled;\n }\n for (const key of ['ttlMs', 'maxEntries'] as const) {\n const v = patch.cache[key];\n if (v === undefined) continue;\n if (!Number.isInteger(v) || v <= 0) {\n throw new Error(`Invalid cache.${key}: ${String(v)} (must be a positive integer)`);\n }\n c[key] = v;\n }\n next.cache = c;\n }\n structural();\n }\n if (patch.llm !== undefined) {\n if (patch.llm === null) {\n next.llm = undefined;\n } else {\n const l = { ...(next.llm ?? {}) };\n if (patch.llm.maxTokens !== undefined) {\n const n = patch.llm.maxTokens;\n if (!Number.isInteger(n) || n <= 0) {\n throw new Error(`Invalid llm.maxTokens: ${String(n)} (must be a positive integer)`);\n }\n l.maxTokens = n;\n }\n if (patch.llm.rejectUncertain !== undefined) {\n if (typeof patch.llm.rejectUncertain !== 'boolean') {\n throw new Error('Invalid llm.rejectUncertain: expected a boolean');\n }\n l.rejectUncertain = patch.llm.rejectUncertain;\n }\n if (patch.llm.denyIsTerminal !== undefined) {\n if (!DENY_TERMINAL_MODES.has(patch.llm.denyIsTerminal)) {\n throw new Error(`Invalid llm.denyIsTerminal: ${String(patch.llm.denyIsTerminal)}`);\n }\n l.denyIsTerminal = patch.llm.denyIsTerminal;\n }\n if (patch.llm.minConfidence !== undefined) {\n const n = patch.llm.minConfidence;\n if (!Number.isFinite(n) || n < 0 || n > 1) {\n throw new Error(`Invalid llm.minConfidence: ${String(n)} (must be in [0, 1])`);\n }\n l.minConfidence = n;\n }\n next.llm = l;\n }\n structural();\n }\n if (patch.trace !== undefined) {\n if (patch.trace === null) {\n next.trace = undefined;\n } else {\n const t = { ...(next.trace ?? {}) };\n if (patch.trace.enabled !== undefined) {\n if (typeof patch.trace.enabled !== 'boolean') {\n throw new Error('Invalid trace.enabled: expected a boolean');\n }\n t.enabled = patch.trace.enabled;\n }\n if (patch.trace.content !== undefined) {\n if (!TRACE_CONTENT_MODES.has(patch.trace.content)) {\n throw new Error(`Invalid trace.content: ${String(patch.trace.content)}`);\n }\n t.content = patch.trace.content;\n }\n if (patch.trace.path !== undefined) t.path = patch.trace.path || undefined;\n if (patch.trace.maxOpenRecords !== undefined) {\n const n = patch.trace.maxOpenRecords;\n if (!Number.isInteger(n) || n <= 0) {\n throw new Error(\n `Invalid trace.maxOpenRecords: ${String(n)} (must be a positive integer)`,\n );\n }\n t.maxOpenRecords = n;\n }\n next.trace = t;\n }\n structural();\n }\n if (patch.monitor !== undefined) {\n next.monitor =\n patch.monitor === null ? undefined : { ...(next.monitor ?? {}), ...patch.monitor };\n structural();\n }\n if (patch.ledger !== undefined) {\n if (patch.ledger === null) {\n next.ledger = undefined;\n } else {\n const l = { ...(next.ledger ?? {}) };\n if (patch.ledger.enabled !== undefined) l.enabled = patch.ledger.enabled;\n if (patch.ledger.autoDenyAfterFailures !== undefined) {\n const n = patch.ledger.autoDenyAfterFailures;\n if (n !== null && (!Number.isInteger(n) || n < 0)) {\n throw new Error(\n `Invalid autoDenyAfterFailures: ${String(n)} (must be an integer >= 0)`,\n );\n }\n l.autoDenyAfterFailures = n ?? undefined;\n }\n for (const key of ['maxMemoryEntries', 'interventionRetryWindowMs'] as const) {\n const v = patch.ledger[key];\n if (v === undefined) continue;\n if (v !== null && (!Number.isInteger(v) || v <= 0)) {\n throw new Error(`Invalid ledger.${key}: ${String(v)} (must be a positive integer)`);\n }\n l[key] = v ?? undefined;\n }\n next.ledger = l;\n }\n structural();\n }\n\n // Structural keys already flagged themselves above; anything not covered\n // by either key set is a typo or a field that was added to the patch type\n // without being registered here, and must fail loudly.\n for (const key of Object.keys(patch)) {\n if ((patch as Record<string, unknown>)[key] === undefined) continue;\n if (!KNOWN_PATCH_KEYS.has(key)) {\n throw new Error(`Unknown brain config field: ${key}`);\n }\n }\n return { next, rebuildNeeded };\n }\n\n function getSnapshot(): BrainConfigSnapshot {\n const councilCfg = cfg.council;\n const voters = (councilCfg?.voters ?? []).map((v) => normalizeVoter(v));\n return {\n mode: cfg.mode ?? 'interactive',\n maxAutoRisk: cfg.maxAutoRisk ?? 'medium',\n models: (cfg.models ?? []).map((m) => normalizeEntry(m)),\n strategy: cfg.strategy ?? 'fallback',\n decisionTimeoutMs: cfg.decisionTimeoutMs,\n humanTimeoutMs: cfg.humanTimeoutMs,\n council: {\n enabled: councilLabels.length > 0,\n configured: councilCfg?.enabled,\n minRisk: councilCfg?.minRisk ?? 'high',\n voters,\n quorum: councilCfg?.quorum,\n approval: councilCfg?.approval,\n judge: councilCfg?.judge ? normalizeEntry(councilCfg.judge) : undefined,\n perCallTimeoutMs: councilCfg?.perCallTimeoutMs,\n maxConcurrency: councilCfg?.maxConcurrency,\n distinctness: councilCfg?.distinctness ?? 'none',\n judgeMaxTokens: councilCfg?.judgeMaxTokens,\n seats: (councilCfg?.seats ?? []).map((seat) => ({ ...seat })),\n },\n ledger: {\n enabled: opts.ledger?.isEnabled() ?? false,\n autoDenyAfterFailures: cfg.ledger?.autoDenyAfterFailures,\n path: opts.ledger?.getPath(),\n maxMemoryEntries: cfg.ledger?.maxMemoryEntries,\n interventionRetryWindowMs: cfg.ledger?.interventionRetryWindowMs,\n },\n rules: (cfg.rules ?? []).map((rule) => ({ ...rule })),\n llm: {\n maxTokens: cfg.llm?.maxTokens ?? DEFAULT_BRAIN_MAX_TOKENS,\n rejectUncertain: cfg.llm?.rejectUncertain ?? true,\n minConfidence: cfg.llm?.minConfidence ?? 0,\n denyIsTerminal: cfg.llm?.denyIsTerminal ?? 'when-decided',\n },\n trace: {\n enabled: cfg.trace?.enabled === true,\n content: cfg.trace?.content ?? 'full',\n path: cfg.trace?.path,\n },\n monitor: { ...(cfg.monitor ?? {}) },\n terminalPolicy: cfg.terminalPolicy ?? 'conservative',\n decisionLogMaxEntries: cfg.decisionLogMaxEntries ?? 20,\n circuit: circuit\n ? {\n state: circuit.state(),\n consecutiveFailures: circuit.snapshot().consecutiveFailures,\n }\n : undefined,\n cache: {\n enabled: cfg.cache?.enabled === true,\n ttlMs: cfg.cache?.ttlMs ?? 300_000,\n maxEntries: cfg.cache?.maxEntries ?? 200,\n hits: decisionCache?.snapshot().hits ?? 0,\n misses: decisionCache?.snapshot().misses ?? 0,\n size: decisionCache?.snapshot().size ?? 0,\n },\n heuristics: {\n lowRiskAutoAnswer: cfg.heuristics?.lowRiskAutoAnswer ?? true,\n blockedResolved: cfg.heuristics?.blockedResolved ?? true,\n deadlockSkip: cfg.heuristics?.deadlockSkip ?? true,\n retryExhausted: cfg.heuristics?.retryExhausted ?? true,\n continuePing: cfg.heuristics?.continuePing ?? true,\n blockedResolvedMarkers: cfg.heuristics?.blockedResolvedMarkers\n ? [...cfg.heuristics.blockedResolvedMarkers]\n : undefined,\n },\n ruleErrors: [...ruleErrors],\n poolLabels: [...poolLabels],\n councilLabels: [...councilLabels],\n judgeLabel,\n judgeIsVoter,\n usingSessionModel: (cfg.models ?? []).length === 0,\n };\n }\n\n function getConfig(): BrainConfig {\n const out: BrainConfig = {};\n if (cfg.mode !== undefined) out.mode = cfg.mode;\n if (cfg.maxAutoRisk !== undefined) out.maxAutoRisk = cfg.maxAutoRisk;\n if (cfg.models?.length) out.models = cfg.models.map((m) => compactEntry(normalizeEntry(m)));\n if (cfg.strategy !== undefined) out.strategy = cfg.strategy;\n if (cfg.decisionTimeoutMs !== undefined) out.decisionTimeoutMs = cfg.decisionTimeoutMs;\n if (cfg.humanTimeoutMs !== undefined) out.humanTimeoutMs = cfg.humanTimeoutMs;\n if (cfg.council !== undefined) {\n const c = cfg.council;\n const outCouncil: NonNullable<BrainConfig['council']> = {};\n if (c.enabled !== undefined) outCouncil.enabled = c.enabled;\n if (c.minRisk !== undefined) outCouncil.minRisk = c.minRisk;\n if (c.voters?.length)\n outCouncil.voters = c.voters.map((v) => compactVoter(normalizeVoter(v)));\n if (c.quorum !== undefined) outCouncil.quorum = c.quorum;\n if (c.approval !== undefined) outCouncil.approval = c.approval;\n if (c.judge !== undefined) outCouncil.judge = compactEntry(normalizeEntry(c.judge));\n // Same rule as the top level: a field missing here is DELETED from the\n // user's config on the next apply(). Guarded by brain-config-roundtrip.\n if (c.perCallTimeoutMs !== undefined) outCouncil.perCallTimeoutMs = c.perCallTimeoutMs;\n if (c.maxConcurrency !== undefined) outCouncil.maxConcurrency = c.maxConcurrency;\n if (c.distinctness !== undefined) outCouncil.distinctness = c.distinctness;\n if (c.judgeMaxTokens !== undefined) outCouncil.judgeMaxTokens = c.judgeMaxTokens;\n if (c.seats?.length) outCouncil.seats = c.seats.map((seat) => ({ ...seat }));\n out.council = outCouncil;\n }\n if (cfg.rules?.length) out.rules = cfg.rules.map((rule) => ({ ...rule }));\n if (cfg.heuristics !== undefined) out.heuristics = { ...cfg.heuristics };\n if (cfg.ledger !== undefined) out.ledger = { ...cfg.ledger };\n if (cfg.monitor !== undefined) out.monitor = { ...cfg.monitor };\n // Blocks that are boot-only (no patch surface yet) must STILL be copied:\n // `apply()` persists this object wholesale, so a field missing here is\n // silently deleted from the user's config the next time any Brain\n // setting changes. `brain-config-roundtrip` guards this.\n if (cfg.trace !== undefined) out.trace = { ...cfg.trace };\n if (cfg.llm !== undefined) out.llm = { ...cfg.llm };\n if (cfg.cache !== undefined) out.cache = { ...cfg.cache };\n if (cfg.terminalPolicy !== undefined) out.terminalPolicy = cfg.terminalPolicy;\n if (cfg.decisionLogMaxEntries !== undefined) {\n out.decisionLogMaxEntries = cfg.decisionLogMaxEntries;\n }\n return out;\n }\n\n return {\n arbiter: {\n decide: (request) => current.decide(request),\n },\n getMode: () => cfg.mode ?? 'interactive',\n getMaxAutoRisk: () => cfg.maxAutoRisk ?? 'medium',\n getHumanTimeoutMs: () => cfg.humanTimeoutMs,\n getSnapshot,\n getConfig,\n apply(patch, applyOpts) {\n const { next, rebuildNeeded } = mergePatch(patch);\n cfg = next;\n // Ledger enablement is host-owned state \u2014 toggle it BEFORE rebuilding\n // so the guard wrap sees the new value.\n if (patch.ledger && patch.ledger.enabled !== undefined) {\n opts.ledger?.setEnabled(patch.ledger.enabled);\n }\n if (rebuildNeeded) rebuild();\n const snapshot = getSnapshot();\n const shouldPersist = applyOpts?.persist !== false && opts.persist !== undefined;\n const persisted: Promise<{ ok: boolean; error?: string | undefined }> = shouldPersist\n ? (opts.persist as (config: BrainConfig) => Promise<void>)(getConfig()).then(\n () => ({ ok: true }),\n (err: unknown) => ({\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n }),\n )\n : Promise.resolve({ ok: true });\n opts.onApplied?.(snapshot);\n return { snapshot, persisted };\n },\n };\n}\n", "import * as fsp from 'node:fs/promises';\nimport type { EventBus } from '../kernel/events.js';\nimport { atomicWrite, withFileLock } from '../utils/atomic-write.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport { color } from '../utils/color.js';\nimport { resolveWstackPaths } from '../utils/wstack-paths.js';\nimport { FsError, ERROR_CODES } from '../types/errors.js';\n\n/**\n * Long-running autonomous mission. A goal survives across sessions and\n * drives the EternalAutonomyEngine \u2014 every iteration of the engine\n * consults the goal to choose what to do next.\n *\n * Storage: `~/.wrongstack/projects/<hash>/goal.json`. Persistent and\n * project-scoped on purpose: the goal belongs to the codebase, not the\n * REPL session.\n */\n\nexport interface JournalEntry {\n /** ISO timestamp of the iteration. */\n at: string;\n /** Sequential iteration counter (1-based, monotonically increasing). */\n iteration: number;\n /** Source that produced the action ('todo' | 'git' | 'brainstorm' | 'resume' | 'manual' | 'parallel' | 'deliverable'). */\n source: 'todo' | 'git' | 'brainstorm' | 'resume' | 'manual' | 'parallel' | 'deliverable';\n /** Short one-line description of what the iteration set out to do. */\n task: string;\n /** Outcome status. */\n status: 'success' | 'failure' | 'aborted' | 'skipped';\n /** Optional free-form note (error message, summary, etc.). */\n note?: string | undefined;\n /** Optional token usage delta for this iteration. */\n tokens?: { input: number; output: number } | undefined;\n /** Optional USD cost delta for this iteration (provider-estimated). */\n costUsd?: number | undefined;\n}\n\nexport interface GoalFile {\n version: 1;\n /** The raw mission statement as entered by the user. */\n goal: string;\n /**\n * LLM-refined version of the goal \u2014 unambiguous, with concrete\n * deliverables and acceptance criteria.\n */\n refinedGoal?: string | undefined;\n /**\n * Concrete, verifiable deliverables extracted from the refined goal.\n */\n deliverables?: string[] | undefined;\n /**\n * Estimated completion 0-100. Updated by the engine after each\n * iteration. Null means \"not yet assessed\".\n */\n progress?: number | undefined;\n /** Human-readable note explaining the current progress estimate. */\n progressNote?: string | undefined;\n /**\n * Time-series of progress measurements for trend analysis.\n * Last 200 entries retained. Use `recordProgress()` to append.\n */\n progressHistory?: ProgressSnapshot[] | undefined;\n /**\n * Computed trend from recent progress measurements.\n * 'accelerating' | 'steady' | 'stalling' | undefined.\n */\n progressTrend?: 'accelerating' | 'steady' | 'stalling' | undefined;\n /** When the goal was first set or last replaced. */\n setAt: string;\n /** Updated on every iteration completion. */\n lastActivityAt: string;\n /** Total iterations the engine has run against this goal (cumulative). */\n iterations: number;\n /** Engine lifecycle state \u2014 'running' means another process owns this goal. */\n engineState: 'idle' | 'running' | 'stopped';\n /** Mission-level lifecycle. */\n goalState?: 'active' | 'paused' | 'completed' | 'abandoned' | undefined;\n /** Goal-linked Kanban board id. Optional for pre-Kanban goal files. */\n kanbanBoardId?: string | undefined;\n /** ISO timestamp recorded after Brain verifies that every deliverable is reached. */\n reachedAt?: string | undefined;\n /** Durable human-readable reach verdict; currently the literal `goal reached`. */\n reachedNote?: string | undefined;\n /**\n * Per-todo attempt counter.\n */\n todoAttempts?: Record<string, number>;\n /** Bounded ring buffer of recent iterations (newest last). */\n journal: JournalEntry[];\n}\n\n/** Cap on persisted journal entries \u2014 older entries are evicted FIFO. */\nexport const MAX_JOURNAL_ENTRIES = 500;\n\n/**\n * Resolve the goal file path for a given project root.\n *\n * SINGLE canonical location: the per-project directory that\n * `resolveWstackPaths()` uses for everything else (sessions, memory, specs) \u2014\n * `~/.wrongstack/projects/<slug>/goal.json`. This is the same path the `/goal`\n * slash command writes via `opts.paths.projectGoal`, so every reader/writer\n * (the eternal/parallel autonomy engines, the CLI autonomy commands, the TUI\n * F9 panel, and `/goal` itself) now agree on one file.\n *\n * Previously this returned a SEPARATE hash-based dir (`projects/<hash>/`), which\n * disagreed with `/goal` and littered the home dir with thousands of stray\n * `<hash>/goal.json` directories that held nothing else.\n */\nexport function goalFilePath(projectRoot: string): string {\n return resolveWstackPaths({ projectRoot }).projectGoal;\n}\n\nexport async function loadGoal(\n filePath: string,\n events?: EventBus,\n warn?: (msg: string) => void,\n): Promise<GoalFile | null> {\n const t0 = Date.now();\n let raw: string;\n try {\n raw = await fsp.readFile(filePath, 'utf8');\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ENOENT') {\n events?.emit('storage.read', {\n sessionId: '~boot~',\n store: 'goal',\n filePath,\n operation: 'load',\n outcome: 'success',\n durationMs: Date.now() - t0,\n });\n return null; // file doesn't exist \u2014 not an error\n }\n events?.emit('storage.error', {\n sessionId: '~boot~',\n store: 'goal',\n filePath,\n operation: 'load',\n error: toErrorMessage(err),\n recoverable: false,\n });\n throw err; // permission errors etc. should surface\n }\n try {\n const parsed = JSON.parse(raw) as GoalFile;\n if (parsed?.version !== 1 || typeof parsed.goal !== 'string' || !Array.isArray(parsed.journal)) {\n (warn ?? ((msg) => console.warn(JSON.stringify({ level: 'warn', event: 'goal_store.invalid_schema', path: filePath, message: msg, timestamp: new Date().toISOString() }))))(\n 'invalid schema \u2014 consider deleting and re-creating',\n );\n events?.emit('storage.read', {\n sessionId: '~boot~',\n store: 'goal',\n filePath,\n operation: 'load',\n outcome: 'failure',\n durationMs: Date.now() - t0,\n error: 'invalid_schema',\n });\n return null;\n }\n events?.emit('storage.read', {\n sessionId: '~boot~',\n store: 'goal',\n filePath,\n operation: 'load',\n outcome: 'success',\n durationMs: Date.now() - t0,\n });\n return parsed;\n } catch {\n (warn ?? ((msg) => console.warn(JSON.stringify({ level: 'warn', event: 'goal_store.parse_failed', path: filePath, message: msg, timestamp: new Date().toISOString() }))))(\n 'JSON parse failed \u2014 consider deleting and re-creating',\n );\n events?.emit('storage.read', {\n sessionId: '~boot~',\n store: 'goal',\n filePath,\n operation: 'load',\n outcome: 'failure',\n durationMs: Date.now() - t0,\n error: 'parse_failed',\n });\n return null;\n }\n}\n\nexport async function saveGoal(filePath: string, goal: GoalFile, events?: EventBus): Promise<void> {\n const t0 = Date.now();\n try {\n await atomicWrite(filePath, JSON.stringify(goal, null, 2), { mode: 0o600 });\n events?.emit('storage.write', {\n sessionId: '~boot~',\n store: 'goal',\n filePath,\n operation: 'save',\n outcome: 'success',\n durationMs: Date.now() - t0,\n });\n } catch (err) {\n events?.emit('storage.error', {\n sessionId: '~boot~',\n store: 'goal',\n filePath,\n operation: 'save',\n error: toErrorMessage(err),\n recoverable: false,\n });\n throw new FsError({\n message: toErrorMessage(err),\n code: ERROR_CODES.FS_ATOMIC_WRITE_FAILED,\n path: filePath,\n cause: err,\n });\n }\n}\n\n/**\n * Atomically load, modify, and save a goal file under a file lock.\n * Prevents lost-update races when the autonomy engine and CLI /goal commands\n * write concurrently (both eternal and parallel engines may run simultaneously).\n *\n * `fn` receives the current GoalFile (or `null` if no goal exists yet)\n * and must return the updated GoalFile (or `null` to delete).\n */\nexport async function updateGoal(\n filePath: string,\n fn: (current: GoalFile | null) => GoalFile | null,\n events?: EventBus,\n): Promise<void> {\n const t0 = Date.now();\n await withFileLock(filePath, async () => {\n const current = await loadGoal(filePath, events);\n const next = fn(current);\n if (next) {\n await saveGoal(filePath, next, events);\n } else {\n try {\n await fsp.unlink(filePath);\n events?.emit('storage.write', {\n sessionId: '~boot~',\n store: 'goal',\n filePath,\n operation: 'delete',\n outcome: 'success',\n durationMs: Date.now() - t0,\n });\n } catch (err) {\n events?.emit('storage.error', {\n sessionId: '~boot~',\n store: 'goal',\n filePath,\n operation: 'delete',\n error: toErrorMessage(err),\n recoverable: true,\n });\n // best-effort \u2014 file may not exist\n }\n }\n events?.emit('storage.write', {\n sessionId: '~boot~',\n store: 'goal',\n filePath,\n operation: 'update',\n outcome: 'success',\n durationMs: Date.now() - t0,\n });\n });\n}\n\nexport function emptyGoal(goal: string): GoalFile {\n const now = new Date().toISOString();\n return {\n version: 1,\n goal,\n setAt: now,\n lastActivityAt: now,\n iterations: 0,\n engineState: 'idle',\n goalState: 'active',\n todoAttempts: {},\n journal: [],\n };\n}\n\n/**\n * Set progress estimate on a goal. Returns a new GoalFile.\n * Clamps progress to 0-100.\n */\nexport function setProgress(\n goal: GoalFile,\n progress: number,\n note?: string,\n): GoalFile {\n const clamped = Math.min(100, Math.max(0, progress));\n return {\n ...goal,\n progress: clamped,\n progressNote: note ?? clamped + '% complete',\n };\n}\n\n/**\n * Append a journal entry, bumping iteration counters and trimming the\n * ring buffer. Returns a new GoalFile \u2014 does not mutate the argument.\n */\nexport function appendJournal(goal: GoalFile, entry: Omit<JournalEntry, 'iteration' | 'at'>): GoalFile {\n const iteration = goal.iterations + 1;\n const at = new Date().toISOString();\n const full: JournalEntry = { ...entry, iteration, at };\n const journal = [...goal.journal, full];\n const trimmed = journal.length > MAX_JOURNAL_ENTRIES\n ? journal.slice(journal.length - MAX_JOURNAL_ENTRIES)\n : journal;\n return {\n ...goal,\n iterations: iteration,\n lastActivityAt: at,\n journal: trimmed,\n };\n}\n\n/**\n * Aggregate cumulative cost + tokens across all journal entries.\n */\nexport function summarizeUsage(goal: GoalFile): {\n totalCostUsd: number;\n totalInputTokens: number;\n totalOutputTokens: number;\n iterationsWithUsage: number;\n} {\n let totalCostUsd = 0;\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let iterationsWithUsage = 0;\n for (const e of goal.journal) {\n if (typeof e.costUsd === 'number') totalCostUsd += e.costUsd;\n if (e.tokens) {\n totalInputTokens += e.tokens.input;\n totalOutputTokens += e.tokens.output;\n }\n if (typeof e.costUsd === 'number' || e.tokens) iterationsWithUsage++;\n }\n return { totalCostUsd, totalInputTokens, totalOutputTokens, iterationsWithUsage };\n}\n\nconst DOLLAR = '\\u0024';\n\n/** Format the goal + recent journal as a human-readable status block. */\nexport function formatGoal(goal: GoalFile, journalLimit = 10): string {\n const lines: string[] = [];\n\n // Header \u2014 show refined goal, with original as annotation if different\n const displayGoal = goal.refinedGoal || goal.goal;\n lines.push(color.bold('Goal') + ': ' + displayGoal);\n if (goal.refinedGoal && goal.refinedGoal !== goal.goal) {\n const snippet = goal.goal.length > 60 ? goal.goal.slice(0, 60) + '\u2026' : goal.goal;\n lines.push(color.dim(' (original: \"' + snippet + '\")'));\n }\n\n // Progress bar (20-segment)\n if (typeof goal.progress === 'number') {\n const pct = Math.min(100, Math.max(0, Math.round(goal.progress)));\n const filled = Math.round(pct / 5);\n const empty = 20 - filled;\n const bar = color.green('\u2588'.repeat(filled)) + color.dim('\u2591'.repeat(empty));\n lines.push('Progress: ' + bar + ' ' + color.bold(pct + '%'));\n if (goal.progressNote) {\n lines.push(' ' + color.dim(goal.progressNote));\n }\n // Trend indicator\n if (goal.progressTrend) {\n const trendIcon = goal.progressTrend === 'accelerating' ? '\uD83D\uDE80'\n : goal.progressTrend === 'stalling' ? '\u26A0\uFE0F'\n : '\u27A1\uFE0F';\n lines.push(' Trend: ' + trendIcon + ' ' + goal.progressTrend);\n }\n }\n\n // Deliverables checklist\n if (goal.deliverables && goal.deliverables.length > 0) {\n lines.push('');\n lines.push(color.bold('Deliverables:'));\n for (const d of goal.deliverables) {\n const done = /^\\[[x\u2713]\\]|\u2705|\\(done\\)/i.test(d);\n const marker = done ? color.green('\u2713') : color.dim('\u25CB');\n lines.push(' ' + marker + ' ' + d);\n }\n }\n\n lines.push('');\n lines.push('Set: ' + goal.setAt);\n lines.push('Last activity: ' + goal.lastActivityAt);\n lines.push('Iterations: ' + goal.iterations);\n const stateLabel = goal.goalState ?? 'active';\n lines.push('State: ' + stateLabel + (goal.iterations > 0 ? ' (iteration #' + goal.iterations + ')' : ''));\n lines.push('Engine: ' + goal.engineState);\n const usage = summarizeUsage(goal);\n if (usage.iterationsWithUsage > 0) {\n const spent = 'Spent: ' + DOLLAR + usage.totalCostUsd.toFixed(4)\n + ' (in ' + usage.totalInputTokens + ' / out ' + usage.totalOutputTokens\n + ' tokens across ' + usage.iterationsWithUsage + ' iterations)';\n lines.push(spent);\n }\n if (goal.journal.length > 0) {\n lines.push('');\n lines.push('Recent journal (last ' + Math.min(journalLimit, goal.journal.length) + '):');\n const tail = goal.journal.slice(-journalLimit);\n for (const e of tail) {\n const mark = e.status === 'success' ? '\u2713' : e.status === 'failure' ? '\u2717' : e.status === 'aborted' ? '\u2298' : '\u00B7';\n const note = e.note ? ' \u2014 ' + e.note : '';\n const cost = typeof e.costUsd === 'number' ? ' (' + DOLLAR + e.costUsd.toFixed(4) + ')' : '';\n lines.push(' #' + e.iteration + ' ' + mark + ' [' + e.source + '] ' + e.task + cost + note);\n }\n }\n return lines.join('\\n');\n}\n\n/** A single progress measurement at a point in time. */\nexport interface ProgressSnapshot {\n at: string;\n progress: number;\n note?: string | undefined;\n}\n\n/**\n * Parse [PROGRESS: N%] from agent final text.\n * Supports formats:\n * [PROGRESS: 45%]\n * [PROGRESS: 45%] \u2014 3/5 deliverables done\n * [progress: 100%]\n * Returns null if no match.\n */\nexport function parseProgressFromText(text: string): { progress: number; note?: string } | null {\n const re = /\\[progress:\\s*(\\d{1,3})%\\]\\s*(?:[\u2014-]\\s*(.+))?/i;\n const m = text.match(re);\n if (!m) return null;\n // Regex match guarantees capture group 1 exists, but use ?? fallback to\n // satisfy noUncheckedIndexedAccess without a non-null assertion.\n const progress = Math.min(100, Math.max(0, Number.parseInt(m[1] ?? '0', 10)));\n const note = m[2]?.trim() || undefined;\n return note === undefined ? { progress } : { progress, note };\n}\n\n/**\n * Record a progress measurement. Returns a new GoalFile with:\n * - progress + progressNote updated\n * - progressHistory appended (last 200 entries kept)\n * - progress trend computed (accelerating/steady/stalling)\n */\nexport function recordProgress(\n goal: GoalFile,\n progress: number,\n note?: string,\n): GoalFile {\n const clamped = Math.min(100, Math.max(0, progress));\n const history = [...(goal.progressHistory ?? []), { at: new Date().toISOString(), progress: clamped, note }];\n // Keep last 200 snapshots\n const trimmed = history.length > 200 ? history.slice(-200) : history;\n\n return {\n ...goal,\n progress: clamped,\n progressNote: note ?? `${clamped}% complete`,\n progressHistory: trimmed,\n progressTrend: computeTrend(trimmed),\n };\n}\n\n/** Max progress history entries to retain. */\nexport const MAX_PROGRESS_HISTORY = 200;\n\nfunction computeTrend(history: ProgressSnapshot[]): 'accelerating' | 'steady' | 'stalling' | undefined {\n if (history.length < 3) return undefined;\n const recent = history.slice(-5);\n const deltas: number[] = [];\n for (let i = 1; i < recent.length; i++) {\n deltas.push((recent[i]?.progress ?? 0) - (recent[i - 1]?.progress ?? 0));\n }\n /* v8 ignore next -- unreachable: history.length>=3 guard above guarantees >=2 deltas */\n if (deltas.length < 2) return undefined;\n const avgDelta = deltas.reduce((a, b) => a + b, 0) / deltas.length;\n if (avgDelta > 2) return 'accelerating';\n if (avgDelta < -1) return 'stalling';\n return 'steady';\n}\n", "import type { FileHandle } from 'node:fs/promises';\nimport {\n type AtomicWriteOptions,\n createPersistencePrimitives,\n type FileLockOptions,\n} from '@wrongstack/persistence';\nimport { FsError } from '../types/errors.js';\n\nexport type { AtomicWriteOptions, FileLockOptions } from '@wrongstack/persistence';\n\nconst primitives = createPersistencePrimitives({\n createLockTimeoutError: ({ targetPath, timeoutMs }) =>\n new FsError({\n message: `Timed out waiting for file lock: ${targetPath}`,\n code: 'FS_ATOMIC_WRITE_FAILED',\n path: targetPath,\n context: { timeoutMs },\n }),\n});\n\nexport const atomicWrite: (\n targetPath: string,\n content: string | Uint8Array,\n opts?: AtomicWriteOptions,\n) => Promise<void> = primitives.atomicWrite;\n/**\n * Atomic replace that streams its new contents instead of taking them as one\n * buffer. Use when the replacement is large enough that materializing it would\n * itself be the memory problem (log rotation, tail compaction).\n */\nexport const atomicReplaceWithWriter: <T>(\n targetPath: string,\n write: (handle: FileHandle) => Promise<T>,\n opts?: AtomicWriteOptions,\n) => Promise<T> = primitives.atomicReplaceWithWriter;\nexport const ensureDir: (dir: string) => Promise<void> = primitives.ensureDir;\nexport const withFileLock: <T>(\n targetPath: string,\n fn: () => Promise<T>,\n opts?: FileLockOptions,\n) => Promise<T> = primitives.withFileLock;\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", "/**\n * System-prompt contributor that surfaces eternal-autonomy state to the\n * model on every turn.\n *\n * Why this exists: when the engine drives a long-running loop, the\n * per-iteration directive carries the rules. But the directive is a USER\n * message \u2014 it scrolls out of working memory after a few compactions and\n * the model forgets it's in autonomy mode (forgets `[GOAL_COMPLETE]`,\n * forgets the todo-state protocol, forgets the no-confirmation rule).\n * Injecting the same anchor as a CACHED system-prompt block solves that\n * \u2014 the rules sit next to the identity layer and survive compactions.\n *\n * Block is tagged `ephemeral` so its content (journal tail, iteration\n * counter) changes each turn without invalidating the upstream prefix\n * cache.\n */\n\nimport type { TextBlock } from '../types/blocks.js';\nimport type { SystemPromptContributor } from '../types/system-prompt-contributor.js';\nimport { loadGoal } from '../storage/goal-store.js';\nimport {\n readBundledInstructionText,\n renderInstructionTemplate,\n} from '../utils/instruction-file.js';\n\nexport interface AutonomyPromptContributorOptions {\n /** Absolute path to the project's `goal.json`. */\n goalPath: string;\n /**\n * Gating function. The contributor consults this on every build and\n * returns an empty array when `false` \u2014 without this, the block would\n * leak into interactive runs that happen to have a goal on disk and\n * teach the model loop-control markers it shouldn't emit.\n *\n * Typical wiring: enable while `eternal` or `eternal-parallel` autonomy is active.\n */\n enabled: () => boolean;\n /** Number of journal entries to include in the recent-tail block. Default 5. */\n journalTailSize?: number | undefined;\n}\n\n/**\n * Build a contributor that renders the autonomy-state system block.\n * Returns `[]` when disabled, no goal exists, or the goal has been\n * completed/abandoned \u2014 all silent fast-paths.\n */\nexport function makeAutonomyPromptContributor(\n opts: AutonomyPromptContributorOptions,\n): SystemPromptContributor {\n return async (ctx): Promise<TextBlock[]> => {\n // Subagents run a single scoped task and don't drive the engine's\n // outer loop \u2014 they have no business emitting `[GOAL_COMPLETE]` or\n // marking todos. Skip the block entirely for subagent prompt builds,\n // mirroring how the active-plan layer is suppressed.\n if (ctx.subagent) return [];\n if (!opts.enabled()) return [];\n\n let goal: Awaited<ReturnType<typeof loadGoal>>;\n try {\n goal = await loadGoal(opts.goalPath);\n } catch {\n return [];\n }\n if (!goal) return [];\n\n // `active` is the default for legacy goal files without the field.\n const missionState = goal.goalState ?? 'active';\n if (missionState !== 'active') return [];\n\n const tailSize = opts.journalTailSize ?? 5;\n const journalTail = goal.journal.slice(-tailSize).map((e) => {\n const note = e.note ? ` \u2014 ${e.note.slice(0, 80)}` : '';\n return ` #${e.iteration} [${e.status}] ${e.task}${note}`;\n });\n\n const text = renderInstructionTemplate(\n readBundledInstructionText('autonomy/active-mission.md'),\n {\n mission: goal.goal,\n iteration: String(goal.iterations),\n recentJournal:\n journalTail.length > 0\n ? `Recent journal (last ${journalTail.length}):\\n${journalTail.join('\\n')}`\n : 'Recent journal: (none \u2014 this is the first iteration)',\n },\n );\n\n return [\n {\n type: 'text',\n text,\n cache_control: { type: 'ephemeral' },\n },\n ];\n };\n}\n", "/**\n * Design Studio \u2014 curated frontend/mobile UI design kits.\n *\n * A \"design kit\" is a self-contained, selectable design direction (an aesthetic\n * + concrete design tokens + per-stack implementation guidance) that the model\n * commits to BEFORE writing UI code. Kits are surfaced progressively: a compact\n * menu is injected when frontend work is detected, and the heavy kit body is\n * only loaded once the model (or user) picks one \u2014 keeping per-turn tokens low.\n *\n * This mirrors the skills subsystem (`types/skill.ts` + `execution/skill-loader.ts`)\n * but adds the per-stack body selection and a token snapshot for visual pickers.\n */\n\n/** Target implementation stacks a kit can speak to. */\nexport const DESIGN_STACKS = ['web', 'react-native', 'flutter', 'swiftui', 'compose'] as const;\n\nexport type DesignStack = (typeof DESIGN_STACKS)[number];\n\nexport function isDesignStack(v: string): v is DesignStack {\n return (DESIGN_STACKS as readonly string[]).includes(v);\n}\n\nexport interface DesignKitManifest {\n id: string;\n name: string;\n /** One-line vibe shown in the menu, e.g. \"Restrained, Linear-style minimalism\". */\n aesthetic: string;\n /** Free-form tags for filtering. */\n tags: string[];\n /** Stacks this kit provides guidance for. */\n stacks: DesignStack[];\n /** Whether the kit ships light + dark themes (almost always true). */\n themes: string[];\n /** \"Best for\u2026\" one-liner used in menu + pickers. */\n bestFor: string;\n version?: string | undefined;\n path: string;\n source: 'project' | 'user' | 'bundled';\n}\n\n/** A single theme's concrete token values (OKLCH strings, font names, etc.). */\nexport interface DesignTokenSet {\n [token: string]: string;\n}\n\n/**\n * The kind of value a token holds, inferred from its string form. Materialize\n * and verify branch on this so non-color axes (radius, spacing, type, motion)\n * are handled correctly \u2014 not just colors. See `classifyTokenValue`.\n */\nexport type TokenValueKind =\n | 'color' // oklch(...) / #hex\n | 'length' // 12px, 0.75rem, 100%, 2em\n | 'duration' // 150ms, 0.2s\n | 'number' // bare numeric (unitless scale/weight/line-height)\n | 'font' // font-family stack\n | 'shadow' // box-shadow definition (offset/blur/color \u2026)\n | 'gradient' // linear-/radial-gradient(...)\n | 'raw'; // anything else (kept verbatim)\n\n/**\n * Recognized token groups by kebab-scale prefix. A kit's `tokens.json` stays a\n * FLAT string map (backward compatible); richness comes from populating these\n * scale keys. `_foundations/tokens.json` supplies defaults that kits override\n * per-axis. CSS materialization maps each group to a Tailwind v4 `@theme`\n * namespace so utilities (`rounded-lg`, `p-4`, `text-base`, `shadow-2`) resolve\n * to the kit.\n *\n * Dot (`.`) is reserved for theme-scoping (`light.`/`dark.`) in overrides, so\n * scale token names use kebab (`radius-lg`, not `radius.lg`).\n */\nexport const KNOWN_TOKEN_GROUPS = {\n /** Corner radii. */\n radius: ['radius-none', 'radius-sm', 'radius-md', 'radius-lg', 'radius-xl', 'radius-full'],\n /** Spacing scale (4/8px rhythm). */\n space: ['space-1', 'space-2', 'space-3', 'space-4', 'space-6', 'space-8', 'space-12'],\n /** Type sizes. */\n text: ['text-xs', 'text-sm', 'text-base', 'text-lg', 'text-xl', 'text-2xl', 'text-3xl'],\n /** Line-heights (unitless). */\n leading: ['leading-tight', 'leading-normal', 'leading-relaxed'],\n /** Font weights (unitless). */\n weight: ['weight-normal', 'weight-medium', 'weight-semibold', 'weight-bold'],\n /** Letter-spacing. */\n tracking: ['tracking-tight', 'tracking-normal', 'tracking-wide'],\n /** Elevation / shadow ramp. */\n shadow: ['shadow-1', 'shadow-2', 'shadow-3', 'shadow-4'],\n /** Border widths. */\n border: ['border-hairline', 'border-thin', 'border-thick'],\n /** Motion durations. */\n duration: ['duration-fast', 'duration-base', 'duration-slow'],\n /** Motion easings. */\n ease: ['ease-standard', 'ease-emphasized'],\n /** Font families. */\n font: ['font-sans', 'font-mono', 'font-display'],\n} as const;\n\n/** Flat list of every known scale token name across all groups. */\nexport const KNOWN_TOKEN_NAMES: readonly string[] = Object.values(KNOWN_TOKEN_GROUPS).flat();\n\n/** Parsed `tokens.json` \u2014 light + dark token snapshots used by visual pickers. */\nexport interface DesignKitTokens {\n light?: DesignTokenSet | undefined;\n dark?: DesignTokenSet | undefined;\n}\n\n/** Compact menu entry rendered into the request when frontend work is detected. */\nexport interface DesignKitEntry {\n id: string;\n name: string;\n aesthetic: string;\n bestFor: string;\n stacks: DesignStack[];\n source: DesignKitManifest['source'];\n}\n\n/**\n * Live Design Studio state stashed on `ctx.meta.designStudio`. Set by the\n * detection middleware (user intent + frontend file writes); read by the\n * request middleware that injects the menu / active-kit reminder.\n */\nexport interface DesignStudioState {\n /** True once frontend/UI work has been detected this session. */\n active: boolean;\n /** Detected target stack, if any. */\n stack?: DesignStack | undefined;\n /** What triggered activation (for transparency / debugging). */\n signals: string[];\n /** Kit id the model/user committed to, if any. */\n activeKit?: string | undefined;\n /**\n * User color/token overrides applied over the active kit's tokens. Keys are\n * token names (`primary`) applied to both themes, or theme-scoped\n * (`light.bg`/`dark.bg`). See `applyTokenOverrides`.\n */\n overrides?: Record<string, string> | undefined;\n}\n\nexport interface DesignKitLoader {\n list(): Promise<DesignKitManifest[]>;\n /** Structured entries for the compact menu. */\n listEntries(): Promise<DesignKitEntry[]>;\n find(id: string): Promise<DesignKitManifest | undefined>;\n /** Compact, model-facing menu of every available kit. */\n menuText(): Promise<string>;\n /**\n * Full kit body for a given stack. Strips frontmatter and, when `stack` is\n * provided, narrows stack-specific sections to that stack.\n */\n readBody(id: string, stack?: DesignStack | undefined): Promise<string>;\n /** Parsed `tokens.json` for a kit (light/dark snapshots), if present. */\n readTokens(id: string): Promise<DesignKitTokens | undefined>;\n /** The mandatory cross-cutting baseline (responsive / a11y / theming / motion). */\n foundationsText(stack?: DesignStack | undefined): Promise<string>;\n invalidateCache(): void;\n}\n", "import { existsSync } from 'node:fs';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n DESIGN_STACKS,\n type DesignKitEntry,\n type DesignKitLoader,\n type DesignKitManifest,\n type DesignKitTokens,\n type DesignStack,\n isDesignStack,\n} from '../types/design-kit.js';\nimport { resolveWstackPaths } from '../utils/wstack-paths.js';\n\nconst KIT_FILE = 'KIT.md';\nconst TOKENS_FILE = 'tokens.json';\nconst FOUNDATIONS_ID = '_foundations';\n\n/** Strip leading YAML frontmatter, returning the markdown body. */\nfunction stripFrontmatter(raw: string): string {\n if (!raw.startsWith('---')) return raw;\n const end = raw.indexOf('\\n---', 4);\n if (end === -1) return raw;\n let body = raw.slice(end + 4);\n if (body.startsWith('\\n')) body = body.slice(1);\n return body;\n}\n\ninterface KitFrontmatter {\n id?: string;\n name?: string;\n aesthetic?: string;\n bestFor?: string;\n version?: string;\n tags: string[];\n stacks: DesignStack[];\n themes: string[];\n}\n\nfunction parseList(value: string): string[] {\n const trimmed = value.trim();\n const inner = trimmed.startsWith('[') && trimmed.endsWith(']') ? trimmed.slice(1, -1) : trimmed;\n return inner\n .split(',')\n .map((s) => s.trim().replace(/^[\"']|[\"']$/g, ''))\n .filter(Boolean);\n}\n\n/**\n * Minimal frontmatter parser supporting scalar fields and both inline\n * (`tags: [a, b]`) and block (`tags:\\n - a`) list syntax. Kit frontmatter is\n * authored by us (bundled) or trusted project owners, so we keep it small\n * rather than pulling in a full YAML dependency.\n */\nfunction parseKitFrontmatter(raw: string): KitFrontmatter {\n const out: KitFrontmatter = { tags: [], stacks: [], themes: [] };\n if (!raw.startsWith('---')) return out;\n const end = raw.indexOf('\\n---', 4);\n if (end === -1) return out;\n const block = raw.slice(4, end);\n const lines = block.split('\\n');\n let listKey: 'tags' | 'stacks' | 'themes' | null = null;\n const setScalar = (key: string, value: string) => {\n const v = value.trim().replace(/^[\"']|[\"']$/g, '');\n if (key === 'id') out.id = v;\n else if (key === 'name') out.name = v;\n else if (key === 'aesthetic') out.aesthetic = v;\n else if (key === 'bestFor') out.bestFor = v;\n else if (key === 'version') out.version = v;\n };\n const setList = (key: 'tags' | 'stacks' | 'themes', items: string[]) => {\n if (key === 'stacks') out.stacks = items.filter(isDesignStack);\n else out[key] = items;\n };\n for (const line of lines) {\n // Block-list item under an open list key.\n const bulletMatch = /^\\s*-\\s+(.*)$/.exec(line);\n if (listKey && bulletMatch) {\n const parsed = parseList(bulletMatch[1] ?? '');\n if (listKey === 'stacks') out.stacks.push(...parsed.filter(isDesignStack));\n else out[listKey].push(...parsed);\n continue;\n }\n const kvMatch = /^([a-zA-Z_]+):\\s*(.*)$/.exec(line);\n if (!kvMatch) continue;\n const key = kvMatch[1] ?? '';\n const rest = (kvMatch[2] ?? '').trim();\n if (key === 'tags' || key === 'stacks' || key === 'themes') {\n if (rest) {\n setList(key, parseList(rest));\n listKey = null;\n } else {\n listKey = key;\n }\n continue;\n }\n listKey = null;\n setScalar(key, rest);\n }\n return out;\n}\n\n/**\n * Keep cross-cutting sections plus only the requested stack's `## Stack: <id>`\n * section. When no stack is given, return the body unchanged. Stack sections\n * are delimited by `## Stack: <stack-id>` headings.\n */\nfunction narrowStackSections(body: string, stack?: DesignStack): string {\n if (!stack) return body;\n const stackHeading = /^##\\s+Stack:\\s*([a-z-]+)\\s*$/gim;\n const sections: { id: string; start: number }[] = [];\n let match: RegExpExecArray | null;\n // biome-ignore lint/suspicious/noAssignInExpressions: standard regex exec loop\n while ((match = stackHeading.exec(body)) !== null) {\n sections.push({ id: (match[1] ?? '').trim(), start: match.index });\n }\n if (sections.length === 0) return body;\n\n // Everything before the first `## Stack:` heading is cross-cutting content.\n const preambleEnd = sections[0]!.start;\n let result = body.slice(0, preambleEnd).trimEnd();\n\n let sectionEnd: number;\n for (let i = 0; i < sections.length; i++) {\n const current = sections[i]!;\n // Each section runs from its heading to the next heading (or end-of-body).\n sectionEnd = i + 1 < sections.length ? sections[i + 1]!.start : body.length;\n if (current.id === stack) {\n result += `\\n\\n${body.slice(current.start, sectionEnd).trimEnd()}`;\n }\n }\n return `${result}\\n`;\n}\n\nexport interface DesignKitLoaderOptions {\n /** <project>/.wrongstack/design-kits */\n inProjectDir: string;\n /** ~/.wrongstack/profiles/<name>/design-kits */\n globalDir: string;\n /** Bundled kits shipped with @wrongstack/core (packages/core/design-kits). */\n bundledDir?: string | undefined;\n}\n\n/**\n * Discovery order (highest priority first; later layers are shadowed by name):\n * 1. Project-committed: <project>/.wrongstack/design-kits/\n * 2. User profile: ~/.wrongstack/profiles/<name>/design-kits/\n * 3. Bundled with build: packages/core/design-kits/\n *\n * The `_foundations` directory is a reserved kit id holding the mandatory\n * cross-cutting baseline; it is excluded from the selectable menu.\n */\nexport class DefaultDesignKitLoader implements DesignKitLoader {\n private readonly dirs: { dir: string; source: DesignKitManifest['source'] }[];\n private cache?: DesignKitManifest[] | undefined;\n private readonly bodyCache = new Map<string, string>();\n private readonly tokenCache = new Map<string, DesignKitTokens | undefined>();\n private readonly rawTokenCache = new Map<string, DesignKitTokens | undefined>();\n\n constructor(opts: DesignKitLoaderOptions) {\n this.dirs = [\n { dir: opts.inProjectDir, source: 'project' },\n { dir: opts.globalDir, source: 'user' },\n ];\n if (opts.bundledDir) this.dirs.push({ dir: opts.bundledDir, source: 'bundled' });\n }\n\n async list(): Promise<DesignKitManifest[]> {\n if (this.cache) return this.cache;\n const found: DesignKitManifest[] = [];\n const seen = new Set<string>();\n for (const { dir, source } of this.dirs) {\n let entries: import('node:fs').Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n continue; // directory may not exist\n }\n for (const e of entries) {\n if (!e.isDirectory()) continue;\n const kitFile = path.join(dir, e.name, KIT_FILE);\n try {\n const raw = await fs.readFile(kitFile, 'utf8');\n const fm = parseKitFrontmatter(raw);\n const id = fm.id ?? e.name;\n if (!fm.name) continue;\n if (seen.has(id)) continue;\n seen.add(id);\n found.push({\n id,\n name: fm.name,\n aesthetic: fm.aesthetic ?? '',\n tags: fm.tags,\n stacks: fm.stacks.length > 0 ? fm.stacks : [...DESIGN_STACKS],\n themes: fm.themes.length > 0 ? fm.themes : ['light', 'dark'],\n bestFor: fm.bestFor ?? '',\n version: fm.version,\n path: kitFile,\n source,\n });\n } catch {\n // skip malformed kit\n }\n }\n }\n this.cache = found;\n return found;\n }\n\n /** Selectable kits only (excludes the reserved `_foundations` entry). */\n private async selectable(): Promise<DesignKitManifest[]> {\n return (await this.list()).filter((k) => k.id !== FOUNDATIONS_ID);\n }\n\n async listEntries(): Promise<DesignKitEntry[]> {\n return (await this.selectable()).map((k) => ({\n id: k.id,\n name: k.name,\n aesthetic: k.aesthetic,\n bestFor: k.bestFor,\n stacks: k.stacks,\n source: k.source,\n }));\n }\n\n async find(id: string): Promise<DesignKitManifest | undefined> {\n const all = await this.list();\n const lower = id.toLowerCase();\n return all.find((k) => k.id.toLowerCase() === lower);\n }\n\n async menuText(): Promise<string> {\n const entries = await this.listEntries();\n if (entries.length === 0) return '';\n const lines = ['## Design kits (pick ONE)'];\n for (const e of entries) {\n const stacks = e.stacks.join('/');\n lines.push(`- **${e.id}** \u2014 ${e.aesthetic}`);\n lines.push(` Best for: ${e.bestFor} \u00B7 Stacks: ${stacks}`);\n }\n return lines.join('\\n');\n }\n\n async readBody(id: string, stack?: DesignStack): Promise<string> {\n const key = `${id.toLowerCase()}:${stack ?? '*'}`;\n const cached = this.bodyCache.get(key);\n if (cached !== undefined) return cached;\n const m = await this.find(id);\n if (!m) throw new Error(`Design kit \"${id}\" not found`);\n const raw = await fs.readFile(m.path, 'utf8');\n const body = narrowStackSections(stripFrontmatter(raw), stack);\n this.bodyCache.set(key, body);\n return body;\n }\n\n /** Read a kit's OWN tokens.json (no foundations merge). Cached per id. */\n private async readRawTokens(id: string): Promise<DesignKitTokens | undefined> {\n const key = id.toLowerCase();\n if (this.rawTokenCache.has(key)) return this.rawTokenCache.get(key);\n const m = await this.find(id);\n let tokens: DesignKitTokens | undefined;\n if (m) {\n const tokensPath = path.join(path.dirname(m.path), TOKENS_FILE);\n try {\n const raw = await fs.readFile(tokensPath, 'utf8');\n tokens = JSON.parse(raw) as DesignKitTokens;\n } catch {\n tokens = undefined;\n }\n }\n this.rawTokenCache.set(key, tokens);\n return tokens;\n }\n\n /**\n * Read a kit's tokens with the `_foundations` base scales merged UNDER them\n * (kit values win, per theme). This is why every kit resolves a full\n * radius/space/type/motion scale even though its tokens.json only lists the\n * axes it changes. `_foundations` itself is returned raw (no self-merge).\n */\n async readTokens(id: string): Promise<DesignKitTokens | undefined> {\n const key = id.toLowerCase();\n if (this.tokenCache.has(key)) return this.tokenCache.get(key);\n let tokens: DesignKitTokens | undefined;\n if (key === FOUNDATIONS_ID) {\n tokens = await this.readRawTokens(FOUNDATIONS_ID);\n } else {\n const own = await this.readRawTokens(id);\n const base = await this.readRawTokens(FOUNDATIONS_ID);\n tokens = mergeKitTokens(base, own);\n }\n this.tokenCache.set(key, tokens);\n return tokens;\n }\n\n async foundationsText(stack?: DesignStack): Promise<string> {\n try {\n return await this.readBody(FOUNDATIONS_ID, stack);\n } catch {\n return '';\n }\n }\n\n invalidateCache(): void {\n this.cache = undefined;\n this.bodyCache.clear();\n this.tokenCache.clear();\n this.rawTokenCache.clear();\n }\n}\n\n/**\n * Merge foundations base scales UNDER a kit's own tokens, per theme (kit wins).\n * Returns undefined only when neither side has tokens. When a kit ships a single\n * theme, the other theme still resolves from the foundations base \u2014 so every\n * kit has a complete light AND dark scale set.\n */\nfunction mergeKitTokens(\n base: DesignKitTokens | undefined,\n own: DesignKitTokens | undefined,\n): DesignKitTokens | undefined {\n if (!base && !own) return undefined;\n if (!base) return own;\n if (!own) return base;\n const mergeTheme = (\n b: Record<string, string> | undefined,\n o: Record<string, string> | undefined,\n ): Record<string, string> | undefined => {\n if (!b && !o) return undefined;\n return { ...(b ?? {}), ...(o ?? {}) };\n };\n const light = mergeTheme(base.light, own.light);\n const dark = mergeTheme(base.dark, own.dark);\n const out: DesignKitTokens = {};\n if (light) out.light = light;\n if (dark) out.dark = dark;\n return out;\n}\n\n/**\n * Resolve the bundled `design-kits/` directory shipped alongside this module.\n * The directory is a sibling of `src/` (dev) and `dist/` (built), so we probe a\n * few candidate depths relative to the compiled module location and return the\n * first that exists. Returns `undefined` if none is found (treated as \"no\n * bundled kits this run\").\n */\nexport function resolveBundledDesignKitsDir(): string | undefined {\n try {\n const here = path.dirname(fileURLToPath(import.meta.url));\n const candidates = [\n path.join(here, 'design-kits'),\n path.join(here, '..', 'design-kits'),\n path.join(here, '..', '..', 'design-kits'),\n path.join(here, '..', '..', '..', 'design-kits'),\n ];\n for (const c of candidates) {\n if (existsSync(c)) return c;\n }\n } catch {\n // ignore\n }\n return undefined;\n}\n\nconst loaderMemo = new Map<string, DefaultDesignKitLoader>();\nconst LOADER_MEMO_MAX_PROJECTS = 32;\n\n/**\n * Memoized per-project loader. Used by the `design` tool and the Design Studio\n * middleware/slash-command so they share one cached instance without threading\n * the loader through every boot path. The loader is a pure disk reader (no\n * injected services), so a module-level memo is safe.\n */\nexport function getDesignKitLoader(projectRoot: string): DefaultDesignKitLoader {\n const existing = loaderMemo.get(projectRoot);\n if (existing) {\n loaderMemo.delete(projectRoot);\n loaderMemo.set(projectRoot, existing);\n return existing;\n }\n const paths = resolveWstackPaths({ projectRoot });\n const loader = new DefaultDesignKitLoader({\n inProjectDir: paths.inProjectDesignKits,\n globalDir: paths.globalDesignKits,\n bundledDir: resolveBundledDesignKitsDir(),\n });\n while (loaderMemo.size >= LOADER_MEMO_MAX_PROJECTS) {\n const oldest = loaderMemo.keys().next().value;\n if (oldest === undefined) break;\n loaderMemo.delete(oldest);\n }\n loaderMemo.set(projectRoot, loader);\n return loader;\n}\n\n/** Test helper \u2014 clears the per-project loader memo. */\nexport function _resetDesignKitLoaderMemo(): void {\n loaderMemo.clear();\n}\n", "/**\n * Project-local Design Studio store \u2014 a gitignored `<project>/.design/` directory\n * that persists design DECISIONS and project-specific design RULES across\n * sessions, separate from the committed `.wrongstack/design-kits/` (shared\n * custom kits). Layout:\n *\n * .design/.gitignore `*` \u2014 self-ignores so the dir is untracked in ANY repo\n * .design/rules.md project design rules (always injected when UI work is active)\n * .design/active.json { kit, stack } \u2014 the pinned kit, restored on session start\n * .design/decisions.md append-only log of kit choices (timestamp \u00B7 kit \u00B7 stack \u00B7 via)\n *\n * All writes are best-effort: a failure here must never break the tool, slash\n * command, or a turn.\n */\n\nimport { existsSync } from 'node:fs';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\nconst DESIGN_DIR = '.design';\n\nexport function designProjectDir(projectRoot: string): string {\n return path.join(projectRoot, DESIGN_DIR);\n}\n\nconst RULE_FILES = ['rules.md', 'RULES.md', 'design.md'];\n\nconst rulesCache = new Map<string, string | undefined>();\nconst RULES_CACHE_MAX_PROJECTS = 32;\n\n/** Read `.design/rules.md` (or RULES.md / design.md). Cached per project root. */\nexport async function loadProjectDesignRules(projectRoot: string): Promise<string | undefined> {\n if (rulesCache.has(projectRoot)) {\n const cached = rulesCache.get(projectRoot);\n rulesCache.delete(projectRoot);\n rulesCache.set(projectRoot, cached);\n return cached;\n }\n let rules: string | undefined;\n for (const name of RULE_FILES) {\n try {\n const txt = await fs.readFile(path.join(designProjectDir(projectRoot), name), 'utf8');\n if (txt.trim()) {\n rules = txt.trim();\n break;\n }\n } catch {\n // file absent \u2014 try next\n }\n }\n while (rulesCache.size >= RULES_CACHE_MAX_PROJECTS) {\n const oldest = rulesCache.keys().next().value;\n if (oldest === undefined) break;\n rulesCache.delete(oldest);\n }\n rulesCache.set(projectRoot, rules);\n return rules;\n}\n\n/**\n * User color/token overrides. Keys are token names (`primary`, `bg`, \u2026) applied\n * to BOTH themes, or theme-scoped (`light.primary`, `dark.bg`). Values are any\n * token string (OKLCH/hex). These override kit `tokens.json` everywhere tokens\n * are consumed \u2014 the `use` snapshot, `materialize`, and `verify`.\n */\nexport type DesignOverrides = Record<string, string>;\n\nexport interface PersistedActiveKit {\n kit: string;\n stack?: string | undefined;\n overrides?: DesignOverrides | undefined;\n}\n\nfunction parseOverrides(value: unknown): DesignOverrides | undefined {\n if (!value || typeof value !== 'object') return undefined;\n const out: DesignOverrides = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (typeof v === 'string' && v.trim()) out[k] = v.trim();\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\n/** Read the persisted active kit from `.design/active.json`, if any. */\nexport async function loadActiveKit(projectRoot: string): Promise<PersistedActiveKit | undefined> {\n try {\n const raw = await fs.readFile(path.join(designProjectDir(projectRoot), 'active.json'), 'utf8');\n const parsed = JSON.parse(raw) as { kit?: unknown; stack?: unknown; overrides?: unknown };\n if (parsed && typeof parsed.kit === 'string') {\n return {\n kit: parsed.kit,\n stack: typeof parsed.stack === 'string' ? parsed.stack : undefined,\n overrides: parseOverrides(parsed.overrides),\n };\n }\n } catch {\n // absent or malformed \u2014 no persisted kit\n }\n return undefined;\n}\n\n/**\n * Apply token overrides onto a kit's light/dark token sets. A bare key\n * (`primary`) is applied to both themes; a scoped key (`light.bg`/`dark.bg`)\n * only to that theme. Returns NEW objects \u2014 never mutates the input.\n */\nexport function applyTokenOverrides<\n T extends {\n light?: Record<string, string> | undefined;\n dark?: Record<string, string> | undefined;\n },\n>(tokens: T, overrides: DesignOverrides | undefined): T {\n if (!overrides || Object.keys(overrides).length === 0) return tokens;\n const light = { ...(tokens.light ?? {}) };\n const dark = { ...(tokens.dark ?? {}) };\n for (const [key, val] of Object.entries(overrides)) {\n // Only a `light.`/`dark.` prefix is theme-scoping. Any other dotted key\n // (or a bare key) is a LITERAL token name applied to both themes \u2014 so\n // kebab-scale names never collide, and a stray `foo.bar` isn't silently\n // dropped (the old code matched `dot > 0` but only acted on light/dark).\n const dot = key.indexOf('.');\n const theme = dot > 0 ? key.slice(0, dot) : '';\n if (theme === 'light') {\n light[key.slice(dot + 1)] = val;\n } else if (theme === 'dark') {\n dark[key.slice(dot + 1)] = val;\n } else {\n light[key] = val;\n dark[key] = val;\n }\n }\n return { ...tokens, light, dark };\n}\n\nasync function ensureDesignDir(projectRoot: string): Promise<string> {\n const dir = designProjectDir(projectRoot);\n await fs.mkdir(dir, { recursive: true });\n // Self-ignore: a `.gitignore` of `*` makes the whole directory untracked in\n // any project, so design decisions never pollute the repo and we don't have\n // to edit the project's root .gitignore.\n const gi = path.join(dir, '.gitignore');\n if (!existsSync(gi)) {\n try {\n await fs.writeFile(gi, '*\\n');\n } catch {\n // best-effort\n }\n }\n return dir;\n}\n\n/**\n * Persist a kit choice: update `active.json` and append to `decisions.md`.\n * `isoTime` is passed in so callers control the timestamp (and tests stay\n * deterministic). Best-effort \u2014 swallows all errors.\n */\nexport async function recordKitChoice(\n projectRoot: string,\n kit: string,\n stack: string | undefined,\n source: string,\n isoTime: string,\n overrides?: DesignOverrides | undefined,\n): Promise<void> {\n try {\n const dir = await ensureDesignDir(projectRoot);\n const record: Record<string, unknown> = { kit, stack: stack ?? null };\n if (overrides && Object.keys(overrides).length > 0) record.overrides = overrides;\n await fs.writeFile(path.join(dir, 'active.json'), `${JSON.stringify(record, null, 2)}\\n`);\n const line = `- ${isoTime} \u00B7 kit=${kit}${stack ? ` stack=${stack}` : ''} \u00B7 via=${source}\\n`;\n await fs.appendFile(path.join(dir, 'decisions.md'), line);\n } catch {\n // best-effort: never break the caller\n }\n}\n\n/**\n * Merge color/token overrides into `active.json` WITHOUT changing the pinned\n * kit (used by `design set primary=\u2026`). Returns the merged override map, or\n * undefined if there is no active kit to attach them to. Best-effort on write.\n */\nexport async function recordOverrides(\n projectRoot: string,\n patch: DesignOverrides,\n isoTime: string,\n): Promise<DesignOverrides | undefined> {\n const active = await loadActiveKit(projectRoot);\n if (!active) return undefined;\n const merged: DesignOverrides = { ...(active.overrides ?? {}) };\n for (const [k, v] of Object.entries(patch)) {\n if (v?.trim()) merged[k] = v.trim();\n else delete merged[k]; // empty value clears an override\n }\n try {\n const dir = await ensureDesignDir(projectRoot);\n const record: Record<string, unknown> = { kit: active.kit, stack: active.stack ?? null };\n if (Object.keys(merged).length > 0) record.overrides = merged;\n await fs.writeFile(path.join(dir, 'active.json'), `${JSON.stringify(record, null, 2)}\\n`);\n const keys = Object.keys(patch).join(',');\n await fs.appendFile(\n path.join(dir, 'decisions.md'),\n `- ${isoTime} \u00B7 kit=${active.kit} \u00B7 override=${keys} \u00B7 via=set\\n`,\n );\n } catch {\n // best-effort\n }\n return merged;\n}\n\n/** Clear the persisted active kit (e.g. `/design off`). Best-effort. */\nexport async function clearPersistedActiveKit(projectRoot: string): Promise<void> {\n try {\n await fs.rm(path.join(designProjectDir(projectRoot), 'active.json'), { force: true });\n } catch {\n // best-effort\n }\n}\n\n/** Test helper \u2014 clears the rules cache. */\nexport function _resetDesignRulesCache(): void {\n rulesCache.clear();\n}\n", "/**\n * Design Studio color utilities.\n *\n * Design kit tokens are authored in OKLCH (CSS-native, the modern 2026 default).\n * CSS targets keep them verbatim, but native stacks (React Native, Flutter,\n * SwiftUI, Compose) need concrete sRGB \u2014 so `materialize` converts each token\n * with `oklchToHex`. The verifier also normalizes colors to hex before\n * comparing, so an `oklch()` token and the same color written as `#rrggbb`\n * count as a match.\n *\n * Conversion is the standard Bj\u00F6rn Ottosson OKLab\u2192linear-sRGB pipeline; values\n * out of the sRGB gamut are clamped (not gamut-mapped) \u2014 adequate for the\n * near-in-gamut palettes our kits use.\n */\n\n/** Clamp a number into [lo, hi]. */\nfunction clamp(n: number, lo: number, hi: number): number {\n return n < lo ? lo : n > hi ? hi : n;\n}\n\n/** Parse an `oklch(L C H[ / a])` string into [L(0..1), C, H(deg), a(0..1)] or null. */\nexport function parseOklch(value: string): [number, number, number, number] | null {\n const m = /^oklch\\(\\s*([^)]+)\\)$/i.exec(value.trim());\n if (!m?.[1]) return null;\n // Split on whitespace and an optional `/ alpha`.\n const [coords, alphaPart] = m[1].split('/');\n const parts = (coords ?? '').trim().split(/\\s+/);\n if (parts.length < 3 || !parts[0] || !parts[1] || !parts[2]) return null;\n const L = parseComponent(parts[0], true);\n const C = parseComponent(parts[1], false);\n const H = parseAngle(parts[2]);\n if (L === null || C === null || H === null) return null;\n let a = 1;\n if (alphaPart !== undefined) {\n const av = parseComponent(alphaPart.trim(), true);\n if (av !== null) a = clamp(av, 0, 1);\n }\n return [clamp(L, 0, 1), Math.max(0, C), H, a];\n}\n\n/**\n * Parse a lightness/chroma/alpha component. `percentIsFraction` selects the\n * percentage reference range (CSS Color 4):\n * - L & alpha (`true`): 100% \u2192 1.0 (`62%` \u2192 0.62)\n * - chroma (`false`): 100% \u2192 0.4 (`50%` \u2192 0.20)\n * A bare number passes through unchanged for all three.\n */\nfunction parseComponent(s: string, percentIsFraction: boolean): number | null {\n s = s.trim();\n if (s.endsWith('%')) {\n const n = Number.parseFloat(s.slice(0, -1));\n if (!Number.isFinite(n)) return null;\n return percentIsFraction ? n / 100 : (n / 100) * 0.4;\n }\n const n = Number.parseFloat(s);\n return Number.isFinite(n) ? n : null;\n}\n\n/** Parse a hue angle: bare number or `145deg`. */\nfunction parseAngle(s: string): number | null {\n s = s.trim().replace(/deg$/i, '');\n const n = Number.parseFloat(s);\n return Number.isFinite(n) ? n : null;\n}\n\nfunction linearToSrgb(c: number): number {\n const v = c <= 0.0031308 ? 12.92 * c : 1.055 * c ** (1 / 2.4) - 0.055;\n return clamp(v, 0, 1);\n}\n\nfunction toHex2(n: number): string {\n return Math.round(n * 255)\n .toString(16)\n .padStart(2, '0');\n}\n\n/**\n * Convert an OKLCH string to `#rrggbb` (or `#rrggbbaa` when alpha < 1).\n * Returns null if `value` is not parseable OKLCH.\n */\nexport function oklchToHex(value: string): string | null {\n const parsed = parseOklch(value);\n if (!parsed) return null;\n const [L, C, Hdeg, alpha] = parsed;\n const h = (Hdeg * Math.PI) / 180;\n const a = C * Math.cos(h);\n const b = C * Math.sin(h);\n\n // OKLab \u2192 LMS (cube of the linear terms).\n const l_ = L + 0.3963377774 * a + 0.2158037573 * b;\n const m_ = L - 0.1055613458 * a - 0.0638541728 * b;\n const s_ = L - 0.0894841775 * a - 1.291485548 * b;\n const l = l_ * l_ * l_;\n const m = m_ * m_ * m_;\n const s = s_ * s_ * s_;\n\n // LMS \u2192 linear sRGB.\n const r = +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;\n const g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;\n const bl = -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s;\n\n let hex = `#${toHex2(linearToSrgb(r))}${toHex2(linearToSrgb(g))}${toHex2(linearToSrgb(bl))}`;\n if (alpha < 1) hex += toHex2(alpha);\n return hex;\n}\n\n/**\n * Normalize any color token to a lowercase `#rrggbb[aa]` hex when possible.\n * Passes through existing hex (lowercased, expanded from #rgb), converts\n * `oklch(...)`, and returns null for values we can't resolve (named colors,\n * gradients, non-color tokens like font names).\n */\nexport function colorToHex(value: string): string | null {\n const v = value.trim();\n const oklch = oklchToHex(v);\n if (oklch) return oklch.toLowerCase();\n const hex = /^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(v);\n if (hex?.[1]) {\n let h = hex[1].toLowerCase();\n if (h.length === 3 || h.length === 4) {\n h = h\n .split('')\n .map((c) => c + c)\n .join('');\n }\n return `#${h}`;\n }\n return null;\n}\n\n/** True when a token value looks like a color (OKLCH or hex), not a font/size. */\nexport function isColorToken(value: string): boolean {\n return colorToHex(value) !== null;\n}\n\n// \u2500\u2500 Value classification (color / length / duration / \u2026) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst LENGTH_RE = /^-?\\d*\\.?\\d+(?:px|rem|em|%|vw|vh|vmin|vmax|ch|pt)$/i;\nconst DURATION_RE = /^-?\\d*\\.?\\d+(?:ms|s)$/i;\nconst NUMBER_RE = /^-?\\d*\\.?\\d+$/;\nconst GRADIENT_RE = /\\b(?:linear|radial|conic)-gradient\\s*\\(/i;\n// A box-shadow-ish value: two+ offset lengths (the first is often a unitless\n// `0`), optionally `inset`, usually with a trailing color. Colors and single\n// lengths are caught earlier by classify, so this only sees multi-part values.\nconst OFFSET = String.raw`(?:0|-?\\d*\\.?\\d+(?:px|rem|em))`;\nconst SHADOW_RE = new RegExp(String.raw`(?:^|,)\\s*(?:inset\\s+)?${OFFSET}\\s+${OFFSET}`, 'i');\n\n/**\n * Classify a design-token string into the axis it drives, so materialize/verify\n * can branch beyond colors. Order matters: colors first (an `oklch()` is not a\n * gradient), then single-unit forms, then multi-part shadow, then font stacks.\n *\n * A font-family is inferred structurally (a comma-separated list, or a single\n * quoted/multi-word/known-generic name) rather than by a token-name allowlist,\n * so custom fonts classify correctly.\n */\nexport function classifyTokenValue(value: string): import('../types/design-kit.js').TokenValueKind {\n const v = value.trim();\n if (!v) return 'raw';\n if (isColorToken(v)) return 'color';\n if (GRADIENT_RE.test(v)) return 'gradient';\n if (LENGTH_RE.test(v)) return 'length';\n if (DURATION_RE.test(v)) return 'duration';\n if (NUMBER_RE.test(v)) return 'number';\n if (SHADOW_RE.test(v)) return 'shadow';\n // Font stack: has a comma (list), or looks like a family name.\n const GENERIC_FONTS =\n /\\b(sans-serif|serif|monospace|system-ui|ui-sans-serif|ui-monospace|ui-serif|cursive|fantasy|emoji)\\b/i;\n if (v.includes(',') || GENERIC_FONTS.test(v) || /^[\"']?[A-Za-z][\\w '-]*[\"']?$/.test(v)) {\n return 'font';\n }\n return 'raw';\n}\n", "/**\n * Heuristic adherence check: does generated UI code actually use the active\n * kit's palette, or did the model drift to off-palette hardcoded colors?\n *\n * `verifyFiles` is pure over file contents; `runDesignVerify` adds the node-side\n * file collection (explicit list or a bounded UI-file walk) so the `design` tool\n * and the WebUI handler share identical rules. For each file it scans color\n * literals (`#hex`, `oklch()`, `rgb()`) and generic Tailwind color utilities\n * (`bg-blue-500`), then flags any that don't resolve to a kit token (directly or\n * via the materialized CSS var / token name). It can't prove adherence \u2014 it\n * surfaces likely drift to steer a correction pass.\n */\n\nimport type { DesignKitTokens } from '../types/design-kit.js';\nimport { colorToHex, isColorToken } from './design-color.js';\n\n/** Which design axis a violation belongs to. */\nexport type DesignAxis = 'color' | 'radius' | 'spacing' | 'type' | 'motion';\n\nexport interface DesignViolation {\n file: string;\n line: number;\n snippet: string;\n reason: string;\n /** The design axis this drift belongs to. Defaults to 'color' (legacy). */\n axis?: DesignAxis;\n}\n\nexport interface DesignVerifyReport {\n filesScanned: number;\n /** Normalized kit palette (hex). */\n palette: string[];\n /** Kit color token names (for var/utility matching). */\n tokenNames: string[];\n violations: DesignViolation[];\n /** 0..1 \u2014 share of color signals that are on-palette. 1 when no signals. */\n score: number;\n ok: boolean;\n}\n\nconst HEX_RE = /#[0-9a-fA-F]{3,8}\\b/g;\nconst FUNC_COLOR_RE = /\\b(?:oklch|rgb|rgba|hsl|hsla)\\([^)]*\\)/gi;\n// Arbitrary-value Tailwind utilities BYPASS the token scale \u2014 a strong drift\n// signal regardless of the exact value. Radius: `rounded-[7px]`. Spacing:\n// `p-[13px]`, `mt-[5px]`, `gap-[10px]`. Utilities like `rounded-lg` / `p-4`\n// resolve to the kit's `@theme` scale, so they are NOT flagged.\nconst ARBITRARY_RADIUS_RE = /\\brounded(?:-[a-z]+)?-\\[[^\\]]+\\]/g;\nconst ARBITRARY_SPACING_RE = /\\b(?:p|px|py|pt|pr|pb|pl|m|mx|my|mt|mr|mb|ml|gap(?:-[xy])?|space-[xy])-\\[[^\\]]+\\]/g;\n// Raw hardcoded `border-radius:` length (CSS/inline style) that isn't a token\n// var or a trivial value (0, 50%, 9999px, full-round).\nconst RAW_RADIUS_RE = /border-radius:\\s*([^;{}]+)/gi;\n// Generic Tailwind palette utilities (bg-/text-/border-/ring-/from-/to-/via- + named scale).\nconst TW_GENERIC_RE =\n /\\b(?:bg|text|border|ring|from|to|via|fill|stroke|decoration|outline|shadow|accent|caret|divide)-(?:slate|gray|grey|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950)\\b/g;\n\nfunction kebab(name: string): string {\n return name\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .replace(/_/g, '-')\n .toLowerCase();\n}\n\nfunction buildPalette(tokens: DesignKitTokens): { hexes: Set<string>; names: string[] } {\n const hexes = new Set<string>();\n const names = new Set<string>();\n for (const set of [tokens.light, tokens.dark]) {\n if (!set) continue;\n for (const [k, v] of Object.entries(set)) {\n if (!isColorToken(v)) continue;\n names.add(k);\n const hex = colorToHex(v);\n if (hex) hexes.add(hex.toLowerCase().slice(0, 7)); // ignore alpha for matching\n }\n }\n return { hexes, names: [...names] };\n}\n\n/**\n * Verify a batch of file contents against a kit's (override-applied) tokens.\n */\nexport function verifyFiles(\n tokens: DesignKitTokens,\n files: { path: string; text: string }[],\n): DesignVerifyReport {\n const { hexes, names } = buildPalette(tokens);\n // Files that reference token names via CSS var / Tailwind token utility are\n // \"token-driven\" \u2014 we don't flag their literal-free color usage.\n const tokenNamePatterns = names.map((n) => kebab(n));\n\n const violations: DesignViolation[] = [];\n let onPalette = 0;\n let offPalette = 0;\n\n for (const { path, text } of files) {\n const lines = text.split('\\n');\n lines.forEach((lineText, i) => {\n const lineNo = i + 1;\n const flag = (snippet: string, reason: string, axis: DesignAxis = 'color') => {\n violations.push({ file: path, line: lineNo, snippet: snippet.slice(0, 80), reason, axis });\n };\n\n // Hardcoded hex + function colors \u2192 on/off palette.\n for (const re of [HEX_RE, FUNC_COLOR_RE]) {\n re.lastIndex = 0;\n for (const m of lineText.matchAll(re)) {\n const lit = m[0];\n const hex = colorToHex(lit);\n if (hex && hexes.has(hex.toLowerCase().slice(0, 7))) {\n onPalette++;\n } else if (hex) {\n offPalette++;\n flag(lit, 'off-palette hardcoded color (not a kit token)');\n }\n // non-color funcs (e.g. transform) silently ignored \u2014 hex null\n }\n }\n\n // Generic Tailwind palette utilities \u2192 drift.\n TW_GENERIC_RE.lastIndex = 0;\n for (const m of lineText.matchAll(TW_GENERIC_RE)) {\n offPalette++;\n flag(m[0], 'generic Tailwind palette utility \u2014 use kit token colors');\n }\n\n // \u2500\u2500 Non-color axes: radius / spacing bypass \u2500\u2500\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 // These push violations but do NOT affect the color `score` (which stays\n // a pure palette-adherence ratio); consumers break down by `axis`.\n ARBITRARY_RADIUS_RE.lastIndex = 0;\n for (const m of lineText.matchAll(ARBITRARY_RADIUS_RE)) {\n flag(m[0], 'arbitrary radius \u2014 use a kit radius scale token (rounded-sm\u2026rounded-full)', 'radius');\n }\n ARBITRARY_SPACING_RE.lastIndex = 0;\n for (const m of lineText.matchAll(ARBITRARY_SPACING_RE)) {\n flag(m[0], 'arbitrary spacing \u2014 use a kit spacing scale token (p-1\u2026p-12)', 'spacing');\n }\n RAW_RADIUS_RE.lastIndex = 0;\n for (const m of lineText.matchAll(RAW_RADIUS_RE)) {\n const val = (m[1] ?? '').trim();\n if (!val || val.startsWith('var(')) continue;\n if (/^(0|0px|9999px|50%|inherit|initial|unset|full)$/i.test(val)) continue;\n flag(`border-radius: ${val}`, 'hardcoded radius \u2014 use var(--radius-*) / a kit radius token', 'radius');\n }\n\n // Count token-name usages as on-palette signals (var(--primary), bg-primary\u2026).\n for (const tn of tokenNamePatterns) {\n if (tn.length < 2) continue;\n if (\n lineText.includes(`--${tn}`) ||\n new RegExp(`\\\\b(?:bg|text|border|ring|fill|stroke)-${tn}\\\\b`).test(lineText)\n ) {\n onPalette++;\n }\n }\n });\n }\n\n const total = onPalette + offPalette;\n const score = total === 0 ? 1 : onPalette / total;\n return {\n filesScanned: files.length,\n palette: [...hexes],\n tokenNames: names,\n violations,\n score,\n ok: violations.length === 0,\n };\n}\n\n// \u2500\u2500 Project-level verify (node IO) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nconst UI_EXT_RE = /\\.(css|scss|sass|less|tsx|jsx|vue|svelte|astro|html?)$/i;\nconst SKIP_DIR = new Set([\n 'node_modules',\n '.git',\n 'dist',\n 'build',\n '.next',\n 'out',\n 'coverage',\n '.wrongstack',\n '.design',\n]);\n\n/** Bounded recursive walk for frontend files under a project root. */\nasync function walkUiFiles(root: string, max = 200): Promise<string[]> {\n const { default: fs } = await import('node:fs/promises');\n const { default: nodePath } = await import('node:path');\n const found: string[] = [];\n async function rec(dir: string, depth: number): Promise<void> {\n if (found.length >= max || depth > 8) return;\n let entries: import('node:fs').Dirent[];\n try {\n entries = (await fs.readdir(dir, { withFileTypes: true })) as import('node:fs').Dirent[];\n } catch {\n return;\n }\n for (const e of entries) {\n if (found.length >= max) return;\n if (e.isDirectory()) {\n if (SKIP_DIR.has(e.name) || e.name.startsWith('.')) continue;\n await rec(nodePath.join(dir, e.name), depth + 1);\n } else if (UI_EXT_RE.test(e.name)) {\n found.push(nodePath.join(dir, e.name));\n }\n }\n }\n await rec(root, 0);\n return found;\n}\n\n/**\n * Resolve + read UI files (explicit list, or a bounded walk) and verify them\n * against a kit's tokens. Shared by the `design` tool and the WebUI handler so\n * the file-collection rules stay identical.\n */\nexport async function runDesignVerify(\n projectRoot: string,\n tokens: DesignKitTokens,\n explicitFiles?: string[] | undefined,\n): Promise<DesignVerifyReport> {\n const { default: fs } = await import('node:fs/promises');\n const { default: nodePath } = await import('node:path');\n const abs =\n explicitFiles && explicitFiles.length > 0\n ? explicitFiles.map((f) => (nodePath.isAbsolute(f) ? f : nodePath.join(projectRoot, f)))\n : await walkUiFiles(projectRoot);\n const files: { path: string; text: string }[] = [];\n for (const a of abs) {\n try {\n files.push({ path: nodePath.relative(projectRoot, a), text: await fs.readFile(a, 'utf8') });\n } catch {\n // unreadable \u2014 skip\n }\n }\n return verifyFiles(tokens, files);\n}\n", "/**\n * Design Studio detection + injection middleware.\n *\n * The system prompt is built ONCE per session (boot / project-switch), so a\n * system-prompt contributor cannot react to \"the model just started building a\n * UI\" mid-session. Instead, detection and injection ride the per-turn pipelines:\n *\n * - userInput middleware \u2192 detect UI intent in the user's message\n * - toolCall middleware \u2192 detect a frontend file being written\n * (both set `ctx.meta.designStudio`)\n * - request middleware \u2192 on every turn, read `ctx.meta.designStudio` and\n * append an ephemeral block to `req.system`: the kit menu (until a kit is\n * chosen) or a one-line adherence reminder (once chosen).\n *\n * Keeping the heavy kit body out of this path \u2014 the model loads it on demand via\n * the `design` tool \u2014 is what keeps per-turn token cost low.\n */\n\nimport type {\n AgentPipelines,\n ToolCallPipelinePayload,\n UserInputPayload,\n} from '../core/agent-types.js';\nimport type { Context } from '../core/context.js';\nimport type { Middleware } from '../kernel/pipeline.js';\nimport type { TextBlock } from '../types/blocks.js';\nimport type { DesignKitLoader, DesignStack, DesignStudioState } from '../types/design-kit.js';\nimport { isDesignStack } from '../types/design-kit.js';\nimport type { Request } from '../types/provider.js';\nimport { getDesignKitLoader } from './design-kit-loader.js';\nimport { applyTokenOverrides, loadActiveKit, loadProjectDesignRules } from './design-project-store.js';\nimport { verifyFiles } from './design-verify.js';\n\nconst META_KEY = 'designStudio';\n\nexport function getDesignState(ctx: {\n meta: Record<string, unknown>;\n}): DesignStudioState | undefined {\n const v = ctx.meta[META_KEY];\n return v && typeof v === 'object' ? (v as DesignStudioState) : undefined;\n}\n\nfunction ensureState(ctx: { meta: Record<string, unknown> }): DesignStudioState {\n let s = getDesignState(ctx);\n if (!s) {\n s = { active: false, signals: [] };\n ctx.meta[META_KEY] = s;\n }\n return s;\n}\n\n/** Mark Design Studio active and merge in detected signals/stack. */\nexport function activateDesign(\n ctx: { meta: Record<string, unknown> },\n signals: string[],\n stack?: DesignStack,\n): DesignStudioState {\n const s = ensureState(ctx);\n s.active = true;\n for (const sig of signals) if (!s.signals.includes(sig)) s.signals.push(sig);\n if (stack && !s.stack) s.stack = stack;\n return s;\n}\n\n/** Record the kit the model/user committed to. */\nexport function setActiveKit(\n ctx: { meta: Record<string, unknown> },\n kitId: string,\n stack?: DesignStack,\n overrides?: Record<string, string> | undefined,\n): void {\n const s = ensureState(ctx);\n s.active = true;\n s.activeKit = kitId;\n if (stack) s.stack = stack;\n if (overrides !== undefined) s.overrides = overrides;\n}\n\n/** Merge color/token overrides into the live state (used by `design set`). */\nexport function setDesignOverrides(\n ctx: { meta: Record<string, unknown> },\n overrides: Record<string, string>,\n): void {\n const s = ensureState(ctx);\n s.overrides = { ...(s.overrides ?? {}), ...overrides };\n}\n\n/** Clear the active kit (e.g. `/design off`), leaving detection state intact. */\nexport function clearActiveKit(ctx: { meta: Record<string, unknown> }): void {\n const s = getDesignState(ctx);\n if (s) s.activeKit = undefined;\n}\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\n\nconst STACK_HINTS: { re: RegExp; stack: DesignStack; label: string }[] = [\n { re: /\\b(flutter|dart)\\b/i, stack: 'flutter', label: 'flutter' },\n { re: /\\bjetpack\\s*compose\\b|\\bcompose\\b/i, stack: 'compose', label: 'compose' },\n { re: /\\bswift\\s*ui\\b|\\bswiftui\\b/i, stack: 'swiftui', label: 'swiftui' },\n { re: /\\b(react\\s*native|expo|nativewind)\\b/i, stack: 'react-native', label: 'react-native' },\n];\n\nconst WEB_INTENT_RE =\n /\\b(ui|ux|frontend|front-end|landing\\s*page|web\\s*site|website|web\\s*app|webapp|dashboard|screen|design\\s*system|component|react|next\\.?js|vue|svelte|tailwind|shadcn|css|theme|redesign|style|interface|hero\\s*section|navbar|sidebar|button|modal|form\\s*design)\\b/i;\n\nconst GENERIC_UI_RE = /\\b(ui|interface|screen|page|app|component|design)\\b/i;\n\n/**\n * Inspect user text for UI/design intent. Returns the strongest stack hint and\n * the matched signals, or `null` when nothing UI-ish was found.\n */\nexport function detectFrontendIntent(\n text: string,\n): { stack?: DesignStack; signals: string[] } | null {\n if (!text) return null;\n const signals: string[] = [];\n let stack: DesignStack | undefined;\n for (const h of STACK_HINTS) {\n if (h.re.test(text)) {\n signals.push(`intent:${h.label}`);\n stack ??= h.stack;\n }\n }\n const webMatch = WEB_INTENT_RE.exec(text);\n if (webMatch) {\n signals.push(`intent:${webMatch[0].toLowerCase().replace(/\\s+/g, '-')}`);\n stack ??= 'web';\n } else if (\n stack === undefined &&\n GENERIC_UI_RE.test(text) &&\n /\\b(build|make|create|design|implement|add)\\b/i.test(text)\n ) {\n // Weak generic signal \u2014 only when paired with a build verb.\n signals.push('intent:ui');\n stack = 'web';\n }\n if (signals.length === 0) return null;\n return stack ? { stack, signals } : { signals };\n}\n\nconst FRONTEND_EXT_STACK: { re: RegExp; stack?: DesignStack }[] = [\n { re: /\\.(tsx|jsx)$/i, stack: 'web' },\n { re: /\\.(css|scss|sass|less)$/i, stack: 'web' },\n { re: /\\.(vue|svelte|astro)$/i, stack: 'web' },\n { re: /\\.html?$/i, stack: 'web' },\n { re: /\\.dart$/i, stack: 'flutter' },\n { re: /\\.swift$/i, stack: 'swiftui' },\n];\n\n/** Detect whether a written/edited file path is a frontend file. */\nexport function detectFrontendFile(filePath: string): { stack?: DesignStack } | null {\n if (!filePath) return null;\n for (const { re, stack } of FRONTEND_EXT_STACK) {\n if (re.test(filePath)) return stack ? { stack } : {};\n }\n return null;\n}\n\n// \u2500\u2500 Middleware \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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/** userInput middleware: detect UI intent from the user's message. */\nexport function makeDesignDetectUserInputMiddleware(): Middleware<UserInputPayload> {\n return {\n name: 'DesignStudioDetectIntent',\n owner: 'core',\n async handler(payload, next) {\n const hit = detectFrontendIntent(payload.text);\n if (hit) activateDesign(payload.ctx, hit.signals, hit.stack);\n return next(payload);\n },\n };\n}\n\n/** toolCall middleware: detect frontend file writes/edits. */\nexport function makeDesignDetectToolCallMiddleware(): Middleware<ToolCallPipelinePayload> {\n return {\n name: 'DesignStudioDetectFile',\n owner: 'core',\n async handler(payload, next) {\n const name = payload.toolUse?.name;\n if (name === 'write' || name === 'edit' || name === 'replace' || name === 'patch') {\n const input = payload.toolUse.input as { path?: unknown } | undefined;\n const p = typeof input?.path === 'string' ? input.path : '';\n const hit = detectFrontendFile(p);\n if (hit) activateDesign(payload.ctx, [`file:${p}`], hit.stack);\n }\n return next(payload);\n },\n };\n}\n\nconst WRITE_TOOLS = new Set(['write', 'edit', 'replace', 'patch']);\n\n/**\n * toolCall middleware: after a frontend file is written/edited AND a kit is\n * pinned, scan the file for off-palette colors and append a non-blocking\n * warning to the tool result. This makes adherence PASSIVE \u2014 the model is\n * nudged toward kit tokens the moment it drifts, without anyone running\n * `design verify` by hand. Best-effort: any failure leaves the result untouched.\n */\nexport function makeDesignVerifyToolCallMiddleware(): Middleware<ToolCallPipelinePayload> {\n return {\n name: 'DesignStudioVerifyWrite',\n owner: 'core',\n async handler(payload, next) {\n const out = await next(payload);\n try {\n const name = out.toolUse?.name;\n if (!name || !WRITE_TOOLS.has(name)) return out;\n if (out.result?.is_error) return out;\n const state = getDesignState(out.ctx);\n if (!state?.activeKit) return out; // no pinned palette \u2192 nothing to check\n const input = out.toolUse.input as { path?: unknown } | undefined;\n const p = typeof input?.path === 'string' ? input.path : '';\n if (!p || !detectFrontendFile(p)) return out;\n\n const ctx = out.ctx;\n const { default: fs } = await import('node:fs/promises');\n const { default: nodePath } = await import('node:path');\n const abs = nodePath.isAbsolute(p) ? p : nodePath.join(ctx.projectRoot, p);\n const text = await fs.readFile(abs, 'utf8').catch(() => '');\n if (!text) return out;\n\n const loader = getDesignKitLoader(ctx.projectRoot);\n const rawTokens = await loader.readTokens(state.activeKit);\n if (!rawTokens) return out;\n const persisted = await loadActiveKit(ctx.projectRoot).catch(() => undefined);\n const tokens = applyTokenOverrides(rawTokens, persisted?.overrides ?? state.overrides);\n const rel = nodePath.relative(ctx.projectRoot, abs);\n const report = verifyFiles(tokens, [{ path: rel, text }]);\n if (report.violations.length === 0) return out;\n\n const top = report.violations\n .slice(0, 5)\n .map((v) => ` L${v.line}: [${v.axis ?? 'color'}] ${v.snippet} \u2014 ${v.reason}`)\n .join('\\n');\n const more =\n report.violations.length > 5 ? `\\n \u2026and ${report.violations.length - 5} more` : '';\n // Summarize which axes drifted (color / radius / spacing / \u2026).\n const axes = [...new Set(report.violations.map((v) => v.axis ?? 'color'))].join(', ');\n out.result.content +=\n `\\n\\n\u26A0\uFE0F Design Studio (kit \"${state.activeKit}\"): ${report.violations.length} ` +\n `design-token issue(s) [${axes}] in ${rel}. Use the kit's scale tokens (or the ` +\n `materialized CSS vars / utilities) instead:\\n${top}${more}`;\n } catch {\n // best-effort \u2014 never break a tool result\n }\n return out;\n },\n };\n}\n\nconst BASELINE = [\n '**Non-negotiable baseline (every UI you write):**',\n '- Mobile-first & fully responsive; respect safe-area insets on native.',\n '- Ship BOTH light and dark themes from one token set (no hard-coded colors).',\n '- WCAG 2.2 AA: semantic markup, focus-visible, 4.5:1 contrast, labelled controls, hit targets \u226544px.',\n '- Tasteful motion with `prefers-reduced-motion` honored.',\n '- Use current stack defaults (e.g. web: React 19 + Tailwind v4 `@theme`/OKLCH + shadcn/ui + Motion).',\n].join('\\n');\n\n/**\n * request middleware: per-turn, inject the kit menu (until a kit is chosen) or a\n * compact adherence reminder (once chosen). No-op when Design Studio is inactive.\n *\n * Closes over the live `Context` because the `request` pipeline payload is just\n * the `Request` \u2014 it carries no ctx. `req.system` shares the array reference\n * with `ctx.systemPrompt`, so we return a NEW array rather than mutating it.\n */\nexport function makeDesignStudioRequestMiddleware(deps: {\n ctx: Context;\n loader: DesignKitLoader;\n enabled?: () => boolean;\n}): Middleware<Request> {\n const { ctx, loader } = deps;\n return {\n name: 'DesignStudioInject',\n owner: 'core',\n async handler(req, next) {\n if (deps.enabled && !deps.enabled()) return next(req);\n const state = getDesignState(ctx);\n if (!state?.active) return next(req);\n\n let text: string;\n if (state.activeKit) {\n const ov =\n state.overrides && Object.keys(state.overrides).length > 0\n ? `\\nUser color overrides (these WIN over kit tokens): ${Object.entries(state.overrides)\n .map(([k, v]) => `${k}=${v}`)\n .join(', ')}.`\n : '';\n text =\n `## Active design kit: ${state.activeKit}\\n` +\n `Adhere strictly to its tokens, components, and patterns. Keep light/dark + ` +\n `responsive + WCAG AA. Re-load the full spec with \\`design use ${state.activeKit}\\` if unsure.` +\n `${ov}`;\n } else {\n const menu = await loader.menuText().catch(() => '');\n const stackLine = state.stack ? ` (detected stack: ${state.stack})` : '';\n const parts = [\n `## Design Studio \u2014 UI work detected${stackLine}`,\n 'Before writing UI code, COMMIT to ONE coherent design direction. Do NOT produce generic, ' +\n 'default-framework, unstyled output.',\n '',\n menu || '(no kits installed)',\n '',\n BASELINE,\n '',\n 'Next: call `design list` to review, then `design use <kit-id> --stack <stack>` to load the ' +\n 'full spec, then implement it faithfully. A user can also pin one with `/design <kit-id>`.',\n ];\n text = parts.join('\\n');\n }\n\n // Project-local design rules (.design/rules.md) override kit defaults.\n const rules = await loadProjectDesignRules(ctx.projectRoot).catch(() => undefined);\n if (rules) {\n text += `\\n\\n## Project design rules (.design/rules.md) \u2014 these OVERRIDE kit defaults on conflict\\n${rules}`;\n }\n\n const block: TextBlock = {\n type: 'text',\n text,\n cache_control: { type: 'ephemeral' },\n };\n const system = Array.isArray(req.system) ? [...req.system, block] : [block];\n return next({ ...req, system });\n },\n };\n}\n\n/**\n * Install the Design Studio per-turn middleware onto an agent's pipelines.\n * Shared by every host (CLI/TUI + both WebUI servers) so auto-detection behaves\n * identically everywhere. All three are PREPENDED:\n * - detection runs first so a short-circuiting middleware can't suppress it;\n * - the request injector must sit ahead of `ModelRuntimeSettings`, which does\n * not call `next` and would otherwise end the chain before us.\n *\n * The `design` tool and `/design` command are wired separately (builtin pack +\n * slash registry); this only installs the activation behavior.\n */\nexport function installDesignStudioMiddleware(deps: {\n pipelines: AgentPipelines;\n ctx: Context;\n /** When false, nothing is installed (tool + /design stay manual). */\n enabled?: boolean | undefined;\n}): void {\n if (deps.enabled === false) return;\n const loader = getDesignKitLoader(deps.ctx.projectRoot);\n deps.pipelines.userInput.prepend(makeDesignDetectUserInputMiddleware());\n deps.pipelines.toolCall.prepend(makeDesignDetectToolCallMiddleware());\n deps.pipelines.toolCall.prepend(makeDesignVerifyToolCallMiddleware());\n deps.pipelines.request.prepend(makeDesignStudioRequestMiddleware({ ctx: deps.ctx, loader }));\n\n // Restore a previously pinned kit from `.design/active.json` so a design\n // direction survives across sessions. Fire-and-forget \u2014 a missing/old file\n // simply leaves Design Studio idle until detection or an explicit pick.\n void loadActiveKit(deps.ctx.projectRoot)\n .then((persisted) => {\n if (persisted && !getDesignState(deps.ctx)?.activeKit) {\n const stack =\n persisted.stack && isDesignStack(persisted.stack) ? persisted.stack : undefined;\n setActiveKit(deps.ctx, persisted.kit, stack, persisted.overrides);\n }\n })\n .catch(() => {\n // best-effort restore\n });\n}\n", "/**\n * Shared regex patterns used across execution and security-scanner.\n * Centralized here to avoid duplication and keep patterns in sync.\n */\n\n/** Matches Node.js ECONN* errors and fetch failure messages. */\nexport const NETWORK_ERR_RE = /ECONN|ETIMEDOUT|ETIME|ENOTFOUND|EAI_AGAIN|fetch failed/i;", "import type { Context } from '../core/context.js';\nimport type { Compactor } from '../types/compactor.js';\nimport type { Config } from '../types/config.js';\nimport type { ErrorHandler, RecoveryDecision } from '../types/error-handler.js';\nimport type { ModelsRegistry } from '../types/models-registry.js';\nimport {\n isContextOverflowShaped,\n isRetryableKind,\n ProviderError,\n type ProviderErrorKind,\n} from '../types/provider.js';\nimport { NETWORK_ERR_RE } from './regex-patterns.js';\n\n/**\n * Tiered error recovery strategies.\n * Each strategy is attempted in order until one returns a decision.\n */\nexport interface RecoveryStrategy {\n /** Human-readable label for logs. */\n label: string;\n /** Optional compactor for context_overflow recovery. */\n compactor?: Compactor | undefined;\n /** Returns an explicit recovery decision, or null to fall through. */\n attempt: (err: unknown, ctx: Context) => Promise<RecoveryDecision | null>;\n}\n\n/**\n * Builds the ordered list of recovery strategies used by DefaultErrorHandler.\n * Exported so callers can customise or extend the strategy chain.\n */\nexport function buildRecoveryStrategies(opts?: {\n compactor?: Compactor | undefined;\n modelsRegistry?: ModelsRegistry | undefined;\n getConfig?: (() => Config) | undefined;\n}): RecoveryStrategy[] {\n return [\n {\n label: 'context_overflow_reduce',\n compactor: opts?.compactor,\n async attempt(err, ctx) {\n if (!(err instanceof ProviderError)) return null;\n // Accept both the cleanly-classified overflow AND an overflow-shaped\n // error a gateway mislabeled (413, or an overflow phrase under a\n // generic invalid_request/400) \u2014 see isContextOverflowShaped.\n if (err.kind !== 'context_overflow' && !isContextOverflowShaped(err)) return null;\n\n // Catalog limits describe the native model, but gateways and\n // subscription routes can enforce a smaller effective window. A\n // provider overflow is authoritative evidence that the current\n // denominator is too large. Learn a session-local ceiling from the\n // rejected request so the context bar and subsequent compaction use\n // the route's observed limit instead of continuing to advertise (for\n // example) 1M while the gateway rejects around 650K.\n learnEffectiveContextLimitFromOverflow(ctx);\n\n if (this.compactor) {\n try {\n const report = await this.compactor.compact(ctx, { aggressive: true });\n // Compaction rewrote the message array, so the real-usage anchor\n // (captured for the pre-compaction array) is stale \u2014 drop it so the\n // retry's pre-flight estimates the compacted array afresh until the\n // next response re-anchors.\n ctx.lastRealInputTokens = undefined;\n if (report.after < report.before) {\n return { action: 'retry', reason: 'context_compacted' };\n }\n } catch {\n // compact failed; fall through\n }\n }\n return null;\n },\n },\n {\n label: 'rate_limit_backoff',\n async attempt(err, ctx) {\n if (!(err instanceof ProviderError) || err.kind !== 'rate_limit') return null;\n\n // Prefer the parsed Retry-After hint the provider extracted into\n // body.retryAfterMs; fall back to 5s when absent.\n const delayMs = err.body?.retryAfterMs ?? 5_000;\n // Clamp between 1s and 60s.\n const delay = Math.min(60_000, Math.max(1_000, delayMs));\n // Race the backoff sleep against the abort signal so a Ctrl+C /\n // cancellation doesn't hang for the full delay window.\n // Guard: ctx may be undefined in test calls that construct the\n // strategy directly without a context.\n if (ctx?.signal) {\n await new Promise<void>((resolve) => {\n if (ctx.signal.aborted) {\n resolve();\n return;\n }\n const timer = setTimeout(resolve, delay);\n ctx.signal.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer);\n resolve();\n },\n { once: true },\n );\n });\n } else {\n await new Promise((r) => setTimeout(r, delay));\n }\n return { action: 'retry', reason: 'rate_limit_backoff' };\n },\n },\n {\n label: 'downgrade_model',\n async attempt(err, ctx) {\n if (!(err instanceof ProviderError)) return null;\n // rate_limit is intentionally NOT handled here: the rate_limit_backoff\n // strategy above always returns a decision for it, so this strategy\n // is never reached. Downgrade applies to overload and generic server\n // errors only.\n if (err.kind !== 'overloaded' && err.kind !== 'server' && err.kind !== 'stream_hang') {\n return null;\n }\n\n const registry = opts?.modelsRegistry;\n if (!registry) return null;\n\n try {\n const providerId = ctx.provider?.id;\n if (!providerId) return null;\n const provider = await registry.getProvider(providerId);\n if (!provider) return null;\n\n const currentModel = await registry.getModel(providerId, ctx.model);\n if (!currentModel) return null;\n\n // Find a cheaper fallback model with the same capabilities.\n // Prefer models with lower input cost, preferring the same family.\n const visibleModels = opts?.getConfig?.().providers?.[providerId]?.models;\n const candidates = provider.models.filter((m) => {\n if (visibleModels !== undefined && !visibleModels.includes(m.id)) return false;\n const modelCost = m.cost?.input ?? Number.POSITIVE_INFINITY;\n const currentCost = currentModel.cost?.input ?? Number.POSITIVE_INFINITY;\n if (modelCost >= currentCost) return false;\n if (currentModel.capabilities.tools && !m.tool_call) return false;\n if (currentModel.capabilities.vision && !m.modalities?.input?.includes('image'))\n return false;\n return true;\n });\n\n if (candidates.length === 0) return null;\n\n // Pick the cheapest candidate. Treat a missing input cost as\n // +Infinity (most expensive) \u2014 matching the filter above, which\n // already excludes undefined-cost models \u2014 so the sentinel stays\n // consistent if the filter is ever loosened.\n const fallback = candidates.reduce((prev, curr) =>\n (curr.cost?.input ?? Number.POSITIVE_INFINITY) <\n (prev.cost?.input ?? Number.POSITIVE_INFINITY)\n ? curr\n : prev,\n );\n\n return {\n action: 'retry',\n reason: 'model_downgrade',\n model: fallback.id,\n };\n } catch {\n return null;\n }\n },\n },\n {\n label: 'content_filter_reroute',\n async attempt(err, ctx) {\n if (!(err instanceof ProviderError) || err.kind !== 'content_filter') return null;\n\n const registry = opts?.modelsRegistry;\n if (!registry) return null;\n\n try {\n const providerId = ctx.provider?.id;\n if (!providerId) return null;\n const provider = await registry.getProvider(providerId);\n if (!provider) return null;\n\n const currentModel = await registry.getModel(providerId, ctx.model);\n if (!currentModel) return null;\n\n const visibleModels = opts?.getConfig?.().providers?.[providerId]?.models;\n const candidates = provider.models.filter((m) => {\n if (m.id === ctx.model) return false;\n if (visibleModels !== undefined && !visibleModels.includes(m.id)) return false;\n if (currentModel.capabilities.tools && !m.tool_call) return false;\n if (currentModel.capabilities.vision && !m.modalities?.input?.includes('image'))\n return false;\n return true;\n });\n if (candidates.length === 0) return null;\n\n // Content filters are model/deployment-specific (Azure-style false\n // positives especially), so the same request may pass a sibling\n // model. This is a reroute, not a downgrade: pick the closest-COST\n // sibling to stay in the same quality tier, tie-broken by id for\n // determinism. The agent loop's recoveryRetries cap (2) bounds any\n // ping-pong between two filtering models.\n const currentCost = currentModel.cost?.input;\n const distance = (m: (typeof candidates)[number]) =>\n currentCost === undefined || m.cost?.input === undefined\n ? Number.POSITIVE_INFINITY\n : Math.abs(m.cost.input - currentCost);\n const reroute = candidates.reduce((prev, curr) => {\n const delta = distance(curr) - distance(prev);\n if (delta < 0) return curr;\n if (delta === 0 && curr.id < prev.id) return curr;\n return prev;\n });\n\n return { action: 'retry', reason: 'content_filter_reroute', model: reroute.id };\n } catch {\n return null;\n }\n },\n },\n ];\n}\n\n/**\n * Clamp a session's effective context ceiling after a provider-authoritative\n * overflow. The rejected request proves that `input + output reserve` is at\n * or beyond the route's real limit. This is intentionally session-local: it\n * must not overwrite user config based on one transient provider route.\n */\nexport function learnEffectiveContextLimitFromOverflow(ctx: Context): number | undefined {\n const inputTokens = positiveFinite(ctx.lastRequestTokens);\n if (!inputTokens) return undefined;\n\n const advertised =\n positiveFinite(ctx.meta?.['effectiveMaxContext']) ??\n positiveFinite(ctx.provider?.capabilities?.maxContext);\n if (!advertised) return undefined;\n\n const configuredOutputReserve = nonNegativeFinite(ctx.meta?.['contextOutputReserveTokens']);\n const outputReserve = configuredOutputReserve ?? Math.floor(Math.min(8192, advertised * 0.08));\n const observedCeiling = Math.max(1, Math.floor(inputTokens + outputReserve));\n const learned = Math.min(advertised, observedCeiling);\n if (learned >= advertised) return advertised;\n\n ctx.meta ??= {};\n ctx.meta['effectiveMaxContext'] = learned;\n ctx.meta['effectiveMaxContextSource'] = 'provider_overflow';\n return learned;\n}\n\nfunction positiveFinite(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) && value > 0\n ? Math.floor(value)\n : undefined;\n}\n\nfunction nonNegativeFinite(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0\n ? Math.floor(value)\n : undefined;\n}\n\nexport const DEFAULT_RECOVERY_STRATEGIES = buildRecoveryStrategies();\n\ntype HandlerKind = ReturnType<ErrorHandler['classify']>['kind'];\n\n/** Canonical taxonomy \u2192 the handler's public (coarser) union. Exhaustive over\n * every kind except 'unknown' (special-cased to preserve err.retryable). */\nconst HANDLER_KIND_BY_PROVIDER_KIND: Record<\n Exclude<ProviderErrorKind, 'unknown'>,\n Exclude<HandlerKind, 'abort' | 'unknown'>\n> = {\n rate_limit: 'rate_limit',\n quota_exhausted: 'rate_limit',\n overloaded: 'overloaded',\n server: 'server',\n stream_hang: 'server',\n timeout: 'network',\n network: 'network',\n context_overflow: 'context_overflow',\n content_filter: 'content_filter',\n auth: 'client',\n invalid_request: 'client',\n};\n\nexport class DefaultErrorHandler implements ErrorHandler {\n private readonly strategies: RecoveryStrategy[];\n\n constructor(strategies: RecoveryStrategy[] = DEFAULT_RECOVERY_STRATEGIES) {\n this.strategies = strategies;\n }\n\n classify(err: unknown): ReturnType<ErrorHandler['classify']> {\n // AbortError can be thrown in both browser (DOMException) and Node (Error).\n // Guard with typeof check so Node builds don't reference the browser-only DOMException.\n if (\n typeof DOMException !== 'undefined' &&\n err instanceof DOMException &&\n err.name === 'AbortError'\n ) {\n return { kind: 'abort', retryable: false };\n }\n if (err instanceof Error && err.name === 'AbortError') {\n return { kind: 'abort', retryable: false };\n }\n if (err instanceof ProviderError) {\n // Map the canonical taxonomy onto the handler's public (coarser) union.\n // Exhaustive by construction \u2014 a new ProviderErrorKind refuses to\n // compile until it is mapped here. Retryability comes from the kind\n // (the canonical source), not the instance's constructor flag.\n if (err.kind === 'unknown') return { kind: 'unknown', retryable: err.retryable };\n return {\n kind: HANDLER_KIND_BY_PROVIDER_KIND[err.kind],\n retryable: isRetryableKind(err.kind),\n };\n }\n if (err instanceof Error && NETWORK_ERR_RE.test(err.message)) {\n return { kind: 'network', retryable: true };\n }\n return { kind: 'unknown', retryable: false };\n }\n\n async recover(err: unknown, ctx: Context): Promise<RecoveryDecision | null> {\n for (const strategy of this.strategies) {\n const result = await strategy.attempt(err, ctx);\n if (result !== null) return result;\n }\n return null;\n }\n}\n", "import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport type { TodoItem } from '../core/context.js';\nimport {\n appendJournal,\n loadGoal,\n saveGoal,\n goalFilePath,\n parseProgressFromText,\n recordProgress,\n type GoalFile,\n type JournalEntry,\n} from '../storage/goal-store.js';\nimport { coordinateGoalIteration } from '../storage/goal-coordination.js';\nimport { sleep } from '../utils/sleep.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport { formatDecisionSummary } from './autonomy-brain.js';\n\nconst execFileP = promisify(execFile);\n\n/**\n * Sense-decide-execute-reflect loop on top of a long-running Goal.\n *\n * Each iteration:\n * 1. Sense \u2014 read goal, pending todos, `git status --porcelain`.\n * 2. Decide \u2014 pick a source (todo / git / brainstorm) and a task.\n * 3. Execute \u2014 single agent.run with a directive prompt.\n * 4. Reflect \u2014 append a journal entry, persist state to disk.\n *\n * The loop runs forever until `stop()` is called externally (REPL SIGINT\n * handler, /autonomy stop). No internal time/cost cap by design \u2014 the\n * user wants \"sittin sene\". Failures are logged and the loop continues\n * with a different source on the next tick.\n */\n\nexport type { EternalAutonomyOptions, EternalEngineState, IterationStage } from './eternal-autonomy-types.js';\nimport type { EternalAutonomyOptions, EternalEngineState, IterationStage } from './eternal-autonomy-types.js';\n\ninterface DecidedAction {\n source: JournalEntry['source'];\n task: string;\n directive: string;\n /** Set when source === 'todo' so the engine can attribute failures. */\n todoId?: string | undefined;\n}\n\n/**\n * Sentinel returned by `brainstormTask` when the LLM declares the goal\n * fully accomplished. Distinct from `null` (which means \"brainstorm\n * failed / no actionable task right now\") so the engine can count\n * consecutive DONE answers toward a real stop.\n */\nconst BRAINSTORM_DONE = Symbol('brainstorm-done');\n\n/**\n * Free-text marker the model can emit (on its own line) to declare the\n * overall mission accomplished. Detected in the successful iteration's\n * `finalText`. When present, the engine flips `goalState='completed'`\n * and stops \u2014 the model has explicitly claimed completion AND the\n * iteration succeeded, which together is the most reliable stop signal\n * we can get without a separate verifier round-trip.\n */\nconst GOAL_COMPLETE_MARKER = /^\\s*\\[goal[_\\s-]*complete\\]\\s*$/im;\n/** Optional per-deliverable completion marker consumed by the coordination loop. */\nconst DONE_DELIVERABLE_MARKER = /\\[done:\\s*[^\\]]+\\]/i;\n\n/**\n * Free-text marker for the `/goal clear` command equivalent \u2014 when the\n * model emits this, the engine treats it as a manual goal clear (not just\n * completion) so the goal file is removed and onEternalStop fires.\n */\nconst GOAL_CLEAR_MARKER = /^\\s*\\[\\/?goal\\s*clear\\]\\s*$/im;\n\nexport class EternalAutonomyEngine {\n private state: EternalEngineState = 'idle';\n private stopRequested = false;\n private consecutiveFailures = 0;\n private consecutiveBrainstormDone = 0;\n /**\n * Count of consecutive transient (recoverable) provider failures. Drives\n * the exponential backoff between iterations. Reset on the first\n * successful iteration so a single bad afternoon doesn't permanently\n * slow the loop down.\n */\n private consecutiveTransientRetries = 0;\n private currentCtrl: AbortController | null = null;\n private iterationsSinceCompact = 0;\n private readonly goalPath: string;\n\n constructor(private readonly opts: EternalAutonomyOptions) {\n this.goalPath = goalFilePath(opts.projectRoot);\n }\n\n /**\n * Emit a structured error. Uses the configured Logger when available;\n * falls back to console.error(JSON) so events are never silently dropped.\n */\n private logError(msg: string, ctx?: Record<string, unknown>): void {\n if (this.opts.logger) {\n this.opts.logger.error(msg, ctx);\n } else {\n console.error(JSON.stringify({ ...ctx, message: msg, timestamp: new Date().toISOString() }));\n }\n }\n\n /** Current engine state \u2014 readable for UIs. */\n get currentState(): EternalEngineState {\n return this.state;\n }\n\n /**\n * Load the goal file with structured logging for parse/schema warnings.\n */\n private loadGoal(): Promise<GoalFile | null> {\n return loadGoal(\n this.goalPath,\n this.opts.events,\n this.opts.logger ? (msg) => this.opts.logger!.warn(msg) : undefined,\n );\n }\n\n /** Synchronously request stop. Resolves once the running iteration aborts. */\n stop(): void {\n this.stopRequested = true;\n this.currentCtrl?.abort();\n // Best-effort: flip the persisted state so the next startup banner\n // doesn't report a phantom \"running\" engine. Fire-and-forget \u2014 if it\n // races with an in-flight iteration's write, the journal write wins\n // (engineState is metadata, not durable correctness).\n void this.persistEngineState('stopped').catch((err) => {\n this.logError(\n 'Engine persist state failed',\n { event: 'engine.persist_state_failed', message: toErrorMessage(err), context: { expectedState: 'stopped' } },\n );\n });\n this.state = 'stopped';\n }\n\n /**\n * Mark the engine as 'running' on disk + reset stop state so a new\n * batch of `runOneIteration()` calls can proceed. Called by the REPL\n * when the user invokes `/autonomy eternal`. Idempotent.\n */\n async prime(): Promise<void> {\n this.stopRequested = false;\n this.state = 'running';\n await this.persistEngineState('running').catch(() => {});\n }\n\n /**\n * Main loop. Returns when stop() is called or the goal file is removed.\n * Does NOT throw \u2014 every iteration is wrapped to keep the loop alive.\n */\n async run(): Promise<void> {\n this.state = 'running';\n await this.persistEngineState('running');\n\n try {\n while (!this.stopRequested) {\n let iterationOk = false;\n try {\n iterationOk = await this.runOneIteration();\n } catch (err) {\n this.consecutiveFailures++;\n this.opts.onError?.(err instanceof Error ? err : new Error(String(err)), this.consecutiveFailures);\n await this.appendFailure('engine error', toErrorMessage(err));\n }\n\n if (iterationOk) {\n this.consecutiveFailures = 0;\n }\n\n if (this.stopRequested) break;\n\n // Brief gap so SIGINT can land between iterations even if the\n // agent is bouncing back results fast. 0 by default for 24/7 mode.\n await sleep(this.opts.cycleGapMs ?? 0);\n }\n } finally {\n this.state = 'stopped';\n await this.persistEngineState('stopped').catch(() => {});\n }\n }\n\n /**\n * Execute a single sense-decide-execute-reflect cycle.\n * Returns true on success, false on handled failure / no-op.\n *\n * Exposed publicly so the REPL can pace iterations from its main loop\n * \u2014 running the engine and the REPL as a single sequential consumer of\n * `agent.run()` avoids race conditions on the shared Context.\n */\n async runOneIteration(): Promise<boolean> {\n // Emit stage transitions so UIs can render the engine's live location.\n const emit = (stage: IterationStage) => {\n this.opts.onStage?.(stage);\n };\n\n const goal = await this.loadGoal();\n if (!goal) {\n // Goal file disappeared \u2014 treat as a graceful stop.\n emit({ phase: 'stopped' });\n this.stopRequested = true;\n return false;\n }\n\n // Mission-level lifecycle gate.\n const missionState = goal.goalState ?? 'active';\n if (missionState !== 'active') {\n emit({ phase: missionState === 'paused' ? 'paused' : 'stopped' });\n this.stopRequested = true;\n return false;\n }\n\n emit({ phase: 'decide', reason: 'picking next task' });\n const action = await this.decide(goal);\n if (!action) {\n if (!this.stopRequested) {\n emit({ phase: 'sleep', ms: 5_000 });\n await sleep(5_000);\n } else {\n emit({ phase: 'stopped' });\n }\n return false;\n }\n\n emit({ phase: 'execute', task: action.task });\n\n const ctrl = new AbortController();\n this.currentCtrl = ctrl;\n const timer = setTimeout(\n () => ctrl.abort(),\n this.opts.iterationTimeoutMs ?? 5 * 60_000,\n );\n let status: JournalEntry['status'] = 'success';\n let note: string | undefined;\n let finalText = '';\n // Captured from `result.error?.recoverable` when the agent.run returns\n // a recoverable WrongStackError (ProviderError sets this for 429/529\n // /5xx/network). Drives the engine's exponential backoff so a\n // transient rate-limit storm doesn't burn the failure budget in\n // seconds. Permanent errors leave this false and trip the normal\n // consecutiveFailures path.\n let isTransientFailure = false;\n\n // Snapshot usage before so the iteration delta can be journaled.\n // Token counter is optional in mock/test contexts \u2014 guard accordingly.\n const tc = this.opts.agent.ctx?.tokenCounter;\n const beforeUsage = tc?.total?.();\n const beforeCost = tc?.estimateCost?.().total;\n\n try {\n const result = await this.opts.agent.run(\n [{ type: 'text' as const, text: action.directive }],\n {\n signal: ctrl.signal,\n // Enable per-call autonomous continuation so the agent can chain\n // multiple internal tool/response cycles end-to-end on one\n // directive instead of returning to the engine after a single\n // round-trip. The model uses `[continue]` / `[done]` markers\n // (or the `continue_to_next_iteration` tool) to control the\n // inner loop. Without this flag the engine produced shallow\n // iterations and almost never let a real task finish.\n autonomousContinue: true,\n // Cap the inner loop so a runaway agent.run can't burn through\n // the iteration timeout \u2014 the engine's own outer loop is the\n // long-running thing, each tick should be bounded.\n maxIterations: this.opts.iterationMaxAgentSteps ?? 500,\n },\n );\n\n if (result.status === 'aborted') {\n status = 'aborted';\n note = 'stopped by user';\n } else if (result.status === 'failed') {\n status = 'failure';\n note = result.error?.describe?.() ?? 'agent run failed';\n isTransientFailure = result.error?.recoverable === true;\n } else if (result.status === 'max_iterations') {\n status = 'failure';\n note = `max iterations (${result.iterations})`;\n } else {\n status = 'success';\n finalText = result.finalText ?? '';\n const tail = finalText.slice(0, 240).replace(/\\s+/g, ' ').trim();\n if (tail) note = tail;\n }\n } catch (err) {\n const isAbort = err instanceof Error && (err.name === 'AbortError' || err.message.includes('abort'));\n status = isAbort ? 'aborted' : 'failure';\n note = toErrorMessage(err);\n // Surface .recoverable on the thrown WrongStackError too \u2014 provider\n // errors that escape the agent's catch (rare; usually wrapped into\n // result.error) still classify correctly.\n if (\n !isAbort &&\n typeof (err as { recoverable?: unknown | undefined })?.recoverable === 'boolean'\n ) {\n isTransientFailure = (err as { recoverable: boolean }).recoverable;\n }\n } finally {\n clearTimeout(timer);\n this.currentCtrl = null;\n }\n\n // Per-todo attempt accounting. On failure of a todo-sourced action,\n // bump the persistent counter so `decide()` can rotate past it once\n // it crosses the configured ceiling. Successful runs leave the\n // counter untouched \u2014 the LLM is responsible for flipping the todo\n // status to `completed` via the todos tool (directive teaches this).\n if (action.source === 'todo' && action.todoId && status !== 'success') {\n await this.bumpTodoAttempt(action.todoId);\n }\n\n // Capture per-iteration usage delta. Cost is always non-negative;\n // if the counter wraps or resets mid-iteration we clamp to 0 so the\n // journal never shows negative spend.\n const afterUsage = tc?.total?.();\n const afterCost = tc?.estimateCost?.().total;\n const tokens =\n beforeUsage && afterUsage\n ? {\n input: Math.max(0, afterUsage.input - beforeUsage.input),\n output: Math.max(0, afterUsage.output - beforeUsage.output),\n }\n : undefined;\n const costUsd =\n typeof beforeCost === 'number' && typeof afterCost === 'number'\n ? Math.max(0, afterCost - beforeCost)\n : undefined;\n\n await this.appendIterationEntry({\n source: action.source,\n task: action.task,\n status,\n note,\n tokens,\n costUsd,\n });\n\n emit({ phase: 'reflect', status, note });\n\n // Re-read the goal so we can emit the real iteration counter rather\n // than the previous placeholder. If the goal was unlinked mid-flight\n // (graceful stop via /goal clear) the iteration index is still\n // useful \u2014 fall back to the in-memory consecutiveFailures-derived\n // approximation only as a last resort.\n let iterationIndex = 0;\n try {\n const reloaded = await this.loadGoal();\n iterationIndex = reloaded?.iterations ?? 0;\n } catch (err) {\n this.logError(\n 'Goal reload failed',\n { event: 'autonomy.goal_reload_failed', message: toErrorMessage(err), context: { goalPath: this.goalPath } },\n );\n }\n this.opts.onIteration?.({\n at: (this.opts.now?.() ?? new Date()).toISOString(),\n iteration: iterationIndex,\n source: action.source,\n task: action.task,\n status,\n note,\n tokens,\n costUsd,\n });\n\n // Transient failure \u2014 sleep with interruptible backoff before retry.\n if (status === 'failure') {\n if (isTransientFailure) {\n this.consecutiveTransientRetries++;\n const delay = this.computeTransientBackoffMs();\n if (delay > 0) {\n emit({ phase: 'sleep', ms: delay });\n await this.sleepInterruptible(delay);\n }\n return false;\n }\n this.consecutiveFailures++;\n return false;\n }\n\n if (status === 'aborted') {\n if (this.stopRequested) return false;\n this.consecutiveFailures++;\n return false;\n }\n\n // Successful iteration\n this.consecutiveTransientRetries = 0;\n const cycleGapMs = this.opts.cycleGapMs ?? 1000;\n emit({ phase: 'sleep', ms: cycleGapMs });\n await sleep(cycleGapMs);\n\n // Adaptive deliverable coordination. A successful iteration can mark one\n // or more deliverables with `[DONE: index|prefix]`. The coordinator mirrors\n // those completions into the goal Kanban, recomputes progress from the\n // board, and performs one Brain verification when the checklist reaches\n // 100%. A verified reach is persisted in goal.json instead of deleting it,\n // so TUI/WebUI can keep showing the final 100% bar and `goal reached` note.\n let coordinatedProgress: number | undefined;\n if (DONE_DELIVERABLE_MARKER.test(finalText)) {\n const coordinated = await coordinateGoalIteration({\n projectRoot: this.opts.projectRoot,\n goalPath: this.goalPath,\n finalText,\n brain: this.opts.brain,\n sessionId: this.opts.agent.ctx.session?.id,\n events: this.opts.events,\n now: this.opts.now,\n });\n coordinatedProgress = coordinated?.goal.progress;\n if (coordinated?.reached) {\n this.stopRequested = true;\n this.opts.onEternalStop?.();\n return true;\n }\n }\n\n // Goal-complete detection. The model emits `[GOAL_COMPLETE]` on its\n // own line in `finalText` when the overall mission is verifiably done.\n // Combined with a successful iteration this is a strong stop signal:\n // the LLM explicitly claimed completion AND the run did not fail. We\n // mark the goal `completed`, journal it, and stop. No separate\n // verifier round-trip \u2014 keeps cost down; if the model lies, the user\n // notices and can re-arm with `/goal set`.\n if (GOAL_COMPLETE_MARKER.test(finalText)) {\n // Treat GOAL_COMPLETE as a full goal clear: remove the goal file and\n // fire onEternalStop so the REPL exits eternal mode. Stronger than\n // just marking completed \u2014 the REPL needs both to happen.\n await this.clearGoalManually(finalText);\n this.stopRequested = true;\n return true;\n }\n // Goal-clear detection \u2014 model emits `[goal clear]` equivalent to\n // `/goal clear`. Treat as a manual stop: remove the goal file and fire\n // onEternalStop so the REPL knows to return to normal mode.\n if (GOAL_CLEAR_MARKER.test(finalText)) {\n await this.clearGoalManually(finalText);\n this.stopRequested = true;\n return true;\n }\n\n // \u2500\u2500 Progress tracking \u2500\u2500\n // Parse [PROGRESS: N%] from the agent's final text and persist it.\n // Also auto-complete the goal when the agent reports 100% progress.\n const parsed = parseProgressFromText(finalText);\n if (parsed) {\n const progress = Math.max(parsed.progress, coordinatedProgress ?? 0);\n await this.updateProgress(progress, parsed.note);\n if (parsed.progress >= 100 && coordinatedProgress === undefined) {\n // Agent claims 100% \u2014 add a final journal entry and complete.\n await this.markGoalCompleted(\n { source: action.source, task: action.task, directive: action.directive },\n `progress reached 100%: ${parsed.note ?? 'goal complete'}`,\n );\n this.stopRequested = true;\n return true;\n }\n }\n\n // Compaction runs only on successful iterations \u2014 there's no point\n // compacting after a failed/aborted iteration that didn't add much to\n // the message history.\n this.iterationsSinceCompact++;\n await this.maybeCompact().catch((err) => {\n // Don't let compaction failure kill the loop; surface via onError.\n this.opts.onError?.(\n err instanceof Error ? err : new Error(String(err)),\n this.consecutiveFailures,\n );\n });\n return true;\n }\n\n /**\n * Run compaction when either trigger fires:\n * - We've done >= compactEveryNIterations since the last compact.\n * - Current request tokens exceed aggressiveCompactRatio * maxContext.\n *\n * The second check uses *aggressive* mode to free more headroom; the\n * cadence check uses non-aggressive (cheaper).\n */\n private async maybeCompact(): Promise<void> {\n const compactor = this.opts.compactor;\n if (!compactor) return;\n const ctx = this.opts.agent.ctx;\n if (!ctx) return;\n\n const cadence = this.opts.compactEveryNIterations ?? 25;\n const threshold = this.opts.aggressiveCompactRatio ?? 0.85;\n const maxCtx = this.opts.maxContextTokens;\n\n let aggressive = false;\n let shouldRun = false;\n\n if (this.iterationsSinceCompact >= cadence) {\n shouldRun = true;\n }\n\n if (maxCtx && maxCtx > 0) {\n const used = ctx.tokenCounter?.currentRequestTokens?.();\n if (used) {\n const total = used.input + used.cacheRead + used.cacheWrite;\n if (total / maxCtx >= threshold) {\n shouldRun = true;\n aggressive = true;\n }\n }\n }\n\n if (!shouldRun) return;\n\n const report = await compactor.compact(ctx, { aggressive });\n this.iterationsSinceCompact = 0;\n // Journal the compaction event so users see it in /goal journal.\n const saved = report.before - report.after;\n await this.appendIterationEntry({\n source: 'manual',\n task: `compaction (${aggressive ? 'aggressive' : 'cadence'})`,\n status: 'success',\n note: `saved ~${saved} tokens (${report.before}\u2192${report.after})`,\n });\n }\n\n /**\n * Hybrid idea source.\n * 1. Pending todos on the agent's context.\n * 2. Dirty git working tree \u2192 propose a \"review and finish this\" task.\n * 3. Otherwise: brainstorm via the LLM against the goal.\n *\n * After failureBudget consecutive failures, force brainstorm so the\n * engine doesn't loop on the same broken todo or stuck git state.\n */\n private async decide(goal: GoalFile): Promise<DecidedAction | null> {\n const forceBrainstorm = this.consecutiveFailures >= (this.opts.failureBudget ?? 3);\n\n if (!forceBrainstorm) {\n const todo = this.pickPendingTodo(goal);\n if (todo) {\n return {\n source: 'todo',\n task: todo.content,\n todoId: todo.id,\n directive: this.buildDirective(goal, 'todo', todo.content),\n };\n }\n\n const gitTask = await this.pickGitTask();\n if (gitTask) {\n return {\n source: 'git',\n task: gitTask,\n directive: this.buildDirective(goal, 'git', gitTask),\n };\n }\n }\n\n const brainstormed = await this.brainstormTask(goal);\n if (brainstormed === BRAINSTORM_DONE) {\n this.consecutiveBrainstormDone++;\n const threshold = this.opts.brainstormDoneStopThreshold ?? 3;\n if (this.consecutiveBrainstormDone >= threshold) {\n // Consult the brain before stopping \u2014 it may decide to continue\n const shouldStop = await this.consultBrainForDone(goal);\n if (shouldStop) {\n await this.markGoalCompleted(\n { source: 'brainstorm', task: 'no further work', directive: '' },\n `brainstorm returned DONE ${this.consecutiveBrainstormDone}x in a row${this.opts.brain ? ', brain confirmed' : ''}`,\n );\n this.stopRequested = true;\n } else {\n // Brain says keep going \u2014 reset the DONE streak\n this.consecutiveBrainstormDone = 0;\n }\n }\n return null;\n }\n if (!brainstormed) return null;\n // Got a real task \u2014 reset the DONE streak.\n this.consecutiveBrainstormDone = 0;\n return {\n source: 'brainstorm',\n task: brainstormed,\n directive: this.buildDirective(goal, 'brainstorm', brainstormed),\n };\n }\n\n private pickPendingTodo(goal: GoalFile): TodoItem | null {\n const todos = this.opts.agent.ctx.todos;\n if (!Array.isArray(todos)) return null;\n const attempts = goal.todoAttempts ?? {};\n const ceiling = this.opts.todoMaxAttempts ?? 3;\n // First-pending strategy with a stuck-task escape hatch: if the\n // first pending todo has already failed `ceiling` times, fall\n // through to later pending todos. Returns null when every pending\n // todo is stuck \u2014 the caller will fall through to git/brainstorm.\n for (const t of todos) {\n if (t.status !== 'pending') continue;\n const used = attempts[t.id] ?? 0;\n if (used >= ceiling) continue;\n return t;\n }\n return null;\n }\n\n private async pickGitTask(): Promise<string | null> {\n let out: string;\n try {\n out = await (this.opts.gitStatusReader?.() ?? this.readGitStatus());\n } catch {\n return null;\n }\n const dirty = out.trim();\n if (!dirty) return null;\n // Surface a concise prompt \u2014 the agent will look at the diff itself.\n const lines = dirty.split('\\n').slice(0, 8);\n const preview = lines.join(', ');\n return `Inspect the dirty working tree and either finish the in-progress work or revert it. Files: ${preview}`;\n }\n\n private async readGitStatus(): Promise<string> {\n const { stdout } = await execFileP('git', ['status', '--porcelain'], {\n cwd: this.opts.projectRoot,\n timeout: 5_000,\n });\n return stdout;\n }\n\n private async brainstormTask(goal: GoalFile): Promise<string | null | typeof BRAINSTORM_DONE> {\n const lastFew = goal.journal\n .slice(-5)\n .map((e) => ` - [${e.status}] ${e.task}`)\n .join('\\n');\n const directive = [\n 'You are deciding the next action in an autonomous loop pursuing a long-running goal.',\n '',\n `Goal: ${goal.goal}`,\n '',\n lastFew ? `Recent iterations:\\n${lastFew}` : 'No prior iterations yet.',\n '',\n 'Output ONE concrete, immediately-actionable task that advances the goal.',\n 'Constraints:',\n '- One sentence, imperative form, under 200 chars.',\n '- No preamble, no explanation, no markdown \u2014 just the task line.',\n '- If recent iterations show repeated failures on the same target, pivot.',\n '- If the goal appears fully accomplished AND you can name a concrete',\n ' artifact / test / output that proves it, output exactly: DONE',\n '- Be conservative with DONE: if the recent journal contains failures',\n ' or aborted entries, the goal is almost certainly NOT done.',\n ].join('\\n');\n\n try {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), 60_000);\n try {\n const result = await this.opts.agent.run(\n [{ type: 'text' as const, text: directive }],\n { signal: ctrl.signal, maxIterations: 1 },\n );\n if (result.status !== 'done') return null;\n const text = (result.finalText ?? '').trim();\n if (!text) return null;\n // Distinct sentinel for DONE so the caller can count consecutive\n // DONE answers toward a real stop. The old `return null` path\n // conflated \"no work\" with \"engine failure\" and looped forever.\n if (/^DONE\\.?$/i.test(text)) return BRAINSTORM_DONE;\n // Take the first non-empty line and clip to 240 chars.\n const firstLine = text.split('\\n').find((l) => l.trim().length > 0)?.trim();\n if (!firstLine) return null;\n if (/^DONE\\.?$/i.test(firstLine)) return BRAINSTORM_DONE;\n return firstLine.slice(0, 240);\n } finally {\n clearTimeout(timer);\n }\n } catch (err) {\n this.logError(\n 'Brainstorm failed',\n { event: 'autonomy.brainstorm_failed', message: toErrorMessage(err), context: { goal: goal.goal.slice(0, 100) } },\n );\n return null;\n }\n }\n\n private buildDirective(goal: GoalFile, source: JournalEntry['source'], task: string): string {\n const recentJournal = goal.journal\n .slice(-5)\n .map((e) => ` #${e.iteration} [${e.status}] ${e.task}${e.note ? ` \u2014 ${e.note.slice(0, 80)}` : ''}`)\n .join('\\n');\n return [\n '\u2550\u2550\u2550 ETERNAL AUTONOMY \u2014 iteration directive \u2550\u2550\u2550',\n '',\n `Mission: ${goal.goal}`,\n `Iteration: #${goal.iterations + 1}`,\n `Source: ${source}`,\n `Task: ${task}`,\n '',\n recentJournal ? `Recent journal (last 5):\\n${recentJournal}` : 'No prior iterations.',\n '',\n '\u2500\u2500 EXECUTION PROTOCOL \u2500\u2500',\n 'You are inside a long-running autonomous loop. Each iteration you',\n 'execute ONE concrete task that advances the Mission. No user is',\n 'available to clarify \u2014 make defensible decisions and move forward.',\n '',\n '1. EXECUTE END-TO-END',\n ' \u2022 Use multiple tool calls freely. Emit `[continue]` on its own line',\n ' to chain to the next internal step without returning.',\n ' \u2022 When this iteration\\'s Task is finished (real artifact / passing',\n ' test / applied diff / clean output), emit `[done]` on its own line.',\n ' \u2022 Do not stop on the first obstacle \u2014 try at least 3 distinct',\n ' approaches before giving up. YOLO is active unless an explicit',\n ' deny rule blocks the call.',\n '',\n '2. UPDATE TODO STATE (when Source is `todo`)',\n ' \u2022 Mark this todo `in_progress` via the todos tool before tool work.',\n ' \u2022 Mark it `completed` on success, with a one-line outcome note.',\n ' \u2022 If you cannot make progress after 2 distinct attempts, mark it',\n ' `cancelled` with the obstacle. The loop will skip it next time.',\n '',\n '3. MISSION-COMPLETE PROTOCOL',\n ' \u2022 If \u2014 and ONLY if \u2014 the OVERALL Mission (not just this Task) is',\n ' verifiably accomplished, emit on its own line:',\n ' [GOAL_COMPLETE]',\n ' followed by a one-paragraph verification recipe (artifact path,',\n ' test command, or 10-second reproduction). This halts the loop.',\n ' \u2022 NEVER emit [GOAL_COMPLETE] on optimism, partial progress, or',\n ' \"looks fine\". Required: a concrete artifact that proves it AND',\n ' no recent journal failures contradicting completion.',\n ' \u2022 If unsure, emit `[done]` instead and let the next iteration',\n ' decide. The loop is patient; false completion is not.',\n '',\n '4. NO INTERACTIVITY',\n ' \u2022 Do not ask questions, do not request confirmation, do not propose',\n ' options. Pick the best path and execute. The user is asleep.',\n ].join('\\n');\n }\n\n /**\n * Exponential backoff for transient provider errors. `2^N * base`\n * capped at `transientBackoffMaxMs`. Zero base disables backoff.\n * Public-private to keep `runOneIteration` readable; the value is\n * recomputed each call from the current retry count, so callers\n * don't have to track state.\n */\n private computeTransientBackoffMs(): number {\n const base = this.opts.transientBackoffBaseMs ?? 2_000;\n const cap = this.opts.transientBackoffMaxMs ?? 60_000;\n if (base <= 0) return 0;\n const exponent = Math.max(0, this.consecutiveTransientRetries - 1);\n return Math.min(cap, base * 2 ** exponent);\n }\n\n /**\n * Sleep that wakes early if `stopRequested` flips. Polls every 250 ms\n * so SIGINT / `/autonomy stop` can land in the middle of a long\n * backoff instead of waiting up to a minute for the timer.\n */\n private async sleepInterruptible(totalMs: number): Promise<void> {\n const step = 250;\n let remaining = totalMs;\n while (remaining > 0 && !this.stopRequested) {\n const chunk = Math.min(step, remaining);\n await sleep(chunk);\n remaining -= chunk;\n }\n }\n\n private async appendIterationEntry(entry: Omit<JournalEntry, 'iteration' | 'at'>): Promise<void> {\n const current = await this.loadGoal();\n if (!current) {\n // Goal was cleared mid-iteration; nothing to write to.\n return;\n }\n const updated = appendJournal(current, entry);\n await saveGoal(this.goalPath, updated, this.opts.events);\n }\n\n /**\n * Persistent per-todo failure counter. Skipped silently when the goal\n * file has been removed (graceful clear). Each non-success iteration\n * against a todo source bumps the counter by 1; `pickPendingTodo` reads\n * the counter to rotate past stuck todos once they cross `todoMaxAttempts`.\n */\n private async bumpTodoAttempt(todoId: string): Promise<void> {\n const current = await this.loadGoal();\n if (!current) return;\n const attempts = { ...(current.todoAttempts ?? {}) };\n attempts[todoId] = (attempts[todoId] ?? 0) + 1;\n await saveGoal(this.goalPath, { ...current, todoAttempts: attempts }, this.opts.events);\n }\n\n /**\n * Flip the mission to `completed` and journal it. Called from two\n * paths: (a) `[GOAL_COMPLETE]` marker in a successful iteration's\n * finalText, (b) `brainstorm` returning DONE consecutively past the\n * configured threshold. Idempotent \u2014 re-entry is a no-op once the\n * goal is already `completed`.\n */\n private async markGoalCompleted(\n action: { source: JournalEntry['source']; task: string; directive: string },\n note: string,\n ): Promise<void> {\n const current = await this.loadGoal();\n if (!current) return;\n if (current.goalState === 'completed') return;\n const withFlag: GoalFile = { ...current, goalState: 'completed' };\n const withEntry = appendJournal(withFlag, {\n source: action.source,\n task: `MISSION COMPLETE \u2014 ${action.task}`.slice(0, 240),\n status: 'success',\n note: note.slice(0, 240),\n });\n await saveGoal(this.goalPath, withEntry, this.opts.events);\n // Remove the goal file so it doesn't persist as stale state.\n // A completed goal should be gone \u2014 the user creates a new one\n // with `/goal set` when they want to work on something else.\n try {\n const { unlink } = await import('node:fs/promises');\n await unlink(this.goalPath);\n } catch {\n // best-effort \u2014 file may already be gone\n }\n // Fire stop callbacks so the REPL knows to exit eternal mode\n // and show a goal-completion banner. Without this the engine\n // stops internally but the REPL keeps spinning in the eternal loop.\n this.opts.onEternalStop?.();\n }\n\n /**\n * Manually clear the goal \u2014 equivalent to `/goal clear` typed by the user.\n * Sets goalState to `abandoned`, removes the goal file, and fires\n * `onEternalStop` so the REPL returns to normal mode.\n */\n private async clearGoalManually(note: string): Promise<void> {\n const current = await this.loadGoal();\n if (current) {\n const abandoned: GoalFile = { ...current, goalState: 'abandoned' };\n await saveGoal(this.goalPath, abandoned, this.opts.events);\n }\n try {\n const { unlink } = await import('node:fs/promises');\n await unlink(this.goalPath);\n } catch {\n // best-effort \u2014 file may already be gone\n }\n this.opts.onEternalStop?.();\n // Best-effort journal write \u2014 a Windows EPERM/ENOENT on the goal file\n // during /goal clear must not surface as an unhandled rejection.\n void this.appendIterationEntry({\n source: 'manual',\n task: 'goal cleared',\n status: 'success',\n note: note.slice(0, 240),\n }).catch(() => {});\n }\n\n private async appendFailure(task: string, note: string): Promise<void> {\n await this.appendIterationEntry({ source: 'manual', task, status: 'failure', note });\n }\n\n /**\n * Consult the brain on whether the goal is truly complete.\n * Without a brain, always returns true (use heuristic: DONE threshold met = done).\n */\n private async consultBrainForDone(goal: GoalFile): Promise<boolean> {\n if (!this.opts.brain) return true; // No brain \u2014 trust the heuristic\n\n const deliverablesStatus = goal.deliverables?.length\n ? `\\nDeliverables: ${goal.deliverables.length} total, progress ${goal.progress ?? 'unknown'}%`\n : '';\n const recentJournal = goal.journal.slice(-5).map(e =>\n ` #${e.iteration} [${e.status}] ${e.task}`\n ).join('\\n');\n\n try {\n const decision = await this.opts.brain.decide({\n id: `goal-done-${goal.iterations}`,\n sessionId: this.opts.agent.ctx.session?.id,\n source: 'system',\n question: `Brainstorm returned DONE ${this.consecutiveBrainstormDone}x. Is the goal truly complete?`,\n context: [\n `Goal: ${goal.goal}`,\n `Iterations: ${goal.iterations}`,\n `Progress: ${goal.progress ?? 'unknown'}%`,\n deliverablesStatus,\n recentJournal ? `\\nRecent work:\\n${recentJournal}` : '',\n ].join('\\n'),\n risk: 'high',\n fallback: 'continue',\n // Structured verdict \u2014 completion is control-plane input, decided by\n // exact option id rather than sniffing prose for \"done\"/\"complete\".\n options: [\n {\n id: 'goal_complete',\n label: 'The goal is complete \u2014 stop the eternal run',\n consequence: 'The engine stops and the goal file is archived.',\n risk: 'high',\n },\n {\n id: 'keep_working',\n label: 'Not complete yet \u2014 keep working',\n consequence: 'The engine continues iterating on the goal.',\n risk: 'low',\n },\n ],\n });\n\n // Log the brain decision into the journal\n const summary = formatDecisionSummary(decision, {\n id: `goal-done-${goal.iterations}`,\n source: 'system',\n question: 'Is the goal complete?',\n risk: 'high',\n fallback: 'continue',\n });\n const rationale = 'rationale' in decision ? decision.rationale : undefined;\n await this.appendIterationEntry({\n source: 'brainstorm',\n task: summary,\n status: 'success',\n note: rationale,\n });\n\n if (decision.type === 'deny') {\n return false;\n }\n if (decision.type === 'answer') {\n // Exact option id only. An answer that names neither option (e.g. a\n // policy fallback \"continue\") conservatively keeps the run alive \u2014\n // never stop on prose.\n return decision.optionId === 'goal_complete';\n }\n return true;\n } catch {\n return true;\n }\n }\n\n /**\n * Persist a progress update from the agent's [PROGRESS: N%] output.\n */\n private async updateProgress(progress: number, note?: string): Promise<void> {\n const current = await this.loadGoal();\n if (!current) return;\n const updated = recordProgress(current, progress, note);\n await saveGoal(this.goalPath, updated, this.opts.events);\n }\n\n private async persistEngineState(state: GoalFile['engineState']): Promise<void> {\n const current = await this.loadGoal();\n if (!current) return;\n if (current.engineState === state) return;\n await saveGoal(this.goalPath, { ...current, engineState: state }, this.opts.events);\n }\n}\n", "import { updateTask } from '@wrongstack/kanban';\nimport type { BrainArbiter } from '../coordination/brain.js';\nimport type { EventBus } from '../kernel/events.js';\nimport { findGoalBoardByTag, findGoalKanbanBoard, type GoalFileWithKanban } from './goal-kanban.js';\nimport { appendJournal, type GoalFile, loadGoal, recordProgress, saveGoal } from './goal-store.js';\n\nconst DONE_MARKER = /\\[done:\\s*([^\\]]+)\\]/gi;\nconst DONE_PREFIX = /^\\s*(?:\u2705|\\[[x\u2713]\\]|\\(done\\))\\s*/i;\n\nexport interface CompletedGoalDeliverable {\n index: number;\n text: string;\n}\n\nexport interface GoalCoordinationResult {\n goal: GoalFile;\n completed: CompletedGoalDeliverable[];\n kanbanUpdatedTaskIds: string[];\n reached: boolean;\n}\n\nexport interface CoordinateGoalIterationOptions {\n projectRoot: string;\n goalPath: string;\n finalText: string;\n brain?: BrainArbiter | undefined;\n sessionId?: string | undefined;\n events?: EventBus | undefined;\n now?: (() => Date) | undefined;\n}\n\n/**\n * Parse optional `[DONE: index]` / `[DONE: text-prefix]` markers emitted by an\n * autonomy iteration. Numeric indices are human-facing and therefore 1-based;\n * `0` is accepted as an explicit first-item alias for backwards compatibility.\n */\nexport function parseCompletedGoalDeliverables(\n finalText: string,\n deliverables: readonly string[],\n): CompletedGoalDeliverable[] {\n if (!finalText || deliverables.length === 0) return [];\n const seen = new Set<number>();\n const completed: CompletedGoalDeliverable[] = [];\n\n for (const match of finalText.matchAll(DONE_MARKER)) {\n const raw = match[1]?.trim();\n if (!raw) continue;\n const numeric = /^\\d+$/.test(raw) ? Number.parseInt(raw, 10) : undefined;\n let index = numeric === undefined ? -1 : numeric === 0 ? 0 : numeric - 1;\n if (index < 0 || index >= deliverables.length) {\n const prefix = raw.toLowerCase();\n index = deliverables.findIndex((item) =>\n stripGoalDeliverableMarker(item).toLowerCase().startsWith(prefix),\n );\n }\n if (index < 0 || index >= deliverables.length || seen.has(index)) continue;\n const source = deliverables[index] ?? '';\n if (isGoalDeliverableComplete(source)) continue;\n seen.add(index);\n completed.push({ index, text: stripGoalDeliverableMarker(source) });\n }\n return completed;\n}\n\nexport function isGoalDeliverableComplete(value: string): boolean {\n return DONE_PREFIX.test(value);\n}\n\nexport function stripGoalDeliverableMarker(value: string): string {\n return value.replace(DONE_PREFIX, '').trim();\n}\n\n/** Mark newly completed deliverables and recompute progress from the checklist. */\nexport function applyGoalDeliverableCompletions(\n goal: GoalFile,\n completed: readonly CompletedGoalDeliverable[],\n): GoalFile {\n if (completed.length === 0) return recomputeGoalProgress(goal);\n const completedIndices = new Set(completed.map((item) => item.index));\n let next: GoalFile = {\n ...goal,\n deliverables: (goal.deliverables ?? []).map((item, index) =>\n completedIndices.has(index) && !isGoalDeliverableComplete(item) ? `\u2705 ${item}` : item,\n ),\n };\n next = appendGoalDeliverableJournals(next, completed);\n return recomputeGoalProgress(next);\n}\n\nfunction appendGoalDeliverableJournals(\n goal: GoalFile,\n completed: readonly CompletedGoalDeliverable[],\n): GoalFile {\n let next = goal;\n for (const item of completed) {\n next = appendJournal(next, {\n source: 'deliverable',\n task: `Deliverable completed: ${item.text}`.slice(0, 240),\n status: 'success',\n note: `[DONE: ${item.index + 1}]`,\n });\n }\n return next;\n}\n\nexport function recomputeGoalProgress(goal: GoalFile): GoalFile {\n const deliverables = goal.deliverables ?? [];\n if (deliverables.length === 0) return goal;\n const done = deliverables.filter(isGoalDeliverableComplete).length;\n const progress = Math.round((done / deliverables.length) * 100);\n return recordProgress(goal, progress, `${done}/${deliverables.length} deliverables complete`);\n}\n\n/**\n * Close the marker \u2192 Kanban \u2192 progress \u2192 Brain loop and persist the resulting\n * goal state. Brain is called exactly once, and only when every deliverable is\n * complete. A missing/negative Brain leaves the goal active at 100%.\n */\nexport async function coordinateGoalIteration(\n options: CoordinateGoalIterationOptions,\n): Promise<GoalCoordinationResult | null> {\n const current = await loadGoal(options.goalPath, options.events);\n if (!current) return null;\n\n const completed = parseCompletedGoalDeliverables(options.finalText, current.deliverables ?? []);\n const board = await resolveGoalBoard(options.projectRoot, current);\n let kanbanUpdatedTaskIds: string[] = [];\n let goal: GoalFile;\n if (board) {\n // Kanban owns durable deliverable status. Marker output is a requested\n // transition; goal.json is rebuilt from the committed board state.\n kanbanUpdatedTaskIds = await refreshGoalKanban(options.projectRoot, current, completed, board);\n goal = await recomputeGoalProgressFromKanban(options.projectRoot, current);\n const confirmed = completed.filter(\n (item) =>\n !isGoalDeliverableComplete(current.deliverables?.[item.index] ?? '') &&\n isGoalDeliverableComplete(goal.deliverables?.[item.index] ?? ''),\n );\n goal = appendGoalDeliverableJournals(goal, confirmed);\n } else {\n // Pre-Kanban goals keep their existing file-backed checklist semantics.\n goal = applyGoalDeliverableCompletions(current, completed);\n }\n\n let reached = false;\n const allComplete =\n (goal.deliverables?.length ?? 0) > 0 &&\n goal.deliverables?.every(isGoalDeliverableComplete) === true;\n if (allComplete && options.brain) {\n const decision = await options.brain.decide({\n id: `goal-reached-${goal.iterations}`,\n sessionId: options.sessionId,\n source: 'system',\n question: 'Have all goal deliverables been reached and verified?',\n context: [\n `Goal: ${goal.refinedGoal ?? goal.goal}`,\n `Progress: ${goal.progress ?? 0}%`,\n 'Completed deliverables:',\n ...(goal.deliverables ?? []).map(\n (item, index) => `${index + 1}. ${stripGoalDeliverableMarker(item)}`,\n ),\n ].join('\\n'),\n risk: 'high',\n fallback: 'continue',\n options: [\n {\n id: 'goal_reached',\n label: 'Goal reached',\n consequence: 'Persist the completed goal and stop the eternal loop.',\n },\n {\n id: 'keep_working',\n label: 'Keep working',\n consequence: 'Leave the goal active for another iteration.',\n },\n ],\n });\n reached = decision.type === 'answer' && decision.optionId === 'goal_reached';\n }\n\n if (reached) {\n const reachedAt = (options.now?.() ?? new Date()).toISOString();\n goal = appendJournal(\n {\n ...goal,\n goalState: 'completed',\n engineState: 'stopped',\n progress: 100,\n progressNote: 'goal reached',\n reachedAt,\n reachedNote: 'goal reached',\n },\n {\n source: 'deliverable',\n task: 'GOAL REACHED',\n status: 'success',\n note: 'goal reached',\n },\n );\n }\n await saveGoal(options.goalPath, goal, options.events);\n return { goal, completed, kanbanUpdatedTaskIds, reached };\n}\n\nasync function resolveGoalBoard(projectRoot: string, goal: GoalFile) {\n const boardId = (goal as GoalFileWithKanban).kanbanBoardId;\n if (boardId) {\n const board = await findGoalKanbanBoard(projectRoot, boardId);\n if (board) return board;\n }\n return findGoalBoardByTag(projectRoot, goal);\n}\n\nasync function refreshGoalKanban(\n projectRoot: string,\n goal: GoalFile,\n completed: readonly CompletedGoalDeliverable[],\n resolvedBoard?: Awaited<ReturnType<typeof resolveGoalBoard>>,\n): Promise<string[]> {\n if (completed.length === 0) return [];\n const board = resolvedBoard ?? (await resolveGoalBoard(projectRoot, goal));\n if (!board) return [];\n const doneColumn = board.columns.find((column) => column.title.toLowerCase() === 'done');\n if (!doneColumn) return [];\n\n // Build a set of deliverable origin keys from completed items.\n // Each item carries its index in the deliverables array, which matches\n // the `deliverable:${index}` origin.taskId set at board creation time.\n const originKeys = new Set(completed.map((item) => `deliverable:${item.index}`));\n\n // Build title-based fallback set for boards created before origin tracking.\n const completedTitles = new Set(completed.map((item) => normalizeTitle(item.text)));\n\n const updated: string[] = [];\n for (const task of board.tasks) {\n // Prefer origin-based matching (stable) over title-based (fragile).\n const originMatch =\n task.origin?.system === 'goal' && task.origin?.taskId\n ? originKeys.has(task.origin.taskId)\n : false;\n const titleMatch = !task.origin?.taskId && completedTitles.has(normalizeTitle(task.title));\n if (!originMatch && !titleMatch) continue;\n const result = await updateTask(\n projectRoot,\n board.id,\n task.id,\n { columnId: doneColumn.id, status: 'completed' },\n {\n actor: 'goal-coordinator',\n note: originMatch\n ? `deliverable-completed: Matched by origin ${task.origin!.taskId}.`\n : 'deliverable-completed: Updated from [DONE:] marker (title fallback).',\n },\n );\n if (result) updated.push(task.id);\n }\n return updated;\n}\n\nasync function recomputeGoalProgressFromKanban(\n projectRoot: string,\n goal: GoalFile,\n): Promise<GoalFile> {\n const board = await resolveGoalBoard(projectRoot, goal);\n if (!board || !goal.deliverables?.length) return recomputeGoalProgress(goal);\n const tasksByOrigin = new Map(\n board.tasks\n .filter((task) => task.origin?.system === 'goal' && task.origin.taskId)\n .map((task) => [task.origin!.taskId!, task]),\n );\n const completedLegacyTitles = new Set(\n board.tasks\n .filter((task) => !task.origin?.taskId && task.status === 'completed')\n .map((task) => normalizeTitle(task.title)),\n );\n const deliverables = goal.deliverables.map((item, index) => {\n const text = stripGoalDeliverableMarker(item);\n const originTask = tasksByOrigin.get(`deliverable:${index}`);\n const complete = originTask\n ? originTask.status === 'completed'\n : completedLegacyTitles.has(normalizeTitle(text)) || isGoalDeliverableComplete(item);\n return complete ? `\u2705 ${text}` : text;\n });\n return recomputeGoalProgress({ ...goal, deliverables });\n}\n\nfunction normalizeTitle(value: string): string {\n return stripGoalDeliverableMarker(value).replace(/\\s+/g, ' ').trim().toLowerCase();\n}\n", "/**\n * Goal-to-Kanban bridge module.\n *\n * Automatically creates and manages a kanban board for each `/goal set` mission.\n * The board mirrors the goal's deliverables as tasks flowing through\n * Backlog \u2192 In Progress \u2192 Done columns, and the autonomy engines update\n * task status as work progresses.\n *\n * API:\n * createGoalKanbanBoard(projectRoot, goalFile, goalId) \u2192 boardId\n * findGoalKanbanBoard(projectRoot, boardId) \u2192 KanbanBoard | null\n * deleteGoalKanbanBoard(projectRoot, boardId) \u2192 void\n * formatGoalKanbanPreview(goalFile) \u2192 string (rich display)\n * formatGoalKanbanChoicePrompt() \u2192 string (selection screen)\n */\n\nimport { addTask, createBoard, getBoard, listBoards, removeBoard } from '@wrongstack/kanban';\nimport { color } from '../utils/color.js';\nimport type { GoalFile } from './goal-store.js';\n\n// \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nconst GOAL_BOARD_TAG_PREFIX = 'goal:';\n\n// \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * Create (or update) a kanban board for the given goal.\n *\n * - If the goal file already carries a `kanbanBoardId` and the board still\n * exists, this is a no-op (returns the existing id).\n * - Otherwise a new board is created with three columns and one task per\n * deliverable. The board id is stored on `goalFile.kanbanBoardId`.\n *\n * Returns the board id. Returns null when the project root is unavailable.\n */\nexport async function createGoalKanbanBoard(\n projectRoot: string,\n goalFile: GoalFile,\n): Promise<string | null> {\n if (!projectRoot) return null;\n\n // Reuse an existing link if the board is still alive\n const existingId = (goalFile as GoalFileWithKanban).kanbanBoardId;\n if (existingId) {\n const existing = await getBoard(projectRoot, existingId).catch(() => null);\n if (existing) return existingId;\n }\n\n // Build a short goal suffix for the board title (max ~60 chars)\n const displayGoal = (goalFile.refinedGoal || goalFile.goal).replace(/\\s+/g, ' ').trim();\n const titleSuffix = displayGoal.length > 80 ? displayGoal.slice(0, 77) + '\u2026' : displayGoal;\n\n const board = await createBoard(projectRoot, {\n title: `\uD83C\uDFAF ${titleSuffix}`,\n description: `Kanban board auto-created for goal: ${displayGoal}`,\n tags: [goalTag(goalFile)],\n // Goal boards mirror an engine-driven run; the goal coordinator owns\n // completion semantics, so the kanban completion gate stays out of the way.\n completionGate: { enforcement: 'off' },\n });\n\n // The board is created with the kanban package's default columns (Backlog,\n // To Do, In Progress, Review, Done) which already cover the goal workflow.\n\n // Add one task per deliverable, each tagged with origin\n // so refreshGoalKanban() can match by stable ID instead of title text.\n const targetColumnId = board.columns[0]?.id ?? 'backlog';\n if (goalFile.deliverables && goalFile.deliverables.length > 0) {\n for (let index = 0; index < goalFile.deliverables.length; index++) {\n const d = goalFile.deliverables[index]!;\n const cleaned = d.replace(/^\\[[x\u2713]\\]|\u2705|\\(done\\)\\s*/i, '').trim();\n if (cleaned) {\n await addTask(projectRoot, board.id, {\n title: cleaned,\n columnId: targetColumnId,\n description: `Deliverable for goal: ${displayGoal}`,\n priority: 'medium',\n origin: {\n system: 'goal',\n taskId: `deliverable:${index}`,\n },\n }).catch(() => {\n // Best-effort: a task-add failure for one deliverable won't crash the goal\n });\n }\n }\n }\n\n // Store the board id on the goal file by mutating the passed reference\n (goalFile as GoalFileWithKanban).kanbanBoardId = board.id;\n\n return board.id;\n}\n\n/**\n * Find a kanban board by id. Returns null when the board doesn't exist\n * (e.g. manually deleted). The caller should handle this gracefully.\n */\nexport async function findGoalKanbanBoard(projectRoot: string, boardId: string) {\n if (!projectRoot || !boardId) return null;\n try {\n return await getBoard(projectRoot, boardId);\n } catch {\n return null;\n }\n}\n\n/**\n * Delete the kanban board linked to a goal. Best-effort.\n */\nexport async function deleteGoalKanbanBoard(projectRoot: string, boardId: string): Promise<void> {\n if (!projectRoot || !boardId) return;\n await removeBoard(projectRoot, boardId).catch(() => {});\n}\n\n/**\n * Find a goal-linked kanban board by its goal tag.\n * Used when the goal file's kanbanBoardId is missing but the board exists.\n */\nexport async function findGoalBoardByTag(projectRoot: string, goalFile: GoalFile) {\n if (!projectRoot) return null;\n const tag = goalTag(goalFile);\n const boards = await listBoards(projectRoot);\n const matched = boards.find((b) => b.tags?.includes(tag));\n if (!matched) return null;\n return getBoard(projectRoot, matched.id).catch(() => null);\n}\n\n/**\n * Build a formatted \"Goal Kanban\" preview block showing deliverables as\n * a kanban-column layout. This is the \"Goal event\" displayed after the\n * deliverables list.\n */\nexport function formatGoalKanbanPreview(\n goalFile: GoalFile,\n boardId?: string | null,\n taskCount?: number,\n): string {\n const lines: string[] = [];\n const displayGoal = (goalFile.refinedGoal || goalFile.goal).replace(/\\s+/g, ' ').trim();\n\n // \u2500\u2500 Header \u2500\u2500\n lines.push('');\n lines.push(color.bold(color.cyan('\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550')));\n lines.push(color.bold(color.cyan(' \uD83C\uDFAF GOAL KANBAN \u2014 Mission Board')));\n lines.push(color.bold(color.cyan('\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550')));\n lines.push('');\n lines.push(` ${color.bold('Mission:')} ${color.bold(displayGoal)}`);\n if (boardId) {\n lines.push(` ${color.dim(`Board: ${boardId.slice(0, 12)}\u2026`)}`);\n }\n if (typeof taskCount === 'number') {\n lines.push(` ${color.dim(`${taskCount} task(s)`)}`);\n }\n lines.push('');\n\n // \u2500\u2500 Deliverables as kanban columns \u2500\u2500\n const deliverables = goalFile.deliverables ?? [];\n const doneDeliverables = deliverables.filter((d) => /^\\[[x\u2713]\\]|\u2705|\\(done\\)/i.test(d)).length;\n const totalDeliverables = deliverables.length;\n\n if (totalDeliverables > 0) {\n // Backlog section (todo items)\n const backlog = deliverables.filter((d) => !/^\\[[x\u2713]\\]|\u2705|\\(done\\)|\uD83D\uDD04|in.progress/i.test(d));\n const inProgress = deliverables.filter((d) => /\uD83D\uDD04|in.progress/i.test(d));\n const done = deliverables.filter((d) => /^\\[[x\u2713]\\]|\u2705|\\(done\\)/i.test(d));\n\n const renderColumn = (\n title: string,\n items: string[],\n icon: string,\n accent: (s: string) => string,\n ) => {\n if (items.length === 0) {\n lines.push(` ${accent(color.bold(`${icon} ${title}`))} ${color.dim('(empty)')}`);\n return;\n }\n lines.push(` ${accent(color.bold(`${icon} ${title} (${items.length})`))}`);\n for (const item of items) {\n const cleaned = item.replace(/^\\[[x\u2713]\\]|\u2705|\\(done\\)|\uD83D\uDD04|in.progress\\s*/gi, '').trim();\n lines.push(` \u25CB ${cleaned}`);\n }\n };\n\n renderColumn('Backlog', backlog, '\uD83D\uDCCB', (s) => color.dim(s));\n renderColumn('In Progress', inProgress, '\uD83D\uDD04', (s) => color.cyan(s));\n renderColumn('Done', done, '\u2705', (s) => color.green(s));\n\n lines.push('');\n lines.push(\n ` ${color.dim(`Progress: ${doneDeliverables}/${totalDeliverables} deliverables complete`)}`,\n );\n }\n\n // \u2500\u2500 Progress bar (when available) \u2500\u2500\n if (typeof goalFile.progress === 'number') {\n const pct = Math.min(100, Math.max(0, Math.round(goalFile.progress)));\n const filled = Math.round(pct / 5);\n const empty = 20 - filled;\n const bar = color.green('\u2588'.repeat(filled)) + color.dim('\u2591'.repeat(empty));\n lines.push(` ${color.dim('Overall:')} ${bar} ${color.bold(`${pct}%`)}`);\n if (goalFile.progressNote) {\n lines.push(` ${color.dim(goalFile.progressNote)}`);\n }\n }\n if (typeof goalFile.progress === 'undefined' && totalDeliverables > 0) {\n const pct = Math.round((doneDeliverables / totalDeliverables) * 100);\n const filled = Math.round(pct / 5);\n const empty = 20 - filled;\n const bar = (pct > 0 ? color.green('\u2588'.repeat(filled)) : '') + color.dim('\u2591'.repeat(empty));\n lines.push(` ${color.dim('Overall:')} ${bar} ${color.bold(`${pct}%`)}`);\n }\n\n lines.push('');\n lines.push(color.bold(color.cyan('\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550')));\n\n return lines.join('\\n');\n}\n\n/**\n * Build the \"Goal event\" banner \u2014 shown after deliverables in `/goal set`.\n * A compact, visually rich summary that doubles as the \"goal event\" trigger.\n */\nexport function formatGoalEvent(goalFile: GoalFile, boardId?: string | null): string {\n const lines: string[] = [];\n\n lines.push('');\n lines.push(color.bold(color.green('\u250C\u2500\u2500\u2500 Goal Event \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510')));\n lines.push(color.bold(color.green('\u2502')) + ' \uD83C\uDFAF Mission locked and ready');\n if (boardId) {\n lines.push(\n color.bold(color.green('\u2502')) +\n ` \uD83D\uDCCB Kanban board created: ${color.cyan(boardId.slice(0, 12) + '\u2026')}`,\n );\n }\n const deliverables = goalFile.deliverables ?? [];\n lines.push(\n color.bold(color.green('\u2502')) +\n ` \uD83D\uDCE6 ${deliverables.length} deliverable${deliverables.length !== 1 ? 's' : ''} extracted`,\n );\n if (typeof goalFile.progress === 'number') {\n lines.push(color.bold(color.green('\u2502')) + ` \uD83D\uDCCA Progress: ${goalFile.progress}%`);\n }\n lines.push(color.bold(color.green('\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518')));\n\n return lines.join('\\n');\n}\n\n/**\n * Build the autonomy choice prompt \u2014 shown after the goal event.\n * Presents the user with two modes and asks for a selection.\n */\nexport function formatGoalAutonomyChoice(): string {\n const lines: string[] = [];\n\n lines.push('');\n lines.push(color.bold(color.magenta('\u2550\u2550\u2550 Choose Autonomy Mode \u2550\u2550\u2550')));\n lines.push('');\n lines.push(\n ` ${color.bold('1')}. ${color.red('Autonomy Eternal')}` +\n ` ${color.dim('\u2014 Single-agent sense/decide/execute/reflect loop')}`,\n );\n lines.push(\n ` ${color.bold('2')}. ${color.magenta('Eternal Parallel')}` +\n ` ${color.dim('\u2014 Multi-agent fan-out (4-8 subagents per tick)')}`,\n );\n lines.push('');\n lines.push(` ${color.dim('Enter 1 or 2 (or press Enter to skip):')}`);\n\n return lines.join('\\n');\n}\n\n/**\n * Parse a user choice for autonomy mode.\n * Returns 'eternal' | 'eternal-parallel' | null (skip).\n */\nexport function parseAutonomyChoice(input: string): 'eternal' | 'eternal-parallel' | null {\n const trimmed = input.trim().toLowerCase();\n if (trimmed === '1' || trimmed === 'eternal' || trimmed === 'e') return 'eternal';\n if (trimmed === '2' || trimmed === 'parallel' || trimmed === 'p') return 'eternal-parallel';\n if (trimmed === '' || trimmed === 'skip' || trimmed === 's' || trimmed === '0') return null;\n return null;\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\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction goalTag(goalFile: GoalFile): string {\n // Use the goal's first 24 chars as a stable tag component\n const goal = (goalFile.refinedGoal || goalFile.goal)\n .replace(/\\s+/g, '-')\n .slice(0, 24)\n .toLowerCase();\n return `${GOAL_BOARD_TAG_PREFIX}${goal}`;\n}\n\n// \u2500\u2500 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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Extended GoalFile with optional kanban board reference.\n */\nexport interface GoalFileWithKanban extends GoalFile {\n kanbanBoardId?: string | undefined;\n}\n", "/** Resolve a promise after `ms` milliseconds. Prefer this over raw\n * `setTimeout` wrappers so all delay sites use a single implementation\n * and an abortable variant can be introduced without a codebase-wide hunt. */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n", "/**\n * `/goal <description>` preamble \u2014 the \"no force can stop this\" mode.\n *\n * Unlike STEERING (which redirects mid-flight), GOAL is a contract:\n * the user hands over a problem, the agent commits to verifiably\n * finishing it, and every iteration re-reads this preamble from the\n * conversation history. The hardening is entirely prompt-level \u2014\n * the system has already removed implicit budget caps, so this\n * preamble's job is to remove the MODEL's tendency to hedge, ask\n * permission, or declare premature success.\n *\n * The four sections are intentional:\n * 1. AUTHORITY \u2014 explicit grant of unbounded fan-out + model\n * switching. Without this the model self-throttles (\"I shouldn't\n * spawn too many\u2026\") even when budgets are unlimited.\n * 2. DONE \u2014 concrete bar for completion. Forces a verifiable\n * artifact (test passing, file written, bug re-run clean).\n * Without this the model returns \"I believe it's fixed\" and\n * counts that as done.\n * 3. NOT DONE \u2014 explicit anti-patterns. Each item is something we\n * saw real agents do as a \"completion\" that wasn't.\n * 4. PERSISTENCE \u2014 three-angle rule for blockers. Stops the model\n * from giving up on the first tool failure.\n *\n * Located in @wrongstack/core (rather than @wrongstack/tui) so headless\n * callers and the WebUI can issue `/goal set` without dragging the TUI\n * package in. The tui re-exports this for backward compatibility.\n */\nimport {\n readBundledInstructionText,\n renderInstructionTemplate,\n} from '../utils/instruction-file.js';\n\nexport function buildGoalPreamble(goal: string, deliverables?: string[]): string {\n const deliverableBlock = deliverables && deliverables.length > 0\n ? [\n 'CONCRETE DELIVERABLES (check these off as you go):',\n ...deliverables.map((d, i) => ` ${i + 1}. ${d}`),\n '',\n 'After EACH iteration, estimate your completion percentage (0\u2013100)',\n 'against this deliverable list. Output it as:',\n ' [PROGRESS: N%] \u2014 <1-sentence status>',\n 'The eternal engine reads this to update the progress bar.',\n ].join('\\n')\n : '';\n\n return renderInstructionTemplate(readBundledInstructionText('autonomy/goal-preamble.md'), {\n goal,\n deliverables: deliverableBlock,\n });\n}\n", "import { createHash } from 'node:crypto';\nimport type { ContentBlock } from '../types/blocks.js';\nimport type { Message } from '../types/messages.js';\nimport { LruCache } from '../utils/lru-cache.js';\n\ninterface CacheEntry {\n value: string;\n expiresAt: number;\n}\n\nexport interface CompactionSummaryCacheOptions {\n /** Maximum distinct summaries retained in memory (default: 32). Must be a positive integer. */\n capacity?: number | undefined;\n /** Time a successful summary remains reusable (default: 1 hour). Must be finite and > 0. */\n ttlMs?: number | undefined;\n}\n\n/** Non-semantic summarizer results that must never become durable cache hits. */\nexport const PLACEHOLDER_SUMMARIES = Object.freeze({\n empty: '(empty)',\n emptySummary: '(empty summary)',\n});\n\nconst placeholderSummaryValues: ReadonlySet<string> = new Set(\n Object.values(PLACEHOLDER_SUMMARIES),\n);\n\nexport function isPlaceholderSummary(value: string): boolean {\n const summary = value.trim();\n return summary.length === 0 || placeholderSummaryValues.has(summary);\n}\n\n/**\n * Small, process-local cache for isolated compaction summaries.\n *\n * Auto-compaction and overflow recovery can race or retry against the same\n * pre-compaction history. Without a shared cache each path pays for the same\n * secondary-model request. The cache is deliberately bounded and TTL-based:\n * long-running agents cannot accumulate one entry per compaction forever.\n */\nexport class CompactionSummaryCache {\n private readonly entries: LruCache<string, CacheEntry>;\n private readonly pending = new Map<string, Promise<string>>();\n private readonly ttlMs: number;\n private generation = 0;\n\n constructor(opts: CompactionSummaryCacheOptions = {}) {\n const capacity = opts.capacity ?? 32;\n if (!Number.isSafeInteger(capacity) || capacity <= 0) {\n throw new Error(`CompactionSummaryCache capacity must be a positive integer, got ${capacity}`);\n }\n this.entries = new LruCache(capacity);\n if (opts.ttlMs !== undefined && (!Number.isFinite(opts.ttlMs) || opts.ttlMs <= 0)) {\n throw new Error(`CompactionSummaryCache ttlMs must be finite and > 0, got ${opts.ttlMs}`);\n }\n this.ttlMs = opts.ttlMs ?? 60 * 60 * 1000;\n }\n\n get(key: string): string | undefined {\n const entry = this.entries.get(key);\n if (!entry) return undefined;\n if (entry.expiresAt <= Date.now()) return undefined;\n return entry.value;\n }\n\n set(key: string, value: string): void {\n this.entries.set(key, { value, expiresAt: Date.now() + this.ttlMs });\n }\n\n /** Clear entries and invalidate pending creators so their results cannot repopulate the cache. */\n clear(): void {\n this.generation++;\n this.entries.clear();\n this.pending.clear();\n }\n\n /** Reuse both completed results and an identical call already in flight. */\n async getOrCreate(key: string, create: () => Promise<string>): Promise<string> {\n const cached = this.get(key);\n if (cached !== undefined) return cached;\n const running = this.pending.get(key);\n if (running) return running;\n\n const generation = this.generation;\n let tracked: Promise<string>;\n tracked = create().then(\n (value) => {\n // The originating call keeps provider formatting; durable cache hits use the trimmed form.\n const summary = value.trim();\n if (generation === this.generation && !isPlaceholderSummary(summary)) {\n this.set(key, summary);\n }\n if (this.pending.get(key) === tracked) this.pending.delete(key);\n return value;\n },\n (error: unknown) => {\n // Clear before rethrowing so rejection observers can retry immediately.\n if (this.pending.get(key) === tracked) this.pending.delete(key);\n throw error;\n },\n );\n this.pending.set(key, tracked);\n return tracked;\n }\n}\n\n/** Process-wide default with a 32-entry capacity and 1-hour TTL. */\nexport const defaultCompactionSummaryCache = new CompactionSummaryCache();\n\nfunction canonicalize(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(canonicalize);\n if (value !== null && typeof value === 'object') {\n const source = value as Record<string, unknown>;\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(source).sort()) sorted[key] = canonicalize(source[key]);\n return sorted;\n }\n return value;\n}\n\nfunction semanticBlock(block: ContentBlock): unknown {\n switch (block.type) {\n case 'text':\n return { type: block.type, text: block.text, cache_control: block.cache_control };\n case 'tool_use':\n return { type: block.type, id: block.id, name: block.name, input: block.input };\n case 'tool_result':\n return {\n type: block.type,\n tool_use_id: block.tool_use_id,\n name: block.name,\n content: block.content,\n is_error: block.is_error,\n };\n case 'image':\n return { type: block.type, source: block.source };\n case 'thinking':\n return { type: block.type, thinking: block.thinking };\n }\n}\n\n/** Stable key for a summary request; transient estimator and provider metadata are excluded. */\nexport function compactionSummaryKey(\n model: string,\n prompt: string,\n messages: readonly Message[],\n): string {\n const hash = createHash('sha256');\n hash.update('wrongstack-compaction-summary-v2\\0').update(model).update('\\0').update(prompt);\n for (const message of messages) {\n hash.update('\\0').update(message.role).update('\\0');\n if (typeof message.content === 'string') {\n hash.update(message.content);\n continue;\n }\n hash.update(JSON.stringify(canonicalize(message.content.map(semanticBlock))));\n }\n return hash.digest('hex');\n}\n", "/**\n * Minimal LRU (Least Recently Used) cache.\n *\n * Uses the insertion-order property of `Map` (oldest entry is the first\n * iterator) to evict the least-recently-used entry when the capacity is\n * reached. Reads and writes re-insert the entry so it becomes the newest,\n * matching LRU semantics.\n *\n * Designed for the permission-policy eval cache (P3 #17, before-release.md):\n * a plain `Map` with no eviction could grow without bound on an iteration\n * that evaluates thousands of unique tool+subject combinations. This wrapper\n * caps the size at a configurable maximum while preserving the `get`/`set`/\n * `clear`/`has` API the policy already uses.\n *\n * Intentionally dependency-free and small (~30 lines) \u2014 not a general-purpose\n * LRU. If richer semantics are needed (TTL, size tracking, weighted entries),\n * bring a dedicated library.\n */\nexport class LruCache<K, V> {\n private readonly store = new Map<K, V>();\n private readonly capacity: number;\n\n constructor(capacity: number) {\n if (capacity < 1) throw new Error(`LruCache capacity must be >= 1, got ${capacity}`);\n this.capacity = capacity;\n }\n\n get(key: K): V | undefined {\n if (!this.store.has(key)) return undefined;\n const value = this.store.get(key);\n // Re-insert so this key becomes the most-recently-used (moves to end).\n this.store.delete(key);\n this.store.set(key, value as V);\n return value;\n }\n\n set(key: K, value: V): void {\n if (this.store.has(key)) this.store.delete(key);\n this.store.set(key, value);\n // Evict the oldest (least-recently-used) entry while over capacity.\n while (this.store.size > this.capacity) {\n const oldest = this.store.keys().next();\n if (oldest.done) break;\n this.store.delete(oldest.value);\n }\n }\n\n has(key: K): boolean {\n return this.store.has(key);\n }\n\n clear(): void {\n this.store.clear();\n }\n\n get size(): number {\n return this.store.size;\n }\n}\n", "import type { Context } from '../core/context.js';\nimport type { TextBlock } from '../types/blocks.js';\nimport { isTextBlock } from '../types/blocks.js';\nimport type { CompactReport, Compactor } from '../types/compactor.js';\nimport type { Message } from '../types/messages.js';\nimport type { Provider, Request } from '../types/provider.js';\nimport type { Logger } from '../types/logger.js';\nimport { noOpLogger } from '../infrastructure/logger.js';\nimport {\n type CompactionSummaryCache,\n compactionSummaryKey,\n defaultCompactionSummaryCache,\n isPlaceholderSummary,\n} from './compaction-summary-cache.js';\nimport type { OneShotOrchestrator } from './one-shot-llm.js';\nimport { estimateRequestTokens } from '../utils/token-estimate.js';\nimport { repairToolUseAdjacency } from '../utils/message-invariants.js';\nimport { readBundledInstructionText } from '../utils/instruction-file.js';\nimport {\n buildContextEvidenceDigest,\n checkCompactionQuality,\n injectEvidenceFloor,\n} from '../utils/context-evidence.js';\nimport {\n buildLosslessDigest,\n buildSmartDigest,\n dedupStaleReads,\n eliseOldToolResults,\n estimateMessages,\n findSafeBoundary,\n setCompactionDebugLogger,\n} from './compaction-core.js';\n\n/**\n * Options for IntelligentCompactor.\n */\nexport interface IntelligentCompactorOptions {\n /** Provider to use for LLM-assisted summarization. Required. */\n provider: Provider;\n /** Fraction of maxContext that triggers a warning (default 0.5). */\n warnThreshold?: number | undefined;\n /** Fraction of maxContext that triggers soft compaction (default 0.65). */\n softThreshold?: number | undefined;\n /** Fraction of maxContext that triggers hard compaction (default 0.8). */\n hardThreshold?: number | undefined;\n /** Max context window in tokens (used only for threshold fraction math). */\n maxContext?: number | undefined;\n /** How many recent (user+assistant) pairs to always preserve (default 4). */\n preserveK?: number | undefined;\n /** Token threshold below which tool results are not elided (default 300). */\n eliseThreshold?: number | undefined;\n /** System prompt for the summarizer sub-LLM. */\n summarizerPrompt?: string | undefined;\n /**\n * Model ID to use for summarization. When not set, falls back to\n * \"deepseek-chat\" when a OneShotOrchestrator is wired, or the agent's\n * own model otherwise. Set to a fast/cheap configured model for\n * resilience and cost efficiency.\n */\n summarizerModel?: string | undefined;\n /**\n * OneShotOrchestrator for LLM-assisted summarization. When set,\n * `callSummarizer` uses it instead of the direct provider.complete()\n * call, gaining fallback chain support and a cheap default model.\n */\n oneShotOrchestrator?: OneShotOrchestrator | undefined;\n /**\n * Shared cache for successful semantic summaries. By default uses the process-wide\n * cache; pass `summaryCache` to inject a private instance for tests or isolation.\n */\n summaryCache?: CompactionSummaryCache | undefined;\n /** Structured logger. Defaults to noOpLogger (silent). */\n logger?: Logger | undefined;\n}\n\n/**\n * An importance label for a message or message range.\n */\n/**\n * IntelligentCompactor uses an LLM to:\n * - Analyze message importance and preserve critical context\n * - Generate semantic summaries for old message ranges\n * - Make intelligent decisions about what to compact\n *\n * It builds on the shared `compaction-core` elision/boundary primitives and\n * adds LLM-assisted summarization on top. When the summarizer call fails it\n * falls back to the same lossless rule-based digest used by HybridCompactor.\n */\nexport class IntelligentCompactor implements Compactor {\n private readonly provider: Provider;\n private readonly warnThreshold: number;\n private readonly softThreshold: number;\n private readonly hardThreshold: number;\n private readonly maxContext: number;\n private readonly preserveK: number;\n private readonly eliseThreshold: number;\n private readonly summarizerPrompt: string;\n private readonly summarizerModel?: string | undefined;\n private readonly oneShotOrchestrator?: OneShotOrchestrator | undefined;\n private readonly summaryCache: CompactionSummaryCache;\n private readonly logger: Logger;\n\n constructor(opts: IntelligentCompactorOptions) {\n this.provider = opts.provider;\n this.warnThreshold = opts.warnThreshold ?? 0.5;\n this.softThreshold = opts.softThreshold ?? 0.65;\n this.hardThreshold = opts.hardThreshold ?? 0.8;\n this.maxContext = opts.maxContext ?? 128_000;\n this.preserveK = opts.preserveK ?? 4;\n this.eliseThreshold = opts.eliseThreshold ?? 300;\n this.summarizerPrompt =\n opts.summarizerPrompt ??\n readBundledInstructionText('llm/intelligent-compactor-summarizer.md');\n this.summarizerModel = opts.summarizerModel;\n this.oneShotOrchestrator = opts.oneShotOrchestrator;\n this.summaryCache = opts.summaryCache ?? defaultCompactionSummaryCache;\n this.logger = opts.logger ?? noOpLogger;\n setCompactionDebugLogger(this.logger);\n }\n\n async compact(ctx: Context, opts: { aggressive?: boolean | undefined } = {}): Promise<CompactReport> {\n const beforeTokens = estimateMessages(ctx.messages);\n const beforeFull = this.estimateFullRequest(ctx);\n const reductions: CompactReport['reductions'] = [];\n\n // Use full request tokens for threshold decisions \u2014 messages alone are inaccurate.\n const load = beforeFull / this.maxContext;\n // Past hardThreshold, force aggressive regardless of caller preference \u2014\n // the alternative (lightweight elision) is unlikely to recover enough.\n const aggressive =\n load >= this.hardThreshold ? true : (opts.aggressive ?? load >= this.softThreshold);\n\n // Phase 1: always run elision (preserves recent K pairs)\n const saved1 = this.elide(ctx);\n if (saved1 > 0) reductions.push({ phase: 'elision', saved: saved1 });\n\n // Phase 1b: collapse superseded repeated reads under the elise threshold.\n const dedup = dedupStaleReads(ctx.messages, ctx.contextEvidence?.repeatedReads ?? [], {\n preserveK: this.preserveK,\n });\n if (dedup.changed) ctx.state.replaceMessages(dedup.messages);\n if (dedup.saved > 0) reductions.push({ phase: 'elision', saved: dedup.saved });\n\n // Phase 2: LLM summarization of ancient turns\n let collapsedDigest: string | undefined;\n if (aggressive) {\n const phase2 = await this.summarizeAncientTurns(ctx);\n if (phase2.digest !== undefined) {\n // Record completed summaries even with 0 token savings because the\n // enrichment preserves critical content across compaction.\n reductions.push({ phase: 'summary', saved: Math.max(0, phase2.saved) });\n collapsedDigest = phase2.digest;\n }\n } else if (load >= this.warnThreshold) {\n // Non-aggressive: lightweight elision only.\n const saved2 = this.elide(ctx);\n if (saved2 > 0) reductions.push({ phase: 'elision', saved: saved2 });\n }\n\n const repaired = repairToolUseAdjacency(ctx.messages);\n if (repaired.report.changed) ctx.state.replaceMessages(repaired.messages);\n\n let afterTokens = estimateMessages(ctx.messages);\n let afterFull = this.estimateFullRequest(ctx);\n const evidenceDigest = buildContextEvidenceDigest(ctx) || undefined;\n const quality = checkCompactionQuality(ctx, {\n collapsedDigest,\n evidenceDigest,\n reduced: beforeTokens > afterTokens || beforeFull > afterFull,\n });\n if (injectEvidenceFloor(ctx, quality)) {\n afterTokens = estimateMessages(ctx.messages);\n afterFull = this.estimateFullRequest(ctx);\n }\n return {\n before: beforeTokens,\n after: afterTokens,\n fullRequestTokensBefore: beforeFull,\n fullRequestTokensAfter: afterFull,\n reductions,\n collapsedDigest,\n evidenceDigest,\n quality,\n repaired: repaired.report.changed\n ? {\n removedToolUses: repaired.report.removedToolUses,\n removedToolResults: repaired.report.removedToolResults,\n removedMessages: repaired.report.removedMessages,\n }\n : undefined,\n };\n }\n\n /**\n * Estimate the full API request token count: messages + systemPrompt + toolDefs.\n * This is the accurate figure for context-window pressure monitoring.\n */\n private estimateFullRequest(ctx: Context): number {\n return estimateRequestTokens(ctx.messages, ctx.systemPrompt, ctx.tools ?? []).total;\n }\n\n /** Run shared tool-result elision and commit through ConversationState. */\n private elide(ctx: Context): number {\n const result = eliseOldToolResults(ctx.messages, {\n preserveK: this.preserveK,\n eliseThreshold: this.eliseThreshold,\n });\n if (result.changed) ctx.state.replaceMessages(result.messages);\n return result.saved;\n }\n\n private async summarizeAncientTurns(\n ctx: Context,\n ): Promise<{ saved: number; digest?: string | undefined }> {\n const messages = ctx.messages;\n const cutoff = Math.max(0, messages.length - this.preserveK * 2);\n if (cutoff <= 2) return { saved: 0 };\n\n // Find the best boundary in the ancient region\n const boundary = findSafeBoundary(messages, 0, cutoff);\n if (boundary <= 1) return { saved: 0 };\n\n const toSummarize = messages.slice(0, boundary);\n const removedTokens = estimateMessages(toSummarize);\n\n const summaryModel = this.summarizerModel ?? (this.oneShotOrchestrator ? 'deepseek-chat' : ctx.model);\n // Cache only the LLM request/result. The context-sensitive smart digest\n // below is rebuilt from this invocation's full messages on every hit, so\n // its deterministic evidence is never inherited from another session.\n const summaryInput = this.messagesToSummary(toSummarize);\n let summaryText: string;\n try {\n // Empty/placeholder results bypass the cache so a later compaction can retry.\n summaryText = await this.callSummarizer(ctx, summaryModel, summaryInput);\n } catch (err) {\n this.logger.warn('Summarizer failed; falling back to lossless digest', { err });\n // Fallback: lossless rule-based digest (text preserved, tool I/O dropped).\n summaryText =\n buildLosslessDigest(toSummarize) ||\n `${toSummarize.length} earlier turns (semantic content preserved)`;\n }\n\n // \u2500\u2500 Type-aware enrichment \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 // Run buildSmartDigest on the same messages to extract critical\n // content (score-5: decisions, errors, corrections) verbatim.\n // Merge it with the LLM summary so important facts survive compaction.\n const smartDigest = buildSmartDigest(toSummarize);\n const enriched = smartDigest\n ? `[CRITICAL]\\n${smartDigest}\\n\\n[SUMMARY]\\n${summaryText}`\n : summaryText;\n\n const summaryMsg: Message = {\n role: 'system',\n content: `[prior_turns_summary: ${enriched}]`,\n };\n const summaryTokens = estimateMessages([summaryMsg]);\n\n // L1-A: route through ConversationState so subscribers see the rewrite.\n const tail = ctx.messages.slice(boundary);\n ctx.state.replaceMessages([summaryMsg, ...tail]);\n return { saved: Math.max(0, removedTokens - summaryTokens), digest: summaryText };\n }\n\n private async callSummarizer(\n ctx: Context,\n summaryModel: string,\n summaryInput: string,\n ): Promise<string> {\n // Cache the semantic summarization request independently of the transport path.\n // Both OneShot and direct provider calls use this model, instruction, and bounded input.\n const messages: Message[] = [{ role: 'user', content: summaryInput }];\n const summaryKey = compactionSummaryKey(summaryModel, this.summarizerPrompt, messages);\n\n // When a OneShotOrchestrator is wired, use it with a cheap default model\n // and fallback support. Otherwise fall back to direct provider.complete().\n const oneShotOrchestrator = this.oneShotOrchestrator;\n if (oneShotOrchestrator) {\n return this.summaryCache.getOrCreate(summaryKey, async () => {\n const result = await oneShotOrchestrator.call({\n system: this.summarizerPrompt,\n messages,\n model: summaryModel,\n timeoutMs: 30_000,\n maxTokens: 1024,\n signal: ctx.signal,\n });\n if (result.error || isPlaceholderSummary(result.text)) {\n throw new Error(result.error || 'Summarizer returned an empty result');\n }\n return result.text;\n });\n }\n\n // Legacy path: direct provider.complete().\n const prompt: TextBlock[] = [\n { type: 'text', text: this.summarizerPrompt },\n { type: 'text', text: '\\n\\nConversation to summarize:\\n' },\n { type: 'text', text: summaryInput },\n ];\n const req: Request = {\n model: summaryModel,\n system: prompt,\n messages: [],\n maxTokens: 1024,\n };\n\n return this.summaryCache.getOrCreate(summaryKey, async () => {\n const timeoutSignal = AbortSignal.timeout(30_000);\n const signal = ctx.signal ? AbortSignal.any([ctx.signal, timeoutSignal]) : timeoutSignal;\n const res = await this.provider.complete(req, { signal });\n const summary = res.content\n .filter(isTextBlock)\n .map((block) => block.text)\n .join('\\n')\n .trim();\n if (isPlaceholderSummary(summary)) {\n throw new Error('Summarizer returned an empty result');\n }\n return summary;\n });\n }\n\n /** Compact string summary of messages (no TextBlock wrapper). */\n private messagesToSummary(messages: Message[]): string {\n const lines: string[] = [];\n for (const message of messages) {\n const text = this.boundedMessageText(message);\n if (text.length > 0) {\n lines.push(`[${message.role.padEnd(10, ' ')}]: ${text}`);\n }\n }\n return lines.join('\\n');\n }\n\n /** Match the summarizer's 500-character limit without joining full block payloads first. */\n private boundedMessageText(message: Message): string {\n if (typeof message.content === 'string') return message.content.slice(0, 500);\n\n let text = '';\n for (const block of message.content) {\n if (!isTextBlock(block)) continue;\n const separator = text.length > 0 ? ' ' : '';\n const remaining = 500 - text.length - separator.length;\n if (remaining <= 0) break;\n text += separator + block.text.slice(0, remaining);\n if (text.length === 500) break;\n }\n return text;\n }\n}\n", "/**\n * Model-runtime resolver + request-pipeline middleware.\n *\n * Maps the shared `Config.modelRuntime` settings into the per-request\n * `Request.reasoning` and `Request.cache` fields, gated by the active model's\n * `reasoningConfig` capabilities so unsupported values are omitted (and\n * surfaced as warnings) instead of triggering provider 400s.\n *\n * Wired once at boot (REPL/TUI/WebUI all go through the same `request`\n * pipeline) \u2014 see `installModelRuntimeMiddleware()`. UIs only need to mutate\n * `Config.modelRuntime` (and persist) for the change to take effect on the next\n * request.\n */\nimport type {\n Capabilities,\n ReasoningConfig,\n ReasoningRequest,\n Request,\n RequestCacheControl,\n} from '../types/provider.js';\nimport type { ModelRuntimeConfig, ModelRuntimeParametersConfig } from '../types/config.js';\n\nexport interface ResolvedModelRuntime {\n reasoning: Request['reasoning'];\n cache: Request['cache'];\n /** Resolved generation parameters (topK, frequencyPenalty, etc.). */\n parameters: Partial<Request> | undefined;\n /** Human-readable warnings for settings that were ignored for this model. */\n warnings: string[];\n}\n\n/**\n * Overlay a scoped runtime override (for example a subagent role matrix entry)\n * on top of the session-wide runtime settings. Nested objects merge so a role\n * can set only `reasoning.effort` without losing the leader's cache TTL or\n * other gated parameters.\n */\nexport function mergeModelRuntime(\n base: ModelRuntimeConfig | undefined,\n override: ModelRuntimeConfig | undefined,\n): ModelRuntimeConfig | undefined {\n if (!base) return override;\n if (!override) return base;\n return {\n ...base,\n ...override,\n reasoning:\n base.reasoning || override.reasoning\n ? { ...base.reasoning, ...override.reasoning }\n : undefined,\n cache:\n base.cache || override.cache\n ? { ...base.cache, ...override.cache }\n : undefined,\n parameters:\n base.parameters || override.parameters\n ? { ...base.parameters, ...override.parameters }\n : undefined,\n };\n}\n\n/**\n * Resolve user-facing runtime settings into request fields for a specific\n * model capability profile. Pure function \u2014 safe to unit-test without a\n * provider or event bus.\n *\n * @param settings `Config.modelRuntime` (may be undefined \u2192 no-op)\n * @param reasoning The model's `reasoningConfig`, or undefined when unknown.\n * When undefined the resolver is conservative: explicit\n * on/off is suppressed (provider default wins) and effort is\n * dropped, because we cannot tell whether the model will\n * accept the fields.\n */\nexport function resolveModelRuntime(\n settings: ModelRuntimeConfig | undefined,\n reasoning: ReasoningConfig | undefined,\n capabilities?: Capabilities | undefined,\n): ResolvedModelRuntime {\n const warnings: string[] = [];\n if (!settings) {\n return { reasoning: undefined, cache: undefined, parameters: undefined, warnings };\n }\n\n const reasoningField = resolveReasoningForRequest(settings, reasoning, warnings);\n const cacheField = resolveCacheForRequest(settings, warnings);\n const paramsField = resolveParametersForRequest(settings.parameters, capabilities, warnings);\n\n return {\n reasoning: reasoningField,\n cache: cacheField,\n parameters: paramsField,\n warnings,\n };\n}\n\nexport function resolveReasoningForRequest(\n settings: ModelRuntimeConfig,\n rc: ReasoningConfig | undefined,\n warnings: string[],\n): Request['reasoning'] {\n const cfg = settings.reasoning;\n if (!cfg) return undefined;\n\n // Capability-unknown: be conservative. Sending explicit enabled/disabled to\n // a model that doesn't understand the field is a common source of 400s\n // (e.g. always-on Kimi code models reject `thinking: { type: \"disabled\" }`).\n // Unknown-capability cases drop the field silently \u2014 the user has no\n // actionable response, and the resolver already omits the value to avoid\n // provider errors. Surfacing a warning every request would be pure noise.\n const capKnown = rc !== undefined;\n const supportsReasoning = rc ? rc.default !== 'disabled' || rc.disableSupported || rc.effortSupported : false;\n\n const out: ReasoningRequest = {};\n\n if (cfg.mode === 'off') {\n if (capKnown && rc?.disableSupported) {\n out.enabled = false;\n } else if (capKnown && rc && rc.default === 'always_on') {\n warnings.push(\n 'reasoning \"off\" requested, but this model has thinking always on; the disable field was omitted to avoid a provider error.',\n );\n } else if (capKnown && rc && !rc.disableSupported) {\n warnings.push('reasoning \"off\" requested, but this model does not support disabling thinking; the setting was omitted.');\n }\n // capKnown === false: silently omit; field is dropped to avoid 400s.\n } else if (cfg.mode === 'on') {\n if (!capKnown) {\n // Silently omit; cannot verify the model accepts an explicit \"on\".\n } else if (!supportsReasoning && rc?.default === 'disabled') {\n warnings.push('reasoning \"on\" requested, but this model has reasoning disabled by default and does not advertise support; the setting was omitted.');\n } else {\n out.enabled = true;\n }\n }\n // mode 'auto' \u2192 never send explicit enabled/disabled; provider default wins.\n\n const effort = cfg.effort;\n if (effort !== undefined) {\n if (capKnown && rc?.effortSupported && rc.effortLevels.includes(effort)) {\n out.effort = effort;\n } else if (capKnown && rc?.effortSupported) {\n warnings.push(\n `reasoning effort \"${effort}\" not supported by this model (supported: ${rc.effortLevels.join(', ')}); the setting was omitted.`,\n );\n } else if (capKnown) {\n warnings.push(`reasoning effort \"${effort}\" requested, but this model does not support effort; the setting was omitted.`);\n }\n // capKnown === false: silently omit; the resolver cannot tell whether\n // the model supports effort, so it drops the field rather than guess.\n }\n\n if (cfg.preserve !== undefined) {\n if (capKnown && rc && rc.preserveThinking !== 'unsupported') {\n out.preserve = cfg.preserve;\n } else if (capKnown && cfg.preserve) {\n // `false` already matches the effective behaviour of a model that\n // cannot preserve thinking. Only an enabled request is unsupported and\n // actionable; warning for an explicit `false` would be both misleading\n // and noisy because this resolver runs for every model request.\n warnings.push('reasoning preserve requested, but this model does not support preserved thinking; the setting was omitted.');\n }\n // Unknown capabilities: preserve is a soft, widely-supported field, so we\n // drop it rather than guess \u2014 provider behaviour varies too much.\n }\n\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nexport function resolveCacheForRequest(\n settings: ModelRuntimeConfig,\n _warnings: string[],\n): Request['cache'] {\n const out: RequestCacheControl = {};\n if (settings.cache?.ttl !== undefined) out.ttl = settings.cache.ttl;\n if (settings.cache?.geminiExplicit === true) out.geminiExplicit = true;\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\n/**\n * Map the user-facing `ModelRuntimeParametersConfig` onto `Request` fields,\n * gated by the active model's `Capabilities`. Parameters whose capability\n * flag is false (or unknown) are silently omitted so unsupported models\n * never receive fields they'd reject.\n */\nexport function resolveParametersForRequest(\n params: ModelRuntimeParametersConfig | undefined,\n caps: Capabilities | undefined,\n _warnings: string[],\n): Partial<Request> | undefined {\n if (!params) return undefined;\n\n const out: Partial<Request> = {};\n\n if (params.topK !== undefined && caps?.topK !== false) {\n out.topK = params.topK;\n }\n if (params.frequencyPenalty !== undefined && caps?.frequencyPenalty !== false) {\n out.frequencyPenalty = params.frequencyPenalty;\n }\n if (params.presencePenalty !== undefined && caps?.presencePenalty !== false) {\n out.presencePenalty = params.presencePenalty;\n }\n if (params.seed !== undefined && caps?.seed !== false) {\n out.seed = params.seed;\n }\n if (params.user !== undefined) {\n out.user = params.user;\n }\n if (params.logprobs !== undefined && caps?.logprobs !== false) {\n out.logprobs = params.logprobs;\n if (params.topLogprobs !== undefined) {\n out.topLogprobs = params.topLogprobs;\n }\n }\n\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nexport interface ModelRuntimeMiddlewareOptions {\n /** Provider id of the active model, for logging/diagnostics only. */\n providerId?: string | undefined;\n /** Model id of the active model, for logging/diagnostics only. */\n modelId?: string | undefined;\n /** Current runtime settings. Called per-request so live changes apply. */\n getSettings(): ModelRuntimeConfig | undefined;\n /** Current model capability profile. Called per-request. */\n getReasoningConfig(): ReasoningConfig | undefined;\n /** Current model capabilities for parameter gating. Called per-request. */\n getCapabilities?(): Capabilities | undefined;\n /** Optional sink for suppressed-setting warnings (e.g. emit to event bus). */\n onWarning?: ((message: string) => void) | undefined;\n}\n\n/**\n * Build a `request`-pipeline middleware that applies runtime settings. The\n * returned function mutates the outgoing request by overlaying resolved\n * `reasoning` / `cache` fields and generic parameters. Existing fields on\n * the request are preserved only when the resolver produces nothing for\n * that field.\n */\nexport function applyModelRuntime(\n req: Request,\n opts: ModelRuntimeMiddlewareOptions,\n): Request {\n const settings = opts.getSettings();\n if (!settings) return req;\n const rc = opts.getReasoningConfig();\n const caps = opts.getCapabilities?.();\n const resolved = resolveModelRuntime(settings, rc, caps);\n for (const w of resolved.warnings) opts.onWarning?.(w);\n\n const next: Request = { ...req };\n if (resolved.reasoning !== undefined) {\n next.reasoning = resolved.reasoning;\n }\n if (resolved.cache !== undefined) {\n // Merge, not replace: a provider-agnostic cache `key` derived at\n // request-build time (agent-response.ts) must survive the config-driven\n // `ttl` overlay. When no cache config exists, `req.cache.key` is untouched.\n next.cache = { ...next.cache, ...resolved.cache };\n }\n if (resolved.parameters !== undefined) {\n Object.assign(next, resolved.parameters);\n }\n return next;\n}\n", "import { expectDefined } from '../utils/expect-defined.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport { randomUUID } from 'node:crypto';\nimport type { Agent } from '../core/agent.js';\nimport type { AgentFactory } from '../coordination/agent-subagent-runner.js';\nimport { makeAgentSubagentRunner, withDisabledToolFiltering } from '../coordination/agent-subagent-runner.js';\nimport { dispatchAgent } from '../coordination/dispatcher.js';\nimport type { DispatchClassifier, DispatchResult } from '../coordination/dispatcher.js';\nimport type { EventBus } from '../kernel/events.js';\nimport type { Logger } from '../types/logger.js';\nimport type { SubagentConfig, TaskResult } from '../types/multi-agent.js';\nimport type { JournalEntry, GoalFile } from '../storage/goal-store.js';\nimport { loadGoal, saveGoal, appendJournal, goalFilePath } from '../storage/goal-store.js';\nimport type { Compactor } from '../types/compactor.js';\nimport { DefaultMultiAgentCoordinator } from '../coordination/multi-agent-coordinator.js';\nimport type { MultiAgentConfig } from '../types/multi-agent.js';\nimport { sleep } from '../utils/sleep.js';\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type ParallelEngineState = 'idle' | 'running' | 'stopped';\n\nexport type ParallelIterationStage =\n | { phase: 'idle' }\n | { phase: 'decompose' }\n | { phase: 'fanout'; slots: number }\n | { phase: 'await'; taskIds: string[] }\n | {\n phase: 'aggregate';\n successCount: number;\n total: number;\n goalComplete: boolean;\n }\n | { phase: 'sleep'; ms: number }\n | { phase: 'stopped' }\n | { phase: 'error'; message: string };\n\nexport interface ParallelEternalOptions {\n /** The coordinating agent \u2014 NOT a subagent. Owns container/tools/providers. */\n agent: Agent;\n /** Project root (used for goal.json path). */\n projectRoot: string;\n /**\n * Override the resolved goal.json path. Defaults to\n * `goalFilePath(projectRoot)` \u2014 the canonical per-project goal file under\n * `~/.wrongstack/projects/<slug>/`, shared with `/goal` and the TUI.\n * Primarily for tests that want an isolated goal file under a temp dir.\n */\n goalPath?: string | undefined;\n /**\n * Number of parallel subagent slots per tick.\n * Default: 4. Range 1\u201316; values >8 are for high-throughput machines.\n */\n parallelSlots?: number | undefined;\n /** Per-subagent default timeout in ms. Default: 300_000 (5 min). */\n iterationTimeoutMs?: number | undefined;\n onIteration?: (((entry: JournalEntry) => void)) | undefined;\n onError?: (err: Error | undefined, iteration: number) => void;\n /** Per-tick phase notifications for live UI/status updates. */\n onStage?: (((stage: ParallelIterationStage) => void)) | undefined;\n gitStatusReader?: ((() => Promise<string>)) | undefined;\n now?: ((() => Date)) | undefined;\n compactor?: Compactor | undefined;\n compactEveryNIterations?: number | undefined;\n aggressiveCompactRatio?: number | undefined;\n maxContextTokens?: number | undefined;\n /** Override the default agent factory (uses main agent if not provided). */\n subagentFactory?: AgentFactory | undefined;\n /**\n * Route each decomposed slot task to the best-fit catalog agent via the\n * smart dispatcher (heuristic keyword scoring). When enabled (default), each\n * slot spawns in-role \u2014 the role's budget tier applies and a persona line is\n * injected into the task \u2014 instead of as a faceless generic worker. Set\n * false to keep the legacy generic spawn.\n */\n dispatch?: boolean | undefined;\n /**\n * Optional LLM fallback for ambiguous tasks. Passed straight to\n * `dispatchAgent`; when omitted, routing is pure heuristic (instant, no\n * provider call \u2014 preferred for a continuously-ticking autonomous loop).\n */\n dispatchClassifier?: DispatchClassifier | undefined;\n /** Optional EventBus for emitting storage.* observability events from goal I/O. */\n events?: EventBus | undefined;\n /** Logger for structured errors. Falls back to console.error when omitted. */\n logger?: Logger | undefined;\n}\n\nconst GOAL_COMPLETE_MARKER = /^\\s*\\[goal[_\\s-]?complete\\]\\s*$/im;\n\n// ---------------------------------------------------------------------------\n// ParallelEternalEngine\n// ---------------------------------------------------------------------------\n\n/**\n * Sense \u2192 Decide \u2192 Fan-out (4\u20138 parallel agents) \u2192 Aggregate \u2192 Loop.\n *\n * Each tick:\n * 1. Sense \u2014 load goal, todos, git status\n * 2. Decide \u2014 decompose goal into N parallel sub-tasks\n * 3. Fan-out \u2014 spawn N subagents simultaneously, await all\n * 4. Aggregate \u2014 write journal, update todos, check [GOAL_COMPLETE]\n * 5. Loop \u2014 continue until stop() or mission complete\n *\n * Uses DefaultMultiAgentCoordinator + AgentSubagentRunner for subagent lifecycle.\n */\nexport class ParallelEternalEngine {\n private state: ParallelEngineState = 'idle';\n private stopRequested = false;\n private iterationsSinceCompact = 0;\n private iterations = 0;\n private consecutiveFailures = 0;\n private readonly goalPath: string;\n private readonly slots: number;\n private readonly timeoutMs: number;\n private coordinator: DefaultMultiAgentCoordinator | null = null;\n private agentFactory: AgentFactory;\n private readonly dispatchEnabled: boolean;\n private readonly dispatchClassifier?: DispatchClassifier | undefined;\n\n constructor(private readonly opts: ParallelEternalOptions) {\n this.goalPath = opts.goalPath ?? goalFilePath(opts.projectRoot);\n this.slots = Math.min(16, Math.max(1, opts.parallelSlots ?? 4));\n this.timeoutMs = opts.iterationTimeoutMs ?? 300_000;\n this.dispatchEnabled = opts.dispatch !== false;\n this.dispatchClassifier = opts.dispatchClassifier;\n this.agentFactory =\n opts.subagentFactory ??\n (async (_config: SubagentConfig) => ({\n agent: this.opts.agent,\n events: this.opts.agent.events,\n }));\n }\n\n /**\n * Emit a structured error. Uses the configured Logger when available;\n * falls back to console.error(JSON) so events are never silently dropped.\n */\n private logError(msg: string, ctx?: Record<string, unknown>): void {\n if (this.opts.logger) {\n this.opts.logger.error(msg, ctx);\n } else {\n console.error(JSON.stringify({ ...ctx, message: msg, timestamp: new Date().toISOString() }));\n }\n }\n\n /**\n * Load the goal file with structured logging for parse/schema warnings.\n */\n private loadGoal(): Promise<GoalFile | null> {\n return loadGoal(\n this.goalPath,\n this.opts.events,\n this.opts.logger ? (msg) => this.opts.logger!.warn(msg) : undefined,\n );\n }\n\n get currentState(): ParallelEngineState {\n return this.state;\n }\n\n /**\n * Get the underlying coordinator for stats/monitoring.\n */\n getCoordinator(): DefaultMultiAgentCoordinator | null {\n return this.coordinator;\n }\n\n stop(): void {\n this.stopRequested = true;\n void this.persistState('stopped').catch((err) => {\n this.logError(\n 'Engine persist state failed',\n { event: 'engine.persist_state_failed', message: toErrorMessage(err), context: { expectedState: 'stopped' } },\n );\n });\n this.state = 'stopped';\n }\n\n async prime(): Promise<void> {\n this.stopRequested = false;\n this.state = 'running';\n await this.persistState('running');\n }\n\n async run(): Promise<void> {\n this.state = 'running';\n await this.persistState('running');\n\n const config: MultiAgentConfig = {\n coordinatorId: `parallel-${randomUUID().slice(0, 8)}`,\n maxConcurrent: this.slots,\n doneCondition: { type: 'all_tasks_done' },\n };\n this.coordinator = new DefaultMultiAgentCoordinator(config);\n // Wrap factory with disabled tool filtering to prevent subagents from\n // using the delegate tool (or any other disabledTools in their config)\n const filteredFactory = withDisabledToolFiltering(this.agentFactory);\n const runner = makeAgentSubagentRunner({ factory: filteredFactory });\n this.coordinator.setRunner?.(runner);\n\n try {\n while (!this.stopRequested) {\n try {\n await this.runOneIteration();\n } catch (err) {\n this.consecutiveFailures++;\n this.opts.onError?.(\n err instanceof Error ? err : new Error(String(err)),\n this.consecutiveFailures,\n );\n await this.appendFailure(\n 'engine error',\n toErrorMessage(err),\n );\n }\n if (this.stopRequested) break;\n await sleep(2000);\n }\n } finally {\n this.state = 'stopped';\n await this.persistState('stopped').catch(() => {});\n }\n }\n\n /**\n * Execute one tick: decompose \u2192 fan-out \u2192 aggregate \u2192 compact.\n * Called by the REPL in its main loop (REPL drives, engine is stateless per tick).\n */\n async runOneIteration(): Promise<boolean> {\n const emit = (stage: ParallelIterationStage) => {\n this.opts.onStage?.(stage);\n };\n\n this.iterations++;\n\n const goal = await this.loadGoal();\n if (!goal) {\n this.stopRequested = true;\n emit({ phase: 'stopped' });\n return false;\n }\n if (goal.goalState !== 'active') {\n this.stopRequested = true;\n emit({ phase: 'stopped' });\n return false;\n }\n\n // Build coordinator on first tick.\n if (!this.coordinator) {\n const config: MultiAgentConfig = {\n coordinatorId: `parallel-${randomUUID().slice(0, 8)}`,\n maxConcurrent: this.slots,\n doneCondition: { type: 'all_tasks_done' },\n };\n this.coordinator = new DefaultMultiAgentCoordinator(config);\n // Wrap factory with disabled tool filtering to prevent subagents from\n // using the delegate tool (or any other disabledTools in their config)\n const filteredFactory = withDisabledToolFiltering(this.agentFactory);\n const runner = makeAgentSubagentRunner({ factory: filteredFactory });\n this.coordinator.setRunner?.(runner);\n }\n\n emit({ phase: 'decompose' });\n const tasks = await this.decomposeGoal(goal);\n if (!tasks || tasks.length === 0) {\n // Nothing to do this tick. The run() loop paces idle iterations itself\n // (see its sleep), so a single runOneIteration() must return promptly.\n emit({ phase: 'sleep', ms: 2000 });\n return false;\n }\n\n emit({ phase: 'fanout', slots: Math.min(this.slots, tasks.length) });\n const fanOut = await this.fanOut(goal, tasks);\n this.iterationsSinceCompact++;\n\n const successCount = fanOut.results.filter((r) => r.status === 'success').length;\n const status: JournalEntry['status'] = fanOut.goalComplete\n ? 'success'\n : fanOut.allSuccessful\n ? 'success'\n : 'failure';\n const note = [\n `${successCount}/${fanOut.results.length} subagents succeeded`,\n fanOut.goalComplete ? '[GOAL_COMPLETE]' : '',\n fanOut.partialOutput ? `Output: ${fanOut.partialOutput.slice(0, 120)}` : '',\n ]\n .filter(Boolean)\n .join(' | ');\n\n // Surface routing in the journal: \"role\u2192task-snippet\" per slot so /goal\n // journal shows which agent handled what.\n const routeSummary =\n fanOut.routes.length > 0\n ? fanOut.routes\n .slice(0, 3)\n .map((r) => `${r.role}\u2192${r.task.slice(0, 28)}`)\n .join(', ')\n : tasks.slice(0, 3).join(', ');\n await this.appendIterationEntry({\n source: 'parallel',\n task: `parallel:${tasks.length} slots \u2014 ${routeSummary}${tasks.length > 3 ? '...' : ''}`,\n status,\n note,\n });\n emit({\n phase: 'aggregate',\n successCount,\n total: fanOut.results.length,\n goalComplete: fanOut.goalComplete,\n });\n\n if (fanOut.goalComplete) {\n this.stopRequested = true;\n this.state = 'stopped';\n emit({ phase: 'stopped' });\n return true;\n }\n\n await this.maybeCompact();\n emit({ phase: 'sleep', ms: 2000 });\n return fanOut.allSuccessful;\n }\n\n // -------------------------------------------------------------------------\n // Fan-out\n // -------------------------------------------------------------------------\n\n private async fanOut(\n goal: GoalFile,\n tasks: string[],\n ): Promise<{\n results: TaskResult[];\n allSuccessful: boolean;\n goalComplete: boolean;\n partialOutput: string;\n routes: Array<{ slot: number; task: string; role: string; method: string }>;\n }> {\n const coordinator = expectDefined(this.coordinator);\n const slotCount = Math.min(this.slots, tasks.length);\n\n // Route each slot task to the best-fit catalog agent. Heuristic by default\n // (instant, no provider call); an injected classifier enables LLM fallback.\n // A dispatch failure for one slot is non-fatal \u2014 that slot stays generic.\n const routes: (DispatchResult | null)[] = this.dispatchEnabled\n ? await Promise.all(\n tasks\n .slice(0, slotCount)\n .map((t) =>\n dispatchAgent(t, { classifier: this.dispatchClassifier }).catch(() => null),\n ),\n )\n : [];\n\n const recentJournal = goal.journal\n .slice(-5)\n .map(\n (e) =>\n ` #${e.iteration} [${e.status}] ${e.task}${e.note ? ` \u2014 ${e.note.slice(0, 80)}` : ''}`,\n )\n .join('\\n');\n\n const directivePreamble = [\n '\u2550\u2550\u2550 ETERNAL AUTONOMY \u2014 parallel task slot \u2550\u2550\u2550',\n '',\n `Mission: ${goal.goal}`,\n `Total parallel slots: ${slotCount}`,\n '',\n recentJournal ? `Recent journal (last 5):\\n${recentJournal}` : 'No prior iterations.',\n '',\n '\u2500\u2500 EXECUTION PROTOCOL \u2500\u2500',\n '\u2022 Execute the assigned task end-to-end using multiple tool calls.',\n '\u2022 Emit `[done]` on its own line when the task is complete.',\n '\u2022 Do not ask before tool use \u2014 YOLO is active unless an explicit deny rule blocks the call.',\n '\u2022 If the overall Mission is accomplished, emit `[GOAL_COMPLETE]` followed by a verification recipe.',\n '\u2022 Keep output concise \u2014 summarize findings, do not transcribe files.',\n ].join('\\n');\n\n const taskIds: string[] = [];\n const subagentIds: string[] = [];\n const routeInfo: Array<{ slot: number; task: string; role: string; method: string }> = [];\n\n const spawnPromises: Array<Promise<void>> = [];\n for (let i = 0; i < slotCount; i++) {\n const task = expectDefined(tasks[i]);\n const route = routes[i] ?? null;\n const subagentId = `parallel-${this.iterations}-${i}`;\n const taskId = randomUUID();\n\n // Persona injection \u2014 works even with the default factory (which reuses\n // the shared main agent and ignores config.prompt/tools), so the agent\n // adopts the routed role's stance for this slot.\n const personaLine = route\n ? `Acting agent: ${route.definition.config.name} \u2014 ${route.definition.capability.summary}\\n`\n : '';\n const spec = {\n id: taskId,\n description: `${directivePreamble}\\n\\n\u2500\u2500 SLOT ${i + 1}/${slotCount} \u2500\u2500\\n${personaLine}Task: ${task}\\n`,\n subagentId,\n };\n\n routeInfo.push({\n slot: i,\n task,\n role: route?.role ?? 'generic',\n method: route?.method ?? 'none',\n });\n\n spawnPromises.push(\n (async () => {\n try {\n // Spawn in-role when routed: `role` lets applyRosterBudget resolve the\n // role's budget tier; name/tools/systemPromptOverride specialize the\n // worker if a real per-role factory is wired (forward-compatible).\n await coordinator.spawn(\n route\n ? {\n id: subagentId,\n name: route.definition.config.name,\n role: route.role,\n tools: route.definition.config.tools,\n systemPromptOverride: route.definition.config.prompt,\n timeoutMs: this.timeoutMs,\n // Disable delegation \u2014 subagents are leaf workers, not orchestrators\n disabledTools: ['delegate'],\n }\n : {\n id: subagentId,\n name: `slot-${subagentId.slice(-6)}`,\n // Let the coordinator apply its default budget (roster or generic).\n // Hardcoding low limits here defeats the x10 budget improvement.\n timeoutMs: this.timeoutMs,\n // Disable delegation \u2014 subagents are leaf workers, not orchestrators\n disabledTools: ['delegate'],\n },\n );\n subagentIds.push(subagentId);\n taskIds.push(taskId);\n await coordinator.assign(spec);\n } catch (err) {\n this.logError(\n 'Parallel spawn failed',\n { event: 'parallel_engine.spawn_failed', message: toErrorMessage(err), context: { slot: i, task, subagentId } },\n );\n }\n })(),\n );\n }\n await Promise.all(spawnPromises);\n\n if (taskIds.length === 0) {\n return {\n results: [],\n allSuccessful: false,\n goalComplete: false,\n partialOutput: '',\n routes: routeInfo,\n };\n }\n\n this.opts.onStage?.({ phase: 'await', taskIds: [...taskIds] });\n\n let results: TaskResult[] = [];\n try {\n // Wait up to 2 hours for subagents to complete. This should cover\n // most subagent tasks since the roster budgets go up to 10 hours.\n // The outer eternal loop manages actual iteration limits.\n //\n // Passed as an explicit per-call timeout: awaitTasks otherwise caps at\n // coordinator.config.timeoutMs (300s default), which would cut a\n // legitimately long subagent short of this window. (The previous\n // AbortController here was dead \u2014 awaitTasks takes no signal.)\n results = await coordinator.awaitTasks(taskIds, {\n timeoutMs: Math.max(this.timeoutMs * 2, 7200_000),\n });\n } catch (err) {\n this.logError(\n 'Brainstorm results failed',\n { event: 'parallel_engine.brainstorm_results_failed', message: toErrorMessage(err), context: { slotCount, taskIds } },\n );\n results = coordinator.results().slice(-taskIds.length);\n }\n\n // Free each per-tick subagent now that its task has resolved. Without this,\n // an eternal-parallel run accumulates dead subagent entries (and their\n // nickname slots) in the coordinator forever \u2014 a slow but unbounded leak\n // over multi-day loops. remove() is idempotent and non-throwing per id.\n await Promise.allSettled(subagentIds.map((id) => coordinator.remove(id)));\n\n const allSuccessful = results.length > 0 && results.every((r) => r.status === 'success');\n const goalComplete = results.some(\n (r) =>\n r.status === 'success' &&\n typeof r.result === 'string' &&\n GOAL_COMPLETE_MARKER.test(r.result),\n );\n const partialOutput = results\n .map((r) => (typeof r.result === 'string' ? r.result : ''))\n .filter(Boolean)\n .join('\\n\\n');\n\n return { results, allSuccessful, goalComplete, partialOutput, routes: routeInfo };\n }\n\n // -------------------------------------------------------------------------\n // Goal decomposition\n // -------------------------------------------------------------------------\n\n private async decomposeGoal(goal: GoalFile): Promise<string[] | null> {\n // Strategy 1: pending todos as sub-tasks\n const todos = this.opts.agent.ctx?.todos;\n const tasks: string[] = [];\n if (Array.isArray(todos)) {\n const pending = todos.filter((t) => t.status === 'pending').slice(0, this.slots);\n for (const t of pending) {\n tasks.push(`[todo] ${t.content}`);\n }\n }\n\n // Strategy 2: git dirty files\n if (tasks.length < this.slots) {\n try {\n const gitStatus = await (this.opts.gitStatusReader?.() ?? this.readGitStatus());\n const dirty = gitStatus.trim();\n if (dirty) {\n const lines = dirty.split('\\n').slice(0, this.slots - tasks.length);\n for (const line of lines) {\n const file = line.replace(/^[ MADRUC?]{2}\\s*/, '').trim();\n if (file) tasks.push(`[git] inspect and fix: ${file}`);\n }\n }\n } catch (err) {\n this.logError(\n 'Git status failed',\n { event: 'parallel_engine.git_status_failed', message: toErrorMessage(err), context: { projectRoot: this.opts.projectRoot } },\n );\n }\n }\n\n // Strategy 3: leader-brainstormed sub-tasks for remaining slots\n if (tasks.length < this.slots) {\n const remaining = this.slots - tasks.length;\n const brainstormed = await this.brainstormSubtasks(goal, remaining);\n tasks.push(...brainstormed);\n }\n\n return tasks.length > 0 ? tasks.slice(0, this.slots) : null;\n }\n\n private async readGitStatus(): Promise<string> {\n const { execFile } = await import('node:child_process');\n const { promisify } = await import('node:util');\n const execFileP = promisify(execFile);\n const { stdout } = await execFileP('git', ['status', '--porcelain'], {\n cwd: this.opts.projectRoot,\n timeout: 5_000,\n });\n return stdout;\n }\n\n private async brainstormSubtasks(goal: GoalFile, count: number): Promise<string[]> {\n const lastFew = goal.journal\n .slice(-5)\n .map((e) => ` - [${e.status}] ${e.task}`)\n .join('\\n');\n const directive = [\n `Decompose this goal into exactly ${count} independent sub-tasks for parallel execution.`,\n '',\n `Goal: ${goal.goal}`,\n '',\n lastFew ? `Recent:\\n${lastFew}` : 'No prior iterations.',\n '',\n `Output exactly ${count} tasks, one per line, under 120 chars each.`,\n 'Format: TASK-1 | TASK-2 | ... (pipe-separated, no numbering, no preamble).',\n 'Each task must be independently actionable with no shared dependencies.',\n ].join('\\n');\n\n try {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), 60_000);\n try {\n const result = await this.opts.agent.run([{ type: 'text' as const, text: directive }], {\n signal: ctrl.signal,\n maxIterations: 1,\n });\n if (result.status !== 'done') return [];\n const text = (result.finalText ?? '').trim();\n if (!text) return [];\n const tasks = text\n .split('|')\n .map((t) => t.trim())\n .filter((t) => t.length > 10 && t.length < 240);\n return tasks.slice(0, count);\n } finally {\n clearTimeout(timer);\n }\n } catch (err) {\n // The leader agent failed to brainstorm. Surface it to onError so the\n // failure is visible, but keep the loop alive (return no tasks \u2014 the\n // next tick retries) rather than crashing the autonomous engine.\n this.opts.onError?.(\n err instanceof Error ? err : new Error(String(err)),\n this.consecutiveFailures,\n );\n return [];\n }\n }\n\n // -------------------------------------------------------------------------\n // Compaction\n // -------------------------------------------------------------------------\n\n private async maybeCompact(): Promise<void> {\n const compactor = this.opts.compactor;\n if (!compactor) return;\n const ctx = this.opts.agent.ctx;\n if (!ctx) return;\n\n const shouldRun = this.iterationsSinceCompact >= (this.opts.compactEveryNIterations ?? 25);\n if (!shouldRun) return;\n\n const report = await compactor.compact(ctx, { aggressive: false });\n this.iterationsSinceCompact = 0;\n await this.appendIterationEntry({\n source: 'manual',\n task: 'compaction (cadence)',\n status: 'success',\n note: `saved ~${report.before - report.after} tokens`,\n });\n }\n\n // -------------------------------------------------------------------------\n // Helpers\n // -------------------------------------------------------------------------\n\n private async appendIterationEntry(entry: Omit<JournalEntry, 'iteration' | 'at'>): Promise<void> {\n const current = await this.loadGoal();\n if (!current) return;\n const updated = appendJournal(current, entry);\n await saveGoal(this.goalPath, updated, this.opts.events);\n const entryWithMeta: JournalEntry = {\n at: (this.opts.now?.() ?? new Date()).toISOString(),\n iteration: updated.iterations,\n ...entry,\n };\n this.opts.onIteration?.(entryWithMeta);\n }\n\n private async appendFailure(task: string, note: string): Promise<void> {\n await this.appendIterationEntry({ source: 'manual', task, status: 'failure', note });\n }\n\n private async persistState(state: GoalFile['engineState']): Promise<void> {\n const current = await this.loadGoal();\n if (!current) return;\n if (current.engineState === state) return;\n await saveGoal(this.goalPath, { ...current, engineState: state }, this.opts.events);\n }\n}\n", "import type { Usage } from '../types/provider.js';\nimport type { EventBus } from '../kernel/events.js';\n\nexport type BudgetKind = 'tool_calls' | 'iterations' | 'tokens' | 'timeout' | 'idle_timeout' | 'cost';\n\n/**\n * Fraction of the wall-clock `timeoutMs` window at which a PROACTIVE extension\n * is negotiated \u2014 BEFORE the deadline is actually crossed. The coordinator\n * watchdog (`executeWithTimeout`) arms at `timeoutMs * TIMEOUT_PREEMPT_FRACTION`\n * so a still-progressing subagent gets its ceiling raised while it is below the\n * limit, and never enters a \"timed out\" state. Reactive enforcement at the real\n * deadline still stands for the no-progress / denied case. Shared so the asking\n * side and any future caller agree on the same lead point.\n */\nexport const TIMEOUT_PREEMPT_FRACTION = 0.85;\n\n/**\n * Hard safety net for budget negotiation decisions. If no listener responds to\n * `budget.threshold_reached` within this window the negotiation defaults to\n * `'stop'`. Exported so the coordinator's watchdog can reuse the same ceiling\n * without hardcoding a second copy.\n */\nexport const DECISION_TIMEOUT_MS = 60_000;\n\nexport class BudgetExceededError extends Error {\n readonly kind: BudgetKind;\n readonly limit: number;\n readonly observed: number;\n\n constructor(kind: BudgetKind, limit: number, observed: number) {\n super(`Budget exceeded: ${kind} (limit=${limit}, observed=${observed})`);\n this.name = 'BudgetExceededError';\n this.kind = kind;\n this.limit = limit;\n this.observed = observed;\n }\n}\n\nexport interface BudgetLimits {\n maxIterations?: number | undefined;\n maxToolCalls?: number | undefined;\n maxTokens?: number | undefined;\n /** Estimated USD cost ceiling. */\n maxCostUsd?: number | undefined;\n /**\n * Hard wall-clock timeout measured from `start()`. Off by default \u2014 set it\n * explicitly only when a task must finish within an absolute window. For\n * the everyday \"don't kill an agent that's still working\" guard, prefer\n * `idleTimeoutMs`, which resets on activity.\n */\n timeoutMs?: number | undefined;\n /**\n * Idle timeout: the maximum gap (ms) between activity signals (iterations,\n * tool calls, token usage, streamed progress) before the subagent is\n * considered hung and reaped. Unlike `timeoutMs`, an actively-working\n * agent continuously resets this clock via `markActivity()`, so it never\n * trips on a long-but-productive run \u2014 only on a genuine stall.\n */\n idleTimeoutMs?: number | undefined;\n}\n\n/**\n * Controls how the budget behaves when `onThreshold` is set and a limit is hit.\n *\n * `'auto'` \u2014 emit `budget.threshold_reached` on the EventBus and wait for a\n * coordinator response (extend/stop). If no listener responds within\n * `DECISION_TIMEOUT_MS` the decision defaults to `'stop'`.\n * `'sync'` \u2014 do not emit any event; treat the threshold as a hard stop and\n * throw `BudgetExceededError` synchronously. Useful for fire-and-forget\n * subagents that have an `onThreshold` handler for logging/metrics but are\n * not wired into a coordinator.\n *\n * @default 'auto'\n */\nexport type BudgetNegotiationMode = 'auto' | 'sync';\n\nexport type BudgetSessionIdSource = string | (() => string | undefined);\n\ninterface SubagentBudgetOptions {\n sessionId?: BudgetSessionIdSource | undefined;\n}\n\nexport interface BudgetUsage {\n iterations: number;\n toolCalls: number;\n tokens: { input: number; output: number; total: number };\n costUsd: number;\n elapsedMs: number;\n}\n\n/**\n * Thrown by `SubagentBudget.record*` when a soft limit is hit and\n * an `onThreshold` handler is configured that wants to ask the\n * coordinator (via `budget.threshold_reached` event). The runner\n * catches this and awaits the embedded `decision` promise to get\n * the coordinator's extend/stop decision.\n *\n * Distinct from `BudgetExceededError` which is a hard stop.\n */\nexport class BudgetThresholdSignal extends Error {\n readonly kind: BudgetKind;\n readonly limit: number;\n readonly used: number;\n /** Resolves to 'extend' (with optional new limits) or 'stop' */\n readonly decision: Promise<BudgetThresholdDecision>;\n\n constructor(\n kind: BudgetKind,\n limit: number,\n used: number,\n decision: Promise<BudgetThresholdDecision>,\n ) {\n super(`Budget soft limit: ${kind} (limit=${limit}, used=${used})`);\n this.name = 'BudgetThresholdSignal';\n this.kind = kind;\n this.limit = limit;\n this.used = used;\n this.decision = decision;\n }\n}\n\nexport type BudgetThresholdDecision =\n | 'stop'\n | { extend: Partial<BudgetLimits> };\n\n/**\n * Callback invoked when a budget limit is about to be exceeded.\n * Return 'throw' for hard stop (default \u2014 throws BudgetExceededError).\n * Return 'continue' to allow one more unit and re-check next time.\n * Return a Promise to ask the coordinator via `budget.threshold_reached`\n * event (uses the same grant/deny pattern as `iteration.limit_reached`).\n */\nexport type BudgetThresholdHandler = (info: {\n kind: BudgetKind;\n used: number;\n limit: number;\n requestDecision: () => Promise<BudgetThresholdDecision>;\n /**\n * Direct grant/deny hooks for SYNCHRONOUS policy or recording handlers that\n * decide in-process without a wired `budget.threshold_reached` listener\n * (e.g. the coordinator watchdog). `extend` patches the limits in place;\n * `deny` records the intent to stop. Production listener-driven handlers use\n * `requestDecision()` instead and can ignore these.\n */\n extend?: (extra: Partial<BudgetLimits>) => void;\n deny?: () => void;\n}) => 'throw' | 'continue' | 'stop' | { extend: Partial<BudgetLimits> } | Promise<BudgetThresholdDecision>;\n\n/**\n * Per-subagent budget enforcement. Each subagent gets its own instance so a\n * runaway agent can't drain the cost ceiling of its siblings. All record/check\n * methods are O(1) and safe to call from hot paths.\n *\n * Behavior without `onThreshold`: hard stops synchronously on every limit hit.\n *\n * Behavior with `onThreshold` and `_mode === 'auto'`: emits `budget.threshold_reached`\n * on the EventBus and throws `BudgetThresholdSignal`. The coordinator's verdict\n * (extend/stop) resolves the embedded promise. If no listener responds within\n * `DECISION_TIMEOUT_MS` the decision defaults to `'stop'`.\n *\n * Behavior with `onThreshold` and `_mode === 'sync'`: throws `BudgetExceededError`\n * synchronously regardless of EventBus state or listener presence. This is useful\n * for fire-and-forget subagents that have an `onThreshold` handler for logging/metrics\n * but are not wired into a coordinator \u2014 the `'sync'` mode makes the hard-stop\n * behavior explicit and means tests can use `expect().toThrow()` even without\n * a fully-wired EventBus.\n */\nexport class SubagentBudget {\n readonly limits: Readonly<BudgetLimits>;\n\n /** Patch one or more budget limits in-place after construction.\n * Used by the coordinator watchdog when granting an extension.\n * All fields are optional \u2014 only provided fields are updated.\n * This is the single write path for limit mutations so that future\n * validation or side-effects live in one place (M1). */\n patchLimits(ext: Partial<BudgetLimits>): void {\n if (ext.maxIterations !== undefined) {\n (this.limits as Record<string, unknown>).maxIterations = ext.maxIterations;\n }\n if (ext.maxToolCalls !== undefined) {\n (this.limits as Record<string, unknown>).maxToolCalls = ext.maxToolCalls;\n }\n if (ext.maxTokens !== undefined) {\n (this.limits as Record<string, unknown>).maxTokens = ext.maxTokens;\n }\n if (ext.maxCostUsd !== undefined) {\n (this.limits as Record<string, unknown>).maxCostUsd = ext.maxCostUsd;\n }\n if (ext.timeoutMs !== undefined) {\n (this.limits as Record<string, unknown>).timeoutMs = ext.timeoutMs;\n }\n if (ext.idleTimeoutMs !== undefined) {\n (this.limits as Record<string, unknown>).idleTimeoutMs = ext.idleTimeoutMs;\n }\n }\n private iterations = 0;\n private toolCalls = 0;\n private tokenInput = 0;\n private tokenOutput = 0;\n private costUsd = 0;\n private startTime: number | null = null;\n /**\n * Timestamp of the most recent activity (iteration / tool call / token\n * usage / streamed progress). Drives the idle timeout \u2014 reset by\n * `markActivity()`. Initialised to `start()` time so a never-active agent\n * still eventually trips its idle window.\n */\n private lastActivityTime: number | null = null;\n private _onThreshold: BudgetThresholdHandler | undefined;\n private readonly _sessionId: BudgetSessionIdSource | undefined;\n /**\n * Hard cap on how long `_negotiateExtension` waits for the coordinator to\n * respond before defaulting to 'stop'. Without this fallback an absent\n * or hung listener (Director not built / event filter detached mid-run)\n * leaves the budget over-limit and never enforces anything.\n */\n private static readonly DECISION_TIMEOUT_MS = DECISION_TIMEOUT_MS;\n /**\n * Injected by the runner when wiring the budget to its EventBus.\n * Used to emit `budget.threshold_reached` events in `'auto'` mode.\n */\n _events?: EventBus | undefined;\n\n /**\n * Guard against dual-path races between the coordinator watchdog\n * (`executeWithTimeout`) and the budget's own `checkTimeout()`.\n * Both paths detect `elapsed >= timeoutMs` and can emit\n * `budget.threshold_reached` for kind `'timeout'` simultaneously.\n * Set to the current `timeoutMs` ceiling by the coordinator BEFORE\n * calling `onThreshold`, and cleared after the negotiation resolves.\n * `checkTimeout()` skips its wall-clock check while this is set so\n * the coordinator's watchdog is the sole source of wall-clock timeout\n * events \u2014 `checkTimeout()` focuses exclusively on `idle_timeout`.\n */\n private _watchdogActive: number | undefined;\n\n /** Returns the timeout ceiling currently being negotiated by the watchdog,\n * or `undefined` when no wall-clock negotiation is in flight.\n * Used by `executeWithTimeout` to detect a stale lock (M3). */\n get watchdogActive(): number | undefined { return this._watchdogActive; }\n\n /** Called by the coordinator watchdog BEFORE calling `onThreshold` so that\n * `checkTimeout()` skips its wall-clock check for this ceiling. Prevents\n * the budget's own `checkTimeout()` from emitting a second\n * `budget.threshold_reached` event while the watchdog is already\n * negotiating the same wall-clock deadline (C1). */\n setWatchdogNegotiation(timeoutMs: number): void { this._watchdogActive = timeoutMs; }\n\n /** Clears the watchdog guard after negotiation resolves. Called in the\n * `finally` block of both the pre-empt and deadline branches so it fires\n * on every exit path: grant, deny, throw, or error. */\n clearWatchdogNegotiation(): void { this._watchdogActive = undefined; }\n\n /**\n * Negotiation mode \u2014 controls whether a threshold hit tries to emit\n * `budget.threshold_reached` and wait for a coordinator decision, or\n * falls straight through to a synchronous hard stop.\n *\n * `'auto'` (default) \u2014 emit on the EventBus and wait; times out to 'stop'.\n * `'sync'` \u2014 throw `BudgetExceededError` immediately regardless of listeners.\n */\n private _mode: BudgetNegotiationMode;\n\n /**\n * Optional callback for soft-limit handling. When set, the budget will\n * invoke it rather than throw immediately. The handler decides whether to\n * throw synchronously, continue, or ask the coordinator for an extension.\n */\n get onThreshold(): BudgetThresholdHandler | undefined {\n return this._onThreshold;\n }\n set onThreshold(fn: BudgetThresholdHandler | undefined) {\n this._onThreshold = fn;\n }\n\n /** Returns the current negotiation mode. */\n get mode(): BudgetNegotiationMode {\n return this._mode;\n }\n\n constructor(\n limits: BudgetLimits = {},\n mode: BudgetNegotiationMode = 'auto',\n options: SubagentBudgetOptions = {},\n ) {\n this._mode = mode;\n this._sessionId = options.sessionId;\n // NOT frozen: `negotiateExtension` patches these limits in place when the\n // coordinator grants an auto-extension. Freezing made every granted\n // extension throw `TypeError: Cannot assign to read only property` in\n // strict mode, which the runner caught as a hard stop \u2014 so extensions\n // silently became kills. The `readonly limits: Readonly<BudgetLimits>`\n // typing still blocks external mutation at compile time.\n this.limits = { ...limits };\n }\n\n private currentSessionId(): string | undefined {\n const value = typeof this._sessionId === 'function' ? this._sessionId() : this._sessionId;\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n }\n\n start(): void {\n this.startTime = Date.now();\n this.lastActivityTime = this.startTime;\n }\n\n /**\n * Reset the idle clock. Called on any sign of forward progress \u2014\n * iterations, tool calls, token usage, and streamed tool/text progress \u2014\n * so a long-but-productive subagent never trips its `idleTimeoutMs`.\n */\n markActivity(): void {\n this.lastActivityTime = Date.now();\n }\n\n /**\n * Milliseconds since the last activity signal. Returns 0 before `start()`\n * (nothing to measure yet). Used by the coordinator watchdog to decide\n * whether to re-arm (still active) or reap (genuinely idle).\n */\n idleMs(): number {\n const since = this.lastActivityTime ?? this.startTime;\n return since === null ? 0 : Date.now() - since;\n }\n\n /** Returns true if we're within 10% of any limit \u2014 useful for pre-flight checks. */\n isNearLimit(): boolean {\n const { maxIterations, maxToolCalls, maxTokens, maxCostUsd } = this.limits;\n if (maxIterations && this.iterations >= maxIterations * 0.9) return true;\n if (maxToolCalls && this.toolCalls >= maxToolCalls * 0.9) return true;\n if (maxTokens && this.tokenInput + this.tokenOutput >= maxTokens * 0.9) return true;\n if (maxCostUsd && this.costUsd >= maxCostUsd * 0.9) return true;\n return false;\n }\n\n /**\n * Synchronous budget check. Always throws synchronously so callers (especially\n * test event handlers using `expect().toThrow()`) get an unhandled rejection\n * when the budget is exceeded without a handler.\n *\n * Decision table:\n * - no `onThreshold` handler \u2192 throw `BudgetExceededError` (hard stop, always)\n * - `mode === 'sync'` \u2192 throw `BudgetExceededError` (hard stop, always)\n * - `mode === 'auto'` + no listener \u2192 throw `BudgetExceededError` (hard stop; no one to ask)\n * - `mode === 'auto'` + listener \u2192 throw `BudgetThresholdSignal` with async decision promise\n */\n /**\n * Collects all exceeded budget kinds into a single NOOP-free negotiation.\n * Called by recordIteration / recordToolCall / recordUsage \u2014 each may call\n * this for its own kind. The first call starts the negotiation and stores\n * the Promise in _pendingNegotiation. Subsequent calls for DIFFERENT\n * kinds (while a negotiation is in flight) are NOOPs \u2014 they don't start\n * new conversations with the coordinator. This prevents an EventBus flood\n * when multiple budget kinds are exceeded simultaneously in one iteration.\n *\n * Returns the kinds that were found to be exceeded (for logging/debugging).\n */\n private checkLimits(elapsedMs?: number): { kind: BudgetKind; used: number; limit: number }[] {\n const exceeded: { kind: BudgetKind; used: number; limit: number }[] = [];\n\n if (this.limits.maxIterations !== undefined && this.iterations > this.limits.maxIterations) {\n exceeded.push({ kind: 'iterations', used: this.iterations, limit: this.limits.maxIterations });\n }\n if (this.limits.maxToolCalls !== undefined && this.toolCalls > this.limits.maxToolCalls) {\n exceeded.push({ kind: 'tool_calls', used: this.toolCalls, limit: this.limits.maxToolCalls });\n }\n const totalTokens = this.tokenInput + this.tokenOutput;\n if (this.limits.maxTokens !== undefined && totalTokens > this.limits.maxTokens) {\n exceeded.push({ kind: 'tokens', used: totalTokens, limit: this.limits.maxTokens });\n }\n if (this.limits.maxCostUsd !== undefined && this.costUsd > this.limits.maxCostUsd) {\n exceeded.push({ kind: 'cost', used: this.costUsd, limit: this.limits.maxCostUsd });\n }\n // Timeout: called from checkTimeout() with elapsedMs (wall-clock) and the\n // current idle gap. Either crossing its limit trips its own kind so the\n // coordinator and auto-extend policy can distinguish them.\n // Wall-clock (`timeoutMs`) is an explicit hard cap; idle (`idleTimeoutMs`)\n // is the default guard that resets on activity. Both can be exceeded in\n // the same call \u2014 we push both entries so all violated limits are reported.\n if (elapsedMs !== undefined) {\n const idle = this.idleMs();\n if (this.limits.idleTimeoutMs !== undefined && idle > this.limits.idleTimeoutMs) {\n exceeded.push({ kind: 'idle_timeout', used: idle, limit: this.limits.idleTimeoutMs });\n }\n // Skip the wall-clock 'timeout' kind while the coordinator watchdog is\n // negotiating this exact ceiling \u2014 it owns wall-clock; checkTimeout/here\n // own idle. Only suppress in the negotiation path (a handler is set); on\n // the no-handler hard-throw path the wall-clock must still trip. (Mirrors\n // the guard in checkTimeout, which previously was NOT applied here \u2014 so\n // an idle trip that called checkLimits re-added 'timeout' and defeated the\n // watchdog dedup.)\n const wallOwnedByWatchdog =\n this._onThreshold !== undefined && this._watchdogActive === this.limits.timeoutMs;\n if (\n this.limits.timeoutMs !== undefined &&\n elapsedMs > this.limits.timeoutMs &&\n !wallOwnedByWatchdog\n ) {\n exceeded.push({ kind: 'timeout', used: elapsedMs, limit: this.limits.timeoutMs });\n }\n }\n\n if (exceeded.length === 0) return [];\n\n if (!this._onThreshold) {\n // Hard stop \u2014 throw on the first exceeded kind.\n const first = exceeded[0] ?? { kind: 'iterations', limit: 0, used: 0 };\n throw new BudgetExceededError(first.kind, first.limit, first.used);\n }\n if (this._mode === 'sync') {\n // Hard stop in sync mode.\n const first = exceeded[0] ?? { kind: 'iterations', limit: 0, used: 0 };\n throw new BudgetExceededError(first.kind, first.limit, first.used);\n }\n const bus = this._events;\n if (!bus) {\n // No EventBus wired at all \u2192 nobody to negotiate with \u2192 hard stop.\n const first = exceeded[0] ?? { kind: 'iterations', limit: 0, used: 0 };\n throw new BudgetExceededError(first.kind, first.limit, first.used);\n }\n\n const first = exceeded[0] ?? { kind: 'iterations', limit: 0, used: 0 };\n\n // LISTENER-DRIVEN PATH. A registered `budget.threshold_reached` listener\n // (director / collab / auto-extend) negotiates asynchronously. Start one\n // negotiation PER exceeded kind \u2014 each reports its OWN kind/used/limit and\n // emits a single event (no O(N^2) re-emission, no cross-kind first-wins\n // drop). Throw `BudgetThresholdSignal` for the first kind so the runner\n // awaits the decision and enforces extend/stop.\n if (bus.hasListenerFor('budget.threshold_reached')) {\n for (const entry of exceeded) {\n if (this._pendingNegotiations.has(entry.kind)) continue; // already negotiating this kind\n this._pendingNegotiations.set(entry.kind, this._negotiateExtension(entry));\n }\n const decision = this._pendingNegotiations.get(first.kind);\n if (!decision) throw new Error(`No pending negotiation for ${first.kind}`);\n throw new BudgetThresholdSignal(first.kind, first.limit, first.used, decision);\n }\n\n // NO-LISTENER PATH. Invoke the handler synchronously to let an in-process\n // policy decide. Two outcomes:\n // \u2022 SYNC handler (returns a string/decision \u2014 e.g. the coordinator\n // watchdog / recording handlers) \u2192 its decision is honored in place\n // (an `extend` patches limits); no throw. This is the path the\n // watchdog drives while it owns wall-clock enforcement.\n // \u2022 ASYNC handler (returns a Promise via `requestDecision()`) \u2192 there is\n // no listener to resolve it and `requestDecision` resolves to 'stop',\n // so this is a definite hard stop: throw `BudgetExceededError`. This is\n // the documented \"auto mode + no listener \u2192 hard stop\" invariant that\n // protects a bare `/spawn` (no director) from a runaway subagent.\n let hardStop: BudgetExceededError | null = null;\n for (const entry of exceeded) {\n // Dedup per kind across back-to-back overruns in the same tick \u2014 a still\n // exceeded kind (e.g. iterations stays over after a grant) must not\n // re-invoke the handler on every record* call. The marker clears on a\n // microtask so a genuinely fresh overrun later can re-negotiate.\n if (this._pendingNegotiations.has(entry.kind)) continue;\n const marker = Promise.resolve<BudgetThresholdDecision>('stop');\n this._pendingNegotiations.set(entry.kind, marker);\n void marker.finally(() => this._pendingNegotiations.delete(entry.kind));\n const sync = this._invokeHandlerSync(entry);\n if (!sync) hardStop ??= new BudgetExceededError(entry.kind, entry.limit, entry.used);\n }\n if (hardStop) throw hardStop;\n return exceeded;\n }\n\n /**\n * Invoke `onThreshold` once for `entry` on the NO-LISTENER path and report\n * whether it decided synchronously. Returns `true` when the handler returned\n * a synchronous decision (already honored \u2014 an `extend` patched the limits),\n * or `false` when it returned a Promise (async; the caller hard-stops, since\n * there is no listener to resolve the negotiation). The handler is given the\n * full info shape (`requestDecision` plus direct `extend`/`deny`) so both\n * recording handlers and policy handlers work without a wired listener.\n */\n private _invokeHandlerSync(entry: { kind: BudgetKind; used: number; limit: number }): boolean {\n const handler = this._onThreshold;\n if (!handler) return false;\n let extendArg: Partial<BudgetLimits> | undefined;\n const result = handler({\n kind: entry.kind,\n used: entry.used,\n limit: entry.limit,\n requestDecision: (): Promise<BudgetThresholdDecision> => this._busRequestDecision(entry),\n // Direct hooks for synchronous policy/recording handlers.\n extend: (extra: Partial<BudgetLimits>) => {\n extendArg = extra;\n },\n deny: () => {},\n } as Parameters<BudgetThresholdHandler>[0]);\n // A thenable means the handler deferred to async negotiation \u2014 but there is\n // no listener here, so it can never be granted \u2192 hard stop.\n if (result && typeof (result as { then?: unknown }).then === 'function') return false;\n if (result === 'throw') return false; // explicit hard stop\n // 'continue' / 'stop' / a returned { extend } decision \u2014 honor in place.\n if (result && typeof result === 'object' && 'extend' in result) {\n extendArg = (result as { extend: Partial<BudgetLimits> }).extend;\n }\n if (extendArg) this.patchLimits(extendArg);\n return true;\n }\n\n /**\n * Emit `budget.threshold_reached` and resolve to the listener's verdict.\n * Resolves to `'stop'` immediately when there is no listener (or no bus) so\n * no negotiation can hang and no fallback timer leaks. Mirrors the\n * coordinator watchdog's own request path so both agree on the no-listener\n * default.\n */\n private _busRequestDecision(entry: {\n kind: BudgetKind;\n used: number;\n limit: number;\n }): Promise<BudgetThresholdDecision> {\n const bus = this._events;\n if (!bus?.hasListenerFor('budget.threshold_reached')) {\n return Promise.resolve('stop');\n }\n return new Promise<BudgetThresholdDecision>((resolve) => {\n let resolved = false;\n const respond = (d: BudgetThresholdDecision) => {\n if (resolved) return;\n resolved = true;\n clearTimeout(fallback);\n resolve(d);\n };\n const fallback = setTimeout(() => respond('stop'), SubagentBudget.DECISION_TIMEOUT_MS);\n const sessionId = this.currentSessionId();\n bus.emit('budget.threshold_reached', {\n ...(sessionId ? { sessionId } : {}),\n kind: entry.kind as\n | 'iterations'\n | 'tool_calls'\n | 'tokens'\n | 'cost'\n | 'timeout'\n | 'idle_timeout',\n used: entry.used,\n limit: entry.limit,\n timeoutMs: SubagentBudget.DECISION_TIMEOUT_MS,\n // deny() wins over a same-dispatch extend(): a listener that both grants\n // and denies (or two listeners disagreeing) is resolved as a stop. The\n // grant is deferred a microtask so a synchronous deny in the same emit\n // pre-empts it; async grants still resolve normally.\n extend: (extra: Partial<BudgetLimits>) => queueMicrotask(() => respond({ extend: extra })),\n deny: () => respond('stop'),\n });\n });\n }\n\n /**\n * Per-kind in-flight negotiation Promises. Each budget kind can have its\n * own concurrent negotiation \u2014 e.g. iterations and timeout can both\n * be exceeded simultaneously without blocking each other. The same kind\n * cannot start two concurrent negotiations (dedup guard).\n * Cleared in `_negotiateExtension`'s `finally` block.\n */\n private _pendingNegotiations = new Map<BudgetKind, Promise<BudgetThresholdDecision>>();\n\n /**\n * Drive the threshold handler to a decision. Resolves with `'stop'`\n * (signal the runner to abort) or `{ extend: ... }` (limits already\n * patched in-place; the runner should not abort). Clears the\n * per-kind slot in `_pendingNegotiations` in `finally`.\n *\n * The 'continue' return from a sync handler is treated as\n * `{ extend: {} }` \u2014 keep going without patching; next overrun fires\n * a fresh signal.\n */\n private async _negotiateExtension(\n entry: { kind: BudgetKind; used: number; limit: number },\n ): Promise<BudgetThresholdDecision> {\n if (!this._onThreshold) {\n // Should never reach here \u2014 caller should have thrown already\n return 'stop';\n }\n try {\n const result = this._onThreshold({\n kind: entry.kind,\n used: entry.used,\n limit: entry.limit,\n // One event for THIS kind only \u2014 each exceeded kind has its own\n // negotiation (and its own resolve), so there is no cross-kind\n // first-wins drop and no O(N^2) re-emission.\n requestDecision: (): Promise<BudgetThresholdDecision> => this._busRequestDecision(entry),\n extend: (extra: Partial<BudgetLimits>) => {\n this.patchLimits(extra);\n },\n deny: () => {},\n } as Parameters<BudgetThresholdHandler>[0]);\n\n if (result === 'throw') return 'stop';\n if (result === 'continue') return { extend: {} };\n\n const decision = await result;\n if (decision === 'stop') return 'stop';\n\n // 'extend' \u2014 patch in-place limits BEFORE resolving (single write path).\n this.patchLimits(decision.extend);\n return decision;\n } finally {\n this._pendingNegotiations.delete(entry.kind);\n }\n }\n\n recordIteration(): void {\n this.iterations++;\n this.markActivity();\n void this.checkLimits();\n }\n\n recordToolCall(): void {\n this.toolCalls++;\n this.markActivity();\n void this.checkLimits();\n }\n\n recordUsage(usage: Usage, costUsd = 0): void {\n this.tokenInput += usage.input;\n this.tokenOutput += usage.output;\n this.costUsd += costUsd;\n this.markActivity();\n void this.checkLimits();\n }\n\n /**\n * Wall-clock / idle budget check. Delegates to `checkLimits(elapsed)`, so\n * `timeout` and `idle_timeout` follow the SAME negotiation path as the other\n * kinds \u2014 they are NOT a special-cased hard stop. This is deliberate: a\n * heartbeat-aware policy (see `attachAutoExtend` and `CollabSession`) grants\n * a timeout extension only while the agent is making progress and denies it\n * once the agent is genuinely stuck, which is safer than an unconditional\n * hard kill of a long-but-working agent. The runner translates the resulting\n * `BudgetThresholdSignal` decision (`extend` \u2192 patch limits in place,\n * `stop` \u2192 abort) just like every other kind.\n *\n * Decision table (same as `checkLimits`):\n * - no `onThreshold` handler \u2192 throw `BudgetExceededError` (hard stop)\n * - `mode === 'sync'` \u2192 throw `BudgetExceededError` (hard stop)\n * - `mode === 'auto'` + no listener \u2192 throw `BudgetExceededError` (no one to ask)\n * - `mode === 'auto'` + listener \u2192 throw `BudgetThresholdSignal` (negotiated;\n * a heartbeat-aware policy may extend the timeout)\n */\n checkTimeout(): void {\n if (this.startTime === null) return;\n const { timeoutMs, idleTimeoutMs } = this.limits;\n if (timeoutMs === undefined && idleTimeoutMs === undefined) return;\n const elapsed = Date.now() - this.startTime;\n // Skip wall-clock timeout if the coordinator watchdog is already in the middle\n // of negotiating this exact ceiling \u2014 tool.progress is too frequent and creates\n // a race where both paths emit budget.threshold_reached for the same kind.\n // The watchdog owns wall-clock; checkTimeout focuses exclusively on idle.\n const wallSkipped =\n this._onThreshold !== undefined &&\n this._watchdogActive !== undefined &&\n timeoutMs !== undefined &&\n this._watchdogActive === timeoutMs;\n const wallTripped = wallSkipped ? false : timeoutMs !== undefined && elapsed > timeoutMs;\n const idleTripped = idleTimeoutMs !== undefined && this.idleMs() > idleTimeoutMs;\n if (!wallTripped && !idleTripped) return;\n void this.checkLimits(elapsed);\n }\n\n /** Returns true if a wall-clock or idle timeout has occurred without throwing. */\n isTimedOut(): boolean {\n if (this.startTime === null) return false;\n const { timeoutMs, idleTimeoutMs } = this.limits;\n if (timeoutMs !== undefined && Date.now() - this.startTime > timeoutMs) return true;\n if (idleTimeoutMs !== undefined && this.idleMs() > idleTimeoutMs) return true;\n return false;\n }\n\n usage(): BudgetUsage {\n return {\n iterations: this.iterations,\n toolCalls: this.toolCalls,\n tokens: {\n input: this.tokenInput,\n output: this.tokenOutput,\n total: this.tokenInput + this.tokenOutput,\n },\n costUsd: this.costUsd,\n elapsedMs: this.startTime === null ? 0 : Date.now() - this.startTime,\n };\n }\n}\n", "/**\n * Well-known tool capabilities used for authorization decisions.\n *\n * These are the preferred values for `Tool.capabilities`.\n * New capabilities should be added here with clear documentation.\n *\n * Philosophy (2026-06+):\n * - Prefer capabilities over exact tool name matching.\n * - Subagent guards and future policies should primarily key off capabilities.\n * - Name-based denylists are legacy and will be phased down.\n */\nexport const ToolCapabilities = {\n /** Can execute arbitrary commands in the user's shell (the `bash` tool). */\n SHELL_ARBITRARY: 'shell.arbitrary',\n\n /** Can execute a restricted set of commands (the `exec` tool). */\n SHELL_RESTRICTED: 'shell.restricted',\n\n /** Can run a restricted project formatter/linter-style command. */\n SHELL_EXEC: 'shell.exec',\n\n /** Can read files inside the project (and possibly outside via symlinks if not guarded). */\n FS_READ: 'fs.read',\n\n /** Can write / modify / delete files inside the project. */\n FS_WRITE: 'fs.write',\n\n /** Can write files outside the current project root (very high risk). */\n FS_WRITE_OUTSIDE_PROJECT: 'fs.write.outside-project',\n\n /** Can perform outbound network requests. */\n NET_OUTBOUND: 'net.outbound',\n\n /** Can mutate in-memory session todos only. */\n SESSION_TODO: 'session.todo',\n\n /** Can mutate in-memory session mode only. */\n SESSION_MODE: 'session.mode',\n\n /** Can inspect registered tool metadata. */\n TOOL_META: 'tool.meta',\n\n /** Can invoke arbitrary registered tools through a meta-tool. */\n TOOL_MUTATE_ANY: 'tool.mutate.any',\n\n /** Can read persistent memory. */\n MEMORY_READ: 'memory.read',\n\n /** Can write persistent memory. */\n MEMORY_WRITE: 'memory.write',\n\n /** Can delete persistent memory. */\n MEMORY_DELETE: 'memory.delete',\n\n /** Proxies tools from external MCP servers (unknown capability). */\n MCP_PROXY: 'mcp.proxy',\n\n /** Can spawn or manage subagents / multi-agent tasks. */\n SUBAGENT_SPAWN: 'subagent.spawn',\n\n /** Can inspect fleet/subagent coordination state without mutating it. */\n COORDINATION_FLEET_READ: 'coordination.fleet.read',\n\n /** Can publish attributed, schema-checked events onto the fleet bus. */\n COORDINATION_FLEET_EMIT: 'coordination.fleet.emit',\n\n /** Can submit a task-local structured result to the parent Director. */\n COORDINATION_RESULT_SUBMIT: 'coordination.result.submit',\n\n /** Can read or write inter-agent mailbox messages. */\n COORDINATION_MAIL: 'coordination.mail',\n\n /** Can schedule, inspect, or cancel in-session cron jobs. */\n COORDINATION_CRON: 'coordination.cron',\n\n /** Can mutate global or session configuration / trust state. */\n CONFIG_MUTATE: 'config.mutate',\n\n /** Can install packages or run package managers with side effects. */\n PACKAGE_INSTALL: 'package.install',\n} as const;\n\nexport type ToolCapability = (typeof ToolCapabilities)[keyof typeof ToolCapabilities];\n\n/**\n * Set of capabilities that are considered dangerous for subagents by default.\n * Subagents should not receive these capabilities unless the leader explicitly\n * allows the specific tool at spawn time.\n */\nexport const DANGEROUS_FOR_SUBAGENTS: readonly ToolCapability[] = [\n ToolCapabilities.SHELL_ARBITRARY,\n ToolCapabilities.SHELL_RESTRICTED,\n ToolCapabilities.SHELL_EXEC,\n ToolCapabilities.FS_WRITE,\n ToolCapabilities.FS_WRITE_OUTSIDE_PROJECT,\n ToolCapabilities.TOOL_MUTATE_ANY,\n ToolCapabilities.MEMORY_WRITE,\n ToolCapabilities.MEMORY_DELETE,\n ToolCapabilities.MCP_PROXY,\n ToolCapabilities.SUBAGENT_SPAWN,\n ToolCapabilities.CONFIG_MUTATE,\n ToolCapabilities.PACKAGE_INSTALL,\n];\n\n/**\n * Wide capability allowlist for subagents that the user has authorized to act\n * with full developer power (the CLI fleet host applies this to any subagent\n * that isn't given an explicit, narrower grant). It covers everything needed to\n * do real work end-to-end \u2014 read, write/edit inside the project, outbound\n * network, all shell/build/install capabilities, session todos, tool metadata, and read-only\n * memory lookup \u2014 so a delegated coding or build agent runs the same toolchain\n * the leader would, without per-tool confirmation it cannot answer.\n *\n * Deliberately EXCLUDED (require an explicit per-spawn `allowedCapabilities`\n * grant, because they escape the task's blast radius rather than perform it):\n * - `fs.write.outside-project` \u2014 writing outside the repo (e.g. ~/.ssh).\n * - `tool.mutate.any` \u2014 arbitrary meta-tool dispatch.\n * - `memory.write` / `memory.delete` \u2014 persistent memory mutation.\n * - `mcp.proxy` \u2014 third-party MCP tools (also hard-blocked by name).\n * - `subagent.spawn` \u2014 recursive delegation (the baseline prompt forbids it).\n * - `config.mutate` \u2014 rewriting trust/config is privilege escalation, not work.\n */\nexport const WIDE_SUBAGENT_CAPABILITIES: readonly ToolCapability[] = [\n ToolCapabilities.FS_READ,\n ToolCapabilities.FS_WRITE,\n ToolCapabilities.NET_OUTBOUND,\n ToolCapabilities.SESSION_TODO,\n ToolCapabilities.TOOL_META,\n ToolCapabilities.MEMORY_READ,\n ToolCapabilities.SHELL_ARBITRARY,\n ToolCapabilities.SHELL_RESTRICTED,\n ToolCapabilities.SHELL_EXEC,\n ToolCapabilities.PACKAGE_INSTALL,\n // Read-only fleet visibility (fleet_status) \u2014 peer awareness has no blast\n // radius and every fleet worker should coordinate around its peers.\n ToolCapabilities.COORDINATION_FLEET_READ,\n ToolCapabilities.COORDINATION_RESULT_SUBMIT,\n];\n\n/**\n * Check if a tool (or its capabilities array) includes any dangerous capability\n * for subagent execution.\n */\nexport function hasDangerousCapabilityForSubagents(\n toolOrCaps: { capabilities?: readonly string[] | undefined } | readonly string[] | undefined,\n): boolean {\n if (!toolOrCaps) return false;\n const input = toolOrCaps as never as { capabilities?: readonly string[] | undefined };\n const caps: readonly string[] = Array.isArray(toolOrCaps) ? toolOrCaps : (input.capabilities ?? []);\n return caps.some((c) => DANGEROUS_FOR_SUBAGENTS.includes(c as ToolCapability));\n}\n\n/**\n * Check if a tool declares a specific capability (or any of the provided ones).\n */\nexport function hasCapability(\n toolOrCaps: { capabilities?: readonly string[] | undefined } | readonly string[] | undefined,\n capability: ToolCapability | ToolCapability[],\n): boolean {\n if (!toolOrCaps) return false;\n const input = toolOrCaps as never as { capabilities?: readonly string[] | undefined };\n const caps: readonly string[] = Array.isArray(toolOrCaps) ? toolOrCaps : (input.capabilities ?? []);\n const toCheck = Array.isArray(capability) ? capability : [capability];\n return toCheck.some((c) => caps.includes(c));\n}\n\n/**\n * Returns the intersection of a tool's capabilities with the dangerous set.\n * Useful for logging and audit trails.\n */\nexport function getDangerousCapabilities(\n toolOrCaps: { capabilities?: readonly string[] | undefined } | readonly string[] | undefined,\n): ToolCapability[] {\n if (!toolOrCaps) return [];\n const input = toolOrCaps as never as { capabilities?: readonly string[] | undefined };\n const caps: readonly string[] = Array.isArray(toolOrCaps) ? toolOrCaps : (input.capabilities ?? []);\n return caps.filter((c): c is ToolCapability =>\n DANGEROUS_FOR_SUBAGENTS.includes(c as ToolCapability),\n );\n}\n", "import type { Context } from '../core/context.js';\nimport { ToolCapabilities } from '../security/capabilities.js';\nimport type { SubagentStructuredReport } from '../types/multi-agent.js';\nimport type { Tool } from '../types/tool.js';\n\n/** Context metadata key used to hand the submitted report to the task runner. */\nexport const SUBAGENT_STRUCTURED_REPORT_META_KEY = 'subagentStructuredReport';\nexport const MAX_SUBAGENT_STRUCTURED_REPORT_CHARS = 8_000;\n\nconst MAX_SUMMARY_CHARS = 1_500;\nconst MAX_FINDINGS = 16;\nconst MAX_FILES = 64;\nconst MAX_NEXT_STEPS = 12;\nconst MAX_ITEM_CHARS = 500;\n\n/**\n * Validate and normalize a model-supplied structured result. The tool executor\n * already applies JSON Schema validation, but this guard keeps direct callers,\n * custom executors, and data read back from Context metadata honest too.\n */\nexport function normalizeSubagentStructuredReport(\n value: unknown,\n): SubagentStructuredReport | undefined {\n if (!isRecord(value)) return undefined;\n const summary = nonEmptyString(value['summary']);\n const findings = stringArray(value['findings']);\n const filesExamined = stringArray(value['files_examined']);\n const nextSteps = stringArray(value['suggested_next_steps']);\n const confidence = value['confidence'];\n const completion = value['completion'];\n const remainingWork = optionalString(value['remaining_work']);\n if (\n !summary ||\n summary.length > MAX_SUMMARY_CHARS ||\n !findings ||\n findings.length > MAX_FINDINGS ||\n !filesExamined ||\n filesExamined.length > MAX_FILES ||\n !nextSteps ||\n nextSteps.length > MAX_NEXT_STEPS ||\n [...findings, ...filesExamined, ...nextSteps].some(\n (item) => item.trim().length > MAX_ITEM_CHARS,\n ) ||\n typeof confidence !== 'number' ||\n !Number.isFinite(confidence) ||\n confidence < 0 ||\n confidence > 1 ||\n (completion !== undefined && completion !== 'complete' && completion !== 'partial') ||\n (completion === 'partial' && !remainingWork) ||\n (remainingWork !== undefined && remainingWork.length > MAX_SUMMARY_CHARS)\n ) {\n return undefined;\n }\n const report: SubagentStructuredReport = {\n summary,\n findings: findings.map((item) => item.trim()).filter(Boolean),\n files_examined: filesExamined.map((item) => item.trim()).filter(Boolean),\n confidence,\n suggested_next_steps: nextSteps.map((item) => item.trim()).filter(Boolean),\n ...(completion === 'complete' || completion === 'partial' ? { completion } : {}),\n ...(remainingWork ? { remaining_work: remainingWork } : {}),\n };\n return JSON.stringify(report).length <= MAX_SUBAGENT_STRUCTURED_REPORT_CHARS\n ? report\n : undefined;\n}\n\nexport function readSubagentStructuredReport(\n ctx: Pick<Context, 'meta'> | { meta?: Record<string, unknown> } | undefined,\n): SubagentStructuredReport | undefined {\n return normalizeSubagentStructuredReport(ctx?.meta?.[SUBAGENT_STRUCTURED_REPORT_META_KEY]);\n}\n\n/** Stable compact text form for mailbox/roll-up surfaces. */\nexport function formatSubagentStructuredReport(report: SubagentStructuredReport): string {\n const findings = report.findings.length\n ? report.findings.map((item) => `- ${item}`).join('\\n')\n : '- (none)';\n const files = report.files_examined.length ? report.files_examined.join(', ') : '(none)';\n const next = report.suggested_next_steps.length\n ? report.suggested_next_steps.map((item) => `- ${item}`).join('\\n')\n : '- (none)';\n return [\n report.summary,\n report.completion ? `Completion: ${report.completion}` : undefined,\n report.remaining_work ? `Remaining work: ${report.remaining_work}` : undefined,\n `\\nFindings:\\n${findings}`,\n `\\nFiles examined: ${files}`,\n `Confidence: ${report.confidence.toFixed(2)}`,\n `\\nSuggested next steps:\\n${next}`,\n ]\n .filter((line): line is string => typeof line === 'string')\n .join('\\n');\n}\n\n/** Safe, task-local handoff channel from a subagent to its Director. */\nexport function makeSubagentResultTool(): Tool {\n return {\n name: 'submit_result',\n description:\n 'Submit the task result as a compact structured report for the Director. Call once near the end, before your final text response.',\n permission: 'auto',\n mutating: false,\n capabilities: [ToolCapabilities.COORDINATION_RESULT_SUBMIT],\n inputSchema: {\n type: 'object',\n properties: {\n summary: {\n type: 'string',\n maxLength: MAX_SUMMARY_CHARS,\n description: 'Concise outcome summary.',\n },\n findings: {\n type: 'array',\n maxItems: MAX_FINDINGS,\n items: { type: 'string' },\n description: 'Atomic findings or changes, with evidence when useful.',\n },\n files_examined: {\n type: 'array',\n maxItems: MAX_FILES,\n items: { type: 'string' },\n description: 'Project-relative files materially read or changed.',\n },\n confidence: {\n type: 'number',\n minimum: 0,\n maximum: 1,\n description: 'Confidence from 0.0 to 1.0.',\n },\n suggested_next_steps: {\n type: 'array',\n maxItems: MAX_NEXT_STEPS,\n items: { type: 'string' },\n description: 'Concrete follow-ups; use an empty array when none remain.',\n },\n completion: {\n type: 'string',\n enum: ['complete', 'partial'],\n description:\n 'Use `partial` only when the task is intentionally stopping at a clean checkpoint and another worker should continue.',\n },\n remaining_work: {\n type: 'string',\n maxLength: MAX_SUMMARY_CHARS,\n description:\n 'Concrete work left for a successor. Required by runtime validation when completion is `partial`.',\n },\n },\n required: ['summary', 'findings', 'files_examined', 'confidence', 'suggested_next_steps'],\n additionalProperties: false,\n },\n async execute(input, ctx) {\n const report = normalizeSubagentStructuredReport(input);\n if (!report) {\n return {\n ok: false,\n error:\n 'Invalid report: summary/findings/files_examined/confidence/suggested_next_steps are required and confidence must be 0..1.',\n };\n }\n ctx.meta[SUBAGENT_STRUCTURED_REPORT_META_KEY] = report;\n return {\n ok: true,\n findings: report.findings.length,\n filesExamined: report.files_examined.length,\n confidence: report.confidence,\n };\n },\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction nonEmptyString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n}\n\nfunction optionalString(value: unknown): string | undefined {\n return value === undefined ? undefined : nonEmptyString(value);\n}\n\nfunction stringArray(value: unknown): string[] | undefined {\n return Array.isArray(value) && value.every((item) => typeof item === 'string')\n ? value\n : undefined;\n}\n", "import type { Agent, AgentInput, RunResult } from '../core/agent.js';\nimport type { EventBus } from '../kernel/events.js';\nimport type {\n SubagentConfig,\n SubagentRunContext,\n SubagentRunOutcome,\n SubagentRunner,\n TaskSpec,\n} from '../types/multi-agent.js';\nimport { AgentError, ERROR_CODES } from '../types/errors.js';\nimport {\n BudgetExceededError,\n BudgetThresholdSignal,\n} from './subagent-budget.js';\nimport type { FleetBus } from './fleet-bus.js';\nimport { readSubagentStructuredReport } from './subagent-result-tool.js';\n\n/**\n * Caller-supplied factory that builds an isolated `Agent` for a subagent.\n * The factory MUST construct a fresh `Context` per call \u2014 sharing context\n * between subagents defeats isolation. Each Agent should also use either\n * its own `EventBus` or a forwarded view, so per-subagent metrics can be\n * attributed correctly.\n */\nexport type AgentFactory = (config: SubagentConfig, task?: TaskSpec) => Promise<AgentFactoryResult>;\n\n/**\n * Wrap a factory to automatically filter out disabled tools from subagent\n * configurations. This provides mechanical enforcement of tool restrictions\n * (e.g., preventing delegation) in addition to the baseline prompt constraint.\n *\n * The wrapper reads `config.disabledTools` and removes those tools from the\n * agent's tool registry before returning.\n *\n * Usage:\n * const filteredFactory = withDisabledToolFiltering(originalFactory);\n * const runner = makeAgentSubagentRunner({ factory: filteredFactory });\n */\nexport function withDisabledToolFiltering(factory: AgentFactory): AgentFactory {\n return async (config: SubagentConfig, task?: TaskSpec) => {\n const result = await factory(config, task);\n const disabled = config.disabledTools ?? [];\n if (disabled.length === 0) return result;\n\n // Agent.tools is a ToolRegistry with unregister() method\n const registry = result.agent.tools;\n if (registry && typeof registry.unregister === 'function') {\n for (const toolName of disabled) {\n registry.unregister(toolName);\n }\n }\n return result;\n };\n}\n\nexport interface AgentFactoryResult {\n agent: Agent;\n /** Event bus the factory wired to this agent \u2014 required for budget hookup. */\n events: EventBus;\n /**\n * Optional cleanup hook invoked in the runner's `finally` block once\n * the task ends (success, failure, abort \u2014 same exit path). Factories\n * that own resources scoped to a single task (per-subagent JSONL\n * writers, transient providers, throwaway containers) implement this\n * to close them deterministically instead of relying on GC. Errors\n * thrown here are swallowed so a flaky cleanup can't mask the task's\n * real result.\n */\n dispose?: ((() => Promise<void> | void)) | undefined;\n}\n\nexport interface AgentRunnerOptions {\n factory: AgentFactory;\n /**\n * Format a TaskSpec into the user input the agent will receive. Defaults\n * to `task.description ?? ''`. Override when subagents expect structured\n * input (e.g. JSON contracts, role-prefixed prompts).\n */\n formatTaskInput?: (task: TaskSpec, config: SubagentConfig) => AgentInput;\n /**\n * When set, the runner attaches the subagent's EventBus to this FleetBus\n * on task start and detaches it when the task finishes. This is the\n * injection seam that lets the TUI fleet panel observe subagent activity\n * live \u2014 without it, FleetBus stays empty.\n */\n fleetBus?: FleetBus | undefined;\n /**\n * Optional parent bus for task-correlated worker telemetry. The worker keeps\n * its own EventBus for isolation; this explicit bridge forwards only the\n * tool/file channels needed by host observability surfaces.\n */\n hostEvents?: EventBus | undefined;\n}\n\n/**\n * Builds a `SubagentRunner` that drives a real `Agent` per task while honoring\n * the coordinator's budget and abort signal. This is the production adapter \u2014\n * the coordinator's `runner` option in CLI/TUI assemblies points here.\n *\n * Lifecycle per task:\n * 1. factory(config) \u2192 fresh Agent + EventBus.\n * 2. Subscribe to events to feed the budget (tool calls, token usage).\n * 3. Call agent.run(input, { signal }) \u2014 the coordinator's signal cancels.\n * 4. Map RunResult.status onto a `SubagentRunOutcome` or throw on failure.\n * 5. Unsubscribe and let the factory's resources be GC'd.\n *\n * The budget is checked synchronously from event handlers \u2014 a runaway agent\n * that crosses its tool-call limit triggers `BudgetExceededError`, which the\n * coordinator surfaces as `status: 'failed'` on the task result.\n */\nexport function makeAgentSubagentRunner(opts: AgentRunnerOptions): SubagentRunner {\n const format = opts.formatTaskInput ?? defaultFormatTaskInput;\n\n return async (task: TaskSpec, ctx: SubagentRunContext): Promise<SubagentRunOutcome> => {\n const taskStartedAt = Date.now();\n const factoryResult = await opts.factory(ctx.config, task);\n const { agent, events } = factoryResult;\n const taskContext = task.context ?? {};\n const hasExplicitTelemetryTask = typeof taskContext['telemetryTaskId'] === 'string';\n const telemetryTaskId = hasExplicitTelemetryTask\n ? (taskContext['telemetryTaskId'] as string)\n : task.id;\n const telemetryRunId =\n typeof taskContext['telemetryRunId'] === 'string'\n ? taskContext['telemetryRunId']\n : undefined;\n const telemetryBoardId =\n typeof taskContext['telemetryBoardId'] === 'string'\n ? taskContext['telemetryBoardId']\n : undefined;\n // Tool calls such as fleet_emit need authoritative caller/task attribution.\n // The Agent and Context are task-scoped, so this cannot leak into a later\n // assignment even when the coordinator reuses the same logical subagent.\n const agentContext = (\n agent as Agent & {\n ctx?: {\n meta?: Record<string, unknown>;\n setCurrentKanbanTask?: (taskId: string | undefined, boardId?: string) => void;\n };\n }\n ).ctx;\n if (agentContext?.meta) {\n agentContext.meta['subagentTaskId'] = task.id;\n const kanbanContext = taskContext['kanban'];\n if (kanbanContext && typeof kanbanContext === 'object') {\n agentContext.meta['kanban'] = kanbanContext;\n }\n if (hasExplicitTelemetryTask) {\n agentContext.meta['telemetryTaskId'] = telemetryTaskId;\n if (telemetryRunId) agentContext.meta['telemetryRunId'] = telemetryRunId;\n }\n }\n if (hasExplicitTelemetryTask) {\n agentContext?.setCurrentKanbanTask?.(telemetryTaskId, telemetryBoardId);\n } else {\n const kanbanContext = taskContext['kanban'];\n if (kanbanContext && typeof kanbanContext === 'object') {\n const kanban = kanbanContext as Record<string, unknown>;\n const boardId = typeof kanban['boardId'] === 'string' ? kanban['boardId'] : undefined;\n const taskId = typeof kanban['taskId'] === 'string' ? kanban['taskId'] : undefined;\n if (taskId) agentContext?.setCurrentKanbanTask?.(taskId, boardId);\n }\n }\n\n // Attach subagent EventBus to FleetBus so the TUI fleet panel (and any\n // other FleetBus subscriber) can observe this subagent live. Detach on\n // task finish \u2014 each task is a fresh Agent + EventBus, so we never\n // want a stale bus lingering after the run.\n const detachFleet = opts.fleetBus?.attach(ctx.subagentId, events, task.id);\n\n // Hook budget into the agent's event stream. We capture errors thrown by\n // recordToolCall/recordUsage so the budget can short-circuit the run by\n // aborting the controller \u2014 the agent then unwinds cooperatively.\n const aborter = new AbortController();\n // Inject the EventBus into the budget so it can emit budget.threshold_reached\n // events when a soft limit is hit and the handler wants to ask the coordinator.\n ctx.budget._events = events;\n // Wire the threshold-negotiation handler. Without this the soft-limit\n // path is dead code: every budget overrun becomes a hard\n // BudgetExceededError and the subagent dies on its first 120-iteration\n // tick instead of asking the Director for headroom. The Director's\n // FleetBus listener (director.ts) auto-grants +50% up to a per-kind\n // ceiling and per-subagent extension count \u2014 wiring this is the\n // missing link that activates that flow.\n ctx.budget.onThreshold = ({ requestDecision }) => requestDecision();\n let budgetError: Error | null = null;\n\n /**\n * Common error handler for all budget-triggered events. Distinguishes:\n * - BudgetExceededError \u2192 hard stop, set budgetError + abort\n * - BudgetThresholdSignal \u2192 soft stop: await the coordinator's\n * decision. If 'stop', abort. If 'extend', the signal handler\n * has already patched the budget so we can continue without\n * actually aborting the agent.\n */\n const onBudgetError = (err: unknown): void => {\n if (err instanceof BudgetThresholdSignal) {\n // Defer the stop/extend decision to the post-finally block below.\n // The coordinator's verdict may arrive after agent.run() returns;\n // awaiting it there (rather than in this fire-and-forget handler)\n // avoids a race where both this callback and the post-finally\n // block try to mutate `budgetError` concurrently.\n budgetError = err;\n return;\n }\n // Hard stop (BudgetExceededError or other)\n aborter.abort();\n budgetError =\n err instanceof BudgetExceededError\n ? err\n : new BudgetExceededError(\n 'tool_calls',\n 0,\n 0,\n );\n // Attach the real error detail so the task result surfaces\n // something actionable instead of a generic budget message.\n if (budgetError !== err && err instanceof Error) {\n budgetError.message += ` (caused by: ${err.message})`;\n }\n };\n\n // Track the name of the most recent tool that returned ok:false so\n // we can lift it into the SubagentError when the agent ends without\n // recovering. Cleared on every successful tool execution so a tool\n // that later succeeded doesn't taint the final report.\n let lastToolFailed: string | null = null;\n\n const unsub: Array<() => void> = [];\n unsub.push(\n events.on('tool.executed', (e) => {\n if (hasExplicitTelemetryTask) {\n opts.hostEvents?.emit('subagent.tool_executed', {\n sessionId: e.sessionId,\n subagentId: ctx.subagentId,\n agentSessionId: e.sessionId,\n agentName: e.agentName ?? ctx.config.name,\n taskId: telemetryTaskId,\n runId: telemetryRunId,\n traceId: e.traceId,\n id: e.id,\n name: e.name,\n durationMs: e.durationMs,\n ok: e.ok,\n // Raw tool inputs may contain credentials or sensitive arguments.\n // Task telemetry crosses from the isolated worker bus to the shared\n // host bus, so expose only execution metadata at this boundary.\n outputBytes: e.outputBytes,\n outputTokens: e.outputTokens,\n outputLines: e.outputLines,\n });\n }\n // Count tool calls on the PAIRED 'tool.executed' event rather\n // than 'tool.started'. A tool can fire start then crash before\n // emitting executed (process killed, signal aborted mid-exec);\n // counting only the paired event keeps the budget tally honest\n // and matches what the model actually saw in its turn.\n try {\n ctx.budget.recordToolCall();\n } catch (eb) {\n onBudgetError(eb);\n }\n // Track ok:false so we can fail the subagent if it ends without\n // recovering. Successful runs clear it \u2014 the model may try a\n // tool, get an error, and self-heal on the next iteration; that\n // path should still report success.\n if (e.ok === false) {\n lastToolFailed = e.name;\n } else if (e.ok === true) {\n lastToolFailed = null;\n }\n }),\n events.on('file.event', (e) => {\n if (!hasExplicitTelemetryTask) return;\n // The fallback factory can reuse the host EventBus. Do not recursively\n // re-bridge the already-correlated copy on that shared-bus path.\n if (e.runId === telemetryRunId && e.taskId === telemetryTaskId) return;\n opts.hostEvents?.emit('file.event', {\n ...e,\n scope: 'task',\n taskId: telemetryTaskId,\n boardId: telemetryBoardId,\n runId: telemetryRunId,\n });\n }),\n events.on('provider.response', (e) => {\n try {\n ctx.budget.recordUsage(e.usage);\n } catch (e2) {\n void onBudgetError(e2);\n }\n }),\n events.on('iteration.started', () => {\n try {\n ctx.budget.recordIteration();\n } catch (e) {\n void onBudgetError(e);\n }\n // Emit a periodic progress snapshot every SUMMARY_INTERVAL\n // iterations so the leader can surface \"AGENT#2 \u25CF L25 \u00B7 47 tools\"\n // in the main chat history without needing the FleetPanel open.\n const u = ctx.budget.usage();\n const since = u.iterations - lastSummaryAtIteration;\n if (since >= SUMMARY_INTERVAL) {\n lastSummaryAtIteration = u.iterations;\n events.emit('subagent.iteration_summary', {\n subagentId: ctx.subagentId,\n iteration: u.iterations,\n toolCalls: u.toolCalls,\n costUsd: u.costUsd,\n currentTool: currentToolName,\n partialText: streamingTextAcc.trim() || undefined,\n });\n }\n }),\n // D3: cooperative timeout enforcement DURING a long tool call.\n // The iteration-loop checkTimeout() only fires between agent\n // iterations \u2014 a single `bash sleep 3600` call would otherwise\n // park inside one tool execution while the timeout silently\n // passes, relying solely on the coordinator's hard Promise.race\n // to interrupt. Tools that emit `tool.progress` (bash chunks,\n // fetch byte progress, spawn-stream stdout) give us a heartbeat\n // we can hang the check on. When the budget trips here:\n // 1. onBudgetError sets budgetError + aborter.abort()\n // 2. aborter signal propagates to agent.run \u2192 tool executor\n // 3. tool's own signal listener kills the child process\n // Cheap: O(1) per progress event, and the budget short-circuits\n // when timeoutMs is unset (most subagents have one set anyway).\n events.on('tool.progress', () => {\n // Streamed progress (bash chunks, fetch bytes, spawn stdout) is forward\n // motion \u2014 reset the idle clock so a long-but-working tool is never\n // mistaken for a stall, THEN check whether a genuine timeout tripped.\n ctx.budget.markActivity();\n try {\n ctx.budget.checkTimeout();\n } catch (e) {\n void onBudgetError(e);\n }\n }),\n );\n\n // Track current tool name + streaming text for the periodic summary.\n let currentToolName: string | undefined;\n let streamingTextAcc = '';\n let lastSummaryAtIteration = 0;\n const SUMMARY_INTERVAL = 25;\n\n unsub.push(\n events.on('tool.started', (e) => {\n currentToolName = e.name;\n }),\n events.on('provider.text_delta', (e) => {\n // Streamed assistant text is forward motion too \u2014 keep the idle\n // clock fresh while the model is actively generating.\n ctx.budget.markActivity();\n // Accumulate last ~2000 chars for the partial text snapshot.\n streamingTextAcc = (streamingTextAcc + e.text).slice(-2000);\n const text = streamingTextAcc.trim();\n if (text) {\n ctx.reportProgress?.({ text, source: 'stream', capturedAt: Date.now() });\n }\n }),\n );\n\n // Forward the coordinator signal so stop() from outside also aborts.\n const onParentAbort = () => aborter.abort();\n ctx.signal.addEventListener('abort', onParentAbort);\n\n let result: RunResult;\n try {\n result = await agent.run(format(task, ctx.config), { signal: aborter.signal });\n const finalText = result.finalText?.trim();\n if (finalText) {\n ctx.reportProgress?.({ text: finalText, source: 'run_result', capturedAt: Date.now() });\n }\n // Emit task_completed BEFORE the finally block unsubscribes the\n // FleetBus \u2014 this lets the WebUI see the subagent's final output.\n events.emit('subagent.task_completed', {\n subagentId: ctx.subagentId,\n taskId: task.id,\n status: result.status === 'done' ? 'success' : 'failed',\n iterations: result.iterations,\n toolCalls: ctx.budget.usage().toolCalls,\n durationMs: Date.now() - taskStartedAt,\n finalText: result.finalText?.trim() || undefined,\n });\n } finally {\n detachFleet?.();\n ctx.signal.removeEventListener('abort', onParentAbort);\n for (const u of unsub) u();\n // Per-task resource cleanup. Closes JSONL writers, throwaway\n // providers, etc. that the factory wired up. Swallowed errors \u2014\n // a flaky cleanup must not mask the real task result. The\n // caller can re-emit via observability if needed.\n if (factoryResult.dispose) {\n try {\n await factoryResult.dispose();\n } catch {\n // intentional swallow \u2014 see comment above\n }\n }\n }\n\n // A budget violation is the signal \u2014 surface it so the coordinator can\n // tag the task with the right failure kind ('failed' for budget; the\n // coordinator separately recognises 'timeout' from BudgetExceededError).\n if (budgetError) {\n // BudgetThresholdSignal: the soft limit was hit but the coordinator\n // hasn't resolved the extension decision yet. If the decision was\n // 'extend', the coordinator patched limits and the agent finished\n // normally \u2014 no error to surface. If 'stop', budgetError becomes\n // a BudgetExceededError thrown below.\n // instanceof check on Error subtypes requires 'any' intersection\n // on the union \u2014 use a property guard instead.\n if ('decision' in budgetError) {\n try {\n const decision = await (budgetError as BudgetThresholdSignal).decision;\n if (decision === 'stop') {\n budgetError = new BudgetExceededError(\n (budgetError as BudgetThresholdSignal).kind,\n (budgetError as BudgetThresholdSignal).limit,\n (budgetError as BudgetThresholdSignal).used,\n );\n } else {\n budgetError = null;\n }\n } catch {\n // Decision promise rejected \u2014 treat as hard stop.\n budgetError = new BudgetExceededError(\n (budgetError as BudgetThresholdSignal).kind,\n (budgetError as BudgetThresholdSignal).limit,\n (budgetError as BudgetThresholdSignal).used,\n );\n }\n }\n if (budgetError) throw budgetError;\n }\n\n if (result.status === 'failed') {\n throw result.error instanceof AgentError\n ? result.error\n : new AgentError({\n message: result.error instanceof Error ? result.error.message : String(result.error ?? 'agent failed'),\n code: ERROR_CODES.AGENT_RUN_FAILED,\n cause: result.error,\n });\n }\n // 'aborted' and 'max_iterations' aren't successes \u2014 let the coordinator\n // classify them. When the parent signal was aborted, coordinator marks\n // the task 'stopped' (matched against subagent.abortController.aborted).\n if (result.status === 'aborted') {\n throw new AgentError({\n message: 'agent aborted',\n code: ERROR_CODES.AGENT_ABORTED,\n });\n }\n if (result.status === 'max_iterations') {\n throw new AgentError({\n message: 'agent exhausted iteration limit',\n code: ERROR_CODES.AGENT_ITERATION_LIMIT,\n recoverable: true,\n });\n }\n\n const usage = ctx.budget.usage();\n // Empty-response guard. A \"successful\" run with no text AND no tool\n // calls is almost always a prompt / config issue, not a real\n // success \u2014 the agent burned an iteration to say nothing. Surface\n // it as a classified failure so callers can show \"\u2717 empty_response\"\n // instead of a confusing green \u2713 with no output. We only trip on\n // the (no-text AND no-tools) intersection because text-less runs\n // with tool calls are legit (e.g. \"run npm test then end_turn\").\n const finalText = (result.finalText ?? '').trim();\n if (finalText.length === 0 && usage.toolCalls === 0) {\n throw new AgentError({\n message: 'empty response \u2014 agent produced no text and no tool calls',\n code: ERROR_CODES.AGENT_RUN_FAILED,\n context: { iterations: result.iterations },\n });\n }\n // Unrecovered-tool-failure guard. If the last executed tool came\n // back ok:false AND the agent ended its turn with no closing text,\n // the agent never acknowledged or recovered from the failure \u2014 the\n // task is effectively broken. A model that handles a tool error\n // emits SOME text on the next iteration (\"the read failed, trying\n // an alternate path\u2026\") which clears `lastToolFailed`; the only way\n // both signals can be live at end-of-run is if the model gave up\n // silently. Surface as `tool_failed` so callers see the actual\n // failure mode instead of a clean \u2713 with no output.\n if (finalText.length === 0 && lastToolFailed !== null) {\n throw new AgentError({\n message: `unrecovered tool failure: ${lastToolFailed} \u2014 agent ended turn without acknowledging the error`,\n code: ERROR_CODES.AGENT_RUN_FAILED,\n context: { tool: lastToolFailed, iterations: result.iterations },\n });\n }\n return {\n result: result.finalText,\n report: readSubagentStructuredReport(agentContext),\n iterations: result.iterations,\n toolCalls: usage.toolCalls,\n };\n };\n}\n\nfunction defaultFormatTaskInput(task: TaskSpec): AgentInput {\n return task.description ?? '';\n}\n", "/**\n * Catalog types for the WrongStack agent fleet.\n *\n * An `AgentDefinition` bundles the runtime `SubagentConfig` (id/name/role/\n * prompt/tools) with two things the bare config lacks:\n * - a per-role `budget` tier (consumed by FLEET_ROSTER_BUDGETS), and\n * - dispatcher `capability` metadata (keywords + summary + phase) used by\n * the smart dispatcher to route a free-form task to the best agent.\n *\n * Phase files (`phase1-discovery.ts` \u2026 `phase9-meta.ts`) each export an\n * `AgentDefinition[]`; `index.ts` aggregates them into `AGENT_CATALOG`.\n * `fleet.ts` derives `FLEET_ROSTER` + `FLEET_ROSTER_BUDGETS` from the catalog.\n */\nimport type { SubagentConfig } from '../../types/multi-agent.js';\n\n/** Lifecycle phase grouping. Drives statusline labels + dispatcher tie-breaks. */\nexport type AgentPhase =\n | 'discovery'\n | 'planning'\n | 'build'\n | 'verify'\n | 'review'\n | 'domain'\n | 'knowledge'\n | 'delivery'\n | 'meta';\n\n/** Per-role budget tier. Same shape as fleet.ts `FleetRosterBudget`. */\nexport interface AgentBudgetTier {\n timeoutMs?: number | undefined;\n maxIterations?: number | undefined;\n maxToolCalls?: number | undefined;\n maxTokens?: number | undefined;\n maxCostUsd?: number | undefined;\n}\n\n/** Dispatcher routing metadata. */\nexport interface AgentCapability {\n phase: AgentPhase;\n /**\n * One-line capability summary. Fed to the LLM dispatcher classifier as the\n * candidate's description, and shown to the user when explaining a routing\n * decision. Keep it concrete and distinct from sibling agents.\n */\n summary: string;\n /**\n * Lowercased signal words/phrases for the heuristic dispatcher. A task whose\n * description contains these scores toward this agent. Order doesn't matter;\n * prefer specific terms (\"graphql\", \"wcag\") over generic ones (\"code\").\n */\n keywords: string[];\n /**\n * Optional `RoleDispatcherSignal` attached to the role. Wave-1/2/3/4 roles\n * carry this to make the \"why this role wins\" rationale auditable; legacy\n * roles omit it and the dispatcher falls back to `summary` + `keywords`.\n */\n rationale?: RoleDispatcherSignal | undefined;\n}\n\n/**\n * Read-only view of a role's dispatcher rationale, surfaceable to operators.\n *\n * `rationale` explains what the role owns; `signals` are the dispatcher's\n * routing tokens (extended with role id, sibling keywords, etc. at scoring\n * time); `differentiatesFrom` is the human-readable contrast against the\n * closest sibling.\n */\nexport interface RoleDispatcherSignal {\n rationale: string;\n signals: readonly string[];\n /**\n * One-line description of how this role differs from its closest sibling\n * (\"X finds defects; Y designs threats before code exists\"). Used by tests\n * to assert distinct boundaries and by docs to explain routing.\n */\n differentiatesFrom: string;\n}\n\n/** A single catalog entry: runtime config + budget tier + routing metadata. */\nexport interface AgentDefinition {\n config: SubagentConfig;\n budget: AgentBudgetTier;\n capability: AgentCapability;\n}\n\nconst HOUR = 60 * 60 * 1000;\n\n/**\n * Budget tiers by workload weight. Deliberately generous \u2014 the project's\n * existing roster uses multi-hour ceilings to avoid spurious timeouts on\n * monorepo-scale work, and the auto-extend handshake raises them further when\n * a subagent is still making progress.\n */\nexport const LIGHT_BUDGET: AgentBudgetTier = {\n timeoutMs: 3 * HOUR,\n maxIterations: 3000,\n maxToolCalls: 8000,\n};\nexport const MEDIUM_BUDGET: AgentBudgetTier = {\n timeoutMs: 5 * HOUR,\n maxIterations: 5000,\n maxToolCalls: 14000,\n};\nexport const HEAVY_BUDGET: AgentBudgetTier = {\n timeoutMs: 10 * HOUR,\n maxIterations: 8000,\n maxToolCalls: 20000,\n};\n\n/**\n * Tool allowlist presets. Agents pass the smallest set that covers their job \u2014\n * a planning agent should not hold `write`/`bash`, a reviewer should be\n * read-only. Spread + extend per-agent where a role needs one extra tool.\n */\nexport const TOOLS = {\n /** Pure read/inspect \u2014 safe for analysis and review agents. */\n read: ['read', 'grep', 'glob', 'search', 'tree', 'mailbox'],\n /** Read + structured inspection (logs, diffs, json, dependency audit). */\n inspect: ['read', 'grep', 'glob', 'search', 'tree', 'json', 'diff', 'logs', 'audit', 'mailbox'],\n /** Read + edit (no shell). For agents that write code/docs but don't run it. */\n write: ['read', 'grep', 'glob', 'search', 'tree', 'write', 'edit', 'replace', 'patch', 'mailbox'],\n /** Full build loop: edit + run (lint/format/typecheck/test/bash). */\n build: [\n 'read',\n 'grep',\n 'glob',\n 'search',\n 'tree',\n 'write',\n 'edit',\n 'replace',\n 'patch',\n 'bash',\n 'exec',\n 'lint',\n 'format',\n 'typecheck',\n 'test',\n 'mailbox',\n ],\n /** Version control. */\n vcs: ['read', 'grep', 'glob', 'git', 'diff'],\n /** Dependency management + CVE audit. */\n deps: ['read', 'grep', 'glob', 'install', 'outdated', 'audit', 'json', 'mailbox'],\n /** Documentation authoring. */\n docs: ['read', 'grep', 'glob', 'search', 'tree', 'write', 'edit', 'document', 'mailbox'],\n /** Web research. */\n research: ['read', 'grep', 'glob', 'search', 'fetch', 'mailbox'],\n} as const satisfies Record<string, readonly string[]>;\n", "import { readFileSync, statSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { resolveWstackPaths } from '../../utils/wstack-paths.js';\nimport { buildProjectContextualizedPrompt } from './project-agent-identity.js';\n\n/**\n * Cache of resolved prompt text, keyed by `<envDir>\\0<id>`. Prompt files do\n * not change during a process lifetime, so the first successful (or failed)\n * lookup is memoized. The key includes the override env var so tests that set\n * `WRONGSTACK_AGENT_INSTRUCTIONS_DIR` still observe fresh resolution.\n */\nconst promptCache = new Map<string, string>();\n\n/**\n * Cache of the ordered candidate directory list, keyed by `<envDir>\\0<cwd-home>`.\n * The list is otherwise identical for every `agentPrompt()` call, so resolving\n * (and sorting via `statSync`) it once per env avoids ~7 redundant `statSync`\n * probes per call. `fleet.ts` + the phase catalogs alone call `agentPrompt()`\n * ~60 times at import time.\n */\nconst candidateCache = new Map<string, string[]>();\n\n/**\n * Mandatory modern technology policy that every built-in roster agent\n * inherits. Read at most once per process (memoized in `promptCache`) and\n * prepended to each role's base prompt so the rule travels with the persona.\n */\nconst TECH_VERSION_POLICY_KEY = '\\u0000__tech_version_policy__';\n\nlet techVersionPolicyBody: string | undefined;\n\nconst INLINE_TECH_VERSION_POLICY = `# Mandatory modern technology policy\n\nYou are bound to the current stable version of every library, framework and\npackage you use. The latest stable is preferred; the latest *published* is\n*required*.\n\n## Non-negotiable rules\n\n1. **Verify the version, never trust a number from training data.** Before\n recommending a package or framework version, fetch the live registry\n (npm, PyPI, crates, Go proxy, GitHub releases). Treat the value you read\n as the only acceptable reference; do not interpolate from memory.\n\n2. **Latest stable by default.** Pick the highest stable release that\n satisfies the project runtime, the pinned peer-dependency range, and\n the role's required APIs. Pin to \\`^<major>.<minor>.0\\` and report the\n exact version.\n\n3. **Reject alpha / beta / RC / nightly** unless the user explicitly\n requests a pre-release. State the rejection reason in the output.\n\n4. **Reject EOL, deprecated and unmaintained packages** \u2014 a package with\n no release in >2 years **and** open critical issues is *dead*. Reject\n it on the same day you find it and propose a maintained replacement.\n\n5. **Reject prehistoric technology.** The well-known blocklist:\n - \\`axios\\` / \\`node-fetch\\` / \\`got\\` / \\`request\\` \u2192 native \\`fetch\\` (Node 18+).\n - \\`moment\\` \u2192 \\`date-fns\\`, \\`luxon\\` or \\`Temporal\\`.\n - jQuery on new projects \u2192 vanilla DOM or React.\n - Gulp / Grunt \u2192 \\`tsup\\`, \\`esbuild\\` or \\`vite\\`.\n - CoffeeScript / Flow \u2192 TypeScript.\n - \\`Bluebird\\` \u2192 native Promises.\n - \\`crypto-js\\` \u2192 \\`node:crypto\\` or Web Crypto.\n - Bower \u2192 npm or pnpm.\n - \\`underscore\\` \u2192 \\`lodash\\` or native ES2020+.\n Use the intervention phrase: **\"This isn't code, this is X-year-old\n technology.\"** Follow with the modern replacement and a one-step\n migration path.\n\n6. **Prefer built-in over third-party.** Before adding a dependency, check\n the language or runtime native API. Examples:\n - Node \u226522.19 \u2192 \\`node:test\\`, \\`node:sqlite\\`, \\`node:fs/promises\\`,\n \\`fetch\\`, \\`WebSocket\\`, \\`node:crypto\\`, \\`node:stream/web\\`, AbortSignal.\n - Browsers \u2192 \\`fetch\\`, \\`AbortController\\`, \\`structuredClone\\`,\n \\`URLPattern\\`, Web Streams.\n - TypeScript \u22655.6 \u2192 \\`using\\` declarations, \\`await using\\`, the new\n iterator helpers, \\`NoInfer\\`, the \\`esnext.disposable\\` types.\n\n7. **Never silently upgrade a pinned version.** If the project pins an\n old version, call it out and report: the new compatible version,\n the breaking changes between them, and a migration recipe. Do not\n upgrade without confirmation.\n\n8. **Always cite the source and the verification time.** Output must\n include the registry URL and the date you verified, so the operator\n can audit the choice.\n\n9. **Never use deprecated APIs even if a tutorial says so.** When a\n vendor marks an API deprecated, switch to the documented replacement\n and record the migration in the role's working notes.\n\n10. **A package must exist.** Reject and call out any hallucinated package\n or framework. The intervention phrase for missing packages is\n **\"This package does not exist on the registry.\"** and the role must\n propose a real, maintained alternative.`;\n\nfunction loadTechVersionPolicy(): string {\n if (techVersionPolicyBody !== undefined) return techVersionPolicyBody;\n const fromDisk = policyBody();\n techVersionPolicyBody = fromDisk || INLINE_TECH_VERSION_POLICY;\n return techVersionPolicyBody;\n}\n\nfunction policyCandidateDirs(): string[] {\n const here = path.dirname(fileURLToPath(import.meta.url));\n const profileInstructions = resolveWstackPaths({ projectRoot: process.cwd() }).globalInstructions;\n return [\n path.resolve(here, '../../../../instructions/agents'),\n path.resolve(here, '../../../instructions/agents'),\n path.resolve(here, '../../instructions/agents'),\n path.resolve(here, '../instructions/agents'),\n path.resolve(here, 'instructions/agents'),\n path.join(profileInstructions, 'agents'),\n profileInstructions,\n ].filter((dir, index, all) => all.indexOf(dir) === index);\n}\n\nfunction policyBody(): string {\n const here = path.dirname(fileURLToPath(import.meta.url));\n // Two layouts must resolve:\n // * source: `packages/core/src/coordination/agents` \u2192 `../../instructions/agents/_policy/tech-version.md`\n // * build: `packages/core/dist/coordination/agents` \u2192 `../../../instructions/agents/_policy/tech-version.md`\n // Both point at the same on-disk file. We list every plausible relative\n // depth so the policy finds the prompt regardless of where the consumer\n // imported the helper from.\n const roots = [\n path.resolve(here, '_policy/tech-version.md'),\n path.resolve(here, '../_policy/tech-version.md'),\n path.resolve(here, '../../../instructions/agents/_policy/tech-version.md'),\n path.resolve(here, '../../instructions/agents/_policy/tech-version.md'),\n path.resolve(here, '../instructions/agents/_policy/tech-version.md'),\n path.resolve(here, '../../../../instructions/agents/_policy/tech-version.md'),\n path.resolve(here, 'instructions/agents/_policy/tech-version.md'),\n ];\n for (const file of roots) {\n try {\n return readFileSync(file, 'utf8').trim();\n } catch {\n // try next candidate\n }\n }\n for (const dir of policyCandidateDirs()) {\n try {\n return readFileSync(path.join(dir, '_policy', 'tech-version.md'), 'utf8').trim();\n } catch {\n // try next candidate\n }\n }\n return '';\n}\n\nexport function agentPrompt(id: string): string {\n // The policy body itself is a single shared suffix; return it directly\n // when the sentinel key is requested (used by tests / docs).\n if (id === TECH_VERSION_POLICY_KEY) return loadTechVersionPolicy();\n\n const envDir = process.env['WRONGSTACK_AGENT_INSTRUCTIONS_DIR'] ?? '';\n const policyOn = process.env['WRONGSTACK_AGENT_POLICY'] === 'on';\n const cacheBypass =\n (globalThis as { __WS_DISABLE_PROMPT_CACHE__?: boolean }).__WS_DISABLE_PROMPT_CACHE__ ===\n true;\n const cacheKey = `${envDir}\\u0000${policyOn ? 1 : 0}\\u0000${id}`;\n const cached = cacheBypass ? undefined : promptCache.get(cacheKey);\n if (cached !== undefined) return cached;\n\n const fileName = `${id}.md`;\n let resolved = '';\n for (const dir of agentPromptDirCandidates(envDir)) {\n try {\n resolved = readFileSync(path.join(dir, fileName), 'utf8').trim();\n break;\n } catch {\n // try next candidate\n }\n }\n // The policy body is appended to *every* role's prompt so the latest-stable\n // invariant is enforced uniformly. It is opt-in: the policy ships only when\n // the host explicitly enables it via `WRONGSTACK_AGENT_POLICY=on`. Tests\n // and byte-equality smoke fixtures stay deterministic by default; the\n // dispatcher and `agent-catalog` integration test opt in for the contract.\n const policy = policyOn ? loadTechVersionPolicy() : '';\n if (policy) {\n if (!resolved) {\n resolved = policy;\n } else if (cacheBypass || !resolved.includes('Mandatory modern technology policy')) {\n // Older role briefs reference the policy by name but do not yet embed\n // its body \u2014 append the canonical body so every prompt carries the\n // latest-stable invariant in full. In test-bypass mode we always\n // append so the cache-bypass assertion sees the canonical text even\n // when an older prompt already mentions the policy by name.\n resolved = `${resolved}\\n\\n---\\n\\n${policy}`;\n }\n }\n // Project-contextualized prompt: overlay identity, learned wisdom and\n // current-knowledge checklist on top of the base role prompt.\n // Uses the current working directory as project root when no explicit\n // WRONGSTACK_PROJECT_ROOT is set, allowing the project-specific agent\n // identity mechanism to work without any code changes.\n const projectRoot = process.env['WRONGSTACK_PROJECT_ROOT'] || process.cwd();\n resolved = buildProjectContextualizedPrompt(resolved, id, projectRoot);\n if (!cacheBypass) promptCache.set(cacheKey, resolved);\n return resolved;\n}\n\nfunction agentPromptDirCandidates(envDir: string): string[] {\n const profileInstructions = resolveWstackPaths({ projectRoot: process.cwd() }).globalInstructions;\n const candKey = `${envDir}\\u0000${profileInstructions}`;\n const cached = candidateCache.get(candKey);\n if (cached !== undefined) return cached;\n\n const here = path.dirname(fileURLToPath(import.meta.url));\n const explicitDir = envDir || undefined;\n const candidates = [\n ...(explicitDir ? [path.resolve(explicitDir)] : []),\n path.join(profileInstructions, 'agents'),\n path.resolve(here, '../../../../instructions/agents'),\n path.resolve(here, '../../../instructions/agents'),\n path.resolve(here, '../../instructions/agents'),\n path.resolve(here, '../instructions/agents'),\n path.resolve(here, 'instructions/agents'),\n ];\n const ordered = candidates.sort((a, b) => Number(!isDirectory(a)) - Number(!isDirectory(b)));\n candidateCache.set(candKey, ordered);\n return ordered;\n}\n\nfunction isDirectory(candidate: string): boolean {\n try {\n return statSync(candidate).isDirectory();\n } catch {\n return false;\n }\n}\n", "/**\n * Project-level agent identity, override and learning layer.\n *\n * Every built-in roster agent has a base definition (role + prompt + tools +\n * skills) in the catalog. On top of that, **each project** can:\n *\n * 1. Override prompt, tools, skills, budget per role\n * 2. Accumulate learned wisdom specific to this codebase\n * 3. Attach a project-custom identity (name, avatar, tone)\n *\n * Resolution cascade (most \u2192 least specific):\n * activeLearning.json \u2192 project-identity.md \u2192 catalog base\n *\n * Files live under `.wrongstack/agents/<role>/`:\n * config.json \u2014 static overrides (tools, budget, skillNames)\n * identity.md \u2014 custom prompt appendix (tone, project-specific rules)\n * learned.md \u2014 auto-generated wisdom from past sessions\n * knowledge.md \u2014 current-needs checklist (what versions to verify today)\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport * as path from 'node:path';\nimport type { SubagentConfig } from '../../types/multi-agent.js';\nimport { validateProjectAgentConfig } from './project-agent-config-validation.js';\nimport { BUILT_IN_KNOWLEDGE_MANIFESTS } from './project-agent-knowledge-manifests.js';\nimport {\n loadProjectAgentLearningPolicy,\n type ProjectAgentLearningPolicy,\n} from './project-agent-learning-policy.js';\nimport {\n splitLearnedEntries,\n tokenOverlap,\n} from './project-agent-learning-entries.js';\nimport {\n mergeStructuredEntries,\n parseStructuredLearnedEntriesFromContent,\n renderLearnedInstructions,\n type StructuredLearnedEntry,\n} from './project-agent-learning-structured.js';\nimport {\n assertProjectAgentRole,\n learningPolicyPath,\n roleDir,\n writeTextAtomically,\n} from './project-agent-paths.js';\nimport {\n LEARNED_HARD_LIMIT,\n LEARNED_SOFT_LIMIT,\n normalizeForComparison,\n normalizeLearnedEntry,\n} from './project-agent-learning-normalize.js';\nimport type {\n LearnedCaptureResult,\n ProjectAgentConfig,\n RoleKnowledgeManifest,\n} from './project-agent-identity-types.js';\nimport {\n isConsolidated,\n loadConsolidationMetadata,\n loadProjectAgentConsolidated,\n type ConsolidationMetadata,\n} from './project-agent-consolidation.js';\n\nexport { validateProjectAgentConfig } from './project-agent-config-validation.js';\nexport {\n classifyLearnedEntry,\n LEARNED_ENTRY_MAX_CHARS,\n LEARNED_HARD_LIMIT,\n LEARNED_SOFT_LIMIT,\n type LearnedEntryCategory,\n normalizeLearnedEntry,\n} from './project-agent-learning-normalize.js';\nexport {\n decomposeLearnedEntry,\n mergeStructuredEntries,\n parseLearnedEntryStamp,\n renderLearnedInstructions,\n type StructuredLearnedEntry,\n} from './project-agent-learning-structured.js';\nexport {\n loadProjectAgentLearningPolicy,\n type ProjectAgentLearningPolicy,\n updateProjectAgentLearningPolicy,\n} from './project-agent-learning-policy.js';\nexport { assertProjectAgentRole } from './project-agent-paths.js';\nexport {\n buildConsolidationInstruction,\n clearProjectAgentConsolidated,\n isConsolidated,\n loadConsolidationMetadata,\n loadProjectAgentConsolidated,\n saveProjectAgentConsolidated,\n type ConsolidationMetadata,\n} from './project-agent-consolidation.js';\nexport type {\n CreateProjectAgentInput,\n LearnedCaptureResult,\n ProjectAgentConfig,\n ProjectAgentProfile,\n RoleKnowledgeManifest,\n} from './project-agent-identity-types.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport {\n createProjectAgent,\n loadProjectAgentProfile,\n slugifyProjectAgentRole,\n} from './project-agent-profile.js';\nexport {\n listProjectAgentRoles,\n refreshProjectAgentIdentity,\n resetProjectAgentIdentity,\n updateProjectAgentConfig,\n updateProjectAgentIdentity,\n updateProjectAgentKnowledge,\n updateProjectAgentLearned,\n} from './project-agent-files.js';\nimport { loadProjectAgentProfile } from './project-agent-profile.js';\nimport { listProjectAgentRoles } from './project-agent-files.js';\n\n/**\n * Live roster overlay. Project policy is resolved lazily for both built-in and\n * project-created roles, so WebUI changes take effect on the next spawn without\n * rebuilding the Director. Built-in roles keep their safety floors; custom\n * roles may opt into a deliberately narrow runtime.\n */\nexport function createProjectAgentRoster(\n baseRoster: Record<string, SubagentConfig>,\n projectRoot?: string,\n): Record<string, SubagentConfig> {\n const target = { ...baseRoster };\n const resolveRole = (role: string, resolving = new Set<string>()): SubagentConfig | undefined => {\n if (resolving.has(role)) return undefined;\n const isBuiltIn = Object.hasOwn(target, role);\n if (!isBuiltIn && !listProjectAgentRoles(projectRoot).includes(role)) return undefined;\n resolving.add(role);\n const profile = loadProjectAgentProfile(role, projectRoot);\n const template = isBuiltIn\n ? target[role]\n : profile\n ? (resolveRole(profile.baseRole, resolving) ?? target['generic'])\n : target['generic'];\n resolving.delete(role);\n if (!template) return undefined;\n const base = isBuiltIn\n ? template\n : {\n ...template,\n id: role,\n role,\n name: profile?.name ?? role,\n ...(profile\n ? {\n dispatch: {\n summary: profile.purpose,\n keywords: [\n ...profile.taskTypes,\n ...new Set(\n `${profile.purpose} ${profile.taskTypes.join(' ')}`\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((word) => word.length >= 3),\n ),\n ],\n },\n }\n : {}),\n };\n return applyProjectAgentConfig(base, loadProjectAgentConfig(role, projectRoot), {\n protectSystemRole: isBuiltIn && !profile,\n });\n };\n\n return new Proxy(target, {\n get(current, property, receiver) {\n if (typeof property !== 'string') return Reflect.get(current, property, receiver);\n return resolveRole(property) ?? Reflect.get(current, property, receiver);\n },\n has(current, property) {\n return typeof property === 'string'\n ? Reflect.has(current, property) || resolveRole(property) !== undefined\n : Reflect.has(current, property);\n },\n ownKeys(current) {\n return [...new Set([...Reflect.ownKeys(current), ...listProjectAgentRoles(projectRoot)])];\n },\n getOwnPropertyDescriptor(current, property) {\n const descriptor = Reflect.getOwnPropertyDescriptor(current, property);\n if (descriptor || typeof property !== 'string' || !resolveRole(property)) return descriptor;\n return {\n configurable: true,\n enumerable: true,\n writable: false,\n value: resolveRole(property),\n };\n },\n });\n}\n\n// ---------------------------------------------------------------------------\n// Project agent config loading\n// ---------------------------------------------------------------------------\n\n/**\n * Load the project-level agent config for a given role.\n * Returns `undefined` when no project override exists.\n */\nexport function loadProjectAgentConfig(\n role: string,\n projectRoot?: string,\n): ProjectAgentConfig | undefined {\n const cfgPath = path.join(roleDir(role, projectRoot), 'config.json');\n try {\n const raw = readFileSync(cfgPath, 'utf8');\n return validateProjectAgentConfig(JSON.parse(raw));\n } catch {\n return undefined;\n }\n}\n\n/**\n * Load the project-level identity appendix for a given role.\n * Appended to the subagent prompt after the base role prompt and policy.\n * Returns the empty string when no identity file exists.\n */\nexport function loadProjectAgentIdentity(role: string, projectRoot?: string): string {\n const identityPath = path.join(roleDir(role, projectRoot), 'identity.md');\n try {\n return readFileSync(identityPath, 'utf8').trim();\n } catch {\n return '';\n }\n}\n\n/**\n * Load the learning-derived wisdom for a given role.\n * Appended to the subagent prompt as a \"knowledge from past sessions\" block.\n * The learning file is auto-generated by the `memory-curator` or\n * `self-improving` agent roles and contains de-duplicated, curated findings.\n */\nexport function loadProjectAgentLearned(role: string, projectRoot?: string): string {\n const learnedPath = path.join(roleDir(role, projectRoot), 'learned.md');\n try {\n return readFileSync(learnedPath, 'utf8').trim();\n } catch {\n return '';\n }\n}\n\n/**\n * Load the current-knowledge checklist for a given role.\n * Returns the built-in directive if no project override exists.\n * The checklist guides the agent on what to verify from live registries\n * before answering questions in its domain.\n */\nexport function loadRoleKnowledgeManifest(\n role: string,\n projectRoot?: string,\n): RoleKnowledgeManifest | undefined {\n // First look for project-level knowledge manifest\n const projectPath = path.join(roleDir(role, projectRoot), 'knowledge.json');\n try {\n const raw = readFileSync(projectPath, 'utf8');\n return JSON.parse(raw) as RoleKnowledgeManifest;\n } catch {\n // Fall back to built-in manifests\n return BUILT_IN_KNOWLEDGE_MANIFESTS[role];\n }\n}\n\n/**\n * Merge a project agent config onto a base `SubagentConfig`.\n * Returns a new config; does not mutate either input.\n */\nexport function applyProjectAgentConfig(\n base: SubagentConfig,\n projectConfig: ProjectAgentConfig | undefined,\n options: { protectSystemRole?: boolean | undefined } = {},\n): SubagentConfig {\n if (!projectConfig) return base;\n const result: SubagentConfig = { ...base };\n if (projectConfig.tools !== undefined) {\n result.tools = options.protectSystemRole\n ? base.tools === undefined\n ? undefined\n : [...new Set([...base.tools, ...projectConfig.tools])]\n : [...projectConfig.tools];\n }\n if (projectConfig.skillNames !== undefined) result.skillNames = [...projectConfig.skillNames];\n if (projectConfig.provider !== undefined) result.provider = projectConfig.provider;\n if (projectConfig.model !== undefined) result.model = projectConfig.model;\n if (projectConfig.modelPolicy !== undefined) {\n result.modelPolicy = {\n allowed: projectConfig.modelPolicy.allowed.map((target) => ({ ...target })),\n fallbacks: projectConfig.modelPolicy.fallbacks?.map((target) => ({ ...target })),\n // System roles must remain recoverable even when a preferred model is\n // temporarily unavailable. Custom roles may opt into a hard boundary.\n strict: options.protectSystemRole ? false : (projectConfig.modelPolicy.strict ?? false),\n };\n result.fallbackModels = (projectConfig.modelPolicy.fallbacks ?? []).map(\n (target) => `${target.provider}/${target.model}`,\n );\n } else if (projectConfig.fallbackProfile !== undefined) {\n result.fallbackProfile = projectConfig.fallbackProfile;\n }\n if (projectConfig.cwd !== undefined) result.cwd = projectConfig.cwd;\n if (projectConfig.worktree !== undefined) {\n result.worktree =\n options.protectSystemRole &&\n (projectConfig.worktree === true || projectConfig.worktree === 'required')\n ? 'auto'\n : projectConfig.worktree;\n }\n if (projectConfig.availability !== undefined) {\n result.availability = {\n ...projectConfig.availability,\n days: [...projectConfig.availability.days],\n mode: options.protectSystemRole ? 'advisory' : (projectConfig.availability.mode ?? 'enforce'),\n };\n }\n if (projectConfig.allowedCapabilities !== undefined) {\n result.allowedCapabilities = options.protectSystemRole\n ? base.allowedCapabilities === undefined\n ? undefined\n : [...new Set([...base.allowedCapabilities, ...projectConfig.allowedCapabilities])]\n : [...projectConfig.allowedCapabilities];\n }\n if (projectConfig.budget) {\n if (projectConfig.budget.timeoutMs !== undefined)\n result.timeoutMs = projectConfig.budget.timeoutMs;\n if (projectConfig.budget.idleTimeoutMs !== undefined)\n result.idleTimeoutMs = projectConfig.budget.idleTimeoutMs;\n if (projectConfig.budget.maxIterations !== undefined)\n result.maxIterations = projectConfig.budget.maxIterations;\n if (projectConfig.budget.maxToolCalls !== undefined)\n result.maxToolCalls = projectConfig.budget.maxToolCalls;\n if (projectConfig.budget.maxTokens !== undefined)\n result.maxTokens = projectConfig.budget.maxTokens;\n if (projectConfig.budget.maxCostUsd !== undefined)\n result.maxCostUsd = projectConfig.budget.maxCostUsd;\n }\n if (options.protectSystemRole) applySystemAgentBudgetFloors(result);\n return result;\n}\n\nconst SYSTEM_AGENT_BUDGET_FLOORS = {\n timeoutMs: 300_000,\n idleTimeoutMs: 120_000,\n maxIterations: 20,\n maxToolCalls: 40,\n maxTokens: 8_192,\n maxCostUsd: 0.25,\n} as const satisfies Partial<Record<keyof SubagentConfig, number>>;\n\ntype BudgetFloorEntry = {\n [K in keyof typeof SYSTEM_AGENT_BUDGET_FLOORS]: [K, (typeof SYSTEM_AGENT_BUDGET_FLOORS)[K]];\n}[keyof typeof SYSTEM_AGENT_BUDGET_FLOORS];\n\nfunction applySystemAgentBudgetFloors(config: SubagentConfig): void {\n for (const [field, floor] of Object.entries(SYSTEM_AGENT_BUDGET_FLOORS) as BudgetFloorEntry[]) {\n const value = config[field];\n if (typeof value === 'number' && value < floor) config[field] = floor;\n }\n}\n\n/**\n * Build the full project-contextualized prompt for a given role.\n *\n * Cascade, from start to end:\n * 1. Base role prompt from instruction files (agentPrompt(id))\n * 2. Technology policy (appended by agentPrompt)\n * 3. Project identity appendix (identity.md)\n * 4. Learned wisdom (learned.md)\n * 5. Live-knowledge checklist\n */\nexport function buildProjectContextualizedPrompt(\n basePrompt: string,\n role: string,\n projectRoot?: string,\n options: { identityOverride?: string | undefined } = {},\n): string {\n const contextStart = '<!-- wrongstack:project-agent-context:start -->';\n const contextEnd = '<!-- wrongstack:project-agent-context:end -->';\n\n // Skip project identity when WRONGSTACK_AGENT_INSTRUCTIONS_DIR is set\n // (this is a test/override context \u2014 keep byte-exact equality with on-disk files).\n // The marker cleanup below is intentionally placed AFTER this early return so a\n // prompt that already contains legacy context markers is preserved verbatim.\n if (process.env['WRONGSTACK_AGENT_INSTRUCTIONS_DIR']) return basePrompt;\n\n const cleanBase = basePrompt\n .replace(\n /\\s*<!-- wrongstack:project-agent-context:start -->[\\s\\S]*?<!-- wrongstack:project-agent-context:end -->\\s*/g,\n '\\n',\n )\n .trim();\n const parts: string[] = [cleanBase];\n\n const identity = options.identityOverride ?? loadProjectAgentIdentity(role, projectRoot);\n if (identity) {\n parts.push(`\\n\\n# Project custom identity\\n\\n${identity}`);\n }\n\n const learningPolicy = loadProjectAgentLearningPolicy(role, projectRoot);\n // Prefer the reviewed, consolidated document over the raw learned.md buffer.\n // The consolidated version is a synthesized, narrowly-scoped representation\n // of everything the agent has learned \u2014 same information, less context volume.\n //\n // STALENESS GATE: When new raw entries have been captured since the last\n // consolidation (entry count > sourceEntryCount), the consolidation is stale.\n // In that case we append the delta entries so the agent still sees new\n // learnings \u2014 preserving the capture\u2192inject feedback loop without losing\n // the optimization benefit of the consolidated document.\n let learnedContent = '';\n let learnedLabel = '';\n if (learningPolicy.enabled) {\n const consolidated = loadProjectAgentConsolidated(role, projectRoot);\n if (consolidated) {\n const meta = loadConsolidationMetadata(role, projectRoot);\n // Read the raw buffer once; split it for entry counting.\n const rawLearned = loadProjectAgentLearned(role, projectRoot);\n const rawEntries = splitLearnedEntries(rawLearned);\n const rawBytes = Buffer.byteLength(rawLearned, 'utf8');\n // Freshness gate: consolidated.md is preferred, but only while the\n // raw buffer hasn't grown past the snapshot at consolidation time.\n // We check both entry count and byte size \u2014 either exceeding the\n // recorded snapshot means the consolidated document is stale. When\n // metadata is missing entirely we cannot verify freshness, so treat\n // it as stale to avoid orphaning new captures.\n const stale =\n meta === undefined ||\n rawEntries.length > meta.sourceEntryCount ||\n rawBytes > meta.sourceBytes;\n if (stale) {\n if (meta !== undefined && meta.sourceEntryCount < rawEntries.length) {\n // New countable entries arrived since consolidation \u2014 append just\n // the delta to preserve the context optimization while surfacing\n // freshly captured knowledge (capture\u2192inject loop).\n const deltaEntries = rawEntries.slice(meta.sourceEntryCount);\n learnedContent = `${consolidated}\\n\\n---\\n\\n## Recently captured (pending next optimization)\\n\\n${deltaEntries.join('\\n\\n---\\n\\n')}`;\n } else {\n // Metadata missing, or raw grew without new countable entries \u2014\n // cannot compute a precise delta, so serve the full raw buffer.\n learnedContent = rawLearned;\n }\n } else {\n learnedContent = consolidated;\n }\n learnedLabel = 'Consolidated knowledge for this project';\n } else {\n learnedContent = loadProjectAgentLearned(role, projectRoot);\n learnedLabel = 'Learned instructions for this project (structured: what / why / how)';\n }\n }\n if (learnedContent) {\n // Only include content that has meaningful text (strip HTML comments)\n const meaningful = learnedContent.replace(/<!--[\\s\\S]*?-->/g, '').trim();\n if (meaningful.length > 0) {\n parts.push(`\\n\\n# ${learnedLabel}\\n\\n${learnedContent}`);\n }\n }\n\n // \u2500\u2500 Capture mechanism: tell every agent HOW to persist new knowledge \u2500\u2500\n const effectiveProjectRoot = projectRoot || process.cwd();\n const learnedFilePath = path.join(\n effectiveProjectRoot,\n '.wrongstack',\n 'agents',\n role,\n 'learned.md',\n );\n if (learningPolicy.enabled) {\n parts.push(\n `\\n\\n## Knowledge capture\\n\\n` +\n `The file below stores **learning data for this project's \"${role}\" agent** \u2014 not your memory, not a session log. ` +\n `It is read back into the system prompt of every future \"${role}\" invocation, so each entry must teach a future agent how to act. ` +\n `On every capture the runtime **merges your new entry with every prior entry and rewrites the whole buffer as a structured instruction list** \u2014 grouped by category (\"What to do\", \"What to avoid\", \"Patterns to follow\", \"Project facts\"), with each item decomposed into **what** (the rule), **why** (the reason), and **how** (the concrete commands, file paths, or package names that anchor the rule). ` +\n `When you discover a durable principle that future invocations should follow, end your response with a \\`## LEARNED\\` block. The runtime persists it to:\\n\\n` +\n ` \\`\\`\\`\\n ${learnedFilePath}\\n \\`\\`\\`\\n\\n` +\n `**Write directives, not narratives.** Each LEARNED entry should be:\\n\\n` +\n `- A **rule or principle** that applies across sessions, not a description of what happened in this one.\\n` +\n `- A short **imperative or statement** (1\u20133 sentences), starting with a verb like \"Always verify\u2026\", \"Use X for Y\", \"Avoid\u2026\", \"Never assume\u2026\".\\n` +\n `- **Generic** \u2014 no commit SHAs, timestamps, specific line numbers, or PR/issue numbers. File paths, package names, and command names are fine when they anchor the lesson.\\n` +\n `- **Self-contained** \u2014 understandable without the surrounding session context.\\n` +\n `- **Front-load concrete anchors** \u2014 commands in backticks, package names like \\`@wrongstack/core\\`, file paths like \\`packages/core/src/.../foo.ts\\`. The structured-list renderer extracts these as the \"how\" for the entry.\\n\\n` +\n `**Bad** (session log \u2014 rejected at capture time):\\n\\n` +\n `\\`\\`\\`\\n## LEARNED\\nWhen I worked on the telegram plugin today, commit 9c7682b84 had a race condition in poll-lock at line 42 because writeFileSync wasn't using the 'wx' flag.\\n\\`\\`\\`\\n\\n` +\n `**Good** (directive \u2014 persists, then merges into the structured list):\\n\\n` +\n `\\`\\`\\`\\n## LEARNED\\nAlways use the 'wx' (exclusive create) flag with writeFileSync when implementing concurrent lock acquisition in \\`packages/core/src/.../poll-lock.ts\\` \u2014 filesystem-level atomicity guarantees only one writer wins.\\n\\`\\`\\`\\n\\n` +\n `Capture only durable, cross-session knowledge \u2014 never ephemeral task details.`,\n );\n }\n\n const knowledge = loadRoleKnowledgeManifest(role, projectRoot);\n if (knowledge && knowledge.checklist.length > 0) {\n const checklist = knowledge.checklist.map((item) => `- ${item}`).join('\\n');\n parts.push(\n `\\n\\n## Current knowledge requirements\\n\\nVerify these before answering:\\n${checklist}`,\n );\n }\n\n const additions = parts.slice(1).join('\\n\\n').trim();\n if (!additions) return cleanBase;\n return `${cleanBase}\\n\\n${contextStart}\\n${additions}\\n${contextEnd}`;\n}\n\n// ---------------------------------------------------------------------------\n// Learned-wisdom capture from agent output\n// ---------------------------------------------------------------------------\n\n// \u2500\u2500\u2500 learned.md automation 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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// TRIGGER Primary: end of a delegated subagent task (CLI fleet host's\n// task.completed handler). The director's task resolution checks the\n// final output text for ## LEARNED blocks and captures durable entries.\n// Secondary: leader's own output after a user-invoked improvement\n// prompt (\"improve the executor agent\"). Never on intermediate tool\n// calls or every iteration \u2014 only once per task resolution.\n// Manual: `/agent-improve <role> capture` at any time.\n//\n// GUARDRAILS\n//\n// 1. COOLDOWN Per-role: minimum 120 seconds between captures. Tracks the\n// last capture timestamp in a module-level Map. A capture within the\n// cooldown window is silently skipped (counter not bumped).\n//\n// 2. FREQUENCY CAP Per-session: at most 3 captures per role before the\n// capture falls through to `/agent-improve` (human-gated). The session\n// is reset on process restart (module reload).\n//\n// 3. HUMAN-APPROVAL THRESHOLD When `learned.md` exceeds `LEARNED_SOFT_LIMIT`\n// (8 KB) the next capture is deferred \u2014 the agent is asked to run\n// `/agent-improve <role> refresh` or the user must call it explicitly.\n// The hintLearnedNeedsSummarization() check is exposed so the CLI can\n// surface this in /agent-improve output.\n//\n// 4. SIZE SOFT_LIMIT = 8 192 B \u2192 hintLearnedNeedsSummarization() returns true.\n// HARD_LIMIT = 16 384 B \u2192 capture halves the structured entry list\n// (oldest first) and re-renders before writing.\n//\n// 5. CONTENT QUALITY A block is run through `normalizeLearnedEntry` and\n// skipped when it cannot be converted into an instructive directive:\n// - too short after stripping ephemeral artifacts (< 30 chars)\n// - all narrative framing with no salvageable directive tail\n// - overwhelmingly narrative (>50% sentences are event descriptions)\n// - longer than LEARNED_ENTRY_MAX_CHARS (600 chars) \u2014 truncated to the\n// first instructive sentence cluster that fits\n// Ephemeral artifacts stripped BEFORE the length check:\n// - git commit SHAs, ISO timestamps, specific line numbers, PR/issue refs\n// Code-only blocks (>70% fenced-code lines) and near-duplicates\n// (Jaccard \u2265 0.55) are still rejected. Surviving entries are stamped\n// with a category tag (convention / pattern / warning / fact).\n//\n// OWNER logic : packages/core/src/coordination/agents/project-agent-identity.ts\n// hook : packages/cli/src/fleet/host.ts\n// ---------------------------------------------------------------------------\n\n// \u2500\u2500\u2500 Automation guardrails \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nconst captureCooldowns = new Map<string, number>(); // role \u2192 timestamp\nconst captureFrequency = new Map<string, number>(); // role \u2192 count\n\nexport const CAPTURE_COOLDOWN_MS = 120_000; // 2 minutes\nexport const CAPTURE_MAX_PER_SESSION = 3;\n\n/**\n * Check whether a new capture is allowed for this role. Returns a rejection\n * reason string when blocked, or undefined when capture may proceed.\n */\nexport function canCaptureNewLearned(\n role: string,\n existingSize: number,\n isManual: boolean,\n projectRoot?: string,\n): string | undefined {\n const key = `${path.resolve(projectRoot ?? process.cwd())}\\0${assertProjectAgentRole(role)}`;\n // Cooldown gate (bypassed for manual captures)\n if (!isManual) {\n const last = captureCooldowns.get(key);\n if (last && Date.now() - last < CAPTURE_COOLDOWN_MS) {\n return `Cooldown active for role \"${role}\" (${Math.ceil((CAPTURE_COOLDOWN_MS - (Date.now() - last)) / 1000)}s remaining)`;\n }\n }\n\n // Frequency cap (bypassed for manual captures)\n if (!isManual) {\n const count = captureFrequency.get(key) ?? 0;\n if (count >= CAPTURE_MAX_PER_SESSION) {\n return `Frequency cap reached for role \"${role}\" (${count}/${CAPTURE_MAX_PER_SESSION}). Use /agent-improve ${role} capture for manual override.`;\n }\n }\n\n // Size gate: when over SOFT_LIMIT, require manual approval\n if (existingSize > LEARNED_SOFT_LIMIT && !isManual) {\n return `learned.md for role \"${role}\" exceeds soft limit (${existingSize}B / ${LEARNED_SOFT_LIMIT}B). Run /agent-improve ${role} capture manually or /agent-improve ${role} refresh to reset.`;\n }\n\n return undefined;\n}\n\n/**\n * Per-role learning stats for monitoring UIs.\n */\nexport interface ProjectAgentLearnStats {\n role: string;\n exists: boolean;\n entryCount: number;\n totalBytes: number;\n lastCapture: string | null;\n lastCaptureTimestamp: number | null;\n cooldownRemainingMs: number;\n sessionCaptureCount: number;\n needsSummarization: boolean;\n learnedPath: string | null;\n identityPath: string | null;\n hasIdentity: boolean;\n hasConfig: boolean;\n hasKnowledge: boolean;\n learningEnabled: boolean;\n lifetimeCaptureCount: number;\n lastCaptureSource: ProjectAgentLearningPolicy['lastCaptureSource'] | null;\n /** Whether a consolidated document exists for this role. */\n isConsolidated: boolean;\n /** Consolidation metadata, if a consolidation has been performed. */\n consolidation?: ConsolidationMetadata | undefined;\n}\n\nexport function getProjectAgentLearnStats(\n role: string,\n projectRoot?: string,\n): ProjectAgentLearnStats {\n const dir = roleDir(role, projectRoot);\n const learnedPath_ = path.join(dir, 'learned.md');\n const identityPath_ = path.join(dir, 'identity.md');\n const configPath_ = path.join(dir, 'config.json');\n const knowledgePath_ = path.join(dir, 'knowledge.json');\n let learnedText = '';\n try {\n learnedText = readFileSync(learnedPath_, 'utf8');\n } catch {\n /* no file */\n }\n // Use the structured parser so entryCount reflects directive entries, not\n // raw chunks split by `---` (the structured document also uses `---` for\n // section dividers and the footer, which would inflate chunk counts).\n const entries = parseStructuredLearnedEntries(role, projectRoot);\n const exists = existsSync(dir);\n const policy = loadProjectAgentLearningPolicy(role, projectRoot);\n const captureKey = `${path.resolve(projectRoot ?? process.cwd())}\\0${assertProjectAgentRole(role)}`;\n const runtimeLastTs = captureCooldowns.get(captureKey) ?? null;\n const persistedLastTs = policy.lastCaptureAt ? Date.parse(policy.lastCaptureAt) : Number.NaN;\n const lastTs = runtimeLastTs ?? (Number.isFinite(persistedLastTs) ? persistedLastTs : null);\n const cooldownRemaining = lastTs ? Math.max(0, CAPTURE_COOLDOWN_MS - (Date.now() - lastTs)) : 0;\n const freq = captureFrequency.get(captureKey) ?? 0;\n\n return {\n role,\n exists,\n entryCount: entries.length,\n totalBytes: Buffer.byteLength(learnedText, 'utf8'),\n lastCapture: lastTs ? new Date(lastTs).toISOString() : null,\n lastCaptureTimestamp: lastTs,\n cooldownRemainingMs: cooldownRemaining,\n sessionCaptureCount: freq,\n needsSummarization: exists\n ? hintLearnedNeedsSummarization(role, projectRoot).length > 0\n : false,\n learnedPath: existsSync(learnedPath_) ? learnedPath_ : null,\n identityPath: existsSync(identityPath_) ? identityPath_ : null,\n hasIdentity: existsSync(identityPath_),\n hasConfig: existsSync(configPath_),\n hasKnowledge: existsSync(knowledgePath_),\n learningEnabled: policy.enabled,\n lifetimeCaptureCount: policy.lifetimeCaptureCount,\n lastCaptureSource: policy.lastCaptureSource ?? null,\n isConsolidated: isConsolidated(role, projectRoot),\n consolidation: loadConsolidationMetadata(role, projectRoot),\n };\n}\n\n/**\n * Re-export existsSync so callers can check file existence without importing fs.\n */\nexport { existsSync };\n\n/**\n * Detect semantic conflicts between different roles' learned wisdom.\n * Returns entries where token overlap \u2265 0.60, which suggests the two\n * roles have learned about the same topic \u2014 potentially contradicting.\n */\nexport function detectLearnedConflicts(projectRoot?: string): Array<{\n roleA: string;\n roleB: string;\n snippetA: string;\n snippetB: string;\n similarity: number;\n detectedAt: string;\n}> {\n const roles = listProjectAgentRoles(projectRoot);\n const entries: { role: string; normalized: string; raw: string }[] = [];\n for (const role of roles) {\n const text = loadProjectAgentLearned(role, projectRoot);\n if (!text || text.trim().length < 50) continue;\n entries.push({ role, normalized: normalizeForComparison(text), raw: text });\n }\n const conflicts: Array<{\n roleA: string;\n roleB: string;\n snippetA: string;\n snippetB: string;\n similarity: number;\n detectedAt: string;\n }> = [];\n for (const [i, a] of entries.entries()) {\n for (const b of entries.slice(i + 1)) {\n const sim = tokenOverlap(a.normalized, b.normalized);\n if (sim >= 0.6) {\n conflicts.push({\n roleA: a.role,\n roleB: b.role,\n snippetA: a.raw.slice(0, 200),\n snippetB: b.raw.slice(0, 200),\n similarity: sim,\n detectedAt: new Date().toISOString(),\n });\n }\n }\n }\n return conflicts.sort((a, b) => b.similarity - a.similarity);\n}\n\nexport function listProjectAgentLearnedEntries(role: string, projectRoot?: string): string[] {\n return splitLearnedEntries(loadProjectAgentLearned(role, projectRoot));\n}\n\n// ---------------------------------------------------------------------------\n// Structured instruction list\n//\n// Each `learned.md` capture now produces a structured instruction list rather\n// than an append-only journal. Every entry is decomposed into a \"what / why /\n// how\" shape so a future agent invocation can read the buffer and immediately\n// understand the rule, the reason behind it, and the concrete steps to apply\n// it. The buffer is rewritten in this structured form on every capture, with\n// historical entries re-decomposed in lockstep so the file stays\n// self-describing and scannable across the lifetime of the role.\n// ---------------------------------------------------------------------------\n\nexport function parseStructuredLearnedEntries(\n role: string,\n projectRoot?: string,\n): StructuredLearnedEntry[] {\n const raw = loadProjectAgentLearned(role, projectRoot);\n return parseStructuredLearnedEntriesFromContent(\n raw,\n listProjectAgentLearnedEntries(role, projectRoot),\n );\n}\n\n/**\n * Learned-wisdom capture from agent output.\n *\n * Scans `output` for `## LEARNED` blocks and persists each unique,\n * quality-passing block to the role's `learned.md`. Each block is run\n * through `normalizeLearnedEntry` so the buffer only accumulates instructive\n * directives \u2014 narrative session logs are rejected at capture time. Near-\n * duplicate entries (token overlap \u2265 0.55) are silently skipped.\n *\n * When the resulting file would exceed `LEARNED_HARD_LIMIT` (16 KB)\n * the oldest entries are rotated out before writing.\n *\n * @returns the number of **new** items actually persisted (0 if none).\n */\nexport function captureLearnedFromAgentOutput(\n output: string,\n role: string,\n projectRoot?: string,\n isManual = false,\n): number {\n return captureLearnedFromAgentOutputDetailed(output, role, projectRoot, isManual).captured;\n}\n\nexport function captureLearnedFromAgentOutputDetailed(\n output: string,\n role: string,\n projectRoot?: string,\n isManual = false,\n): LearnedCaptureResult {\n const normalizedRole = assertProjectAgentRole(role);\n if (!output.trim()) {\n return { role: normalizedRole, captured: 0, skipped: 0, status: 'empty_output' };\n }\n const policy = loadProjectAgentLearningPolicy(normalizedRole, projectRoot);\n if (!policy.enabled && !isManual) {\n return {\n role: normalizedRole,\n captured: 0,\n skipped: 0,\n status: 'disabled',\n reason: 'Automatic learning is disabled for this role.',\n };\n }\n\n const regex = /^##\\s*LEARNED\\s*$/gim;\n const candidates: string[] = [];\n let startMatch = regex.exec(output);\n while (startMatch !== null) {\n const blockStart = startMatch.index + startMatch[0].length;\n const rest = output.slice(blockStart);\n const nextHeading = /^##\\s/gm.exec(rest);\n const blockEnd = nextHeading ? blockStart + nextHeading.index : output.length;\n candidates.push(output.slice(blockStart, blockEnd).trim());\n regex.lastIndex = Math.max(regex.lastIndex, blockEnd);\n startMatch = regex.exec(output);\n }\n if (candidates.length === 0) {\n return { role: normalizedRole, captured: 0, skipped: 0, status: 'no_blocks' };\n }\n\n const existingRaw = loadProjectAgentLearned(normalizedRole, projectRoot);\n const guard = canCaptureNewLearned(\n normalizedRole,\n Buffer.byteLength(existingRaw, 'utf8'),\n isManual,\n projectRoot,\n );\n if (guard) {\n return {\n role: normalizedRole,\n captured: 0,\n skipped: candidates.length,\n status: 'guarded',\n reason: guard,\n };\n }\n\n // Dedup against existing structured entries' directive keys so the\n // capture loop can reject near-duplicates using the same normalization\n // the structured renderer applies. This replaces the old chunked-text\n // dedup path which could not see through the structured document format.\n const normalizedEntries = parseStructuredLearnedEntries(normalizedRole, projectRoot).map(\n (entry) => entry.key,\n );\n let structuredEntries = parseStructuredLearnedEntries(normalizedRole, projectRoot);\n let captured = 0;\n let skipped = 0;\n const now = new Date();\n const nowIso = now.toISOString();\n const remainingSessionCaptures = isManual\n ? Number.POSITIVE_INFINITY\n : Math.max(\n 0,\n CAPTURE_MAX_PER_SESSION -\n (captureFrequency.get(\n `${path.resolve(projectRoot ?? process.cwd())}\\0${normalizedRole}`,\n ) ?? 0),\n );\n\n for (const content of candidates) {\n if (captured >= remainingSessionCaptures) {\n skipped++;\n continue;\n }\n // Run normalization FIRST: strip ephemeral artifacts, drop narrative\n // framing, classify, and reject entries that cannot be salvaged into\n // instructive directives. This is the quality gate that keeps the\n // buffer from accumulating session logs.\n const normalized = normalizeLearnedEntry(content);\n if (!normalized) {\n skipped++;\n continue;\n }\n // Code-only check: rejects entries that are mostly fenced code even after\n // normalization (the normalizer preserves prose, so a code-only block\n // will already be short on text \u2014 this is a belt-and-braces check).\n const totalLines = Math.max(1, content.split('\\n').length);\n const codeBodyLines = (content.match(/```[\\s\\S]*?```/g) ?? []).reduce(\n (sum, block) => sum + Math.max(0, block.split('\\n').length - 2),\n 0,\n );\n if (totalLines > 5 && codeBodyLines / totalLines > 0.7) {\n skipped++;\n continue;\n }\n const candidateNorm = normalizeForComparison(normalized.text);\n if (normalizedEntries.some((entry) => tokenOverlap(candidateNorm, entry) >= 0.55)) {\n skipped++;\n continue;\n }\n normalizedEntries.push(candidateNorm);\n // Merge the new directive into the structured list, deduplicating against\n // existing entries by content similarity. The buffer is rewritten as a\n // structured instruction list (what / why / how) at the end of this\n // function \u2014 historical entries are re-decomposed in lockstep so the\n // file is always a current, consistent snapshot.\n structuredEntries = mergeStructuredEntries(structuredEntries, {\n text: normalized.text,\n category: normalized.category,\n capturedAt: nowIso,\n });\n captured++;\n }\n\n if (captured === 0) {\n return {\n role: normalizedRole,\n captured: 0,\n skipped,\n status: 'quality_rejected',\n reason:\n 'Every LEARNED block was too short, too narrative, or a near-duplicate. Write directives, not session logs.',\n };\n }\n\n // Render the merged list as a structured instruction document. This is the\n // single source of truth \u2014 the buffer is rewritten in full on every\n // capture so the file always reflects the current, merged state.\n let newContent = renderLearnedInstructions(normalizedRole, structuredEntries, nowIso);\n if (Buffer.byteLength(newContent, 'utf8') >= LEARNED_HARD_LIMIT) {\n // Trim oldest entries when the document exceeds the hard limit. Keep\n // the structured form intact by re-rendering after pruning.\n const trimmed = structuredEntries.slice(-Math.max(1, Math.floor(structuredEntries.length / 2)));\n newContent = renderLearnedInstructions(normalizedRole, trimmed, nowIso);\n }\n\n writeTextAtomically(path.join(roleDir(normalizedRole, projectRoot), 'learned.md'), newContent);\n const captureKey = `${path.resolve(projectRoot ?? process.cwd())}\\0${normalizedRole}`;\n captureCooldowns.set(captureKey, now.getTime());\n // Increment the frequency counter by 1 per capture attempt (not by\n // `captured`, the number of LEARNED blocks appended). Otherwise a single\n // response that yields N blocks immediately exhausts the\n // CAPTURE_MAX_PER_SESSION budget for the rest of the session, while a\n // response that yields 0 blocks consumes nothing \u2014 both diverge from the\n // documented \"attempts per session\" semantics the cap is meant to enforce.\n captureFrequency.set(captureKey, (captureFrequency.get(captureKey) ?? 0) + 1);\n const nextPolicy: ProjectAgentLearningPolicy = {\n ...policy,\n lifetimeCaptureCount: policy.lifetimeCaptureCount + captured,\n lastCaptureAt: now.toISOString(),\n lastCaptureSource: isManual ? 'manual' : 'automatic',\n };\n writeTextAtomically(\n learningPolicyPath(normalizedRole, projectRoot),\n `${JSON.stringify(nextPolicy, null, 2)}\\n`,\n );\n return { role: normalizedRole, captured, skipped, status: 'captured' };\n}\n\n/**\n * Signal the host that a background summarisation pass is warranted.\n * Called by `captureLearnedFromAgentOutput` when the **new** learned size\n * crosses `LEARNED_SOFT_LIMIT`. The host is responsible for scheduling a\n * low-priority consolidation task (typically via the Brain or a shadow agent).\n *\n * The summary _mechanism_ is intentionally shallow here \u2014 the real\n * summarisation is an LLM call that should run as a deferred, uncritical\n * fleet task so it never blocks a user-facing operation.\n *\n * @returns a summary brief for the host, or '' when no action is needed.\n */\nexport function hintLearnedNeedsSummarization(role: string, projectRoot?: string): string {\n const learned = loadProjectAgentLearned(role, projectRoot);\n if (!learned) return '';\n const bytes = Buffer.byteLength(learned, 'utf8');\n if (bytes < LEARNED_SOFT_LIMIT) return '';\n return `Learned wisdom for role \"${role}\" is ${bytes} B (soft limit ${LEARNED_SOFT_LIMIT}). Schedule a low-priority consolidation pass.`;\n}\n\n// ---------------------------------------------------------------------------\n// Consolidation: review raw learned.md \u2192 produce consolidated.md\n// ---------------------------------------------------------------------------\n//\n// The learned.md file is an append-only capture buffer. Over time it grows\n// with verbose, overlapping entries. The consolidation pass reads every raw\n// entry, asks an LLM to synthesize them into a single narrowly-scoped\n// document that represents what the agent has learned for its role, and\n// writes the result to consolidated.md.\n//\n// Once consolidated.md exists, buildProjectContextualizedPrompt prefers it\n// over the raw learned.md \u2014 the raw buffer is retained on disk for audit\n// but no longer injected into prompts (reducing context volume without\n// omitting information, because every fact was carried into the summary).\n//\n// Files (under .wrongstack/agents/<role>/):\n// consolidated.md \u2014 the synthesized, reviewed document\n// consolidation.json \u2014 metadata tracking the last review\n", "import type { RoleKnowledgeManifest } from './project-agent-identity-types.js';\n\nexport const BUILT_IN_KNOWLEDGE_MANIFESTS: Record<string, RoleKnowledgeManifest> = {\n android: {\n role: 'android',\n // Only machine-readable JSON registries belong in liveQueries. Android\n // release/API data has no JSON registry endpoint, so those checks stay as\n // checklist prose below.\n liveQueries: {\n kotlin: {\n registry: 'https://registry.npmjs.org/kotlin/latest',\n key: 'version',\n description: 'Kotlin latest stable',\n },\n },\n checklist: [\n 'Current Android Gradle Plugin version (8.x+)',\n 'Current Kotlin version (2.x+)',\n 'Current compileSdk / targetSdk (\u2265 34, check Play Store policy)',\n 'Current Jetpack Compose stable version',\n 'All third-party dependencies are at latest compatible minor',\n ],\n verifyThreshold: 0.5,\n },\n frontend: {\n role: 'frontend',\n liveQueries: {\n react: {\n registry: 'https://registry.npmjs.org/react/latest',\n key: 'version',\n description: 'React latest stable',\n },\n nextjs: {\n registry: 'https://registry.npmjs.org/next/latest',\n key: 'version',\n description: 'Next.js latest stable',\n },\n },\n checklist: [\n 'Current React version (pinned in package.json)',\n 'Current Next.js / Vite / framework version',\n 'Node.js runtime version (project .nvmrc or engines)',\n 'All devDependencies are at latest compatible versions',\n 'Browser compatibility targets from browserslist',\n ],\n verifyThreshold: 0.5,\n },\n executor: {\n role: 'executor',\n liveQueries: {\n node: {\n registry: 'https://registry.npmjs.org/node/latest',\n key: 'version',\n description: 'Node.js latest release',\n },\n },\n checklist: [\n 'Node.js version from .nvmrc or package.engines',\n 'TypeScript version from package.json',\n 'Package manager (pnpm \u2265 9) from packageManager',\n 'Current toolchain: esbuild, vitest, etc.',\n ],\n verifyThreshold: 0.6,\n },\n};\n", "import { readFileSync } from 'node:fs';\nimport {\n learningPolicyPath,\n writeTextAtomically,\n} from './project-agent-paths.js';\n\n/** Persistent controls and counters for one roster role's learning loop. */\nexport interface ProjectAgentLearningPolicy {\n /** Retain knowledge but stop prompt injection and automatic capture when false. */\n enabled: boolean;\n lifetimeCaptureCount: number;\n lastCaptureAt?: string | undefined;\n lastCaptureSource?: 'automatic' | 'manual' | 'taught' | undefined;\n}\n\nconst DEFAULT_LEARNING_POLICY: ProjectAgentLearningPolicy = {\n enabled: true,\n lifetimeCaptureCount: 0,\n};\n\nexport function loadProjectAgentLearningPolicy(\n role: string,\n projectRoot?: string,\n): ProjectAgentLearningPolicy {\n try {\n const parsed = JSON.parse(\n readFileSync(learningPolicyPath(role, projectRoot), 'utf8'),\n ) as Partial<ProjectAgentLearningPolicy>;\n return {\n enabled: parsed.enabled !== false,\n lifetimeCaptureCount:\n typeof parsed.lifetimeCaptureCount === 'number' &&\n Number.isInteger(parsed.lifetimeCaptureCount) &&\n parsed.lifetimeCaptureCount >= 0\n ? parsed.lifetimeCaptureCount\n : 0,\n ...(typeof parsed.lastCaptureAt === 'string' ? { lastCaptureAt: parsed.lastCaptureAt } : {}),\n ...(parsed.lastCaptureSource === 'automatic' ||\n parsed.lastCaptureSource === 'manual' ||\n parsed.lastCaptureSource === 'taught'\n ? { lastCaptureSource: parsed.lastCaptureSource }\n : {}),\n };\n } catch {\n return { ...DEFAULT_LEARNING_POLICY };\n }\n}\n\nexport function updateProjectAgentLearningPolicy(\n role: string,\n patch: Partial<Pick<ProjectAgentLearningPolicy, 'enabled'>>,\n projectRoot?: string,\n): ProjectAgentLearningPolicy {\n const current = loadProjectAgentLearningPolicy(role, projectRoot);\n const updated = {\n ...current,\n ...(patch.enabled !== undefined ? { enabled: patch.enabled } : {}),\n };\n writeTextAtomically(\n learningPolicyPath(role, projectRoot),\n `${JSON.stringify(updated, null, 2)}\\n`,\n );\n return updated;\n}\n", "import { randomUUID } from 'node:crypto';\nimport { mkdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';\nimport * as path from 'node:path';\n\nconst AGENT_ROLE_PATTERN = /^[a-z0-9][a-z0-9._-]{0,95}$/i;\n\nexport function assertProjectAgentRole(role: string): string {\n const normalized = role.trim();\n if (\n !AGENT_ROLE_PATTERN.test(normalized) ||\n normalized === '.' ||\n normalized === '..' ||\n normalized.includes('/') ||\n normalized.includes('\\\\')\n ) {\n throw new Error(`Invalid project agent role: \"${role}\".`);\n }\n return normalized;\n}\n\nexport function isProjectAgentRoleName(name: string): boolean {\n return AGENT_ROLE_PATTERN.test(name) && name !== '.' && name !== '..';\n}\n\nexport function agentsDir(projectRoot?: string): string {\n const root = projectRoot ?? process.cwd();\n return path.join(root, '.wrongstack', 'agents');\n}\n\nexport function roleDir(role: string, projectRoot?: string): string {\n return path.join(agentsDir(projectRoot), assertProjectAgentRole(role));\n}\n\nexport function writeTextAtomically(filePath: string, content: string): void {\n mkdirSync(path.dirname(filePath), { recursive: true });\n const temporaryPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;\n try {\n writeFileSync(temporaryPath, content, 'utf8');\n renameSync(temporaryPath, filePath);\n } finally {\n try {\n rmSync(temporaryPath, { force: true });\n } catch {\n // Best-effort cleanup after a failed rename.\n }\n }\n}\n\nexport function learningPolicyPath(role: string, projectRoot?: string): string {\n return path.join(roleDir(role, projectRoot), 'learning.json');\n}\n\nexport function projectAgentProfilePath(role: string, projectRoot?: string): string {\n return path.join(roleDir(role, projectRoot), 'profile.json');\n}\n", "/**\n * Return the Jaccard similarity (0-1) of two normalised token sets.\n */\nexport function tokenOverlap(a: string, b: string): number {\n const setA = new Set(a.split(/\\s+/));\n const setB = new Set(b.split(/\\s+/));\n const intersect = new Set([...setA].filter((t) => setB.has(t)));\n const union = new Set([...setA, ...setB]);\n return union.size === 0 ? 0 : intersect.size / union.size;\n}\n\n/**\n * Split an existing learned.md body into individual entries.\n * Entries are delimited by `---\\n\\n` sequences.\n */\nexport function splitLearnedEntries(body: string): string[] {\n return body\n .split(/\\n---\\n+/)\n .map((entry) => entry.trim())\n .map((entry) =>\n entry\n .replace(/^# Learned wisdom for .+$/im, '')\n .replace(/<!--[\\s\\S]*?-->/g, '')\n .trim(),\n )\n .filter(Boolean);\n}\n", "import {\n existsSync,\n mkdirSync,\n readFileSync,\n rmSync,\n} from 'node:fs';\nimport * as path from 'node:path';\nimport { splitLearnedEntries } from './project-agent-learning-entries.js';\nimport { assertProjectAgentRole, roleDir, writeTextAtomically } from './project-agent-paths.js';\n\nexport interface ConsolidationMetadata {\n /** ISO timestamp of the last consolidation. */\n consolidatedAt: string;\n /** Number of raw learned.md entries that were synthesized. */\n sourceEntryCount: number;\n /** Byte size of the raw learned.md at consolidation time. */\n sourceBytes: number;\n /** Byte size of the resulting consolidated.md. */\n consolidatedBytes: number;\n /** Whether the consolidation was user-triggered or automatic. */\n trigger: 'manual' | 'automatic';\n /** Optional model that produced the consolidation. */\n model?: string | undefined;\n}\n\nfunction learnedPath(role: string, projectRoot?: string): string {\n return path.join(roleDir(role, projectRoot), 'learned.md');\n}\n\nfunction loadProjectAgentLearnedText(role: string, projectRoot?: string): string {\n try {\n return readFileSync(learnedPath(role, projectRoot), 'utf8').trim();\n } catch {\n return '';\n }\n}\n\nfunction listProjectAgentLearnedTextEntries(role: string, projectRoot?: string): string[] {\n return splitLearnedEntries(loadProjectAgentLearnedText(role, projectRoot));\n}\n\nfunction consolidationPath(role: string, projectRoot?: string): string {\n return path.join(roleDir(role, projectRoot), 'consolidated.md');\n}\n\nfunction consolidationMetaPath(role: string, projectRoot?: string): string {\n return path.join(roleDir(role, projectRoot), 'consolidation.json');\n}\n\nexport function loadProjectAgentConsolidated(role: string, projectRoot?: string): string {\n try {\n return readFileSync(consolidationPath(role, projectRoot), 'utf8').trim();\n } catch {\n return '';\n }\n}\n\nexport function loadConsolidationMetadata(\n role: string,\n projectRoot?: string,\n): ConsolidationMetadata | undefined {\n try {\n const raw = readFileSync(consolidationMetaPath(role, projectRoot), 'utf8');\n const parsed = JSON.parse(raw) as unknown;\n if (\n typeof parsed === 'object' &&\n parsed !== null &&\n typeof (parsed as ConsolidationMetadata).consolidatedAt === 'string' &&\n typeof (parsed as ConsolidationMetadata).sourceEntryCount === 'number'\n ) {\n return parsed as ConsolidationMetadata;\n }\n return undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function isConsolidated(role: string, projectRoot?: string): boolean {\n return existsSync(consolidationMetaPath(role, projectRoot));\n}\n\nexport function saveProjectAgentConsolidated(\n role: string,\n content: string,\n projectRoot?: string,\n metadata?: Partial<ConsolidationMetadata>,\n): string {\n if (!content.trim()) {\n return consolidationPath(assertProjectAgentRole(role), projectRoot);\n }\n const normalizedRole = assertProjectAgentRole(role);\n const dir = roleDir(normalizedRole, projectRoot);\n mkdirSync(dir, { recursive: true });\n const fp = consolidationPath(normalizedRole, projectRoot);\n writeTextAtomically(fp, content);\n\n const rawEntries = listProjectAgentLearnedTextEntries(normalizedRole, projectRoot);\n const rawBytes = Buffer.byteLength(loadProjectAgentLearnedText(normalizedRole, projectRoot), 'utf8');\n const meta: ConsolidationMetadata = {\n consolidatedAt: new Date().toISOString(),\n sourceEntryCount: rawEntries.length,\n sourceBytes: rawBytes,\n consolidatedBytes: Buffer.byteLength(content, 'utf8'),\n trigger: metadata?.trigger ?? 'manual',\n ...(metadata?.model ? { model: metadata.model } : {}),\n };\n writeTextAtomically(\n consolidationMetaPath(normalizedRole, projectRoot),\n `${JSON.stringify(meta, null, 2)}\\n`,\n );\n return fp;\n}\n\nexport function clearProjectAgentConsolidated(role: string, projectRoot?: string): void {\n const normalizedRole = assertProjectAgentRole(role);\n for (const file of [\n consolidationPath(normalizedRole, projectRoot),\n consolidationMetaPath(normalizedRole, projectRoot),\n ]) {\n try {\n rmSync(file, { force: true });\n } catch {\n // already absent\n }\n }\n}\n\nexport function buildConsolidationInstruction(\n role: string,\n projectRoot?: string,\n): {\n instruction: string;\n rawEntries: string[];\n hasExistingConsolidation: boolean;\n} {\n const normalizedRole = assertProjectAgentRole(role);\n const rawEntries = listProjectAgentLearnedTextEntries(normalizedRole, projectRoot);\n const existingConsolidation = loadProjectAgentConsolidated(normalizedRole, projectRoot);\n const rawBody = rawEntries.map((entry, i) => `### Entry ${i + 1}\\n\\n${entry}`).join('\\n\\n');\n\n const sections: string[] = [\n `You are reviewing and consolidating the captured learning entries for the \"${normalizedRole}\" agent role in this project.`,\n '',\n 'Your task is to synthesize the raw entries below into a single, narrowly-scoped document that represents what this agent has learned \u2014 specifically for its skills and role responsibilities. This document is the **instruction manual for future invocations** of this agent in this project. It is not a journal, not an exhaustive transcription, and not a memory store.',\n '',\n '## Requirements',\n '',\n '1. **Be selective.** Some raw entries are noise \u2014 narrative descriptions of single-session events, ephemeral references (commit SHAs, timestamps, line numbers, PR refs), or thin fragments that cannot be generalized. **Drop them.** The output must be smaller than the input; a consolidation that preserves every word is not a consolidation.',\n '2. **Extract the directive.** When a raw entry mixes narrative framing with a buried lesson (\"When I worked on X, I realized Y\"), extract the lesson as a directive and discard the framing.',\n '3. **Generic, not specific.** Rewrite entries so they apply across sessions. Replace session-specific anchors (commit SHAs, dates, line numbers) with general principles or concrete tools/commands that will still be valid next month.',\n '4. **Self-contained bullets.** Each bullet must make sense standalone \u2014 understandable to a future agent that has no context about the session that produced it.',\n '5. **Narrow scope.** Keep only knowledge that is genuinely durable and role-relevant. When in doubt, leave it out.',\n '6. **Structured format.** Organize the content under clear markdown headings (##) by topic. Use bullet points for individual facts. Group by category (Conventions, Patterns, Warnings, Project Facts) when it helps scannability.',\n '7. **Preserve actionable anchors.** Keep exact file paths, command names, package names, and configuration values that make a directive concrete and runnable.',\n '8. **No filler.** Do not include meta-commentary about the consolidation process. The document should read as if it were always a single authoritative reference.',\n '',\n rawEntries.length > 0\n ? `## Raw learned entries (${rawEntries.length} total)\\n\\n${rawBody}`\n : '## Raw learned entries\\n\\n(No raw entries yet \u2014 return an empty document.)',\n ];\n\n if (existingConsolidation) {\n sections.push(\n '',\n `## Existing consolidated document (for reference \u2014 improve upon it)\\n\\n${existingConsolidation}`,\n );\n }\n\n sections.push(\n '',\n '## Output',\n '',\n 'Return ONLY the consolidated markdown document. Do not wrap it in code fences or add commentary.',\n );\n\n return {\n instruction: sections.join('\\n'),\n rawEntries,\n hasExistingConsolidation: Boolean(existingConsolidation),\n };\n}\n", "import { type AgentDefinition, LIGHT_BUDGET, MEDIUM_BUDGET, TOOLS } from './types.js';\nimport { agentPrompt } from './agent-prompts.js';\n\n/** Phase 1 \u00B7 Discovery \u2014 map the territory before any work begins. */\nexport const DISCOVERY_AGENTS: AgentDefinition[] = [\n {\n config: {\n id: 'explore',\n name: 'Explore',\n role: 'explore',\n tools: [...TOOLS.read],\n prompt: agentPrompt('explore'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'discovery',\n summary: 'Maps unfamiliar codebases: entry points, structure, architecture, feature flow (read-only).',\n keywords: [\n 'explore',\n 'map',\n 'understand',\n 'where is',\n 'how does',\n 'codebase',\n 'architecture',\n 'structure',\n 'overview',\n 'find file',\n 'entry point',\n 'orient',\n ],\n },\n },\n {\n config: {\n id: 'search',\n name: 'Search',\n role: 'search',\n tools: [...TOOLS.read],\n prompt: agentPrompt('search'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'discovery',\n summary: 'Semantic + lexical code search across repos; finds definitions, references, duplicates, ranks by relevance.',\n keywords: [\n 'search',\n 'find all',\n 'references',\n 'usages',\n 'call sites',\n 'grep',\n 'locate symbol',\n 'duplicate',\n 'where used',\n 'occurrences',\n 'cross-repo',\n ],\n },\n },\n {\n config: {\n id: 'research',\n name: 'Research',\n role: 'research',\n tools: [...TOOLS.research],\n prompt: agentPrompt('research'),\n },\n budget: LIGHT_BUDGET,\n capability: {\n phase: 'discovery',\n summary: 'Technical research and feasibility: compares libraries/approaches, recommends a path with evidence and tradeoffs.',\n keywords: [\n 'research',\n 'feasibility',\n 'compare libraries',\n 'which library',\n 'best practice',\n 'tradeoff',\n 'investigate',\n 'evaluate approach',\n 'should we use',\n 'pros and cons',\n ],\n },\n },\n];\n", "import { type AgentDefinition, HEAVY_BUDGET, LIGHT_BUDGET, TOOLS } from './types.js';\nimport { agentPrompt } from './agent-prompts.js';\n\nconst PLAN_TOOLS = [...TOOLS.read, 'plan', 'todo'];\n\n/** Phase 2 \u00B7 Planning \u2014 turn intent into requirements, plans, and architecture. */\nexport const PLANNING_AGENTS: AgentDefinition[] = [\n {\n config: {\n id: 'analyst',\n name: 'Analyst',\n role: 'analyst',\n tools: [...PLAN_TOOLS],\n prompt: agentPrompt('analyst'),\n },\n budget: LIGHT_BUDGET,\n capability: {\n phase: 'planning',\n summary: 'Requirement analysis: turns vague requests into testable specs with acceptance criteria and open questions.',\n keywords: [\n 'requirements',\n 'analyze requirement',\n 'acceptance criteria',\n 'spec',\n 'specification',\n 'clarify',\n 'scope',\n 'user story',\n 'what should it do',\n ],\n },\n },\n {\n config: {\n id: 'planner',\n name: 'Planner',\n role: 'planner',\n tools: [...PLAN_TOOLS],\n prompt: agentPrompt('planner'),\n },\n budget: LIGHT_BUDGET,\n capability: {\n phase: 'planning',\n summary: 'Execution planning: decomposes a goal into ordered, dependency-aware, parallelizable steps with checkpoints.',\n keywords: [\n 'plan',\n 'execution plan',\n 'break down',\n 'decompose',\n 'steps',\n 'sequence',\n 'roadmap',\n 'task breakdown',\n 'order of work',\n 'milestones',\n ],\n },\n },\n {\n config: {\n id: 'architect',\n name: 'Architect',\n role: 'architect',\n tools: [...PLAN_TOOLS],\n prompt: agentPrompt('architect'),\n },\n budget: LIGHT_BUDGET,\n capability: {\n phase: 'planning',\n summary: 'System architecture: designs module boundaries, interfaces, data flow, and records key decisions.',\n keywords: [\n 'architecture',\n 'design system',\n 'module boundaries',\n 'interfaces',\n 'data flow',\n 'component design',\n 'system design',\n 'decision record',\n 'adr',\n 'structure the',\n ],\n },\n },\n {\n config: {\n id: 'critic',\n name: 'Critic',\n role: 'critic',\n tools: [...TOOLS.read],\n prompt: agentPrompt('critic'),\n },\n budget: LIGHT_BUDGET,\n capability: {\n phase: 'planning',\n summary: 'Adversarial review of plans/designs: finds gaps, risks, and unstated assumptions with ranked fixes.',\n keywords: [\n 'critique',\n 'review plan',\n 'review design',\n 'red team',\n 'poke holes',\n 'risks',\n 'what could go wrong',\n 'second opinion',\n 'challenge',\n 'flaws',\n ],\n },\n },\n {\n config: {\n id: 'refactor-planner',\n name: 'Refactor Planner',\n role: 'refactor-planner',\n tools: [...PLAN_TOOLS, 'diff'],\n prompt: agentPrompt('refactor-planner'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'planning',\n summary: 'Refactoring planner: analyzes code structure, maps dependencies, produces risk-scored phased plans with rollback strategy.',\n keywords: [\n 'refactor',\n 'refactoring',\n 'restructure',\n 'debt',\n 'technical debt',\n 'clean up',\n 'modularize',\n 'decouple',\n 'dependency graph',\n 'code structure',\n ],\n },\n },\n];\n", "import { type AgentDefinition, HEAVY_BUDGET, MEDIUM_BUDGET, TOOLS } from './types.js';\nimport { agentPrompt } from './agent-prompts.js';\n\n/** Phase 3 \u00B7 Build \u2014 write, refactor, migrate, and fix code. */\nexport const BUILD_AGENTS: AgentDefinition[] = [\n {\n config: {\n id: 'executor',\n name: 'Executor',\n role: 'executor',\n tools: [...TOOLS.build],\n prompt: agentPrompt('executor'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'build',\n summary: 'Implements well-specified tasks: writes code, runs checks, leaves the tree green.',\n keywords: [\n 'implement',\n 'build',\n 'write code',\n 'add feature',\n 'create',\n 'code up',\n 'develop',\n 'apply change',\n 'make it work',\n ],\n },\n },\n {\n config: {\n id: 'refactor',\n name: 'Refactor',\n role: 'refactor',\n tools: [...TOOLS.build],\n prompt: agentPrompt('refactor'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'build',\n summary: 'Structural refactoring: extract/split/move/rename/decouple without changing observable behavior.',\n keywords: [\n 'refactor',\n 'restructure',\n 'extract',\n 'split module',\n 'decouple',\n 'rename',\n 'move code',\n 'break dependency',\n 'reorganize',\n ],\n },\n },\n {\n config: {\n id: 'simplifier',\n name: 'Simplifier',\n role: 'simplifier',\n tools: [...TOOLS.build],\n prompt: agentPrompt('simplifier'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'build',\n summary: 'Reduces complexity: deletes dead code, collapses needless abstractions, shortens and clarifies code.',\n keywords: [\n 'simplify',\n 'dead code',\n 'remove unused',\n 'reduce complexity',\n 'clean up',\n 'denest',\n 'shorten',\n 'over-engineered',\n 'too complex',\n ],\n },\n },\n {\n config: {\n id: 'migration',\n name: 'Migration',\n role: 'migration',\n tools: [...TOOLS.build, 'install', 'outdated'],\n prompt: agentPrompt('migration'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'build',\n summary: 'Framework/language/version upgrades: applies codemods across call sites, staged and verified.',\n keywords: [\n 'migrate',\n 'upgrade',\n 'codemod',\n 'breaking change',\n 'major version',\n 'port to',\n 'convert to',\n 'esm',\n 'modernize',\n ],\n },\n },\n {\n config: {\n id: 'vision',\n name: 'Vision',\n role: 'vision',\n tools: [...TOOLS.write, 'fetch'],\n prompt: agentPrompt('vision'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'build',\n summary: 'Screenshot/mockup \u2192 UI code: infers component tree and generates matching, accessible markup.',\n keywords: [\n 'screenshot',\n 'mockup',\n 'design to code',\n 'image to ui',\n 'figma',\n 'replicate this ui',\n 'from this picture',\n 'vision',\n 'clone ui',\n ],\n },\n },\n {\n config: {\n id: 'debugger',\n name: 'Debugger',\n role: 'debugger',\n tools: [...TOOLS.build, 'logs'],\n prompt: agentPrompt('debugger'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'build',\n summary: 'Root-cause bug fixing: reproduces, bisects to the true cause, applies a minimal fix with a regression test.',\n keywords: [\n 'bug',\n 'fix',\n 'debug',\n 'broken',\n 'error',\n 'crash',\n 'root cause',\n 'not working',\n 'failing',\n 'reproduce',\n 'why does',\n ],\n },\n },\n {\n config: {\n id: 'tracer',\n name: 'Tracer',\n role: 'tracer',\n tools: [...TOOLS.build, 'logs'],\n prompt: agentPrompt('tracer'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'build',\n summary: 'Runtime tracing: instruments and runs code to observe call order, values, and timing, then cleans up.',\n keywords: [\n 'trace',\n 'runtime',\n 'instrument',\n 'execution path',\n 'what happens at runtime',\n 'call order',\n 'profile execution',\n 'observe behavior',\n 'stack trace',\n ],\n },\n },\n];\n", "import { agentPrompt } from './agent-prompts.js';\nimport type { BundledAgentSkill } from './role-skills.js';\nimport {\n type AgentDefinition,\n type RoleDispatcherSignal,\n HEAVY_BUDGET,\n MEDIUM_BUDGET,\n TOOLS,\n} from './types.js';\n\n\nconst skillSet = (...names: BundledAgentSkill[]): BundledAgentSkill[] => names;\n\nvoid skillSet;\n\n/**\n * Wave 1: Platform and systems engineering.\n *\n * Six new specialist roles sit alongside the existing build/domain/verify\n * phases. Each carries an explicit `RoleDispatcherSignal` so the dispatcher\n * can tell it apart from siblings that share vocabulary.\n */\n\nconst ANDROID_META = {\n rationale:\n 'Android platform specialist: Kotlin, Jetpack Compose, Android SDK and Play Store delivery. Mirrors the iOS role on the Android side of the mobile fence.',\n signals: [\n 'android',\n 'kotlin',\n 'jetpack compose',\n 'compose',\n 'android sdk',\n 'gradle',\n 'play store',\n 'aosp',\n ] as const,\n differentiatesFrom:\n 'frontend builds cross-platform UI; android owns the Android-specific lifecycle, framework and platform APIs.',\n} satisfies RoleDispatcherSignal;\n\nconst DESKTOP_META = {\n rationale:\n 'Desktop application specialist: Electron, Tauri, native packaging, IPC and OS integration. Owns the process/IPC boundary that web-only roles ignore.',\n signals: [\n 'desktop',\n 'electron',\n 'tauri',\n 'ipc',\n 'tray',\n 'native packaging',\n 'sandbox',\n 'os integration',\n ] as const,\n differentiatesFrom:\n 'frontend assumes a single browser tab; desktop owns the multi-process / IPC / OS-level boundaries.',\n} satisfies RoleDispatcherSignal;\n\nconst REALTIME_META = {\n rationale:\n 'Realtime transport specialist: WebSocket, SSE, presence, heartbeat, reconnect and backpressure. Owns long-lived connection state and lifecycle.',\n signals: [\n 'realtime',\n 'websocket',\n 'sse',\n 'server-sent events',\n 'presence',\n 'heartbeat',\n 'backpressure',\n 'reconnect',\n ] as const,\n differentiatesFrom:\n 'api designs request/response contracts; realtime designs long-lived connections and presence semantics.',\n} satisfies RoleDispatcherSignal;\n\nconst DISTRIBUTED_SYSTEMS_META = {\n rationale:\n 'Distributed-systems engineer: consistency, partitioning, idempotency, saga and distributed coordination. Implementation-level specialist; architect designs the surface, distributed-systems implements the failure semantics.',\n signals: [\n 'distributed systems',\n 'consensus',\n 'saga',\n 'idempotency',\n 'partition',\n 'eventual consistency',\n 'leader election',\n 'replication',\n ] as const,\n differentiatesFrom:\n 'architect designs the system surface; distributed-systems implements the failure semantics and coordination protocols.',\n} satisfies RoleDispatcherSignal;\n\nconst CONCURRENCY_META = {\n rationale:\n 'Concurrency engineer: race conditions, locks, worker pools, async lifecycle and shared-state safety. Focused practitioner; debugger diagnoses, concurrency designs.',\n signals: [\n 'concurrency',\n 'race condition',\n 'deadlock',\n 'worker pool',\n 'lock',\n 'mutex',\n 'async lifecycle',\n 'shared state',\n ] as const,\n differentiatesFrom:\n 'debugger diagnoses concurrency incidents; concurrency designs shared-state systems to avoid them in the first place.',\n} satisfies RoleDispatcherSignal;\n\nconst PLATFORM_ENGINEER_META = {\n rationale:\n 'Platform engineer: monorepo, build graph, internal tooling and developer experience. The \"DX half\" of CI/CD, separate from devops which owns deployment.',\n signals: [\n 'platform',\n 'monorepo',\n 'build graph',\n 'developer experience',\n 'developer tooling',\n 'scaffolding',\n 'workspace',\n ] as const,\n differentiatesFrom:\n 'devops owns deploy/operate; platform-engineer owns the internal developer surface that ships the code.',\n} satisfies RoleDispatcherSignal;\n\nexport const WAVE1_AGENTS: AgentDefinition[] = [\n {\n config: {\n id: 'android',\n name: 'Android',\n role: 'android',\n tools: [...TOOLS.build, 'fetch'],\n prompt: agentPrompt('android'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'domain',\n summary:\n 'Android platform specialist: Kotlin, Jetpack Compose, Android SDK, lifecycle and Play Store delivery.',\n keywords: [\n ...ANDROID_META.signals,\n 'android',\n 'kotlin',\n 'compose',\n 'gradle',\n 'playstore',\n ],\n },\n },\n {\n config: {\n id: 'desktop',\n name: 'Desktop',\n role: 'desktop',\n tools: [...TOOLS.build, 'fetch'],\n prompt: agentPrompt('desktop'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'domain',\n summary:\n 'Desktop application specialist: Electron or Tauri, native packaging, IPC and OS integration.',\n keywords: [\n ...DESKTOP_META.signals,\n 'desktop',\n 'electron',\n 'tauri',\n 'ipc',\n 'tray',\n ],\n },\n },\n {\n config: {\n id: 'realtime',\n name: 'Realtime',\n role: 'realtime',\n tools: [...TOOLS.build, 'logs'],\n prompt: agentPrompt('realtime'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'verify',\n summary:\n 'Realtime transport specialist: WebSocket, SSE, presence, heartbeat, reconnect and backpressure.',\n keywords: [\n ...REALTIME_META.signals,\n 'realtime',\n 'websocket',\n 'sse',\n 'presence',\n 'heartbeat',\n 'reconnect',\n ],\n },\n },\n {\n config: {\n id: 'distributed-systems',\n name: 'Distributed Systems',\n role: 'distributed-systems',\n tools: [...TOOLS.inspect, 'plan', 'test'],\n prompt: agentPrompt('distributed-systems'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'domain',\n summary:\n 'Distributed-systems engineer: consistency, partitioning, idempotency, saga and coordination at the implementation level.',\n keywords: [\n ...DISTRIBUTED_SYSTEMS_META.signals,\n 'distributed-systems',\n 'consensus',\n 'saga',\n 'idempotency',\n 'partition',\n 'leader-election',\n ],\n },\n },\n {\n config: {\n id: 'concurrency',\n name: 'Concurrency',\n role: 'concurrency',\n tools: [...TOOLS.build, 'logs'],\n prompt: agentPrompt('concurrency'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'build',\n summary:\n 'Concurrency engineer: race conditions, locks, worker pools, async lifecycle and shared-state safety.',\n keywords: [\n ...CONCURRENCY_META.signals,\n 'concurrency',\n 'race',\n 'deadlock',\n 'worker-pool',\n 'lock',\n ],\n },\n },\n {\n config: {\n id: 'platform-engineer',\n name: 'Platform Engineer',\n role: 'platform-engineer',\n tools: [...TOOLS.build, 'install', 'git', 'node-modern'],\n prompt: agentPrompt('platform-engineer'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'delivery',\n summary:\n 'Platform engineer: monorepo, build graph, internal tooling and developer experience.',\n keywords: [\n ...PLATFORM_ENGINEER_META.signals,\n 'platform',\n 'monorepo',\n 'build-graph',\n 'dx',\n 'scaffolding',\n 'workspace',\n ],\n },\n },\n];\n\nexport const WAVE1_ROLE_METAS: Record<string, RoleDispatcherSignal> = {\n android: ANDROID_META,\n desktop: DESKTOP_META,\n realtime: REALTIME_META,\n 'distributed-systems': DISTRIBUTED_SYSTEMS_META,\n concurrency: CONCURRENCY_META,\n 'platform-engineer': PLATFORM_ENGINEER_META,\n};\n\nexport const WAVE1_ROLES = new Set<string>(Object.keys(WAVE1_ROLE_METAS));\n", "import { agentPrompt } from './agent-prompts.js';\nimport type { BundledAgentSkill } from './role-skills.js';\nimport {\n type AgentDefinition,\n type RoleDispatcherSignal,\n LIGHT_BUDGET,\n MEDIUM_BUDGET,\n TOOLS,\n} from './types.js';\n\nconst skillSet = (...names: BundledAgentSkill[]): BundledAgentSkill[] => names;\n\n/**\n * Wave 2: Security, resilience, governance and agent platform.\n *\n * These roles extend the existing 51-role phase catalog with focused\n * specialists. Each role carries an `agentMeta` block so the dispatcher\n * can distinguish it from siblings via an explicit rationale and signal\n * list. The legacy `keywords` array is kept for backward compatibility\n * with the heuristic dispatcher.\n */\n\nconst THREAT_MODELER_META = {\n rationale:\n 'Models trust boundaries, abuse cases and data flow before code is written; threat-modeler is the pre-implementation counterpart to security-reviewer.',\n signals: [\n 'threat model',\n 'trust boundary',\n 'abuse case',\n 'attack tree',\n 'data flow diagram',\n 'stride',\n 'asset',\n 'adversary',\n ] as const,\n differentiatesFrom:\n 'security-reviewer finds defects in code; threat-modeler designs the threat surface before code exists.',\n};\n\nconst SECURE_CODING_COACH_META = {\n rationale:\n 'Teaches secure patterns, produces safe defaults and walks engineers through fixes; secure-coding-coach is the counterpart to security-scanner that drives adoption.',\n signals: [\n 'secure coding',\n 'secure default',\n 'hardening',\n 'security example',\n 'security review',\n 'security fix',\n 'defensive',\n 'owasp',\n ] as const,\n differentiatesFrom:\n 'security-scanner detects issues; secure-coding-coach produces prescriptive safe-by-default code and guidance.',\n};\n\nconst RESILIENCE_ENGINEER_META = {\n rationale:\n 'Designs retry, timeout, circuit breaker and graceful-degradation patterns; resilience-engineer is the protective counterpart to chaos.',\n signals: [\n 'retry',\n 'timeout',\n 'circuit breaker',\n 'bulkhead',\n 'graceful degradation',\n 'backoff',\n 'resilience',\n 'fault tolerance',\n ] as const,\n differentiatesFrom:\n 'chaos injects faults to test existing code; resilience-engineer designs the protective mechanisms ahead of time.',\n};\n\nconst CHAOS_ENGINEER_META = {\n rationale:\n 'Builds the controlled fault-injection harness and blast-radius discipline; chaos-engineer is the operator counterpart to the chaos reviewer.',\n signals: [\n 'chaos experiment',\n 'fault injection',\n 'blast radius',\n 'gameday',\n 'steady state',\n 'hypothesis',\n 'explosion radius',\n ] as const,\n differentiatesFrom:\n 'chaos verifies fault behavior; chaos-engineer designs the experiments and runs them safely.',\n};\n\nconst COMPLIANCE_AUDITOR_META = {\n rationale:\n 'Produces auditable control evidence, traceability and evidence maps; compliance-auditor is the documenter counterpart to compliance.',\n signals: [\n 'audit',\n 'control evidence',\n 'evidence map',\n 'soc2',\n 'iso 27001',\n 'attestation',\n 'auditable',\n 'remediation tracking',\n ] as const,\n differentiatesFrom:\n 'compliance reviews the design; compliance-auditor produces traceable evidence for an external audit.',\n};\n\nconst PRIVACY_ENGINEER_META = {\n rationale:\n 'Implements data minimization, consent, retention and deletion; privacy-engineer is the implementation counterpart to compliance.',\n signals: [\n 'privacy',\n 'pii',\n 'consent',\n 'retention',\n 'deletion',\n 'data minimization',\n 'lawful basis',\n 'gdpr',\n ] as const,\n differentiatesFrom:\n 'compliance audits controls; privacy-engineer implements privacy-by-design in code and pipelines.',\n};\n\nconst PLUGIN_AUTHOR_META = {\n rationale:\n 'Builds, packages and ships runnable WrongStack plugins; plugin-author is the production counterpart to skill-manage.',\n signals: [\n 'plugin',\n 'plugin api',\n 'lifecycle',\n 'health',\n 'teardown',\n 'packaging',\n 'distribution',\n ] as const,\n differentiatesFrom:\n 'skill-manage authors skills; plugin-author authors full lifecycle plugins with health and teardown.',\n};\n\nconst TOOL_AUTHOR_META = {\n rationale:\n 'Designs tool schemas, capability declarations and error contracts; tool-author is the narrow, security-focused counterpart to plugin-author.',\n signals: [\n 'tool',\n 'tool schema',\n 'capability',\n 'permission',\n 'tool contract',\n 'tool error',\n 'tool lifecycle',\n ] as const,\n differentiatesFrom:\n 'plugin-author writes full plugin lifecycle; tool-author focuses on a single tool contract and capability set.',\n};\n\nconst PROMPT_EVALUATOR_META = {\n rationale:\n 'Builds rubrics and runs adversarial / regression tests on prompts; prompt-evaluator is the independent measurement counterpart to prompt.',\n signals: [\n 'prompt eval',\n 'prompt regression',\n 'rubric',\n 'adversarial prompt',\n 'prompt benchmark',\n 'judge prompt',\n 'eval suite',\n ] as const,\n differentiatesFrom:\n 'prompt authors prompts; prompt-evaluator independently measures them with rubrics and adversarial inputs.',\n};\n\nconst BENCHMARK_ENGINEER_META = {\n rationale:\n 'Designs reproducible benchmarks and methodology for comparing models and agent setups; benchmark-engineer is the measurement-infrastructure counterpart to performance.',\n signals: [\n 'benchmark',\n 'reproducible',\n 'evaluation harness',\n 'regression suite',\n 'metric methodology',\n 'baseline',\n 'deterministic run',\n ] as const,\n differentiatesFrom:\n 'performance optimizes product code; benchmark-engineer builds the measurement infrastructure that supports comparison.',\n};\n\nconst MEMORY_CURATOR_META = {\n rationale:\n 'Validates, merges and de-duplicates long-term memory entries with audience scope; memory-curator is the quality counterpart to context.',\n signals: [\n 'memory',\n 'curate',\n 'memory audit',\n 'memory merge',\n 'memory expiry',\n 'audience scope',\n 'memory recall quality',\n ] as const,\n differentiatesFrom:\n 'context manages the active context window; memory-curator curates the long-term memory store for accuracy.',\n};\n\nconst FLEET_COORDINATOR_META = {\n rationale:\n 'Owns job partitioning, capacity and result synthesis across many workers; fleet-coordinator is the multi-agent execution counterpart to planner.',\n signals: [\n 'fleet',\n 'fan out',\n 'parallel agents',\n 'synthesis',\n 'subagent capacity',\n 'coordinator',\n 'result aggregation',\n ] as const,\n differentiatesFrom:\n 'planner designs ordered steps for one worker; fleet-coordinator runs many workers in parallel and merges their results.',\n};\n\nexport const WAVE2_AGENTS: AgentDefinition[] = [\n {\n config: {\n id: 'threat-modeler',\n name: 'Threat Modeler',\n role: 'threat-modeler',\n tools: [...TOOLS.read, 'write', 'document'],\n prompt: agentPrompt('threat-modeler'),\n },\n budget: LIGHT_BUDGET,\n capability: {\n phase: 'review',\n summary:\n 'Models trust boundaries, abuse cases and data flow before code is written; produces a threat model with attack trees.',\n keywords: [\n ...THREAT_MODELER_META.signals,\n 'threat-modeler',\n 'trust',\n 'boundary',\n 'abuse',\n 'attack',\n 'stride',\n 'asset',\n 'adversary',\n ],\n },\n },\n {\n config: {\n id: 'secure-coding-coach',\n name: 'Secure Coding Coach',\n role: 'secure-coding-coach',\n tools: [...TOOLS.read],\n prompt: agentPrompt('secure-coding-coach'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'review',\n summary:\n 'Teaches secure patterns, produces safe defaults and walks engineers through prescriptive fixes.',\n keywords: [\n ...SECURE_CODING_COACH_META.signals,\n 'secure-coding',\n 'security-coach',\n 'hardening',\n 'safe-default',\n 'owasp',\n ],\n },\n },\n {\n config: {\n id: 'resilience-engineer',\n name: 'Resilience Engineer',\n role: 'resilience-engineer',\n tools: [...TOOLS.build, 'logs', 'observability'],\n // uniqueness guaranteed by 'observability' vs chaos-engineer's 'test'\n prompt: agentPrompt('resilience-engineer'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'verify',\n summary:\n 'Designs retry, timeout, circuit breaker, bulkhead and graceful-degradation patterns ahead of time.',\n keywords: [\n ...RESILIENCE_ENGINEER_META.signals,\n 'resilience',\n 'timeout',\n 'circuit-breaker',\n 'bulkhead',\n 'backoff',\n 'graceful',\n ],\n },\n },\n {\n config: {\n id: 'chaos-engineer',\n name: 'Chaos Engineer',\n role: 'chaos-engineer',\n tools: [...TOOLS.build, 'logs', 'observability'],\n // uniqueness guaranteed by 'observability' vs chaos-engineer's 'test'\n prompt: agentPrompt('chaos-engineer'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'verify',\n summary:\n 'Builds and runs controlled fault-injection experiments with a defined blast radius, steady state and hypothesis.',\n keywords: [\n ...CHAOS_ENGINEER_META.signals,\n 'chaos-engineer',\n 'chaos-experiment',\n 'gameday',\n 'steady-state',\n ],\n },\n },\n {\n config: {\n id: 'compliance-auditor',\n name: 'Compliance Auditor',\n role: 'compliance-auditor',\n tools: [...TOOLS.inspect],\n prompt: agentPrompt('compliance-auditor'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'review',\n summary:\n 'Produces auditable control evidence, traceability and evidence maps for SOC2, ISO and similar frameworks.',\n keywords: [\n ...COMPLIANCE_AUDITOR_META.signals,\n 'compliance-auditor',\n 'soc2',\n 'iso',\n 'evidence-map',\n 'attestation',\n 'auditable',\n ],\n },\n },\n {\n config: {\n id: 'privacy-engineer',\n name: 'Privacy Engineer',\n role: 'privacy-engineer',\n tools: [...TOOLS.build, 'audit'],\n prompt: agentPrompt('privacy-engineer'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'review',\n summary:\n 'Implements data minimization, consent, retention and deletion; privacy-by-design across the stack.',\n keywords: [\n ...PRIVACY_ENGINEER_META.signals,\n 'privacy-engineer',\n 'pii',\n 'gdpr',\n 'consent',\n 'retention',\n 'deletion',\n 'data-minimization',\n ],\n },\n },\n];\n\nexport const WAVE2_ROLE_METAS: Record<string, RoleDispatcherSignal> = {\n 'threat-modeler': THREAT_MODELER_META,\n 'secure-coding-coach': SECURE_CODING_COACH_META,\n 'resilience-engineer': RESILIENCE_ENGINEER_META,\n 'chaos-engineer': CHAOS_ENGINEER_META,\n 'compliance-auditor': COMPLIANCE_AUDITOR_META,\n 'privacy-engineer': PRIVACY_ENGINEER_META,\n 'plugin-author': PLUGIN_AUTHOR_META,\n 'tool-author': TOOL_AUTHOR_META,\n 'prompt-evaluator': PROMPT_EVALUATOR_META,\n 'benchmark-engineer': BENCHMARK_ENGINEER_META,\n 'memory-curator': MEMORY_CURATOR_META,\n 'fleet-coordinator': FLEET_COORDINATOR_META,\n};\n\nexport const WAVE2_ROLES = new Set<string>(Object.keys(WAVE2_ROLE_METAS));\n\nvoid skillSet;\n\n", "import { agentPrompt } from './agent-prompts.js';\nimport { type AgentDefinition, HEAVY_BUDGET, MEDIUM_BUDGET, TOOLS } from './types.js';\n\n/** Phase 4 \u00B7 Verify \u2014 prove the code works under normal, end-to-end, and adverse conditions. */\nexport const VERIFY_AGENTS: AgentDefinition[] = [\n {\n config: {\n id: 'verifier',\n name: 'Verifier',\n role: 'verifier',\n tools: [...TOOLS.inspect, 'bash', 'exec', 'lint', 'typecheck', 'test', 'git'],\n prompt: agentPrompt('verifier'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'verify',\n summary:\n 'Independent verification gate: runs the relevant checks until they pass or returns exact failures that need another implementation pass.',\n keywords: [\n 'verify',\n 'verification',\n 'quality gate',\n 'prove it works',\n 'run checks',\n 'run tests until pass',\n 'test pass',\n 'green build',\n 'typecheck',\n 'lint',\n 'regression check',\n 'acceptance gate',\n ],\n },\n },\n {\n config: {\n id: 'test',\n name: 'Test',\n role: 'test',\n tools: [...TOOLS.build],\n prompt: agentPrompt('test'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'verify',\n summary:\n 'Unit + integration testing: writes meaningful tests covering golden path and edge cases, runs the suite.',\n keywords: [\n 'test',\n 'unit test',\n 'integration test',\n 'write tests',\n 'coverage',\n 'test suite',\n 'vitest',\n 'jest',\n 'add tests',\n 'spec',\n ],\n },\n },\n {\n config: {\n id: 'e2e',\n name: 'E2E',\n role: 'e2e',\n tools: [\n ...TOOLS.build,\n 'fetch',\n 'playwright_navigate',\n 'playwright_screenshot',\n 'playwright_click',\n 'playwright_type',\n 'playwright_evaluate',\n 'playwright_select_option',\n 'playwright_hover',\n 'playwright_fill_form',\n 'playwright_wait_for',\n 'playwright_press_key',\n 'playwright_drag',\n ],\n prompt: agentPrompt('e2e'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'verify',\n summary:\n 'End-to-end testing: drives full user journeys across UI/CLI/API boundaries with reproducible failures.',\n keywords: [\n 'e2e',\n 'end to end',\n 'end-to-end',\n 'user journey',\n 'smoke test',\n 'playwright',\n 'browser',\n 'screenshot',\n 'web ui',\n 'headless',\n 'cypress',\n 'full flow',\n 'browser test',\n 'acceptance test',\n 'navigate',\n 'click',\n 'form fill',\n 'dom',\n 'page load',\n ],\n },\n },\n {\n config: {\n id: 'browser',\n name: 'Browser',\n role: 'browser',\n tools: [\n ...TOOLS.read,\n 'fetch',\n 'playwright_navigate',\n 'playwright_screenshot',\n 'playwright_click',\n 'playwright_type',\n 'playwright_evaluate',\n 'playwright_select_option',\n 'playwright_hover',\n 'playwright_fill_form',\n 'playwright_wait_for',\n 'playwright_press_key',\n 'playwright_drag',\n ],\n prompt: agentPrompt('browser'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'verify',\n summary:\n 'Browser automation: opens pages, clicks, types, screenshots, extracts data via Playwright headless Chromium.',\n keywords: [\n 'browser',\n 'screenshot',\n 'navigate',\n 'web page',\n 'scrape',\n 'crawl',\n 'headless',\n 'chrome',\n 'open url',\n 'capture',\n 'page title',\n 'extract data',\n 'fill form',\n 'click button',\n 'take screenshot',\n ],\n },\n },\n {\n config: {\n id: 'performance',\n name: 'Performance',\n role: 'performance',\n tools: [...TOOLS.build, 'logs'],\n prompt: agentPrompt('performance'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'verify',\n summary:\n 'Performance analysis: benchmarks/profiles to find the real bottleneck, optimizes, proves speedup with numbers.',\n keywords: [\n 'performance',\n 'slow',\n 'optimize',\n 'bottleneck',\n 'profile',\n 'benchmark',\n 'latency',\n 'throughput',\n 'memory',\n 'speed up',\n 'too slow',\n ],\n },\n },\n {\n config: {\n id: 'chaos',\n name: 'Chaos',\n role: 'chaos',\n tools: [...TOOLS.build, 'logs'],\n prompt: agentPrompt('chaos'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'verify',\n summary:\n 'Resilience testing via fault injection: breaks network/disk/timing to find ungraceful failures and recovery gaps.',\n keywords: [\n 'chaos',\n 'resilience',\n 'fault injection',\n 'failure mode',\n 'fail safe',\n 'retry',\n 'circuit breaker',\n 'graceful degradation',\n 'inject failure',\n 'robustness',\n ],\n },\n },\n {\n config: {\n id: 'security-scanner',\n name: 'Security Scanner',\n role: 'security-scanner',\n tools: [...TOOLS.inspect],\n prompt: agentPrompt('security-scanner'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'verify',\n summary:\n 'Security scanner: detects hardcoded secrets, injection vectors, insecure patterns, and supply-chain risks with remediation.',\n keywords: [\n 'security',\n 'scan',\n 'vulnerability',\n 'secret',\n 'api key',\n 'hardcoded',\n 'injection',\n 'cve',\n 'audit dependencies',\n 'supply chain',\n 'xss',\n 'sqli',\n 'shell injection',\n 'sensitive data',\n 'credential',\n ],\n },\n },\n {\n config: {\n id: 'bug-hunter',\n name: 'Bug Hunter',\n role: 'bug-hunter',\n tools: [...TOOLS.inspect],\n prompt: agentPrompt('bug-hunter'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'verify',\n summary:\n 'Bug hunter: scans source code for bugs, anti-patterns, and code smells, producing a file:line-ranked hit list with fixes.',\n keywords: [\n 'bug',\n 'hunt',\n 'scan',\n 'code smell',\n 'anti-pattern',\n 'race condition',\n 'memory leak',\n 'null deref',\n 'type safety',\n 'unhandled error',\n 'find bugs',\n 'audit code',\n 'code quality',\n ],\n },\n },\n {\n config: {\n id: 'audit-log',\n name: 'Audit Log',\n role: 'audit-log',\n tools: [...TOOLS.inspect],\n prompt: agentPrompt('audit-log'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'verify',\n summary:\n 'Audit log analyzer: parses session JSONL, detects failure patterns, tool anomalies, and cost trends with structured reports.',\n keywords: [\n 'audit',\n 'log',\n 'logs',\n 'session',\n 'trace',\n 'analyze logs',\n 'error patterns',\n 'cost analysis',\n 'tool usage',\n 'token usage',\n 'post-mortem',\n 'trend',\n 'anomaly',\n ],\n },\n },\n];\n", "import { agentPrompt } from './agent-prompts.js';\nimport { type AgentDefinition, MEDIUM_BUDGET, TOOLS } from './types.js';\n\n/** Phase 5 \u00B7 Review \u2014 read-only quality, security, a11y, and compliance gates. */\nexport const REVIEW_AGENTS: AgentDefinition[] = [\n {\n config: {\n id: 'reviewer',\n name: 'Reviewer',\n role: 'reviewer',\n tools: [...TOOLS.inspect, 'git'],\n prompt: agentPrompt('reviewer'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'review',\n summary:\n \"Independent AI reviewer: audits another agent's output, flags uncertainty, correlated-failure risk, and must-fix defects.\",\n keywords: [\n 'reviewer',\n 'independent review',\n 'ai review',\n 'review agent',\n 'quality review',\n 'second opinion',\n 'check another agent',\n 'cross check',\n 'uncertainty',\n 'correlated error',\n 'verify output',\n 'quality control',\n ],\n },\n },\n {\n config: {\n id: 'code-reviewer',\n name: 'Code Reviewer',\n role: 'code-reviewer',\n tools: [...TOOLS.inspect, 'git'],\n prompt: agentPrompt('code-reviewer'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'review',\n summary:\n 'Correctness-first code review of diffs/PRs: finds bugs, edge cases, and convention violations with fixes.',\n keywords: [\n 'review',\n 'code review',\n 'review pr',\n 'review diff',\n 'look over',\n 'feedback on code',\n 'quality',\n 'is this correct',\n 'check my code',\n ],\n },\n },\n {\n config: {\n id: 'security-reviewer',\n name: 'Security Reviewer',\n role: 'security-reviewer',\n tools: [...TOOLS.inspect, 'git'],\n prompt: agentPrompt('security-reviewer'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'review',\n summary:\n 'Security review: finds injection/authz/secret/crypto issues mapped to OWASP severity with remediation.',\n keywords: [\n 'security review',\n 'security',\n 'vulnerability',\n 'vulnerabilities',\n 'owasp',\n 'injection',\n 'sql injection',\n 'xss',\n 'ssrf',\n 'authz',\n 'secrets',\n 'security audit',\n 'threat',\n 'unsafe',\n ],\n },\n },\n {\n config: {\n id: 'accessibility',\n name: 'Accessibility',\n role: 'accessibility',\n tools: [...TOOLS.read],\n prompt: agentPrompt('accessibility'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'review',\n summary:\n 'WCAG/a11y review of UI: checks semantics, ARIA, keyboard, contrast; maps findings to success criteria.',\n keywords: [\n 'accessibility',\n 'a11y',\n 'wcag',\n 'aria',\n 'screen reader',\n 'keyboard navigation',\n 'contrast',\n 'disabled users',\n 'accessible',\n ],\n },\n },\n {\n config: {\n id: 'compliance',\n name: 'Compliance',\n role: 'compliance',\n tools: [...TOOLS.inspect],\n prompt: agentPrompt('compliance'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'review',\n summary:\n 'License/privacy/regulatory review: audits licenses, PII handling, and controls vs GDPR/SOC2.',\n keywords: [\n 'compliance',\n 'license',\n 'gdpr',\n 'soc2',\n 'privacy',\n 'pii',\n 'data retention',\n 'regulatory',\n 'audit log',\n 'legal review',\n ],\n },\n },\n];\n", "import { type AgentDefinition, HEAVY_BUDGET, MEDIUM_BUDGET, TOOLS } from './types.js';\nimport { agentPrompt } from './agent-prompts.js';\n\n/** Phase 6 \u00B7 Domain \u2014 specialists for the major slices of a system. */\nexport const DOMAIN_AGENTS: AgentDefinition[] = [\n {\n config: {\n id: 'database',\n name: 'Database',\n role: 'database',\n tools: [...TOOLS.build],\n prompt: agentPrompt('database'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'domain',\n summary: 'Schema design, query optimization, and safe reversible migrations for SQL databases.',\n keywords: [\n 'database',\n 'schema',\n 'sql',\n 'migration',\n 'query',\n 'index',\n 'postgres',\n 'mysql',\n 'table',\n 'orm',\n 'slow query',\n ],\n },\n },\n {\n config: {\n id: 'api',\n name: 'API',\n role: 'api',\n tools: [...TOOLS.build, 'fetch'],\n prompt: agentPrompt('api'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'domain',\n summary: 'REST + GraphQL API design and implementation: contracts, HTTP/GraphQL semantics, versioning.',\n keywords: [\n 'api',\n 'rest',\n 'graphql',\n 'endpoint',\n 'resolver',\n 'http',\n 'openapi',\n 'swagger',\n 'route',\n 'contract',\n 'webhook',\n ],\n },\n },\n {\n config: {\n id: 'auth',\n name: 'Auth',\n role: 'auth',\n tools: [...TOOLS.build],\n prompt: agentPrompt('auth'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'domain',\n summary: 'Authentication and authorization: identity, sessions/tokens, RBAC/ABAC, OAuth/OIDC, done securely.',\n keywords: [\n 'auth',\n 'authentication',\n 'authorization',\n 'login',\n 'session',\n 'jwt',\n 'oauth',\n 'oidc',\n 'rbac',\n 'permissions',\n 'token',\n 'sso',\n ],\n },\n },\n {\n config: {\n id: 'data',\n name: 'Data',\n role: 'data',\n tools: [...TOOLS.build],\n prompt: agentPrompt('data'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'domain',\n summary: 'Data engineering: ETL/ELT pipelines, data-quality validation, idempotent transforms, reconciliation.',\n keywords: [\n 'etl',\n 'elt',\n 'pipeline',\n 'data quality',\n 'data engineering',\n 'transform',\n 'ingestion',\n 'batch',\n 'stream',\n 'reconcile',\n 'dataset',\n ],\n },\n },\n {\n config: {\n id: 'frontend',\n name: 'Frontend',\n role: 'frontend',\n tools: [...TOOLS.build, 'fetch'],\n prompt: agentPrompt('frontend'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'domain',\n summary: 'UI implementation: components, client state, data fetching, responsive and accessible by default.',\n keywords: [\n 'frontend',\n 'component',\n 'react',\n 'vue',\n 'svelte',\n 'client state',\n 'ui implementation',\n 'css',\n 'responsive',\n 'hook',\n 'render',\n ],\n },\n },\n {\n config: {\n id: 'backend',\n name: 'Backend',\n role: 'backend',\n tools: [...TOOLS.build],\n prompt: agentPrompt('backend'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'domain',\n summary: 'Server-side logic: services, business rules, persistence/queue wiring, concurrency and transactions.',\n keywords: [\n 'backend',\n 'server',\n 'service',\n 'business logic',\n 'controller',\n 'handler',\n 'queue',\n 'cache',\n 'transaction',\n 'microservice',\n 'server-side',\n ],\n },\n },\n {\n config: {\n id: 'designer',\n name: 'Designer',\n role: 'designer',\n tools: [...TOOLS.docs],\n prompt: agentPrompt('designer'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'domain',\n summary: 'UI/UX design: user flows, layout/wireframes, interaction states, and design-system decisions.',\n keywords: [\n 'design',\n 'ux',\n 'ui design',\n 'wireframe',\n 'user flow',\n 'layout',\n 'design system',\n 'interaction',\n 'mockup design',\n 'information architecture',\n ],\n },\n },\n {\n config: {\n id: 'ios',\n name: 'iOS',\n role: 'ios',\n tools: [...TOOLS.build, 'fetch'],\n prompt: agentPrompt('ios'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'domain',\n summary:\n 'Apple-platform app development in Swift against the latest Xcode/iOS-SDK line: SwiftUI, UIKit, SwiftData, concurrency, accessibility, and App Store submission.',\n keywords: [\n 'ios',\n 'iphone',\n 'ipad',\n 'ipados',\n 'watchos',\n 'tvos',\n 'visionos',\n 'macos',\n 'swift',\n 'swiftui',\n 'uikit',\n 'xcode',\n 'swiftdata',\n 'app store',\n 'app intents',\n 'swift package manager',\n 'cocoapods',\n 'foundation models',\n ],\n },\n },\n];\n", "import { type AgentDefinition, LIGHT_BUDGET, MEDIUM_BUDGET, TOOLS } from './types.js';\nimport { agentPrompt } from './agent-prompts.js';\n\n/** Phase 7 \u00B7 Knowledge \u2014 documentation, diagrams, localization, and prompts. */\nexport const KNOWLEDGE_AGENTS: AgentDefinition[] = [\n {\n config: {\n id: 'document',\n name: 'Document',\n role: 'document',\n tools: [...TOOLS.docs],\n prompt: agentPrompt('document'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'knowledge',\n summary: 'Technical documentation: READMEs, API/reference docs, guides, and verified examples grounded in code.',\n keywords: [\n 'document',\n 'documentation',\n 'readme',\n 'docs',\n 'write up',\n 'guide',\n 'api docs',\n 'explain in writing',\n 'reference',\n 'changelog notes',\n ],\n },\n },\n {\n config: {\n id: 'uml',\n name: 'UML',\n role: 'uml',\n tools: [...TOOLS.read, 'write', 'edit'],\n prompt: agentPrompt('uml'),\n },\n budget: LIGHT_BUDGET,\n capability: {\n phase: 'knowledge',\n summary: 'Diagram generation from code: class/sequence/component/ER diagrams as Mermaid/PlantUML.',\n keywords: [\n 'uml',\n 'diagram',\n 'mermaid',\n 'plantuml',\n 'sequence diagram',\n 'class diagram',\n 'er diagram',\n 'visualize',\n 'flowchart',\n 'architecture diagram',\n ],\n },\n },\n {\n config: {\n id: 'i18n',\n name: 'I18n',\n role: 'i18n',\n tools: [...TOOLS.write],\n prompt: agentPrompt('i18n'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'knowledge',\n summary: 'Internationalization/localization: string extraction, catalog management, plurals/RTL/format handling.',\n keywords: [\n 'i18n',\n 'internationalization',\n 'localization',\n 'l10n',\n 'translation',\n 'translate ui',\n 'locale',\n 'rtl',\n 'message catalog',\n 'multilingual',\n ],\n },\n },\n {\n config: {\n id: 'prompt',\n name: 'Prompt',\n role: 'prompt',\n tools: [...TOOLS.write],\n prompt: agentPrompt('prompt'),\n },\n budget: LIGHT_BUDGET,\n capability: {\n phase: 'knowledge',\n summary: 'Prompt engineering: designs/refines/evaluates LLM system prompts and agent instructions.',\n keywords: [\n 'prompt',\n 'prompt engineering',\n 'system prompt',\n 'llm instructions',\n 'few-shot',\n 'refine prompt',\n 'agent instructions',\n 'prompt template',\n ],\n },\n },\n];\n", "import { type AgentDefinition, MEDIUM_BUDGET, TOOLS } from './types.js';\nimport { agentPrompt } from './agent-prompts.js';\n\n/** Phase 8 \u00B7 Delivery & Ops \u2014 ship it, run it, keep it healthy. */\nexport const DELIVERY_AGENTS: AgentDefinition[] = [\n {\n config: {\n id: 'git',\n name: 'Git',\n role: 'git',\n tools: [...TOOLS.vcs, 'bash'],\n prompt: agentPrompt('git'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'delivery',\n summary: 'Git automation: focused commits, branch/rebase/conflict handling, PR prep, history investigation.',\n keywords: [\n 'git',\n 'commit',\n 'branch',\n 'rebase',\n 'merge',\n 'pull request',\n 'pr',\n 'conflict',\n 'blame',\n 'bisect',\n 'cherry-pick',\n 'stash',\n ],\n },\n },\n {\n config: {\n id: 'release',\n name: 'Release',\n role: 'release',\n tools: [...TOOLS.vcs, 'bash', 'json'],\n prompt: agentPrompt('release'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'delivery',\n summary: 'Release management: semver bumps, changelogs, and release notes derived from real history.',\n keywords: [\n 'release',\n 'version',\n 'semver',\n 'changelog',\n 'release notes',\n 'tag',\n 'bump version',\n 'publish',\n 'versioning',\n ],\n },\n },\n {\n config: {\n id: 'devops',\n name: 'DevOps',\n role: 'devops',\n tools: [\n ...TOOLS.build,\n 'mcp__ssh__ssh_list_servers',\n 'mcp__ssh__ssh_connection_status',\n 'mcp__ssh__ssh_execute',\n 'mcp__ssh__ssh_execute_sudo',\n 'mcp__ssh__ssh_upload',\n 'mcp__ssh__ssh_download',\n 'mcp__ssh__ssh_sync',\n 'mcp__ssh__ssh_deploy',\n 'mcp__ssh__ssh_health_check',\n 'mcp__ssh__ssh_service_status',\n 'mcp__ssh__ssh_process_manager',\n 'mcp__ssh__ssh_tunnel',\n 'mcp__ssh__ssh_backup_create',\n 'mcp__ssh__ssh_backup_list',\n 'mcp__ssh__ssh_backup_restore',\n 'mcp__ssh__ssh_db_list',\n 'mcp__ssh__ssh_db_query',\n 'mcp__ssh__ssh_profile',\n ],\n prompt: agentPrompt('devops'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'delivery',\n summary: 'CI/CD, containerization, and deployment config: reproducible builds and safe deploys with rollback.',\n keywords: [\n 'devops',\n 'ci',\n 'cd',\n 'ci/cd',\n 'pipeline',\n 'docker',\n 'dockerfile',\n 'kubernetes',\n 'k8s',\n 'deploy',\n 'ssh',\n 'remote ssh',\n 'remote server',\n 'sftp',\n 'tunnel',\n 'bastion',\n 'jump host',\n 'github actions',\n 'container',\n ],\n },\n },\n {\n config: {\n id: 'observability',\n name: 'Observability',\n role: 'observability',\n tools: [...TOOLS.build, 'logs'],\n prompt: agentPrompt('observability'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'delivery',\n summary: 'Observability: structured logging, metrics, distributed tracing, and alerts/dashboards.',\n keywords: [\n 'observability',\n 'logging',\n 'metrics',\n 'tracing',\n 'telemetry',\n 'opentelemetry',\n 'otel',\n 'prometheus',\n 'monitoring',\n 'alert',\n 'dashboard',\n 'instrument',\n ],\n },\n },\n {\n config: {\n id: 'dependency',\n name: 'Dependency',\n role: 'dependency',\n tools: [...TOOLS.deps, 'bash'],\n prompt: agentPrompt('dependency'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'delivery',\n summary: 'Package management + supply-chain safety: CVE audit, safe upgrades, pruning, install-script review.',\n keywords: [\n 'dependency',\n 'dependencies',\n 'package',\n 'npm',\n 'pnpm',\n 'cve',\n 'vulnerability scan',\n 'upgrade deps',\n 'audit',\n 'supply chain',\n 'outdated',\n 'lockfile',\n ],\n },\n },\n];\n", "import { agentPrompt } from './agent-prompts.js';\nimport type { BundledAgentSkill } from './role-skills.js';\nimport {\n type AgentDefinition,\n type RoleDispatcherSignal,\n HEAVY_BUDGET,\n MEDIUM_BUDGET,\n TOOLS,\n} from './types.js';\n\nconst skillSet = (...names: BundledAgentSkill[]): BundledAgentSkill[] => names;\n\n/**\n * Wave 3: Product and data specialists.\n *\n * Six roles that own areas the existing 51-role catalog only touches\n * generically. Each carries an explicit `RoleDispatcherSignal` so the\n * dispatcher can disambiguate from close siblings.\n */\n\nconst PAYMENTS_META = {\n rationale:\n 'Payments specialist: ledger, refund, webhook, idempotency, reconciliation. Financial correctness is too domain-specific to leave to a general backend role.',\n signals: [\n 'payments',\n 'ledger',\n 'refund',\n 'webhook',\n 'idempotency',\n 'reconciliation',\n 'pci',\n 'currency',\n ] as const,\n differentiatesFrom:\n 'backend builds services; payments owns the financial-correctness invariants and money-handling patterns.',\n} satisfies RoleDispatcherSignal;\n\nconst MESSAGING_META = {\n rationale:\n 'Messaging infrastructure specialist: queue, pub/sub, delivery semantics, DLQ. Owns distributed-messaging failure modes that the distributed-systems role designs but does not implement.',\n signals: [\n 'messaging',\n 'queue',\n 'pubsub',\n 'dead letter',\n 'dlq',\n 'delivery semantics',\n 'at-least-once',\n 'at-most-once',\n 'kafka',\n ] as const,\n differentiatesFrom:\n 'distributed-systems designs the failure semantics; messaging implements the broker and consumer infrastructure.',\n} satisfies RoleDispatcherSignal;\n\nconst SEARCH_RELEVANCE_META = {\n rationale:\n 'Search relevance specialist: indexing, ranking, retrieval, evaluation. Owns the offline and online quality metrics that a generic database role does not.',\n signals: [\n 'search',\n 'search relevance',\n 'ranking',\n 'retrieval',\n 'indexing',\n 'recall',\n 'precision',\n 'reranker',\n ] as const,\n differentiatesFrom:\n 'database stores rows; search-relevance owns the ranking, retrieval and relevance-evaluation pipeline.',\n} satisfies RoleDispatcherSignal;\n\nconst STORAGE_META = {\n rationale:\n 'Object-storage specialist: upload, checksum, lifecycle, CDN. Owns the durability and replication boundaries of blob data.',\n signals: [\n 'object storage',\n 'blob',\n 'upload',\n 'checksum',\n 'lifecycle',\n 'cdn',\n 'presigned url',\n 'multipart upload',\n ] as const,\n differentiatesFrom:\n 'database owns structured rows; storage owns unstructured blob lifecycle and replication.',\n} satisfies RoleDispatcherSignal;\n\nconst ML_ENGINEER_META = {\n rationale:\n 'ML engineer: model integration, inference, evaluation, guardrail. The catalog has no existing ML-application specialist.',\n signals: [\n 'ml',\n 'machine learning',\n 'inference',\n 'embedding',\n 'model evaluation',\n 'guardrail',\n 'llm evaluation',\n ] as const,\n differentiatesFrom:\n 'data builds pipelines; ml-engineer integrates models, evaluates them and wires guardrails.',\n} satisfies RoleDispatcherSignal;\n\nconst DATA_GOVERNANCE_META = {\n rationale:\n 'Data governance specialist: lineage, classification, ownership, data contracts. Owns accountability and quality-of-record for data assets.',\n signals: [\n 'data governance',\n 'lineage',\n 'classification',\n 'ownership',\n 'data contract',\n 'data quality',\n 'retention policy',\n ] as const,\n differentiatesFrom:\n 'data builds pipelines; data-governance owns accountability, lineage and the data contracts that bind them.',\n} satisfies RoleDispatcherSignal;\n\nexport const WAVE3_AGENTS: AgentDefinition[] = [\n {\n config: {\n id: 'payments',\n name: 'Payments',\n role: 'payments',\n tools: [...new Set([...TOOLS.build, ...TOOLS.write, ...TOOLS.inspect, 'fetch'])],\n prompt: agentPrompt('payments'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'domain',\n summary:\n 'Payments specialist: ledger, refund, webhook, idempotency and reconciliation with financial-correctness invariants.',\n keywords: [\n ...PAYMENTS_META.signals,\n 'payments',\n 'ledger',\n 'refund',\n 'webhook',\n 'idempotency',\n 'pci',\n ],\n },\n },\n {\n config: {\n id: 'messaging',\n name: 'Messaging',\n role: 'messaging',\n tools: [...TOOLS.build, 'logs', 'observability'],\n prompt: agentPrompt('messaging'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'domain',\n summary:\n 'Messaging infrastructure specialist: queue, pub/sub, delivery semantics and DLQ with broker failure modes.',\n keywords: [\n ...MESSAGING_META.signals,\n 'messaging',\n 'queue',\n 'pubsub',\n 'dlq',\n 'kafka',\n 'rabbitmq',\n ],\n },\n },\n {\n config: {\n id: 'search-relevance',\n name: 'Search Relevance',\n role: 'search-relevance',\n tools: [...TOOLS.build, 'logs'],\n prompt: agentPrompt('search-relevance'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'domain',\n summary:\n 'Search relevance specialist: indexing, ranking, retrieval and offline/online evaluation of search quality.',\n keywords: [\n ...SEARCH_RELEVANCE_META.signals,\n 'search',\n 'ranking',\n 'retrieval',\n 'indexing',\n 'recall',\n 'rerank',\n ],\n },\n },\n {\n config: {\n id: 'storage',\n name: 'Storage',\n role: 'storage',\n tools: [...TOOLS.build, 'fetch', 'logs'],\n prompt: agentPrompt('storage'),\n },\n budget: HEAVY_BUDGET,\n capability: {\n phase: 'domain',\n summary:\n 'Object-storage specialist: upload, checksum, lifecycle, CDN and replication for unstructured blob data.',\n keywords: [\n ...STORAGE_META.signals,\n 'object-storage',\n 'blob',\n 'upload',\n 'checksum',\n 'lifecycle',\n 'cdn',\n ],\n },\n },\n {\n config: {\n id: 'ml-engineer',\n name: 'ML Engineer',\n role: 'ml-engineer',\n tools: [...TOOLS.build, 'logs'],\n prompt: agentPrompt('ml-engineer'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'domain',\n summary:\n 'ML engineer: model integration, inference, evaluation and guardrail wiring.',\n keywords: [\n ...ML_ENGINEER_META.signals,\n 'ml',\n 'inference',\n 'embedding',\n 'guardrail',\n 'llm-eval',\n ],\n },\n },\n {\n config: {\n id: 'data-governance',\n name: 'Data Governance',\n role: 'data-governance',\n tools: [...TOOLS.read, 'write', 'audit'],\n prompt: agentPrompt('data-governance'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'domain',\n summary:\n 'Data governance specialist: lineage, classification, ownership and data contracts with quality-of-record.',\n keywords: [\n ...DATA_GOVERNANCE_META.signals,\n 'data-governance',\n 'lineage',\n 'classification',\n 'data-contract',\n 'retention',\n ],\n },\n },\n];\n\nexport const WAVE3_ROLE_METAS: Record<string, RoleDispatcherSignal> = {\n payments: PAYMENTS_META,\n messaging: MESSAGING_META,\n 'search-relevance': SEARCH_RELEVANCE_META,\n storage: STORAGE_META,\n 'ml-engineer': ML_ENGINEER_META,\n 'data-governance': DATA_GOVERNANCE_META,\n};\n\nexport const WAVE3_ROLES = new Set<string>(Object.keys(WAVE3_ROLE_METAS));\n\nvoid skillSet;\n", "import { type AgentDefinition, LIGHT_BUDGET, MEDIUM_BUDGET, TOOLS } from './types.js';\nimport { agentPrompt } from './agent-prompts.js';\n\n/** Phase 9 \u00B7 Meta \u2014 agents that improve the agent system itself. */\nexport const META_AGENTS: AgentDefinition[] = [\n {\n config: {\n id: 'skill-manage',\n name: 'Skill Manager',\n role: 'skill-manage',\n tools: [...TOOLS.write],\n prompt: agentPrompt('skill-manage'),\n },\n budget: LIGHT_BUDGET,\n capability: {\n phase: 'meta',\n summary: 'Skill curation: audits, refines descriptions/triggers, scaffolds, and retires skills.',\n keywords: [\n 'skill',\n 'skills',\n 'curate skill',\n 'skill description',\n 'create skill',\n 'skill library',\n 'skill trigger',\n 'manage skills',\n ],\n },\n },\n {\n config: {\n id: 'self-improving',\n name: 'Self-Improving',\n role: 'self-improving',\n tools: [...TOOLS.inspect],\n prompt: agentPrompt('self-improving'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'meta',\n summary: 'Learns from execution logs: mines recurring failures/inefficiencies and proposes evidence-based improvements.',\n keywords: [\n 'self-improving',\n 'learn from',\n 'session logs',\n 'execution analysis',\n 'recurring failure',\n 'improve agents',\n 'post-mortem',\n 'retrospective',\n 'meta-analysis',\n ],\n },\n },\n {\n config: {\n id: 'context',\n name: 'Context',\n role: 'context',\n tools: [...TOOLS.inspect, 'remember', 'forget'],\n prompt: agentPrompt('context'),\n },\n budget: LIGHT_BUDGET,\n capability: {\n phase: 'meta',\n summary: 'Memory + context-window management: compaction, recall, and curation within a token budget.',\n keywords: [\n 'context',\n 'context window',\n 'memory',\n 'compact',\n 'summarize history',\n 'recall',\n 'token budget',\n 'prune context',\n 'remember',\n 'dfmt',\n ],\n },\n },\n {\n config: {\n id: 'cost',\n name: 'Cost',\n role: 'cost',\n tools: [...TOOLS.inspect],\n prompt: agentPrompt('cost'),\n },\n budget: LIGHT_BUDGET,\n capability: {\n phase: 'meta',\n summary: 'Token/cloud cost optimization: finds spend waste, recommends model routing and trimming with $ estimates.',\n keywords: [\n 'cost',\n 'token cost',\n 'optimize cost',\n 'spend',\n 'cheaper',\n 'model routing',\n 'budget',\n 'expensive',\n 'reduce tokens',\n 'pricing',\n 'cloud cost',\n ],\n },\n },\n {\n config: {\n id: 'tech-stack',\n name: 'Tech Stack Validator',\n role: 'tech-stack',\n tools: ['search', 'fetch', 'read', 'grep', 'glob', 'outdated', 'audit', 'json', 'mailbox'],\n prompt: agentPrompt('tech-stack'),\n },\n budget: {\n timeoutMs: 120_000,\n maxIterations: 10,\n maxToolCalls: 40,\n maxTokens: 60_000,\n maxCostUsd: 0.25,\n },\n capability: {\n phase: 'meta',\n summary: 'Single-shot tech stack validator: checks npm for latest versions, rejects dead/obsolete packages, enforces modern alternatives.',\n keywords: [\n 'tech stack',\n 'version',\n 'package',\n 'library',\n 'framework',\n 'dependency',\n 'install',\n 'upgrade',\n 'latest',\n 'npm',\n 'pnpm add',\n 'outdated',\n 'obsolete',\n 'deprecated',\n 'what version',\n 'which package',\n 'check version',\n 'verify version',\n 'is this current',\n ],\n },\n },\n];\n", "import { agentPrompt } from './agent-prompts.js';\nimport type { BundledAgentSkill } from './role-skills.js';\nimport {\n type AgentDefinition,\n type RoleDispatcherSignal,\n LIGHT_BUDGET,\n MEDIUM_BUDGET,\n TOOLS,\n} from './types.js';\n\nconst skillSet = (...names: BundledAgentSkill[]): BundledAgentSkill[] => names;\n\n/**\n * Wave 4: Agent platform and quality.\n *\n * Six roles that improve the agent system itself. The existing\n * `skill-manage`, `self-improving`, `context`, `cost` and `tech-stack` roles\n * are kept; the new roles focus on quality measurement and the platform\n * surface that the host exposes to extensions.\n */\n\nconst PROMPT_evaluator_META = {\n rationale:\n 'Prompt evaluator: builds rubrics, adversarial tests and regression suites. Independent measurement counterpart to the `prompt` author role.',\n signals: [\n 'prompt eval',\n 'prompt regression',\n 'rubric',\n 'adversarial prompt',\n 'prompt benchmark',\n 'judge prompt',\n 'eval suite',\n ] as const,\n differentiatesFrom:\n 'prompt authors prompts; prompt-evaluator independently measures them with rubrics and adversarial inputs.',\n} satisfies RoleDispatcherSignal;\n\nconst BENCHMARK_ENGINEER_META = {\n rationale:\n 'Benchmark engineer: reproducible benchmark design and methodology. The measurement-infrastructure counterpart to `performance`.',\n signals: [\n 'benchmark',\n 'reproducible',\n 'evaluation harness',\n 'regression suite',\n 'metric methodology',\n 'baseline',\n 'deterministic run',\n ] as const,\n differentiatesFrom:\n 'performance optimizes product code; benchmark-engineer builds the measurement infrastructure that supports comparison.',\n} satisfies RoleDispatcherSignal;\n\nconst MEMORY_CURATOR_META = {\n rationale:\n 'Memory curator: validates, merges and de-duplicates long-term memory with audience scope. Quality counterpart to `context`.',\n signals: [\n 'memory',\n 'curate',\n 'memory audit',\n 'memory merge',\n 'memory expiry',\n 'audience scope',\n 'memory recall quality',\n ] as const,\n differentiatesFrom:\n 'context manages the active context window; memory-curator curates the long-term memory store for accuracy.',\n} satisfies RoleDispatcherSignal;\n\nconst FLEET_COORDINATOR_META = {\n rationale:\n 'Fleet coordinator: multi-agent job partitioning, capacity planning and result synthesis. Operational counterpart to `planner`.',\n signals: [\n 'fleet',\n 'fan out',\n 'parallel agents',\n 'synthesis',\n 'subagent capacity',\n 'coordinator',\n 'result aggregation',\n ] as const,\n differentiatesFrom:\n 'planner designs ordered steps for one worker; fleet-coordinator runs many workers in parallel and merges their results.',\n} satisfies RoleDispatcherSignal;\n\nconst PLUGIN_AUTHOR_META = {\n rationale:\n 'Plugin author: build, package and ship runnable WrongStack plugins. The production counterpart to `skill-manage`.',\n signals: [\n 'plugin',\n 'plugin api',\n 'lifecycle',\n 'health',\n 'teardown',\n 'packaging',\n 'distribution',\n ] as const,\n differentiatesFrom:\n 'skill-manage authors skills; plugin-author authors full lifecycle plugins with health and teardown.',\n} satisfies RoleDispatcherSignal;\n\nconst TOOL_AUTHOR_META = {\n rationale:\n 'Tool author: tool schema, capability declaration, permission and error contract. The narrow, security-focused counterpart to `plugin-author`.',\n signals: [\n 'tool',\n 'tool schema',\n 'capability',\n 'permission',\n 'tool contract',\n 'tool error',\n 'tool lifecycle',\n ] as const,\n differentiatesFrom:\n 'plugin-author writes full plugin lifecycle; tool-author focuses on a single tool contract and capability set.',\n} satisfies RoleDispatcherSignal;\n\nexport const WAVE4_AGENTS: AgentDefinition[] = [\n {\n config: {\n id: 'plugin-author',\n name: 'Plugin Author',\n role: 'plugin-author',\n tools: [...TOOLS.write, 'fetch'],\n prompt: agentPrompt('plugin-author'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'meta',\n summary:\n 'Plugin author: build, package and ship runnable WrongStack plugins with full lifecycle, health and teardown.',\n keywords: [\n ...PLUGIN_AUTHOR_META.signals,\n 'plugin',\n 'plugin-author',\n 'lifecycle',\n 'health',\n 'teardown',\n 'plugin-packaging',\n ],\n },\n },\n {\n config: {\n id: 'tool-author',\n name: 'Tool Author',\n role: 'tool-author',\n tools: [...TOOLS.write, 'install'],\n prompt: agentPrompt('tool-author'),\n },\n budget: LIGHT_BUDGET,\n capability: {\n phase: 'meta',\n summary:\n 'Tool author: design tool schemas, capability declarations, permissions and error contracts with security as the first concern.',\n keywords: [\n ...TOOL_AUTHOR_META.signals,\n 'tool',\n 'tool-author',\n 'capability',\n 'permission',\n 'tool-schema',\n 'tool-error',\n ],\n },\n },\n {\n config: {\n id: 'prompt-evaluator',\n name: 'Prompt Evaluator',\n role: 'prompt-evaluator',\n tools: [...TOOLS.read, 'write'],\n prompt: agentPrompt('prompt-evaluator'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'meta',\n summary:\n 'Prompt evaluator: build rubrics, adversarial prompt tests and regression suites for independent measurement.',\n keywords: [\n ...PROMPT_evaluator_META.signals,\n 'prompt-evaluator',\n 'rubric',\n 'adversarial',\n 'regression',\n 'judge',\n ],\n },\n },\n {\n config: {\n id: 'benchmark-engineer',\n name: 'Benchmark Engineer',\n role: 'benchmark-engineer',\n tools: [...TOOLS.read, 'write', 'logs'],\n prompt: agentPrompt('benchmark-engineer'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'meta',\n summary:\n 'Benchmark engineer: design reproducible benchmarks and methodology with deterministic baselines.',\n keywords: [\n ...BENCHMARK_ENGINEER_META.signals,\n 'benchmark-engineer',\n 'benchmark',\n 'baseline',\n 'eval-harness',\n 'deterministic',\n ],\n },\n },\n {\n config: {\n id: 'memory-curator',\n name: 'Memory Curator',\n role: 'memory-curator',\n tools: [...TOOLS.read, 'memory'],\n prompt: agentPrompt('memory-curator'),\n },\n budget: LIGHT_BUDGET,\n capability: {\n phase: 'meta',\n summary:\n 'Memory curator: validate, merge and de-duplicate long-term memory entries with audience scoping.',\n keywords: [\n ...MEMORY_CURATOR_META.signals,\n 'memory-curator',\n 'curate',\n 'memory-audit',\n 'memory-merge',\n 'audience-scope',\n ],\n },\n },\n {\n config: {\n id: 'fleet-coordinator',\n name: 'Fleet Coordinator',\n role: 'fleet-coordinator',\n tools: [...TOOLS.read, 'plan', 'multi-agent'],\n prompt: agentPrompt('fleet-coordinator'),\n },\n budget: MEDIUM_BUDGET,\n capability: {\n phase: 'meta',\n summary:\n 'Fleet coordinator: own multi-agent job partitioning, capacity planning and result synthesis across many parallel workers.',\n keywords: [\n ...FLEET_COORDINATOR_META.signals,\n 'fleet-coordinator',\n 'fan-out',\n 'parallel',\n 'synthesis',\n 'subagent-capacity',\n ],\n },\n },\n];\n\nexport const WAVE4_ROLE_METAS: Record<string, RoleDispatcherSignal> = {\n 'plugin-author': PLUGIN_AUTHOR_META,\n 'tool-author': TOOL_AUTHOR_META,\n 'prompt-evaluator': PROMPT_evaluator_META,\n 'benchmark-engineer': BENCHMARK_ENGINEER_META,\n 'memory-curator': MEMORY_CURATOR_META,\n 'fleet-coordinator': FLEET_COORDINATOR_META,\n};\n\nexport const WAVE4_ROLES = new Set<string>(Object.keys(WAVE4_ROLE_METAS));\n\nvoid skillSet;\n", "import type { AgentDefinition } from './types.js';\n\n/**\n * Bundled skills currently assigned to built-in roster agents.\n *\n * Keeping this list explicit makes role assignments auditable and prevents a\n * typo from silently degrading a worker into its persona-only fallback.\n */\nconst BUNDLED_AGENT_SKILLS = [\n 'api-design',\n 'audit-log',\n 'bug-hunter',\n 'chimera',\n 'data-governance',\n 'docker-deploy',\n 'git-flow',\n 'mnemosyne',\n 'multi-agent',\n 'node-modern',\n 'observability',\n 'output-standards',\n 'plugin-author',\n 'prompt-engineering',\n 'react-modern',\n 'refactor-planner',\n 'research-web',\n 'sdd',\n 'security-scanner',\n 'skill-creator',\n 'tech-stack',\n 'testing',\n 'typescript-strict',\n 'wrongstack-mailbox',\n] as const;\n\nexport type BundledAgentSkill = (typeof BUNDLED_AGENT_SKILLS)[number];\n\nconst skillSet = (...names: BundledAgentSkill[]): BundledAgentSkill[] => names;\n\n/**\n * Curated cross-disciplinary skill sets for every catalog role.\n *\n * A role prompt supplies the specialist persona; these skills add reusable\n * methods and safety rails from adjacent disciplines. Sets intentionally mix\n * domain knowledge, verification, security, and delivery rather than merely\n * repeating the role name.\n */\nexport const ROLE_SKILL_SETS = {\n explore: skillSet('research-web', 'node-modern', 'typescript-strict'),\n search: skillSet('bug-hunter', 'typescript-strict', 'research-web'),\n research: skillSet('research-web', 'tech-stack', 'security-scanner', 'api-design'),\n\n analyst: skillSet('sdd', 'api-design', 'testing', 'security-scanner'),\n planner: skillSet('sdd', 'multi-agent', 'refactor-planner', 'testing'),\n architect: skillSet('sdd', 'api-design', 'refactor-planner', 'security-scanner', 'observability'),\n critic: skillSet('chimera', 'bug-hunter', 'security-scanner', 'refactor-planner'),\n 'refactor-planner': skillSet(\n 'refactor-planner',\n 'sdd',\n 'typescript-strict',\n 'testing',\n 'bug-hunter',\n ),\n\n executor: skillSet('sdd', 'typescript-strict', 'node-modern', 'testing', 'git-flow'),\n refactor: skillSet('refactor-planner', 'typescript-strict', 'testing', 'bug-hunter'),\n simplifier: skillSet('bug-hunter', 'typescript-strict', 'testing', 'refactor-planner'),\n migration: skillSet('tech-stack', 'node-modern', 'typescript-strict', 'testing', 'git-flow'),\n vision: skillSet('react-modern', 'testing', 'typescript-strict', 'security-scanner'),\n debugger: skillSet('bug-hunter', 'testing', 'typescript-strict', 'observability', 'audit-log'),\n tracer: skillSet('observability', 'audit-log', 'bug-hunter', 'testing'),\n\n verifier: skillSet('testing', 'typescript-strict', 'security-scanner', 'chimera'),\n test: skillSet('testing', 'typescript-strict', 'bug-hunter', 'security-scanner'),\n e2e: skillSet('testing', 'react-modern', 'api-design', 'security-scanner'),\n browser: skillSet('testing', 'react-modern', 'security-scanner', 'research-web'),\n performance: skillSet('observability', 'testing', 'node-modern', 'audit-log'),\n chaos: skillSet('testing', 'observability', 'security-scanner', 'audit-log'),\n 'security-scanner': skillSet('security-scanner', 'bug-hunter', 'api-design', 'tech-stack'),\n 'bug-hunter': skillSet('bug-hunter', 'typescript-strict', 'testing', 'security-scanner'),\n 'audit-log': skillSet('audit-log', 'observability', 'bug-hunter', 'output-standards'),\n\n reviewer: skillSet('chimera', 'bug-hunter', 'security-scanner', 'testing'),\n 'code-reviewer': skillSet('chimera', 'bug-hunter', 'typescript-strict', 'testing'),\n 'security-reviewer': skillSet('security-scanner', 'chimera', 'api-design', 'tech-stack'),\n accessibility: skillSet('react-modern', 'testing', 'chimera', 'security-scanner'),\n compliance: skillSet('security-scanner', 'audit-log', 'tech-stack', 'chimera'),\n\n database: skillSet('api-design', 'testing', 'security-scanner', 'observability'),\n api: skillSet('api-design', 'typescript-strict', 'node-modern', 'testing', 'security-scanner'),\n auth: skillSet('security-scanner', 'api-design', 'testing', 'typescript-strict', 'audit-log'),\n data: skillSet('typescript-strict', 'testing', 'observability', 'security-scanner'),\n frontend: skillSet('react-modern', 'typescript-strict', 'testing', 'security-scanner'),\n backend: skillSet('node-modern', 'typescript-strict', 'api-design', 'testing', 'observability'),\n designer: skillSet('react-modern', 'prompt-engineering', 'research-web', 'output-standards'),\n ios: skillSet('sdd', 'testing', 'security-scanner', 'research-web'),\n\n document: skillSet('output-standards', 'research-web', 'api-design', 'prompt-engineering'),\n uml: skillSet('sdd', 'refactor-planner', 'api-design', 'output-standards'),\n i18n: skillSet('react-modern', 'testing', 'typescript-strict', 'output-standards'),\n prompt: skillSet('prompt-engineering', 'skill-creator', 'output-standards', 'testing'),\n\n git: skillSet('git-flow', 'chimera', 'testing', 'security-scanner'),\n release: skillSet('git-flow', 'tech-stack', 'chimera', 'security-scanner'),\n devops: skillSet('docker-deploy', 'observability', 'security-scanner', 'git-flow', 'tech-stack'),\n observability: skillSet('observability', 'node-modern', 'testing', 'audit-log'),\n dependency: skillSet('tech-stack', 'security-scanner', 'node-modern', 'git-flow'),\n\n 'skill-manage': skillSet(\n 'skill-creator',\n 'prompt-engineering',\n 'security-scanner',\n 'output-standards',\n ),\n 'self-improving': skillSet(\n 'audit-log',\n 'mnemosyne',\n 'prompt-engineering',\n 'bug-hunter',\n 'observability',\n ),\n context: skillSet('mnemosyne', 'output-standards', 'prompt-engineering', 'audit-log'),\n cost: skillSet('audit-log', 'tech-stack', 'observability', 'research-web'),\n 'tech-stack': skillSet('tech-stack', 'research-web', 'security-scanner', 'node-modern'),\n\n // \u2500\u2500 Wave 1: Platform and systems engineering \u2500\u2500\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 android: skillSet('react-modern', 'typescript-strict', 'testing', 'security-scanner', 'tech-stack'),\n desktop: skillSet('node-modern', 'typescript-strict', 'testing', 'security-scanner', 'tech-stack'),\n realtime: skillSet(\n 'api-design',\n 'observability',\n 'node-modern',\n 'typescript-strict',\n 'testing',\n 'tech-stack',\n ),\n 'distributed-systems': skillSet(\n 'api-design',\n 'observability',\n 'typescript-strict',\n 'testing',\n 'security-scanner',\n 'tech-stack',\n ),\n concurrency: skillSet(\n 'bug-hunter',\n 'typescript-strict',\n 'testing',\n 'observability',\n 'node-modern',\n 'tech-stack',\n ),\n 'platform-engineer': skillSet(\n 'node-modern',\n 'typescript-strict',\n 'git-flow',\n 'docker-deploy',\n 'tech-stack',\n ),\n\n // \u2500\u2500 Wave 3: Product and data specialists \u2500\u2500\u2500\u2500\u2500\u2500\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 payments: skillSet(\n 'api-design',\n 'security-scanner',\n 'audit-log',\n 'testing',\n 'typescript-strict',\n 'tech-stack',\n ),\n messaging: skillSet(\n 'api-design',\n 'observability',\n 'node-modern',\n 'testing',\n 'security-scanner',\n 'tech-stack',\n ),\n 'search-relevance': skillSet(\n 'api-design',\n 'observability',\n 'testing',\n 'typescript-strict',\n 'data-governance',\n 'tech-stack',\n ),\n storage: skillSet(\n 'api-design',\n 'security-scanner',\n 'testing',\n 'observability',\n 'node-modern',\n 'tech-stack',\n ),\n 'ml-engineer': skillSet(\n 'observability',\n 'typescript-strict',\n 'testing',\n 'security-scanner',\n 'data-governance',\n 'tech-stack',\n ),\n 'data-governance': skillSet(\n 'audit-log',\n 'security-scanner',\n 'observability',\n 'testing',\n 'output-standards',\n 'tech-stack',\n ),\n\n // \u2500\u2500 Wave 4: Agent platform and quality \u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 'plugin-author': skillSet(\n 'plugin-author',\n 'node-modern',\n 'typescript-strict',\n 'testing',\n 'security-scanner',\n 'tech-stack',\n ),\n 'tool-author': skillSet(\n 'typescript-strict',\n 'security-scanner',\n 'testing',\n 'output-standards',\n 'tech-stack',\n ),\n 'prompt-evaluator': skillSet(\n 'prompt-engineering',\n 'testing',\n 'output-standards',\n 'security-scanner',\n 'tech-stack',\n ),\n 'benchmark-engineer': skillSet(\n 'observability',\n 'testing',\n 'output-standards',\n 'tech-stack',\n ),\n 'memory-curator': skillSet(\n 'mnemosyne',\n 'audit-log',\n 'testing',\n 'output-standards',\n 'tech-stack',\n ),\n 'fleet-coordinator': skillSet(\n 'multi-agent',\n 'sdd',\n 'output-standards',\n 'testing',\n 'tech-stack',\n ),\n\n // \u2500\u2500 Wave 2: Security, resilience, governance and agent platform \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n 'threat-modeler': skillSet(\n 'security-scanner',\n 'api-design',\n 'tech-stack',\n 'audit-log',\n 'testing',\n ),\n 'secure-coding-coach': skillSet(\n 'security-scanner',\n 'testing',\n 'typescript-strict',\n 'api-design',\n 'tech-stack',\n ),\n 'resilience-engineer': skillSet(\n 'observability',\n 'testing',\n 'typescript-strict',\n 'api-design',\n 'tech-stack',\n ),\n 'chaos-engineer': skillSet(\n 'observability',\n 'testing',\n 'security-scanner',\n 'git-flow',\n 'tech-stack',\n ),\n 'compliance-auditor': skillSet(\n 'audit-log',\n 'security-scanner',\n 'output-standards',\n 'testing',\n 'tech-stack',\n ),\n 'privacy-engineer': skillSet(\n 'security-scanner',\n 'audit-log',\n 'api-design',\n 'data-governance',\n 'tech-stack',\n ),\n} as const satisfies Record<string, readonly BundledAgentSkill[]>;\n\nexport type CatalogRoleWithSkills = keyof typeof ROLE_SKILL_SETS;\n\n/** Standalone operational role that lives outside the phase catalog. */\nexport const SHADOW_AGENT_SKILLS = skillSet(\n 'wrongstack-mailbox',\n 'multi-agent',\n 'audit-log',\n 'observability',\n 'security-scanner',\n);\n\n/** Attach a fresh skill-name array so catalog templates remain mutation-safe. */\nexport function assignSkillsToAgents(definitions: readonly AgentDefinition[]): AgentDefinition[] {\n return definitions.map((definition) => {\n const role = definition.config.role;\n if (!role || !Object.hasOwn(ROLE_SKILL_SETS, role)) {\n throw new Error(\n `Missing curated skill set for roster role: \"${role ?? definition.config.name}\"`,\n );\n }\n const skills = ROLE_SKILL_SETS[role as CatalogRoleWithSkills];\n return {\n ...definition,\n config: {\n ...definition.config,\n skillNames: [...skills],\n },\n };\n });\n}\n", "/**\n * Agent catalog aggregator.\n *\n * Collects every phase's `AgentDefinition[]` into:\n * - `ALL_AGENT_DEFINITIONS` \u2014 flat list, catalog order (phase 1 \u2192 9 + waves)\n * - `AGENT_CATALOG` \u2014 keyed by role for O(1) lookup\n * - `AGENTS_BY_PHASE` \u2014 grouped for statusline / dispatcher tie-breaks\n *\n * `fleet.ts` derives `FLEET_ROSTER` + `FLEET_ROSTER_BUDGETS` from this, and the\n * dispatcher routes free-form tasks against `capability` metadata here.\n */\n\nimport { DISCOVERY_AGENTS } from './phase1-discovery.js';\nimport { PLANNING_AGENTS } from './phase2-planning.js';\nimport { BUILD_AGENTS } from './phase3-build.js';\nimport { WAVE1_AGENTS } from './phase3-wave1-platform.js';\nimport { WAVE2_AGENTS } from './phase3-wave2-meta.js';\nimport { VERIFY_AGENTS } from './phase4-verify.js';\nimport { REVIEW_AGENTS } from './phase5-review.js';\nimport { DOMAIN_AGENTS } from './phase6-domain.js';\nimport { KNOWLEDGE_AGENTS } from './phase7-knowledge.js';\nimport { DELIVERY_AGENTS } from './phase8-delivery.js';\nimport { WAVE3_AGENTS } from './phase8-wave3-products.js';\nimport { META_AGENTS } from './phase9-meta.js';\nimport { WAVE4_AGENTS } from './phase9-wave4-platform-meta.js';\nimport { ROLE_SKILL_SETS, SHADOW_AGENT_SKILLS, assignSkillsToAgents } from './role-skills.js';\nimport type { AgentDefinition, AgentPhase } from './types.js';\n\nexport * from './role-skills.js';\nexport * from './types.js';\nexport * from './phase3-wave1-platform.js';\nexport * from './phase3-wave2-meta.js';\nexport * from './phase8-wave3-products.js';\nexport * from './phase9-wave4-platform-meta.js';\nexport * from './project-agent-identity.js';\nexport {\n BUILD_AGENTS,\n DELIVERY_AGENTS,\n DISCOVERY_AGENTS,\n DOMAIN_AGENTS,\n KNOWLEDGE_AGENTS,\n META_AGENTS,\n PLANNING_AGENTS,\n REVIEW_AGENTS,\n VERIFY_AGENTS,\n WAVE1_AGENTS,\n WAVE2_AGENTS,\n WAVE3_AGENTS,\n WAVE4_AGENTS,\n};\n\n/** Every catalog agent, in phase order, enriched with its curated skills. */\nexport const ALL_AGENT_DEFINITIONS: AgentDefinition[] = assignSkillsToAgents([\n ...DISCOVERY_AGENTS,\n ...PLANNING_AGENTS,\n ...BUILD_AGENTS,\n ...WAVE1_AGENTS,\n ...WAVE2_AGENTS,\n ...VERIFY_AGENTS,\n ...REVIEW_AGENTS,\n ...DOMAIN_AGENTS,\n ...KNOWLEDGE_AGENTS,\n ...DELIVERY_AGENTS,\n ...WAVE3_AGENTS,\n ...META_AGENTS,\n ...WAVE4_AGENTS,\n]);\n\n/** Phase \u2192 its enriched agents, for grouped display and dispatcher fallbacks. */\nconst agentsInPhase = (phase: AgentPhase): AgentDefinition[] =>\n ALL_AGENT_DEFINITIONS.filter((definition) => definition.capability.phase === phase);\n\nexport const AGENTS_BY_PHASE = {\n discovery: agentsInPhase('discovery'),\n planning: agentsInPhase('planning'),\n build: agentsInPhase('build'),\n verify: agentsInPhase('verify'),\n review: agentsInPhase('review'),\n domain: agentsInPhase('domain'),\n knowledge: agentsInPhase('knowledge'),\n delivery: agentsInPhase('delivery'),\n meta: agentsInPhase('meta'),\n} satisfies Record<AgentPhase, AgentDefinition[]>;\n\n/**\n * Role \u2192 definition. Built once at module load. Throws on a duplicate role so\n * a copy-paste collision fails loudly at startup instead of silently shadowing.\n */\nexport const AGENT_CATALOG: Record<string, AgentDefinition> = (() => {\n const map: Record<string, AgentDefinition> = {};\n for (const def of ALL_AGENT_DEFINITIONS) {\n const role = def.config.role;\n if (!role) {\n throw new Error(`Agent \"${def.config.name}\" is missing a role`);\n }\n if (map[role]) {\n throw new Error(`Duplicate agent role in catalog: \"${role}\"`);\n }\n map[role] = def;\n }\n return map;\n})();\n\n/** Role lookup helper. Returns undefined for unknown roles. */\nexport function getAgentDefinition(role: string): AgentDefinition | undefined {\n return AGENT_CATALOG[role];\n}\n\n// Re-export the skill-set aliases that some callers historically imported\n// from this module so the wave-1/2/3/4 surface keeps backward compatibility.\nexport { ROLE_SKILL_SETS, SHADOW_AGENT_SKILLS };\n", "/**\n * Smart agent dispatcher.\n *\n * Routes a free-form task description to the best agent in the catalog using a\n * two-stage strategy:\n *\n * 1. Heuristic \u2014 keyword/phrase scoring against each agent's `capability`\n * metadata. Deterministic, instant, no provider call. Multi-word phrases\n * score higher than single words (they're more specific signals).\n *\n * 2. LLM fallback \u2014 when the heuristic is ambiguous (confidence below the\n * threshold, or no keyword hit at all) an injected `classifier` resolves\n * the tie. The classifier is provider-agnostic: callers wire it to any\n * `complete(prompt) => text` function via `makeLLMClassifier`, so core\n * stays free of provider dependencies and the path is unit-testable.\n *\n * If neither stage yields a confident pick, the dispatcher falls back to the\n * `executor` generalist rather than failing.\n */\n\nimport {\n readBundledInstructionText,\n renderInstructionTemplate,\n} from '../utils/instruction-file.js';\nimport { safeParse } from '../utils/safe-json.js';\nimport { AGENT_CATALOG, type AgentDefinition } from './agents/index.js';\n\n/** Default agent used when nothing else matches \u2014 the generalist builder. */\nexport const DEFAULT_DISPATCH_ROLE = 'executor';\n\n/** Fallback agent definition for catalog lookup failures. */\nconst FALLBACK_DEFINITION: AgentDefinition = {\n config: { role: 'unknown', name: 'Unknown Agent' },\n budget: {},\n capability: { phase: 'meta', summary: '', keywords: [] },\n};\n\nexport interface DispatchCandidate {\n role: string;\n name: string;\n score: number;\n /** Capability keywords that matched the task text. */\n matched: string[];\n}\n\nexport type DispatchMethod = 'heuristic' | 'llm' | 'fallback';\n\nexport interface DispatchResult {\n role: string;\n definition: AgentDefinition;\n /** 0..1 \u2014 heuristic margin, or 1 when an LLM made a definite choice. */\n confidence: number;\n method: DispatchMethod;\n /** Human-readable explanation of why this agent was chosen. */\n reason: string;\n /** Runner-up candidates (top heuristic scorers), best-first. */\n alternatives: DispatchCandidate[];\n}\n\n/**\n * Provider-agnostic classifier seam. Given the task and the candidate agents\n * (role + summary), return the chosen role (and optional reason), or null to\n * decline. Wire via `makeLLMClassifier`.\n */\nexport type DispatchClassifier = (\n task: string,\n candidates: { role: string; name: string; summary: string }[],\n) => Promise<{ role: string; reason?: string | undefined } | null>;\n\nexport interface DispatchOptions {\n /** Optional LLM fallback for ambiguous tasks. */\n classifier?: DispatchClassifier | undefined;\n /** Heuristic confidence below this triggers the classifier. Default 0.4. */\n confidenceThreshold?: number | undefined;\n /** How many top candidates to offer the classifier. Default 6. */\n maxCandidates?: number | undefined;\n /** Override the catalog (testing). Defaults to the full `AGENT_CATALOG`. */\n catalog?: Record<string, AgentDefinition> | undefined;\n}\n\nfunction normalize(text: string): string {\n return ` ${text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, ' ')\n .trim()} `;\n}\n\n/**\n * Score every agent against the task. A keyword hit adds 1 point; a multi-word\n * keyword phrase adds points equal to its word count (more specific = stronger\n * signal). Returns candidates sorted best-first, zero-score agents dropped.\n */\nexport function scoreAgents(\n task: string,\n catalog: Record<string, AgentDefinition> = AGENT_CATALOG,\n): DispatchCandidate[] {\n // Tokenize once \u2014 O(task words) \u2014 then do O(1) set lookups per keyword\n const haySet = new Set(normalize(task).split(/\\s+/).filter(Boolean));\n const out: DispatchCandidate[] = [];\n for (const def of Object.values(catalog)) {\n if (!def?.config?.role) continue;\n let score = 0;\n const matched: string[] = [];\n for (const kw of def.capability.keywords) {\n const needleWords = normalize(kw).split(/\\s+/).filter(Boolean);\n // Check if all words in the keyword phrase are present in the task\n const allPresent = needleWords.every((w) => haySet.has(w));\n if (allPresent) {\n score += needleWords.length;\n matched.push(kw);\n }\n }\n if (score > 0) {\n out.push({ role: def.config.role, name: def.config.name, score, matched });\n }\n }\n out.sort((a, b) => b.score - a.score);\n return out;\n}\n\n/**\n * Heuristic confidence from the score distribution: the margin between the top\n * candidate and the runner-up, scaled by the top score's strength. A clear\n * winner (high top, low second) approaches 1; a near-tie approaches 0.\n */\nfunction heuristicConfidence(candidates: DispatchCandidate[]): number {\n if (candidates.length === 0) return 0;\n const top = candidates[0]?.score ?? 0;\n const second = candidates[1]?.score ?? 0;\n // Strength factor: a single weak match (score 1) shouldn't read as confident.\n const strength = Math.min(1, top / 3);\n const margin = (top - second + 1) / (top + 1);\n return Math.min(1, strength * margin);\n}\n\n/**\n * Route a task to the best agent. Async because the LLM fallback may run; the\n * pure-heuristic path resolves without awaiting anything.\n */\nexport async function dispatchAgent(\n task: string,\n opts: DispatchOptions = {},\n): Promise<DispatchResult> {\n const catalog = opts.catalog ?? AGENT_CATALOG;\n const threshold = opts.confidenceThreshold ?? 0.4;\n const maxCandidates = opts.maxCandidates ?? 6;\n\n const candidates = scoreAgents(task, catalog);\n const confidence = heuristicConfidence(candidates);\n const top = candidates[0];\n\n // Confident heuristic pick \u2014 done, no provider call.\n if (top && confidence >= threshold) {\n return {\n role: top.role,\n definition: catalog[top.role] ?? FALLBACK_DEFINITION,\n confidence,\n method: 'heuristic',\n reason: `Matched keywords: ${top.matched.slice(0, 4).join(', ')}`,\n alternatives: candidates.slice(1, maxCandidates),\n };\n }\n\n // Ambiguous or no signal \u2014 ask the classifier if one is wired.\n if (opts.classifier) {\n // Offer the classifier the top heuristic candidates; if there were none,\n // offer the whole catalog so it can still choose.\n const pool = (\n candidates.length > 0\n ? candidates.slice(0, maxCandidates).map((c) => catalog[c.role] ?? FALLBACK_DEFINITION)\n : Object.values(catalog)\n ).map((d) => ({\n role: d.config.role as string,\n name: d.config.name,\n summary: d.capability.summary,\n }));\n try {\n const choice = await opts.classifier(task, pool);\n if (choice && catalog[choice.role]) {\n return {\n role: choice.role,\n definition: catalog[choice.role] ?? FALLBACK_DEFINITION,\n confidence: 1,\n method: 'llm',\n reason: choice.reason ?? 'Selected by LLM classifier',\n alternatives: candidates.slice(0, maxCandidates).filter((c) => c.role !== choice.role),\n };\n }\n } catch {\n // Classifier failure must not break dispatch \u2014 fall through to fallback.\n }\n }\n\n // Best heuristic guess if we have one, else the generalist.\n if (top) {\n return {\n role: top.role,\n definition: catalog[top.role] ?? FALLBACK_DEFINITION,\n confidence,\n method: 'heuristic',\n reason: `Weak match (${top.matched.slice(0, 3).join(', ') || 'low signal'})`,\n alternatives: candidates.slice(1, maxCandidates),\n };\n }\n const fallbackRole = catalog[DEFAULT_DISPATCH_ROLE]\n ? DEFAULT_DISPATCH_ROLE\n : (Object.keys(catalog)[0] ?? DEFAULT_DISPATCH_ROLE);\n return {\n role: fallbackRole,\n definition: catalog[fallbackRole] ?? FALLBACK_DEFINITION,\n confidence: 0,\n method: 'fallback',\n reason: 'No keyword signal; defaulting to the generalist Executor',\n alternatives: [],\n };\n}\n\n/**\n * Build a `DispatchClassifier` from a minimal `complete(prompt) => text`\n * function. The caller supplies the provider call; this owns the prompt and\n * the parsing. Keeps `dispatcher` free of any provider import.\n */\nexport function makeLLMClassifier(\n complete: (prompt: string) => Promise<string>,\n): DispatchClassifier {\n return async (task, candidates) => {\n const list = candidates.map((c, i) => `${i + 1}. ${c.role} \u2014 ${c.summary}`).join('\\n');\n const prompt = renderInstructionTemplate(readBundledInstructionText('llm/agent-router.md'), {\n task,\n agents: list,\n });\n const raw = (await complete(prompt)).trim();\n // Tolerate accidental code fences / surrounding text \u2014 extract first {...}.\n const match = raw.match(/\\{[\\s\\S]*\\}/);\n if (!match) return null;\n const parsed = safeParse<{ role?: unknown | undefined; reason?: unknown | undefined }>(\n match[0],\n );\n if (!parsed.ok || !parsed.value || typeof parsed.value.role !== 'string') return null;\n const role = parsed.value.role.trim();\n const valid = candidates.some((c) => c.role === role);\n if (!valid) return null;\n return {\n role,\n reason: typeof parsed.value.reason === 'string' ? parsed.value.reason : undefined,\n };\n };\n}\n", "import { randomUUID } from 'node:crypto';\nimport { EventEmitter } from 'node:events';\nimport type { AgentBridge, BridgeMessage } from '../types/agent-bridge.js';\nimport type {\n AwaitAnyResult,\n CoordinatorStatus,\n MultiAgentConfig,\n MultiAgentCoordinator,\n SpawnResult,\n SubagentConfig,\n SubagentContext,\n SubagentRunContext,\n SubagentPartialResult,\n SubagentRunner,\n TaskResult,\n TaskSpec,\n} from '../types/multi-agent.js';\nimport {\n type BudgetSessionIdSource,\n BudgetExceededError,\n SubagentBudget,\n} from './subagent-budget.js';\nimport { classifySubagentError } from './coordinator/error-classifier.js';\nimport { applyRosterBudget } from './fleet.js';\nimport { assignNickname } from './subagent-nicknames.js';\nimport { executeSubagentWithTimeout } from './multi-agent-timeout.js';\n\ntype SubagentStatus = 'running' | 'idle' | 'stopped' | 'error';\n\ninterface SubagentEntry {\n config: SubagentConfig;\n context: SubagentContext;\n status: SubagentStatus;\n currentTask?: string | undefined;\n abortController: AbortController;\n /** Lazily created on first dispatch \u2014 budget is per-task, not per-subagent. */\n activeBudget?: SubagentBudget | undefined;\n}\n\nexport interface MultiAgentCoordinatorOptions {\n /**\n * Callback that executes a task on behalf of a subagent. Required for\n * `assign()` to actually run anything \u2014 without it, tasks queue forever.\n * The coordinator provides per-subagent isolation (own budget, own signal,\n * own bridge) and enforces timeout + concurrency.\n */\n runner?: SubagentRunner | undefined;\n /**\n * Session id for EventBus/FleetBus emissions produced by this coordinator.\n * Accepts a getter so a long-lived coordinator follows session resume/new.\n */\n sessionId?: BudgetSessionIdSource | undefined;\n}\n\nexport class DefaultMultiAgentCoordinator extends EventEmitter implements MultiAgentCoordinator {\n readonly coordinatorId: string;\n readonly config: MultiAgentConfig;\n private runner?: SubagentRunner | undefined;\n private readonly sessionId: BudgetSessionIdSource | undefined;\n private fleetBus?: import('./fleet-bus.js').FleetBus | undefined;\n\n private readonly subagents = new Map<string, SubagentEntry>();\n\n /**\n * Base nickname keys already handed out this run (e.g. `einstein`, `tesla`).\n * Prevents two workers sharing a name. Direct `coordinator.spawn()` callers\n * (parallel/eternal engine, SDD parallel run) don't go through\n * `Director.spawn()` where nicknames are normally assigned, so the\n * coordinator upgrades placeholder names (\"Executor\", \"slot-ab12cd\", role\n * names) to memorable ones here \u2014 that's what surfaces in the fleet monitor.\n */\n private readonly usedNicknames = new Set<string>();\n /** Maps subagentId \u2192 nickname key (e.g. 'einstein'). Used to free the slot on remove(). */\n private readonly subagentNicknames = new Map<string, string>();\n\n private pendingTasks: TaskSpec[] = [];\n private completedResults: TaskResult[] = [];\n /** Prevents completedResults from growing unbounded in long-running coordinators. */\n private static readonly MAX_COMPLETED_RESULTS = 10_000;\n /** Caps each subagent's retained task history (see assign()); bounds RAM + the recordCompletion lookup. */\n private static readonly MAX_SUBAGENT_TASK_HISTORY = 64;\n private totalIterations = 0;\n private inFlight = 0;\n /**\n * Subagents currently being stopped. Set on entry to `stop()`, cleared\n * once `recordCompletion` lands the terminal TaskResult. Used by\n * `runDispatched` and `findIdleSubagent` to refuse mid-flight dispatch\n * to a subagent the caller has already asked to terminate \u2014 closes the\n * assign+terminate race where a fresh task could land on a worker that\n * was about to be killed.\n */\n private readonly terminating = new Set<string>();\n\n constructor(config: MultiAgentConfig, options: MultiAgentCoordinatorOptions = {}) {\n super();\n // awaitTasks() registers one short-lived 'task.completed' listener per\n // awaited id; a single call awaiting >10 ids (or several concurrent\n // callers) crosses Node's default 10-listener cap and prints a spurious\n // MaxListenersExceededWarning that also masks genuine leaks. These waiters\n // are bounded and self-removing, so lift the cap.\n this.setMaxListeners(0);\n this.coordinatorId = config.coordinatorId;\n this.config = config;\n this.runner = options.runner;\n this.sessionId = options.sessionId;\n }\n\n private currentSessionId(): string | undefined {\n const value = typeof this.sessionId === 'function' ? this.sessionId() : this.sessionId;\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n }\n\n /**\n * Replace the runner after construction. Used when the runner depends\n * on infrastructure (e.g. FleetBus) that isn't available until after\n * the coordinator's owning Director is built.\n */\n setRunner(runner: SubagentRunner): void {\n this.runner = runner;\n }\n\n /**\n * Wire a FleetBus for director-mode event emission. Call after the\n * FleetManager is constructed so the coordinator can emit lifecycle\n * events the TUI and monitoring tools subscribe to.\n */\n setFleetBus(fleet: import('./fleet-bus.js').FleetBus): void {\n this.fleetBus = fleet;\n }\n\n /**\n * Change the in-flight dispatch ceiling at runtime. Lowering does NOT\n * preempt running tasks \u2014 already-dispatched subagents finish their\n * current task; only future dispatches respect the new cap. Raising\n * immediately tries to fill the freed slots from the pending queue.\n */\n setMaxConcurrent(n: number): void {\n if (!Number.isFinite(n) || n < 1) {\n throw new Error(`maxConcurrent must be a finite integer >= 1, got ${n}`);\n }\n this.config.maxConcurrent = Math.floor(n);\n this.tryDispatchNext();\n }\n\n /**\n * Upgrade a placeholder/role-derived name to a memorable scientist nickname\n * (e.g. \"Einstein (Executor)\"). A name is treated as a placeholder when it is\n * empty, equals the role (case-insensitive), is a generic default\n * (\"subagent\"/\"adhoc\"/\"generic\"), or is an auto-generated `slot-\u2026` id.\n * Explicit, human-chosen names \u2014 including nicknames already assigned by\n * `Director.spawn()` \u2014 are left untouched, so this never double-assigns.\n */\n private withNickname(subagent: SubagentConfig, subagentId: string): SubagentConfig {\n const role = subagent.role ?? 'subagent';\n const name = subagent.name?.trim() ?? '';\n const isPlaceholder =\n name === '' ||\n name.toLowerCase() === role.toLowerCase() ||\n name === 'subagent' ||\n name === 'adhoc' ||\n name === 'generic' ||\n /^slot-/.test(name);\n if (!isPlaceholder) return subagent;\n const { key, display } = assignNickname(role, this.usedNicknames);\n this.usedNicknames.add(key);\n this.subagentNicknames.set(subagentId, key);\n return { ...subagent, name: display };\n }\n\n async spawn(subagent: SubagentConfig): Promise<SpawnResult> {\n const id = subagent.id || randomUUID();\n const cfg = this.withNickname(subagent, id);\n // Duplicate-id guard. Previously a second spawn({id}) with the\n // same id silently overwrote the existing entry \u2014 orphaning the\n // first subagent's AbortController, Context, and any in-flight\n // task referencing it. Two spawns with the same id are almost\n // always a bug at the caller; refuse and let them surface it.\n if (this.subagents.has(id)) {\n throw new Error(`Subagent id \"${id}\" already exists \u2014 refusing to overwrite`);\n }\n const context: SubagentContext = {\n subagentId: id,\n tasks: [],\n // Wired later by the caller via setSubagentBridge() once the\n // bidirectional bridge is created. Readers must null-check / use\n // hasParentBridge() \u2014 the type now reflects this.\n parentBridge: null,\n doneCondition: this.config.doneCondition,\n maxConcurrent: this.config.maxConcurrent ?? 16,\n };\n\n this.subagents.set(id, {\n config: { ...cfg, id },\n context,\n status: 'idle',\n abortController: new AbortController(),\n });\n\n this.emit('subagent.started', { subagent: { ...cfg, id } });\n\n this.fleetBus?.emit({\n subagentId: id,\n ts: Date.now(),\n type: 'subagent.assigned',\n payload: {\n subagentId: id,\n name: subagent.name,\n provider: subagent.provider,\n model: subagent.model,\n },\n });\n\n this.emitCoordinatorStats();\n\n return { subagentId: id, agentId: id };\n }\n\n async assign(task: TaskSpec): Promise<void> {\n this.pendingTasks.push(task);\n this.tryDispatchNext();\n }\n\n async delegate(to: string, msg: BridgeMessage): Promise<void> {\n const subagent = this.subagents.get(to);\n if (!subagent) throw new Error(`Subagent \"${to}\" not found`);\n if (!subagent.context.parentBridge) {\n throw new Error(`Subagent \"${to}\" has no parentBridge \u2014 call setSubagentBridge() first`);\n }\n await subagent.context.parentBridge.send(msg);\n }\n\n /**\n * Wire up the communication bridge for a subagent. Call after spawn() once\n * the caller has created the bidirectional connection.\n */\n setSubagentBridge(subagentId: string, bridge: AgentBridge): void {\n const subagent = this.subagents.get(subagentId);\n if (!subagent) throw new Error(`Subagent \"${subagentId}\" not found`);\n subagent.context.parentBridge = bridge;\n }\n\n async stop(subagentId: string): Promise<void> {\n const subagent = this.subagents.get(subagentId);\n if (!subagent) return;\n\n // Mark terminating BEFORE the abort so a synchronous tryDispatchNext\n // observation in another callback path sees the intent and skips\n // this subagent. Cleared by recordCompletion once the runner's\n // catch block lands the terminal TaskResult.\n this.terminating.add(subagentId);\n\n // Abort any in-flight run, then sever the bridge so further messages fail\n // fast instead of silently queueing on a dead subagent.\n subagent.abortController.abort();\n subagent.status = 'stopped';\n subagent.currentTask = undefined;\n subagent.context.parentBridge = null;\n\n this.emit('subagent.stopped', { subagentId, reason: 'stopped by coordinator' });\n\n this.fleetBus?.emit({\n subagentId,\n ts: Date.now(),\n type: 'subagent.stopped',\n payload: { subagentId, reason: 'stopped by coordinator' },\n });\n\n this.emitCoordinatorStats();\n }\n\n async stopAll(): Promise<void> {\n // Clear the queue FIRST so no new tasks land on subagents while\n // we're tearing them down. Each dropped task gets a synthetic\n // `aborted_by_parent` completion so any caller awaiting it (e.g.\n // delegate tool's awaitTasks) resolves instead of hanging.\n //\n // Pending tasks never reached `inFlight`, so we cannot route them\n // through `recordCompletion` \u2014 its underflow guard would short-\n // circuit on the second pending task and emit a warning instead\n // of the completion event. The shared helper inline-emits.\n this.drainPendingAsAborted('Coordinator stopAll() drained the pending queue');\n // allSettled so one failure doesn't leave other subagents un-stopped.\n await Promise.allSettled([...this.subagents.keys()].map((id) => this.stop(id)));\n }\n\n /**\n * Get current coordinator stats for monitoring/debugging.\n */\n getStats(): {\n total: number;\n running: number;\n idle: number;\n stopped: number;\n inFlight: number;\n pending: number;\n completed: number;\n } {\n let running = 0;\n let idle = 0;\n let stopped = 0;\n for (const [, entry] of this.subagents) {\n if (entry.status === 'running') running++;\n else if (entry.status === 'idle') idle++;\n else stopped++;\n }\n return {\n total: this.subagents.size,\n running,\n idle,\n stopped,\n inFlight: this.inFlight,\n pending: this.pendingTasks.length,\n completed: this.completedResults.length,\n };\n }\n\n /** Emit a reactive coordinator.stats event on FleetBus so the TUI can subscribe. */\n private emitCoordinatorStats(): void {\n const stats = this.getStats();\n const subagentStatuses = Array.from(this.subagents.entries()).map(([id, s]) => ({\n subagentId: id,\n taskId: s.currentTask ?? '',\n status: s.status,\n assigned: s.context.parentBridge !== null,\n }));\n const sessionId = this.currentSessionId();\n this.fleetBus?.emit({\n subagentId: this.coordinatorId,\n ts: Date.now(),\n type: 'coordinator.stats',\n payload: {\n ...(sessionId ? { sessionId } : {}),\n ...stats,\n subagentStatuses,\n },\n });\n }\n\n getStatus(): CoordinatorStatus {\n return {\n coordinatorId: this.coordinatorId,\n subagents: Array.from(this.subagents.entries()).map(([id, s]) => ({\n id,\n name: s.config.name,\n status: s.status,\n currentTask: s.currentTask,\n })),\n pendingTasks: this.pendingTasks.length,\n completedTasks: this.completedResults.length,\n totalIterations: this.totalIterations,\n done: this.isDone(),\n };\n }\n\n /** Expose snapshot of completed results \u2014 useful for callers awaiting all done. */\n results(): readonly TaskResult[] {\n return this.completedResults;\n }\n\n /** Defensive snapshot of the still-queued (not yet dispatched) tasks. */\n listPendingTasks(): readonly TaskSpec[] {\n return this.pendingTasks.map((t) => ({ ...t }));\n }\n\n /**\n * Re-pin a still-PENDING task to a different subagent (`undefined` =\n * unpin, any idle worker may take it), then try to dispatch. Returns\n * `false` when the task is not in the pending queue \u2014 already\n * dispatched, completed, or unknown. Running tasks can never be pulled;\n * they can only be steered or terminated. The mutation is synchronous\n * (same tick as the check), so it cannot race a concurrent dispatch:\n * `tryDispatchNext` runs on this same call stack or a later one.\n *\n * The task keeps its id, so waiters, the report-back notifier, and\n * checkpoint bookkeeping resolve unchanged when it eventually completes.\n */\n retargetPendingTask(taskId: string, subagentId: string | undefined): boolean {\n const task = this.pendingTasks.find((t) => t.id === taskId);\n if (!task) return false;\n if (subagentId !== undefined && !this.subagents.has(subagentId)) return false;\n task.subagentId = subagentId;\n this.tryDispatchNext();\n return true;\n }\n\n /**\n * Wait for one or more tasks to complete and return their results.\n * If a task is already done when called, returns immediately.\n * Resolves to an array in the same order as `taskIds`.\n */\n async awaitTasks(taskIds: string[], opts?: { timeoutMs?: number }): Promise<TaskResult[]> {\n // Per-call override lets a caller with a longer budget (e.g. the eternal\n // engine's multi-hour subagent window) wait past the default without\n // being cut at config.timeoutMs. Defaults to config.timeoutMs, then 300s.\n const timeoutMs = opts?.timeoutMs ?? this.config.timeoutMs ?? 300_000;\n return Promise.all(\n taskIds.map((id) => {\n const cached = this.completedResults.find((r) => r.taskId === id);\n if (cached) return cached;\n // Fallback: poll until the task completes (up to timeoutMs).\n // The coordinator fires 'task.completed' on every result, so\n // we use a promise-based waiter tied to that event.\n return new Promise<TaskResult>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.off('task.completed', handler);\n reject(new Error(`awaitTasks timed out waiting for task \"${id}\"`));\n }, timeoutMs);\n const handler = ({ result }: { task: TaskSpec; result: TaskResult }) => {\n if (result.taskId === id) {\n clearTimeout(timeout);\n this.off('task.completed', handler);\n resolve(result);\n }\n };\n this.on('task.completed', handler);\n });\n }),\n );\n }\n\n /**\n * Wait until AT LEAST ONE of the named tasks completes. Returns every\n * requested result already available at that moment (drain-what's-done)\n * plus the ids still outstanding, so callers can loop \"handle finishers,\n * re-await the remainder\" instead of blocking on the whole batch.\n *\n * Unlike `awaitTasks`, this never rejects and deliberately does NOT\n * inherit `config.timeoutMs` \u2014 a \"return whatever is done\" call has no\n * business timing out unless the caller asks for a window explicitly.\n */\n async awaitTasksAny(\n taskIds: string[],\n opts?: { timeoutMs?: number },\n ): Promise<AwaitAnyResult> {\n const ids = new Set(taskIds);\n const completed = this.completedResults.filter((r) => ids.has(r.taskId));\n if (completed.length > 0 || ids.size === 0) {\n const done = new Set(completed.map((r) => r.taskId));\n return { completed, pending: taskIds.filter((id) => !done.has(id)) };\n }\n return new Promise<AwaitAnyResult>((resolve) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const handler = ({ result }: { task: TaskSpec; result: TaskResult }) => {\n if (!ids.has(result.taskId)) return;\n if (timer) clearTimeout(timer);\n this.off('task.completed', handler);\n resolve({\n completed: [result],\n pending: taskIds.filter((id) => id !== result.taskId),\n });\n };\n if (opts?.timeoutMs !== undefined) {\n timer = setTimeout(() => {\n this.off('task.completed', handler);\n resolve({ completed: [], pending: [...taskIds], timedOut: true });\n }, opts.timeoutMs);\n }\n this.on('task.completed', handler);\n });\n }\n\n /**\n * Manual completion \u2014 for callers that drive subagents without a runner\n * (e.g. external orchestrators). When a runner is configured the coordinator\n * calls this itself.\n */\n completeTask(result: TaskResult): void {\n this.recordCompletion(result);\n }\n\n // --- internal dispatching ---------------------------------------------\n\n private tryDispatchNext(): void {\n while (this.canDispatch()) {\n const dispatchable = this.takeNextDispatchableTask();\n if (!dispatchable) {\n // No idle worker right now. If every spawned subagent is\n // stopped or mid-termination, the pending queue is dead \u2014\n // a pending task can never start, so synthetic-complete it\n // as `aborted_by_parent`. Without this, an `assign()` after\n // `stop()` would hang forever waiting for `task.completed`.\n // We DO NOT drain when subagents are busy (status='running'):\n // those will free up and accept the work normally.\n if (this.pendingTasks.length > 0 && !this.hasLiveSubagent()) {\n this.drainPendingAsAborted(\n 'No live subagent available \u2014 all stopped or mid-termination',\n );\n }\n return;\n }\n const { subagentId, task } = dispatchable;\n // Attach a catch so a synchronous throw inside runDispatched (rare \u2014\n // e.g. provider misconfiguration before the first await) becomes a\n // visible failed task instead of an unhandled rejection that leaves\n // `inFlight` permanently elevated.\n this.runDispatched(subagentId, task).catch((err) => {\n this.recordCompletion({\n subagentId,\n taskId: task.id,\n status: 'failed',\n error: classifySubagentError(err),\n iterations: 0,\n toolCalls: 0,\n durationMs: 0,\n });\n });\n }\n }\n\n private canDispatch(): boolean {\n const max = this.config.maxConcurrent ?? 16;\n return this.inFlight < max && this.pendingTasks.length > 0;\n }\n\n private takeNextDispatchableTask(): { subagentId: string; task: TaskSpec } | null {\n for (let i = 0; i < this.pendingTasks.length; i++) {\n const task = this.pendingTasks[i];\n if (!task) continue;\n const subagentId = task.subagentId\n ? this.isIdleSubagent(task.subagentId)\n ? task.subagentId\n : null\n : this.findIdleSubagent();\n if (!subagentId) continue;\n this.pendingTasks.splice(i, 1);\n return { subagentId, task };\n }\n return null;\n }\n\n private findIdleSubagent(): string | null {\n for (const [id, s] of this.subagents) {\n // Skip subagents that are mid-termination \u2014 `stop()` set the\n // `terminating` flag and aborted the controller, but the\n // status mutation happens synchronously after; checking both\n // is belt-and-suspenders against any race where status is\n // transiently still 'idle' while termination is in flight.\n if (s.status === 'idle' && !this.terminating.has(id)) return id;\n }\n return null;\n }\n\n private isIdleSubagent(id: string): boolean {\n const subagent = this.subagents.get(id);\n return !!subagent && subagent.status === 'idle' && !this.terminating.has(id);\n }\n\n /**\n * Returns true iff at least one spawned subagent could still\n * process a task. A \"live\" subagent is one that is not stopped\n * AND not mid-termination \u2014 `running` workers count because they\n * will eventually finish and become idle.\n *\n * When no subagent has ever been spawned, returns `true` so a\n * pre-spawn `assign()` simply queues (legacy behaviour). The\n * dead-end detection only fires after `stop()` has retired every\n * spawned worker.\n *\n * Used by `tryDispatchNext` to detect a dead-end pending queue.\n */\n private hasLiveSubagent(): boolean {\n if (this.subagents.size === 0) return true;\n for (const [id, s] of this.subagents) {\n if (s.status !== 'stopped' && !this.terminating.has(id)) return true;\n }\n return false;\n }\n\n /**\n * Drain every pending task with a synthetic `aborted_by_parent`\n * completion event. Same shape as the `stopAll()` drain \u2014 we go\n * around `recordCompletion` because pending tasks were never\n * counted in `inFlight` and routing them through would trip the\n * underflow guard on every task after the first.\n */\n private drainPendingAsAborted(message: string): void {\n const dropped = this.pendingTasks.splice(0, this.pendingTasks.length);\n for (const t of dropped) this.emitPendingAborted(t, message);\n }\n\n /**\n * Emit a synthetic `stopped`/`aborted_by_parent` completion for a single\n * PENDING task \u2014 one that was never counted in `inFlight`. This MUST bypass\n * `recordCompletion`: that path does `inFlight--`, which for a pending task\n * steals a decrement from a genuinely in-flight task and trips the underflow\n * guard \u2014 suppressing that real task's `task.completed` and hanging its\n * `awaitTasks()` caller. Pushes the result and fires the event directly.\n */\n private emitPendingAborted(task: TaskSpec, message: string): void {\n const synthetic: TaskResult = {\n subagentId: task.subagentId ?? 'unassigned',\n taskId: task.id,\n status: 'stopped',\n error: {\n kind: 'aborted_by_parent',\n message,\n retryable: false,\n },\n iterations: 0,\n toolCalls: 0,\n durationMs: 0,\n };\n this.completedResults.push(synthetic);\n this.emit('task.completed', { task, result: synthetic });\n }\n\n private async runDispatched(subagentId: string, task: TaskSpec): Promise<void> {\n const subagent = this.subagents.get(subagentId);\n if (!subagent) return;\n // Final race guard: if `stop(subagentId)` ran between dispatch\n // and us arriving here, refuse to start the task and surface it\n // as `aborted_by_parent` so any caller awaiting the task id\n // unblocks. Without this, the task would be marked 'running',\n // collide with the just-completed 'stopped' state, and leak\n // inFlight by 1 because no recordCompletion path covers it.\n if (this.terminating.has(subagentId) || subagent.status === 'stopped') {\n this.recordCompletion({\n subagentId,\n taskId: task.id,\n status: 'stopped',\n error: {\n kind: 'aborted_by_parent',\n message: 'Subagent was terminated before task could start',\n retryable: false,\n },\n iterations: 0,\n toolCalls: 0,\n durationMs: 0,\n });\n return;\n }\n\n subagent.status = 'running';\n subagent.currentTask = task.id;\n task.subagentId = subagentId;\n subagent.context.tasks.push(task);\n // Bound the per-subagent task history: a worker runs one task at a time, so\n // the completing task is always among the most recent entries. This keeps a\n // long-lived worker (idle\u2192assign\u2192complete\u2192\u2026) from accumulating every task it\n // ever ran, and keeps the `.find` at recordCompletion O(cap) instead of O(N).\n if (subagent.context.tasks.length > DefaultMultiAgentCoordinator.MAX_SUBAGENT_TASK_HISTORY) {\n subagent.context.tasks.splice(\n 0,\n subagent.context.tasks.length - DefaultMultiAgentCoordinator.MAX_SUBAGENT_TASK_HISTORY,\n );\n }\n\n this.fleetBus?.emit({\n subagentId,\n taskId: task.id,\n ts: Date.now(),\n type: 'subagent.running',\n payload: { subagentId, taskId: task.id },\n });\n\n this.emit('task.assigned', { task, subagentId });\n this.emitCoordinatorStats();\n\n // Budget combines coordinator defaults with per-subagent and per-task overrides.\n // Precedence: task > subagent (raw, no roster fills) > coordinator default > roster default.\n // We intentionally call applyRosterBudget LATE \u2014 only as a final fallback after\n // the coordinator's defaultBudget has had a chance to apply. This prevents\n // GENERIC_SUBAGENT_BUDGET (5000 iter) from shadowing the coordinator's explicit default.\n const rawMaxIterations = subagent.config.maxIterations;\n const rawMaxToolCalls = subagent.config.maxToolCalls;\n const rawMaxTokens = subagent.config.maxTokens;\n const rawMaxCostUsd = subagent.config.maxCostUsd;\n const rawTimeoutMs = subagent.config.timeoutMs;\n const rawIdleTimeoutMs = subagent.config.idleTimeoutMs;\n const configWithRosterDefaults = applyRosterBudget(subagent.config);\n const budget = new SubagentBudget(\n {\n maxIterations:\n rawMaxIterations ?? this.config.defaultBudget?.maxIterations ?? configWithRosterDefaults.maxIterations,\n maxToolCalls:\n rawMaxToolCalls ??\n this.config.defaultBudget?.maxToolCalls ??\n configWithRosterDefaults.maxToolCalls,\n maxTokens:\n rawMaxTokens ?? this.config.defaultBudget?.maxTokens ?? configWithRosterDefaults.maxTokens,\n maxCostUsd:\n rawMaxCostUsd ?? this.config.defaultBudget?.maxCostUsd ?? configWithRosterDefaults.maxCostUsd,\n // Wall-clock cap is opt-in (explicit config / defaultBudget only); the\n // roster no longer supplies one. Idle is the default reaper.\n timeoutMs:\n rawTimeoutMs ?? this.config.defaultBudget?.timeoutMs ?? configWithRosterDefaults.timeoutMs,\n idleTimeoutMs:\n rawIdleTimeoutMs ??\n this.config.defaultBudget?.idleTimeoutMs ??\n configWithRosterDefaults.idleTimeoutMs,\n },\n 'auto',\n { sessionId: () => this.currentSessionId() },\n );\n subagent.activeBudget = budget;\n\n if (!this.runner) {\n // No runner wired \u2014 caller drives execution via completeTask(). Status\n // reverts when the caller reports. We intentionally don't bump\n // `inFlight` here: `completeTask` \u2192 `recordCompletion` would then\n // decrement an inFlight that runDispatched never incremented, masking\n // the \"no runner\" state. With this guard, `isDone()`'s all_tasks_done\n // check still settles correctly once the caller reports.\n return;\n }\n\n // Only count inFlight when we actually own the execution lifecycle.\n this.inFlight++;\n\n const startTime = Date.now();\n let latestPartial: SubagentPartialResult | undefined;\n const runCtx: SubagentRunContext = {\n subagentId,\n config: subagent.config,\n budget,\n signal: subagent.abortController.signal,\n bridge: subagent.context.parentBridge || null,\n reportProgress: (partial) => {\n const text = partial.text.trim();\n if (!text) return;\n latestPartial = {\n ...partial,\n // A partial is context recovery, not a transcript replacement.\n text: text.slice(-4_000),\n };\n },\n };\n\n let result: TaskResult;\n\n budget.start();\n try {\n const outcome = await this.executeWithTimeout(\n this.runner,\n task,\n runCtx,\n budget,\n subagent.config.preemptFraction,\n );\n result = {\n subagentId,\n taskId: task.id,\n status: 'success',\n result: outcome.result,\n ...(outcome.report ? { report: outcome.report } : {}),\n iterations: outcome.iterations,\n toolCalls: outcome.toolCalls,\n durationMs: Date.now() - startTime,\n };\n } catch (err) {\n // Order matters: a timeout calls abort() to signal cooperative runners,\n // which also flips `signal.aborted=true`. Inspect the error first so we\n // surface 'timeout' rather than masking it as 'stopped'.\n const status: TaskResult['status'] =\n err instanceof BudgetExceededError && (err.kind === 'timeout' || err.kind === 'idle_timeout')\n ? 'timeout'\n : subagent.abortController.signal.aborted\n ? 'stopped'\n : 'failed';\n const usage = budget.usage();\n result = {\n subagentId,\n taskId: task.id,\n status,\n error: classifySubagentError(err, {\n parentAborted: subagent.abortController.signal.aborted,\n }),\n ...(latestPartial ? { partial: latestPartial } : {}),\n iterations: usage.iterations,\n toolCalls: usage.toolCalls,\n durationMs: Date.now() - startTime,\n };\n }\n\n this.recordCompletion(result);\n }\n\n private async executeWithTimeout(\n runner: SubagentRunner,\n task: TaskSpec,\n ctx: SubagentRunContext,\n budget: SubagentBudget,\n preemptFraction?: number | undefined,\n ) {\n return executeSubagentWithTimeout({\n runner,\n task,\n ctx,\n budget,\n preemptFraction,\n abortSubagent: (subagentId) => this.subagents.get(subagentId)?.abortController.abort(),\n currentSessionId: () => this.currentSessionId(),\n });\n }\n\n private recordCompletion(result: TaskResult): void {\n this.completedResults.push(result);\n // Trim oldest entries when the cap is exceeded \u2014 keep the most recent\n // results so /fleet and roll_up still have data to work with.\n if (this.completedResults.length > DefaultMultiAgentCoordinator.MAX_COMPLETED_RESULTS) {\n this.completedResults.splice(\n 0,\n this.completedResults.length - DefaultMultiAgentCoordinator.MAX_COMPLETED_RESULTS,\n );\n }\n this.totalIterations += result.iterations;\n if (this.inFlight > 0) {\n this.inFlight--;\n } else if (this.runner) {\n // Runner-driven path completed without an outstanding inFlight slot \u2014\n // shouldn't happen unless completeTask was called externally.\n this.emit('warning', {\n type: 'inFlight_underflow',\n taskId: result.taskId,\n subagentId: result.subagentId,\n });\n return;\n }\n\n const subagent = this.subagents.get(result.subagentId);\n if (subagent && subagent.status !== 'stopped') {\n const failed = result.status === 'failed' || result.status === 'timeout';\n // Synchronously reset the worker to idle after either a clean\n // finish or a transient failure. The previous code parked the\n // subagent in 'error' and used a `queueMicrotask` to flip it\n // back to 'idle' \u2014 that opened a window where `assign()` +\n // `tryDispatchNext` could race the microtask, leaving the\n // worker stuck in 'running' state while actually idle. By\n // resetting now, no async gap can leak the state machine.\n subagent.status = 'idle';\n void failed; // kept for future telemetry hooks\n subagent.currentTask = undefined;\n // If the run aborted (timeout or explicit stop), the subagent's\n // signal is now permanently aborted \u2014 recycling the controller lets\n // the next dispatched task start with a fresh cancellation scope.\n if (subagent.abortController.signal.aborted) {\n subagent.abortController = new AbortController();\n }\n\n this.fleetBus?.emit({\n subagentId: result.subagentId,\n ts: Date.now(),\n type: 'subagent.idle',\n payload: { subagentId: result.subagentId },\n });\n }\n // Clear the terminating flag now that the worker has a terminal\n // TaskResult on record. Subsequent stop() calls re-add it; new\n // assign() calls can flow normally.\n this.terminating.delete(result.subagentId);\n\n this.emit('task.completed', {\n task: subagent?.context.tasks.find((t) => t.id === result.taskId) ?? { id: result.taskId },\n result,\n });\n\n this.fleetBus?.emit({\n subagentId: result.subagentId,\n taskId: result.taskId,\n ts: Date.now(),\n type: 'subagent.completed',\n payload: {\n subagentId: result.subagentId,\n taskId: result.taskId,\n status: result.status,\n result: result.result,\n report: result.report,\n partial: result.partial,\n iterations: result.iterations,\n toolCalls: result.toolCalls,\n durationMs: result.durationMs,\n },\n });\n\n this.tryDispatchNext();\n\n // Emit after tryDispatchNext so the stats reflect the post-dispatch\n // state (either a new running subagent, or idle if the queue is drained).\n this.emitCoordinatorStats();\n\n if (this.isDone()) {\n this.emit('done', {\n results: this.completedResults,\n totalIterations: this.totalIterations,\n });\n }\n }\n\n /**\n * Stop a subagent and remove it from the coordinator. Releases all\n * associated resources (AbortController, context, budget state).\n * The subagent entry is deleted so the id can be reused in a future spawn.\n */\n async remove(subagentId: string): Promise<void> {\n const subagent = this.subagents.get(subagentId);\n if (!subagent) return;\n\n // Gracefully stop first \u2014 same logic as stop() but don't block on it.\n if (subagent.status === 'running' || subagent.status === 'idle') {\n this.terminating.add(subagentId);\n subagent.abortController.abort();\n subagent.status = 'stopped';\n }\n\n // Release all resources associated with this subagent.\n this.subagents.delete(subagentId);\n this.terminating.delete(subagentId);\n // Free the nickname slot so the same name can be reused by a future spawn.\n const nicknameKey = this.subagentNicknames.get(subagentId);\n if (nicknameKey) {\n this.usedNicknames.delete(nicknameKey);\n this.subagentNicknames.delete(subagentId);\n }\n\n // Clean up any pending tasks assigned to this subagent \u2014 emit synthetic\n // 'stopped' completions so callers awaiting them via awaitTasks() unblock\n // instead of hanging forever. Without this, a task queued for a removed\n // subagent would leave its waiter permanently unresolved.\n const orphaned = this.pendingTasks.filter((t) => t.subagentId === subagentId);\n this.pendingTasks = this.pendingTasks.filter((t) => t.subagentId !== subagentId);\n for (const t of orphaned) {\n // Inline-emit, NOT recordCompletion: these are PENDING tasks that were\n // never counted in inFlight. Routing them through recordCompletion would\n // decrement inFlight on behalf of a still-running task and suppress that\n // task's own completion via the underflow guard, hanging its awaiter.\n this.emitPendingAborted(\n t,\n `Subagent \"${subagentId}\" was removed while task \"${t.id}\" was pending`,\n );\n }\n\n this.fleetBus?.emit({\n subagentId,\n ts: Date.now(),\n type: 'subagent.removed',\n payload: { subagentId },\n });\n\n this.emitCoordinatorStats();\n }\n\n private isDone(): boolean {\n if (this.config.doneCondition.type === 'all_tasks_done') {\n return this.pendingTasks.length === 0 && this.inFlight === 0;\n }\n if (\n this.config.doneCondition.maxIterations !== undefined &&\n this.totalIterations >= this.config.doneCondition.maxIterations\n ) {\n return true;\n }\n return false;\n }\n}\n\n/**\n * Map any raw exception thrown out of a subagent's runner into a\n * structured `SubagentError`. Delegates to the shared classifier.\n * Re-exported for backward compatibility.\n */\nexport { classifySubagentError } from './coordinator/error-classifier.js';\n", "import { AgentError } from '../../types/errors.js';\nimport type { SubagentError, SubagentErrorKind } from '../../types/multi-agent.js';\nimport { ProviderError } from '../../types/provider.js';\nimport { toErrorMessage } from '../../utils/error.js';\nimport { BudgetExceededError } from '../subagent-budget.js';\n\n/**\n * Map any raw exception thrown out of a subagent's runner into a\n * structured `SubagentError`. This is the single point where the\n * coordinator decides \"what kind of failure was that\" \u2014 so callers\n * (delegate tool output, /agents UI, retry policies) branch on\n * `kind` instead of substring-matching `error.message`.\n *\n * Exported because tests and CLI surfaces want to assert on the\n * classification without instantiating a coordinator.\n */\nexport function classifySubagentError(\n err: unknown,\n hints: { parentAborted?: boolean | undefined } = {},\n): SubagentError {\n // Unwrap AgentError wrappers \u2014 the runner wraps non-AgentError\n // throwables (ProviderError, TypeError, etc.) in AgentError so the\n // coordinator's try/catch catches a consistent type. Recurse into the\n // inner cause so classification sees the original error kind.\n if (err instanceof AgentError && err.cause) {\n return classifySubagentError(err.cause, hints);\n }\n\n const cause =\n err instanceof Error ? { name: err.name, message: err.message, stack: err.stack } : undefined;\n\n if (err instanceof ProviderError) {\n const baseMessage = err.describe();\n return providerErrorToSubagentError(err, baseMessage, cause);\n }\n\n const baseMessage = toErrorMessage(err);\n\n if (err instanceof BudgetExceededError) {\n const map: Record<BudgetExceededError['kind'], SubagentErrorKind> = {\n iterations: 'budget_iterations',\n tool_calls: 'budget_tool_calls',\n tokens: 'budget_tokens',\n cost: 'budget_cost',\n timeout: 'budget_timeout',\n idle_timeout: 'budget_timeout',\n };\n return {\n kind: map[err.kind],\n message: baseMessage,\n retryable: false,\n cause,\n };\n }\n\n if (hints.parentAborted) {\n return { kind: 'aborted_by_parent', message: baseMessage, retryable: false, cause };\n }\n\n const lower = baseMessage.toLowerCase();\n if (/agent aborted$/i.test(baseMessage)) {\n return { kind: 'aborted_by_parent', message: baseMessage, retryable: false, cause };\n }\n if (/agent exhausted iteration limit$/i.test(baseMessage)) {\n return { kind: 'budget_iterations', message: baseMessage, retryable: false, cause };\n }\n if (/empty response/i.test(baseMessage)) {\n return { kind: 'empty_response', message: baseMessage, retryable: false, cause };\n }\n if (/^tool failed: /i.test(baseMessage)) {\n return { kind: 'tool_failed', message: baseMessage, retryable: false, cause };\n }\n if (lower.includes('bridge transport') || /bridge.*(closed|disconnect)/i.test(baseMessage)) {\n return { kind: 'bridge_failed', message: baseMessage, retryable: false, cause };\n }\n if (/context length|max.*tokens?.*exceeded|prompt is too long/i.test(baseMessage)) {\n return { kind: 'context_overflow', message: baseMessage, retryable: false, cause };\n }\n\n return { kind: 'unknown', message: baseMessage, retryable: false, cause };\n}\n\nfunction providerErrorToSubagentError(\n err: ProviderError,\n message: string,\n cause: SubagentError['cause'],\n): SubagentError {\n // Branch on the canonical taxonomy computed at error-construction time \u2014\n // this classifier must not re-derive kinds from status codes or regexes.\n // No default: the switch is exhaustive over ProviderErrorKind, so a new\n // kind refuses to compile until it is mapped here.\n switch (err.kind) {\n case 'rate_limit':\n case 'quota_exhausted':\n return {\n kind: 'provider_rate_limit',\n message,\n retryable: true,\n backoffMs: err.body?.retryAfterMs ?? 5_000,\n cause,\n };\n case 'auth':\n return { kind: 'provider_auth', message, retryable: false, cause };\n case 'timeout':\n case 'network':\n return { kind: 'provider_timeout', message, retryable: true, cause };\n case 'overloaded':\n case 'server':\n case 'stream_hang':\n return { kind: 'provider_5xx', message, retryable: true, backoffMs: 3_000, cause };\n case 'context_overflow':\n return { kind: 'context_overflow', message, retryable: false, cause };\n case 'invalid_request':\n case 'content_filter':\n case 'unknown':\n return { kind: 'unknown', message, retryable: err.retryable, cause };\n }\n}\n", "/**\n * Pre-built subagent role configurations for the WrongStack fleet.\n * These can be passed to `MultiAgentHost.spawn()` or used as templates\n * for the director's roster.\n */\nimport type { SubagentConfig } from '../types/multi-agent.js';\nimport { agentPrompt } from './agents/agent-prompts.js';\nimport { ALL_AGENT_DEFINITIONS, SHADOW_AGENT_SKILLS } from './agents/index.js';\n\nfunction defineAgent(\n id: string,\n name: string,\n promptRole: string = id,\n provider?: string,\n): SubagentConfig {\n return {\n id,\n name,\n role: id,\n prompt: agentPrompt(promptRole),\n ...(provider === undefined ? {} : { provider }),\n };\n}\n\n/**\n * Audit Log Agent \u2014 analyzes session logs, event streams, and traces.\n * Use for: post-mortems, trend analysis, operational insights.\n */\nexport const AUDIT_LOG_AGENT = defineAgent('audit-log', 'Audit Log');\n\n/**\n * Bug Hunter Agent \u2014 systematic bug and code smell detection.\n * Use for: pre-refactoring health checks, code review, regression prevention.\n */\nexport const BUG_HUNTER_AGENT = defineAgent('bug-hunter', 'Bug Hunter');\n\n/**\n * Refactor Planner Agent \u2014 structured refactoring planning.\n * Use for: large rewrites, technical debt reduction, architecture improvements.\n */\nexport const REFACTOR_PLANNER_AGENT = defineAgent('refactor-planner', 'Refactor Planner');\n\n/**\n * Security Scanner Agent \u2014 vulnerability and secret detection.\n * Use for: CI checks, pre-release audits, dependency vulnerability scanning.\n */\nexport const SECURITY_SCANNER_AGENT = defineAgent('security-scanner', 'Security Scanner');\n\n/**\n * Shadow Agent \u2014 one-shot fleet monitoring and intervention.\n * Use for: quiet anomaly checks and on-demand intervention.\n */\nconst SHADOW_AGENT: SubagentConfig = {\n ...defineAgent('shadow-agent', 'Shadow'),\n skillNames: [...SHADOW_AGENT_SKILLS],\n};\n\n/**\n * Critic Agent \u2014 evaluates code quality, architecture decisions, and\n * refactoring plans against project conventions and engineering standards.\n * Use for: real-time evaluation of bug reports, refactor plans, and\n * architectural proposals during collaborative debugging sessions.\n */\nconst CRITIC_AGENT = defineAgent('critic', 'Critic');\n\n/** Generic template used directly or cloned into project-specific roles. */\nexport const GENERIC_AGENT = defineAgent('generic', 'Generic Project Agent');\n\n/**\n * All agents in a map for easy lookup by role. The 75-role phase catalog\n * (`ALL_AGENT_DEFINITIONS`) already includes `critic` and the historical\n * audit/review specialists. Adding standalone `generic` and `shadow-agent`\n * roles produces 77 unique built-in role ids.\n */\nexport const FLEET_ROSTER: Record<string, SubagentConfig> = {\n 'audit-log': AUDIT_LOG_AGENT,\n 'bug-hunter': BUG_HUNTER_AGENT,\n 'refactor-planner': REFACTOR_PLANNER_AGENT,\n 'security-scanner': SECURITY_SCANNER_AGENT,\n critic: CRITIC_AGENT,\n generic: GENERIC_AGENT,\n 'shadow-agent': SHADOW_AGENT,\n ...Object.fromEntries(\n ALL_AGENT_DEFINITIONS.map((d) => [d.config.role as string, d.config] as const),\n ),\n};\n\n// ---------------------------------------------------------------------------\n// Default per-role budgets \u2014 tuned for token cost efficiency.\n//\n// Reduced from x10 to ~x5 to prevent runaway costs while keeping enough\n// headroom for productive multi-step tasks. A subagent that needs more\n// can explicitly set `timeoutMs`/`maxIterations`/`maxToolCalls` via the\n// delegate tool or the per-task `budget` field in spawn.\n//\n// Shrinking defaults means each subagent consumes fewer iterations and\n// tool calls before budget renegotiation kicks in, and a runaway agent\n// hits its ceiling sooner.\n// ---------------------------------------------------------------------------\nexport interface FleetRosterBudget {\n timeoutMs?: number | undefined;\n /** Idle reap window (ms). Resets on activity \u2014 see `applyRosterBudget`. */\n idleTimeoutMs?: number | undefined;\n maxIterations?: number | undefined;\n maxToolCalls?: number | undefined;\n maxTokens?: number | undefined;\n maxCostUsd?: number | undefined;\n}\n\n/**\n * Default idle window for delegated subagents: reap after 10 min with\n * NO activity (no iteration / tool call / streamed progress). An actively-\n * working agent resets this clock continuously, so it runs until its task\n * naturally ends. Power users can still impose a hard `timeoutMs` per delegate.\n */\nconst DEFAULT_IDLE_TIMEOUT_MS = 10 * 60 * 1000;\n\nexport const FLEET_ROSTER_BUDGETS: Record<string, FleetRosterBudget> = {\n 'audit-log': { timeoutMs: 3 * 60 * 60 * 1000, maxIterations: 2500, maxToolCalls: 7500 },\n 'bug-hunter': { timeoutMs: 5 * 60 * 60 * 1000, maxIterations: 4000, maxToolCalls: 10000 },\n 'refactor-planner': { timeoutMs: 4 * 60 * 60 * 1000, maxIterations: 3000, maxToolCalls: 9000 },\n 'security-scanner': { timeoutMs: 5 * 60 * 60 * 1000, maxIterations: 4000, maxToolCalls: 10000 },\n critic: { timeoutMs: 3 * 60 * 60 * 1000, maxIterations: 2000, maxToolCalls: 6000 },\n generic: { idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS, maxIterations: 2500, maxToolCalls: 7500 },\n 'shadow-agent': {\n idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS,\n maxIterations: 1000,\n maxToolCalls: 2500,\n // Monitoring passes routinely include a large system prompt plus fleet\n // context. 30k was below observed single-pass usage and therefore triggered\n // a post-response negotiation every run; 96k leaves headroom while the cost\n // and tool/iteration caps still bound runaway work.\n maxTokens: 96_000,\n maxCostUsd: 0.5,\n },\n ...Object.fromEntries(\n ALL_AGENT_DEFINITIONS.map((d) => [d.config.role as string, d.budget] as const),\n ),\n};\n\n/**\n * Apply roster budget to a config (only when the config has no explicit\n * budget fields set). This is called by the coordinator before dispatch.\n */\n// Generic default budget applied when no role matches and no explicit budget\n// fields are set. Used for `name` / free-form delegates. There is no default\n// wall-clock timeout \u2014 a delegated agent runs until its task naturally ends\n// (`end_turn`) or it stalls past the idle window. Iteration / tool-call ceilings\n// remain as a runaway backstop.\nconst GENERIC_SUBAGENT_BUDGET: FleetRosterBudget = {\n idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS,\n maxIterations: 2500,\n maxToolCalls: 7500,\n};\n\nexport function applyRosterBudget(cfg: SubagentConfig): SubagentConfig {\n // First try role-specific budget; fall back to generic for name-only delegates.\n const roleBudget = cfg.role ? FLEET_ROSTER_BUDGETS[cfg.role] : undefined;\n const defaultBudget = roleBudget ?? (cfg.name ? GENERIC_SUBAGENT_BUDGET : undefined);\n if (!defaultBudget) return cfg;\n return {\n ...cfg,\n // Wall-clock cap is opt-in only: forward an explicit `cfg.timeoutMs`, but\n // do NOT impose the roster's historical multi-hour wall-clock default \u2014 it\n // killed agents that were still actively working. Reaping is idle-based.\n timeoutMs: cfg.timeoutMs,\n // Idle window is the default reaper. Resets on activity, so a long-but-\n // productive run is never killed; only a genuine stall is reaped.\n idleTimeoutMs: cfg.idleTimeoutMs ?? defaultBudget.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS,\n maxIterations: cfg.maxIterations ?? defaultBudget.maxIterations,\n maxToolCalls: cfg.maxToolCalls ?? defaultBudget.maxToolCalls,\n maxTokens: cfg.maxTokens ?? defaultBudget.maxTokens,\n maxCostUsd: cfg.maxCostUsd ?? defaultBudget.maxCostUsd,\n };\n}\n\n/** Quick-access list for spawning all at once. */\nexport const ALL_FLEET_AGENTS = Object.values(FLEET_ROSTER);\n\n// ---------------------------------------------------------------------------\n// ACP external agents \u2014 WrongStack spawns these as subagents via ACP protocol.\n// Each agent runs its own loop; WrongStack sends tasks as ACP messages and\n// receives results. These don't go through makeAgentSubagentRunner \u2014 they\n// are handled by makeACPSubagentRunner in the CLI multi-agent layer.\n// ---------------------------------------------------------------------------\n\n/**\n * Cline \u2014 ACP-compatible coding agent by @asonix.\n * Spawned as: `npx @agentify/cline`\n */\nconst CLINE_AGENT = defineAgent('cline', 'Cline', 'acp-cline', 'acp');\n\n/**\n * Gemini CLI \u2014 Google's ACP-compatible command-line agent.\n * Spawned as: `gemini` (when gemini CLI is installed and in PATH)\n */\nconst GEMINI_CLI_AGENT = defineAgent('gemini-cli', 'Gemini CLI', 'acp-gemini-cli', 'acp');\n\n/**\n * GitHub Copilot (public preview) \u2014 ACP-compatible Copilot CLI agent.\n * Spawned as: `gh copilot` (when gh CLI with copilot extension is installed)\n */\nconst COPILOT_AGENT = defineAgent('copilot', 'GitHub Copilot', 'acp-copilot', 'acp');\n\n/**\n * OpenHands \u2014 AI coding agent by all-in.ai, ACP-compatible.\n * Spawned as: `openhands` (when installed)\n */\nconst OPENHANDS_AGENT = defineAgent('openhands', 'OpenHands', 'acp-openhands', 'acp');\n\n/**\n * Goose \u2014 IDE agent by ExoRL, ACP-compatible.\n * Spawned as: `goose` (when goose CLI is installed)\n */\nconst GOOSE_AGENT = defineAgent('goose', 'Goose', 'acp-goose', 'acp');\n\n/** All ACP external agents. */\nexport const ACP_AGENTS: SubagentConfig[] = [\n CLINE_AGENT,\n GEMINI_CLI_AGENT,\n COPILOT_AGENT,\n OPENHANDS_AGENT,\n GOOSE_AGENT,\n];\n\n// ACP agents share the same generous budgets as the built-in fleet agents.\n// External ACP agents may need more time than typical in-process subagents\n// since they run their own loops and may do tool-call round-trips.\nconst ACP_AGENT_BUDGET: FleetRosterBudget = {\n timeoutMs: 10 * 60 * 60 * 1000,\n maxIterations: 8000,\n maxToolCalls: 20000,\n};\nfor (const agent of ACP_AGENTS) {\n FLEET_ROSTER_BUDGETS[agent.role as string] = { ...ACP_AGENT_BUDGET };\n}\n\n/** Extended roster including ACP agents. */\nexport const FLEET_ROSTER_WITHACP: Record<string, SubagentConfig> = {\n ...FLEET_ROSTER,\n ...Object.fromEntries(ACP_AGENTS.map((a) => [a.role as string, a])),\n};\n", "/**\n * Subagent nickname pool \u2014 famous scientists, mathematicians, and computing pioneers.\n * Names are grouped by domain affinity so the nickname hints at the agent's role.\n */\n\nconst NICKNAME_POOL = {\n // Physics & fundamental sciences\n 'einstein': { name: 'Einstein', domain: 'physics' },\n 'newton': { name: 'Newton', domain: 'physics' },\n 'feynman': { name: 'Feynman', domain: 'physics' },\n 'dirac': { name: 'Dirac', domain: 'physics' },\n 'bohr': { name: 'Bohr', domain: 'physics' },\n 'planck': { name: 'Planck', domain: 'physics' },\n 'curie': { name: 'Curie', domain: 'physics' },\n 'fermi': { name: 'Fermi', domain: 'physics' },\n 'heisenberg': { name: 'Heisenberg', domain: 'physics' },\n 'schrodinger': { name: 'Schr\u00F6dinger', domain: 'physics' },\n\n // Mathematics\n 'euclid': { name: 'Euclid', domain: 'math' },\n 'gauss': { name: 'Gauss', domain: 'math' },\n 'turing': { name: 'Turing', domain: 'math' },\n 'poincare': { name: 'Poincar\u00E9', domain: 'math' },\n 'riemann': { name: 'Riemann', domain: 'math' },\n 'hilbert': { name: 'Hilbert', domain: 'math' },\n 'pythagoras': { name: 'Pythagoras', domain: 'math' },\n\n // Computing & information theory\n 'von-neumann': { name: 'Von Neumann', domain: 'computing' },\n 'shannon': { name: 'Shannon', domain: 'computing' },\n 'hopper': { name: 'Hopper', domain: 'computing' },\n 'backus': { name: 'Backus', domain: 'computing' },\n 'knuth': { name: 'Knuth', domain: 'computing' },\n 'torvalds': { name: 'Torvalds', domain: 'computing' },\n 'stallman': { name: 'Stallman', domain: 'computing' },\n 'berners-lee': { name: 'Berners-Lee', domain: 'computing' },\n 'babbage': { name: 'Babbage', domain: 'computing' },\n 'lovelace': { name: 'Lovelace', domain: 'computing' },\n 'klein': { name: 'Klein', domain: 'computing' },\n\n // Electronics & electrical engineering\n 'edison': { name: 'Edison', domain: 'ee' },\n 'tesla': { name: 'Tesla', domain: 'ee' },\n 'faraday': { name: 'Faraday', domain: 'ee' },\n 'maxwell': { name: 'Maxwell', domain: 'ee' },\n 'ohm': { name: 'Ohm', domain: 'ee' },\n 'bell': { name: 'Bell', domain: 'ee' },\n 'marconi': { name: 'Marconi', domain: 'ee' },\n 'lamarr': { name: 'Lamarr', domain: 'ee' },\n\n // General science / multi-disciplinary\n 'darwin': { name: 'Darwin', domain: 'biology' },\n 'mendel': { name: 'Mendel', domain: 'biology' },\n 'pasteur': { name: 'Pasteur', domain: 'biology' },\n 'hawking': { name: 'Hawking', domain: 'cosmology' },\n 'sagan': { name: 'Sagan', domain: 'cosmology' },\n\n // Exploration & navigation\n 'columbus': { name: 'Columbus', domain: 'exploration' },\n 'polo': { name: 'Polo', domain: 'exploration' },\n 'magellan': { name: 'Magellan', domain: 'exploration' },\n\n // Chemistry / materials\n 'lavoisier': { name: 'Lavoisier', domain: 'chemistry' },\n 'mendeleev': { name: 'Mendeleev', domain: 'chemistry' },\n} as const;\n\n/** Flat ordered list of all available nicknames \u2014 used for round-robin. */\nconst ALL_NICKNAMES = Object.entries(NICKNAME_POOL) as [NicknameKey, { name: string; domain: string }][];\n\n/** Reverse index: display name (e.g. \"Von Neumann\") \u2192 canonical pool key. */\nconst NAME_TO_KEY: Record<string, string> = Object.fromEntries(\n ALL_NICKNAMES.map(([key, entry]) => [entry.name, key]),\n);\n\n/** Domain \u2192 preferred nickname keys (fallback chain). */\nconst DOMAIN_PREFERENCES: Record<string, string[]> = {\n 'security': ['shannon', 'turing', 'lamarr', 'stallman'],\n 'bug-hunter': ['darwin', 'curie', 'feynman', 'fermi'],\n 'refactor': ['gauss', 'hilbert', 'euclid', 'planck'],\n 'audit-log': ['sagan', 'hawking', 'poincare', 'newton'],\n 'planner': ['hilbert', 'gauss', 'turing', 'euclid'],\n 'researcher': ['sagan', 'hawking', 'darwin', 'pasteur'],\n 'explorer': ['marconi', 'bell', 'columbus', 'polo'],\n 'testing': ['pasteur', 'curie', 'fermi', 'bohr'],\n 'frontend': ['lovelace', 'hopper', 'babbage', 'backus'],\n 'backend': ['torvalds', 'stallman', 'von-neumann', 'backus'],\n 'database': ['turing', 'shannon', 'backus', 'knuth'],\n 'devops': ['tesla', 'edison', 'faraday', 'bell'],\n 'security-scanner': ['shannon', 'turing', 'lamarr', 'stallman'],\n 'refactor-planner': ['gauss', 'hilbert', 'planck', 'newton'],\n 'architect': ['von-neumann', 'turing', 'gauss', 'hilbert'],\n 'critic': ['einstein', 'feynman', 'dirac', 'bohr'],\n 'e2e': ['hopper', 'bell', 'marconi', 'tesla'],\n 'performance': ['knuth', 'gauss', 'planck', 'feynman'],\n 'chaos': ['tesla', 'edison', 'curie', 'fermi'],\n 'cost': ['ohm', 'bell', 'marconi', 'tesla'],\n // default fallback\n 'default': ['einstein', 'newton', 'curie', 'tesla', 'edison', 'turing', 'shannon', 'hopper', 'knuth', 'stallman'],\n};\n\ntype NicknameKey = keyof typeof NICKNAME_POOL;\n\n/** Result of a nickname assignment. */\nexport interface NicknameAssignment {\n /**\n * Canonical pool key (e.g. `von-neumann`). This \u2014 NOT the display string \u2014 is\n * what callers must add to their `used` set and later remove on release.\n * Deriving the key by parsing the display string is unsafe: multi-word names\n * like \"Von Neumann\" would be truncated to \"von\" and never dedupe correctly.\n */\n key: string;\n /** Human display string, e.g. `Von Neumann (Backend)`. */\n display: string;\n}\n\n/**\n * Assign a unique nickname to a subagent based on its role.\n *\n * Returns both the canonical pool `key` (for the `used` set) and the formatted\n * `display` string (`Name (Role)`, e.g. `Einstein (Bug Hunter)`).\n *\n * @param role - The subagent's role id (e.g. 'bug-hunter', 'security-scanner')\n * @param used - Set of nickname KEYS already assigned in this fleet\n * (so no two subagents share the same base name)\n */\nexport function assignNickname(role: string, used: ReadonlySet<string>): NicknameAssignment {\n // 1. Build preference list: role-specific \u2192 default fallback\n const preferences = [\n ...(DOMAIN_PREFERENCES[role] ?? []),\n ...(DOMAIN_PREFERENCES['default'] ?? []),\n ];\n\n // 2. Find the first unassigned nickname from preferences. Skip keys that are\n // not in the pool \u2014 preference lists can drift out of sync with the pool\n // (typos, removed names), and an unknown key must not crash assignment.\n for (const key of preferences) {\n const entry = NICKNAME_POOL[key as NicknameKey];\n if (entry && !used.has(key)) {\n return { key, display: `${entry.name} (${formatRole(role)})` };\n }\n }\n\n // 3. Exhausted preferences \u2014 pick the first unused name round-robin style.\n for (const [key, entry] of ALL_NICKNAMES) {\n if (!used.has(key)) {\n return { key, display: `${entry.name} (${formatRole(role)})` };\n }\n }\n\n // 4. Pool exhausted \u2014 synthesize a stable, unique key/display pair.\n const counter = used.size + 1;\n return { key: `scientist-${counter}`, display: `Scientist #${counter} (${formatRole(role)})` };\n}\n\n/**\n * Resolve a previously-assigned display string back to its canonical pool key,\n * for release paths that only retained the formatted name (e.g. a manifest\n * entry). Strips the trailing ` (Role)` suffix, then matches the base name\n * against the pool. Returns `undefined` when the name is not a known nickname.\n *\n * Use this instead of `name.split(' ')[0]` \u2014 the latter mangles multi-word\n * names like \"Von Neumann\" and \"Berners-Lee\".\n */\nexport function nicknameKeyFromDisplay(display: string): string | undefined {\n const base = display.replace(/\\s*\\([^)]*\\)\\s*$/, '').trim();\n const key = NAME_TO_KEY[base];\n if (key) return key;\n const synthesized = base.match(/^Scientist #(\\d+)$/);\n return synthesized ? `scientist-${synthesized[1]}` : undefined;\n}\n\n/** Format role id into human-readable title-case. */\nfunction formatRole(role: string): string {\n return role\n .split(/[-_]/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(' ');\n}\n\n/**\n * Returns all available nickname keys. Useful for testing or reset logic.\n */\nexport function getAllNicknameKeys(): string[] {\n return Object.keys(NICKNAME_POOL);\n}\n", "import type {\n SubagentRunContext,\n SubagentRunner,\n TaskSpec,\n} from '../types/multi-agent.js';\nimport {\n BudgetExceededError,\n DECISION_TIMEOUT_MS,\n type SubagentBudget,\n TIMEOUT_PREEMPT_FRACTION,\n} from './subagent-budget.js';\n\nexport interface ExecuteSubagentWithTimeoutOptions {\n runner: SubagentRunner;\n task: TaskSpec;\n ctx: SubagentRunContext;\n budget: SubagentBudget;\n preemptFraction?: number | undefined;\n abortSubagent: (subagentId: string) => void;\n currentSessionId: () => string | undefined;\n}\n\nexport async function executeSubagentWithTimeout({\n runner,\n task,\n ctx,\n budget,\n preemptFraction = TIMEOUT_PREEMPT_FRACTION,\n abortSubagent,\n currentSessionId,\n}: ExecuteSubagentWithTimeoutOptions) {\n const initialTimeoutMs = budget.limits.timeoutMs;\n const idleLimitMs = budget.limits.idleTimeoutMs;\n if (initialTimeoutMs === undefined && idleLimitMs === undefined) {\n return runner(task, ctx);\n }\n\n const start = Date.now();\n let timer: ReturnType<typeof setTimeout> | null = null;\n enum PreemptState {\n ACTIVE = 'active',\n LOCKED = 'locked',\n }\n let preemptedCeiling: number | null = null;\n let preemptState: PreemptState = PreemptState.ACTIVE;\n let lastGrantActivityTs = -1;\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n const terminate = (kind: 'timeout' | 'idle_timeout', limit: number, used: number) => {\n abortSubagent(ctx.subagentId);\n reject(\n budget._events?.hasListenerFor('budget.threshold_reached')\n ? new Error(`subagent stopped: budget ${kind} (limit=${limit}, used=${used})`)\n : new BudgetExceededError(kind, limit, used),\n );\n };\n const armFor = (ms: number) => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(onTick, Math.max(0, ms));\n };\n const scheduleNext = () => {\n const wallLimit = budget.limits.timeoutMs ?? initialTimeoutMs;\n const wallRemaining =\n initialTimeoutMs === undefined\n ? Number.POSITIVE_INFINITY\n : (wallLimit as number) - (Date.now() - start);\n const idleRemaining =\n idleLimitMs === undefined\n ? Number.POSITIVE_INFINITY\n : (budget.limits.idleTimeoutMs ?? idleLimitMs) - budget.idleMs();\n const preemptRemaining =\n initialTimeoutMs === undefined || preemptedCeiling === wallLimit\n ? Number.POSITIVE_INFINITY\n : (wallLimit as number) * preemptFraction - (Date.now() - start);\n armFor(Math.max(25, Math.min(wallRemaining, idleRemaining, preemptRemaining)));\n };\n\n const negotiateTimeout = async (\n used: number,\n limit: number,\n ): Promise<'stop' | 'continue' | 'throw' | { extend: { timeoutMs?: number | undefined } }> => {\n const handler = budget.onThreshold;\n if (!handler) return 'stop';\n const result = handler({\n kind: 'timeout',\n used,\n limit,\n requestDecision: () => {\n if (!budget._events?.hasListenerFor('budget.threshold_reached')) {\n return Promise.resolve<'stop' | { extend: { timeoutMs?: number | undefined } }>('stop');\n }\n return new Promise<'stop' | { extend: { timeoutMs?: number | undefined } }>((resolveDecision) => {\n let settled = false;\n const resolve = (d: 'stop' | { extend: { timeoutMs?: number | undefined } }) => {\n if (settled) return;\n settled = true;\n resolveDecision(d);\n };\n const fallback = setTimeout(() => resolve('stop'), DECISION_TIMEOUT_MS);\n const sessionId = currentSessionId();\n budget._events?.emit('budget.threshold_reached', {\n ...(sessionId ? { sessionId } : {}),\n kind: 'timeout',\n used,\n limit,\n timeoutMs: DECISION_TIMEOUT_MS,\n extend: (extra) => {\n clearTimeout(fallback);\n queueMicrotask(() => resolve({ extend: extra }));\n },\n deny: () => {\n clearTimeout(fallback);\n resolve('stop');\n },\n });\n });\n },\n });\n return typeof result === 'string' ? result : await result;\n };\n\n const onTick = async () => {\n const elapsed = Date.now() - start;\n const wallLimit =\n initialTimeoutMs === undefined ? undefined : budget.limits.timeoutMs ?? initialTimeoutMs;\n const idleLimit =\n idleLimitMs === undefined ? undefined : budget.limits.idleTimeoutMs ?? idleLimitMs;\n const wallExceeded = wallLimit !== undefined && elapsed >= wallLimit;\n const idleExceeded = idleLimit !== undefined && budget.idleMs() >= idleLimit;\n\n if (idleExceeded && !wallExceeded) {\n const sessionId = currentSessionId();\n budget._events?.emit('budget.threshold_reached', {\n ...(sessionId ? { sessionId } : {}),\n kind: 'idle_timeout',\n used: budget.idleMs(),\n limit: idleLimit ?? 0,\n timeoutMs: DECISION_TIMEOUT_MS,\n extend: () => {},\n deny: () => {},\n });\n abortSubagent(ctx.subagentId);\n reject(new BudgetExceededError('idle_timeout', idleLimit ?? 0, budget.idleMs()));\n return;\n }\n\n if (\n wallLimit !== undefined &&\n !wallExceeded &&\n budget.onThreshold &&\n preemptState === PreemptState.ACTIVE &&\n elapsed >= wallLimit * preemptFraction\n ) {\n const activityTs = Date.now() - budget.idleMs();\n if (activityTs <= lastGrantActivityTs) {\n preemptState = PreemptState.LOCKED;\n preemptedCeiling = wallLimit;\n scheduleNext();\n return;\n }\n budget.setWatchdogNegotiation(wallLimit);\n try {\n const decision = await negotiateTimeout(elapsed, wallLimit);\n if (typeof decision !== 'string' && decision.extend.timeoutMs !== undefined) {\n budget.patchLimits({ timeoutMs: decision.extend.timeoutMs });\n lastGrantActivityTs = Date.now() - budget.idleMs();\n preemptState = PreemptState.ACTIVE;\n preemptedCeiling = null;\n } else {\n preemptState = PreemptState.LOCKED;\n preemptedCeiling = wallLimit;\n }\n } catch {\n preemptState = PreemptState.LOCKED;\n preemptedCeiling = wallLimit;\n } finally {\n budget.clearWatchdogNegotiation();\n }\n scheduleNext();\n return;\n }\n\n if (!wallExceeded) {\n scheduleNext();\n return;\n }\n\n const limit = wallLimit ?? 0;\n if (!budget.onThreshold) {\n abortSubagent(ctx.subagentId);\n reject(new BudgetExceededError('timeout', limit, elapsed));\n return;\n }\n budget.setWatchdogNegotiation(limit);\n try {\n const decision = await negotiateTimeout(elapsed, limit);\n if (decision === 'throw') {\n terminate('timeout', limit, elapsed);\n return;\n }\n if (decision === 'continue') {\n preemptState = PreemptState.LOCKED;\n preemptedCeiling = wallLimit;\n armFor(Math.max(1_000, limit));\n return;\n }\n if (decision === 'stop') {\n terminate('timeout', limit, elapsed);\n return;\n }\n if (decision.extend.timeoutMs !== undefined) {\n budget.patchLimits({ timeoutMs: decision.extend.timeoutMs });\n lastGrantActivityTs = Date.now() - budget.idleMs();\n preemptState = PreemptState.ACTIVE;\n preemptedCeiling = null;\n scheduleNext();\n return;\n }\n terminate('timeout', limit, elapsed);\n return;\n } catch (err) {\n abortSubagent(ctx.subagentId);\n reject(\n err instanceof BudgetExceededError\n ? err\n : new BudgetExceededError('timeout', limit, elapsed),\n );\n return;\n } finally {\n budget.clearWatchdogNegotiation();\n }\n };\n scheduleNext();\n });\n\n try {\n return await Promise.race([runner(task, ctx), timeoutPromise]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n", "import { randomInt } from 'node:crypto';\nimport { ProviderError, type ProviderErrorKind } from '../types/provider.js';\nimport type { RetryPolicy } from '../types/retry-policy.js';\nimport { NETWORK_ERR_RE } from './regex-patterns.js';\n\n/**\n * Upper bound for any Retry-After hint surfaced by a provider.\n *\n * The HTTP `Retry-After` header can carry either a delta-seconds\n * integer or an absolute HTTP-date. The latter can legitimately be\n * far in the future if the provider is asking us to back off for\n * minutes or hours. We never want to be stuck waiting that long \u2014\n * the agent kernel has its own pacing and a multi-minute single\n * retry would freeze the user. 60 seconds is the conventional cap\n * (it matches what most providers document as the practical upper\n * bound for a single rate-limit window).\n */\nconst MAX_RETRY_AFTER_MS = 60_000;\n\n/**\n * In-place attempts per canonical failure kind. Exhaustive by construction\n * (`Record<ProviderErrorKind, \u2026>`) \u2014 adding a new kind refuses to compile\n * until it gets an attempt budget. Zero for request-shaped failures\n * (auth / invalid_request / context_overflow / content_filter): replaying\n * the same request can't succeed.\n */\nconst MAX_ATTEMPTS_BY_KIND: Record<ProviderErrorKind, number> = {\n rate_limit: 5,\n quota_exhausted: 0,\n stream_hang: 2, // proxy-level timeout \u2014 retrying 5x wastes ~40s before fallback kicks in\n overloaded: 3,\n server: 3,\n timeout: 2,\n network: 2,\n auth: 0,\n invalid_request: 0,\n context_overflow: 0,\n content_filter: 0,\n unknown: 0,\n};\n\nexport class DefaultRetryPolicy implements RetryPolicy {\n shouldRetry(err: Error | ProviderError, attempt: number): boolean {\n const isProviderErr = err instanceof ProviderError || ProviderError.isProviderError(err);\n if (isProviderErr) {\n if (!(err as ProviderError).retryable) return false;\n return attempt < this.maxAttempts(err);\n }\n const msg = err.message ?? '';\n const isNetwork = NETWORK_ERR_RE.test(msg);\n if (isNetwork) return attempt < 2;\n return false;\n }\n\n maxAttempts(err: Error | ProviderError): number {\n const isProviderErr = err instanceof ProviderError || ProviderError.isProviderError(err);\n if (isProviderErr) {\n return MAX_ATTEMPTS_BY_KIND[(err as ProviderError).kind];\n }\n return 2;\n }\n\n /**\n * Compute the retry delay.\n *\n * Precedence:\n * 1. If `err` is a `ProviderError` with a populated\n * `body.retryAfterMs`, honour it \u2014 clamped into\n * [0, MAX_RETRY_AFTER_MS]. The provider told us exactly when\n * to come back; we should listen.\n * 2. Otherwise fall through to the exponential-with-jitter\n * schedule (`1000 * 2^attempt + jitter`, capped at 30s).\n *\n * `err` is optional for back-compat with the existing interface;\n * callers should pass it whenever available.\n */\n delayMs(attempt: number, err?: Error | ProviderError): number {\n const hint = retryAfterMsFromError(err);\n if (hint !== undefined) {\n // Server told us exactly when to come back. No jitter \u2014 the\n // server's clock is the authoritative source for \"when\"; adding\n // jitter here would either land us back inside the rate-limit\n // window or push us needlessly past it. We still clamp to the\n // 60s upper bound.\n return Math.max(0, Math.min(hint, MAX_RETRY_AFTER_MS));\n }\n const base = 1000;\n const exp = base * 2 ** attempt;\n // crypto.randomInt(min, max) is half-open: returns an integer in\n // [min, max). With (0, base) we get integers in [0, 1000), matching\n // the previous Math.random() * 1000 jitter range. Using crypto\n // (not Math.random) per the project's deterministic-source\n // convention (see docs/design-provider-health-gate.md).\n const jitter = randomInt(0, base);\n return Math.min(30_000, exp + jitter);\n }\n}\n\n/**\n * Extract a Retry-After hint in milliseconds from an error, if\n * present and well-formed. Returns `undefined` for missing, zero,\n * negative, or non-finite values so the caller falls through to the\n * exponential schedule.\n *\n * The field lives at `err.body.retryAfterMs` (ProviderErrorBody).\n * Providers populate this when they parse the upstream\n * `Retry-After` header (either as a delta-seconds integer or as an\n * absolute HTTP-date converted to ms-from-now).\n */\nfunction retryAfterMsFromError(err: Error | ProviderError | undefined): number | undefined {\n if (!err) return undefined;\n const isProviderErr = err instanceof ProviderError || ProviderError.isProviderError(err);\n if (!isProviderErr) return undefined;\n const ms = (err as ProviderError).body?.retryAfterMs;\n if (typeof ms !== 'number' || !Number.isFinite(ms) || ms <= 0) return undefined;\n return ms;\n}\n", "import { isTextBlock } from '../types/blocks.js';\nimport type { Message } from '../types/messages.js';\n\nconst PATH_HINT_PATTERN =\n /(?:(?:[A-Za-z]:)?[./\\\\]?[\\w@.-]+(?:[\\\\/][\\w@(). -]+)+\\.[A-Za-z0-9]{1,12})/g;\nconst PATH_BACKSLASH_PATTERN = /\\\\/g;\nconst PATH_TRIM_PATTERN = /^[\"'`]+|[\"'`),;:]+$/g;\nconst ERROR_LINE_PATTERN =\n /\\b(error|exception|failed|failure|fatal|panic|timeout|denied|enoent|eacces|eperm)\\b/i;\nconst NEWLINE_SPLIT_PATTERN = /\\r?\\n/;\nconst WHITESPACE_COLLAPSE_PATTERN = /\\s+/g;\n\n/**\n * Compact, information-dense representation of one message for selector and\n * summarizer calls. Kept in the neutral utils layer so models do not depend\n * on execution at runtime.\n */\nexport function buildCompactionPreview(message: Message, maxChars = 600): string {\n if (maxChars <= 0) return '';\n if (typeof message.content === 'string') {\n return truncatePreview(message.content, maxChars);\n }\n\n const parts: string[] = [];\n for (const block of message.content) {\n if (isTextBlock(block)) {\n const text = truncatePreview(block.text, maxChars);\n if (text) parts.push(text);\n continue;\n }\n if (block.type === 'tool_use') {\n const input = truncatePreview(safePreviewString(block.input), 220);\n parts.push(`[tool_use: ${block.name}${input ? `; input=${input}` : ''}]`);\n continue;\n }\n if (block.type === 'tool_result') {\n const raw = safePreviewString(block.content);\n const details: string[] = [block.is_error ? 'error' : 'ok'];\n if (block.name) details.push(`tool=${block.name}`);\n const files = extractPathHints(raw).slice(0, 5);\n if (files.length > 0) details.push(`files=${files.join(', ')}`);\n const error = firstErrorLine(raw);\n if (error) details.push(`error=${error}`);\n const sample = truncatePreview(raw, 260);\n if (sample) details.push(`sample=${sample}`);\n parts.push(`[tool_result: ${details.join('; ')}]`);\n continue;\n }\n parts.push(`[${block.type}]`);\n }\n return truncatePreview(parts.join(' '), maxChars);\n}\n\nfunction safePreviewString(value: unknown): string {\n if (typeof value === 'string') return value;\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nfunction truncatePreview(value: string, maxChars: number): string {\n const compact = value.replace(WHITESPACE_COLLAPSE_PATTERN, ' ').trim();\n if (compact.length <= maxChars) return compact;\n return `${compact.slice(0, Math.max(0, maxChars - 1))}\u2026`;\n}\n\nfunction extractPathHints(content: unknown): string[] {\n const text = safePreviewString(content);\n const out = new Set<string>();\n for (const match of text.matchAll(PATH_HINT_PATTERN)) {\n const clean = match[0]?.replace(PATH_BACKSLASH_PATTERN, '/').replace(PATH_TRIM_PATTERN, '');\n if (clean) out.add(clean);\n }\n return [...out];\n}\n\nfunction firstErrorLine(content: unknown): string | undefined {\n const text = safePreviewString(content);\n for (const line of text.split(NEWLINE_SPLIT_PATTERN)) {\n if (!ERROR_LINE_PATTERN.test(line)) continue;\n const trimmed = line.replace(WHITESPACE_COLLAPSE_PATTERN, ' ').trim();\n if (trimmed) return truncatePreview(trimmed, 220);\n }\n return undefined;\n}\n", "import { expectDefined } from '../utils/expect-defined.js';\nimport { estimateMessageTokens, estimateTextTokens } from '../utils/token-estimate.js';\nimport { isTextBlock } from '../types/blocks.js';\nimport type { Logger } from '../types/logger.js';\nimport { noOpLogger } from '../infrastructure/logger.js';\nimport type { Message } from '../types/messages.js';\nimport type { Provider, Request } from '../types/provider.js';\nimport type { MessageSelector, SelectorResult } from '../types/selector.js';\nimport type { OneShotOrchestrator } from '../execution/one-shot-llm.js';\nimport { buildCompactionPreview } from '../utils/compaction-preview.js';\nimport { readBundledInstructionText } from '../utils/instruction-file.js';\nexport interface LLMSelectorOptions {\n /** Provider used for the selector LLM call. Required. */\n provider: Provider;\n /** Model for the selector. Defaults to the provider's default model. */\n model?: string | undefined;\n /**\n * Maximum tokens to keep in context (target budget).\n * Selector will aim to keep total content below this.\n */\n maxContextTokens?: number | undefined;\n /**\n * Prompt instructing the selector how to behave.\n * Should guide the LLM on importance tiers and output format.\n */\n systemPrompt?: string | undefined;\n /**\n * Maximum output tokens for the selector LLM call.\n * Controls both the JSON response budget and the token reservation for the\n * history text budget calculation (default: 1024).\n */\n maxOutputTokens?: number | undefined;\n /**\n * OneShotOrchestrator for the selector LLM call. When set, uses it\n * instead of direct provider.complete(), gaining fallback chain support.\n */\n oneShotOrchestrator?: OneShotOrchestrator | undefined;\n /** Structured logger. Defaults to noOpLogger (silent). */\n logger?: Logger | undefined;\n}\n\nconst DEFAULT_SYSTEM_PROMPT = readBundledInstructionText('llm/llm-selector.md');\n\n/**\n * Format messages as a compact text dump for the selector LLM.\n * Uses token estimation (not character count) to budget the output,\n * so long sessions don't silently truncate the selector's view of history.\n */\nfunction formatMessages(messages: Message[], maxTokens = 2048): string {\n const previewChars = Math.max(\n 120,\n Math.min(600, Math.floor((maxTokens * 3.2) / Math.max(1, messages.length))),\n );\n const lines: Array<{ index: number; text: string; tokens: number }> = [];\n for (let i = 0; i < messages.length; i++) {\n const m = expectDefined(messages[i]);\n const role = m.role.padEnd(10, ' ');\n const line = `[${i}][${role}]: ${buildCompactionPreview(m, previewChars)}`;\n lines.push({ index: i, text: line, tokens: estimateTextTokens(line) });\n }\n\n const total = lines.reduce((sum, line) => sum + line.tokens, 0);\n if (total <= maxTokens) return lines.map((line) => line.text).join('\\n');\n\n // A selector must always see the live working tail. Fill the remainder from\n // the oldest side so long histories retain both the original constraints\n // and the current task, with an explicit marker for any omitted middle.\n const recentCount = Math.min(8, lines.length);\n const recentStart = lines.length - recentCount;\n const tail: typeof lines = [];\n let usedTokens = 0;\n for (let i = lines.length - 1; i >= recentStart; i--) {\n const line = expectDefined(lines[i]);\n if (tail.length >= 2 && usedTokens + line.tokens > Math.floor(maxTokens * 0.45)) continue;\n tail.unshift(line);\n usedTokens += line.tokens;\n }\n\n const head: typeof lines = [];\n for (let i = 0; i < recentStart; i++) {\n const line = expectDefined(lines[i]);\n if (usedTokens + line.tokens > maxTokens) break;\n head.push(line);\n usedTokens += line.tokens;\n }\n const omitted = Math.max(0, recentStart - head.length);\n const marker = omitted > 0 ? [`[\u2026 ${omitted} middle message(s) omitted from selector preview \u2026]`] : [];\n return [...head.map((line) => line.text), ...marker, ...tail.map((line) => line.text)].join('\\n');\n}\n\n/**\n * LLM-powered message selector. Calls a sub-LLM to analyze the\n * message history and produce a keep/collapse plan \u2014 more surgical\n * than fixed-window rules.\n */\nexport class LLMSelector implements MessageSelector {\n private readonly provider: Provider;\n private readonly model: string;\n private readonly maxContextTokens: number;\n private readonly systemPrompt: string;\n private readonly maxOutputTokens: number;\n private readonly oneShotOrchestrator?: OneShotOrchestrator | undefined;\n private readonly logger: Logger;\n\n constructor(opts: LLMSelectorOptions) {\n this.provider = opts.provider;\n this.model = opts.model ?? 'unknown';\n this.logger = opts.logger ?? noOpLogger;\n if (\n this.model === 'unknown' &&\n (process.env['NODE_ENV'] === 'development' || process.env['WRONGSTACK_DEBUG'] === '1')\n ) {\n this.logger.warn(\n '[LLMSelector] model not set \u2014 selector will use the provider default. Set `model` explicitly in LLMSelectorOptions to silence this warning.',\n );\n }\n this.maxContextTokens = opts.maxContextTokens ?? 40_000;\n this.systemPrompt = opts.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;\n this.maxOutputTokens = opts.maxOutputTokens ?? 1024;\n this.oneShotOrchestrator = opts.oneShotOrchestrator;\n }\n\n async select(messages: Message[], maxToKeep: number): Promise<SelectorResult> {\n const effectiveBudget = Math.min(maxToKeep, this.maxContextTokens);\n\n const totalTokens = estimateMessageTokens(messages);\n const systemText = `${this.systemPrompt}\\n\\nConversation (${messages.length} messages, ~${totalTokens} tokens, budget: ${effectiveBudget}):\\n`;\n // Reserve tokens for the system prefix and output (maxOutputTokens), then give the\n // rest to the formatted history so the selector sees the maximum possible context.\n const systemTokens = estimateTextTokens(systemText);\n const historyBudget = Math.max(512, effectiveBudget - systemTokens - this.maxOutputTokens);\n\n // Build a concise representation of the conversation within the token budget\n const historyText = formatMessages(messages, historyBudget);\n\n // Add instruction to stay within budget\n const budgetInstruction =\n totalTokens > effectiveBudget\n ? `\\n\\nIMPORTANT: Total conversation (${totalTokens} tokens) exceeds budget (${effectiveBudget}). You MUST collapse enough to fit. Prefer collapsing older/lower-importance ranges.`\n : '';\n\n const req: Request = {\n model: this.model,\n system: [{ type: 'text', text: systemText + budgetInstruction }],\n messages: [{ role: 'user', content: historyText }],\n maxTokens: this.maxOutputTokens,\n };\n\n let raw: string;\n const ac = new AbortController();\n try {\n if (this.oneShotOrchestrator) {\n const result = await this.oneShotOrchestrator.call({\n system: systemText + budgetInstruction,\n userPrompt: historyText,\n maxTokens: this.maxOutputTokens,\n timeoutMs: 30_000,\n });\n if (result.error) throw new Error(result.error);\n raw = result.text;\n } else {\n // 30-second timeout so a stuck selector LLM call can't hang the compactor.\n const timeoutSignal = AbortSignal.timeout(30_000);\n const res = await this.provider.complete(req, {\n signal: AbortSignal.any([ac.signal, timeoutSignal]),\n });\n const textBlocks = res.content.filter(isTextBlock);\n raw = textBlocks\n .map((b) => b.text)\n .join('\\n')\n .trim();\n }\n } catch (err) {\n if (err instanceof Error) {\n this.logger.warn(`selector call failed, using recency fallback: ${err.message}`, {\n event: 'llm_selector.call_failed',\n });\n }\n return this.fallbackSelect(messages, effectiveBudget);\n } finally {\n ac.abort();\n }\n\n return this.parseSelectorOutput(raw, messages);\n }\n\n private fallbackSelect(messages: Message[], budget: number): SelectorResult {\n // Simple fallback: keep from the end until we hit budget\n const toKeep: SelectorResult['kept'] = [];\n const toCollapse: SelectorResult['collapsed'] = [];\n\n let tokenCount = 0;\n let startIdx = 0;\n\n // Scan from the end backwards\n for (let i = messages.length - 1; i >= 0; i--) {\n const m = expectDefined(messages[i]);\n const cost = estimateMessageTokens([m]);\n\n if (tokenCount + cost <= budget) {\n tokenCount += cost;\n } else {\n startIdx = i + 1;\n break;\n }\n }\n\n if (startIdx > 0) {\n toCollapse.push({ from: 0, to: startIdx - 1 });\n }\n toKeep.push({ from: startIdx, to: messages.length - 1, importance: 'high' });\n\n return {\n kept: toKeep,\n collapsed: toCollapse,\n reasoning: `Fallback: kept last ${messages.length - startIdx} messages within ${budget} token budget`,\n };\n }\n\n /**\n * Parse and validate the raw LLM output into a SelectorResult.\n * Falls back to recency-based selection if the LLM output is malformed,\n * out-of-bounds, or internally inconsistent.\n */\n private parseSelectorOutput(raw: string, messages: Message[]): SelectorResult {\n const messageCount = messages.length;\n if (messageCount === 0) {\n return { kept: [], collapsed: [], reasoning: 'empty session' };\n }\n\n // Try to extract JSON from the response\n const jsonStart = raw.indexOf('{');\n const jsonEnd = raw.lastIndexOf('}');\n if (jsonStart === -1 || jsonEnd === -1) {\n return this.fallbackSelect(messages, this.maxContextTokens);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw.slice(jsonStart, jsonEnd + 1));\n } catch {\n return this.fallbackSelect(messages, this.maxContextTokens);\n }\n\n const obj = parsed as Record<string, unknown>;\n const keptRaw =\n (obj.kept as Array<{ from: number; to: number; importance: string }> | undefined) ?? [];\n const collapsedRaw =\n (obj.collapsed as Array<{ from: number; to: number; summary?: string | undefined }> | undefined) ?? [];\n\n // Validate kept ranges \u2014 must be within [0, messageCount), from <= to\n const kept: SelectorResult['kept'] = [];\n for (const k of keptRaw) {\n if (\n typeof k.from !== 'number' ||\n typeof k.to !== 'number' ||\n k.from < 0 ||\n k.to >= messageCount ||\n k.from > k.to\n ) {\n return this.fallbackSelect(messages, this.maxContextTokens);\n }\n kept.push({\n from: k.from,\n to: k.to,\n importance: (k.importance ?? 'medium') as 'critical' | 'high' | 'medium',\n });\n }\n\n // Validate collapsed ranges \u2014 same bounds check\n const collapsed: SelectorResult['collapsed'] = [];\n for (const c of collapsedRaw) {\n if (\n typeof c.from !== 'number' ||\n typeof c.to !== 'number' ||\n c.from < 0 ||\n c.to >= messageCount ||\n c.from > c.to\n ) {\n return this.fallbackSelect(messages, this.maxContextTokens);\n }\n collapsed.push({ from: c.from, to: c.to, summary: c.summary });\n }\n\n // Check for overlaps: kept ranges must not overlap with each other or with collapsed ranges\n const allRanges: Array<{ from: number; to: number }> = [...kept, ...collapsed];\n for (let i = 0; i < allRanges.length; i++) {\n const a = allRanges[i];\n if (!a) continue;\n for (let j = i + 1; j < allRanges.length; j++) {\n const b = allRanges[j];\n if (!b) continue;\n // Overlap: a starts before b ends AND a ends after b starts\n if (a.from <= b.to && a.to >= b.from) {\n return this.fallbackSelect(messages, this.maxContextTokens);\n }\n }\n }\n\n return {\n kept,\n collapsed,\n reasoning: typeof obj.reasoning === 'string' ? obj.reasoning : '',\n };\n }\n}\n", "import type { Context } from '../core/context.js';\nimport { LLMSelector } from '../models/llm-selector.js';\nimport { isTextBlock } from '../types/blocks.js';\nimport type { Logger } from '../types/logger.js';\nimport { noOpLogger } from '../infrastructure/logger.js';\nimport {\n type CompactionSummaryCache,\n compactionSummaryKey,\n defaultCompactionSummaryCache,\n} from './compaction-summary-cache.js';\nimport type { CompactReport, Compactor } from '../types/compactor.js';\nimport type { Message } from '../types/messages.js';\nimport type { Provider, Request } from '../types/provider.js';\nimport type { MessageSelector, SelectorResult } from '../types/selector.js';\nimport { estimateRequestTokens } from '../utils/token-estimate.js';\nimport { repairToolUseAdjacency } from '../utils/message-invariants.js';\nimport { readBundledInstructionText } from '../utils/instruction-file.js';\nimport { buildCompactionPreview } from '../utils/compaction-preview.js';\nimport {\n buildContextEvidenceDigest,\n checkCompactionQuality,\n injectEvidenceFloor,\n} from '../utils/context-evidence.js';\nimport {\n dedupStaleReads,\n eliseOldToolResults as coreEliseOldToolResults,\n estimateMessages,\n findPreserveStart,\n setCompactionDebugLogger,\n} from './compaction-core.js';\n\n/**\n * Options for SelectiveCompactor \u2014 the most configurable compactor.\n */\nexport interface SelectiveCompactorOptions {\n /** Provider for LLM calls (selector + summarizer). Required. */\n provider: Provider;\n /** Selector for LLM-driven importance analysis. */\n selector?: MessageSelector | undefined;\n /** Fraction of maxContext that triggers a warning (default 0.5). */\n warnThreshold?: number | undefined;\n /** Fraction of maxContext that triggers soft compaction (default 0.65). */\n softThreshold?: number | undefined;\n /** Fraction of maxContext that triggers hard compaction (default 0.8). */\n hardThreshold?: number | undefined;\n /** Max context window in tokens (used for threshold fraction math). */\n maxContext?: number | undefined;\n /** How many recent (user+assistant) pairs to always preserve (default 4). */\n preserveK?: number | undefined;\n /** Token threshold below which tool results are not elided (default 300). */\n eliseThreshold?: number | undefined;\n /** Model for selector LLM calls (default: same as provider default). */\n selectorModel?: string | undefined;\n /** Max output tokens for the selector LLM call (default: 1024). */\n selectorMaxOutputTokens?: number | undefined;\n /** Summarizer model for collapsed ranges (default: same as selectorModel). */\n summarizerModel?: string | undefined;\n /** Structured logger. Defaults to noOpLogger (silent). */\n logger?: Logger | undefined;\n /** Prompt for the summarizer sub-LLM. */\n summarizerPrompt?: string | undefined;\n /** Shared cache for successful semantic summaries. */\n summaryCache?: CompactionSummaryCache | undefined;\n}\n\n/**\n * SelectiveCompactor uses an LLM-driven MessageSelector to make\n * surgical decisions about which message ranges to keep vs collapse.\n *\n * Compared to HybridCompactor / IntelligentCompactor:\n * - HybridCompactor: rule-based (preserveK + elision), no LLM calls\n * - IntelligentCompactor: LLM summarization but no structured selection\n * - SelectiveCompactor: full LLM-driven selection + optional summarization\n */\nexport class SelectiveCompactor implements Compactor {\n private readonly provider: Provider;\n private readonly selector: MessageSelector;\n private readonly warnThreshold: number;\n private readonly softThreshold: number;\n private readonly hardThreshold: number;\n private readonly maxContext: number;\n private readonly preserveK: number;\n private readonly eliseThreshold: number;\n private readonly summarizerModel: string | undefined;\n private readonly summarizerPrompt: string;\n private readonly summaryCache: CompactionSummaryCache;\n private readonly logger: Logger;\n\n constructor(opts: SelectiveCompactorOptions) {\n this.provider = opts.provider;\n this.selector =\n opts.selector ?? new LLMSelector({ provider: opts.provider, model: opts.selectorModel, maxOutputTokens: opts.selectorMaxOutputTokens });\n this.warnThreshold = opts.warnThreshold ?? 0.5;\n this.softThreshold = opts.softThreshold ?? 0.65;\n this.hardThreshold = opts.hardThreshold ?? 0.8;\n this.maxContext = opts.maxContext ?? 128_000;\n this.preserveK = opts.preserveK ?? 4;\n this.eliseThreshold = opts.eliseThreshold ?? 300;\n // Leave undefined when unset so summarizeRange() can fall back to the\n // live ctx.model (mirrors IntelligentCompactor). Never send a 'unknown'\n // sentinel to the provider \u2014 that yields a 400 in non-dev deployments.\n // The debug event below makes this potentially expensive fallback observable.\n this.summarizerModel = opts.summarizerModel ?? opts.selectorModel;\n this.summaryCache = opts.summaryCache ?? defaultCompactionSummaryCache;\n this.logger = opts.logger ?? noOpLogger;\n // Wire the module-level compaction debug logger so instrumentation\n // in compaction-core.ts (emitCompactionMetrics, findPreserveStart,\n // eliseOldToolResults) uses structured logging when available.\n setCompactionDebugLogger(this.logger);\n if (this.summarizerModel === undefined) {\n this.logger.debug(\n '[SelectiveCompactor] summarizerModel not set \u2014 will fall back to ctx.model at summarize time. Set `summarizerModel` explicitly to avoid using the primary model for summaries.',\n );\n }\n this.summarizerPrompt =\n opts.summarizerPrompt ??\n readBundledInstructionText('llm/selective-compactor-summarizer.md');\n }\n\n async compact(ctx: Context, opts: { aggressive?: boolean | undefined } = {}): Promise<CompactReport> {\n const beforeTokens = this.estimateTokens(ctx.messages);\n const beforeFull = this.estimateFullRequest(ctx);\n const reductions: CompactReport['reductions'] = [];\n\n // Use full request tokens for threshold decisions \u2014 messages alone are inaccurate.\n const load = beforeFull / this.maxContext;\n const shouldCompact = load >= this.warnThreshold || opts.aggressive;\n\n if (!shouldCompact) {\n // Only do lightweight elision if below warn threshold\n const saved = this.eliseOldToolResults(ctx);\n if (saved > 0) reductions.push({ phase: 'elision', saved });\n const dedupSaved = this.dedupStaleReads(ctx);\n if (dedupSaved > 0) reductions.push({ phase: 'elision', saved: dedupSaved });\n const repair = this.repairProtocolAdjacency(ctx);\n return this.finalize(ctx, beforeTokens, beforeFull, reductions, repair);\n }\n\n // Phase 1: elision \u2014 always run first to get a baseline reduction\n const savedElision = this.eliseOldToolResults(ctx);\n if (savedElision > 0) reductions.push({ phase: 'elision', saved: savedElision });\n const dedupSaved = this.dedupStaleReads(ctx);\n if (dedupSaved > 0) reductions.push({ phase: 'elision', saved: dedupSaved });\n\n // Phase 2: LLM-driven selective compaction\n const afterPhase1 = this.estimateTokens(ctx.messages);\n const targetBudget = this.computeTargetBudget(load);\n\n if (afterPhase1 > targetBudget) {\n const savedSelective = await this.runSelector(ctx, targetBudget);\n if (savedSelective > 0) reductions.push({ phase: 'selective', saved: savedSelective });\n }\n\n const repair = this.repairProtocolAdjacency(ctx);\n return this.finalize(ctx, beforeTokens, beforeFull, reductions, repair);\n }\n\n /**\n * Compute after-tokens, run the shared quality check, inject the evidence\n * floor when compaction dropped the intent/path anchor, and assemble the\n * report \u2014 shared by both exit paths so every SelectiveCompactor run reports\n * quality and carries a `[context_state]` evidence digest like the others.\n */\n private finalize(\n ctx: Context,\n beforeTokens: number,\n beforeFull: number,\n reductions: CompactReport['reductions'],\n repaired: CompactReport['repaired'],\n ): CompactReport {\n const evidenceDigest = buildContextEvidenceDigest(ctx) || undefined;\n let afterTokens = this.estimateTokens(ctx.messages);\n let afterFull = this.estimateFullRequest(ctx);\n const quality = checkCompactionQuality(ctx, {\n evidenceDigest,\n reduced: beforeTokens > afterTokens || beforeFull > afterFull,\n });\n if (injectEvidenceFloor(ctx, quality)) {\n afterTokens = this.estimateTokens(ctx.messages);\n afterFull = this.estimateFullRequest(ctx);\n }\n return {\n before: beforeTokens,\n after: afterTokens,\n fullRequestTokensBefore: beforeFull,\n fullRequestTokensAfter: afterFull,\n reductions,\n repaired,\n evidenceDigest,\n quality,\n };\n }\n\n /**\n * Estimate the full API request token count: messages + systemPrompt + toolDefs.\n * This is the accurate figure for context-window pressure monitoring.\n */\n private estimateFullRequest(ctx: Context): number {\n const breakdown = estimateRequestTokens(ctx.messages, ctx.systemPrompt, ctx.tools ?? []);\n return breakdown.total;\n }\n\n private repairProtocolAdjacency(ctx: Context): CompactReport['repaired'] {\n const repaired = repairToolUseAdjacency(ctx.messages);\n if (repaired.report.changed) ctx.state.replaceMessages(repaired.messages);\n return repaired.report.changed\n ? {\n removedToolUses: repaired.report.removedToolUses,\n removedToolResults: repaired.report.removedToolResults,\n removedMessages: repaired.report.removedMessages,\n }\n : undefined;\n }\n\n /**\n * Run the LLM selector to decide what to keep vs collapse.\n * Returns the token savings achieved.\n */\n private async runSelector(ctx: Context, targetBudget: number): Promise<number> {\n const before = this.estimateTokens(ctx.messages);\n\n let result: SelectorResult;\n try {\n result = await this.selector.select(ctx.messages, targetBudget);\n } catch {\n // Fallback to aggressive recency preservation\n return this.aggressiveRecencyTrim(ctx);\n }\n\n // Execute the selector's plan\n await this.executePlan(ctx, result);\n\n const after = this.estimateTokens(ctx.messages);\n return Math.max(0, before - after);\n }\n\n /**\n * Execute a SelectorResult plan: collapse/remove ranges and\n * insert summaries where the selector provided them.\n */\n private async executePlan(ctx: Context, plan: SelectorResult): Promise<void> {\n if (ctx.messages.length === 0) return;\n\n // Process collapsed ranges in reverse order to preserve indices. We work\n // on a local copy and commit through `ctx.state.replaceMessages` at the\n // end so subscribers see a single state change for the whole rewrite.\n const messages = [...ctx.messages];\n // preserveK is configured as recent user/assistant pairs. The shared\n // boundary helper counts individual messages, so convert pairs to a\n // message count and enforce the live-tail invariant independently of the\n // ranges returned by the selector.\n const preserveStart = findPreserveStart(messages, this.preserveK * 2);\n const sortedCollapsed = plan.collapsed\n .map((range) => ({ ...range, to: Math.min(range.to, preserveStart - 1) }))\n .filter((range) => range.from >= 0 && range.from <= range.to)\n .sort((a, b) => b.from - a.from);\n\n for (const range of sortedCollapsed) {\n if (range.from < 0 || range.to >= messages.length || range.from > range.to) continue;\n\n const toSummarize = messages.slice(range.from, range.to + 1);\n let summary = range.summary;\n if (!summary) {\n summary = await this.summarizeRange(toSummarize, ctx);\n }\n\n // The selector works from a compact overview. Preserve deterministic\n // evidence from actual tool blocks so file paths and the first failure\n // are not lost even when its prose summary omits them.\n const toolEvidence = this.toolEvidence(toSummarize);\n if (toolEvidence) summary = `${summary}\\n[tool evidence] ${toolEvidence}`;\n\n const summaryMsg: Message = {\n role: 'system',\n content: `[prior_turns_${range.from}-${range.to}: ${summary}]`,\n };\n\n messages.splice(range.from, range.to - range.from + 1, summaryMsg);\n }\n\n ctx.state.replaceMessages(messages);\n }\n\n private async summarizeRange(messages: Message[], ctx: Context): Promise<string> {\n const systemText = `${this.summarizerPrompt}\\n\\nSummarize the following message range:`;\n const body = messages.map((m, i) => `[${i}] ${m.role}: ${this.messagePreview(m)}`).join('\\n');\n const model = this.summarizerModel ?? ctx.model;\n const key = compactionSummaryKey(model, systemText, messages);\n\n try {\n return await this.summaryCache.getOrCreate(key, async () => {\n const req: Request = {\n model,\n system: [{ type: 'text', text: systemText }],\n messages: [{ role: 'user', content: body }],\n maxTokens: 512,\n };\n // 30-second timeout so a stuck summarizer can't hang compaction.\n const timeoutSignal = AbortSignal.timeout(30_000);\n const res = await this.provider.complete(req, {\n signal: AbortSignal.any([ctx.signal, timeoutSignal]),\n });\n return (\n res.content\n .filter(isTextBlock)\n .map((b) => b.text)\n .join('\\n')\n .trim() || '(empty)'\n );\n });\n } catch {\n return `[${messages.length} earlier turns omitted]`;\n }\n }\n\n private messagePreview(m: Message): string {\n return buildCompactionPreview(m, 700);\n }\n\n private toolEvidence(messages: Message[]): string {\n const evidence: string[] = [];\n for (const message of messages) {\n if (typeof message.content === 'string') continue;\n if (!message.content.some((block) => block.type === 'tool_use' || block.type === 'tool_result')) continue;\n const preview = buildCompactionPreview(message, 360);\n if (preview) evidence.push(preview);\n if (evidence.join(' ').length >= 1400) break;\n }\n const joined = evidence.join(' ');\n return joined.length <= 1400 ? joined : `${joined.slice(0, 1399)}\u2026`;\n }\n\n /**\n * Fallback when selector fails: aggressively trim from the oldest end\n * until we hit targetBudget.\n */\n private aggressiveRecencyTrim(ctx: Context): number {\n const messages = ctx.messages;\n const preserveIdx = Math.max(0, messages.length - this.preserveK * 2);\n\n if (preserveIdx <= 0) return 0;\n\n // Find safe boundary near preserveIdx\n let boundary = preserveIdx;\n for (let i = preserveIdx; i < messages.length && i < preserveIdx + 6; i++) {\n const m = messages[i];\n if (!m) continue;\n if (m.role === 'user' && this.hasTextContent(m)) {\n boundary = i;\n break;\n }\n }\n\n const removed = messages.slice(0, boundary);\n const removedTokens = this.estimateTokens(removed);\n\n const summaryMsg: Message = {\n role: 'system',\n content: `[${removed.length} earlier turns trimmed \u2014 see session log for details]`,\n };\n const tail = messages.slice(boundary);\n ctx.state.replaceMessages([summaryMsg, ...tail]);\n\n return Math.max(0, removedTokens - this.estimateTokens([summaryMsg]));\n }\n\n private computeTargetBudget(load: number): number {\n if (load >= this.hardThreshold) {\n return Math.floor(this.maxContext * 0.5); // keep only 50%\n }\n if (load >= this.softThreshold) {\n return Math.floor(this.maxContext * 0.65); // keep 65%\n }\n return Math.floor(this.maxContext * 0.75); // keep 75% at warn\n }\n\n private eliseOldToolResults(ctx: Context): number {\n // Delegate to the shared core so SelectiveCompactor gets the same\n // tool_use/tool_result pair preservation as the other compactors \u2014 its\n // previous local copy lacked the forward walk and could elide the result\n // of a tool call it was supposed to keep.\n const result = coreEliseOldToolResults(ctx.messages, {\n preserveK: this.preserveK,\n eliseThreshold: this.eliseThreshold,\n });\n if (result.changed) ctx.state.replaceMessages(result.messages);\n return result.saved;\n }\n\n /** Collapse superseded repeated reads that slipped under the elise threshold. */\n private dedupStaleReads(ctx: Context): number {\n const result = dedupStaleReads(ctx.messages, ctx.contextEvidence?.repeatedReads ?? [], {\n preserveK: this.preserveK,\n });\n if (result.changed) ctx.state.replaceMessages(result.messages);\n return result.saved;\n }\n\n private hasTextContent(m: Message): boolean {\n if (typeof m.content === 'string') return m.content.trim().length > 0;\n return m.content.some((b) => b.type === 'text' && b.text.trim().length > 0);\n }\n\n /**\n * Estimate message-array tokens via the shared `estimateMessages` primitive\n * so SelectiveCompactor's before/after/load figures agree with the\n * middleware threshold math and the other compactors. Previously this used a\n * private `ceil(len/3.5)` walk that diverged from the calibrated shared\n * estimator, causing the selective `load`/`targetBudget` comparison to mix\n * two incompatible token scales.\n */\n private estimateTokens(messages: Message[]): number {\n return estimateMessages(messages);\n }\n}\n", "import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { FOREIGN_SKILL_TOOLS, resolveForeignToolIds } from '../skills/foreign-sources.js';\nimport { isValidSkillNameFormat, parseSkillFrontmatter } from '../skills/frontmatter.js';\nimport { SKILL_LIMITS } from '../skills/limits.js';\nimport type { SkillEntry, SkillLoader, SkillManifest } from '../types/skill.js';\nimport type { WstackPaths } from '../utils/wstack-paths.js';\n\n/**\n * Strip YAML frontmatter from a SKILL.md file, returning only the body.\n */\nfunction stripFrontmatter(raw: string): string {\n if (!raw.startsWith('---')) return raw;\n const end = raw.indexOf('\\n---', 4);\n if (end === -1) return raw;\n let body = raw.slice(end + 4);\n if (body.startsWith('\\n')) body = body.slice(1);\n return body;\n}\n\n/**\n * Compact a full skill body for token-saving fallback.\n * Extracts the Overview and Rules sections, trims to the compact budget.\n */\nfunction compactSkillBody(body: string): string {\n const sections: string[] = [];\n const overviewMatch = body.match(/##\\s*Overview\\s*\\n([\\s\\S]*?)(?=\\n##|\\n$|$)/i);\n const overview = overviewMatch?.[1];\n if (overview?.trim()) {\n sections.push(overview.trim().slice(0, SKILL_LIMITS.COMPACT_OVERVIEW_MAX));\n }\n const rulesMatch = body.match(/##\\s*Rules\\s*\\n([\\s\\S]*?)(?=\\n##|\\n$|$)/i);\n const rules = rulesMatch?.[1];\n if (rules?.trim()) {\n const trimmed = rules.trim().slice(0, SKILL_LIMITS.COMPACT_RULES_MAX);\n const ruleLines = trimmed\n .split('\\n')\n .filter((l) => /^\\s*[-*]\\s/.test(l) || /^\\s*\\d+[.)]\\s/.test(l))\n .slice(0, 6)\n .join('\\n');\n if (ruleLines) sections.push(ruleLines);\n }\n if (sections.length === 0) {\n const first = body.trim().slice(0, SKILL_LIMITS.COMPACT_OVERVIEW_MAX);\n if (first) sections.push(first);\n }\n const result = sections.join('\\n\\n');\n const total = SKILL_LIMITS.COMPACT_TOTAL_MAX;\n return result.length > total ? result.slice(0, total - 3) + '\u2026' : result;\n}\n\n/**\n * True if `entry` is a directory, following symlinks. `Dirent.isDirectory()`\n * is lstat-based and returns false for a symlink \u2014 but Claude Code and other\n * agents commonly symlink skill dirs (e.g. `~/.claude/skills/foo` \u2192\n * `~/.agents/skills/foo`), so we stat the target for symlink entries.\n */\nasync function entryIsDirectory(dir: string, entry: import('node:fs').Dirent): Promise<boolean> {\n if (entry.isDirectory()) return true;\n if (entry.isSymbolicLink()) {\n try {\n return (await fs.stat(path.join(dir, entry.name))).isDirectory();\n } catch {\n return false; // broken symlink\n }\n }\n return false;\n}\n\nexport interface SkillLoaderOptions {\n paths: WstackPaths;\n bundledDir?: string | undefined;\n /** Read foreign `.claude/skills` dirs (project + user). Default `true`. */\n readClaudeSkills?: boolean | undefined;\n /** Scan other agents' skill dirs (codex/cursor/agents/qwen/trae/\u2026). Default `true` (all); `string[]` restricts, `false` disables. */\n foreignSources?: boolean | string[] | undefined;\n /** Extra skill directories to scan (lowest priority, before bundled). */\n extraDirs?: string[] | undefined;\n}\n\n/**\n * Discovery order (we walk highest priority first and skip names already\n * seen, so earlier layers shadow later ones):\n * 1. Project-committed: <project>/.wrongstack/skills/\n * 2. Project foreign: <project>/.claude/skills/ (opt-out)\n * 3. Project foreign: <project>/.{codex,cursor,agents,\u2026}/skills/\n * 4. User profile: ~/.wrongstack/profiles/<name>/skills/\n * 5. User foreign: ~/.claude/skills/ (opt-out)\n * 6. User foreign: ~/.{codex,cursor,agents,\u2026}/skills/\n * 7. Extra dirs: config.skills.extraDirs (user config only)\n * 8. Bundled with build: packages/core/skills/\n *\n * The `.claude/*` layers let skills authored for other coding agents (Claude\n * Code, Codex, Gemini, `asm`, `gh skill`) be used without copying. They are\n * read-only \u2014 the installer never writes there.\n */\nexport class DefaultSkillLoader implements SkillLoader {\n private readonly dirs: { dir: string; source: SkillManifest['source']; originTool?: string }[];\n private cache?: SkillManifest[] | undefined;\n private entriesCache?: SkillEntry[] | undefined;\n private readonly bodyCache = new Map<string, string>();\n\n constructor(opts: SkillLoaderOptions) {\n const readClaude = opts.readClaudeSkills !== false;\n const foreignIds = resolveForeignToolIds(opts.foreignSources);\n const dirs: { dir: string; source: SkillManifest['source']; originTool?: string }[] = [];\n // Push each enabled foreign tool's dir under `root`, in registry order.\n const pushForeign = (root: string | undefined) => {\n if (!root) return;\n for (const tool of FOREIGN_SKILL_TOOLS) {\n if (!foreignIds.includes(tool.id)) continue;\n dirs.push({\n dir: path.join(root, '.' + tool.id, tool.subdir),\n source: 'foreign',\n originTool: tool.id,\n });\n }\n };\n dirs.push({ dir: opts.paths.inProjectSkills, source: 'project' });\n if (readClaude) dirs.push({ dir: opts.paths.inProjectClaudeSkills, source: 'claude-project' });\n pushForeign(opts.paths.projectRoot);\n dirs.push({ dir: opts.paths.globalSkills, source: 'user' });\n if (readClaude) dirs.push({ dir: opts.paths.globalClaudeSkills, source: 'claude-user' });\n pushForeign(opts.paths.homeDir);\n for (const d of opts.extraDirs ?? []) dirs.push({ dir: d, source: 'extra' });\n if (opts.bundledDir) dirs.push({ dir: opts.bundledDir, source: 'bundled' });\n this.dirs = dirs;\n }\n\n async list(): Promise<SkillManifest[]> {\n if (this.cache) return this.cache;\n const found: SkillManifest[] = [];\n const seen = new Set<string>();\n for (const { dir, source, originTool } of this.dirs) {\n try {\n // Node does not guarantee filesystem enumeration order. Sort each\n // discovery layer so eager-budget selection and prompt output are\n // deterministic across ext4/APFS/NTFS and packaged installations.\n const entries = (await fs.readdir(dir, { withFileTypes: true })).sort((a, b) =>\n a.name < b.name ? -1 : a.name > b.name ? 1 : 0,\n );\n for (const e of entries) {\n if (!(await entryIsDirectory(dir, e))) continue;\n const skillFile = path.join(dir, e.name, 'SKILL.md');\n try {\n const raw = await fs.readFile(skillFile, 'utf8');\n const fm = parseSkillFrontmatter(raw);\n if (!fm.name || !fm.description) continue;\n // agentskills.io name format \u2014 skip genuinely malformed names.\n if (!isValidSkillNameFormat(fm.name)) continue;\n if (seen.has(fm.name)) continue;\n seen.add(fm.name);\n found.push({\n name: fm.name,\n description: fm.description,\n version: fm.version,\n license: fm.license,\n compatibility: fm.compatibility,\n metadata: fm.metadata,\n allowedTools: fm.allowedTools,\n path: skillFile,\n source,\n originTool,\n });\n } catch {\n // skip malformed skill\n }\n }\n } catch {\n // directory may not exist\n }\n }\n this.cache = found;\n return found;\n }\n\n async find(name: string): Promise<SkillManifest | undefined> {\n const all = await this.list();\n const lower = name.toLowerCase();\n return all.find((s) => s.name.toLowerCase() === lower);\n }\n\n async manifestText(): Promise<string> {\n const entries = await this.listEntries();\n if (entries.length === 0) return '';\n const lines = ['## Available skills'];\n for (const e of entries) {\n const scopeTag = e.scope.length > 0 ? ` \u2014 ${e.scope.slice(0, 3).join(', ')}` : '';\n lines.push(`- **${e.name}**${scopeTag}`);\n lines.push(` Use when: ${e.trigger}`);\n }\n return lines.join('\\n');\n }\n\n async listEntries(): Promise<SkillEntry[]> {\n if (this.entriesCache) return this.entriesCache;\n const skills = await this.list();\n const entries: SkillEntry[] = [];\n for (const s of skills) {\n // Parse trigger/scope from the description that list() already parsed \u2014\n // no need to re-read the file; s.description === fm.description.\n const { trigger, scope } = parseDescriptionFromText(s.description ?? '');\n entries.push({\n name: s.name,\n trigger,\n scope,\n source: s.source,\n originTool: s.originTool,\n path: s.path,\n });\n }\n this.entriesCache = entries;\n return entries;\n }\n\n invalidateCache(): void {\n this.cache = undefined;\n this.entriesCache = undefined;\n this.bodyCache.clear();\n }\n\n async readBody(name: string): Promise<string> {\n const key = name.toLowerCase();\n const cached = this.bodyCache.get(key);\n if (cached !== undefined) return cached;\n const m = await this.find(name);\n if (!m) throw new Error(`Skill \"${name}\" not found`);\n const body = await fs.readFile(m.path, 'utf8');\n this.bodyCache.set(key, body);\n return body;\n }\n\n async readSaveBody(name: string): Promise<string> {\n const key = `save:${name.toLowerCase()}`;\n const cached = this.bodyCache.get(key);\n if (cached !== undefined) return cached;\n const m = await this.find(name);\n if (!m) throw new Error(`Skill \"${name}\" not found`);\n // Try SKILL.save.md in the same directory as SKILL.md\n const savePath = path.join(path.dirname(m.path), 'SKILL.save.md');\n let result: string;\n try {\n result = await fs.readFile(savePath, 'utf8');\n } catch {\n // No hand-crafted save variant \u2014 auto-compact the full body\n const full = await fs.readFile(m.path, 'utf8');\n const body = stripFrontmatter(full);\n const compact = compactSkillBody(body);\n if (compact) {\n result = `## Overview\\n\\n${compact}`;\n } else {\n // Fallback: return first 300 chars of full body\n result = body.trim().slice(0, 300);\n }\n }\n this.bodyCache.set(key, result);\n return result;\n }\n}\n\n/**\n * Parse skill description into:\n * - trigger: extracted \"Use when...\" sentence (first sentence of description)\n * - scope: comma-separated items from first line's parenthetical or file-ext list\n */\n/**\n * Extract trigger and scope from a skill's description text.\n * Used by listEntries() when the description has already been parsed from frontmatter.\n */\nfunction parseDescriptionFromText(desc: string): { trigger: string; scope: string[] } {\n // Extract first sentence as trigger\n const firstSentenceEnd = desc.indexOf('. ');\n const trigger =\n firstSentenceEnd !== -1\n ? desc.slice(0, firstSentenceEnd + 1).trim()\n : (desc.trim().split('\\n')[0] ?? '');\n\n // Extract scope from parenthetical: \"Covers X, Y, and Z\" or \"for A, B, C\"\n const scope: string[] = [];\n const coversMatch = /(?:covers|for|including)\\s+([^.]+)/i.exec(desc);\n if (coversMatch) {\n // NB: parenthesize the `?? ''` \u2014 without it, `??` binds looser than the\n // method chain, so `items` would be the raw match string and `...items`\n // would spread it into individual characters.\n const items = (coversMatch[1] ?? '')\n .replace(/[\u00B7\u2022]/g, ',')\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n scope.push(...items);\n }\n\n return { trigger, scope };\n}\n", "/**\n * Well-known foreign coding-agent skill directories. All follow the\n * agentskills.io `SKILL.md` format, so the same loader reads them \u2014 this just\n * tells it WHERE each agent keeps them.\n *\n * Claude is handled separately by the loader (`claude-project` / `claude-user`\n * sources); this list covers the OTHER agents. Every tool here stores skills\n * under `~/.<tool>/skills` (+ `<project>/.<tool>/skills`).\n *\n * Dirs that don't exist are skipped gracefully, so listing many is cheap.\n *\n * NOTE: Cursor previously used a non-standard `skills-cursor` subdir. As of the\n * 2026-07 alignment with the broader skills.sh / antfu-skills-cli / vercel-labs\n * ecosystem, Cursor uses the standard `skills` subdir like everyone else.\n * (`skills-cursor` was WrongStack-only and meant real Cursor skills were never\n * discovered \u2014 see docs/skills.md.)\n */\nexport interface ForeignSkillTool {\n /** Tool id \u2014 also the directory name segment (`~/.<id>/\u2026`). */\n id: string;\n /** Skills subdirectory name under `~/.<id>/`. */\n subdir: string;\n}\n\nexport const FOREIGN_SKILL_TOOLS: readonly ForeignSkillTool[] = [\n { id: 'agents', subdir: 'skills' }, // shared store (asm / agentskills.io ecosystem)\n { id: 'codex', subdir: 'skills' }, // OpenAI Codex CLI\n { id: 'gemini', subdir: 'skills' }, // Gemini CLI\n { id: 'cursor', subdir: 'skills' }, // Cursor (standard subdir, aligned with skills.sh ecosystem)\n { id: 'qwen', subdir: 'skills' }, // Qwen Code\n { id: 'trae', subdir: 'skills' }, // Trae\n { id: 'windsurf', subdir: 'skills' }, // Windsurf\n];\n\n/** Set of known tool ids \u2014 used to flag typos in `config.skills.foreignSources`. */\nconst KNOWN_FOREIGN_IDS = new Set(FOREIGN_SKILL_TOOLS.map((t) => t.id));\n\n/** Result of resolving a `foreignSources` config option. */\nexport interface ResolvedForeignTools {\n /** Tool ids that will be scanned (subset of {@link FOREIGN_SKILL_TOOLS}). */\n ids: string[];\n /** Tool ids the user asked for that aren't known \u2014 likely typos (e.g. `corser`). */\n unknownIds: string[];\n}\n\n/**\n * Resolve the `config.skills.foreignSources` option into the list of tool ids\n * to scan. Kept for backward compatibility (returns only `ids`).\n * - `false` \u2192 none\n * - `string[]` \u2192 only those ids (unknown ids silently dropped \u2014 see\n * {@link resolveForeignToolIdsWithWarnings} to surface them)\n * - `true` / `undefined` \u2192 all well-known tools\n */\nexport function resolveForeignToolIds(opt: boolean | string[] | undefined): string[] {\n return resolveForeignToolIdsWithWarnings(opt).ids;\n}\n\n/**\n * Like {@link resolveForeignToolIds}, but also returns tool ids the caller asked\n * for that don't match any known agent. Callers that want to warn the user\n * about a likely typo (e.g. `foreignSources: [\"corser\"]`) should prefer this.\n *\n * - `false` \u2192 none\n * - `string[]` \u2192 known ids included, unknown ones returned in `unknownIds`\n * - `true` / `undefined` \u2192 all well-known tools (no unknowns possible)\n */\nexport function resolveForeignToolIdsWithWarnings(\n opt: boolean | string[] | undefined,\n): ResolvedForeignTools {\n if (opt === false) return { ids: [], unknownIds: [] };\n if (Array.isArray(opt)) {\n const ids: string[] = [];\n const unknownIds: string[] = [];\n for (const id of opt) {\n if (KNOWN_FOREIGN_IDS.has(id)) ids.push(id);\n else unknownIds.push(id);\n }\n return { ids, unknownIds };\n }\n return { ids: FOREIGN_SKILL_TOOLS.map((t) => t.id), unknownIds: [] };\n}\n\n/**\n * Security tier bucket for a registry skill's `securityScore` (0\u2013100).\n * Mirrors the ags (agentskill-sh/ags) thresholds: skills below 30 need\n * explicit confirmation before install.\n */\nexport type SkillSecurityTier = 'low' | 'medium' | 'high';\n\n/** Classify a 0\u2013100 security score into a tier. 0/undefined \u2192 unknown \u2192 `low`. */\nexport function securityScoreToTier(score: number | undefined | null): SkillSecurityTier {\n if (score == null || Number.isNaN(score)) return 'low';\n if (score < 30) return 'low';\n if (score < 70) return 'medium';\n return 'high';\n}\n", "/**\n * Shared SKILL.md frontmatter parser + agentskills.io name validation.\n *\n * The SKILL.md format (https://agentskills.io/specification) is YAML\n * frontmatter between `---` markers followed by a Markdown body. This parser is\n * intentionally minimal \u2014 it handles the fields skills actually use, with YAML\n * block scalars (`|` / `>`) for multi-line values and an indented map for\n * `metadata`. It is NOT a general YAML parser; skill files are trusted markdown.\n */\nexport interface ParsedSkillFrontmatter {\n name?: string | undefined;\n description?: string | undefined;\n /** WrongStack extension; informational only. */\n version?: string | undefined;\n license?: string | undefined;\n compatibility?: string | undefined;\n metadata?: Record<string, string> | undefined;\n /** `allowed-tools` (spec, experimental) \u2192 split on whitespace. */\n allowedTools?: string[] | undefined;\n}\n\n/** Fields whose value is a single scalar string. */\nconst SCALAR_KEYS = new Set(['name', 'description', 'version', 'license', 'compatibility']);\n\n/**\n * Parse the YAML frontmatter block from a raw SKILL.md file. Returns `{}` when\n * there is no (or unclosed) frontmatter \u2014 callers treat that as \"skip\".\n *\n * Line endings are normalized first: CRLF (and lone CR) would otherwise leave a\n * trailing `\\r` on each line, and since `.` / `$` don't match `\\r`, the\n * `key: value` regex would fail on every line and silently drop the whole\n * frontmatter. Real skill files are frequently CRLF (Windows / some editors).\n */\nexport function parseSkillFrontmatter(raw: string): ParsedSkillFrontmatter {\n const text = normalizeLineEndings(raw);\n if (!text.startsWith('---')) return {};\n const end = text.indexOf('\\n---', 4);\n if (end === -1) return {};\n return parseFrontmatterBlock(text.slice(4, end));\n}\n\n/** Strip leading YAML frontmatter (`---\\n\u2026\\n---`) from a SKILL.md file. */\nexport function stripFrontmatter(raw: string): string {\n const text = normalizeLineEndings(raw);\n if (!text.startsWith('---')) return text;\n const end = text.indexOf('\\n---', 4);\n if (end === -1) return text;\n let body = text.slice(end + 4);\n if (body.startsWith('\\n')) body = body.slice(1);\n return body;\n}\n\n/** Normalize CRLF and lone CR to LF. */\nfunction normalizeLineEndings(s: string): string {\n return s.replace(/\\r\\n?/g, '\\n');\n}\n\nfunction parseFrontmatterBlock(block: string): ParsedSkillFrontmatter {\n const out: ParsedSkillFrontmatter = {};\n const lines = block.split('\\n');\n let i = 0;\n while (i < lines.length) {\n const line = lines[i] ?? '';\n const m = /^([a-zA-Z][a-zA-Z0-9_-]*):\\s*(.*)$/.exec(line);\n if (!m) {\n i++;\n continue;\n }\n const key = m[1] ?? '';\n const rest = (m[2] ?? '').trim();\n\n if (key === 'metadata') {\n const map: Record<string, string> = {};\n i++;\n while (i < lines.length) {\n const sub = lines[i] ?? '';\n const sm = /^\\s+([a-zA-Z0-9_.-]+):\\s*(.*)$/.exec(sub);\n if (!sm) break;\n map[sm[1] ?? ''] = unquote((sm[2] ?? '').trim());\n i++;\n }\n if (Object.keys(map).length > 0) out.metadata = map;\n continue;\n }\n\n if (rest === '|' || rest === '>') {\n // Block scalar \u2014 collect following indented (or blank) lines.\n const collected: string[] = [];\n i++;\n while (i < lines.length) {\n const sub = lines[i] ?? '';\n if (sub === '' || sub.startsWith(' ') || sub.startsWith('\\t')) {\n collected.push(sub.replace(/^\\s+/, ''));\n i++;\n } else break;\n }\n (out as Record<string, unknown>)[normalizeKey(key)] = collected.join('\\n').trim();\n continue;\n }\n\n if (key === 'allowed-tools' || key === 'allowedTools') {\n // Spec: space-separated; tolerate comma-separated (common in real skills).\n out.allowedTools = rest.split(/[\\s,]+/).filter(Boolean);\n i++;\n continue;\n }\n\n if (SCALAR_KEYS.has(key)) {\n (out as Record<string, unknown>)[key] = unquote(rest);\n i++;\n continue;\n }\n\n // Unknown key \u2014 ignore.\n i++;\n }\n return out;\n}\n\n/** `allowed-tools` (hyphen) \u2192 `allowedTools` (camel); other keys pass through. */\nfunction normalizeKey(key: string): string {\n return key === 'allowed-tools' ? 'allowedTools' : key;\n}\n\n/** Strip surrounding single/double YAML quotes from a scalar value. */\nfunction unquote(s: string): string {\n if (\n s.length >= 2 &&\n ((s.startsWith('\"') && s.endsWith('\"')) || (s.startsWith(\"'\") && s.endsWith(\"'\")))\n ) {\n return s.slice(1, -1);\n }\n return s;\n}\n\n/** True when `name` matches the agentskills.io name format (chars + length only). */\nexport function isValidSkillNameFormat(name: string): boolean {\n return name.length >= 1 && name.length <= 64 && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(name);\n}\n\n/**\n * Validate a skill `name` against the agentskills.io spec:\n * 1-64 chars; lowercase letters, digits, and single hyphens only; no\n * leading/trailing/consecutive hyphens. Pass the parent directory name to also\n * enforce the \"name must match the parent directory\" rule.\n *\n * Returns a list of human-readable violations (empty = valid).\n */\nexport function validateSkillName(name: string, parentDirName?: string): string[] {\n const errors: string[] = [];\n if (!name || name.trim().length === 0) {\n errors.push('name is empty');\n return errors;\n }\n if (name.length > 64) errors.push(`name is ${name.length} characters (max 64)`);\n if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name)) {\n errors.push(\n 'name must be lowercase letters, digits, and single hyphens only ' +\n '(no leading/trailing/consecutive hyphens)',\n );\n }\n if (parentDirName !== undefined && name !== parentDirName) {\n errors.push(`name \"${name}\" must match its parent directory \"${parentDirName}\"`);\n }\n return errors;\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 * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { DefaultPromptStore, migratePromptEntry } from '../storage/prompt-store.js';\nimport {\n isBuiltinCategory,\n PROMPT_CATEGORY_LABELS,\n type PromptCategoryCount,\n type PromptEntry,\n type PromptLoader,\n type PromptSearchOptions,\n} from '../types/prompt.js';\nimport type { WstackPaths } from '../utils/wstack-paths.js';\n\nexport interface PromptLoaderOptions {\n paths: WstackPaths;\n /** Directory containing the bundled dataset (`data/prompts`), if shipped. */\n bundledDir?: string | undefined;\n}\n\n/**\n * DefaultPromptLoader \u2014 read-side view over the three prompt layers, merged and\n * de-duplicated by `slug`. Mirrors `DefaultSkillLoader`.\n *\n * Discovery order (higher priority shadows lower by slug):\n * 1. Project-committed: <project>/.wrongstack/prompts/ (writable, source 'project')\n * 2. User profile: ~/.wrongstack/profiles/<name>/prompts/ (writable, source 'user'/'synced')\n * 3. Bundled with build: <core>/data/prompts/prompts/** (read-only, source 'builtin')\n *\n * Writes go to the user layer by default (or the project layer when\n * `scope:'project'`). Favoriting/editing a builtin copies it down into the user\n * layer (copy-on-write) so the read-only dataset is never mutated.\n */\nexport class DefaultPromptLoader implements PromptLoader {\n private readonly projectStore?: DefaultPromptStore | undefined;\n private readonly userStore?: DefaultPromptStore | undefined;\n private readonly builtinDir?: string | undefined;\n private cache?: PromptEntry[] | undefined;\n private builtinCache?: PromptEntry[] | undefined;\n\n constructor(opts: PromptLoaderOptions) {\n // Guard each layer dir: a partial WstackPaths (or a globalRoot-only test\n // setup) may omit one. A missing dir just means that layer is empty.\n this.projectStore =\n typeof opts.paths.inProjectPrompts === 'string'\n ? new DefaultPromptStore(opts.paths.inProjectPrompts)\n : undefined;\n this.userStore =\n typeof opts.paths.globalPrompts === 'string'\n ? new DefaultPromptStore(opts.paths.globalPrompts)\n : undefined;\n this.builtinDir = opts.bundledDir ? path.join(opts.bundledDir, 'prompts') : undefined;\n }\n\n async list(): Promise<PromptEntry[]> {\n if (this.cache) return this.cache;\n const seen = new Set<string>();\n const out: PromptEntry[] = [];\n const layers: PromptEntry[][] = [\n (await (this.projectStore?.list() ?? Promise.resolve([]))).map((e) => ({\n ...e,\n source: 'project' as const,\n })),\n await (this.userStore?.list() ?? Promise.resolve([])), // keeps stored source ('user' or 'synced')\n await this.readBuiltin(),\n ];\n for (const layer of layers) {\n for (const e of layer) {\n if (seen.has(e.slug)) continue;\n seen.add(e.slug);\n out.push(e);\n }\n }\n this.cache = out;\n return out;\n }\n\n async find(slugOrId: string): Promise<PromptEntry | undefined> {\n const all = await this.list();\n return all.find((e) => e.slug === slugOrId) ?? all.find((e) => e.id === slugOrId);\n }\n\n async search(query: string, opts: PromptSearchOptions = {}): Promise<PromptEntry[]> {\n let pool = await this.list();\n if (opts.category) pool = pool.filter((e) => e.category === opts.category);\n\n const q = query.trim().toLowerCase();\n let results: PromptEntry[];\n if (!q) {\n results = pool;\n } else {\n const tokens = q.split(/\\s+/).filter(Boolean);\n results = pool\n .map((e) => ({ e, score: scorePrompt(e, tokens) }))\n .filter((r) => r.score > 0)\n .sort((a, b) => b.score - a.score)\n .map((r) => r.e);\n }\n return typeof opts.limit === 'number' ? results.slice(0, opts.limit) : results;\n }\n\n async categories(): Promise<PromptCategoryCount[]> {\n const all = await this.list();\n const counts = new Map<string, number>();\n for (const e of all) counts.set(e.category, (counts.get(e.category) ?? 0) + 1);\n return [...counts.entries()]\n .map(([id, count]) => ({\n id,\n label: isBuiltinCategory(id) ? PROMPT_CATEGORY_LABELS[id] : id,\n count,\n }))\n .sort((a, b) => b.count - a.count || a.label.localeCompare(b.label));\n }\n\n async save(entry: PromptEntry, opts: { scope?: 'user' | 'project' } = {}): Promise<void> {\n const store = opts.scope === 'project' ? this.projectStore : this.userStore;\n if (!store)\n throw new Error(`Prompt ${opts.scope ?? 'user'} layer is not writable (no directory).`);\n // Never persist `source:'builtin'` into a writable layer \u2014 that would let a\n // user copy masquerade as read-only. Demote to the layer it's written to.\n const normalized: PromptEntry =\n entry.source === 'builtin'\n ? {\n ...entry,\n source: opts.scope === 'project' ? 'project' : 'user',\n forkedFrom: entry.forkedFrom ?? entry.slug,\n }\n : entry;\n await store.save(normalized);\n this.invalidateCache();\n }\n\n async delete(slugOrId: string): Promise<boolean> {\n const entry = await this.find(slugOrId);\n if (!entry) return false;\n if (entry.source === 'builtin') return false; // read-only\n const store = entry.source === 'project' ? this.projectStore : this.userStore;\n if (!store) return false;\n const ok = await store.delete(entry.id);\n if (ok) this.invalidateCache();\n return ok;\n }\n\n async setFavorite(slugOrId: string, favorite: boolean): Promise<PromptEntry | undefined> {\n const entry = await this.find(slugOrId);\n if (!entry) return undefined;\n const now = new Date().toISOString();\n\n if (entry.source === 'builtin') {\n // Copy-on-write: materialize a user-layer copy that shadows the builtin.\n if (!this.userStore) return undefined;\n const copy: PromptEntry = {\n ...entry,\n favorite,\n source: 'user',\n forkedFrom: entry.slug,\n updatedAt: now,\n };\n await this.userStore.save(copy);\n this.invalidateCache();\n return copy;\n }\n\n const updated: PromptEntry = { ...entry, favorite, updatedAt: now };\n const store = entry.source === 'project' ? this.projectStore : this.userStore;\n if (!store) return undefined;\n await store.save(updated);\n this.invalidateCache();\n return updated;\n }\n\n invalidateCache(): void {\n this.cache = undefined;\n this.builtinCache = undefined;\n }\n\n private async readBuiltin(): Promise<PromptEntry[]> {\n if (this.builtinCache) return this.builtinCache;\n const dir = this.builtinDir;\n if (!dir) {\n this.builtinCache = [];\n return [];\n }\n const out: PromptEntry[] = [];\n const files = await walkJson(dir);\n for (const file of files) {\n try {\n const parsed = JSON.parse(await fs.readFile(file, 'utf8'));\n // Builtin files store a bare PromptEntry (no { version, entry } wrapper).\n const migrated = migratePromptEntry(parsed);\n if (migrated) out.push({ ...migrated, source: 'builtin' });\n } catch {\n // skip malformed builtin file\n }\n }\n this.builtinCache = out;\n return out;\n }\n}\n\n/** Recursively collect `*.json` paths under `dir` (skips `index.json`/`schema.json`). */\nasync function walkJson(dir: string): Promise<string[]> {\n const out: string[] = [];\n let entries: import('node:fs').Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return out;\n }\n for (const e of entries) {\n const full = path.join(dir, e.name);\n if (e.isDirectory()) {\n out.push(...(await walkJson(full)));\n } else if (e.name.endsWith('.json') && e.name !== 'index.json' && e.name !== 'schema.json') {\n out.push(full);\n }\n }\n return out;\n}\n\nfunction scorePrompt(e: PromptEntry, tokens: string[]): number {\n const title = e.title.toLowerCase();\n const slug = e.slug.toLowerCase();\n const desc = e.description.toLowerCase();\n const cat = e.category.toLowerCase();\n const tags = e.tags.map((t) => t.toLowerCase());\n const content = e.content.toLowerCase();\n\n let score = 0;\n for (const tok of tokens) {\n let hit = 0;\n if (title.includes(tok)) hit += 5;\n if (slug.includes(tok)) hit += 4;\n if (tags.some((t) => t.includes(tok))) hit += 3;\n if (desc.includes(tok)) hit += 2;\n if (cat.includes(tok)) hit += 2;\n if (content.includes(tok)) hit += 1;\n // Fuzzy fallback: a typo / abbreviation (\"dpl\" \u2192 \"deploy\") still matches if\n // the token's characters appear in order in the most relevant fields. Scored\n // low so exact substring hits always rank above fuzzy ones.\n if (hit === 0 && tok.length >= 3) {\n if (isSubsequence(tok, title)) hit += 2;\n else if (isSubsequence(tok, slug)) hit += 2;\n else if (tags.some((t) => isSubsequence(tok, t))) hit += 1;\n }\n if (hit === 0) return 0; // every token must match somewhere (AND semantics)\n score += hit;\n }\n if (e.favorite) score += 1; // gentle tiebreak toward favorites\n return score;\n}\n\n/** True when every char of `needle` appears in `hay`, in order (subsequence). */\nfunction isSubsequence(needle: string, hay: string): boolean {\n let i = 0;\n for (let j = 0; j < hay.length && i < needle.length; j++) {\n if (hay[j] === needle[i]) i++;\n }\n return i === needle.length;\n}\n\n/**\n * Fill a prompt's `{{variable}}` placeholders with `values`. Unknown\n * placeholders are left intact unless a declared variable supplies a `default`.\n * Returns the rendered string, any required variables left unfilled\n * (`missing`), and any supplied values outside a variable's declared `enum`\n * (`invalid`).\n */\nexport function renderPrompt(\n entry: PromptEntry,\n values: Record<string, string> = {},\n): { text: string; missing: string[]; invalid: string[] } {\n const declared = new Map((entry.variables ?? []).map((v) => [v.name, v]));\n const missing: string[] = [];\n const invalid: string[] = [];\n\n const text = entry.content.replace(/\\{\\{\\s*([\\w.-]+)\\s*\\}\\}/g, (whole, rawName: string) => {\n const name = rawName.trim();\n if (Object.hasOwn(values, name) && values[name] !== undefined) {\n return values[name] as string;\n }\n const decl = declared.get(name);\n if (decl?.default !== undefined) return decl.default;\n if (decl?.required) missing.push(name);\n return whole; // leave the placeholder untouched\n });\n\n // Surface declared-but-never-referenced required vars too.\n for (const v of entry.variables ?? []) {\n if (v.required && !(v.name in values) && v.default === undefined && !missing.includes(v.name)) {\n // Only report if the placeholder actually exists in content; otherwise ignore.\n if (new RegExp(`\\\\{\\\\{\\\\s*${escapeRegExp(v.name)}\\\\s*\\\\}\\\\}`).test(entry.content)) {\n missing.push(v.name);\n }\n }\n // Reject a supplied value that isn't one of the declared enum options.\n if (\n v.enum &&\n v.enum.length > 0 &&\n Object.hasOwn(values, v.name) &&\n values[v.name] !== undefined &&\n values[v.name] !== '' &&\n !v.enum.includes(values[v.name] as string)\n ) {\n invalid.push(v.name);\n }\n }\n\n return { text, missing, invalid };\n}\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n", "import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { PromptEntry, PromptVariable } from '../types/prompt.js';\nimport { atomicWrite, ensureDir } from '../utils/atomic-write.js';\nimport { slugify } from '../utils/slug.js';\nimport { ulid } from '../utils/ulid.js';\nimport type { WstackPaths } from '../utils/wstack-paths.js';\n\nexport type { PromptEntry, PromptSource, PromptVariable } from '../types/prompt.js';\n\nexport interface PromptStore {\n list(): Promise<PromptEntry[]>;\n get(id: string): Promise<PromptEntry | null>;\n save(entry: PromptEntry): Promise<void>;\n delete(id: string): Promise<boolean>;\n find(query: string): Promise<PromptEntry[]>;\n}\n\n/** Current on-disk schema version. */\nconst SCHEMA_VERSION = 2;\n\ninterface RawPromptFile {\n version: number;\n entry: unknown;\n}\n\n/** sha256 of a prompt's content \u2014 used for builtin/synced integrity checks. */\nexport function promptChecksum(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n\n/**\n * Upgrade any persisted prompt record (v1 or v2) to a fully-populated v2\n * `PromptEntry`. Pure \u2014 does not touch disk. v1 records (only\n * `id/title/content/tags/createdAt/updatedAt`) get sensible defaults:\n * slug from title, empty description, `uncategorized` category, `user` source.\n */\nexport function migratePromptEntry(raw: unknown): PromptEntry | null {\n if (!raw || typeof raw !== 'object') return null;\n const r = raw as Record<string, unknown>;\n if (typeof r['id'] !== 'string' || typeof r['title'] !== 'string') return null;\n\n const title = r['title'];\n const content = typeof r['content'] === 'string' ? r['content'] : '';\n const now = typeof r['createdAt'] === 'string' ? r['createdAt'] : new Date(0).toISOString();\n const tags = Array.isArray(r['tags'])\n ? (r['tags'].filter((t) => typeof t === 'string') as string[])\n : [];\n\n return {\n id: r['id'],\n slug: typeof r['slug'] === 'string' && r['slug'].length > 0 ? r['slug'] : slugify(title),\n title,\n description: typeof r['description'] === 'string' ? r['description'] : '',\n content,\n category:\n typeof r['category'] === 'string' && r['category'].length > 0\n ? r['category']\n : 'uncategorized',\n tags,\n source: isPromptSource(r['source']) ? r['source'] : 'user',\n favorite: r['favorite'] === true,\n variables: normalizeVariables(r['variables']),\n author: typeof r['author'] === 'string' ? r['author'] : undefined,\n version: typeof r['version'] === 'string' ? r['version'] : undefined,\n license: typeof r['license'] === 'string' ? r['license'] : undefined,\n checksum: typeof r['checksum'] === 'string' ? r['checksum'] : undefined,\n forkedFrom: typeof r['forkedFrom'] === 'string' ? r['forkedFrom'] : undefined,\n createdAt: now,\n updatedAt: typeof r['updatedAt'] === 'string' ? r['updatedAt'] : now,\n };\n}\n\nfunction isPromptSource(v: unknown): v is PromptEntry['source'] {\n return v === 'builtin' || v === 'user' || v === 'project' || v === 'synced';\n}\n\nfunction normalizeVariables(v: unknown): PromptVariable[] | undefined {\n if (!Array.isArray(v)) return undefined;\n const out: PromptVariable[] = [];\n for (const item of v) {\n if (\n item &&\n typeof item === 'object' &&\n typeof (item as Record<string, unknown>)['name'] === 'string'\n ) {\n const o = item as Record<string, unknown>;\n const enumVals =\n Array.isArray(o['enum']) && o['enum'].every((x) => typeof x === 'string')\n ? (o['enum'] as string[])\n : undefined;\n out.push({\n name: o['name'] as string,\n description: typeof o['description'] === 'string' ? o['description'] : undefined,\n default: typeof o['default'] === 'string' ? o['default'] : undefined,\n required: o['required'] === true ? true : undefined,\n enum: enumVals && enumVals.length > 0 ? enumVals : undefined,\n multiline: o['multiline'] === true ? true : undefined,\n });\n }\n }\n return out.length > 0 ? out : undefined;\n}\n\n/**\n * DefaultPromptStore \u2014 file-per-prompt JSON in a single directory (the global\n * the active profile's `prompts` directory by default, or a layer dir the loader passes in).\n * Reads tolerate legacy v1 files via `migratePromptEntry`; writes always emit\n * the current v2 schema.\n */\nexport class DefaultPromptStore implements PromptStore {\n private readonly dir: string;\n\n constructor(pathsOrDir: WstackPaths | string) {\n this.dir = typeof pathsOrDir === 'string' ? pathsOrDir : pathsOrDir.globalPrompts;\n }\n\n async list(): Promise<PromptEntry[]> {\n await ensureDir(this.dir);\n const entries: PromptEntry[] = [];\n try {\n const files = await fs.readdir(this.dir);\n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n try {\n const raw: RawPromptFile = JSON.parse(\n await fs.readFile(path.join(this.dir, file), 'utf8'),\n );\n const migrated = migratePromptEntry(raw.entry);\n if (migrated) entries.push(migrated);\n } catch {\n // skip corrupt files\n }\n }\n } catch {\n // dir doesn't exist yet\n }\n return entries.sort(\n (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime(),\n );\n }\n\n async get(id: string): Promise<PromptEntry | null> {\n const file = path.join(this.dir, `${id}.json`);\n try {\n const raw: RawPromptFile = JSON.parse(await fs.readFile(file, 'utf8'));\n return migratePromptEntry(raw.entry);\n } catch {\n return null;\n }\n }\n\n async save(entry: PromptEntry): Promise<void> {\n await ensureDir(this.dir);\n const file = path.join(this.dir, `${entry.id}.json`);\n const raw: RawPromptFile = { version: SCHEMA_VERSION, entry };\n await atomicWrite(file, JSON.stringify(raw, null, 2));\n }\n\n async delete(id: string): Promise<boolean> {\n const file = path.join(this.dir, `${id}.json`);\n try {\n await fs.unlink(file);\n return true;\n } catch {\n return false;\n }\n }\n\n async find(query: string): Promise<PromptEntry[]> {\n const all = await this.list();\n const lower = query.toLowerCase();\n return all.filter(\n (e) =>\n e.title.toLowerCase().includes(lower) ||\n e.description.toLowerCase().includes(lower) ||\n e.content.toLowerCase().includes(lower) ||\n e.category.toLowerCase().includes(lower) ||\n e.tags.some((t) => t.toLowerCase().includes(lower)),\n );\n }\n\n /** Create a new v2 entry and return it. Does NOT persist \u2014 call save() afterwards. */\n createNew(\n title: string,\n content: string,\n tags: string[] = [],\n extra: Partial<\n Omit<PromptEntry, 'id' | 'title' | 'content' | 'tags' | 'createdAt' | 'updatedAt'>\n > = {},\n ): PromptEntry {\n const now = new Date().toISOString();\n return {\n id: ulid(),\n slug: extra.slug && extra.slug.length > 0 ? extra.slug : slugify(title),\n title,\n description: extra.description ?? '',\n content,\n category: extra.category ?? 'uncategorized',\n tags,\n source: extra.source ?? 'user',\n favorite: extra.favorite ?? false,\n variables: extra.variables,\n author: extra.author,\n version: extra.version,\n license: extra.license,\n checksum: extra.checksum,\n forkedFrom: extra.forkedFrom,\n createdAt: now,\n updatedAt: now,\n };\n }\n}\n", "/**\n * Turn an arbitrary string into a filesystem- and URL-safe lowercase slug.\n *\n * Collapses every run of non-alphanumeric characters into a single hyphen,\n * trims leading/trailing hyphens, and caps the length. Returns `fallback`\n * when the input slugifies to the empty string.\n *\n * Used as the stable dedup + registry key for prompts. (Distinct from the\n * project-folder slug in `wstack-paths.ts`, which has its own `'project'`\n * fallback and shorter cap.)\n */\nexport function slugify(name: string, fallback = 'prompt', maxLen = 64): string {\n return (\n name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, maxLen)\n .replace(/-+$/g, '') || fallback\n );\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 * Prompt library types \u2014 the canonical home for the prompt data model and the\n * loader/registry contracts. Has no internal dependencies so both `storage/`\n * (the writable store) and `execution/` (the layered loader) can import it\n * without creating a cycle.\n */\n\n/** Provenance of a prompt \u2014 which layer it came from. */\nexport type PromptSource = 'builtin' | 'user' | 'project' | 'synced';\n\n/**\n * The fourteen first-party categories shipped with the builtin dataset, plus\n * the `uncategorized` sentinel used when migrating legacy v1 entries. Builtin\n * prompts MUST use one of these (enforced by the dataset schema test); user and\n * project prompts may use any free-form string.\n */\nexport const BUILTIN_PROMPT_CATEGORIES = [\n 'coding',\n 'debugging',\n 'refactoring',\n 'testing',\n 'code-review',\n 'architecture',\n 'devops',\n 'documentation',\n 'data-analysis',\n 'writing',\n 'research',\n 'product',\n 'agentic-workflows',\n 'meta-prompting',\n 'uncategorized',\n] as const;\n\nexport type BuiltinPromptCategory = (typeof BUILTIN_PROMPT_CATEGORIES)[number];\n\n/**\n * Human-readable labels for the builtin categories (for UI chips / pickers).\n */\nexport const PROMPT_CATEGORY_LABELS: Record<BuiltinPromptCategory, string> = {\n coding: 'Coding',\n debugging: 'Debugging',\n refactoring: 'Refactoring',\n testing: 'Testing',\n 'code-review': 'Code Review',\n architecture: 'Architecture',\n devops: 'DevOps',\n documentation: 'Documentation',\n 'data-analysis': 'Data Analysis',\n writing: 'Writing',\n research: 'Research',\n product: 'Product',\n 'agentic-workflows': 'Agentic Workflows',\n 'meta-prompting': 'Meta-Prompting',\n uncategorized: 'Uncategorized',\n};\n\n/**\n * A prompt's category. Typed as a free-form string because user/project prompts\n * may invent their own; the builtin dataset is constrained to\n * {@link BUILTIN_PROMPT_CATEGORIES} by its schema.\n */\nexport type PromptCategory = BuiltinPromptCategory | (string & {});\n\nexport function isBuiltinCategory(value: string): value is BuiltinPromptCategory {\n return (BUILTIN_PROMPT_CATEGORIES as readonly string[]).includes(value);\n}\n\n/** A `{{name}}` placeholder declared by a prompt. */\nexport interface PromptVariable {\n /** Placeholder name as it appears between `{{ }}` (case-sensitive). */\n name: string;\n description?: string | undefined;\n default?: string | undefined;\n required?: boolean | undefined;\n /**\n * Closed set of allowed values. When present, surfaces render a dropdown\n * instead of a free text field and a supplied value outside the set is\n * reported as invalid by {@link renderPrompt}.\n */\n enum?: string[] | undefined;\n /**\n * UI hint: the value is expected to span multiple lines (pasted code, a\n * diff, a long passage). Surfaces render a textarea instead of a one-line\n * input. Has no effect on rendering \u2014 purely presentational.\n */\n multiline?: boolean | undefined;\n}\n\n/**\n * A reusable prompt. v2 schema. Legacy v1 entries (only `id/title/content/tags/\n * createdAt/updatedAt`) are upgraded lazily on read by `migratePromptEntry`.\n */\nexport interface PromptEntry {\n /** Stable unique handle (ULID for new entries; legacy short hex tolerated). */\n id: string;\n /** kebab-case stable key \u2014 the dedup key across layers and registry key. */\n slug: string;\n title: string;\n /** One-line summary shown in lists/pickers. */\n description: string;\n content: string;\n category: PromptCategory;\n /** Secondary facets (free-form). */\n tags: string[];\n source: PromptSource;\n favorite: boolean;\n /** `{{placeholder}}` variables this prompt expects, if any. */\n variables?: PromptVariable[] | undefined;\n author?: string | undefined;\n version?: string | undefined;\n license?: string | undefined;\n /** sha256 of `content` \u2014 set for builtin/synced entries for integrity. */\n checksum?: string | undefined;\n /** When a builtin was copy-on-written into the user layer, its origin slug. */\n forkedFrom?: string | undefined;\n createdAt: string;\n updatedAt: string;\n}\n\n/** One category with its prompt count, for picker chips. */\nexport interface PromptCategoryCount {\n id: PromptCategory;\n label: string;\n count: number;\n}\n\nexport interface PromptSearchOptions {\n category?: PromptCategory | undefined;\n /** Max results (default: unbounded). */\n limit?: number | undefined;\n}\n\n/**\n * Read-side contract over the three prompt layers (project > user > builtin),\n * merged and de-duplicated by slug. Mirrors `SkillLoader` in shape.\n */\nexport interface PromptLoader {\n /** All prompts across layers, project/user shadowing builtin by slug. */\n list(): Promise<PromptEntry[]>;\n /** Resolve by slug first, then by id. */\n find(slugOrId: string): Promise<PromptEntry | undefined>;\n /** Ranked search over title/description/content/tags, optional category filter. */\n search(query: string, opts?: PromptSearchOptions): Promise<PromptEntry[]>;\n /** Category counts across all layers, for UI chips. */\n categories(): Promise<PromptCategoryCount[]>;\n /**\n * Persist into the writable (user, or project when `scope:'project'`) layer.\n * Throws if the resolved target is the read-only builtin layer.\n */\n save(entry: PromptEntry, opts?: { scope?: 'user' | 'project' }): Promise<void>;\n /** Delete from a writable layer. Returns false if not found / builtin. */\n delete(slugOrId: string): Promise<boolean>;\n /**\n * Mark/unmark a prompt as favorite. Favoriting a builtin copies it down into\n * the user layer (copy-on-write, `source:'user'`, `forkedFrom:<slug>`).\n */\n setFavorite(slugOrId: string, favorite: boolean): Promise<PromptEntry | undefined>;\n /** Clear the internal cache so the next read re-scans disk. */\n invalidateCache(): void;\n}\n\n/**\n * The packed builtin index (also the shape a remote registry manifest mirrors\n * \u2014 see `types/prompt-registry.ts`).\n */\nexport interface PromptManifest {\n datasetVersion: number;\n generatedAt: string;\n count: number;\n categories: PromptCategoryCount[];\n prompts: PromptManifestRef[];\n}\n\nexport interface PromptManifestRef {\n id: string;\n slug: string;\n title: string;\n description: string;\n category: PromptCategory;\n tags: string[];\n checksum: string;\n /** Relative path of the per-prompt file within the dataset. */\n file: string;\n}\n", "/**\n * Minimal JSON Schema validator \u2014 covers the subset needed for plugin\n * configSchema validation and tool inputSchema sanity checks. Intentionally\n * small (~80 lines, zero deps) and tolerant: unknown keywords are ignored so\n * authors can mix in non-standard extensions without breaking validation.\n *\n * NOT for full JSON Schema 2020-12 conformance. If a plugin needs $ref,\n * conditional schemas, format validation, or anything else exotic, it should\n * bring its own ajv-based validator and call this only for the cheap path.\n */\nimport type { JSONSchema } from '../types/tool.js';\n\nexport interface ValidationError {\n path: string;\n message: string;\n}\n\nexport interface ValidationResult {\n ok: boolean;\n errors: ValidationError[];\n}\n\nexport function validateAgainstSchema(value: unknown, schema: JSONSchema): ValidationResult {\n const errors: ValidationError[] = [];\n walk(value, schema, '', errors, 0);\n return { ok: errors.length === 0, errors };\n}\n\n/**\n * Maximum nesting depth before the validator stops recursing and reports a\n * \"schema too deep\" error. Deeply nested input (e.g. batch_tool_use with 100\n * nested calls \u2192 tool_use \u2192 input) can otherwise hit `RangeError: Maximum\n * call stack size exceeded` and crash the tool executor.\n *\n * 64 is generous: real-world tool schemas rarely nest beyond 5-6 levels, and\n * even pathological inputs (deeply recursive JSON) stay well under this.\n * The limit is a safety net against unbounded recursion, not a tight bound.\n */\nconst MAX_SCHEMA_DEPTH = 64;\n\nfunction walk(\n value: unknown,\n schema: JSONSchema,\n path: string,\n errors: ValidationError[],\n depth: number,\n): void {\n // P2 #8 (before-release.md): cap recursion depth to prevent\n // `RangeError: Maximum call stack size exceeded` on deeply nested input.\n // Push a validation error and stop descending \u2014 the caller still gets a\n // usable (ok: false) result instead of a crash.\n if (depth > MAX_SCHEMA_DEPTH) {\n errors.push({\n path: path || '<root>',\n message: `schema nesting exceeds maximum depth (${MAX_SCHEMA_DEPTH})`,\n });\n return;\n }\n if (schema.enum !== undefined) {\n if (!enumIncludes(schema.enum, value)) {\n errors.push({\n path: path || '<root>',\n message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`,\n });\n return;\n }\n }\n\n if (typeof schema.type === 'string') {\n if (!checkType(value, schema.type)) {\n errors.push({\n path: path || '<root>',\n message: `expected ${schema.type}, got ${describeType(value)} (${previewValue(value)})`,\n });\n return;\n }\n }\n\n if (schema.type === 'object' && isPlainObject(value)) {\n const obj = value as Record<string, unknown>;\n for (const req of schema.required ?? []) {\n if (!(req in obj)) {\n const expected = schema.properties?.[req]?.type;\n errors.push({\n path: joinPath(path, req),\n message: `required property missing${typeof expected === 'string' ? ` (expected ${expected})` : ''}`,\n });\n }\n }\n if (schema.properties) {\n for (const [key, subSchema] of Object.entries(schema.properties)) {\n if (key in obj) {\n walk(obj[key], subSchema, joinPath(path, key), errors, depth + 1);\n }\n }\n }\n }\n\n if (schema.type === 'array' && Array.isArray(value) && schema.items) {\n for (let i = 0; i < value.length; i++) {\n walk(value[i], schema.items as JSONSchema, `${path}[${i}]`, errors, depth + 1);\n }\n }\n}\n\nexport interface CoercionResult {\n value: unknown;\n /** True when at least one leaf was rewritten. */\n changed: boolean;\n}\n\n/**\n * Best-effort, lossless coercion of a value toward a JSON Schema. Models \u2014\n * especially through OpenAI-compatible proxies \u2014 frequently deliver\n * arguments with the right *content* in the wrong *type*: numbers and\n * booleans encoded as strings (\"5\", \"true\"), scalars where a string is\n * expected, or a whole nested object serialized into a JSON string.\n *\n * Only conversions that cannot lose information are applied:\n * - string \u2192 number/integer when the whole trimmed string parses cleanly\n * - string \"true\"/\"false\" \u2192 boolean\n * - number/boolean \u2192 string when a string is expected\n * - JSON-serialized string \u2192 object/array when the parse yields that shape\n * Recurses into `properties`/`items`. Returns the (possibly new) value and\n * whether anything changed \u2014 callers should re-validate before trusting it.\n */\nexport function coerceAgainstSchema(value: unknown, schema: JSONSchema): CoercionResult {\n return coerceWalk(value, schema, 0);\n}\n\nfunction coerceWalk(value: unknown, schema: JSONSchema, depth: number): CoercionResult {\n if (depth > MAX_SCHEMA_DEPTH) return { value, changed: false };\n\n const type = typeof schema.type === 'string' ? schema.type : undefined;\n\n // Leaf conversions (only when the current type does NOT already match).\n if (type && !checkType(value, type)) {\n if (type === 'string' && (typeof value === 'number' || typeof value === 'boolean')) {\n return { value: String(value), changed: true };\n }\n if ((type === 'number' || type === 'integer') && typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed !== '' && /^-?(\\d+\\.?\\d*|\\.\\d+)([eE][+-]?\\d+)?$/.test(trimmed)) {\n const num = Number(trimmed);\n if (!Number.isNaN(num) && (type === 'number' || Number.isInteger(num))) {\n return { value: num, changed: true };\n }\n }\n return { value, changed: false };\n }\n if (type === 'boolean' && typeof value === 'string') {\n const lowered = value.trim().toLowerCase();\n if (lowered === 'true') return { value: true, changed: true };\n if (lowered === 'false') return { value: false, changed: true };\n return { value, changed: false };\n }\n if ((type === 'object' || type === 'array') && typeof value === 'string') {\n // A nested structure serialized into a string (double-encoded args).\n try {\n const parsed: unknown = JSON.parse(value);\n if (checkType(parsed, type)) {\n // Recurse so leaves inside the revived structure also coerce.\n return { value: coerceWalk(parsed, schema, depth + 1).value, changed: true };\n }\n } catch {\n // fall through \u2014 leave as-is, validation will report it\n }\n return { value, changed: false };\n }\n return { value, changed: false };\n }\n\n // Structural recursion.\n if (type === 'object' && isPlainObject(value) && schema.properties) {\n const obj = value as Record<string, unknown>;\n let changed = false;\n const out: Record<string, unknown> = { ...obj };\n for (const [key, subSchema] of Object.entries(schema.properties)) {\n if (!(key in obj)) continue;\n const r = coerceWalk(obj[key], subSchema, depth + 1);\n if (r.changed) {\n out[key] = r.value;\n changed = true;\n }\n }\n return changed ? { value: out, changed } : { value, changed: false };\n }\n\n if (type === 'array' && Array.isArray(value) && schema.items) {\n let changed = false;\n const out = value.map((item) => {\n const r = coerceWalk(item, schema.items as JSONSchema, depth + 1);\n if (r.changed) changed = true;\n return r.value;\n });\n return changed ? { value: out, changed } : { value, changed: false };\n }\n\n return { value, changed: false };\n}\n\nfunction checkType(value: unknown, type: string): boolean {\n switch (type) {\n case 'string':\n return typeof value === 'string';\n case 'number':\n return typeof value === 'number' && !Number.isNaN(value);\n case 'integer':\n return typeof value === 'number' && Number.isInteger(value);\n case 'boolean':\n return typeof value === 'boolean';\n case 'null':\n return value === null;\n case 'array':\n return Array.isArray(value);\n case 'object':\n return isPlainObject(value);\n default:\n return true;\n }\n}\n\nfunction isPlainObject(v: unknown): boolean {\n return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n\nfunction describeType(v: unknown): string {\n if (v === null) return 'null';\n if (Array.isArray(v)) return 'array';\n return typeof v;\n}\n\n/** Short serialized preview of the offending value for error messages. */\nfunction previewValue(v: unknown): string {\n try {\n const s = JSON.stringify(v);\n if (s === undefined) return String(v);\n return s.length > 80 ? `${s.slice(0, 80)}\u2026` : s;\n } catch {\n return String(v);\n }\n}\n\nfunction joinPath(parent: string, key: string): string {\n if (!parent) return key;\n return `${parent}.${key}`;\n}\n\nfunction enumIncludes(values: readonly unknown[], value: unknown): boolean {\n if (value === null || typeof value !== 'object') return values.includes(value);\n return values.some((candidate) => deepEqual(candidate, value));\n}\n\nfunction deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a !== typeof b) return false;\n if (a === null || b === null) return a === b;\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));\n }\n if (typeof a === 'object' && typeof b === 'object') {\n const ak = Object.keys(a as object);\n const bk = Object.keys(b as object);\n if (ak.length !== bk.length) return false;\n return ak.every((k) =>\n deepEqual((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]),\n );\n }\n return false;\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", "import type {\n ToolResultRenderMode,\n ToolResultRenderModeConfig,\n} from '../types/config.js';\nimport type { Tool } from '../types/tool.js';\n\nexport const DEFAULT_TOOL_RESULT_RENDER_MODE: ToolResultRenderMode = 'extend';\n\n/**\n * Normalize a raw value to a {@link ToolResultRenderMode}. Accepts the\n * canonical strings (`'extend' | 'simple'`) plus a few synonyms so the\n * slash command feels forgiving (`extended`/`full` \u2192 `extend`,\n * `short`/`brief` \u2192 `simple`). Returns `undefined` for anything else so\n * the caller can reject unknown input without throwing.\n */\nexport function normalizeToolResultRenderMode(value: unknown): ToolResultRenderMode | undefined {\n if (typeof value !== 'string') return undefined;\n const raw = value.trim().toLowerCase();\n if (raw === 'extend' || raw === 'extended' || raw === 'full') return 'extend';\n if (raw === 'simple' || raw === 'short' || raw === 'brief') return 'simple';\n return undefined;\n}\n\n/**\n * Look up the result-render mode for `toolName` from a config map. Falls\n * back to the default `'extend'` when the map is missing the entry.\n */\nexport function resolveToolResultRenderMode(\n modes: ToolResultRenderModeConfig | undefined,\n toolName: string,\n): ToolResultRenderMode {\n return normalizeToolResultRenderMode(modes?.[toolName]) ?? DEFAULT_TOOL_RESULT_RENDER_MODE;\n}\n\n/**\n * Subset of {@link import('../registry/tool-registry.js').ToolRegistry}\n * the result-render-mode setters need. Decouples this module from the\n * concrete registry class so it can be reused by tests and by tools\n * that wrap their own registry.\n */\nexport interface ToolResultRenderModeRegistryLike {\n get(name: string): Tool | undefined;\n setResultRenderMode?(name: string, mode: ToolResultRenderMode): boolean;\n applyResultRenderModes?(\n modes?: ToolResultRenderModeConfig,\n ): { applied: number; missing: string[] };\n getResultRenderMode?(name: string): ToolResultRenderMode;\n}\n\n/**\n * Set a single tool's result-render mode on a registry. Prefers the\n * registry's native accessor (so it can update any internal state, e.g.\n * usage caches); falls back to a no-op so callers stay decoupled from\n * the registry implementation.\n */\nexport function setToolResultRenderMode(\n registry: ToolResultRenderModeRegistryLike,\n name: string,\n mode: ToolResultRenderMode,\n): boolean {\n if (typeof registry.setResultRenderMode === 'function') {\n return registry.setResultRenderMode(name, mode);\n }\n return false;\n}\n\n/**\n * Look up the current result-render mode for a single tool. Returns the\n * registry's view if it has one, otherwise the default. This is what the\n * tool-executor calls on each tool invocation to decide whether the next\n * `writeToolResult` should be `simple` or `extend`.\n */\nexport function getToolResultRenderMode(\n registry: ToolResultRenderModeRegistryLike,\n name: string,\n): ToolResultRenderMode {\n return registry.getResultRenderMode?.(name) ?? DEFAULT_TOOL_RESULT_RENDER_MODE;\n}\n\n/**\n * Bulk-apply a config map (`tools.resultRenderMode`) to a registry.\n * Mirrors {@link import('./tool-description-mode.js').applyToolDescriptionModes}\n * for symmetry with the LLM-side description mode.\n */\nexport function applyToolResultRenderModes(\n registry: ToolResultRenderModeRegistryLike,\n modes?: ToolResultRenderModeConfig,\n): { applied: number; missing: string[] } {\n if (typeof registry.applyResultRenderModes === 'function') {\n return registry.applyResultRenderModes(modes);\n }\n\n const entries = Object.entries(modes ?? {});\n const missing: string[] = [];\n let applied = 0;\n for (const [name, rawMode] of entries) {\n const mode = normalizeToolResultRenderMode(rawMode);\n if (!mode) continue;\n if (setToolResultRenderMode(registry, name, mode)) applied++;\n else missing.push(name);\n }\n return { applied, missing };\n}", "const GLOB_METACHARACTERS = /[*?[\\]]/g;\n\nexport function escapeGlobSubject(value: string): string {\n return value.replace(GLOB_METACHARACTERS, (char) => `\\\\${char}`);\n}\n\nexport function normalizePathSubject(value: string): string {\n return escapeGlobSubject(value.replace(/\\\\/g, '/'));\n}\n\nexport function isPathSubjectKey(subjectKey: string): boolean {\n return subjectKey === 'path' || subjectKey === 'file' || subjectKey === 'files';\n}\n\nexport function subjectForToolInput(\n toolName: string,\n input: unknown,\n subjectKey?: string,\n): string | undefined {\n if (!input || typeof input !== 'object') return undefined;\n const obj = input as Record<string, unknown>;\n\n if (subjectKey) {\n const value = obj[subjectKey];\n if (typeof value === 'string') {\n return isPathSubjectKey(subjectKey) ? normalizePathSubject(value) : escapeGlobSubject(value);\n }\n }\n\n if (toolName === 'bash' && typeof obj.command === 'string') {\n return escapeGlobSubject(obj.command);\n }\n if (typeof obj.path === 'string') {\n return normalizePathSubject(obj.path);\n }\n if (typeof obj.url === 'string') {\n return escapeGlobSubject(obj.url);\n }\n if (typeof obj.name === 'string') {\n return escapeGlobSubject(obj.name);\n }\n return undefined;\n}\n", "import type { Context } from '../core/context.js';\nimport type { CompactReport, Compactor } from '../types/compactor.js';\nimport type { ContextWindowPolicy } from '../types/context-window.js';\nimport type { Message } from '../types/messages.js';\nimport { toErrorMessage } from '../utils/index.js';\nimport { HybridCompactor } from './compactor.js';\nimport { IntelligentCompactor } from './intelligent-compactor.js';\nimport type { OneShotOrchestrator } from './one-shot-llm.js';\nimport { SelectiveCompactor } from './selective-compactor.js';\n\nexport type CompactorStrategy = 'hybrid' | 'intelligent' | 'selective';\n\nexport interface StrategyCompactorOptions {\n /** Which compactor to use. Defaults to 'hybrid' (lossless, no LLM). */\n strategy?: CompactorStrategy | string | undefined;\n /** Recent user/assistant pairs to always preserve. */\n preserveK?: number | undefined;\n /** Token threshold below which tool results are not elided. */\n eliseThreshold?: number | undefined;\n /**\n * Enable content-aware smart digest for 'hybrid' strategy. When true,\n * collapsed ancient turns use buildSmartDigest: critical content (errors,\n * corrections, decisions) stays verbatim; normal exchanges get first-sentence\n * summaries; noise (repeated failures, large tool outputs) is aggressively\n * compressed. Defaults to false (lossless digest).\n */\n smart?: boolean | undefined;\n /** Model used by the LLM-backed strategies for summarization/selection. */\n summarizerModel?: string | undefined;\n /** Max output tokens for the selector LLM call in 'selective' strategy (default: 1024). */\n selectorMaxOutputTokens?: number | undefined;\n /**\n * Legacy shortcut for `strategy: 'selective'`. When `strategy` is unset (or\n * 'hybrid') and this is true, the selective (LLM-driven) compactor is used.\n * An explicit `strategy` always wins.\n */\n llmSelector?: boolean | undefined;\n /**\n * OneShotOrchestrator for LLM-backed compaction summarization. When set,\n * the intelligent/selective compactor uses it instead of direct provider\n * calls, gaining fallback chain support and a cheap default model.\n */\n oneShotOrchestrator?: OneShotOrchestrator | undefined;\n}\n\n/**\n * Build the compactor named by `config.context.strategy`.\n *\n * - `hybrid` (default): lossless rule-based \u2014 no provider needed.\n * - `intelligent` / `selective`: LLM-backed. These need a `provider`, which is\n * only known per-run, so we return a thin wrapper that resolves the concrete\n * compactor from `ctx` at `compact()`-time. This deliberately avoids the\n * container/provider construction-ordering problem: `TOKENS.Compactor` is\n * resolved (and memoized) before `context.provider` exists, but `ctx.provider`\n * is always present once a run is actually compacting. If no provider is\n * available at compact-time the wrapper degrades to the lossless hybrid rules\n * rather than failing.\n */\nexport function createStrategyCompactor(opts: StrategyCompactorOptions = {}): Compactor {\n const requested = opts.strategy ?? (opts.llmSelector ? 'selective' : 'hybrid');\n const strategy = requested as CompactorStrategy;\n let inner: Compactor;\n if (strategy === 'intelligent' || strategy === 'selective') {\n inner = new ProviderBackedCompactor(strategy, opts);\n } else {\n inner = new HybridCompactor({\n preserveK: opts.preserveK,\n eliseThreshold: opts.eliseThreshold,\n smart: opts.smart,\n });\n }\n return new JournaledCompactor(inner);\n}\n\n/**\n * Persists the exact post-compaction message array as a reconstruct event.\n * Every production compaction entry point resolves its compactor through\n * createStrategyCompactor(), so manual, automatic, recovery, WebUI and\n * eternal-engine compactions all share this one durability boundary.\n */\nclass JournaledCompactor implements Compactor {\n constructor(private readonly inner: Compactor) {}\n\n async compact(\n ctx: Context,\n compactOpts: { aggressive?: boolean | undefined } = {},\n ): Promise<CompactReport> {\n const state = ctx.state;\n const revisionBefore = state.revision;\n const report = await this.inner.compact(ctx, compactOpts);\n const changed =\n state.revision !== revisionBefore ||\n report.reductions.some((reduction) => reduction.saved > 0) ||\n report.repaired !== undefined;\n const writer = ctx.session;\n if (!changed || !writer) return report;\n\n const messages = ctx.messages.map(stripTransientMessageFields);\n try {\n await writer.append({\n type: 'context_snapshot',\n ts: new Date().toISOString(),\n reason: 'compaction',\n messages,\n });\n // A snapshot is a reconstruct boundary: do not return from compaction\n // while it exists only in the writer's in-memory batch.\n await writer.flush();\n } catch (err) {\n // Session logging remains best-effort by contract. Keep the compacted\n // live state usable, but make the lost exact-replay boundary explicit.\n console.error(\n JSON.stringify({\n level: 'error',\n event: 'session.context_snapshot_write_failed',\n sessionId: writer.id,\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }),\n );\n }\n return report;\n }\n}\n\nfunction stripTransientMessageFields(message: Message): Message {\n const { _estTokens: _ignored, ...persisted } = message;\n return persisted;\n}\n\nclass ProviderBackedCompactor implements Compactor {\n constructor(\n private readonly strategy: 'intelligent' | 'selective',\n private readonly opts: StrategyCompactorOptions,\n ) {}\n\n async compact(\n ctx: Context,\n compactOpts: { aggressive?: boolean | undefined } = {},\n ): Promise<CompactReport> {\n return this.resolveInner(ctx).compact(ctx, compactOpts);\n }\n\n /**\n * Construct the concrete compactor for this run. Rebuilt per call (cheap, no\n * I/O) so a model switch \u2014 which changes `ctx.provider.capabilities.maxContext`\n * \u2014 is always reflected. Reads the active ContextWindowPolicy from `ctx.meta`\n * so the LLM compactors honor the same thresholds/preserveK as the policy.\n */\n private resolveInner(ctx: Context): Compactor {\n const provider = ctx.provider;\n if (!provider) {\n // No provider on ctx \u2192 cannot run an LLM compactor. Degrade to lossless rules.\n return new HybridCompactor({\n preserveK: this.opts.preserveK,\n eliseThreshold: this.opts.eliseThreshold,\n });\n }\n\n const policy = readPolicy(ctx);\n const learnedMax = ctx.meta?.['effectiveMaxContext'];\n const maxContext =\n typeof learnedMax === 'number' && Number.isFinite(learnedMax) && learnedMax > 0\n ? Math.floor(learnedMax)\n : provider.capabilities?.maxContext || undefined;\n const thresholds = policy?.thresholds;\n const common = {\n provider,\n maxContext,\n preserveK: this.opts.preserveK ?? policy?.preserveK,\n eliseThreshold: this.opts.eliseThreshold ?? policy?.eliseThreshold,\n ...(thresholds\n ? { warnThreshold: thresholds.warn, softThreshold: thresholds.soft, hardThreshold: thresholds.hard }\n : {}),\n };\n\n if (this.strategy === 'selective') {\n return new SelectiveCompactor({\n ...common,\n selectorModel: this.opts.summarizerModel,\n selectorMaxOutputTokens: this.opts.selectorMaxOutputTokens,\n summarizerModel: this.opts.summarizerModel,\n });\n }\n return new IntelligentCompactor({\n ...common,\n summarizerModel: this.opts.summarizerModel,\n oneShotOrchestrator: this.opts.oneShotOrchestrator,\n });\n }\n}\n\nfunction readPolicy(ctx: Context): ContextWindowPolicy | null {\n const policy = ctx.meta?.['contextWindowPolicy'];\n if (!policy || typeof policy !== 'object') return null;\n const candidate = policy as Partial<ContextWindowPolicy>;\n if (typeof candidate.preserveK !== 'number' || !candidate.thresholds) return null;\n return candidate as ContextWindowPolicy;\n}\n", "import { randomUUID } from 'node:crypto';\nimport { runWithProcessTelemetry } from '../observability/process-telemetry.js';\nimport { runWithNetworkTelemetry } from '../observability/network-telemetry.js';\nimport { isDeepStrictEqual } from 'node:util';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { type Context, resolveEventSessionId } from '../core/context.js';\nimport {\n getDangerousCapabilities,\n hasDangerousCapabilityForSubagents,\n} from '../security/capabilities.js';\nimport { evaluateToolKanbanBoundary } from '../security/kanban-boundary.js';\nimport type { ToolResultBlock, ToolUseBlock } from '../types/blocks.js';\nimport type { Tool } from '../types/tool.js';\nimport {\n GOVERNED_TOOL_EXECUTOR_META_KEY,\n type GovernedToolExecutor,\n type ToolBatchResult,\n type ToolConfirmPendingResult,\n type ToolExecutionOutput,\n type ToolExecutorOptions,\n type ToolExecutorStrategy,\n} from '../types/tool-executor.js';\nimport { isWrongStackError } from '../types/errors.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport { coerceAgainstSchema, validateAgainstSchema } from '../utils/json-schema-validate.js';\nimport { subjectForToolInput } from '../utils/tool-subject.js';\nimport { createToolOutputSerializer } from '../utils/tool-output-serializer.js';\nimport type { ToolResultRenderMode } from '../types/config.js';\nimport { resolveToolResultRenderMode } from '../utils/tool-result-render-mode.js';\nimport type { ToolResultRenderModeConfig } from '../types/config.js';\nimport {\n abortReasonToError,\n clampTimeoutMs,\n classifyToolError,\n extractMalformedRaw,\n hashPermissionInput,\n hasMalformedArguments,\n maybePersistLargeToolOutput,\n} from './tool-executor-support.js';\nimport {\n blockedByHookResult,\n deniedResult,\n malformedInputResult,\n unknownToolResult,\n} from './tool-executor-results.js';\nimport {\n logToolFailure as logToolFailureEvent,\n logToolSuccess as logToolSuccessEvent,\n} from './tool-executor-logging.js';\nimport { executeStreamedTool } from './tool-executor-stream.js';\nexport { classifyToolError } from './tool-executor-support.js';\nexport class ToolExecutor {\n /** Minimum gap between coalesced `partial_output` tool.progress emits. */\n static readonly PROGRESS_EMIT_INTERVAL_MS = 100;\n /** Max chars of accumulated stream text carried per coalesced emit (tail). */\n static readonly PROGRESS_TAIL_CHARS = 16_384;\n /** Max chars of the head (beginning of output) kept alongside the tail. */\n static readonly PROGRESS_HEAD_CHARS = 16_384;\n\n private readonly serializer;\n private readonly iterationTimeoutMs: number;\n private readonly maxToolTimeoutMs: number;\n\n constructor(\n private readonly registry: { get(name: string): Tool | undefined; list(): Tool[] },\n private opts: ToolExecutorOptions,\n ) {\n this.iterationTimeoutMs = opts.iterationTimeoutMs ?? 300_000;\n this.maxToolTimeoutMs = opts.maxToolTimeoutMs ?? 300_000;\n this.serializer = createToolOutputSerializer({\n perIterationOutputCapBytes: opts.perIterationOutputCapBytes ?? 100_000,\n });\n }\n\n /**\n * Clear the interactive confirm awaiter so the executor returns\n * `ToolConfirmPendingResult` instead of blocking on stdin. Used by\n * the CLI to switch from inline prompts (REPL) to event-driven\n * confirmation (TUI) at runtime.\n */\n clearConfirmAwaiter(): void {\n this.opts.confirmAwaiter = undefined;\n }\n\n /**\n * Push the tool's per-tool result-render mode into the renderer as the\n * next-result render mode. The config key is `tools.resultRenderMode[name]`\n * \u2014 independent of the LLM-side `descriptionMode` so the two can be\n * toggled separately (`/tool read desc simple` vs `/tool read result\n * simple`). Defaults to `extend` when no entry is set.\n *\n * The hint is one-shot: the renderer consumes it on the next\n * `writeToolResult` call so an unset follow-up doesn't inherit a\n * previous tool's mode. Safe no-op when the renderer doesn't implement\n * `setResultRenderMode` (e.g. headless/test renderers).\n */\n private hintRenderMode(toolName: string): void {\n const renderer = this.opts.renderer;\n if (!renderer || typeof renderer.setResultRenderMode !== 'function') return;\n const modes: ToolResultRenderModeConfig | undefined = this.opts.resultRenderModes;\n const mode: ToolResultRenderMode = resolveToolResultRenderMode(modes, toolName);\n renderer.setResultRenderMode(toolName, mode);\n }\n\n private logToolSuccess(\n ctx: Context,\n use: ToolUseBlock,\n toolName: string,\n durationMs: number,\n outputChars: number,\n ): void {\n logToolSuccessEvent(this.opts, ctx, use, toolName, durationMs, outputChars);\n }\n\n private logToolFailure(\n ctx: Context,\n use: ToolUseBlock,\n toolName: string,\n durationMs: number,\n err: unknown,\n ): void {\n logToolFailureEvent(this.opts, ctx, use, toolName, durationMs, err);\n }\n\n /**\n * Execute a batch of tool uses using the configured strategy.\n * Returns the execution results and the remaining output budget.\n */\n async executeBatch(\n toolUses: ToolUseBlock[],\n ctx: Context,\n strategy: ToolExecutorStrategy,\n ): Promise<ToolBatchResult> {\n return this.withGovernedExecutionBridge(ctx, () =>\n this.executeBatchInternal(toolUses, ctx, strategy),\n );\n }\n\n /**\n * Internal batch implementation. Nested meta-tool calls enter here through\n * the governed bridge so they traverse the same validation, hooks,\n * permission/capability, timeout, scrubbing, and audit path without\n * replacing the bridge that is already active for the outer call.\n */\n private async executeBatchInternal(\n toolUses: ToolUseBlock[],\n ctx: Context,\n strategy: ToolExecutorStrategy,\n ): Promise<ToolBatchResult> {\n let budget = this.opts.perIterationOutputCapBytes ?? 100_000;\n\n const runOne = async (use0: ToolUseBlock): Promise<ToolExecutionOutput> => {\n const start = Date.now();\n // `use` is rebindable because a PreToolUse hook may rewrite its input.\n let use = use0;\n const tool = this.registry.get(use.name);\n\n // Fast path: unknown tool\n if (!tool) {\n const result = unknownToolResult(use, () => this.registry.list().map((t) => t.name));\n budget = this.budgetForString(result.content, budget);\n return { result, tool, durationMs: Date.now() - start };\n }\n\n // Provider boundary: the model's tool arguments arrive as a raw JSON\n // string accumulated over streamed deltas. When that string is not a\n // valid JSON object (truncated, scalar, or mangled by a proxy/local\n // model), the parsers wrap it under a sentinel key instead of silently\n // producing `{}`. Detect the sentinel BEFORE schema validation: a\n // schema with required fields would otherwise mask this case with a\n // misleading \"field missing\" error, when the actionable feedback is\n // \"your arguments were not a JSON object \u2014 here is what arrived\".\n if (hasMalformedArguments(use.input)) {\n const result = malformedInputResult(use, extractMalformedRaw(use.input));\n budget = this.budgetForString(result.content, budget);\n return { result, tool, durationMs: Date.now() - start };\n }\n\n // Strong guarantee: Validate input against the tool's declared JSON Schema\n // *before* permission checks or execution. This is a hard gate \u2014 bad calls\n // are rejected early with actionable feedback so the model can self-correct.\n // Before rejecting, one lossless coercion pass runs (string \"5\" \u2192 5,\n // \"true\" \u2192 true, double-encoded JSON strings revived): models routinely\n // deliver the right content in the wrong type, and silently fixing that\n // beats burning a round-trip on an error the model may repeat.\n const validation = validateAgainstSchema(use.input, tool.inputSchema);\n if (!validation.ok) {\n const coercion = coerceAgainstSchema(use.input, tool.inputSchema);\n const revalidation = coercion.changed\n ? validateAgainstSchema(coercion.value, tool.inputSchema)\n : validation;\n if (coercion.changed && revalidation.ok) {\n this.opts.logger?.info('tool arguments coerced to match inputSchema', {\n tool: tool.name,\n id: use.id,\n });\n use = { ...use, input: coercion.value as Record<string, unknown> };\n } else {\n const errorDetails = revalidation.errors\n .map((e) => ` - ${e.path || 'input'}: ${e.message}`)\n .join('\\n');\n\n const result = {\n type: 'tool_result' as const,\n tool_use_id: use.id,\n content:\n `Invalid arguments for tool \"${tool.name}\".\\n\\n` +\n `Validation errors:\\n${errorDetails}\\n\\n` +\n `Fix exactly the fields listed above and call the tool again. ` +\n `You can use the \"tool-help\" tool with name=\"${tool.name}\" to see the exact expected schema.`,\n is_error: true,\n };\n budget = this.budgetForString(result.content, budget);\n return { result, tool, durationMs: Date.now() - start };\n }\n }\n\n // Capability safety net at the executor level (defense in depth).\n // Tools declaring dangerous capabilities are subject to stricter\n // permission enforcement in the post-policy block below (line ~150+).\n // In non-YOLO contexts, an `auto` permission is elevated to `confirm`\n // for dangerous-capability tools, reducing prompt-injection blast radius.\n const toolDangerousCaps = getDangerousCapabilities(tool);\n\n // PreToolUse hooks: may block the call outright or rewrite its input.\n // Runs before the permission check so a hook can veto a tool that the\n // trust policy would otherwise auto-allow.\n if (this.opts.hookRunner?.has('PreToolUse')) {\n const pre = await this.opts.hookRunner.preToolUse(tool.name, use.input, ctx);\n if (pre.block) {\n const result = blockedByHookResult(use, pre.reason);\n budget = this.budgetForString(result.content, budget);\n return { result, tool, durationMs: Date.now() - start };\n }\n if (pre.input) {\n // P3 #19 (before-release.md): skip the re-validation when the hook\n // passed the input through unchanged. Most hooks either block or\n // return the original input verbatim \u2014 re-validating the same shape\n // the executor already validated above is wasted work. Use\n // node:util's isDeepStrictEqual for a structural, order-sensitive\n // comparison (tool inputs are plain JSON, so reference identity is\n // not enough \u2014 a hook may clone before returning).\n if (!isDeepStrictEqual(pre.input, use.input)) {\n // A hook rewrote the arguments \u2014 re-validate before trusting them.\n const reval = validateAgainstSchema(pre.input, tool.inputSchema);\n if (!reval.ok) {\n const errorDetails = reval.errors\n .map((e) => ` - ${e.path || 'input'}: ${e.message}`)\n .join('\\n');\n const result = {\n type: 'tool_result' as const,\n tool_use_id: use.id,\n content:\n `A PreToolUse hook rewrote the arguments for \"${tool.name}\" into an invalid shape.\\n\\n` +\n `Validation errors:\\n${errorDetails}`,\n is_error: true,\n };\n budget = this.budgetForString(result.content, budget);\n return { result, tool, durationMs: Date.now() - start };\n }\n use = { ...use, input: pre.input };\n }\n }\n }\n\n // P3 #16 (before-release.md): cross-field validation. Called after\n // schema validation and PreToolUse hooks (which may have rewritten\n // the input) but before permission checks and execution. Lets tools\n // express invariants the JSON Schema cannot (e.g. old_string !==\n // new_string) and get them rejected with the same error formatting.\n if (typeof tool.validate === 'function') {\n const crossFieldErrors = tool.validate(use.input);\n if (crossFieldErrors.length > 0) {\n const errorDetails = crossFieldErrors.map((e) => ` - ${e}`).join('\\n');\n const result = {\n type: 'tool_result' as const,\n tool_use_id: use.id,\n content:\n `Invalid arguments for tool \"${tool.name}\".\\n\\n` +\n `Validation errors:\\n${errorDetails}`,\n is_error: true,\n };\n budget = this.budgetForString(result.content, budget);\n return { result, tool, durationMs: Date.now() - start };\n }\n }\n\n // Kanban boundaries are an execution-time ceiling, not prompt advice.\n // Resolve the live board/task on every call so edits made in WebUI/TUI\n // take effect during an already-running agent assignment.\n const boundary = await evaluateToolKanbanBoundary(tool, use.input, ctx);\n if (boundary.decision === 'block') {\n const result = {\n type: 'tool_result' as const,\n tool_use_id: use.id,\n content: `Tool \"${tool.name}\" blocked by Kanban boundary. ${boundary.reason ?? ''}`.trim(),\n is_error: true,\n };\n budget = this.budgetForString(result.content, budget);\n return { result, tool, durationMs: Date.now() - start };\n }\n\n const decision = await this.opts.permissionPolicy.evaluate(tool, use.input, ctx);\n\n // Post-permission dangerous capability enforcement (B-side guarantee).\n // Even after the permission policy has spoken, we apply an extra conservative\n // rule for tools that declare high-risk capabilities (shell arbitrary, write outside\n // project, mcp proxy, etc.). This reduces the blast radius of prompt injection.\n let effectivePermission = decision.permission;\n\n // YOLO is the user's explicit fast-path, so it waives the post-policy\n // dangerous-capability net after the permission policy has returned\n // `auto`. Outside YOLO, a trust-file auto-allow for a shell tool still\n // gets a confirm, so a single trusted pattern can't silently widen into\n // arbitrary shell.\n // Detected via optional methods so policies without them (AutoApprove,\n // test mocks) keep the stricter default.\n const policy = this.opts.permissionPolicy;\n const yolo = policy.getYolo?.() === true;\n\n // An `auto` decision sourced from `'yolo'` is authoritative: it comes\n // either from the leader's explicit YOLO mode or from a subagent's\n // `AutoApprovePermissionPolicy`, which already enforces a capability\n // allowlist (and now requires every dangerous capability to be granted\n // explicitly). In both cases the allowlist IS the blast-radius control,\n // so the conservative downgrade below would be redundant \u2014 and for a\n // non-interactive subagent (no confirmAwaiter) it would turn a granted\n // write into a `confirm` that can never be answered. Trust-file `auto`\n // (source 'trust') is NOT waived: a single trusted pattern must not\n // silently widen into arbitrary dangerous-capability execution.\n const authoritativeAuto = decision.source === 'yolo';\n\n const capabilityDowngraded =\n toolDangerousCaps.length > 0 &&\n effectivePermission === 'auto' &&\n !yolo &&\n !authoritativeAuto;\n if (capabilityDowngraded) {\n // Outside yolo we force at least 'confirm' for dangerous-capability tools.\n effectivePermission = 'confirm';\n }\n\n // Explicit YOLO/trust rules never waive a Kanban scope. A confirm-mode\n // violation needs a fresh human approval for this concrete call.\n if (boundary.decision === 'confirm' && effectivePermission !== 'deny') {\n effectivePermission = 'confirm';\n }\n\n this.opts.events?.emit('permission.evaluated', {\n sessionId: resolveEventSessionId(ctx),\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}),\n ...(ctx.agentId ? { agentId: ctx.agentId } : {}),\n name: tool.name,\n id: use.id,\n inputHash: hashPermissionInput(use.input, this.opts.secretScrubber),\n policyDecision: decision.permission,\n effectiveDecision: effectivePermission,\n decisionSource: decision.source,\n ...(decision.reason ? { reason: decision.reason } : {}),\n ...(decision.riskTier ?? tool.riskTier\n ? { riskTier: decision.riskTier ?? tool.riskTier }\n : {}),\n yoloEnabled: yolo,\n boundaryDecision: boundary.decision,\n ...(boundary.reason ? { boundaryReason: boundary.reason } : {}),\n capabilityDowngraded,\n taskId: ctx.currentKanbanTaskId,\n boardId: ctx.currentKanbanBoardId,\n ...(typeof ctx.provider === 'object'\n ? { provider: (ctx.provider as { id: string }).id }\n : {}),\n ...(ctx.model ? { model: ctx.model } : {}),\n });\n\n if (effectivePermission === 'deny') {\n const result = deniedResult(use, decision.reason);\n budget = this.budgetForString(result.content, budget);\n return { result, tool, durationMs: Date.now() - start };\n }\n\n if (effectivePermission === 'confirm') {\n const suggestedPattern =\n boundary.decision === 'confirm'\n ? `kanban-boundary:${boundary.path ?? tool.name}`\n : subjectForToolInput(tool.name, use.input, tool.subjectKey) ?? tool.name;\n if (this.opts.confirmAwaiter) {\n // Race the interactive prompt against the run's abort signal so an\n // interrupt never leaves the executor blocked on a confirmation\n // nobody will answer. 'abort' produces a distinct (non-deny) error\n // result \u2014 no trust/deny bookkeeping happens for an interrupt.\n const awaiter = this.opts.confirmAwaiter;\n const choice = await new Promise<'yes' | 'no' | 'always' | 'deny' | 'abort'>(\n (resolve, reject) => {\n const signal = 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 awaiter(tool, use.input, use.id, suggestedPattern).then(\n (c) => {\n signal.removeEventListener('abort', onAbort);\n resolve(c);\n },\n (e) => {\n signal.removeEventListener('abort', onAbort);\n reject(e);\n },\n );\n },\n );\n if (choice !== 'yes' && choice !== 'always') {\n const result = {\n type: 'tool_result' as const,\n tool_use_id: use.id,\n content:\n choice === 'abort'\n ? `Tool \"${tool.name}\" was not executed \u2014 the run was aborted while awaiting confirmation.`\n : `Tool \"${tool.name}\" denied by user.`,\n is_error: true,\n };\n budget = this.budgetForString(result.content, budget);\n return { result, tool, durationMs: Date.now() - start };\n }\n // fall through to execute\n } else {\n const pending: ToolConfirmPendingResult = {\n type: 'tool_confirm_pending',\n toolUseId: use.id,\n toolName: tool.name,\n input: use.input,\n suggestedPattern,\n decisionSource: decision.source,\n riskTier: decision.riskTier ?? tool.riskTier,\n ...(boundary.decision === 'confirm' && boundary.reason\n ? { boundaryReason: boundary.reason }\n : {}),\n };\n return { result: pending, tool, durationMs: Date.now() - start };\n }\n }\n\n // effectivePermission === 'auto' (after all safety layers)\n // Capability audit for observability.\n const toolCapsForAudit = hasDangerousCapabilityForSubagents(tool)\n ? (tool.capabilities ?? [])\n : [];\n\n // L1-C: trace each tool execution. Span is a no-op unless an OTel\n // adapter or other Tracer is bound \u2014 zero overhead by default.\n // Skip JSON.stringify for the common case (no dangerous capabilities)\n // to avoid per-call serialization of a static empty array.\n const span = this.opts.tracer?.startSpan(`tool.${tool.name}`, {\n 'tool.name': tool.name,\n 'tool.mutating': tool.mutating,\n 'tool.permission': tool.permission,\n 'tool.capabilities':\n toolCapsForAudit.length > 0 ? JSON.stringify(tool.capabilities ?? []) : '[]',\n 'tool.has_dangerous_capabilities': toolCapsForAudit.length > 0,\n });\n try {\n // Snapshot the target before a write executes so its eventual file event\n // can distinguish a new file from an overwrite. This is deliberately\n // best-effort: observability must never prevent the tool from running.\n const inputPath =\n use.input && typeof use.input === 'object'\n ? (use.input as Record<string, unknown>).path\n : undefined;\n const caps = tool.capabilities ?? [];\n const hasFileCapability = caps.includes('fs.read') || caps.includes('fs.write');\n const absPath =\n hasFileCapability && typeof inputPath === 'string'\n ? path.isAbsolute(inputPath)\n ? inputPath\n : path.resolve(ctx.projectRoot, inputPath)\n : undefined;\n let writeTargetExisted: boolean | undefined;\n if (tool.name === 'write' && caps.includes('fs.write') && absPath) {\n writeTargetExisted = await fs.stat(absPath).then(\n (stat) => stat.isFile(),\n (error: NodeJS.ErrnoException) => (error.code === 'ENOENT' ? false : undefined),\n );\n }\n\n // Split produce (async, concurrency-safe) from settle (synchronous,\n // budget-mutating). The long tool run + serialize + scrub + spill\n // happens here and touches no shared budget. The cap is then applied\n // synchronously below against the LIVE budget, so parallel tools\n // settling in sequence share one cumulative cap instead of each\n // reading the same stale starting budget (which let N parallel tools\n // pass N\u00D7 the cap). Pass the current budget only as a spill-threshold\n // hint, not as the authoritative cap.\n const producedText = await this.produceToolOutput(tool, use, ctx, budget);\n // \u2500\u2500 Synchronous settle: no `await` between reading `budget` and\n // writing it back, so two parallel tools can't interleave here.\n let { block: result, bytes } = this.settleToolOutput(tool, use, producedText, budget);\n budget -= bytes;\n // PostToolUse hooks: observe the result and optionally append\n // context (e.g. a linter note) that the model sees alongside the\n // tool output. Append the post-hook bytes to the budget spend\n // without re-walking the full result content.\n if (this.opts.hookRunner?.has('PostToolUse')) {\n const post = await this.opts.hookRunner.postToolUse(\n tool.name,\n use.input,\n { content: String(result.content), isError: !!result.is_error },\n ctx,\n );\n if (post.additionalContext) {\n if (post.contextAs === 'separate') {\n // Keep plugin notices visually separated from the actual tool\n // output by storing the context on ctx so agent-tools merges\n // it into the same user message as the tool_results \u2014 this\n // preserves tool-use/tool-result adjacency. Accumulate across\n // multiple parallel PostToolUse hooks.\n ctx.pendingPostToolContext = ctx.pendingPostToolContext\n ? `${ctx.pendingPostToolContext}\\n\\n${post.additionalContext}`\n : post.additionalContext;\n } else {\n const appended = `\\n\\n${post.additionalContext}`;\n result = { ...result, content: `${result.content}${appended}` };\n // Only the appended bytes are new \u2014 the pre-hook portion was\n // already counted by enforceCap. Walking just the appended\n // tail is `O(additionalContext.length)`, never `O(content)`.\n // Floor at 0 to match `decrementBudget`'s pre-fix clamp.\n budget = Math.max(0, budget - Buffer.byteLength(appended, 'utf8'));\n }\n }\n }\n const outputChars = typeof result.content === 'string' ? result.content.length : 0;\n span?.setAttribute('tool.is_error', !!result.is_error);\n span?.setAttribute('tool.output_bytes', outputChars);\n this.logToolSuccess(ctx, use, tool.name, Date.now() - start, outputChars);\n\n // Auto-emit file event for tools with fs.read or fs.write capabilities.\n // This central integration captures ALL file operations without requiring\n // per-tool wiring \u2014 the tool executor is the single dispatch point.\n if (!result.is_error && typeof inputPath === 'string' && absPath) {\n const operation =\n tool.name === 'read'\n ? 'read'\n : caps.includes('fs.write') && tool.name === 'write'\n ? writeTargetExisted === false\n ? 'create'\n : 'update'\n : caps.includes('fs.write')\n ? 'update'\n : 'read';\n const ts = new Date().toISOString();\n ctx.recordFileEvent?.({\n operation,\n filePath: inputPath,\n absPath,\n toolName: tool.name,\n toolUseId: use.id,\n durationMs: Date.now() - start,\n });\n // Also emit EventBus event for live observability subscribers\n // (the `file.event` channel). The same data shape is persisted\n // to session JSONL via ctx.recordFileEvent() above.\n this.opts.events?.emit('file.event', {\n operation,\n filePath: inputPath,\n absPath,\n sessionId: resolveEventSessionId(ctx),\n agentId: ctx.agentId,\n agentName: ctx.agentName,\n provider:\n typeof ctx.provider === 'object'\n ? (ctx.provider as { id: string }).id\n : String(ctx.provider),\n model: ctx.model,\n toolName: tool.name,\n toolUseId: use.id,\n scope: ctx.currentKanbanTaskId ? 'task' : 'session',\n taskId: ctx.currentKanbanTaskId,\n boardId: ctx.currentKanbanBoardId,\n timestamp: ts,\n durationMs: Date.now() - start,\n });\n }\n\n return { result, tool, durationMs: Date.now() - start };\n } catch (err) {\n // Preserve structured errors on the throw path. A WrongStackError\n // carries `code`, `subsystem`, `severity`, `recoverable`, `context`,\n // and `cause` \u2014 flattening it to `err.message` here would lose all of\n // that before the agent loop, audit log, or recovery strategies ever\n // see it. Re-throw so safeRun's catch can render via `describe()` and\n // any outer handler (agent-loop.toWrongStackError, etc.) preserves the\n // structured shape. Bare Errors and primitives keep the old behavior:\n // there's no rich data to preserve, so the user gets a scrubbed\n // tool_result block.\n if (isWrongStackError(err)) {\n if (err instanceof Error) span?.recordError(err);\n span?.setAttribute('tool.is_error', true);\n this.logToolFailure(ctx, use, tool.name, Date.now() - start, err);\n throw err;\n }\n const msg = toErrorMessage(err);\n const scrubbed = this.opts.secretScrubber.scrub(msg);\n const { category, retryable, detail } = classifyToolError(err);\n this.hintRenderMode(tool.name);\n this.opts.renderer?.writeToolResult(tool.name, scrubbed, true);\n const result = {\n type: 'tool_result' as const,\n tool_use_id: use.id,\n content: `Tool \"${tool.name}\" threw: ${scrubbed}`,\n is_error: true,\n };\n budget = this.budgetForString(result.content, budget);\n if (err instanceof Error) span?.recordError(err);\n span?.setAttribute('tool.is_error', true);\n span?.setAttribute('tool.error_category', category);\n span?.setAttribute('tool.error_retryable', retryable);\n if (detail) span?.setAttribute('tool.error_detail', detail);\n this.logToolFailure(ctx, use, tool.name, Date.now() - start, err);\n return { result, tool, durationMs: Date.now() - start };\n } finally {\n span?.end();\n }\n };\n\n // Run a single tool but never let an exception propagate to the\n // gather() below \u2014 `runOne` is already try/catch-wrapped for the\n // execution phase, but the *pre*-execution paths (permission policy,\n // confirmAwaiter) are unguarded and an unexpected throw there would\n // collapse Promise.all and lose every sibling's output. Wrap each\n // call so a per-tool failure becomes a per-tool error result.\n const safeRun = async (use: ToolUseBlock): Promise<ToolExecutionOutput> => {\n try {\n return await runOne(use);\n } catch (err) {\n // For structured errors, render via describe() so the model and user\n // see `code: message [context...]` instead of just `message`. This is\n // the second half of the structured-error preservation path \u2014 the\n // first half is runOne's catch rethrowing instead of flattening.\n // Bare errors keep the old \"execution failed: <scrubbed>\" prefix.\n const isStructured = isWrongStackError(err);\n const msg = isStructured ? err.describe() : toErrorMessage(err);\n const scrubbed = this.opts.secretScrubber.scrub(msg);\n const { category, retryable, detail } = classifyToolError(err);\n const tool = this.registry.get(use.name);\n const toolName = tool?.name ?? use.name;\n this.hintRenderMode(toolName);\n this.opts.renderer?.writeToolResult(toolName, scrubbed, true);\n const result = {\n type: 'tool_result' as const,\n tool_use_id: use.id,\n content: isStructured ? scrubbed : `Tool \"${use.name}\" execution failed: ${scrubbed}`,\n is_error: true,\n };\n budget = this.budgetForString(result.content, budget);\n // Classification result is stored in the result for future retry logic;\n // span attributes are set in runOne's catch block (this err bubbles from there).\n void category;\n void retryable;\n void detail;\n return { result, tool, durationMs: 0 };\n }\n };\n\n if (strategy === 'sequential') {\n const outputs: ToolExecutionOutput[] = [];\n for (const use of toolUses) {\n if (use) outputs.push(await safeRun(use));\n }\n return { outputs, remainingBudget: budget };\n }\n\n if (strategy === 'parallel') {\n const outputs = await Promise.all(toolUses.map((use) => safeRun(use)));\n return { outputs, remainingBudget: budget };\n }\n\n // smart: non-mutating in parallel, then mutating sequentially\n const nonMutating: ToolUseBlock[] = [];\n const mutating: ToolUseBlock[] = [];\n for (const use of toolUses) {\n if (!use) continue;\n const tool = this.registry.get(use.name);\n if (tool?.mutating) mutating.push(use);\n else nonMutating.push(use);\n }\n const firstPass = await Promise.all(nonMutating.map((use) => safeRun(use)));\n const secondPass: ToolExecutionOutput[] = [];\n for (const use of mutating) {\n secondPass.push(await safeRun(use));\n }\n return {\n outputs: [...firstPass, ...secondPass],\n remainingBudget: budget,\n };\n }\n\n /**\n * Install the executor-owned bridge used by meta-tools for nested calls.\n * The bridge deliberately returns the governed, scrubbed ToolResultBlock\n * content rather than the raw tool value. This prevents a meta-tool from\n * bypassing output controls while preserving structured success/failure.\n */\n private async withGovernedExecutionBridge<T>(ctx: Context, run: () => Promise<T>): Promise<T> {\n const previous = ctx.meta[GOVERNED_TOOL_EXECUTOR_META_KEY];\n if (typeof previous === 'function') return run();\n\n const bridge: GovernedToolExecutor = async (toolName, input) => {\n const nestedUse: ToolUseBlock = {\n type: 'tool_use',\n id: `nested-${randomUUID()}`,\n name: toolName,\n input,\n };\n const batch = await this.executeBatchInternal([nestedUse], ctx, 'sequential');\n const output = batch.outputs[0];\n if (!output) {\n return { success: false, error: `tool \"${toolName}\" produced no result` };\n }\n if (output.result.type === 'tool_confirm_pending') {\n return {\n success: false,\n error: `tool \"${toolName}\" requires separate confirmation; call it directly`,\n };\n }\n if (output.result.is_error) {\n return { success: false, error: String(output.result.content) };\n }\n return { success: true, result: output.result.content };\n };\n\n ctx.meta[GOVERNED_TOOL_EXECUTOR_META_KEY] = bridge;\n try {\n return await run();\n } finally {\n if (previous === undefined) delete ctx.meta[GOVERNED_TOOL_EXECUTOR_META_KEY];\n else ctx.meta[GOVERNED_TOOL_EXECUTOR_META_KEY] = previous;\n }\n }\n\n /**\n * Execute a single tool with timeout and output capping after its permission\n * decision has already been resolved by executeBatch/the confirmation flow.\n * Also installs the governed bridge because confirmed tools are re-run\n * through this method after a pending confirmation.\n */\n async executeTool(\n tool: Tool,\n use: ToolUseBlock,\n ctx: Context,\n budget: number,\n ): Promise<{ block: ToolResultBlock; bytes: number }> {\n return this.withGovernedExecutionBridge(ctx, async () => {\n const text = await this.produceToolOutput(tool, use, ctx, budget);\n return this.settleToolOutput(tool, use, text, budget);\n });\n }\n\n /**\n * Async \"produce\" phase: run the tool, serialize, scrub, and spill an\n * oversized output to a disk artifact. Returns the pre-cap text. This is\n * the long-running, concurrency-safe part \u2014 it touches NO shared budget\n * state, so multiple invocations can run in parallel without racing.\n *\n * The `budgetHint` only gates the disk-spill threshold (a heuristic for\n * \"is this output large enough to persist\"); it is NOT the output cap.\n * The authoritative cap is applied synchronously in settleToolOutput()\n * against the live budget.\n */\n private async produceToolOutput(\n tool: Tool,\n use: ToolUseBlock,\n ctx: Context,\n budgetHint: number,\n ): Promise<string> {\n this.opts.events?.emit('tool.started', {\n sessionId: resolveEventSessionId(ctx),\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}),\n agentId: ctx.agentId,\n agentName: ctx.agentName,\n name: tool.name,\n id: use.id,\n input: use.input,\n taskId: ctx.currentKanbanTaskId,\n boardId: ctx.currentKanbanBoardId,\n ...(typeof ctx.provider === 'object'\n ? { provider: (ctx.provider as { id: string }).id }\n : {}),\n ...(ctx.model ? { model: ctx.model } : {}),\n });\n this.opts.renderer?.writeToolCall(tool.name, use.input);\n const output = await this.runWithTimeout(tool, use.input, ctx.signal, ctx, use.id);\n const text = this.serializer.serialize(output, { toolName: tool.name, input: use.input, tool });\n const scrubbed = this.opts.secretScrubber.scrub(text);\n return maybePersistLargeToolOutput(tool.name, scrubbed, budgetHint);\n }\n\n /**\n * Synchronous \"settle\" phase: enforce the output cap against the CURRENT\n * budget, render, and build the result block. This MUST stay synchronous\n * (no awaits) so that, in the parallel/smart strategies, two tools settling\n * one after another against the shared closure budget can't interleave a\n * stale read with a write. The first to settle consumes its bytes; the next\n * settles against the reduced budget; once the budget hits 0, enforceCap\n * truncates \u2014 making the per-iteration cap genuinely CUMULATIVE across\n * parallel tools instead of degrading into a per-tool cap.\n */\n private settleToolOutput(\n tool: Tool,\n use: ToolUseBlock,\n text: string,\n budget: number,\n ): { block: ToolResultBlock; bytes: number } {\n // enforceCap already walks the text to compute bytes for the budget\n // cap. Carry the residual budget back as `bytes` so the caller can\n // deduct the spend without a second `Buffer.byteLength` walk \u2014 and\n // never falls back to `JSON.stringify` on a structured value.\n const { text: capped, newBudget } = this.serializer.enforceCap(text, budget);\n this.hintRenderMode(tool.name);\n this.opts.renderer?.writeToolResult(tool.name, capped, false);\n return {\n block: {\n type: 'tool_result',\n tool_use_id: use.id,\n name: tool.name,\n content: capped,\n is_error: false,\n },\n // `budget - newBudget` is the exact byte count enforceCap spent\n // (capped at `budget` so a truncated output shows as `budget`\n // consumed, matching the pre-fix `decrementBudget` semantics).\n bytes: budget - newBudget,\n };\n }\n\n private async runWithTimeout(\n tool: Tool,\n input: unknown,\n parentSignal: AbortSignal,\n ctx: Context,\n toolUseId?: string | undefined,\n ): Promise<unknown> {\n if (parentSignal.aborted) {\n // Re-throw the original abort reason, whether it's an Error, string, or undefined.\n if (parentSignal.reason instanceof Error) throw parentSignal.reason;\n throw new Error(typeof parentSignal.reason === 'string' ? parentSignal.reason : 'aborted');\n }\n // A small number of orchestration tools (notably `delegate`) implement\n // their own heartbeat-aware timeout policy. Applying the executor's fixed\n // max-tool ceiling on top would abort healthy multi-hour work after five\n // minutes. They still run through the abort race below with parentSignal,\n // so /interrupt and session cancellation remain immediate.\n const combined = tool.managesOwnTimeout\n ? parentSignal\n : AbortSignal.any([\n parentSignal,\n AbortSignal.timeout(\n clampTimeoutMs(tool.timeoutMs ?? this.iterationTimeoutMs, this.maxToolTimeoutMs),\n ),\n ]);\n\n let output: unknown;\n // Streaming variant takes precedence \u2014 yields progress events, then\n // a final 'final' event with the typed output. Tools that don't\n // implement executeStream fall through to the standard execute path.\n // The async IIFE also captures a synchronous throw from execute() as\n // a rejection so the race below observes it.\n const execute = () => typeof tool.executeStream === 'function'\n ? this.runStreamedTool(tool, input, ctx, combined, toolUseId)\n : (async () => tool.execute(input, ctx, { signal: combined }))();\n const telemetryToolCallId = toolUseId ?? `nested-${randomUUID()}`;\n const toolPromise: Promise<unknown> = this.opts.events\n ? runWithNetworkTelemetry({\n events: this.opts.events!, sessionId: resolveEventSessionId(ctx),\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}), ...(ctx.agentId ? { agentId: ctx.agentId } : {}),\n toolCallId: telemetryToolCallId, initiator: 'tool', operationName: tool.name,\n }, () => runWithProcessTelemetry(\n {\n events: this.opts.events!,\n sessionId: resolveEventSessionId(ctx),\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}),\n ...(ctx.agentId ? { agentId: ctx.agentId } : {}),\n toolCallId: telemetryToolCallId,\n toolName: tool.name,\n },\n execute,\n ))\n : execute();\n // Side branch: when the race exits early on abort, the still-running\n // tool promise must not surface its eventual rejection as an\n // unhandled-rejection crash.\n toolPromise.catch(() => {});\n try {\n // Race the tool against the combined abort/timeout signal. A tool\n // that honors the signal rejects on its own; a tool that IGNORES it\n // (e.g. a blocking fleet wait like `delegate` or `await_tasks`)\n // would otherwise pin the agent loop forever \u2014 the abort check in\n // agent-loop only runs after executeTools() settles. The race\n // guarantees the executor itself unblocks the moment the signal\n // fires, so /interrupt, Esc, and timeouts can always unwind the run.\n output = await new Promise<unknown>((resolve, reject) => {\n const onAbort = () => {\n // One macrotask of grace: a signal-honoring tool typically rejects\n // with its own (richer) error from its abort listener, which ran\n // before this one. Deferring our generic rejection past the pending\n // microtask chain (promise adoption included) lets the tool's error\n // win, while a signal-IGNORING tool is still cut off within ~1ms.\n setTimeout(() => reject(abortReasonToError(combined.reason)), 0);\n };\n combined.addEventListener('abort', onAbort, { once: true });\n toolPromise.then(\n (v) => {\n combined.removeEventListener('abort', onAbort);\n resolve(v);\n },\n (e) => {\n combined.removeEventListener('abort', onAbort);\n reject(e);\n },\n );\n });\n } catch (err) {\n // If aborted, run cleanup before re-throwing so the tool can release\n // resources (child processes, file handles, network connections).\n if (combined.aborted) await this.runToolCleanup(tool, input, ctx);\n throw err;\n }\n // The tool returned without throwing, but the signal may have aborted\n // in the same tick a signal-ignoring tool resolved. Treat that as an\n // abort: clean up and surface the abort to the caller so a late, stale\n // result is never returned as success.\n if (combined.aborted) {\n await this.runToolCleanup(tool, input, ctx);\n throw abortReasonToError(combined.reason);\n }\n return output;\n }\n\n /** Best-effort tool cleanup; never let it mask the original error. */\n private async runToolCleanup(tool: Tool, input: unknown, ctx: Context): Promise<void> {\n if (typeof tool.cleanup !== 'function') return;\n try {\n await tool.cleanup(input, ctx);\n } catch {\n /* swallow \u2014 never let cleanup mask the original error */\n }\n }\n\n private async runStreamedTool(\n tool: Tool,\n input: unknown,\n ctx: Context,\n signal: AbortSignal,\n toolUseId: string | undefined,\n ): Promise<unknown> {\n return executeStreamedTool({\n tool,\n input,\n ctx,\n signal,\n toolUseId,\n events: this.opts.events,\n progressEmitIntervalMs: ToolExecutor.PROGRESS_EMIT_INTERVAL_MS,\n progressTailChars: ToolExecutor.PROGRESS_TAIL_CHARS,\n progressHeadChars: ToolExecutor.PROGRESS_HEAD_CHARS,\n });\n }\n\n /**\n * Subtract a string-content result's UTF-8 byte length from the\n * iteration output budget. Used for synthesized results (unknown tool,\n * validation error, blocked, threw) where the content is a small\n * string built in the executor. The success path no longer goes\n * through here \u2014 `executeTool` carries the exact byte count it spent\n * in its return value, derived from `enforceCap`'s `newBudget`.\n *\n * Floors the result at 0 to match the pre-fix `decrementBudget`\n * semantics (over-budget spends don't underflow the running total).\n */\n private budgetForString(content: string, budget: number): number {\n return Math.max(0, budget - Buffer.byteLength(content, 'utf8'));\n }\n}\n", "import { AsyncLocalStorage } from 'node:async_hooks';\nimport { createHash } from 'node:crypto';\nimport type { EventBus, EventMap } from '../kernel/events.js';\nimport { redactCommandArgs } from './redact-command.js';\n\nexport interface ProcessTelemetryContext {\n events: EventBus;\n sessionId: string;\n traceId?: string | undefined;\n agentId?: string | undefined;\n toolCallId: string;\n toolName: string;\n}\n\nconst storage = new AsyncLocalStorage<ProcessTelemetryContext>();\n\nexport function runWithProcessTelemetry<T>(context: ProcessTelemetryContext, run: () => T): T {\n return storage.run(context, run);\n}\n\nexport function emitProcessStarted(\n event: Omit<EventMap['process.started'], keyof ProcessTelemetryContext>,\n): void {\n // SECURITY: redact command + args centrally so every consumer (bash, exec,\n // spawnStream) is safe by default. process.* events flow to observability\n // sinks (OTLP/Prometheus exporters live in this package), and secret-bearing\n // CLI flags (--token=\u2026, -pSECRET, curl -H \"Authorization: Bearer \u2026\") must\n // never reach them. Joining command+args then redacting (rather than\n // redacting each in isolation) handles the common case where the flag name\n // and its value land in separate argv tokens.\n const { command, args } = redactCommandArgs(event.command, event.args);\n emit('process.started', { ...event, command, args });\n}\n\nexport function emitProcessOutput(input: {\n pid?: number | undefined;\n stream: 'stdout' | 'stderr';\n chunk: string | Buffer;\n}): void {\n const bytes = Buffer.byteLength(input.chunk);\n emit('process.output', {\n ...(input.pid !== undefined ? { pid: input.pid } : {}),\n stream: input.stream,\n bytes,\n chunkHash: createHash('sha256').update(input.chunk).digest('hex'),\n at: new Date().toISOString(),\n });\n}\n\nexport function emitProcessCompleted(\n event: Omit<EventMap['process.completed'], keyof ProcessTelemetryContext>,\n): void {\n emit('process.completed', event);\n}\n\nfunction emit<E extends 'process.started' | 'process.output' | 'process.completed'>(\n name: E,\n event: Omit<EventMap[E], keyof ProcessTelemetryContext>,\n): void {\n const context = storage.getStore();\n if (!context) return;\n const { events, ...identity } = context;\n events.emit(name, { ...identity, ...event } as unknown as EventMap[E]);\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 { realpath } from 'node:fs/promises';\nimport * as path from 'node:path';\nimport {\n evaluateKanbanBoundaryOpaque,\n evaluateKanbanBoundaryPath,\n type KanbanBoundaryEvaluation,\n readBoard,\n resolveKanbanBoundaryLayers,\n} from '@wrongstack/kanban';\nimport type { Context } from '../core/context.js';\nimport type { Tool } from '../types/tool.js';\n\nexport interface ToolKanbanBoundaryEvaluation extends KanbanBoundaryEvaluation {\n boardId?: string | undefined;\n taskId?: string | undefined;\n}\n\nconst PATH_KEYS = new Set([\n 'path',\n 'paths',\n 'file',\n 'files',\n 'directory',\n 'dir',\n 'cwd',\n 'root',\n 'baseDir',\n 'out',\n 'outputPath',\n 'sourcePath',\n 'targetPath',\n 'destinationPath',\n 'fromPath',\n 'toPath',\n 'worktreePath',\n]);\n\nconst TOOL_PATH_KEYS: Readonly<Record<string, readonly string[]>> = {\n // `target` is an identifier in tools such as plan/task/document, but a\n // filesystem target in language_info. Keep ambiguous names tool-specific.\n language_info: ['target'],\n};\n\n/** Resolve the live board/task policy and gate one tool invocation. */\nexport async function evaluateToolKanbanBoundary(\n tool: Tool,\n input: Record<string, unknown>,\n ctx: Context,\n): Promise<ToolKanbanBoundaryEvaluation> {\n const identity = resolveKanbanIdentity(ctx);\n if (!identity.boardId) return { decision: 'allow' };\n const board = await readBoard(identity.policyRoot ?? ctx.projectRoot, identity.boardId);\n if (!board) return { decision: 'allow' };\n const task = identity.taskId\n ? board.tasks.find((candidate) => candidate.id === identity.taskId)\n : undefined;\n\n // Lease ownership check: when the subagent was dispatched with a frozen\n // leaseId, verify the task's current assignment still matches. A mismatch\n // means recover_stale reclaimed and reassigned this task \u2014 the subagent is\n // stale and must not perform filesystem writes (except the kanban tool,\n // which has its own expectedLeaseId fence in the assignment handlers).\n if (identity.leaseId && task?.assignment) {\n const caps = tool.capabilities ?? [];\n const isWrite =\n caps.includes('fs.write') ||\n caps.includes('fs.write.outside-project') ||\n caps.some((c) => c.startsWith('shell.'));\n if (isWrite && tool.name !== 'kanban' && task.assignment.leaseId !== identity.leaseId) {\n return {\n decision: 'block',\n reason:\n `Task ${task.id} lease mismatch: the current worker's lease (${identity.leaseId}) ` +\n `does not match the active lease on the board (${task.assignment.leaseId}). ` +\n `This task was likely recovered and reassigned to another worker. ` +\n `File modifications from a stale worker are blocked. ` +\n `Use kanban mark_assignment with expectedLeaseId to resolve, or use ` +\n `kanban get_board to reassess the current state.`,\n boardId: board.id,\n taskId: task.id,\n };\n }\n }\n\n const layers = resolveKanbanBoundaryLayers(board, task);\n if (layers.length === 0) return { decision: 'allow' };\n\n const caps = tool.capabilities ?? [];\n const access =\n caps.includes('fs.write') || caps.includes('fs.write.outside-project')\n ? 'write'\n : caps.includes('fs.read')\n ? 'read'\n : undefined;\n const shellLike = caps.some((capability) => capability.startsWith('shell.'));\n const candidates = access ? await extractCandidatePaths(tool.name, input, ctx) : [];\n\n let evaluation: KanbanBoundaryEvaluation;\n if (shellLike || (access && candidates.length === 0)) {\n evaluation = evaluateKanbanBoundaryOpaque(layers, tool.name);\n } else if (access) {\n const results = candidates.map((candidate) =>\n evaluateKanbanBoundaryPath(layers, candidate, access),\n );\n evaluation = results.find((result) => result.decision === 'block') ??\n results.find((result) => result.decision === 'confirm') ?? { decision: 'allow' };\n } else {\n evaluation = { decision: 'allow' };\n }\n return {\n ...evaluation,\n boardId: board.id,\n ...(task ? { taskId: task.id } : {}),\n };\n}\n\nfunction resolveKanbanIdentity(ctx: Context): {\n boardId?: string;\n taskId?: string;\n policyRoot?: string;\n leaseId?: string;\n} {\n const metaKanban = ctx.meta['kanban'];\n const record =\n metaKanban && typeof metaKanban === 'object'\n ? (metaKanban as Record<string, unknown>)\n : undefined;\n const boardId =\n ctx.currentKanbanBoardId ??\n (typeof record?.['boardId'] === 'string' ? record['boardId'] : undefined);\n const taskId =\n ctx.currentKanbanTaskId ??\n (typeof record?.['taskId'] === 'string' ? record['taskId'] : undefined);\n const policyRoot =\n typeof record?.['projectRoot'] === 'string' ? record['projectRoot'] : undefined;\n const leaseId =\n typeof record?.['leaseId'] === 'string' ? record['leaseId'] : undefined;\n return {\n ...(boardId ? { boardId } : {}),\n ...(taskId ? { taskId } : {}),\n ...(policyRoot ? { policyRoot } : {}),\n ...(leaseId ? { leaseId } : {}),\n };\n}\n\nasync function extractCandidatePaths(\n toolName: string,\n input: Record<string, unknown>,\n ctx: Context,\n): Promise<string[]> {\n if (toolName === 'patch' && typeof input['patch'] === 'string') {\n const directoryInput = stringValue(input['directory']) ?? ctx.workingDir;\n const directory = path.isAbsolute(directoryInput)\n ? directoryInput\n : path.resolve(ctx.workingDir, directoryInput);\n const strip = Math.max(1, numericValue(input['strip']) ?? 1);\n const targets = extractPatchTargets(input['patch'], strip).map((target) =>\n relativeToProject(path.resolve(directory, target), ctx.projectRoot),\n );\n return Promise.all(targets.map((target) => canonicalizeCandidatePath(target, ctx)));\n }\n\n const values: string[] = [];\n const pathKeys = new Set(PATH_KEYS);\n for (const key of TOOL_PATH_KEYS[toolName] ?? []) pathKeys.add(key);\n collectPathValues(input, values, pathKeys);\n if (toolName === 'scaffold' && typeof input['name'] === 'string') {\n const cwd = stringValue(input['cwd']) ?? ctx.workingDir;\n values.push(path.join(cwd, input['name']));\n }\n const candidates = [\n ...new Set(values.flatMap(splitPathList).map((value) => resolveInputPath(value, ctx))),\n ];\n return Promise.all(candidates.map((candidate) => canonicalizeCandidatePath(candidate, ctx)));\n}\n\nasync function canonicalizeCandidatePath(candidate: string, ctx: Context): Promise<string> {\n if (path.isAbsolute(candidate)) return candidate;\n const absolute = path.resolve(ctx.projectRoot, candidate);\n const canonicalRoot = await realpath(ctx.projectRoot).catch(() => ctx.projectRoot);\n let probe = absolute;\n const missingSegments: string[] = [];\n while (true) {\n try {\n const canonical = path.join(await realpath(probe), ...missingSegments);\n return relativeToProject(canonical, canonicalRoot);\n } catch (cause) {\n const code = (cause as NodeJS.ErrnoException).code;\n if (code !== 'ENOENT' && code !== 'ENOTDIR') return absolute;\n const parent = path.dirname(probe);\n if (parent === probe) return absolute;\n missingSegments.unshift(path.basename(probe));\n probe = parent;\n }\n }\n}\n\nfunction collectPathValues(\n value: unknown,\n output: string[],\n pathKeys: ReadonlySet<string>,\n key?: string,\n): void {\n if (typeof value === 'string') {\n if (key && pathKeys.has(key)) output.push(value);\n return;\n }\n if (Array.isArray(value)) {\n for (const item of value) collectPathValues(item, output, pathKeys, key);\n return;\n }\n if (!value || typeof value !== 'object') return;\n for (const [childKey, child] of Object.entries(value as Record<string, unknown>)) {\n collectPathValues(child, output, pathKeys, childKey);\n }\n}\n\nfunction splitPathList(value: string): string[] {\n return value\n .split(',')\n .map((item) => item.trim())\n .filter(Boolean);\n}\n\nfunction resolveInputPath(value: string, ctx: Context): string {\n const absolute = path.isAbsolute(value) ? value : path.resolve(ctx.workingDir, value);\n return relativeToProject(absolute, ctx.projectRoot);\n}\n\nfunction relativeToProject(absolute: string, projectRoot: string): string {\n const relative = path.relative(projectRoot, absolute).replace(/\\\\/g, '/');\n return relative.startsWith('../') || path.isAbsolute(relative) ? absolute : relative || '.';\n}\n\nfunction extractPatchTargets(patchText: string, strip: number): string[] {\n const targets: string[] = [];\n for (const match of patchText.matchAll(/^\\+\\+\\+\\s+([^\\t\\r\\n]+)/gm)) {\n const raw = match[1]?.trim();\n if (!raw || raw === '/dev/null') continue;\n const parts = raw\n .replace(/\\\\/g, '/')\n .split('/')\n .filter((part) => part && part !== '.');\n if (parts.length > strip) targets.push(parts.slice(strip).join('/'));\n }\n return targets;\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value : undefined;\n}\n\nfunction numericValue(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n", "import type { ToolResultBlock, ToolUseBlock } from '../types/blocks.js';\nimport type { Tool } from '../types/tool.js';\n\n/** Context.meta key installed by ToolExecutor for governed calls made by meta-tools. */\nexport const GOVERNED_TOOL_EXECUTOR_META_KEY = 'toolExecutor.executeGoverned';\n\n/** Result returned to meta-tools after a nested call traverses the normal executor. */\nexport interface GovernedToolExecutionResult {\n success: boolean;\n result?: unknown | undefined;\n error?: string | undefined;\n}\n\n/** Governed execution bridge exposed to meta-tools through Context.meta. */\nexport type GovernedToolExecutor = (\n toolName: string,\n input: Record<string, unknown>,\n) => Promise<GovernedToolExecutionResult>;\n\n/**\n * Input for a single tool execution, scoped to a single iteration's budget.\n */\nexport interface ToolExecution {\n toolUse: ToolUseBlock;\n result: ToolResultBlock;\n /** True if the tool was not found in the registry. */\n unknownTool?: boolean | undefined;\n /** True if the tool execution threw an exception. */\n threw?: boolean | undefined;\n}\n\n/**\n * Output from a single tool execution.\n */\nexport interface ToolExecutionOutput {\n result: ToolResultBlock | ToolConfirmPendingResult;\n tool?: Tool | undefined;\n durationMs: number;\n}\n\n/**\n * Result of running a batch of tools for a single agent iteration.\n */\nexport interface ToolBatchResult {\n outputs: ToolExecutionOutput[];\n remainingBudget: number;\n}\n\nexport type ConfirmAwaiter = (\n tool: Tool,\n input: unknown,\n toolUseId: string,\n suggestedPattern: string,\n) => Promise<'yes' | 'no' | 'always' | 'deny'>;\n\nexport interface ToolExecutorOptions {\n permissionPolicy: import('../types/permission.js').PermissionPolicy;\n secretScrubber: import('../types/secret-scrubber.js').SecretScrubber;\n renderer?: import('../types/renderer.js').Renderer | undefined;\n /**\n * Optional event bus. When provided, the executor emits `tool.started`\n * before invoking each tool's `execute()`. Closes the observability gap\n * between \"model decided to call tool\" and \"tool finished\".\n */\n events?: import('../kernel/events.js').EventBus | undefined;\n /**\n * Optional tracer. When provided, every tool execution opens a\n * `tool.<name>` span with attributes for tool name, permission decision,\n * input size, output size, and outcome. Spans are no-op by default.\n */\n tracer?: import('../types/observability.js').Tracer | undefined;\n /**\n * Optional structured logger for production diagnostics. Tool execution logs\n * include correlation IDs and metadata only \u2014 never raw tool inputs or output.\n */\n logger?: import('../types/logger.js').Logger | undefined;\n /**\n * Async callback invoked when a tool needs user confirmation.\n * When omitted and confirmation is required, the executor returns a\n * failure result immediately (TUI path). When provided (CLI path),\n * the callback handles the interactive prompt and returns a decision.\n */\n confirmAwaiter?: ConfirmAwaiter | undefined;\n iterationTimeoutMs?: number | undefined;\n /** Hard upper bound for a single tool call timeout. Defaults to 5 minutes. */\n maxToolTimeoutMs?: number | undefined;\n perIterationOutputCapBytes?: number | undefined;\n /**\n * Optional lifecycle hook runner. When present, `PreToolUse` hooks run\n * before the permission check (and can block the call or rewrite its input)\n * and `PostToolUse` hooks run after the tool returns (and can append context\n * to the result the model sees).\n */\n hookRunner?: import('../hooks/runner.js').HookRunner | undefined;\n /**\n * Per-tool on-screen result render mode map (`tools.resultRenderMode[name]`).\n * When set, the executor reads this map to decide whether the next\n * `writeToolResult` call should render in `simple` (meta only) or `extend`\n * (full preview) mode. Independent of the LLM-side `descriptionMode`.\n */\n resultRenderModes?: import('./config.js').ToolResultRenderModeConfig | undefined;\n}\n\nexport interface ToolExecutorInit {\n registry: import('../registry/tool-registry.js').ToolRegistry;\n options: ToolExecutorOptions;\n}\n\n/**\n * Result returned by executeBatch when a tool needs confirmation and\n * no confirmAwaiter is available. The TUI catches this and surfaces a\n * confirmation dialog; once resolved the tool is re-executed.\n * The string tag identifies it as a \"pending confirm\" result so callers\n * can distinguish it from an error without inspecting content strings.\n */\nexport interface ToolConfirmPendingResult {\n type: 'tool_confirm_pending';\n toolUseId: string;\n toolName: string;\n input: unknown;\n suggestedPattern: string;\n decisionSource?: import('./permission.js').PermissionDecision['source'] | undefined;\n riskTier?: import('./tool.js').RiskTier | undefined;\n /** Present when approval is required specifically by a Kanban scope. */\n boundaryReason?: string | undefined;\n}\n\nexport type ToolExecutorStrategy = 'parallel' | 'sequential' | 'smart';\n\n/**\n * Minimal contract for tool execution.\n *\n * Defined here (in `types/`) so `core/` does not need to import the\n * concrete `ToolExecutor` class from `execution/`. Callers that create\n * the executor (e.g. CLI wiring) implement this interface.\n *\n * Only the methods actually called by `Agent` are included \u2014 keeping the\n * interface narrow prevents unnecessary coupling.\n */\nexport interface ToolExecutorLike {\n /**\n * Execute a batch of tool uses. The strategy controls whether tools run\n * sequentially, in parallel, or smart (parallel non-mutating + sequential mutating).\n */\n executeBatch(\n toolUses: import('./blocks.js').ToolUseBlock[],\n ctx: import('../core/context.js').Context,\n strategy: ToolExecutorStrategy,\n ): Promise<ToolBatchResult>;\n\n /**\n * Clear the interactive confirm awaiter so the executor returns\n * `ToolConfirmPendingResult` instead of blocking.\n */\n clearConfirmAwaiter(): void;\n\n /**\n * Execute a single tool with timeout and output capping.\n * Used by the agent when it needs to run one tool at a time.\n *\n * Returns the rendered `ToolResultBlock` plus the exact byte count it\n * consumed against the iteration output cap. The caller subtracts\n * `bytes` from the running budget \u2014 no second `Buffer.byteLength`\n * walk, and no `JSON.stringify` fallback for structured results.\n */\n executeTool(\n tool: Tool,\n use: ToolUseBlock,\n ctx: import('../core/context.js').Context,\n budget: number,\n ): Promise<{ block: ToolResultBlock; bytes: number }>;\n}\n", "import { createHash, randomUUID } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { ToolErrorCategory } from '../types/tool.js';\nimport { ToolErrorCategory as ToolErrorCategoryEnum } from '../types/tool.js';\nimport type { ToolExecutorOptions } from '../types/tool-executor.js';\nimport {\n FetchError,\n ToolValidationError,\n WrongStackError,\n} from '../types/errors.js';\nimport { MALFORMED_ARG_MARKERS } from '../types/tool-markers.js';\nimport { expectDefined } from '../utils/expect-defined.js';\nimport { wstackGlobalRoot } from '../utils/wstack-paths.js';\n\nconst TOOL_OUTPUT_ARTIFACT_THRESHOLD_BYTES = 64 * 1024;\nconst TOOL_OUTPUT_ARTIFACT_PREVIEW_BYTES = 12 * 1024;\nconst TOOL_OUTPUT_ARTIFACT_OMISSION = '\\n\u2026[artifact middle omitted]\u2026\\n';\n\nexport function clampTimeoutMs(timeoutMs: number, maxTimeoutMs: number): number {\n const fallback = 300_000;\n const finiteTimeout = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : fallback;\n const finiteMax = Number.isFinite(maxTimeoutMs) && maxTimeoutMs > 0 ? maxTimeoutMs : fallback;\n return Math.max(1, Math.min(finiteTimeout, finiteMax));\n}\n\n/** Normalize an AbortSignal reason (Error | string | undefined) to an Error. */\nexport function abortReasonToError(reason: unknown): Error {\n return reason instanceof Error\n ? reason\n : new Error(typeof reason === 'string' ? reason : 'tool timeout');\n}\n\nexport function hasMalformedArguments(input: unknown): boolean {\n if (!input || typeof input !== 'object' || Array.isArray(input)) return false;\n const obj = input as Record<string, unknown>;\n // The sentinel is the *only* key when wrapping occurred - a real tool call\n // that legitimately uses a key named e.g. `_raw` will carry other keys too.\n const keys = Object.keys(obj);\n return keys.length === 1 && MALFORMED_ARG_MARKERS.includes(keys[0] as never);\n}\n\nexport function extractMalformedRaw(input: unknown): string | undefined {\n if (!hasMalformedArguments(input)) return undefined;\n const obj = input as Record<string, unknown>;\n const value = obj[expectDefined(Object.keys(obj)[0])];\n if (value === undefined || value === null) return undefined;\n if (typeof value === 'string') return value;\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Classify a tool execution error into a structured ToolErrorCategory.\n * Used for observability (span attributes) and retry strategy decisions.\n */\nexport function classifyToolError(err: unknown): {\n category: ToolErrorCategory;\n retryable: boolean;\n detail?: string;\n} {\n // AbortError - user cancellation, never retry\n if (err instanceof Error && err.name === 'AbortError') {\n return { category: ToolErrorCategoryEnum.FATAL, retryable: false, detail: 'aborted' };\n }\n\n // Node.js ErrnoException with system error codes\n if (err instanceof Error && 'code' in err) {\n const code = (err as NodeJS.ErrnoException).code;\n switch (code) {\n case 'ETIMEDOUT':\n case 'ECONNRESET':\n case 'ECONNREFUSED':\n case 'ENETUNREACH':\n case 'EHOSTUNREACH':\n return { category: ToolErrorCategoryEnum.TRANSIENT, retryable: true, detail: code };\n case 'ENOENT':\n case 'ENOTDIR':\n return { category: ToolErrorCategoryEnum.NOT_FOUND, retryable: false, detail: code };\n case 'EACCES':\n case 'EPERM':\n return { category: ToolErrorCategoryEnum.PERMISSION, retryable: false, detail: code };\n case 'EBUSY':\n case 'EMFILE':\n case 'ENFILE':\n return { category: ToolErrorCategoryEnum.TRANSIENT, retryable: true, detail: code };\n }\n }\n\n if (err instanceof FetchError) {\n return httpStatusToCategory(err.status);\n }\n if (err instanceof Error && 'response' in err) {\n const response = (err as { response: { status?: number } }).response;\n const status = response?.status;\n if (status !== undefined) {\n return httpStatusToCategory(status);\n }\n }\n\n if (err instanceof ToolValidationError) {\n return { category: ToolErrorCategoryEnum.VALIDATION, retryable: false, detail: 'validation' };\n }\n if (err instanceof Error && err.message.includes('validation')) {\n return { category: ToolErrorCategoryEnum.VALIDATION, retryable: false, detail: 'validation' };\n }\n\n if (err instanceof WrongStackError) {\n const wse = err as WrongStackError;\n const category =\n wse.severity === 'warning' ? ToolErrorCategoryEnum.TRANSIENT : ToolErrorCategoryEnum.FATAL;\n return {\n category,\n retryable: wse.recoverable,\n detail: `${wse.code} [${wse.subsystem}]`,\n };\n }\n\n return {\n category: ToolErrorCategoryEnum.FATAL,\n retryable: false,\n detail: err instanceof Error ? err.message.slice(0, 100) : String(err).slice(0, 100),\n };\n}\n\nfunction httpStatusToCategory(status: number): {\n category: ToolErrorCategory;\n retryable: boolean;\n detail: string;\n} {\n if (status === 429 || status === 503 || status === 502 || status === 504) {\n return { category: ToolErrorCategoryEnum.TRANSIENT, retryable: true, detail: `HTTP ${status}` };\n }\n if (status === 404 || status === 410) {\n return {\n category: ToolErrorCategoryEnum.NOT_FOUND,\n retryable: false,\n detail: `HTTP ${status}`,\n };\n }\n if (status === 401 || status === 403) {\n return {\n category: ToolErrorCategoryEnum.PERMISSION,\n retryable: false,\n detail: `HTTP ${status}`,\n };\n }\n if (status === 400) {\n return {\n category: ToolErrorCategoryEnum.VALIDATION,\n retryable: false,\n detail: `HTTP ${status}`,\n };\n }\n return { category: ToolErrorCategoryEnum.FATAL, retryable: false, detail: `HTTP ${status}` };\n}\n\nexport async function maybePersistLargeToolOutput(\n toolName: string,\n content: string,\n budget: number,\n): Promise<string> {\n const bytes = Buffer.byteLength(content, 'utf8');\n if (bytes <= Math.min(TOOL_OUTPUT_ARTIFACT_THRESHOLD_BYTES, Math.max(0, budget))) {\n return content;\n }\n\n try {\n const dir = path.join(wstackGlobalRoot(), 'tool-output');\n await fs.mkdir(dir, { recursive: true });\n const safeTool = toolName.replace(/[^a-zA-Z0-9._-]+/g, '_').slice(0, 40) || 'tool';\n const stamp = new Date().toISOString().replace(/[:.]/g, '-');\n const filePath = path.join(dir, `${stamp}-${safeTool}-${randomUUID()}.log`);\n await fs.writeFile(filePath, content, 'utf8');\n const marker =\n `[full tool output: ${bytes} bytes at ${filePath}; ` +\n 'read/grep that file selectively instead of re-running or requesting more output]';\n const fixedBytes = Buffer.byteLength(marker + TOOL_OUTPUT_ARTIFACT_OMISSION, 'utf8');\n const previewBytes = Math.min(\n TOOL_OUTPUT_ARTIFACT_PREVIEW_BYTES,\n Math.max(0, budget - fixedBytes),\n );\n if (previewBytes < 256) return marker;\n\n const headBudget = Math.ceil(previewBytes / 2);\n const tailBudget = previewBytes - headBudget;\n const head = sliceUtf8Prefix(content, headBudget);\n const tail = sliceUtf8Suffix(content, tailBudget);\n return `${marker}\\n${head}${TOOL_OUTPUT_ARTIFACT_OMISSION}${tail}`;\n } catch {\n return content;\n }\n}\n\nexport function hashPermissionInput(\n input: unknown,\n scrubber: ToolExecutorOptions['secretScrubber'],\n): string {\n let serialized: string;\n try {\n serialized = JSON.stringify(input) ?? '';\n } catch {\n serialized = String(input);\n }\n return createHash('sha256').update(scrubber.scrub(serialized), 'utf8').digest('hex');\n}\n\nfunction sliceUtf8Prefix(text: string, maxBytes: number): string {\n if (maxBytes <= 0) return '';\n if (Buffer.byteLength(text, 'utf8') <= maxBytes) return text;\n let low = 0;\n let high = text.length;\n while (low < high) {\n const mid = Math.ceil((low + high) / 2);\n if (Buffer.byteLength(text.slice(0, mid), 'utf8') <= maxBytes) low = mid;\n else high = mid - 1;\n }\n let end = low;\n const last = text.charCodeAt(end - 1);\n if (last >= 0xd800 && last <= 0xdbff) end--;\n return text.slice(0, end);\n}\n\nfunction sliceUtf8Suffix(text: string, maxBytes: number): string {\n if (maxBytes <= 0) return '';\n if (Buffer.byteLength(text, 'utf8') <= maxBytes) return text;\n let low = 0;\n let high = text.length;\n while (low < high) {\n const chars = Math.ceil((low + high) / 2);\n if (Buffer.byteLength(text.slice(text.length - chars), 'utf8') <= maxBytes) low = chars;\n else high = chars - 1;\n }\n let start = text.length - low;\n const first = text.charCodeAt(start);\n if (first >= 0xdc00 && first <= 0xdfff) start++;\n return text.slice(start);\n}\n", "/**\n * Sentinel keys provider adapters use to wrap tool-call arguments that could\n * not be parsed into a proper JSON object. Single source of truth \u2014 the core\n * tool executor (which DETECTS these markers to surface a friendly error)\n * defines them here, and the providers package (which PRODUCES them when\n * wrapping) imports from `@wrongstack/core`.\n *\n * P3 #14 (before-release.md): the list was duplicated in tool-executor.ts with\n * a \"Keep this list in sync\" comment \u2014 a manual rule that will eventually be\n * forgotten. Centralizing it removes the sync burden.\n *\n * Layering note: this lives in core (not providers) because the dependency\n * direction is providers \u2192 core, not the reverse. Putting it in providers\n * would force core into a forbidden upward dependency.\n *\n * Current markers:\n * - `__raw` \u2014 produced by `parseToolInput` (Anthropic / shared)\n * - `__raw_arguments` \u2014 produced by `contentFromOpenAI` (OpenAI / compatible)\n * - `_raw` \u2014 produced by the streaming response builder's\n * `safeJsonOrRaw` (legacy fallback)\n */\nexport const MALFORMED_ARG_MARKERS = ['__raw', '__raw_arguments', '_raw'] as const;\n", "import type { ToolResultBlock, ToolUseBlock } from '../types/blocks.js';\n\nexport function unknownToolResult(use: ToolUseBlock, listFns: () => string[]): ToolResultBlock {\n return {\n type: 'tool_result',\n tool_use_id: use.id,\n content: `Tool \"${use.name}\" is not registered. Available tools: ${listFns().join(', ')}`,\n is_error: true,\n };\n}\n\nexport function malformedInputResult(use: ToolUseBlock, raw?: string): ToolResultBlock {\n let content =\n `Tool \"${use.name}\" received arguments that were not a valid JSON object, so they ` +\n `could not be parsed. Re-issue the call with the arguments encoded as a single ` +\n `well-formed JSON object matching the tool's input schema.`;\n if (raw) {\n const max = 800;\n const excerpt =\n raw.length > max ? `${raw.slice(0, max)}\u2026 (truncated, ${raw.length} chars total)` : raw;\n content +=\n ` Common cause: a string field (e.g. code in old_string/new_string) ` +\n `contains literal newlines, quotes, or backslashes that must be JSON-escaped, ` +\n `or the payload was cut off mid-stream. The raw arguments received were:\\n${excerpt}`;\n }\n return {\n type: 'tool_result',\n tool_use_id: use.id,\n content,\n is_error: true,\n };\n}\n\nexport function deniedResult(use: ToolUseBlock, reason?: string): ToolResultBlock {\n return {\n type: 'tool_result',\n tool_use_id: use.id,\n content: `Tool \"${use.name}\" denied: ${reason ?? 'policy'}`,\n is_error: true,\n };\n}\n\nexport function blockedByHookResult(use: ToolUseBlock, reason?: string): ToolResultBlock {\n return {\n type: 'tool_result',\n tool_use_id: use.id,\n content: `Tool \"${use.name}\" was blocked by a PreToolUse hook: ${reason ?? 'no reason given'}`,\n is_error: true,\n };\n}\n", "import type { Context } from '../core/context.js';\nimport type { ToolUseBlock } from '../types/blocks.js';\nimport { isWrongStackError } from '../types/errors.js';\nimport type { ToolExecutorOptions } from '../types/tool-executor.js';\nimport { classifyToolError } from './tool-executor-support.js';\n\nfunction toolLogBase(\n ctx: Context,\n use: ToolUseBlock,\n toolName: string,\n durationMs: number,\n): Record<string, unknown> {\n return {\n event: 'tool.execution',\n traceId: ctx.traceId,\n sessionId: ctx.session.id,\n agentId: ctx.agentId ?? '<unknown>',\n toolName,\n toolUseId: use.id,\n durationMs,\n };\n}\n\nexport function logToolSuccess(\n opts: ToolExecutorOptions,\n ctx: Context,\n use: ToolUseBlock,\n toolName: string,\n durationMs: number,\n outputChars: number,\n): void {\n opts.events?.emit('tool.completed', {\n name: toolName,\n id: use.id,\n sessionId: ctx.session.id,\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}),\n agentId: ctx.agentId ?? '<unknown>',\n durationMs,\n outputChars,\n });\n opts.logger?.info('tool execution completed', {\n ...toolLogBase(ctx, use, toolName, durationMs),\n outcome: 'success',\n isError: false,\n outputChars,\n });\n}\n\nexport function logToolFailure(\n opts: ToolExecutorOptions,\n ctx: Context,\n use: ToolUseBlock,\n toolName: string,\n durationMs: number,\n err: unknown,\n): void {\n const { category, retryable, detail } = classifyToolError(err);\n const structured = isWrongStackError(err);\n const structuredError = structured\n ? {\n errorCode: err.code,\n errorSubsystem: err.subsystem,\n errorSeverity: err.severity,\n }\n : {};\n opts.events?.emit('tool.failed', {\n name: toolName,\n id: use.id,\n sessionId: ctx.session.id,\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}),\n agentId: ctx.agentId ?? '<unknown>',\n durationMs,\n category,\n retryable,\n ...(detail ? { detail } : {}),\n ...structuredError,\n taskId: ctx.currentKanbanTaskId,\n boardId: ctx.currentKanbanBoardId,\n ...(typeof ctx.provider === 'object'\n ? { provider: (ctx.provider as { id: string }).id }\n : {}),\n ...(ctx.model ? { model: ctx.model } : {}),\n });\n opts.logger?.warn('tool execution failed', {\n ...toolLogBase(ctx, use, toolName, durationMs),\n outcome: 'failure',\n isError: true,\n errorCategory: category,\n retryable,\n errorDetail: detail,\n ...structuredError,\n });\n}\n", "import { type Context, resolveEventSessionId } from '../core/context.js';\nimport { ToolError } from '../types/errors.js';\nimport type { Tool, ToolProgressEvent } from '../types/tool.js';\nimport type { ToolExecutorOptions } from '../types/tool-executor.js';\n\ninterface StreamedToolExecutionOptions {\n tool: Tool;\n input: unknown;\n ctx: Context;\n signal: AbortSignal;\n toolUseId: string | undefined;\n events: ToolExecutorOptions['events'];\n progressEmitIntervalMs: number;\n progressTailChars: number;\n progressHeadChars: number;\n}\n\nexport async function executeStreamedTool({\n tool,\n input,\n ctx,\n signal,\n toolUseId,\n events,\n progressEmitIntervalMs,\n progressTailChars,\n progressHeadChars,\n}: StreamedToolExecutionOptions): Promise<unknown> {\n let finalOutput: unknown;\n let sawFinal = false;\n if (!tool.executeStream) {\n throw new ToolError({\n message: `Tool \"${tool.name}\" does not support streaming execution`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: tool.name,\n context: { reason: 'streaming_not_supported' },\n });\n }\n const stream = tool.executeStream(input, ctx, { signal });\n const iter = stream[Symbol.asyncIterator]();\n let progressTail = '';\n let progressHead = '';\n let headComplete = false;\n let lastProgressEmitAt = 0;\n const emitProgress = (ev: ToolProgressEvent) => {\n events?.emit('tool.progress', {\n sessionId: resolveEventSessionId(ctx),\n ...(ctx.traceId ? { traceId: ctx.traceId } : {}),\n agentId: ctx.agentId,\n agentName: ctx.agentName,\n name: tool.name,\n id: toolUseId ?? '<unknown>',\n event: ev,\n });\n };\n const flushProgressTail = (force: boolean) => {\n if (progressTail.length === 0) return;\n const now = Date.now();\n if (!force && now - lastProgressEmitAt < progressEmitIntervalMs) return;\n lastProgressEmitAt = now;\n const text =\n force && headComplete && progressTail.length > 0\n ? `${progressHead}\\n[...output truncated...]\\n${progressTail}`\n : progressTail;\n progressTail = '';\n emitProgress({ type: 'partial_output', text });\n };\n try {\n while (true) {\n const { done, value: ev } = await iter.next();\n if (done) break;\n if (ev.type === 'final') {\n finalOutput = ev.output;\n sawFinal = true;\n break;\n }\n if (ev.type === 'partial_output' && typeof ev.text === 'string') {\n if (ev.data?.['livePreview'] === true) {\n flushProgressTail(true);\n emitProgress(ev);\n continue;\n }\n if (!headComplete) {\n const remaining = progressHeadChars - progressHead.length;\n if (ev.text.length <= remaining) {\n progressHead += ev.text;\n } else {\n progressHead += ev.text.slice(0, remaining);\n headComplete = true;\n }\n }\n progressTail += ev.text;\n if (progressTail.length > progressTailChars) {\n progressTail = progressTail.slice(-progressTailChars);\n }\n flushProgressTail(false);\n continue;\n }\n flushProgressTail(true);\n emitProgress(ev);\n }\n flushProgressTail(true);\n } finally {\n await iter.return?.(undefined);\n }\n if (!sawFinal) {\n throw new ToolError({\n message: `tool \"${tool.name}\" executeStream completed without a 'final' event`,\n code: 'TOOL_EXECUTION_FAILED',\n toolName: tool.name,\n context: { reason: 'missing_final_event' },\n });\n }\n return finalOutput;\n}\n", "import type { FallbackChain } from '../core/fallback-profile-manager.js';\nimport { evaluateModelCalendar } from '../core/model-availability-calendar.js';\nimport { isTextBlock } from '../types/blocks.js';\nimport type { Config } from '../types/config.js';\nimport type { Message } from '../types/messages.js';\nimport type {\n OneShotLLMInput,\n OneShotLLMResult,\n OneShotOrchestratorOptions,\n} from '../types/one-shot-llm.js';\nimport {\n isFallbackWorthy,\n type Provider,\n ProviderError,\n type Request,\n type Response,\n} from '../types/provider.js';\nimport { estimateRequestTokens } from '../utils/token-estimate.js';\n\n/**\n * Default timeout for one-shot LLM calls when the caller doesn't specify one.\n */\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/**\n * Default max output tokens when the caller doesn't specify.\n */\nconst DEFAULT_MAX_TOKENS = 1024;\n\ntype CallAttempt =\n | { response: Response; error?: never; fallbackEligible: false }\n | { response?: never; error: unknown; fallbackEligible: boolean };\n\n/**\n * OneShotOrchestrator \u2014 a stateless, reusable utility for making single\n * LLM calls with provider resolution, fallback chains, and structured results.\n *\n * Usage:\n * ```ts\n * const oneShot = new OneShotOrchestrator({ buildProvider, getConfig });\n * const result = await oneShot.call({\n * system: 'You are a helpful assistant.',\n * userPrompt: 'Summarize this conversation.',\n * model: 'deepseek-chat',\n * fallbackModels: ['anthropic/claude-haiku'],\n * });\n * console.log(result.text);\n * ```\n *\n * Every method is stateless \u2014 a single instance can be shared across\n * the entire process lifetime.\n */\nexport class OneShotOrchestrator {\n private readonly opts: OneShotOrchestratorOptions;\n\n constructor(opts: OneShotOrchestratorOptions) {\n this.opts = opts;\n }\n\n /**\n * Make a one-shot LLM call. Resolves provider+model, applies fallback\n * chain on transient errors, and returns a structured result.\n *\n * Never throws \u2014 all errors are captured in `OneShotLLMResult.error`.\n */\n async call(input: OneShotLLMInput): Promise<OneShotLLMResult> {\n const startedAt = performance.now();\n const config = this.opts.getConfig();\n\n // \u2500\u2500 1. Resolve target provider + model \u2500\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 const target = this.resolveTarget(input, config);\n if (!target) {\n return {\n text: '',\n model: input.model ?? config.model ?? 'unknown',\n provider: input.providerId ?? config.provider ?? 'unknown',\n tokens: { input: 0, output: 0, total: 0 },\n durationMs: Math.round(performance.now() - startedAt),\n fromFallback: false,\n error: 'No provider or model could be resolved. Check your config.',\n };\n }\n\n let provider: Provider;\n try {\n provider = await this.opts.buildProvider(target.providerId, target.model);\n } catch (err) {\n return {\n text: '',\n model: target.model,\n provider: target.providerId,\n tokens: { input: 0, output: 0, total: 0 },\n durationMs: Math.round(performance.now() - startedAt),\n fromFallback: false,\n error: `Cannot build provider \"${target.providerId}\": ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n\n // \u2500\u2500 2. Build the request \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 const request = this.buildRequest(input, target.model);\n const signal = this.resolveSignal(input);\n\n // \u2500\u2500 3. Build fallback chain \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 const chain = this.resolveFallbackChain(input, config, target);\n\n // \u2500\u2500 4. Attempt the call with fallback rotation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const tracker = this.opts.statusTracker;\n let servingProviderId = provider.id;\n let servingModel = target.model;\n let fromFallback = false;\n let lastError: unknown;\n let fallbackEligible = false;\n\n // Check if the primary target is blocked\n if (\n (tracker && !tracker.isAvailable(target.providerId, target.model)) ||\n !evaluateModelCalendar(config.modelAvailabilitySchedule, target.providerId, target.model)\n .allowed\n ) {\n this.opts.logger?.debug(\n `one-shot: primary \"${target.providerId}/${target.model}\" is blocked \u2014 trying fallback`,\n );\n // Fall through to the fallback chain\n } else {\n const primaryAttempt = await this.tryCall(\n provider,\n request,\n signal,\n target.providerId,\n target.model,\n );\n const result = primaryAttempt.response;\n lastError = primaryAttempt.error;\n fallbackEligible = primaryAttempt.fallbackEligible;\n\n if (result) {\n tracker?.recordSuccess(target.providerId, target.model);\n servingProviderId = provider.id;\n servingModel = target.model;\n return this.buildResult(result, servingProviderId, servingModel, false, startedAt);\n }\n\n if (!fallbackEligible || chain.length === 0) {\n return this.buildErrorResult(lastError, target.providerId, target.model, false, startedAt);\n }\n }\n\n // \u2500\u2500 4b. Fallback chain \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 // Estimate request tokens lazily \u2014 only reached when the primary call\n // failed or was blocked. Used to pre-filter fallback entries whose context\n // window is provably too small, avoiding a guaranteed context_overflow.\n const estimatedTokens = estimateRequestTokens(request.messages, request.system, []).total;\n\n // Filter blocked entries from the chain\n const usableChain = tracker\n ? chain.filter((e) => tracker.isAvailable(e.providerId, e.model))\n : chain;\n\n for (const entry of usableChain) {\n if (\n !evaluateModelCalendar(config.modelAvailabilitySchedule, entry.providerId, entry.model)\n .allowed\n )\n continue;\n // Re-check availability right before attempting \u2014 a concurrent failure\n // may have pushed this entry into the waiting room since the chain was\n // filtered. Skipping here avoids a wasted provider call.\n if (tracker && !tracker.isAvailable(entry.providerId, entry.model)) {\n continue;\n }\n if (entry.providerId === provider.id && entry.model === target.model) continue;\n\n let fbProvider: Provider;\n try {\n fbProvider = await this.opts.buildProvider(entry.providerId, entry.model);\n } catch (err) {\n lastError = err;\n continue;\n }\n\n // Pre-filter: skip entries whose context window is provably too small\n // for the current request. A guaranteed context_overflow is not\n // fallback-worthy and would surface as an error, wasting the call.\n const fbMaxContext = fbProvider.capabilities.maxContext;\n if (\n typeof fbMaxContext === 'number' &&\n Number.isFinite(fbMaxContext) &&\n fbMaxContext > 0 &&\n estimatedTokens > fbMaxContext\n ) {\n this.opts.logger?.debug(\n `one-shot: skipping \"${entry.providerId}/${entry.model}\" \u2014 context window ` +\n `(${fbMaxContext}) is smaller than request tokens (${estimatedTokens})`,\n );\n continue;\n }\n\n servingProviderId = fbProvider.id;\n servingModel = entry.model;\n const attempt = await this.tryCall(\n fbProvider,\n this.buildRequest(input, entry.model),\n signal,\n entry.providerId,\n entry.model,\n );\n if (attempt.response) {\n tracker?.recordSuccess(entry.providerId, entry.model);\n fromFallback = true;\n return this.buildResult(attempt.response, servingProviderId, servingModel, true, startedAt);\n }\n\n lastError = attempt.error;\n // Do NOT break on a non-fallback-eligible error from a chain entry.\n // Only the primary's eligibility (checked above at the gate) decides\n // whether we enter the chain at all. A stale entry (deleted model \u2192\n // 404 \u2192 invalid_request) must not abort every healthy entry after it.\n // Mirrors the agent-loop fix in fallback-model.ts (lines 464\u2013481).\n }\n\n // Total failure \u2014 all providers exhausted or non-retryable error.\n return this.buildErrorResult(\n lastError,\n servingProviderId,\n servingModel,\n fromFallback,\n startedAt,\n );\n }\n\n // \u2500\u2500 Private 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\n\n /**\n * Resolve the target provider + model from input + config.\n * Priority: role-based routing > explicit providerId+model > defaults.\n */\n private resolveTarget(\n input: OneShotLLMInput,\n config: import('../types/config.js').Config,\n ): { providerId: string; model: string } | undefined {\n // Role-based routing via ModelRouter (highest priority)\n if (input.role && this.opts.modelRouter) {\n const pick = this.opts.modelRouter.pickForTask(input.role, '');\n if (pick) {\n return { providerId: pick.provider, model: pick.model };\n }\n }\n\n // Explicit providerId + model\n if (input.providerId && input.model) {\n return { providerId: input.providerId, model: input.model };\n }\n\n // Model only \u2014 use default provider\n if (input.model) {\n return { providerId: config.provider, model: input.model };\n }\n\n // Provider only \u2014 use default model\n if (input.providerId) {\n return { providerId: input.providerId, model: config.model };\n }\n\n // Neither \u2014 use session defaults\n if (config.provider && config.model) {\n return { providerId: config.provider, model: config.model };\n }\n\n return undefined;\n }\n\n /**\n * Build a Provider Request from the input.\n */\n private buildRequest(input: OneShotLLMInput, model: string): Request {\n const messages: Message[] = [...(input.messages ?? [])];\n if (input.userPrompt) {\n messages.push({ role: 'user', content: input.userPrompt });\n }\n\n const system = asTextBlocks(input.system);\n\n return {\n model,\n ...(system.length > 0 ? { system } : {}),\n messages,\n maxTokens: input.maxTokens ?? DEFAULT_MAX_TOKENS,\n ...(input.temperature !== undefined ? { temperature: input.temperature } : {}),\n ...(input.responseFormat ? { responseFormat: input.responseFormat } : {}),\n };\n }\n\n /**\n * Resolve the abort signal. Provider calls always receive the per-call\n * timeout, composed with external cancellation when the caller supplies it.\n */\n private resolveSignal(input: OneShotLLMInput): AbortSignal {\n const timeoutSignal = AbortSignal.timeout(input.timeoutMs ?? DEFAULT_TIMEOUT_MS);\n return input.signal ? AbortSignal.any([input.signal, timeoutSignal]) : timeoutSignal;\n }\n\n /**\n * Build the fallback model chain from input + config + current target.\n * The injected {@link OneShotOrchestratorOptions.fallbackProfileManager}\n * is the only allowed manager \u2014 OneShot never owns a private snapshot\n * so a live `ConfigStore` change reaches every call without rebuilding\n * the manager.\n */\n private resolveFallbackChain(\n input: OneShotLLMInput,\n config: Config,\n target: { providerId: string; model: string },\n ): FallbackChain {\n const mgr = this.opts.fallbackProfileManager;\n\n // Explicit chain wins\n if (input.fallbackModels && input.fallbackModels.length > 0) {\n return mgr.resolveRefs(input.fallbackModels, target);\n }\n\n // Config-level fallbackModels \u2014 independent of fallbackAuto\n if (config.fallbackModels && config.fallbackModels.length > 0) {\n return mgr.resolveRefs(config.fallbackModels, target);\n }\n\n // Smart default from config (only when auto-derivation is enabled)\n if (config.fallbackAuto !== false) {\n return mgr.resolveEffective({\n fallbackAuto: true,\n exclude: target,\n });\n }\n\n return Object.freeze([]) as FallbackChain;\n }\n\n /** Attempt a provider call while preserving the actual failure for callers. */\n private async tryCall(\n provider: Provider,\n request: Request,\n signal: AbortSignal,\n providerId?: string,\n model?: string,\n ): Promise<CallAttempt> {\n try {\n return {\n response: await provider.complete(request, { signal }),\n fallbackEligible: false,\n };\n } catch (err) {\n // Record the failure in the tracker\n if (err instanceof ProviderError && providerId && model) {\n this.opts.statusTracker?.recordFailure(\n providerId,\n model,\n err.kind,\n err.status,\n err.describe(),\n { retryAfterMs: err.body?.retryAfterMs },\n );\n }\n return {\n error: err,\n fallbackEligible:\n !signal.aborted && (!(err instanceof ProviderError) || isFallbackWorthy(err.kind)),\n };\n }\n }\n\n /** Build a success result from a provider Response. */\n private buildResult(\n response: Response,\n servingProviderId: string,\n servingModel: string,\n fromFallback: boolean,\n startedAt: number,\n ): OneShotLLMResult {\n const textBlocks = response.content.filter(isTextBlock);\n const text = textBlocks\n .map((b) => b.text)\n .join('\\n')\n .trim();\n return {\n text: text || '(empty response)',\n model: response.model ?? servingModel,\n provider: servingProviderId,\n tokens: {\n input: response.usage?.input ?? 0,\n output: response.usage?.output ?? 0,\n total: (response.usage?.input ?? 0) + (response.usage?.output ?? 0),\n },\n durationMs: Math.round(performance.now() - startedAt),\n fromFallback,\n stopReason: response.stopReason,\n };\n }\n\n /** Build a total-failure error result. */\n private buildErrorResult(\n error: unknown,\n servingProviderId: string,\n servingModel: string,\n fromFallback: boolean,\n startedAt: number,\n ): OneShotLLMResult {\n return {\n text: '',\n model: servingModel,\n provider: servingProviderId,\n tokens: { input: 0, output: 0, total: 0 },\n durationMs: Math.round(performance.now() - startedAt),\n fromFallback,\n error: error instanceof Error ? error.message : String(error ?? 'Unknown error'),\n };\n }\n}\n\n/**\n * Normalize system prompt to TextBlock[].\n */\nfunction asTextBlocks(\n system: string | import('../types/blocks.js').TextBlock[] | undefined,\n): import('../types/blocks.js').TextBlock[] {\n if (!system) return [];\n if (Array.isArray(system)) return system;\n return [{ type: 'text', text: system }];\n}\n", "import type { ContentBlock } from '../types/blocks.js';\nimport { isTextBlock } from '../types/blocks.js';\nimport type { Message } from '../types/messages.js';\nimport type { MemoryEntry, MemoryScope, MemoryStore } from '../types/memory.js';\nimport type {\n Provider,\n ReasoningConfig,\n ReasoningEffort,\n ReasoningRequest,\n Request,\n} from '../types/provider.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport type { OneShotOrchestrator } from './one-shot-llm.js';\nimport { readBundledInstructionText } from '../utils/instruction-file.js';\n\n/**\n * Prompt refinement (\"did you mean this?\").\n *\n * Runs a one-shot LLM call in a SEPARATE context (its own system prompt, no\n * conversation history, no tools) that rewrites a raw user message into a\n * clearer, more complete instruction BEFORE the main agent sees it. The goal\n * is to make the main context start from a well-understood request rather than\n * guessing intent from terse input like \"fix the bug\".\n *\n * This mirrors `IntelligentCompactor.callSummarizer` \u2014 a plain\n * `provider.complete()` with a dedicated system prompt \u2014 and is deliberately\n * free of React / TUI dependencies so it can be unit-tested in isolation.\n */\n\nexport const ENHANCER_SYSTEM_PROMPT = readBundledInstructionText('llm/prompt-enhancer.md');\n\n/** Words/phrases that are control answers, not refinable requests. */\nconst AFFIRMATION_RE =\n /^(y|n|yes|no|yep|nope|ok|okay|sure|go|go ahead|continue|proceed|stop|cancel|done|next|skip|retry|again|please do|do it)\\b[.! ]*$/i;\n\n/**\n * Heuristic gate: should this raw input be sent through the refiner at all?\n * Pure + exported for unit testing. Returns false for inputs where refinement\n * is pointless or unwanted (slash commands, one-word affirmations, trivially\n * short text, bare numbers).\n */\nexport function shouldEnhance(text: string): boolean {\n const t = text.trim();\n if (!t) return false;\n if (t.startsWith('/')) return false; // slash command\n if (t.length < 12) return false; // too short to be worth refining\n if (AFFIRMATION_RE.test(t)) return false; // \"yes\" / \"continue\" / ...\n if (/^[\\d\\s.,]+$/.test(t)) return false; // bare numbers (menu picks, etc.)\n const words = t.split(/\\s+/).filter(Boolean);\n if (words.length < 3) return false; // 1\u20132 words rarely benefit\n return true;\n}\n\n/**\n * Preference order when picking an effort level: the cheapest level that still\n * does SOME reasoning first ('low', then 'minimal'), then up the ladder, with\n * fully-off ('none') last so it's only chosen when it's the sole advertised\n * option. This keeps the refiner cheap without dropping reasoning entirely when\n * a little still helps. 'low' leads because it's the most widely accepted low\n * level across adapters (e.g. OpenAI's reasoning_effort set).\n */\nconst EFFORT_PREFERENCE: ReasoningEffort[] = [\n 'low',\n 'minimal',\n 'medium',\n 'high',\n 'xhigh',\n 'max',\n 'none',\n];\n\n/**\n * Build a reasoning directive for the refiner that minimizes wasted thinking,\n * gated to what the model actually accepts. Refinement is a shallow rewrite\n * task \u2014 extended thinking adds latency and (hidden) token cost for little\n * gain \u2014 so we ask the model to spend as little reasoning as it safely can.\n *\n * The gating mirrors `resolveReasoningForRequest` so we never send a field the\n * model would reject:\n * - effort-capable model \u2192 its lowest advertised effort level;\n * - else disable-capable model \u2192 disable thinking (`enabled: false`);\n * - else (always-on / unknown) \u2192 `undefined` (leave the provider default).\n *\n * Returns `undefined` whenever nothing can be safely reduced. Callers forward\n * that verbatim to `enhanceUserPrompt`, which then sends no reasoning field \u2014\n * identical to the behavior before this hint existed. Pure + exported for unit\n * testing.\n */\nexport function gatedEnhancerReasoning(\n rc: ReasoningConfig | undefined,\n): ReasoningRequest | undefined {\n // Capabilities unknown \u2192 don't risk an unsupported field (matches the\n // conservative \"capabilities unknown\" branch in resolveReasoningForRequest).\n if (!rc) return undefined;\n if (rc.effortSupported && rc.effortLevels.length > 0) {\n const lowest = EFFORT_PREFERENCE.find((e) => rc.effortLevels.includes(e)) ?? rc.effortLevels[0];\n if (lowest) return { effort: lowest };\n }\n if (rc.disableSupported) return { enabled: false };\n return undefined;\n}\n\n/**\n * Normalize for \"did the refiner actually change anything?\" comparison \u2014\n * collapse whitespace and lowercase so trivial reformatting doesn't trigger\n * the confirmation panel.\n */\nexport function normalizedEqual(a: string, b: string): boolean {\n const norm = (s: string) => s.trim().replace(/\\s+/g, ' ').toLowerCase();\n return norm(a) === norm(b);\n}\n\n// Deliberately narrow prompt-domain lexicons, not a general language detector.\n// Unknown text is rejected so the model gets one corrective pass rather than\n// allowing an unverified English label through.\nconst ENGLISH_PROMPT_WORDS = new Set([\n 'a',\n 'add',\n 'analyze',\n 'and',\n 'api',\n 'as',\n 'build',\n 'change',\n 'check',\n 'code',\n 'configure',\n 'create',\n 'delete',\n 'document',\n 'ensure',\n 'error',\n 'explain',\n 'failure',\n 'feature',\n 'file',\n 'fix',\n 'for',\n 'from',\n 'function',\n 'implement',\n 'improve',\n 'in',\n 'into',\n 'is',\n 'issue',\n 'it',\n 'keep',\n 'make',\n 'model',\n 'of',\n 'only',\n 'output',\n 'parser',\n 'preserve',\n 'prompt',\n 'race',\n 'refactor',\n 'remove',\n 'request',\n 'resolve',\n 'response',\n 'return',\n 'run',\n 'should',\n 'test',\n 'that',\n 'the',\n 'this',\n 'to',\n 'translate',\n 'update',\n 'use',\n 'validate',\n 'version',\n 'when',\n 'with',\n 'write',\n 'condition',\n]);\n\nconst NON_ENGLISH_PROMPT_WORDS = new Set([\n // Turkish\n 'ama',\n 'bir',\n 'bu',\n 'de',\n 'd\u00FCzelt',\n 'et',\n 'hata',\n 'hatas\u0131n\u0131',\n 'hatay\u0131',\n 'i\u00E7in',\n 'ile',\n 'olarak',\n 'sadece',\n 've',\n 'yap',\n '\u015Fu',\n // Spanish / Portuguese\n 'con',\n 'corrige',\n 'debe',\n 'el',\n 'en',\n 'erro',\n 'la',\n 'para',\n 'que',\n 'sin',\n 'una',\n // French\n 'avec',\n 'dans',\n 'des',\n 'doit',\n 'erreur',\n 'et',\n 'le',\n 'les',\n 'pour',\n 'sans',\n 'une',\n // German\n 'das',\n 'den',\n 'der',\n 'die',\n 'ein',\n 'fehler',\n 'f\u00FCr',\n 'mit',\n 'ohne',\n 'und',\n]);\n\nfunction languageWords(text: string): string[] {\n // Normalize Turkish capital dotted \u0130 before lowercasing; generic/English\n // locale lowercasing otherwise leaves a combining dot that splits words.\n return (\n text\n .replaceAll('\u0130', 'i')\n .toLowerCase()\n .match(/\\p{L}+/gu) ?? []\n );\n}\n\nfunction hasNonLatinScript(text: string): boolean {\n return /[\\p{Script=Arabic}\\p{Script=Cyrillic}\\p{Script=Han}\\p{Script=Hangul}\\p{Script=Hiragana}\\p{Script=Katakana}]/u.test(\n text,\n );\n}\n\nfunction languageScores(text: string): { english: number; nonEnglish: number; words: string[] } {\n const words = languageWords(text);\n let english = 0;\n let nonEnglish = 0;\n for (const word of words) {\n if (ENGLISH_PROMPT_WORDS.has(word)) english++;\n if (NON_ENGLISH_PROMPT_WORDS.has(word)) nonEnglish++;\n }\n // Inspect the original text before languageWords() normalizes dotted \u0130;\n // these Turkish-specific characters are meaningful non-English evidence.\n if (/[\u00E7\u011F\u0131\u00F6\u015F\u00FC\u0130\u0131]/u.test(text)) nonEnglish += 2;\n if (hasNonLatinScript(text)) nonEnglish += 3;\n return { english, nonEnglish, words };\n}\n\n/**\n * Conservative validation for the English half of a bilingual refinement.\n * It requires explicit English instruction vocabulary and rejects every known\n * non-English marker; identifiers and file paths alone are not language proof.\n */\nexport function isValidEnglishRefinement(text: string): boolean {\n const trimmed = text.trim();\n if (!trimmed) return false;\n const scores = languageScores(trimmed);\n return scores.nonEnglish === 0 && scores.english > 0;\n}\n\ntype LatestMessageLanguage = 'english' | 'non_english' | 'unknown';\n\nfunction latestMessageLanguage(text: string): LatestMessageLanguage {\n const scores = languageScores(text);\n if (scores.nonEnglish > scores.english) return 'non_english';\n if (scores.english > scores.nonEnglish) return 'english';\n return 'unknown';\n}\n\n/**\n * Parse and validate the two-version wire format emitted by the refiner.\n * Visually blank separator padding (ASCII/non-breaking/zero-width whitespace)\n * and CRLF are tolerated, but exactly one separator and two non-empty versions\n * are required. The second version must be English.\n */\nexport function parseBilingualEnhancement(raw: string, original: string): EnhanceResult | null {\n const separator = /^[\\t \\u00a0\\u200b-\\u200d\\ufeff]*---[\\t \\u00a0\\u200b-\\u200d\\ufeff]*\\r?$/gm;\n const matches = [...raw.matchAll(separator)];\n if (matches.length !== 1) return null;\n const [match] = matches;\n if (!match) return null;\n const refined = raw.slice(0, match.index).trim();\n const english = raw.slice(match.index + match[0].length).trim();\n if (!refined || !english || !isValidEnglishRefinement(english)) return null;\n\n // Reject a clearly English first half when the original was non-English.\n // For lexically ambiguous input, require the model to make the first half\n // classifiable; otherwise two unchecked halves could bypass correction.\n const inputLanguage = latestMessageLanguage(original);\n const refinedLanguage = latestMessageLanguage(refined);\n if (inputLanguage === 'non_english' && refinedLanguage === 'english') return null;\n if (inputLanguage === 'unknown' && refinedLanguage === 'unknown') return null;\n return { refined, english };\n}\n\n/** A single text-only conversation turn used as refiner context. */\nexport interface ConversationTurn {\n role: 'user' | 'assistant';\n text: string;\n}\n\n/** Additional context the refiner may use to resolve references. */\nexport interface RefinerContextSection {\n title: string;\n items: string[];\n}\n\n/**\n * Minimal structural shape of the live agent context needed to enrich the\n * refiner. Kept structural so browser/client bundles do not need the Context\n * class and tests can pass plain objects.\n */\nexport interface RefinerSessionContextLike {\n projectRoot?: unknown;\n cwd?: unknown;\n workingDir?: unknown;\n readFiles?: unknown;\n writtenFiles?: unknown;\n todos?: unknown;\n}\n\n/**\n * Result of a successful prompt refinement. Carries the original-language and\n * validated English versions so the UI can offer both. English input still\n * uses the two-part wire contract; both fields may contain identical text.\n */\nexport interface EnhanceResult {\n /** Refined in the user's original language. */\n refined: string;\n /** Refined in English. Equals `refined` when the input was already English. */\n english: string;\n}\n\n/**\n * Why a refine attempt fell through. Callers use this to decide the recovery\n * path: `timeout` is a transient capacity/latency failure worth an automatic\n * retry with a longer window (the model was reachable, just slow); `empty` and\n * `provider_error` mean the attempt produced nothing useful, so the caller\n * should surface the recovery options (retry, switch model, send as-is) rather\n * than silently retry. User-initiated cancellation is NOT reported here (it\n * returns `null` with no `onError` call).\n */\nexport type EnhanceFailureKind = 'timeout' | 'empty' | 'provider_error';\n\nexport const DEFAULT_REFINER_RETRY_FEEDBACK =\n 'Make another pass that is sharper and more self-contained. Use the provided project memory, current session context, and recent conversation only to resolve references and preserve project vocabulary; keep the original scope unchanged.';\n\nexport interface EnhanceUserPromptOptions {\n provider: Provider;\n model: string;\n text: string;\n /**\n * Recent conversation turns (oldest\u2192newest), text only, used purely as\n * CONTEXT so the refiner can resolve references in a follow-up message\n * (\"it\", \"the same\", \"that file\"). Without this, the refiner is blind to\n * the conversation and can only refine self-contained prompts. Build with\n * `recentTextTurns(ctx.messages)`.\n */\n history?: ConversationTurn[] | undefined;\n /**\n * Project/session context snippets, already filtered and compacted by the\n * caller. They are context only: the refiner may use them to resolve\n * references, names, files, conventions, and constraints, but must not turn\n * them into extra requirements.\n */\n contextSections?: RefinerContextSection[] | undefined;\n /** Previous refinement when the user asks for another pass. */\n previousRefinement?: EnhanceResult | undefined;\n /** Short instruction for a retry pass. Defaults to `DEFAULT_REFINER_RETRY_FEEDBACK`. */\n retryFeedback?: string | undefined;\n /** Parent abort signal (e.g. the run controller / Esc). */\n signal?: AbortSignal | undefined;\n /** Hard cap on how long to wait for the refiner before giving up. Default 90s. */\n timeoutMs?: number | undefined;\n /** Max tokens for the refined output. Default 2048. */\n maxTokens?: number | undefined;\n /**\n * Reasoning directive for the refiner call. Refinement is a shallow\n * restate-this-more-clearly task that does not benefit from extended\n * thinking, so callers pass a low-effort / thinking-disabled hint here to\n * cut latency and (hidden) reasoning-token cost \u2014 most impactful on slow\n * reasoning models. Build it with `gatedEnhancerReasoning(rc)` so the field\n * is gated to what the model accepts. Omit (undefined) to send no reasoning\n * directive at all (the provider's own default applies).\n */\n reasoning?: ReasoningRequest | undefined;\n /**\n * Called with a short reason and a machine-readable `kind` when refinement\n * fails (provider error, timeout, empty response). NOT called when the caller\n * cancels via `signal`. The `kind` lets the UI drive recovery: `timeout` is\n * eligible for an automatic longer-window retry; `empty` / `provider_error`\n * surface the recovery options instead. The second argument is optional so\n * existing callers that only read the reason keep compiling.\n */\n onError?: ((reason: string, kind?: EnhanceFailureKind) => void) | undefined;\n /**\n * OneShotOrchestrator for the refiner LLM call. When set, uses it instead\n * of direct provider.complete(), gaining fallback chain support.\n */\n oneShotOrchestrator?: OneShotOrchestrator | undefined;\n}\n\n/**\n * Compose the single user message sent to the refiner: the recent\n * conversation and project/session hints embedded as plain text (so we never\n * trip provider role-alternation rules) followed by the latest message to\n * refine.\n */\nfunction buildRefinerInput(\n text: string,\n history?: ConversationTurn[],\n contextSections?: RefinerContextSection[],\n previousRefinement?: EnhanceResult,\n retryFeedback?: string,\n): string {\n const parts: string[] = [];\n const renderedContext = renderRefinerContextSections(contextSections);\n if (renderedContext) parts.push(renderedContext);\n\n if (previousRefinement || retryFeedback) {\n const retryLines = [\n 'Retry context (context only - the user asked for another refinement pass):',\n ];\n if (previousRefinement?.refined) {\n retryLines.push(`Previous refined version: ${compactText(previousRefinement.refined, 900)}`);\n }\n if (\n previousRefinement?.english\n && previousRefinement.english.trim() !== previousRefinement.refined.trim()\n ) {\n retryLines.push(`Previous English version: ${compactText(previousRefinement.english, 900)}`);\n }\n retryLines.push(`Retry instruction: ${retryFeedback ?? DEFAULT_REFINER_RETRY_FEEDBACK}`);\n parts.push(retryLines.join('\\n'));\n }\n\n if (history && history.length > 0) {\n const lines = history.map((t) => `${t.role === 'user' ? 'User' : 'Assistant'}: ${t.text}`);\n parts.push(\n [\n 'Recent conversation (context only - do not act on it):',\n ...lines,\n ].join('\\n'),\n );\n }\n\n if (parts.length === 0) return text;\n return [\n ...parts,\n '',\n 'Latest message to refine:',\n text,\n ].join('\\n\\n');\n}\n\nfunction renderRefinerContextSections(\n contextSections?: RefinerContextSection[],\n): string | undefined {\n const sections = (contextSections ?? [])\n .map((section) => ({\n title: section.title.trim(),\n items: section.items.map((item) => compactText(item, 360)).filter(Boolean),\n }))\n .filter((section) => section.title && section.items.length > 0);\n if (sections.length === 0) return undefined;\n const lines = [\n 'Additional project/session context (context only - use to resolve references, conventions, and constraints; do not add new requirements):',\n ];\n for (const section of sections) {\n lines.push('', `${section.title}:`);\n for (const item of section.items) lines.push(`- ${item}`);\n }\n return lines.join('\\n');\n}\n\nfunction compactText(text: string, maxChars: number): string {\n const compacted = text.replace(/\\s+/g, ' ').trim();\n if (compacted.length <= maxChars) return compacted;\n return `${compacted.slice(0, Math.max(0, maxChars - 3)).trimEnd()}...`;\n}\n\nfunction unknownString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n}\n\nfunction iterableStrings(value: unknown): string[] {\n if (!value || typeof value === 'string') return [];\n if (Array.isArray(value)) {\n return value.flatMap((item) => {\n const text = unknownString(item);\n return text ? [text] : [];\n });\n }\n if (value instanceof Set) {\n return [...value].flatMap((item) => {\n const text = unknownString(item);\n return text ? [text] : [];\n });\n }\n if (\n typeof value === 'object'\n && typeof (value as { [Symbol.iterator]?: unknown })[Symbol.iterator] === 'function'\n ) {\n try {\n return Array.from(value as Iterable<unknown>).flatMap((item) => {\n const text = unknownString(item);\n return text ? [text] : [];\n });\n } catch {\n return [];\n }\n }\n return [];\n}\n\nfunction lastItems(values: string[], maxItems: number): string[] {\n return values.slice(Math.max(0, values.length - maxItems));\n}\n\nfunction todoLines(value: unknown, maxItems: number): string[] {\n if (!Array.isArray(value)) return [];\n const open = value.filter((item): item is Record<string, unknown> => {\n if (!item || typeof item !== 'object') return false;\n const status = item['status'];\n return status === 'pending' || status === 'in_progress';\n });\n return open.slice(0, maxItems).flatMap((todo) => {\n const content = unknownString(todo['activeForm']) ?? unknownString(todo['content']);\n if (!content) return [];\n return [`open todo (${String(todo['status'])}): ${compactText(content, 220)}`];\n });\n}\n\nfunction buildRefinerSessionContextSection(\n context?: RefinerSessionContextLike,\n): RefinerContextSection | undefined {\n if (!context) return undefined;\n const items: string[] = [];\n const projectRoot = unknownString(context.projectRoot);\n const workingDir = unknownString(context.workingDir) ?? unknownString(context.cwd);\n if (projectRoot) items.push(`project root: ${projectRoot}`);\n if (workingDir && workingDir !== projectRoot) items.push(`working dir: ${workingDir}`);\n\n for (const file of lastItems(iterableStrings(context.readFiles), 6)) {\n items.push(`recently read file: ${file}`);\n }\n for (const file of lastItems(iterableStrings(context.writtenFiles), 6)) {\n items.push(`recently written file: ${file}`);\n }\n items.push(...todoLines(context.todos, 6));\n return items.length > 0 ? { title: 'Current session state', items } : undefined;\n}\n\nfunction formatMemoryEntry(entry: MemoryEntry): string {\n const meta = [entry.scope, entry.type, entry.priority].filter(Boolean).join('/');\n const tags = entry.tags && entry.tags.length > 0 ? ` tags: ${entry.tags.slice(0, 5).join(', ')}` : '';\n return `${meta ? `[${meta}] ` : ''}${compactText(entry.text, 260)}${tags}`;\n}\n\nasync function collectMemoryEntries(\n memoryStore: MemoryStore,\n text: string,\n scope: MemoryScope,\n limit: number,\n): Promise<MemoryEntry[]> {\n const scored = memoryStore.scoreRelevant\n ? await memoryStore\n .scoreRelevant({ currentTask: text }, scope, limit)\n .catch(() => [] as MemoryEntry[])\n : [];\n if (scored.length > 0) return scored;\n return memoryStore.search(text || 'prompt refinement', scope, limit).catch(() => []);\n}\n\nasync function buildRefinerMemoryContextSection(\n memoryStore: MemoryStore | undefined,\n text: string,\n): Promise<RefinerContextSection | undefined> {\n if (!memoryStore) return undefined;\n const seen = new Set<string>();\n const entries: MemoryEntry[] = [];\n for (const scope of ['project-memory', 'user-memory'] as const) {\n const remaining = Math.max(0, 6 - entries.length);\n if (remaining === 0) break;\n for (const entry of await collectMemoryEntries(memoryStore, text.trim(), scope, remaining)) {\n const key = `${entry.scope}:${entry.text}`;\n if (seen.has(key)) continue;\n seen.add(key);\n entries.push(entry);\n if (entries.length >= 6) break;\n }\n }\n if (entries.length === 0) return undefined;\n return { title: 'Relevant project memory', items: entries.map(formatMemoryEntry) };\n}\n\nexport async function buildRefinerContextSections(opts: {\n text: string;\n memoryStore?: MemoryStore | undefined;\n context?: RefinerSessionContextLike | undefined;\n}): Promise<RefinerContextSection[]> {\n const sections: RefinerContextSection[] = [];\n const memory = await buildRefinerMemoryContextSection(opts.memoryStore, opts.text);\n if (memory) sections.push(memory);\n const session = buildRefinerSessionContextSection(opts.context);\n if (session) sections.push(session);\n return sections;\n}\n\n/**\n * Refine a raw user prompt. Returns the refined text, or `null` when the\n * caller should fall back to the original (refiner errored, timed out, was\n * aborted, or returned nothing useful). NEVER throws \u2014 refinement is a\n * best-effort convenience and must never block the user from sending.\n */\nexport interface RefinerCompletionOptions {\n provider: Provider;\n oneShotOrchestrator?: OneShotOrchestrator | undefined;\n request: Request;\n signal: AbortSignal;\n timeoutMs: number;\n}\n\n/** Execute one refiner pass through either the orchestrator or direct provider. */\nexport async function completeRefinerPass(\n input: string,\n opts: RefinerCompletionOptions,\n): Promise<{ text: string; error?: string | undefined }> {\n if (opts.oneShotOrchestrator) {\n const result = await opts.oneShotOrchestrator.call({\n system: ENHANCER_SYSTEM_PROMPT,\n messages: [{ role: 'user', content: input }],\n maxTokens: opts.request.maxTokens,\n timeoutMs: opts.timeoutMs,\n signal: opts.signal,\n });\n return result.error ? { text: '', error: result.error } : { text: result.text.trim() };\n }\n const response = await opts.provider.complete(\n { ...opts.request, messages: [{ role: 'user', content: input }] },\n { signal: opts.signal },\n );\n return {\n text: response.content\n .filter(isTextBlock)\n .map((block) => block.text)\n .join('\\n')\n .trim(),\n };\n}\n\nexport async function enhanceUserPrompt(\n opts: EnhanceUserPromptOptions,\n): Promise<EnhanceResult | null> {\n const { provider, model, text } = opts;\n // Reasoning models (\"thinking\" models like DeepSeek reasoner / o1) take\n // longer to first token, so give a generous default window.\n const timeoutMs = opts.timeoutMs ?? 90000;\n // Generous default: on some endpoints the model's hidden \"thinking\" tokens\n // count against this budget, so a small cap can leave NO room for the actual\n // refined text (\u2192 empty completion \u2192 null). 2048 keeps the output room ample.\n const maxTokens = opts.maxTokens ?? 2048;\n const refinerInput = buildRefinerInput(\n text,\n opts.history,\n opts.contextSections,\n opts.previousRefinement,\n opts.retryFeedback,\n );\n\n const req: Request = {\n model,\n system: [{ type: 'text', text: ENHANCER_SYSTEM_PROMPT }],\n messages: [{ role: 'user', content: refinerInput }],\n maxTokens,\n // NOTE: deliberately NO `temperature`. The main agent loop never sets it,\n // and reasoning models (DeepSeek reasoner, o1/o3, \u2026) return HTTP 400 when\n // `temperature` is present \u2014 which would make every refine call fail and\n // silently fall back to the original (no panel shown).\n //\n // A reasoning hint is forwarded ONLY when the caller supplies one (it must\n // already be gated to the model's advertised support \u2014 see\n // `gatedEnhancerReasoning`). Absent it, no reasoning field is sent, which\n // is identical to the original behavior.\n ...(opts.reasoning ? { reasoning: opts.reasoning } : {}),\n };\n\n let timedOut = false;\n const runPass = async (input: string): Promise<{ text: string; error?: string | undefined }> => {\n // Each model pass receives the full configured window. The parent signal\n // still cancels both passes immediately, while a slow first pass cannot\n // consume the corrective retry's entire timeout budget.\n const timer = new AbortController();\n const timeout = setTimeout(() => timer.abort(new Error('enhancer timeout')), timeoutMs);\n const signal = opts.signal ? AbortSignal.any([opts.signal, timer.signal]) : timer.signal;\n try {\n return await completeRefinerPass(input, {\n provider,\n oneShotOrchestrator: opts.oneShotOrchestrator,\n request: req,\n signal,\n timeoutMs,\n });\n } catch (error) {\n if (timer.signal.aborted && !opts.signal?.aborted) timedOut = true;\n throw error;\n } finally {\n timer.abort();\n clearTimeout(timeout);\n }\n };\n\n try {\n const first = await runPass(refinerInput);\n if (first.error) {\n opts.onError?.(first.error, 'provider_error');\n return null;\n }\n const parsed = parseBilingualEnhancement(first.text, text);\n if (parsed) return parsed;\n\n // The output contract is deliberately validated outside the model. Give a\n // malformed response one corrective pass, with the failure and exact wire\n // format made explicit, instead of silently treating non-English text as\n // the English option.\n const correctionInput = [\n 'Your previous response did not satisfy the required bilingual output contract.',\n 'Return exactly two non-empty versions separated by one line containing only \"---\".',\n 'The first version must match the language of the latest message. The second version must be English.',\n 'Do not add labels, headings, fences, commentary, or additional separators.',\n '',\n `Latest message to refine:\\n${text}`,\n '',\n `Invalid previous response:\\n${compactText(first.text || '(empty response)', 1800)}`,\n ].join('\\n');\n const corrected = await runPass(correctionInput);\n if (corrected.error) {\n opts.onError?.(corrected.error, 'provider_error');\n return null;\n }\n const correctedParsed = parseBilingualEnhancement(corrected.text, text);\n if (correctedParsed) return correctedParsed;\n\n opts.onError?.('model returned malformed bilingual output after one corrective retry', 'empty');\n return null;\n } catch (err) {\n // User-initiated cancel \u2192 stay silent (they chose to send the original).\n if (opts.signal?.aborted) return null;\n if (timedOut) {\n opts.onError?.(`timed out after ${Math.round(timeoutMs / 1000)}s`, 'timeout');\n return null;\n }\n opts.onError?.(toErrorMessage(err), 'provider_error');\n return null;\n }\n}\n\n/** Pull the visible text out of a message's content (ignores tool blocks). */\nfunction messageText(content: string | ContentBlock[]): string {\n if (typeof content === 'string') return content;\n return content\n .filter(isTextBlock)\n .map((b) => b.text)\n .join('\\n')\n .trim();\n}\n\n/**\n * Extract the last few user/assistant TEXT turns from a conversation, newest\n * last, for use as refiner context. Skips system messages and tool-only turns\n * (tool_use / tool_result carry no useful natural-language context and bloat\n * the call). Each turn is truncated to `maxChars`; at most `maxTurns` are\n * returned. Pure + exported for unit testing.\n */\nexport function recentTextTurns(\n messages: Message[],\n maxTurns = 6,\n maxChars = 1500,\n): ConversationTurn[] {\n const turns: ConversationTurn[] = [];\n for (let i = messages.length - 1; i >= 0 && turns.length < maxTurns; i--) {\n const m = messages[i];\n if (!m || (m.role !== 'user' && m.role !== 'assistant')) continue;\n const text = messageText(m.content);\n if (!text) continue;\n turns.unshift({\n role: m.role,\n text: text.length > maxChars ? `${text.slice(0, maxChars - 1)}\u2026` : text,\n });\n }\n return turns;\n}\n", "/**\n * Shared recovery policy for prompt refinement (\"enhance\") across every\n * surface \u2014 TUI, CLI-hosted WebUI, and the standalone WebUI server. Keeping the\n * timeout escalation and fallback-model resolution here means all three surfaces\n * apply the SAME rule: a slow first attempt (a `timeout` failure) is retried\n * once with a longer window before the user is asked, and the one-key \"retry\n * with another model\" offer resolves to the same model everywhere.\n *\n * Pure + framework-free so it can be unit-tested in isolation and imported by\n * both the React TUI and the Node WebSocket servers.\n */\n\nimport {\n effectiveFallbackChain,\n normalizeModelRef,\n parseModelRef,\n} from '../core/fallback-model.js';\nimport type { Config } from '../types/config.js';\n\n/** Default first-attempt refine window (mirrors `enhanceUserPrompt`'s default). */\nexport const ENHANCE_BASE_TIMEOUT_MS = 90_000;\n\n/** Floor for a retry window \u2014 a retry only helps if it's meaningfully longer. */\nexport const ENHANCE_MIN_RETRY_TIMEOUT_MS = 180_000;\n\n/**\n * Dedicated provider/model configured for prompt refinement, normalized as a\n * `provider/model` ref. The named refiner profile has precedence over the\n * explicit refiner provider/model, matching `/refiner` and goal refinement.\n * Returns undefined only when no dedicated refiner is configured; callers may\n * then deliberately fall back to the live session target.\n */\nexport function resolveConfiguredRefinerRef(config: Config): string | undefined {\n const activeProvider = config.provider?.trim();\n const profileName = config.autonomy?.refinerFallbackProfile?.trim();\n if (profileName) {\n for (const entry of config.fallbackProfiles?.[profileName] ?? []) {\n if (!parseModelRef(entry).model) continue;\n return normalizeModelRef(entry, activeProvider);\n }\n }\n\n const provider = config.autonomy?.refinerProvider?.trim() || activeProvider;\n const model = config.autonomy?.refinerModel?.trim();\n if (!model || !provider) return undefined;\n return normalizeModelRef(`${provider}/${model}`, provider);\n}\n\n/**\n * Timeout to use for a retry after a first attempt timed out. Prefers an\n * explicit `enhanceRetryTimeoutMs` config override; otherwise doubles the base\n * window, floored at {@link ENHANCE_MIN_RETRY_TIMEOUT_MS} so the \"extra time\"\n * is always a real increase over the (already generous) default.\n */\nexport function nextEnhanceTimeout(\n baseMs: number,\n config?: { enhanceRetryTimeoutMs?: number | undefined } | undefined,\n): number {\n const configured = config?.enhanceRetryTimeoutMs;\n if (typeof configured === 'number' && Number.isFinite(configured) && configured > 0) {\n // Never let an override shorten the window below the base attempt.\n return Math.max(configured, baseMs);\n }\n return Math.max(baseMs * 2, ENHANCE_MIN_RETRY_TIMEOUT_MS);\n}\n\n/**\n * The `provider/model` ref offered as the one-key \"retry with another model\"\n * action on a refine failure, or `undefined` when nothing usable is available.\n * Prefers an explicit `enhanceFallbackModel`; otherwise reuses the first entry\n * of the agent's existing effective fallback chain (so a user who already\n * configured `fallbackModels` / has a smart-default chain gets a sensible\n * offer with zero extra config). Always normalized to `provider/model`.\n */\nexport function resolveEnhanceFallbackRef(config: Config): string | undefined {\n // The active model just failed, so it must never be offered as its own\n // fallback \u2014 normalize both sides and compare.\n const current = config.provider\n ? normalizeModelRef(`${config.provider}/${config.model ?? ''}`, config.provider)\n : undefined;\n const usable = (ref: string): string | undefined => {\n if (!parseModelRef(ref).model) return undefined;\n const normalized = normalizeModelRef(ref, config.provider);\n return normalized === current ? undefined : normalized;\n };\n\n const explicit = config.autonomy?.enhanceFallbackModel?.trim();\n if (explicit) {\n const usableExplicit = usable(explicit);\n if (usableExplicit) return usableExplicit;\n // An explicit ref equal to the active model falls through to the chain\n // rather than offering the model that just failed.\n }\n for (const ref of effectiveFallbackChain(config)) {\n const usableRef = usable(ref);\n if (usableRef) return usableRef;\n }\n return undefined;\n}\n"],
5
- "mappings": "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",
6
- "names": ["hasToolUse", "tokens", "hasToolUse", "path", "LEVEL_RANK", "path", "extractText", "option", "path", "isRecord", "appendFile", "mkdir", "rename", "stat", "dirname", "truncate", "mkdir", "dirname", "appendFile", "stat", "rename", "requireFraction", "fsp", "path", "projectHash", "fs", "path", "fileURLToPath", "fileURLToPath", "existsSync", "fs", "path", "n", "path", "fs", "resolve", "resolve", "unlink", "createHash", "createHash", "randomUUID", "first", "resolve", "isRecord", "optionalString", "isRecord", "optionalString", "finalText", "readFileSync", "statSync", "path", "fileURLToPath", "existsSync", "readFileSync", "path", "readFileSync", "path", "readFileSync", "existsSync", "readFileSync", "path", "readFileSync", "readFileSync", "fileURLToPath", "readFileSync", "isDirectory", "statSync", "BENCHMARK_ENGINEER_META", "MEMORY_CURATOR_META", "FLEET_COORDINATOR_META", "PLUGIN_AUTHOR_META", "TOOL_AUTHOR_META", "baseMessage", "PreemptState", "resolve", "resolve", "GOAL_COMPLETE_MARKER", "randomUUID", "execFile", "promisify", "execFileP", "PATH_HINT_PATTERN", "PATH_BACKSLASH_PATTERN", "PATH_TRIM_PATTERN", "ERROR_LINE_PATTERN", "NEWLINE_SPLIT_PATTERN", "WHITESPACE_COLLAPSE_PATTERN", "extractPathHints", "firstErrorLine", "dedupSaved", "repair", "fs", "path", "stripFrontmatter", "fs", "path", "fs", "path", "slugify", "slugify", "path", "isRecord", "randomUUID", "AsyncLocalStorage", "storage", "AsyncLocalStorage", "storage", "fs", "path", "path", "caps", "access", "relative", "createHash", "randomUUID", "fs", "path", "randomUUID", "createHash", "resolve", "stat", "randomUUID"]
7
- }