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,37 @@
1
+ /** Presentation only: no fields are read, no requests are sent, and no
2
+ * keyboard events are captured. A focused input alone is NOT a keyboard. */
3
+ export const MOBILE_VIEWPORT_SCRIPT = String.raw `
4
+ (function(){
5
+ var root=document.documentElement,viewport=window.visualViewport;
6
+ if(!viewport)return;
7
+ var phone=window.matchMedia('(max-width: 760px)'),baseline=window.innerHeight,frame=0;
8
+ function update(){
9
+ frame=0;
10
+ var active=document.activeElement;
11
+ var editing=active&&active.matches('textarea,input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]),[contenteditable=true]');
12
+ if(!editing)baseline=window.innerHeight;
13
+ var gap=Math.max(0,window.innerHeight-viewport.height-viewport.offsetTop);
14
+ var open=phone.matches&&viewport.scale===1&&editing&&(gap>120||baseline-viewport.height>120);
15
+ // A reader at the end of a thread stays there when the keyboard rises:
16
+ // the page grows room beneath the raised composer, so the newest
17
+ // message must follow it up instead of hiding behind it.
18
+ var opening=open&&!root.hasAttribute('data-mobile-keyboard');
19
+ var atEnd=opening&&window.innerHeight+window.scrollY>=root.scrollHeight-120;
20
+ root.toggleAttribute('data-mobile-keyboard',Boolean(open));
21
+ root.style.setProperty('--keyboard-inset',open?Math.round(gap)+'px':'0px');
22
+ if(atEnd)window.scrollTo({top:root.scrollHeight,behavior:'instant'});
23
+ }
24
+ function schedule(){if(!frame)frame=requestAnimationFrame(update);}
25
+ viewport.addEventListener('resize',schedule);
26
+ viewport.addEventListener('scroll',schedule);
27
+ window.addEventListener('resize',schedule);
28
+ window.addEventListener('pageshow',schedule);
29
+ window.addEventListener('orientationchange',function(){baseline=window.innerHeight;schedule();});
30
+ document.addEventListener('focusin',schedule);
31
+ document.addEventListener('focusout',schedule);
32
+ var composer=document.querySelector('.composer');
33
+ if(composer&&window.ResizeObserver){
34
+ new ResizeObserver(function(){root.style.setProperty('--composer-height',Math.ceil(composer.getBoundingClientRect().height)+'px');}).observe(composer);
35
+ }
36
+ update();
37
+ })();`;
@@ -0,0 +1,118 @@
1
+ import type { Store } from "./store.js";
2
+ import { type OpenRouterModel } from "./openrouter-models.js";
3
+ import { type ProviderId } from "./provider.js";
4
+ export declare const MODELS_SCHEMA = "\nCREATE TABLE IF NOT EXISTS model_seen (\n source TEXT NOT NULL CHECK (source IN ('claude','codex','gemini','openrouter')),\n id TEXT NOT NULL,\n name TEXT NOT NULL,\n input_usd REAL,\n output_usd REAL,\n context INTEGER,\n tools INTEGER NOT NULL DEFAULT 0,\n released_at TEXT,\n first_seen_at TEXT NOT NULL,\n last_seen_at TEXT NOT NULL,\n PRIMARY KEY (source, id)\n);\nCREATE TABLE IF NOT EXISTS runtime_check (\n tool TEXT PRIMARY KEY CHECK (tool IN ('claude','codex','gemini')),\n installed TEXT,\n latest TEXT,\n update_command TEXT,\n problem TEXT,\n checked_at TEXT NOT NULL,\n updated_at TEXT,\n updated_by TEXT\n);\nCREATE TABLE IF NOT EXISTS model_watch (\n id INTEGER PRIMARY KEY CHECK (id = 1),\n enabled INTEGER NOT NULL DEFAULT 0,\n checked_at TEXT,\n problem TEXT,\n changed_by TEXT,\n changed_at TEXT\n);";
5
+ export type ModelSource = "claude" | "codex" | "gemini" | "openrouter";
6
+ export type SeenModel = {
7
+ source: ModelSource;
8
+ id: string;
9
+ name: string;
10
+ inputUsd: number | null;
11
+ outputUsd: number | null;
12
+ context: number | null;
13
+ tools: boolean;
14
+ releasedAt: string | null;
15
+ firstSeenAt: string;
16
+ };
17
+ export type RuntimeTool = "claude" | "codex" | "gemini";
18
+ export type RuntimeState = {
19
+ tool: RuntimeTool;
20
+ name: string;
21
+ installed: string | null;
22
+ latest: string | null;
23
+ updateCommand: string[] | null;
24
+ problem: string | null;
25
+ checkedAt: string;
26
+ updatedAt: string | null;
27
+ updatedBy: string | null;
28
+ behind: boolean;
29
+ };
30
+ export type VersionRunner = (command: string, args: string[], options: {
31
+ timeoutMs: number;
32
+ env?: NodeJS.ProcessEnv;
33
+ }) => Promise<{
34
+ code: number;
35
+ stdout: string;
36
+ stderr: string;
37
+ }>;
38
+ export type CatalogSeams = {
39
+ fetcher?: typeof fetch;
40
+ runner?: VersionRunner;
41
+ home?: string;
42
+ path?: string;
43
+ };
44
+ export declare const RUNTIME_TOOLS: Record<RuntimeTool, {
45
+ name: string;
46
+ command: string;
47
+ pkg: string;
48
+ }>;
49
+ export declare const WATCH_EVERY_MS: number;
50
+ /** `anthropic/claude-opus-5.5` → `claude-opus-5-5`, the name the Claude CLI and API use. */
51
+ export declare function claudeIdOf(openrouterId: string): string | null;
52
+ /** The Codex CLI's own list — account-specific, maintained by the CLI. */
53
+ export declare function codexCatalog(home?: string): {
54
+ id: string;
55
+ name: string;
56
+ }[];
57
+ type Row = Omit<SeenModel, "firstSeenAt">;
58
+ /** Pure: the catalog rows each source should hold after a fetch. */
59
+ export declare function catalogRows(openrouter: OpenRouterModel[], codex: {
60
+ id: string;
61
+ name: string;
62
+ }[]): Row[];
63
+ /** Upsert a fetch. Returns models first seen now, except on a source's first
64
+ * fetch (the baseline would otherwise announce every model at once). */
65
+ export declare function recordCatalog(store: Store, rows: Row[], now: Date): SeenModel[];
66
+ export declare function seenModels(store: Store, source: ModelSource, options?: {
67
+ current?: boolean;
68
+ }): SeenModel[];
69
+ export declare function seenModel(store: Store, source: ModelSource, id: string): SeenModel | null;
70
+ export declare function isNewModel(model: SeenModel, now: Date): boolean;
71
+ /** What the Claude CLI's short name currently runs: the newest of its family. */
72
+ export declare function aliasTarget(store: Store, alias: string): SeenModel | null;
73
+ export declare function dollars(amount: number | null): string;
74
+ export declare function priceWords(model: SeenModel): string;
75
+ /** The friendly name for a saved provider + model, e.g. "opus" → "Claude Opus 5.5". */
76
+ export declare function modelWords(store: Store, provider: string, model: string | null): string;
77
+ export type ModelOption = {
78
+ value: string;
79
+ label: string;
80
+ isNew: boolean;
81
+ };
82
+ /** Every model a provider can run, newest first, with prices. */
83
+ export declare function modelOptions(store: Store, provider: ProviderId, now: Date, home?: string): ModelOption[];
84
+ /** Chat reserves worst-case spend: price per token in whole micro-dollars,
85
+ * rounded UP from the live list price. null = no live price. */
86
+ export declare function livePin(store: Store, chatProvider: string, model: string): {
87
+ inMicrousd: number;
88
+ outMicrousd: number;
89
+ } | null;
90
+ export declare function compareVersions(a: string, b: string): number;
91
+ /** How this copy was installed decides the one safe update command. */
92
+ export declare function updateCommandFor(tool: RuntimeTool, resolved: string): string[] | null;
93
+ export declare function runtimeStates(store: Store): RuntimeState[];
94
+ export declare function checkRuntimes(store: Store, now: Date, seams?: CatalogSeams): Promise<RuntimeState[]>;
95
+ /** Update one CLI, only while nothing is running, then read its version again. */
96
+ export declare function updateRuntime(store: Store, tool: RuntimeTool, by: string, now: Date, seams?: CatalogSeams): Promise<{
97
+ ok: boolean;
98
+ message: string;
99
+ }>;
100
+ export type WatchState = {
101
+ enabled: boolean;
102
+ checkedAt: string | null;
103
+ problem: string | null;
104
+ changedBy: string | null;
105
+ };
106
+ export declare function watchState(store: Store): WatchState;
107
+ export declare function setWatch(store: Store, enabled: boolean, by: string, now: Date): void;
108
+ /** One full check: the catalog, the CLIs, and a notice for each new model or
109
+ * newly available update. Idempotent per model and per released version. */
110
+ export declare function checkModels(store: Store, now: Date, seams?: CatalogSeams): Promise<{
111
+ ok: boolean;
112
+ added: SeenModel[];
113
+ runtimes: RuntimeState[];
114
+ problem: string | null;
115
+ }>;
116
+ /** The background pass: runs only when the person turned checks on. */
117
+ export declare function modelWatchPass(store: Store, now: Date, seams?: CatalogSeams): Promise<boolean>;
118
+ export {};
@@ -0,0 +1,376 @@
1
+ /**
2
+ * The live model and tool catalog. OpenRouter's public list (no key, nothing
3
+ * about the person sent) names what Anthropic, OpenAI and Google currently
4
+ * ship and what each costs; the Codex CLI's own cache names what this
5
+ * account may run; `--version` and the npm registry say whether the
6
+ * installed CLIs are current. Everything lands in orders.db so pickers,
7
+ * spend pins and "new model" notices read one saved snapshot.
8
+ */
9
+ import { execFile } from "node:child_process";
10
+ import { accessSync, constants, lstatSync, readFileSync, realpathSync } from "node:fs";
11
+ import { homedir } from "node:os";
12
+ import { delimiter, join } from "node:path";
13
+ import { fetchOpenRouterModels } from "./openrouter-models.js";
14
+ import { readCappedBody } from "./converse.js";
15
+ import { validModelId } from "./provider.js";
16
+ import { activeUpdateWork } from "./desktop-update-gate.js";
17
+ export const MODELS_SCHEMA = `
18
+ CREATE TABLE IF NOT EXISTS model_seen (
19
+ source TEXT NOT NULL CHECK (source IN ('claude','codex','gemini','openrouter')),
20
+ id TEXT NOT NULL,
21
+ name TEXT NOT NULL,
22
+ input_usd REAL,
23
+ output_usd REAL,
24
+ context INTEGER,
25
+ tools INTEGER NOT NULL DEFAULT 0,
26
+ released_at TEXT,
27
+ first_seen_at TEXT NOT NULL,
28
+ last_seen_at TEXT NOT NULL,
29
+ PRIMARY KEY (source, id)
30
+ );
31
+ CREATE TABLE IF NOT EXISTS runtime_check (
32
+ tool TEXT PRIMARY KEY CHECK (tool IN ('claude','codex','gemini')),
33
+ installed TEXT,
34
+ latest TEXT,
35
+ update_command TEXT,
36
+ problem TEXT,
37
+ checked_at TEXT NOT NULL,
38
+ updated_at TEXT,
39
+ updated_by TEXT
40
+ );
41
+ CREATE TABLE IF NOT EXISTS model_watch (
42
+ id INTEGER PRIMARY KEY CHECK (id = 1),
43
+ enabled INTEGER NOT NULL DEFAULT 0,
44
+ checked_at TEXT,
45
+ problem TEXT,
46
+ changed_by TEXT,
47
+ changed_at TEXT
48
+ );`;
49
+ export const RUNTIME_TOOLS = {
50
+ claude: { name: "Claude Code", command: "claude", pkg: "@anthropic-ai/claude-code" },
51
+ codex: { name: "Codex", command: "codex", pkg: "@openai/codex" },
52
+ gemini: { name: "Gemini CLI", command: "gemini", pkg: "@google/gemini-cli" },
53
+ };
54
+ export const WATCH_EVERY_MS = 6 * 3_600_000;
55
+ /** A model counts as new for two weeks after its release. */
56
+ const NEW_FOR_MS = 14 * 86_400_000;
57
+ const FAMILIES = ["opus", "sonnet", "haiku", "fable"];
58
+ const ALIAS_WORDS = { opus: "complex tasks", sonnet: "everyday coding", haiku: "smaller tasks" };
59
+ const title = (word) => word.charAt(0).toUpperCase() + word.slice(1);
60
+ const stripVendor = (name) => name.replace(/^(Anthropic|OpenAI|Google): /, "");
61
+ /** `anthropic/claude-opus-5.5` → `claude-opus-5-5`, the name the Claude CLI and API use. */
62
+ export function claudeIdOf(openrouterId) {
63
+ const hit = /^anthropic\/(claude-(?:opus|sonnet|haiku|fable)-[0-9][0-9.]*)$/.exec(openrouterId);
64
+ return hit === null ? null : hit[1].replaceAll(".", "-");
65
+ }
66
+ function geminiIdOf(openrouterId) {
67
+ const hit = /^google\/(gemini-[0-9][0-9a-z.-]*)$/.exec(openrouterId);
68
+ return hit === null || /image|tts|audio|embed/.test(hit[1]) ? null : hit[1];
69
+ }
70
+ /** The Codex CLI's own list — account-specific, maintained by the CLI. */
71
+ export function codexCatalog(home = homedir()) {
72
+ try {
73
+ const path = join(home, ".codex", "models_cache.json");
74
+ if (lstatSync(path).size >= 2_000_000)
75
+ return [];
76
+ const data = JSON.parse(readFileSync(path, "utf8"));
77
+ return (Array.isArray(data.models) ? data.models : [])
78
+ .filter(one => one != null && one.visibility === "list" && typeof one.slug === "string" && validModelId(one.slug))
79
+ .slice(0, 30).map(one => ({ id: one.slug, name: typeof one.display_name === "string" ? one.display_name.slice(0, 80) : one.slug }));
80
+ }
81
+ catch {
82
+ return [];
83
+ }
84
+ }
85
+ /** Pure: the catalog rows each source should hold after a fetch. */
86
+ export function catalogRows(openrouter, codex) {
87
+ const released = (model) => model.created === null ? null : new Date(model.created * 1000).toISOString();
88
+ const base = (model) => ({ inputUsd: model.input, outputUsd: model.output, context: model.context, tools: model.tools, releasedAt: released(model) });
89
+ const rows = [];
90
+ const byId = new Map(openrouter.map(model => [model.id, model]));
91
+ for (const model of openrouter) {
92
+ if (model.id.includes(":"))
93
+ continue;
94
+ rows.push({ source: "openrouter", id: model.id, name: model.name, ...base(model) });
95
+ const claude = claudeIdOf(model.id);
96
+ if (claude !== null)
97
+ rows.push({ source: "claude", id: claude, name: stripVendor(model.name), ...base(model) });
98
+ const gemini = geminiIdOf(model.id);
99
+ if (gemini !== null)
100
+ rows.push({ source: "gemini", id: gemini, name: stripVendor(model.name), ...base(model) });
101
+ }
102
+ for (const one of codex) {
103
+ const priced = byId.get(`openai/${one.id}`);
104
+ rows.push({ source: "codex", id: one.id, name: one.name, ...(priced === undefined
105
+ ? { inputUsd: null, outputUsd: null, context: null, tools: true, releasedAt: null } : base(priced)) });
106
+ }
107
+ return rows;
108
+ }
109
+ const readRow = (row) => ({
110
+ source: row["source"], id: String(row["id"]), name: String(row["name"]),
111
+ inputUsd: row["input_usd"] == null ? null : Number(row["input_usd"]), outputUsd: row["output_usd"] == null ? null : Number(row["output_usd"]),
112
+ context: row["context"] == null ? null : Number(row["context"]), tools: Number(row["tools"]) === 1,
113
+ releasedAt: row["released_at"] == null ? null : String(row["released_at"]), firstSeenAt: String(row["first_seen_at"]),
114
+ });
115
+ /** Upsert a fetch. Returns models first seen now, except on a source's first
116
+ * fetch (the baseline would otherwise announce every model at once). */
117
+ export function recordCatalog(store, rows, now) {
118
+ const stamp = now.toISOString();
119
+ return store.transact(() => {
120
+ const had = new Set(store.handle.prepare("SELECT DISTINCT source FROM model_seen").all().map(row => String(row["source"])));
121
+ const added = [];
122
+ const exists = store.handle.prepare("SELECT 1 AS hit FROM model_seen WHERE source = ? AND id = ?");
123
+ const upsert = store.handle.prepare(`INSERT INTO model_seen (source, id, name, input_usd, output_usd, context, tools, released_at, first_seen_at, last_seen_at)
124
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
125
+ ON CONFLICT(source, id) DO UPDATE SET name = excluded.name, input_usd = excluded.input_usd, output_usd = excluded.output_usd,
126
+ context = excluded.context, tools = excluded.tools, released_at = COALESCE(excluded.released_at, model_seen.released_at), last_seen_at = excluded.last_seen_at`);
127
+ for (const row of rows) {
128
+ const fresh = exists.get(row.source, row.id) === undefined;
129
+ upsert.run(row.source, row.id, row.name.slice(0, 150), row.inputUsd, row.outputUsd, row.context, row.tools ? 1 : 0, row.releasedAt, stamp, stamp);
130
+ if (fresh && had.has(row.source))
131
+ added.push({ ...row, firstSeenAt: stamp });
132
+ }
133
+ // A model the source no longer lists stops being offered; its row stays
134
+ // so a saved choice can still be named.
135
+ return added;
136
+ });
137
+ }
138
+ export function seenModels(store, source, options = {}) {
139
+ const latest = options.current === false ? null : store.handle.prepare("SELECT MAX(last_seen_at) AS at FROM model_seen WHERE source = ?").get(source);
140
+ return store.handle.prepare(`SELECT * FROM model_seen WHERE source = ? AND (? IS NULL OR last_seen_at = ?) ORDER BY COALESCE(released_at, '') DESC, name`).all(source, latest?.["at"] ?? null, latest?.["at"] ?? null).map(readRow);
141
+ }
142
+ export function seenModel(store, source, id) {
143
+ const row = store.handle.prepare("SELECT * FROM model_seen WHERE source = ? AND id = ?").get(source, id);
144
+ return row === undefined ? null : readRow(row);
145
+ }
146
+ export function isNewModel(model, now) {
147
+ return model.releasedAt !== null && now.getTime() - Date.parse(model.releasedAt) < NEW_FOR_MS;
148
+ }
149
+ /** What the Claude CLI's short name currently runs: the newest of its family. */
150
+ export function aliasTarget(store, alias) {
151
+ if (!FAMILIES.includes(alias))
152
+ return null;
153
+ return seenModels(store, "claude").find(model => model.id.startsWith(`claude-${alias}-`)) ?? null;
154
+ }
155
+ export function dollars(amount) {
156
+ if (amount === null)
157
+ return "price not listed";
158
+ if (amount === 0)
159
+ return "free";
160
+ return `$${Number(amount.toPrecision(3))}`;
161
+ }
162
+ export function priceWords(model) {
163
+ return model.inputUsd === null && model.outputUsd === null ? "price not listed" : `${dollars(model.inputUsd)} / ${dollars(model.outputUsd)} per 1M tokens`;
164
+ }
165
+ /** The friendly name for a saved provider + model, e.g. "opus" → "Claude Opus 5.5". */
166
+ export function modelWords(store, provider, model) {
167
+ if (model === null || model === "" || model === "default")
168
+ return "its default model";
169
+ if (provider === "claude" || provider === "claude-subscription" || provider === "anthropic-api") {
170
+ const alias = aliasTarget(store, model);
171
+ if (alias !== null)
172
+ return `${title(model)} (now ${alias.name})`;
173
+ return seenModel(store, "claude", model)?.name ?? model;
174
+ }
175
+ const source = provider === "codex" || provider === "codex-subscription" ? "codex" : provider === "gemini" ? "gemini" : provider === "openrouter" || provider === "openrouter-api" ? "openrouter" : null;
176
+ return source === null ? model : seenModel(store, source, model)?.name ?? model;
177
+ }
178
+ /** Every model a provider can run, newest first, with prices. */
179
+ export function modelOptions(store, provider, now, home = homedir()) {
180
+ const option = (model) => ({ value: model.id, label: `${model.name} · ${priceWords(model)}${isNewModel(model, now) ? " · New" : ""}`, isNew: isNewModel(model, now) });
181
+ if (provider === "claude") {
182
+ const aliases = ["sonnet", "opus", "haiku"].map(alias => {
183
+ const target = aliasTarget(store, alias);
184
+ // Short enough that a phone's select still shows which model it means.
185
+ return { value: alias, label: target === null ? `${title(alias)} — ${ALIAS_WORDS[alias]}` : `${title(alias)} · latest (${target.name.replace(/^Claude /, "")})`, isNew: false };
186
+ });
187
+ return [...aliases, ...seenModels(store, "claude").slice(0, 20).map(option)];
188
+ }
189
+ if (provider === "codex") {
190
+ const live = codexCatalog(home);
191
+ return live.map(one => {
192
+ const seen = seenModel(store, "codex", one.id);
193
+ return seen === null ? { value: one.id, label: one.name, isNew: false } : option({ ...seen, name: one.name });
194
+ });
195
+ }
196
+ if (provider === "gemini")
197
+ return seenModels(store, "gemini").slice(0, 20).map(option);
198
+ return seenModels(store, "openrouter").filter(model => model.tools).sort((a, b) => a.name.localeCompare(b.name)).map(option);
199
+ }
200
+ /** Chat reserves worst-case spend: price per token in whole micro-dollars,
201
+ * rounded UP from the live list price. null = no live price. */
202
+ export function livePin(store, chatProvider, model) {
203
+ const seen = chatProvider === "anthropic-api" ? seenModel(store, "claude", model) : chatProvider === "openrouter-api" ? seenModel(store, "openrouter", model) : null;
204
+ if (seen === null || seen.inputUsd === null || seen.outputUsd === null)
205
+ return null;
206
+ // USD per million tokens is micro-dollars per token.
207
+ const pin = (usd) => usd === 0 ? 0 : Math.ceil(usd - 1e-9);
208
+ return { inMicrousd: pin(seen.inputUsd), outMicrousd: pin(seen.outputUsd) };
209
+ }
210
+ // ---------------------------------------------------------------- runtimes
211
+ export function compareVersions(a, b) {
212
+ const parts = (v) => v.split(/[.-]/).slice(0, 3).map(part => Number.parseInt(part, 10) || 0);
213
+ const [x, y] = [parts(a), parts(b)];
214
+ for (let i = 0; i < 3; i += 1)
215
+ if ((x[i] ?? 0) !== (y[i] ?? 0))
216
+ return (x[i] ?? 0) - (y[i] ?? 0);
217
+ return 0;
218
+ }
219
+ const versionIn = (text) => /\b(\d+\.\d+\.\d+)\b/.exec(text)?.[1] ?? null;
220
+ const defaultRunner = (command, args, options) => new Promise(resolve => {
221
+ execFile(command, args, { timeout: options.timeoutMs, maxBuffer: 1_000_000, ...(options.env === undefined ? {} : { env: options.env }) }, (error, stdout, stderr) => {
222
+ const code = error === null ? 0 : typeof error.code === "number" ? Number(error.code) : 1;
223
+ resolve({ code, stdout: String(stdout), stderr: String(stderr) });
224
+ });
225
+ });
226
+ function onPath(command, path) {
227
+ for (const dir of path.split(delimiter)) {
228
+ if (dir === "")
229
+ continue;
230
+ const candidate = join(dir, command);
231
+ try {
232
+ accessSync(candidate, constants.X_OK);
233
+ return realpathSync(candidate);
234
+ }
235
+ catch { /* next */ }
236
+ }
237
+ return null;
238
+ }
239
+ /** How this copy was installed decides the one safe update command. */
240
+ export function updateCommandFor(tool, resolved) {
241
+ const pkg = RUNTIME_TOOLS[tool].pkg;
242
+ if (tool === "claude" && /\/\.local\/share\/claude\/versions\//.test(resolved))
243
+ return ["claude", "update"];
244
+ if (resolved.includes(`/node_modules/${pkg}/`))
245
+ return ["npm", "install", "-g", `${pkg}@latest`];
246
+ return null;
247
+ }
248
+ async function latestVersion(pkg, fetcher) {
249
+ try {
250
+ const response = await fetcher(`https://registry.npmjs.org/${pkg}/latest`, { headers: { accept: "application/json" }, redirect: "error", signal: AbortSignal.timeout(8_000) });
251
+ if (!response.ok) {
252
+ await response.body?.cancel();
253
+ return null;
254
+ }
255
+ const body = await readCappedBody(response, 2_000_000);
256
+ if (body === null)
257
+ return null;
258
+ const version = JSON.parse(new TextDecoder().decode(body)).version;
259
+ return typeof version === "string" && /^\d+\.\d+\.\d+/.test(version) ? version : null;
260
+ }
261
+ catch {
262
+ return null;
263
+ }
264
+ }
265
+ function readRuntime(row) {
266
+ const tool = row["tool"];
267
+ const installed = row["installed"] == null ? null : String(row["installed"]);
268
+ const latest = row["latest"] == null ? null : String(row["latest"]);
269
+ let command = null;
270
+ try {
271
+ command = row["update_command"] == null ? null : JSON.parse(String(row["update_command"]));
272
+ }
273
+ catch {
274
+ command = null;
275
+ }
276
+ return {
277
+ tool, name: RUNTIME_TOOLS[tool].name, installed, latest, updateCommand: command,
278
+ problem: row["problem"] == null ? null : String(row["problem"]), checkedAt: String(row["checked_at"]),
279
+ updatedAt: row["updated_at"] == null ? null : String(row["updated_at"]), updatedBy: row["updated_by"] == null ? null : String(row["updated_by"]),
280
+ behind: installed !== null && latest !== null && compareVersions(latest, installed) > 0,
281
+ };
282
+ }
283
+ export function runtimeStates(store) {
284
+ return store.handle.prepare("SELECT * FROM runtime_check WHERE installed IS NOT NULL ORDER BY CASE tool WHEN 'claude' THEN 0 WHEN 'codex' THEN 1 ELSE 2 END").all().map(readRuntime);
285
+ }
286
+ export async function checkRuntimes(store, now, seams = {}) {
287
+ const runner = seams.runner ?? defaultRunner, fetcher = seams.fetcher ?? fetch, path = seams.path ?? process.env["PATH"] ?? "";
288
+ for (const tool of Object.keys(RUNTIME_TOOLS)) {
289
+ const spec = RUNTIME_TOOLS[tool];
290
+ const resolved = onPath(spec.command, path);
291
+ let installed = null, problem = null;
292
+ if (resolved !== null) {
293
+ const ran = await runner(spec.command, ["--version"], { timeoutMs: 15_000 });
294
+ installed = ran.code === 0 ? versionIn(ran.stdout) : null;
295
+ if (installed === null)
296
+ problem = `${spec.name} did not report its version.`;
297
+ }
298
+ const latest = resolved === null ? null : await latestVersion(spec.pkg, fetcher);
299
+ if (resolved !== null && latest === null && problem === null)
300
+ problem = "The latest version could not be checked.";
301
+ store.handle.prepare(`INSERT INTO runtime_check (tool, installed, latest, update_command, problem, checked_at) VALUES (?, ?, ?, ?, ?, ?)
302
+ ON CONFLICT(tool) DO UPDATE SET installed = excluded.installed, latest = COALESCE(excluded.latest, runtime_check.latest),
303
+ update_command = excluded.update_command, problem = excluded.problem, checked_at = excluded.checked_at`).run(tool, installed, latest, resolved === null ? null : JSON.stringify(updateCommandFor(tool, resolved)), problem, now.toISOString());
304
+ }
305
+ return runtimeStates(store);
306
+ }
307
+ /** Update one CLI, only while nothing is running, then read its version again. */
308
+ export async function updateRuntime(store, tool, by, now, seams = {}) {
309
+ const state = runtimeStates(store).find(one => one.tool === tool);
310
+ if (state === undefined)
311
+ return { ok: false, message: `${RUNTIME_TOOLS[tool].name} is not installed on this computer.` };
312
+ if (state.updateCommand === null)
313
+ return { ok: false, message: `${state.name} was installed in a way Toolroll cannot update. Update it the way you installed it.` };
314
+ const work = activeUpdateWork(store.handle);
315
+ const busy = Object.values(work).reduce((sum, n) => sum + n, 0);
316
+ if (busy > 0)
317
+ return { ok: false, message: `Work is running (${busy} item${busy === 1 ? "" : "s"}). Update ${state.name} when it finishes.` };
318
+ const runner = seams.runner ?? defaultRunner;
319
+ const [command, ...args] = state.updateCommand;
320
+ const env = { ...process.env };
321
+ delete env["NODE_OPTIONS"];
322
+ const ran = await runner(command, args, { timeoutMs: 300_000, env });
323
+ const after = (await checkRuntimes(store, now, seams)).find(one => one.tool === tool);
324
+ if (ran.code !== 0)
325
+ return { ok: false, message: `${state.name} did not update. ${(ran.stderr || ran.stdout).trim().split("\n").at(-1)?.slice(0, 200) ?? ""}`.trim() };
326
+ store.handle.prepare("UPDATE runtime_check SET updated_at = ?, updated_by = ? WHERE tool = ?").run(now.toISOString(), by, tool);
327
+ return after?.installed === state.installed
328
+ ? { ok: true, message: `${state.name} is already at ${after?.installed ?? state.installed}.` }
329
+ : { ok: true, message: `${state.name} updated to ${after?.installed ?? "the latest version"}. New work uses it; nothing running was touched.` };
330
+ }
331
+ export function watchState(store) {
332
+ const row = store.handle.prepare("SELECT * FROM model_watch WHERE id = 1").get();
333
+ return { enabled: Number(row?.["enabled"] ?? 0) === 1, checkedAt: row?.["checked_at"] == null ? null : String(row["checked_at"]),
334
+ problem: row?.["problem"] == null ? null : String(row["problem"]), changedBy: row?.["changed_by"] == null ? null : String(row["changed_by"]) };
335
+ }
336
+ export function setWatch(store, enabled, by, now) {
337
+ store.handle.prepare(`INSERT INTO model_watch (id, enabled, changed_by, changed_at) VALUES (1, ?, ?, ?)
338
+ ON CONFLICT(id) DO UPDATE SET enabled = excluded.enabled, changed_by = excluded.changed_by, changed_at = excluded.changed_at`).run(enabled ? 1 : 0, by, now.toISOString());
339
+ }
340
+ /** One full check: the catalog, the CLIs, and a notice for each new model or
341
+ * newly available update. Idempotent per model and per released version. */
342
+ export async function checkModels(store, now, seams = {}) {
343
+ const fetched = await fetchOpenRouterModels(null, seams.fetcher ?? fetch);
344
+ let added = [];
345
+ if (fetched.ok)
346
+ added = recordCatalog(store, catalogRows(fetched.models, codexCatalog(seams.home)), now);
347
+ const runtimes = await checkRuntimes(store, now, seams);
348
+ const problem = fetched.ok ? null : fetched.problem;
349
+ store.handle.prepare(`INSERT INTO model_watch (id, checked_at, problem) VALUES (1, ?, ?)
350
+ ON CONFLICT(id) DO UPDATE SET checked_at = excluded.checked_at, problem = excluded.problem`).run(now.toISOString(), problem);
351
+ for (const model of added.filter(one => one.source !== "openrouter")) {
352
+ const maker = model.source === "claude" ? "Anthropic" : model.source === "codex" ? "OpenAI" : "Google";
353
+ const alias = model.source === "claude" ? FAMILIES.find(family => model.id.startsWith(`claude-${family}-`)) : undefined;
354
+ const using = alias !== undefined && ["opus", "sonnet", "haiku"].includes(alias) && aliasTarget(store, alias)?.id === model.id
355
+ ? ` Agents set to "${alias}" use it from now on.` : "";
356
+ store.enqueueNotification({ dedupeKey: `model-new:${model.source}:${model.id}`, kind: "model-available",
357
+ subject: `New model: ${model.name}`, body: `${maker} released ${model.name} (${priceWords(model)}).${using} Choose it in Settings → Models.`,
358
+ link: "/settings/models", source: { installation: true } }, now);
359
+ }
360
+ for (const runtime of runtimes.filter(one => one.behind)) {
361
+ store.enqueueNotification({ dedupeKey: `runtime-update:${runtime.tool}:${runtime.latest}`, kind: "runtime-update",
362
+ subject: `${runtime.name} ${runtime.latest} is available`, body: `This computer has ${runtime.installed}. ${runtime.updateCommand === null ? "Update it the way you installed it." : "Update it in Settings → Models when no work is running."}`,
363
+ link: "/settings/models", source: { installation: true } }, now);
364
+ }
365
+ return { ok: fetched.ok, added, runtimes, problem };
366
+ }
367
+ /** The background pass: runs only when the person turned checks on. */
368
+ export async function modelWatchPass(store, now, seams = {}) {
369
+ const state = watchState(store);
370
+ if (!state.enabled)
371
+ return false;
372
+ if (state.checkedAt !== null && now.getTime() - Date.parse(state.checkedAt) < WATCH_EVERY_MS)
373
+ return false;
374
+ await checkModels(store, now, seams);
375
+ return true;
376
+ }
@@ -0,0 +1,102 @@
1
+ import { type CatalogSeams } from "./model-catalog.js";
2
+ import type { Store } from "./store.js";
3
+ export declare const MODELS_DESCRIPTORS: readonly [{
4
+ readonly action: "status";
5
+ readonly synopsis: "installed CLI versions, available updates, new models and the automatic check";
6
+ readonly mutation: "none";
7
+ readonly takesQuery: false;
8
+ readonly flags: readonly [{
9
+ readonly name: "provider";
10
+ readonly takesValue: true;
11
+ readonly meaning: "claude, codex, gemini or openrouter, for models list";
12
+ }, {
13
+ readonly name: "json";
14
+ readonly takesValue: false;
15
+ readonly meaning: "versioned structured response";
16
+ }, {
17
+ readonly name: "db";
18
+ readonly takesValue: true;
19
+ readonly meaning: "local Toolroll database";
20
+ }];
21
+ }, {
22
+ readonly action: "list";
23
+ readonly synopsis: "models a provider can run, newest first, with prices (--provider claude|codex|gemini|openrouter)";
24
+ readonly mutation: "none";
25
+ readonly takesQuery: false;
26
+ readonly flags: readonly [{
27
+ readonly name: "provider";
28
+ readonly takesValue: true;
29
+ readonly meaning: "claude, codex, gemini or openrouter, for models list";
30
+ }, {
31
+ readonly name: "json";
32
+ readonly takesValue: false;
33
+ readonly meaning: "versioned structured response";
34
+ }, {
35
+ readonly name: "db";
36
+ readonly takesValue: true;
37
+ readonly meaning: "local Toolroll database";
38
+ }];
39
+ }, {
40
+ readonly action: "check";
41
+ readonly synopsis: "fetch the public model lists and check CLI versions now";
42
+ readonly mutation: "unkeyed";
43
+ readonly takesQuery: false;
44
+ readonly flags: readonly [{
45
+ readonly name: "provider";
46
+ readonly takesValue: true;
47
+ readonly meaning: "claude, codex, gemini or openrouter, for models list";
48
+ }, {
49
+ readonly name: "json";
50
+ readonly takesValue: false;
51
+ readonly meaning: "versioned structured response";
52
+ }, {
53
+ readonly name: "db";
54
+ readonly takesValue: true;
55
+ readonly meaning: "local Toolroll database";
56
+ }];
57
+ }, {
58
+ readonly action: "update";
59
+ readonly synopsis: "update one CLI while no work is running: models update claude|codex|gemini";
60
+ readonly mutation: "unkeyed";
61
+ readonly takesQuery: true;
62
+ readonly flags: readonly [{
63
+ readonly name: "provider";
64
+ readonly takesValue: true;
65
+ readonly meaning: "claude, codex, gemini or openrouter, for models list";
66
+ }, {
67
+ readonly name: "json";
68
+ readonly takesValue: false;
69
+ readonly meaning: "versioned structured response";
70
+ }, {
71
+ readonly name: "db";
72
+ readonly takesValue: true;
73
+ readonly meaning: "local Toolroll database";
74
+ }];
75
+ }, {
76
+ readonly action: "watch";
77
+ readonly synopsis: "turn the 6-hourly check and its messages on or off: models watch on|off";
78
+ readonly mutation: "unkeyed";
79
+ readonly takesQuery: true;
80
+ readonly flags: readonly [{
81
+ readonly name: "provider";
82
+ readonly takesValue: true;
83
+ readonly meaning: "claude, codex, gemini or openrouter, for models list";
84
+ }, {
85
+ readonly name: "json";
86
+ readonly takesValue: false;
87
+ readonly meaning: "versioned structured response";
88
+ }, {
89
+ readonly name: "db";
90
+ readonly takesValue: true;
91
+ readonly meaning: "local Toolroll database";
92
+ }];
93
+ }];
94
+ export type ModelsCliContext = {
95
+ store: Store;
96
+ write: (line: string) => void;
97
+ json: boolean;
98
+ now: Date;
99
+ actor: string | null;
100
+ seams?: CatalogSeams;
101
+ };
102
+ export declare function runModelsCommand(positional: readonly string[], options: Map<string, string | true>, context: ModelsCliContext): Promise<number>;