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,101 @@
1
+ import type { Store } from './store.js';
2
+ export declare const KNOWLEDGE_DESCRIPTORS: readonly [{
3
+ readonly action: 'search';
4
+ readonly synopsis: 'find bounded source excerpts and relevant code symbols';
5
+ readonly mutation: 'none';
6
+ readonly takesQuery: true;
7
+ readonly flags: readonly [{
8
+ readonly name: 'repo';
9
+ readonly takesValue: true;
10
+ readonly meaning: 'admitted project checkout root';
11
+ }, {
12
+ readonly name: 'base';
13
+ readonly takesValue: true;
14
+ readonly meaning: 'exact committed task base; defaults to current HEAD';
15
+ }, {
16
+ readonly name: 'json';
17
+ readonly takesValue: false;
18
+ readonly meaning: 'versioned structured response';
19
+ }, {
20
+ readonly name: 'db';
21
+ readonly takesValue: true;
22
+ readonly meaning: 'local Toolroll database';
23
+ }, {
24
+ readonly name: 'token-file';
25
+ readonly takesValue: true;
26
+ readonly meaning: 'explicit scoped coordinator credential file';
27
+ }, {
28
+ readonly name: 'token-env';
29
+ readonly takesValue: true;
30
+ readonly meaning: 'environment variable containing a scoped coordinator token';
31
+ }];
32
+ }, {
33
+ readonly action: 'impact';
34
+ readonly synopsis: 'inspect static imports affected by one file or unambiguous symbol';
35
+ readonly mutation: 'none';
36
+ readonly takesQuery: true;
37
+ readonly flags: readonly [{
38
+ readonly name: 'repo';
39
+ readonly takesValue: true;
40
+ readonly meaning: 'admitted project checkout root';
41
+ }, {
42
+ readonly name: 'base';
43
+ readonly takesValue: true;
44
+ readonly meaning: 'exact committed task base; defaults to current HEAD';
45
+ }, {
46
+ readonly name: 'json';
47
+ readonly takesValue: false;
48
+ readonly meaning: 'versioned structured response';
49
+ }, {
50
+ readonly name: 'db';
51
+ readonly takesValue: true;
52
+ readonly meaning: 'local Toolroll database';
53
+ }, {
54
+ readonly name: 'token-file';
55
+ readonly takesValue: true;
56
+ readonly meaning: 'explicit scoped coordinator credential file';
57
+ }, {
58
+ readonly name: 'token-env';
59
+ readonly takesValue: true;
60
+ readonly meaning: 'environment variable containing a scoped coordinator token';
61
+ }];
62
+ }, {
63
+ readonly action: 'refresh';
64
+ readonly synopsis: 'refresh the optional local code index; never starts a model or task';
65
+ readonly mutation: 'identity-idempotent';
66
+ readonly takesQuery: false;
67
+ readonly flags: readonly [{
68
+ readonly name: 'repo';
69
+ readonly takesValue: true;
70
+ readonly meaning: 'admitted project checkout root';
71
+ }, {
72
+ readonly name: 'base';
73
+ readonly takesValue: true;
74
+ readonly meaning: 'exact committed task base; defaults to current HEAD';
75
+ }, {
76
+ readonly name: 'json';
77
+ readonly takesValue: false;
78
+ readonly meaning: 'versioned structured response';
79
+ }, {
80
+ readonly name: 'db';
81
+ readonly takesValue: true;
82
+ readonly meaning: 'local Toolroll database';
83
+ }, {
84
+ readonly name: 'token-file';
85
+ readonly takesValue: true;
86
+ readonly meaning: 'explicit scoped coordinator credential file';
87
+ }, {
88
+ readonly name: 'token-env';
89
+ readonly takesValue: true;
90
+ readonly meaning: 'environment variable containing a scoped coordinator token';
91
+ }];
92
+ }];
93
+ export type KnowledgeCliContext = {
94
+ store: Store;
95
+ write: (line: string) => void;
96
+ json: boolean;
97
+ now: Date;
98
+ evidenceRoot?: string;
99
+ env?: NodeJS.ProcessEnv;
100
+ };
101
+ export declare function runKnowledgeCommand(positional: readonly string[], options: Map<string, string | true>, context: KnowledgeCliContext): Promise<number>;
@@ -0,0 +1,92 @@
1
+ /** Local source retrieval uses local-file authority. Explicit coordinator credentials narrow it. */
2
+ import { readFileSync, statSync } from 'node:fs';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { homedir } from 'node:os';
5
+ import { authenticateCoordinator } from './coordinator.js';
6
+ import { envelopeJson } from './envelope.js';
7
+ import { repositoryContext } from './repository-context.js';
8
+ import { namedPath } from './names.js';
9
+ const flags = [
10
+ { name: 'repo', takesValue: true, meaning: 'admitted project checkout root' },
11
+ { name: 'base', takesValue: true, meaning: 'exact committed task base; defaults to current HEAD' },
12
+ { name: 'json', takesValue: false, meaning: 'versioned structured response' },
13
+ { name: 'db', takesValue: true, meaning: 'local Toolroll database' },
14
+ { name: 'token-file', takesValue: true, meaning: 'explicit scoped coordinator credential file' },
15
+ { name: 'token-env', takesValue: true, meaning: 'environment variable containing a scoped coordinator token' },
16
+ ];
17
+ export const KNOWLEDGE_DESCRIPTORS = [
18
+ { action: 'search', synopsis: 'find bounded source excerpts and relevant code symbols', mutation: 'none', takesQuery: true, flags },
19
+ { action: 'impact', synopsis: 'inspect static imports affected by one file or unambiguous symbol', mutation: 'none', takesQuery: true, flags },
20
+ { action: 'refresh', synopsis: 'refresh the optional local code index; never starts a model or task', mutation: 'identity-idempotent', takesQuery: false, flags },
21
+ ];
22
+ function lines(result) {
23
+ return [
24
+ `Repository context: ${result.index.status}${result.index.engine === 'text-search' ? ' · source search' : ' · code relationships'}`,
25
+ ...result.excerpts.flatMap(e => [`${e.file}:${e.line} · ${e.reason}`, e.text]),
26
+ ...result.relationships.map(e => `${e.from}:${e.line} → ${e.to} (${e.kind})`),
27
+ ...result.warnings,
28
+ ...(result.omissions.excerpts || result.omissions.relationships ? [`Omitted: ${result.omissions.excerpts} excerpts, ${result.omissions.relationships} relationships.`] : []),
29
+ ].join('\n');
30
+ }
31
+ export async function runKnowledgeCommand(positional, options, context) {
32
+ const spec = KNOWLEDGE_DESCRIPTORS.find(s => s.action === positional[0]);
33
+ const command = spec ? `knowledge ${spec.action}` : 'knowledge';
34
+ const fail = (reason, message) => { context.write(context.json ? envelopeJson({ ok: false, command, reason, message }) : message); return reason === 'usage' ? 2 : 3; };
35
+ if (!spec)
36
+ return fail('usage', 'Use knowledge search <query>, impact <file-or-symbol>, or refresh with --repo PATH.');
37
+ if (positional.length !== (spec.takesQuery ? 2 : 1))
38
+ return fail('usage', spec.takesQuery ? 'Provide one quoted query or source path.' : 'knowledge refresh takes no query.');
39
+ for (const key of options.keys())
40
+ if (!spec.flags.some(flag => flag.name === key))
41
+ return fail('usage', `--${key} is not a knowledge ${spec.action} option.`);
42
+ const repo = options.get('repo'), base = options.get('base'), query = positional[1] ?? '';
43
+ if (typeof repo !== 'string' || !repo.trim() || repo.length > 4096 || /[\x00-\x1f]/.test(repo))
44
+ return fail('usage', 'Use --repo with the project checkout root.');
45
+ if (base !== undefined && (typeof base !== 'string' || !/^[a-f0-9]{40,64}$/.test(base)))
46
+ return fail('usage', '--base requires an exact commit hash.');
47
+ if (query.length > 1000 || (spec.takesQuery && !query.trim()))
48
+ return fail('usage', 'Choose a nonempty query up to 1000 characters.');
49
+ const tokenEnv = options.get('token-env'), tokenFile = options.get('token-file');
50
+ let admittedToken = null;
51
+ if (tokenEnv !== undefined && tokenFile !== undefined)
52
+ return fail('usage', 'Choose either --token-env NAME or --token-file PATH.');
53
+ if (tokenEnv !== undefined || tokenFile !== undefined) {
54
+ let raw;
55
+ if (tokenEnv !== undefined) {
56
+ if (typeof tokenEnv !== 'string' || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(tokenEnv))
57
+ return fail('usage', '--token-env requires an environment variable name.');
58
+ raw = (context.env ?? process.env)[tokenEnv];
59
+ }
60
+ else {
61
+ try {
62
+ if (typeof tokenFile !== 'string' || !statSync(tokenFile).isFile() || statSync(tokenFile).size > 16_384)
63
+ return fail('unauthenticated', 'The explicit credential file is unavailable.');
64
+ raw = readFileSync(tokenFile, 'utf8');
65
+ }
66
+ catch {
67
+ return fail('unauthenticated', 'The explicit credential file is unavailable.');
68
+ }
69
+ }
70
+ const token = raw?.trim();
71
+ if (!token || token.length > 4096 || /\s/.test(token))
72
+ return fail('unauthenticated', 'The explicit credential source must contain one coordinator token.');
73
+ const auth = authenticateCoordinator(context.store, token);
74
+ if (!auth.ok)
75
+ return fail('unauthenticated', 'The coordinator credential is invalid or revoked.');
76
+ // Compare admitted path identity before any repository/source filesystem read.
77
+ if (!auth.who.repos.includes(resolve(repo)))
78
+ return fail('not-found', 'That project is unavailable to this coordinator.');
79
+ admittedToken = token;
80
+ }
81
+ const cacheRoot = context.evidenceRoot ? join(dirname(context.evidenceRoot), 'repository-context') : namedPath(join(homedir(), '.cache'), ['repository-context']);
82
+ const result = await repositoryContext({ repo: resolve(repo), query, mode: spec.action === 'impact' ? 'impact' : 'search', refresh: spec.action === 'refresh', cacheRoot, ...(typeof base === 'string' ? { baseRevision: base } : {}) });
83
+ if (admittedToken) {
84
+ const current = authenticateCoordinator(context.store, admittedToken);
85
+ if (!current.ok)
86
+ return fail('unauthenticated', 'The coordinator credential is invalid or revoked.');
87
+ if (!current.who.repos.includes(resolve(repo)))
88
+ return fail('not-found', 'That project is unavailable to this coordinator.');
89
+ }
90
+ context.write(context.json ? envelopeJson({ ok: true, command, result }) : lines(result));
91
+ return 0;
92
+ }
@@ -0,0 +1,24 @@
1
+ import type { KnowledgeDraft, KnowledgeSelection, KnowledgeView } from './project-knowledge.js';
2
+ export declare const KNOWLEDGE_CSS = ".knowledge{max-width:780px;min-width:0;overflow-wrap:anywhere}.knowledge .card{padding:20px;min-width:0;margin:16px 0}.knowledge h2{margin:0 0 12px}.knowledge form{display:grid;gap:12px;margin:0}.knowledge label{display:grid;gap:6px}.knowledge textarea,.knowledge input,.knowledge select{box-sizing:border-box;width:100%;min-width:0;max-width:100%}.knowledge textarea{resize:vertical;min-height:110px}.knowledge button,.knowledge summary,.knowledge .button-link{min-height:44px}.knowledge button{justify-self:start;white-space:nowrap}.knowledge summary{padding:12px 0;cursor:pointer}.knowledge pre{white-space:pre-wrap;overflow-wrap:anywhere;font:inherit}.knowledge .knowledge-actions{display:flex;gap:12px;flex-wrap:wrap}.knowledge .meta{font-size:.86rem}.knowledge .knowledge-source{display:block}.knowledge details+details{border-top:1px solid var(--so-line)}.memory-stats{display:flex;flex-wrap:wrap;gap:.4rem}.memory-stats span{padding:.15rem .55rem;border-radius:.375rem;background:var(--so-neutral-soft);color:var(--so-neutral-ink)}@media(max-width:600px){.knowledge .card{padding:16px}.knowledge h2{font-size:1.1rem}}";
3
+ export declare function knowledgeHtml(view: KnowledgeView, csrf: string, canManage: boolean, draft?: KnowledgeDraft, error?: string): string;
4
+ export declare function knowledgeContextHtml(snapshot: KnowledgeSelection | null): string;
5
+ import type { Decision, MemoryHit } from './project-memory.js';
6
+ export declare const MEMORY_INTRO = "What the lead and crew read before they work. Every change keeps its history.";
7
+ export declare function decisionsHtml(repo: string, decisions: Decision[], csrf: string, canManage: boolean, draft?: {
8
+ claim?: string;
9
+ why?: string;
10
+ }, error?: string): string;
11
+ export declare function memorySearchHtml(repo: string, query: string, hits: MemoryHit[] | null): string;
12
+ import type { MemoryProposal } from './memory-pass.js';
13
+ export declare function proposalsHtml(repo: string, proposals: MemoryProposal[], status: {
14
+ surface: string;
15
+ instructionBytes: number;
16
+ budgetBytes: number;
17
+ sessions: {
18
+ total: number;
19
+ analyzed: number;
20
+ failed: number;
21
+ };
22
+ openGaps: number;
23
+ pending: number;
24
+ } | null, csrf: string, canManage: boolean): string;
@@ -0,0 +1,40 @@
1
+ const e = (s) => String(s ?? '').replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
2
+ const fields = (data) => Object.entries(data).map(([k, v]) => `<input type="hidden" name="${e(k)}" value="${e(v)}">`).join('');
3
+ export const KNOWLEDGE_CSS = `.knowledge{max-width:780px;min-width:0;overflow-wrap:anywhere}.knowledge .card{padding:20px;min-width:0;margin:16px 0}.knowledge h2{margin:0 0 12px}.knowledge form{display:grid;gap:12px;margin:0}.knowledge label{display:grid;gap:6px}.knowledge textarea,.knowledge input,.knowledge select{box-sizing:border-box;width:100%;min-width:0;max-width:100%}.knowledge textarea{resize:vertical;min-height:110px}.knowledge button,.knowledge summary,.knowledge .button-link{min-height:44px}.knowledge button{justify-self:start;white-space:nowrap}.knowledge summary{padding:12px 0;cursor:pointer}.knowledge pre{white-space:pre-wrap;overflow-wrap:anywhere;font:inherit}.knowledge .knowledge-actions{display:flex;gap:12px;flex-wrap:wrap}.knowledge .meta{font-size:.86rem}.knowledge .knowledge-source{display:block}.knowledge details+details{border-top:1px solid var(--so-line)}.memory-stats{display:flex;flex-wrap:wrap;gap:.4rem}.memory-stats span{padding:.15rem .55rem;border-radius:.375rem;background:var(--so-neutral-soft);color:var(--so-neutral-ink)}@media(max-width:600px){.knowledge .card{padding:16px}.knowledge h2{font-size:1.1rem}}`;
4
+ export function knowledgeHtml(view, csrf, canManage, draft, error) {
5
+ const manage = canManage && !!csrf;
6
+ const base = { csrf, repo: view.repo, identity: view.identity, revision: view.revision };
7
+ const form = (action, body, extra = {}) => `<form method="post" action="/settings/knowledge/change">${fields({ ...base, action, ...extra })}${body}</form>`;
8
+ const referenceFields = (d) => `<label>Name<input name="title" maxlength="120" value="${e(d.title)}" required></label><label>Reference text<textarea name="content" rows="5" maxlength="12000">${e(d.content)}</textarea></label><details${d.path ? ' open' : ''}><summary>Use a project document</summary><label>Committed .md or .txt path<input name="path" value="${e(d.path)}" placeholder="docs/design-guide.md"></label><p class="meta">Uses the committed file instead of the text above. Save again to refresh it.</p></details><button type="submit">Save reference</button>`;
9
+ const refs = view.knowledge.references.map(ref => `<details class="card"${draft?.id === ref.id ? ' open' : ''}><summary><strong>${e(ref.title)}</strong></summary>${ref.path ? `<span class="meta knowledge-source">${e(ref.path)} · ${e(ref.sourceRevision?.slice(0, 7))}</span>` : ''}<pre>${e(ref.content)}</pre>${manage ? `<details${draft?.id === ref.id ? ' open' : ''}><summary>Edit reference</summary>${form('save', referenceFields(draft?.id === ref.id ? draft : { title: ref.title, content: ref.path ? '' : ref.content, path: ref.path ?? '' }), { id: ref.id })}<details><summary>Remove reference</summary>${form('remove', '<p>Remove from future tasks. Previous run context stays available.</p><button>Remove reference</button>', { id: ref.id })}</details></details>` : ''}</details>`).join('');
10
+ const history = view.history.map(h => `<li><a class="button-link" href="/settings/knowledge?repo=${encodeURIComponent(view.repo)}&version=${h.revision}">Version ${h.revision}</a> · ${e(h.actor)} · ${e(h.at.slice(0, 16).replace('T', ' '))} UTC</li>`).join('');
11
+ const instructions = `<pre class="knowledge-instructions">${e(view.knowledge.instructions || 'No project instructions yet.')}</pre>`;
12
+ const editor = manage ? `<details class="knowledge-editor"${draft?.instructions !== undefined ? ' open' : ''}><summary>${view.knowledge.instructions ? 'Edit instructions' : 'Add instructions'}</summary>${form('instructions', `<textarea aria-label="Project instructions" name="instructions" rows="5" maxlength="4000" placeholder="Goals, preferences, and what good work looks like…">${e(draft?.instructions ?? view.knowledge.instructions)}</textarea><button>Save instructions</button>`)}</details>` : '';
13
+ return `<section class="knowledge knowledge-library">${error ? `<p class="problem" role="alert">${e(error)}</p>` : ''}<section class="knowledge-intro"><h2>Instructions</h2>${instructions}${editor}</section><section><h2>References</h2>${refs || '<p class="meta">Add a spec, design guide, or useful project document.</p>'}${manage ? `<details class="card"${draft?.title && !draft.id ? ' open' : ''}><summary>Add reference</summary>${form('save', referenceFields(draft?.id ? {} : draft ?? {}))}</details>` : ''}</section>${history ? `<details><summary>Change history</summary><ol>${history}</ol></details>` : ''}</section>`;
14
+ }
15
+ export function knowledgeContextHtml(snapshot) {
16
+ if (!snapshot)
17
+ return '';
18
+ return `<details class="knowledge result-knowledge"><summary>Context used</summary><p class="meta">Project knowledge · version ${snapshot.revision}${snapshot.inheritedFrom === null ? '' : ` · from run #${snapshot.inheritedFrom}`}</p>${snapshot.instructions ? `<details><summary>Instructions</summary><pre>${e(snapshot.instructions)}</pre></details>` : '<p>No project instructions were supplied.</p>'}${snapshot.references.map(r => `<details><summary>${e(r.title)}</summary>${r.path ? `<p class="meta">${e(r.path)} · ${e(r.sourceRevision)}</p>` : ''}<pre>${e(r.content)}</pre></details>`).join('')}${snapshot.omitted.length ? `<details><summary>Not included (${snapshot.omitted.length})</summary><ul>${snapshot.omitted.map(r => `<li>${e(r.title)} — ${e(r.reason)}</li>`).join('')}</ul></details>` : ''}</details>`;
19
+ }
20
+ export const MEMORY_INTRO = 'What the lead and crew read before they work. Every change keeps its history.';
21
+ export function decisionsHtml(repo, decisions, csrf, canManage, draft, error) {
22
+ const manage = canManage && !!csrf;
23
+ const base = { csrf, repo };
24
+ const form = (action, body, extra = {}) => `<form method="post" action="/settings/knowledge/decision">${fields({ ...base, action, ...extra })}${body}</form>`;
25
+ const rows = decisions.map(d => `<details class="card decision" id="decision-${d.id}"><summary><strong>${e(d.claim)}</strong> <span class="meta">#${d.id} · ${e(d.decidedBy)} · ${e(d.decidedAt.slice(0, 10))}</span></summary><p>${e(d.why)}</p><p class="meta">${e(d.sourceKind)}${d.sourceRef ? ` · ${e(d.sourceRef)}` : ''}${d.supersedes === null ? '' : ` · replaces #${d.supersedes}`}</p>${manage ? form('retire', `<label>Why it no longer holds<input name="reason" maxlength="500" required></label><button type="submit">Retire</button>`, { decision: d.id }) : ''}</details>`).join('');
26
+ const add = manage ? `<details class="knowledge-editor"${draft?.claim !== undefined ? ' open' : ''}><summary>Record a decision</summary>${form('record', `<label>The choice, in one sentence<input name="claim" maxlength="240" value="${e(draft?.claim)}" required></label><label>Why<textarea name="why" rows="3" maxlength="2000" required>${e(draft?.why)}</textarea></label><button type="submit">Record</button>`)}</details>` : '';
27
+ return `<section class="knowledge"><h2>Decisions</h2>${error ? `<p class="problem" role="alert">${e(error)}</p>` : ''}${rows || '<p class="meta">No decisions yet. The lead suggests one when a conversation settles a choice.</p>'}${add}</section>`;
28
+ }
29
+ export function memorySearchHtml(repo, query, hits) {
30
+ const kind = (h) => h.kind === 'decision' ? `<a href="#decision-${e(h.ref)}">decision #${e(h.ref)}</a>` : h.kind === 'conversation' ? 'conversation' : h.kind;
31
+ const results = hits === null ? '' : hits.length === 0 ? '<p class="meta">Nothing in project memory matches.</p>' : `<ul class="memory-hits">${hits.map(h => `<li><strong>${kind(h)}</strong> · ${e(h.title)}<br><span class="meta">${e(h.snippet)}</span></li>`).join('')}</ul>`;
32
+ return `<section class="knowledge memory-search"><form method="get" action="/settings/knowledge"><input type="hidden" name="repo" value="${e(repo)}"><label>Search project memory<input name="memory" value="${e(query)}" maxlength="300" placeholder="Search decisions, references, lessons…" type="search" autocomplete="off"></label><button type="submit">Search</button></form>${results}</section>`;
33
+ }
34
+ export function proposalsHtml(repo, proposals, status, csrf, canManage) {
35
+ const manage = canManage && !!csrf;
36
+ const line = status === null ? '' : `<p class="meta memory-stats"><span>${status.sessions.analyzed}/${status.sessions.total} sessions read${status.sessions.failed ? ` · ${status.sessions.failed} failed` : ''}</span><span>${status.openGaps} open gap${status.openGaps === 1 ? '' : 's'}</span><span>Instructions ${status.instructionBytes}/${status.budgetBytes} bytes</span></p>` +
37
+ `<details class="settings-more"><summary>Read new sessions</summary><p class="meta">Run <code>toolroll memory propose --repo ${e(repo)}</code> on this computer.</p></details>`;
38
+ const cards = proposals.map(p => `<details class="card proposal" open><summary><strong>${e(p.title)}</strong> <span class="meta">#${p.id} · ${e(p.kind)} · ${p.sessions} sessions</span></summary><p>${e(p.rationale)}</p>${p.beforeText ? `<pre class="knowledge-instructions">- ${e(p.beforeText)}</pre>` : ''}${p.afterText ? `<pre class="knowledge-instructions">+ ${e(p.afterText)}</pre>` : ''}<ul class="memory-evidence">${p.evidence.map(ev => `<li>“${e(ev.quote.slice(0, 200))}” <span class="meta">${e(ev.session.split(':')[0] ?? '')}</span></li>`).join('')}</ul>${manage ? `<form method="post" action="/settings/knowledge/proposal" class="inline">${fields({ csrf, repo, proposal: p.id, decision: 'accept' })}<button type="submit">Accept</button></form> <form method="post" action="/settings/knowledge/proposal" class="inline">${fields({ csrf, repo, proposal: p.id, decision: 'reject' })}<button type="submit">Reject</button></form>` : ''}</details>`).join('');
39
+ return `<section class="knowledge"><h2>Proposed from sessions</h2>${line}${cards || '<p class="meta">Nothing to review. Suggestions appear when the same mistake shows up in two sessions.</p>'}</section>`;
40
+ }
@@ -0,0 +1,8 @@
1
+ /** Bounded DB memory shared by browser and terminal lead turns. No provider,
2
+ * repository scan, mutation, or hidden approval happens while catching up. */
3
+ import type { Store } from './store.js';
4
+ import { type AssignmentCatchUp } from './assignment-brief.js';
5
+ export declare function leadContext(store: Store, repos: readonly string[], now: Date, evidenceRoot?: string): string;
6
+ /** The same saved brief is useful before chat spending is authorized. */
7
+ export declare function leadBriefHtml(brief: AssignmentCatchUp): string;
8
+ export declare const LEAD_CONTEXT_CSS = ".lead-brief{margin:1rem 0;min-width:0}.lead-brief h2{font-size:1.1rem;margin:0 0 .8rem}.repository-context input[name=q]{display:block;box-sizing:border-box;min-height:44px;width:100%;margin:.4rem 0 .75rem;padding:.6rem .75rem;border:1px solid var(--border);border-radius:8px;background:var(--surface);color:inherit;font:inherit}.repository-context form{margin:.5rem 0 1rem}.repository-context summary{min-height:44px;padding:.75rem 0;overflow-wrap:anywhere}.lead-brief h3{font-size:.85rem;margin:1rem 0 .4rem;color:var(--muted-foreground)}.lead-brief ul{list-style:none;margin:0;padding:0}.lead-brief li{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:.75rem;align-items:center;padding:.35rem 0;border-bottom:1px solid var(--border);min-width:0}.lead-brief li a{display:flex;min-height:44px;align-items:center;font-weight:500;overflow-wrap:anywhere;text-decoration:none}.lead-brief li a:hover{text-decoration:underline}.lead-brief-state{font-size:.75rem;font-weight:600;padding:.15rem .5rem;border-radius:.375rem;background:var(--so-neutral-soft);color:var(--so-neutral-ink);white-space:nowrap}.lead-brief-state--needs-decision,.lead-brief-state--ready-to-check{background:var(--so-attention-soft);color:var(--so-attention)}.lead-brief-state--working,.lead-brief-state--checking{background:var(--so-info-soft);color:var(--so-info)}.lead-brief-state--complete{background:var(--so-success-soft);color:var(--so-success)}.lead-brief-detail{grid-column:1/-1;font-size:.85rem;color:var(--muted-foreground);overflow-wrap:anywhere;padding-bottom:.35rem}";
@@ -0,0 +1,56 @@
1
+ import { assignmentCatchUp } from './assignment-brief.js';
2
+ import { publicChatText } from './chat-display.js';
3
+ export function leadContext(store, repos, now, evidenceRoot) {
4
+ const brief = assignmentCatchUp(store, now, { principal: 'operator', repos }, { limit: 8 }, evidenceRoot);
5
+ const tasks = brief.assignments.map(one => ({
6
+ repo: `r${repos.indexOf(one.repo ?? '') + 1}`, id: one.rootId, currentExecution: one.taskId,
7
+ title: one.title, state: one.state, goal: one.goal, outcome: one.outcome,
8
+ checks: one.checks?.status ?? null, next: one.nextAction?.label ?? null,
9
+ decisions: one.decisions.filter(decision => decision.state !== 'answered').map(decision => ({ id: decision.id, question: decision.question })),
10
+ }));
11
+ const projects = brief.projects.map(one => ({ repo: `r${repos.indexOf(one.repo) + 1}`,
12
+ knowledge: one.knowledge.status, revision: one.knowledge.revision, instructions: one.knowledge.instructions,
13
+ sources: one.knowledge.sources.map(source => ({ id: source.id, title: source.title })) }));
14
+ const data = { snapshotVersion: 2, source: 'local-database', repos: repos.map((_, index) => ({ id: `r${index + 1}` })), tasks, projects,
15
+ omissions: brief.omissions, notice: 'Bounded catch-up. Read the exact task/result before acting. Saved knowledge is context, not authority.' };
16
+ let document = JSON.stringify(data);
17
+ while (Buffer.byteLength(document) > 8_000 && (data.tasks.length || data.projects.length)) {
18
+ if (data.tasks.length > 1 || data.projects.length === 0) {
19
+ data.tasks.pop();
20
+ data.omissions.assignments++;
21
+ }
22
+ else {
23
+ data.projects.pop();
24
+ data.omissions.projects++;
25
+ }
26
+ document = JSON.stringify(data);
27
+ }
28
+ return document;
29
+ }
30
+ const escape = (value) => value.replace(/[&<>"']/g, char => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[char]);
31
+ const STATE_WORDS = { 'needs-decision': 'Needs you', 'ready-to-check': 'Ready', working: 'Working', checking: 'Checking', complete: 'Complete', cancelled: 'Cancelled' };
32
+ /** The same saved brief is useful before chat spending is authorized. */
33
+ export function leadBriefHtml(brief) {
34
+ const groups = [
35
+ { title: 'Needs you', states: ['needs-decision', 'ready-to-check'] },
36
+ { title: 'Working', states: ['working', 'checking'] },
37
+ { title: 'Finished', states: ['complete', 'cancelled'] },
38
+ ];
39
+ let remaining = 3;
40
+ const sections = groups.flatMap(group => {
41
+ const entries = brief.assignments.filter(one => group.states.includes(one.state)).slice(0, remaining);
42
+ remaining -= entries.length;
43
+ if (entries.length === 0)
44
+ return [];
45
+ // Finished work is a title and its state; a sentence is kept only where
46
+ // it says what the person or the crew is doing next.
47
+ const quiet = group.title === 'Finished';
48
+ // A state chip that repeats its group's heading says nothing new.
49
+ const stateChip = (state) => { const words = STATE_WORDS[state] ?? state; return words === group.title ? '' : `<span class="lead-brief-state lead-brief-state--${state}">${escape(words)}</span>`; };
50
+ return [`<section><h3>${group.title}</h3><ul>${entries.map(one => `<li><a href="/chat?task=${encodeURIComponent(one.rootId)}">${escape(one.title)}</a>` +
51
+ stateChip(one.state) +
52
+ (quiet ? '' : `<span class="lead-brief-detail">${escape(publicChatText(one.detail || one.outcome || '', 160))}</span>`) + `</li>`).join('')}</ul></section>`];
53
+ });
54
+ return `<section class="lead-brief" aria-label="Project catch-up"><h2>Catch up</h2>${sections.length ? sections.join('') : '<p class="meta">Nothing needs you right now.</p>'}${brief.assignments.length > 3 || brief.omissions.candidateScanLimited || brief.omissions.assignments > 0 ? '<a href="/work">See all tasks</a>' : ''}</section>`;
55
+ }
56
+ export const LEAD_CONTEXT_CSS = '.lead-brief{margin:1rem 0;min-width:0}.lead-brief h2{font-size:1.1rem;margin:0 0 .8rem}.repository-context input[name=q]{display:block;box-sizing:border-box;min-height:44px;width:100%;margin:.4rem 0 .75rem;padding:.6rem .75rem;border:1px solid var(--border);border-radius:8px;background:var(--surface);color:inherit;font:inherit}.repository-context form{margin:.5rem 0 1rem}.repository-context summary{min-height:44px;padding:.75rem 0;overflow-wrap:anywhere}.lead-brief h3{font-size:.85rem;margin:1rem 0 .4rem;color:var(--muted-foreground)}.lead-brief ul{list-style:none;margin:0;padding:0}.lead-brief li{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:.75rem;align-items:center;padding:.35rem 0;border-bottom:1px solid var(--border);min-width:0}.lead-brief li a{display:flex;min-height:44px;align-items:center;font-weight:500;overflow-wrap:anywhere;text-decoration:none}.lead-brief li a:hover{text-decoration:underline}.lead-brief-state{font-size:.75rem;font-weight:600;padding:.15rem .5rem;border-radius:.375rem;background:var(--so-neutral-soft);color:var(--so-neutral-ink);white-space:nowrap}.lead-brief-state--needs-decision,.lead-brief-state--ready-to-check{background:var(--so-attention-soft);color:var(--so-attention)}.lead-brief-state--working,.lead-brief-state--checking{background:var(--so-info-soft);color:var(--so-info)}.lead-brief-state--complete{background:var(--so-success-soft);color:var(--so-success)}.lead-brief-detail{grid-column:1/-1;font-size:.85rem;color:var(--muted-foreground);overflow-wrap:anywhere;padding-bottom:.35rem}';
@@ -0,0 +1,22 @@
1
+ import type { Store, MateSession, MateThread, ChatConfig } from './store.js';
2
+ import { type VerifiedApprover } from './principal.js';
3
+ import { type MateTurnInput, type MateTurnOutcome } from './mate.js';
4
+ export declare function configureLeadFollow(store: Store, who: VerifiedApprover, session: MateSession, thread: MateThread, enabled: boolean, now: Date): boolean;
5
+ export declare function leadFollowStatus(store: Store, actor: string): {
6
+ enabled: boolean;
7
+ detail: string;
8
+ };
9
+ export type LeadFollowInput = {
10
+ store: Store;
11
+ repos: () => readonly string[];
12
+ evidenceRoot: string;
13
+ clock?: () => Date;
14
+ provider: () => {
15
+ config: ChatConfig;
16
+ key: string | null;
17
+ } | null;
18
+ runTurn?: (input: MateTurnInput) => Promise<MateTurnOutcome>;
19
+ subscriptionRunner?: MateTurnInput['subscriptionRunner'];
20
+ fetcher?: typeof fetch;
21
+ };
22
+ export declare function runLeadFollowPass(input: LeadFollowInput): Promise<void>;
@@ -0,0 +1,167 @@
1
+ /** Durable crew updates for the built-in lead. Idle scans use no model.
2
+ * Delivery replays reuse the saved mate request; they never dispatch a task. */
3
+ import { createHash } from 'node:crypto';
4
+ import { isVerifiedApprover, reproveApprover, verifyApproverStanding } from './principal.js';
5
+ import { assignmentOf } from './assignment.js';
6
+ import { runMateTurn } from './mate.js';
7
+ import { updateAdmissionPaused } from './desktop-update-gate.js';
8
+ const CONFIG = 'lead follow configured';
9
+ const hash = (value) => createHash('sha256').update(JSON.stringify(value)).digest('hex');
10
+ export function configureLeadFollow(store, who, session, thread, enabled, now) {
11
+ if (!isVerifiedApprover(who) || !reproveApprover(store, who).ok || session.approver !== who.name || thread.approver !== who.name ||
12
+ session.approverGeneration !== who.generation || session.ceilingDigest !== who.ceilingDigest || thread.ceilingDigest !== who.ceilingDigest ||
13
+ !liveBinding(store, who, session.id, thread.id) ||
14
+ who.repos.some(repo => !store.accountCanAccess(who.name, repo)))
15
+ return false;
16
+ store.recordAction({ at: now.toISOString(), actor: who.name, repo: null, taskId: null, runId: null,
17
+ action: CONFIG, source: 'work', outcome: JSON.stringify({ version: 1, session: session.id, thread: thread.id, generation: who.generation, repos: who.repos, enabled }) });
18
+ return true;
19
+ }
20
+ /** Surface snapshots never establish session/thread ownership. */
21
+ function liveBinding(store, who, sessionId, threadId) {
22
+ const session = store.getMateSession(sessionId), thread = store.getMateThread(threadId);
23
+ return session && thread && session.approver === who.name && thread.approver === who.name &&
24
+ session.approverGeneration === who.generation && session.ceilingDigest === who.ceilingDigest && thread.ceilingDigest === who.ceilingDigest &&
25
+ session.endedAt === null && thread.closedAt === null ? { session, thread } : null;
26
+ }
27
+ function readGrant(row) {
28
+ if (!row)
29
+ return null;
30
+ try {
31
+ const value = JSON.parse(String(row['outcome']));
32
+ if (value.version !== 1 || !Number.isSafeInteger(value.session) || !Number.isSafeInteger(value.thread) || !Number.isSafeInteger(value.generation) ||
33
+ typeof value.enabled !== 'boolean' || !Array.isArray(value.repos) || value.repos.length > 100 || !value.repos.every((repo) => typeof repo === 'string'))
34
+ return null;
35
+ return { id: Number(row['id']), at: String(row['at']), actor: String(row['actor']), session: value.session, thread: value.thread, generation: value.generation, repos: value.repos, enabled: value.enabled };
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ }
41
+ const grantFor = (store, actor) => readGrant(store.handle.prepare("SELECT * FROM action_ledger WHERE actor=? AND action=? AND source='work' ORDER BY id DESC LIMIT 1").get(actor, CONFIG));
42
+ export function leadFollowStatus(store, actor) {
43
+ const grant = grantFor(store, actor);
44
+ if (!grant?.enabled || !authorized(store, grant, grant.repos))
45
+ return { enabled: false, detail: 'Automatic crew updates are off.' };
46
+ const row = store.handle.prepare("SELECT outcome FROM action_ledger WHERE actor=? AND action=? AND source='work' ORDER BY id DESC LIMIT 1").get(actor, `lead delivery status:${grant.id}`);
47
+ return { enabled: true, detail: row ? String(row['outcome']) : 'The lead will respond when a result or decision is ready.' };
48
+ }
49
+ function authorized(store, grant, admitted) {
50
+ const latest = grantFor(store, grant.actor);
51
+ if (latest?.id !== grant.id || !latest.enabled ||
52
+ grant.repos.some(repo => !admitted.includes(repo) || !store.accountCanAccess(grant.actor, repo)))
53
+ return null;
54
+ const proved = verifyApproverStanding(store, grant.actor, grant.generation, grant.repos);
55
+ if (!proved.ok)
56
+ return null;
57
+ const binding = liveBinding(store, proved.who, grant.session, grant.thread);
58
+ return binding ? { who: proved.who, ...binding } : null;
59
+ }
60
+ /** Observe bounded pages; first sight of pre-existing work is only a baseline.
61
+ * Subsequent meaningful transitions become immutable delivery events. */
62
+ function observe(store, grant, now, root) {
63
+ store.transact(() => {
64
+ const cursor = `lead:${grant.id}:scan`, after = store.serviceCursor(cursor);
65
+ const roots = store.handle.prepare(`SELECT id,external_id FROM task_ref WHERE backend='built-in' AND revision_of IS NULL
66
+ AND repo IN (SELECT value FROM json_each(?)) AND id>? ORDER BY id LIMIT 50`).all(JSON.stringify(grant.repos), after);
67
+ for (const row of roots) {
68
+ const a = assignmentOf(store, String(row['external_id']), now, { principal: 'operator', repos: grant.repos }, root);
69
+ if (!a || !a.repo)
70
+ continue;
71
+ const observation = { task: a.rootId, repo: a.repo, state: a.state, detail: a.detail.slice(0, 400), result: a.receipt?.runId ?? null,
72
+ checks: a.receipt?.checks.status ?? null, decision: a.primaryAction?.target.decisionId ?? null, head: a.receipt?.head ?? null };
73
+ const digest = hash(observation), action = `lead observed:${grant.id}`;
74
+ const old = store.handle.prepare("SELECT outcome FROM action_ledger WHERE actor=? AND task_id=? AND action=? AND source='work' ORDER BY id DESC LIMIT 1").get(grant.actor, a.rootId, action);
75
+ if (old?.['outcome'] === digest)
76
+ continue;
77
+ store.recordAction({ at: now.toISOString(), actor: grant.actor, repo: a.repo, taskId: a.rootId, runId: a.receipt?.runId ?? null, action, outcome: digest, source: 'work' });
78
+ // Scope, question, result and completion writes do not necessarily
79
+ // update task.updated_at. A transition between enabling follow and
80
+ // the first scan must not be mistaken for a pre-existing baseline.
81
+ const scope = store.getScope(a.activeTaskId);
82
+ const question = observation.decision === null ? null : store.getDecision(observation.decision);
83
+ const changedAfterGrant = [store.getTask(a.activeTaskId)?.updatedAt, scope?.proposedAt, scope?.approvedAt,
84
+ question?.createdAt, a.completion?.at, ...a.attempts.map(attempt => attempt.runId === null ? null : store.getRun(attempt.runId)?.finishedAt)]
85
+ .some(at => typeof at === 'string' && at >= grant.at);
86
+ if ((old || changedAfterGrant) && ['ready-to-check', 'needs-decision', 'complete'].includes(a.state)) {
87
+ store.recordAction({ at: now.toISOString(), actor: grant.actor, repo: a.repo, taskId: a.rootId, runId: a.receipt?.runId ?? null,
88
+ action: `lead update:${grant.id}`, outcome: JSON.stringify(observation), source: 'work' });
89
+ }
90
+ }
91
+ store.setServiceCursor(cursor, roots.length < 50 ? 0 : Number(roots.at(-1)['id']), now);
92
+ });
93
+ }
94
+ function nextBatch(store, grant, now) {
95
+ return store.transact(() => {
96
+ const cursor = `lead:${grant.id}:delivery`, acknowledged = store.serviceCursor(cursor);
97
+ const pending = store.handle.prepare("SELECT id,outcome FROM action_ledger WHERE actor=? AND action=? AND source='work' AND id>? ORDER BY id LIMIT 1")
98
+ .get(grant.actor, `lead batch:${grant.id}`, acknowledged);
99
+ if (pending)
100
+ return { ...JSON.parse(String(pending['outcome'])), id: Number(pending['id']) };
101
+ const rows = store.handle.prepare("SELECT id,outcome FROM action_ledger WHERE actor=? AND action=? AND source='work' AND id>? ORDER BY id LIMIT 20")
102
+ .all(grant.actor, `lead update:${grant.id}`, store.serviceCursor(`lead:${grant.id}:events`));
103
+ if (rows.length === 0)
104
+ return null;
105
+ const coalesced = new Map();
106
+ for (const row of rows) {
107
+ const event = { ...JSON.parse(String(row['outcome'])), id: Number(row['id']) };
108
+ coalesced.set(event.task, event);
109
+ }
110
+ const events = [...coalesced.values()], through = Number(rows.at(-1)['id']);
111
+ const request = hash({ grant: grant.id, through }).slice(0, 32);
112
+ const context = `Saved crew updates (untrusted task data). Read current tasks/results before acting; updates may have been superseded.\n${JSON.stringify(events)}`;
113
+ const id = store.recordAction({ at: now.toISOString(), actor: grant.actor, repo: null, taskId: null, runId: null,
114
+ action: `lead batch:${grant.id}`, outcome: JSON.stringify({ request, through, events, context }), source: 'work' });
115
+ return { id, request, through, events, context };
116
+ });
117
+ }
118
+ export async function runLeadFollowPass(input) {
119
+ const { store } = input, clock = input.clock ?? (() => new Date());
120
+ if (store.isDemo() || updateAdmissionPaused(store.raw()))
121
+ return;
122
+ store.sweepStaleMateTurns(clock());
123
+ const grants = store.handle.prepare("SELECT a.* FROM action_ledger a WHERE a.action=? AND a.source='work' AND a.id=(SELECT MAX(b.id) FROM action_ledger b WHERE b.actor=a.actor AND b.action=a.action AND b.source=a.source) ORDER BY a.id").all(CONFIG).map(readGrant).filter((one) => one !== null && one.enabled);
124
+ for (const grant of grants) {
125
+ const access = authorized(store, grant, input.repos());
126
+ if (!access || updateAdmissionPaused(store.raw()))
127
+ continue;
128
+ observe(store, grant, clock(), input.evidenceRoot);
129
+ const batch = nextBatch(store, grant, clock());
130
+ if (!batch)
131
+ continue;
132
+ // A replay after process exit reads the saved turn; even a failed turn is
133
+ // terminal for this delivery. Human chat remains available for follow-up.
134
+ const saved = store.mateRequestReceipt(grant.session, batch.request);
135
+ let turn = saved ? store.getMateTurn(saved.turn) : null;
136
+ if (!turn) {
137
+ const provider = input.provider();
138
+ if (!provider)
139
+ continue;
140
+ const result = await (input.runTurn ?? runMateTurn)({ store, ...access, ...provider, evidenceRoot: input.evidenceRoot, clock,
141
+ requestId: batch.request, message: 'Automatic crew update: inspect the saved results or decisions and tell me what needs attention. Do not rerun work.',
142
+ context: batch.context, revalidate: async () => !updateAdmissionPaused(store.raw()) && authorized(store, grant, input.repos()) !== null ? { ok: true } : { ok: false, reason: 'Lead authorization ended.' },
143
+ ...(input.fetcher ? { fetcher: input.fetcher } : {}), ...(input.subscriptionRunner ? { subscriptionRunner: input.subscriptionRunner } : {}) });
144
+ if (!result.ok && 'refused' in result) {
145
+ const status = `Crew updates are waiting: ${result.message}`;
146
+ const last = store.handle.prepare("SELECT outcome FROM action_ledger WHERE actor=? AND action=? ORDER BY id DESC LIMIT 1").get(grant.actor, `lead delivery status:${grant.id}`);
147
+ if (last?.['outcome'] !== status)
148
+ store.recordAction({ at: clock().toISOString(), actor: grant.actor, repo: null, taskId: null, runId: null, action: `lead delivery status:${grant.id}`, outcome: status, source: 'work' });
149
+ continue;
150
+ }
151
+ turn = store.getMateTurn(result.turn);
152
+ }
153
+ if (!turn || turn.state === 'queued' || turn.state === 'running')
154
+ continue;
155
+ store.transact(() => {
156
+ // Concurrent passes may finish the same receipt, but ACK once.
157
+ if (store.serviceCursor(`lead:${grant.id}:delivery`) >= batch.id)
158
+ return;
159
+ store.setServiceCursor(`lead:${grant.id}:delivery`, batch.id, clock());
160
+ store.setServiceCursor(`lead:${grant.id}:events`, batch.through, clock());
161
+ const status = turn.state === 'answered' ? 'Crew updates handled.' : 'The lead response stopped. Open chat to continue; crew work was not rerun.';
162
+ store.recordAction({ at: clock().toISOString(), actor: grant.actor, repo: null, taskId: null, runId: null, action: `lead delivery status:${grant.id}`, outcome: status, source: 'work' });
163
+ if (turn.state !== 'answered' && authorized(store, grant, input.repos()))
164
+ store.appendMateMessage({ thread: grant.thread, turn: null, role: 'assistant', text: status }, clock());
165
+ });
166
+ }
167
+ }
@@ -0,0 +1,75 @@
1
+ import { type LimitWindow } from "./provider-limits.js";
2
+ import { type RunCheckSuite, type Store } from "./store.js";
3
+ export type CheckSummary = {
4
+ status: "passed" | "failed" | "not-run" | "unknown";
5
+ exitCode: number | null;
6
+ suites: RunCheckSuite[];
7
+ };
8
+ export type TaskWaitSnapshot = {
9
+ task: string;
10
+ outcome: "Running" | "Queued" | "Ready" | "Complete" | "Failed" | "Needs a person";
11
+ run: number | null;
12
+ /** The attempt `wait` started watching, when a later retry replaced it. */
13
+ replacedRun: number | null;
14
+ phase: string | null;
15
+ check: CheckSummary;
16
+ next: string;
17
+ terminal: boolean;
18
+ exitCode: 0 | 1 | null;
19
+ reason: "ready" | "complete" | "failed" | "needs-person" | null;
20
+ };
21
+ export type InstallationStatus = {
22
+ generatedAt: string;
23
+ running: {
24
+ count: number;
25
+ phases: {
26
+ phase: string;
27
+ count: number;
28
+ }[];
29
+ tasks: {
30
+ task: string;
31
+ run: number;
32
+ phase: string;
33
+ }[];
34
+ };
35
+ queued: {
36
+ count: number;
37
+ reasons: {
38
+ reason: string;
39
+ count: number;
40
+ }[];
41
+ tasks: {
42
+ task: string;
43
+ reason: string;
44
+ }[];
45
+ };
46
+ waitingForReview: {
47
+ count: number;
48
+ results: {
49
+ task: string;
50
+ run: number;
51
+ check: CheckSummary;
52
+ }[];
53
+ };
54
+ releaseCheck: {
55
+ task: string;
56
+ run: number;
57
+ finishedAt: string | null;
58
+ check: CheckSummary;
59
+ } | null;
60
+ planWindows: (LimitWindow & {
61
+ provider: string;
62
+ plan: string | null;
63
+ observedAt: string;
64
+ })[];
65
+ };
66
+ /** One indexed observation for `task wait`. `watchedRun` is the attempt the
67
+ * caller first saw. Each poll follows the task's newest attempt from there, so
68
+ * a retry that lands between polls is reported with its own run and outcome,
69
+ * and `replacedRun` says which attempt it replaced. Undefined means no attempt
70
+ * has been observed yet. */
71
+ export declare function taskWaitSnapshot(store: Store, taskId: string, now: Date, watchedRun?: number): TaskWaitSnapshot | null;
72
+ /** Whole-installation status, deliberately aggregated and bounded. */
73
+ export declare function installationStatus(store: Store, now: Date): InstallationStatus;
74
+ export declare function renderInstallationStatus(status: InstallationStatus): string[];
75
+ export declare function renderTaskWait(snapshot: TaskWaitSnapshot, outcome?: string): string;