agent-bober 0.17.1 → 0.18.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 (355) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +15 -0
  3. package/README.md +158 -5
  4. package/dist/chat/answerer.d.ts +17 -0
  5. package/dist/chat/answerer.d.ts.map +1 -0
  6. package/dist/chat/answerer.js +52 -0
  7. package/dist/chat/answerer.js.map +1 -0
  8. package/dist/chat/approval-cursor.d.ts +25 -0
  9. package/dist/chat/approval-cursor.d.ts.map +1 -0
  10. package/dist/chat/approval-cursor.js +61 -0
  11. package/dist/chat/approval-cursor.js.map +1 -0
  12. package/dist/chat/approval-reader.d.ts +11 -0
  13. package/dist/chat/approval-reader.d.ts.map +1 -0
  14. package/dist/chat/approval-reader.js +20 -0
  15. package/dist/chat/approval-reader.js.map +1 -0
  16. package/dist/chat/careful-sidecar.d.ts +15 -0
  17. package/dist/chat/careful-sidecar.d.ts.map +1 -0
  18. package/dist/chat/careful-sidecar.js +39 -0
  19. package/dist/chat/careful-sidecar.js.map +1 -0
  20. package/dist/chat/chat-session.d.ts +129 -0
  21. package/dist/chat/chat-session.d.ts.map +1 -0
  22. package/dist/chat/chat-session.js +470 -0
  23. package/dist/chat/chat-session.js.map +1 -0
  24. package/dist/chat/completion-tailer.d.ts +27 -0
  25. package/dist/chat/completion-tailer.d.ts.map +1 -0
  26. package/dist/chat/completion-tailer.js +187 -0
  27. package/dist/chat/completion-tailer.js.map +1 -0
  28. package/dist/chat/conversation-store.d.ts +22 -0
  29. package/dist/chat/conversation-store.d.ts.map +1 -0
  30. package/dist/chat/conversation-store.js +66 -0
  31. package/dist/chat/conversation-store.js.map +1 -0
  32. package/dist/chat/cursor-store.d.ts +23 -0
  33. package/dist/chat/cursor-store.d.ts.map +1 -0
  34. package/dist/chat/cursor-store.js +42 -0
  35. package/dist/chat/cursor-store.js.map +1 -0
  36. package/dist/chat/pid-sidecar.d.ts +22 -0
  37. package/dist/chat/pid-sidecar.d.ts.map +1 -0
  38. package/dist/chat/pid-sidecar.js +42 -0
  39. package/dist/chat/pid-sidecar.js.map +1 -0
  40. package/dist/chat/roster-reader.d.ts +16 -0
  41. package/dist/chat/roster-reader.d.ts.map +1 -0
  42. package/dist/chat/roster-reader.js +39 -0
  43. package/dist/chat/roster-reader.js.map +1 -0
  44. package/dist/chat/run-spawner.d.ts +71 -0
  45. package/dist/chat/run-spawner.d.ts.map +1 -0
  46. package/dist/chat/run-spawner.js +121 -0
  47. package/dist/chat/run-spawner.js.map +1 -0
  48. package/dist/chat/slash-commands.d.ts +36 -0
  49. package/dist/chat/slash-commands.d.ts.map +1 -0
  50. package/dist/chat/slash-commands.js +133 -0
  51. package/dist/chat/slash-commands.js.map +1 -0
  52. package/dist/chat/steer-cleanup.d.ts +12 -0
  53. package/dist/chat/steer-cleanup.d.ts.map +1 -0
  54. package/dist/chat/steer-cleanup.js +60 -0
  55. package/dist/chat/steer-cleanup.js.map +1 -0
  56. package/dist/chat/turn-classifier.d.ts +43 -0
  57. package/dist/chat/turn-classifier.d.ts.map +1 -0
  58. package/dist/chat/turn-classifier.js +150 -0
  59. package/dist/chat/turn-classifier.js.map +1 -0
  60. package/dist/cli/commands/blackboard.d.ts +33 -0
  61. package/dist/cli/commands/blackboard.d.ts.map +1 -0
  62. package/dist/cli/commands/blackboard.js +114 -0
  63. package/dist/cli/commands/blackboard.js.map +1 -0
  64. package/dist/cli/commands/chat.d.ts +13 -0
  65. package/dist/cli/commands/chat.d.ts.map +1 -0
  66. package/dist/cli/commands/chat.js +43 -0
  67. package/dist/cli/commands/chat.js.map +1 -0
  68. package/dist/cli/commands/evolve.d.ts +18 -0
  69. package/dist/cli/commands/evolve.d.ts.map +1 -0
  70. package/dist/cli/commands/evolve.js +72 -0
  71. package/dist/cli/commands/evolve.js.map +1 -0
  72. package/dist/cli/commands/facts.d.ts +15 -0
  73. package/dist/cli/commands/facts.d.ts.map +1 -0
  74. package/dist/cli/commands/facts.js +213 -0
  75. package/dist/cli/commands/facts.js.map +1 -0
  76. package/dist/cli/commands/medical.d.ts +24 -0
  77. package/dist/cli/commands/medical.d.ts.map +1 -0
  78. package/dist/cli/commands/medical.js +132 -0
  79. package/dist/cli/commands/medical.js.map +1 -0
  80. package/dist/cli/commands/memory.d.ts +2 -1
  81. package/dist/cli/commands/memory.d.ts.map +1 -1
  82. package/dist/cli/commands/memory.js +94 -7
  83. package/dist/cli/commands/memory.js.map +1 -1
  84. package/dist/cli/commands/plan.d.ts.map +1 -1
  85. package/dist/cli/commands/plan.js +29 -3
  86. package/dist/cli/commands/plan.js.map +1 -1
  87. package/dist/cli/commands/replay.d.ts +17 -0
  88. package/dist/cli/commands/replay.d.ts.map +1 -0
  89. package/dist/cli/commands/replay.js +261 -0
  90. package/dist/cli/commands/replay.js.map +1 -0
  91. package/dist/cli/commands/run.d.ts +9 -0
  92. package/dist/cli/commands/run.d.ts.map +1 -1
  93. package/dist/cli/commands/run.js +27 -1
  94. package/dist/cli/commands/run.js.map +1 -1
  95. package/dist/cli/commands/sprint.d.ts.map +1 -1
  96. package/dist/cli/commands/sprint.js +17 -3
  97. package/dist/cli/commands/sprint.js.map +1 -1
  98. package/dist/cli/index.js +12 -0
  99. package/dist/cli/index.js.map +1 -1
  100. package/dist/config/defaults.d.ts.map +1 -1
  101. package/dist/config/defaults.js +8 -0
  102. package/dist/config/defaults.js.map +1 -1
  103. package/dist/config/role-providers.d.ts +1 -1
  104. package/dist/config/role-providers.d.ts.map +1 -1
  105. package/dist/config/role-providers.js +6 -1
  106. package/dist/config/role-providers.js.map +1 -1
  107. package/dist/config/schema.d.ts +467 -222
  108. package/dist/config/schema.d.ts.map +1 -1
  109. package/dist/config/schema.js +25 -0
  110. package/dist/config/schema.js.map +1 -1
  111. package/dist/contracts/eval-result.d.ts +84 -84
  112. package/dist/contracts/spec.d.ts +28 -28
  113. package/dist/contracts/sprint-contract.d.ts +4 -4
  114. package/dist/fleet/critic-deep.d.ts +53 -0
  115. package/dist/fleet/critic-deep.d.ts.map +1 -0
  116. package/dist/fleet/critic-deep.js +199 -0
  117. package/dist/fleet/critic-deep.js.map +1 -0
  118. package/dist/fleet/decomposer-deep-constants.d.ts +4 -0
  119. package/dist/fleet/decomposer-deep-constants.d.ts.map +1 -0
  120. package/dist/fleet/decomposer-deep-constants.js +14 -0
  121. package/dist/fleet/decomposer-deep-constants.js.map +1 -0
  122. package/dist/fleet/decomposer-deep-types.d.ts +8 -0
  123. package/dist/fleet/decomposer-deep-types.d.ts.map +1 -0
  124. package/dist/fleet/decomposer-deep-types.js +9 -0
  125. package/dist/fleet/decomposer-deep-types.js.map +1 -0
  126. package/dist/fleet/decomposer-deep.d.ts +51 -0
  127. package/dist/fleet/decomposer-deep.d.ts.map +1 -0
  128. package/dist/fleet/decomposer-deep.js +261 -0
  129. package/dist/fleet/decomposer-deep.js.map +1 -0
  130. package/dist/fleet/decomposer.d.ts +22 -0
  131. package/dist/fleet/decomposer.d.ts.map +1 -0
  132. package/dist/fleet/decomposer.js +144 -0
  133. package/dist/fleet/decomposer.js.map +1 -0
  134. package/dist/fleet/index.d.ts +93 -0
  135. package/dist/fleet/index.d.ts.map +1 -1
  136. package/dist/fleet/index.js +230 -2
  137. package/dist/fleet/index.js.map +1 -1
  138. package/dist/fleet/manifest-write.d.ts +30 -0
  139. package/dist/fleet/manifest-write.d.ts.map +1 -0
  140. package/dist/fleet/manifest-write.js +90 -0
  141. package/dist/fleet/manifest-write.js.map +1 -0
  142. package/dist/fleet/manifest.d.ts +6 -6
  143. package/dist/fleet/shared-blackboard.d.ts +51 -0
  144. package/dist/fleet/shared-blackboard.d.ts.map +1 -0
  145. package/dist/fleet/shared-blackboard.js +79 -0
  146. package/dist/fleet/shared-blackboard.js.map +1 -0
  147. package/dist/fleet/synthesis.d.ts +16 -0
  148. package/dist/fleet/synthesis.d.ts.map +1 -0
  149. package/dist/fleet/synthesis.js +22 -0
  150. package/dist/fleet/synthesis.js.map +1 -0
  151. package/dist/fleet/tier-policy.d.ts +18 -0
  152. package/dist/fleet/tier-policy.d.ts.map +1 -0
  153. package/dist/fleet/tier-policy.js +53 -0
  154. package/dist/fleet/tier-policy.js.map +1 -0
  155. package/dist/fleet/tool-role-guard.d.ts +24 -0
  156. package/dist/fleet/tool-role-guard.d.ts.map +1 -0
  157. package/dist/fleet/tool-role-guard.js +55 -0
  158. package/dist/fleet/tool-role-guard.js.map +1 -0
  159. package/dist/incident/resolution-verify.d.ts +4 -4
  160. package/dist/incident/types.d.ts +8 -8
  161. package/dist/mcp/run-manager.d.ts +9 -1
  162. package/dist/mcp/run-manager.d.ts.map +1 -1
  163. package/dist/mcp/run-manager.js.map +1 -1
  164. package/dist/medical/adapters/apple-health.d.ts +32 -0
  165. package/dist/medical/adapters/apple-health.d.ts.map +1 -0
  166. package/dist/medical/adapters/apple-health.js +100 -0
  167. package/dist/medical/adapters/apple-health.js.map +1 -0
  168. package/dist/medical/audit.d.ts +31 -0
  169. package/dist/medical/audit.d.ts.map +1 -0
  170. package/dist/medical/audit.js +56 -0
  171. package/dist/medical/audit.js.map +1 -0
  172. package/dist/medical/consent.d.ts +37 -0
  173. package/dist/medical/consent.d.ts.map +1 -0
  174. package/dist/medical/consent.js +73 -0
  175. package/dist/medical/consent.js.map +1 -0
  176. package/dist/medical/disclaimer.d.ts +11 -0
  177. package/dist/medical/disclaimer.d.ts.map +1 -0
  178. package/dist/medical/disclaimer.js +21 -0
  179. package/dist/medical/disclaimer.js.map +1 -0
  180. package/dist/medical/egress.d.ts +30 -0
  181. package/dist/medical/egress.d.ts.map +1 -0
  182. package/dist/medical/egress.js +50 -0
  183. package/dist/medical/egress.js.map +1 -0
  184. package/dist/medical/engine.d.ts +73 -0
  185. package/dist/medical/engine.d.ts.map +1 -0
  186. package/dist/medical/engine.js +333 -0
  187. package/dist/medical/engine.js.map +1 -0
  188. package/dist/medical/guardrails.d.ts +47 -0
  189. package/dist/medical/guardrails.d.ts.map +1 -0
  190. package/dist/medical/guardrails.js +92 -0
  191. package/dist/medical/guardrails.js.map +1 -0
  192. package/dist/medical/health-store.d.ts +80 -0
  193. package/dist/medical/health-store.d.ts.map +1 -0
  194. package/dist/medical/health-store.js +204 -0
  195. package/dist/medical/health-store.js.map +1 -0
  196. package/dist/medical/inference.d.ts +22 -0
  197. package/dist/medical/inference.d.ts.map +1 -0
  198. package/dist/medical/inference.js +39 -0
  199. package/dist/medical/inference.js.map +1 -0
  200. package/dist/medical/ingestion.d.ts +33 -0
  201. package/dist/medical/ingestion.d.ts.map +1 -0
  202. package/dist/medical/ingestion.js +52 -0
  203. package/dist/medical/ingestion.js.map +1 -0
  204. package/dist/medical/numerics.d.ts +66 -0
  205. package/dist/medical/numerics.d.ts.map +1 -0
  206. package/dist/medical/numerics.js +216 -0
  207. package/dist/medical/numerics.js.map +1 -0
  208. package/dist/medical/red-flag.d.ts +42 -0
  209. package/dist/medical/red-flag.d.ts.map +1 -0
  210. package/dist/medical/red-flag.js +161 -0
  211. package/dist/medical/red-flag.js.map +1 -0
  212. package/dist/medical/refusal.d.ts +46 -0
  213. package/dist/medical/refusal.d.ts.map +1 -0
  214. package/dist/medical/refusal.js +131 -0
  215. package/dist/medical/refusal.js.map +1 -0
  216. package/dist/medical/retrieval/grounding-critic.d.ts +34 -0
  217. package/dist/medical/retrieval/grounding-critic.d.ts.map +1 -0
  218. package/dist/medical/retrieval/grounding-critic.js +153 -0
  219. package/dist/medical/retrieval/grounding-critic.js.map +1 -0
  220. package/dist/medical/retrieval/literature.d.ts +78 -0
  221. package/dist/medical/retrieval/literature.d.ts.map +1 -0
  222. package/dist/medical/retrieval/literature.js +292 -0
  223. package/dist/medical/retrieval/literature.js.map +1 -0
  224. package/dist/medical/retrieval/medline-source.d.ts +72 -0
  225. package/dist/medical/retrieval/medline-source.d.ts.map +1 -0
  226. package/dist/medical/retrieval/medline-source.js +120 -0
  227. package/dist/medical/retrieval/medline-source.js.map +1 -0
  228. package/dist/medical/team.d.ts +15 -0
  229. package/dist/medical/team.d.ts.map +1 -0
  230. package/dist/medical/team.js +44 -0
  231. package/dist/medical/team.js.map +1 -0
  232. package/dist/medical/types.d.ts +175 -0
  233. package/dist/medical/types.d.ts.map +1 -0
  234. package/dist/medical/types.js +8 -0
  235. package/dist/medical/types.js.map +1 -0
  236. package/dist/medical/whoop/whoop-client.d.ts +114 -0
  237. package/dist/medical/whoop/whoop-client.d.ts.map +1 -0
  238. package/dist/medical/whoop/whoop-client.js +226 -0
  239. package/dist/medical/whoop/whoop-client.js.map +1 -0
  240. package/dist/medical/whoop/whoop-sync.d.ts +25 -0
  241. package/dist/medical/whoop/whoop-sync.d.ts.map +1 -0
  242. package/dist/medical/whoop/whoop-sync.js +97 -0
  243. package/dist/medical/whoop/whoop-sync.js.map +1 -0
  244. package/dist/medical/whoop/whoop-token.d.ts +44 -0
  245. package/dist/medical/whoop/whoop-token.d.ts.map +1 -0
  246. package/dist/medical/whoop/whoop-token.js +66 -0
  247. package/dist/medical/whoop/whoop-token.js.map +1 -0
  248. package/dist/orchestrator/context-handoff.d.ts +60 -60
  249. package/dist/orchestrator/contract-materialization.d.ts +33 -0
  250. package/dist/orchestrator/contract-materialization.d.ts.map +1 -0
  251. package/dist/orchestrator/contract-materialization.js +113 -0
  252. package/dist/orchestrator/contract-materialization.js.map +1 -0
  253. package/dist/orchestrator/memory/distill.d.ts +4 -1
  254. package/dist/orchestrator/memory/distill.d.ts.map +1 -1
  255. package/dist/orchestrator/memory/distill.js +41 -1
  256. package/dist/orchestrator/memory/distill.js.map +1 -1
  257. package/dist/orchestrator/memory/fact-detector.d.ts +61 -0
  258. package/dist/orchestrator/memory/fact-detector.d.ts.map +1 -0
  259. package/dist/orchestrator/memory/fact-detector.js +153 -0
  260. package/dist/orchestrator/memory/fact-detector.js.map +1 -0
  261. package/dist/orchestrator/memory/fact-judge.d.ts +19 -0
  262. package/dist/orchestrator/memory/fact-judge.d.ts.map +1 -0
  263. package/dist/orchestrator/memory/fact-judge.js +121 -0
  264. package/dist/orchestrator/memory/fact-judge.js.map +1 -0
  265. package/dist/orchestrator/memory/fact-retrieve.d.ts +52 -0
  266. package/dist/orchestrator/memory/fact-retrieve.d.ts.map +1 -0
  267. package/dist/orchestrator/memory/fact-retrieve.js +117 -0
  268. package/dist/orchestrator/memory/fact-retrieve.js.map +1 -0
  269. package/dist/orchestrator/memory/hygiene.d.ts +66 -0
  270. package/dist/orchestrator/memory/hygiene.d.ts.map +1 -0
  271. package/dist/orchestrator/memory/hygiene.js +153 -0
  272. package/dist/orchestrator/memory/hygiene.js.map +1 -0
  273. package/dist/orchestrator/memory/reconcile.d.ts +47 -0
  274. package/dist/orchestrator/memory/reconcile.d.ts.map +1 -0
  275. package/dist/orchestrator/memory/reconcile.js +116 -0
  276. package/dist/orchestrator/memory/reconcile.js.map +1 -0
  277. package/dist/orchestrator/memory/retrieve.d.ts +5 -3
  278. package/dist/orchestrator/memory/retrieve.d.ts.map +1 -1
  279. package/dist/orchestrator/memory/retrieve.js +9 -6
  280. package/dist/orchestrator/memory/retrieve.js.map +1 -1
  281. package/dist/orchestrator/pipeline.d.ts +19 -3
  282. package/dist/orchestrator/pipeline.d.ts.map +1 -1
  283. package/dist/orchestrator/pipeline.js +63 -52
  284. package/dist/orchestrator/pipeline.js.map +1 -1
  285. package/dist/orchestrator/planner-agent.d.ts.map +1 -1
  286. package/dist/orchestrator/planner-agent.js +16 -1
  287. package/dist/orchestrator/planner-agent.js.map +1 -1
  288. package/dist/orchestrator/selfimprove/eval-guards.d.ts +51 -0
  289. package/dist/orchestrator/selfimprove/eval-guards.d.ts.map +1 -0
  290. package/dist/orchestrator/selfimprove/eval-guards.js +120 -0
  291. package/dist/orchestrator/selfimprove/eval-guards.js.map +1 -0
  292. package/dist/orchestrator/selfimprove/gepa.d.ts +74 -0
  293. package/dist/orchestrator/selfimprove/gepa.d.ts.map +1 -0
  294. package/dist/orchestrator/selfimprove/gepa.js +227 -0
  295. package/dist/orchestrator/selfimprove/gepa.js.map +1 -0
  296. package/dist/orchestrator/selfimprove/replay-harness.d.ts +65 -0
  297. package/dist/orchestrator/selfimprove/replay-harness.d.ts.map +1 -0
  298. package/dist/orchestrator/selfimprove/replay-harness.js +134 -0
  299. package/dist/orchestrator/selfimprove/replay-harness.js.map +1 -0
  300. package/dist/orchestrator/selfimprove/replay-store.d.ts +45 -0
  301. package/dist/orchestrator/selfimprove/replay-store.d.ts.map +1 -0
  302. package/dist/orchestrator/selfimprove/replay-store.js +119 -0
  303. package/dist/orchestrator/selfimprove/replay-store.js.map +1 -0
  304. package/dist/orchestrator/selfimprove/replay-types.d.ts +32 -0
  305. package/dist/orchestrator/selfimprove/replay-types.d.ts.map +1 -0
  306. package/dist/orchestrator/selfimprove/replay-types.js +15 -0
  307. package/dist/orchestrator/selfimprove/replay-types.js.map +1 -0
  308. package/dist/orchestrator/workflow/engine.d.ts +3 -1
  309. package/dist/orchestrator/workflow/engine.d.ts.map +1 -1
  310. package/dist/orchestrator/workflow/selector.d.ts +18 -0
  311. package/dist/orchestrator/workflow/selector.d.ts.map +1 -1
  312. package/dist/orchestrator/workflow/selector.js +41 -0
  313. package/dist/orchestrator/workflow/selector.js.map +1 -1
  314. package/dist/orchestrator/workflow/ts-engine.d.ts +3 -1
  315. package/dist/orchestrator/workflow/ts-engine.d.ts.map +1 -1
  316. package/dist/orchestrator/workflow/ts-engine.js +2 -2
  317. package/dist/orchestrator/workflow/ts-engine.js.map +1 -1
  318. package/dist/orchestrator/workflow/workflow-engine.d.ts +3 -1
  319. package/dist/orchestrator/workflow/workflow-engine.d.ts.map +1 -1
  320. package/dist/orchestrator/workflow/workflow-engine.js +3 -3
  321. package/dist/orchestrator/workflow/workflow-engine.js.map +1 -1
  322. package/dist/state/facts.d.ts +110 -0
  323. package/dist/state/facts.d.ts.map +1 -0
  324. package/dist/state/facts.js +208 -0
  325. package/dist/state/facts.js.map +1 -0
  326. package/dist/state/guidance.d.ts +37 -0
  327. package/dist/state/guidance.d.ts.map +1 -0
  328. package/dist/state/guidance.js +144 -0
  329. package/dist/state/guidance.js.map +1 -0
  330. package/dist/state/history.d.ts +2 -2
  331. package/dist/state/index.d.ts +1 -1
  332. package/dist/state/index.d.ts.map +1 -1
  333. package/dist/state/index.js +1 -1
  334. package/dist/state/index.js.map +1 -1
  335. package/dist/state/memory.d.ts +43 -11
  336. package/dist/state/memory.d.ts.map +1 -1
  337. package/dist/state/memory.js +93 -15
  338. package/dist/state/memory.js.map +1 -1
  339. package/dist/state/pause.d.ts +47 -0
  340. package/dist/state/pause.d.ts.map +1 -0
  341. package/dist/state/pause.js +146 -0
  342. package/dist/state/pause.js.map +1 -0
  343. package/dist/state/sprint-state.d.ts +8 -0
  344. package/dist/state/sprint-state.d.ts.map +1 -1
  345. package/dist/state/sprint-state.js +32 -1
  346. package/dist/state/sprint-state.js.map +1 -1
  347. package/dist/teams/registry.d.ts +16 -0
  348. package/dist/teams/registry.d.ts.map +1 -0
  349. package/dist/teams/registry.js +53 -0
  350. package/dist/teams/registry.js.map +1 -0
  351. package/dist/teams/types.d.ts +25 -0
  352. package/dist/teams/types.d.ts.map +1 -0
  353. package/dist/teams/types.js +2 -0
  354. package/dist/teams/types.js.map +1 -0
  355. package/package.json +3 -1
