toolroll 0.5.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 (626) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1113 -0
  3. package/THIRD_PARTY_NOTICES.md +449 -0
  4. package/dist/accent-colors.d.ts +48 -0
  5. package/dist/accent-colors.js +122 -0
  6. package/dist/action-ledger.d.ts +26 -0
  7. package/dist/action-ledger.js +75 -0
  8. package/dist/agent-fence.d.ts +42 -0
  9. package/dist/agent-fence.js +183 -0
  10. package/dist/agentconfig.d.ts +216 -0
  11. package/dist/agentconfig.js +454 -0
  12. package/dist/api-tokens.d.ts +16 -0
  13. package/dist/api-tokens.js +27 -0
  14. package/dist/approval-policy.d.ts +69 -0
  15. package/dist/approval-policy.js +137 -0
  16. package/dist/approval-rules-ui.d.ts +25 -0
  17. package/dist/approval-rules-ui.js +39 -0
  18. package/dist/assignment-adapters.d.ts +180 -0
  19. package/dist/assignment-adapters.js +239 -0
  20. package/dist/assignment-brief.d.ts +71 -0
  21. package/dist/assignment-brief.js +129 -0
  22. package/dist/assignment-delivery.d.ts +56 -0
  23. package/dist/assignment-delivery.js +160 -0
  24. package/dist/assignment-presentation.d.ts +26 -0
  25. package/dist/assignment-presentation.js +80 -0
  26. package/dist/assignment-status.d.ts +62 -0
  27. package/dist/assignment-status.js +152 -0
  28. package/dist/assignment-ui.d.ts +71 -0
  29. package/dist/assignment-ui.js +103 -0
  30. package/dist/assignment.d.ts +222 -0
  31. package/dist/assignment.js +399 -0
  32. package/dist/attest.d.ts +56 -0
  33. package/dist/attest.js +153 -0
  34. package/dist/backend.d.ts +97 -0
  35. package/dist/backend.js +166 -0
  36. package/dist/backup-ui.d.ts +22 -0
  37. package/dist/backup-ui.js +59 -0
  38. package/dist/backup.d.ts +84 -0
  39. package/dist/backup.js +421 -0
  40. package/dist/beads.d.ts +34 -0
  41. package/dist/beads.js +135 -0
  42. package/dist/bin.d.ts +2 -0
  43. package/dist/bin.js +22 -0
  44. package/dist/board.d.ts +150 -0
  45. package/dist/board.js +210 -0
  46. package/dist/boot-identity.d.ts +63 -0
  47. package/dist/boot-identity.js +99 -0
  48. package/dist/browser/THIRD_PARTY_NOTICES.txt +2295 -0
  49. package/dist/browser/workspace.css +4 -0
  50. package/dist/browser/workspace.js +225 -0
  51. package/dist/browser-crew.d.ts +11 -0
  52. package/dist/browser-crew.js +50 -0
  53. package/dist/browser-shell.d.ts +8 -0
  54. package/dist/browser-shell.js +60 -0
  55. package/dist/browser-workspace.d.ts +780 -0
  56. package/dist/browser-workspace.js +47 -0
  57. package/dist/budget-alerts.d.ts +19 -0
  58. package/dist/budget-alerts.js +46 -0
  59. package/dist/builder.d.ts +370 -0
  60. package/dist/builder.js +3262 -0
  61. package/dist/capscan.d.ts +35 -0
  62. package/dist/capscan.js +113 -0
  63. package/dist/chat-acceptance.d.ts +71 -0
  64. package/dist/chat-acceptance.js +120 -0
  65. package/dist/chat-actions.d.ts +265 -0
  66. package/dist/chat-actions.js +1273 -0
  67. package/dist/chat-channel.d.ts +109 -0
  68. package/dist/chat-channel.js +652 -0
  69. package/dist/chat-continuity.d.ts +32 -0
  70. package/dist/chat-continuity.js +317 -0
  71. package/dist/chat-controls.d.ts +113 -0
  72. package/dist/chat-controls.js +53 -0
  73. package/dist/chat-delivery-state.d.ts +159 -0
  74. package/dist/chat-delivery-state.js +309 -0
  75. package/dist/chat-delivery.d.ts +38 -0
  76. package/dist/chat-delivery.js +693 -0
  77. package/dist/chat-display.d.ts +1 -0
  78. package/dist/chat-display.js +18 -0
  79. package/dist/chat-evidence.d.ts +123 -0
  80. package/dist/chat-evidence.js +207 -0
  81. package/dist/chat-flow.d.ts +44 -0
  82. package/dist/chat-flow.js +215 -0
  83. package/dist/chat-inbox.d.ts +57 -0
  84. package/dist/chat-inbox.js +123 -0
  85. package/dist/chat-polish.d.ts +16 -0
  86. package/dist/chat-polish.js +135 -0
  87. package/dist/chat-review.d.ts +46 -0
  88. package/dist/chat-review.js +98 -0
  89. package/dist/chat-rooms.d.ts +123 -0
  90. package/dist/chat-rooms.js +216 -0
  91. package/dist/chat-task-actions.d.ts +44 -0
  92. package/dist/chat-task-actions.js +79 -0
  93. package/dist/check-progress.d.ts +51 -0
  94. package/dist/check-progress.js +290 -0
  95. package/dist/child-database.d.ts +12 -0
  96. package/dist/child-database.js +30 -0
  97. package/dist/claim.d.ts +688 -0
  98. package/dist/claim.js +1740 -0
  99. package/dist/cli.d.ts +137 -0
  100. package/dist/cli.js +1461 -0
  101. package/dist/codex-limits.d.ts +15 -0
  102. package/dist/codex-limits.js +145 -0
  103. package/dist/coding-context.d.ts +55 -0
  104. package/dist/coding-context.js +92 -0
  105. package/dist/coding-handoff.d.ts +57 -0
  106. package/dist/coding-handoff.js +277 -0
  107. package/dist/coding-provider.d.ts +72 -0
  108. package/dist/coding-provider.js +424 -0
  109. package/dist/coding-shipping-ui.d.ts +4 -0
  110. package/dist/coding-shipping-ui.js +12 -0
  111. package/dist/coding-types.d.ts +62 -0
  112. package/dist/coding-types.js +1 -0
  113. package/dist/coding-ui.d.ts +17 -0
  114. package/dist/coding-ui.js +364 -0
  115. package/dist/coding-update.d.ts +15 -0
  116. package/dist/coding-update.js +149 -0
  117. package/dist/coding-workspace.d.ts +124 -0
  118. package/dist/coding-workspace.js +768 -0
  119. package/dist/container-state.d.ts +5 -0
  120. package/dist/container-state.js +62 -0
  121. package/dist/containment.d.ts +197 -0
  122. package/dist/containment.js +559 -0
  123. package/dist/contest.d.ts +318 -0
  124. package/dist/contest.js +753 -0
  125. package/dist/control-setup.d.ts +35 -0
  126. package/dist/control-setup.js +40 -0
  127. package/dist/control-ui.d.ts +29 -0
  128. package/dist/control-ui.js +53 -0
  129. package/dist/controller-service.d.ts +1 -0
  130. package/dist/controller-service.js +19 -0
  131. package/dist/controller-supervisor.d.ts +30 -0
  132. package/dist/controller-supervisor.js +104 -0
  133. package/dist/converse.d.ts +304 -0
  134. package/dist/converse.js +849 -0
  135. package/dist/coordinator-proposals.d.ts +29 -0
  136. package/dist/coordinator-proposals.js +137 -0
  137. package/dist/coordinator.d.ts +186 -0
  138. package/dist/coordinator.js +447 -0
  139. package/dist/credentials-ui.d.ts +25 -0
  140. package/dist/credentials-ui.js +48 -0
  141. package/dist/daemon.d.ts +209 -0
  142. package/dist/daemon.js +604 -0
  143. package/dist/decision.d.ts +120 -0
  144. package/dist/decision.js +388 -0
  145. package/dist/demo.d.ts +55 -0
  146. package/dist/demo.js +992 -0
  147. package/dist/desktop-access.d.ts +28 -0
  148. package/dist/desktop-access.js +88 -0
  149. package/dist/desktop-bundle.d.ts +16 -0
  150. package/dist/desktop-bundle.js +74 -0
  151. package/dist/desktop-host.d.ts +54 -0
  152. package/dist/desktop-host.js +508 -0
  153. package/dist/desktop-update-gate.d.ts +12 -0
  154. package/dist/desktop-update-gate.js +91 -0
  155. package/dist/desktop-update-recovery.d.ts +14 -0
  156. package/dist/desktop-update-recovery.js +243 -0
  157. package/dist/desktop-update.d.ts +110 -0
  158. package/dist/desktop-update.js +740 -0
  159. package/dist/discord-api.d.ts +20 -0
  160. package/dist/discord-api.js +138 -0
  161. package/dist/discord-chat.d.ts +16 -0
  162. package/dist/discord-chat.js +381 -0
  163. package/dist/discord-settings.d.ts +7 -0
  164. package/dist/discord-settings.js +75 -0
  165. package/dist/discord.d.ts +10 -0
  166. package/dist/discord.js +169 -0
  167. package/dist/discover.d.ts +75 -0
  168. package/dist/discover.js +150 -0
  169. package/dist/dispatch.d.ts +100 -0
  170. package/dist/dispatch.js +311 -0
  171. package/dist/dispose.d.ts +161 -0
  172. package/dist/dispose.js +803 -0
  173. package/dist/email-settings.d.ts +34 -0
  174. package/dist/email-settings.js +50 -0
  175. package/dist/envelope.d.ts +47 -0
  176. package/dist/envelope.js +105 -0
  177. package/dist/evidence-pack.d.ts +185 -0
  178. package/dist/evidence-pack.js +258 -0
  179. package/dist/evidence.d.ts +345 -0
  180. package/dist/evidence.js +782 -0
  181. package/dist/exec.d.ts +285 -0
  182. package/dist/exec.js +1841 -0
  183. package/dist/exhaustion.d.ts +85 -0
  184. package/dist/exhaustion.js +141 -0
  185. package/dist/export-ui.d.ts +4 -0
  186. package/dist/export-ui.js +17 -0
  187. package/dist/export.d.ts +48 -0
  188. package/dist/export.js +305 -0
  189. package/dist/flow-actions.d.ts +77 -0
  190. package/dist/flow-actions.js +203 -0
  191. package/dist/flow-code.d.ts +50 -0
  192. package/dist/flow-code.js +159 -0
  193. package/dist/flow-draft.d.ts +38 -0
  194. package/dist/flow-draft.js +80 -0
  195. package/dist/flow-engine.d.ts +66 -0
  196. package/dist/flow-engine.js +416 -0
  197. package/dist/flow-insights.d.ts +95 -0
  198. package/dist/flow-insights.js +149 -0
  199. package/dist/flow-live.d.ts +24 -0
  200. package/dist/flow-live.js +150 -0
  201. package/dist/flow-people.d.ts +24 -0
  202. package/dist/flow-people.js +91 -0
  203. package/dist/flow-replies.d.ts +48 -0
  204. package/dist/flow-replies.js +113 -0
  205. package/dist/flow-scripts.d.ts +38 -0
  206. package/dist/flow-scripts.js +73 -0
  207. package/dist/flow-secrets.d.ts +13 -0
  208. package/dist/flow-secrets.js +45 -0
  209. package/dist/flow-sort.d.ts +82 -0
  210. package/dist/flow-sort.js +153 -0
  211. package/dist/flow-steps.d.ts +40 -0
  212. package/dist/flow-steps.js +408 -0
  213. package/dist/flow-triggers.d.ts +244 -0
  214. package/dist/flow-triggers.js +959 -0
  215. package/dist/flows-ui.d.ts +20 -0
  216. package/dist/flows-ui.js +175 -0
  217. package/dist/flows.d.ts +229 -0
  218. package/dist/flows.js +968 -0
  219. package/dist/fonts.d.ts +19 -0
  220. package/dist/fonts.js +19 -0
  221. package/dist/gaps.d.ts +35 -0
  222. package/dist/gaps.js +101 -0
  223. package/dist/gate-failure.d.ts +40 -0
  224. package/dist/gate-failure.js +66 -0
  225. package/dist/git.d.ts +54 -0
  226. package/dist/git.js +94 -0
  227. package/dist/google-mail.d.ts +58 -0
  228. package/dist/google-mail.js +151 -0
  229. package/dist/grant.d.ts +136 -0
  230. package/dist/grant.js +238 -0
  231. package/dist/graph.d.ts +164 -0
  232. package/dist/graph.js +383 -0
  233. package/dist/guides.d.ts +22 -0
  234. package/dist/guides.js +363 -0
  235. package/dist/held.d.ts +150 -0
  236. package/dist/held.js +799 -0
  237. package/dist/invoke.d.ts +112 -0
  238. package/dist/invoke.js +780 -0
  239. package/dist/issues.d.ts +41 -0
  240. package/dist/issues.js +131 -0
  241. package/dist/job-object-helper.ps1 +252 -0
  242. package/dist/jsonl-discriminants.d.ts +11 -0
  243. package/dist/jsonl-discriminants.js +93 -0
  244. package/dist/keys.d.ts +104 -0
  245. package/dist/keys.js +229 -0
  246. package/dist/kits-ui.d.ts +17 -0
  247. package/dist/kits-ui.js +46 -0
  248. package/dist/kits.d.ts +86 -0
  249. package/dist/kits.js +215 -0
  250. package/dist/knowledge-cli.d.ts +101 -0
  251. package/dist/knowledge-cli.js +92 -0
  252. package/dist/knowledge-ui.d.ts +24 -0
  253. package/dist/knowledge-ui.js +40 -0
  254. package/dist/lead-context.d.ts +8 -0
  255. package/dist/lead-context.js +56 -0
  256. package/dist/lead-follow.d.ts +22 -0
  257. package/dist/lead-follow.js +167 -0
  258. package/dist/lead-status.d.ts +75 -0
  259. package/dist/lead-status.js +285 -0
  260. package/dist/ledger-chain.d.ts +46 -0
  261. package/dist/ledger-chain.js +187 -0
  262. package/dist/ledger-csv.d.ts +4 -0
  263. package/dist/ledger-csv.js +11 -0
  264. package/dist/ledger-view.d.ts +24 -0
  265. package/dist/ledger-view.js +58 -0
  266. package/dist/limits-ui.d.ts +26 -0
  267. package/dist/limits-ui.js +67 -0
  268. package/dist/link.d.ts +72 -0
  269. package/dist/link.js +217 -0
  270. package/dist/live.d.ts +96 -0
  271. package/dist/live.js +366 -0
  272. package/dist/liveness.d.ts +30 -0
  273. package/dist/liveness.js +42 -0
  274. package/dist/log.d.ts +7 -0
  275. package/dist/log.js +25 -0
  276. package/dist/mailbox.d.ts +57 -0
  277. package/dist/mailbox.js +150 -0
  278. package/dist/maintenance.d.ts +11 -0
  279. package/dist/maintenance.js +35 -0
  280. package/dist/mate-cli.d.ts +52 -0
  281. package/dist/mate-cli.js +345 -0
  282. package/dist/mate-contract.d.ts +10 -0
  283. package/dist/mate-contract.js +30 -0
  284. package/dist/mate-doors.d.ts +69 -0
  285. package/dist/mate-doors.js +548 -0
  286. package/dist/mate-progress.d.ts +29 -0
  287. package/dist/mate-progress.js +121 -0
  288. package/dist/mate-tools.d.ts +94 -0
  289. package/dist/mate-tools.js +1878 -0
  290. package/dist/mate.d.ts +92 -0
  291. package/dist/mate.js +435 -0
  292. package/dist/mcp-connect.d.ts +103 -0
  293. package/dist/mcp-connect.js +252 -0
  294. package/dist/mcp.d.ts +27 -0
  295. package/dist/mcp.js +651 -0
  296. package/dist/memory-cli.d.ts +466 -0
  297. package/dist/memory-cli.js +111 -0
  298. package/dist/memory-pass.d.ts +160 -0
  299. package/dist/memory-pass.js +409 -0
  300. package/dist/metrics.d.ts +3 -0
  301. package/dist/metrics.js +56 -0
  302. package/dist/mobile-viewport.d.ts +3 -0
  303. package/dist/mobile-viewport.js +37 -0
  304. package/dist/model-catalog.d.ts +118 -0
  305. package/dist/model-catalog.js +376 -0
  306. package/dist/models-cli.d.ts +102 -0
  307. package/dist/models-cli.js +66 -0
  308. package/dist/models-ui.d.ts +34 -0
  309. package/dist/models-ui.js +68 -0
  310. package/dist/modes.d.ts +80 -0
  311. package/dist/modes.js +182 -0
  312. package/dist/monitoring-settings.d.ts +44 -0
  313. package/dist/monitoring-settings.js +173 -0
  314. package/dist/monitoring-ui.d.ts +20 -0
  315. package/dist/monitoring-ui.js +51 -0
  316. package/dist/monitoring.d.ts +34 -0
  317. package/dist/monitoring.js +221 -0
  318. package/dist/names.d.ts +67 -0
  319. package/dist/names.js +102 -0
  320. package/dist/observations.d.ts +40 -0
  321. package/dist/observations.js +211 -0
  322. package/dist/oidc.d.ts +71 -0
  323. package/dist/oidc.js +182 -0
  324. package/dist/onboard.d.ts +108 -0
  325. package/dist/onboard.js +325 -0
  326. package/dist/openrouter-models.d.ts +30 -0
  327. package/dist/openrouter-models.js +120 -0
  328. package/dist/operate.d.ts +118 -0
  329. package/dist/operate.js +11321 -0
  330. package/dist/peek-cli.d.ts +97 -0
  331. package/dist/peek-cli.js +215 -0
  332. package/dist/peek.d.ts +134 -0
  333. package/dist/peek.js +578 -0
  334. package/dist/phase-routing.d.ts +307 -0
  335. package/dist/phase-routing.js +658 -0
  336. package/dist/plan-auto.d.ts +14 -0
  337. package/dist/plan-auto.js +92 -0
  338. package/dist/plan.d.ts +186 -0
  339. package/dist/plan.js +401 -0
  340. package/dist/planner-source.d.ts +251 -0
  341. package/dist/planner-source.js +460 -0
  342. package/dist/planner.d.ts +75 -0
  343. package/dist/planner.js +992 -0
  344. package/dist/policy-ui.d.ts +20 -0
  345. package/dist/policy-ui.js +41 -0
  346. package/dist/policy.d.ts +111 -0
  347. package/dist/policy.js +231 -0
  348. package/dist/prepared-evidence.d.ts +16 -0
  349. package/dist/prepared-evidence.js +96 -0
  350. package/dist/pricing.d.ts +45 -0
  351. package/dist/pricing.js +77 -0
  352. package/dist/principal.d.ts +42 -0
  353. package/dist/principal.js +82 -0
  354. package/dist/probe.d.ts +46 -0
  355. package/dist/probe.js +79 -0
  356. package/dist/process-custody.d.ts +17 -0
  357. package/dist/process-custody.js +91 -0
  358. package/dist/process-liveness.d.ts +10 -0
  359. package/dist/process-liveness.js +81 -0
  360. package/dist/process-recovery-anchor.d.ts +75 -0
  361. package/dist/process-recovery-anchor.js +188 -0
  362. package/dist/process-recovery-coalition.d.ts +25 -0
  363. package/dist/process-recovery-coalition.js +105 -0
  364. package/dist/process-recovery-eligibility.d.ts +178 -0
  365. package/dist/process-recovery-eligibility.js +170 -0
  366. package/dist/process-recovery-native.d.ts +172 -0
  367. package/dist/process-recovery-native.js +592 -0
  368. package/dist/process-recovery-provenance.d.ts +163 -0
  369. package/dist/process-recovery-provenance.js +292 -0
  370. package/dist/process-recovery-services.d.ts +56 -0
  371. package/dist/process-recovery-services.js +191 -0
  372. package/dist/process-recovery-settlement.d.ts +32 -0
  373. package/dist/process-recovery-settlement.js +132 -0
  374. package/dist/process-recovery.d.ts +41 -0
  375. package/dist/process-recovery.js +91 -0
  376. package/dist/process-tree.d.ts +41 -0
  377. package/dist/process-tree.js +264 -0
  378. package/dist/project-access.d.ts +14 -0
  379. package/dist/project-access.js +34 -0
  380. package/dist/project-cli.d.ts +18 -0
  381. package/dist/project-cli.js +104 -0
  382. package/dist/project-delete-ui.d.ts +22 -0
  383. package/dist/project-delete-ui.js +48 -0
  384. package/dist/project-delete.d.ts +55 -0
  385. package/dist/project-delete.js +413 -0
  386. package/dist/project-knowledge.d.ts +111 -0
  387. package/dist/project-knowledge.js +241 -0
  388. package/dist/project-learning.d.ts +100 -0
  389. package/dist/project-learning.js +438 -0
  390. package/dist/project-memory.d.ts +81 -0
  391. package/dist/project-memory.js +264 -0
  392. package/dist/project-skills.d.ts +152 -0
  393. package/dist/project-skills.js +660 -0
  394. package/dist/project-tools.d.ts +219 -0
  395. package/dist/project-tools.js +796 -0
  396. package/dist/project.d.ts +61 -0
  397. package/dist/project.js +125 -0
  398. package/dist/prompt.d.ts +22 -0
  399. package/dist/prompt.js +72 -0
  400. package/dist/proof.d.ts +513 -0
  401. package/dist/proof.js +1140 -0
  402. package/dist/proposal.d.ts +82 -0
  403. package/dist/proposal.js +210 -0
  404. package/dist/provider-connection.d.ts +22 -0
  405. package/dist/provider-connection.js +98 -0
  406. package/dist/provider-limits.d.ts +35 -0
  407. package/dist/provider-limits.js +95 -0
  408. package/dist/provider.d.ts +279 -0
  409. package/dist/provider.js +935 -0
  410. package/dist/publish.d.ts +107 -0
  411. package/dist/publish.js +650 -0
  412. package/dist/pulls.d.ts +118 -0
  413. package/dist/pulls.js +240 -0
  414. package/dist/push.d.ts +95 -0
  415. package/dist/push.js +353 -0
  416. package/dist/quality.d.ts +8 -0
  417. package/dist/quality.js +6 -0
  418. package/dist/recipe-ui.d.ts +18 -0
  419. package/dist/recipe-ui.js +152 -0
  420. package/dist/recipes.d.ts +81 -0
  421. package/dist/recipes.js +332 -0
  422. package/dist/remote.d.ts +67 -0
  423. package/dist/remote.js +122 -0
  424. package/dist/render.d.ts +64 -0
  425. package/dist/render.js +587 -0
  426. package/dist/report-summary.d.ts +13 -0
  427. package/dist/report-summary.js +15 -0
  428. package/dist/repos.d.ts +65 -0
  429. package/dist/repos.js +277 -0
  430. package/dist/repository-context-ui.d.ts +2 -0
  431. package/dist/repository-context-ui.js +10 -0
  432. package/dist/repository-context.d.ts +67 -0
  433. package/dist/repository-context.js +376 -0
  434. package/dist/restart-certification.d.ts +134 -0
  435. package/dist/restart-certification.js +226 -0
  436. package/dist/result-actions.d.ts +28 -0
  437. package/dist/result-actions.js +270 -0
  438. package/dist/result-completion.d.ts +18 -0
  439. package/dist/result-completion.js +66 -0
  440. package/dist/result-review.d.ts +213 -0
  441. package/dist/result-review.js +430 -0
  442. package/dist/retention-ui.d.ts +12 -0
  443. package/dist/retention-ui.js +39 -0
  444. package/dist/retention.d.ts +72 -0
  445. package/dist/retention.js +288 -0
  446. package/dist/review-context.d.ts +243 -0
  447. package/dist/review-context.js +1043 -0
  448. package/dist/review-evidence.d.ts +33 -0
  449. package/dist/review-evidence.js +56 -0
  450. package/dist/reviewer.d.ts +97 -0
  451. package/dist/reviewer.js +202 -0
  452. package/dist/routine.d.ts +228 -0
  453. package/dist/routine.js +764 -0
  454. package/dist/runner.d.ts +266 -0
  455. package/dist/runner.js +399 -0
  456. package/dist/scan.d.ts +32 -0
  457. package/dist/scan.js +92 -0
  458. package/dist/scope.d.ts +695 -0
  459. package/dist/scope.js +1176 -0
  460. package/dist/scout-report.d.ts +42 -0
  461. package/dist/scout-report.js +108 -0
  462. package/dist/scout.d.ts +69 -0
  463. package/dist/scout.js +351 -0
  464. package/dist/serve.d.ts +313 -0
  465. package/dist/serve.js +21776 -0
  466. package/dist/session-brief.d.ts +8 -0
  467. package/dist/session-brief.js +24 -0
  468. package/dist/session-cli.d.ts +13 -0
  469. package/dist/session-cli.js +284 -0
  470. package/dist/session-contract.d.ts +183 -0
  471. package/dist/session-contract.js +122 -0
  472. package/dist/session-http.d.ts +19 -0
  473. package/dist/session-http.js +154 -0
  474. package/dist/session-server.d.ts +12 -0
  475. package/dist/session-server.js +37 -0
  476. package/dist/session-service.d.ts +22 -0
  477. package/dist/session-service.js +157 -0
  478. package/dist/setup-guide.d.ts +39 -0
  479. package/dist/setup-guide.js +93 -0
  480. package/dist/sign-in-guard.d.ts +45 -0
  481. package/dist/sign-in-guard.js +74 -0
  482. package/dist/skills-ui.d.ts +11 -0
  483. package/dist/skills-ui.js +58 -0
  484. package/dist/skills.d.ts +97 -0
  485. package/dist/skills.js +276 -0
  486. package/dist/slack-api.d.ts +55 -0
  487. package/dist/slack-api.js +229 -0
  488. package/dist/slack-chat.d.ts +28 -0
  489. package/dist/slack-chat.js +413 -0
  490. package/dist/slack-settings.d.ts +7 -0
  491. package/dist/slack-settings.js +75 -0
  492. package/dist/slack-state.d.ts +13 -0
  493. package/dist/slack-state.js +9 -0
  494. package/dist/slack.d.ts +13 -0
  495. package/dist/slack.js +167 -0
  496. package/dist/spend-ui.d.ts +28 -0
  497. package/dist/spend-ui.js +95 -0
  498. package/dist/spend.d.ts +142 -0
  499. package/dist/spend.js +313 -0
  500. package/dist/sqlite-runtime.d.ts +3 -0
  501. package/dist/sqlite-runtime.js +6 -0
  502. package/dist/sso-settings.d.ts +33 -0
  503. package/dist/sso-settings.js +103 -0
  504. package/dist/sso-ui.d.ts +22 -0
  505. package/dist/sso-ui.js +39 -0
  506. package/dist/storage.d.ts +15 -0
  507. package/dist/storage.js +84 -0
  508. package/dist/store.d.ts +7754 -0
  509. package/dist/store.js +23279 -0
  510. package/dist/structured-output.d.ts +58 -0
  511. package/dist/structured-output.js +103 -0
  512. package/dist/style-asset.d.ts +7 -0
  513. package/dist/style-asset.js +41 -0
  514. package/dist/subscription-chat.d.ts +46 -0
  515. package/dist/subscription-chat.js +275 -0
  516. package/dist/summary.d.ts +33 -0
  517. package/dist/summary.js +71 -0
  518. package/dist/supervisor.mjs +297 -0
  519. package/dist/surface.d.ts +63 -0
  520. package/dist/surface.js +352 -0
  521. package/dist/sync.d.ts +94 -0
  522. package/dist/sync.js +279 -0
  523. package/dist/task-composer.d.ts +13 -0
  524. package/dist/task-composer.js +52 -0
  525. package/dist/task-control.d.ts +165 -0
  526. package/dist/task-control.js +214 -0
  527. package/dist/task-outcome-cli.d.ts +10 -0
  528. package/dist/task-outcome-cli.js +92 -0
  529. package/dist/task-text.d.ts +30 -0
  530. package/dist/task-text.js +41 -0
  531. package/dist/team-cli.d.ts +15 -0
  532. package/dist/team-cli.js +618 -0
  533. package/dist/team-contract.d.ts +92 -0
  534. package/dist/team-contract.js +1 -0
  535. package/dist/team-http.d.ts +17 -0
  536. package/dist/team-http.js +144 -0
  537. package/dist/team-leads.d.ts +81 -0
  538. package/dist/team-leads.js +565 -0
  539. package/dist/team-runtime.d.ts +27 -0
  540. package/dist/team-runtime.js +264 -0
  541. package/dist/team-ui.d.ts +3 -0
  542. package/dist/team-ui.js +9 -0
  543. package/dist/team-updates.d.ts +8 -0
  544. package/dist/team-updates.js +57 -0
  545. package/dist/teammate-admin.d.ts +53 -0
  546. package/dist/teammate-admin.js +111 -0
  547. package/dist/teammate-desk.d.ts +60 -0
  548. package/dist/teammate-desk.js +154 -0
  549. package/dist/teammate-memory.d.ts +64 -0
  550. package/dist/teammate-memory.js +196 -0
  551. package/dist/teammate-question.d.ts +59 -0
  552. package/dist/teammate-question.js +175 -0
  553. package/dist/teammate-tools.d.ts +108 -0
  554. package/dist/teammate-tools.js +271 -0
  555. package/dist/teammate-week.d.ts +68 -0
  556. package/dist/teammate-week.js +132 -0
  557. package/dist/teammate-work.d.ts +76 -0
  558. package/dist/teammate-work.js +280 -0
  559. package/dist/teammates-ui.d.ts +20 -0
  560. package/dist/teammates-ui.js +166 -0
  561. package/dist/teammates.d.ts +180 -0
  562. package/dist/teammates.js +253 -0
  563. package/dist/teams-api.d.ts +33 -0
  564. package/dist/teams-api.js +204 -0
  565. package/dist/teams-chat.d.ts +26 -0
  566. package/dist/teams-chat.js +215 -0
  567. package/dist/teams-settings.d.ts +12 -0
  568. package/dist/teams-settings.js +57 -0
  569. package/dist/teams.d.ts +21 -0
  570. package/dist/teams.js +124 -0
  571. package/dist/telegram-flow.d.ts +49 -0
  572. package/dist/telegram-flow.js +110 -0
  573. package/dist/telegram-mate.d.ts +137 -0
  574. package/dist/telegram-mate.js +707 -0
  575. package/dist/telegram-progress.d.ts +14 -0
  576. package/dist/telegram-progress.js +129 -0
  577. package/dist/telegram-settings.d.ts +9 -0
  578. package/dist/telegram-settings.js +36 -0
  579. package/dist/telegram-status.d.ts +75 -0
  580. package/dist/telegram-status.js +265 -0
  581. package/dist/telegram-team.d.ts +85 -0
  582. package/dist/telegram-team.js +359 -0
  583. package/dist/telegram.d.ts +230 -0
  584. package/dist/telegram.js +1931 -0
  585. package/dist/templates.d.ts +65 -0
  586. package/dist/templates.js +118 -0
  587. package/dist/tool-launcher.d.ts +1 -0
  588. package/dist/tool-launcher.js +101 -0
  589. package/dist/tools-ui.d.ts +30 -0
  590. package/dist/tools-ui.js +40 -0
  591. package/dist/transitions-recipes.d.ts +1 -0
  592. package/dist/transitions-recipes.js +203 -0
  593. package/dist/tree-proof.d.ts +34 -0
  594. package/dist/tree-proof.js +58 -0
  595. package/dist/verification-evidence.d.ts +44 -0
  596. package/dist/verification-evidence.js +238 -0
  597. package/dist/version.d.ts +2 -0
  598. package/dist/version.js +10 -0
  599. package/dist/webhooks.d.ts +91 -0
  600. package/dist/webhooks.js +283 -0
  601. package/dist/work-index.d.ts +68 -0
  602. package/dist/work-index.js +384 -0
  603. package/dist/work-summary.d.ts +57 -0
  604. package/dist/work-summary.js +116 -0
  605. package/dist/workspace-motion.d.ts +4 -0
  606. package/dist/workspace-motion.js +133 -0
  607. package/dist/workspace-revision.d.ts +19 -0
  608. package/dist/workspace-revision.js +92 -0
  609. package/dist/workspace-ui.d.ts +204 -0
  610. package/dist/workspace-ui.js +411 -0
  611. package/dist/worktree-notices.d.ts +13 -0
  612. package/dist/worktree-notices.js +17 -0
  613. package/dist/worktree.d.ts +249 -0
  614. package/dist/worktree.js +720 -0
  615. package/package.json +122 -0
  616. package/scripts/canary-assertions.mjs +42 -0
  617. package/scripts/crash-canary.mjs +253 -0
  618. package/scripts/fixtures/crash-process.mjs +74 -0
  619. package/scripts/fixtures/pilot-scenarios.mjs +85 -0
  620. package/scripts/fixtures/restart-service.mjs +27 -0
  621. package/scripts/launchd-certification.mjs +143 -0
  622. package/scripts/pilot.mjs +121 -0
  623. package/scripts/proof-preflight.mjs +140 -0
  624. package/scripts/provider-canary.mjs +379 -0
  625. package/scripts/recovery-canary.mjs +135 -0
  626. package/scripts/restart-certification.mjs +98 -0
