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,75 @@
1
+ import { loadPrimary } from "./webhooks.js";
2
+ import { loadSlackCredentials } from "./slack-api.js";
3
+ import { SlackState } from "./slack-state.js";
4
+ const escape = (text) => text
5
+ .replaceAll("&", "&")
6
+ .replaceAll("<", "&lt;")
7
+ .replaceAll(">", "&gt;")
8
+ .replaceAll('"', "&quot;")
9
+ .replaceAll("'", "&#39;");
10
+ export function slackSettingsHtml(store, dir, csrf, options = {}) {
11
+ const credentials = loadSlackCredentials(dir), state = new SlackState(store), bindings = credentials ? state.bindings(credentials.installation).filter(one => state.live(one)) : [], binding = options.who === undefined ? null : bindings.find(one => one.approver === options.who) ?? null, others = bindings.length - (binding === null ? 0 : 1);
12
+ const runtime = credentials
13
+ ? state.db
14
+ .prepare("SELECT connected,problem,lease_until FROM slack_runtime WHERE installation=?")
15
+ .get(credentials.installation)
16
+ : null;
17
+ const now = options.now ?? new Date(), live = runtime &&
18
+ typeof runtime.lease_until === "string" &&
19
+ runtime.lease_until > now.toISOString() &&
20
+ runtime.connected;
21
+ const hidden = `<input type="hidden" name="csrf" value="${escape(csrf)}">`;
22
+ const password = '<label>Your Toolroll password<input style="min-height:44px" type="password" name="password" autocomplete="current-password" required></label>';
23
+ const post = (action, content) => `<form method="post" action="/settings/slack/${action}" class="card">${hidden}${content}</form>`;
24
+ let content = "";
25
+ if (!credentials) {
26
+ content =
27
+ "<p>Manage projects and review results in a private Slack conversation.</p>" +
28
+ '<details open><summary>Create your Slack app</summary><ol><li>Download the <a href="/settings/slack/manifest">app manifest</a>, then <a href="https://api.slack.com/apps" target="_blank" rel="noopener noreferrer">create an app</a> in your workspace using that manifest.</li><li>Under Basic Information, create an app-level token with <code>connections:write</code>.</li><li>Under OAuth &amp; Permissions, install the app and copy its bot token.</li></ol></details>' +
29
+ post("connect", '<label>App token<input style="min-height:44px" type="password" name="app-token" autocomplete="off" placeholder="xapp-…" required></label><label>Bot token<input style="min-height:44px" type="password" name="bot-token" autocomplete="off" placeholder="xoxb-…" required></label>' +
30
+ password +
31
+ '<p class="meta">Tokens stay on this installation. Next, pair your own Slack account.</p><button type="submit">Connect Slack</button>');
32
+ }
33
+ else {
34
+ content = `<p><strong>${escape(credentials.workspace)}</strong> · ${live ? "Connected" : "Waiting for connection"}</p>`;
35
+ if (runtime?.problem)
36
+ content += `<p role="status">${escape(String(runtime.problem))}</p>`;
37
+ if (!live && !runtime?.problem)
38
+ content +=
39
+ "<p>Keep the Toolroll worker running to receive Slack messages.</p>";
40
+ if (options.code) {
41
+ content +=
42
+ "<h2>Pair your account</h2><p>Send this in a direct message to your Toolroll Slack app. It expires in 10 minutes.</p>" +
43
+ `<label>Pairing message<input type="text" readonly value="pair ${escape(options.code)}" autocomplete="off" style="width:100%;max-width:100%;font-size:14px;min-height:44px"></label>` +
44
+ '<a class="button-link" style="min-height:44px;white-space:nowrap" href="/settings/slack">Check connection</a>';
45
+ }
46
+ else if (binding && state.live(binding)) {
47
+ const pending = Number(state.db
48
+ .prepare("SELECT count(*) n FROM slack_part p JOIN slack_event e ON e.id=p.event WHERE e.binding=? AND p.state='pending'")
49
+ .get(binding.id)?.n ?? 0);
50
+ const failed = Number(state.db
51
+ .prepare("SELECT count(*) n FROM slack_part p JOIN slack_event e ON e.id=p.event WHERE e.binding=? AND p.state='dropped'")
52
+ .get(binding.id)?.n ?? 0);
53
+ content +=
54
+ `<p>Your Slack account is paired.${others ? ` ${others} teammate${others === 1 ? " is" : "s are"} paired too.` : ""}${pending ? ` ${pending} replies waiting to send.` : ""}${failed ? ` ${failed} replies could not be delivered. Open the saved chat to recover them.` : ""}</p>` +
55
+ "<p>Try “What needs my attention?” or “Show the evidence for the latest result.”</p>" +
56
+ '<p><a href="/chat">Open saved chat</a></p>' +
57
+ (loadPrimary(process.env, dir) === "slack"
58
+ ? "<p>Task updates are sent here.</p>"
59
+ : post("alerts", '<button type="submit">Send task updates here</button>'));
60
+ }
61
+ else {
62
+ content += post("pair", "<h2>Pair your account</h2><p>Your paired Slack account can read your connected projects and confirm proposed changes. Password approvals still open in Toolroll." +
63
+ (others ? ` ${others} teammate${others === 1 ? " is" : "s are"} already paired.` : "") + "</p>" +
64
+ password +
65
+ '<button type="submit">Create pairing code</button>');
66
+ }
67
+ if (binding && state.live(binding) && !options.code)
68
+ content += post("unpair", password + '<p class="meta">Unpairing ends every open button in your chat. Teammates are unaffected.</p><button type="submit">Unpair my account</button>');
69
+ content +=
70
+ "<details><summary>Connection settings</summary>" +
71
+ post("disconnect", password + '<button type="submit">Disconnect Slack</button>') +
72
+ "</details>";
73
+ }
74
+ return `<section style="max-width:42rem;overflow-wrap:anywhere"><p><a href="/settings">Settings</a></p><h1>Slack</h1>${options.problem ? `<p class="problem" role="alert">${escape(options.problem)}</p>` : ""}${content}<details><summary>Access and setup</summary><p>Private messages and threads use your Toolroll permissions. Shared channels are not supported. Secure review links use this installation’s configured HTTPS console address.</p><p>Socket Mode connects out to Slack. It does not need a public webhook or a Tailscale account.</p></details></section>`;
75
+ }
@@ -0,0 +1,13 @@
1
+ /** Slack compatibility names for the shared durable transport state. */
2
+ import { ChatState } from "./chat-delivery-state.js";
3
+ import type { Store } from "./store.js";
4
+ export { chatHash as slackHash } from "./chat-delivery-state.js";
5
+ export type { ChatBinding as SlackBinding, ChatEvent as SlackEvent, ChatPart as SlackPart, ChatContent as SlackContent, } from "./chat-delivery-state.js";
6
+ import type { ChatIdentity } from "./chat-delivery-state.js";
7
+ export type SlackIdentity = ChatIdentity & {
8
+ team: string;
9
+ };
10
+ export declare const SLACK_SCHEMA: string, SLACK_TABLES: string[];
11
+ export declare class SlackState extends ChatState {
12
+ constructor(store: Store);
13
+ }
@@ -0,0 +1,9 @@
1
+ /** Slack compatibility names for the shared durable transport state. */
2
+ import { ChatState, chatSchema, chatTables } from "./chat-delivery-state.js";
3
+ export { chatHash as slackHash } from "./chat-delivery-state.js";
4
+ export const SLACK_SCHEMA = chatSchema("slack"), SLACK_TABLES = chatTables("slack");
5
+ export class SlackState extends ChatState {
6
+ constructor(store) {
7
+ super(store, "slack");
8
+ }
9
+ }
@@ -0,0 +1,13 @@
1
+ import { SocketModeClient } from "@slack/socket-mode";
2
+ import { type SlackChatOptions } from "./slack-chat.js";
3
+ /** The bot and socket tokens must belong to the same app, including after reconnect. */
4
+ export declare class ToolrollSlackSocket extends SocketModeClient {
5
+ expectedApp: string;
6
+ wrongApp: () => void;
7
+ protected onWebSocketMessage(data: string | ArrayBuffer, isBinary: boolean): Promise<void>;
8
+ }
9
+ export declare function followSlack(options: Omit<SlackChatOptions, "identity" | "api" | "owner" | "current"> & {
10
+ dir: string;
11
+ signal: AbortSignal;
12
+ notifications: () => boolean;
13
+ }): Promise<void>;
package/dist/slack.js ADDED
@@ -0,0 +1,167 @@
1
+ /** One leased Socket Mode connection, hosted by the ordinary worker. */
2
+ import { randomBytes } from "node:crypto";
3
+ import { setTimeout as sleep } from "node:timers/promises";
4
+ import { SocketModeClient, LogLevel } from "@slack/socket-mode";
5
+ import { loadSlackCredentials, slackApi } from "./slack-api.js";
6
+ import { SlackState } from "./slack-state.js";
7
+ import { receiveSlack, processSlackEvent, deliverSlackPart, planSlackNotifications, planSlackRooms, } from "./slack-chat.js";
8
+ /** The bot and socket tokens must belong to the same app, including after reconnect. */
9
+ export class ToolrollSlackSocket extends SocketModeClient {
10
+ expectedApp = "";
11
+ wrongApp = () => { };
12
+ async onWebSocketMessage(data, isBinary) {
13
+ let packet;
14
+ try {
15
+ packet = JSON.parse(typeof data === "string" ? data : new TextDecoder().decode(data));
16
+ }
17
+ catch {
18
+ return;
19
+ }
20
+ if (packet.type === "hello") {
21
+ const info = packet.connection_info;
22
+ if (info?.app_id !== this.expectedApp) {
23
+ this.wrongApp();
24
+ await this.disconnect();
25
+ return;
26
+ }
27
+ }
28
+ return super.onWebSocketMessage(data, isBinary);
29
+ }
30
+ }
31
+ export async function followSlack(options) {
32
+ const owner = randomBytes(16).toString("hex"), state = new SlackState(options.store);
33
+ const pause = async (ms) => {
34
+ try {
35
+ await sleep(ms, undefined, { signal: options.signal });
36
+ }
37
+ catch {
38
+ /* shutdown */
39
+ }
40
+ };
41
+ while (!options.signal.aborted) {
42
+ const credentials = loadSlackCredentials(options.dir);
43
+ if (!credentials ||
44
+ !state.lease(credentials.installation, owner, new Date())) {
45
+ await pause(2000);
46
+ continue;
47
+ }
48
+ let alive = true, connected = false;
49
+ const same = () => {
50
+ const current = loadSlackCredentials(options.dir);
51
+ return (alive &&
52
+ !options.signal.aborted &&
53
+ current?.installation === credentials.installation &&
54
+ current.botToken === credentials.botToken &&
55
+ current.appToken === credentials.appToken &&
56
+ state.owns(credentials.installation, owner));
57
+ };
58
+ const problem = (text) => state.db
59
+ .prepare("UPDATE slack_runtime SET problem=? WHERE installation=? AND owner=?")
60
+ .run(text, credentials.installation, owner);
61
+ // SDK log output can include envelopes/tokens. Only fixed status phrases are saved.
62
+ const client = new ToolrollSlackSocket({
63
+ appToken: credentials.appToken,
64
+ autoReconnectEnabled: true,
65
+ clientOptions: { retryConfig: { retries: 2 }, timeout: 15_000 },
66
+ logger: {
67
+ debug() { },
68
+ info() { },
69
+ warn() { },
70
+ error() {
71
+ problem("Slack is reconnecting. Check the app tokens if this continues.");
72
+ },
73
+ setLevel() { },
74
+ getLevel() {
75
+ return LogLevel.ERROR;
76
+ },
77
+ setName() { },
78
+ },
79
+ });
80
+ client.expectedApp = credentials.app;
81
+ client.wrongApp = () => {
82
+ alive = false;
83
+ problem("The app token and bot token belong to different Slack apps. Disconnect and use tokens from the same app.");
84
+ };
85
+ const stop = () => {
86
+ alive = false;
87
+ void client.disconnect().catch(() => { });
88
+ };
89
+ options.signal.addEventListener("abort", stop, { once: true });
90
+ const heartbeat = setInterval(() => {
91
+ if (!same() || !state.lease(credentials.installation, owner, new Date()))
92
+ stop();
93
+ }, 10_000);
94
+ client.on("connected", () => {
95
+ connected = true;
96
+ state.db
97
+ .prepare("UPDATE slack_runtime SET connected=?,problem=NULL WHERE installation=? AND owner=?")
98
+ .run(new Date().toISOString(), credentials.installation, owner);
99
+ });
100
+ client.on("disconnected", () => {
101
+ connected = false;
102
+ if (alive)
103
+ problem("Slack is disconnected; queued replies are saved.");
104
+ });
105
+ client.on("reconnecting", () => {
106
+ connected = false;
107
+ problem("Reconnecting to Slack…");
108
+ });
109
+ client.on("error", () => problem("Slack connection failed. Check the app tokens and reconnect."));
110
+ client.on("slack_event", (envelope) => {
111
+ if (!same())
112
+ return;
113
+ try {
114
+ receiveSlack(state, credentials, envelope.type, envelope.body, new Date());
115
+ void envelope
116
+ .ack()
117
+ .catch(() => problem("Slack acknowledgement was lost; a repeated event will be recognized."));
118
+ }
119
+ catch {
120
+ problem("Slack could not save an incoming message; it has not been acknowledged.");
121
+ }
122
+ });
123
+ const chat = {
124
+ ...options,
125
+ identity: credentials,
126
+ owner,
127
+ api: slackApi(credentials.botToken),
128
+ canNotify: options.notifications,
129
+ current: same,
130
+ };
131
+ try {
132
+ await client.start();
133
+ while (same()) {
134
+ const retry = state.db
135
+ .prepare("SELECT retry_at FROM slack_runtime WHERE installation=?")
136
+ .get(credentials.installation)?.retry_at;
137
+ if (!connected ||
138
+ (typeof retry === "string" && retry > new Date().toISOString())) {
139
+ await pause(1000);
140
+ continue;
141
+ }
142
+ await processSlackEvent(chat);
143
+ if (same())
144
+ await planSlackRooms(chat);
145
+ if (same())
146
+ await deliverSlackPart(chat);
147
+ if (same() && options.notifications())
148
+ await planSlackNotifications(chat);
149
+ await pause(1000);
150
+ }
151
+ }
152
+ catch {
153
+ if (alive)
154
+ problem("Slack connection is unavailable. Retrying shortly.");
155
+ }
156
+ finally {
157
+ clearInterval(heartbeat);
158
+ alive = false;
159
+ options.signal.removeEventListener("abort", stop);
160
+ await client.disconnect().catch(() => { });
161
+ state.db
162
+ .prepare("UPDATE slack_runtime SET owner=NULL,lease_until=NULL,connected=NULL WHERE installation=? AND owner=?")
163
+ .run(credentials.installation, owner);
164
+ }
165
+ await pause(5000);
166
+ }
167
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The Spend page (v105): what agent work cost this month, where it went, and
3
+ * the monthly budgets that alert at 50/80/100 % and (unless set to alert
4
+ * only) stop new work at 100 %. An instance operator's page; budgets change
5
+ * with a step-up.
6
+ */
7
+ import { type BudgetState, type SpendItem } from "./spend.js";
8
+ export declare const SPEND_CSS: string;
9
+ export type SpendView = {
10
+ month: string;
11
+ previous: string;
12
+ next: string | null;
13
+ items: SpendItem[];
14
+ budgets: BudgetState[];
15
+ targets: {
16
+ value: string;
17
+ label: string;
18
+ group: "Everything" | "Projects" | "People" | "Teammates";
19
+ }[];
20
+ teammateNames: Map<number, string>;
21
+ csrf: string;
22
+ };
23
+ export declare function spendHtml(view: SpendView, notice: {
24
+ said?: string | null;
25
+ problem?: string | null;
26
+ }): string;
27
+ /** One row per piece of spend, for a spreadsheet. */
28
+ export declare function spendCsv(items: readonly SpendItem[], teammateNames: Map<number, string>): string;
@@ -0,0 +1,95 @@
1
+ /**
2
+ * The Spend page (v105): what agent work cost this month, where it went, and
3
+ * the monthly budgets that alert at 50/80/100 % and (unless set to alert
4
+ * only) stop new work at 100 %. An instance operator's page; budgets change
5
+ * with a step-up.
6
+ */
7
+ import { budgetLabel, usd } from "./spend.js";
8
+ const e = (value) => String(value ?? "").replace(/[&<>"']/g, c => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
9
+ const projectName = (repo) => repo.split("/").filter(Boolean).pop() ?? repo;
10
+ export const SPEND_CSS = `.spend{max-width:960px;min-width:0}.spend-head{display:flex;justify-content:space-between;align-items:baseline;gap:12px;flex-wrap:wrap}.spend-head h1{margin:0}` +
11
+ `.spend-month{display:flex;gap:10px;align-items:baseline;font-size:.875rem}.spend-total{font-size:1.5rem;font-weight:600;margin:12px 0 2px;font-variant-numeric:tabular-nums}` +
12
+ `.spend h2{font-size:.9375rem;margin:24px 0 8px}.spend table{width:100%;border-collapse:collapse;font-size:.8125rem}.spend th,.spend td{text-align:left;padding:6px 8px 6px 0;border-bottom:1px solid var(--border);overflow-wrap:anywhere}` +
13
+ `.spend th{font-weight:500;color:var(--muted-foreground)}.spend td.n{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}.spend-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:0 24px}` +
14
+ `.budget{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:4px 12px;padding:10px 0;border-bottom:1px solid var(--border)}.budget .name{font-weight:500;font-size:.875rem}` +
15
+ `.budget .figures{font-size:.8125rem;font-variant-numeric:tabular-nums;text-align:right}.budget .bar{grid-column:1/-1;height:6px;border-radius:3px;background:var(--muted);overflow:hidden}` +
16
+ `.budget .bar span{display:block;height:100%;background:var(--foreground)}.budget.over .bar span{background:var(--danger)}.budget.over .figures{color:var(--danger)}.budget .meta{grid-column:1/-1}` +
17
+ `.budget details{grid-column:1/-1}.spend form.budget-form{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:8px 12px;align-items:end;margin:8px 0}` +
18
+ `.spend form.budget-form label{display:grid;gap:4px;font-size:.8125rem}.spend form.budget-form .choice{display:flex;gap:8px;align-items:center}.spend form.budget-form button{justify-self:start}`;
19
+ /** The rows of a breakdown: spend and count by a key, biggest first. */
20
+ function breakdown(items, keyOf, top = 12) {
21
+ const rows = new Map();
22
+ for (const item of items) {
23
+ const key = keyOf(item);
24
+ if (key === null)
25
+ continue;
26
+ const row = rows.get(key) ?? { key, microusd: 0, count: 0, unpriced: 0 };
27
+ row.microusd += item.microusd ?? 0;
28
+ row.count++;
29
+ if (item.microusd === null && item.source === "unpriced")
30
+ row.unpriced++;
31
+ rows.set(key, row);
32
+ }
33
+ return [...rows.values()].sort((a, b) => b.microusd - a.microusd || b.count - a.count).slice(0, top);
34
+ }
35
+ function table(title, rows, name) {
36
+ if (rows.length === 0)
37
+ return "";
38
+ return `<section><h2>${e(title)}</h2><table><tbody>${rows.map(row => `<tr><td>${e(name(row.key))}</td><td class="n">${row.count}</td><td class="n">${usd(row.microusd)}${row.unpriced > 0 ? ` <span class="meta">+${row.unpriced} unpriced</span>` : ""}</td></tr>`).join("")}</tbody></table></section>`;
39
+ }
40
+ export function spendHtml(view, notice) {
41
+ const note = notice.problem ? `<p class="problem" role="alert">${e(notice.problem)}</p>` : notice.said ? `<p role="status">${e(notice.said)}</p>` : "";
42
+ const total = view.items.reduce((sum, item) => sum + (item.microusd ?? 0), 0);
43
+ const unpriced = view.items.filter(item => item.microusd === null && (item.tokensIn !== null || item.kind !== "run")).length;
44
+ const counts = { run: view.items.filter(item => item.kind === "run").length, teammate: view.items.filter(item => item.kind === "teammate").length, chat: view.items.filter(item => item.kind === "chat").length, sort: view.items.filter(item => item.kind === "sort").length };
45
+ const parts = [`${counts.run} ${counts.run === 1 ? "run" : "runs"}`, ...(counts.teammate > 0 ? [`${counts.teammate} teammate turns`] : []), ...(counts.chat > 0 ? [`${counts.chat} chat turns`] : []), ...(counts.sort > 0 ? [`${counts.sort} ${counts.sort === 1 ? "sort" : "sorts"}`] : [])];
46
+ const nameOfTeammate = (key) => view.teammateNames.get(Number(key)) ?? `Teammate ${key}`;
47
+ const budgets = view.budgets.map(budget => {
48
+ const width = Math.min(100, Math.max(0, budget.percent));
49
+ const over = budget.spentMicrousd >= budget.limitMicrousd;
50
+ const label = budgetLabel(budget, budget.scope === "teammate" ? nameOfTeammate(budget.key) : undefined).replace(/'s$/, "");
51
+ return `<div class="budget${over ? " over" : ""}" data-budget="${budget.id}"><span class="name">${e(label)}</span>` +
52
+ `<span class="figures">${usd(budget.spentMicrousd)} of ${usd(budget.limitMicrousd)} · ${budget.percent}%</span>` +
53
+ `<span class="bar" aria-hidden="true"><span style="width:${width}%"></span></span>` +
54
+ `<span class="meta">${over && budget.hardStop ? "Used up: new API work waits until next month or a higher budget." : budget.hardStop ? "Stops API work at 100%." : "Alerts only."}${budget.unpriced > 0 ? ` ${budget.unpriced} unpriced` : ""}</span>` +
55
+ `<details><summary>Change</summary><form method="post" action="/spend/budget" class="budget-form"><input type="hidden" name="csrf" value="${e(view.csrf)}"><input type="hidden" name="target" value="${e(`${budget.scope}:${budget.key}`)}">` +
56
+ `<label>Monthly limit (US dollars)<input type="number" name="usd" min="1" step="1" value="${Math.round(budget.limitMicrousd / 1_000_000)}" required></label>` +
57
+ `<label class="choice"><input type="checkbox" name="stop" value="1"${budget.hardStop ? " checked" : ""}> Stop new work at 100%</label>` +
58
+ `<label>Your Toolroll password<input type="password" name="password" autocomplete="current-password"></label>` +
59
+ `<button type="submit" name="action" value="save">Save</button> <button type="submit" name="action" value="remove">Remove</button></form></details></div>`;
60
+ }).join("");
61
+ const groups = ["Everything", "Projects", "People", "Teammates"];
62
+ const options = groups.map(group => {
63
+ const members = view.targets.filter(one => one.group === group);
64
+ return members.length === 0 ? "" : `<optgroup label="${group}">${members.map(one => `<option value="${e(one.value)}">${e(one.label)}</option>`).join("")}</optgroup>`;
65
+ }).join("");
66
+ const add = `<details${view.budgets.length === 0 ? " open" : ""}><summary>Add a budget</summary><form method="post" action="/spend/budget" class="budget-form"><input type="hidden" name="csrf" value="${e(view.csrf)}">` +
67
+ `<label>For<select name="target" required>${options}</select></label>` +
68
+ `<label>Monthly limit (US dollars)<input type="number" name="usd" min="1" step="1" required></label>` +
69
+ `<label class="choice"><input type="checkbox" name="stop" value="1" checked> Stop new work at 100%</label>` +
70
+ `<label>Your Toolroll password<input type="password" name="password" autocomplete="current-password"></label>` +
71
+ `<button type="submit" name="action" value="save">Add budget</button></form></details>`;
72
+ const csv = `/spend?month=${e(view.month)}&amp;format=csv`;
73
+ return `<article class="spend">` +
74
+ `<div class="spend-head"><h1>Spend</h1><p class="spend-month"><a href="/spend?month=${e(view.previous)}">← ${e(view.previous)}</a><strong>${e(view.month)}</strong>${view.next === null ? "" : `<a href="/spend?month=${e(view.next)}">${e(view.next)} →</a>`}<a href="${csv}" download>CSV</a></p></div>${note}` +
75
+ `<p class="spend-total" data-spend-total="${total}">${usd(total)}</p><p class="meta">${parts.join(" · ")}${unpriced > 0 ? ` · ${unpriced} unpriced (no reported cost or catalogue price)` : ""} · UTC month</p>` +
76
+ `<section><h2>Budgets</h2>${budgets === "" ? `<p class="meta">No budgets yet.</p>` : budgets}${add}</section>` +
77
+ `<div class="spend-grid">` +
78
+ table("By project", breakdown(view.items, item => item.project), projectName) +
79
+ table("By person", breakdown(view.items, item => item.person), key => key) +
80
+ table("By teammate", breakdown(view.items, item => item.teammate === null ? null : String(item.teammate)), nameOfTeammate) +
81
+ table("By model", breakdown(view.items, item => `${item.provider}${item.model === null ? "" : ` · ${item.model}`}`), key => key) +
82
+ `</div><p class="meta">Subscription work is $0; its limits are on Tasks. API work is what the provider reported, or its tokens at the prices in Settings → Models.</p></article>`;
83
+ }
84
+ /** One row per piece of spend, for a spreadsheet. */
85
+ export function spendCsv(items, teammateNames) {
86
+ const cell = (value) => {
87
+ const text = value === null || value === undefined ? "" : String(value);
88
+ const safe = /^[=+\-@\t\r]/.test(text) ? `'${text}` : text;
89
+ return /[",\n\r]/.test(safe) ? `"${safe.replace(/"/g, '""')}"` : safe;
90
+ };
91
+ const head = ["time_utc", "kind", "project", "person", "teammate", "task", "run", "provider", "model", "tokens_in", "tokens_out", "cost_usd", "priced_by", "billing"];
92
+ const rows = items.map(item => [item.at, item.kind, item.project, item.person, item.teammate === null ? null : teammateNames.get(item.teammate) ?? item.teammate,
93
+ item.taskId, item.runId, item.provider, item.model, item.tokensIn, item.tokensOut, item.microusd === null ? null : (item.microusd / 1_000_000).toFixed(6), item.source, item.authMode].map(cell).join(","));
94
+ return `${head.join(",")}\r\n${rows.map(row => `${row}\r\n`).join("")}`;
95
+ }
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Spend (v105): what agent work cost, priced for every provider, and who and
3
+ * what it counts toward. Work on a subscription (a Claude or Codex login)
4
+ * costs nothing extra and counts as $0 (its limits are what bind it; see
5
+ * provider-limits.ts). Work billed to an API key costs what its provider
6
+ * reported; otherwise its tokens at the model's catalogue price (Settings →
7
+ * Models), or at the provider's highest listed price when the model isn't
8
+ * listed; work with no tokens and no cost is "unpriced" and said so.
9
+ *
10
+ * Spend counts toward a project (a run's task, a teammate's, a project chat),
11
+ * a person (who filed the task, or had the chat), a teammate (its turns, and
12
+ * tasks it filed), and the whole installation. Budgets are per calendar
13
+ * month (UTC).
14
+ */
15
+ import type { Database } from "./store.js";
16
+ export type PriceSource = "reported" | "estimated" | "unpriced" | "subscription";
17
+ export type Billing = "subscription" | "api-key";
18
+ /** How a provider's work is billed right now: an API key when Toolroll is set to use one, or when the CLI
19
+ * itself was last seen billing a key (a key helper, a Console login, Bedrock or Vertex, `codex login --with-api-key`);
20
+ * otherwise its plan. `db` supplies what was seen (provider_account); without it, the setting alone. */
21
+ export declare function billingOf(provider: string, db?: Database): Billing;
22
+ /** How a provider's CLI was last seen billing (provider_account), or null. */
23
+ export declare function seenBilling(db: Database, provider: string): Billing | null;
24
+ /** How a Claude turn was really billed, from its own stream. Only a plan reports its usage windows (Claude Code 2.1
25
+ * does on every turn), so that is the one sign of the plan; a named key source or a cloud model id (Bedrock, Vertex)
26
+ * is a key, and so is "none" without windows (a gateway's bearer token or a cloud provider says "none" too). Null when
27
+ * the stream said nothing. */
28
+ export declare function claudeBillingFrom(seen: {
29
+ keySource: string | null;
30
+ model: string | null;
31
+ planWindows: boolean;
32
+ }): Billing | null;
33
+ /** How Claude bills on this computer when Toolroll gives it no key (teammate turns, drafts): as its keyless runs
34
+ * were last seen, and its plan until one has been. */
35
+ export declare function claudeMachineBilling(db: Database): Billing;
36
+ /** Whether API work on this provider can be priced: it reports its cost, or the catalogue has its prices. */
37
+ export declare function canPrice(db: Database, provider: string): boolean;
38
+ export type Price = {
39
+ inputUsd: number;
40
+ outputUsd: number;
41
+ model: string;
42
+ };
43
+ /** A model's catalogue price (US dollars per million tokens), or null when the catalogue doesn't list one. A
44
+ * Claude short name ("sonnet") is priced as the newest of its family, as the Claude CLI runs it. */
45
+ export declare function priceFor(db: Database, provider: string, model: string | null): Price | null;
46
+ /** The provider's highest listed price, for API work whose model the catalogue doesn't list (or that ran the CLI's
47
+ * default): a budget that stops work must never see it as free. */
48
+ export declare function ceilingPriceFor(db: Database, provider: string): Price | null;
49
+ /** What a piece of work cost, in micro-dollars: nothing on a subscription; otherwise reported, or tokens at the
50
+ * catalogue price (usd per million tokens times tokens is micro-dollars), or unpriced. */
51
+ export declare function priceWork(db: Database, work: {
52
+ provider: string;
53
+ model: string | null;
54
+ costUsd: number | null;
55
+ tokensIn: number | null;
56
+ tokensOut: number | null;
57
+ billing: Billing;
58
+ }): {
59
+ microusd: number | null;
60
+ source: PriceSource;
61
+ price: Price | null;
62
+ };
63
+ export declare const SPEND_SCHEMA = "\nCREATE TABLE IF NOT EXISTS run_spend (\n run INTEGER PRIMARY KEY,\n microusd INTEGER,\n source TEXT NOT NULL CHECK (source IN ('reported', 'estimated', 'unpriced', 'subscription')),\n billing TEXT NOT NULL CHECK (billing IN ('subscription', 'api-key')),\n -- 1 once the run's own evidence set it (a key it was given, what its CLI said); a later turn can only make it a key.\n billing_fixed INTEGER NOT NULL DEFAULT 0,\n price_model TEXT,\n input_usd REAL,\n output_usd REAL,\n priced_at TEXT NOT NULL\n);\nCREATE TABLE IF NOT EXISTS budget (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n scope_kind TEXT NOT NULL CHECK (scope_kind IN ('installation', 'project', 'person', 'teammate')),\n scope_key TEXT NOT NULL,\n limit_microusd INTEGER NOT NULL CHECK (limit_microusd > 0),\n hard_stop INTEGER NOT NULL DEFAULT 1,\n created_by TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_by TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n removed_by TEXT,\n removed_at TEXT\n);\nCREATE UNIQUE INDEX IF NOT EXISTS budget_live ON budget (scope_kind, scope_key) WHERE removed_at IS NULL;\nCREATE TABLE IF NOT EXISTS provider_limit (\n provider TEXT NOT NULL,\n window TEXT NOT NULL,\n used_percent REAL NOT NULL,\n window_minutes INTEGER,\n resets_at TEXT,\n reached INTEGER NOT NULL DEFAULT 0,\n plan TEXT,\n observed_at TEXT NOT NULL,\n PRIMARY KEY (provider, window)\n);\n-- Spend that isn't a run, a teammate turn or a chat: a flow's Claude draft.\nCREATE TABLE IF NOT EXISTS side_spend (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n kind TEXT NOT NULL CHECK (kind IN ('draft')),\n repo TEXT,\n provider TEXT NOT NULL,\n model TEXT,\n cost_usd REAL,\n billing TEXT NOT NULL CHECK (billing IN ('subscription', 'api-key')),\n at TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS side_spend_at ON side_spend (at);\nCREATE TABLE IF NOT EXISTS provider_account (\n provider TEXT PRIMARY KEY,\n billing TEXT NOT NULL CHECK (billing IN ('subscription', 'api-key')),\n observed_at TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS chat_turn_created ON chat_turn (created_at);\nCREATE INDEX IF NOT EXISTS mate_turn_created ON mate_turn (created_at);\nCREATE INDEX IF NOT EXISTS teammate_turn_at ON teammate_turn (at);\n";
64
+ export type BudgetScope = "installation" | "project" | "person" | "teammate";
65
+ export type Budget = {
66
+ id: number;
67
+ scope: BudgetScope;
68
+ key: string;
69
+ limitMicrousd: number;
70
+ hardStop: boolean;
71
+ updatedBy: string;
72
+ updatedAt: string;
73
+ };
74
+ /** One piece of spend, whatever made it, with what it counts toward. */
75
+ export type SpendItem = {
76
+ at: string;
77
+ kind: "run" | "teammate" | "chat" | "sort" | "draft";
78
+ microusd: number | null;
79
+ source: PriceSource;
80
+ project: string | null;
81
+ person: string | null;
82
+ teammate: number | null;
83
+ provider: string;
84
+ model: string | null;
85
+ tokensIn: number | null;
86
+ tokensOut: number | null;
87
+ taskId: string | null;
88
+ runId: number | null;
89
+ authMode: string | null;
90
+ };
91
+ /** The calendar month (UTC) `at` falls in: [start, end) as ISO strings, and its name (YYYY-MM). */
92
+ export declare function monthOf(at: Date): {
93
+ from: string;
94
+ to: string;
95
+ name: string;
96
+ };
97
+ /** A month by its name (YYYY-MM), or null. */
98
+ export declare function monthNamed(name: string | null): {
99
+ from: string;
100
+ to: string;
101
+ name: string;
102
+ } | null;
103
+ /** Every teammate's name by id (its handle when its soul file names none). */
104
+ export declare function teammateNames(db: Database): Map<number, string>;
105
+ export declare function teammateFilers(db: Database): (repo: string | null, filedBy: string | null, kind: string | null) => number | null;
106
+ /** Who a task's work counts toward: its own filer, or, for a revision filed by automation (an automatic repair), the
107
+ * filer of the task it revises, up its ancestry (bounded). */
108
+ export declare function filersOf(db: Database): (taskRef: number) => {
109
+ repo: string | null;
110
+ filedBy: string | null;
111
+ kind: string | null;
112
+ };
113
+ /** Every piece of spend in [from, to): runs (by when they started), teammate turns and chat turns. `modeOf` says how
114
+ * a provider bills when a record doesn't (older rows): its current login or key. */
115
+ export declare function spendItems(db: Database, from: string, to: string, modeOf?: (provider: string) => Billing): SpendItem[];
116
+ /** Whether a piece of spend counts toward a budget. */
117
+ export declare function countsToward(item: SpendItem, budget: Pick<Budget, "scope" | "key">): boolean;
118
+ export type BudgetState = Budget & {
119
+ spentMicrousd: number;
120
+ unpriced: number;
121
+ percent: number;
122
+ };
123
+ /** A piece of work's agents as a budget sees them: which provider, billed how. */
124
+ export type BudgetAgent = {
125
+ provider: string;
126
+ billing: Billing;
127
+ };
128
+ /** What a budget gate says: nothing holds it, or the budget it's over (used up), or the budget that covers API work it
129
+ * can't price (no reported cost, no catalogue prices yet: never counted as free). */
130
+ export type BudgetHold = {
131
+ over: BudgetState | null;
132
+ why: "used-up" | "unpriced" | null;
133
+ unpricedProvider: string | null;
134
+ remainingMicrousd: number | null;
135
+ };
136
+ /** Why work waits on a budget, in words. */
137
+ export declare function budgetHoldWords(hold: BudgetHold, month: string, teammateName?: string): string;
138
+ /** Each budget's month so far: what counted toward it, and how many pieces of work had no price. */
139
+ export declare function budgetStates(budgets: readonly Budget[], items: readonly SpendItem[]): BudgetState[];
140
+ /** A budget in words: "The shop project's", "alex's", "Maya's (teammate)", "The whole installation's". */
141
+ export declare function budgetLabel(budget: Pick<Budget, "scope" | "key">, teammateName?: string): string;
142
+ export declare const usd: (microusd: number | null) => string;