@@ -0,0 +1,121 @@
1
+ // ── run-spawner.ts ─────────────────────────────────────────────────────
2
+ //
3
+ // Launches a DETACHED `agent-bober run <task> --run-id <id>` child that
4
+ // survives the REPL exiting. Writes the roster state.json BEFORE spawning
5
+ // so the run is visible the same turn; records the pid in a sidecar.
6
+ import { execa } from "execa";
7
+ import { writeRunState, readRunState } from "../state/run-state.js";
8
+ import { resolveCliEntry } from "../fleet/runner.js";
9
+ import { PidSidecar } from "./pid-sidecar.js";
10
+ // ── RunSpawner ─────────────────────────────────────────────────────────
11
+ export class RunSpawner {
12
+ projectRoot;
13
+ sessionId;
14
+ spawnFn;
15
+ killFn;
16
+ cliEntry;
17
+ nodeBin;
18
+ now;
19
+ sidecar;
20
+ constructor(opts) {
21
+ this.projectRoot = opts.projectRoot;
22
+ this.sessionId = opts.sessionId;
23
+ this.spawnFn =
24
+ opts.spawn ??
25
+ // bober: thin execa wrapper; execa returns a ChildProcess-like w/ .pid and .unref
26
+ ((file, args, options) => execa(file, args, options));
27
+ this.killFn =
28
+ opts.kill ??
29
+ // bober: default delegates to process.kill; swap for a fake in tests (sc-4-9)
30
+ ((pid, signal) => { process.kill(pid, signal); });
31
+ this.cliEntry = opts.cliEntry ?? resolveCliEntry();
32
+ this.nodeBin = opts.nodeBin ?? process.execPath;
33
+ this.now = opts.now ?? (() => new Date().toISOString());
34
+ this.sidecar = new PidSidecar(this.projectRoot, this.sessionId);
35
+ }
36
+ /**
37
+ * Write the roster state.json, launch a detached child, record the pid,
38
+ * and return an immediate SpawnAck without waiting for the child to finish.
39
+ *
40
+ * @param opts.careful - When true, appends --approve-gates with the curated
41
+ * gate list to the child args. Default false (autopilot — byte-for-byte
42
+ * identical to Phase 1 behavior).
43
+ */
44
+ async spawn(task, runId, opts = {}) {
45
+ const cwd = this.projectRoot;
46
+ // 1. Write roster state.json BEFORE spawning so the run is visible immediately (sc-2-6)
47
+ const state = {
48
+ runId,
49
+ task,
50
+ status: "running",
51
+ startedAt: this.now(),
52
+ progress: { completed: 0, total: 0 },
53
+ projectRoot: cwd,
54
+ };
55
+ await writeRunState(cwd, state);
56
+ // 2. Launch detached child — do NOT await (sc-2-9, sc-2-6)
57
+ try {
58
+ const args = [this.cliEntry, "run", task, "--run-id", runId];
59
+ if (opts.careful) {
60
+ args.push("--approve-gates", "post-research,post-plan,post-sprint");
61
+ }
62
+ const child = this.spawnFn(this.nodeBin, args, { cwd, detached: true, stdio: "ignore" });
63
+ child.unref();
64
+ // 3. Record pid in session sidecar (sc-2-7)
65
+ await this.sidecar.record(runId, {
66
+ pid: child.pid,
67
+ task,
68
+ spawnedAt: this.now(),
69
+ });
70
+ return { runId, task, pid: child.pid, cwd };
71
+ }
72
+ catch (err) {
73
+ return {
74
+ runId,
75
+ task,
76
+ cwd,
77
+ spawnError: err instanceof Error ? err.message : String(err),
78
+ };
79
+ }
80
+ }
81
+ /**
82
+ * Stop a running run by its runId.
83
+ * Resolves the PID from the session sidecar and sends SIGTERM.
84
+ * If no sidecar entry is found, flips state to 'aborted' on disk only.
85
+ * Tolerates ESRCH (already-dead pid) — treat as already stopped.
86
+ */
87
+ async stop(runId, reason) {
88
+ const all = await this.sidecar.readAll();
89
+ const entry = all[runId];
90
+ if (entry?.pid !== undefined) {
91
+ // Try to kill the process; tolerate ESRCH (already dead)
92
+ try {
93
+ this.killFn(entry.pid, "SIGTERM");
94
+ }
95
+ catch {
96
+ // Already gone — not an error (mirrors pipeline-lifecycle.ts:316-320)
97
+ }
98
+ // Flip disk state to aborted
99
+ const s = await readRunState(this.projectRoot, runId);
100
+ if (s) {
101
+ s.status = "aborted";
102
+ s.abortedAt = this.now();
103
+ s.abortReason = reason;
104
+ await writeRunState(this.projectRoot, s);
105
+ }
106
+ return { stopped: true, runId, killedPid: entry.pid };
107
+ }
108
+ // No sidecar entry — fall back to disk-only aborted flip
109
+ const s = await readRunState(this.projectRoot, runId);
110
+ if (s) {
111
+ s.status = "aborted";
112
+ s.abortedAt = this.now();
113
+ s.abortReason = reason;
114
+ await writeRunState(this.projectRoot, s);
115
+ return { stopped: true, runId, fallbackFlagOnly: true };
116
+ }
117
+ // Run not found at all
118
+ return { stopped: false, runId };
119
+ }
120
+ }
121
+ //# sourceMappingURL=run-spawner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-spawner.js","sourceRoot":"","sources":["../../src/chat/run-spawner.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,EAAE;AACF,wEAAwE;AACxE,0EAA0E;AAC1E,qEAAqE;AAErE,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAE9B,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AA+C9C,0EAA0E;AAE1E,MAAM,OAAO,UAAU;IACJ,WAAW,CAAS;IACpB,SAAS,CAAS;IAClB,OAAO,CAAU;IACjB,MAAM,CAAS;IACf,QAAQ,CAAS;IACjB,OAAO,CAAS;IAChB,GAAG,CAAe;IAClB,OAAO,CAAa;IAErC,YAAY,IAAuB;QACjC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;QACpC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QAChC,IAAI,CAAC,OAAO;YACV,IAAI,CAAC,KAAK;gBACV,kFAAkF;gBAClF,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CACvB,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAmD,CAAC,CAAC;QAClF,IAAI,CAAC,MAAM;YACT,IAAI,CAAC,IAAI;gBACT,8EAA8E;gBAC9E,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,eAAe,EAAE,CAAC;QACnD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC;QAChD,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;QACxD,IAAI,CAAC,OAAO,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAClE,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,KAAK,CAAC,IAAY,EAAE,KAAa,EAAE,OAA8B,EAAE;QACvE,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC;QAE7B,wFAAwF;QACxF,MAAM,KAAK,GAAa;YACtB,KAAK;YACL,IAAI;YACJ,MAAM,EAAE,SAAS;YACjB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,QAAQ,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;YACpC,WAAW,EAAE,GAAG;SACjB,CAAC;QACF,MAAM,aAAa,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAEhC,2DAA2D;QAC3D,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;YAC7D,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjB,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,qCAAqC,CAAC,CAAC;YACtE,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CACxB,IAAI,CAAC,OAAO,EACZ,IAAI,EACJ,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CACzC,CAAC;YACF,KAAK,CAAC,KAAK,EAAE,CAAC;YAEd,4CAA4C;YAC5C,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE;gBAC/B,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,IAAI;gBACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB,CAAC,CAAC;YAEH,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;QAC9C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,KAAK;gBACL,IAAI;gBACJ,GAAG;gBACH,UAAU,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aAC7D,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,IAAI,CAAC,KAAa,EAAE,MAAc;QACtC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;QAEzB,IAAI,KAAK,EAAE,GAAG,KAAK,SAAS,EAAE,CAAC;YAC7B,yDAAyD;YACzD,IAAI,CAAC;gBACH,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YACpC,CAAC;YAAC,MAAM,CAAC;gBACP,sEAAsE;YACxE,CAAC;YAED,6BAA6B;YAC7B,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;YACtD,IAAI,CAAC,EAAE,CAAC;gBACN,CAAC,CAAC,MAAM,GAAG,SAAS,CAAC;gBACrB,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACzB,CAAC,CAAC,WAAW,GAAG,MAAM,CAAC;gBACvB,MAAM,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;YAC3C,CAAC;YAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC;QACxD,CAAC;QAED,yDAAyD;QACzD,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QACtD,IAAI,CAAC,EAAE,CAAC;YACN,CAAC,CAAC,MAAM,GAAG,SAAS,CAAC;YACrB,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACzB,CAAC,CAAC,WAAW,GAAG,MAAM,CAAC;YACvB,MAAM,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;YACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC;QAC1D,CAAC;QAED,uBAAuB;QACvB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IACnC,CAAC;CACF"}
@@ -0,0 +1,36 @@
1
+ import type { RosterReader } from "./roster-reader.js";
2
+ export type SlashResult = {
3
+ handled: true;
4
+ output: string;
5
+ exit?: false;
6
+ } | {
7
+ handled: true;
8
+ output?: undefined;
9
+ exit: true;
10
+ } | {
11
+ handled: false;
12
+ };
13
+ /**
14
+ * Handle a slash command if the input starts with '/'.
15
+ * Returns { handled: false } for non-slash input.
16
+ * Never calls the LLMClient.
17
+ *
18
+ * @param stopHandler - Optional handler for /stop <runId>. When omitted, /stop
19
+ * returns an "unavailable" message. Kept optional so existing 2-arg callers
20
+ * are not broken (sc-4-6).
21
+ * @param carefulHandler - Optional handler for /careful [on|off]. When omitted,
22
+ * /careful returns an "unavailable" message. Kept optional so existing 2-/3-arg
23
+ * callers are not broken.
24
+ * @param approveHandler - Optional handler for /approve <id>. When omitted, /approve
25
+ * returns an "unavailable" message. Kept optional so existing callers are not broken.
26
+ * @param rejectHandler - Optional handler for /reject <id> [feedback]. When omitted,
27
+ * /reject returns an "unavailable" message. Kept optional so existing callers are not broken.
28
+ * @param tellHandler - Optional handler for /tell <runId> <text>. When omitted,
29
+ * /tell returns an "unavailable" message.
30
+ * @param pauseHandler - Optional handler for /pause <runId>. When omitted,
31
+ * /pause returns an "unavailable" message. Kept optional for back-compat.
32
+ * @param resumeHandler - Optional handler for /resume <runId>. When omitted,
33
+ * /resume returns an "unavailable" message. Last optional param preserves back-compat.
34
+ */
35
+ export declare function dispatch(input: string, roster: RosterReader, stopHandler?: (runId: string) => Promise<string>, carefulHandler?: (arg: string | undefined) => Promise<string>, approveHandler?: (id: string) => Promise<string>, rejectHandler?: (id: string, feedback: string) => Promise<string>, tellHandler?: (runId: string, text: string) => Promise<string>, pauseHandler?: (runId: string) => Promise<string>, resumeHandler?: (runId: string) => Promise<string>): Promise<SlashResult>;
36
+ //# sourceMappingURL=slash-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slash-commands.d.ts","sourceRoot":"","sources":["../../src/chat/slash-commands.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIvD,MAAM,MAAM,WAAW,GACnB;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,KAAK,CAAA;CAAE,GAC/C;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,GACjD;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,CAAC;AAsBvB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,YAAY,EACpB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,EAChD,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,CAAC,MAAM,CAAC,EAC7D,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,EAChD,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,EACjE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,EAC9D,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,EACjD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GACjD,OAAO,CAAC,WAAW,CAAC,CA6FtB"}
@@ -0,0 +1,133 @@
1
+ // ── slash-commands.ts ────────────────────────────────────────────────
2
+ //
3
+ // Deterministic slash-command dispatcher.
4
+ // Handles /runs, /help, /exit WITHOUT touching the LLMClient.
5
+ // ── Help text ─────────────────────────────────────────────────────────
6
+ const HELP_TEXT = [
7
+ "Available slash commands:",
8
+ " /runs — List all active and recent runs",
9
+ " /stop <runId> — Stop a run by killing its process (hard stop)",
10
+ " /pause <runId> — Soft-pause a run at the next boundary (process stays alive)",
11
+ " /resume <runId> — Resume a soft-paused run",
12
+ " /careful [on|off] — Toggle approval gates for new runs",
13
+ " /approve <id> — Approve a pending checkpoint (resume the run)",
14
+ " /reject <id> [why] — Reject a pending checkpoint with optional feedback",
15
+ " /tell <runId> <text> — Queue free-text guidance for a run (applied at next boundary)",
16
+ " /help — Show this help message",
17
+ " /exit — Exit the chat session",
18
+ "",
19
+ "Any other input is sent to the AI assistant.",
20
+ ].join("\n");
21
+ // ── dispatch ──────────────────────────────────────────────────────────
22
+ /**
23
+ * Handle a slash command if the input starts with '/'.
24
+ * Returns { handled: false } for non-slash input.
25
+ * Never calls the LLMClient.
26
+ *
27
+ * @param stopHandler - Optional handler for /stop <runId>. When omitted, /stop
28
+ * returns an "unavailable" message. Kept optional so existing 2-arg callers
29
+ * are not broken (sc-4-6).
30
+ * @param carefulHandler - Optional handler for /careful [on|off]. When omitted,
31
+ * /careful returns an "unavailable" message. Kept optional so existing 2-/3-arg
32
+ * callers are not broken.
33
+ * @param approveHandler - Optional handler for /approve <id>. When omitted, /approve
34
+ * returns an "unavailable" message. Kept optional so existing callers are not broken.
35
+ * @param rejectHandler - Optional handler for /reject <id> [feedback]. When omitted,
36
+ * /reject returns an "unavailable" message. Kept optional so existing callers are not broken.
37
+ * @param tellHandler - Optional handler for /tell <runId> <text>. When omitted,
38
+ * /tell returns an "unavailable" message.
39
+ * @param pauseHandler - Optional handler for /pause <runId>. When omitted,
40
+ * /pause returns an "unavailable" message. Kept optional for back-compat.
41
+ * @param resumeHandler - Optional handler for /resume <runId>. When omitted,
42
+ * /resume returns an "unavailable" message. Last optional param preserves back-compat.
43
+ */
44
+ export async function dispatch(input, roster, stopHandler, carefulHandler, approveHandler, rejectHandler, tellHandler, pauseHandler, resumeHandler) {
45
+ const trimmed = input.trimStart();
46
+ if (!trimmed.startsWith("/")) {
47
+ return { handled: false };
48
+ }
49
+ const command = trimmed.split(/\s+/)[0]?.toLowerCase() ?? "";
50
+ switch (command) {
51
+ case "/runs": {
52
+ const states = await roster.read();
53
+ const output = roster.summarize(states);
54
+ return { handled: true, output };
55
+ }
56
+ case "/help": {
57
+ return { handled: true, output: HELP_TEXT };
58
+ }
59
+ case "/stop": {
60
+ const arg = trimmed.split(/\s+/)[1];
61
+ if (!arg)
62
+ return { handled: true, output: "Usage: /stop <runId>" };
63
+ const output = stopHandler
64
+ ? await stopHandler(arg)
65
+ : "Stop is unavailable.";
66
+ return { handled: true, output };
67
+ }
68
+ case "/careful": {
69
+ const arg = trimmed.split(/\s+/)[1]?.toLowerCase();
70
+ const output = carefulHandler
71
+ ? await carefulHandler(arg)
72
+ : "Careful mode is unavailable.";
73
+ return { handled: true, output };
74
+ }
75
+ case "/approve": {
76
+ const arg = trimmed.split(/\s+/)[1];
77
+ if (!arg)
78
+ return { handled: true, output: "Usage: /approve <checkpointId>" };
79
+ const output = approveHandler
80
+ ? await approveHandler(arg)
81
+ : "Approve is unavailable.";
82
+ return { handled: true, output };
83
+ }
84
+ case "/reject": {
85
+ const parts = trimmed.split(/\s+/);
86
+ const id = parts[1];
87
+ if (!id)
88
+ return { handled: true, output: "Usage: /reject <checkpointId> [feedback]" };
89
+ // Everything after the id is feedback (preserve spacing of the remainder)
90
+ const feedback = trimmed.replace(/^\/reject\s+\S+\s*/, "");
91
+ const output = rejectHandler
92
+ ? await rejectHandler(id, feedback)
93
+ : "Reject is unavailable.";
94
+ return { handled: true, output };
95
+ }
96
+ case "/tell": {
97
+ const parts = trimmed.split(/\s+/);
98
+ const runId = parts[1];
99
+ if (!runId)
100
+ return { handled: true, output: "Usage: /tell <runId> <text>" };
101
+ // Capture everything after the runId as the guidance text (preserve spacing)
102
+ const text = trimmed.replace(/^\/tell\s+\S+\s*/, "");
103
+ if (!text)
104
+ return { handled: true, output: "Usage: /tell <runId> <text>" };
105
+ const output = tellHandler
106
+ ? await tellHandler(runId, text)
107
+ : "Tell is unavailable.";
108
+ return { handled: true, output };
109
+ }
110
+ case "/pause": {
111
+ const arg = trimmed.split(/\s+/)[1];
112
+ if (!arg)
113
+ return { handled: true, output: "Usage: /pause <runId>" };
114
+ const output = pauseHandler ? await pauseHandler(arg) : "Pause is unavailable.";
115
+ return { handled: true, output };
116
+ }
117
+ case "/resume": {
118
+ const arg = trimmed.split(/\s+/)[1];
119
+ if (!arg)
120
+ return { handled: true, output: "Usage: /resume <runId>" };
121
+ const output = resumeHandler ? await resumeHandler(arg) : "Resume is unavailable.";
122
+ return { handled: true, output };
123
+ }
124
+ case "/exit": {
125
+ return { handled: true, exit: true };
126
+ }
127
+ default: {
128
+ const output = `Unknown command: ${command}\n${HELP_TEXT}`;
129
+ return { handled: true, output };
130
+ }
131
+ }
132
+ }
133
+ //# sourceMappingURL=slash-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slash-commands.js","sourceRoot":"","sources":["../../src/chat/slash-commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Remove all disk + RunState steer artifacts for a run that has gone terminal.
3
+ * Best-effort: each step is individually guarded; the function never throws.
4
+ *
5
+ * Steps:
6
+ * 1. Delete pending approval marker(s) correlated to this runId (by runId field).
7
+ * 2. Unlink .bober/runs/<runId>/guidance.jsonl + paused.json (tolerate ENOENT).
8
+ * 3. Clear RunState pending/paused fields (pendingCheckpointId, pendingPrompt,
9
+ * pendingSince, pausedAt) while leaving the terminal status (completed/aborted) as-is.
10
+ */
11
+ export declare function cleanupTerminalRun(projectRoot: string, runId: string): Promise<void>;
12
+ //# sourceMappingURL=steer-cleanup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"steer-cleanup.d.ts","sourceRoot":"","sources":["../../src/chat/steer-cleanup.ts"],"names":[],"mappings":"AAcA;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAqCf"}
@@ -0,0 +1,60 @@
1
+ // ── steer-cleanup.ts ──────────────────────────────────────────────────
2
+ //
3
+ // Best-effort hygiene: when the chat process observes a run reach a terminal
4
+ // status (completed/aborted), remove its stale pending approval marker(s),
5
+ // guidance.jsonl, and paused.json, and clear RunState pending/paused fields.
6
+ // NEVER throws — a cleanup failure must not break a chat turn.
7
+ import { unlink } from "node:fs/promises";
8
+ import { join } from "node:path";
9
+ import { deletePending, listPending } from "../state/approval-state.js";
10
+ import { readRunState, writeRunState } from "../state/run-state.js";
11
+ import { safeSegment } from "../state/guidance.js";
12
+ /**
13
+ * Remove all disk + RunState steer artifacts for a run that has gone terminal.
14
+ * Best-effort: each step is individually guarded; the function never throws.
15
+ *
16
+ * Steps:
17
+ * 1. Delete pending approval marker(s) correlated to this runId (by runId field).
18
+ * 2. Unlink .bober/runs/<runId>/guidance.jsonl + paused.json (tolerate ENOENT).
19
+ * 3. Clear RunState pending/paused fields (pendingCheckpointId, pendingPrompt,
20
+ * pendingSince, pausedAt) while leaving the terminal status (completed/aborted) as-is.
21
+ */
22
+ export async function cleanupTerminalRun(projectRoot, runId) {
23
+ if (!safeSegment(runId))
24
+ return; // unsafe id → skip silently (mirrors pause.ts:79)
25
+ // 1. Delete pending markers correlated to this runId (checkpointId-keyed dir).
26
+ try {
27
+ const pending = await listPending(projectRoot);
28
+ for (const m of pending) {
29
+ if (m.runId === runId) {
30
+ await deletePending(projectRoot, m.checkpointId); // already best-effort (:138)
31
+ }
32
+ }
33
+ }
34
+ catch {
35
+ // never throw into a turn
36
+ }
37
+ // 2. Unlink guidance.jsonl + paused.json under .bober/runs/<runId>/ (tolerate ENOENT).
38
+ const runDir = join(projectRoot, ".bober", "runs", runId);
39
+ await unlink(join(runDir, "guidance.jsonl")).catch(() => { });
40
+ await unlink(join(runDir, "paused.json")).catch(() => { });
41
+ // 3. Clear RunState pending/paused fields (only if a state file exists).
42
+ // Preserve the terminal status (completed/aborted) — do NOT force back to running.
43
+ try {
44
+ const state = await readRunState(projectRoot, runId);
45
+ if (state) {
46
+ // Destructure out optional fields — established idiom from chat-session.ts:441-447
47
+ const { pendingCheckpointId, pendingPrompt, pendingSince, pausedAt, ...rest } = state;
48
+ // Suppress unused-variable warnings in strict mode
49
+ void pendingCheckpointId;
50
+ void pendingPrompt;
51
+ void pendingSince;
52
+ void pausedAt;
53
+ await writeRunState(projectRoot, rest);
54
+ }
55
+ }
56
+ catch {
57
+ // never throw into a turn
58
+ }
59
+ }
60
+ //# sourceMappingURL=steer-cleanup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"steer-cleanup.js","sourceRoot":"","sources":["../../src/chat/steer-cleanup.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,6EAA6E;AAC7E,+DAA+D;AAE/D,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,WAAmB,EACnB,KAAa;IAEb,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,kDAAkD;IAEnF,+EAA+E;IAC/E,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC,CAAC;QAC/C,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;gBACtB,MAAM,aAAa,CAAC,WAAW,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,6BAA6B;YACjF,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,0BAA0B;IAC5B,CAAC;IAED,uFAAuF;IACvF,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAC1D,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC7D,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAE1D,yEAAyE;IACzE,sFAAsF;IACtF,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QACrD,IAAI,KAAK,EAAE,CAAC;YACV,mFAAmF;YACnF,MAAM,EAAE,mBAAmB,EAAE,aAAa,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;YACtF,mDAAmD;YACnD,KAAK,mBAAmB,CAAC;YACzB,KAAK,aAAa,CAAC;YACnB,KAAK,YAAY,CAAC;YAClB,KAAK,QAAQ,CAAC;YACd,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,0BAA0B;IAC5B,CAAC;AACH,CAAC"}
@@ -0,0 +1,43 @@
1
+ import type { LLMClient } from "../providers/types.js";
2
+ export type ClassifierAction = {
3
+ action: "answer";
4
+ } | {
5
+ action: "spawn";
6
+ task: string;
7
+ } | {
8
+ action: "steer";
9
+ op: "inspect";
10
+ } | {
11
+ action: "steer";
12
+ op: "stop";
13
+ runId: string;
14
+ } | {
15
+ action: "approve";
16
+ checkpointId?: string;
17
+ } | {
18
+ action: "reject";
19
+ checkpointId?: string;
20
+ feedback?: string;
21
+ } | {
22
+ action: "tell";
23
+ runId: string;
24
+ text: string;
25
+ } | {
26
+ action: "pause";
27
+ runId: string;
28
+ } | {
29
+ action: "resume";
30
+ runId: string;
31
+ };
32
+ export declare class TurnClassifier {
33
+ private readonly llm;
34
+ private readonly model;
35
+ constructor(llm: LLMClient, model: string);
36
+ /**
37
+ * Classify the user's input turn.
38
+ * Uses jsonObjectMode:true (loose JSON mode) for provider parity.
39
+ * Any failure in the LLM call or JSON parse returns { action: "answer" }.
40
+ */
41
+ classify(input: string): Promise<ClassifierAction>;
42
+ }
43
+ //# sourceMappingURL=turn-classifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turn-classifier.d.ts","sourceRoot":"","sources":["../../src/chat/turn-classifier.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAIvD,MAAM,MAAM,gBAAgB,GACxB;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,GACpB;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,SAAS,CAAA;CAAE,GAClC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9D;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AA0GxC,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAY;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM;IAKzC;;;;OAIG;IACG,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;CA8BzD"}
@@ -0,0 +1,150 @@
1
+ // ── turn-classifier.ts ────────────────────────────────────────────────
2
+ //
3
+ // Classifies each user turn via a single jsonObjectMode LLMClient.chat call.
4
+ // Any parse failure returns { action: "answer" } — never throws.
5
+ import { z } from "zod";
6
+ // ── Zod discriminated union ───────────────────────────────────────────
7
+ const ClassifierActionSchema = z.discriminatedUnion("action", [
8
+ z.object({ action: z.literal("answer") }),
9
+ z.object({ action: z.literal("spawn"), task: z.string() }),
10
+ z.object({
11
+ action: z.literal("steer"),
12
+ op: z.union([
13
+ z.literal("inspect"),
14
+ z.object({ op: z.literal("stop"), runId: z.string() }).shape.op,
15
+ ]),
16
+ runId: z.string().optional(),
17
+ }),
18
+ z.object({ action: z.literal("approve"), checkpointId: z.string().optional() }),
19
+ z.object({
20
+ action: z.literal("reject"),
21
+ checkpointId: z.string().optional(),
22
+ feedback: z.string().optional(),
23
+ }),
24
+ z.object({ action: z.literal("tell"), runId: z.string(), text: z.string() }),
25
+ z.object({ action: z.literal("pause"), runId: z.string() }),
26
+ z.object({ action: z.literal("resume"), runId: z.string() }),
27
+ ]);
28
+ const FALLBACK = { action: "answer" };
29
+ // ── Helpers ───────────────────────────────────────────────────────────
30
+ /**
31
+ * Strip code fences (```json ... ``` or ``` ... ```) from a string.
32
+ */
33
+ function stripCodeFences(text) {
34
+ return text.replace(/```(?:json)?\s*([\s\S]*?)```/g, "$1").trim();
35
+ }
36
+ /**
37
+ * Extract the first balanced {...} JSON object substring.
38
+ * Returns null if no balanced object found.
39
+ */
40
+ function extractFirstObject(text) {
41
+ const start = text.indexOf("{");
42
+ if (start === -1)
43
+ return null;
44
+ let depth = 0;
45
+ for (let i = start; i < text.length; i++) {
46
+ if (text[i] === "{")
47
+ depth++;
48
+ else if (text[i] === "}") {
49
+ depth--;
50
+ if (depth === 0)
51
+ return text.slice(start, i + 1);
52
+ }
53
+ }
54
+ return null;
55
+ }
56
+ /**
57
+ * Defensively parse text into a ClassifierAction.
58
+ * Returns FALLBACK on any error.
59
+ */
60
+ function parseClassifierAction(text) {
61
+ try {
62
+ const stripped = stripCodeFences(text);
63
+ const extracted = extractFirstObject(stripped) ?? stripped;
64
+ const parsed = JSON.parse(extracted);
65
+ const result = ClassifierActionSchema.safeParse(parsed);
66
+ if (result.success) {
67
+ // Reconstruct steer with proper shape
68
+ const data = result.data;
69
+ if (data.action === "answer")
70
+ return { action: "answer" };
71
+ if (data.action === "spawn")
72
+ return { action: "spawn", task: data.task };
73
+ if (data.action === "steer") {
74
+ const raw = parsed;
75
+ if (raw["op"] === "stop" && typeof raw["runId"] === "string") {
76
+ return { action: "steer", op: "stop", runId: raw["runId"] };
77
+ }
78
+ return { action: "steer", op: "inspect" };
79
+ }
80
+ if (data.action === "approve") {
81
+ return { action: "approve", checkpointId: data.checkpointId };
82
+ }
83
+ if (data.action === "reject") {
84
+ return {
85
+ action: "reject",
86
+ checkpointId: data.checkpointId,
87
+ feedback: data.feedback,
88
+ };
89
+ }
90
+ if (data.action === "tell") {
91
+ return { action: "tell", runId: data.runId, text: data.text };
92
+ }
93
+ if (data.action === "pause") {
94
+ return { action: "pause", runId: data.runId };
95
+ }
96
+ if (data.action === "resume") {
97
+ return { action: "resume", runId: data.runId };
98
+ }
99
+ }
100
+ return FALLBACK;
101
+ }
102
+ catch {
103
+ return FALLBACK;
104
+ }
105
+ }
106
+ // ── TurnClassifier ────────────────────────────────────────────────────
107
+ export class TurnClassifier {
108
+ llm;
109
+ model;
110
+ constructor(llm, model) {
111
+ this.llm = llm;
112
+ this.model = model;
113
+ }
114
+ /**
115
+ * Classify the user's input turn.
116
+ * Uses jsonObjectMode:true (loose JSON mode) for provider parity.
117
+ * Any failure in the LLM call or JSON parse returns { action: "answer" }.
118
+ */
119
+ async classify(input) {
120
+ const system = [
121
+ "You are a routing classifier for a chat assistant.",
122
+ "Given the user message, decide what action to take.",
123
+ 'Return ONLY a JSON object with an "action" field.',
124
+ 'Options:',
125
+ ' {"action":"answer"} — answer the question directly',
126
+ ' {"action":"spawn","task":"<task description>"} — spawn a new agent run',
127
+ ' {"action":"steer","op":"inspect"} — inspect running agents',
128
+ ' {"action":"steer","op":"stop","runId":"<id>"} — stop a specific run',
129
+ ' {"action":"approve","checkpointId":"<id?>"} — approve a pending checkpoint',
130
+ ' {"action":"reject","checkpointId":"<id?>","feedback":"<why?>"} — reject a checkpoint',
131
+ ' {"action":"tell","runId":"<id>","text":"<instruction>"} — queue free-text guidance for a run',
132
+ ' {"action":"pause","runId":"<id>"} — soft-pause a run (process stays alive)',
133
+ ' {"action":"resume","runId":"<id>"} — resume a soft-paused run',
134
+ "Return ONLY the JSON object, no other text.",
135
+ ].join("\n");
136
+ try {
137
+ const response = await this.llm.chat({
138
+ model: this.model,
139
+ system,
140
+ messages: [{ role: "user", content: input }],
141
+ jsonObjectMode: true,
142
+ });
143
+ return parseClassifierAction(response.text);
144
+ }
145
+ catch {
146
+ return FALLBACK;
147
+ }
148
+ }
149
+ }
150
+ //# sourceMappingURL=turn-classifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turn-classifier.js","sourceRoot":"","sources":["../../src/chat/turn-classifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * `agent-bober blackboard publish|read` — inter-agent fleet blackboard CLI (Phase B).
3
+ *
4
+ * Subcommands:
5
+ * publish <value> [--round N] — Publish a finding to the shared fleet blackboard.
6
+ * read [--all] — Print findings from the shared fleet blackboard.
7
+ *
8
+ * Error handling: CLI handlers MUST NOT throw. They set process.exitCode=1 and
9
+ * return on all errors. Pattern mirrors src/cli/commands/facts.ts.
10
+ *
11
+ * The db path is read from config.fleet.blackboardDbPath ONLY — never re-derived
12
+ * from cwd. This is the child-visible seam: the scaffolder wrote the absolute path
13
+ * into each child's bober.config.json so children in different cwds can share one db.
14
+ */
15
+ import type { Command } from "commander";
16
+ /**
17
+ * Core for `blackboard publish` — DI'd projectRoot + nowIso for tests.
18
+ * Reads the absolute db path from config.fleet only (never re-derives from cwd).
19
+ * Clean exit-1 (no throw) when no fleet section is present.
20
+ */
21
+ export declare function runBlackboardPublish(projectRoot: string, value: string, opts: {
22
+ round?: string;
23
+ }, nowIso?: string): Promise<void>;
24
+ /**
25
+ * Core for `blackboard read [--all]` — DI'd projectRoot for tests.
26
+ * Reads the absolute db path from config.fleet only (never re-derives from cwd).
27
+ * Clean exit-1 (no throw) when no fleet section is present.
28
+ */
29
+ export declare function runBlackboardRead(projectRoot: string, opts: {
30
+ all?: boolean;
31
+ }): Promise<void>;
32
+ export declare function registerBlackboardCommand(program: Command): void;
33
+ //# sourceMappingURL=blackboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blackboard.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/blackboard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAezC;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EACxB,MAAM,GAAE,MAAiC,GACxC,OAAO,CAAC,IAAI,CAAC,CAuCf;AAID;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,GACtB,OAAO,CAAC,IAAI,CAAC,CAkCf;AAID,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoBhE"}