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,447 @@
1
+ /**
2
+ * The coordinator principal (MCP gateway spec v6; DESIGN.md §9b).
3
+ *
4
+ * A coordinator is the ONE credential the MCP surface accepts: minted by
5
+ * an operator password ceremony, hashed at rest, repo-scoped at the mint,
6
+ * rate-limited, revocable — and able to do exactly one thing: file a
7
+ * proposal through the canonical door. What it files is an ordinary
8
+ * UNAPPROVED task; admission is the operator's existing scope ceremony,
9
+ * and the quarantine (sealScopeApproval's mode-kind refusal + the claim
10
+ * primitive's exclusion) keeps every pre-seal road shut.
11
+ *
12
+ * The brand: `VerifiedCoordinator` is disjoint from the operator's
13
+ * `VerifiedAuthor` by construction, and its maker is module-private —
14
+ * the exported-cast mistake is named in the spec and not repeated here.
15
+ * Steering and every operator-speech surface cannot accept this type.
16
+ */
17
+ import { createHash, randomBytes } from "node:crypto";
18
+ import { canonicalRepos } from "./runner.js";
19
+ import { fileTaskProposal } from "./proposal.js";
20
+ import { describeScope } from "./scope.js";
21
+ import { reportSummaryFor } from "./mate-tools.js";
22
+ import { taskWorkSummaryOf } from "./work-summary.js";
23
+ import { assignmentOf, assignmentBrief } from "./assignment.js";
24
+ /** Module-private: the ONLY maker, reachable only through the token
25
+ * verification below. Never exported, never a cast at a call site. */
26
+ function verified(row) {
27
+ return row;
28
+ }
29
+ const NAME = /^[a-z0-9-]{1,32}$/;
30
+ const CID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
31
+ const KEY = /^[\x21-\x7e]{8,64}$/;
32
+ function hashSecret(token) {
33
+ return createHash("sha256").update(token, "utf8").digest("hex");
34
+ }
35
+ function mintCid() {
36
+ const bytes = randomBytes(12);
37
+ let cid = "";
38
+ for (const b of bytes)
39
+ cid += CID_ALPHABET[b % CID_ALPHABET.length];
40
+ return cid;
41
+ }
42
+ export function mintCoordinator(store, input) {
43
+ const days = input.days ?? 90;
44
+ if (!Number.isInteger(days) || days < 1 || days > 365)
45
+ return { ok: false, reason: "bad-rate" };
46
+ const expiresAt = new Date(input.now.getTime() + days * 86_400_000).toISOString();
47
+ const name = input.name.normalize("NFC");
48
+ if (!NAME.test(name))
49
+ return { ok: false, reason: "bad-name" };
50
+ const perHour = input.perHour ?? 6;
51
+ if (!Number.isInteger(perHour) || perHour < 1 || perHour > 60)
52
+ return { ok: false, reason: "bad-rate" };
53
+ if (input.repos.length === 0)
54
+ return { ok: false, reason: "no-repos" };
55
+ const repos = canonicalRepos(input.repos);
56
+ const token = (input.newToken ?? (() => randomBytes(32).toString("base64url")))();
57
+ return store.transact(() => {
58
+ for (let attempt = 0; attempt < 5; attempt += 1) {
59
+ const cid = (input.newCid ?? mintCid)();
60
+ try {
61
+ store.handle
62
+ .prepare(`INSERT INTO coordinator_credential (cid, name, credential_hash, repos, per_hour, created_by, created_at, expires_at)
63
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
64
+ .run(cid, name, hashSecret(token), JSON.stringify(repos), perHour, input.by, input.now.toISOString(), expiresAt);
65
+ return { ok: true, cid, token, repos };
66
+ }
67
+ catch (error) {
68
+ const said = String(error);
69
+ // The live-name unique index answers "taken"; a cid collision
70
+ // (astronomically rare) retries with a fresh one.
71
+ if (said.includes("coordinator_live_name"))
72
+ return { ok: false, reason: "name-taken" };
73
+ if (!said.includes("PRIMARY KEY") && !said.includes("UNIQUE"))
74
+ throw error;
75
+ }
76
+ }
77
+ return { ok: false, reason: "name-taken" };
78
+ });
79
+ }
80
+ /** The token IS the identity — no name travels with it. Verified against
81
+ * the stored hash; the caller re-runs this INSIDE any mutating
82
+ * transaction (the startup check is a courtesy; the txn check is law). */
83
+ export function authenticateCoordinator(store, token) {
84
+ const row = store.handle
85
+ .prepare("SELECT * FROM coordinator_credential WHERE credential_hash = ?")
86
+ .get(hashSecret(token));
87
+ if (row === undefined)
88
+ return { ok: false, reason: "unknown" };
89
+ if (row["revoked_at"] !== null)
90
+ return { ok: false, reason: "revoked" };
91
+ // v101: a credential made with an expiry stops at it (one made before expiry existed lives until it's renewed or revoked).
92
+ if (row["expires_at"] != null && Date.parse(String(row["expires_at"])) <= Date.now())
93
+ return { ok: false, reason: "expired" };
94
+ return {
95
+ ok: true,
96
+ who: verified({
97
+ cid: String(row["cid"]),
98
+ name: String(row["name"]),
99
+ repos: JSON.parse(String(row["repos"])),
100
+ perHour: Number(row["per_hour"]),
101
+ }),
102
+ };
103
+ }
104
+ export function revokeCoordinator(store, cid, by, now) {
105
+ return store.transact(() => {
106
+ const row = store.handle.prepare("SELECT revoked_at FROM coordinator_credential WHERE cid = ?").get(cid);
107
+ if (row === undefined)
108
+ return { ok: false, reason: "unknown" };
109
+ if (row["revoked_at"] !== null)
110
+ return { ok: false, reason: "already-revoked" };
111
+ store.handle
112
+ .prepare("UPDATE coordinator_credential SET revoked_at = ? WHERE cid = ?")
113
+ .run(now.toISOString(), cid);
114
+ // The revocation event rides the SAME transaction as the state change,
115
+ // and the credential's pending proposals expire with it (mate arc v3).
116
+ store.handle
117
+ .prepare("INSERT INTO coordinator_event (cid, kind, detail, created_at) VALUES (?, 'revoked', ?, ?)")
118
+ .run(cid, `by ${by}`, now.toISOString());
119
+ store.sweepCoordinatorProposals(now, cid);
120
+ return { ok: true };
121
+ });
122
+ }
123
+ export function listCoordinators(store) {
124
+ return store.handle
125
+ .prepare(`SELECT c.*, (SELECT MAX(e.created_at) FROM coordinator_event e WHERE e.cid = c.cid AND e.kind = 'filed') AS last_filed
126
+ FROM coordinator_credential c ORDER BY c.created_at, c.cid`)
127
+ .all()
128
+ .map(row => ({
129
+ cid: String(row["cid"]),
130
+ name: String(row["name"]),
131
+ repos: JSON.parse(String(row["repos"])),
132
+ perHour: Number(row["per_hour"]),
133
+ createdBy: String(row["created_by"]),
134
+ createdAt: String(row["created_at"]),
135
+ revokedAt: row["revoked_at"] === null ? null : String(row["revoked_at"]),
136
+ lastFiledAt: row["last_filed"] === null ? null : String(row["last_filed"]),
137
+ expiresAt: row["expires_at"] == null ? null : String(row["expires_at"]),
138
+ }));
139
+ }
140
+ /** What each artifact kind IS on the wire — evidence metadata carries a
141
+ * media type so a client knows what it would be asking for (round-2 f4). */
142
+ const MEDIA_BY_KIND = {
143
+ diff: "text/x-diff",
144
+ "terminal-diff": "text/x-diff",
145
+ "diff-stat": "application/json",
146
+ status: "text/plain",
147
+ "park-payload": "application/json",
148
+ plan: "text/markdown",
149
+ handoff: "application/json",
150
+ "revision-brief": "text/markdown",
151
+ "base-tree": "text/plain",
152
+ };
153
+ /** Outstanding = filed by this cid, scope UNSEALED (missing seal or a
154
+ * stale digest both count), task not done/cancelled — `failed` COUNTS:
155
+ * dead unsealed filings pressure cleanup, not silence. */
156
+ const OUTSTANDING_SQL = `
157
+ SELECT COUNT(*) AS n FROM task_ref
158
+ JOIN task ON task.id = task_ref.external_id AND task_ref.backend = 'built-in'
159
+ LEFT JOIN task_scope ON task_scope.task_id = task_ref.external_id
160
+ WHERE task_ref.coordinator_cid IS NOT NULL
161
+ AND task.state NOT IN ('done','cancelled')
162
+ AND (task_scope.task_id IS NULL
163
+ OR task_scope.approved_at IS NULL
164
+ OR task_scope.approved_digest IS NOT task_scope.digest)`;
165
+ export const PER_CID_OUTSTANDING = 10;
166
+ export const GLOBAL_OUTSTANDING = 50;
167
+ /**
168
+ * The one write the MCP surface owns, as ONE transaction: authenticate →
169
+ * revocation re-check → replay lookup → rate window → caps → the
170
+ * canonical door → the cid stamp → idempotency + event rows. The rate
171
+ * window reads the event ledger (filings are events, so the window and
172
+ * the audit cannot disagree), and a replay charges no slot.
173
+ */
174
+ export function fileCoordinatorProposal(store, token, input, now) {
175
+ if (!KEY.test(input.idempotencyKey)) {
176
+ return { ok: false, reason: "bad-key", message: "idempotency_key is 8–64 printable ASCII characters" };
177
+ }
178
+ const digest = createHash("sha256")
179
+ .update(JSON.stringify({ repo: input.repo, title: input.title, intent: input.intent ?? null, ...(input.deliverable === undefined ? {} : { deliverable: input.deliverable }) }), "utf8")
180
+ .digest("hex");
181
+ return store.transact(() => {
182
+ // The law lives here: the token re-verifies INSIDE the transaction.
183
+ const auth = authenticateCoordinator(store, token);
184
+ if (!auth.ok) {
185
+ return auth.reason === "revoked" || auth.reason === "expired"
186
+ ? { ok: false, reason: "revoked", message: auth.reason === "expired" ? "this credential expired — ask the operator for a new one" : "this credential was revoked — ask the operator for a new one" }
187
+ : { ok: false, reason: "unauthenticated", message: "no live coordinator credential matches this token" };
188
+ }
189
+ const { who } = auth;
190
+ const replay = store.handle
191
+ .prepare("SELECT request_digest, task_id FROM mcp_idempotency WHERE cid = ? AND key = ?")
192
+ .get(who.cid, input.idempotencyKey);
193
+ if (replay !== undefined) {
194
+ if (String(replay["request_digest"]) !== digest) {
195
+ return {
196
+ ok: false,
197
+ reason: "idempotency-conflict",
198
+ message: "this idempotency_key was already used for a DIFFERENT request — mint a new key",
199
+ };
200
+ }
201
+ return { ok: true, id: String(replay["task_id"]), replayed: true };
202
+ }
203
+ const windowStart = new Date(now.getTime() - 3_600_000).toISOString();
204
+ const filedRow = store.handle
205
+ .prepare("SELECT COUNT(*) AS n, MIN(created_at) AS oldest FROM coordinator_event WHERE cid = ? AND kind = 'filed' AND created_at > ?")
206
+ .get(who.cid, windowStart);
207
+ // Filings and proposals share the hourly window in BOTH directions
208
+ // (v3 review, finding 2).
209
+ const filed = Number(filedRow?.["n"] ?? 0) + store.coordinatorProposalsSince(who.cid, new Date(windowStart));
210
+ if (filed >= who.perHour) {
211
+ const oldest = String(filedRow?.["oldest"] ?? now.toISOString());
212
+ const slotMs = new Date(oldest).getTime() + 3_600_000 - now.getTime();
213
+ const minutes = Math.max(1, Math.ceil(slotMs / 60_000));
214
+ return {
215
+ ok: false,
216
+ reason: "rate-limited",
217
+ message: `rate-limited: ${filed} filed in the last hour — next slot in ${minutes}m`,
218
+ };
219
+ }
220
+ const mine = Number(store.handle.prepare(`${OUTSTANDING_SQL} AND task_ref.coordinator_cid = ?`).get(who.cid)?.["n"] ?? 0);
221
+ if (mine >= PER_CID_OUTSTANDING) {
222
+ return {
223
+ ok: false,
224
+ reason: "outstanding-cap",
225
+ message: `${mine} of your filings are still waiting on approval or dismissal — the operator resolves them before more file`,
226
+ };
227
+ }
228
+ const everyone = Number(store.handle.prepare(OUTSTANDING_SQL).get()?.["n"] ?? 0);
229
+ if (everyone >= GLOBAL_OUTSTANDING) {
230
+ return {
231
+ ok: false,
232
+ reason: "global-cap",
233
+ message: `${everyone} coordinator filings are unresolved across the installation — the backlog resolves before more file`,
234
+ };
235
+ }
236
+ // The canonical door: the credential's repo allowlist IS the ceiling,
237
+ // and (since the empty-repo fix) a repo must be named inside it.
238
+ const made = fileTaskProposal(store, {
239
+ title: input.title,
240
+ repo: input.repo,
241
+ ...(input.intent === undefined
242
+ ? {}
243
+ : {
244
+ goal: input.intent,
245
+ // v39: a coordinator's intent is provisional pending the
246
+ // operator's own review (the quarantine already refuses to
247
+ // auto-approve anything a coordinator wrote) — a placeholder
248
+ // criterion names that review as the outstanding work,
249
+ // rather than blocking the filing on a rubric a remote
250
+ // caller has no real standing to author.
251
+ acceptance: [
252
+ { id: "c1", statement: "The operator has reviewed this filing's intent and written a real rubric before approving it.", how: null, evidence: ["manual-review"] },
253
+ ],
254
+ }),
255
+ ...(input.deliverable === undefined ? {} : { deliverable: input.deliverable }),
256
+ filedVia: `mcp:${who.name}`, filedBy: { name: store.handle.prepare("SELECT created_by FROM coordinator_credential WHERE cid = ?").get(who.cid)?.["created_by"] ?? null, kind: "coordinator" },
257
+ admittedRepos: who.repos,
258
+ }, now);
259
+ if (!made.ok)
260
+ return { ok: false, reason: made.reason, message: made.message };
261
+ // The branded door's OWN write: the authoritative linkage column. No
262
+ // other filer sets it; provenance is a join, never string parsing.
263
+ store.handle
264
+ .prepare("UPDATE task_ref SET coordinator_cid = ? WHERE backend = 'built-in' AND external_id = ? AND coordinator_cid IS NULL")
265
+ .run(who.cid, made.id);
266
+ store.handle
267
+ .prepare("INSERT INTO mcp_idempotency (cid, key, request_digest, task_id, created_at) VALUES (?, ?, ?, ?, ?)")
268
+ .run(who.cid, input.idempotencyKey, digest, made.id, now.toISOString());
269
+ store.handle
270
+ .prepare("INSERT INTO coordinator_event (cid, kind, task_id, created_at) VALUES (?, 'filed', ?, ?)")
271
+ .run(who.cid, made.id, now.toISOString());
272
+ return { ok: true, id: made.id, replayed: false };
273
+ });
274
+ }
275
+ // ---- credential-scoped reads (MCP spec v6: the allowlist intersected IN
276
+ // SQL, before aggregation, ordering, LIMIT, and counts; repo-null rows
277
+ // excluded from every result; a foreign ref answers not-found) ----------
278
+ function inClause(repos) {
279
+ return { sql: repos.map(() => "?").join(","), args: [...repos] };
280
+ }
281
+ export function statusFor(store, who, now) {
282
+ const { sql, args } = inClause(who.repos);
283
+ const dayAgo = new Date(now.getTime() - 24 * 3_600_000).toISOString();
284
+ const one = (query, extra = []) => Number(store.handle.prepare(query).get(...args, ...extra)?.["n"] ?? 0);
285
+ // "Waits on you" = the board's attention lanes over this allowlist:
286
+ // unsealed scopes + open decisions on live runs.
287
+ const unsealed = one(`SELECT COUNT(*) AS n FROM task_ref JOIN task ON task.id = task_ref.external_id AND task_ref.backend = 'built-in'
288
+ LEFT JOIN task_scope ON task_scope.task_id = task_ref.external_id
289
+ WHERE task_ref.repo IN (${sql}) AND task.state = 'queued'
290
+ AND (task_scope.task_id IS NULL OR task_scope.approved_at IS NULL OR task_scope.approved_digest IS NOT task_scope.digest)`);
291
+ const questions = one(`SELECT COUNT(*) AS n FROM decision JOIN run ON run.id = decision.run
292
+ JOIN task_ref ON task_ref.id = run.task_ref AND task_ref.backend = 'built-in'
293
+ WHERE task_ref.repo IN (${sql}) AND decision.answered_at IS NULL AND decision.state IN ('open','expired')`);
294
+ // "Running" is lease-based liveness, never `outcome IS NULL` (review
295
+ // finding 6): a live, unexpired, newest-generation claim.
296
+ const running = one(`SELECT COUNT(DISTINCT claim.task_ref) AS n FROM claim
297
+ JOIN task_ref ON task_ref.id = claim.task_ref AND task_ref.backend = 'built-in'
298
+ WHERE task_ref.repo IN (${sql}) AND claim.released_at IS NULL AND claim.expires_at > ?
299
+ AND claim.lease_generation = (SELECT MAX(newest.lease_generation) FROM claim AS newest WHERE newest.task_ref = claim.task_ref)`, [now.toISOString()]);
300
+ const incidents = one(`SELECT COUNT(*) AS n FROM incident JOIN run ON run.id = incident.run
301
+ JOIN task_ref ON task_ref.id = run.task_ref AND task_ref.backend = 'built-in'
302
+ WHERE task_ref.repo IN (${sql}) AND incident.resolved_at IS NULL`);
303
+ const picks = one(`SELECT COUNT(*) AS n FROM contest JOIN task_ref ON task_ref.id = contest.task_ref AND task_ref.backend = 'built-in'
304
+ WHERE task_ref.repo IN (${sql}) AND contest.state = 'pick-wait'`);
305
+ const builtToday = one(`SELECT COUNT(*) AS n FROM run JOIN task_ref ON task_ref.id = run.task_ref AND task_ref.backend = 'built-in'
306
+ WHERE task_ref.repo IN (${sql}) AND run.outcome = 'built' AND run.finished_at > ?`, [dayAgo]);
307
+ const failedToday = one(`SELECT COUNT(*) AS n FROM run JOIN task_ref ON task_ref.id = run.task_ref AND task_ref.backend = 'built-in'
308
+ WHERE task_ref.repo IN (${sql}) AND run.outcome = 'failed' AND run.finished_at > ?`, [dayAgo]);
309
+ const repos = store.handle
310
+ .prepare(`SELECT task_ref.repo AS repo,
311
+ SUM(CASE WHEN task.state = 'queued' THEN 1 ELSE 0 END) AS queued,
312
+ SUM(CASE WHEN task.state = 'running' THEN 1 ELSE 0 END) AS running
313
+ FROM task_ref JOIN task ON task.id = task_ref.external_id AND task_ref.backend = 'built-in'
314
+ WHERE task_ref.repo IN (${sql}) GROUP BY task_ref.repo ORDER BY task_ref.repo`)
315
+ .all(...args)
316
+ .map(row => ({ repo: String(row["repo"]), queued: Number(row["queued"]), running: Number(row["running"]) }));
317
+ return {
318
+ waitsOnYou: unsealed + questions + incidents + picks,
319
+ waits: { approvals: unsealed, questions, incidents, picks },
320
+ running,
321
+ builtToday,
322
+ failedToday,
323
+ repos,
324
+ };
325
+ }
326
+ export function listTasksFor(store, who, filter, now) {
327
+ const limit = Math.min(Math.max(filter.limit ?? 20, 1), 50);
328
+ const repos = filter.repo === undefined ? [...who.repos] : who.repos.includes(filter.repo) ? [filter.repo] : [];
329
+ if (repos.length === 0)
330
+ return { tasks: [], nextCursor: null };
331
+ const { sql, args } = inClause(repos);
332
+ const rows = store.handle
333
+ .prepare(`SELECT task_ref.id AS rid, task.id AS tid, task.title AS title, task.state AS state, task_ref.repo AS repo, task_ref.filed_via AS via,
334
+ EXISTS(SELECT 1 FROM claim WHERE claim.task_ref = task_ref.id AND claim.released_at IS NULL AND claim.expires_at > ?
335
+ AND claim.lease_generation = (SELECT MAX(newest.lease_generation) FROM claim AS newest WHERE newest.task_ref = claim.task_ref)) AS live,
336
+ EXISTS(SELECT 1 FROM task_scope WHERE task_scope.task_id = task.id AND task_scope.approved_at IS NOT NULL AND task_scope.approved_digest = task_scope.digest) AS sealed
337
+ FROM task_ref JOIN task ON task.id = task_ref.external_id AND task_ref.backend = 'built-in'
338
+ WHERE task_ref.repo IN (${sql})
339
+ AND (? IS NULL OR task.state = ?)
340
+ AND task_ref.id > ?
341
+ ORDER BY task_ref.id LIMIT ?`)
342
+ .all(now.toISOString(), ...args, filter.state ?? null, filter.state ?? null, filter.cursor ?? 0, limit + 1);
343
+ const chipOf = (state, live, sealed) => {
344
+ if (live)
345
+ return "building";
346
+ if (state === "queued")
347
+ return sealed ? "ready to build" : "waiting for approval";
348
+ if (state === "running")
349
+ return "running";
350
+ if (state === "done")
351
+ return "built";
352
+ if (state === "failed")
353
+ return "failed";
354
+ return state;
355
+ };
356
+ const page = rows.slice(0, limit).map(row => ({
357
+ ref: String(row["tid"]),
358
+ title: String(row["title"]),
359
+ state: String(row["state"]),
360
+ chip: chipOf(String(row["state"]), Number(row["live"]) === 1, Number(row["sealed"]) === 1),
361
+ repo: String(row["repo"]),
362
+ filedVia: row["via"] === null ? null : String(row["via"]),
363
+ }));
364
+ const nextCursor = rows.length > limit ? Number(rows[limit - 1]?.["rid"] ?? 0) : null;
365
+ return { tasks: page, nextCursor };
366
+ }
367
+ export function taskDetailFor(store, who, taskId, evidenceRoot, now = new Date()) {
368
+ const { sql, args } = inClause(who.repos);
369
+ const row = store.handle
370
+ .prepare(`SELECT task_ref.id AS rid, task.id AS tid, task.title AS title, task.state AS state, task_ref.repo AS repo
371
+ FROM task_ref JOIN task ON task.id = task_ref.external_id AND task_ref.backend = 'built-in'
372
+ WHERE task.id = ? AND task_ref.repo IN (${sql})`)
373
+ .get(taskId, ...args);
374
+ // A foreign or absent ref is the SAME answer: not-found — existence
375
+ // outside the allowlist is not this credential's to learn.
376
+ if (row === undefined)
377
+ return null;
378
+ const rid = Number(row["rid"]);
379
+ const scope = store.getScope(taskId);
380
+ const attempts = store.handle
381
+ .prepare(`SELECT outcome, provider, model, started_at, finished_at, cost_usd FROM run
382
+ WHERE task_ref = ? ORDER BY id`)
383
+ .all(rid)
384
+ .map(one => ({
385
+ outcome: one["outcome"] === null ? null : String(one["outcome"]),
386
+ provider: String(one["provider"]),
387
+ model: one["model"] === null ? null : String(one["model"]),
388
+ startedAt: String(one["started_at"]),
389
+ finishedAt: one["finished_at"] === null ? null : String(one["finished_at"]),
390
+ durationMs: one["finished_at"] === null
391
+ ? null
392
+ : new Date(String(one["finished_at"])).getTime() - new Date(String(one["started_at"])).getTime(),
393
+ // Integer micro-USD, never a float (review finding 6); null = unmeasured.
394
+ costMicrousd: one["cost_usd"] === null ? null : Math.round(Number(one["cost_usd"]) * 1_000_000),
395
+ }));
396
+ const measured = attempts.filter(one => one.costMicrousd !== null);
397
+ const waits = [];
398
+ const question = store.handle
399
+ .prepare(`SELECT 1 AS hit FROM decision JOIN run ON run.id = decision.run
400
+ WHERE run.task_ref = ? AND decision.answered_at IS NULL AND decision.state IN ('open','expired') LIMIT 1`)
401
+ .get(rid);
402
+ if (question !== undefined)
403
+ waits.push("a question waits on the operator");
404
+ if (!store.scopeSealed(taskId))
405
+ waits.push("the scope waits on the operator's signature");
406
+ const latestRun = store.handle.prepare("SELECT MAX(id) AS top FROM run WHERE task_ref = ?").get(rid);
407
+ const evidence = latestRun?.["top"] === null || latestRun?.["top"] === undefined
408
+ ? []
409
+ : store.handle
410
+ .prepare("SELECT id, kind, bytes_original, sha256, capture_status FROM artifact WHERE run = ? ORDER BY id")
411
+ .all(Number(latestRun["top"]))
412
+ .map(one => ({
413
+ // Opaque metadata only — no filesystem paths, no bodies (spec v6).
414
+ id: Number(one["id"]),
415
+ kind: String(one["kind"]),
416
+ bytes: Number(one["bytes_original"]),
417
+ sha256: String(one["sha256"]),
418
+ captureStatus: one["capture_status"] === null ? null : String(one["capture_status"]),
419
+ mediaType: MEDIA_BY_KIND[String(one["kind"])] ?? "text/plain",
420
+ }));
421
+ const deliverable = store.refForId(rid)?.deliverable ?? "branch";
422
+ return {
423
+ ref: String(row["tid"]),
424
+ work: taskWorkSummaryOf(store, taskId, now, { principal: "coordinator", repos: who.repos }),
425
+ assignment: assignmentBrief(assignmentOf(store, taskId, now, { principal: "coordinator", repos: who.repos }, evidenceRoot)),
426
+ title: String(row["title"]),
427
+ state: String(row["state"]),
428
+ repo: String(row["repo"]),
429
+ deliverable,
430
+ report: reportSummaryFor(store, evidenceRoot, rid),
431
+ filedBy: store.coordinatorProvenanceOf(taskId)?.label ?? null,
432
+ scope: {
433
+ sealed: store.scopeSealed(taskId),
434
+ goal: scope?.goal ?? null,
435
+ // The scope in the console's own words — fallback chain included.
436
+ words: scope === null ? [] : describeScope(scope),
437
+ },
438
+ waits,
439
+ attempts,
440
+ cost: {
441
+ totalMicrousd: measured.reduce((sum, one) => sum + (one.costMicrousd ?? 0), 0),
442
+ measuredRuns: measured.length,
443
+ totalRuns: attempts.length,
444
+ },
445
+ evidence,
446
+ };
447
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Settings → Sessions & tokens (v101): where you're signed in (sign any of
3
+ * them out), and your API tokens (make one, revoke one). An instance operator
4
+ * can see and end everyone's.
5
+ */
6
+ import type { ApiTokenRow, WebSessionRow } from "./store.js";
7
+ export declare const CREDENTIALS_CSS: string;
8
+ /** "Chrome on macOS", from a user agent, for a person to recognise a session. */
9
+ export declare function deviceWords(agent: string | null): string;
10
+ export type CredentialsView = {
11
+ who: string;
12
+ everyone: boolean;
13
+ canSeeEveryone: boolean;
14
+ sessions: (WebSessionRow & {
15
+ here: boolean;
16
+ })[];
17
+ tokens: ApiTokenRow[];
18
+ now: number;
19
+ };
20
+ export declare function credentialsHtml(view: CredentialsView, csrf: string, notice: {
21
+ said?: string | null;
22
+ problem?: string | null;
23
+ }): string;
24
+ /** The token, once: a focused page with no script. */
25
+ export declare function tokenShownHtml(name: string, token: string, access: "read" | "act", expiresAt: string): string;
@@ -0,0 +1,48 @@
1
+ import { TOKEN_DAYS } from "./api-tokens.js";
2
+ const e = (value) => String(value ?? "").replace(/[&<>"']/g, c => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
3
+ export const CREDENTIALS_CSS = `.credentials{max-width:820px;min-width:0}.credentials .card{padding:14px 16px;margin:12px 0}.credentials h2{font-size:1.05rem;margin:0 0 8px}` +
4
+ `.credentials .rows{display:grid;gap:0;border:1px solid var(--so-line);border-radius:10px;overflow:hidden}.credentials .row-item{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 14px;border-bottom:1px solid var(--so-line)}` +
5
+ `.credentials .row-item:last-child{border-bottom:0}.credentials .row-item p{margin:0}.credentials .row-item .meta{font-size:.85rem}.credentials form{margin:0}.credentials button{min-height:40px;white-space:nowrap}` +
6
+ `.credentials .create{display:grid;gap:10px}.credentials .create label{display:grid;gap:6px}.credentials .create input,.credentials .create select{box-sizing:border-box;width:100%}.credentials .badge-here{font-size:.75rem;padding:1px 6px;border-radius:999px;background:var(--so-success-soft);color:var(--so-success);margin-left:6px}` +
7
+ `@media(max-width:600px){.credentials .row-item{flex-wrap:wrap}.credentials .create input,.credentials .create select{font-size:16px}}`;
8
+ /** "Chrome on macOS", from a user agent, for a person to recognise a session. */
9
+ export function deviceWords(agent) {
10
+ if (agent === null || agent === "")
11
+ return "Unknown device";
12
+ const browser = /Edg\//.test(agent) ? "Edge" : /Firefox\//.test(agent) ? "Firefox" : /Chrome\//.test(agent) ? "Chrome" : /Safari\//.test(agent) ? "Safari" : /curl|node|undici|python|Go-http/i.test(agent) ? "A script" : "A browser";
13
+ const system = /iPhone|iPad/.test(agent) ? "iPhone or iPad" : /Android/.test(agent) ? "Android" : /Mac OS X|Macintosh/.test(agent) ? "macOS" : /Windows/.test(agent) ? "Windows" : /Linux/.test(agent) ? "Linux" : null;
14
+ return system === null ? browser : `${browser} on ${system}`;
15
+ }
16
+ const when = (value, now) => {
17
+ if (value === null)
18
+ return "never";
19
+ const at = typeof value === "number" ? value : Date.parse(value);
20
+ const minutes = Math.round((now - at) / 60_000);
21
+ return minutes < 1 ? "just now" : minutes < 60 ? `${minutes} min ago` : minutes < 60 * 24 ? `${Math.round(minutes / 60)} h ago` : new Date(at).toISOString().slice(0, 10);
22
+ };
23
+ export function credentialsHtml(view, csrf, notice) {
24
+ const hidden = (fields) => Object.entries(fields).map(([k, v]) => `<input type="hidden" name="${e(k)}" value="${e(v)}">`).join("");
25
+ const post = (fields, label, style = "secondary") => `<form method="post" action="/settings/sessions">${hidden({ csrf, ...fields, ...(view.everyone ? { everyone: "1" } : {}) })}<button class="${style}">${label}</button></form>`;
26
+ const note = notice.problem ? `<p class="problem" role="alert">${e(notice.problem)}</p>` : notice.said ? `<p role="status">${e(notice.said)}</p>` : "";
27
+ const toggle = view.canSeeEveryone ? `<p class="meta"><a href="/settings/sessions${view.everyone ? "" : "?everyone=1"}">${view.everyone ? "Show only mine" : "Show everyone's"}</a></p>` : "";
28
+ const sessions = view.sessions.length === 0 ? `<p class="meta">No one else is signed in.</p>` : `<div class="rows">${view.sessions.map(one => `<div class="row-item" data-session="${e(one.idHash.slice(0, 12))}"><div><p>${view.everyone ? `<strong>${e(one.account)}</strong> · ` : ""}${e(deviceWords(one.agent))}${one.here ? `<span class="badge-here">This browser</span>` : ""}</p>` +
29
+ `<p class="meta">${one.ssoAt === null ? "Password" : "Identity provider"} · ${e(one.address ?? "unknown address")} · active ${e(when(one.lastSeen, view.now))} · signed in ${e(when(one.createdAt, view.now))}</p></div>` +
30
+ `${one.here ? "" : post({ action: "end-session", session: one.idHash }, "Sign out")}</div>`).join("")}</div>`;
31
+ const others = view.sessions.filter(one => !one.here && one.account === view.who).length;
32
+ const endOthers = others > 0 && !view.everyone ? post({ action: "end-others" }, `Sign out everywhere else (${others})`) : "";
33
+ const live = view.tokens.filter(one => one.revokedAt === null && Date.parse(one.expiresAt) > view.now);
34
+ const tokens = live.length === 0 ? `<p class="meta">No API tokens.</p>` : `<div class="rows">${live.map(one => `<div class="row-item" data-token="${e(one.id)}"><div><p>${view.everyone ? `<strong>${e(one.account)}</strong> · ` : ""}${e(one.name)} · ${one.access === "act" ? "Can act" : "Read only"}</p>` +
35
+ `<p class="meta">Expires ${e(one.expiresAt.slice(0, 10))} · last used ${e(when(one.lastUsedAt, view.now))}</p></div>${post({ action: "revoke-token", token: one.id }, "Revoke")}</div>`).join("")}</div>`;
36
+ const create = `<details class="card"><summary>New API token</summary><form method="post" action="/settings/sessions" class="create">${hidden({ csrf, action: "create-token" })}` +
37
+ `<label>Name<input type="text" name="name" maxlength="60" required placeholder="for example: CI"></label>` +
38
+ `<label>It can<select name="access"><option value="read">Read (tasks, results, the ledger)</option><option value="act">Act as you (file and manage work; never approve)</option></select></label>` +
39
+ `<label>Expires in<select name="days">${TOKEN_DAYS.map(days => `<option value="${days}"${days === 90 ? " selected" : ""}>${days} days</option>`).join("")}</select></label>` +
40
+ `<label>Your Toolroll password<input type="password" name="password" autocomplete="current-password" required></label><button>Make the token</button></form></details>`;
41
+ return `<section class="credentials">${note}${toggle}<h2>Signed in</h2>${sessions}${endOthers}<h2 style="margin-top:1.5rem">API tokens</h2>` +
42
+ `<p class="meta">For scripts and CI: send <code>Authorization: Bearer &lt;token&gt;</code>. A token can't approve anything.</p>${tokens}${view.everyone ? "" : create}</section>`;
43
+ }
44
+ /** The token, once: a focused page with no script. */
45
+ export function tokenShownHtml(name, token, access, expiresAt) {
46
+ return `<h1>${e(name)}</h1><div class="card"><p>Your API token, shown once. Only a hash is kept, so copy it now.</p><p class="mono secret-value">${e(token)}</p>` +
47
+ `<p class="meta">${access === "act" ? "It acts as you (never approves)" : "It reads"} until ${e(expiresAt.slice(0, 10))}. Revoke it any time on Sessions &amp; tokens.</p></div><p class="meta"><a href="/settings/sessions">Back to Sessions &amp; tokens</a></p>`;
48
+ }