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,508 @@
1
+ /** Entry point for the macOS shell. No account credential enters argv or logs. */
2
+ import { randomBytes } from "node:crypto";
3
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, realpathSync } from "node:fs";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { homedir, hostname } from "node:os";
6
+ import { fileURLToPath } from "node:url";
7
+ import { createHmac } from "node:crypto";
8
+ import { openStore, openStoreNoMigrate, databasePath, readSchemaVersion, SCHEMA_VERSION } from "./store.js";
9
+ import { DatabaseSync } from "node:sqlite";
10
+ import { authenticateApprover, hashPassword } from "./scope.js";
11
+ import { runOperate, writeLoginFileDurably } from "./operate.js";
12
+ import { daemonStatus, installLaunchdService, planDesktopService, stopLaunchdService } from "./daemon.js";
13
+ import { run as execRun } from "./exec.js";
14
+ import { containmentStatus, effectiveContainment, parseContainmentPolicy, probeContainmentCapability } from "./containment.js";
15
+ import { updateRepos, addRepos } from "./repos.js";
16
+ import { projectSelection } from "./project.js";
17
+ import { superviseController } from "./controller-supervisor.js";
18
+ import { normalizeRunnerName, validRunnerName } from "./runner.js";
19
+ import { checkDesktopProjects, currentDesktopAccess } from "./desktop-access.js";
20
+ import { updateAdmissionPaused, updateGateOwned, UPDATE_PAUSED } from "./desktop-update-gate.js";
21
+ import { envTwins, envValue } from "./names.js";
22
+ export function readDesktopConfig(stateDir) {
23
+ const config = JSON.parse(readFileSync(join(stateDir, "desktop.json"), "utf8"));
24
+ if (config.version !== 1 || typeof config.databaseFile !== "string" || !Array.isArray(config.repos) || config.repos.some(repo => typeof repo !== "string") || !Number.isInteger(config.port) || config.port < 1024 || config.port > 65535 || !/^[a-f0-9]{64}$/.test(config.identity))
25
+ throw new Error("Desktop configuration is invalid.");
26
+ if (config.runnerName !== undefined && (typeof config.runnerName !== "string" || !validRunnerName(config.runnerName)))
27
+ throw new Error("Desktop worker identity is invalid.");
28
+ if (config.containment !== undefined && (typeof config.containment !== "string" || !parseContainmentPolicy(config.containment).ok))
29
+ throw new Error("Desktop containment policy is invalid.");
30
+ if (config.databaseInitialized !== undefined && typeof config.databaseInitialized !== "boolean")
31
+ throw new Error("Desktop database setup state is invalid.");
32
+ config.repos = [...new Set(config.repos.map(repo => {
33
+ try {
34
+ return realpathSync(repo);
35
+ }
36
+ catch (error) {
37
+ // An unplugged volume or moved checkout must never reset the account,
38
+ // database selection, or service identity. Keep it visible for recovery.
39
+ if (["ENOENT", "EACCES", "EPERM"].includes(error.code ?? ""))
40
+ return resolve(repo);
41
+ throw error;
42
+ }
43
+ }))];
44
+ return config;
45
+ }
46
+ export function writeDesktopConfig(stateDir, config) {
47
+ mkdirSync(stateDir, { recursive: true, mode: 0o700 });
48
+ const path = join(stateDir, "desktop.json");
49
+ const temp = `${path}.${process.pid}.tmp`;
50
+ writeFileSync(temp, JSON.stringify(config, null, 2), { mode: 0o600 });
51
+ renameSync(temp, path);
52
+ }
53
+ export async function addDesktopProjects(stateDir, store, paths, exact = false) {
54
+ const repos = await projectSelection(paths);
55
+ if (exact && JSON.stringify(repos) !== JSON.stringify(paths))
56
+ throw new Error("A selected project moved. Review the selection again.");
57
+ const current = readDesktopConfig(stateDir);
58
+ const enrolled = await updateRepos(join(dirname(current.databaseFile), "repos.json"), existing => addRepos(existing, repos));
59
+ if (!enrolled.ok)
60
+ throw new Error(enrolled.message);
61
+ // Native helpers and the browser share this database lock. Read/merge/write
62
+ // synchronously under it so simultaneous selections cannot lose a project.
63
+ return store.transact(() => {
64
+ const latest = readDesktopConfig(stateDir);
65
+ latest.repos = [...new Set([...latest.repos, ...repos])];
66
+ writeDesktopConfig(stateDir, latest);
67
+ return latest;
68
+ });
69
+ }
70
+ export function loadOrCreateDesktopConfig(stateDir, isolated = false) {
71
+ if (existsSync(join(stateDir, "desktop.json")))
72
+ return readDesktopConfig(stateDir);
73
+ const config = { version: 1, databaseFile: isolated ? join(stateDir, "orders.db") : databasePath(process.env, homedir()), repos: [], port: 4187, identity: randomBytes(32).toString("hex"), runnerName: normalizeRunnerName(hostname()), databaseInitialized: false };
74
+ writeDesktopConfig(stateDir, config);
75
+ return config;
76
+ }
77
+ export function openDesktopStore(file) {
78
+ if (!existsSync(file))
79
+ return openStore(file);
80
+ const opened = openStoreNoMigrate(file);
81
+ if (!opened.ok)
82
+ throw new Error(`${opened.message} Stop and upgrade the existing controller before opening this desktop build.`);
83
+ return opened.store;
84
+ }
85
+ export function openConfiguredDesktopStore(stateDir) {
86
+ const config = readDesktopConfig(stateDir);
87
+ // Only a recorded first-time setup may create a queue. An established or
88
+ // legacy installation whose database disappeared must fail closed.
89
+ let store;
90
+ if (config.databaseInitialized === false)
91
+ store = openDesktopStore(config.databaseFile);
92
+ else {
93
+ const opened = openStoreNoMigrate(config.databaseFile);
94
+ if (!opened.ok)
95
+ throw new Error(desktopDatabaseStatus(config.databaseFile).message);
96
+ store = opened.store;
97
+ }
98
+ try {
99
+ if (config.databaseInitialized !== true)
100
+ store.transact(() => {
101
+ const latest = readDesktopConfig(stateDir);
102
+ if (latest.databaseFile !== config.databaseFile)
103
+ throw new Error("The selected database changed during setup. Open the app again.");
104
+ latest.databaseInitialized = true;
105
+ writeDesktopConfig(stateDir, latest);
106
+ });
107
+ return store;
108
+ }
109
+ catch (error) {
110
+ store.close();
111
+ throw error;
112
+ }
113
+ }
114
+ /** Recovery controls must not depend on opening or migrating the task store. */
115
+ export function desktopDatabaseStatus(file) {
116
+ let db;
117
+ const result = (ready, message) => ({ ready, message, expectedSchema: SCHEMA_VERSION });
118
+ try {
119
+ // Read-only open: a missing/unreadable file must never become a new queue.
120
+ db = new DatabaseSync(file, { readOnly: true });
121
+ db.exec("PRAGMA busy_timeout = 1000");
122
+ const schema = readSchemaVersion(db);
123
+ if (!schema.ok)
124
+ return result(false, `This app cannot use the saved task database: ${schema.problem}. Keep the database; use a compatible release or restore a verified backup separately.`);
125
+ if (schema.version === SCHEMA_VERSION)
126
+ return result(true, "The saved task database is compatible with this app.");
127
+ if (schema.version === null)
128
+ return result(false, "The task database has not been set up. Complete setup before starting work.");
129
+ if (schema.version < 0)
130
+ return result(false, "A database update did not finish. Keep the service stopped and complete the documented database upgrade before starting work.");
131
+ return result(false, `The saved tasks need a database upgrade (version ${schema.version} → ${SCHEMA_VERSION}). Keep the service stopped, back up the database, then complete the documented upgrade. This check changes nothing.`);
132
+ }
133
+ catch {
134
+ return result(false, "The saved task database cannot be read. Check that its disk is connected and accessible. If the file is damaged, keep it and restore a verified backup separately; do not create a replacement queue.");
135
+ }
136
+ finally {
137
+ db?.close();
138
+ }
139
+ }
140
+ async function readInput() {
141
+ let input = "";
142
+ for await (const part of process.stdin) {
143
+ input += String(part);
144
+ if (input.length > 8192)
145
+ throw new Error("Credential input too large.");
146
+ }
147
+ const value = JSON.parse(input);
148
+ if (typeof value !== "object" || value === null || !("name" in value) || !("password" in value) || typeof value.name !== "string" || typeof value.password !== "string")
149
+ throw new Error("A username and password are required.");
150
+ return { name: value.name, password: value.password };
151
+ }
152
+ function legacyLogin(file) {
153
+ try {
154
+ const input = readFileSync(file, "utf8").trim();
155
+ const index = input.indexOf(" ");
156
+ return index < 1 ? null : { name: input.slice(0, index), password: input.slice(index + 1) };
157
+ }
158
+ catch {
159
+ return null;
160
+ }
161
+ }
162
+ /** Share `up`'s existing durable credential, without replacing another login. */
163
+ export function pairDesktopLogin(store, file, login) {
164
+ if (!/^[A-Za-z0-9_.-]{1,64}$/.test(login.name) || login.password.length < 8 || login.password.trim() !== login.password || /[\r\n\u0000]/.test(login.password))
165
+ throw new Error("Use a valid username and a password of at least eight characters without surrounding whitespace or line breaks.");
166
+ const first = store.listApprovers().length === 0;
167
+ if (!first && !authenticateApprover(store, login.name, login.password).ok)
168
+ throw new Error("This username and password do not match an active operator.");
169
+ const remembered = legacyLogin(file);
170
+ if (remembered === null) {
171
+ // File before row, as in `up`: a crashed bootstrap can adopt the same intent.
172
+ writeLoginFileDurably(file, login.name, login.password);
173
+ }
174
+ else if (!(first && remembered.name === login.name && remembered.password === login.password) && !authenticateApprover(store, remembered.name, remembered.password).ok) {
175
+ throw new Error("The existing up-login.txt is stale. Restore its valid login before starting the desktop service.");
176
+ }
177
+ if (first)
178
+ store.bootstrapApproverIfNone(login.name, hashPassword(login.password), new Date());
179
+ if (!authenticateApprover(store, login.name, login.password).ok)
180
+ throw new Error("Another operator was created during setup. Sign in again.");
181
+ }
182
+ /** The desktop service definition the shell asks for: the shared launchd contract, labelled by the shell. */
183
+ export function desktopServiceDefinition(stateDir, args) {
184
+ const runtimeDir = dirname(args.node);
185
+ const home = args.home ?? homedir();
186
+ return planDesktopService({
187
+ node: args.node,
188
+ helper: args.helper,
189
+ stateDir,
190
+ label: args.label,
191
+ associatedBundleId: args.bundleId ?? "com.standing-orders.desktop",
192
+ home,
193
+ environment: { ...envTwins("CONTAINMENT", args.containment ?? "observed"), ...(args.buildId ? envTwins("DESKTOP_BUILD", args.buildId) : {}) },
194
+ pathEnv: [runtimeDir, ...(args.providerBin ? [args.providerBin] : []), join(home, ".local", "bin"), "/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin"].join(":"),
195
+ });
196
+ }
197
+ /** The fresh-liveness check: the controller answers its identity challenge on the configured port. */
198
+ export async function verifyDesktopLiveness(config, fetchImpl = fetch) {
199
+ const challenge = randomBytes(32).toString("hex");
200
+ try {
201
+ const response = await fetchImpl(`http://127.0.0.1:${config.port}/desktop/health?challenge=${challenge}`, { signal: AbortSignal.timeout(2_000) });
202
+ if (response.status !== 200)
203
+ return { alive: false, port: config.port, problem: `the controller answered ${response.status} on port ${config.port}` };
204
+ const body = (await response.json());
205
+ const expected = createHmac("sha256", Buffer.from(config.identity, "hex")).update(challenge).digest("hex");
206
+ if (body.proof !== expected)
207
+ return { alive: false, port: config.port, problem: `something on port ${config.port} is not this installation's controller` };
208
+ return { alive: true, port: config.port };
209
+ }
210
+ catch (error) {
211
+ return { alive: false, port: config.port, problem: `no controller answered on port ${config.port} (${error instanceof Error ? error.message : String(error)})` };
212
+ }
213
+ }
214
+ /** `service-start | service-stop | service-status --node <path> --helper <path> --label <label>`: the shell's service verbs, on the shared lifecycle. */
215
+ export async function desktopServiceCommand(verb, stateDir, config, argv, supervise = execRun) {
216
+ const read = (name) => {
217
+ const at = argv.indexOf(`--${name}`);
218
+ const value = at >= 0 ? argv[at + 1] : undefined;
219
+ if (value === undefined || value.startsWith("--"))
220
+ throw new Error(`${verb} needs --${name}.`);
221
+ return value;
222
+ };
223
+ const parsed = parseContainmentPolicy(config.containment ?? envValue(process.env, "CONTAINMENT"));
224
+ if (!parsed.ok)
225
+ throw new Error(parsed.problem);
226
+ const providerAt = argv.indexOf("--provider-bin");
227
+ const bundleAt = argv.indexOf("--bundle-id");
228
+ const buildAt = argv.indexOf("--build-id");
229
+ const definition = desktopServiceDefinition(stateDir, { node: read("node"), helper: read("helper"), label: read("label"), containment: parsed.policy, ...(providerAt >= 0 ? { providerBin: read("provider-bin") } : {}), ...(bundleAt >= 0 ? { bundleId: read("bundle-id") } : {}), ...(buildAt >= 0 ? { buildId: read("build-id") } : {}) });
230
+ if (verb === "service-start") {
231
+ if (argv.includes("--update-id")) {
232
+ const update = await import("./desktop-update.js");
233
+ const journal = update.readUpdateJournal(stateDir);
234
+ if (!journal || journal.id !== read("update-id") || update.updateStopRequested(journal))
235
+ throw new Error("This update is no longer allowed to start the background service.");
236
+ }
237
+ if (config.repos.length === 0)
238
+ throw new Error("Choose a repository in the desktop app first.");
239
+ // Fail before installing/reloading launchd. Stop and Status deliberately
240
+ // skip this gate, including when an incompatible update was installed.
241
+ const database = desktopDatabaseStatus(config.databaseFile);
242
+ if (!database.ready)
243
+ throw new Error(database.message);
244
+ const opened = openStoreNoMigrate(config.databaseFile);
245
+ if (!opened.ok)
246
+ throw new Error(opened.message);
247
+ try {
248
+ const updateAt = argv.indexOf("--update-id");
249
+ if (updateAdmissionPaused(opened.store.raw()) && (updateAt < 0 || !updateGateOwned(opened.store.raw(), read("update-id"))))
250
+ throw new Error(UPDATE_PAUSED);
251
+ }
252
+ finally {
253
+ opened.store.close();
254
+ }
255
+ // The log stays private: the service writes into the state directory only.
256
+ if (!existsSync(definition.logPath))
257
+ writeFileSync(definition.logPath, "", { mode: 0o600 });
258
+ const started = await installLaunchdService(definition, supervise);
259
+ if (!started.ok)
260
+ throw new Error(started.message);
261
+ return { ok: true, action: started.action, changed: started.changed, label: definition.label, unit: definition.unitPath };
262
+ }
263
+ if (verb === "service-stop") {
264
+ if (!argv.includes("--update-id") && existsSync(join(stateDir, "desktop-update.json"))) {
265
+ // An operator stop is durable and wins over later automatic recovery.
266
+ // A broken update record must not take away the ordinary Stop control.
267
+ try {
268
+ await (await import("./desktop-update.js")).requestUpdateStop(stateDir);
269
+ }
270
+ catch {
271
+ // If disk/receipt damage prevents a durable stop intent, disabling
272
+ // the exact recovery job is the independent fail-closed boundary.
273
+ const recoveryLabel = `${definition.label}.update`;
274
+ const recoveryStopped = await stopLaunchdService({ ...definition, label: recoveryLabel, unitPath: join(dirname(definition.unitPath), `${recoveryLabel}.plist`) }, supervise);
275
+ console.error(recoveryStopped.ok ? "The update stop request could not be recorded, so automatic update recovery was disabled. Preserve the update files and check Update status before restarting." : "The update stop request and recovery-service stop could not be confirmed. Check Update status and service logs before leaving this installation unattended.");
276
+ }
277
+ }
278
+ const stopped = await stopLaunchdService(definition, supervise);
279
+ if (!stopped.ok)
280
+ throw new Error(stopped.message);
281
+ return { ok: true, wasLoaded: stopped.wasLoaded, label: definition.label };
282
+ }
283
+ if (verb === "service-status") {
284
+ const status = await daemonStatus(definition, supervise);
285
+ const liveness = status.state === "running" ? await verifyDesktopLiveness(config) : null;
286
+ return { ok: true, ...status, label: definition.label, liveness, database: desktopDatabaseStatus(config.databaseFile), containment: containmentStatus(effectiveContainment(parsed.policy, probeContainmentCapability())) };
287
+ }
288
+ throw new Error("Unknown desktop service operation.");
289
+ }
290
+ export async function desktopMain(argv, supervise = execRun) {
291
+ const stateArg = argv.indexOf("--state");
292
+ if (stateArg >= 0 && !argv[stateArg + 1])
293
+ throw new Error("--state needs a directory.");
294
+ const defaultState = join(homedir(), "Library", "Application Support", "Standing Orders");
295
+ const stateDir = resolve(stateArg >= 0 ? argv[stateArg + 1] : defaultState);
296
+ if (argv[0]?.startsWith("update-")) {
297
+ const update = await import("./desktop-update.js");
298
+ const required = (name) => { const at = argv.indexOf(`--${name}`); const value = at < 0 ? undefined : argv[at + 1]; if (!value || value.startsWith("--"))
299
+ throw Error(`--${name} needs a value.`); return value; };
300
+ if (argv[0] === "update-preview")
301
+ console.log(JSON.stringify(await update.previewDesktopUpdate(stateDir, required("installed"), required("candidate"), required("label"))));
302
+ else if (argv[0] === "update-start") {
303
+ await update.prepareDesktopUpdate(stateDir, required("installed"), required("candidate"), required("label"), required("digest"));
304
+ await update.launchDesktopUpdate(stateDir);
305
+ console.log(JSON.stringify(update.desktopUpdateStatus(stateDir)));
306
+ }
307
+ else if (argv[0] === "update-status")
308
+ console.log(JSON.stringify(update.desktopUpdateStatus(stateDir)));
309
+ else if (argv[0] === "update-resume" || argv[0] === "update-cancel") {
310
+ if (argv[0] === "update-cancel")
311
+ update.requestUpdateRestore(stateDir);
312
+ await update.launchDesktopUpdate(stateDir, true);
313
+ console.log(JSON.stringify(update.desktopUpdateStatus(stateDir)));
314
+ }
315
+ else if (argv[0] === "update-run") {
316
+ const idAt = argv.indexOf("--update-id");
317
+ if (idAt >= 0 && update.readUpdateJournal(stateDir)?.id !== required("update-id"))
318
+ return;
319
+ await update.runDesktopUpdate(stateDir);
320
+ console.log(JSON.stringify(update.desktopUpdateStatus(stateDir)));
321
+ }
322
+ else if (argv[0] === "update-supervise") {
323
+ const stopping = new AbortController();
324
+ const stop = () => stopping.abort();
325
+ process.once("SIGTERM", stop);
326
+ process.once("SIGINT", stop);
327
+ try {
328
+ await (await import("./desktop-update-recovery.js")).superviseDesktopUpdate(stateDir, required("update-id"), stopping.signal);
329
+ }
330
+ finally {
331
+ process.off("SIGTERM", stop);
332
+ process.off("SIGINT", stop);
333
+ }
334
+ }
335
+ else
336
+ throw Error("Unknown update operation.");
337
+ return;
338
+ }
339
+ if (argv[0] === "database-status") {
340
+ // Candidate-build preflight: no setup, login, supervisor, or project probe.
341
+ console.log(JSON.stringify(desktopDatabaseStatus(readDesktopConfig(stateDir).databaseFile)));
342
+ return;
343
+ }
344
+ let config = loadOrCreateDesktopConfig(stateDir, stateDir !== defaultState);
345
+ if (argv[0] === "service-start" || argv[0] === "service-stop" || argv[0] === "service-status") {
346
+ console.log(JSON.stringify(await desktopServiceCommand(argv[0], stateDir, config, argv.slice(1), supervise)));
347
+ return;
348
+ }
349
+ if (argv[0] === "serve") {
350
+ const stopping = new AbortController();
351
+ const stop = () => stopping.abort();
352
+ process.on("SIGTERM", stop);
353
+ process.on("SIGINT", stop);
354
+ try {
355
+ await superviseController({ file: process.execPath, argv: [fileURLToPath(import.meta.url), "serve-controller", "--state", stateDir], signal: stopping.signal,
356
+ onState: state => {
357
+ const path = join(stateDir, "controller-supervisor.json");
358
+ const temp = `${path}.${process.pid}.tmp`;
359
+ writeFileSync(temp, JSON.stringify({ version: 1, supervisorPid: process.pid, buildId: envValue(process.env, "DESKTOP_BUILD") ?? null, updatedAt: new Date().toISOString(), ...state }), { mode: 0o600 });
360
+ renameSync(temp, path);
361
+ if (state.phase === "backoff")
362
+ console.error(`Controller exited (${state.exit?.signal ?? state.exit?.code ?? "unknown"}); restart in ${state.retryMs} ms.`);
363
+ },
364
+ });
365
+ }
366
+ finally {
367
+ process.off("SIGTERM", stop);
368
+ process.off("SIGINT", stop);
369
+ }
370
+ return;
371
+ }
372
+ // Inspection and launch must never migrate another running controller.
373
+ const store = openConfiguredDesktopStore(stateDir);
374
+ const legacyFile = join(dirname(config.databaseFile), "up-login.txt");
375
+ if (argv[0] !== "serve-controller") {
376
+ try {
377
+ if (argv[0] === "inspect") {
378
+ const legacy = legacyLogin(legacyFile);
379
+ console.log(JSON.stringify({ ...config, names: store.listApprovers().map(one => one.name), importable: legacy !== null && authenticateApprover(store, legacy.name, legacy.password).ok }));
380
+ }
381
+ else if (argv[0] === "import-login") {
382
+ // Only the native helper's private stdout pipe receives this value.
383
+ const legacy = legacyLogin(legacyFile);
384
+ if (legacy === null || !authenticateApprover(store, legacy.name, legacy.password).ok)
385
+ throw new Error("No valid remembered login is available.");
386
+ console.log(JSON.stringify(legacy));
387
+ }
388
+ else if (argv[0] === "pair") {
389
+ const login = await readInput();
390
+ pairDesktopLogin(store, legacyFile, login);
391
+ console.log(JSON.stringify({ ok: true }));
392
+ }
393
+ else if (argv[0] === "add-repo" || argv[0] === "add-repos") {
394
+ config = await addDesktopProjects(stateDir, store, argv.slice(1, stateArg < 0 ? undefined : stateArg));
395
+ console.log(JSON.stringify({ ok: true, repos: config.repos }));
396
+ }
397
+ else if (argv[0] === "containment") {
398
+ const parsed = parseContainmentPolicy(argv[1]);
399
+ if (!argv[1] || !parsed.ok)
400
+ throw new Error("containment needs observed, preferred, or required.");
401
+ store.transact(() => { const latest = readDesktopConfig(stateDir); latest.containment = parsed.policy; writeDesktopConfig(stateDir, latest); });
402
+ console.log(JSON.stringify({ ok: true, containment: parsed.policy, restartRequired: true }));
403
+ }
404
+ else if (argv[0] === "access-recheck") {
405
+ writeFileSync(join(stateDir, "project-access-request"), randomBytes(16).toString("hex"), { mode: 0o600 });
406
+ console.log(JSON.stringify({ ok: true }));
407
+ }
408
+ else if (argv[0] === "access-status") {
409
+ const read = (name) => { try {
410
+ return JSON.parse(readFileSync(join(stateDir, name), "utf8"));
411
+ }
412
+ catch {
413
+ return null;
414
+ } };
415
+ const report = currentDesktopAccess(read("project-access.json"), read("controller-supervisor.json"), config.repos, accessRequest(stateDir));
416
+ const now = new Date().toISOString();
417
+ const watching = config.repos.filter(repo => store.raw().prepare("SELECT 1 FROM watch_lease WHERE repo=? AND runner=? AND expires_at>?").get(repo, config.runnerName ?? "", now));
418
+ const connected = report.verified && (await verifyDesktopLiveness(config)).alive;
419
+ console.log(JSON.stringify({ ...report, watching: watching.length, total: config.repos.length, ready: connected && watching.length === config.repos.length }));
420
+ }
421
+ else
422
+ throw new Error("Unknown desktop operation.");
423
+ }
424
+ finally {
425
+ store.close();
426
+ }
427
+ return;
428
+ }
429
+ if (config.repos.length === 0) {
430
+ store.close();
431
+ throw new Error("Choose a repository in the desktop app first.");
432
+ }
433
+ // Persist the legacy default once, under the same lock as project edits.
434
+ // Explicit identity makes a restart await its predecessor's real liveness
435
+ // fences instead of creating hostname-2 and stranding the old worker's work.
436
+ if (config.runnerName === undefined || config.containment === undefined) {
437
+ config = store.transact(() => {
438
+ const latest = readDesktopConfig(stateDir);
439
+ if (latest.runnerName === undefined)
440
+ latest.runnerName = normalizeRunnerName(hostname());
441
+ if (latest.containment === undefined) {
442
+ const parsed = parseContainmentPolicy(envValue(process.env, "CONTAINMENT"));
443
+ if (!parsed.ok)
444
+ throw new Error(parsed.problem);
445
+ latest.containment = parsed.policy;
446
+ }
447
+ writeDesktopConfig(stateDir, latest);
448
+ return latest;
449
+ });
450
+ }
451
+ store.close();
452
+ // Only the real controller writes these receipts. A foreground helper's
453
+ // successful read would not establish launchd/TCC access for the worker.
454
+ let checking = false, lastSelection = "", lastRequest = "";
455
+ const checkAccess = async () => {
456
+ if (checking)
457
+ return;
458
+ const repos = readDesktopConfig(stateDir).repos, request = accessRequest(stateDir), selection = JSON.stringify(repos);
459
+ if (selection === lastSelection && request === lastRequest)
460
+ return;
461
+ checking = true;
462
+ try {
463
+ const projects = await checkDesktopProjects(repos);
464
+ const report = { version: 1, controllerPid: process.pid, checkedAt: new Date().toISOString(), request, projects };
465
+ const file = join(stateDir, "project-access.json"), temp = `${file}.${process.pid}.tmp`;
466
+ writeFileSync(temp, JSON.stringify(report), { mode: 0o600 });
467
+ renameSync(temp, file);
468
+ lastSelection = selection;
469
+ lastRequest = request;
470
+ }
471
+ finally {
472
+ checking = false;
473
+ }
474
+ };
475
+ await checkAccess();
476
+ const accessTimer = setInterval(() => { void checkAccess().catch(() => { }); }, 2000);
477
+ accessTimer.unref();
478
+ // Reuse the same registry supervisor, worker, custody, and recovery paths as
479
+ // the CLI. The service parent owns this controller; closing the web view
480
+ // owns nothing here. `serve-controller` is its child entry, never a new engine.
481
+ const remembered = legacyLogin(legacyFile);
482
+ let exit;
483
+ try {
484
+ exit = await runOperate("up", ["--db", config.databaseFile, ...(remembered === null ? [] : ["--as", remembered.name]),
485
+ "--runner", config.runnerName, "--containment", config.containment, "--host", "127.0.0.1", "--port", String(config.port), "--no-open", "--json"], line => console.log(line), {
486
+ desktopIdentity: config.identity, inferProjectFromCwd: false, openDatabase: file => {
487
+ if (file !== config.databaseFile || readDesktopConfig(stateDir).databaseFile !== file)
488
+ throw new Error("The selected database changed. Restart the desktop service before continuing.");
489
+ return openConfiguredDesktopStore(stateDir);
490
+ },
491
+ additionalProjectRepos: () => readDesktopConfig(stateDir).repos,
492
+ });
493
+ }
494
+ finally {
495
+ clearInterval(accessTimer);
496
+ }
497
+ if (exit !== 0)
498
+ throw new Error("The local controller could not start. Review the service log.");
499
+ }
500
+ function accessRequest(stateDir) { try {
501
+ return readFileSync(join(stateDir, "project-access-request"), "utf8");
502
+ }
503
+ catch {
504
+ return "";
505
+ } }
506
+ if (process.argv[1] !== undefined && realpathSync(resolve(process.argv[1])) === fileURLToPath(import.meta.url)) {
507
+ desktopMain(process.argv.slice(2)).catch(error => { console.error(error instanceof Error ? error.message : "Desktop service failed."); process.exitCode = 1; });
508
+ }
@@ -0,0 +1,12 @@
1
+ import type { Database } from "./store.js";
2
+ export declare const UPDATE_PAUSED = "Toolroll is updating. Current work can finish; new work will resume after the update. Open Update status in the desktop app.";
3
+ /** SQLite enforces the gate even for a CLI racing an old in-memory snapshot.
4
+ * Existing leases, replies, heartbeats and task data remain writable. */
5
+ export declare function installUpdateGate(db: Database, id: string): void;
6
+ export declare function removeUpdateGate(db: Database, id: string): void;
7
+ export declare function updateAdmissionPaused(db: Database): boolean;
8
+ export declare function updateGateOwned(db: Database, id: string): boolean;
9
+ export declare function activeUpdateWork(db: Database): Record<string, number>;
10
+ /** Last admission race closes in the same SQLite write transaction as the
11
+ * empty-work check. Existing work is never killed to satisfy an update. */
12
+ export declare function freezeUpdateGate(db: Database, id: string): boolean;
@@ -0,0 +1,91 @@
1
+ import { activeCodingUpdateWork, installCodingUpdateGate, removeCodingUpdateGate } from "./coding-update.js";
2
+ export const UPDATE_PAUSED = "Toolroll is updating. Current work can finish; new work will resume after the update. Open Update status in the desktop app.";
3
+ const prefix = "so_desktop_update_";
4
+ const rows = (db) => db.prepare("SELECT name, sql FROM sqlite_master WHERE type='trigger' AND name GLOB 'so_desktop_update_*' ORDER BY name").all();
5
+ const statements = (id, frozen = false) => {
6
+ if (!/^[a-f0-9-]{36}$/.test(id))
7
+ throw Error("Invalid update identity.");
8
+ return [
9
+ `CREATE TRIGGER ${prefix}claim BEFORE INSERT ON claim BEGIN SELECT RAISE(ABORT, '${UPDATE_PAUSED} [${id}]'); END`,
10
+ `CREATE TRIGGER ${prefix}mate BEFORE INSERT ON mate_turn BEGIN SELECT RAISE(ABORT, '${UPDATE_PAUSED} [${id}]'); END`,
11
+ `CREATE TRIGGER ${prefix}run BEFORE INSERT ON run ${frozen ? "" : "WHEN NEW.parent_run IS NULL AND NOT EXISTS (SELECT 1 FROM claim WHERE lease_id=NEW.lease_id AND released_at IS NULL) "}BEGIN SELECT RAISE(ABORT, '${UPDATE_PAUSED} [${id}]'); END`,
12
+ // An already-owned mate turn may finish its remaining provider steps.
13
+ `CREATE TRIGGER ${prefix}chat BEFORE INSERT ON chat_turn ${frozen ? "" : "WHEN NEW.mate_turn IS NULL "}BEGIN SELECT RAISE(ABORT, '${UPDATE_PAUSED} [${id}]'); END`,
14
+ ];
15
+ };
16
+ /** SQLite enforces the gate even for a CLI racing an old in-memory snapshot.
17
+ * Existing leases, replies, heartbeats and task data remain writable. */
18
+ export function installUpdateGate(db, id) {
19
+ const wanted = statements(id);
20
+ db.exec("BEGIN IMMEDIATE");
21
+ try {
22
+ const existing = rows(db);
23
+ if (existing.length > 0 && (existing.length !== wanted.length || existing.some(row => ![...wanted, ...statements(id, true)].includes(String(row.sql)))))
24
+ throw Error("Another or unrecognized update owns admission. Recover that update first.");
25
+ if (existing.length === 0)
26
+ for (const statement of wanted)
27
+ db.exec(statement);
28
+ db.exec("COMMIT");
29
+ }
30
+ catch (error) {
31
+ db.exec("ROLLBACK");
32
+ throw error;
33
+ }
34
+ installCodingUpdateGate(db, id);
35
+ }
36
+ export function removeUpdateGate(db, id) {
37
+ const wanted = [...statements(id), ...statements(id, true)];
38
+ db.exec("BEGIN IMMEDIATE");
39
+ try {
40
+ const existing = rows(db);
41
+ if (existing.some(row => !wanted.includes(String(row.sql))))
42
+ throw Error("This update does not own the admission pause. Nothing was cleared.");
43
+ removeCodingUpdateGate(db, id);
44
+ for (const row of existing)
45
+ db.exec(`DROP TRIGGER "${String(row.name)}"`);
46
+ db.exec("COMMIT");
47
+ }
48
+ catch (error) {
49
+ db.exec("ROLLBACK");
50
+ throw error;
51
+ }
52
+ }
53
+ export function updateAdmissionPaused(db) { return rows(db).length > 0; }
54
+ export function updateGateOwned(db, id) {
55
+ const wanted = [...statements(id), ...statements(id, true)], existing = rows(db);
56
+ return existing.length === statements(id).length && existing.every(row => wanted.includes(String(row.sql)));
57
+ }
58
+ export function activeUpdateWork(db) {
59
+ const count = (sql) => Number(db.prepare(sql).get()?.n ?? 0);
60
+ return {
61
+ runs: count("SELECT count(*) n FROM run WHERE outcome IS NULL"),
62
+ claims: count("SELECT count(*) n FROM claim WHERE released_at IS NULL"),
63
+ conversations: count("SELECT count(*) n FROM mate_turn WHERE state IN ('queued','running')") + count("SELECT count(*) n FROM chat_turn WHERE state IN ('queued','running')"),
64
+ sessions: count("SELECT count(*) n FROM held_session WHERE ended_at IS NULL"),
65
+ stopping: count("SELECT count(*) n FROM run_stop WHERE settled_at IS NULL"),
66
+ ...activeCodingUpdateWork(db),
67
+ };
68
+ }
69
+ /** Last admission race closes in the same SQLite write transaction as the
70
+ * empty-work check. Existing work is never killed to satisfy an update. */
71
+ export function freezeUpdateGate(db, id) {
72
+ db.exec("BEGIN IMMEDIATE");
73
+ try {
74
+ if (!updateGateOwned(db, id))
75
+ throw Error("The update no longer owns admission.");
76
+ installCodingUpdateGate(db, id);
77
+ const idle = Object.values(activeUpdateWork(db)).every(n => n === 0);
78
+ if (idle) {
79
+ for (const row of rows(db))
80
+ db.exec(`DROP TRIGGER "${String(row.name)}"`);
81
+ for (const sql of statements(id, true))
82
+ db.exec(sql);
83
+ }
84
+ db.exec("COMMIT");
85
+ return idle;
86
+ }
87
+ catch (error) {
88
+ db.exec("ROLLBACK");
89
+ throw error;
90
+ }
91
+ }
@@ -0,0 +1,14 @@
1
+ import { type ServiceDefinition, type SupervisorRunner } from "./daemon.js";
2
+ import { type UpdateJournal } from "./desktop-update.js";
3
+ export declare function updateRecoveryDefinition(j: UpdateJournal, home?: string): ServiceDefinition;
4
+ export declare function armUpdateRecovery(stateDir: string, retry?: boolean, supervise?: SupervisorRunner, home?: string): Promise<void>;
5
+ export type RecoveryHooks = {
6
+ attempt?: (j: UpdateJournal, signal: AbortSignal, onPid: (pid: number | null) => void) => Promise<void>;
7
+ cleanup?: (j: UpdateJournal) => Promise<void>;
8
+ sleep?: (ms: number) => Promise<void>;
9
+ pollMs?: number;
10
+ staleMs?: number;
11
+ receiptDir?: string;
12
+ };
13
+ export declare function runUpdateAttempt(j: UpdateJournal, signal: AbortSignal, onPid: (pid: number | null) => void, hooks?: RecoveryHooks): Promise<void>;
14
+ export declare function superviseDesktopUpdate(stateDir: string, id: string, signal: AbortSignal, hooks?: RecoveryHooks): Promise<void>;