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,20 @@
1
+ /**
2
+ * Settings → Policy (sprint 8): the organisation policy — allowed providers,
3
+ * models and tools, and the permission ceiling — and its history from the
4
+ * action ledger. Anyone signed in reads it; an instance operator changes it
5
+ * with their password.
6
+ */
7
+ import type { LedgerEntry } from "./action-ledger.js";
8
+ import { type SavedPolicy } from "./policy.js";
9
+ export declare const POLICY_CSS: string;
10
+ export type PolicyView = {
11
+ policy: SavedPolicy;
12
+ history: LedgerEntry[];
13
+ canChange: boolean;
14
+ /** The project tools here, as a hint for the tools list. */
15
+ toolNames: string[];
16
+ };
17
+ export declare function policyHtml(view: PolicyView, csrf: string, notice: {
18
+ said?: string | null;
19
+ problem?: string | null;
20
+ }): string;
@@ -0,0 +1,41 @@
1
+ import { LEVEL_HINTS, LEVEL_NAMES, PERMISSION_LEVELS, POLICY_PROVIDERS, PROVIDER_NAMES, policyParts } from "./policy.js";
2
+ const e = (value) => String(value ?? "").replace(/[&<>"']/g, c => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
3
+ export const POLICY_CSS = `.policy{max-width:720px;min-width:0}.policy dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:6px 16px;margin:12px 0 0;font-size:.875rem}` +
4
+ `.policy dt{color:var(--muted-foreground)}.policy dd{margin:0;overflow-wrap:anywhere}.policy fieldset{border:0;padding:0;margin:20px 0 0;min-width:0}` +
5
+ `.policy legend{font-weight:600;font-size:.875rem;margin-bottom:8px}.policy legend{padding:0}.policy .providers{display:grid;grid-template-columns:repeat(auto-fill,minmax(132px,1fr));gap:0 16px}.policy .providers label{display:flex;gap:8px;align-items:center;min-height:44px;margin:0;padding:0;font-weight:400}` +
6
+ `.policy .choice{display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;align-items:start;margin:0 0 10px;font-weight:400}.policy .choice input{margin:.2rem 0 0}` +
7
+ `.policy .choice strong{display:block;font-size:.875rem;font-weight:500}.policy .choice small,.policy .hint{display:block;color:var(--muted-foreground);font-size:.8125rem;margin-top:2px}` +
8
+ `.policy textarea{width:100%;min-height:72px;font-family:var(--font-mono);font-size:.8125rem;box-sizing:border-box}.policy .step-up{margin-top:18px}.policy button[type=submit]{margin-top:14px}` +
9
+ `.policy details{margin-top:28px}.policy summary{cursor:pointer;min-height:44px;display:flex;align-items:center;font-weight:600;font-size:.875rem}` +
10
+ `.policy ol{list-style:none;padding:0;margin:0}.policy li{padding:10px 0;border-bottom:1px solid var(--border);font-size:.8125rem;overflow-wrap:anywhere}.policy li .what{display:block;font-size:.875rem}`;
11
+ /** A ledger entry as one line of history: when, who, what, before → after. */
12
+ function historyItem(entry) {
13
+ const what = entry.action.replace(/^organisation policy: /, "");
14
+ const [before, after] = (entry.detail ?? "").split(" → ");
15
+ return `<li><span class="what">${e(what.charAt(0).toUpperCase() + what.slice(1))}: ${e(before ?? "")} → <strong>${e(after ?? "")}</strong></span>` +
16
+ `<span class="meta">${e(entry.actor)} · <time datetime="${e(entry.at)}">${e(entry.at.slice(0, 16).replace("T", " "))} UTC</time></span></li>`;
17
+ }
18
+ export function policyHtml(view, csrf, notice) {
19
+ const note = notice.problem ? `<p class="problem" role="alert">${e(notice.problem)}</p>` : notice.said ? `<p role="status">${e(notice.said)}</p>` : "";
20
+ const parts = policyParts(view.policy);
21
+ const changed = view.policy.updatedBy === null ? "" : `<p class="meta">Changed by ${e(view.policy.updatedBy)} on ${e((view.policy.updatedAt ?? "").slice(0, 10))}.</p>`;
22
+ const current = `<dl><dt>Providers</dt><dd>${e(parts.providers === "any" ? "Any" : parts.providers)}</dd><dt>Models</dt><dd>${e(parts.models === "any" ? "Any" : parts.models)}</dd>` +
23
+ `<dt>Tools</dt><dd>${e(parts.tools === "any" ? "Any" : parts.tools)}</dd><dt>Ceiling</dt><dd>${e(parts.ceiling)}</dd></dl>${changed}`;
24
+ const history = view.history.length === 0 ? "" : `<details><summary>History (${view.history.length})</summary><ol>${view.history.map(historyItem).join("")}</ol></details>`;
25
+ if (!view.canChange)
26
+ return `<section class="policy">${note}${current}<p class="meta">An instance operator sets the policy.</p>${history}</section>`;
27
+ const providers = POLICY_PROVIDERS.map(one => `<label><input type="checkbox" name="provider" value="${one}"${view.policy.providers === null || view.policy.providers.includes(one) ? " checked" : ""}> ${PROVIDER_NAMES[one]}</label>`).join("");
28
+ const levels = [...PERMISSION_LEVELS].reverse().map(level => `<label class="choice"><input type="radio" name="ceiling" value="${level}"${view.policy.ceiling === level ? " checked" : ""}>` +
29
+ `<span><strong>${LEVEL_NAMES[level]}</strong><small>${e(LEVEL_HINTS[level])}</small></span></label>`).join("");
30
+ const toolHint = view.toolNames.length === 0 ? "" : ` Tools here: ${view.toolNames.slice(0, 12).join(", ")}${view.toolNames.length > 12 ? "…" : ""}.`;
31
+ return `<section class="policy">${note}${changed}` +
32
+ `<form method="post" action="/settings/policy"><input type="hidden" name="csrf" value="${e(csrf)}">` +
33
+ `<fieldset><legend>Providers</legend><div class="providers">${providers}</div></fieldset>` +
34
+ `<fieldset><legend><label for="policy-models">Models</label></legend><textarea id="policy-models" name="models" spellcheck="false" placeholder="Any model" aria-describedby="policy-models-hint">${e((view.policy.models ?? []).join("\n"))}</textarea>` +
35
+ `<span class="hint" id="policy-models-hint">One per line; end with * to allow a family. Blank allows any.</span></fieldset>` +
36
+ `<fieldset><legend><label for="policy-tools">Project tools</label></legend><textarea id="policy-tools" name="tools" spellcheck="false" placeholder="Any tool" aria-describedby="policy-tools-hint">${e((view.policy.tools ?? []).join("\n"))}</textarea>` +
37
+ `<span class="hint" id="policy-tools-hint">One per line. Blank allows any.${e(toolHint)}</span></fieldset>` +
38
+ `<fieldset><legend>Permission ceiling</legend>${levels}</fieldset>` +
39
+ `<div class="step-up"><label>Your Toolroll password<input type="password" name="password" autocomplete="current-password" required></label></div>` +
40
+ `<button type="submit">Save policy</button></form>${history}</section>`;
41
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Organisation policy (sprint 8): one policy for the whole installation, set
3
+ * by an instance operator on Settings → Policy or with `toolroll policy
4
+ * set`. It says which providers and models may run, which project tools
5
+ * (MCP servers) agents may use, and the highest permission level any task,
6
+ * project or mode may run with.
7
+ *
8
+ * Nothing set means nothing restricted: no row is the open policy. The
9
+ * permission levels, lowest first:
10
+ * safe edits only: Claude accepts edits (acceptEdits), Gemini auto_edit;
11
+ * Codex and OpenRouter have no setting this low
12
+ * standard routine commands: Claude auto, Codex's workspace sandbox
13
+ * escalated full access: Claude bypassPermissions, Codex danger-full-access, Gemini yolo
14
+ * Work above the ceiling runs at the highest level beneath it its provider has
15
+ * (lowered), or, when there is none, doesn't run (refused); the words say which.
16
+ *
17
+ * Every road that admits work asks here: scope approval, the tick before a
18
+ * run starts (and build() as the last look), fallback entries, race lanes,
19
+ * attended sessions, the lead and project chats, teammates and flow steps.
20
+ */
21
+ import type { Database } from "./store.js";
22
+ import type { ExecutionProfile } from "./scope.js";
23
+ export type PermissionLevel = "safe" | "standard" | "escalated";
24
+ export declare const PERMISSION_LEVELS: readonly PermissionLevel[];
25
+ export declare const POLICY_PROVIDERS: readonly ["claude", "codex", "gemini", "openrouter"];
26
+ export type PolicyProvider = (typeof POLICY_PROVIDERS)[number];
27
+ /** The policy as saved: null lists allow everything of their kind. */
28
+ export type OrgPolicy = {
29
+ providers: PolicyProvider[] | null;
30
+ models: string[] | null;
31
+ tools: string[] | null;
32
+ ceiling: PermissionLevel;
33
+ };
34
+ export type SavedPolicy = OrgPolicy & {
35
+ updatedBy: string | null;
36
+ updatedAt: string | null;
37
+ };
38
+ export declare const OPEN_POLICY: OrgPolicy;
39
+ /** v105 keeps its version: the policy is a table of its own, made beside the spend tables. One row, or none. */
40
+ export declare const POLICY_SCHEMA = "\nCREATE TABLE IF NOT EXISTS org_policy (\n id INTEGER PRIMARY KEY CHECK (id = 1),\n providers_json TEXT,\n models_json TEXT,\n tools_json TEXT,\n ceiling TEXT NOT NULL DEFAULT 'escalated' CHECK (ceiling IN ('safe', 'standard', 'escalated')),\n updated_by TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\n";
41
+ /** The policy in force. A missing table (a database not yet opened by this build) reads as open. */
42
+ export declare function readPolicy(db: Database): SavedPolicy;
43
+ export declare const PROVIDER_NAMES: Record<PolicyProvider, string>;
44
+ export declare const LEVEL_NAMES: Record<PermissionLevel, string>;
45
+ export declare const LEVEL_HINTS: Record<PermissionLevel, string>;
46
+ /** Where a refusal sends people. */
47
+ export declare const WHERE = "An instance operator can change it in Settings \u2192 Policy.";
48
+ /** A provider id as the policy knows it: chat and key variants count as their provider. */
49
+ export declare function policyProvider(provider: string): PolicyProvider | null;
50
+ /** Each rule in words, for the page, the command and the ledger. */
51
+ export declare function policyParts(policy: OrgPolicy): {
52
+ providers: string;
53
+ models: string;
54
+ tools: string;
55
+ ceiling: string;
56
+ };
57
+ export declare function isOpen(policy: OrgPolicy): boolean;
58
+ /** Whether a model id matches an entry: the same id (any case), or a prefix ending in `*`. */
59
+ export declare function modelMatches(entry: string, model: string): boolean;
60
+ /** Why the policy stops an agent on this provider and model, or null. A default model ("default", or none) can't be
61
+ * checked against a model list, so a list stops it. */
62
+ export declare function agentRefusal(policy: OrgPolicy, provider: string, model: string | null): string | null;
63
+ /** Why the policy stops agents using a project tool, or null. */
64
+ export declare function toolRefusal(policy: OrgPolicy, tool: string): string | null;
65
+ export declare const levelAbove: (level: PermissionLevel, ceiling: PermissionLevel) => boolean;
66
+ /** The level a profile runs at. */
67
+ export declare function levelOfProfile(profile: ExecutionProfile): PermissionLevel;
68
+ /** A level's words for one provider: "Full access", "Auto", "Accept edits". */
69
+ export declare function levelWords(profile: ExecutionProfile): string;
70
+ export type CeilingVerdict = {
71
+ ok: true;
72
+ profile: ExecutionProfile;
73
+ lowered: null;
74
+ } | {
75
+ ok: true;
76
+ profile: ExecutionProfile;
77
+ lowered: string;
78
+ } | {
79
+ ok: false;
80
+ message: string;
81
+ };
82
+ /** Hold a profile to the ceiling: as it is, lowered (and the words say so), or refused (and the words say why). */
83
+ export declare function underCeiling(policy: OrgPolicy, profile: ExecutionProfile): CeilingVerdict;
84
+ /** Why the ceiling stops a planner, scout or native coding session on this provider, or null. They carry no sealed
85
+ * profile to lower: on Claude and Gemini they edit only (Safe); on Codex and OpenRouter they run in the workspace
86
+ * sandbox (Standard), those providers' lowest. */
87
+ export declare function sessionCeilingRefusal(policy: OrgPolicy, provider: string, what: string): string | null;
88
+ /** Everything the policy says about a profile before it runs: refused (words), or what runs and any lowering. */
89
+ export declare function profileVerdict(policy: OrgPolicy, profile: ExecutionProfile): CeilingVerdict;
90
+ /** An attended session runs at exactly what the person signed, so nothing is lowered: it runs as signed, or is refused. */
91
+ export declare function attendedRefusal(policy: OrgPolicy, profile: ExecutionProfile): string | null;
92
+ /** At approval, a person signs exact terms: anything above the ceiling is refused with words (a new filing is lowered). */
93
+ export declare function approvalRefusal(policy: OrgPolicy, profiles: readonly ExecutionProfile[], legs?: readonly {
94
+ provider: string;
95
+ model: string | null;
96
+ }[]): string | null;
97
+ /** Read a list typed by a person: commas or new lines, trimmed, no repeats; blank is "any". */
98
+ export declare function parseList(text: string | null | undefined): string[] | null;
99
+ /** Check a policy before it's saved. */
100
+ export declare function checkPolicy(input: {
101
+ providers: readonly string[] | null;
102
+ models: readonly string[] | null;
103
+ tools: readonly string[] | null;
104
+ ceiling: string;
105
+ }): {
106
+ ok: true;
107
+ policy: OrgPolicy;
108
+ } | {
109
+ ok: false;
110
+ problem: string;
111
+ };
package/dist/policy.js ADDED
@@ -0,0 +1,231 @@
1
+ export const PERMISSION_LEVELS = ["safe", "standard", "escalated"];
2
+ export const POLICY_PROVIDERS = ["claude", "codex", "gemini", "openrouter"];
3
+ export const OPEN_POLICY = { providers: null, models: null, tools: null, ceiling: "escalated" };
4
+ /** v105 keeps its version: the policy is a table of its own, made beside the spend tables. One row, or none. */
5
+ export const POLICY_SCHEMA = `
6
+ CREATE TABLE IF NOT EXISTS org_policy (
7
+ id INTEGER PRIMARY KEY CHECK (id = 1),
8
+ providers_json TEXT,
9
+ models_json TEXT,
10
+ tools_json TEXT,
11
+ ceiling TEXT NOT NULL DEFAULT 'escalated' CHECK (ceiling IN ('safe', 'standard', 'escalated')),
12
+ updated_by TEXT NOT NULL,
13
+ updated_at TEXT NOT NULL
14
+ );
15
+ `;
16
+ const listOf = (value) => {
17
+ if (value === null || value === undefined)
18
+ return null;
19
+ try {
20
+ const parsed = JSON.parse(String(value));
21
+ return Array.isArray(parsed) ? parsed.map(one => String(one)) : null;
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ };
27
+ /** The policy in force. A missing table (a database not yet opened by this build) reads as open. */
28
+ export function readPolicy(db) {
29
+ let row;
30
+ try {
31
+ row = db.prepare("SELECT * FROM org_policy WHERE id = 1").get();
32
+ }
33
+ catch {
34
+ row = undefined;
35
+ }
36
+ if (row === undefined)
37
+ return { ...OPEN_POLICY, updatedBy: null, updatedAt: null };
38
+ const ceiling = PERMISSION_LEVELS.includes(row["ceiling"]) ? row["ceiling"] : "escalated";
39
+ return {
40
+ providers: listOf(row["providers_json"])?.filter((one) => POLICY_PROVIDERS.includes(one)) ?? null,
41
+ models: listOf(row["models_json"]),
42
+ tools: listOf(row["tools_json"]),
43
+ ceiling,
44
+ updatedBy: row["updated_by"] == null ? null : String(row["updated_by"]),
45
+ updatedAt: row["updated_at"] == null ? null : String(row["updated_at"]),
46
+ };
47
+ }
48
+ // ---- words -------------------------------------------------------------------------------
49
+ export const PROVIDER_NAMES = { claude: "Claude", codex: "Codex", gemini: "Gemini", openrouter: "OpenRouter" };
50
+ export const LEVEL_NAMES = { safe: "Safe", standard: "Standard", escalated: "Escalated" };
51
+ export const LEVEL_HINTS = {
52
+ safe: "Edits in the project only. Codex and OpenRouter can't run this low.",
53
+ standard: "Edits and routine commands. Full access is lowered to this.",
54
+ escalated: "Anything a task, project or mode was approved for, full access included.",
55
+ };
56
+ /** Where a refusal sends people. */
57
+ export const WHERE = "An instance operator can change it in Settings → Policy.";
58
+ /** A provider id as the policy knows it: chat and key variants count as their provider. */
59
+ export function policyProvider(provider) {
60
+ const base = provider === "anthropic-api" ? "claude" : provider.replace(/-(subscription|api)$/, "");
61
+ return POLICY_PROVIDERS.includes(base) ? base : null;
62
+ }
63
+ const providerName = (provider) => {
64
+ const known = policyProvider(provider);
65
+ return known === null ? provider : PROVIDER_NAMES[known];
66
+ };
67
+ const listWords = (list, names = one => one) => list === null ? "any" : list.length === 0 ? "none" : list.map(names).join(", ");
68
+ /** Each rule in words, for the page, the command and the ledger. */
69
+ export function policyParts(policy) {
70
+ return {
71
+ providers: listWords(policy.providers, one => PROVIDER_NAMES[one] ?? one),
72
+ models: listWords(policy.models),
73
+ tools: listWords(policy.tools),
74
+ ceiling: LEVEL_NAMES[policy.ceiling],
75
+ };
76
+ }
77
+ export function isOpen(policy) {
78
+ return policy.providers === null && policy.models === null && policy.tools === null && policy.ceiling === "escalated";
79
+ }
80
+ // ---- providers, models and tools -----------------------------------------------------------
81
+ /** Whether a model id matches an entry: the same id (any case), or a prefix ending in `*`. */
82
+ export function modelMatches(entry, model) {
83
+ const want = entry.trim().toLowerCase(), have = model.trim().toLowerCase();
84
+ return want.endsWith("*") ? have.startsWith(want.slice(0, -1)) : want === have;
85
+ }
86
+ /** Why the policy stops an agent on this provider and model, or null. A default model ("default", or none) can't be
87
+ * checked against a model list, so a list stops it. */
88
+ export function agentRefusal(policy, provider, model) {
89
+ const family = policyProvider(provider);
90
+ if (policy.providers !== null && (family === null || !policy.providers.includes(family))) {
91
+ return `The organisation policy doesn't allow ${providerName(provider)}. ${WHERE}`;
92
+ }
93
+ if (policy.models !== null) {
94
+ if (model === null || model === "" || model === "default") {
95
+ return `The organisation policy allows only listed models, and this uses ${providerName(provider)}'s default model. Choose a listed model, or ${WHERE.charAt(0).toLowerCase()}${WHERE.slice(1)}`;
96
+ }
97
+ if (!policy.models.some(entry => modelMatches(entry, model)))
98
+ return `The organisation policy doesn't allow the model ${model}. ${WHERE}`;
99
+ }
100
+ return null;
101
+ }
102
+ /** Why the policy stops agents using a project tool, or null. */
103
+ export function toolRefusal(policy, tool) {
104
+ return policy.tools === null || policy.tools.includes(tool) ? null : `The organisation policy doesn't allow the tool ${tool}. ${WHERE}`;
105
+ }
106
+ // ---- the permission ceiling ------------------------------------------------------------------
107
+ const RANK = { safe: 0, standard: 1, escalated: 2 };
108
+ export const levelAbove = (level, ceiling) => RANK[level] > RANK[ceiling];
109
+ /** The level a profile runs at. */
110
+ export function levelOfProfile(profile) {
111
+ if (profile.provider === "claude")
112
+ return profile.permissionArgv === "bypassPermissions" ? "escalated" : profile.permissionArgv === "auto" ? "standard" : "safe";
113
+ if (profile.provider === "gemini")
114
+ return profile.approvalArgv === "yolo" ? "escalated" : "safe";
115
+ return profile.sandboxMode === "danger-full-access" ? "escalated" : "standard";
116
+ }
117
+ /** The same profile at a level, or null when its provider has no setting that low. */
118
+ function profileAt(profile, level) {
119
+ if (profile.provider === "claude")
120
+ return { ...profile, permissionArgv: level === "escalated" ? "bypassPermissions" : level === "standard" ? "auto" : "acceptEdits" };
121
+ if (profile.provider === "gemini")
122
+ return { ...profile, approvalArgv: level === "escalated" ? "yolo" : "auto_edit" };
123
+ return level === "safe" ? null : { ...profile, sandboxMode: level === "escalated" ? "danger-full-access" : "workspace-write" };
124
+ }
125
+ /** A level's words for one provider: "Full access", "Auto", "Accept edits". */
126
+ export function levelWords(profile) {
127
+ if (profile.provider === "claude")
128
+ return profile.permissionArgv === "bypassPermissions" ? "full access" : profile.permissionArgv === "auto" ? "auto" : "accept edits";
129
+ if (profile.provider === "gemini")
130
+ return profile.approvalArgv === "yolo" ? "full access" : "auto edit";
131
+ return profile.sandboxMode === "danger-full-access" ? "full access" : "the workspace sandbox";
132
+ }
133
+ /** Hold a profile to the ceiling: as it is, lowered (and the words say so), or refused (and the words say why). */
134
+ export function underCeiling(policy, profile) {
135
+ const level = levelOfProfile(profile);
136
+ if (!levelAbove(level, policy.ceiling))
137
+ return { ok: true, profile, lowered: null };
138
+ const ceiling = LEVEL_NAMES[policy.ceiling];
139
+ for (const below of [...PERMISSION_LEVELS].reverse()) {
140
+ if (levelAbove(below, policy.ceiling) || !levelAbove(level, below))
141
+ continue;
142
+ const lower = profileAt(profile, below);
143
+ if (lower === null)
144
+ continue;
145
+ return { ok: true, profile: lower, lowered: `The organisation policy's permission ceiling is ${ceiling}, so this runs with ${levelWords(lower)} instead of ${levelWords(profile)}.` };
146
+ }
147
+ return { ok: false, message: `The organisation policy's permission ceiling is ${ceiling}, and ${providerName(profile.provider)} can't run that low. ${WHERE}` };
148
+ }
149
+ /** Why the ceiling stops a planner, scout or native coding session on this provider, or null. They carry no sealed
150
+ * profile to lower: on Claude and Gemini they edit only (Safe); on Codex and OpenRouter they run in the workspace
151
+ * sandbox (Standard), those providers' lowest. */
152
+ export function sessionCeilingRefusal(policy, provider, what) {
153
+ const known = policyProvider(provider);
154
+ const level = known === "claude" || known === "gemini" ? "safe" : "standard";
155
+ if (!levelAbove(level, policy.ceiling))
156
+ return null;
157
+ return `The organisation policy's permission ceiling is ${LEVEL_NAMES[policy.ceiling]}, and ${providerName(provider)} ${what} can't run that low. ${WHERE}`;
158
+ }
159
+ /** Everything the policy says about a profile before it runs: refused (words), or what runs and any lowering. */
160
+ export function profileVerdict(policy, profile) {
161
+ const agent = agentRefusal(policy, profile.provider, profile.model);
162
+ if (agent !== null)
163
+ return { ok: false, message: agent };
164
+ const repair = profile.repairModel === "inherit" || profile.repairModel === profile.model ? null : agentRefusal(policy, profile.provider, profile.repairModel);
165
+ if (repair !== null)
166
+ return { ok: false, message: `Its repairs: ${repair.charAt(0).toLowerCase()}${repair.slice(1)}` };
167
+ return underCeiling(policy, profile);
168
+ }
169
+ /** An attended session runs at exactly what the person signed, so nothing is lowered: it runs as signed, or is refused. */
170
+ export function attendedRefusal(policy, profile) {
171
+ const verdict = profileVerdict(policy, profile);
172
+ if (!verdict.ok)
173
+ return verdict.message;
174
+ return verdict.lowered === null ? null
175
+ : `This session asks for ${levelWords(profile)}, above the organisation policy's permission ceiling (${LEVEL_NAMES[policy.ceiling]}). Authorise it again with a lower permission, or ${WHERE.charAt(0).toLowerCase()}${WHERE.slice(1)}`;
176
+ }
177
+ /** At approval, a person signs exact terms: anything above the ceiling is refused with words (a new filing is lowered). */
178
+ export function approvalRefusal(policy, profiles, legs = []) {
179
+ for (const profile of profiles) {
180
+ const verdict = profileVerdict(policy, profile);
181
+ if (!verdict.ok)
182
+ return verdict.message;
183
+ if (verdict.lowered !== null) {
184
+ return `This asks for ${levelWords(profile)}, above the organisation policy's permission ceiling (${LEVEL_NAMES[policy.ceiling]}). File it again to run it within the ceiling, or ${WHERE.charAt(0).toLowerCase()}${WHERE.slice(1)}`;
185
+ }
186
+ }
187
+ for (const leg of legs) {
188
+ const refused = agentRefusal(policy, leg.provider, leg.model);
189
+ if (refused !== null)
190
+ return refused;
191
+ }
192
+ return null;
193
+ }
194
+ // ---- changes ---------------------------------------------------------------------------------
195
+ /** Read a list typed by a person: commas or new lines, trimmed, no repeats; blank is "any". */
196
+ export function parseList(text) {
197
+ const items = [...new Set(String(text ?? "").split(/[,\n]/).map(one => one.trim()).filter(one => one !== ""))];
198
+ return items.length === 0 ? null : items;
199
+ }
200
+ /** Check a policy before it's saved. */
201
+ export function checkPolicy(input) {
202
+ if (!PERMISSION_LEVELS.includes(input.ceiling))
203
+ return { ok: false, problem: "Choose a permission ceiling: safe, standard or escalated." };
204
+ let providers = null;
205
+ if (input.providers !== null) {
206
+ const unknown = input.providers.filter(one => policyProvider(one.toLowerCase()) === null);
207
+ if (unknown.length > 0)
208
+ return { ok: false, problem: `${unknown.join(", ")} isn't a provider here. Choose from Claude, Codex, Gemini and OpenRouter.` };
209
+ providers = POLICY_PROVIDERS.filter(one => input.providers.some(given => policyProvider(given.toLowerCase()) === one));
210
+ if (providers.length === 0)
211
+ return { ok: false, problem: "Allow at least one provider, or allow any." };
212
+ }
213
+ const clean = (list, what, limit) => {
214
+ if (list === null)
215
+ return null;
216
+ const items = [...new Set(list.map(one => one.trim()).filter(one => one !== ""))];
217
+ if (items.length > limit)
218
+ return { problem: `List at most ${limit} ${what}.` };
219
+ const bad = items.find(one => one.length > 120 || !/^[A-Za-z0-9._:/@~*+-]+$/.test(one));
220
+ if (bad !== undefined)
221
+ return { problem: `${bad.slice(0, 40)} isn't a ${what.replace(/s$/, "")} name. Use letters, numbers and . _ - : / @ ~ * only.` };
222
+ return items.length === 0 ? null : items;
223
+ };
224
+ const models = clean(input.models, "models", 100);
225
+ if (models !== null && !Array.isArray(models))
226
+ return { ok: false, problem: models.problem };
227
+ const tools = clean(input.tools, "tools", 100);
228
+ if (tools !== null && !Array.isArray(tools))
229
+ return { ok: false, problem: tools.problem };
230
+ return { ok: true, policy: { providers, models, tools, ceiling: input.ceiling } };
231
+ }
@@ -0,0 +1,16 @@
1
+ import { type ParsedProof } from './proof.js';
2
+ export declare const PREPARED_EVIDENCE_FILE = "standing-orders.evidence.json";
3
+ export declare const PREPARED_EVIDENCE_GIT: readonly ['--literal-pathspecs', '--no-lazy-fetch', '--no-replace-objects', '--no-optional-locks'];
4
+ export type PreparedEvidence = {
5
+ proof: ParsedProof;
6
+ files: {
7
+ path: string;
8
+ sha256: string;
9
+ cap: number;
10
+ }[];
11
+ };
12
+ /** Reads immutable Git objects; local/untracked files cannot fill a missing entry. */
13
+ export declare function readPreparedEvidence(repo: string, candidate: string, required?: boolean): PreparedEvidence | null;
14
+ export declare function preparedScreenshotMatches(inventory: PreparedEvidence, path: string, bytes: Buffer): boolean;
15
+ /** After checkout/setup, read without following links and mint this worker's receipt. */
16
+ export declare function writePreparedEvidence(worktree: string, nonceFile: string, inventory: PreparedEvidence): void;
@@ -0,0 +1,96 @@
1
+ /** Committed image inventory, never claimed checks, completion, or approval. */
2
+ import { execFileSync } from 'node:child_process';
3
+ import { createHash } from 'node:crypto';
4
+ import { lstatSync, writeFileSync } from 'node:fs';
5
+ import { join } from 'node:path';
6
+ import { imageDimensions, looksLikeProtocolFile, readMailbox, SCREENSHOT_BYTE_CAP, validateScreenshotBytes } from './evidence.js';
7
+ import { parseProof, PROOF_LIMITS, SCREENSHOT_EVIDENCE_MIN_BYTES, SCREENSHOT_EVIDENCE_MIN_HEIGHT, SCREENSHOT_EVIDENCE_MIN_WIDTH, serializeProof } from './proof.js';
8
+ export const PREPARED_EVIDENCE_FILE = 'standing-orders.evidence.json';
9
+ export const PREPARED_EVIDENCE_GIT = ['--literal-pathspecs', '--no-lazy-fetch', '--no-replace-objects', '--no-optional-locks'];
10
+ const nextAction = 'Ask Codex to prepare review screenshots and commit them with standing-orders.evidence.json, then review the new result.';
11
+ const fail = (detail) => { throw Error(`Review screenshots are not ready. ${nextAction} ${detail}`); };
12
+ const digest = (bytes) => createHash('sha256').update(bytes).digest('hex');
13
+ /** Reads immutable Git objects; local/untracked files cannot fill a missing entry. */
14
+ export function readPreparedEvidence(repo, candidate, required = false) {
15
+ if (!/^[a-f0-9]{40}$/.test(candidate))
16
+ fail('The saved commit is invalid.');
17
+ const git = (args, cap) => {
18
+ try {
19
+ return execFileSync('git', [...PREPARED_EVIDENCE_GIT, '-C', repo, ...args], { stdio: ['ignore', 'pipe', 'pipe'], timeout: 10_000, maxBuffer: cap });
20
+ }
21
+ catch {
22
+ return fail('The committed screenshot inventory could not be read.');
23
+ }
24
+ };
25
+ const blob = (path, cap) => {
26
+ const entries = git(['ls-tree', '-z', '-l', candidate, '--', path], 2048).toString('utf8').split('\0').filter(Boolean);
27
+ if (!entries.length)
28
+ return null;
29
+ const match = /^(100644|100755) blob ([a-f0-9]{40}) +([0-9]+)\t([\s\S]+)$/.exec(entries[0]);
30
+ if (entries.length !== 1 || !match || match[4] !== path)
31
+ fail(`${path} must be a committed regular file.`);
32
+ const size = Number(match[3]);
33
+ if (!Number.isSafeInteger(size) || size > cap)
34
+ fail(`${path} exceeds the supported evidence size.`);
35
+ const bytes = git(['cat-file', 'blob', match[2]], cap);
36
+ if (bytes.length !== size || createHash('sha1').update(`blob ${bytes.length}\0`).update(bytes).digest('hex') !== match[2])
37
+ fail(`${path} could not be read completely or its Git identity changed.`);
38
+ return bytes;
39
+ };
40
+ const raw = blob(PREPARED_EVIDENCE_FILE, PROOF_LIMITS.payload);
41
+ if (raw === null) {
42
+ if (required)
43
+ fail('No committed screenshot inventory was found.');
44
+ return null;
45
+ }
46
+ let body;
47
+ try {
48
+ body = JSON.parse(raw.toString('utf8'));
49
+ }
50
+ catch {
51
+ return fail('The screenshot inventory must be valid JSON.');
52
+ }
53
+ if (!body || typeof body !== 'object' || Array.isArray(body) || Object.keys(body).some(key => !['version', 'screenshots'].includes(key)) ||
54
+ !Array.isArray(body['screenshots']) || body['screenshots'].some(shot => !shot || typeof shot !== 'object' || Array.isArray(shot) || Object.keys(shot).some(key => !['path', 'caption'].includes(key)))) {
55
+ fail('The inventory may contain only version 1 and screenshots with path and caption.');
56
+ }
57
+ const parsed = parseProof(raw.toString('utf8'));
58
+ if (!parsed.ok)
59
+ return fail(parsed.problems.map(problem => problem.message).join('; '));
60
+ if (required && parsed.proof.screenshots.length === 0)
61
+ fail('The committed inventory has no screenshots.');
62
+ const files = [{ path: PREPARED_EVIDENCE_FILE, sha256: digest(raw), cap: PROOF_LIMITS.payload }];
63
+ for (const shot of parsed.proof.screenshots) {
64
+ if (shot.path.split('/').some(part => /^\.git$/i.test(part) || looksLikeProtocolFile(part)))
65
+ fail('A screenshot cannot name Git metadata or a prior attempt’s protocol file.');
66
+ const bytes = blob(shot.path, SCREENSHOT_BYTE_CAP);
67
+ if (bytes === null)
68
+ fail(`${shot.path} is not committed in this result.`);
69
+ const image = validateScreenshotBytes(bytes);
70
+ if (!image.ok)
71
+ return fail(`${shot.path}: ${image.problem}`);
72
+ const dims = imageDimensions(bytes, image.kind);
73
+ if (bytes.length < SCREENSHOT_EVIDENCE_MIN_BYTES || !dims || dims.width < SCREENSHOT_EVIDENCE_MIN_WIDTH || dims.height < SCREENSHOT_EVIDENCE_MIN_HEIGHT)
74
+ fail(`${shot.path} needs a readable screenshot of at least ${SCREENSHOT_EVIDENCE_MIN_BYTES} bytes and ${SCREENSHOT_EVIDENCE_MIN_WIDTH}×${SCREENSHOT_EVIDENCE_MIN_HEIGHT} pixels.`);
75
+ files.push({ path: shot.path, sha256: digest(bytes), cap: SCREENSHOT_BYTE_CAP });
76
+ }
77
+ return { proof: parsed.proof, files };
78
+ }
79
+ export function preparedScreenshotMatches(inventory, path, bytes) {
80
+ return inventory.files.some(file => file.path === path && file.sha256 === digest(bytes));
81
+ }
82
+ /** After checkout/setup, read without following links and mint this worker's receipt. */
83
+ export function writePreparedEvidence(worktree, nonceFile, inventory) {
84
+ for (const file of inventory.files) {
85
+ const parts = file.path.split('/');
86
+ for (let count = 1; count < parts.length; count++) {
87
+ const parent = lstatSync(join(worktree, ...parts.slice(0, count)));
88
+ if (!parent.isDirectory() || parent.isSymbolicLink())
89
+ fail(`${file.path} has a linked or missing parent directory.`);
90
+ }
91
+ const read = readMailbox(join(worktree, file.path), file.cap);
92
+ if (!read.ok || !preparedScreenshotMatches(inventory, file.path, read.raw))
93
+ fail(`${file.path} no longer matches the saved commit.`);
94
+ }
95
+ writeFileSync(join(worktree, nonceFile), serializeProof(inventory.proof), { flag: 'wx', mode: 0o600 });
96
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Pinned build-model prices (tournament design v3, stage 1; the round-3
3
+ * findings are the spec). Integer micro-dollars per SINGLE token, rounded
4
+ * UP from list prices, with the cache token classes priced separately —
5
+ * finding 24: a "one call" tail computed from rates alone bounds nothing;
6
+ * quantity must be pinned too, so every model row carries its context
7
+ * window and maximum output, and the tail is the worst legal call:
8
+ * every context token at the DEAREST input class plus every output token.
9
+ *
10
+ * Conservative by construction: reservations overcharge, never under.
11
+ * PRICE_VERSION is stamped into approved tournament terms — a price table
12
+ * edit never silently reprices an existing approval.
13
+ */
14
+ export declare const BUILD_PRICE_VERSION = 1;
15
+ export type BuildModelPrice = {
16
+ /** Micro-dollars per token, ceil'd from list. */
17
+ inMicrousd: number;
18
+ outMicrousd: number;
19
+ cacheWriteMicrousd: number;
20
+ cacheReadMicrousd: number;
21
+ /** The pinned request envelope's quantity bounds (finding 24). */
22
+ contextTokens: number;
23
+ maxOutputTokens: number;
24
+ };
25
+ export declare function buildPriceOf(model: string): BuildModelPrice | null;
26
+ export declare const PRICED_BUILD_MODELS: readonly string[];
27
+ /**
28
+ * The non-spendable overrun reserve: the worst one API call the pinned
29
+ * envelope permits. Claude's native cap checks the budget AFTER each
30
+ * call, so the true maximum is budget + one full call — this is that
31
+ * call, priced at the dearest input class (finding 24's arithmetic).
32
+ * Held apart from the spendable budget and NEVER granted to a later
33
+ * invocation: each lineage invocation's native cap derives from
34
+ * max(spendable − accounted, 0) alone.
35
+ */
36
+ export declare function oneCallTailMicrousd(model: string): number | null;
37
+ /** Settlement at pinned rates from a usage report that itemizes cache
38
+ * classes; absent classes count as zero, absent totals fail closed by
39
+ * returning null (the caller latches unknown spend, never guesses). */
40
+ export declare function settleBuildMicrousd(model: string, usage: {
41
+ inputTokens?: number;
42
+ outputTokens?: number;
43
+ cacheWriteTokens?: number;
44
+ cacheReadTokens?: number;
45
+ }): number | null;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Pinned build-model prices (tournament design v3, stage 1; the round-3
3
+ * findings are the spec). Integer micro-dollars per SINGLE token, rounded
4
+ * UP from list prices, with the cache token classes priced separately —
5
+ * finding 24: a "one call" tail computed from rates alone bounds nothing;
6
+ * quantity must be pinned too, so every model row carries its context
7
+ * window and maximum output, and the tail is the worst legal call:
8
+ * every context token at the DEAREST input class plus every output token.
9
+ *
10
+ * Conservative by construction: reservations overcharge, never under.
11
+ * PRICE_VERSION is stamped into approved tournament terms — a price table
12
+ * edit never silently reprices an existing approval.
13
+ */
14
+ export const BUILD_PRICE_VERSION = 1;
15
+ const PRICES = {
16
+ "claude-sonnet-5": {
17
+ inMicrousd: 3,
18
+ outMicrousd: 15,
19
+ cacheWriteMicrousd: 4, // 1.25x input, ceil'd
20
+ cacheReadMicrousd: 1, // 0.1x input, ceil'd up
21
+ contextTokens: 200_000,
22
+ maxOutputTokens: 64_000,
23
+ },
24
+ "claude-opus-5": {
25
+ inMicrousd: 15,
26
+ outMicrousd: 75,
27
+ cacheWriteMicrousd: 19,
28
+ cacheReadMicrousd: 2,
29
+ contextTokens: 200_000,
30
+ maxOutputTokens: 32_000,
31
+ },
32
+ "claude-haiku-4-5": {
33
+ inMicrousd: 1,
34
+ outMicrousd: 5,
35
+ cacheWriteMicrousd: 2,
36
+ cacheReadMicrousd: 1,
37
+ contextTokens: 200_000,
38
+ maxOutputTokens: 64_000,
39
+ },
40
+ };
41
+ export function buildPriceOf(model) {
42
+ return PRICES[model] ?? null;
43
+ }
44
+ export const PRICED_BUILD_MODELS = Object.keys(PRICES);
45
+ /**
46
+ * The non-spendable overrun reserve: the worst one API call the pinned
47
+ * envelope permits. Claude's native cap checks the budget AFTER each
48
+ * call, so the true maximum is budget + one full call — this is that
49
+ * call, priced at the dearest input class (finding 24's arithmetic).
50
+ * Held apart from the spendable budget and NEVER granted to a later
51
+ * invocation: each lineage invocation's native cap derives from
52
+ * max(spendable − accounted, 0) alone.
53
+ */
54
+ export function oneCallTailMicrousd(model) {
55
+ const price = buildPriceOf(model);
56
+ if (price === null)
57
+ return null;
58
+ const dearestInput = Math.max(price.inMicrousd, price.cacheWriteMicrousd, price.cacheReadMicrousd);
59
+ return price.contextTokens * dearestInput + price.maxOutputTokens * price.outMicrousd;
60
+ }
61
+ /** Settlement at pinned rates from a usage report that itemizes cache
62
+ * classes; absent classes count as zero, absent totals fail closed by
63
+ * returning null (the caller latches unknown spend, never guesses). */
64
+ export function settleBuildMicrousd(model, usage) {
65
+ const price = buildPriceOf(model);
66
+ if (price === null)
67
+ return null;
68
+ const { inputTokens, outputTokens } = usage;
69
+ if (inputTokens === undefined || outputTokens === undefined)
70
+ return null;
71
+ if (!Number.isFinite(inputTokens) || !Number.isFinite(outputTokens) || inputTokens < 0 || outputTokens < 0)
72
+ return null;
73
+ return (inputTokens * price.inMicrousd +
74
+ outputTokens * price.outMicrousd +
75
+ (usage.cacheWriteTokens ?? 0) * price.cacheWriteMicrousd +
76
+ (usage.cacheReadTokens ?? 0) * price.cacheReadMicrousd);
77
+ }