@wrongstack/core 0.284.1 → 0.286.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 (831) hide show
  1. package/dist/agent-status-tracker.d.ts +74 -0
  2. package/dist/agent-status-tracker.d.ts.map +1 -0
  3. package/dist/autophase/auto-phase-planner.d.ts +79 -0
  4. package/dist/autophase/auto-phase-planner.d.ts.map +1 -0
  5. package/dist/autophase/auto-phase-runner.d.ts +79 -0
  6. package/dist/autophase/auto-phase-runner.d.ts.map +1 -0
  7. package/dist/autophase/checkpoint.d.ts +49 -0
  8. package/dist/autophase/checkpoint.d.ts.map +1 -0
  9. package/dist/autophase/index.d.ts +9 -0
  10. package/dist/autophase/index.d.ts.map +1 -0
  11. package/dist/autophase/phase-graph-builder.d.ts +46 -0
  12. package/dist/autophase/phase-graph-builder.d.ts.map +1 -0
  13. package/dist/autophase/phase-orchestrator.d.ts +150 -0
  14. package/dist/autophase/phase-orchestrator.d.ts.map +1 -0
  15. package/dist/autophase/phase-store.d.ts +29 -0
  16. package/dist/autophase/phase-store.d.ts.map +1 -0
  17. package/dist/autophase/types.d.ts +329 -0
  18. package/dist/autophase/types.d.ts.map +1 -0
  19. package/dist/boot.d.ts +73 -0
  20. package/dist/boot.d.ts.map +1 -0
  21. package/dist/coordination/adaptive-concurrency.d.ts +63 -0
  22. package/dist/coordination/adaptive-concurrency.d.ts.map +1 -0
  23. package/dist/coordination/agent-bridge.d.ts +24 -0
  24. package/dist/coordination/agent-bridge.d.ts.map +1 -0
  25. package/dist/coordination/agent-monitor.d.ts +129 -0
  26. package/dist/coordination/agent-monitor.d.ts.map +1 -0
  27. package/dist/coordination/agent-subagent-runner.d.ts +74 -0
  28. package/dist/coordination/agent-subagent-runner.d.ts.map +1 -0
  29. package/dist/coordination/agents/agent-prompts.d.ts +2 -0
  30. package/dist/coordination/agents/agent-prompts.d.ts.map +1 -0
  31. package/dist/coordination/agents/index.d.ts +35 -0
  32. package/dist/coordination/agents/index.d.ts.map +1 -0
  33. package/dist/coordination/agents/phase1-discovery.d.ts +4 -0
  34. package/dist/coordination/agents/phase1-discovery.d.ts.map +1 -0
  35. package/dist/coordination/agents/phase2-planning.d.ts +4 -0
  36. package/dist/coordination/agents/phase2-planning.d.ts.map +1 -0
  37. package/dist/coordination/agents/phase3-build.d.ts +4 -0
  38. package/dist/coordination/agents/phase3-build.d.ts.map +1 -0
  39. package/dist/coordination/agents/phase3-techstack.d.ts +13 -0
  40. package/dist/coordination/agents/phase3-techstack.d.ts.map +1 -0
  41. package/dist/coordination/agents/phase4-verify.d.ts +4 -0
  42. package/dist/coordination/agents/phase4-verify.d.ts.map +1 -0
  43. package/dist/coordination/agents/phase5-review.d.ts +4 -0
  44. package/dist/coordination/agents/phase5-review.d.ts.map +1 -0
  45. package/dist/coordination/agents/phase6-domain.d.ts +4 -0
  46. package/dist/coordination/agents/phase6-domain.d.ts.map +1 -0
  47. package/dist/coordination/agents/phase7-knowledge.d.ts +4 -0
  48. package/dist/coordination/agents/phase7-knowledge.d.ts.map +1 -0
  49. package/dist/coordination/agents/phase8-delivery.d.ts +4 -0
  50. package/dist/coordination/agents/phase8-delivery.d.ts.map +1 -0
  51. package/dist/coordination/agents/phase9-meta.d.ts +4 -0
  52. package/dist/coordination/agents/phase9-meta.d.ts.map +1 -0
  53. package/dist/coordination/agents/types.d.ts +79 -0
  54. package/dist/coordination/agents/types.d.ts.map +1 -0
  55. package/dist/coordination/agents.d.ts +8 -0
  56. package/dist/coordination/agents.d.ts.map +1 -0
  57. package/dist/coordination/auto-extend.d.ts +46 -0
  58. package/dist/coordination/auto-extend.d.ts.map +1 -0
  59. package/dist/coordination/autonomous-brain.d.ts +152 -0
  60. package/dist/coordination/autonomous-brain.d.ts.map +1 -0
  61. package/dist/coordination/autonomous-coordinator.d.ts +243 -0
  62. package/dist/coordination/autonomous-coordinator.d.ts.map +1 -0
  63. package/dist/coordination/brain-ledger.d.ts +142 -0
  64. package/dist/coordination/brain-ledger.d.ts.map +1 -0
  65. package/dist/coordination/brain-monitor.d.ts +103 -0
  66. package/dist/coordination/brain-monitor.d.ts.map +1 -0
  67. package/dist/coordination/brain.d.ts +147 -0
  68. package/dist/coordination/brain.d.ts.map +1 -0
  69. package/dist/coordination/change-manager.d.ts +151 -0
  70. package/dist/coordination/change-manager.d.ts.map +1 -0
  71. package/dist/coordination/checkpoint-wiring.d.ts +61 -0
  72. package/dist/coordination/checkpoint-wiring.d.ts.map +1 -0
  73. package/dist/coordination/collab-bus.d.ts +132 -0
  74. package/dist/coordination/collab-bus.d.ts.map +1 -0
  75. package/dist/coordination/collab-debug.d.ts +302 -0
  76. package/dist/coordination/collab-debug.d.ts.map +1 -0
  77. package/dist/coordination/commit-safety.d.ts +72 -0
  78. package/dist/coordination/commit-safety.d.ts.map +1 -0
  79. package/dist/coordination/consensus-protocol.d.ts +106 -0
  80. package/dist/coordination/consensus-protocol.d.ts.map +1 -0
  81. package/dist/coordination/coordinator/error-classifier.d.ts +15 -0
  82. package/dist/coordination/coordinator/error-classifier.d.ts.map +1 -0
  83. package/dist/coordination/delegate-tool.d.ts +101 -0
  84. package/dist/coordination/delegate-tool.d.ts.map +1 -0
  85. package/dist/coordination/dep-watcher-bridge.d.ts +47 -0
  86. package/dist/coordination/dep-watcher-bridge.d.ts.map +1 -0
  87. package/dist/coordination/dep-watcher.d.ts +74 -0
  88. package/dist/coordination/dep-watcher.d.ts.map +1 -0
  89. package/dist/coordination/director/director-errors.d.ts +29 -0
  90. package/dist/coordination/director/director-errors.d.ts.map +1 -0
  91. package/dist/coordination/director-construction.d.ts +90 -0
  92. package/dist/coordination/director-construction.d.ts.map +1 -0
  93. package/dist/coordination/director-prompts.d.ts +119 -0
  94. package/dist/coordination/director-prompts.d.ts.map +1 -0
  95. package/dist/coordination/director-session.d.ts +68 -0
  96. package/dist/coordination/director-session.d.ts.map +1 -0
  97. package/dist/coordination/director-tools.d.ts +65 -0
  98. package/dist/coordination/director-tools.d.ts.map +1 -0
  99. package/dist/coordination/director.d.ts +802 -0
  100. package/dist/coordination/director.d.ts.map +1 -0
  101. package/dist/coordination/dispatcher.d.ts +82 -0
  102. package/dist/coordination/dispatcher.d.ts.map +1 -0
  103. package/dist/coordination/file-author-tracker.d.ts +76 -0
  104. package/dist/coordination/file-author-tracker.d.ts.map +1 -0
  105. package/dist/coordination/fleet-bus.d.ts +122 -0
  106. package/dist/coordination/fleet-bus.d.ts.map +1 -0
  107. package/dist/coordination/fleet-event-validation.d.ts +10 -0
  108. package/dist/coordination/fleet-event-validation.d.ts.map +1 -0
  109. package/dist/coordination/fleet-manager.d.ts +234 -0
  110. package/dist/coordination/fleet-manager.d.ts.map +1 -0
  111. package/dist/coordination/fleet-spawn.d.ts +102 -0
  112. package/dist/coordination/fleet-spawn.d.ts.map +1 -0
  113. package/dist/coordination/fleet-status-tool.d.ts +36 -0
  114. package/dist/coordination/fleet-status-tool.d.ts.map +1 -0
  115. package/dist/coordination/fleet-supervisor.d.ts +157 -0
  116. package/dist/coordination/fleet-supervisor.d.ts.map +1 -0
  117. package/dist/coordination/fleet.d.ts +96 -0
  118. package/dist/coordination/fleet.d.ts.map +1 -0
  119. package/dist/coordination/global-mailbox.d.ts +295 -0
  120. package/dist/coordination/global-mailbox.d.ts.map +1 -0
  121. package/dist/coordination/icoordinator.d.ts +97 -0
  122. package/dist/coordination/icoordinator.d.ts.map +1 -0
  123. package/dist/coordination/ifleet-manager.d.ts +177 -0
  124. package/dist/coordination/ifleet-manager.d.ts.map +1 -0
  125. package/dist/coordination/in-memory-transport.d.ts +12 -0
  126. package/dist/coordination/in-memory-transport.d.ts.map +1 -0
  127. package/dist/coordination/index.d.ts +79 -2587
  128. package/dist/coordination/index.d.ts.map +1 -0
  129. package/dist/coordination/index.js +2262 -673
  130. package/dist/coordination/index.js.map +7 -1
  131. package/dist/coordination/knowledge-graph.d.ts +229 -0
  132. package/dist/coordination/knowledge-graph.d.ts.map +1 -0
  133. package/dist/coordination/large-answer-store.d.ts +61 -0
  134. package/dist/coordination/large-answer-store.d.ts.map +1 -0
  135. package/dist/coordination/mail-tools.d.ts +34 -0
  136. package/dist/coordination/mail-tools.d.ts.map +1 -0
  137. package/dist/coordination/mailbox-actions.d.ts +67 -0
  138. package/dist/coordination/mailbox-actions.d.ts.map +1 -0
  139. package/dist/coordination/mailbox-constants.d.ts +64 -0
  140. package/dist/coordination/mailbox-constants.d.ts.map +1 -0
  141. package/dist/coordination/mailbox-events.d.ts +32 -0
  142. package/dist/coordination/mailbox-events.d.ts.map +1 -0
  143. package/dist/coordination/mailbox-health.d.ts +131 -0
  144. package/dist/coordination/mailbox-health.d.ts.map +1 -0
  145. package/dist/coordination/mailbox-hooks.d.ts +55 -0
  146. package/dist/coordination/mailbox-hooks.d.ts.map +1 -0
  147. package/dist/coordination/mailbox-message-codec.d.ts +8 -0
  148. package/dist/coordination/mailbox-message-codec.d.ts.map +1 -0
  149. package/dist/coordination/mailbox-tool.d.ts +75 -0
  150. package/dist/coordination/mailbox-tool.d.ts.map +1 -0
  151. package/dist/{mailbox-types-BGZWrYTJ.d.ts → coordination/mailbox-types.d.ts} +125 -26
  152. package/dist/coordination/mailbox-types.d.ts.map +1 -0
  153. package/dist/coordination/mailbox.d.ts +88 -0
  154. package/dist/coordination/mailbox.d.ts.map +1 -0
  155. package/dist/coordination/model-matrix.d.ts +98 -0
  156. package/dist/coordination/model-matrix.d.ts.map +1 -0
  157. package/dist/coordination/multi-agent-coordinator.d.ts +202 -0
  158. package/dist/coordination/multi-agent-coordinator.d.ts.map +1 -0
  159. package/dist/coordination/null-fleet-bus.d.ts +10 -0
  160. package/dist/coordination/null-fleet-bus.d.ts.map +1 -0
  161. package/dist/coordination/package-author-tracker.d.ts +87 -0
  162. package/dist/coordination/package-author-tracker.d.ts.map +1 -0
  163. package/dist/coordination/package-outdated-watcher.d.ts +83 -0
  164. package/dist/coordination/package-outdated-watcher.d.ts.map +1 -0
  165. package/dist/coordination/single-instance-mailbox.d.ts +154 -0
  166. package/dist/coordination/single-instance-mailbox.d.ts.map +1 -0
  167. package/dist/coordination/spawn-budget.d.ts +6 -0
  168. package/dist/coordination/spawn-budget.d.ts.map +1 -0
  169. package/dist/coordination/subagent-budget.d.ts +323 -0
  170. package/dist/coordination/subagent-budget.d.ts.map +1 -0
  171. package/dist/coordination/subagent-nicknames.d.ts +42 -0
  172. package/dist/coordination/subagent-nicknames.d.ts.map +1 -0
  173. package/dist/coordination/subagent-result-tool.d.ts +20 -0
  174. package/dist/coordination/subagent-result-tool.d.ts.map +1 -0
  175. package/dist/coordination/task-auctioneer.d.ts +143 -0
  176. package/dist/coordination/task-auctioneer.d.ts.map +1 -0
  177. package/dist/coordination/task-dag.d.ts +147 -0
  178. package/dist/coordination/task-dag.d.ts.map +1 -0
  179. package/dist/coordination/techstack-mailbox-consumer.d.ts +50 -0
  180. package/dist/coordination/techstack-mailbox-consumer.d.ts.map +1 -0
  181. package/dist/coordination/transport.d.ts +2 -0
  182. package/dist/coordination/transport.d.ts.map +1 -0
  183. package/dist/coordination/worktree-task-runner.d.ts +45 -0
  184. package/dist/coordination/worktree-task-runner.d.ts.map +1 -0
  185. package/dist/core/agent-internals.d.ts +41 -0
  186. package/dist/core/agent-internals.d.ts.map +1 -0
  187. package/dist/core/agent-loop.d.ts +18 -0
  188. package/dist/core/agent-loop.d.ts.map +1 -0
  189. package/dist/core/agent-response.d.ts +21 -0
  190. package/dist/core/agent-response.d.ts.map +1 -0
  191. package/dist/core/agent-tools.d.ts +21 -0
  192. package/dist/core/agent-tools.d.ts.map +1 -0
  193. package/dist/core/agent-types.d.ts +95 -0
  194. package/dist/core/agent-types.d.ts.map +1 -0
  195. package/dist/core/agent.d.ts +54 -0
  196. package/dist/core/agent.d.ts.map +1 -0
  197. package/dist/core/btw.d.ts +40 -0
  198. package/dist/core/btw.d.ts.map +1 -0
  199. package/dist/core/context.d.ts +269 -0
  200. package/dist/core/context.d.ts.map +1 -0
  201. package/dist/core/continue-intent.d.ts +92 -0
  202. package/dist/core/continue-intent.d.ts.map +1 -0
  203. package/dist/core/continue-to-next-iteration.d.ts +96 -0
  204. package/dist/core/continue-to-next-iteration.d.ts.map +1 -0
  205. package/dist/core/conversation-state.d.ts +96 -0
  206. package/dist/core/conversation-state.d.ts.map +1 -0
  207. package/dist/core/fallback-model.d.ts +94 -0
  208. package/dist/core/fallback-model.d.ts.map +1 -0
  209. package/dist/core/fleet-pulse.d.ts +42 -0
  210. package/dist/core/fleet-pulse.d.ts.map +1 -0
  211. package/dist/core/input-builder.d.ts +95 -0
  212. package/dist/core/input-builder.d.ts.map +1 -0
  213. package/dist/core/instruction-bundle.d.ts +22 -0
  214. package/dist/core/instruction-bundle.d.ts.map +1 -0
  215. package/dist/core/iteration-limit.d.ts +35 -0
  216. package/dist/core/iteration-limit.d.ts.map +1 -0
  217. package/dist/core/mailbox-loop.d.ts +63 -0
  218. package/dist/core/mailbox-loop.d.ts.map +1 -0
  219. package/dist/core/modes/brief.d.ts +2 -0
  220. package/dist/core/modes/brief.d.ts.map +1 -0
  221. package/dist/core/modes/default.d.ts +8 -0
  222. package/dist/core/modes/default.d.ts.map +1 -0
  223. package/dist/core/modes/teach.d.ts +2 -0
  224. package/dist/core/modes/teach.d.ts.map +1 -0
  225. package/dist/core/provider-runner.d.ts +24 -0
  226. package/dist/core/provider-runner.d.ts.map +1 -0
  227. package/dist/core/queued-messages.d.ts +55 -0
  228. package/dist/core/queued-messages.d.ts.map +1 -0
  229. package/dist/core/run-env.d.ts +49 -0
  230. package/dist/core/run-env.d.ts.map +1 -0
  231. package/dist/core/streaming-response-builder.d.ts +78 -0
  232. package/dist/core/streaming-response-builder.d.ts.map +1 -0
  233. package/dist/core/system-prompt-builder.d.ts +213 -0
  234. package/dist/core/system-prompt-builder.d.ts.map +1 -0
  235. package/dist/defaults/index.d.ts +68 -158
  236. package/dist/defaults/index.d.ts.map +1 -0
  237. package/dist/defaults/index.js +2061 -1300
  238. package/dist/defaults/index.js.map +7 -1
  239. package/dist/execution/auto-compaction-middleware.d.ts +123 -0
  240. package/dist/execution/auto-compaction-middleware.d.ts.map +1 -0
  241. package/dist/execution/autonomous-runner.d.ts +61 -0
  242. package/dist/execution/autonomous-runner.d.ts.map +1 -0
  243. package/dist/execution/autonomy-brain.d.ts +151 -0
  244. package/dist/execution/autonomy-brain.d.ts.map +1 -0
  245. package/dist/execution/autonomy-prompt-contributor.d.ts +39 -0
  246. package/dist/execution/autonomy-prompt-contributor.d.ts.map +1 -0
  247. package/dist/execution/brain-chain.d.ts +53 -0
  248. package/dist/execution/brain-chain.d.ts.map +1 -0
  249. package/dist/execution/brain-evaluation.d.ts +66 -0
  250. package/dist/execution/brain-evaluation.d.ts.map +1 -0
  251. package/dist/execution/brain-runtime.d.ts +171 -0
  252. package/dist/execution/brain-runtime.d.ts.map +1 -0
  253. package/dist/execution/compaction-core.d.ts +103 -0
  254. package/dist/execution/compaction-core.d.ts.map +1 -0
  255. package/dist/execution/compactor.d.ts +56 -0
  256. package/dist/execution/compactor.d.ts.map +1 -0
  257. package/dist/execution/council-brain.d.ts +79 -0
  258. package/dist/execution/council-brain.d.ts.map +1 -0
  259. package/dist/execution/design-color.d.ts +31 -0
  260. package/dist/execution/design-color.d.ts.map +1 -0
  261. package/dist/execution/design-detect.d.ts +96 -0
  262. package/dist/execution/design-detect.d.ts.map +1 -0
  263. package/dist/execution/design-kit-loader.d.ts +53 -0
  264. package/dist/execution/design-kit-loader.d.ts.map +1 -0
  265. package/dist/execution/design-materialize.d.ts +32 -0
  266. package/dist/execution/design-materialize.d.ts.map +1 -0
  267. package/dist/execution/design-project-store.d.ts +57 -0
  268. package/dist/execution/design-project-store.d.ts.map +1 -0
  269. package/dist/execution/design-verify.d.ts +44 -0
  270. package/dist/execution/design-verify.d.ts.map +1 -0
  271. package/dist/execution/error-handler.d.ts +34 -0
  272. package/dist/execution/error-handler.d.ts.map +1 -0
  273. package/dist/{parallel-eternal-engine-HUrtePLd.d.ts → execution/eternal-autonomy.d.ts} +22 -225
  274. package/dist/execution/eternal-autonomy.d.ts.map +1 -0
  275. package/dist/execution/goal-preamble.d.ts +2 -0
  276. package/dist/execution/goal-preamble.d.ts.map +1 -0
  277. package/dist/execution/index.d.ts +25 -180
  278. package/dist/execution/index.d.ts.map +1 -0
  279. package/dist/execution/index.js +1748 -490
  280. package/dist/execution/index.js.map +7 -1
  281. package/dist/execution/intelligent-compactor.d.ts +85 -0
  282. package/dist/execution/intelligent-compactor.d.ts.map +1 -0
  283. package/dist/execution/model-runtime.d.ts +75 -0
  284. package/dist/execution/model-runtime.d.ts.map +1 -0
  285. package/dist/execution/parallel-eternal-engine.d.ts +142 -0
  286. package/dist/execution/parallel-eternal-engine.d.ts.map +1 -0
  287. package/dist/execution/prompt-enhancer.d.ts +12 -13
  288. package/dist/execution/prompt-enhancer.d.ts.map +1 -0
  289. package/dist/execution/prompt-enhancer.js +13 -7
  290. package/dist/execution/prompt-enhancer.js.map +7 -1
  291. package/dist/execution/prompt-loader.d.ts +52 -0
  292. package/dist/execution/prompt-loader.d.ts.map +1 -0
  293. package/dist/execution/provider-runner-impl.d.ts +14 -0
  294. package/dist/execution/provider-runner-impl.d.ts.map +1 -0
  295. package/dist/execution/regex-patterns.d.ts +7 -0
  296. package/dist/execution/regex-patterns.d.ts.map +1 -0
  297. package/dist/execution/retry-policy.d.ts +35 -0
  298. package/dist/execution/retry-policy.d.ts.map +1 -0
  299. package/dist/execution/selective-compactor.d.ts +94 -0
  300. package/dist/execution/selective-compactor.d.ts.map +1 -0
  301. package/dist/execution/skill-loader.d.ts +43 -0
  302. package/dist/execution/skill-loader.d.ts.map +1 -0
  303. package/dist/execution/strategy-compactor.d.ts +43 -0
  304. package/dist/execution/strategy-compactor.d.ts.map +1 -0
  305. package/dist/execution/tool-executor.d.ts +112 -0
  306. package/dist/execution/tool-executor.d.ts.map +1 -0
  307. package/dist/extension/extension-points.d.ts +121 -0
  308. package/dist/extension/extension-points.d.ts.map +1 -0
  309. package/dist/extension/index.d.ts +3 -10
  310. package/dist/extension/index.d.ts.map +1 -0
  311. package/dist/extension/index.js +59 -5
  312. package/dist/extension/index.js.map +7 -1
  313. package/dist/extension/registry.d.ts +86 -0
  314. package/dist/extension/registry.d.ts.map +1 -0
  315. package/dist/fleet-notifier.d.ts +28 -0
  316. package/dist/fleet-notifier.d.ts.map +1 -0
  317. package/dist/hooks/http-executor.d.ts +11 -0
  318. package/dist/hooks/http-executor.d.ts.map +1 -0
  319. package/dist/hooks/index.d.ts +10 -0
  320. package/dist/hooks/index.d.ts.map +1 -0
  321. package/dist/hooks/registry.d.ts +71 -0
  322. package/dist/hooks/registry.d.ts.map +1 -0
  323. package/dist/hooks/runner.d.ts +65 -0
  324. package/dist/hooks/runner.d.ts.map +1 -0
  325. package/dist/hooks/shell-executor.d.ts +33 -0
  326. package/dist/hooks/shell-executor.d.ts.map +1 -0
  327. package/dist/hooks/shell-hooks-equal.d.ts +15 -0
  328. package/dist/hooks/shell-hooks-equal.d.ts.map +1 -0
  329. package/dist/hq/agent-bridge.d.ts +27 -0
  330. package/dist/hq/agent-bridge.d.ts.map +1 -0
  331. package/dist/hq/alerts.d.ts +67 -0
  332. package/dist/hq/alerts.d.ts.map +1 -0
  333. package/dist/hq/auth-store.d.ts +179 -0
  334. package/dist/hq/auth-store.d.ts.map +1 -0
  335. package/dist/hq/brain-bridge.d.ts +37 -0
  336. package/dist/hq/brain-bridge.d.ts.map +1 -0
  337. package/dist/hq/commands.d.ts +122 -0
  338. package/dist/hq/commands.d.ts.map +1 -0
  339. package/dist/hq/cost-bridge.d.ts +36 -0
  340. package/dist/hq/cost-bridge.d.ts.map +1 -0
  341. package/dist/hq/factory.d.ts +69 -0
  342. package/dist/hq/factory.d.ts.map +1 -0
  343. package/dist/hq/fleet-bridge.d.ts +39 -0
  344. package/dist/hq/fleet-bridge.d.ts.map +1 -0
  345. package/dist/hq/index.d.ts +18 -816
  346. package/dist/hq/index.d.ts.map +1 -0
  347. package/dist/hq/index.js +1043 -192
  348. package/dist/hq/index.js.map +7 -1
  349. package/dist/hq/mailbox-mapper.d.ts +27 -0
  350. package/dist/hq/mailbox-mapper.d.ts.map +1 -0
  351. package/dist/hq/persistence.d.ts +121 -0
  352. package/dist/hq/persistence.d.ts.map +1 -0
  353. package/dist/hq/protocol.d.ts +612 -0
  354. package/dist/hq/protocol.d.ts.map +1 -0
  355. package/dist/hq/publisher.d.ts +181 -0
  356. package/dist/hq/publisher.d.ts.map +1 -0
  357. package/dist/hq/redaction.d.ts +30 -0
  358. package/dist/hq/redaction.d.ts.map +1 -0
  359. package/dist/hq/session-bridge.d.ts +29 -0
  360. package/dist/hq/session-bridge.d.ts.map +1 -0
  361. package/dist/hq/tool-bridge.d.ts +41 -0
  362. package/dist/hq/tool-bridge.d.ts.map +1 -0
  363. package/dist/hq/transcript-mapper.d.ts +36 -0
  364. package/dist/hq/transcript-mapper.d.ts.map +1 -0
  365. package/dist/hq/worktree-bridge.d.ts +34 -0
  366. package/dist/hq/worktree-bridge.d.ts.map +1 -0
  367. package/dist/index.d.ts +114 -2872
  368. package/dist/index.d.ts.map +1 -0
  369. package/dist/index.js +6104 -2737
  370. package/dist/index.js.map +7 -1
  371. package/dist/infrastructure/context-manager.d.ts +92 -0
  372. package/dist/infrastructure/context-manager.d.ts.map +1 -0
  373. package/dist/infrastructure/index.d.ts +6 -64
  374. package/dist/infrastructure/index.d.ts.map +1 -0
  375. package/dist/infrastructure/index.js +39 -12
  376. package/dist/infrastructure/index.js.map +7 -1
  377. package/dist/infrastructure/logger.d.ts +99 -0
  378. package/dist/infrastructure/logger.d.ts.map +1 -0
  379. package/dist/infrastructure/mcp-servers.d.ts +83 -0
  380. package/dist/infrastructure/mcp-servers.d.ts.map +1 -0
  381. package/dist/{path-resolver-CMS5307d.d.ts → infrastructure/path-resolver.d.ts} +3 -5
  382. package/dist/infrastructure/path-resolver.d.ts.map +1 -0
  383. package/dist/infrastructure/token-counter.d.ts +57 -0
  384. package/dist/infrastructure/token-counter.d.ts.map +1 -0
  385. package/dist/kernel/container.d.ts +84 -0
  386. package/dist/kernel/container.d.ts.map +1 -0
  387. package/dist/{events-Bgnh43r9.d.ts → kernel/events.d.ts} +134 -210
  388. package/dist/kernel/events.d.ts.map +1 -0
  389. package/dist/kernel/index.d.ts +6 -107
  390. package/dist/kernel/index.d.ts.map +1 -0
  391. package/dist/kernel/index.js +56 -4
  392. package/dist/kernel/index.js.map +7 -1
  393. package/dist/kernel/pipeline.d.ts +105 -0
  394. package/dist/kernel/pipeline.d.ts.map +1 -0
  395. package/dist/kernel/run-controller.d.ts +55 -0
  396. package/dist/kernel/run-controller.d.ts.map +1 -0
  397. package/dist/kernel/tokens.d.ts +53 -0
  398. package/dist/kernel/tokens.d.ts.map +1 -0
  399. package/dist/mailbox-attach.d.ts +27 -0
  400. package/dist/mailbox-attach.d.ts.map +1 -0
  401. package/dist/middleware/collab-pause.d.ts +73 -0
  402. package/dist/middleware/collab-pause.d.ts.map +1 -0
  403. package/dist/models/codex-catalog.d.ts +41 -0
  404. package/dist/models/codex-catalog.d.ts.map +1 -0
  405. package/dist/models/index.d.ts +8 -163
  406. package/dist/models/index.d.ts.map +1 -0
  407. package/dist/models/index.js +150 -51
  408. package/dist/models/index.js.map +7 -1
  409. package/dist/models/llm-selector.d.ts +47 -0
  410. package/dist/models/llm-selector.d.ts.map +1 -0
  411. package/dist/models/mode-store.d.ts +22 -0
  412. package/dist/models/mode-store.d.ts.map +1 -0
  413. package/dist/models/model-intelligence.d.ts +56 -0
  414. package/dist/models/model-intelligence.d.ts.map +1 -0
  415. package/dist/models/model-router.d.ts +100 -0
  416. package/dist/models/model-router.d.ts.map +1 -0
  417. package/dist/models/models-registry.d.ts +106 -0
  418. package/dist/models/models-registry.d.ts.map +1 -0
  419. package/dist/models/provider-model-resolve.d.ts +69 -0
  420. package/dist/models/provider-model-resolve.d.ts.map +1 -0
  421. package/dist/observability/event-bridge.d.ts +10 -0
  422. package/dist/observability/event-bridge.d.ts.map +1 -0
  423. package/dist/observability/health.d.ts +18 -0
  424. package/dist/observability/health.d.ts.map +1 -0
  425. package/dist/observability/index.d.ts +9 -354
  426. package/dist/observability/index.d.ts.map +1 -0
  427. package/dist/observability/index.js +37 -23
  428. package/dist/observability/index.js.map +7 -1
  429. package/dist/observability/metrics.d.ts +26 -0
  430. package/dist/observability/metrics.d.ts.map +1 -0
  431. package/dist/observability/otel-tracer.d.ts +41 -0
  432. package/dist/observability/otel-tracer.d.ts.map +1 -0
  433. package/dist/observability/otlp-metrics.d.ts +111 -0
  434. package/dist/observability/otlp-metrics.d.ts.map +1 -0
  435. package/dist/observability/otlp-traces.d.ts +95 -0
  436. package/dist/observability/otlp-traces.d.ts.map +1 -0
  437. package/dist/observability/prometheus.d.ts +49 -0
  438. package/dist/observability/prometheus.d.ts.map +1 -0
  439. package/dist/observability/tracer.d.ts +9 -0
  440. package/dist/observability/tracer.d.ts.map +1 -0
  441. package/dist/plugin/api.d.ts +226 -0
  442. package/dist/plugin/api.d.ts.map +1 -0
  443. package/dist/plugin/loader.d.ts +73 -0
  444. package/dist/plugin/loader.d.ts.map +1 -0
  445. package/dist/plugins/chimera-plugin.d.ts +37 -0
  446. package/dist/plugins/chimera-plugin.d.ts.map +1 -0
  447. package/dist/plugins/prompts-plugin.d.ts +26 -0
  448. package/dist/plugins/prompts-plugin.d.ts.map +1 -0
  449. package/dist/plugins/security-plugin.d.ts +19 -0
  450. package/dist/plugins/security-plugin.d.ts.map +1 -0
  451. package/dist/plugins/skills-plugin.d.ts +42 -0
  452. package/dist/plugins/skills-plugin.d.ts.map +1 -0
  453. package/dist/plugins/sync-plugin.d.ts +22 -0
  454. package/dist/plugins/sync-plugin.d.ts.map +1 -0
  455. package/dist/prompts/index.d.ts +3 -0
  456. package/dist/prompts/index.d.ts.map +1 -0
  457. package/dist/prompts/prompt-installer.d.ts +50 -0
  458. package/dist/prompts/prompt-installer.d.ts.map +1 -0
  459. package/dist/prompts/prompt-manifest-store.d.ts +18 -0
  460. package/dist/prompts/prompt-manifest-store.d.ts.map +1 -0
  461. package/dist/registry/provider-registry.d.ts +51 -0
  462. package/dist/registry/provider-registry.d.ts.map +1 -0
  463. package/dist/registry/slash-command-registry.d.ts +61 -0
  464. package/dist/registry/slash-command-registry.d.ts.map +1 -0
  465. package/dist/registry/tool-registry.d.ts +154 -0
  466. package/dist/registry/tool-registry.d.ts.map +1 -0
  467. package/dist/replay/hash.d.ts +31 -0
  468. package/dist/replay/hash.d.ts.map +1 -0
  469. package/dist/replay/replay-provider-runner.d.ts +53 -0
  470. package/dist/replay/replay-provider-runner.d.ts.map +1 -0
  471. package/dist/{index-CbyuOE5y.d.ts → security/capabilities.d.ts} +31 -34
  472. package/dist/security/capabilities.d.ts.map +1 -0
  473. package/dist/security/config-secrets.d.ts +25 -0
  474. package/dist/security/config-secrets.d.ts.map +1 -0
  475. package/dist/security/index.d.ts +7 -8
  476. package/dist/security/index.d.ts.map +1 -0
  477. package/dist/security/index.js +354 -401
  478. package/dist/security/index.js.map +7 -1
  479. package/dist/security/permission-policy-schema.d.ts +77 -0
  480. package/dist/security/permission-policy-schema.d.ts.map +1 -0
  481. package/dist/security/permission-policy.d.ts +158 -0
  482. package/dist/security/permission-policy.d.ts.map +1 -0
  483. package/dist/security/secret-scrubber.d.ts +14 -0
  484. package/dist/security/secret-scrubber.d.ts.map +1 -0
  485. package/dist/security/secret-vault.d.ts +96 -0
  486. package/dist/security/secret-vault.d.ts.map +1 -0
  487. package/dist/security/yolo-risk.d.ts +11 -0
  488. package/dist/security/yolo-risk.d.ts.map +1 -0
  489. package/dist/{session-registry-Dvg7i_IA.d.ts → session-registry.d.ts} +8 -9
  490. package/dist/session-registry.d.ts.map +1 -0
  491. package/dist/skills/foreign-sources.d.ts +59 -0
  492. package/dist/skills/foreign-sources.d.ts.map +1 -0
  493. package/dist/skills/frontmatter.d.ts +44 -0
  494. package/dist/skills/frontmatter.d.ts.map +1 -0
  495. package/dist/skills/github-fetcher.d.ts +38 -0
  496. package/dist/skills/github-fetcher.d.ts.map +1 -0
  497. package/dist/skills/index.d.ts +11 -582
  498. package/dist/skills/index.d.ts.map +1 -0
  499. package/dist/skills/index.js +81 -43
  500. package/dist/skills/index.js.map +7 -1
  501. package/dist/skills/limits.d.ts +92 -0
  502. package/dist/skills/limits.d.ts.map +1 -0
  503. package/dist/skills/manifest-store.d.ts +42 -0
  504. package/dist/skills/manifest-store.d.ts.map +1 -0
  505. package/dist/skills/registry/github-direct-adapter.d.ts +17 -0
  506. package/dist/skills/registry/github-direct-adapter.d.ts.map +1 -0
  507. package/dist/skills/registry/registry-adapter.d.ts +84 -0
  508. package/dist/skills/registry/registry-adapter.d.ts.map +1 -0
  509. package/dist/skills/registry/skills-sh-adapter.d.ts +13 -0
  510. package/dist/skills/registry/skills-sh-adapter.d.ts.map +1 -0
  511. package/dist/skills/skill-generator.d.ts +82 -0
  512. package/dist/skills/skill-generator.d.ts.map +1 -0
  513. package/dist/skills/skill-installer.d.ts +124 -0
  514. package/dist/skills/skill-installer.d.ts.map +1 -0
  515. package/dist/storage/annotations-store.d.ts +118 -0
  516. package/dist/storage/annotations-store.d.ts.map +1 -0
  517. package/dist/storage/attachment-store.d.ts +31 -0
  518. package/dist/storage/attachment-store.d.ts.map +1 -0
  519. package/dist/storage/cloud-sync.d.ts +44 -0
  520. package/dist/storage/cloud-sync.d.ts.map +1 -0
  521. package/dist/storage/completed-work-checkpoint.d.ts +11 -0
  522. package/dist/storage/completed-work-checkpoint.d.ts.map +1 -0
  523. package/dist/storage/config-loader.d.ts +114 -0
  524. package/dist/storage/config-loader.d.ts.map +1 -0
  525. package/dist/storage/config-migration.d.ts +87 -0
  526. package/dist/storage/config-migration.d.ts.map +1 -0
  527. package/dist/storage/config-store.d.ts +22 -0
  528. package/dist/storage/config-store.d.ts.map +1 -0
  529. package/dist/{director-state-CMS_bMs4.d.ts → storage/director-state.d.ts} +28 -8
  530. package/dist/storage/director-state.d.ts.map +1 -0
  531. package/dist/storage/file-session-writer.d.ts +169 -0
  532. package/dist/storage/file-session-writer.d.ts.map +1 -0
  533. package/dist/{goal-store-Datpp-ar.d.ts → storage/goal-store.d.ts} +26 -19
  534. package/dist/storage/goal-store.d.ts.map +1 -0
  535. package/dist/storage/index.d.ts +39 -1031
  536. package/dist/storage/index.d.ts.map +1 -0
  537. package/dist/storage/index.js +783 -443
  538. package/dist/storage/index.js.map +7 -1
  539. package/dist/storage/input-history-store.d.ts +56 -0
  540. package/dist/storage/input-history-store.d.ts.map +1 -0
  541. package/dist/storage/memory-backend.d.ts +66 -0
  542. package/dist/storage/memory-backend.d.ts.map +1 -0
  543. package/dist/storage/memory-consolidator.d.ts +50 -0
  544. package/dist/storage/memory-consolidator.d.ts.map +1 -0
  545. package/dist/storage/memory-graph-backend.d.ts +117 -0
  546. package/dist/storage/memory-graph-backend.d.ts.map +1 -0
  547. package/dist/storage/memory-store.d.ts +119 -0
  548. package/dist/storage/memory-store.d.ts.map +1 -0
  549. package/dist/storage/plan-store.d.ts +78 -0
  550. package/dist/storage/plan-store.d.ts.map +1 -0
  551. package/dist/storage/plan-templates.d.ts +21 -0
  552. package/dist/storage/plan-templates.d.ts.map +1 -0
  553. package/dist/storage/prompt-store.d.ts +37 -0
  554. package/dist/storage/prompt-store.d.ts.map +1 -0
  555. package/dist/storage/prompt-usage-store.d.ts +29 -0
  556. package/dist/storage/prompt-usage-store.d.ts.map +1 -0
  557. package/dist/storage/provider-config-watcher.d.ts +34 -0
  558. package/dist/storage/provider-config-watcher.d.ts.map +1 -0
  559. package/dist/storage/queue-store.d.ts +41 -0
  560. package/dist/storage/queue-store.d.ts.map +1 -0
  561. package/dist/storage/recovery-lock.d.ts +79 -0
  562. package/dist/storage/recovery-lock.d.ts.map +1 -0
  563. package/dist/storage/replay-log-store.d.ts +97 -0
  564. package/dist/storage/replay-log-store.d.ts.map +1 -0
  565. package/dist/storage/session-analyzer.d.ts +48 -0
  566. package/dist/storage/session-analyzer.d.ts.map +1 -0
  567. package/dist/storage/session-checkpoint-cas.d.ts +37 -0
  568. package/dist/storage/session-checkpoint-cas.d.ts.map +1 -0
  569. package/dist/{session-event-bridge-D_z_mBwk.d.ts → storage/session-event-bridge.d.ts} +14 -15
  570. package/dist/storage/session-event-bridge.d.ts.map +1 -0
  571. package/dist/storage/session-helpers.d.ts +9 -0
  572. package/dist/storage/session-helpers.d.ts.map +1 -0
  573. package/dist/storage/session-id.d.ts +18 -0
  574. package/dist/storage/session-id.d.ts.map +1 -0
  575. package/dist/storage/session-reader.d.ts +21 -0
  576. package/dist/storage/session-reader.d.ts.map +1 -0
  577. package/dist/storage/session-recovery.d.ts +93 -0
  578. package/dist/storage/session-recovery.d.ts.map +1 -0
  579. package/dist/storage/session-resume-validation.d.ts +6 -0
  580. package/dist/storage/session-resume-validation.d.ts.map +1 -0
  581. package/dist/storage/session-rewinder.d.ts +21 -0
  582. package/dist/storage/session-rewinder.d.ts.map +1 -0
  583. package/dist/storage/session-store.d.ts +219 -0
  584. package/dist/storage/session-store.d.ts.map +1 -0
  585. package/dist/storage/session-summary.d.ts +12 -0
  586. package/dist/storage/session-summary.d.ts.map +1 -0
  587. package/dist/storage/session-tool-call-ends.d.ts +5 -0
  588. package/dist/storage/session-tool-call-ends.d.ts.map +1 -0
  589. package/dist/storage/storage-concurrency.d.ts +2 -0
  590. package/dist/storage/storage-concurrency.d.ts.map +1 -0
  591. package/dist/storage/task-store.d.ts +33 -0
  592. package/dist/storage/task-store.d.ts.map +1 -0
  593. package/dist/storage/todos-checkpoint.d.ts +39 -0
  594. package/dist/storage/todos-checkpoint.d.ts.map +1 -0
  595. package/dist/storage/tool-audit-log.d.ts +141 -0
  596. package/dist/storage/tool-audit-log.d.ts.map +1 -0
  597. package/dist/tasking/index.d.ts +3 -124
  598. package/dist/tasking/index.d.ts.map +1 -0
  599. package/dist/tasking/index.js +57 -4
  600. package/dist/tasking/index.js.map +7 -1
  601. package/dist/tasking/task-store.d.ts +22 -0
  602. package/dist/tasking/task-store.d.ts.map +1 -0
  603. package/dist/tasking/task-tracker.d.ts +102 -0
  604. package/dist/tasking/task-tracker.d.ts.map +1 -0
  605. package/dist/tools/index.d.ts +2 -59
  606. package/dist/tools/index.d.ts.map +1 -0
  607. package/dist/tools/index.js +93 -14
  608. package/dist/tools/index.js.map +7 -1
  609. package/dist/tools/mcp-control.d.ts +53 -0
  610. package/dist/tools/mcp-control.d.ts.map +1 -0
  611. package/dist/tools/mcp-use.d.ts +24 -0
  612. package/dist/tools/mcp-use.d.ts.map +1 -0
  613. package/dist/types/agent-bridge.d.ts +42 -0
  614. package/dist/types/agent-bridge.d.ts.map +1 -0
  615. package/dist/types/attachment.d.ts +54 -0
  616. package/dist/types/attachment.d.ts.map +1 -0
  617. package/dist/types/autonomy.d.ts +5 -0
  618. package/dist/types/autonomy.d.ts.map +1 -0
  619. package/dist/types/blocks.d.ts +76 -0
  620. package/dist/types/blocks.d.ts.map +1 -0
  621. package/dist/{compactor-DQLL4HTo.d.ts → types/compactor.d.ts} +5 -7
  622. package/dist/types/compactor.d.ts.map +1 -0
  623. package/dist/{config-MRqn1V-u.d.ts → types/config.d.ts} +344 -355
  624. package/dist/types/config.d.ts.map +1 -0
  625. package/dist/types/context-evidence.d.ts +68 -0
  626. package/dist/types/context-evidence.d.ts.map +1 -0
  627. package/dist/types/context-window.d.ts +35 -0
  628. package/dist/types/context-window.d.ts.map +1 -0
  629. package/dist/{default-config-B79_gJYv.d.ts → types/default-config.d.ts} +10 -11
  630. package/dist/types/default-config.d.ts.map +1 -0
  631. package/dist/types/design-kit.d.ts +91 -0
  632. package/dist/types/design-kit.d.ts.map +1 -0
  633. package/dist/{retry-policy-CQ7KwXJa.d.ts → types/error-handler.d.ts} +5 -12
  634. package/dist/types/error-handler.d.ts.map +1 -0
  635. package/dist/types/errors.d.ts +277 -0
  636. package/dist/types/errors.d.ts.map +1 -0
  637. package/dist/types/hooks.d.ts +167 -0
  638. package/dist/types/hooks.d.ts.map +1 -0
  639. package/dist/types/index.d.ts +40 -244
  640. package/dist/types/index.d.ts.map +1 -0
  641. package/dist/types/index.js +101 -12
  642. package/dist/types/index.js.map +7 -1
  643. package/dist/{input-reader-E-ffP2ee.d.ts → types/input-reader.d.ts} +3 -4
  644. package/dist/types/input-reader.d.ts.map +1 -0
  645. package/dist/{logger-B63L5bTg.d.ts → types/logger.d.ts} +3 -4
  646. package/dist/types/logger.d.ts.map +1 -0
  647. package/dist/types/memory.d.ts +89 -0
  648. package/dist/types/memory.d.ts.map +1 -0
  649. package/dist/types/messages.d.ts +24 -0
  650. package/dist/types/messages.d.ts.map +1 -0
  651. package/dist/types/mode-prompts.d.ts +2 -0
  652. package/dist/types/mode-prompts.d.ts.map +1 -0
  653. package/dist/{mode-CZlO9iU1.d.ts → types/mode.d.ts} +6 -7
  654. package/dist/types/mode.d.ts.map +1 -0
  655. package/dist/types/models-registry.d.ts +105 -0
  656. package/dist/types/models-registry.d.ts.map +1 -0
  657. package/dist/types/multi-agent.d.ts +443 -0
  658. package/dist/types/multi-agent.d.ts.map +1 -0
  659. package/dist/{observability-D-HZN_mF.d.ts → types/observability.d.ts} +17 -13
  660. package/dist/types/observability.d.ts.map +1 -0
  661. package/dist/{path-resolver-CPRj4bFY.d.ts → types/path-resolver.d.ts} +2 -3
  662. package/dist/types/path-resolver.d.ts.map +1 -0
  663. package/dist/{permission-ByDKXEcG.d.ts → types/permission.d.ts} +8 -9
  664. package/dist/types/permission.d.ts.map +1 -0
  665. package/dist/types/plugin.d.ts +385 -0
  666. package/dist/types/plugin.d.ts.map +1 -0
  667. package/dist/types/prompt-registry.d.ts +81 -0
  668. package/dist/types/prompt-registry.d.ts.map +1 -0
  669. package/dist/{prompt-DLd35n4Q.d.ts → types/prompt.d.ts} +14 -15
  670. package/dist/types/prompt.d.ts.map +1 -0
  671. package/dist/{provider-runner-ChL-kVg6.d.ts → types/provider-runner.d.ts} +9 -10
  672. package/dist/types/provider-runner.d.ts.map +1 -0
  673. package/dist/types/provider.d.ts +387 -0
  674. package/dist/types/provider.d.ts.map +1 -0
  675. package/dist/types/renderer.d.ts +23 -0
  676. package/dist/types/renderer.d.ts.map +1 -0
  677. package/dist/types/retry-policy.d.ts +7 -0
  678. package/dist/types/retry-policy.d.ts.map +1 -0
  679. package/dist/types/secret-scrubber.d.ts +5 -0
  680. package/dist/types/secret-scrubber.d.ts.map +1 -0
  681. package/dist/{secret-vault-BAKpgFw_.d.ts → types/secret-vault.d.ts} +13 -7
  682. package/dist/types/secret-vault.d.ts.map +1 -0
  683. package/dist/{selector-D8O6B_Rm.d.ts → types/selector.d.ts} +4 -6
  684. package/dist/types/selector.d.ts.map +1 -0
  685. package/dist/types/session-reader.d.ts +81 -0
  686. package/dist/types/session-reader.d.ts.map +1 -0
  687. package/dist/{session-rewinder-C9HnMkhP.d.ts → types/session-rewinder.d.ts} +5 -6
  688. package/dist/types/session-rewinder.d.ts.map +1 -0
  689. package/dist/types/session.d.ts +650 -0
  690. package/dist/types/session.d.ts.map +1 -0
  691. package/dist/types/side-effect.d.ts +34 -0
  692. package/dist/types/side-effect.d.ts.map +1 -0
  693. package/dist/{skill-DHniprNl.d.ts → types/skill.d.ts} +4 -5
  694. package/dist/types/skill.d.ts.map +1 -0
  695. package/dist/types/slash-command.d.ts +59 -0
  696. package/dist/types/slash-command.d.ts.map +1 -0
  697. package/dist/types/spec.d.ts +77 -0
  698. package/dist/types/spec.d.ts.map +1 -0
  699. package/dist/types/system-prompt-contributor.d.ts +20 -0
  700. package/dist/types/system-prompt-contributor.d.ts.map +1 -0
  701. package/dist/types/system-prompt.d.ts +51 -0
  702. package/dist/types/system-prompt.d.ts.map +1 -0
  703. package/dist/{task-graph-CH3acNQ7.d.ts → types/task-graph.d.ts} +21 -22
  704. package/dist/types/task-graph.d.ts.map +1 -0
  705. package/dist/types/token-counter.d.ts +42 -0
  706. package/dist/types/token-counter.d.ts.map +1 -0
  707. package/dist/types/tool-executor.d.ts +133 -0
  708. package/dist/types/tool-executor.d.ts.map +1 -0
  709. package/dist/types/tool-markers.d.ts +23 -0
  710. package/dist/types/tool-markers.d.ts.map +1 -0
  711. package/dist/types/tool.d.ts +252 -0
  712. package/dist/types/tool.d.ts.map +1 -0
  713. package/dist/types/utility-types.d.ts +31 -0
  714. package/dist/types/utility-types.d.ts.map +1 -0
  715. package/dist/utils/assert-never.d.ts +14 -0
  716. package/dist/utils/assert-never.d.ts.map +1 -0
  717. package/dist/utils/atomic-write.d.ts +12 -0
  718. package/dist/utils/atomic-write.d.ts.map +1 -0
  719. package/dist/utils/child-env.d.ts +67 -0
  720. package/dist/utils/child-env.d.ts.map +1 -0
  721. package/dist/utils/color.d.ts +20 -0
  722. package/dist/utils/color.d.ts.map +1 -0
  723. package/dist/utils/config-json.d.ts +14 -0
  724. package/dist/utils/config-json.d.ts.map +1 -0
  725. package/dist/utils/context-evidence.d.ts +47 -0
  726. package/dist/utils/context-evidence.d.ts.map +1 -0
  727. package/dist/utils/deep-merge.d.ts +64 -0
  728. package/dist/utils/deep-merge.d.ts.map +1 -0
  729. package/dist/utils/diff.d.ts +11 -0
  730. package/dist/utils/diff.d.ts.map +1 -0
  731. package/dist/utils/error.d.ts +2 -3
  732. package/dist/utils/error.d.ts.map +1 -0
  733. package/dist/utils/error.js +3 -3
  734. package/dist/utils/error.js.map +7 -1
  735. package/dist/utils/expect-defined.d.ts +2 -3
  736. package/dist/utils/expect-defined.d.ts.map +1 -0
  737. package/dist/utils/expect-defined.js +3 -3
  738. package/dist/utils/expect-defined.js.map +7 -1
  739. package/dist/utils/glob-expand.d.ts +10 -0
  740. package/dist/utils/glob-expand.d.ts.map +1 -0
  741. package/dist/utils/glob-match.d.ts +4 -0
  742. package/dist/utils/glob-match.d.ts.map +1 -0
  743. package/dist/utils/incoming-images.d.ts +39 -0
  744. package/dist/utils/incoming-images.d.ts.map +1 -0
  745. package/dist/utils/index.d.ts +38 -920
  746. package/dist/utils/index.d.ts.map +1 -0
  747. package/dist/utils/index.js +323 -36
  748. package/dist/utils/index.js.map +7 -1
  749. package/dist/utils/instruction-file.d.ts +3 -0
  750. package/dist/utils/instruction-file.d.ts.map +1 -0
  751. package/dist/utils/ip-guard.d.ts +34 -0
  752. package/dist/utils/ip-guard.d.ts.map +1 -0
  753. package/dist/utils/json-repair.d.ts +23 -0
  754. package/dist/utils/json-repair.d.ts.map +1 -0
  755. package/dist/utils/json-schema-validate.d.ts +42 -0
  756. package/dist/utils/json-schema-validate.d.ts.map +1 -0
  757. package/dist/utils/lru-cache.d.ts +29 -0
  758. package/dist/utils/lru-cache.d.ts.map +1 -0
  759. package/dist/utils/merge-custom-models.d.ts +12 -0
  760. package/dist/utils/merge-custom-models.d.ts.map +1 -0
  761. package/dist/utils/merge-models-payload.d.ts +20 -0
  762. package/dist/utils/merge-models-payload.d.ts.map +1 -0
  763. package/dist/utils/message-invariants.d.ts +22 -0
  764. package/dist/utils/message-invariants.d.ts.map +1 -0
  765. package/dist/utils/newline-normalize.d.ts +5 -0
  766. package/dist/utils/newline-normalize.d.ts.map +1 -0
  767. package/dist/utils/regex-guard.d.ts +21 -0
  768. package/dist/utils/regex-guard.d.ts.map +1 -0
  769. package/dist/utils/safe-json.d.ts +31 -0
  770. package/dist/utils/safe-json.d.ts.map +1 -0
  771. package/dist/utils/session-scoped-path.d.ts +13 -0
  772. package/dist/utils/session-scoped-path.d.ts.map +1 -0
  773. package/dist/utils/sleep.d.ts +5 -0
  774. package/dist/utils/sleep.d.ts.map +1 -0
  775. package/dist/utils/slug.d.ts +13 -0
  776. package/dist/utils/slug.d.ts.map +1 -0
  777. package/dist/utils/string.d.ts +9 -0
  778. package/dist/utils/string.d.ts.map +1 -0
  779. package/dist/utils/task-format.d.ts +22 -0
  780. package/dist/utils/task-format.d.ts.map +1 -0
  781. package/dist/utils/term.d.ts +133 -0
  782. package/dist/utils/term.d.ts.map +1 -0
  783. package/dist/utils/todos-format.d.ts +30 -0
  784. package/dist/utils/todos-format.d.ts.map +1 -0
  785. package/dist/utils/token-estimate.d.ts +112 -0
  786. package/dist/utils/token-estimate.d.ts.map +1 -0
  787. package/dist/utils/tool-description-mode.d.ts +28 -0
  788. package/dist/utils/tool-description-mode.d.ts.map +1 -0
  789. package/dist/utils/tool-output-serializer.d.ts +40 -0
  790. package/dist/utils/tool-output-serializer.d.ts.map +1 -0
  791. package/dist/utils/tool-result-render-mode.d.ts +55 -0
  792. package/dist/utils/tool-result-render-mode.d.ts.map +1 -0
  793. package/dist/utils/tool-subject.d.ts +5 -0
  794. package/dist/utils/tool-subject.d.ts.map +1 -0
  795. package/dist/utils/tool-wire-compact.d.ts +28 -0
  796. package/dist/utils/tool-wire-compact.d.ts.map +1 -0
  797. package/dist/utils/ulid.d.ts +11 -0
  798. package/dist/utils/ulid.d.ts.map +1 -0
  799. package/dist/{wstack-paths-C3K40Qst.d.ts → utils/wstack-paths.d.ts} +7 -8
  800. package/dist/utils/wstack-paths.d.ts.map +1 -0
  801. package/dist/worktree/index.d.ts +2 -0
  802. package/dist/worktree/index.d.ts.map +1 -0
  803. package/dist/{worktree-manager-DzwxKE35.d.ts → worktree/worktree-manager.d.ts} +32 -17
  804. package/dist/worktree/worktree-manager.d.ts.map +1 -0
  805. package/instructions/agents/browser.md +25 -16
  806. package/instructions/autonomy/active-mission.md +2 -4
  807. package/instructions/coordination/subagent-baseline.md +16 -2
  808. package/instructions/leader-after-task.md +3 -1
  809. package/instructions/sections/tool/common-patterns.md +7 -1
  810. package/instructions/sections/tool/delegation-full.md +1 -1
  811. package/instructions/system.md +47 -0
  812. package/package.json +4 -5
  813. package/skills/docker-deploy/SKILL.md +1 -1
  814. package/skills/node-modern/SKILL.md +2 -2
  815. package/skills/plugin-author/SKILL.md +9 -16
  816. package/skills/wrongstack-mailbox/SKILL.md +51 -12
  817. package/dist/dispatcher-types.d-BBeXBQgS.d.ts +0 -66
  818. package/dist/global-mailbox-sZwyI6CS.d.ts +0 -959
  819. package/dist/index--Gm41aBJ.d.ts +0 -671
  820. package/dist/mcp-servers-DEV4s6Ks.d.ts +0 -259
  821. package/dist/multi-agent-coordinator-4RCRZKjN.d.ts +0 -1770
  822. package/dist/null-fleet-bus-CFoNVQEK.d.ts +0 -2127
  823. package/dist/pipeline-DGDyIohT.d.ts +0 -331
  824. package/dist/provider-model-resolve-o2hHLs79.d.ts +0 -263
  825. package/dist/secret-scrubber-3MHDDAtm.d.ts +0 -6
  826. package/dist/secret-vault-DxohkUBc.d.ts +0 -272
  827. package/dist/session-reader-7Esxrkpw.d.ts +0 -155
  828. package/dist/task-format-GX0B1mMC.d.ts +0 -23
  829. package/dist/todos-checkpoint-FY7PjmMx.d.ts +0 -850
  830. package/dist/tool-BNlnIJvo.d.ts +0 -2190
  831. package/dist/tool-executor-CckSCM5E.d.ts +0 -906
@@ -1,29 +1,22 @@
1
- import { randomUUID, createHash, randomBytes } from 'crypto';
2
- import * as fsp9 from 'fs/promises';
3
- import * as path9 from 'path';
4
- import { isAbsolute, resolve } from 'path';
5
- import * as os from 'os';
6
- import { hostname } from 'os';
7
- import { readFileSync, statSync, createReadStream, openSync, writeSync, fsyncSync, closeSync } from 'fs';
8
- import { fileURLToPath } from 'url';
9
- import { EventEmitter } from 'events';
10
- import { listReadyTasks, claimReadyTask, updateTaskAssignment } from '@wrongstack/kanban';
11
- import { createInterface } from 'readline';
12
- import { execFileSync, spawn } from 'child_process';
13
-
14
1
  // src/coordination/agent-bridge.ts
2
+ import { randomUUID } from "node:crypto";
3
+
4
+ // src/utils/atomic-write.ts
5
+ import { randomBytes } from "node:crypto";
6
+ import * as fs from "node:fs/promises";
7
+ import * as path from "node:path";
15
8
  async function atomicWrite(targetPath, content, opts = {}) {
16
- const dir = path9.dirname(targetPath);
17
- await fsp9.mkdir(dir, { recursive: true });
18
- const tmp = path9.join(dir, `.${path9.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
9
+ const dir = path.dirname(targetPath);
10
+ await fs.mkdir(dir, { recursive: true });
11
+ const tmp = path.join(dir, `.${path.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
19
12
  try {
20
13
  if (typeof content === "string") {
21
- await fsp9.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
14
+ await fs.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
22
15
  } else {
23
- await fsp9.writeFile(tmp, content, { flag: "wx" });
16
+ await fs.writeFile(tmp, content, { flag: "wx" });
24
17
  }
25
18
  try {
26
- const fh = await fsp9.open(tmp, "r+");
19
+ const fh = await fs.open(tmp, "r+");
27
20
  try {
28
21
  await fh.sync();
29
22
  } finally {
@@ -33,56 +26,56 @@ async function atomicWrite(targetPath, content, opts = {}) {
33
26
  }
34
27
  let mode;
35
28
  try {
36
- const stat9 = await fsp9.stat(targetPath);
29
+ const stat9 = await fs.stat(targetPath);
37
30
  mode = stat9.mode & 511;
38
31
  } catch {
39
32
  mode = opts.mode;
40
33
  }
41
34
  if (mode !== void 0) {
42
- await fsp9.chmod(tmp, mode);
35
+ await fs.chmod(tmp, mode);
43
36
  }
44
37
  await renameWithRetry(tmp, targetPath);
45
38
  if (mode !== void 0 && process.platform === "win32") {
46
39
  try {
47
- await fsp9.chmod(targetPath, mode);
40
+ await fs.chmod(targetPath, mode);
48
41
  } catch {
49
42
  }
50
43
  }
51
44
  } catch (err) {
52
45
  try {
53
- await fsp9.unlink(tmp);
46
+ await fs.unlink(tmp);
54
47
  } catch {
55
48
  }
56
49
  throw err;
57
50
  }
58
51
  }
59
52
  async function ensureDir(dir) {
60
- await fsp9.mkdir(dir, { recursive: true });
53
+ await fs.mkdir(dir, { recursive: true });
61
54
  }
62
55
  async function withFileLock(targetPath, fn, opts = {}) {
63
- const dir = path9.dirname(targetPath);
64
- await fsp9.mkdir(dir, { recursive: true });
65
- const lockPath = path9.join(dir, `.${path9.basename(targetPath)}.lock`);
56
+ const dir = path.dirname(targetPath);
57
+ await fs.mkdir(dir, { recursive: true });
58
+ const lockPath = path.join(dir, `.${path.basename(targetPath)}.lock`);
66
59
  const timeoutMs = opts.timeoutMs ?? 5e3;
67
60
  const staleMs = opts.staleMs ?? 3e4;
68
61
  const started = Date.now();
69
62
  let handle;
70
63
  for (; ; ) {
71
64
  try {
72
- handle = await fsp9.open(lockPath, "wx");
65
+ handle = await fs.open(lockPath, "wx");
73
66
  await handle.writeFile(`${process.pid}:${Date.now()}`);
74
67
  break;
75
68
  } catch (err) {
76
69
  const code = err.code;
77
70
  if (code === "ENOENT") {
78
- await fsp9.mkdir(dir, { recursive: true });
71
+ await fs.mkdir(dir, { recursive: true });
79
72
  continue;
80
73
  }
81
74
  if (code !== "EEXIST") throw err;
82
75
  try {
83
- const stat9 = await fsp9.stat(lockPath);
76
+ const stat9 = await fs.stat(lockPath);
84
77
  if (Date.now() - stat9.mtimeMs > staleMs) {
85
- await fsp9.unlink(lockPath);
78
+ await fs.unlink(lockPath);
86
79
  continue;
87
80
  }
88
81
  } catch {
@@ -107,7 +100,7 @@ async function withFileLock(targetPath, fn, opts = {}) {
107
100
  } catch {
108
101
  }
109
102
  try {
110
- await fsp9.unlink(lockPath);
103
+ await fs.unlink(lockPath);
111
104
  } catch {
112
105
  }
113
106
  }
@@ -115,14 +108,14 @@ async function withFileLock(targetPath, fn, opts = {}) {
115
108
  var TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
116
109
  async function renameWithRetry(from, to) {
117
110
  if (process.platform !== "win32") {
118
- await fsp9.rename(from, to);
111
+ await fs.rename(from, to);
119
112
  return;
120
113
  }
121
114
  const delays = [10, 25, 60, 120, 250];
122
115
  let lastErr;
123
116
  for (let i = 0; i <= delays.length; i++) {
124
117
  try {
125
- await fsp9.rename(from, to);
118
+ await fs.rename(from, to);
126
119
  return;
127
120
  } catch (err) {
128
121
  lastErr = err;
@@ -210,8 +203,9 @@ function sanitizeNodeOptions(value) {
210
203
  }
211
204
  return kept.join(" ");
212
205
  }
206
+ var gitIdentity = null;
213
207
  function buildChildEnv(optsOrSessionId) {
214
- const opts = {};
208
+ const opts = typeof optsOrSessionId === "string" ? { sessionId: optsOrSessionId } : optsOrSessionId ?? {};
215
209
  const hasOwn = Object.hasOwn(process.env, "WRONGSTACK_CHILD_ENV_PASSTHROUGH");
216
210
  const legacyHasOwn = Object.hasOwn(process.env, "WRONGSTACK_BASH_ENV_PASSTHROUGH");
217
211
  const passthrough = hasOwn && process.env["WRONGSTACK_CHILD_ENV_PASSTHROUGH"] === "1" || legacyHasOwn && process.env["WRONGSTACK_BASH_ENV_PASSTHROUGH"] === "1";
@@ -249,6 +243,16 @@ function buildChildEnv(optsOrSessionId) {
249
243
  out[k] = v;
250
244
  }
251
245
  }
246
+ if (gitIdentity) {
247
+ if (gitIdentity.name) {
248
+ out["GIT_AUTHOR_NAME"] = gitIdentity.name;
249
+ out["GIT_COMMITTER_NAME"] = gitIdentity.name;
250
+ }
251
+ if (gitIdentity.email) {
252
+ out["GIT_AUTHOR_EMAIL"] = gitIdentity.email;
253
+ out["GIT_COMMITTER_EMAIL"] = gitIdentity.email;
254
+ }
255
+ }
252
256
  if (opts.extra) {
253
257
  Object.assign(out, opts.extra);
254
258
  }
@@ -264,12 +268,16 @@ function toErrorMessage(err) {
264
268
  // src/utils/expect-defined.ts
265
269
  function expectDefined(value, label) {
266
270
  if (value === null || value === void 0) {
267
- const err = new Error("Expected value to be defined");
271
+ const err = new Error(label ? `Expected ${label} to be defined` : "Expected value to be defined");
268
272
  err.name = "ExpectDefinedError";
269
273
  throw err;
270
274
  }
271
275
  return value;
272
276
  }
277
+
278
+ // src/utils/glob-expand.ts
279
+ import * as fsp from "node:fs/promises";
280
+ import { isAbsolute, resolve } from "node:path";
273
281
  var GLOB_CHARS = /* @__PURE__ */ new Set(["*", "?", "["]);
274
282
  var IS_WINDOWS = process.platform === "win32";
275
283
  var SEP = IS_WINDOWS ? "\\" : "/";
@@ -321,9 +329,17 @@ function globToRegex(pat) {
321
329
  return new RegExp(re + "$");
322
330
  }
323
331
  function baseDir(pat) {
324
- let i = pat.length - 1;
325
- while (i >= 0 && !GLOB_CHARS.has(expectDefined(pat[i])) && pat[i] !== SEP && pat[i] !== "/") i--;
326
- const cut = i >= 0 ? pat.lastIndexOf(SEP, i) : pat.lastIndexOf("/", i);
332
+ let firstGlob = pat.length;
333
+ for (let i = 0; i < pat.length; i++) {
334
+ if (GLOB_CHARS.has(expectDefined(pat[i]))) {
335
+ firstGlob = i;
336
+ break;
337
+ }
338
+ }
339
+ const cut = Math.max(
340
+ pat.lastIndexOf(SEP, firstGlob - 1),
341
+ pat.lastIndexOf("/", firstGlob - 1)
342
+ );
327
343
  return cut < 0 ? "." : pat.slice(0, cut);
328
344
  }
329
345
  async function expandGlob(pattern) {
@@ -335,7 +351,7 @@ async function expandGlob(pattern) {
335
351
  async function walk(dir, pat) {
336
352
  let entries;
337
353
  try {
338
- entries = await fsp9.readdir(dir);
354
+ entries = await fsp.readdir(dir);
339
355
  } catch {
340
356
  return;
341
357
  }
@@ -357,7 +373,7 @@ async function expandGlob(pattern) {
357
373
  for (const e of entries) {
358
374
  const full = `${dir}${SEP}${e}`;
359
375
  try {
360
- const stat9 = await fsp9.stat(full);
376
+ const stat9 = await fsp.stat(full);
361
377
  if (stat9.isDirectory()) await walk(full, rest);
362
378
  } catch {
363
379
  }
@@ -375,7 +391,7 @@ async function expandGlob(pattern) {
375
391
  if (entries.includes(seg)) {
376
392
  const full = `${dir}${SEP}${seg}`;
377
393
  try {
378
- const stat9 = await fsp9.stat(full);
394
+ const stat9 = await fsp.stat(full);
379
395
  if (stat9.isDirectory()) await walk(full, rest);
380
396
  } catch {
381
397
  }
@@ -513,13 +529,16 @@ function safeStringify(value, pretty = false) {
513
529
  });
514
530
  }
515
531
  }
532
+
533
+ // src/utils/session-scoped-path.ts
534
+ import * as path2 from "node:path";
516
535
  function sessionScopedPath(dir, sessionId, suffix) {
517
536
  if (!sessionId || sessionId.includes("\\") || sessionId.includes("..")) {
518
537
  throw invalid(sessionId);
519
538
  }
520
- const resolved = path9.resolve(dir, `${sessionId}${suffix}`);
521
- const rel = path9.relative(path9.resolve(dir), resolved);
522
- if (rel.startsWith("..") || path9.isAbsolute(rel)) {
539
+ const resolved = path2.resolve(dir, `${sessionId}${suffix}`);
540
+ const rel = path2.relative(path2.resolve(dir), resolved);
541
+ if (rel.startsWith("..") || path2.isAbsolute(rel)) {
523
542
  throw invalid(sessionId);
524
543
  }
525
544
  return resolved;
@@ -532,6 +551,9 @@ function invalid(sessionId) {
532
551
  context: { reason: "path_traversal" }
533
552
  });
534
553
  }
554
+
555
+ // src/utils/ulid.ts
556
+ import { randomBytes as randomBytes2 } from "node:crypto";
535
557
  var ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
536
558
  var ENCODING_LEN = ENCODING.length;
537
559
  var TIME_LEN = 10;
@@ -547,7 +569,7 @@ function encodeTime(now, len) {
547
569
  return str;
548
570
  }
549
571
  function encodeRandom(len) {
550
- const bytes = randomBytes(len);
572
+ const bytes = randomBytes2(len);
551
573
  let str = "";
552
574
  for (let i = 0; i < len; i++) {
553
575
  str += ENCODING[bytes[i] % ENCODING_LEN];
@@ -562,9 +584,14 @@ function ulid(seedTime = Date.now()) {
562
584
  function truncate(s, max) {
563
585
  return s.length <= max ? s : `${s.slice(0, max - 1)}\u2026`;
564
586
  }
587
+
588
+ // src/utils/wstack-paths.ts
589
+ import { createHash } from "node:crypto";
590
+ import * as os from "node:os";
591
+ import * as path3 from "node:path";
565
592
  function projectSlug(absRoot) {
566
- const base = slugify(path9.basename(absRoot));
567
- const hash = createHash("sha256").update(path9.resolve(absRoot)).digest("hex").slice(0, 6);
593
+ const base = slugify(path3.basename(absRoot));
594
+ const hash = createHash("sha256").update(path3.resolve(absRoot)).digest("hex").slice(0, 6);
568
595
  return `${base}-${hash}`;
569
596
  }
570
597
  function slugify(name) {
@@ -572,8 +599,8 @@ function slugify(name) {
572
599
  }
573
600
  function wstackGlobalRoot() {
574
601
  const fromEnv = process.env["WRONGSTACK_HOME"];
575
- if (fromEnv && fromEnv.trim().length > 0) return path9.resolve(fromEnv);
576
- return path9.join(os.homedir(), ".wrongstack");
602
+ if (fromEnv && fromEnv.trim().length > 0) return path3.resolve(fromEnv);
603
+ return path3.join(os.homedir(), ".wrongstack");
577
604
  }
578
605
 
579
606
  // src/types/errors.ts
@@ -586,13 +613,53 @@ var ERROR_CODES = {
586
613
  PROVIDER_SERVER_ERROR: "PROVIDER_SERVER_ERROR",
587
614
  PROVIDER_NETWORK_ERROR: "PROVIDER_NETWORK_ERROR",
588
615
  PROVIDER_CONTEXT_OVERFLOW: "PROVIDER_CONTEXT_OVERFLOW",
616
+ // Tool
617
+ TOOL_NOT_FOUND: "TOOL_NOT_FOUND",
618
+ TOOL_PERMISSION_DENIED: "TOOL_PERMISSION_DENIED",
619
+ TOOL_EXECUTION_FAILED: "TOOL_EXECUTION_FAILED",
620
+ TOOL_TIMEOUT: "TOOL_TIMEOUT",
621
+ TOOL_INPUT_INVALID: "TOOL_INPUT_INVALID",
622
+ // Config
623
+ CONFIG_INVALID: "CONFIG_INVALID",
624
+ CONFIG_NOT_FOUND: "CONFIG_NOT_FOUND",
625
+ CONFIG_PARSE_FAILED: "CONFIG_PARSE_FAILED",
626
+ CONFIG_MIGRATION_NEEDED: "CONFIG_MIGRATION_NEEDED",
627
+ // Plugin
628
+ PLUGIN_LOAD_FAILED: "PLUGIN_LOAD_FAILED",
629
+ PLUGIN_API_MISMATCH: "PLUGIN_API_MISMATCH",
630
+ PLUGIN_MISSING_DEPENDENCY: "PLUGIN_MISSING_DEPENDENCY",
589
631
  // Agent
590
632
  AGENT_ITERATION_LIMIT: "AGENT_ITERATION_LIMIT",
633
+ AGENT_CONTEXT_OVERFLOW: "AGENT_CONTEXT_OVERFLOW",
591
634
  AGENT_ABORTED: "AGENT_ABORTED",
592
635
  AGENT_RUN_FAILED: "AGENT_RUN_FAILED",
636
+ // Session
637
+ SESSION_NOT_FOUND: "SESSION_NOT_FOUND",
638
+ SESSION_CORRUPTED: "SESSION_CORRUPTED",
639
+ SESSION_WRITE_FAILED: "SESSION_WRITE_FAILED",
640
+ // Container / Registry
641
+ CONTAINER_TOKEN_ALREADY_BOUND: "CONTAINER_TOKEN_ALREADY_BOUND",
642
+ CONTAINER_TOKEN_NOT_BOUND: "CONTAINER_TOKEN_NOT_BOUND",
643
+ CONTAINER_CIRCULAR_DEPENDENCY: "CONTAINER_CIRCULAR_DEPENDENCY",
644
+ REGISTRY_DUPLICATE: "REGISTRY_DUPLICATE",
645
+ REGISTRY_NOT_FOUND: "REGISTRY_NOT_FOUND",
646
+ REGISTRY_INVALID: "REGISTRY_INVALID",
593
647
  // File system
594
648
  FS_READ_FAILED: "FS_READ_FAILED",
595
- FS_DELETE_FAILED: "FS_DELETE_FAILED"};
649
+ FS_WRITE_FAILED: "FS_WRITE_FAILED",
650
+ FS_MKDIR_FAILED: "FS_MKDIR_FAILED",
651
+ FS_DELETE_FAILED: "FS_DELETE_FAILED",
652
+ FS_ATOMIC_WRITE_FAILED: "FS_ATOMIC_WRITE_FAILED",
653
+ // SDD (Spec-Driven Development)
654
+ SDD_VALIDATION_FAILED: "SDD_VALIDATION_FAILED",
655
+ SDD_PARSE_FAILED: "SDD_PARSE_FAILED",
656
+ SDD_INVALID_STATE: "SDD_INVALID_STATE",
657
+ SDD_NOT_READY: "SDD_NOT_READY",
658
+ // General
659
+ VALIDATION_ERROR: "VALIDATION_ERROR",
660
+ PARSE_FAILED: "PARSE_FAILED",
661
+ UNKNOWN: "UNKNOWN"
662
+ };
596
663
  var WrongStackError = class extends Error {
597
664
  code;
598
665
  subsystem;
@@ -1271,10 +1338,30 @@ var ToolCapabilities = {
1271
1338
  SHELL_RESTRICTED: "shell.restricted",
1272
1339
  /** Can run a restricted project formatter/linter-style command. */
1273
1340
  SHELL_EXEC: "shell.exec",
1341
+ /** Can read files inside the project (and possibly outside via symlinks if not guarded). */
1342
+ FS_READ: "fs.read",
1274
1343
  /** Can write / modify / delete files inside the project. */
1275
1344
  FS_WRITE: "fs.write",
1276
1345
  /** Can write files outside the current project root (very high risk). */
1277
1346
  FS_WRITE_OUTSIDE_PROJECT: "fs.write.outside-project",
1347
+ /** Can perform outbound network requests. */
1348
+ NET_OUTBOUND: "net.outbound",
1349
+ /** Can mutate in-memory session todos only. */
1350
+ SESSION_TODO: "session.todo",
1351
+ /** Can mutate in-memory session mode only. */
1352
+ SESSION_MODE: "session.mode",
1353
+ /** Can inspect registered tool metadata. */
1354
+ TOOL_META: "tool.meta",
1355
+ /** Can invoke arbitrary registered tools through a meta-tool. */
1356
+ TOOL_MUTATE_ANY: "tool.mutate.any",
1357
+ /** Can read persistent memory. */
1358
+ MEMORY_READ: "memory.read",
1359
+ /** Can write persistent memory. */
1360
+ MEMORY_WRITE: "memory.write",
1361
+ /** Can delete persistent memory. */
1362
+ MEMORY_DELETE: "memory.delete",
1363
+ /** Proxies tools from external MCP servers (unknown capability). */
1364
+ MCP_PROXY: "mcp.proxy",
1278
1365
  /** Can spawn or manage subagents / multi-agent tasks. */
1279
1366
  SUBAGENT_SPAWN: "subagent.spawn",
1280
1367
  /** Can inspect fleet/subagent coordination state without mutating it. */
@@ -1285,9 +1372,43 @@ var ToolCapabilities = {
1285
1372
  COORDINATION_RESULT_SUBMIT: "coordination.result.submit",
1286
1373
  /** Can read or write inter-agent mailbox messages. */
1287
1374
  COORDINATION_MAIL: "coordination.mail",
1375
+ /** Can schedule, inspect, or cancel in-session cron jobs. */
1376
+ COORDINATION_CRON: "coordination.cron",
1377
+ /** Can mutate global or session configuration / trust state. */
1378
+ CONFIG_MUTATE: "config.mutate",
1288
1379
  /** Can install packages or run package managers with side effects. */
1289
1380
  PACKAGE_INSTALL: "package.install"
1290
1381
  };
1382
+ var DANGEROUS_FOR_SUBAGENTS = [
1383
+ ToolCapabilities.SHELL_ARBITRARY,
1384
+ ToolCapabilities.SHELL_RESTRICTED,
1385
+ ToolCapabilities.SHELL_EXEC,
1386
+ ToolCapabilities.FS_WRITE,
1387
+ ToolCapabilities.FS_WRITE_OUTSIDE_PROJECT,
1388
+ ToolCapabilities.TOOL_MUTATE_ANY,
1389
+ ToolCapabilities.MEMORY_WRITE,
1390
+ ToolCapabilities.MEMORY_DELETE,
1391
+ ToolCapabilities.MCP_PROXY,
1392
+ ToolCapabilities.SUBAGENT_SPAWN,
1393
+ ToolCapabilities.CONFIG_MUTATE,
1394
+ ToolCapabilities.PACKAGE_INSTALL
1395
+ ];
1396
+ var WIDE_SUBAGENT_CAPABILITIES = [
1397
+ ToolCapabilities.FS_READ,
1398
+ ToolCapabilities.FS_WRITE,
1399
+ ToolCapabilities.NET_OUTBOUND,
1400
+ ToolCapabilities.SESSION_TODO,
1401
+ ToolCapabilities.TOOL_META,
1402
+ ToolCapabilities.MEMORY_READ,
1403
+ ToolCapabilities.SHELL_ARBITRARY,
1404
+ ToolCapabilities.SHELL_RESTRICTED,
1405
+ ToolCapabilities.SHELL_EXEC,
1406
+ ToolCapabilities.PACKAGE_INSTALL,
1407
+ // Read-only fleet visibility (fleet_status) — peer awareness has no blast
1408
+ // radius and every fleet worker should coordinate around its peers.
1409
+ ToolCapabilities.COORDINATION_FLEET_READ,
1410
+ ToolCapabilities.COORDINATION_RESULT_SUBMIT
1411
+ ];
1291
1412
 
1292
1413
  // src/coordination/subagent-result-tool.ts
1293
1414
  var SUBAGENT_STRUCTURED_REPORT_META_KEY = "subagentStructuredReport";
@@ -1304,9 +1425,11 @@ function normalizeSubagentStructuredReport(value) {
1304
1425
  const filesExamined = stringArray(value["files_examined"]);
1305
1426
  const nextSteps = stringArray(value["suggested_next_steps"]);
1306
1427
  const confidence = value["confidence"];
1428
+ const completion = value["completion"];
1429
+ const remainingWork = optionalString(value["remaining_work"]);
1307
1430
  if (!summary || summary.length > MAX_SUMMARY_CHARS || !findings || findings.length > MAX_FINDINGS || !filesExamined || filesExamined.length > MAX_FILES || !nextSteps || nextSteps.length > MAX_NEXT_STEPS || [...findings, ...filesExamined, ...nextSteps].some(
1308
1431
  (item) => item.trim().length > MAX_ITEM_CHARS
1309
- ) || typeof confidence !== "number" || !Number.isFinite(confidence) || confidence < 0 || confidence > 1) {
1432
+ ) || typeof confidence !== "number" || !Number.isFinite(confidence) || confidence < 0 || confidence > 1 || completion !== void 0 && completion !== "complete" && completion !== "partial" || completion === "partial" && !remainingWork || remainingWork !== void 0 && remainingWork.length > MAX_SUMMARY_CHARS) {
1310
1433
  return void 0;
1311
1434
  }
1312
1435
  const report = {
@@ -1314,7 +1437,9 @@ function normalizeSubagentStructuredReport(value) {
1314
1437
  findings: findings.map((item) => item.trim()).filter(Boolean),
1315
1438
  files_examined: filesExamined.map((item) => item.trim()).filter(Boolean),
1316
1439
  confidence,
1317
- suggested_next_steps: nextSteps.map((item) => item.trim()).filter(Boolean)
1440
+ suggested_next_steps: nextSteps.map((item) => item.trim()).filter(Boolean),
1441
+ ...completion === "complete" || completion === "partial" ? { completion } : {},
1442
+ ...remainingWork ? { remaining_work: remainingWork } : {}
1318
1443
  };
1319
1444
  return JSON.stringify(report).length <= MAX_SUBAGENT_STRUCTURED_REPORT_CHARS ? report : void 0;
1320
1445
  }
@@ -1327,6 +1452,8 @@ function formatSubagentStructuredReport(report) {
1327
1452
  const next = report.suggested_next_steps.length ? report.suggested_next_steps.map((item) => `- ${item}`).join("\n") : "- (none)";
1328
1453
  return [
1329
1454
  report.summary,
1455
+ report.completion ? `Completion: ${report.completion}` : void 0,
1456
+ report.remaining_work ? `Remaining work: ${report.remaining_work}` : void 0,
1330
1457
  `
1331
1458
  Findings:
1332
1459
  ${findings}`,
@@ -1336,7 +1463,7 @@ Files examined: ${files}`,
1336
1463
  `
1337
1464
  Suggested next steps:
1338
1465
  ${next}`
1339
- ].join("\n");
1466
+ ].filter((line) => typeof line === "string").join("\n");
1340
1467
  }
1341
1468
  function makeSubagentResultTool() {
1342
1469
  return {
@@ -1376,6 +1503,16 @@ function makeSubagentResultTool() {
1376
1503
  maxItems: MAX_NEXT_STEPS,
1377
1504
  items: { type: "string" },
1378
1505
  description: "Concrete follow-ups; use an empty array when none remain."
1506
+ },
1507
+ completion: {
1508
+ type: "string",
1509
+ enum: ["complete", "partial"],
1510
+ description: "Use `partial` only when the task is intentionally stopping at a clean checkpoint and another worker should continue."
1511
+ },
1512
+ remaining_work: {
1513
+ type: "string",
1514
+ maxLength: MAX_SUMMARY_CHARS,
1515
+ description: "Concrete work left for a successor. Required by runtime validation when completion is `partial`."
1379
1516
  }
1380
1517
  },
1381
1518
  required: ["summary", "findings", "files_examined", "confidence", "suggested_next_steps"],
@@ -1405,6 +1542,9 @@ function isRecord(value) {
1405
1542
  function nonEmptyString(value) {
1406
1543
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
1407
1544
  }
1545
+ function optionalString(value) {
1546
+ return value === void 0 ? void 0 : nonEmptyString(value);
1547
+ }
1408
1548
  function stringArray(value) {
1409
1549
  return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : void 0;
1410
1550
  }
@@ -1685,6 +1825,12 @@ var TOOLS = {
1685
1825
  /** Web research. */
1686
1826
  research: ["read", "grep", "glob", "search", "fetch", "mailbox"]
1687
1827
  };
1828
+
1829
+ // src/coordination/agents/agent-prompts.ts
1830
+ import { readFileSync, statSync } from "node:fs";
1831
+ import * as os2 from "node:os";
1832
+ import * as path4 from "node:path";
1833
+ import { fileURLToPath } from "node:url";
1688
1834
  var promptCache = /* @__PURE__ */ new Map();
1689
1835
  var candidateCache = /* @__PURE__ */ new Map();
1690
1836
  function agentPrompt(id) {
@@ -1696,7 +1842,7 @@ function agentPrompt(id) {
1696
1842
  let resolved = "";
1697
1843
  for (const dir of agentPromptDirCandidates(envDir)) {
1698
1844
  try {
1699
- resolved = readFileSync(path9.join(dir, fileName), "utf8").trimEnd();
1845
+ resolved = readFileSync(path4.join(dir, fileName), "utf8").trimEnd();
1700
1846
  break;
1701
1847
  } catch {
1702
1848
  }
@@ -1705,20 +1851,20 @@ function agentPrompt(id) {
1705
1851
  return resolved;
1706
1852
  }
1707
1853
  function agentPromptDirCandidates(envDir) {
1708
- const globalRoot = process.env["WRONGSTACK_HOME"] || path9.join(os.homedir(), ".wrongstack");
1854
+ const globalRoot = process.env["WRONGSTACK_HOME"] || path4.join(os2.homedir(), ".wrongstack");
1709
1855
  const candKey = `${envDir}\0${globalRoot}`;
1710
1856
  const cached = candidateCache.get(candKey);
1711
1857
  if (cached !== void 0) return cached;
1712
- const here = path9.dirname(fileURLToPath(import.meta.url));
1858
+ const here = path4.dirname(fileURLToPath(import.meta.url));
1713
1859
  const explicitDir = envDir || void 0;
1714
1860
  const candidates = [
1715
- ...explicitDir ? [path9.resolve(explicitDir)] : [],
1716
- path9.join(globalRoot, "instructions", "agents"),
1717
- path9.resolve(here, "../../../../instructions/agents"),
1718
- path9.resolve(here, "../../../instructions/agents"),
1719
- path9.resolve(here, "../../instructions/agents"),
1720
- path9.resolve(here, "../instructions/agents"),
1721
- path9.resolve(here, "instructions/agents")
1861
+ ...explicitDir ? [path4.resolve(explicitDir)] : [],
1862
+ path4.join(globalRoot, "instructions", "agents"),
1863
+ path4.resolve(here, "../../../../instructions/agents"),
1864
+ path4.resolve(here, "../../../instructions/agents"),
1865
+ path4.resolve(here, "../../instructions/agents"),
1866
+ path4.resolve(here, "../instructions/agents"),
1867
+ path4.resolve(here, "instructions/agents")
1722
1868
  ];
1723
1869
  const ordered = candidates.sort((a, b) => Number(!isDirectory(a)) - Number(!isDirectory(b)));
1724
1870
  candidateCache.set(candKey, ordered);
@@ -3339,7 +3485,12 @@ var BrainDecisionQueue = class {
3339
3485
  if (this.opts.timeoutMs && this.opts.timeoutMs > 0) {
3340
3486
  entry.timer = setTimeout(() => {
3341
3487
  this.pending.delete(request.id);
3342
- resolve9({ type: "deny", reason: "Brain human decision timed out." });
3488
+ resolve9(
3489
+ this.opts.onTimeout?.(request) ?? {
3490
+ type: "deny",
3491
+ reason: "Brain human decision timed out."
3492
+ }
3493
+ );
3343
3494
  }, this.opts.timeoutMs);
3344
3495
  }
3345
3496
  this.pending.set(request.id, entry);
@@ -3356,6 +3507,46 @@ var BrainDecisionQueue = class {
3356
3507
  }
3357
3508
  }
3358
3509
  };
3510
+ function terminalPolicyDecision(request) {
3511
+ const recommended = request.options?.find((option) => option.recommended);
3512
+ if (recommended && (request.risk === "low" || request.risk === "medium")) {
3513
+ return {
3514
+ type: "answer",
3515
+ optionId: recommended.id,
3516
+ text: recommended.label,
3517
+ rationale: `Headless terminal policy: caller-recommended option accepted at ${request.risk} risk (no human available by configuration).`
3518
+ };
3519
+ }
3520
+ if (request.fallback === "continue") {
3521
+ return {
3522
+ type: "answer",
3523
+ text: "Continue with the caller default.",
3524
+ rationale: "Headless terminal policy: request declares continue as its safe fallback."
3525
+ };
3526
+ }
3527
+ return {
3528
+ type: "deny",
3529
+ reason: `Headless terminal policy: no safe automatic option for "${request.question}" (risk: ${request.risk}). The proposed action was not taken.`
3530
+ };
3531
+ }
3532
+ var EscalationRoutingBrainArbiter = class {
3533
+ constructor(inner, queue, getMode) {
3534
+ this.inner = inner;
3535
+ this.queue = queue;
3536
+ this.getMode = getMode;
3537
+ }
3538
+ inner;
3539
+ queue;
3540
+ getMode;
3541
+ async decide(request) {
3542
+ const decision = await this.inner.decide(request);
3543
+ if (decision.type !== "ask_human") return decision;
3544
+ if (this.getMode() === "interactive" && this.queue) {
3545
+ return this.queue.requestHumanDecision(request);
3546
+ }
3547
+ return terminalPolicyDecision(request);
3548
+ }
3549
+ };
3359
3550
  var HumanEscalatingBrainArbiter = class {
3360
3551
  constructor(inner, queue) {
3361
3552
  this.inner = inner;
@@ -3430,27 +3621,342 @@ function formatHumanPrompt(request) {
3430
3621
  lines.push("", `Risk: ${request.risk}`);
3431
3622
  return lines.join("\n");
3432
3623
  }
3624
+
3625
+ // src/coordination/brain-ledger.ts
3626
+ import { appendFile, mkdir as mkdir2, readFile } from "node:fs/promises";
3627
+ import { dirname as dirname3 } from "node:path";
3628
+ var QUESTION_MAX = 200;
3629
+ var DETAIL_MAX = 240;
3630
+ var truncate2 = (s, max) => s === void 0 ? void 0 : s.length > max ? `${s.slice(0, max - 1)}\u2026` : s;
3631
+ function brainDecisionKey(source, question) {
3632
+ const normalized = question.toLowerCase().replace(/[^\s]*\d[^\s]*/g, "#").replace(/\s+/g, " ").trim().slice(0, 100);
3633
+ return `${source ?? "?"}:${normalized}`;
3634
+ }
3635
+ function fmtAge(ms) {
3636
+ const s = Math.max(0, Math.round(ms / 1e3));
3637
+ if (s < 60) return `${s}s ago`;
3638
+ if (s < 3600) return `${Math.round(s / 60)}m ago`;
3639
+ return `${Math.round(s / 3600)}h ago`;
3640
+ }
3641
+ function createLedgerGuardBrainArbiter(opts) {
3642
+ const denyAfter = opts.denyAfter ?? 3;
3643
+ return {
3644
+ async decide(request) {
3645
+ if (denyAfter > 0) {
3646
+ const streak = opts.failureStreakFor(request);
3647
+ if (streak >= denyAfter) {
3648
+ return {
3649
+ type: "deny",
3650
+ reason: `Ledger guard: the last ${streak} approved decisions of this kind all ended in observed failures \u2014 denying deterministically until a success is recorded. (${request.question.slice(0, 120)})`
3651
+ };
3652
+ }
3653
+ }
3654
+ return opts.inner.decide(request);
3655
+ }
3656
+ };
3657
+ }
3658
+ var BrainDecisionLedger = class {
3659
+ constructor(opts) {
3660
+ this.opts = opts;
3661
+ this.maxMemoryEntries = opts.maxMemoryEntries ?? 500;
3662
+ this.retryWindowMs = opts.interventionRetryWindowMs ?? 10 * 6e4;
3663
+ this.now = opts.now ?? Date.now;
3664
+ }
3665
+ opts;
3666
+ entries = [];
3667
+ outcomeByRequest = /* @__PURE__ */ new Map();
3668
+ /** subagentId → decision request ids awaiting that subagent's task result. */
3669
+ pendingBudgetOutcomes = /* @__PURE__ */ new Map();
3670
+ lastInterventionByKind = /* @__PURE__ */ new Map();
3671
+ unsubscribers = [];
3672
+ /** Serialized fire-and-forget writes — awaited by `stop()` (drain). */
3673
+ writeChain = Promise.resolve();
3674
+ dirReady = false;
3675
+ maxMemoryEntries;
3676
+ retryWindowMs;
3677
+ now;
3678
+ /**
3679
+ * Subscribe to the EventBus and seed the in-memory ring from the JSONL
3680
+ * tail. The returned promise resolves once the seed load finished
3681
+ * (best-effort — a missing/corrupt file is an empty history, not an error).
3682
+ */
3683
+ async start() {
3684
+ const { events } = this.opts;
3685
+ this.unsubscribers.push(
3686
+ events.on("brain.decision_answered", (e) => {
3687
+ this.record({
3688
+ at: e.at,
3689
+ sessionId: e.sessionId,
3690
+ requestId: e.request.id,
3691
+ kind: "answered",
3692
+ source: e.request.source,
3693
+ risk: e.request.risk,
3694
+ question: truncate2(e.request.question, QUESTION_MAX),
3695
+ optionId: e.decision.type === "answer" ? e.decision.optionId : void 0,
3696
+ detail: e.decision.type === "answer" ? truncate2(e.decision.rationale ?? e.decision.text, DETAIL_MAX) : void 0
3697
+ });
3698
+ }),
3699
+ events.on("brain.decision_denied", (e) => {
3700
+ this.record({
3701
+ at: e.at,
3702
+ sessionId: e.sessionId,
3703
+ requestId: e.request.id,
3704
+ kind: "denied",
3705
+ source: e.request.source,
3706
+ risk: e.request.risk,
3707
+ question: truncate2(e.request.question, QUESTION_MAX),
3708
+ detail: e.decision.type === "deny" ? truncate2(e.decision.reason, DETAIL_MAX) : void 0
3709
+ });
3710
+ }),
3711
+ events.on("brain.decision_ask_human", (e) => {
3712
+ this.record({
3713
+ at: e.at,
3714
+ sessionId: e.sessionId,
3715
+ requestId: e.request.id,
3716
+ kind: "ask_human",
3717
+ source: e.request.source,
3718
+ risk: e.request.risk,
3719
+ question: truncate2(e.request.question, QUESTION_MAX)
3720
+ });
3721
+ }),
3722
+ events.on("brain.intervention", (e) => {
3723
+ this.record({
3724
+ at: e.at,
3725
+ sessionId: e.sessionId,
3726
+ requestId: e.request.id,
3727
+ kind: "intervention",
3728
+ source: e.request.source,
3729
+ risk: e.request.risk,
3730
+ question: truncate2(`[${e.kind}] ${e.request.question}`, QUESTION_MAX),
3731
+ detail: e.intervened ? "steered" : "observed only"
3732
+ });
3733
+ if (!e.intervened) return;
3734
+ const prev = this.lastInterventionByKind.get(e.kind);
3735
+ if (prev && e.at - prev.at <= this.retryWindowMs) {
3736
+ this.recordOutcome(
3737
+ prev.requestId,
3738
+ "failure",
3739
+ `same signal (${e.kind}) re-triggered ${fmtAge(e.at - prev.at).replace(" ago", " later")}`,
3740
+ e.sessionId
3741
+ );
3742
+ }
3743
+ this.lastInterventionByKind.set(e.kind, { requestId: e.request.id, at: e.at });
3744
+ }),
3745
+ // ── Outcome correlation: budget extensions ────────────────────────
3746
+ events.on("subagent.budget_extended", (e) => {
3747
+ const requestId = `director-budget-${e.subagentId}-${e.kind}`;
3748
+ if (!this.entries.some((entry) => entry.requestId === requestId)) return;
3749
+ let set = this.pendingBudgetOutcomes.get(e.subagentId);
3750
+ if (!set) {
3751
+ set = /* @__PURE__ */ new Set();
3752
+ this.pendingBudgetOutcomes.set(e.subagentId, set);
3753
+ }
3754
+ set.add(requestId);
3755
+ }),
3756
+ events.on("subagent.task_completed", (e) => {
3757
+ const pending = this.pendingBudgetOutcomes.get(e.subagentId);
3758
+ if (!pending) return;
3759
+ this.pendingBudgetOutcomes.delete(e.subagentId);
3760
+ const outcome = e.status === "success" ? "success" : "failure";
3761
+ for (const requestId of pending) {
3762
+ this.recordOutcome(
3763
+ requestId,
3764
+ outcome,
3765
+ `budget-extended subagent's task ${e.status}`,
3766
+ e.sessionId
3767
+ );
3768
+ }
3769
+ })
3770
+ );
3771
+ await this.load();
3772
+ }
3773
+ /** Unsubscribe and drain pending writes. Safe to call twice. */
3774
+ async stop() {
3775
+ for (const off of this.unsubscribers) off();
3776
+ this.unsubscribers.length = 0;
3777
+ await this.writeChain.catch(() => {
3778
+ });
3779
+ }
3780
+ /**
3781
+ * Attach a real-world outcome to an earlier decision. Appended to the
3782
+ * JSONL, folded into future digests, and re-emitted as `brain.outcome`.
3783
+ */
3784
+ recordOutcome(requestId, outcome, detail, sessionId) {
3785
+ this.outcomeByRequest.set(requestId, outcome);
3786
+ this.record({
3787
+ at: this.now(),
3788
+ sessionId,
3789
+ requestId,
3790
+ kind: "outcome",
3791
+ outcome,
3792
+ detail: truncate2(detail, DETAIL_MAX)
3793
+ });
3794
+ this.opts.events.emit("brain.outcome", {
3795
+ sessionId,
3796
+ requestId,
3797
+ outcome,
3798
+ detail,
3799
+ at: this.now()
3800
+ });
3801
+ }
3802
+ /** Last `n` ledger rows, oldest first. */
3803
+ tail(n) {
3804
+ return this.entries.slice(-n);
3805
+ }
3806
+ /**
3807
+ * Consecutive most-recent FAILURE outcomes among answered decisions of
3808
+ * this request's group. Decisions whose outcome is still unknown are
3809
+ * skipped (they neither extend nor break the streak); the first known
3810
+ * SUCCESS ends it. Powers the deterministic ledger guard: "the last K
3811
+ * times we approved this, it went wrong — stop approving".
3812
+ */
3813
+ failureStreakFor(request) {
3814
+ const key = brainDecisionKey(request.source, request.question);
3815
+ let streak = 0;
3816
+ for (let i = this.entries.length - 1; i >= 0; i--) {
3817
+ const e = this.entries[i];
3818
+ if (e?.kind !== "answered" || e.requestId === request.id || e.question === void 0 || brainDecisionKey(e.source, e.question) !== key) {
3819
+ continue;
3820
+ }
3821
+ const outcome = this.outcomeByRequest.get(e.requestId);
3822
+ if (outcome === void 0) continue;
3823
+ if (outcome === "success") break;
3824
+ streak += 1;
3825
+ }
3826
+ return streak;
3827
+ }
3828
+ /**
3829
+ * Short decision-history block for the LLM/council prompt: how similar
3830
+ * past decisions went and — when known — how they turned OUT. Returns
3831
+ * undefined when there is no relevant history (no prompt noise).
3832
+ */
3833
+ digestFor(request) {
3834
+ const key = brainDecisionKey(request.source, request.question);
3835
+ const related = this.entries.filter(
3836
+ (e) => (e.kind === "answered" || e.kind === "denied") && e.requestId !== request.id && e.question !== void 0 && brainDecisionKey(e.source, e.question) === key
3837
+ );
3838
+ if (related.length === 0) return void 0;
3839
+ const recent = related.slice(-5).reverse();
3840
+ const now = this.now();
3841
+ const lines = recent.map((e) => {
3842
+ const what = e.kind === "denied" ? "denied" : e.optionId ? `chose [${e.optionId}]` : "answered";
3843
+ const outcome = this.outcomeByRequest.get(e.requestId);
3844
+ const suffix = outcome === "failure" ? " \u2192 later FAILED" : outcome === "success" ? " \u2192 later succeeded" : "";
3845
+ return `- ${fmtAge(now - e.at)}: ${what}${suffix}`;
3846
+ });
3847
+ const approved = related.filter((e) => e.kind === "answered");
3848
+ const failedAfter = approved.filter(
3849
+ (e) => this.outcomeByRequest.get(e.requestId) === "failure"
3850
+ ).length;
3851
+ const summary = `Summary: ${related.length} similar decision(s); ${approved.length} answered${failedAfter > 0 ? ` (${failedAfter} later failed)` : ""}, ${related.length - approved.length} denied.`;
3852
+ return [...lines, summary].join("\n");
3853
+ }
3854
+ // ── Private ───────────────────────────────────────────────────────────
3855
+ record(entry) {
3856
+ this.entries.push(entry);
3857
+ if (this.entries.length > this.maxMemoryEntries) {
3858
+ const evictedRequestIds = /* @__PURE__ */ new Set();
3859
+ const evictCount = this.entries.length - this.maxMemoryEntries;
3860
+ const evicted = this.entries.splice(0, evictCount);
3861
+ for (const e of evicted) {
3862
+ if (e.requestId) evictedRequestIds.add(e.requestId);
3863
+ }
3864
+ if (evictedRequestIds.size > 0) {
3865
+ const remainingRequestIds = /* @__PURE__ */ new Set();
3866
+ for (const e of this.entries) {
3867
+ if (e.requestId) remainingRequestIds.add(e.requestId);
3868
+ }
3869
+ for (const id of evictedRequestIds) {
3870
+ if (!remainingRequestIds.has(id)) this.outcomeByRequest.delete(id);
3871
+ }
3872
+ }
3873
+ }
3874
+ this.append(entry);
3875
+ }
3876
+ append(entry) {
3877
+ this.writeChain = this.writeChain.then(async () => {
3878
+ if (!this.dirReady) {
3879
+ await mkdir2(dirname3(this.opts.filePath), { recursive: true });
3880
+ this.dirReady = true;
3881
+ }
3882
+ await appendFile(this.opts.filePath, `${JSON.stringify(entry)}
3883
+ `, "utf8");
3884
+ }).catch(() => {
3885
+ });
3886
+ }
3887
+ /** Seed the in-memory ring from the JSONL tail (cross-session learning). */
3888
+ async load() {
3889
+ let raw;
3890
+ try {
3891
+ raw = await readFile(this.opts.filePath, "utf8");
3892
+ } catch {
3893
+ return;
3894
+ }
3895
+ const lines = raw.split("\n").filter((l) => l.trim().length > 0);
3896
+ const seed = [];
3897
+ for (const line of lines.slice(-this.maxMemoryEntries)) {
3898
+ try {
3899
+ const parsed = JSON.parse(line);
3900
+ if (typeof parsed?.requestId === "string" && typeof parsed.at === "number") {
3901
+ seed.push(parsed);
3902
+ }
3903
+ } catch {
3904
+ }
3905
+ }
3906
+ this.entries.unshift(...seed);
3907
+ if (this.entries.length > this.maxMemoryEntries) {
3908
+ this.entries.splice(0, this.entries.length - this.maxMemoryEntries);
3909
+ }
3910
+ for (const e of this.entries) {
3911
+ if (e.kind === "outcome" && e.outcome) this.outcomeByRequest.set(e.requestId, e.outcome);
3912
+ }
3913
+ }
3914
+ };
3915
+
3916
+ // src/coordination/brain-monitor.ts
3917
+ import { randomUUID as randomUUID2 } from "node:crypto";
3918
+ var FILE_EDIT_TOOLS = /* @__PURE__ */ new Set(["edit", "write", "patch", "multi_edit", "multiedit", "str_replace"]);
3919
+ function editedPath(input) {
3920
+ if (!input || typeof input !== "object") return void 0;
3921
+ const r = input;
3922
+ const candidate = r["file_path"] ?? r["path"] ?? r["filePath"] ?? r["file"];
3923
+ return typeof candidate === "string" && candidate.length > 0 ? candidate : void 0;
3924
+ }
3433
3925
  var BrainMonitor = class {
3434
3926
  constructor(opts) {
3435
3927
  this.opts = opts;
3436
3928
  this.toolFailureStreak = opts.toolFailureStreak ?? 3;
3437
3929
  this.errorStormCount = opts.errorStormCount ?? 4;
3438
3930
  this.errorStormWindowMs = opts.errorStormWindowMs ?? 6e4;
3931
+ this.stallMs = opts.stallMs ?? 3e5;
3932
+ this.stallCheckIntervalMs = opts.stallCheckIntervalMs ?? 3e4;
3933
+ this.fileChurnThreshold = opts.fileChurnThreshold ?? 5;
3934
+ this.fileChurnWindowMs = opts.fileChurnWindowMs ?? 6e5;
3439
3935
  this.cooldownMs = opts.cooldownMs ?? 12e4;
3440
3936
  }
3441
3937
  opts;
3442
3938
  failStreaks = /* @__PURE__ */ new Map();
3443
3939
  errorTimestamps = [];
3940
+ editTimestamps = /* @__PURE__ */ new Map();
3444
3941
  lastEngagedAt = /* @__PURE__ */ new Map();
3445
3942
  unsubscribers = [];
3446
3943
  engaging = false;
3944
+ activeRuns = 0;
3945
+ lastProgressAt = 0;
3946
+ stallTimer;
3447
3947
  toolFailureStreak;
3448
3948
  errorStormCount;
3449
3949
  errorStormWindowMs;
3950
+ stallMs;
3951
+ stallCheckIntervalMs;
3952
+ fileChurnThreshold;
3953
+ fileChurnWindowMs;
3450
3954
  cooldownMs;
3451
3955
  start() {
3452
3956
  this.unsubscribers.push(
3453
3957
  this.opts.events.on("tool.executed", (e) => {
3958
+ this.lastProgressAt = Date.now();
3959
+ this.trackFileChurn(e.name, e.ok, e.input);
3454
3960
  if (e.ok) {
3455
3961
  this.failStreaks.delete(e.name);
3456
3962
  return;
@@ -3470,6 +3976,38 @@ var BrainMonitor = class {
3470
3976
  }
3471
3977
  })
3472
3978
  );
3979
+ if (this.stallMs > 0) {
3980
+ this.unsubscribers.push(
3981
+ this.opts.events.on("agent.run.started", () => {
3982
+ this.activeRuns += 1;
3983
+ this.lastProgressAt = Date.now();
3984
+ }),
3985
+ this.opts.events.on("agent.run.completed", () => {
3986
+ this.activeRuns = Math.max(0, this.activeRuns - 1);
3987
+ }),
3988
+ this.opts.events.on("agent.run.error", () => {
3989
+ this.activeRuns = Math.max(0, this.activeRuns - 1);
3990
+ }),
3991
+ this.opts.events.on("iteration.started", () => {
3992
+ this.lastProgressAt = Date.now();
3993
+ })
3994
+ );
3995
+ this.stallTimer = setInterval(() => {
3996
+ if (this.activeRuns === 0 || this.lastProgressAt === 0) return;
3997
+ const idleMs = Date.now() - this.lastProgressAt;
3998
+ if (idleMs < this.stallMs) return;
3999
+ this.lastProgressAt = Date.now();
4000
+ void this.engage("agent_stall", {
4001
+ question: `An active run has made no observable progress (no tool call or iteration) for ${Math.round(idleMs / 6e4)} minute(s). Should the agent be steered before more time is wasted?`,
4002
+ context: [
4003
+ `Active runs: ${this.activeRuns}`,
4004
+ `Idle for: ${Math.round(idleMs / 1e3)}s`,
4005
+ `Stall threshold: ${Math.round(this.stallMs / 1e3)}s`
4006
+ ].join("\n")
4007
+ });
4008
+ }, this.stallCheckIntervalMs);
4009
+ this.stallTimer.unref?.();
4010
+ }
3473
4011
  this.unsubscribers.push(
3474
4012
  this.opts.events.on("error", (e) => {
3475
4013
  const now = Date.now();
@@ -3494,6 +4032,37 @@ var BrainMonitor = class {
3494
4032
  this.unsubscribers.length = 0;
3495
4033
  this.failStreaks.clear();
3496
4034
  this.errorTimestamps = [];
4035
+ this.editTimestamps.clear();
4036
+ if (this.stallTimer) {
4037
+ clearInterval(this.stallTimer);
4038
+ this.stallTimer = void 0;
4039
+ }
4040
+ this.activeRuns = 0;
4041
+ this.lastProgressAt = 0;
4042
+ }
4043
+ /** Sliding-window count of successful edits per file → churn signal. */
4044
+ trackFileChurn(toolName, ok, input) {
4045
+ if (!ok || !FILE_EDIT_TOOLS.has(toolName.toLowerCase())) return;
4046
+ const path20 = editedPath(input);
4047
+ if (!path20) return;
4048
+ const now = Date.now();
4049
+ const stamps = (this.editTimestamps.get(path20) ?? []).filter(
4050
+ (t) => now - t <= this.fileChurnWindowMs
4051
+ );
4052
+ stamps.push(now);
4053
+ if (stamps.length >= this.fileChurnThreshold) {
4054
+ this.editTimestamps.delete(path20);
4055
+ void this.engage("file_churn", {
4056
+ question: `The file "${path20}" has been edited ${stamps.length} times within ${Math.round(this.fileChurnWindowMs / 6e4)} minutes \u2014 the agent may be oscillating (edit/revert loop) instead of converging. Should it be steered?`,
4057
+ context: [
4058
+ `File: ${path20}`,
4059
+ `Edits in window: ${stamps.length}`,
4060
+ `Window: ${Math.round(this.fileChurnWindowMs / 1e3)}s`
4061
+ ].join("\n")
4062
+ });
4063
+ return;
4064
+ }
4065
+ this.editTimestamps.set(path20, stamps);
3497
4066
  }
3498
4067
  async engage(kind, input) {
3499
4068
  const last = this.lastEngagedAt.get(kind) ?? 0;
@@ -3502,7 +4071,7 @@ var BrainMonitor = class {
3502
4071
  this.lastEngagedAt.set(kind, Date.now());
3503
4072
  try {
3504
4073
  const request = {
3505
- id: `brainmon-${randomUUID()}`,
4074
+ id: `brainmon-${randomUUID2()}`,
3506
4075
  sessionId: this.opts.sessionId?.(),
3507
4076
  source: "system",
3508
4077
  question: input.question,
@@ -3565,6 +4134,11 @@ var BrainMonitor = class {
3565
4134
  }
3566
4135
  };
3567
4136
 
4137
+ // src/coordination/collab-debug.ts
4138
+ import { EventEmitter } from "node:events";
4139
+ import * as fsp2 from "node:fs/promises";
4140
+ import { randomUUID as randomUUID3 } from "node:crypto";
4141
+
3568
4142
  // src/coordination/fleet-event-validation.ts
3569
4143
  var ROLE_BY_EVENT = {
3570
4144
  "bug.found": "bug-hunter",
@@ -3721,7 +4295,7 @@ var CollabSession = class extends EventEmitter {
3721
4295
  _timeoutTimer;
3722
4296
  constructor(director, fleetBus, options) {
3723
4297
  super();
3724
- this.sessionId = randomUUID();
4298
+ this.sessionId = randomUUID3();
3725
4299
  this.options = options;
3726
4300
  this.director = director;
3727
4301
  this.fleetBus = fleetBus;
@@ -3783,8 +4357,8 @@ var CollabSession = class extends EventEmitter {
3783
4357
  for (const filePath of allFiles) {
3784
4358
  try {
3785
4359
  const [content, stat9] = await Promise.all([
3786
- fsp9.readFile(filePath, "utf8"),
3787
- fsp9.stat(filePath)
4360
+ fsp2.readFile(filePath, "utf8"),
4361
+ fsp2.stat(filePath)
3788
4362
  ]);
3789
4363
  const ext = filePath.split(".").pop() ?? "";
3790
4364
  const language = ext === "ts" || ext === "tsx" ? "typescript" : ext === "js" || ext === "jsx" ? "javascript" : ext === "md" ? "markdown" : ext === "json" ? "json" : void 0;
@@ -3961,7 +4535,7 @@ var CollabSession = class extends EventEmitter {
3961
4535
  timeoutMs: budget.timeoutMs
3962
4536
  };
3963
4537
  const subagentId = await this.director.spawn(cfg);
3964
- await this.director.assign({ id: randomUUID(), subagentId, description: taskBrief });
4538
+ await this.director.assign({ id: randomUUID3(), subagentId, description: taskBrief });
3965
4539
  return subagentId;
3966
4540
  }
3967
4541
  buildBugHunterTask() {
@@ -4212,7 +4786,7 @@ Emit each evaluation immediately. Do not wait until you have read all reports.`;
4212
4786
  for (const file of this.snapshot.files) {
4213
4787
  if (file.snapshotMtimeMs === void 0 && file.snapshotSizeBytes === void 0) continue;
4214
4788
  try {
4215
- const stat9 = await fsp9.stat(file.path);
4789
+ const stat9 = await fsp2.stat(file.path);
4216
4790
  const mtimeChanged = file.snapshotMtimeMs !== void 0 && stat9.mtimeMs > file.snapshotMtimeMs + 1;
4217
4791
  const sizeChanged = file.snapshotSizeBytes !== void 0 && stat9.size !== file.snapshotSizeBytes;
4218
4792
  if (mtimeChanged || sizeChanged) {
@@ -4289,59 +4863,33 @@ Emit each evaluation immediately. Do not wait until you have read all reports.`;
4289
4863
  }
4290
4864
  };
4291
4865
 
4866
+ // src/coordination/delegate-tool.ts
4867
+ import * as fsp3 from "node:fs/promises";
4868
+ import * as path5 from "node:path";
4869
+ import { randomUUID as randomUUID4 } from "node:crypto";
4870
+
4292
4871
  // src/coordination/fleet.ts
4293
- var AUDIT_LOG_AGENT = {
4294
- id: "audit-log",
4295
- name: "Audit Log",
4296
- role: "audit-log",
4297
- prompt: agentPrompt("audit-log")
4298
- // No hardcoded budgets — the orchestrator (delegate tool or
4299
- // spawn_subagent) decides per-task how much room a subagent gets.
4300
- // A monorepo audit needs hours; a single-file lint check needs
4301
- // seconds. Pinning a number here forces the orchestrator to fight
4302
- // the role's default instead of just asking for what it needs.
4303
- };
4304
- var BUG_HUNTER_AGENT = {
4305
- id: "bug-hunter",
4306
- name: "Bug Hunter",
4307
- role: "bug-hunter",
4308
- prompt: agentPrompt("bug-hunter")
4309
- // Budgets are set by the orchestrator per task — see fleet.ts header.
4310
- };
4311
- var REFACTOR_PLANNER_AGENT = {
4312
- id: "refactor-planner",
4313
- name: "Refactor Planner",
4314
- role: "refactor-planner",
4315
- prompt: agentPrompt("refactor-planner")
4316
- // Budgets are set by the orchestrator per task — see fleet.ts header.
4317
- };
4318
- var SECURITY_SCANNER_AGENT = {
4319
- id: "security-scanner",
4320
- name: "Security Scanner",
4321
- role: "security-scanner",
4322
- prompt: agentPrompt("security-scanner")
4323
- // Budgets are set by the orchestrator per task — see fleet.ts header.
4324
- };
4325
- var SHADOW_AGENT = {
4326
- id: "shadow-agent",
4327
- name: "Shadow",
4328
- role: "shadow-agent",
4329
- prompt: agentPrompt("shadow-agent")
4330
- // Budgets are set by the orchestrator per task — see fleet.ts header.
4331
- };
4332
- var CRITIC_AGENT = {
4333
- id: "critic",
4334
- name: "Critic",
4335
- role: "critic",
4336
- prompt: agentPrompt("critic")
4337
- // Budgets are set by the orchestrator per task — see fleet.ts header.
4338
- };
4872
+ function defineAgent(id, name, promptRole = id, provider) {
4873
+ return {
4874
+ id,
4875
+ name,
4876
+ role: id,
4877
+ prompt: agentPrompt(promptRole),
4878
+ ...provider === void 0 ? {} : { provider }
4879
+ };
4880
+ }
4881
+ var AUDIT_LOG_AGENT = defineAgent("audit-log", "Audit Log");
4882
+ var BUG_HUNTER_AGENT = defineAgent("bug-hunter", "Bug Hunter");
4883
+ var REFACTOR_PLANNER_AGENT = defineAgent("refactor-planner", "Refactor Planner");
4884
+ var SECURITY_SCANNER_AGENT = defineAgent("security-scanner", "Security Scanner");
4885
+ var SHADOW_AGENT = defineAgent("shadow-agent", "Shadow");
4886
+ var CRITIC_AGENT = defineAgent("critic", "Critic");
4339
4887
  var FLEET_ROSTER = {
4340
4888
  "audit-log": AUDIT_LOG_AGENT,
4341
4889
  "bug-hunter": BUG_HUNTER_AGENT,
4342
4890
  "refactor-planner": REFACTOR_PLANNER_AGENT,
4343
4891
  "security-scanner": SECURITY_SCANNER_AGENT,
4344
- "critic": CRITIC_AGENT,
4892
+ critic: CRITIC_AGENT,
4345
4893
  "shadow-agent": SHADOW_AGENT,
4346
4894
  ...Object.fromEntries(
4347
4895
  ALL_AGENT_DEFINITIONS.map((d) => [d.config.role, d.config])
@@ -4353,7 +4901,7 @@ var FLEET_ROSTER_BUDGETS = {
4353
4901
  "bug-hunter": { timeoutMs: 10 * 60 * 60 * 1e3, maxIterations: 8e3, maxToolCalls: 2e4 },
4354
4902
  "refactor-planner": { timeoutMs: 7.5 * 60 * 60 * 1e3, maxIterations: 6e3, maxToolCalls: 18e3 },
4355
4903
  "security-scanner": { timeoutMs: 10 * 60 * 60 * 1e3, maxIterations: 8e3, maxToolCalls: 2e4 },
4356
- "critic": { timeoutMs: 5 * 60 * 60 * 1e3, maxIterations: 4e3, maxToolCalls: 12e3 },
4904
+ critic: { timeoutMs: 5 * 60 * 60 * 1e3, maxIterations: 4e3, maxToolCalls: 12e3 },
4357
4905
  "shadow-agent": {
4358
4906
  idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS,
4359
4907
  maxIterations: 2e3,
@@ -4390,41 +4938,11 @@ function applyRosterBudget(cfg) {
4390
4938
  };
4391
4939
  }
4392
4940
  var ALL_FLEET_AGENTS = Object.values(FLEET_ROSTER);
4393
- var CLINE_AGENT = {
4394
- id: "cline",
4395
- name: "Cline",
4396
- role: "cline",
4397
- prompt: agentPrompt("acp-cline"),
4398
- provider: "acp"
4399
- };
4400
- var GEMINI_CLI_AGENT = {
4401
- id: "gemini-cli",
4402
- name: "Gemini CLI",
4403
- role: "gemini-cli",
4404
- prompt: agentPrompt("acp-gemini-cli"),
4405
- provider: "acp"
4406
- };
4407
- var COPILOT_AGENT = {
4408
- id: "copilot",
4409
- name: "GitHub Copilot",
4410
- role: "copilot",
4411
- prompt: agentPrompt("acp-copilot"),
4412
- provider: "acp"
4413
- };
4414
- var OPENHANDS_AGENT = {
4415
- id: "openhands",
4416
- name: "OpenHands",
4417
- role: "openhands",
4418
- prompt: agentPrompt("acp-openhands"),
4419
- provider: "acp"
4420
- };
4421
- var GOOSE_AGENT = {
4422
- id: "goose",
4423
- name: "Goose",
4424
- role: "goose",
4425
- prompt: agentPrompt("acp-goose"),
4426
- provider: "acp"
4427
- };
4941
+ var CLINE_AGENT = defineAgent("cline", "Cline", "acp-cline", "acp");
4942
+ var GEMINI_CLI_AGENT = defineAgent("gemini-cli", "Gemini CLI", "acp-gemini-cli", "acp");
4943
+ var COPILOT_AGENT = defineAgent("copilot", "GitHub Copilot", "acp-copilot", "acp");
4944
+ var OPENHANDS_AGENT = defineAgent("openhands", "OpenHands", "acp-openhands", "acp");
4945
+ var GOOSE_AGENT = defineAgent("goose", "Goose", "acp-goose", "acp");
4428
4946
  var ACP_AGENTS = [
4429
4947
  CLINE_AGENT,
4430
4948
  GEMINI_CLI_AGENT,
@@ -4432,11 +4950,14 @@ var ACP_AGENTS = [
4432
4950
  OPENHANDS_AGENT,
4433
4951
  GOOSE_AGENT
4434
4952
  ];
4435
- FLEET_ROSTER_BUDGETS["cline"] = { timeoutMs: 10 * 60 * 60 * 1e3, maxIterations: 8e3, maxToolCalls: 2e4 };
4436
- FLEET_ROSTER_BUDGETS["gemini-cli"] = { timeoutMs: 10 * 60 * 60 * 1e3, maxIterations: 8e3, maxToolCalls: 2e4 };
4437
- FLEET_ROSTER_BUDGETS["copilot"] = { timeoutMs: 10 * 60 * 60 * 1e3, maxIterations: 8e3, maxToolCalls: 2e4 };
4438
- FLEET_ROSTER_BUDGETS["openhands"] = { timeoutMs: 10 * 60 * 60 * 1e3, maxIterations: 8e3, maxToolCalls: 2e4 };
4439
- FLEET_ROSTER_BUDGETS["goose"] = { timeoutMs: 10 * 60 * 60 * 1e3, maxIterations: 8e3, maxToolCalls: 2e4 };
4953
+ var ACP_AGENT_BUDGET = {
4954
+ timeoutMs: 10 * 60 * 60 * 1e3,
4955
+ maxIterations: 8e3,
4956
+ maxToolCalls: 2e4
4957
+ };
4958
+ for (const agent of ACP_AGENTS) {
4959
+ FLEET_ROSTER_BUDGETS[agent.role] = { ...ACP_AGENT_BUDGET };
4960
+ }
4440
4961
  var FLEET_ROSTER_WITHACP = {
4441
4962
  ...FLEET_ROSTER,
4442
4963
  ...Object.fromEntries(ACP_AGENTS.map((a) => [a.role, a]))
@@ -4444,7 +4965,7 @@ var FLEET_ROSTER_WITHACP = {
4444
4965
 
4445
4966
  // src/coordination/delegate-tool.ts
4446
4967
  function createDelegateTool(opts) {
4447
- const defaultTimeoutMs = opts.defaultTimeoutMs ?? 30 * 60 * 1e3;
4968
+ const defaultTimeoutMs = opts.defaultTimeoutMs ?? 4 * 60 * 60 * 1e3;
4448
4969
  const rosterIds = opts.roster ? Object.keys(opts.roster) : [];
4449
4970
  const inputSchema = {
4450
4971
  type: "object",
@@ -4503,24 +5024,39 @@ function createDelegateTool(opts) {
4503
5024
  type: "number",
4504
5025
  minimum: 0,
4505
5026
  description: "Maximum estimated USD cost the subagent may incur. Unset = use the role/coordinator default."
5027
+ },
5028
+ maxHandoffs: {
5029
+ type: "number",
5030
+ minimum: 0,
5031
+ maximum: 8,
5032
+ description: "Maximum fresh-worker continuations after partial completion or budget exhaustion. Default 1; set 0 to disable. Each successor receives the prior structured/partial report and is told to continue only the remaining work."
4506
5033
  }
4507
5034
  },
4508
5035
  required: ["task"]
4509
5036
  };
4510
5037
  return {
4511
5038
  name: "delegate",
4512
- description: "Hand a discrete piece of work to a dedicated subagent and wait for its result. The subagent has its own context, its own LLM call, and its own budget \u2014 use this when a task is self-contained, would otherwise blow up your context, or benefits from a specialized role (bug-hunter, security-scanner, refactor-planner, audit-log). For free-form coding tasks (not tied to a pre-defined role), pass `name` + `task` \u2014 the subagent runs as a general-purpose coding agent with a large default budget. YOU decide how big the budget is: pass `timeoutMs`, `maxIterations`, and `maxToolCalls` sized to the actual work. There is no hidden cap forcing a 3-minute / 80-iteration limit \u2014 if a monorepo audit needs 2 hours and 500 tool calls, ask for that. Call multiple delegates in parallel through the provider's parallel-tool-call surface to fan work out across roles.",
4513
- usageHint: "Set `task` to a complete instruction. Either pick `role` from the roster (audit-log, bug-hunter, refactor-planner, security-scanner) or pass `name` to run a free-form coding agent. For non-trivial work, also pass `timeoutMs`, `maxIterations`, and `maxToolCalls`. Returns the subagent's `TaskResult` \u2014 including the textual `result`, iteration count, tool count, and duration. Auto-promotes the host into director mode on first call.",
5039
+ description: "Hand a discrete piece of work to a dedicated subagent and wait for its result. The subagent has its own context, its own LLM call, and a generous, auto-extending budget. If it reports explicit partial completion or still exhausts a recoverable budget, delegate can continue the remaining work with a fresh subagent (bounded by `maxHandoffs`, default 1). Workers may ask the leader to spawn a parallel helper through the mailbox, but cannot recursively spawn agents themselves. Use specialized roster roles when possible; otherwise pass `name` + `task`. Call multiple delegates in parallel through the provider's parallel-tool-call surface for independent work.",
5040
+ usageHint: "Set `task` to a complete instruction. Either pick `role` from the roster or pass `name` for a free-form coding agent. Defaults are intentionally generous; override `timeoutMs`, `maxIterations`, `maxToolCalls`, or `maxHandoffs` only when the task warrants it. Returns the final TaskResult plus a `handoffs` history when fresh workers continued partial work. Requires Director mode in normal CLI sessions.",
4514
5041
  permission: "auto",
4515
5042
  mutating: false,
5043
+ managesOwnTimeout: true,
4516
5044
  capabilities: [ToolCapabilities.SUBAGENT_SPAWN],
4517
5045
  inputSchema,
4518
- async execute(input) {
5046
+ async execute(input, _ctx, execOpts) {
4519
5047
  const sessionId = opts.directorRunId;
5048
+ const abortSignal = execOpts?.signal;
4520
5049
  const i = input ?? {};
4521
5050
  if (typeof i.task !== "string" || !i.task.trim()) {
4522
5051
  return { ok: false, error: "`task` is required." };
4523
5052
  }
5053
+ if (abortSignal?.aborted) {
5054
+ return {
5055
+ ok: false,
5056
+ stopReason: "aborted",
5057
+ error: "Delegation cancelled before spawn \u2014 the run was interrupted."
5058
+ };
5059
+ }
4524
5060
  const target = i.role ?? i.name ?? "subagent";
4525
5061
  try {
4526
5062
  let director = await opts.host.ensureDirector();
@@ -4544,7 +5080,7 @@ function createDelegateTool(opts) {
4544
5080
  error: `Unknown role "${i.role}". Available: ${rosterIds.join(", ") || "(no roster configured)"}.`
4545
5081
  };
4546
5082
  }
4547
- cfg = instantiateRosterConfig(i.role, base);
5083
+ cfg = instantiateRosterConfig(i.role, base, i.timeoutMs, defaultTimeoutMs);
4548
5084
  if (i.systemPromptOverride) cfg.systemPromptOverride = i.systemPromptOverride;
4549
5085
  if (i.provider) cfg.provider = i.provider;
4550
5086
  if (i.model) cfg.model = i.model;
@@ -4583,136 +5119,175 @@ function createDelegateTool(opts) {
4583
5119
  cfg.timeoutMs = Math.max(3e4, timeoutMs - SUBAGENT_TIMEOUT_BUFFER_MS);
4584
5120
  }
4585
5121
  opts.events?.emit("delegate.started", { sessionId, target, task: i.task });
4586
- const subagentId = await director.spawn(cfg);
4587
- const taskId = await director.assign({
4588
- id: `${randomUUID()}`,
4589
- description: i.task,
4590
- subagentId
4591
- });
4592
5122
  const dir = director;
4593
- const result = await new Promise((resolve9) => {
4594
- let settled = false;
4595
- let timer;
4596
- const finish = (value) => {
4597
- if (settled) return;
4598
- settled = true;
4599
- if (timer) clearTimeout(timer);
4600
- offTool();
4601
- offIter();
4602
- offProgress();
4603
- resolve9(value);
4604
- };
4605
- const arm = () => {
4606
- if (timer) clearTimeout(timer);
4607
- timer = setTimeout(() => finish({ __timeout: true }), timeoutMs);
4608
- };
4609
- const bump = (e) => {
4610
- if (e.subagentId === subagentId) arm();
4611
- };
4612
- const offTool = dir.fleet.filter("tool.executed", bump);
4613
- const offIter = dir.fleet.filter("iteration.started", bump);
4614
- const offProgress = dir.fleet.filter("tool.progress", bump);
4615
- arm();
4616
- dir.awaitTasks([taskId]).then((r) => finish(r[0] ?? { __emptyResult: true })).catch(() => finish({ __timeout: true }));
4617
- });
4618
- if ("__timeout" in result) {
4619
- const partial2 = await readSubagentPartial(opts, subagentId);
4620
- opts.events?.emit("delegate.completed", {
4621
- sessionId,
4622
- target,
4623
- task: i.task,
4624
- ok: false,
4625
- status: "host_timeout",
4626
- summary: `[${target}] timed out \u2014 no result within ${Math.round(timeoutMs / 1e3)}s`,
4627
- durationMs: timeoutMs,
4628
- iterations: partial2?.events ?? 0,
4629
- toolCalls: partial2?.toolUsesObserved ?? 0,
5123
+ const maxHandoffs = Math.min(8, Math.max(0, Math.floor(i.maxHandoffs ?? 1)));
5124
+ const handoffs = [];
5125
+ let delegatedTask = i.task;
5126
+ let handoffCount = 0;
5127
+ for (; ; ) {
5128
+ const attemptConfig = handoffCount === 0 ? cfg : freshHandoffConfig(cfg, i.role, handoffCount);
5129
+ const subagentId = await dir.spawn(attemptConfig);
5130
+ const taskId = await dir.assign({
5131
+ id: randomUUID4(),
5132
+ description: delegatedTask,
4630
5133
  subagentId
4631
5134
  });
4632
- return {
4633
- ok: false,
4634
- stopReason: "host_timeout",
4635
- error: `Subagent did not finish within ${timeoutMs}ms.`,
4636
- hint: "Reduce scope of the next delegate, raise timeoutMs, or use spawn_subagent + await_tasks for long-running work.",
5135
+ const result = await awaitDelegateAttempt(
5136
+ dir,
4637
5137
  subagentId,
4638
5138
  taskId,
4639
- partial: partial2
4640
- };
4641
- }
4642
- if ("__emptyResult" in result) {
4643
- const partial2 = await readSubagentPartial(opts, subagentId);
5139
+ timeoutMs,
5140
+ abortSignal
5141
+ );
5142
+ if ("__aborted" in result) {
5143
+ try {
5144
+ await dir.terminate(subagentId);
5145
+ } catch {
5146
+ }
5147
+ const partial2 = await readSubagentPartial(opts, subagentId);
5148
+ opts.events?.emit("delegate.completed", {
5149
+ sessionId,
5150
+ target,
5151
+ task: i.task,
5152
+ ok: false,
5153
+ status: "aborted",
5154
+ summary: `[${target}] aborted \u2014 the run was interrupted`,
5155
+ durationMs: 0,
5156
+ iterations: partial2?.events ?? 0,
5157
+ toolCalls: partial2?.toolUsesObserved ?? 0,
5158
+ subagentId
5159
+ });
5160
+ return {
5161
+ ok: false,
5162
+ stopReason: "aborted",
5163
+ error: "Delegated task aborted \u2014 the run was interrupted.",
5164
+ subagentId,
5165
+ taskId,
5166
+ partial: partial2,
5167
+ ...handoffs.length > 0 ? { handoffs } : {}
5168
+ };
5169
+ }
5170
+ if ("__timeout" in result) {
5171
+ try {
5172
+ await dir.terminate(subagentId);
5173
+ } catch {
5174
+ }
5175
+ const partial2 = await readSubagentPartial(opts, subagentId);
5176
+ opts.events?.emit("delegate.completed", {
5177
+ sessionId,
5178
+ target,
5179
+ task: i.task,
5180
+ ok: false,
5181
+ status: "host_timeout",
5182
+ summary: `[${target}] timed out \u2014 no progress within ${Math.round(timeoutMs / 1e3)}s`,
5183
+ durationMs: timeoutMs,
5184
+ iterations: partial2?.events ?? 0,
5185
+ toolCalls: partial2?.toolUsesObserved ?? 0,
5186
+ subagentId
5187
+ });
5188
+ return {
5189
+ ok: false,
5190
+ stopReason: "host_timeout",
5191
+ error: `Subagent timed out: it did not finish or report progress within ${timeoutMs}ms.`,
5192
+ hint: "Raise timeoutMs for unusually long single operations, or split the remaining work.",
5193
+ subagentId,
5194
+ taskId,
5195
+ partial: partial2,
5196
+ ...handoffs.length > 0 ? { handoffs } : {}
5197
+ };
5198
+ }
5199
+ if ("__emptyResult" in result) {
5200
+ const partial2 = await readSubagentPartial(opts, subagentId);
5201
+ opts.events?.emit("delegate.completed", {
5202
+ sessionId,
5203
+ target,
5204
+ task: i.task,
5205
+ ok: false,
5206
+ status: "empty_result",
5207
+ summary: `[${target}] completed without a task result`,
5208
+ durationMs: 0,
5209
+ iterations: partial2?.events ?? 0,
5210
+ toolCalls: partial2?.toolUsesObserved ?? 0,
5211
+ subagentId
5212
+ });
5213
+ return {
5214
+ ok: false,
5215
+ stopReason: "error",
5216
+ error: "Director returned no task result for the delegated task.",
5217
+ hint: "Check fleet state, then retry or reassign the task.",
5218
+ subagentId,
5219
+ taskId,
5220
+ partial: partial2,
5221
+ ...handoffs.length > 0 ? { handoffs } : {}
5222
+ };
5223
+ }
5224
+ const partial = result.status === "success" ? void 0 : result.partial ? {
5225
+ lastAssistantText: result.partial.text,
5226
+ toolUsesObserved: result.toolCalls,
5227
+ events: result.iterations
5228
+ } : await readSubagentPartial(opts, subagentId);
5229
+ const continuation = continuationFor(result, partial, attemptConfig);
5230
+ if (continuation && handoffCount < maxHandoffs) {
5231
+ handoffs.push({
5232
+ fromSubagentId: result.subagentId,
5233
+ fromTaskId: result.taskId,
5234
+ status: result.status,
5235
+ errorKind: result.error?.kind,
5236
+ summary: continuation.summary,
5237
+ remainingWork: continuation.remainingWork
5238
+ });
5239
+ handoffCount += 1;
5240
+ delegatedTask = buildHandoffTask(i.task, continuation, handoffCount, maxHandoffs);
5241
+ continue;
5242
+ }
5243
+ const incomplete = result.report?.completion === "partial";
5244
+ const baseStopReason = incomplete ? "handoff_limit" : result.status === "success" ? "end_turn" : result.status === "timeout" ? "subagent_timeout" : result.status === "stopped" ? "aborted" : "budget_exhausted";
5245
+ const errorKind = result.error?.kind;
5246
+ const retryable = result.error?.retryable;
5247
+ const backoffMs = result.error?.backoffMs;
5248
+ const summary = incomplete ? `[${target}] partial checkpoint \u2014 handoff limit reached after ${handoffCount} continuation(s)` : buildDelegateSummary(i.role, result);
5249
+ let costUsd;
5250
+ try {
5251
+ costUsd = dir.snapshot().perSubagent[result.subagentId]?.cost;
5252
+ } catch {
5253
+ costUsd = void 0;
5254
+ }
4644
5255
  opts.events?.emit("delegate.completed", {
4645
5256
  sessionId,
4646
5257
  target,
4647
5258
  task: i.task,
4648
- ok: false,
4649
- status: "empty_result",
4650
- summary: `[${target}] completed without a task result`,
4651
- durationMs: 0,
4652
- iterations: partial2?.events ?? 0,
4653
- toolCalls: partial2?.toolUsesObserved ?? 0,
4654
- subagentId
5259
+ ok: result.status === "success" && !incomplete,
5260
+ status: incomplete ? "partial" : result.status,
5261
+ summary,
5262
+ durationMs: result.durationMs,
5263
+ iterations: result.iterations,
5264
+ toolCalls: result.toolCalls,
5265
+ costUsd,
5266
+ subagentId: result.subagentId
4655
5267
  });
4656
5268
  return {
4657
- ok: false,
4658
- stopReason: "error",
4659
- error: "Director returned no task result for the delegated task.",
4660
- hint: "Check fleet state with /fleet status, then retry or reassign the task.",
4661
- subagentId,
4662
- taskId,
4663
- partial: partial2
5269
+ ok: result.status === "success" && !incomplete,
5270
+ status: incomplete ? "partial" : result.status,
5271
+ stopReason: baseStopReason,
5272
+ errorKind,
5273
+ retryable,
5274
+ backoffMs,
5275
+ subagentId: result.subagentId,
5276
+ taskId: result.taskId,
5277
+ result: result.result,
5278
+ report: result.report,
5279
+ error: result.error,
5280
+ iterations: result.iterations,
5281
+ toolCalls: result.toolCalls,
5282
+ durationMs: result.durationMs,
5283
+ ...partial ? { partial } : {},
5284
+ ...handoffs.length > 0 ? { handoffs } : {},
5285
+ ...incomplete ? {
5286
+ hint: "A clean partial checkpoint remains. Reinvoke delegate with a larger maxHandoffs or assign report.remaining_work explicitly."
5287
+ } : hintForKind(errorKind, retryable, backoffMs, partial) ? { hint: hintForKind(errorKind, retryable, backoffMs, partial) } : {},
5288
+ summary
4664
5289
  };
4665
5290
  }
4666
- const baseStopReason = result.status === "success" ? "end_turn" : result.status === "timeout" ? "subagent_timeout" : result.status === "stopped" ? "aborted" : "budget_exhausted";
4667
- const partial = result.status === "success" ? void 0 : result.partial ? {
4668
- lastAssistantText: result.partial.text,
4669
- toolUsesObserved: result.toolCalls,
4670
- events: result.iterations
4671
- } : await readSubagentPartial(opts, subagentId);
4672
- const errorKind = result.error?.kind;
4673
- const retryable = result.error?.retryable;
4674
- const backoffMs = result.error?.backoffMs;
4675
- const summary = buildDelegateSummary(i.role, result);
4676
- let costUsd;
4677
- try {
4678
- costUsd = dir.snapshot().perSubagent[result.subagentId]?.cost;
4679
- } catch {
4680
- costUsd = void 0;
4681
- }
4682
- opts.events?.emit("delegate.completed", {
4683
- sessionId,
4684
- target,
4685
- task: i.task,
4686
- ok: result.status === "success",
4687
- status: result.status,
4688
- summary,
4689
- durationMs: result.durationMs,
4690
- iterations: result.iterations,
4691
- toolCalls: result.toolCalls,
4692
- costUsd,
4693
- subagentId: result.subagentId
4694
- });
4695
- return {
4696
- ok: result.status === "success",
4697
- status: result.status,
4698
- stopReason: baseStopReason,
4699
- errorKind,
4700
- retryable,
4701
- backoffMs,
4702
- subagentId: result.subagentId,
4703
- taskId: result.taskId,
4704
- result: result.result,
4705
- report: result.report,
4706
- error: result.error,
4707
- iterations: result.iterations,
4708
- toolCalls: result.toolCalls,
4709
- durationMs: result.durationMs,
4710
- ...partial ? { partial } : {},
4711
- ...hintForKind(errorKind, retryable, backoffMs, partial) ? { hint: hintForKind(errorKind, retryable, backoffMs, partial) } : {},
4712
- // Summary is included so callers (TUI, CLI renderer) can surface
4713
- // it as a chat history line — the LLM also sees it for continuity.
4714
- summary
4715
- };
4716
5291
  } catch (err) {
4717
5292
  const message = toErrorMessage(err);
4718
5293
  opts.events?.emit("delegate.completed", {
@@ -4735,13 +5310,106 @@ function createDelegateTool(opts) {
4735
5310
  }
4736
5311
  };
4737
5312
  }
4738
- function instantiateRosterConfig(role, base) {
5313
+ async function awaitDelegateAttempt(director, subagentId, taskId, timeoutMs, abortSignal) {
5314
+ return new Promise((resolve9) => {
5315
+ let settled = false;
5316
+ let timer;
5317
+ let offAbort = () => {
5318
+ };
5319
+ const finish = (value) => {
5320
+ if (settled) return;
5321
+ settled = true;
5322
+ if (timer) clearTimeout(timer);
5323
+ offTool();
5324
+ offIter();
5325
+ offProgress();
5326
+ offAbort();
5327
+ resolve9(value);
5328
+ };
5329
+ const arm = () => {
5330
+ if (timer) clearTimeout(timer);
5331
+ timer = setTimeout(() => finish({ __timeout: true }), timeoutMs);
5332
+ };
5333
+ const bump = (event) => {
5334
+ if (event.subagentId === subagentId) arm();
5335
+ };
5336
+ const offTool = director.fleet.filter("tool.executed", bump);
5337
+ const offIter = director.fleet.filter("iteration.started", bump);
5338
+ const offProgress = director.fleet.filter("tool.progress", bump);
5339
+ if (abortSignal) {
5340
+ const onAbort = () => finish({ __aborted: true });
5341
+ abortSignal.addEventListener("abort", onAbort, { once: true });
5342
+ offAbort = () => abortSignal.removeEventListener("abort", onAbort);
5343
+ if (abortSignal.aborted) onAbort();
5344
+ }
5345
+ arm();
5346
+ director.awaitTasks([taskId]).then((results) => finish(results[0] ?? { __emptyResult: true })).catch(() => finish({ __timeout: true }));
5347
+ });
5348
+ }
5349
+ function freshHandoffConfig(cfg, role, handoffCount) {
5350
+ return {
5351
+ ...cfg,
5352
+ id: role ? `${role}-${randomUUID4().slice(0, 8)}` : `${cfg.name.toLowerCase().replace(/[^a-z0-9]+/g, "-") || "subagent"}-handoff-${handoffCount}-${randomUUID4().slice(0, 6)}`
5353
+ };
5354
+ }
5355
+ function continuationFor(result, partial, config) {
5356
+ if (result.report?.completion === "partial" && result.report.remaining_work) {
5357
+ return {
5358
+ summary: result.report.summary,
5359
+ remainingWork: result.report.remaining_work,
5360
+ partialText: typeof result.result === "string" ? result.result : partial?.lastAssistantText
5361
+ };
5362
+ }
5363
+ const budgetKinds = /* @__PURE__ */ new Set([
5364
+ "budget_iterations",
5365
+ "budget_tool_calls",
5366
+ "budget_tokens",
5367
+ "budget_cost",
5368
+ "budget_timeout"
5369
+ ]);
5370
+ const partialText = result.partial?.text ?? partial?.lastAssistantText;
5371
+ const mayHaveIsolatedWrites = config.worktree !== false && config.worktree !== "off" && (!config.tools || config.tools.some(
5372
+ (tool) => ["write", "edit", "replace", "patch", "bash", "exec", "install", "format"].includes(tool)
5373
+ ));
5374
+ if (!mayHaveIsolatedWrites && result.status !== "success" && result.error?.kind && budgetKinds.has(result.error.kind) && partialText) {
5375
+ return {
5376
+ summary: `Prior worker stopped at ${result.error.kind} after ${result.iterations} iterations and ${result.toolCalls} tool calls.`,
5377
+ remainingWork: "Inspect the existing workspace and finish only the work that remains from the original task.",
5378
+ partialText
5379
+ };
5380
+ }
5381
+ return void 0;
5382
+ }
5383
+ function buildHandoffTask(originalTask, continuation, handoffCount, maxHandoffs) {
5384
+ const partial = continuation.partialText?.trim().slice(-6e3);
5385
+ return [
5386
+ `Continue an oversized delegated task as fresh worker ${handoffCount} of ${maxHandoffs}.`,
5387
+ "Do not blindly repeat completed actions. Inspect the current workspace, git diff, tests, and any files named below before changing anything.",
5388
+ 'If the remaining work is still too large, stop at a clean checkpoint and call submit_result with completion="partial" plus concrete remaining_work.',
5389
+ "If parallel help would materially improve the outcome and mail_send is available, send the leader an `ask` that names the exact helper task; do not spawn agents yourself.",
5390
+ `Original task:
5391
+ ${originalTask}`,
5392
+ `Prior checkpoint summary:
5393
+ ${continuation.summary}`,
5394
+ `Remaining work:
5395
+ ${continuation.remainingWork}`,
5396
+ partial ? `Prior worker's last useful output:
5397
+ ${partial}` : ""
5398
+ ].filter(Boolean).join("\n\n");
5399
+ }
5400
+ function instantiateRosterConfig(role, base, requestedTimeoutMs, defaultTimeoutMs) {
4739
5401
  const withBudget = applyRosterBudget({ ...base, role });
5402
+ const rosterTimeoutMs = FLEET_ROSTER_BUDGETS[role]?.timeoutMs;
4740
5403
  return {
4741
5404
  ...withBudget,
5405
+ // Without an explicit host wait, apply the role's tuned multi-hour
5406
+ // wall-clock budget. With an explicit wait, leave this unset so the buffer
5407
+ // logic above derives a slightly shorter child budget without clamping the
5408
+ // role defaults used by ordinary calls.
5409
+ timeoutMs: requestedTimeoutMs === void 0 ? rosterTimeoutMs ?? defaultTimeoutMs : void 0,
4742
5410
  // Give each spawn a fresh id so parallel or repeated delegates
4743
5411
  // can use the same role safely.
4744
- id: `${role}-${randomUUID().slice(0, 8)}`
5412
+ id: `${role}-${randomUUID4().slice(0, 8)}`
4745
5413
  };
4746
5414
  }
4747
5415
  function hintForKind(kind, retryable, backoffMs, partial) {
@@ -4816,13 +5484,13 @@ async function readSubagentPartial(opts, subagentId) {
4816
5484
  if (!opts.sessionsRoot) return void 0;
4817
5485
  const candidates = [];
4818
5486
  if (opts.directorRunId) {
4819
- candidates.push(path9.join(opts.sessionsRoot, opts.directorRunId, `${subagentId}.jsonl`));
5487
+ candidates.push(path5.join(opts.sessionsRoot, opts.directorRunId, `${subagentId}.jsonl`));
4820
5488
  } else {
4821
5489
  try {
4822
- const entries = await fsp9.readdir(opts.sessionsRoot, { withFileTypes: true });
5490
+ const entries = await fsp3.readdir(opts.sessionsRoot, { withFileTypes: true });
4823
5491
  for (const entry of entries) {
4824
5492
  if (entry.isDirectory()) {
4825
- candidates.push(path9.join(opts.sessionsRoot, entry.name, `${subagentId}.jsonl`));
5493
+ candidates.push(path5.join(opts.sessionsRoot, entry.name, `${subagentId}.jsonl`));
4826
5494
  }
4827
5495
  }
4828
5496
  } catch {
@@ -4832,7 +5500,7 @@ async function readSubagentPartial(opts, subagentId) {
4832
5500
  for (const file of candidates) {
4833
5501
  let raw;
4834
5502
  try {
4835
- raw = await fsp9.readFile(file, "utf8");
5503
+ raw = await fsp3.readFile(file, "utf8");
4836
5504
  } catch {
4837
5505
  continue;
4838
5506
  }
@@ -4924,13 +5592,13 @@ function makeDependencyWatcherConfig(opts) {
4924
5592
  const globPatterns = patterns.filter((p) => p.includes("*"));
4925
5593
  const plainPatterns = patterns.filter((p) => !p.includes("*"));
4926
5594
  function matchesPattern(filePath) {
4927
- const basename8 = filePath.split("/").pop()?.split("\\").pop() ?? "";
4928
- if (plainPatterns.includes(basename8)) return true;
5595
+ const basename7 = filePath.split("/").pop()?.split("\\").pop() ?? "";
5596
+ if (plainPatterns.includes(basename7)) return true;
4929
5597
  for (const gp of globPatterns) {
4930
5598
  const regex = new RegExp(
4931
5599
  "^" + gp.replace(/\./g, "\\.").replace(/\*/g, ".*") + "$"
4932
5600
  );
4933
- if (regex.test(basename8)) return true;
5601
+ if (regex.test(basename7)) return true;
4934
5602
  }
4935
5603
  return false;
4936
5604
  }
@@ -5013,10 +5681,19 @@ function attachDepWatcherBridge(opts) {
5013
5681
  unsub();
5014
5682
  };
5015
5683
  }
5684
+
5685
+ // src/coordination/director.ts
5686
+ import { randomUUID as randomUUID7 } from "node:crypto";
5687
+ import * as fsp5 from "node:fs/promises";
5688
+ import * as path7 from "node:path";
5689
+
5690
+ // src/storage/director-state.ts
5691
+ import * as fsp4 from "node:fs/promises";
5692
+ import { hostname } from "node:os";
5016
5693
  async function acquireDirectorStateLock(lockPath, processId = process.pid) {
5017
5694
  let existing;
5018
5695
  try {
5019
- existing = await fsp9.readFile(lockPath, "utf8");
5696
+ existing = await fsp4.readFile(lockPath, "utf8");
5020
5697
  } catch {
5021
5698
  }
5022
5699
  if (existing) {
@@ -5040,7 +5717,7 @@ async function acquireDirectorStateLock(lockPath, processId = process.pid) {
5040
5717
  }
5041
5718
  async function releaseDirectorStateLock(lockPath) {
5042
5719
  try {
5043
- await fsp9.unlink(lockPath);
5720
+ await fsp4.unlink(lockPath);
5044
5721
  } catch {
5045
5722
  }
5046
5723
  }
@@ -5260,6 +5937,11 @@ var FleetContextOverflowError = class extends Error {
5260
5937
  this.observed = observed;
5261
5938
  }
5262
5939
  };
5940
+
5941
+ // src/utils/instruction-file.ts
5942
+ import { readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
5943
+ import * as path6 from "node:path";
5944
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
5263
5945
  var textCache = /* @__PURE__ */ new Map();
5264
5946
  var rootCandidates;
5265
5947
  function readBundledInstructionText(relativePath) {
@@ -5268,7 +5950,7 @@ function readBundledInstructionText(relativePath) {
5268
5950
  let resolved = "";
5269
5951
  for (const root of instructionRootCandidates()) {
5270
5952
  try {
5271
- resolved = readFileSync(path9.join(root, relativePath), "utf8").trimEnd();
5953
+ resolved = readFileSync2(path6.join(root, relativePath), "utf8").trimEnd();
5272
5954
  break;
5273
5955
  } catch {
5274
5956
  }
@@ -5284,18 +5966,18 @@ function renderInstructionTemplate(template, values) {
5284
5966
  }
5285
5967
  function instructionRootCandidates() {
5286
5968
  if (rootCandidates !== void 0) return rootCandidates;
5287
- const here = path9.dirname(fileURLToPath(import.meta.url));
5969
+ const here = path6.dirname(fileURLToPath2(import.meta.url));
5288
5970
  const candidates = [
5289
- path9.resolve(here, "../../instructions"),
5290
- path9.resolve(here, "../instructions"),
5291
- path9.resolve(here, "instructions")
5971
+ path6.resolve(here, "../../instructions"),
5972
+ path6.resolve(here, "../instructions"),
5973
+ path6.resolve(here, "instructions")
5292
5974
  ];
5293
5975
  rootCandidates = candidates.sort((a, b) => Number(!isDirectory2(a)) - Number(!isDirectory2(b)));
5294
5976
  return rootCandidates;
5295
5977
  }
5296
5978
  function isDirectory2(candidate) {
5297
5979
  try {
5298
- return statSync(candidate).isDirectory();
5980
+ return statSync2(candidate).isDirectory();
5299
5981
  } catch {
5300
5982
  return false;
5301
5983
  }
@@ -5362,6 +6044,14 @@ function rosterSummaryFromConfigs(roster) {
5362
6044
  return lines.join("\n");
5363
6045
  }
5364
6046
 
6047
+ // src/coordination/director-tools.ts
6048
+ import { randomUUID as randomUUID5 } from "node:crypto";
6049
+ import {
6050
+ claimReadyTask,
6051
+ listReadyTasks,
6052
+ updateTaskAssignment
6053
+ } from "@wrongstack/kanban";
6054
+
5365
6055
  // src/coordination/dispatcher.ts
5366
6056
  var DEFAULT_DISPATCH_ROLE = "executor";
5367
6057
  var FALLBACK_DEFINITION = {
@@ -5621,7 +6311,7 @@ function instantiateRosterConfig2(role, base) {
5621
6311
  ...base,
5622
6312
  // Roster entries are templates. A director may spawn several
5623
6313
  // workers with the same role, so never reuse the template id.
5624
- id: `${role}-${randomUUID().slice(0, 8)}`
6314
+ id: `${role}-${randomUUID5().slice(0, 8)}`
5625
6315
  };
5626
6316
  }
5627
6317
  function makeQualityGateTool(director, roster) {
@@ -5720,7 +6410,7 @@ function makeQualityGateTool(director, roster) {
5720
6410
  makeQualityGateSubagentConfig("verifier", roster, i.verifierWorktree ?? "auto")
5721
6411
  );
5722
6412
  const taskId = await director.assign({
5723
- id: randomUUID(),
6413
+ id: randomUUID5(),
5724
6414
  subagentId,
5725
6415
  description: buildVerifierTask(i, {
5726
6416
  attempt,
@@ -5738,7 +6428,7 @@ function makeQualityGateTool(director, roster) {
5738
6428
  makeQualityGateSubagentConfig("reviewer", roster, i.reviewerWorktree ?? "off")
5739
6429
  );
5740
6430
  const taskId = await director.assign({
5741
- id: randomUUID(),
6431
+ id: randomUUID5(),
5742
6432
  subagentId,
5743
6433
  description: buildReviewerTask(i, {
5744
6434
  attempt,
@@ -5766,7 +6456,7 @@ function makeQualityGateTool(director, roster) {
5766
6456
  };
5767
6457
  }
5768
6458
  const repairTaskId = await director.assign({
5769
- id: randomUUID(),
6459
+ id: randomUUID5(),
5770
6460
  subagentId: i.repairSubagentId,
5771
6461
  description: buildRepairTask(i, attempts[attempts.length - 1], attempt),
5772
6462
  timeoutMs: i.timeoutMs
@@ -6034,7 +6724,7 @@ function makeAssignTool(director) {
6034
6724
  async execute(input) {
6035
6725
  const i = input;
6036
6726
  const task = {
6037
- id: randomUUID(),
6727
+ id: randomUUID5(),
6038
6728
  description: i.description,
6039
6729
  subagentId: i.subagentId,
6040
6730
  maxToolCalls: i.maxToolCalls,
@@ -6115,7 +6805,7 @@ function makeKanbanQueueTool(director, roster) {
6115
6805
  const leaseTtlMs = Math.max(1e3, Math.floor(i.leaseTtlMs ?? 5 * 60 * 1e3));
6116
6806
  const claimedAt = nowIso();
6117
6807
  const leaseSeeding = {
6118
- leaseId: randomUUID(),
6808
+ leaseId: randomUUID5(),
6119
6809
  claimedAt,
6120
6810
  heartbeatAt: claimedAt,
6121
6811
  leaseExpiresAt: new Date(Date.now() + leaseTtlMs).toISOString()
@@ -6169,7 +6859,7 @@ function makeKanbanQueueTool(director, roster) {
6169
6859
  const config = buildKanbanSubagentConfig(claim.task, i, roster);
6170
6860
  subagentId = await director.spawn(config);
6171
6861
  runTaskId = await director.assign({
6172
- id: randomUUID(),
6862
+ id: randomUUID5(),
6173
6863
  subagentId,
6174
6864
  description: buildKanbanFleetTaskPrompt(claim.board, claim.task, {
6175
6865
  heartbeatIntervalMs: i.heartbeatIntervalMs ?? 6e4,
@@ -7184,6 +7874,7 @@ function fallbackProfileChain(config, profileName) {
7184
7874
  const chain = config.fallbackProfiles?.[profileName];
7185
7875
  return Array.isArray(chain) ? chain.filter((ref) => parseModelRef(ref).model) : [];
7186
7876
  }
7877
+ var DEFAULT_PRIMARY_COOLDOWN_MAX_MS = 10 * 6e4;
7187
7878
 
7188
7879
  // src/coordination/model-matrix.ts
7189
7880
  var MATRIX_PHASE_KEYS = Object.keys(AGENTS_BY_PHASE);
@@ -7357,6 +8048,10 @@ function isValidMatrixKey(key) {
7357
8048
  return matrixKeyKind(key) !== "unknown";
7358
8049
  }
7359
8050
 
8051
+ // src/coordination/multi-agent-coordinator.ts
8052
+ import { randomUUID as randomUUID6 } from "node:crypto";
8053
+ import { EventEmitter as EventEmitter2 } from "node:events";
8054
+
7360
8055
  // src/coordination/coordinator/error-classifier.ts
7361
8056
  function classifySubagentError(err, hints = {}) {
7362
8057
  if (err instanceof AgentError && err.cause) {
@@ -7551,7 +8246,7 @@ function formatRole(role) {
7551
8246
  }
7552
8247
 
7553
8248
  // src/coordination/multi-agent-coordinator.ts
7554
- var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends EventEmitter {
8249
+ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends EventEmitter2 {
7555
8250
  coordinatorId;
7556
8251
  config;
7557
8252
  runner;
@@ -7644,7 +8339,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
7644
8339
  return { ...subagent, name: display };
7645
8340
  }
7646
8341
  async spawn(subagent) {
7647
- const id = subagent.id || randomUUID();
8342
+ const id = subagent.id || randomUUID6();
7648
8343
  const cfg = this.withNickname(subagent, id);
7649
8344
  if (this.subagents.has(id)) {
7650
8345
  throw new Error(`Subagent id "${id}" already exists \u2014 refusing to overwrite`);
@@ -8311,8 +9006,9 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
8311
9006
  }
8312
9007
  const subagent = this.subagents.get(result.subagentId);
8313
9008
  if (subagent && subagent.status !== "stopped") {
8314
- result.status === "failed" || result.status === "timeout";
9009
+ const failed = result.status === "failed" || result.status === "timeout";
8315
9010
  subagent.status = "idle";
9011
+ void failed;
8316
9012
  subagent.currentTask = void 0;
8317
9013
  if (subagent.abortController.signal.aborted) {
8318
9014
  subagent.abortController = new AbortController();
@@ -8701,6 +9397,9 @@ var Director = class _Director {
8701
9397
  subagentBaseline;
8702
9398
  /** See {@link DirectorOptions.taskResultNotifier}. */
8703
9399
  taskResultNotifier;
9400
+ subagentIdleTimeoutMs;
9401
+ retireSubagentOnTaskComplete;
9402
+ subagentIdleTimers = /* @__PURE__ */ new Map();
8704
9403
  /** Absolute path to the fleet's shared scratchpad directory, or null
8705
9404
  * when none was configured. Exposed as a readonly getter for callers
8706
9405
  * that need to surface the path to the user (e.g. the CLI logging
@@ -8796,13 +9495,15 @@ var Director = class _Director {
8796
9495
  /** Prevents large `ask_subagent` answers from bloating the leader's context window. */
8797
9496
  largeAnswerStore;
8798
9497
  constructor(opts) {
8799
- this.id = opts.config.coordinatorId || randomUUID();
9498
+ this.id = opts.config.coordinatorId || randomUUID7();
8800
9499
  this.brain = opts.brain;
8801
9500
  this.manifestPath = opts.manifestPath;
8802
9501
  this.roster = opts.roster;
8803
9502
  this.directorPreamble = opts.directorPreamble ?? DEFAULT_DIRECTOR_PREAMBLE;
8804
9503
  this.subagentBaseline = opts.subagentBaseline ?? DEFAULT_SUBAGENT_BASELINE;
8805
9504
  this.taskResultNotifier = opts.taskResultNotifier;
9505
+ this.subagentIdleTimeoutMs = typeof opts.subagentIdleTimeoutMs === "number" && Number.isFinite(opts.subagentIdleTimeoutMs) && opts.subagentIdleTimeoutMs >= 0 ? opts.subagentIdleTimeoutMs : void 0;
9506
+ this.retireSubagentOnTaskComplete = opts.retireSubagentOnTaskComplete ?? true;
8806
9507
  this.sharedScratchpadPath = opts.sharedScratchpadPath ?? null;
8807
9508
  this.maxSpawns = opts.maxSpawns ?? Number.POSITIVE_INFINITY;
8808
9509
  this.maxSpawnDepth = opts.fleetManager?.maxSpawnDepth ?? resolveMaxSpawnDepth(opts.maxSpawnDepth);
@@ -8813,7 +9514,7 @@ var Director = class _Director {
8813
9514
  this.dispatchClassifier = opts.dispatchClassifier;
8814
9515
  this.maxFleetCostUsd = opts.directorBudget?.maxCostUsd ?? Number.POSITIVE_INFINITY;
8815
9516
  this.maxFleetTokens = opts.directorBudget?.maxTokens ?? Number.POSITIVE_INFINITY;
8816
- this.maxBudgetExtensions = opts.maxBudgetExtensions ?? 5;
9517
+ this.maxBudgetExtensions = opts.maxBudgetExtensions ?? 12;
8817
9518
  this.maxLeaderContextLoad = opts.maxLeaderContextLoad ?? 0.85;
8818
9519
  this.maxContext = opts.maxContext ?? 128e3;
8819
9520
  this.modelMatrix = opts.modelMatrix;
@@ -8833,7 +9534,7 @@ var Director = class _Director {
8833
9534
  this.fleetManager = opts.fleetManager;
8834
9535
  this.logger = opts.logger;
8835
9536
  if (this.sharedScratchpadPath) {
8836
- void fsp9.mkdir(this.sharedScratchpadPath, { recursive: true }).catch((err) => this.logShutdownError("shared_scratchpad_mkdir", err));
9537
+ void fsp5.mkdir(this.sharedScratchpadPath, { recursive: true }).catch((err) => this.logShutdownError("shared_scratchpad_mkdir", err));
8837
9538
  }
8838
9539
  this.transport = new InMemoryBridgeTransport();
8839
9540
  this.bridge = new InMemoryAgentBridge(
@@ -8947,6 +9648,10 @@ var Director = class _Director {
8947
9648
  } else {
8948
9649
  this.scheduleManifest();
8949
9650
  }
9651
+ this.armSubagentIdleRetirement(
9652
+ r.subagentId,
9653
+ this.retireSubagentOnTaskComplete ? 0 : this.subagentIdleTimeoutMs
9654
+ );
8950
9655
  };
8951
9656
  this.coordinator.on("task.completed", this.taskCompletedListener);
8952
9657
  const extendCounts = /* @__PURE__ */ new Map();
@@ -9058,7 +9763,7 @@ var Director = class _Director {
9058
9763
  payload.deny();
9059
9764
  return;
9060
9765
  }
9061
- if (decision.optionId === "stop" || /\bstop\b/i.test(decision.text)) {
9766
+ if (decision.optionId === "stop") {
9062
9767
  payload.deny();
9063
9768
  return;
9064
9769
  }
@@ -9419,6 +10124,7 @@ var Director = class _Director {
9419
10124
  });
9420
10125
  this.scheduleManifest();
9421
10126
  }
10127
+ this.armSubagentIdleRetirement(result.subagentId, this.subagentIdleTimeoutMs);
9422
10128
  return result.subagentId;
9423
10129
  }
9424
10130
  /**
@@ -9441,7 +10147,7 @@ var Director = class _Director {
9441
10147
  );
9442
10148
  }
9443
10149
  const msg = {
9444
- id: randomUUID(),
10150
+ id: randomUUID7(),
9445
10151
  type: "task",
9446
10152
  from: this.id,
9447
10153
  to: subagentId,
@@ -9540,7 +10246,7 @@ var Director = class _Director {
9540
10246
  })),
9541
10247
  usage: this.usage.snapshot()
9542
10248
  };
9543
- await fsp9.mkdir(path9.dirname(this.manifestPath), { recursive: true });
10249
+ await fsp5.mkdir(path7.dirname(this.manifestPath), { recursive: true });
9544
10250
  await atomicWrite(this.manifestPath, JSON.stringify(manifest, null, 2), { mode: 384 });
9545
10251
  return this.manifestPath;
9546
10252
  }
@@ -9567,6 +10273,8 @@ var Director = class _Director {
9567
10273
  this.budgetFilter();
9568
10274
  this.budgetFilter = null;
9569
10275
  }
10276
+ for (const timer of this.subagentIdleTimers.values()) clearTimeout(timer);
10277
+ this.subagentIdleTimers.clear();
9570
10278
  await this.coordinator.stopAll();
9571
10279
  for (const b of this.subagentBridges.values()) {
9572
10280
  await b.stop().catch((err) => this.logShutdownError("subagent_bridge_stop", err));
@@ -9583,6 +10291,7 @@ var Director = class _Director {
9583
10291
  await this.stateCheckpoint.flush().catch((err) => this.logShutdownError("state_checkpoint_flush", err));
9584
10292
  await this.stateCheckpoint.releaseLock().catch((err) => this.logShutdownError("state_checkpoint_lock_release", err));
9585
10293
  }
10294
+ this.largeAnswerStore.clear();
9586
10295
  }
9587
10296
  /**
9588
10297
  * Funnel for shutdown-phase errors. We can't throw — `shutdown()` is
@@ -9606,7 +10315,7 @@ var Director = class _Director {
9606
10315
  * concurrency limit applies — the task may queue before running.
9607
10316
  */
9608
10317
  async assign(task) {
9609
- const taskWithId = task.id ? task : { ...task, id: randomUUID() };
10318
+ const taskWithId = task.id ? task : { ...task, id: randomUUID7() };
9610
10319
  if (this.workCompleteFlag) {
9611
10320
  const synthetic = {
9612
10321
  subagentId: taskWithId.subagentId ?? "unassigned",
@@ -9670,7 +10379,7 @@ var Director = class _Director {
9670
10379
  * rollups and persisted fleet task history.
9671
10380
  */
9672
10381
  async assignInternal(task) {
9673
- const taskWithId = task.id ? task : { ...task, id: randomUUID() };
10382
+ const taskWithId = task.id ? task : { ...task, id: randomUUID7() };
9674
10383
  this.internalTaskIds.add(taskWithId.id);
9675
10384
  try {
9676
10385
  await this.coordinator.assign(taskWithId);
@@ -9784,11 +10493,21 @@ var Director = class _Director {
9784
10493
  }
9785
10494
  async terminate(subagentId) {
9786
10495
  await this.coordinator.stop(subagentId);
10496
+ void this.remove(subagentId).catch(
10497
+ (err) => this.logShutdownError("terminate_remove", err)
10498
+ );
9787
10499
  }
9788
10500
  async terminateAll() {
10501
+ const ids = this.status().subagents.map((s) => s.id);
9789
10502
  await this.coordinator.stopAll();
10503
+ for (const id of ids) {
10504
+ void this.remove(id).catch(
10505
+ (err) => this.logShutdownError("terminate_all_remove", err)
10506
+ );
10507
+ }
9790
10508
  }
9791
10509
  async remove(subagentId) {
10510
+ this.clearSubagentIdleRetirement(subagentId);
9792
10511
  await this.coordinator.remove(subagentId);
9793
10512
  const bridge = this.subagentBridges.get(subagentId);
9794
10513
  if (bridge) {
@@ -9809,6 +10528,34 @@ var Director = class _Director {
9809
10528
  this.taskOwners.delete(subagentId);
9810
10529
  this.taskDescriptions.delete(subagentId);
9811
10530
  }
10531
+ clearSubagentIdleRetirement(subagentId) {
10532
+ const timer = this.subagentIdleTimers.get(subagentId);
10533
+ if (!timer) return;
10534
+ clearTimeout(timer);
10535
+ this.subagentIdleTimers.delete(subagentId);
10536
+ }
10537
+ /**
10538
+ * Arm one lifecycle timer per worker. The callback re-checks coordinator
10539
+ * state so a task assigned in the same turn always wins over retirement.
10540
+ */
10541
+ armSubagentIdleRetirement(subagentId, delayMs) {
10542
+ this.clearSubagentIdleRetirement(subagentId);
10543
+ if (delayMs === void 0) return;
10544
+ const timer = setTimeout(() => {
10545
+ this.subagentIdleTimers.delete(subagentId);
10546
+ const entry = this.coordinator.getStatus().subagents.find((a) => a.id === subagentId);
10547
+ if (entry?.status !== "idle") return;
10548
+ if (this.coordinator.listPendingTasks().some((task) => task.subagentId === subagentId)) {
10549
+ this.armSubagentIdleRetirement(subagentId, this.subagentIdleTimeoutMs);
10550
+ return;
10551
+ }
10552
+ void this.remove(subagentId).catch(
10553
+ (err) => this.logShutdownError("subagent_idle_retirement", err)
10554
+ );
10555
+ }, delayMs);
10556
+ if (typeof timer.unref === "function") timer.unref();
10557
+ this.subagentIdleTimers.set(subagentId, timer);
10558
+ }
9812
10559
  status() {
9813
10560
  const base = this.coordinator.getStatus();
9814
10561
  return {
@@ -9860,10 +10607,10 @@ var Director = class _Director {
9860
10607
  */
9861
10608
  async readSession(subagentId, tail) {
9862
10609
  if (!this.sessionsRoot) return null;
9863
- const filePath = path9.join(this.sessionsRoot, this.directorRunId, `${subagentId}.jsonl`);
10610
+ const filePath = path7.join(this.sessionsRoot, this.directorRunId, `${subagentId}.jsonl`);
9864
10611
  let raw;
9865
10612
  try {
9866
- raw = await fsp9.readFile(filePath, "utf8");
10613
+ raw = await fsp5.readFile(filePath, "utf8");
9867
10614
  } catch {
9868
10615
  return null;
9869
10616
  }
@@ -10028,6 +10775,21 @@ var Director = class _Director {
10028
10775
  }
10029
10776
  };
10030
10777
 
10778
+ // src/coordination/director-session.ts
10779
+ import * as path12 from "node:path";
10780
+
10781
+ // src/storage/session-store.ts
10782
+ import { createHash as createHash4 } from "node:crypto";
10783
+ import { createReadStream } from "node:fs";
10784
+ import * as fsp9 from "node:fs/promises";
10785
+ import * as path11 from "node:path";
10786
+ import { createInterface } from "node:readline";
10787
+
10788
+ // src/storage/file-session-writer.ts
10789
+ import { closeSync, fsyncSync, openSync, writeSync } from "node:fs";
10790
+ import * as fsp6 from "node:fs/promises";
10791
+ import * as path8 from "node:path";
10792
+
10031
10793
  // src/storage/session-helpers.ts
10032
10794
  function userInputTitle(content) {
10033
10795
  const text = typeof content === "string" ? content : content.filter((b) => b.type === "text").map((b) => b.text).join(" ");
@@ -10043,7 +10805,7 @@ var FileSessionWriter = class _FileSessionWriter {
10043
10805
  this.meta = meta;
10044
10806
  this.events = events;
10045
10807
  this.resumed = opts.resumed ?? false;
10046
- this.manifestFile = opts.dir ? path9.join(opts.dir, `${path9.basename(id)}.summary.json`) : "";
10808
+ this.manifestFile = opts.dir ? path8.join(opts.dir, `${path8.basename(id)}.summary.json`) : "";
10047
10809
  this.filePath = opts.filePath ?? "";
10048
10810
  this.secretScrubber = opts.secretScrubber;
10049
10811
  this.checkpointCas = opts.checkpointCas;
@@ -10583,7 +11345,7 @@ var FileSessionWriter = class _FileSessionWriter {
10583
11345
  let removedCount = 0;
10584
11346
  let targetCheckpointSeen = false;
10585
11347
  try {
10586
- fd = await fsp9.open(this.filePath, "r", 384);
11348
+ fd = await fsp6.open(this.filePath, "r", 384);
10587
11349
  while (true) {
10588
11350
  const buf = Buffer.alloc(CHUNK_SIZE);
10589
11351
  const { bytesRead } = await fd.read(buf, 0, CHUNK_SIZE, fileOffset);
@@ -10638,7 +11400,7 @@ var FileSessionWriter = class _FileSessionWriter {
10638
11400
  await this.writeChain;
10639
11401
  await this.handle.close();
10640
11402
  const tmpPath = `${this.filePath}.rewind.tmp`;
10641
- const src = await fsp9.open(this.filePath, "r", 384);
11403
+ const src = await fsp6.open(this.filePath, "r", 384);
10642
11404
  try {
10643
11405
  const statResult = await src.stat();
10644
11406
  const totalSize = statResult.size;
@@ -10654,7 +11416,7 @@ var FileSessionWriter = class _FileSessionWriter {
10654
11416
  } else {
10655
11417
  newlineAfterCheckpoint = totalSize;
10656
11418
  }
10657
- const writeFd = await fsp9.open(tmpPath, "w", 384);
11419
+ const writeFd = await fsp6.open(tmpPath, "w", 384);
10658
11420
  try {
10659
11421
  let readOffset = 0;
10660
11422
  while (readOffset < newlineAfterCheckpoint) {
@@ -10702,11 +11464,11 @@ var FileSessionWriter = class _FileSessionWriter {
10702
11464
  await writeFd.close();
10703
11465
  }
10704
11466
  await src.close();
10705
- await fsp9.rename(tmpPath, this.filePath);
10706
- this.handle = await fsp9.open(this.filePath, "a", 384);
11467
+ await fsp6.rename(tmpPath, this.filePath);
11468
+ this.handle = await fsp6.open(this.filePath, "a", 384);
10707
11469
  } catch (err) {
10708
- await fsp9.unlink(tmpPath).catch(() => void 0);
10709
- this.handle = await fsp9.open(this.filePath, "a", 384).catch(() => this.handle);
11470
+ await fsp6.unlink(tmpPath).catch(() => void 0);
11471
+ this.handle = await fsp6.open(this.filePath, "a", 384).catch(() => this.handle);
10710
11472
  throw err;
10711
11473
  }
10712
11474
  await this.append({
@@ -10741,7 +11503,7 @@ var FileSessionWriter = class _FileSessionWriter {
10741
11503
  provider: this.meta.provider ?? "unknown"
10742
11504
  })}
10743
11505
  `;
10744
- await fsp9.writeFile(this.filePath, record, "utf8");
11506
+ await fsp6.writeFile(this.filePath, record, "utf8");
10745
11507
  this.activePromptIndex = null;
10746
11508
  this.pendingFileSnapshots = [];
10747
11509
  }
@@ -10786,6 +11548,12 @@ var FileSessionWriter = class _FileSessionWriter {
10786
11548
  }
10787
11549
  };
10788
11550
 
11551
+ // src/storage/session-checkpoint-cas.ts
11552
+ import { spawn } from "node:child_process";
11553
+ import { createHash as createHash2, randomUUID as randomUUID8 } from "node:crypto";
11554
+ import * as fsp7 from "node:fs/promises";
11555
+ import * as path9 from "node:path";
11556
+
10789
11557
  // src/storage/storage-concurrency.ts
10790
11558
  async function mapWithConcurrency(items, concurrency, mapper) {
10791
11559
  if (items.length === 0) return [];
@@ -10812,7 +11580,7 @@ var MAX_GIT_OUTPUT = 16 * 1024 * 1024;
10812
11580
  var MAX_BLOB_BYTES = 64 * 1024 * 1024;
10813
11581
  var MAX_CHECKPOINT_BYTES = 512 * 1024 * 1024;
10814
11582
  function sha256(content) {
10815
- return createHash("sha256").update(content).digest("hex");
11583
+ return createHash2("sha256").update(content).digest("hex");
10816
11584
  }
10817
11585
  function isInside(root, target) {
10818
11586
  const relative4 = path9.relative(root, target);
@@ -10868,9 +11636,9 @@ var SessionCheckpointCas = class {
10868
11636
  return null;
10869
11637
  }
10870
11638
  try {
10871
- const stat9 = await fsp9.lstat(absolute);
11639
+ const stat9 = await fsp7.lstat(absolute);
10872
11640
  if (stat9.isSymbolicLink()) {
10873
- const linkTarget = await fsp9.readlink(absolute);
11641
+ const linkTarget = await fsp7.readlink(absolute);
10874
11642
  const resolvedLink = path9.resolve(path9.dirname(absolute), linkTarget);
10875
11643
  if (path9.isAbsolute(linkTarget) || !isInside(this.projectRoot, resolvedLink)) {
10876
11644
  unresolved.push({
@@ -10900,7 +11668,7 @@ var SessionCheckpointCas = class {
10900
11668
  return null;
10901
11669
  }
10902
11670
  scheduledBytes += stat9.size;
10903
- const content = await fsp9.readFile(absolute);
11671
+ const content = await fsp7.readFile(absolute);
10904
11672
  const blobHash = sha256(content);
10905
11673
  await this.putBlob(blobHash, content);
10906
11674
  return { path: relative4, state: "file", blobHash, mode: stat9.mode & 511 };
@@ -10938,7 +11706,7 @@ var SessionCheckpointCas = class {
10938
11706
  if (target === this.projectRoot) {
10939
11707
  throw new Error("Refusing to materialize a workspace checkpoint over the parent project root");
10940
11708
  }
10941
- const targetStat = await fsp9.stat(target);
11709
+ const targetStat = await fsp7.stat(target);
10942
11710
  if (!targetStat.isDirectory()) throw new Error(`Checkpoint target is not a directory: ${target}`);
10943
11711
  const manifest = await this.loadManifest(checkpoint.manifestHash);
10944
11712
  if (manifest.baseHead !== checkpoint.baseHead.toLowerCase() || manifest.coverage !== checkpoint.coverage || manifest.entries.length !== checkpoint.entryCount || manifest.unresolved.length !== checkpoint.unresolvedCount) {
@@ -10965,7 +11733,7 @@ var SessionCheckpointCas = class {
10965
11733
  if (targetStatus.stdout.length > 0) {
10966
11734
  throw new Error("Checkpoint target must be a clean checkout before materialization");
10967
11735
  }
10968
- const realTarget = await fsp9.realpath(target);
11736
+ const realTarget = await fsp7.realpath(target);
10969
11737
  const writtenFiles = [];
10970
11738
  const deletedFiles = [];
10971
11739
  const errors = [];
@@ -10995,24 +11763,24 @@ var SessionCheckpointCas = class {
10995
11763
  for (const { entry, output, content } of prepared) {
10996
11764
  try {
10997
11765
  if (entry.state === "absent") {
10998
- await fsp9.unlink(output).catch((err) => {
11766
+ await fsp7.unlink(output).catch((err) => {
10999
11767
  if (err.code !== "ENOENT") throw err;
11000
11768
  });
11001
11769
  deletedFiles.push(entry.path);
11002
11770
  continue;
11003
11771
  }
11004
11772
  if (entry.state === "symlink") {
11005
- await fsp9.unlink(output).catch((err) => {
11773
+ await fsp7.unlink(output).catch((err) => {
11006
11774
  if (err.code !== "ENOENT") throw err;
11007
11775
  });
11008
- await fsp9.mkdir(path9.dirname(output), { recursive: true });
11009
- await fsp9.symlink(entry.linkTarget, output);
11776
+ await fsp7.mkdir(path9.dirname(output), { recursive: true });
11777
+ await fsp7.symlink(entry.linkTarget, output);
11010
11778
  writtenFiles.push(entry.path);
11011
11779
  continue;
11012
11780
  }
11013
11781
  if (!content) throw new Error("CAS blob was not prepared");
11014
11782
  await atomicWrite(output, content, { mode: entry.mode });
11015
- await fsp9.chmod(output, entry.mode).catch(() => void 0);
11783
+ await fsp7.chmod(output, entry.mode).catch(() => void 0);
11016
11784
  writtenFiles.push(entry.path);
11017
11785
  } catch (err) {
11018
11786
  errors.push(`${entry.path}: ${toErrorMessage(err)}`);
@@ -11030,9 +11798,9 @@ var SessionCheckpointCas = class {
11030
11798
  }
11031
11799
  async putBlob(hash, content) {
11032
11800
  const target = this.objectPath(hash);
11033
- await fsp9.mkdir(path9.dirname(target), { recursive: true });
11801
+ await fsp7.mkdir(path9.dirname(target), { recursive: true });
11034
11802
  try {
11035
- const existing = await fsp9.readFile(target);
11803
+ const existing = await fsp7.readFile(target);
11036
11804
  if (sha256(existing) !== hash) throw new Error(`Corrupt CAS object collision: ${hash}`);
11037
11805
  return;
11038
11806
  } catch (err) {
@@ -11040,30 +11808,30 @@ var SessionCheckpointCas = class {
11040
11808
  }
11041
11809
  const temp = path9.join(
11042
11810
  path9.dirname(target),
11043
- `.${path9.basename(target)}.${process.pid}.${randomUUID()}.tmp`
11811
+ `.${path9.basename(target)}.${process.pid}.${randomUUID8()}.tmp`
11044
11812
  );
11045
11813
  let handle;
11046
11814
  try {
11047
- handle = await fsp9.open(temp, "wx", 384);
11815
+ handle = await fsp7.open(temp, "wx", 384);
11048
11816
  await handle.writeFile(content);
11049
11817
  await handle.sync();
11050
11818
  await handle.close();
11051
11819
  handle = void 0;
11052
11820
  try {
11053
- await fsp9.link(temp, target);
11821
+ await fsp7.link(temp, target);
11054
11822
  } catch (err) {
11055
11823
  if (err.code !== "EEXIST") throw err;
11056
- const existing = await fsp9.readFile(target);
11824
+ const existing = await fsp7.readFile(target);
11057
11825
  if (sha256(existing) !== hash) throw new Error(`Corrupt CAS object collision: ${hash}`);
11058
11826
  }
11059
11827
  } finally {
11060
11828
  await handle?.close().catch(() => void 0);
11061
- await fsp9.unlink(temp).catch(() => void 0);
11829
+ await fsp7.unlink(temp).catch(() => void 0);
11062
11830
  }
11063
11831
  }
11064
11832
  async putManifest(hash, encoded) {
11065
11833
  const target = this.manifestPath(hash);
11066
- const existing = await fsp9.readFile(target).catch(() => null);
11834
+ const existing = await fsp7.readFile(target).catch(() => null);
11067
11835
  if (existing) {
11068
11836
  if (sha256(existing) !== hash) throw new Error(`Corrupt checkpoint manifest collision: ${hash}`);
11069
11837
  return;
@@ -11071,12 +11839,12 @@ var SessionCheckpointCas = class {
11071
11839
  await atomicWrite(target, encoded, { mode: 384 });
11072
11840
  }
11073
11841
  async readBlob(hash) {
11074
- const content = await fsp9.readFile(this.objectPath(hash));
11842
+ const content = await fsp7.readFile(this.objectPath(hash));
11075
11843
  if (sha256(content) !== hash) throw new Error(`CAS blob integrity check failed: ${hash}`);
11076
11844
  return content;
11077
11845
  }
11078
11846
  async loadManifest(hash) {
11079
- const raw = await fsp9.readFile(this.manifestPath(hash));
11847
+ const raw = await fsp7.readFile(this.manifestPath(hash));
11080
11848
  if (sha256(raw) !== hash) throw new Error(`Checkpoint manifest integrity check failed: ${hash}`);
11081
11849
  const parsed = JSON.parse(raw.toString("utf8"));
11082
11850
  if (parsed.version !== 1 || typeof parsed.baseHead !== "string" || parsed.coverage !== "git-head-plus-dirty" || !Array.isArray(parsed.entries) || !Array.isArray(parsed.unresolved)) {
@@ -11106,7 +11874,7 @@ var SessionCheckpointCas = class {
11106
11874
  let probe = output;
11107
11875
  for (; ; ) {
11108
11876
  try {
11109
- const real = await fsp9.realpath(probe);
11877
+ const real = await fsp7.realpath(probe);
11110
11878
  if (!isInside(realTarget, real)) throw new Error("path resolves through a symlink outside checkpoint target");
11111
11879
  return output;
11112
11880
  } catch (err) {
@@ -11166,12 +11934,17 @@ function defaultRunGit(args, cwd) {
11166
11934
  child.on("close", (code) => resolve9(result(code ?? 1)));
11167
11935
  });
11168
11936
  }
11937
+
11938
+ // src/storage/session-resume-validation.ts
11939
+ import { createHash as createHash3 } from "node:crypto";
11940
+ import * as fsp8 from "node:fs/promises";
11941
+ import * as path10 from "node:path";
11169
11942
  var MAX_REVALIDATE_BYTES = 5 * 1024 * 1024;
11170
11943
  var VALIDATION_CONCURRENCY = 8;
11171
11944
  var NOTICE_PATH_LIMIT = 20;
11172
11945
  function isInside2(root, target) {
11173
- const relative4 = path9.relative(root, target);
11174
- return relative4 === "" || !relative4.startsWith("..") && !path9.isAbsolute(relative4);
11946
+ const relative4 = path10.relative(root, target);
11947
+ return relative4 === "" || !relative4.startsWith("..") && !path10.isAbsolute(relative4);
11175
11948
  }
11176
11949
  function errno(err) {
11177
11950
  return err && typeof err === "object" && "code" in err ? String(err.code) : void 0;
@@ -11182,7 +11955,7 @@ function latestObservations(events, projectRoot) {
11182
11955
  if (event.type !== "file_observation" || typeof event.path !== "string" || event.path.length === 0 || typeof event.hash !== "string" || !/^[a-f\d]{64}$/i.test(event.hash)) {
11183
11956
  continue;
11184
11957
  }
11185
- const normalized = path9.resolve(projectRoot, event.path);
11958
+ const normalized = path10.resolve(projectRoot, event.path);
11186
11959
  latest.set(normalized, {
11187
11960
  path: normalized,
11188
11961
  hash: event.hash.toLowerCase(),
@@ -11206,7 +11979,7 @@ async function validateOne(observation, lexicalRoot, realRoot) {
11206
11979
  }
11207
11980
  let realFile;
11208
11981
  try {
11209
- realFile = await fsp9.realpath(observation.path);
11982
+ realFile = await fsp8.realpath(observation.path);
11210
11983
  } catch (err) {
11211
11984
  if (errno(err) === "ENOENT") return { ...base, status: "deleted" };
11212
11985
  return { ...base, status: "unreadable", detail: toErrorMessage(err) };
@@ -11219,7 +11992,7 @@ async function validateOne(observation, lexicalRoot, realRoot) {
11219
11992
  };
11220
11993
  }
11221
11994
  try {
11222
- const stat9 = await fsp9.stat(realFile);
11995
+ const stat9 = await fsp8.stat(realFile);
11223
11996
  if (!stat9.isFile()) {
11224
11997
  return { ...base, status: "unreadable", detail: "Path is no longer a regular file." };
11225
11998
  }
@@ -11230,8 +12003,8 @@ async function validateOne(observation, lexicalRoot, realRoot) {
11230
12003
  detail: `File now exceeds the ${MAX_REVALIDATE_BYTES}-byte validation limit.`
11231
12004
  };
11232
12005
  }
11233
- const content = await fsp9.readFile(realFile, "utf8");
11234
- const actualHash = createHash("sha256").update(content, "utf8").digest("hex");
12006
+ const content = await fsp8.readFile(realFile, "utf8");
12007
+ const actualHash = createHash3("sha256").update(content, "utf8").digest("hex");
11235
12008
  if (actualHash === observation.hash) return null;
11236
12009
  return { ...base, status: "modified", actualHash };
11237
12010
  } catch (err) {
@@ -11240,8 +12013,8 @@ async function validateOne(observation, lexicalRoot, realRoot) {
11240
12013
  }
11241
12014
  }
11242
12015
  async function validateResumeFileObservations(events, projectRoot) {
11243
- const lexicalRoot = path9.resolve(projectRoot);
11244
- const realRoot = await fsp9.realpath(lexicalRoot).catch(() => lexicalRoot);
12016
+ const lexicalRoot = path10.resolve(projectRoot);
12017
+ const realRoot = await fsp8.realpath(lexicalRoot).catch(() => lexicalRoot);
11245
12018
  const observations = latestObservations(events, lexicalRoot);
11246
12019
  const results = await mapWithConcurrency(
11247
12020
  observations,
@@ -11256,9 +12029,9 @@ async function validateResumeFileObservations(events, projectRoot) {
11256
12029
  }
11257
12030
  function formatResumeValidationNotice(validation, projectRoot) {
11258
12031
  if (validation.staleFiles.length === 0) return null;
11259
- const root = path9.resolve(projectRoot);
12032
+ const root = path10.resolve(projectRoot);
11260
12033
  const shown = validation.staleFiles.slice(0, NOTICE_PATH_LIMIT).map((entry) => {
11261
- const relative4 = path9.relative(root, entry.path);
12034
+ const relative4 = path10.relative(root, entry.path);
11262
12035
  const display = isInside2(root, entry.path) ? relative4 || "." : entry.path;
11263
12036
  return `- ${JSON.stringify(display)} [${entry.status}]`;
11264
12037
  });
@@ -11363,6 +12136,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
11363
12136
  projectRoot;
11364
12137
  checkpointCas;
11365
12138
  isSessionInUse;
12139
+ logger;
11366
12140
  /**
11367
12141
  * In-memory cache for load() results, keyed by session ID. The cache is
11368
12142
  * invalidated when the file's mtimeMs or size changes (indicating the
@@ -11380,14 +12154,26 @@ var DefaultSessionStore = class _DefaultSessionStore {
11380
12154
  static LIST_SCAN_CONCURRENCY = 32;
11381
12155
  constructor(opts) {
11382
12156
  this.dir = opts.dir;
11383
- this.projectRoot = opts.projectRoot ? path9.resolve(opts.projectRoot) : void 0;
12157
+ this.projectRoot = opts.projectRoot ? path11.resolve(opts.projectRoot) : void 0;
11384
12158
  this.checkpointCas = this.projectRoot ? new SessionCheckpointCas({
11385
- rootDir: path9.join(this.dir, "_cas"),
12159
+ rootDir: path11.join(this.dir, "_cas"),
11386
12160
  projectRoot: this.projectRoot
11387
12161
  }) : void 0;
11388
12162
  this.events = opts.events;
11389
12163
  this.secretScrubber = opts.secretScrubber;
11390
12164
  this.isSessionInUse = opts.isSessionInUse;
12165
+ this.logger = opts.logger;
12166
+ }
12167
+ /**
12168
+ * Emit a structured warning. Uses the configured Logger when available;
12169
+ * falls back to console.warn(JSON) so warnings are never silently dropped.
12170
+ */
12171
+ logWarn(msg, ctx) {
12172
+ if (this.logger) {
12173
+ this.logger.warn(msg, ctx);
12174
+ } else {
12175
+ console.warn(JSON.stringify({ ...ctx, message: msg, timestamp: (/* @__PURE__ */ new Date()).toISOString() }));
12176
+ }
11391
12177
  }
11392
12178
  /**
11393
12179
  * Clear the load() cache. Useful for testing or when the caller knows
@@ -11436,17 +12222,17 @@ var DefaultSessionStore = class _DefaultSessionStore {
11436
12222
  }
11437
12223
  /** Absolute path to the session index file. */
11438
12224
  get indexFile() {
11439
- return path9.join(this.dir, "_index.jsonl");
12225
+ return path11.join(this.dir, "_index.jsonl");
11440
12226
  }
11441
12227
  /** Join session ID to its absolute path within the store directory. */
11442
12228
  sessionPath(id, ext) {
11443
12229
  return sessionScopedPath(this.dir, id, ext);
11444
12230
  }
11445
12231
  shardManifestPath(shardKey) {
11446
- return shardKey ? path9.join(this.dir, shardKey, "_manifest.json") : path9.join(this.dir, "_manifest.json");
12232
+ return shardKey ? path11.join(this.dir, shardKey, "_manifest.json") : path11.join(this.dir, "_manifest.json");
11447
12233
  }
11448
12234
  shardKeyForSessionId(id) {
11449
- const dirName = path9.dirname(id);
12235
+ const dirName = path11.dirname(id);
11450
12236
  return dirName === "." ? "" : dirName;
11451
12237
  }
11452
12238
  invalidateShardManifestBySessionId(id) {
@@ -11458,7 +12244,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
11458
12244
  * subdirectory so sessions group naturally by day.
11459
12245
  */
11460
12246
  async ensureShardDir(id) {
11461
- const dirPath = path9.dirname(sessionScopedPath(this.dir, id, ""));
12247
+ const dirPath = path11.dirname(sessionScopedPath(this.dir, id, ""));
11462
12248
  await ensureDir(dirPath);
11463
12249
  return dirPath;
11464
12250
  }
@@ -11489,12 +12275,10 @@ var DefaultSessionStore = class _DefaultSessionStore {
11489
12275
  this.emitWrite(id, file, "create", "success", Date.now() - t0);
11490
12276
  return writer;
11491
12277
  } catch (err) {
11492
- await handle.close().catch((e) => console.warn(JSON.stringify({
11493
- level: "warn",
11494
- event: "session_store.handle_close_failed",
11495
- message: e instanceof Error ? e.message : String(e),
11496
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
11497
- })));
12278
+ await handle.close().catch((e) => this.logWarn(
12279
+ "Session handle close failed",
12280
+ { event: "session_store.handle_close_failed", message: e instanceof Error ? e.message : String(e) }
12281
+ ));
11498
12282
  this.emitError(id, file, "create", toErrorMessage(err), true);
11499
12283
  throw err;
11500
12284
  }
@@ -11520,7 +12304,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
11520
12304
  }
11521
12305
  const parentPrefix = parent.events.slice(0, boundary + 1);
11522
12306
  const workspaceCheckpoint = targetCheckpoint?.workspaceCheckpoint;
11523
- const checkpointHash = createHash("sha256").update(parentPrefix.map((event) => JSON.stringify(event)).join("\n") + "\n", "utf8").digest("hex");
12307
+ const checkpointHash = createHash4("sha256").update(parentPrefix.map((event) => JSON.stringify(event)).join("\n") + "\n", "utf8").digest("hex");
11524
12308
  const inherited = parentPrefix.filter(inheritsIntoFork);
11525
12309
  const writer = await this.create({
11526
12310
  id: "",
@@ -11615,7 +12399,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
11615
12399
  // Shard directory (sessions/<date>/) — must match create() so the
11616
12400
  // .summary.json sidecar lands next to the JSONL instead of the
11617
12401
  // sessions root (where summaryFor() would never find it).
11618
- dir: path9.dirname(file),
12402
+ dir: path11.dirname(file),
11619
12403
  filePath: file,
11620
12404
  secretScrubber: this.secretScrubber,
11621
12405
  checkpointCas: this.checkpointCas,
@@ -11625,12 +12409,10 @@ var DefaultSessionStore = class _DefaultSessionStore {
11625
12409
  this.emitWrite(id, file, "resume", "success", Date.now() - t0);
11626
12410
  return { writer, data: resumedData };
11627
12411
  } catch (err) {
11628
- await handle.close().catch((e) => console.warn(JSON.stringify({
11629
- level: "warn",
11630
- event: "session_store.handle_close_failed",
11631
- message: e instanceof Error ? e.message : String(e),
11632
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
11633
- })));
12412
+ await handle.close().catch((e) => this.logWarn(
12413
+ "Session handle close failed",
12414
+ { event: "session_store.handle_close_failed", message: e instanceof Error ? e.message : String(e) }
12415
+ ));
11634
12416
  this.emitError(id, file, "resume", toErrorMessage(err), true);
11635
12417
  throw err;
11636
12418
  }
@@ -12170,7 +12952,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
12170
12952
  return entry;
12171
12953
  }
12172
12954
  async collectSessionFilesInShard(shardKey) {
12173
- const dir = shardKey ? path9.join(this.dir, shardKey) : this.dir;
12955
+ const dir = shardKey ? path11.join(this.dir, shardKey) : this.dir;
12174
12956
  const entries = await this.collectSessionFiles(dir, shardKey);
12175
12957
  return shardKey ? entries.filter((entry) => entry.id.startsWith(`${shardKey}/`)) : entries.filter((entry) => !entry.id.includes("/"));
12176
12958
  }
@@ -12193,13 +12975,13 @@ var DefaultSessionStore = class _DefaultSessionStore {
12193
12975
  if (entry.name === "_index.jsonl") continue;
12194
12976
  const base = entry.name.replace(/\.jsonl$/, "");
12195
12977
  const id = prefix ? `${prefix}/${base}` : base;
12196
- files.push({ id, filePath: path9.join(dir, entry.name) });
12978
+ files.push({ id, filePath: path11.join(dir, entry.name) });
12197
12979
  }
12198
12980
  }
12199
12981
  const childFileArrays = await Promise.all(
12200
12982
  dirEntries.map((entry) => {
12201
12983
  const childPrefix = depth === 0 ? entry.name : `${prefix}/${entry.name}`;
12202
- return this.collectSessionFiles(path9.join(dir, entry.name), childPrefix, depth + 1);
12984
+ return this.collectSessionFiles(path11.join(dir, entry.name), childPrefix, depth + 1);
12203
12985
  })
12204
12986
  );
12205
12987
  return [...childFileArrays.flat(), ...files];
@@ -12232,7 +13014,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
12232
13014
  const childIdArrays = await Promise.all(
12233
13015
  dirEntries.map((entry) => {
12234
13016
  const childPrefix = depth === 0 ? entry.name : `${prefix}/${entry.name}`;
12235
- return this.collectSessionIds(path9.join(dir, entry.name), childPrefix, depth + 1);
13017
+ return this.collectSessionIds(path11.join(dir, entry.name), childPrefix, depth + 1);
12236
13018
  })
12237
13019
  );
12238
13020
  return [...childIdArrays.flat(), ...fileIds];
@@ -12251,13 +13033,10 @@ var DefaultSessionStore = class _DefaultSessionStore {
12251
13033
  await atomicWrite(manifest, JSON.stringify(summary), { mode: 384 }).catch((err) => {
12252
13034
  const msg = toErrorMessage(err);
12253
13035
  this.emitError(id, manifest, "summary_fallback", msg, true);
12254
- console.warn(JSON.stringify({
12255
- level: "warn",
12256
- event: "session_store.manifest_write_failed",
12257
- sessionId: id,
12258
- message: msg,
12259
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
12260
- }));
13036
+ this.logWarn(
13037
+ "Session manifest write failed",
13038
+ { event: "session_store.manifest_write_failed", sessionId: id, message: msg }
13039
+ );
12261
13040
  });
12262
13041
  outcome = "failure";
12263
13042
  errorMsg = "summary fallback \xE2\u20AC\u201D manifest rebuilt";
@@ -12349,9 +13128,9 @@ var DefaultSessionStore = class _DefaultSessionStore {
12349
13128
  async deleteSession(id) {
12350
13129
  const jsonlPath = this.sessionPath(id, ".jsonl");
12351
13130
  const summaryPath = this.sessionPath(id, ".summary.json");
12352
- const shardDir = path9.dirname(jsonlPath);
12353
- const base = path9.basename(id);
12354
- const sessDir = path9.join(shardDir, base);
13131
+ const shardDir = path11.dirname(jsonlPath);
13132
+ const base = path11.basename(id);
13133
+ const sessDir = path11.join(shardDir, base);
12355
13134
  const deletions = [
12356
13135
  fsp9.unlink(jsonlPath),
12357
13136
  fsp9.unlink(summaryPath),
@@ -12392,7 +13171,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
12392
13171
  */
12393
13172
  async readActiveSessionId() {
12394
13173
  try {
12395
- const raw = await fsp9.readFile(path9.join(this.dir, "active.json"), "utf8");
13174
+ const raw = await fsp9.readFile(path11.join(this.dir, "active.json"), "utf8");
12396
13175
  const active = JSON.parse(raw);
12397
13176
  return active.sessionId ?? null;
12398
13177
  } catch {
@@ -12455,7 +13234,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
12455
13234
  const activeSessionId = await this.readActiveSessionId();
12456
13235
  const isPrunableJsonl = (name) => name.endsWith(".jsonl") && name !== "_index.jsonl" && name !== "_mailbox.jsonl" && !name.endsWith(".replay.jsonl") && !name.endsWith(".audit.jsonl");
12457
13236
  const pruneFile = async (dir, name, prefix) => {
12458
- const jsonlPath = path9.join(dir, name);
13237
+ const jsonlPath = path11.join(dir, name);
12459
13238
  try {
12460
13239
  const stat9 = await fsp9.stat(jsonlPath);
12461
13240
  if (stat9.mtimeMs >= cutoff) return;
@@ -12475,7 +13254,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
12475
13254
  continue;
12476
13255
  }
12477
13256
  if (!entry.isDirectory()) continue;
12478
- const dateDir = path9.join(this.dir, entry.name);
13257
+ const dateDir = path11.join(this.dir, entry.name);
12479
13258
  const files = await fsp9.readdir(dateDir, { withFileTypes: true }).catch(() => []);
12480
13259
  for (const file of files) {
12481
13260
  if (!file.isFile() || !isPrunableJsonl(file.name)) continue;
@@ -12487,7 +13266,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
12487
13266
  }
12488
13267
  for (const entry of entries) {
12489
13268
  if (!entry.isDirectory()) continue;
12490
- const dateDir = path9.join(this.dir, entry.name);
13269
+ const dateDir = path11.join(this.dir, entry.name);
12491
13270
  try {
12492
13271
  const remaining = await fsp9.readdir(dateDir);
12493
13272
  if (remaining.length === 0) {
@@ -12618,9 +13397,9 @@ function makeDirectorSessionFactory(opts) {
12618
13397
  let dir;
12619
13398
  if (opts.store) {
12620
13399
  store = opts.store;
12621
- dir = opts.sessionsRoot ? path9.join(opts.sessionsRoot, runId) : "(caller-managed)";
13400
+ dir = opts.sessionsRoot ? path12.join(opts.sessionsRoot, runId) : "(caller-managed)";
12622
13401
  } else if (opts.sessionsRoot) {
12623
- dir = path9.join(opts.sessionsRoot, runId);
13402
+ dir = path12.join(opts.sessionsRoot, runId);
12624
13403
  store = new DefaultSessionStore({ dir });
12625
13404
  } else {
12626
13405
  throw new Error("makeDirectorSessionFactory requires either `store` or `sessionsRoot`");
@@ -12642,6 +13421,11 @@ function makeDirectorSessionFactory(opts) {
12642
13421
  }
12643
13422
  };
12644
13423
  }
13424
+
13425
+ // src/coordination/fleet-manager.ts
13426
+ import { randomUUID as randomUUID9 } from "node:crypto";
13427
+ import * as fsp10 from "node:fs/promises";
13428
+ import * as path13 from "node:path";
12645
13429
  var FleetManager = class {
12646
13430
  /** The fleet-wide event bus. */
12647
13431
  fleet;
@@ -12687,7 +13471,7 @@ var FleetManager = class {
12687
13471
  maxContext;
12688
13472
  constructor(opts = {}) {
12689
13473
  this.manifestPath = opts.manifestPath;
12690
- this.directorRunId = opts.directorRunId ?? randomUUID();
13474
+ this.directorRunId = opts.directorRunId ?? randomUUID9();
12691
13475
  this.maxSpawns = opts.maxSpawns ?? Number.POSITIVE_INFINITY;
12692
13476
  this.maxSpawnDepth = resolveMaxSpawnDepth(opts.maxSpawnDepth);
12693
13477
  this.spawnDepth = opts.spawnDepth ?? 0;
@@ -12902,7 +13686,7 @@ var FleetManager = class {
12902
13686
  })),
12903
13687
  usage: this.usage.snapshot()
12904
13688
  };
12905
- await fsp9.mkdir(path9.dirname(this.manifestPath), { recursive: true });
13689
+ await fsp10.mkdir(path13.dirname(this.manifestPath), { recursive: true });
12906
13690
  await atomicWrite(this.manifestPath, JSON.stringify(manifest, null, 2), { mode: 384 });
12907
13691
  return this.manifestPath;
12908
13692
  }
@@ -13039,6 +13823,153 @@ var FleetManager = class {
13039
13823
  }
13040
13824
  };
13041
13825
 
13826
+ // src/coordination/global-mailbox.ts
13827
+ import { randomUUID as randomUUID10 } from "node:crypto";
13828
+ import * as fsp11 from "node:fs/promises";
13829
+ import * as path14 from "node:path";
13830
+
13831
+ // src/coordination/mailbox-constants.ts
13832
+ var AGENT_STALE_MS = 6e4;
13833
+ var CLIENT_STALE_MS = 6e4;
13834
+ var HEARTBEAT_THROTTLE_MS = 5e3;
13835
+ var REGISTRY_CACHE_TTL_MS = 2e3;
13836
+ var LINE_SEPARATOR = "\n";
13837
+ var MESSAGE_CACHE_MAX_ENTRIES = 1e4;
13838
+ var AUTO_COMPACT_INTERVAL_MS = 3e5;
13839
+ var AUTO_COMPACT_READ_MAX_AGE_MS = 6e5;
13840
+ var AUTO_COMPACT_DEFAULT_TTL_MS = 864e5;
13841
+
13842
+ // src/coordination/mailbox-message-codec.ts
13843
+ var MESSAGE_TYPES = /* @__PURE__ */ new Set([
13844
+ "note",
13845
+ "ask",
13846
+ "assign",
13847
+ "steer",
13848
+ "btw",
13849
+ "broadcast",
13850
+ "status",
13851
+ "result",
13852
+ "review",
13853
+ "control"
13854
+ ]);
13855
+ var PRIORITIES = /* @__PURE__ */ new Set(["low", "normal", "high"]);
13856
+ var TASK_STATUSES = /* @__PURE__ */ new Set([
13857
+ "pending",
13858
+ "in_progress",
13859
+ "completed",
13860
+ "failed",
13861
+ "idle",
13862
+ "running",
13863
+ "streaming",
13864
+ "waiting_user",
13865
+ "error",
13866
+ "offline",
13867
+ "busy"
13868
+ ]);
13869
+ function isRecord3(value) {
13870
+ return typeof value === "object" && value !== null && !Array.isArray(value);
13871
+ }
13872
+ function requiredString(record, key) {
13873
+ const value = record[key];
13874
+ if (typeof value !== "string") {
13875
+ throw new TypeError(`mailbox message field "${key}" must be a string`);
13876
+ }
13877
+ return value;
13878
+ }
13879
+ function optionalString2(record, key) {
13880
+ const value = record[key];
13881
+ if (value === void 0) return {};
13882
+ if (typeof value !== "string") {
13883
+ throw new TypeError(`mailbox message field "${key}" must be a string when present`);
13884
+ }
13885
+ return { [key]: value };
13886
+ }
13887
+ function parseMessageType(value) {
13888
+ if (value === "info") return "note";
13889
+ if (value === "task") return "assign";
13890
+ if (typeof value === "string" && MESSAGE_TYPES.has(value)) {
13891
+ return value;
13892
+ }
13893
+ throw new TypeError('mailbox message field "type" is invalid');
13894
+ }
13895
+ function normalizeMailboxMessageType(value) {
13896
+ return parseMessageType(value);
13897
+ }
13898
+ function parsePriority(value) {
13899
+ if (typeof value === "string" && PRIORITIES.has(value)) {
13900
+ return value;
13901
+ }
13902
+ if (typeof value === "string") return "normal";
13903
+ throw new TypeError('mailbox message field "priority" must be a string');
13904
+ }
13905
+ function parseReadReceipts(record, to) {
13906
+ const value = record["readBy"];
13907
+ if (value === void 0) {
13908
+ const legacyReadAt = record["readAt"];
13909
+ return record["read"] === true && typeof legacyReadAt === "string" ? { [to || "unknown"]: legacyReadAt } : {};
13910
+ }
13911
+ if (!isRecord3(value)) {
13912
+ throw new TypeError('mailbox message field "readBy" must be an object');
13913
+ }
13914
+ const receipts = {};
13915
+ for (const [agentId, timestamp] of Object.entries(value)) {
13916
+ if (typeof timestamp !== "string") {
13917
+ throw new TypeError("mailbox message read receipt timestamps must be strings");
13918
+ }
13919
+ receipts[agentId] = timestamp;
13920
+ }
13921
+ return receipts;
13922
+ }
13923
+ function parseTaskContext(value) {
13924
+ if (value === void 0) return void 0;
13925
+ if (!isRecord3(value)) {
13926
+ throw new TypeError('mailbox message field "taskContext" must be an object');
13927
+ }
13928
+ const status = value["status"];
13929
+ if (status !== void 0 && (typeof status !== "string" || !TASK_STATUSES.has(status))) {
13930
+ throw new TypeError("mailbox message taskContext status is invalid");
13931
+ }
13932
+ return {
13933
+ ...optionalString2(value, "agentRole"),
13934
+ ...optionalString2(value, "agentName"),
13935
+ ...optionalString2(value, "taskId"),
13936
+ ...status === void 0 ? {} : { status }
13937
+ };
13938
+ }
13939
+ function parseMailboxMessage(value) {
13940
+ if (!isRecord3(value)) throw new TypeError("mailbox message must be an object");
13941
+ const to = value["to"] === void 0 ? "" : requiredString(value, "to");
13942
+ const completed = value["completed"];
13943
+ if (typeof completed !== "boolean") {
13944
+ throw new TypeError('mailbox message field "completed" must be a boolean');
13945
+ }
13946
+ const taskContext = parseTaskContext(value["taskContext"]);
13947
+ return {
13948
+ id: requiredString(value, "id"),
13949
+ from: requiredString(value, "from"),
13950
+ to,
13951
+ type: parseMessageType(value["type"]),
13952
+ subject: requiredString(value, "subject"),
13953
+ body: requiredString(value, "body"),
13954
+ priority: parsePriority(value["priority"]),
13955
+ readBy: parseReadReceipts(value, to),
13956
+ completed,
13957
+ timestamp: requiredString(value, "timestamp"),
13958
+ ...optionalString2(value, "completedBy"),
13959
+ ...optionalString2(value, "outcome"),
13960
+ ...optionalString2(value, "completedAt"),
13961
+ ...optionalString2(value, "deletedAt"),
13962
+ ...optionalString2(value, "deletedBy"),
13963
+ ...optionalString2(value, "replyTo"),
13964
+ ...optionalString2(value, "senderSessionId"),
13965
+ ...optionalString2(value, "expiresAt"),
13966
+ ...taskContext === void 0 ? {} : { taskContext }
13967
+ };
13968
+ }
13969
+ function parseMailboxMessageLine(line) {
13970
+ return parseMailboxMessage(JSON.parse(line));
13971
+ }
13972
+
13042
13973
  // src/coordination/mailbox-types.ts
13043
13974
  function normalizeRecipient(to) {
13044
13975
  return to.trim().toLowerCase() === "all" ? "*" : to.trim();
@@ -13047,15 +13978,8 @@ function normalizeRecipient(to) {
13047
13978
  // src/coordination/global-mailbox.ts
13048
13979
  var MAILBOX_FILE = "_mailbox.jsonl";
13049
13980
  var CLIENT_REGISTRY_FILE = "_mailbox.clients.json";
13050
- var AGENT_STALE_MS = 6e4;
13051
- var AGENT_PURGE_MS = 864e5;
13052
- var CLIENT_STALE_MS = 6e4;
13053
- var HEARTBEAT_THROTTLE_MS = 5e3;
13054
- var REGISTRY_CACHE_TTL_MS = 2e3;
13055
- var LINE_SEPARATOR = "\n";
13056
- var MESSAGE_CACHE_MAX_ENTRIES = 1e4;
13057
13981
  function resolveProjectDir(projectRoot, globalRoot) {
13058
- return path9.join(globalRoot, "projects", projectSlug(projectRoot));
13982
+ return path14.join(globalRoot, "projects", projectSlug(projectRoot));
13059
13983
  }
13060
13984
  var GlobalMailbox = class {
13061
13985
  /** Path to the JSONL message file. */
@@ -13068,6 +13992,12 @@ var GlobalMailbox = class {
13068
13992
  _events;
13069
13993
  /** Optional HQ publisher for cross-project command-center telemetry. */
13070
13994
  _hqPublisher;
13995
+ /**
13996
+ * Optional SSE event emitter for real-time push to HTTP bridge clients.
13997
+ * When present, `send`/`ack`/`softDelete`/`restore` emit events that
13998
+ * connected SSE subscribers receive instantly.
13999
+ */
14000
+ eventEmitter;
13071
14001
  /**
13072
14002
  * Local cache of the agent registry to avoid re-reading on every call.
13073
14003
  * Time-bounded: the registry file is shared ACROSS PROCESSES (that's the
@@ -13113,20 +14043,47 @@ var GlobalMailbox = class {
13113
14043
  * that follows the read. Pattern mirrors `DefaultMemoryStore.runSerialized`.
13114
14044
  */
13115
14045
  _readChain = Promise.resolve([]);
14046
+ /**
14047
+ * Recipient → Set of indices into `_messageCache`. Maintained alongside
14048
+ * the cache so `query({ to })` and `unreadCount(agentId)` can skip the
14049
+ * O(N) full scan and iterate only the messages addressed to the target
14050
+ * recipient (plus broadcasts `*`).
14051
+ *
14052
+ * The index is rebuilt whenever the cache array is replaced
14053
+ * (`_setMessageCache`), extended when new messages are pushed
14054
+ * (`_pushToCache`, `_readNewMessagesOnly`), and cleared on `close()`.
14055
+ * It is `null` when the cache itself is null (> MESSAGE_CACHE_MAX_ENTRIES
14056
+ * or never populated).
14057
+ *
14058
+ * Safety: array indices are valid only as long as the cache array
14059
+ * reference hasn't changed. Since we rebuild the index in the same
14060
+ * synchronous step that replaces the cache, a reader that calls
14061
+ * `_readMessagesCached()` either gets the old array + old index, or
14062
+ * the new array + new index — never a mismatch.
14063
+ */
14064
+ _recipientIndex = null;
14065
+ /**
14066
+ * Sender → Set of indices into `_messageCache`. Same lifecycle and
14067
+ * safety properties as `_recipientIndex`, but keyed on `msg.from`
14068
+ * so `query({ from })` can skip the full scan.
14069
+ */
14070
+ _senderIndex = null;
13116
14071
  /**
13117
14072
  * @param projectDir — `~/.wrongstack/projects/<slug>/`
13118
14073
  * @param events — optional EventBus for real-time TUI/WebUI notifications
13119
14074
  * @param hqPublisher — optional HQ publisher, or getter, for cross-project telemetry
14075
+ * @param eventEmitter — optional SSE event emitter for HTTP bridge push
13120
14076
  */
13121
- constructor(projectDir, events, hqPublisher) {
13122
- this.messagePath = path9.join(projectDir, MAILBOX_FILE);
13123
- this.registryPath = path9.join(projectDir, "_mailbox.registry.json");
13124
- this.clientRegistryPath = path9.join(projectDir, CLIENT_REGISTRY_FILE);
14077
+ constructor(projectDir, events, hqPublisher, eventEmitter) {
14078
+ this.messagePath = path14.join(projectDir, MAILBOX_FILE);
14079
+ this.registryPath = path14.join(projectDir, "_mailbox.registry.json");
14080
+ this.clientRegistryPath = path14.join(projectDir, CLIENT_REGISTRY_FILE);
13125
14081
  this._events = events;
13126
14082
  this._hqPublisher = hqPublisher;
14083
+ this.eventEmitter = eventEmitter;
13127
14084
  }
13128
14085
  get hqMailboxId() {
13129
- return `${path9.basename(path9.dirname(this.messagePath))}:mailbox`;
14086
+ return `${path14.basename(path14.dirname(this.messagePath))}:mailbox`;
13130
14087
  }
13131
14088
  get hqPublisher() {
13132
14089
  return typeof this._hqPublisher === "function" ? this._hqPublisher() : this._hqPublisher;
@@ -13147,12 +14104,12 @@ var GlobalMailbox = class {
13147
14104
  async send(input) {
13148
14105
  const now = (/* @__PURE__ */ new Date()).toISOString();
13149
14106
  const msg = {
13150
- id: randomUUID(),
14107
+ id: randomUUID10(),
13151
14108
  from: input.from,
13152
14109
  // "all" is an accepted spelling of the broadcast address — canonical
13153
14110
  // form on disk is '*' so every query/checker matches it.
13154
14111
  to: normalizeRecipient(input.to),
13155
- type: input.type,
14112
+ type: normalizeMailboxMessageType(input.type),
13156
14113
  subject: input.subject,
13157
14114
  body: input.body,
13158
14115
  priority: input.priority ?? "normal",
@@ -13160,12 +14117,13 @@ var GlobalMailbox = class {
13160
14117
  completed: false,
13161
14118
  timestamp: now,
13162
14119
  replyTo: input.replyTo,
13163
- taskContext: input.taskContext
14120
+ taskContext: input.taskContext,
14121
+ expiresAt: input.ttlMs !== void 0 ? new Date(Date.now() + input.ttlMs).toISOString() : void 0
13164
14122
  };
13165
14123
  const line = JSON.stringify(msg) + LINE_SEPARATOR;
13166
- await fsp9.mkdir(path9.dirname(this.messagePath), { recursive: true });
14124
+ await fsp11.mkdir(path14.dirname(this.messagePath), { recursive: true });
13167
14125
  await withFileLock(this.messagePath, async () => {
13168
- await fsp9.appendFile(this.messagePath, line, "utf8");
14126
+ await fsp11.appendFile(this.messagePath, line, "utf8");
13169
14127
  const { mtimeMs, size } = await this._statMessageFile();
13170
14128
  this._pushToCache(msg, mtimeMs, size);
13171
14129
  });
@@ -13175,21 +14133,49 @@ var GlobalMailbox = class {
13175
14133
  message: msg
13176
14134
  });
13177
14135
  this.publishHqMailboxSnapshot();
14136
+ this._events?.emitCustom("mailbox.message_sent", {
14137
+ messageId: msg.id,
14138
+ from: msg.from,
14139
+ to: msg.to,
14140
+ type: msg.type,
14141
+ subject: msg.subject
14142
+ });
14143
+ this.eventEmitter?.emit({
14144
+ type: "message.sent",
14145
+ messageId: msg.id,
14146
+ from: msg.from,
14147
+ to: msg.to,
14148
+ timestamp: now
14149
+ });
13178
14150
  return msg;
13179
14151
  }
13180
14152
  async query(q) {
14153
+ const queryType = q.type === void 0 ? void 0 : normalizeMailboxMessageType(q.type);
13181
14154
  const all = await this._readMessagesCached();
13182
14155
  const limit = q.limit ?? 50;
13183
14156
  const order = q.minPriority !== void 0 ? { low: 0, normal: 1, high: 2 } : null;
13184
14157
  const minPriorityRank = order && q.minPriority !== void 0 ? order[q.minPriority] : 0;
13185
14158
  const out = [];
13186
- for (let i = 0; i < all.length; i++) {
13187
- const m = all[i];
14159
+ let candidates;
14160
+ if (q.to !== void 0 && this._recipientIndex !== null && q.from === void 0 && q.type === void 0 && q.minPriority === void 0) {
14161
+ const indices = /* @__PURE__ */ new Set();
14162
+ const direct = this._recipientIndex.get(q.to);
14163
+ if (direct !== void 0) for (const i of direct) indices.add(i);
14164
+ const broadcasts = this._recipientIndex.get("*");
14165
+ if (broadcasts !== void 0) for (const i of broadcasts) indices.add(i);
14166
+ candidates = [...indices].sort((a, b) => a - b).map((i) => all[i]);
14167
+ } else if (q.from !== void 0 && q.to === void 0 && this._senderIndex !== null && q.type === void 0 && q.minPriority === void 0) {
14168
+ const indices = this._senderIndex.get(q.from);
14169
+ candidates = indices !== void 0 ? [...indices].sort((a, b) => a - b).map((i) => all[i]) : [];
14170
+ } else {
14171
+ candidates = all;
14172
+ }
14173
+ for (const m of candidates) {
13188
14174
  if (q.to !== void 0 && m.to !== q.to && m.to !== "*") continue;
13189
14175
  if (q.from !== void 0 && m.from !== q.from) continue;
13190
14176
  if (q.unreadBy !== void 0 && q.unreadBy in m.readBy) continue;
13191
14177
  if (q.incompleteOnly && m.completed) continue;
13192
- if (q.type !== void 0 && m.type !== q.type) continue;
14178
+ if (queryType !== void 0 && m.type !== queryType) continue;
13193
14179
  if (order !== null && (order[m.priority] ?? 1) < minPriorityRank) {
13194
14180
  continue;
13195
14181
  }
@@ -13236,7 +14222,7 @@ var GlobalMailbox = class {
13236
14222
  }
13237
14223
  if (changed) {
13238
14224
  const serialized = all.map((m) => JSON.stringify(m)).join(LINE_SEPARATOR) + LINE_SEPARATOR;
13239
- await fsp9.writeFile(this.messagePath, serialized, "utf8");
14225
+ await fsp11.writeFile(this.messagePath, serialized, "utf8");
13240
14226
  }
13241
14227
  const { mtimeMs, size } = await this._statMessageFile();
13242
14228
  this._setMessageCache(all, mtimeMs, size);
@@ -13247,6 +14233,13 @@ var GlobalMailbox = class {
13247
14233
  action: message.completed ? "message.completed" : "message.read",
13248
14234
  message
13249
14235
  });
14236
+ this.eventEmitter?.emit({
14237
+ type: "message.acked",
14238
+ messageId: message.id,
14239
+ from: message.from,
14240
+ to: message.to,
14241
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
14242
+ });
13250
14243
  }
13251
14244
  if (updated.length > 0) this.publishHqMailboxSnapshot();
13252
14245
  return updated;
@@ -13254,10 +14247,22 @@ var GlobalMailbox = class {
13254
14247
  async unreadCount(forAgentId) {
13255
14248
  const all = await this._readMessagesCached();
13256
14249
  let count = 0;
13257
- for (let i = 0; i < all.length; i++) {
13258
- const m = all[i];
13259
- if ((m.to === forAgentId || m.to === "*") && !(forAgentId in m.readBy) && !m.completed) {
13260
- count++;
14250
+ if (this._recipientIndex !== null) {
14251
+ const indices = /* @__PURE__ */ new Set();
14252
+ const direct = this._recipientIndex.get(forAgentId);
14253
+ if (direct !== void 0) for (const i of direct) indices.add(i);
14254
+ const broadcasts = this._recipientIndex.get("*");
14255
+ if (broadcasts !== void 0) for (const i of broadcasts) indices.add(i);
14256
+ for (const i of indices) {
14257
+ const m = all[i];
14258
+ if (!(forAgentId in m.readBy) && !m.completed) count++;
14259
+ }
14260
+ } else {
14261
+ for (let i = 0; i < all.length; i++) {
14262
+ const m = all[i];
14263
+ if ((m.to === forAgentId || m.to === "*") && !(forAgentId in m.readBy) && !m.completed) {
14264
+ count++;
14265
+ }
13261
14266
  }
13262
14267
  }
13263
14268
  return count;
@@ -13267,6 +14272,7 @@ var GlobalMailbox = class {
13267
14272
  await withFileLock(this.messagePath, async () => {
13268
14273
  const all = await this._readMessagesFresh();
13269
14274
  const now = (/* @__PURE__ */ new Date()).toISOString();
14275
+ let changed = false;
13270
14276
  for (const m of all) {
13271
14277
  if (m.id !== mailId) continue;
13272
14278
  if (m.deletedAt !== void 0) {
@@ -13276,19 +14282,30 @@ var GlobalMailbox = class {
13276
14282
  m.deletedAt = now;
13277
14283
  m.deletedBy = by;
13278
14284
  updated = m;
14285
+ changed = true;
14286
+ }
14287
+ if (changed) {
14288
+ const serialized = all.map((m) => JSON.stringify(m)).join(LINE_SEPARATOR) + LINE_SEPARATOR;
14289
+ await fsp11.writeFile(this.messagePath, serialized, "utf8");
13279
14290
  }
13280
- const serialized = all.map((m) => JSON.stringify(m)).join(LINE_SEPARATOR) + LINE_SEPARATOR;
13281
- await fsp9.writeFile(this.messagePath, serialized, "utf8");
13282
14291
  const { mtimeMs, size } = await this._statMessageFile();
13283
14292
  this._setMessageCache(all, mtimeMs, size);
13284
14293
  });
13285
14294
  if (updated !== null) {
14295
+ const msg = updated;
13286
14296
  this.publishHqMailboxEvent({
13287
14297
  mailboxId: this.hqMailboxId,
13288
14298
  action: "message.updated",
13289
- message: updated
14299
+ message: msg
13290
14300
  });
13291
14301
  this.publishHqMailboxSnapshot();
14302
+ this.eventEmitter?.emit({
14303
+ type: "message.deleted",
14304
+ messageId: msg.id,
14305
+ from: msg.from,
14306
+ to: msg.to,
14307
+ timestamp: msg.deletedAt ?? (/* @__PURE__ */ new Date()).toISOString()
14308
+ });
13292
14309
  }
13293
14310
  return updated;
13294
14311
  }
@@ -13296,24 +14313,40 @@ var GlobalMailbox = class {
13296
14313
  let updated = null;
13297
14314
  await withFileLock(this.messagePath, async () => {
13298
14315
  const all = await this._readMessagesFresh();
14316
+ let changed = false;
13299
14317
  for (const m of all) {
13300
14318
  if (m.id !== mailId) continue;
14319
+ if (m.deletedAt === void 0 && m.deletedBy === void 0) {
14320
+ updated = m;
14321
+ continue;
14322
+ }
13301
14323
  delete m.deletedAt;
13302
14324
  delete m.deletedBy;
13303
14325
  updated = m;
14326
+ changed = true;
14327
+ }
14328
+ if (changed) {
14329
+ const serialized = all.map((m) => JSON.stringify(m)).join(LINE_SEPARATOR) + LINE_SEPARATOR;
14330
+ await fsp11.writeFile(this.messagePath, serialized, "utf8");
13304
14331
  }
13305
- const serialized = all.map((m) => JSON.stringify(m)).join(LINE_SEPARATOR) + LINE_SEPARATOR;
13306
- await fsp9.writeFile(this.messagePath, serialized, "utf8");
13307
14332
  const { mtimeMs, size } = await this._statMessageFile();
13308
14333
  this._setMessageCache(all, mtimeMs, size);
13309
14334
  });
13310
14335
  if (updated !== null) {
14336
+ const msg = updated;
13311
14337
  this.publishHqMailboxEvent({
13312
14338
  mailboxId: this.hqMailboxId,
13313
14339
  action: "message.updated",
13314
- message: updated
14340
+ message: msg
13315
14341
  });
13316
14342
  this.publishHqMailboxSnapshot();
14343
+ this.eventEmitter?.emit({
14344
+ type: "message.restored",
14345
+ messageId: msg.id,
14346
+ from: msg.from,
14347
+ to: msg.to,
14348
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
14349
+ });
13317
14350
  }
13318
14351
  return updated;
13319
14352
  }
@@ -13446,8 +14479,19 @@ var GlobalMailbox = class {
13446
14479
  }
13447
14480
  async getAgentStatuses() {
13448
14481
  await this._ensureRegistry();
13449
- const registry = await this._readRegistry();
14482
+ let registry = await this._readRegistry();
14483
+ const before = registry.size;
13450
14484
  this._pruneStaleInPlace(registry);
14485
+ if (registry.size < before) {
14486
+ await withFileLock(this.registryPath, async () => {
14487
+ const fresh = await this._readRegistry({ fresh: true });
14488
+ this._pruneStaleInPlace(fresh);
14489
+ this._registryCache = fresh;
14490
+ this._registryCacheAt = Date.now();
14491
+ await this._writeRegistry(fresh);
14492
+ registry = fresh;
14493
+ });
14494
+ }
13451
14495
  const now = Date.now();
13452
14496
  return Array.from(registry.values()).map((a) => ({
13453
14497
  agentId: a.agentId,
@@ -13499,6 +14543,20 @@ var GlobalMailbox = class {
13499
14543
  });
13500
14544
  this.publishHqMailboxSnapshot();
13501
14545
  }
14546
+ async deregisterClient(clientId) {
14547
+ await this._ensureClientRegistry();
14548
+ await withFileLock(this.clientRegistryPath, async () => {
14549
+ const registry = await this._readClientRegistry({ fresh: true });
14550
+ this._pruneStaleClientsInPlace(registry);
14551
+ registry.delete(clientId);
14552
+ this._clientRegistryCache = registry;
14553
+ this._clientRegistryCacheAt = Date.now();
14554
+ await this._writeClientRegistry(registry);
14555
+ });
14556
+ this._lastClientHeartbeat.delete(clientId);
14557
+ this._events?.emitCustom("mailbox.client_deregistered", { clientId });
14558
+ this.publishHqMailboxSnapshot();
14559
+ }
13502
14560
  async clientHeartbeat(input) {
13503
14561
  const last = this._lastClientHeartbeat.get(input.clientId) ?? 0;
13504
14562
  const now = Date.now();
@@ -13528,7 +14586,11 @@ var GlobalMailbox = class {
13528
14586
  async getClientStatuses() {
13529
14587
  await this._ensureClientRegistry();
13530
14588
  const registry = await this._readClientRegistry();
14589
+ const before = registry.size;
13531
14590
  this._pruneStaleClientsInPlace(registry);
14591
+ if (registry.size < before) {
14592
+ await this._writeClientRegistry(registry);
14593
+ }
13532
14594
  const now = Date.now();
13533
14595
  return Array.from(registry.values()).map((c) => ({
13534
14596
  clientId: c.clientId,
@@ -13540,6 +14602,32 @@ var GlobalMailbox = class {
13540
14602
  pid: c.pid
13541
14603
  })).sort((a, b) => b.lastSeenAt.localeCompare(a.lastSeenAt));
13542
14604
  }
14605
+ /**
14606
+ * Explicitly purge stale clients from the registry and write back to disk.
14607
+ * Removes client entries whose lastSeenAt is older than CLIENT_STALE_MS.
14608
+ * Returns the number of entries purged.
14609
+ *
14610
+ * Idempotent — safe to call regularly. The same pruning runs implicitly
14611
+ * inside registerClient, clientHeartbeat, and getClientStatuses, but if
14612
+ * no client registers or heartbeats for a long time, this public method
14613
+ * ensures the file gets cleaned up on demand.
14614
+ */
14615
+ async purgeClients() {
14616
+ await this._ensureClientRegistry();
14617
+ let purged = 0;
14618
+ await withFileLock(this.clientRegistryPath, async () => {
14619
+ const registry = await this._readClientRegistry({ fresh: true });
14620
+ const before = registry.size;
14621
+ this._pruneStaleClientsInPlace(registry);
14622
+ purged = before - registry.size;
14623
+ if (purged > 0) {
14624
+ this._clientRegistryCache = registry;
14625
+ this._clientRegistryCacheAt = Date.now();
14626
+ await this._writeClientRegistry(registry);
14627
+ }
14628
+ });
14629
+ return purged;
14630
+ }
13543
14631
  // ── Lifecycle ───────────────────────────────────────────────────────────
13544
14632
  async close() {
13545
14633
  this._registryCache = null;
@@ -13547,10 +14635,12 @@ var GlobalMailbox = class {
13547
14635
  this._messageCache = null;
13548
14636
  this._messageCacheMtime = -1;
13549
14637
  this._messageCacheSize = -1;
14638
+ this._recipientIndex = null;
14639
+ this._senderIndex = null;
13550
14640
  }
13551
14641
  async clearAll() {
13552
14642
  await withFileLock(this.messagePath, async () => {
13553
- await fsp9.writeFile(this.messagePath, "", "utf8");
14643
+ await fsp11.writeFile(this.messagePath, "", "utf8");
13554
14644
  const { mtimeMs, size } = await this._statMessageFile();
13555
14645
  this._setMessageCache([], mtimeMs, size);
13556
14646
  });
@@ -13583,7 +14673,7 @@ var GlobalMailbox = class {
13583
14673
  remaining = kept.length;
13584
14674
  if (kept.length < all.length) {
13585
14675
  const content = kept.map((m) => JSON.stringify(m)).join(LINE_SEPARATOR) + LINE_SEPARATOR;
13586
- await fsp9.writeFile(this.messagePath, content, "utf8");
14676
+ await fsp11.writeFile(this.messagePath, content, "utf8");
13587
14677
  }
13588
14678
  const { mtimeMs, size } = await this._statMessageFile();
13589
14679
  this._setMessageCache(kept, mtimeMs, size);
@@ -13595,6 +14685,100 @@ var GlobalMailbox = class {
13595
14685
  remaining
13596
14686
  };
13597
14687
  }
14688
+ // ── Auto-compaction ─────────────────────────────────────────────────────
14689
+ _autoCompactTimer = null;
14690
+ async autoCompact(opts) {
14691
+ const readMaxAgeMs = opts?.readMaxAgeMs ?? AUTO_COMPACT_READ_MAX_AGE_MS;
14692
+ const defaultTtlMs = opts?.defaultTtlMs ?? AUTO_COMPACT_DEFAULT_TTL_MS;
14693
+ const completedMaxAgeMs = opts?.completedMaxAgeMs ?? 864e5;
14694
+ const incompleteMaxAgeMs = opts?.incompleteMaxAgeMs ?? 6048e5;
14695
+ let expiredPurged = 0;
14696
+ let readByAllPurged = 0;
14697
+ let completedPurged = 0;
14698
+ let incompletePurged = 0;
14699
+ let remaining = 0;
14700
+ let onlineAgentIds = null;
14701
+ try {
14702
+ const statuses = await this.getAgentStatuses();
14703
+ const online = statuses.filter((s) => s.online);
14704
+ onlineAgentIds = online.length > 0 ? new Set(online.map((s) => s.agentId)) : null;
14705
+ } catch {
14706
+ onlineAgentIds = null;
14707
+ }
14708
+ await withFileLock(this.messagePath, async () => {
14709
+ const all = await this._readMessagesFresh();
14710
+ const now = Date.now();
14711
+ const cutoffReadAge = now - readMaxAgeMs;
14712
+ const cutoffCompleted = now - completedMaxAgeMs;
14713
+ const cutoffIncomplete = now - incompleteMaxAgeMs;
14714
+ const cutoffDefaultTtl = now - defaultTtlMs;
14715
+ const kept = [];
14716
+ for (const msg of all) {
14717
+ const msgTime = new Date(msg.timestamp).getTime();
14718
+ if (msg.expiresAt !== void 0) {
14719
+ if (new Date(msg.expiresAt).getTime() < now) {
14720
+ expiredPurged++;
14721
+ continue;
14722
+ }
14723
+ } else if (msgTime < cutoffDefaultTtl) {
14724
+ expiredPurged++;
14725
+ continue;
14726
+ }
14727
+ if (onlineAgentIds !== null && !msg.completed) {
14728
+ const readByAll = onlineAgentIds.size > 0 && [...onlineAgentIds].every((id) => id in msg.readBy);
14729
+ if (readByAll) {
14730
+ const readTimes = Object.values(msg.readBy).map((t) => new Date(t).getTime());
14731
+ const latestRead = Math.max(...readTimes);
14732
+ if (latestRead < cutoffReadAge) {
14733
+ readByAllPurged++;
14734
+ continue;
14735
+ }
14736
+ }
14737
+ }
14738
+ const completedTime = msg.completedAt ? new Date(msg.completedAt).getTime() : 0;
14739
+ if (msg.completed && completedTime < cutoffCompleted) {
14740
+ completedPurged++;
14741
+ continue;
14742
+ }
14743
+ if (!msg.completed && msgTime < cutoffIncomplete) {
14744
+ incompletePurged++;
14745
+ continue;
14746
+ }
14747
+ kept.push(msg);
14748
+ }
14749
+ remaining = kept.length;
14750
+ if (kept.length < all.length) {
14751
+ const content = kept.map((m) => JSON.stringify(m)).join(LINE_SEPARATOR) + LINE_SEPARATOR;
14752
+ await fsp11.writeFile(this.messagePath, content, "utf8");
14753
+ }
14754
+ const { mtimeMs, size } = await this._statMessageFile();
14755
+ this._setMessageCache(kept, mtimeMs, size);
14756
+ });
14757
+ const totalRemoved = expiredPurged + readByAllPurged + completedPurged + incompletePurged;
14758
+ return {
14759
+ expiredRemoved: expiredPurged,
14760
+ readByAllRemoved: readByAllPurged,
14761
+ stalePurged: completedPurged + incompletePurged,
14762
+ totalRemoved,
14763
+ remaining
14764
+ };
14765
+ }
14766
+ startAutoCompactTimer(opts) {
14767
+ if (this._autoCompactTimer !== null) {
14768
+ clearInterval(this._autoCompactTimer);
14769
+ }
14770
+ const intervalMs = opts?.intervalMs ?? AUTO_COMPACT_INTERVAL_MS;
14771
+ const timer = setInterval(() => {
14772
+ this.autoCompact(opts).catch(() => {
14773
+ });
14774
+ }, intervalMs);
14775
+ timer.unref?.();
14776
+ this._autoCompactTimer = timer;
14777
+ return () => {
14778
+ clearInterval(timer);
14779
+ this._autoCompactTimer = null;
14780
+ };
14781
+ }
13598
14782
  // ── Internal ────────────────────────────────────────────────────────────
13599
14783
  /**
13600
14784
  * Read all messages from the JSONL file. Always reads + parses the file.
@@ -13604,7 +14788,7 @@ var GlobalMailbox = class {
13604
14788
  */
13605
14789
  async _readMessages() {
13606
14790
  try {
13607
- const raw = await fsp9.readFile(this.messagePath, "utf8");
14791
+ const raw = await fsp11.readFile(this.messagePath, "utf8");
13608
14792
  return this._parseLines(raw);
13609
14793
  } catch (err) {
13610
14794
  if (err.code === "ENOENT") return [];
@@ -13627,44 +14811,59 @@ var GlobalMailbox = class {
13627
14811
  const buf = Buffer.alloc(tailLen);
13628
14812
  await fd.read(buf, 0, tailLen, oldSize);
13629
14813
  const tail = buf.toString("utf8");
13630
- for (const line of tail.split(LINE_SEPARATOR)) {
14814
+ if (!tail.endsWith(LINE_SEPARATOR)) {
14815
+ const lastSeparatorIdx = tail.lastIndexOf(LINE_SEPARATOR);
14816
+ if (lastSeparatorIdx === -1) {
14817
+ return this._messageCache;
14818
+ }
14819
+ const completeTail = tail.slice(0, lastSeparatorIdx + 1);
14820
+ this._appendIncrementalLines(completeTail);
14821
+ this._messageCacheSize = oldSize + lastSeparatorIdx + 1;
14822
+ return this._messageCache;
14823
+ }
14824
+ this._appendIncrementalLines(tail);
14825
+ this._messageCacheSize = newSize;
14826
+ return this._messageCache;
14827
+ }
14828
+ _appendIncrementalLines(raw) {
14829
+ for (const line of raw.split(LINE_SEPARATOR)) {
13631
14830
  if (!line.trim()) continue;
13632
- try {
13633
- const parsed = JSON.parse(line);
13634
- if (!parsed["readBy"]) {
13635
- const readBy = {};
13636
- if (parsed["read"] && parsed["readAt"]) {
13637
- readBy[parsed["to"]] = parsed["readAt"];
13638
- }
13639
- parsed["readBy"] = readBy;
13640
- delete parsed["read"];
13641
- delete parsed["readAt"];
14831
+ const message = this._parseLine(line);
14832
+ if (message === null) continue;
14833
+ this._messageCache.push(message);
14834
+ const idx = this._messageCache.length - 1;
14835
+ if (this._recipientIndex !== null) {
14836
+ let set = this._recipientIndex.get(message.to);
14837
+ if (set === void 0) {
14838
+ set = /* @__PURE__ */ new Set();
14839
+ this._recipientIndex.set(message.to, set);
13642
14840
  }
13643
- this._messageCache.push(parsed);
13644
- } catch {
14841
+ set.add(idx);
14842
+ }
14843
+ if (this._senderIndex !== null) {
14844
+ let set = this._senderIndex.get(message.from);
14845
+ if (set === void 0) {
14846
+ set = /* @__PURE__ */ new Set();
14847
+ this._senderIndex.set(message.from, set);
14848
+ }
14849
+ set.add(idx);
13645
14850
  }
13646
14851
  }
13647
- return this._messageCache;
14852
+ }
14853
+ _parseLine(line) {
14854
+ try {
14855
+ return parseMailboxMessageLine(line);
14856
+ } catch {
14857
+ return null;
14858
+ }
13648
14859
  }
13649
14860
  /** Parse a JSONL string into MailboxMessage[], including migration. */
13650
14861
  _parseLines(raw) {
13651
14862
  const lines = raw.split(LINE_SEPARATOR).filter((l) => l.trim().length > 0);
13652
14863
  const messages = [];
13653
14864
  for (const line of lines) {
13654
- try {
13655
- const parsed = JSON.parse(line);
13656
- if (!parsed["readBy"]) {
13657
- const readBy = {};
13658
- if (parsed["read"] && parsed["readAt"]) {
13659
- readBy[parsed["to"]] = parsed["readAt"];
13660
- }
13661
- parsed["readBy"] = readBy;
13662
- delete parsed["read"];
13663
- delete parsed["readAt"];
13664
- }
13665
- messages.push(parsed);
13666
- } catch {
13667
- }
14865
+ const message = this._parseLine(line);
14866
+ if (message !== null) messages.push(message);
13668
14867
  }
13669
14868
  return messages;
13670
14869
  }
@@ -13697,7 +14896,7 @@ var GlobalMailbox = class {
13697
14896
  */
13698
14897
  async _statMessageFile() {
13699
14898
  try {
13700
- const st = await fsp9.stat(this.messagePath);
14899
+ const st = await fsp11.stat(this.messagePath);
13701
14900
  return { mtimeMs: st.mtimeMs, size: st.size };
13702
14901
  } catch (err) {
13703
14902
  if (err.code === "ENOENT") {
@@ -13743,16 +14942,15 @@ var GlobalMailbox = class {
13743
14942
  */
13744
14943
  async _readMessagesCachedWork() {
13745
14944
  try {
13746
- const st = await fsp9.stat(this.messagePath);
14945
+ const st = await fsp11.stat(this.messagePath);
13747
14946
  if (this._messageCache !== null && this._messageCacheMtime === st.mtimeMs && this._messageCacheSize === st.size) {
13748
14947
  return this._messageCache;
13749
14948
  }
13750
14949
  if (this._messageCache !== null && this._messageCacheSize >= 0 && st.size > this._messageCacheSize) {
13751
- const fd = await fsp9.open(this.messagePath, "r");
14950
+ const fd = await fsp11.open(this.messagePath, "r");
13752
14951
  try {
13753
14952
  const updated = await this._readNewMessagesOnly(fd, this._messageCacheSize, st.size);
13754
14953
  this._messageCacheMtime = st.mtimeMs;
13755
- this._messageCacheSize = st.size;
13756
14954
  return updated;
13757
14955
  } finally {
13758
14956
  await fd.close();
@@ -13789,11 +14987,46 @@ var GlobalMailbox = class {
13789
14987
  this._messageCache = null;
13790
14988
  this._messageCacheMtime = -1;
13791
14989
  this._messageCacheSize = -1;
14990
+ this._recipientIndex = null;
14991
+ this._senderIndex = null;
13792
14992
  return;
13793
14993
  }
13794
14994
  this._messageCache = messages;
13795
14995
  this._messageCacheMtime = mtime;
13796
14996
  this._messageCacheSize = size;
14997
+ this._rebuildRecipientIndex();
14998
+ }
14999
+ /**
15000
+ * Build the recipient AND sender indexes from the current `_messageCache`.
15001
+ * Called only from `_setMessageCache` so both indexes are always in sync
15002
+ * with a freshly-replaced cache array.
15003
+ */
15004
+ _rebuildRecipientIndex() {
15005
+ const cache = this._messageCache;
15006
+ if (cache === null) {
15007
+ this._recipientIndex = null;
15008
+ this._senderIndex = null;
15009
+ return;
15010
+ }
15011
+ const recIdx = /* @__PURE__ */ new Map();
15012
+ const sndIdx = /* @__PURE__ */ new Map();
15013
+ for (let i = 0; i < cache.length; i++) {
15014
+ const msg = cache[i];
15015
+ let rSet = recIdx.get(msg.to);
15016
+ if (rSet === void 0) {
15017
+ rSet = /* @__PURE__ */ new Set();
15018
+ recIdx.set(msg.to, rSet);
15019
+ }
15020
+ rSet.add(i);
15021
+ let sSet = sndIdx.get(msg.from);
15022
+ if (sSet === void 0) {
15023
+ sSet = /* @__PURE__ */ new Set();
15024
+ sndIdx.set(msg.from, sSet);
15025
+ }
15026
+ sSet.add(i);
15027
+ }
15028
+ this._recipientIndex = recIdx;
15029
+ this._senderIndex = sndIdx;
13797
15030
  }
13798
15031
  /**
13799
15032
  * Append a single just-sent message to the in-memory cache without
@@ -13820,18 +15053,35 @@ var GlobalMailbox = class {
13820
15053
  return;
13821
15054
  }
13822
15055
  this._messageCache.push(msg);
15056
+ const newIdx = this._messageCache.length - 1;
15057
+ if (this._recipientIndex !== null) {
15058
+ let set = this._recipientIndex.get(msg.to);
15059
+ if (set === void 0) {
15060
+ set = /* @__PURE__ */ new Set();
15061
+ this._recipientIndex.set(msg.to, set);
15062
+ }
15063
+ set.add(newIdx);
15064
+ }
15065
+ if (this._senderIndex !== null) {
15066
+ let set = this._senderIndex.get(msg.from);
15067
+ if (set === void 0) {
15068
+ set = /* @__PURE__ */ new Set();
15069
+ this._senderIndex.set(msg.from, set);
15070
+ }
15071
+ set.add(newIdx);
15072
+ }
13823
15073
  this._messageCacheMtime = mtime;
13824
15074
  this._messageCacheSize = size;
13825
15075
  }
13826
15076
  async _ensureRegistry() {
13827
- await fsp9.mkdir(path9.dirname(this.registryPath), { recursive: true });
15077
+ await fsp11.mkdir(path14.dirname(this.registryPath), { recursive: true });
13828
15078
  }
13829
15079
  async _readRegistry(opts) {
13830
15080
  if (!opts?.fresh && this._registryCache && Date.now() - this._registryCacheAt < REGISTRY_CACHE_TTL_MS) {
13831
15081
  return new Map(this._registryCache);
13832
15082
  }
13833
15083
  try {
13834
- const raw = await fsp9.readFile(this.registryPath, "utf8");
15084
+ const raw = await fsp11.readFile(this.registryPath, "utf8");
13835
15085
  const data = JSON.parse(raw);
13836
15086
  const map = /* @__PURE__ */ new Map();
13837
15087
  for (const [id, agent] of Object.entries(data)) {
@@ -13851,21 +15101,12 @@ var GlobalMailbox = class {
13851
15101
  }
13852
15102
  }
13853
15103
  _pruneStaleInPlace(registry) {
13854
- const staleCutoff = Date.now() - AGENT_STALE_MS;
13855
- const purgeCutoff = Date.now() - AGENT_PURGE_MS;
13856
- const toDelete = [];
15104
+ const cutoff = Date.now() - AGENT_STALE_MS;
13857
15105
  for (const [id, agent] of registry) {
13858
- const lastSeen = new Date(agent.lastSeenAt).getTime();
13859
- if (lastSeen < purgeCutoff) {
13860
- toDelete.push(id);
13861
- continue;
15106
+ const lastSeen = Date.parse(agent.lastSeenAt);
15107
+ if (!Number.isFinite(lastSeen) || lastSeen < cutoff) {
15108
+ registry.delete(id);
13862
15109
  }
13863
- if (lastSeen < staleCutoff) {
13864
- agent.status = "idle";
13865
- }
13866
- }
13867
- for (const id of toDelete) {
13868
- registry.delete(id);
13869
15110
  }
13870
15111
  }
13871
15112
  async _writeRegistry(registry) {
@@ -13873,20 +15114,20 @@ var GlobalMailbox = class {
13873
15114
  for (const [id, agent] of registry) {
13874
15115
  obj[id] = agent;
13875
15116
  }
13876
- const tmp = `${this.registryPath}.${randomUUID().slice(0, 8)}.tmp`;
13877
- await fsp9.writeFile(tmp, JSON.stringify(obj), "utf8");
13878
- await fsp9.rename(tmp, this.registryPath);
15117
+ const tmp = `${this.registryPath}.${randomUUID10().slice(0, 8)}.tmp`;
15118
+ await fsp11.writeFile(tmp, JSON.stringify(obj), "utf8");
15119
+ await fsp11.rename(tmp, this.registryPath);
13879
15120
  }
13880
15121
  // ── Client registry internals ───────────────────────────────────────────
13881
15122
  async _ensureClientRegistry() {
13882
- await fsp9.mkdir(path9.dirname(this.clientRegistryPath), { recursive: true });
15123
+ await fsp11.mkdir(path14.dirname(this.clientRegistryPath), { recursive: true });
13883
15124
  }
13884
15125
  async _readClientRegistry(opts) {
13885
15126
  if (!opts?.fresh && this._clientRegistryCache && Date.now() - this._clientRegistryCacheAt < REGISTRY_CACHE_TTL_MS) {
13886
15127
  return new Map(this._clientRegistryCache);
13887
15128
  }
13888
15129
  try {
13889
- const raw = await fsp9.readFile(this.clientRegistryPath, "utf8");
15130
+ const raw = await fsp11.readFile(this.clientRegistryPath, "utf8");
13890
15131
  const data = JSON.parse(raw);
13891
15132
  const map = /* @__PURE__ */ new Map();
13892
15133
  for (const [id, client] of Object.entries(data)) {
@@ -13907,9 +15148,10 @@ var GlobalMailbox = class {
13907
15148
  }
13908
15149
  _pruneStaleClientsInPlace(registry) {
13909
15150
  const cutoff = Date.now() - CLIENT_STALE_MS;
13910
- for (const client of registry.values()) {
13911
- if (new Date(client.lastSeenAt).getTime() < cutoff) {
13912
- client.lastSeenAt = new Date(cutoff).toISOString();
15151
+ for (const [id, client] of registry) {
15152
+ const lastSeen = Date.parse(client.lastSeenAt);
15153
+ if (!Number.isFinite(lastSeen) || lastSeen < cutoff) {
15154
+ registry.delete(id);
13913
15155
  }
13914
15156
  }
13915
15157
  }
@@ -13918,16 +15160,19 @@ var GlobalMailbox = class {
13918
15160
  for (const [id, client] of registry) {
13919
15161
  obj[id] = client;
13920
15162
  }
13921
- const tmp = `${this.clientRegistryPath}.${randomUUID().slice(0, 8)}.tmp`;
13922
- await fsp9.writeFile(tmp, JSON.stringify(obj), "utf8");
13923
- await fsp9.rename(tmp, this.clientRegistryPath);
15163
+ const tmp = `${this.clientRegistryPath}.${randomUUID10().slice(0, 8)}.tmp`;
15164
+ await fsp11.writeFile(tmp, JSON.stringify(obj), "utf8");
15165
+ await fsp11.rename(tmp, this.clientRegistryPath);
13924
15166
  }
13925
15167
  };
15168
+
15169
+ // src/coordination/mailbox-tool.ts
15170
+ import { createHash as createHash5 } from "node:crypto";
13926
15171
  function defaultResolveProjectDir(ctx) {
13927
15172
  return resolveProjectDir(ctx.projectRoot, wstackGlobalRoot());
13928
15173
  }
13929
15174
  function mailboxSessionTag(sessionId) {
13930
- return createHash("sha256").update(sessionId).digest("hex").slice(0, 8);
15175
+ return createHash5("sha256").update(sessionId).digest("hex").slice(0, 8);
13931
15176
  }
13932
15177
  function resolveMailboxIdentity(ctx, fallbackBase = "leader") {
13933
15178
  const fieldId = ctx.agentId && ctx.agentId !== "unknown" ? ctx.agentId : void 0;
@@ -13964,7 +15209,7 @@ function makeMailboxTool(opts = {}) {
13964
15209
  description: "Which mailbox operation to perform."
13965
15210
  },
13966
15211
  to: { type: "string", description: "Recipient agent id, or '*' / 'all' for broadcast." },
13967
- type: { type: "string", enum: ["note", "ask", "assign", "steer", "btw", "broadcast", "status", "result", "review"], description: "Message type." },
15212
+ type: { type: "string", enum: ["note", "ask", "assign", "steer", "btw", "broadcast", "status", "result", "review", "control"], description: "Message type." },
13968
15213
  subject: { type: "string", description: "Short subject line." },
13969
15214
  body: { type: "string", description: "Full message content." },
13970
15215
  priority: { type: "string", enum: ["low", "normal", "high"] },
@@ -14273,6 +15518,9 @@ function makeFleetStatusTool(opts = {}) {
14273
15518
  }
14274
15519
  };
14275
15520
  }
15521
+
15522
+ // src/coordination/fleet-supervisor.ts
15523
+ import { randomUUID as randomUUID11 } from "node:crypto";
14276
15524
  var COLLAB_ID_PREFIXES = ["bug-hunter-", "refactor-planner-", "critic-"];
14277
15525
  var DEFAULTS = {
14278
15526
  intervalMs: 2e4,
@@ -14514,7 +15762,7 @@ var FleetSupervisor = class {
14514
15762
  */
14515
15763
  async decide(question, context, options, risk) {
14516
15764
  const request = {
14517
- id: `fleetsup-${randomUUID()}`,
15765
+ id: `fleetsup-${randomUUID11()}`,
14518
15766
  sessionId: this.opts.sessionId?.(),
14519
15767
  source: "system",
14520
15768
  question,
@@ -15002,6 +16250,11 @@ function makeMailInboxTool(opts = {}) {
15002
16250
  }
15003
16251
  };
15004
16252
  }
16253
+
16254
+ // src/coordination/mailbox.ts
16255
+ import { randomUUID as randomUUID12 } from "node:crypto";
16256
+ import * as fsp12 from "node:fs/promises";
16257
+ import * as path15 from "node:path";
15005
16258
  var MAILBOX_FILE2 = "_mailbox.jsonl";
15006
16259
  var LINE_SEPARATOR2 = "\n";
15007
16260
  var MESSAGE_CACHE_MAX_ENTRIES2 = 1e4;
@@ -15010,14 +16263,18 @@ var DefaultMailbox = class {
15010
16263
  _messageCache = null;
15011
16264
  _messageCacheMtime = -1;
15012
16265
  _messageCacheSize = -1;
16266
+ /** True when the cache is only the newest MESSAGE_CACHE_MAX_ENTRIES records. */
16267
+ _messageCacheTruncated = false;
15013
16268
  /** Primary index: recipient → Set of messages (points into _messageCache). */
15014
16269
  _byTo = /* @__PURE__ */ new Map();
15015
16270
  /** Secondary index: sender → Set of messages (points into _messageCache). */
15016
16271
  _byFrom = /* @__PURE__ */ new Map();
15017
16272
  /** Counts malformed JSONL lines skipped during parsing for observability. */
15018
16273
  _corruptionCount = 0;
15019
- constructor(sessionDir) {
15020
- this.filePath = path9.join(sessionDir, MAILBOX_FILE2);
16274
+ logger;
16275
+ constructor(sessionDir, opts) {
16276
+ this.filePath = path15.join(sessionDir, MAILBOX_FILE2);
16277
+ this.logger = opts?.logger;
15021
16278
  }
15022
16279
  get mailboxPath() {
15023
16280
  return this.filePath;
@@ -15030,12 +16287,12 @@ var DefaultMailbox = class {
15030
16287
  async send(input) {
15031
16288
  const now = (/* @__PURE__ */ new Date()).toISOString();
15032
16289
  const msg = {
15033
- id: randomUUID(),
16290
+ id: randomUUID12(),
15034
16291
  from: input.from,
15035
16292
  // "all" is an accepted spelling of the broadcast address — canonical
15036
16293
  // form on disk is '*' so every query/checker matches it.
15037
16294
  to: normalizeRecipient(input.to),
15038
- type: input.type,
16295
+ type: normalizeMailboxMessageType(input.type),
15039
16296
  subject: input.subject,
15040
16297
  body: input.body,
15041
16298
  priority: input.priority ?? "normal",
@@ -15046,9 +16303,9 @@ var DefaultMailbox = class {
15046
16303
  taskContext: input.taskContext
15047
16304
  };
15048
16305
  const line = JSON.stringify(msg) + LINE_SEPARATOR2;
15049
- await fsp9.mkdir(path9.dirname(this.filePath), { recursive: true });
16306
+ await fsp12.mkdir(path15.dirname(this.filePath), { recursive: true });
15050
16307
  await withFileLock(this.filePath, async () => {
15051
- await fsp9.appendFile(this.filePath, line, "utf8");
16308
+ await fsp12.appendFile(this.filePath, line, "utf8");
15052
16309
  this._pushToCache(msg);
15053
16310
  const { mtime, size } = await this._statUnderLockOrAbsent();
15054
16311
  this._messageCacheMtime = mtime;
@@ -15058,12 +16315,14 @@ var DefaultMailbox = class {
15058
16315
  }
15059
16316
  // ── Query ─────────────────────────────────────────────────────────────
15060
16317
  async query(q) {
16318
+ const queryType = q.type === void 0 ? void 0 : normalizeMailboxMessageType(q.type);
15061
16319
  const needFullScan = q.unreadBy !== void 0 || q.since !== void 0;
16320
+ const cached = await this._readAllCached(false);
15062
16321
  let candidates;
16322
+ let candidatesComplete = !this._messageCacheTruncated || cached !== this._messageCache;
15063
16323
  if (needFullScan) {
15064
- candidates = await this._readAllCached();
16324
+ candidates = cached;
15065
16325
  } else {
15066
- await this._readAllCached();
15067
16326
  if (q.to !== void 0) {
15068
16327
  const direct = this._byTo.get(q.to);
15069
16328
  const broadcast = this._byTo.get("*");
@@ -15071,10 +16330,12 @@ var DefaultMailbox = class {
15071
16330
  if (direct) for (const m of direct) combined.set(m.id, m);
15072
16331
  if (broadcast) for (const m of broadcast) combined.set(m.id, m);
15073
16332
  candidates = Array.from(combined.values());
16333
+ candidatesComplete = !this._messageCacheTruncated;
15074
16334
  } else if (q.from !== void 0) {
15075
16335
  candidates = Array.from(this._byFrom.get(q.from) ?? []);
16336
+ candidatesComplete = !this._messageCacheTruncated;
15076
16337
  } else {
15077
- candidates = await this._readAllCached();
16338
+ candidates = cached;
15078
16339
  }
15079
16340
  }
15080
16341
  const limit = q.limit ?? 50;
@@ -15085,27 +16346,37 @@ var DefaultMailbox = class {
15085
16346
  if (q.from !== void 0 && msg.from !== q.from) return false;
15086
16347
  if (q.unreadBy !== void 0 && q.unreadBy in msg.readBy) return false;
15087
16348
  if (q.incompleteOnly && msg.completed) return false;
15088
- if (q.type !== void 0 && msg.type !== q.type) return false;
16349
+ if (queryType !== void 0 && msg.type !== queryType) return false;
15089
16350
  if (order !== null && (order[msg.priority] ?? 1) < minPriorityRank)
15090
16351
  return false;
15091
16352
  if (q.since !== void 0 && msg.timestamp <= q.since) return false;
15092
16353
  return true;
15093
16354
  };
15094
- if (order === null) {
16355
+ const selectNewest = (source) => {
15095
16356
  const out = [];
15096
- for (let i = candidates.length - 1; i >= 0 && out.length < limit; i--) {
15097
- const msg = candidates[i];
16357
+ for (let i = source.length - 1; i >= 0 && out.length < limit; i--) {
16358
+ const msg = source[i];
15098
16359
  if (passes(msg)) out.push(msg);
15099
16360
  }
15100
16361
  return out;
15101
- }
15102
- const filtered = [];
15103
- for (let i = candidates.length - 1; i >= 0; i--) {
15104
- const msg = candidates[i];
15105
- if (passes(msg)) filtered.push(msg);
15106
- }
15107
- filtered.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
15108
- return filtered.slice(0, limit);
16362
+ };
16363
+ if (order === null) {
16364
+ const out = selectNewest(candidates);
16365
+ if (out.length >= limit || candidatesComplete) return out;
16366
+ return selectNewest(await this._readAll());
16367
+ }
16368
+ const selectByPriority = (source) => {
16369
+ const filtered2 = [];
16370
+ for (let i = source.length - 1; i >= 0; i--) {
16371
+ const msg = source[i];
16372
+ if (passes(msg)) filtered2.push(msg);
16373
+ }
16374
+ filtered2.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
16375
+ return filtered2.slice(0, limit);
16376
+ };
16377
+ const filtered = selectByPriority(candidates);
16378
+ if (filtered.length >= limit || candidatesComplete) return filtered;
16379
+ return selectByPriority(await this._readAll());
15109
16380
  }
15110
16381
  // ── Ack ───────────────────────────────────────────────────────────────
15111
16382
  async ack(input) {
@@ -15148,7 +16419,7 @@ var DefaultMailbox = class {
15148
16419
  }
15149
16420
  if (changed) {
15150
16421
  const serialized = all.map((m) => JSON.stringify(m)).join(LINE_SEPARATOR2) + LINE_SEPARATOR2;
15151
- await fsp9.writeFile(this.filePath, serialized, "utf8");
16422
+ await fsp12.writeFile(this.filePath, serialized, "utf8");
15152
16423
  }
15153
16424
  const { mtime, size } = await this._statUnderLockOrAbsent();
15154
16425
  this._setMessageCache(all, mtime, size);
@@ -15162,7 +16433,7 @@ var DefaultMailbox = class {
15162
16433
  for (const m of all) {
15163
16434
  if (m.type !== "status") continue;
15164
16435
  const existing = latest.get(m.from);
15165
- if (existing && m.timestamp <= existing.lastActivityAt) continue;
16436
+ if (existing && m.timestamp < existing.lastActivityAt) continue;
15166
16437
  latest.set(m.from, {
15167
16438
  agentId: m.from,
15168
16439
  name: m.taskContext?.agentName ?? m.from,
@@ -15204,12 +16475,13 @@ var DefaultMailbox = class {
15204
16475
  this._messageCache = null;
15205
16476
  this._messageCacheMtime = -1;
15206
16477
  this._messageCacheSize = -1;
16478
+ this._messageCacheTruncated = false;
15207
16479
  this._byTo.clear();
15208
16480
  this._byFrom.clear();
15209
16481
  }
15210
16482
  async clearAll() {
15211
16483
  await withFileLock(this.filePath, async () => {
15212
- await fsp9.writeFile(this.filePath, "", "utf8");
16484
+ await fsp12.writeFile(this.filePath, "", "utf8");
15213
16485
  const { mtime, size } = await this._statUnderLockOrAbsent();
15214
16486
  this._setMessageCache([], mtime, size);
15215
16487
  });
@@ -15242,7 +16514,7 @@ var DefaultMailbox = class {
15242
16514
  remaining = kept.length;
15243
16515
  if (kept.length < all.length) {
15244
16516
  const content = kept.map((m) => JSON.stringify(m)).join(LINE_SEPARATOR2) + LINE_SEPARATOR2;
15245
- await fsp9.writeFile(this.filePath, content, "utf8");
16517
+ await fsp12.writeFile(this.filePath, content, "utf8");
15246
16518
  }
15247
16519
  const { mtime, size } = await this._statUnderLockOrAbsent();
15248
16520
  this._setMessageCache(kept, mtime, size);
@@ -15255,17 +16527,36 @@ var DefaultMailbox = class {
15255
16527
  };
15256
16528
  }
15257
16529
  // ── Client registry stubs (not applicable per-session) ─────────────────
16530
+ async autoCompact(_opts) {
16531
+ const purged = await this.purgeStale(_opts);
16532
+ return {
16533
+ readByAllRemoved: 0,
16534
+ expiredRemoved: 0,
16535
+ stalePurged: purged.totalPurged,
16536
+ totalRemoved: purged.totalPurged,
16537
+ remaining: purged.remaining
16538
+ };
16539
+ }
16540
+ startAutoCompactTimer(_opts) {
16541
+ return () => {
16542
+ };
16543
+ }
15258
16544
  async registerClient(_input) {
15259
16545
  }
15260
16546
  async clientHeartbeat(_input) {
15261
16547
  }
16548
+ async deregisterClient(_clientId) {
16549
+ }
15262
16550
  async getClientStatuses() {
15263
16551
  return [];
15264
16552
  }
16553
+ async purgeClients() {
16554
+ return 0;
16555
+ }
15265
16556
  // ── Internal ──────────────────────────────────────────────────────────
15266
16557
  async _readAll() {
15267
16558
  try {
15268
- const raw = await fsp9.readFile(this.filePath, "utf8");
16559
+ const raw = await fsp12.readFile(this.filePath, "utf8");
15269
16560
  return this._parseLines(raw);
15270
16561
  } catch (err) {
15271
16562
  if (err.code === "ENOENT") return [];
@@ -15275,60 +16566,62 @@ var DefaultMailbox = class {
15275
16566
  /**
15276
16567
  * Read only newly-appended bytes from the file and append them to the
15277
16568
  * in-memory cache, avoiding a full re-read when the file only grew.
16569
+ *
16570
+ * Guards against a half-written tail: when the tail doesn't end with
16571
+ * LINE_SEPARATOR, another process may be mid-append. Parsing a partial
16572
+ * JSON line would throw (caught below), but worse: the NEXT incremental
16573
+ * read would skip that same line because the size tracker already advanced.
15278
16574
  */
15279
16575
  async _readNewMessagesOnly(fd, oldSize, newSize) {
15280
16576
  const tailLen = newSize - oldSize;
15281
16577
  const buf = Buffer.alloc(tailLen);
15282
16578
  await fd.read(buf, 0, tailLen, oldSize);
15283
16579
  const tail = buf.toString("utf8");
15284
- for (const line of tail.split(LINE_SEPARATOR2)) {
16580
+ if (!tail.endsWith(LINE_SEPARATOR2)) {
16581
+ const lastSeparatorIdx = tail.lastIndexOf(LINE_SEPARATOR2);
16582
+ if (lastSeparatorIdx === -1) {
16583
+ return this._messageCache;
16584
+ }
16585
+ const completeTail = tail.slice(0, lastSeparatorIdx + 1);
16586
+ this._appendIncrementalLines(completeTail);
16587
+ this._messageCacheSize = oldSize + lastSeparatorIdx + 1;
16588
+ return this._messageCache;
16589
+ }
16590
+ this._appendIncrementalLines(tail);
16591
+ this._messageCacheSize = newSize;
16592
+ return this._messageCache;
16593
+ }
16594
+ _appendIncrementalLines(raw) {
16595
+ for (const line of raw.split(LINE_SEPARATOR2)) {
15285
16596
  if (!line.trim()) continue;
15286
- try {
15287
- const parsed = JSON.parse(line);
15288
- if (!parsed["readBy"]) {
15289
- const readBy = {};
15290
- if (parsed["read"] && parsed["readAt"]) {
15291
- readBy[parsed["to"] ?? "unknown"] = parsed["readAt"];
15292
- }
15293
- parsed["readBy"] = readBy;
15294
- delete parsed["read"];
15295
- delete parsed["readAt"];
15296
- }
15297
- const msg = parsed;
15298
- this._messageCache.push(msg);
15299
- this._indexMsg(msg);
15300
- } catch (err) {
15301
- this._corruptionCount++;
15302
- console.debug(
15303
- `[mailbox] skipped malformed line during incremental read: ${err.message}`
16597
+ const msg = this._parseLine(line, "incremental read");
16598
+ if (msg === null) continue;
16599
+ this._pushToCache(msg);
16600
+ }
16601
+ }
16602
+ _parseLine(line, source) {
16603
+ try {
16604
+ return parseMailboxMessageLine(line);
16605
+ } catch (err) {
16606
+ this._corruptionCount++;
16607
+ if (this.logger) {
16608
+ this.logger.debug(
16609
+ "Skipped malformed mailbox line",
16610
+ { source, error: err.message, corruptionCount: this._corruptionCount }
15304
16611
  );
16612
+ } else {
16613
+ console.debug(`[mailbox] skipped malformed line during ${source}: ${err.message}`);
15305
16614
  }
16615
+ return null;
15306
16616
  }
15307
- return this._messageCache;
15308
16617
  }
15309
16618
  /** Parse a JSONL string into MailboxMessage[], including migration. */
15310
16619
  _parseLines(raw) {
15311
16620
  const lines = raw.split(LINE_SEPARATOR2).filter((l) => l.trim().length > 0);
15312
16621
  const messages = [];
15313
16622
  for (const line of lines) {
15314
- try {
15315
- const parsed = JSON.parse(line);
15316
- if (!parsed["readBy"]) {
15317
- const readBy = {};
15318
- if (parsed["read"] && parsed["readAt"]) {
15319
- readBy[parsed["to"] ?? "unknown"] = parsed["readAt"];
15320
- }
15321
- parsed["readBy"] = readBy;
15322
- delete parsed["read"];
15323
- delete parsed["readAt"];
15324
- }
15325
- messages.push(parsed);
15326
- } catch (err) {
15327
- this._corruptionCount++;
15328
- console.debug(
15329
- `[mailbox] skipped malformed line during full parse: ${err.message}`
15330
- );
15331
- }
16623
+ const message = this._parseLine(line, "full parse");
16624
+ if (message !== null) messages.push(message);
15332
16625
  }
15333
16626
  return messages;
15334
16627
  }
@@ -15340,7 +16633,7 @@ var DefaultMailbox = class {
15340
16633
  */
15341
16634
  async _statUnderLockOrAbsent() {
15342
16635
  try {
15343
- const st = await fsp9.stat(this.filePath);
16636
+ const st = await fsp12.stat(this.filePath);
15344
16637
  return { mtime: st.mtimeMs, size: st.size };
15345
16638
  } catch (err) {
15346
16639
  if (err.code === "ENOENT") {
@@ -15349,18 +16642,19 @@ var DefaultMailbox = class {
15349
16642
  throw err;
15350
16643
  }
15351
16644
  }
15352
- async _readAllCached() {
16645
+ async _readAllCached(requireComplete = true) {
15353
16646
  try {
15354
- const st = await fsp9.stat(this.filePath);
16647
+ const st = await fsp12.stat(this.filePath);
15355
16648
  if (this._messageCache !== null && this._messageCacheMtime === st.mtimeMs && this._messageCacheSize === st.size) {
16649
+ if (requireComplete && this._messageCacheTruncated) return this._readAll();
15356
16650
  return this._messageCache;
15357
16651
  }
15358
16652
  if (this._messageCache !== null && this._messageCacheSize >= 0 && st.size > this._messageCacheSize) {
15359
- const fd = await fsp9.open(this.filePath, "r");
16653
+ const fd = await fsp12.open(this.filePath, "r");
15360
16654
  try {
15361
16655
  const updated = await this._readNewMessagesOnly(fd, this._messageCacheSize, st.size);
15362
16656
  this._messageCacheMtime = st.mtimeMs;
15363
- this._messageCacheSize = st.size;
16657
+ if (requireComplete && this._messageCacheTruncated) return this._readAll();
15364
16658
  return updated;
15365
16659
  } finally {
15366
16660
  await fd.close();
@@ -15378,28 +16672,18 @@ var DefaultMailbox = class {
15378
16672
  }
15379
16673
  }
15380
16674
  _setMessageCache(messages, mtime, size) {
15381
- if (messages.length > MESSAGE_CACHE_MAX_ENTRIES2) {
15382
- this._messageCache = null;
15383
- this._messageCacheMtime = -1;
15384
- this._messageCacheSize = -1;
15385
- this._byTo.clear();
15386
- this._byFrom.clear();
15387
- return;
15388
- }
15389
- this._messageCache = messages;
15390
- this._buildIndexes(messages);
16675
+ this._messageCacheTruncated = messages.length > MESSAGE_CACHE_MAX_ENTRIES2;
16676
+ this._messageCache = this._messageCacheTruncated ? messages.slice(-MESSAGE_CACHE_MAX_ENTRIES2) : messages;
16677
+ this._buildIndexes(this._messageCache);
15391
16678
  this._messageCacheMtime = mtime;
15392
16679
  this._messageCacheSize = size;
15393
16680
  }
15394
16681
  _pushToCache(msg) {
15395
16682
  if (this._messageCache === null) return;
15396
16683
  if (this._messageCache.length >= MESSAGE_CACHE_MAX_ENTRIES2) {
15397
- this._messageCache = null;
15398
- this._messageCacheMtime = -1;
15399
- this._messageCacheSize = -1;
15400
- this._byTo.clear();
15401
- this._byFrom.clear();
15402
- return;
16684
+ const evicted = this._messageCache.shift();
16685
+ if (evicted !== void 0) this._unindexMsg(evicted);
16686
+ this._messageCacheTruncated = true;
15403
16687
  }
15404
16688
  this._messageCache.push(msg);
15405
16689
  this._indexMsg(msg);
@@ -15427,6 +16711,15 @@ var DefaultMailbox = class {
15427
16711
  this._byFrom.set(msg.from, /* @__PURE__ */ new Set([msg]));
15428
16712
  }
15429
16713
  }
16714
+ /** Remove an evicted message from both indexes without rebuilding them. */
16715
+ _unindexMsg(msg) {
16716
+ const toSet = this._byTo.get(msg.to);
16717
+ toSet?.delete(msg);
16718
+ if (toSet?.size === 0) this._byTo.delete(msg.to);
16719
+ const fromSet = this._byFrom.get(msg.from);
16720
+ fromSet?.delete(msg);
16721
+ if (fromSet?.size === 0) this._byFrom.delete(msg.from);
16722
+ }
15430
16723
  };
15431
16724
 
15432
16725
  // src/coordination/mailbox-actions.ts
@@ -15695,14 +16988,18 @@ function createMailboxHooks(opts) {
15695
16988
 
15696
16989
  // src/coordination/null-fleet-bus.ts
15697
16990
  var NULL_FLEET_BUS = new FleetBus();
16991
+
16992
+ // src/coordination/package-author-tracker.ts
16993
+ import * as fs2 from "node:fs/promises";
16994
+ import * as path16 from "node:path";
15698
16995
  var DEFAULT_MAX_ENTRIES = 1e4;
15699
16996
  var LOG_FILENAME = "package-authors.json";
15700
16997
  function logPath(storageDir) {
15701
- return path9.join(storageDir, LOG_FILENAME);
16998
+ return path16.join(storageDir, LOG_FILENAME);
15702
16999
  }
15703
17000
  async function loadLog(storageDir, projectRoot) {
15704
17001
  try {
15705
- const raw = await fsp9.readFile(logPath(storageDir), "utf-8");
17002
+ const raw = await fs2.readFile(logPath(storageDir), "utf-8");
15706
17003
  const parsed = JSON.parse(raw);
15707
17004
  if (!parsed.entries || !Array.isArray(parsed.entries)) {
15708
17005
  return { projectRoot, entries: [] };
@@ -15716,13 +17013,13 @@ async function loadLog(storageDir, projectRoot) {
15716
17013
  }
15717
17014
  }
15718
17015
  async function saveLog(storageDir, log) {
15719
- await fsp9.mkdir(storageDir, { recursive: true });
17016
+ await fs2.mkdir(storageDir, { recursive: true });
15720
17017
  const tmp = `${logPath(storageDir)}.tmp.${Date.now()}`;
15721
- await fsp9.writeFile(tmp, JSON.stringify(log, null, 2) + "\n", "utf-8");
15722
- await fsp9.rename(tmp, logPath(storageDir));
17018
+ await fs2.writeFile(tmp, JSON.stringify(log, null, 2) + "\n", "utf-8");
17019
+ await fs2.rename(tmp, logPath(storageDir));
15723
17020
  }
15724
17021
  function detectEcosystem(manifestPath) {
15725
- const name = path9.basename(manifestPath).toLowerCase();
17022
+ const name = path16.win32.basename(manifestPath).toLowerCase();
15726
17023
  if (name === "package.json") return "npm";
15727
17024
  if (name === "go.mod") return "go";
15728
17025
  if (name === "cargo.toml") return "cargo";
@@ -15967,11 +17264,18 @@ mvn versions:use-latest-versions`;
15967
17264
  return `# Update ${entry.name} to ${entry.latestVersion} using your package manager`;
15968
17265
  }
15969
17266
  }
17267
+
17268
+ // src/coordination/single-instance-mailbox.ts
17269
+ import { randomBytes as randomBytes3 } from "node:crypto";
17270
+ import * as fsp13 from "node:fs/promises";
17271
+ import { execFileSync } from "node:child_process";
17272
+ import * as os3 from "node:os";
17273
+ import * as path17 from "node:path";
15970
17274
  var MAILBOX_BRIDGE_LOCK_FILENAME = ".mailbox-bridge.lock";
15971
17275
  var MAILBOX_BRIDGE_TOKEN_FILENAME = ".mailbox.token";
15972
17276
  async function acquireOrJoin(opts) {
15973
- const lockPath = path9.join(opts.projectDir, MAILBOX_BRIDGE_LOCK_FILENAME);
15974
- const tokenPath = path9.join(opts.projectDir, MAILBOX_BRIDGE_TOKEN_FILENAME);
17277
+ const lockPath = path17.join(opts.projectDir, MAILBOX_BRIDGE_LOCK_FILENAME);
17278
+ const tokenPath = path17.join(opts.projectDir, MAILBOX_BRIDGE_TOKEN_FILENAME);
15975
17279
  const inspected = await readLockForInspection(lockPath);
15976
17280
  if (inspected.kind === "live") {
15977
17281
  const existing = inspected.lock;
@@ -15981,10 +17285,10 @@ async function acquireOrJoin(opts) {
15981
17285
  return { kind: "joined", lock: existing, tokenPath };
15982
17286
  }
15983
17287
  if (inspected.kind === "stale") {
15984
- await fsp9.unlink(lockPath).catch(() => void 0);
17288
+ await fsp13.unlink(lockPath).catch(() => void 0);
15985
17289
  }
15986
17290
  const generation = inspected.kind === "stale" ? inspected.lock.generation + 1 : 1;
15987
- const token = randomBytes(32).toString("hex");
17291
+ const token = randomBytes3(32).toString("hex");
15988
17292
  const tentative = {
15989
17293
  pid: process.pid,
15990
17294
  host: opts.host,
@@ -15999,34 +17303,34 @@ async function acquireOrJoin(opts) {
15999
17303
  return { kind: "acquired", lock: tentative, tokenPath };
16000
17304
  }
16001
17305
  async function finalize(projectDir, tentative, boundPort) {
16002
- const lockPath = path9.join(projectDir, MAILBOX_BRIDGE_LOCK_FILENAME);
16003
- const tokenPath = path9.join(projectDir, MAILBOX_BRIDGE_TOKEN_FILENAME);
17306
+ const lockPath = path17.join(projectDir, MAILBOX_BRIDGE_LOCK_FILENAME);
17307
+ const tokenPath = path17.join(projectDir, MAILBOX_BRIDGE_TOKEN_FILENAME);
16004
17308
  const finalized = {
16005
17309
  ...tentative,
16006
17310
  port: boundPort,
16007
17311
  url: `http://${tentative.host}:${boundPort}`
16008
17312
  };
16009
17313
  await atomicWriteJson(lockPath, finalized);
16010
- await fsp9.writeFile(tokenPath, finalized.token, { mode: 384 });
17314
+ await fsp13.writeFile(tokenPath, finalized.token, { mode: 384 });
16011
17315
  return finalized;
16012
17316
  }
16013
17317
  async function release(projectDir, generation) {
16014
- const lockPath = path9.join(projectDir, MAILBOX_BRIDGE_LOCK_FILENAME);
16015
- const tokenPath = path9.join(projectDir, MAILBOX_BRIDGE_TOKEN_FILENAME);
17318
+ const lockPath = path17.join(projectDir, MAILBOX_BRIDGE_LOCK_FILENAME);
17319
+ const tokenPath = path17.join(projectDir, MAILBOX_BRIDGE_TOKEN_FILENAME);
16016
17320
  try {
16017
- const raw = await fsp9.readFile(lockPath, "utf-8");
17321
+ const raw = await fsp13.readFile(lockPath, "utf-8");
16018
17322
  const parsed = JSON.parse(raw);
16019
17323
  if (parsed.generation !== generation) return;
16020
17324
  if (parsed.pid !== process.pid) return;
16021
- await fsp9.unlink(lockPath).catch(() => void 0);
16022
- await fsp9.unlink(tokenPath).catch(() => void 0);
17325
+ await fsp13.unlink(lockPath).catch(() => void 0);
17326
+ await fsp13.unlink(tokenPath).catch(() => void 0);
16023
17327
  } catch {
16024
17328
  }
16025
17329
  }
16026
17330
  async function readLockForInspection(lockPath) {
16027
17331
  let raw;
16028
17332
  try {
16029
- raw = await fsp9.readFile(lockPath, "utf-8");
17333
+ raw = await fsp13.readFile(lockPath, "utf-8");
16030
17334
  } catch {
16031
17335
  return { kind: "absent" };
16032
17336
  }
@@ -16034,7 +17338,7 @@ async function readLockForInspection(lockPath) {
16034
17338
  try {
16035
17339
  parsed = JSON.parse(raw);
16036
17340
  } catch {
16037
- await fsp9.unlink(lockPath).catch(() => void 0);
17341
+ await fsp13.unlink(lockPath).catch(() => void 0);
16038
17342
  return { kind: "absent" };
16039
17343
  }
16040
17344
  if (!isProcessAlive(parsed.pid)) {
@@ -16046,7 +17350,7 @@ async function readLockForInspection(lockPath) {
16046
17350
  return { kind: "live", lock: parsed };
16047
17351
  }
16048
17352
  async function readLiveLock(projectDir) {
16049
- const lockPath = path9.join(projectDir, MAILBOX_BRIDGE_LOCK_FILENAME);
17353
+ const lockPath = path17.join(projectDir, MAILBOX_BRIDGE_LOCK_FILENAME);
16050
17354
  const result = await readLockForInspection(lockPath);
16051
17355
  if (result.kind === "live") {
16052
17356
  return { kind: "live", lock: result.lock };
@@ -16057,28 +17361,29 @@ async function readLiveLock(projectDir) {
16057
17361
  return { kind: "absent" };
16058
17362
  }
16059
17363
  async function atomicWriteJson(targetPath, value) {
16060
- const dir = path9.dirname(targetPath);
16061
- await fsp9.mkdir(dir, { recursive: true });
16062
- const tmp = `${targetPath}.tmp.${process.pid}.${randomBytes(4).toString("hex")}`;
17364
+ const dir = path17.dirname(targetPath);
17365
+ await fsp13.mkdir(dir, { recursive: true });
17366
+ const tmp = `${targetPath}.tmp.${process.pid}.${randomBytes3(4).toString("hex")}`;
16063
17367
  const body = JSON.stringify(value, null, 2) + "\n";
16064
- await fsp9.writeFile(tmp, body, { mode: 384 });
17368
+ await fsp13.writeFile(tmp, body, { mode: 384 });
16065
17369
  try {
16066
- await fsp9.rename(tmp, targetPath);
17370
+ await fsp13.rename(tmp, targetPath);
16067
17371
  } catch (err) {
16068
- await fsp9.unlink(tmp).catch(() => void 0);
17372
+ await fsp13.unlink(tmp).catch(() => void 0);
16069
17373
  throw err;
16070
17374
  }
16071
17375
  }
16072
17376
  function isProcessAlive(pid) {
16073
17377
  if (!Number.isInteger(pid) || pid <= 0) return false;
16074
17378
  if (pid === process.pid) return true;
16075
- if (os.platform() === "win32") {
17379
+ if (os3.platform() === "win32") {
16076
17380
  try {
16077
17381
  const out = execFileSync("tasklist", ["/FI", `PID eq ${pid}`, "/NH", "/FO", "CSV"], {
16078
17382
  encoding: "utf-8",
16079
17383
  stdio: ["pipe", "pipe", "pipe"]
16080
17384
  });
16081
- return /\b"?,?\d+,?"?/.test(out) || out.includes(String(pid));
17385
+ const match = /(?:^|\n)"[^"]*","(\d+)"/.exec(out);
17386
+ return match !== null && match[1] === String(pid);
16082
17387
  } catch {
16083
17388
  return false;
16084
17389
  }
@@ -16279,7 +17584,11 @@ var AdaptiveConcurrencyController = class {
16279
17584
  };
16280
17585
  }
16281
17586
  };
16282
- var AgentMonitorService = class {
17587
+
17588
+ // src/coordination/agent-monitor.ts
17589
+ import * as fs3 from "node:fs/promises";
17590
+ import * as path18 from "node:path";
17591
+ var AgentMonitorService = class _AgentMonitorService {
16283
17592
  _fleetBus;
16284
17593
  _events;
16285
17594
  _sessionId;
@@ -16289,6 +17598,15 @@ var AgentMonitorService = class {
16289
17598
  _onEntry;
16290
17599
  /** Per-subagent virtual sessions. */
16291
17600
  _sessions = /* @__PURE__ */ new Map();
17601
+ /**
17602
+ * Per-subagent OPEN streaming segment. Provider text/thinking deltas
17603
+ * arrive word-by-word; writing one transcript entry per delta fragments
17604
+ * every surface (ring, JSONL, HQ) into unreadable single-word lines.
17605
+ * Instead, consecutive same-kind/same-iteration deltas append into ONE
17606
+ * entry that is already in the ring (live views see it grow in place);
17607
+ * the JSONL line is written once, when the segment closes.
17608
+ */
17609
+ _openStreams = /* @__PURE__ */ new Map();
16292
17610
  /** Disposers for FleetBus subscriptions, keyed by subagentId. */
16293
17611
  _subscriptions = /* @__PURE__ */ new Map();
16294
17612
  /** Generic fleet-wide subscription disposer. */
@@ -16351,6 +17669,9 @@ var AgentMonitorService = class {
16351
17669
  stop() {
16352
17670
  if (!this._started) return;
16353
17671
  this._started = false;
17672
+ for (const subagentId of [...this._openStreams.keys()]) {
17673
+ this._closeStream(subagentId);
17674
+ }
16354
17675
  if (this._fleetDisposer) {
16355
17676
  this._fleetDisposer();
16356
17677
  this._fleetDisposer = void 0;
@@ -16417,6 +17738,14 @@ var AgentMonitorService = class {
16417
17738
  task: session.task
16418
17739
  });
16419
17740
  }
17741
+ /** Drop a retired subagent from every live in-memory monitor surface. */
17742
+ removeSubagent(subagentId) {
17743
+ this._closeStream(subagentId);
17744
+ this._sessions.delete(subagentId);
17745
+ const dispose = this._subscriptions.get(subagentId);
17746
+ if (dispose) dispose();
17747
+ this._subscriptions.delete(subagentId);
17748
+ }
16420
17749
  // ── Internal ───────────────────────────────────────────────────────
16421
17750
  _routeEvent(subagentId, type, payload) {
16422
17751
  const session = this._sessions.get(subagentId);
@@ -16425,31 +17754,13 @@ var AgentMonitorService = class {
16425
17754
  case "provider.text_delta": {
16426
17755
  const text = payload.text;
16427
17756
  if (!text || text.length === 0) return;
16428
- const iteration = payload.iteration ?? 0;
16429
- this._addEntry(subagentId, {
16430
- id: this._uid(),
16431
- subagentId,
16432
- agentName: session.agentName,
16433
- ts: (/* @__PURE__ */ new Date()).toISOString(),
16434
- kind: "text",
16435
- content: text,
16436
- iteration
16437
- });
17757
+ this._appendStreamDelta(subagentId, session, "text", text, payload.iteration ?? 0);
16438
17758
  break;
16439
17759
  }
16440
17760
  case "provider.thinking_delta": {
16441
17761
  const text = payload.text;
16442
17762
  if (!text || text.length === 0) return;
16443
- const iteration = payload.iteration ?? 0;
16444
- this._addEntry(subagentId, {
16445
- id: this._uid(),
16446
- subagentId,
16447
- agentName: session.agentName,
16448
- ts: (/* @__PURE__ */ new Date()).toISOString(),
16449
- kind: "thinking",
16450
- content: text,
16451
- iteration
16452
- });
17763
+ this._appendStreamDelta(subagentId, session, "thinking", text, payload.iteration ?? 0);
16453
17764
  break;
16454
17765
  }
16455
17766
  case "tool.started": {
@@ -16506,15 +17817,66 @@ var AgentMonitorService = class {
16506
17817
  }
16507
17818
  }
16508
17819
  }
17820
+ /** Max characters accumulated into one streaming segment before rolling over. */
17821
+ static _MAX_SEGMENT_CHARS = 2e4;
17822
+ /**
17823
+ * Fold a provider text/thinking delta into the subagent's open streaming
17824
+ * segment, or open a new one. A segment breaks on kind change, iteration
17825
+ * change, size cap, or any non-delta entry (see `_addEntry`). The entry
17826
+ * is pushed to the ring when the segment OPENS (live views poll the ring
17827
+ * and watch it grow in place); the JSONL line AND the timeline/HQ
17828
+ * announcement happen once, on close, with the COMPLETE segment — so
17829
+ * downstream consumers get one whole message instead of a word-per-event
17830
+ * firehose (or, worse, only the first word).
17831
+ */
17832
+ _appendStreamDelta(subagentId, session, kind, text, iteration) {
17833
+ const open7 = this._openStreams.get(subagentId);
17834
+ if (open7 && open7.entry.kind === kind && open7.entry.iteration === iteration && open7.entry.content.length + text.length <= _AgentMonitorService._MAX_SEGMENT_CHARS) {
17835
+ open7.entry.content += text;
17836
+ return;
17837
+ }
17838
+ this._closeStream(subagentId);
17839
+ const entry = {
17840
+ id: this._uid(),
17841
+ subagentId,
17842
+ agentName: session.agentName,
17843
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
17844
+ kind,
17845
+ content: text,
17846
+ iteration
17847
+ };
17848
+ this._openStreams.set(subagentId, { entry });
17849
+ session.transcript.push(entry);
17850
+ if (session.transcript.length > this._maxEntries) {
17851
+ session.transcript.splice(0, session.transcript.length - this._maxEntries);
17852
+ }
17853
+ }
17854
+ /**
17855
+ * Close the subagent's open streaming segment: persist it to JSONL and
17856
+ * announce the completed entry on the local bus + HQ callback.
17857
+ */
17858
+ _closeStream(subagentId) {
17859
+ const open7 = this._openStreams.get(subagentId);
17860
+ if (!open7) return;
17861
+ this._openStreams.delete(subagentId);
17862
+ this._appendToFile(subagentId, open7.entry).catch(() => {
17863
+ });
17864
+ this._emitEntry(open7.entry);
17865
+ }
16509
17866
  _addEntry(subagentId, entry) {
16510
17867
  const session = this._sessions.get(subagentId);
16511
17868
  if (!session) return;
17869
+ this._closeStream(subagentId);
16512
17870
  session.transcript.push(entry);
16513
17871
  if (session.transcript.length > this._maxEntries) {
16514
17872
  session.transcript.splice(0, session.transcript.length - this._maxEntries);
16515
17873
  }
16516
17874
  this._appendToFile(subagentId, entry).catch(() => {
16517
17875
  });
17876
+ this._emitEntry(entry);
17877
+ }
17878
+ /** Announce a transcript entry on the local bus + HQ callback. */
17879
+ _emitEntry(entry) {
16518
17880
  this._events.emit("agent.timeline.message", {
16519
17881
  sessionId: this._sessionId,
16520
17882
  subagentId: entry.subagentId,
@@ -16529,11 +17891,11 @@ var AgentMonitorService = class {
16529
17891
  this._onEntry?.(entry);
16530
17892
  }
16531
17893
  async _appendToFile(subagentId, entry) {
16532
- const dir = path9.join(this._transcriptsDir, subagentId);
16533
- await fsp9.mkdir(dir, { recursive: true });
16534
- const filePath = path9.join(dir, "transcript.jsonl");
17894
+ const dir = path18.join(this._transcriptsDir, subagentId);
17895
+ await fs3.mkdir(dir, { recursive: true });
17896
+ const filePath = path18.join(dir, "transcript.jsonl");
16535
17897
  const line = JSON.stringify(entry) + "\n";
16536
- await fsp9.appendFile(filePath, line, { encoding: "utf8" });
17898
+ await fs3.appendFile(filePath, line, { encoding: "utf8" });
16537
17899
  }
16538
17900
  _uid() {
16539
17901
  return `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
@@ -16541,8 +17903,11 @@ var AgentMonitorService = class {
16541
17903
  _formatToolUse(name, input) {
16542
17904
  if (input === void 0) return `${name}()`;
16543
17905
  const body = this._stringifyForTimeline(input);
16544
- return body ? `${name}
16545
- ${body}` : `${name}()`;
17906
+ if (!body) return `${name}()`;
17907
+ const inline = body.replace(/\s+/g, " ").trim();
17908
+ const head = inline.length <= 160 ? `${name}(${inline})` : `${name}(${inline.slice(0, 159)}\u2026)`;
17909
+ return `${head}
17910
+ ${body}`;
16546
17911
  }
16547
17912
  _formatToolResult(summary, output, outputBytes) {
16548
17913
  if (!output) return summary;
@@ -16568,6 +17933,9 @@ ${output}${suffix}`;
16568
17933
  function createAgentMonitorService(opts) {
16569
17934
  return new AgentMonitorService(opts);
16570
17935
  }
17936
+
17937
+ // src/coordination/autonomous-brain.ts
17938
+ import { randomUUID as randomUUID13 } from "node:crypto";
16571
17939
  var AutonomousBrain = class {
16572
17940
  graph;
16573
17941
  // Fleet bus for emitting decisions — null-safe, no-op if not provided
@@ -16576,8 +17944,6 @@ var AutonomousBrain = class {
16576
17944
  maxRetries;
16577
17945
  consensusRiskThreshold;
16578
17946
  selfImprove;
16579
- /** Decision history for self-improvement and audit. */
16580
- decisionHistory = [];
16581
17947
  /** Tracks failure patterns for self-improvement. */
16582
17948
  failurePatterns = /* @__PURE__ */ new Map();
16583
17949
  RISK_ORDER = ["low", "medium", "high", "critical"];
@@ -16675,7 +18041,7 @@ var AutonomousBrain = class {
16675
18041
  consequence: i === 0 ? `Spawn the most appropriate agent for: ${taskDescription.slice(0, 80)}` : `Spawn an alternative agent for the same task`
16676
18042
  }));
16677
18043
  return this.decideAuto({
16678
- id: randomUUID(),
18044
+ id: randomUUID13(),
16679
18045
  source,
16680
18046
  decisionType: "spawn",
16681
18047
  question: `Should we spawn a subagent for this task?`,
@@ -16718,7 +18084,7 @@ var AutonomousBrain = class {
16718
18084
  }
16719
18085
  ];
16720
18086
  return this.decideAuto({
16721
- id: randomUUID(),
18087
+ id: randomUUID13(),
16722
18088
  source,
16723
18089
  decisionType: "approve_change",
16724
18090
  question: `Should we approve the change "${change.title}"?`,
@@ -16777,7 +18143,7 @@ var AutonomousBrain = class {
16777
18143
  consequence: "Break the task into smaller sub-tasks"
16778
18144
  });
16779
18145
  return this.decideAuto({
16780
- id: randomUUID(),
18146
+ id: randomUUID13(),
16781
18147
  source,
16782
18148
  decisionType: "escalate_task",
16783
18149
  question: `Task failed: ${error.slice(0, 100)}. How should we proceed?`,
@@ -16889,7 +18255,6 @@ ${ctx.error}`);
16889
18255
  madeAt: (/* @__PURE__ */ new Date()).toISOString(),
16890
18256
  context: input.context
16891
18257
  });
16892
- this.decisionHistory.push(node);
16893
18258
  return node;
16894
18259
  }
16895
18260
  _inferRoles(task) {
@@ -16910,7 +18275,16 @@ ${ctx.error}`);
16910
18275
  return "low";
16911
18276
  }
16912
18277
  };
16913
- var KnowledgeGraph = class {
18278
+
18279
+ // src/coordination/autonomous-coordinator.ts
18280
+ import { randomUUID as randomUUID16 } from "node:crypto";
18281
+
18282
+ // src/coordination/knowledge-graph.ts
18283
+ import { randomUUID as randomUUID14 } from "node:crypto";
18284
+ import * as fsp14 from "node:fs/promises";
18285
+ import * as path19 from "node:path";
18286
+ var DEFAULT_MAX_NODES = 2e3;
18287
+ var KnowledgeGraph = class _KnowledgeGraph {
16914
18288
  nodes = /* @__PURE__ */ new Map();
16915
18289
  index = /* @__PURE__ */ new Map();
16916
18290
  // tag/field → node ids
@@ -16918,6 +18292,7 @@ var KnowledgeGraph = class {
16918
18292
  pendingDeliveries = /* @__PURE__ */ new Map();
16919
18293
  filePath;
16920
18294
  graphFilePath;
18295
+ maxNodes;
16921
18296
  /**
16922
18297
  * Stable per-node insertion sequence. `nodes` (a Map) preserves insertion
16923
18298
  * order even across `update()` (Map.set on an existing key keeps its slot),
@@ -16936,9 +18311,10 @@ var KnowledgeGraph = class {
16936
18311
  getIndex() {
16937
18312
  return this.index;
16938
18313
  }
16939
- constructor(sessionDir) {
16940
- this.filePath = path9.join(sessionDir, "_knowledge_graph");
16941
- this.graphFilePath = path9.join(this.filePath, "graph.jsonl");
18314
+ constructor(sessionDir, maxNodes = DEFAULT_MAX_NODES) {
18315
+ this.filePath = path19.join(sessionDir, "_knowledge_graph");
18316
+ this.graphFilePath = path19.join(this.filePath, "graph.jsonl");
18317
+ this.maxNodes = maxNodes;
16942
18318
  }
16943
18319
  // ── Write ──────────────────────────────────────────────────────────────
16944
18320
  /**
@@ -16946,10 +18322,11 @@ var KnowledgeGraph = class {
16946
18322
  * Returns the node with its assigned id.
16947
18323
  */
16948
18324
  async add(node) {
16949
- const full = { id: randomUUID(), ...node };
18325
+ const full = { id: randomUUID14(), ...node };
16950
18326
  this.nodes.set(full.id, full);
16951
18327
  this._trackSeq(full.id);
16952
18328
  this._addToIndex(full, this._indexKeys(full));
18329
+ this._prune();
16953
18330
  await this._persist(full);
16954
18331
  this._deliver(full);
16955
18332
  return full;
@@ -16962,10 +18339,48 @@ var KnowledgeGraph = class {
16962
18339
  const updated = { ...existing, ...patch };
16963
18340
  this.nodes.set(id, updated);
16964
18341
  this._addToIndex(updated, this._indexKeys(updated));
18342
+ this._prune();
16965
18343
  this._deliver(updated);
16966
18344
  await this._append(updated);
16967
18345
  return updated;
16968
18346
  }
18347
+ /**
18348
+ * True when the node is in a terminal / settled state — no future mutations
18349
+ * are expected. Such nodes are the first to be evicted when the in-memory
18350
+ * cap is reached. The JSONL file on disk retains the full history.
18351
+ */
18352
+ static _isTerminal(node) {
18353
+ if (node.type === "goal") return node.status === "done" || node.status === "failed";
18354
+ if (node.type === "change") return node.status === "rejected" || node.status === "rolled_back";
18355
+ if (node.type === "vote") return true;
18356
+ return false;
18357
+ }
18358
+ /**
18359
+ * Evict oldest terminal-state nodes when the in-memory cap is exceeded.
18360
+ * The JSONL file is the authoritative record; eviction only affects memory.
18361
+ */
18362
+ _prune() {
18363
+ if (this.nodes.size <= this.maxNodes) return;
18364
+ const toEvict = this.nodes.size - this.maxNodes;
18365
+ const terminal = [];
18366
+ for (const [id, node] of this.nodes) {
18367
+ if (_KnowledgeGraph._isTerminal(node)) terminal.push({ id, seq: this.seq.get(id) ?? 0 });
18368
+ }
18369
+ terminal.sort((a, b) => a.seq - b.seq);
18370
+ const evicted = new Set(terminal.slice(0, toEvict).map((e) => e.id));
18371
+ if (evicted.size === 0) return;
18372
+ for (const id of evicted) {
18373
+ const node = this.nodes.get(id);
18374
+ if (!node) continue;
18375
+ this._removeFromIndex(node, this._indexKeys(node));
18376
+ this.nodes.delete(id);
18377
+ this.seq.delete(id);
18378
+ for (const pending of this.pendingDeliveries.values()) {
18379
+ const idx = pending.findIndex((n) => n.id === id);
18380
+ if (idx >= 0) pending.splice(idx, 1);
18381
+ }
18382
+ }
18383
+ }
16969
18384
  // ── Read ───────────────────────────────────────────────────────────────
16970
18385
  get(id) {
16971
18386
  return this.nodes.get(id);
@@ -17029,8 +18444,8 @@ var KnowledgeGraph = class {
17029
18444
  * used to poll for new nodes since the last check.
17030
18445
  */
17031
18446
  subscribe(agentId, filter) {
17032
- const channel = randomUUID();
17033
- const sub = { id: randomUUID(), agentId, filter, channel };
18447
+ const channel = randomUUID14();
18448
+ const sub = { id: randomUUID14(), agentId, filter, channel };
17034
18449
  this.subs.set(channel, sub);
17035
18450
  this.pendingDeliveries.set(channel, []);
17036
18451
  return channel;
@@ -17120,7 +18535,8 @@ var KnowledgeGraph = class {
17120
18535
  const nodeTags = node.tags ?? node.tags ?? [];
17121
18536
  if (!f.tags.some((t) => nodeTags.includes(t))) return false;
17122
18537
  }
17123
- if (f.since && node.id > f.since) ;
18538
+ if (f.since && node.id > f.since) {
18539
+ }
17124
18540
  return true;
17125
18541
  }
17126
18542
  _deliver(node) {
@@ -17132,23 +18548,23 @@ var KnowledgeGraph = class {
17132
18548
  }
17133
18549
  }
17134
18550
  async _persist(node) {
17135
- await fsp9.mkdir(this.filePath, { recursive: true });
18551
+ await fsp14.mkdir(this.filePath, { recursive: true });
17136
18552
  const line = JSON.stringify(node) + "\n";
17137
18553
  await withFileLock(this.graphFilePath, async () => {
17138
- await fsp9.appendFile(this.graphFilePath, line, "utf8");
18554
+ await fsp14.appendFile(this.graphFilePath, line, "utf8");
17139
18555
  });
17140
18556
  }
17141
18557
  async _append(node) {
17142
- await fsp9.mkdir(this.filePath, { recursive: true });
18558
+ await fsp14.mkdir(this.filePath, { recursive: true });
17143
18559
  const line = JSON.stringify({ op: "update", node }) + "\n";
17144
18560
  await withFileLock(this.graphFilePath, async () => {
17145
- await fsp9.appendFile(this.graphFilePath, line, "utf8");
18561
+ await fsp14.appendFile(this.graphFilePath, line, "utf8");
17146
18562
  });
17147
18563
  }
17148
18564
  /** Rebuild in-memory state from the log file. Call on startup. */
17149
18565
  async load() {
17150
18566
  try {
17151
- const content = await fsp9.readFile(this.graphFilePath, "utf8");
18567
+ const content = await fsp14.readFile(this.graphFilePath, "utf8");
17152
18568
  const lines = content.split("\n").filter(Boolean);
17153
18569
  for (const line of lines) {
17154
18570
  try {
@@ -17470,6 +18886,9 @@ var TaskDAG = class {
17470
18886
  return false;
17471
18887
  }
17472
18888
  };
18889
+
18890
+ // src/coordination/task-auctioneer.ts
18891
+ import { randomUUID as randomUUID15 } from "node:crypto";
17473
18892
  var TaskAuctioneer = class {
17474
18893
  graph;
17475
18894
  fleet;
@@ -17589,7 +19008,7 @@ var TaskAuctioneer = class {
17589
19008
  const score = dispatchResult.confidence * (dispatchResult.role === agent.agentRole ? 1.2 : 1);
17590
19009
  if (score < this.minConfidence) return false;
17591
19010
  const bid = {
17592
- id: randomUUID(),
19011
+ id: randomUUID15(),
17593
19012
  taskId,
17594
19013
  agentId: agent.agentId,
17595
19014
  agentName: agent.agentName,
@@ -18394,6 +19813,7 @@ var AutonomousCoordinator = class _AutonomousCoordinator {
18394
19813
  mailbox;
18395
19814
  events;
18396
19815
  onCoordinatorEvent;
19816
+ logger;
18397
19817
  running = false;
18398
19818
  iterationCount = 0;
18399
19819
  lastSyncAt = 0;
@@ -18410,6 +19830,7 @@ var AutonomousCoordinator = class _AutonomousCoordinator {
18410
19830
  this.mailbox = opts.mailbox ?? void 0;
18411
19831
  this.events = opts.events ?? void 0;
18412
19832
  this.onCoordinatorEvent = opts.onCoordinatorEvent;
19833
+ this.logger = opts.logger;
18413
19834
  this.graph = new KnowledgeGraph(opts.sessionDir);
18414
19835
  this.dag = new TaskDAG();
18415
19836
  this.auction = new TaskAuctioneer({
@@ -18515,7 +19936,7 @@ var AutonomousCoordinator = class _AutonomousCoordinator {
18515
19936
  break;
18516
19937
  }
18517
19938
  const decision = await this.brain.decideAuto({
18518
- id: randomUUID(),
19939
+ id: randomUUID16(),
18519
19940
  source: "system",
18520
19941
  decisionType: "prioritize_goals",
18521
19942
  question: `What should we work on next? Open goals: ${dispatchable.map((g) => g.title).join(", ")}`,
@@ -18568,15 +19989,22 @@ var AutonomousCoordinator = class _AutonomousCoordinator {
18568
19989
  stop() {
18569
19990
  if (!this.running) return;
18570
19991
  this.running = false;
18571
- console.error(
18572
- JSON.stringify({
18573
- level: "error",
18574
- event: "autonomous_coordinator.stop_signal",
18575
- message: "stop signal received \u2014 shutting down",
18576
- iteration: this.iterationCount,
18577
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
18578
- })
18579
- );
19992
+ if (this.logger) {
19993
+ this.logger.error(
19994
+ "Stop signal received \u2014 shutting down",
19995
+ { event: "autonomous_coordinator.stop_signal", iteration: this.iterationCount }
19996
+ );
19997
+ } else {
19998
+ console.error(
19999
+ JSON.stringify({
20000
+ level: "error",
20001
+ event: "autonomous_coordinator.stop_signal",
20002
+ message: "stop signal received \u2014 shutting down",
20003
+ iteration: this.iterationCount,
20004
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
20005
+ })
20006
+ );
20007
+ }
18580
20008
  }
18581
20009
  /**
18582
20010
  * Report that a terminal worker (not a Director subagent) completed a claimed
@@ -19010,7 +20438,168 @@ ${input.detail}`
19010
20438
  this.onCoordinatorEvent?.(event);
19011
20439
  }
19012
20440
  };
19013
-
19014
- export { ACP_AGENTS, AGENTS_BY_PHASE, AGENT_CATALOG, TOOLS as AGENT_TOOL_PRESETS, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AdaptiveConcurrencyController, AgentMonitorService, AutonomousBrain, AutonomousCoordinator, BUG_HUNTER_AGENT, BUILD_AGENTS, BrainDecisionQueue, BrainMonitor, BudgetExceededError, BudgetThresholdSignal, ChangeManager, CollabSession, ConsensusProtocol, DECISION_TIMEOUT_MS, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_MAX_FLEET_SPAWNS, DEFAULT_QUALITY_CHECKS, DEFAULT_SUBAGENT_BASELINE, DELIVERY_AGENTS, DEPENDENCY_FILE_PATTERNS, DISCOVERY_AGENTS, DOMAIN_AGENTS, DefaultBrainArbiter, DefaultMailbox, DefaultMultiAgentCoordinator, Director, DirectorAlertLevel, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FLEET_ROSTER_WITHACP, FleetBus, FleetCostCapError, FleetManager, FleetSpawnBudgetError, FleetSupervisor, FleetTokenCapError, FleetUsageAggregator, GlobalMailbox, HARD_MAX_SPAWN_DEPTH, HEAVY_BUDGET, HumanEscalatingBrainArbiter, InMemoryAgentBridge, InMemoryBridgeTransport, KNOWLEDGE_AGENTS, KnowledgeGraph, LIGHT_BUDGET, LargeAnswerStore, MAILBOX_BRIDGE_LOCK_FILENAME, MAILBOX_BRIDGE_TOKEN_FILENAME, MAILBOX_HEALTH_DEFAULT_FAILURE_THRESHOLD, MAILBOX_HEALTH_DEFAULT_FROM, MAILBOX_HEALTH_DEFAULT_INTERVAL_MS, MAILBOX_HEALTH_DEFAULT_TIMEOUT_MS, MATRIX_PHASE_KEYS, MAX_SUBAGENT_STRUCTURED_REPORT_CHARS, MEDIUM_BUDGET, META_AGENTS, MailboxHealthWatchdog, NULL_FLEET_BUS, ObservableBrainArbiter, PLANNING_AGENTS, REFACTOR_PLANNER_AGENT, REVIEW_AGENTS, SECURITY_SCANNER_AGENT, SUBAGENT_STRUCTURED_REPORT_META_KEY, SubagentBudget, TIMEOUT_PREEMPT_FRACTION, TaskAuctioneer, TaskDAG, VERIFY_AGENTS, WorktreeIntegrationError, acquireOrJoin, actionToAckInput, applyRosterBudget, attachAutoExtend, attachDepWatcherBridge, buildDownAlert, buildRecoveryAlert, composeDirectorPrompt, composeSubagentPrompt, createAgentMonitorService, createDelegateTool, createMailboxHooks, createMessage, detectEcosystem, dispatchAgent, finalize, formatHumanPrompt, formatSubagentStructuredReport, getAgentDefinition, getFullPackageLog, getManifestPackages, getPackageAuthor, getPackagesByAgent, isValidMatrixKey, mailboxSessionTag, makeAgentSubagentRunner, makeAskResultTool, makeAskTool, makeAssignTool, makeAwaitTasksTool, makeCollabDebugTool, makeDependencyWatcherConfig, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetTool as makeFleetHealthTool, makeFleetTool as makeFleetSessionTool, makeFleetStatusTool, makeFleetTool, makeFleetTool as makeFleetUsageTool, makeKanbanQueueTool, makeLLMClassifier, makeMailInboxTool, makeMailSendTool, makeMailboxTool, makeQualityGateTool, makeRollUpTool, makeSpawnTool, makeSubagentResultTool, makeTerminateAllTool, makeTerminateTool, makeWorkCompleteTool, matrixKeyKind, normalizeRecipient, normalizeSubagentStructuredReport, phaseForRole, readLiveLock, readSubagentStructuredReport, recordPackageAction, release, resolveImplementationModelTarget, resolveMailboxIdentity, resolveMaxSpawnDepth, resolveModelMatrix, resolveModelMatrixResolution, resolveModelTargetFromEntry, resolveProjectDir, resolveSubagentModelTarget, resolveSubagentWorktreeDecision, roleNeedsIndependentReviewModel, rosterSummaryFromConfigs, sameModelReference, scoreAgents, startPackageOutdatedWatcher, subagentNeedsWorktree, updatePackageOutdatedStatus, validateWatchdogOptions, withDisabledToolFiltering, wrapSubagentRunnerWithWorktrees };
20441
+ export {
20442
+ ACP_AGENTS,
20443
+ AGENTS_BY_PHASE,
20444
+ AGENT_CATALOG,
20445
+ TOOLS as AGENT_TOOL_PRESETS,
20446
+ ALL_AGENT_DEFINITIONS,
20447
+ ALL_FLEET_AGENTS,
20448
+ AUDIT_LOG_AGENT,
20449
+ AdaptiveConcurrencyController,
20450
+ AgentMonitorService,
20451
+ AutonomousBrain,
20452
+ AutonomousCoordinator,
20453
+ BUG_HUNTER_AGENT,
20454
+ BUILD_AGENTS,
20455
+ BrainDecisionLedger,
20456
+ BrainDecisionQueue,
20457
+ BrainMonitor,
20458
+ BudgetExceededError,
20459
+ BudgetThresholdSignal,
20460
+ ChangeManager,
20461
+ CollabSession,
20462
+ ConsensusProtocol,
20463
+ DECISION_TIMEOUT_MS,
20464
+ DEFAULT_DIRECTOR_PREAMBLE,
20465
+ DEFAULT_DISPATCH_ROLE,
20466
+ DEFAULT_MAX_FLEET_SPAWNS,
20467
+ DEFAULT_QUALITY_CHECKS,
20468
+ DEFAULT_SUBAGENT_BASELINE,
20469
+ DELIVERY_AGENTS,
20470
+ DEPENDENCY_FILE_PATTERNS,
20471
+ DISCOVERY_AGENTS,
20472
+ DOMAIN_AGENTS,
20473
+ DefaultBrainArbiter,
20474
+ DefaultMailbox,
20475
+ DefaultMultiAgentCoordinator,
20476
+ Director,
20477
+ DirectorAlertLevel,
20478
+ EscalationRoutingBrainArbiter,
20479
+ FLEET_ROSTER,
20480
+ FLEET_ROSTER_BUDGETS,
20481
+ FLEET_ROSTER_WITHACP,
20482
+ FleetBus,
20483
+ FleetCostCapError,
20484
+ FleetManager,
20485
+ FleetSpawnBudgetError,
20486
+ FleetSupervisor,
20487
+ FleetTokenCapError,
20488
+ FleetUsageAggregator,
20489
+ GlobalMailbox,
20490
+ HARD_MAX_SPAWN_DEPTH,
20491
+ HEAVY_BUDGET,
20492
+ HumanEscalatingBrainArbiter,
20493
+ InMemoryAgentBridge,
20494
+ InMemoryBridgeTransport,
20495
+ KNOWLEDGE_AGENTS,
20496
+ KnowledgeGraph,
20497
+ LIGHT_BUDGET,
20498
+ LargeAnswerStore,
20499
+ MAILBOX_BRIDGE_LOCK_FILENAME,
20500
+ MAILBOX_BRIDGE_TOKEN_FILENAME,
20501
+ MAILBOX_HEALTH_DEFAULT_FAILURE_THRESHOLD,
20502
+ MAILBOX_HEALTH_DEFAULT_FROM,
20503
+ MAILBOX_HEALTH_DEFAULT_INTERVAL_MS,
20504
+ MAILBOX_HEALTH_DEFAULT_TIMEOUT_MS,
20505
+ MATRIX_PHASE_KEYS,
20506
+ MAX_SUBAGENT_STRUCTURED_REPORT_CHARS,
20507
+ MEDIUM_BUDGET,
20508
+ META_AGENTS,
20509
+ MailboxHealthWatchdog,
20510
+ NULL_FLEET_BUS,
20511
+ ObservableBrainArbiter,
20512
+ PLANNING_AGENTS,
20513
+ REFACTOR_PLANNER_AGENT,
20514
+ REVIEW_AGENTS,
20515
+ SECURITY_SCANNER_AGENT,
20516
+ SUBAGENT_STRUCTURED_REPORT_META_KEY,
20517
+ SubagentBudget,
20518
+ TIMEOUT_PREEMPT_FRACTION,
20519
+ TaskAuctioneer,
20520
+ TaskDAG,
20521
+ VERIFY_AGENTS,
20522
+ WorktreeIntegrationError,
20523
+ acquireOrJoin,
20524
+ actionToAckInput,
20525
+ applyRosterBudget,
20526
+ attachAutoExtend,
20527
+ attachDepWatcherBridge,
20528
+ brainDecisionKey,
20529
+ buildDownAlert,
20530
+ buildRecoveryAlert,
20531
+ composeDirectorPrompt,
20532
+ composeSubagentPrompt,
20533
+ createAgentMonitorService,
20534
+ createDelegateTool,
20535
+ createLedgerGuardBrainArbiter,
20536
+ createMailboxHooks,
20537
+ createMessage,
20538
+ detectEcosystem,
20539
+ dispatchAgent,
20540
+ finalize,
20541
+ formatHumanPrompt,
20542
+ formatSubagentStructuredReport,
20543
+ getAgentDefinition,
20544
+ getFullPackageLog,
20545
+ getManifestPackages,
20546
+ getPackageAuthor,
20547
+ getPackagesByAgent,
20548
+ isValidMatrixKey,
20549
+ mailboxSessionTag,
20550
+ makeAgentSubagentRunner,
20551
+ makeAskResultTool,
20552
+ makeAskTool,
20553
+ makeAssignTool,
20554
+ makeAwaitTasksTool,
20555
+ makeCollabDebugTool,
20556
+ makeDependencyWatcherConfig,
20557
+ makeDirectorSessionFactory,
20558
+ makeFleetEmitTool,
20559
+ makeFleetTool as makeFleetHealthTool,
20560
+ makeFleetTool as makeFleetSessionTool,
20561
+ makeFleetStatusTool,
20562
+ makeFleetTool,
20563
+ makeFleetTool as makeFleetUsageTool,
20564
+ makeKanbanQueueTool,
20565
+ makeLLMClassifier,
20566
+ makeMailInboxTool,
20567
+ makeMailSendTool,
20568
+ makeMailboxTool,
20569
+ makeQualityGateTool,
20570
+ makeRollUpTool,
20571
+ makeSpawnTool,
20572
+ makeSubagentResultTool,
20573
+ makeTerminateAllTool,
20574
+ makeTerminateTool,
20575
+ makeWorkCompleteTool,
20576
+ matrixKeyKind,
20577
+ normalizeRecipient,
20578
+ normalizeSubagentStructuredReport,
20579
+ phaseForRole,
20580
+ readLiveLock,
20581
+ readSubagentStructuredReport,
20582
+ recordPackageAction,
20583
+ release,
20584
+ resolveImplementationModelTarget,
20585
+ resolveMailboxIdentity,
20586
+ resolveMaxSpawnDepth,
20587
+ resolveModelMatrix,
20588
+ resolveModelMatrixResolution,
20589
+ resolveModelTargetFromEntry,
20590
+ resolveProjectDir,
20591
+ resolveSubagentModelTarget,
20592
+ resolveSubagentWorktreeDecision,
20593
+ roleNeedsIndependentReviewModel,
20594
+ rosterSummaryFromConfigs,
20595
+ sameModelReference,
20596
+ scoreAgents,
20597
+ startPackageOutdatedWatcher,
20598
+ subagentNeedsWorktree,
20599
+ terminalPolicyDecision,
20600
+ updatePackageOutdatedStatus,
20601
+ validateWatchdogOptions,
20602
+ withDisabledToolFiltering,
20603
+ wrapSubagentRunnerWithWorktrees
20604
+ };
19015
20605
  //# sourceMappingURL=index.js.map
19016
- //# sourceMappingURL=index.js.map