package/dist/held.js ADDED
@@ -0,0 +1,799 @@
1
+ /**
2
+ * The HeldSessionCoordinator (Parity II Phase 2, spec v2 S0 as amended
3
+ * through v6): the ONE owner of held attended sessions in an `up` process.
4
+ *
5
+ * Ownership transfer is the whole design: build() reaches its spawn point,
6
+ * hands this coordinator the captured settlement record and returns `held`
7
+ * WITHOUT settling anything — the watch loop keeps dispatching, and the
8
+ * session's lease heartbeats, exact timers, turn ledger, and eventual
9
+ * settlement all live here. A held run completes through the SAME
10
+ * settleProviderOutcome → disposeBuildOutcome pair every other road uses,
11
+ * or it is fenced to `interrupted` — never a third way.
12
+ *
13
+ * Phase 2D scope note, stated: this coordinator runs the attended
14
+ * authorization road end-to-end — final proof, custody, the brief as turn
15
+ * one, per-turn acceptance and marginal-delta settlement, expiry/lapse/
16
+ * turn-timeout/lease fences, crash custody — and ends the hold at the
17
+ * agent's first settled turn (terminal handoff, park, or silence, each
18
+ * classified by the shared settlement). The multi-turn conversation loop
19
+ * (operator turn box, answer injection, held repair) arrives with its
20
+ * console surfaces in the next slice; nothing here forecloses it.
21
+ */
22
+ import { randomBytes } from "node:crypto";
23
+ import { join } from "node:path";
24
+ import { connect } from "node:net";
25
+ import { attendedLivenessState, BEAT_MS } from "./liveness.js";
26
+ import { settleProviderOutcome } from "./builder.js";
27
+ import { disposeBuildOutcome } from "./dispose.js";
28
+ import { heldSocketPathProblem, startClaudeHeldSession } from "./exec.js";
29
+ import { invokeHeldAgent } from "./invoke.js";
30
+ import { claudeHeldArgv } from "./provider.js";
31
+ import { existsSync } from "node:fs";
32
+ import { finalizeParkHeld, heartbeat, release } from "./claim.js";
33
+ import { parseDecision, repairPrompt } from "./decision.js";
34
+ import { captureParkEvidence, readMailbox, storeEvidence } from "./evidence.js";
35
+ import { profileDigestOf } from "./scope.js";
36
+ import { heartbeat as runnerHeartbeat } from "./runner.js";
37
+ const dollarsToMicrousd = (dollars) => typeof dollars === "number" && Number.isFinite(dollars) ? Math.round(dollars * 1_000_000) : null;
38
+ /** Thrown INSIDE the final proof to roll the whole transaction back. */
39
+ class ConsumeRaced extends Error {
40
+ }
41
+ export class HeldSessionCoordinator {
42
+ sessions = new Map();
43
+ count() {
44
+ return this.sessions.size;
45
+ }
46
+ /**
47
+ * The final proof, custody intent, brief recording, spawn, and timer
48
+ * arming — one road, refusals typed. Returns once the session is HELD
49
+ * (or refused); never awaits the hold itself.
50
+ */
51
+ async launch(args) {
52
+ const { store, captured, runId, leaseId, runner, clock } = args;
53
+ const socketPath = join(args.socketDir, `so-${randomBytes(6).toString("hex")}.sock`);
54
+ const pathProblem = heldSocketPathProblem(socketPath);
55
+ if (pathProblem !== null)
56
+ return { ok: false, reason: "attended-unsupported", message: pathProblem };
57
+ const cookie = randomBytes(16).toString("hex");
58
+ // ---- the FINAL transactional proof (v2 S2d, v3 R6): rederived against
59
+ // live state AFTER worktree setup read the actual HEAD, consuming the
60
+ // one attempt and writing the custody intent immediately before spawn.
61
+ let proof;
62
+ try {
63
+ proof = store.transact(() => {
64
+ const live = store.readAuthorization(args.authorization.id);
65
+ if (live === null || live.closedAt !== null) {
66
+ return { ok: false, reason: "attended-only", message: "the authorization closed before dispatch" };
67
+ }
68
+ // The one attempt was consumed and bound at ADMISSION (atomic
69
+ // authority closure): the authorization names this very run, or it
70
+ // was spent elsewhere and nothing here spawns.
71
+ if (live.attemptRun !== runId) {
72
+ return { ok: false, reason: "attended-only", message: live.attemptRun === null ? "the authorization's attempt was never bound to this run at admission" : "the authorization's one attempt is already spent" };
73
+ }
74
+ let terms;
75
+ try {
76
+ terms = JSON.parse(live.termsJson);
77
+ }
78
+ catch {
79
+ return { ok: false, reason: "stale-authorization", message: "the signed terms cannot be parsed" };
80
+ }
81
+ const liveScopeDigest = captured.scope?.digest ?? "";
82
+ if (terms.scopeDigest !== liveScopeDigest) {
83
+ return { ok: false, reason: "stale-authorization", message: "the scope moved since the authorization was signed" };
84
+ }
85
+ const liveProfileDigest = profileDigestOf(captured.effective.profile);
86
+ if (terms.profileDigest !== liveProfileDigest) {
87
+ return { ok: false, reason: "stale-authorization", message: "the execution profile moved since the authorization was signed" };
88
+ }
89
+ if (terms.repo !== args.dispose.repo) {
90
+ return { ok: false, reason: "stale-authorization", message: "the repository moved since the authorization was signed" };
91
+ }
92
+ if (terms.head !== captured.baseRevision) {
93
+ return { ok: false, reason: "stale-authorization", message: `the head moved since the authorization was signed (${terms.head.slice(0, 12)} → ${captured.baseRevision.slice(0, 12)})` };
94
+ }
95
+ if (live.runner !== runner) {
96
+ return { ok: false, reason: "attended-held", message: `the authorization names ${live.runner}` };
97
+ }
98
+ // Custody FIRST, consumption LAST (parallel-sessions round 1,
99
+ // finding 4): a refusal returned from inside transact() COMMITS —
100
+ // only a throw rolls back — so the old consume-then-custody order
101
+ // left a run-held refusal with the one attempt already spent.
102
+ // Every refusal below this line must leave attempt_run null.
103
+ if (args.maxHeldSessions !== undefined && store.openHeldSessionCount(runner) >= args.maxHeldSessions) {
104
+ return {
105
+ ok: false,
106
+ reason: "session-cap",
107
+ message: `this machine holds ${store.openHeldSessionCount(runner)} of ${args.maxHeldSessions} attended sessions — end one, or raise --max-held-sessions`,
108
+ };
109
+ }
110
+ const custody = store.openHeldSession({
111
+ run: runId,
112
+ authorizationId: live.id,
113
+ runner,
114
+ leaseId,
115
+ upIncarnation: args.upIncarnation,
116
+ cookie,
117
+ socketPath,
118
+ now: clock(),
119
+ });
120
+ if (!custody.ok) {
121
+ return { ok: false, reason: custody.reason, message: "this run already holds a session" };
122
+ }
123
+ // The binding is re-proved in this same transaction: the run row
124
+ // carries the authorization it was admitted under, and the
125
+ // authorization still names the run. A disagreement rolls the
126
+ // custody insert back with the transaction — nothing spawns on a
127
+ // pair that moved.
128
+ const bound = store.readAuthorization(live.id);
129
+ const row = store.getRun(runId);
130
+ if (bound === null || bound.attemptRun !== runId || row === null || (row.attendedAuthorization ?? null) !== live.id) {
131
+ throw new ConsumeRaced();
132
+ }
133
+ return { ok: true };
134
+ });
135
+ }
136
+ catch (error) {
137
+ if (error instanceof ConsumeRaced) {
138
+ proof = { ok: false, reason: "attended-only", message: "another dispatch consumed the attempt first" };
139
+ }
140
+ else {
141
+ throw error;
142
+ }
143
+ }
144
+ if (!proof.ok) {
145
+ // The one attempt was spent at ADMISSION (atomic authority closure):
146
+ // a refusal here cannot un-spend it, so the authorization closes in
147
+ // the refusal's words rather than standing open-and-spent until its
148
+ // expiry — the operator sees why, and authorizes again if they wish.
149
+ store.closeAuthorization(args.authorization.id, `refused:${proof.reason}`, clock());
150
+ return proof;
151
+ }
152
+ // ---- the brief is turn one, recorded before any byte is written.
153
+ const recorded = store.recordSessionTurn({ run: runId, sourceKind: "brief", text: args.brief, now: clock() });
154
+ if (!recorded.ok) {
155
+ store.endHeldSession(runId, `refused:${recorded.reason}`, clock());
156
+ return { ok: false, reason: recorded.reason, message: `the brief could not be recorded (${recorded.reason})` };
157
+ }
158
+ // Answers riding the brief (round-6 finding 2): the builder's ordinary
159
+ // pre-spawn attach claimed delivery the agent has not proven — withdraw
160
+ // it, CAS each decision's delivery to the brief turn, and let
161
+ // acceptance re-attach exactly like an answer turn.
162
+ store.bindBriefDeliveries(runId, recorded.turn.id, captured.answers.map(one => one.decision.id));
163
+ // v105: and no more than what's left of a monthly budget this work counts toward, when it bills a key.
164
+ const monthly = store.budgetGate(new Date())({ ...store.budgetSubject(args.captured.taskRef), agents: store.agentsFor([captured.effective.profile.provider]) }).remainingMicrousd;
165
+ const remainingMicrousd = Math.min(args.authorization.budgetMicrousd - store.authorizationSpendMicrousd(args.authorization.id), monthly ?? Infinity);
166
+ const argv = claudeHeldArgv({
167
+ phase: "build",
168
+ model: captured.effective.model,
169
+ maxTurns: captured.effective.maxTurns ?? 40,
170
+ permissionMode: captured.effective.profile.provider === "claude" && captured.effective.profile.permissionArgv !== "bypassPermissions"
171
+ ? captured.effective.profile.permissionArgv
172
+ : "auto",
173
+ skipPermissions: captured.effective.skipPermissions,
174
+ resumeSession: null,
175
+ maxBudgetUsd: Math.max(0.01, remainingMicrousd / 1_000_000),
176
+ });
177
+ const controller = this.makeController(args, recorded.turn, socketPath, cookie);
178
+ const start = await invokeHeldAgent(store, runId, { provider: "claude", model: captured.effective.model }, argv, {
179
+ cwd: args.cwd,
180
+ omitEnv: args.omitEnv,
181
+ socketPath,
182
+ cookie,
183
+ ...(args.graceMs === undefined ? {} : { graceMs: args.graceMs }),
184
+ ...(args.starter === undefined ? {} : { starter: args.starter }),
185
+ events: {
186
+ onTurnInit: seq => this.onTurnInit(args, seq),
187
+ onTurnResult: (seq, event) => void this.onTurnResult(args, seq, event),
188
+ onStreamEvent: event => args.liveLog?.observe(event),
189
+ onExit: info => void this.onExit(args, info.code),
190
+ },
191
+ clock,
192
+ });
193
+ if (!start.ok) {
194
+ // Spawn failure with no pid ever stamped (v5's adopted F7 edge):
195
+ // close custody and settle explicitly — no permanent orphan.
196
+ store.settleTurnTerminal(recorded.turn.id, "cancelled", clock());
197
+ store.endHeldSession(runId, "spawn-failed", clock());
198
+ store.closeAuthorization(args.authorization.id, "spawn-failed", clock());
199
+ store.finishRun(runId, { outcome: "failed", reason: "spawn-failed", now: clock() });
200
+ release(store, leaseId, clock());
201
+ await args.releaseWorktree(args.cwd);
202
+ args.liveLog?.close();
203
+ this.drop(runId);
204
+ return { ok: false, reason: "spawn-failed", message: start.message };
205
+ }
206
+ controller.handle = start.handle;
207
+ if (!store.stampHeldSession(runId, start.handle.supervisorPid ?? -1, start.handle.agentPgid ?? -1)) {
208
+ // The custody row closed underneath the spawn: kill synchronously,
209
+ // never leave an unrecorded provider alive (v2 S1e).
210
+ start.handle.killHard();
211
+ this.drop(runId);
212
+ return { ok: false, reason: "fenced", message: "custody closed underneath the spawn" };
213
+ }
214
+ // The turn reaches stdin only after custody is stamped.
215
+ const turnJson = JSON.stringify({
216
+ type: "user",
217
+ message: { role: "user", content: [{ type: "text", text: args.brief }] },
218
+ });
219
+ if (start.handle.writeTurn(turnJson)) {
220
+ store.markTurnWritten(recorded.turn.id, clock());
221
+ this.armTurnTimer(args, controller);
222
+ }
223
+ else {
224
+ void this.fence(args, "write-failed");
225
+ }
226
+ return { ok: true };
227
+ }
228
+ /** Shutdown: fence every controller under ONE absolute deadline (v2 S0f
229
+ * + parallel-sessions round 1, finding 7): the deadline timer is cleared
230
+ * when the fences win so it cannot hold the process open, and the runs
231
+ * that did NOT settle in time are RETURNED for the caller to page —
232
+ * silence here contradicted up's "settled or paged" promise. */
233
+ async close() {
234
+ const all = [...this.sessions.keys()];
235
+ let deadline;
236
+ const timedOut = new Promise(pass => {
237
+ deadline = setTimeout(() => pass("deadline"), 30_000);
238
+ deadline.unref?.();
239
+ });
240
+ const winner = await Promise.race([
241
+ Promise.all(all.map(runId => this.fenceByRun(runId, "shutdown"))).then(() => "fenced"),
242
+ timedOut,
243
+ ]);
244
+ if (deadline !== undefined)
245
+ clearTimeout(deadline);
246
+ return winner === "fenced" ? [] : [...this.sessions.keys()];
247
+ }
248
+ /**
249
+ * The exact-run stop (v52): fence ONE held session now, through the
250
+ * supervisor's own handle — EOF → grace → kill, conservative settlement,
251
+ * the worktree preserved, the stop settled as `held` by the run's ending.
252
+ * The console calls this after the durable request; the lapse interval
253
+ * takes the same road for a stop filed by another process. Idempotent:
254
+ * a session already fencing or gone settles nothing twice.
255
+ */
256
+ stop(runId) {
257
+ return this.fenceByRun(runId, "stopped");
258
+ }
259
+ /** The beat endpoint, answers, and revocation poke this directly (v2 S1d). */
260
+ poke(runId) {
261
+ const controller = this.sessions.get(runId);
262
+ if (controller === undefined)
263
+ return;
264
+ const args = this.launches.get(runId);
265
+ if (args !== undefined)
266
+ void this.injectPendingAnswers(args);
267
+ }
268
+ /**
269
+ * The operator's own turn (v2 S1g, ruling 12-as-accepted): session-grade
270
+ * speech, recorded through the SAME gated transaction every injection
271
+ * takes — cap, single-flight, budget, open-decision, lease — so every
272
+ * refusal is typed and atomic.
273
+ */
274
+ injectOperatorTurn(runId, author, text) {
275
+ const args = this.launches.get(runId);
276
+ const controller = this.sessions.get(runId);
277
+ if (args === undefined || controller === undefined || controller.fenceStarted || controller.concluded) {
278
+ return { ok: false, reason: "no-held-session" };
279
+ }
280
+ return this.injectTurn(args, controller, { sourceKind: "operator", sourceId: null, author, text });
281
+ }
282
+ injectTurn(args, controller, turn) {
283
+ const recorded = args.store.recordSessionTurn({
284
+ run: args.runId,
285
+ sourceKind: turn.sourceKind,
286
+ sourceId: turn.sourceId,
287
+ author: turn.author,
288
+ text: turn.text,
289
+ repairLimit: 2,
290
+ now: args.clock(),
291
+ });
292
+ if (!recorded.ok)
293
+ return { ok: false, reason: recorded.reason };
294
+ const json = JSON.stringify({
295
+ type: "user",
296
+ message: { role: "user", content: [{ type: "text", text: turn.text }] },
297
+ });
298
+ if (controller.handle === null || !controller.handle.writeTurn(json)) {
299
+ args.store.settleTurnTerminal(recorded.turn.id, "cancelled", args.clock());
300
+ return { ok: false, reason: "write-failed" };
301
+ }
302
+ args.store.markTurnWritten(recorded.turn.id, args.clock());
303
+ this.armTurnTimer(args, controller);
304
+ return { ok: true };
305
+ }
306
+ async injectPendingAnswers(args) {
307
+ const controller = this.sessions.get(args.runId);
308
+ if (controller === undefined || controller.fenceStarted || controller.concluded)
309
+ return;
310
+ for (const decision of args.store.undeliveredDecisionsOf(args.runId)) {
311
+ const text = [
312
+ `The operator answered your question (decision ${decision.id}):`,
313
+ `chose "${decision.choice ?? decision.recommendation}"${decision.note === null || decision.note === "" ? "" : ` — ${decision.note}`}.`,
314
+ "Continue the work within the approved scope. When you finish, write your handoff exactly as the brief instructed.",
315
+ ].join(" ");
316
+ const injected = this.injectTurn(args, controller, {
317
+ sourceKind: "answer",
318
+ sourceId: decision.id,
319
+ author: null,
320
+ text,
321
+ });
322
+ // One at a time: single-flight means a second undelivered answer
323
+ // waits for the next scan after this turn settles.
324
+ if (injected.ok)
325
+ break;
326
+ }
327
+ }
328
+ // ---- internals -----------------------------------------------------------
329
+ launches = new Map();
330
+ makeController(args, brief, socketPath, cookie) {
331
+ let finish = () => { };
332
+ const done = new Promise(pass => {
333
+ finish = pass;
334
+ });
335
+ const controller = {
336
+ runId: args.runId,
337
+ fenceStarted: false,
338
+ concluded: false,
339
+ handle: null,
340
+ timers: [],
341
+ intervals: [],
342
+ turnTimer: null,
343
+ done,
344
+ finish,
345
+ };
346
+ this.sessions.set(args.runId, controller);
347
+ this.launches.set(args.runId, args);
348
+ // Exact timers (v2 S1d): absolute expiry, liveness lapse, lease pulse.
349
+ const now = args.clock().getTime();
350
+ const untilExpiry = Math.max(0, Date.parse(args.authorization.absoluteExpiry) - now);
351
+ const expiry = setTimeout(() => void this.fence(args, "expired"), untilExpiry);
352
+ expiry.unref?.();
353
+ controller.timers.push(expiry);
354
+ const lapse = setInterval(() => {
355
+ // The operator's exact-run stop (v52) takes the same fence road as a
356
+ // revocation: EOF → grace → kill through the supervisor's handle,
357
+ // conservative settlement, the worktree preserved.
358
+ if (args.store.applicableStopFor(args.runId) !== null) {
359
+ void this.fence(args, "stopped");
360
+ return;
361
+ }
362
+ const live = args.store.readAuthorization(args.authorization.id);
363
+ if (live === null || live.closedAt !== null) {
364
+ void this.fence(args, live?.endReason === "revoked" ? "revoked" : "lapsed");
365
+ return;
366
+ }
367
+ const state = attendedLivenessState(live.lastBeatAt === null ? null : Date.parse(live.lastBeatAt), args.clock().getTime(), Date.parse(live.absoluteExpiry));
368
+ if (state === "lapsed" || state === "expired")
369
+ void this.fence(args, state);
370
+ }, 5_000);
371
+ lapse.unref?.();
372
+ controller.intervals.push(lapse);
373
+ const lease = setInterval(() => {
374
+ try {
375
+ const answer = heartbeat(args.store, args.leaseId, args.clock());
376
+ if (!answer.ok) {
377
+ void this.fence(args, "lease-lost");
378
+ return;
379
+ }
380
+ if (args.runnerToken !== undefined) {
381
+ const alive = runnerHeartbeat(args.store, args.runner, args.runnerToken, args.clock());
382
+ if (!alive.ok) {
383
+ void this.fence(args, "lease-lost");
384
+ return;
385
+ }
386
+ }
387
+ // Answers persisted by ANY surface reach the live session here
388
+ // (v3 R3): the delivery-CAS inside recordSessionTurn makes the
389
+ // injection exactly-once whatever raced.
390
+ void this.injectPendingAnswers(args);
391
+ }
392
+ catch {
393
+ void this.fence(args, "lease-lost");
394
+ }
395
+ }, BEAT_MS);
396
+ lease.unref?.();
397
+ controller.intervals.push(lease);
398
+ return controller;
399
+ }
400
+ armTurnTimer(args, controller) {
401
+ if (controller.turnTimer !== null)
402
+ clearTimeout(controller.turnTimer);
403
+ const timer = setTimeout(() => void this.fence(args, "turn-timeout"), args.captured.effective.timeoutMs);
404
+ timer.unref?.();
405
+ controller.turnTimer = timer;
406
+ }
407
+ onTurnInit(args, seq) {
408
+ const turn = args.store.sessionTurnsOf(args.runId).find(one => one.seq === seq);
409
+ if (turn !== undefined)
410
+ args.store.markTurnAccepted(turn.id, args.clock());
411
+ // The brief's acceptance is the held road's receipt (round-6 finding
412
+ // 6): attached steering settles delivered on the same proof the
413
+ // one-shot transport's onReceipt carried.
414
+ if (seq === 1)
415
+ void args.store.settleSteerDelivered(args.runId, args.clock());
416
+ }
417
+ async onTurnResult(args, seq, event) {
418
+ const controller = this.sessions.get(args.runId);
419
+ if (controller === undefined || controller.fenceStarted || controller.concluded)
420
+ return;
421
+ const turn = args.store.sessionTurnsOf(args.runId).find(one => one.seq === seq);
422
+ if (turn === undefined)
423
+ return;
424
+ const usage = event["usage"];
425
+ const settled = args.store.settleTurn(turn.id, {
426
+ cumulativeMicrousd: dollarsToMicrousd(event["total_cost_usd"]),
427
+ outputTokens: typeof usage?.output_tokens === "number" ? usage.output_tokens : null,
428
+ now: args.clock(),
429
+ });
430
+ if (!settled.ok && settled.reason === "telemetry") {
431
+ await this.fence(args, "telemetry");
432
+ return;
433
+ }
434
+ if (controller.turnTimer !== null) {
435
+ clearTimeout(controller.turnTimer);
436
+ controller.turnTimer = null;
437
+ }
438
+ // CLASSIFY (v2 S1f, v6 W4): a terminal handoff concludes through the
439
+ // shared settlement; a park records the decision and the session STAYS
440
+ // HELD for the answer; a budget-exhausted result ends the hold; and a
441
+ // settled turn that left neither file is a conversation pause — the
442
+ // session waits for the operator.
443
+ const donePath = join(args.cwd, args.captured.done);
444
+ const mailboxPath = join(args.cwd, args.captured.mailbox);
445
+ if (String(event["subtype"] ?? "") === "error_max_budget_usd") {
446
+ await this.fence(args, "budget-exhausted");
447
+ return;
448
+ }
449
+ if (existsSync(donePath)) {
450
+ await this.conclude(args, event);
451
+ return;
452
+ }
453
+ if (existsSync(mailboxPath)) {
454
+ await this.heldPark(args, turn.id, event);
455
+ return;
456
+ }
457
+ // Idle: held, watching, awaiting the next turn.
458
+ }
459
+ /**
460
+ * A park inside a held session (v2 S1f + round-6 finding 3): payload
461
+ * preserved as evidence and unlinked exactly like the ordinary road,
462
+ * the decision recorded WITHOUT ending anything, causally linked to the
463
+ * turn that produced it. A malformed payload takes the held repair road
464
+ * — a machine-authored ledger turn in the SAME session, correlated to
465
+ * the producing turn (a malformed mailbox has no decision id), bounded;
466
+ * exhaustion disposes through the shared malformed machinery.
467
+ */
468
+ async heldPark(args, producingTurn, lastResult) {
469
+ const controller = this.sessions.get(args.runId);
470
+ if (controller === undefined || controller.fenceStarted || controller.concluded)
471
+ return;
472
+ const store = args.store;
473
+ const path = join(args.cwd, args.captured.mailbox);
474
+ const read = readMailbox(path);
475
+ if (!read.ok) {
476
+ if (!read.missing) {
477
+ try {
478
+ const { unlinkSync } = await import("node:fs");
479
+ unlinkSync(path);
480
+ }
481
+ catch {
482
+ // Unremovable is survivable; the commit path excludes the name.
483
+ }
484
+ }
485
+ return;
486
+ }
487
+ storeEvidence(store, args.captured.root, args.runId, "park-payload", "park.json", read.raw, `mailbox ${args.captured.mailbox}`, args.clock());
488
+ try {
489
+ const { unlinkSync } = await import("node:fs");
490
+ unlinkSync(path);
491
+ }
492
+ catch {
493
+ // The bytes are already in evidence.
494
+ }
495
+ const parsed = parseDecision(read.raw.toString("utf8"));
496
+ if (parsed.ok) {
497
+ const evidence = await captureParkEvidence(store, args.captured.git, args.cwd, args.captured.baseRevision, args.captured.root, args.runId, args.clock());
498
+ const payload = store.artifactsFor(args.runId).find(artifact => artifact.kind === "park-payload");
499
+ const sealed = finalizeParkHeld(store, {
500
+ runId: args.runId,
501
+ taskId: args.captured.taskId,
502
+ decision: parsed.decision,
503
+ artifactIds: [...(payload === undefined ? [] : [payload.id]), ...evidence],
504
+ sessionTurn: producingTurn,
505
+ now: args.clock(),
506
+ });
507
+ if (!sealed.ok)
508
+ await this.fence(args, sealed.reason);
509
+ return; // held: the answer arrives as the next turn
510
+ }
511
+ // Malformed: the held repair road (round-6 finding 3).
512
+ const repair = this.injectTurn(args, controller, {
513
+ sourceKind: "repair",
514
+ sourceId: producingTurn,
515
+ author: null,
516
+ text: repairPrompt(parsed.problems, args.captured.mailbox),
517
+ });
518
+ if (!repair.ok && repair.reason === "repair-exhausted") {
519
+ controller.concluded = true;
520
+ this.clearClocks(controller);
521
+ args.store.endHeldSession(args.runId, "malformed-decision", args.clock());
522
+ controller.handle?.endInput();
523
+ await Promise.race([
524
+ controller.handle?.exited ?? Promise.resolve({ code: null }),
525
+ new Promise(pass => setTimeout(() => {
526
+ controller.handle?.killHard();
527
+ pass({ code: null });
528
+ }, (args.graceMs ?? 10_000) + 10_000)),
529
+ ]);
530
+ const disposition = disposeBuildOutcome({
531
+ store: args.store,
532
+ policy: args.dispose.policy ?? "tick",
533
+ leaseId: args.leaseId,
534
+ runId: args.runId,
535
+ taskId: args.captured.taskId,
536
+ taskRef: args.captured.taskRef,
537
+ runner: args.runner,
538
+ repo: args.dispose.repo,
539
+ branch: args.captured.branch,
540
+ origin: args.dispose.origin,
541
+ provider: args.dispose.provider,
542
+ model: args.dispose.model,
543
+ worktreePath: args.cwd,
544
+ clock: args.clock,
545
+ }, { ok: false, reason: "malformed-decision", message: "the agent parked, but the payload is not a decision — twice over", problems: parsed.problems });
546
+ await args.releaseWorktree(args.cwd);
547
+ args.store.closeAuthorization(args.authorization.id, "malformed-decision", args.clock());
548
+ args.liveLog?.close();
549
+ args.onDisposed?.(disposition);
550
+ this.drop(args.runId);
551
+ }
552
+ void lastResult;
553
+ }
554
+ async onExit(args, code) {
555
+ const controller = this.sessions.get(args.runId);
556
+ if (controller === undefined || controller.fenceStarted || controller.concluded)
557
+ return;
558
+ // The process died with no settled result: conservative settlement.
559
+ await this.fence(args, code === null ? "exited" : `exited:${code}`);
560
+ }
561
+ async conclude(args, lastResult) {
562
+ const controller = this.sessions.get(args.runId);
563
+ if (controller === undefined || controller.concluded || controller.fenceStarted)
564
+ return;
565
+ controller.concluded = true;
566
+ this.clearClocks(controller);
567
+ // The admission door closes BEFORE anything awaits (round-6 finding
568
+ // 1): with ended_at stamped, a late external turn recording refuses
569
+ // inside ITS transaction, and a late result cannot re-open settlement
570
+ // (its turn is already settled or terminal).
571
+ args.store.endHeldSession(args.runId, "finished", args.clock());
572
+ // End the hold: EOF, let the supervisor fence its own child, bounded.
573
+ controller.handle?.endInput();
574
+ const exited = await Promise.race([
575
+ controller.handle?.exited ?? Promise.resolve({ code: 0 }),
576
+ new Promise(pass => setTimeout(() => {
577
+ controller.handle?.killHard();
578
+ pass({ code: null });
579
+ }, (args.graceMs ?? 10_000) + 20_000)),
580
+ ]);
581
+ const isError = lastResult["is_error"] === true || String(lastResult["subtype"] ?? "") !== "success";
582
+ const outcome = {
583
+ code: isError ? 1 : (exited.code ?? 0),
584
+ stderr: isError ? String(lastResult["result"] ?? lastResult["subtype"] ?? "error result") : "",
585
+ timedOut: false,
586
+ notFound: false,
587
+ sessionId: args.store.getRun(args.runId)?.sessionId ?? null,
588
+ finalMessage: typeof lastResult["result"] === "string" ? lastResult["result"] : null,
589
+ usage: { tokensIn: null, tokensOut: null, costUsd: null },
590
+ initFailed: false,
591
+ };
592
+ const result = await settleProviderOutcome(args.captured, outcome);
593
+ const disposition = disposeBuildOutcome({
594
+ store: args.store,
595
+ policy: args.dispose.policy ?? "tick",
596
+ leaseId: args.leaseId,
597
+ runId: args.runId,
598
+ taskId: args.captured.taskId,
599
+ taskRef: args.captured.taskRef,
600
+ runner: args.runner,
601
+ repo: args.dispose.repo,
602
+ branch: args.captured.branch,
603
+ origin: args.dispose.origin,
604
+ provider: args.dispose.provider,
605
+ model: args.dispose.model,
606
+ worktreePath: args.cwd,
607
+ evidenceRoot: args.captured.root,
608
+ clock: args.clock,
609
+ }, result);
610
+ await args.releaseWorktree(args.cwd);
611
+ args.store.closeAuthorization(args.authorization.id, "finished", args.clock());
612
+ args.liveLog?.close();
613
+ args.onDisposed?.(disposition);
614
+ this.drop(args.runId);
615
+ }
616
+ fenceByRun(runId, reason) {
617
+ const args = this.launches.get(runId);
618
+ if (args === undefined)
619
+ return Promise.resolve();
620
+ return this.fence(args, reason);
621
+ }
622
+ /**
623
+ * The interruption road (v2 S2e): stop admission, EOF → grace → kill via
624
+ * the supervisor, conservative settlement, `interrupted`, worktree
625
+ * preserved, authorization closed with the reason. Idempotent.
626
+ */
627
+ async fence(args, reason) {
628
+ const controller = this.sessions.get(args.runId);
629
+ if (controller === undefined || controller.fenceStarted || controller.concluded)
630
+ return;
631
+ controller.fenceStarted = true;
632
+ this.clearClocks(controller);
633
+ // TERMINAL SEIZURE before any waiting (round-6 finding 1): the CAS to
634
+ // 'fencing' + the lease fence make every late admission and every
635
+ // stale write refuse in ITS OWN transaction during the grace window —
636
+ // in-memory flags guard only this process. Losing the CAS means an
637
+ // external fencer owns settlement: kill our handle and step aside.
638
+ const fencer = `coordinator:${process.pid}`;
639
+ const seized = args.store.seizeHeldSession(args.runId, fencer, new Date(args.clock().getTime() + 120_000), args.clock());
640
+ if (!seized.ok) {
641
+ controller.handle?.terminate();
642
+ args.liveLog?.close();
643
+ this.drop(args.runId);
644
+ return;
645
+ }
646
+ controller.handle?.terminate();
647
+ await Promise.race([
648
+ controller.handle?.exited ?? Promise.resolve({ code: null }),
649
+ new Promise(pass => setTimeout(() => {
650
+ controller.handle?.killHard();
651
+ pass({ code: null });
652
+ }, (args.graceMs ?? 10_000) + 10_000)),
653
+ ]);
654
+ const store = args.store;
655
+ for (const turn of store.sessionTurnsOf(args.runId)) {
656
+ if (turn.state === "recorded")
657
+ store.settleTurnTerminal(turn.id, "cancelled", args.clock());
658
+ else if (turn.state === "written" || turn.state === "accepted") {
659
+ store.settleTurnTerminal(turn.id, "uncertain", args.clock());
660
+ }
661
+ }
662
+ // The run's ending settles a pending stop as `held` (v52): by here the
663
+ // supervisor's exit was awaited or its hard kill ordered.
664
+ store.finishRun(args.runId, { outcome: "interrupted", reason, now: args.clock(), stopSettlement: "held" });
665
+ store.closeHeldFencing(args.runId, fencer, reason, args.clock());
666
+ store.closeAuthorization(args.authorization.id, reason, args.clock());
667
+ // The worktree is PRESERVED on interruption (released to the pool
668
+ // unverified — same as every failure road; the work stays on disk).
669
+ await args.releaseWorktree(args.cwd);
670
+ args.liveLog?.close();
671
+ args.onDisposed?.({ kind: "interrupted", reason });
672
+ store.settleRunStop(args.runId, "held", args.clock());
673
+ this.drop(args.runId);
674
+ }
675
+ clearClocks(controller) {
676
+ for (const timer of controller.timers)
677
+ clearTimeout(timer);
678
+ for (const interval of controller.intervals)
679
+ clearInterval(interval);
680
+ controller.timers = [];
681
+ controller.intervals = [];
682
+ }
683
+ drop(runId) {
684
+ const controller = this.sessions.get(runId);
685
+ controller?.finish();
686
+ this.sessions.delete(runId);
687
+ this.launches.delete(runId);
688
+ }
689
+ }
690
+ /**
691
+ * The DB-side orphan fence (v4 Q5 + v5 P3/P4 + v6 W6): sweep every open
692
+ * custody row whose recorded lease is NO LONGER the task's current live
693
+ * lease, seize it (CAS open→fencing + lease fence in one transaction),
694
+ * order the kill through the supervisor's socket — the kernel-stable
695
+ * road — and settle. A supervisor that cannot be reached keeps custody
696
+ * and PAGES (never a guessed PID kill); a later sweep resumes from
697
+ * wherever the CASes stand. Runs BEFORE generic recovery at every entry
698
+ * point; recovery excludes fenced-open held rows.
699
+ */
700
+ export async function sweepHeldOrphans(store, fencer, now) {
701
+ // TWO PHASES (parallel-sessions round 1, finding 6): seize everything
702
+ // first — fast, transactional, per-run CAS — then run the kill orders
703
+ // CONCURRENTLY. The old serial loop paid up to eight seconds per
704
+ // unreachable socket BEFORE up could register its runner; thirty
705
+ // orphans meant four minutes of startup. Now the wall clock is one
706
+ // socket timeout, not their sum.
707
+ const owned = [];
708
+ for (const session of store.openHeldSessions()) {
709
+ const run = store.getRun(session.run);
710
+ if (run === null)
711
+ continue;
712
+ const currentLease = store.currentLiveLease(run.taskRef, now());
713
+ if (currentLease === session.leaseId)
714
+ continue; // a live owner — leave it be
715
+ if (session.state === "open") {
716
+ const seized = store.seizeHeldSession(session.run, fencer, new Date(now().getTime() + 120_000), now());
717
+ if (!seized.ok)
718
+ continue; // another fencer took it between reads
719
+ owned.push({ session: seized.session, run });
720
+ }
721
+ else {
722
+ // 'fencing' already: help only when the prior fencer's deadline is gone.
723
+ if (!store.takeoverHeldFencing(session.run, fencer, new Date(now().getTime() + 120_000), now()))
724
+ continue;
725
+ owned.push({ session, run });
726
+ }
727
+ }
728
+ let fenced = 0;
729
+ let paged = 0;
730
+ await Promise.all(owned.map(async ({ session, run }) => {
731
+ const killed = store.runCustodyProvenGone(session.run) ? { settled: true } : await orderKill(session.socketPath, session.cookie);
732
+ if (!killed.settled) {
733
+ // Page, keep custody, leave 'fencing' for a later helper (v5 P4).
734
+ store.enqueueNotification({
735
+ source: { run: session.run },
736
+ dedupeKey: `held:${session.run}:unkillable`,
737
+ kind: "attention",
738
+ subject: `run ${session.run}: a held agent process could not be stopped`,
739
+ body: `The supervisor at ${session.socketPath} is unreachable. Stop the recorded processes by hand (supervisor pid ${session.supervisorPid ?? "?"}, agent group ${session.agentPgid ?? "?"}), then reconcile.`,
740
+ }, now());
741
+ paged += 1;
742
+ return;
743
+ }
744
+ for (const turn of store.sessionTurnsOf(session.run)) {
745
+ if (turn.state === "recorded")
746
+ store.settleTurnTerminal(turn.id, "cancelled", now());
747
+ else if (turn.state === "written" || turn.state === "accepted") {
748
+ store.settleTurnTerminal(turn.id, "uncertain", now());
749
+ }
750
+ }
751
+ if (run.outcome === null) {
752
+ store.finishRun(session.run, { outcome: "interrupted", reason: "orphaned", now: now() });
753
+ }
754
+ store.closeHeldFencing(session.run, fencer, "orphaned", now());
755
+ store.closeAuthorization(session.authorizationId, "orphaned", now());
756
+ fenced += 1;
757
+ }));
758
+ return { fenced, paged };
759
+ }
760
+ /** One cookie-authenticated kill order; unreachable = not settled. */
761
+ function orderKill(socketPath, cookie) {
762
+ return new Promise(pass => {
763
+ let answered = false;
764
+ const settle = (settled) => {
765
+ if (answered)
766
+ return;
767
+ answered = true;
768
+ pass({ settled });
769
+ };
770
+ let wire;
771
+ try {
772
+ wire = connect(socketPath, () => {
773
+ wire.write(`${JSON.stringify({ cookie, verb: "kill" })}\n`);
774
+ });
775
+ }
776
+ catch {
777
+ settle(false);
778
+ return;
779
+ }
780
+ let answer = "";
781
+ wire.setTimeout(8_000, () => {
782
+ wire.destroy();
783
+ settle(false);
784
+ });
785
+ wire.on("data", chunk => {
786
+ answer += String(chunk);
787
+ });
788
+ wire.on("end", () => {
789
+ try {
790
+ const parsed = JSON.parse(answer);
791
+ settle(parsed.ok === true && parsed.settled === true);
792
+ }
793
+ catch {
794
+ settle(false);
795
+ }
796
+ });
797
+ wire.on("error", () => settle(false));
798
+ });
799
+ }