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
@@ -0,0 +1,379 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * A real-provider release canary.
4
+ *
5
+ * This deliberately drives the public CLI rather than importing builder
6
+ * internals: the disposable repository must cross the same registration,
7
+ * planning, approval, worktree, provider, commit, verification, and evidence
8
+ * boundaries as a person's task. It never pushes or opens a pull request.
9
+ */
10
+
11
+ import { createHash, randomUUID } from "node:crypto";
12
+ import { spawn } from "node:child_process";
13
+ import { mkdir, mkdtemp, readFile, readdir, realpath, rm, writeFile } from "node:fs/promises";
14
+ import { tmpdir } from "node:os";
15
+ import { dirname, join, resolve } from "node:path";
16
+ import { fileURLToPath } from "node:url";
17
+ import { createFixtureLead, completeFixtureAssignment } from "./canary-assertions.mjs";
18
+
19
+ const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
20
+ const bin = join(root, "dist", "bin.js");
21
+ const TASK_ID = "provider-canary";
22
+
23
+ function usage() {
24
+ return [
25
+ "Real-provider Never Stuck canary",
26
+ "",
27
+ " npm run certify:provider -- --provider claude --model sonnet",
28
+ " npm run certify:provider -- --provider codex --model gpt-5.6-sol",
29
+ "",
30
+ "Options:",
31
+ " --provider claude|codex|gemini|openrouter CLI transport to exercise",
32
+ " --model <model> exact model sealed into plan and build",
33
+ " --output <file> write the final JSON certificate",
34
+ " --auto-approve sign an unchanged-plan policy",
35
+ " --keep keep the disposable repo and evidence",
36
+ " --json print only the final JSON certificate",
37
+ ].join("\n");
38
+ }
39
+
40
+ function parseArgs(argv) {
41
+ const result = { provider: null, model: null, output: null, keep: false, autoApprove: false, json: false, help: false };
42
+ for (let index = 0; index < argv.length; index++) {
43
+ const arg = argv[index];
44
+ if (arg === "--keep") result.keep = true;
45
+ else if (arg === "--auto-approve") result.autoApprove = true;
46
+ else if (arg === "--json") result.json = true;
47
+ else if (arg === "--help" || arg === "-h") result.help = true;
48
+ else if (["--provider", "--model", "--output"].includes(arg)) {
49
+ const value = argv[++index];
50
+ if (value === undefined || value.startsWith("--")) throw new Error(`${arg} needs a value`);
51
+ result[arg.slice(2)] = value;
52
+ } else throw new Error(`unknown option ${arg}`);
53
+ }
54
+ if (result.help) return result;
55
+ if (!["claude", "codex", "gemini", "openrouter"].includes(result.provider)) {
56
+ throw new Error("--provider is claude, codex, gemini or openrouter");
57
+ }
58
+ if (typeof result.model !== "string" || result.model.trim() === "") {
59
+ throw new Error("--model is required because task approvals seal exact routing");
60
+ }
61
+ return result;
62
+ }
63
+
64
+ function run(file, args, options = {}) {
65
+ return new Promise((resolvePromise, reject) => {
66
+ const child = spawn(file, args, {
67
+ cwd: options.cwd ?? root,
68
+ env: options.env ?? process.env,
69
+ windowsHide: true,
70
+ stdio: ["ignore", "pipe", "pipe"],
71
+ });
72
+ let stdout = "";
73
+ let stderr = "";
74
+ child.stdout.setEncoding("utf8");
75
+ child.stderr.setEncoding("utf8");
76
+ child.stdout.on("data", chunk => { stdout += chunk; });
77
+ child.stderr.on("data", chunk => { stderr += chunk; });
78
+ child.on("error", reject);
79
+ child.on("close", code => resolvePromise({ code: code ?? 1, stdout, stderr }));
80
+ });
81
+ }
82
+
83
+ function parseEnvelope(answer, label, acceptedCodes = [0]) {
84
+ let envelope = null;
85
+ try {
86
+ envelope = JSON.parse(answer.stdout.trim());
87
+ } catch {
88
+ // The thrown diagnostic below includes the bounded raw answer.
89
+ }
90
+ if (!acceptedCodes.includes(answer.code) || envelope === null || typeof envelope !== "object") {
91
+ const details = [
92
+ `${label} failed (exit ${answer.code})`,
93
+ answer.stderr.trim(),
94
+ answer.stdout.trim(),
95
+ ].filter(Boolean).join("\n").slice(0, 8_000);
96
+ throw new Error(details);
97
+ }
98
+ return envelope;
99
+ }
100
+
101
+ /** The executable bytes and source identity tested by this run. Each CLI
102
+ * boundary rechecks them; an in-place build cannot silently change the
103
+ * implementation halfway through a successful certificate. */
104
+ async function runtimeIdentity() {
105
+ const hash = createHash("sha256");
106
+ async function hashDirectory(directory, prefix) {
107
+ const entries = (await readdir(directory, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
108
+ for (const entry of entries) {
109
+ const relative = `${prefix}/${entry.name}`;
110
+ if (entry.isDirectory()) await hashDirectory(join(directory, entry.name), relative);
111
+ else if (entry.isFile()) hash.update(relative).update("\0").update(await readFile(join(directory, entry.name))).update("\0");
112
+ else throw new Error(`unexpected runtime entry ${relative}`);
113
+ }
114
+ }
115
+ await hashDirectory(join(root, "dist"), "dist");
116
+ for (const file of ["package.json", "scripts/provider-canary.mjs", "scripts/canary-assertions.mjs", "scripts/proof-preflight.mjs"]) {
117
+ hash.update(file).update("\0").update(await readFile(join(root, file))).update("\0");
118
+ }
119
+ const revision = await run("git", ["rev-parse", "HEAD"]);
120
+ const changes = await run("git", ["status", "--porcelain", "--untracked-files=no"]);
121
+ return { sha256: hash.digest("hex"), sourceCommit: revision.code === 0 ? revision.stdout.trim() : null,
122
+ trackedChanges: changes.code === 0 ? changes.stdout.trim() !== "" : null };
123
+ }
124
+
125
+ async function main() {
126
+ let options;
127
+ try {
128
+ options = parseArgs(process.argv.slice(2));
129
+ } catch (error) {
130
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n\n${usage()}\n`);
131
+ process.exitCode = 2;
132
+ return;
133
+ }
134
+ if (options.help) {
135
+ process.stdout.write(`${usage()}\n`);
136
+ return;
137
+ }
138
+
139
+ const startedAt = new Date();
140
+ const base = await realpath(await mkdtemp(join(tmpdir(), "standing-orders-provider-canary-")));
141
+ const repo = join(base, "repo");
142
+ const db = join(base, "orders.db");
143
+ const pool = join(base, "worktrees");
144
+ const password = `canary-${randomUUID()}`;
145
+ const common = ["--db", db, "--json"];
146
+ let passed = false;
147
+ let runtime = null;
148
+ const steps = [];
149
+ const assertRuntime = async () => {
150
+ if (runtime !== null && JSON.stringify(await runtimeIdentity()) !== JSON.stringify(runtime)) {
151
+ throw new Error("the Toolroll runtime changed during the canary; rerun against one fixed build");
152
+ }
153
+ };
154
+
155
+ const note = message => {
156
+ if (!options.json) process.stdout.write(`${message}\n`);
157
+ else process.stderr.write(`${message}\n`);
158
+ };
159
+ const cli = async (label, args, acceptedCodes = [0]) => {
160
+ await assertRuntime();
161
+ note(` ${label}`);
162
+ const started = Date.now();
163
+ const answer = await run(process.execPath, [bin, ...args, ...common]);
164
+ steps.push({ label, durationMs: Date.now() - started, exitCode: answer.code });
165
+ return parseEnvelope(answer, label, acceptedCodes);
166
+ };
167
+ const git = async (...args) => {
168
+ const answer = await run("git", args, { cwd: repo });
169
+ if (answer.code !== 0) throw new Error(`git ${args.join(" ")} failed\n${answer.stderr}`);
170
+ return answer.stdout.trim();
171
+ };
172
+
173
+ let certificate;
174
+ try {
175
+ runtime = await runtimeIdentity();
176
+ note(`Certifying ${options.provider} · ${options.model} through the real workflow`);
177
+ await mkdir(repo, { recursive: true });
178
+ await git("init", "-q", "-b", "main");
179
+ await git("config", "user.email", "canary@standing-orders.local");
180
+ await git("config", "user.name", "Toolroll Canary");
181
+ await writeFile(
182
+ join(repo, "package.json"),
183
+ `${JSON.stringify({ name: "standing-orders-provider-canary", private: true, type: "module", scripts: { test: "node --test" } }, null, 2)}\n`,
184
+ );
185
+ await writeFile(join(repo, "README.md"), "# Toolroll provider canary\n\nThis repository is disposable.\n");
186
+ await git("add", ".");
187
+ await git("commit", "-qm", "seed provider canary");
188
+ const baseSha = await git("rev-parse", "HEAD");
189
+
190
+ await cli("create the isolated approver", ["approver", "add", "canary", "--password", password]);
191
+ const registered = await cli("register a repository-bound worker", [
192
+ "runner", "register", "canary-worker", "--repo", repo,
193
+ "--as", "canary", "--token", password,
194
+ ]);
195
+ const runnerToken = registered.token;
196
+ if (typeof runnerToken !== "string" || runnerToken === "") throw new Error("runner registration returned no token");
197
+
198
+ for (const phase of ["plan", "build", "repair"]) {
199
+ const provider = options.provider;
200
+ const model = options.model;
201
+ await cli(`route ${phase} to ${provider}`, [
202
+ "config", "set", phase,
203
+ "--provider", provider,
204
+ "--model", model,
205
+ "--as", "canary", "--token", password,
206
+ ]);
207
+ }
208
+ await cli("approve the repository verification command", [
209
+ "verify", "set", "--repo", repo,
210
+ "--command", "node --test", "--timeout-seconds", "120", "--yes",
211
+ "--as", "canary", "--token", password,
212
+ ]);
213
+
214
+ const title = [
215
+ `Add canary.txt: exactly "standing-orders ${options.provider} canary passed" plus newline.`,
216
+ "Add canary.test.js using node:test.",
217
+ "Only these files; no questions; acceptance evidence: check and changed-path only.",
218
+ ].join(" ");
219
+ await cli("file the task", ["task", "add", title, "--id", TASK_ID, "--repo", repo]);
220
+ let filedDigest = null;
221
+ if (options.autoApprove) {
222
+ await cli("sign bounded unchanged-plan approval", [
223
+ "mode", "set", "--repo", repo, "--name", "standard", "--days", "1",
224
+ "--auto-approve", "true", "--plan-auto", "--as", "canary", "--token", password,
225
+ ]);
226
+ await cli("file the fixed contract without approving its scope", [
227
+ "task", "scope", TASK_ID, "--goal", title, "--not", "No other files and no publication.",
228
+ "--touches", "canary.txt,canary.test.js",
229
+ "--acceptance", `canary.txt contains exactly standing-orders ${options.provider} canary passed followed by one newline.|changed-path;canary.test.js uses node:test to verify the exact file bytes and the approved node --test command passes.|check,changed-path`,
230
+ ]);
231
+ const filed = await cli("retain the exact filed contract digest", ["task", "show", TASK_ID]);
232
+ filedDigest = filed.scope?.digest;
233
+ if (typeof filedDigest !== "string" || filed.scope.approvedAt != null) throw new Error("fixed contract was missing or prematurely approved");
234
+ }
235
+ const requested = await cli("request a repository-aware plan", [
236
+ "task", "plan", TASK_ID,
237
+ "--provider", options.provider, "--model", options.model,
238
+ "--as", "canary", "--token", password,
239
+ ]);
240
+ if (options.autoApprove && requested.autoPlan !== true) throw new Error("the exact filed plan was not pre-authorized");
241
+ const planned = await cli("run the planning pass", [
242
+ "tick", "--runner", "canary-worker", "--token", runnerToken,
243
+ "--repo", repo, "--pool", pool,
244
+ ]);
245
+ if (!Array.isArray(planned.dispatched) || !planned.dispatched.some(item => item?.outcome === "planned")) {
246
+ throw new Error(`planner did not produce a scope: ${JSON.stringify(planned)}`);
247
+ }
248
+
249
+ const afterPlan = await cli("read the drafted scope", ["task", "show", TASK_ID]);
250
+ const digest = afterPlan.scope?.digest;
251
+ if (typeof digest !== "string" || digest === "") throw new Error("the planning pass produced no approvable scope");
252
+ if (!Array.isArray(afterPlan.scope?.acceptance) || afterPlan.scope.acceptance.length === 0) {
253
+ throw new Error("the planning pass produced no acceptance criteria");
254
+ }
255
+ if (options.autoApprove) {
256
+ if (digest !== filedDigest || afterPlan.scope.approvedDigest !== digest || afterPlan.scope.approvalBasis !== "mode") {
257
+ throw new Error("the unchanged plan did not receive the exact signed mode approval");
258
+ }
259
+ } else await cli("approve the exact planned scope", [
260
+ "task", "approve", TASK_ID, "--yes", "--digest", digest,
261
+ "--as", "canary", "--token", password,
262
+ ]);
263
+
264
+ const built = await cli("run the build and evidence pass", [
265
+ "tick", "--runner", "canary-worker", "--token", runnerToken,
266
+ "--repo", repo, "--pool", pool,
267
+ ]);
268
+ if (!Array.isArray(built.dispatched) || !built.dispatched.some(item => item?.outcome === "built")) {
269
+ throw new Error(`builder did not complete the task: ${JSON.stringify(built)}`);
270
+ }
271
+
272
+ let final = await cli("read the terminal task and proof", ["task", "show", TASK_ID]);
273
+ if (final.task?.state !== "done") throw new Error(`task ended ${String(final.task?.state ?? "without a state")}`);
274
+ const buildRun = Array.isArray(final.runs)
275
+ ? final.runs.find(runRow => runRow?.role === "builder" && runRow?.outcome === "built")
276
+ : null;
277
+ if (buildRun === null || buildRun === undefined || typeof buildRun.branch !== "string") {
278
+ throw new Error("no completed builder run named its branch");
279
+ }
280
+ const branchSha = await git("rev-parse", buildRun.branch);
281
+ if (branchSha === baseSha) throw new Error("the build branch did not advance");
282
+ const canaryText = await git("show", `${buildRun.branch}:canary.txt`);
283
+ const expectedText = `standing-orders ${options.provider} canary passed`;
284
+ if (canaryText !== expectedText) throw new Error(`canary.txt contained ${JSON.stringify(canaryText)}`);
285
+ await git("show", `${buildRun.branch}:canary.test.js`);
286
+ const changed = (await git("diff", "--name-only", baseSha, branchSha)).split("\n").filter(Boolean).sort();
287
+ if (JSON.stringify(changed) !== JSON.stringify(["canary.test.js", "canary.txt"])) {
288
+ throw new Error(`the canary changed unexpected paths: ${JSON.stringify(changed)}`);
289
+ }
290
+
291
+ const leadFile = await createFixtureLead(args => cli("scope the fixture lead", args), {
292
+ repo, auth: ["--as", "canary", "--token", password], tokenFile: join(base, "lead.token"),
293
+ });
294
+ const completion = await completeFixtureAssignment(args => cli("inspect and handle saved result", args), TASK_ID, leadFile, { head: branchSha, runId: buildRun.id });
295
+
296
+ const duplicate = await cli("prove the completed task cannot dispatch twice", [
297
+ "tick", "--runner", "canary-worker", "--token", runnerToken,
298
+ "--repo", repo, "--pool", pool,
299
+ ], [3]);
300
+ if (duplicate.reason !== "empty") throw new Error(`duplicate pass was not empty: ${JSON.stringify(duplicate)}`);
301
+ if (await git("rev-parse", "main") !== baseSha) throw new Error("the default branch changed");
302
+ if (Number(await git("rev-list", "--count", `${baseSha}..${branchSha}`)) !== 1) throw new Error("expected exactly one work commit");
303
+ await assertRuntime();
304
+
305
+ const providerRun = final.runs.find(runRow => runRow?.provider === options.provider && runRow?.providerStartedAt != null);
306
+ certificate = {
307
+ version: 3,
308
+ passed: true,
309
+ provider: options.provider,
310
+ model: options.model,
311
+ startedAt: startedAt.toISOString(),
312
+ finishedAt: new Date().toISOString(),
313
+ durationSeconds: Math.round((Date.now() - startedAt.getTime()) / 1000),
314
+ platform: process.platform,
315
+ architecture: process.arch,
316
+ node: process.versions.node,
317
+ runtime,
318
+ steps,
319
+ workflow: {
320
+ registration: "passed",
321
+ planning: "passed",
322
+ approval: options.autoApprove ? "unchanged-plan-under-signed-mode" : "passed",
323
+ humanActionsAfterPlanningStarted: options.autoApprove ? 0 : 1,
324
+ filedScopeDigest: filedDigest,
325
+ worktreeBuild: "passed",
326
+ commit: branchSha,
327
+ verificationCommand: "node --test",
328
+ proofVerdict: final.proofVerdict,
329
+ criterionMatrix: final.proofMatrix,
330
+ leadCompletion: completion,
331
+ duplicateDispatch: "refused-empty",
332
+ },
333
+ providerRun: providerRun == null ? null : {
334
+ run: providerRun.id,
335
+ role: providerRun.role,
336
+ version: providerRun.providerVersion,
337
+ tokensIn: providerRun.tokensIn,
338
+ tokensOut: providerRun.tokensOut,
339
+ costUsd: providerRun.costUsd,
340
+ },
341
+ runs: final.runs.map(one => ({ id: one.id, role: one.role, parentRun: one.parentRun,
342
+ provider: one.provider, model: one.model, version: one.providerVersion, outcome: one.outcome,
343
+ startedAt: one.startedAt, providerStartedAt: one.providerStartedAt, firstByteAt: one.firstByteAt, finishedAt: one.finishedAt,
344
+ })),
345
+ retainedAt: options.keep ? base : null,
346
+ note: "This canary never pushed or opened a pull request.",
347
+ };
348
+ passed = true;
349
+ } catch (error) {
350
+ certificate = {
351
+ version: 3,
352
+ passed: false,
353
+ provider: options.provider,
354
+ model: options.model,
355
+ startedAt: startedAt.toISOString(),
356
+ finishedAt: new Date().toISOString(),
357
+ durationSeconds: Math.round((Date.now() - startedAt.getTime()) / 1000),
358
+ platform: process.platform,
359
+ architecture: process.arch,
360
+ node: process.versions.node,
361
+ runtime,
362
+ steps,
363
+ retainedAt: base,
364
+ error: error instanceof Error ? error.message : String(error),
365
+ };
366
+ } finally {
367
+ if (options.output !== null) {
368
+ const output = resolve(options.output);
369
+ await mkdir(dirname(output), { recursive: true });
370
+ await writeFile(output, `${JSON.stringify(certificate, null, 2)}\n`);
371
+ }
372
+ if (passed && !options.keep) await rm(base, { recursive: true, force: true });
373
+ }
374
+
375
+ process.stdout.write(`${JSON.stringify(certificate, null, 2)}\n`);
376
+ if (!passed) process.exitCode = 1;
377
+ }
378
+
379
+ await main();
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env node
2
+ /** Repeated real-process occupancy and draft-preservation checks. No model calls. */
3
+ import assert from "node:assert/strict";
4
+ import { spawn } from "node:child_process";
5
+ import { once } from "node:events";
6
+ import { mkdtemp, mkdir, readFile, realpath, rm, writeFile } from "node:fs/promises";
7
+ import { tmpdir } from "node:os";
8
+ import { dirname, join, resolve } from "node:path";
9
+ import { fileURLToPath, pathToFileURL } from "node:url";
10
+
11
+ const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
12
+ let rounds = 100;
13
+ let output = resolve("output/certification/recovery.json");
14
+ let keep = false;
15
+ const usage = "npm run certify:recovery -- [--rounds 100] [--output <file>] [--keep]";
16
+ for (let index = 2; index < process.argv.length; index++) {
17
+ const arg = process.argv[index];
18
+ if (arg === "--help") { console.log(usage); process.exit(0); }
19
+ else if (arg === "--keep") keep = true;
20
+ else if (arg === "--rounds" || arg === "--output") {
21
+ const value = process.argv[++index];
22
+ if (value === undefined || value.startsWith("--")) throw new Error(`${arg} needs a value; ${usage}`);
23
+ if (arg === "--rounds") rounds = Number(value);
24
+ else output = resolve(value);
25
+ } else throw new Error(`unknown option ${arg}; ${usage}`);
26
+ }
27
+ assert(Number.isSafeInteger(rounds) && rounds > 0 && rounds <= 1000, "rounds must be an integer from 1 to 1000");
28
+ const { openStore } = await import(pathToFileURL(join(root, "dist/store.js")));
29
+ const { register, recoverDead, DEFAULT_LIVENESS_MS } = await import(pathToFileURL(join(root, "dist/runner.js")));
30
+ const { acquire, completeFenced } = await import(pathToFileURL(join(root, "dist/claim.js")));
31
+ const { WorktreePool } = await import(pathToFileURL(join(root, "dist/worktree.js")));
32
+ const { run } = await import(pathToFileURL(join(root, "dist/exec.js")));
33
+ const { HANDOFF_PREFIX } = await import(pathToFileURL(join(root, "dist/evidence.js")));
34
+
35
+ const base = await realpath(await mkdtemp(join(tmpdir(), "standing-orders-recovery-canary-")));
36
+ const started = Date.now();
37
+ const cases = [];
38
+ let failure = null;
39
+ const git = async (repo, args) => {
40
+ const result = await run("git", args, { cwd: repo, timeoutMs: 10000 });
41
+ assert.equal(result.code, 0, result.stderr);
42
+ return result.stdout.trim();
43
+ };
44
+ const revision = await git(root, ["rev-parse", "HEAD"]);
45
+ try {
46
+ for (let index = 0; index < rounds; index++) {
47
+ const round = join(base, String(index));
48
+ const repo = join(round, "repo");
49
+ await mkdir(repo, { recursive: true });
50
+ await git(repo, ["init", "-q", "-b", "main"]);
51
+ await git(repo, ["config", "user.email", "canary@standing-orders.local"]);
52
+ await git(repo, ["config", "user.name", "Recovery Canary"]);
53
+ await writeFile(join(repo, "README.md"), "disposable recovery fixture\n");
54
+ await git(repo, ["add", "."]);
55
+ await git(repo, ["commit", "-qm", "seed"]);
56
+ const store = openStore(join(round, "orders.db"));
57
+ let writer = null;
58
+ let exited = null;
59
+ try {
60
+ const now = new Date();
61
+ const expired = new Date(now.getTime() + DEFAULT_LIVENESS_MS + 1000);
62
+ const old = register(store, { name: "old", host: "fixture", repos: [repo], now });
63
+ store.createTask({ id: "work", title: "preserve an interrupted draft" }, now);
64
+ const ref = store.refFor("built-in", "work").id;
65
+ store.placeTask(ref, repo);
66
+ const claim = acquire(store, ref, "old", { token: old.token, now, newLeaseId: () => "old-lease" });
67
+ assert.equal(claim.ok, true);
68
+ store.setTaskState("work", "running", now);
69
+ const pool = new WorktreePool(store, { root: join(round, "pool") });
70
+ const leased = await pool.lease({ repo, branch: "draft", base: "main", runner: "old", taskRef: ref, now });
71
+ assert.equal(leased.ok, true, leased.message);
72
+ const path = leased.worktree.path;
73
+ const runId = store.startRun({ taskRef: ref, runner: "old", leaseId: "old-lease", branch: "draft", worktree: path, now,
74
+ route: { routeDigest: "legacy", phase: "build", provider: "claude", model: null, chosen: "legacy" } });
75
+ const scenario = ["partial-draft", "completed-handoff", "committed-with-late-writer"][index % 3];
76
+ if (scenario === "completed-handoff") {
77
+ await writeFile(join(path, `${HANDOFF_PREFIX}0123456789abcdef.json`), JSON.stringify({ version: 1, status: "completed", conclusion: "A finished draft before control-plane interruption." }));
78
+ }
79
+ if (scenario === "committed-with-late-writer") {
80
+ await writeFile(join(path, "finished.txt"), "a commit already exists\n");
81
+ await git(path, ["add", "finished.txt"]);
82
+ await git(path, ["commit", "-qm", "finished work before interruption"]);
83
+ }
84
+ const head = await git(path, ["rev-parse", "HEAD"]);
85
+ // A real live process keeps writing after the controller's liveness
86
+ // expires. The clock injection is deliberate: this is an occupancy
87
+ // fence canary, not a claim to have killed the entire product worker.
88
+ writer = spawn(process.execPath, ["-e", "const fs=require('node:fs');let n=0;const write=()=>fs.writeFileSync('draft.txt','preserved '+(++n)+'\\n');write();console.log('ready');setInterval(write,10)"],
89
+ { cwd: path, stdio: ["ignore", "pipe", "ignore"] });
90
+ exited = once(writer, "exit");
91
+ await once(writer.stdout, "data");
92
+ assert.equal(pool.markProviderOccupancy(path, "old", writer.pid), true);
93
+ const recovered = recoverDead(store, expired);
94
+ assert.equal(store.getRun(runId).outcome, "failed");
95
+ assert.equal(store.getRun(runId).reason, "interrupted");
96
+ assert.deepEqual(recovered[0].requeued, ["work"]);
97
+ const next = register(store, { name: "next", host: "fixture", repos: [repo], now: expired });
98
+ const successor = acquire(store, ref, "next", { token: next.token, now: expired, newLeaseId: () => "new-lease" });
99
+ assert.equal(successor.ok, true);
100
+ const request = { repo, branch: "draft", runner: "next", taskRef: ref, now: expired, reclaim: { evidenceRoot: join(round, "evidence") } };
101
+ const blocked = await pool.lease(request);
102
+ assert.equal(blocked.ok, false);
103
+ assert.equal(blocked.reason, "in-use");
104
+ assert.equal(completeFenced(store, "old-lease", "done", expired).ok, false);
105
+ assert.notEqual(store.getTask("work").state, "done");
106
+ writer.kill("SIGKILL");
107
+ await exited;
108
+ writer = null;
109
+ const draft = await readFile(join(path, "draft.txt"), "utf8");
110
+ const resumed = await pool.lease(request);
111
+ assert.equal(resumed.ok, true, resumed.message);
112
+ assert.equal(resumed.resumedFromRun, runId);
113
+ assert.equal(resumed.recoveryKind, scenario === "completed-handoff" ? "completed" : "partial");
114
+ assert.equal(await readFile(join(path, "draft.txt"), "utf8"), draft);
115
+ assert.equal(await git(path, ["rev-parse", "HEAD"]), head);
116
+ assert((await readFile(resumed.reclaimed, "utf8")).includes(draft.trim()));
117
+ assert.equal(completeFenced(store, "new-lease", "failed", expired).ok, true);
118
+ await pool.release(path, expired);
119
+ cases.push({ round: index + 1, scenario, passed: true, oldCompletion: "fenced", liveWriter: "refused-reuse", draft: "preserved", commit: "preserved" });
120
+ } finally {
121
+ if (writer !== null) { writer.kill("SIGKILL"); await exited.catch(() => {}); }
122
+ store.close();
123
+ }
124
+ if ((index + 1) % 10 === 0) process.stdout.write(`${index + 1}/${rounds} recovery cases passed\n`);
125
+ }
126
+ } catch (error) { failure = error instanceof Error ? error.stack : String(error); }
127
+ const certificate = { version: 1, passed: failure === null, sourceCommit: revision, platform: process.platform, node: process.versions.node,
128
+ roundsRequested: rounds, roundsPassed: cases.length, durationSeconds: (Date.now() - started) / 1000,
129
+ scope: "Real writer processes with injected controller liveness expiry: no reuse while the writer is alive; stale completion fenced; draft, handoff and existing commit preserved after writer exit.",
130
+ exclusions: ["actual controller crash at every transition", "process trees with detached descendants", "Windows reboot", "provider session resume", "interrupted verification receipt reuse"],
131
+ cases, error: failure, retainedAt: failure === null && !keep ? null : base };
132
+ await mkdir(dirname(output), { recursive: true });
133
+ await writeFile(output, JSON.stringify(certificate, null, 2) + "\n");
134
+ if (failure === null && !keep) await rm(base, { recursive: true, force: true });
135
+ if (failure !== null) { process.stderr.write(failure + "\n"); process.exitCode = 1; }
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Restart certification (docs/PROCESS_CONTAINMENT_PLAN.md, acceptance 7).
4
+ *
5
+ * npm run certify:restart -- baseline --db <orders.db> [--label <service label>] [--output <file>]
6
+ * npm run certify:restart -- verify --db <orders.db> --baseline <file> [--label <label>] [--expect reboot|login|either] [--output <file>]
7
+ *
8
+ * `baseline` records the OS boot identity, the runtime, the installed
9
+ * service's state, the containment status and the database's live custody
10
+ * (pending stops, open runs, running tasks, open witnesses) — names and
11
+ * timestamps only, never a credential. A person then logs out and in, or
12
+ * reboots, THEMSELVES: this tool never does, and never restarts a service.
13
+ * `verify` compares the same database afterwards: whether the boot really
14
+ * changed (the kernel's own token), whether the service is a working
15
+ * controller (running AND a fresh heartbeat), whether what the old boot
16
+ * left pending settled by the controller's own rules, and whether the
17
+ * tasks that were running moved on. Its exit code is the verdict; its
18
+ * output carries the exact limits of what a pass proves.
19
+ */
20
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
21
+ import { dirname, resolve } from "node:path";
22
+ import { fileURLToPath, pathToFileURL } from "node:url";
23
+
24
+ const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
25
+ const usage = "npm run certify:restart -- baseline|verify --db <file> [--label <label>] [--baseline <file>] [--expect reboot|login|either] [--output <file>] [--runner <name>] [--task <id>] [--no-recover]";
26
+ const [mode, ...rest] = process.argv.slice(2);
27
+ if (mode === undefined || mode === "--help" || (mode !== "baseline" && mode !== "verify")) { console.log(usage); process.exit(mode === "--help" ? 0 : 2); }
28
+ const options = { db: undefined, label: undefined, baseline: undefined, expect: "either", output: undefined, recover: true, runner: undefined, tasks: [] };
29
+ for (let index = 0; index < rest.length; index++) {
30
+ const arg = rest[index];
31
+ if (arg === "--no-recover") { options.recover = false; continue; }
32
+ const value = rest[++index];
33
+ if (value === undefined || value.startsWith("--")) throw new Error(`${arg} needs a value; ${usage}`);
34
+ if (arg === "--runner") options.runner = value;
35
+ else if (arg === "--task") options.tasks.push(value);
36
+ else if (arg === "--db") options.db = resolve(value);
37
+ else if (arg === "--label") options.label = value;
38
+ else if (arg === "--baseline") options.baseline = resolve(value);
39
+ else if (arg === "--expect") options.expect = value;
40
+ else if (arg === "--output") options.output = resolve(value);
41
+ else throw new Error(`unknown option ${arg}; ${usage}`);
42
+ }
43
+ if (options.db === undefined || !existsSync(options.db)) throw new Error(`--db must name an existing database; ${usage}`);
44
+ if (!["reboot", "login", "either"].includes(options.expect)) throw new Error(`--expect is reboot, login or either; ${usage}`);
45
+
46
+ const { openStoreNoMigrate } = await import(pathToFileURL(resolve(root, "dist/store.js")));
47
+ const { installedServiceDefinition } = await import(pathToFileURL(resolve(root, "dist/daemon.js")));
48
+ const { run } = await import(pathToFileURL(resolve(root, "dist/exec.js")));
49
+ const { recordRestartBaseline, verifyRestartRecovery, assertNoSecret } = await import(pathToFileURL(resolve(root, "dist/restart-certification.js")));
50
+
51
+ // The certificate NEVER migrates a database: a live controller's file is
52
+ // opened exactly as it is, and a file this build cannot read is refused.
53
+ const opened = openStoreNoMigrate(options.db);
54
+ if (!opened.ok) throw new Error(opened.message);
55
+ const store = opened.store;
56
+ try {
57
+ const service = options.label === undefined ? undefined : (() => {
58
+ const definition = installedServiceDefinition({ label: options.label, configDir: dirname(options.db) });
59
+ if (definition === null) throw new Error(`no installed unit found for ${options.label} — the service view needs the unit file on disk`);
60
+ return { definition, run };
61
+ })();
62
+ // Secrets that might sit beside the database: never in the output.
63
+ const secrets = [];
64
+ for (const name of ["runner-token", "telegram-token"]) {
65
+ const file = resolve(dirname(options.db), name);
66
+ if (existsSync(file)) secrets.push(readFileSync(file, "utf8").trim());
67
+ }
68
+ if (mode === "baseline") {
69
+ const baseline = await recordRestartBaseline({ store, ...(options.runner ? { runnerName: options.runner } : {}), completionTasks: options.tasks, ...(service === undefined ? {} : { service }) });
70
+ const json = JSON.stringify(baseline, null, 2);
71
+ assertNoSecret(json, secrets);
72
+ const output = options.output ?? resolve("output/certification/restart-baseline.json");
73
+ mkdirSync(dirname(output), { recursive: true });
74
+ writeFileSync(output, `${json}\n`);
75
+ console.log(`baseline recorded at ${output}`);
76
+ console.log(` host ${baseline.host} · boot ${baseline.boot.id ?? `unknown (${baseline.boot.problem})`} · node ${baseline.runtime.nodeVersion} · schema v${baseline.database.schemaVersion}`);
77
+ console.log(` service ${baseline.service === null ? "(none named; pass --label)" : `${baseline.service.label}: ${baseline.service.detail}`}`);
78
+ console.log(` custody: ${baseline.database.pendingStops.length} pending stop(s), ${baseline.database.openRuns.length} open run(s), ${baseline.database.runningTasks.length} running task(s), ${baseline.database.witnesses.length} open witness(es)`);
79
+ console.log(" now log out and in, or reboot — this tool does neither — then run verify against the same database.");
80
+ for (const limit of baseline.limits) console.log(` limit: ${limit}`);
81
+ process.exit(0);
82
+ }
83
+ if (options.baseline === undefined || !existsSync(options.baseline)) throw new Error(`verify needs --baseline <file>; ${usage}`);
84
+ const baseline = JSON.parse(readFileSync(options.baseline, "utf8"));
85
+ const verified = await verifyRestartRecovery({ store, baseline, expect: options.expect, recover: options.recover, ...(service === undefined ? {} : { service }) });
86
+ const json = JSON.stringify(verified, null, 2);
87
+ assertNoSecret(json, secrets);
88
+ const output = options.output ?? resolve("output/certification/restart-verification.json");
89
+ mkdirSync(dirname(output), { recursive: true });
90
+ writeFileSync(output, `${json}\n`);
91
+ console.log(`${verified.ok ? "PASS" : "FAIL"} — restart certification (${verified.expectation}); boot ${verified.bootChanged === null ? "unknown" : verified.bootChanged ? "changed" : "unchanged"}`);
92
+ for (const check of verified.checks) console.log(` ${check.ok ? "ok " : "FAIL"} ${check.name}: ${check.detail}`);
93
+ console.log(` written to ${output}`);
94
+ for (const limit of verified.limits) console.log(` limit: ${limit}`);
95
+ process.exit(verified.ok ? 0 : 1);
96
+ } finally {
97
+ store.close();
98
+ }