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,149 @@
1
+ /**
2
+ * Flow insights (v84): how work moves through a flow and where it breaks,
3
+ * read from what the flow already records — every card's moves (flow_event)
4
+ * and every script or update step's run (flow_step_run, with its log). No
5
+ * model, no sampling: counts over a window, per zone and per script.
6
+ */
7
+ import { flowDefinitionOf } from "./flow-engine.js";
8
+ import { parseSortDecision } from "./flow-sort.js";
9
+ const median = (values) => {
10
+ if (values.length === 0)
11
+ return null;
12
+ const sorted = [...values].sort((a, b) => a - b);
13
+ const middle = Math.floor(sorted.length / 2);
14
+ return sorted.length % 2 === 1 ? sorted[middle] : (sorted[middle - 1] + sorted[middle]) / 2;
15
+ };
16
+ /** One flow's insights over the last `days` days. */
17
+ export function flowInsights(store, flow, now, days = 30) {
18
+ const since = new Date(now.getTime() - days * 86_400_000);
19
+ const definition = flowDefinitionOf(flow);
20
+ const stages = definition?.stages ?? [];
21
+ const titleOf = (id) => stages.find(one => one.id === id)?.title ?? id;
22
+ const cards = store.flowCards(flow.id, true);
23
+ const cardTitle = (id) => cards.find(one => one.id === id)?.title ?? `card ${id}`;
24
+ const zones = new Map(stages.map(stage => [stage.id, {
25
+ zone: stage.id, title: stage.title, kind: stage.kind, entered: 0, movedOn: 0, failed: 0, sentBack: 0,
26
+ here: cards.filter(card => card.state === "active" && card.stage === stage.id).length, typicalMinutes: null, lastProblem: null, stays: [],
27
+ }]));
28
+ const moves = store.flowMoves(flow.id, since);
29
+ const byCard = new Map();
30
+ for (const move of moves)
31
+ byCard.set(move.card, [...byCard.get(move.card) ?? [], move]);
32
+ for (const [card, list] of byCard)
33
+ list.forEach((move, index) => {
34
+ const arrived = zones.get(move.toStage);
35
+ if (arrived !== undefined) {
36
+ arrived.entered++;
37
+ const next = list[index + 1];
38
+ if (next !== undefined)
39
+ arrived.stays.push((Date.parse(next.at) - Date.parse(move.at)) / 60_000);
40
+ }
41
+ const left = move.fromStage === null ? undefined : zones.get(move.fromStage);
42
+ if (left === undefined)
43
+ return;
44
+ if (move.outcome === "fail" || move.outcome === "sent-back") {
45
+ if (move.outcome === "fail")
46
+ left.failed++;
47
+ else
48
+ left.sentBack++;
49
+ left.lastProblem = { card, cardTitle: cardTitle(card), note: move.note, at: move.at };
50
+ }
51
+ else if (move.outcome !== "cancelled")
52
+ left.movedOn++;
53
+ });
54
+ const zoneList = [...zones.values()].map(({ stays, ...zone }) => ({ ...zone, typicalMinutes: median(stays) === null ? null : Math.round(median(stays) * 10) / 10 }));
55
+ const doneZones = new Set(stages.filter(one => one.kind === "done").map(one => one.id));
56
+ const runs = store.flowStepRuns(flow.id, since, 200);
57
+ const scripts = new Map();
58
+ for (const run of runs) {
59
+ if (run.script === null || (run.state !== "passed" && run.state !== "failed"))
60
+ continue;
61
+ const entry = scripts.get(run.script) ?? { runs: 0, passed: 0, failed: 0, durations: [], lastFailure: null };
62
+ entry.runs++;
63
+ if (run.state === "passed")
64
+ entry.passed++;
65
+ else {
66
+ entry.failed++;
67
+ entry.lastFailure ??= run.result;
68
+ }
69
+ if (run.durationMs !== null)
70
+ entry.durations.push(run.durationMs / 1000);
71
+ scripts.set(run.script, entry);
72
+ }
73
+ const sorts = stages.filter(one => one.kind === "sort" && one.sort !== null).map(stage => sortInsight(stage, runs, byCard));
74
+ return {
75
+ flow: flow.id, name: flow.name, days,
76
+ cards: {
77
+ started: moves.filter(one => one.outcome === "created").length,
78
+ finished: new Set(moves.filter(one => doneZones.has(one.toStage)).map(one => one.card)).size,
79
+ active: cards.filter(one => one.state === "active").length,
80
+ },
81
+ zones: zoneList,
82
+ breaks: zoneList.filter(one => one.failed + one.sentBack > 0).sort((a, b) => (b.failed + b.sentBack) - (a.failed + a.sentBack)).slice(0, 3)
83
+ .map(one => ({ zone: one.zone, title: one.title, problems: one.failed + one.sentBack, of: Math.max(one.entered, one.failed + one.sentBack) })),
84
+ scripts: [...scripts].map(([script, one]) => ({ script, runs: one.runs, passed: one.passed, failed: one.failed, typicalSeconds: median(one.durations) === null ? null : Math.round(median(one.durations)), lastFailure: one.lastFailure })),
85
+ sorts,
86
+ runs: runs.slice(0, 40).map(run => ({
87
+ card: run.card, cardTitle: run.cardTitle, entry: run.entry, zone: run.stage, zoneTitle: titleOf(run.stage), kind: run.kind, script: run.script, version: run.scriptVersion,
88
+ state: run.state, result: run.result, exitCode: run.exitCode, durationMs: run.durationMs, at: run.finishedAt ?? run.startedAt, hasLog: run.log !== null && run.log !== "",
89
+ })),
90
+ };
91
+ }
92
+ const BANDS = [[90, 101], [80, 90], [70, 80], [50, 70]];
93
+ function sortInsight(stage, runs, byCard) {
94
+ const sort = stage.sort;
95
+ const targets = new Set(sort.answers.map(one => one.to));
96
+ const bands = BANDS.map(([from, to]) => ({ from, to: Math.min(to, 100), right: 0, of: 0 }));
97
+ const insight = { zone: stage.id, title: stage.title, sureAt: sort.sureAt, sorted: 0, alone: 0, notSure: 0, corrected: 0, bands, costUsd: 0, suggestion: null };
98
+ for (const run of runs) {
99
+ if (run.kind !== "sort" || run.stage !== stage.id || run.state !== "passed")
100
+ continue;
101
+ const decision = parseSortDecision(run.decisionJson);
102
+ if (decision === null)
103
+ continue;
104
+ insight.sorted++;
105
+ if (decision.confident)
106
+ insight.alone++;
107
+ else
108
+ insight.notSure++;
109
+ insight.costUsd += decision.cost ?? 0;
110
+ // Where the sort sent the card, and what happened to it next.
111
+ const moves = byCard.get(run.card) ?? [];
112
+ const sent = moves.findIndex(one => one.fromStage === stage.id && one.actor === "flow" && one.at >= run.startedAt);
113
+ const after = sent === -1 ? undefined : moves[sent + 1];
114
+ const picked = sort.answers.find(one => one.answer === decision.answer)?.to ?? null;
115
+ let right = null;
116
+ if (after !== undefined && after.actor !== "flow" && after.outcome === "moved" && targets.has(after.toStage)) {
117
+ // A person placed it where an answer leads: that is what the answer should have been.
118
+ right = after.toStage === picked;
119
+ if (decision.confident && !right)
120
+ insight.corrected++;
121
+ }
122
+ else if (decision.confident && after !== undefined)
123
+ right = true;
124
+ if (right === null)
125
+ continue;
126
+ const band = bands.find(one => decision.sure * 100 >= one.from && decision.sure * 100 < (one.to === 100 ? 101 : one.to));
127
+ if (band !== undefined) {
128
+ band.of++;
129
+ if (right)
130
+ band.right++;
131
+ }
132
+ }
133
+ insight.costUsd = Math.round(insight.costUsd * 1_000_000) / 1_000_000;
134
+ // Say so only with enough cards behind it.
135
+ const at = Math.round(sort.sureAt * 100);
136
+ const below = bands.find(one => one.to <= at && one.to > at - 15 && one.of >= 5);
137
+ const above = bands.filter(one => one.from >= at && one.of >= 5);
138
+ const shaky = above.find(one => one.right / one.of < 0.8);
139
+ if (shaky !== undefined)
140
+ insight.suggestion = `Jev was wrong on ${shaky.of - shaky.right} of ${shaky.of} cards it sent on alone at ${shaky.from}–${shaky.to}% sure. Consider asking for ${Math.min(95, shaky.to)}%.`;
141
+ else if (below !== undefined && below.right / below.of >= 0.9)
142
+ insight.suggestion = `Cards Jev was ${below.from}–${below.to}% sure about were right ${below.right} of ${below.of} times. You could let it act alone from ${below.from}%.`;
143
+ return insight;
144
+ }
145
+ /** One line for a flow's list entry: where it has had the most trouble lately. */
146
+ export function troubleWords(insights) {
147
+ const worst = insights.breaks[0];
148
+ return worst === undefined ? null : `most trouble in ${worst.title} (${worst.problems} of ${worst.of} in the last ${insights.days} days)`;
149
+ }
@@ -0,0 +1,24 @@
1
+ import type { ServerResponse } from "node:http";
2
+ import type { Store } from "./store.js";
3
+ export type FlowPresence = {
4
+ name: string;
5
+ cards: number[];
6
+ editing: boolean;
7
+ };
8
+ export type FlowViewer = {
9
+ name: string;
10
+ card: number | null;
11
+ editing: boolean;
12
+ response: ServerResponse;
13
+ valid: () => boolean;
14
+ };
15
+ /** What changes when anything on the canvas changes: one row, one read, kept short and opaque. */
16
+ export declare function flowFingerprint(store: Store, flow: number): string | null;
17
+ export type FlowRooms = {
18
+ /** Keep this page's stream on the flow until it closes; the first event says where the flow stands. */
19
+ join: (flow: number, viewer: FlowViewer) => void;
20
+ /** Every stream, ended (the server is closing). */
21
+ close: () => void;
22
+ size: () => number;
23
+ };
24
+ export declare function createFlowRooms(fingerprint: (flow: number) => string | null, tickMs?: number): FlowRooms;
@@ -0,0 +1,150 @@
1
+ /**
2
+ * The live canvas (v88): a flow open in several browsers stays the same in
3
+ * all of them, and each shows who else has it open.
4
+ *
5
+ * - A change nudge. While anyone has a flow open, one cheap query a second
6
+ * reads the flow's fingerprint (its revision, cards, moves, comments,
7
+ * watchers, step runs and triggers); when it changes, every open page
8
+ * hears "change" and reads the flow again the usual way. The nudge
9
+ * carries no card data: what a page shows is always what its own read
10
+ * returned, under its own checks.
11
+ * - Who's here. Each open page says which card it has open and whether it
12
+ * is changing the flow; everyone else on the flow hears the list, by
13
+ * name. It lives in memory only and goes when the page closes or hides.
14
+ *
15
+ * Streams are refresh hints only: nothing here writes, and a page that
16
+ * can't keep one open falls back to reading every few seconds.
17
+ */
18
+ import { createHash } from "node:crypto";
19
+ const TICK_MS = 1_000;
20
+ const CHECK_EVERY = 15;
21
+ const HEARTBEAT_EVERY = 15;
22
+ const PRESENCE_SETTLE_MS = 150;
23
+ /** What changes when anything on the canvas changes: one row, one read, kept short and opaque. */
24
+ export function flowFingerprint(store, flow) {
25
+ const row = store.handle.prepare(`SELECT f.state || '|' || f.revision || '|' || f.updated_at || '|' || coalesce(f.owner, '') AS head,
26
+ (SELECT count(*) || ':' || coalesce(max(updated_at), '') FROM flow_card WHERE flow = f.id) AS cards,
27
+ (SELECT coalesce(max(e.id), 0) FROM flow_event e JOIN flow_card c ON c.id = e.card WHERE c.flow = f.id) AS moves,
28
+ (SELECT coalesce(max(m.id), 0) FROM flow_comment m JOIN flow_card c ON c.id = m.card WHERE c.flow = f.id) AS comments,
29
+ (SELECT count(*) || ':' || coalesce(max(w.added_at), '') FROM flow_card_watcher w JOIN flow_card c ON c.id = w.card WHERE c.flow = f.id) AS watchers,
30
+ (SELECT count(*) || ':' || coalesce(sum(r.attempts), 0) || ':' || coalesce(max(coalesce(r.finished_at, r.started_at)), '') || ':' || coalesce(sum(r.state = 'running'), 0)
31
+ FROM flow_step_run r JOIN flow_card c ON c.id = r.card WHERE c.flow = f.id) AS runs,
32
+ (SELECT count(*) || ':' || coalesce(max(updated_at), '') || ':' || coalesce(max(last_at), '') || ':' || coalesce(sum(failures), 0) FROM flow_trigger WHERE flow = f.id) AS triggers
33
+ FROM flow f WHERE f.id = ?`).get(flow);
34
+ return row === undefined ? null : createHash("sha256").update(Object.values(row).map(String).join("|")).digest("hex").slice(0, 16);
35
+ }
36
+ export function createFlowRooms(fingerprint, tickMs = TICK_MS) {
37
+ const rooms = new Map();
38
+ const write = (viewer, event, data) => {
39
+ if (viewer.response.writableEnded || viewer.response.destroyed)
40
+ return;
41
+ viewer.response.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
42
+ };
43
+ /** Everyone on the flow but you, one line per person however many pages they have open. */
44
+ const others = (room, me) => {
45
+ const people = new Map();
46
+ for (const one of room.viewers) {
47
+ if (one.name === me)
48
+ continue;
49
+ const seen = people.get(one.name) ?? { name: one.name, cards: [], editing: false };
50
+ if (one.card !== null && !seen.cards.includes(one.card))
51
+ seen.cards.push(one.card);
52
+ seen.editing ||= one.editing;
53
+ people.set(one.name, seen);
54
+ }
55
+ return [...people.values()].sort((a, b) => a.name.localeCompare(b.name));
56
+ };
57
+ const announce = (room) => {
58
+ // A page that moves from one card to the next leaves and joins at once: say it once, after it settles.
59
+ if (room.settling !== null)
60
+ clearTimeout(room.settling);
61
+ room.settling = setTimeout(() => {
62
+ room.settling = null;
63
+ for (const viewer of room.viewers)
64
+ write(viewer, "here", { people: others(room, viewer.name) });
65
+ }, PRESENCE_SETTLE_MS);
66
+ room.settling.unref();
67
+ };
68
+ const leave = (flow, viewer) => {
69
+ const room = rooms.get(flow);
70
+ if (room === undefined || !room.viewers.delete(viewer))
71
+ return;
72
+ if (!viewer.response.writableEnded)
73
+ viewer.response.end();
74
+ if (room.viewers.size > 0) {
75
+ announce(room);
76
+ return;
77
+ }
78
+ if (room.timer !== null)
79
+ clearInterval(room.timer);
80
+ if (room.settling !== null)
81
+ clearTimeout(room.settling);
82
+ rooms.delete(flow);
83
+ };
84
+ const tick = (flow, room) => {
85
+ room.ticks += 1;
86
+ if (room.ticks % CHECK_EVERY === 0) {
87
+ // A signed-out or narrowed account stops hearing about the flow.
88
+ for (const viewer of [...room.viewers])
89
+ if (!viewer.valid()) {
90
+ write(viewer, "gone", {});
91
+ leave(flow, viewer);
92
+ }
93
+ if (!rooms.has(flow))
94
+ return;
95
+ }
96
+ let now;
97
+ try {
98
+ now = fingerprint(flow);
99
+ }
100
+ catch {
101
+ return; /* a busy database: the next tick reads again */
102
+ }
103
+ if (now === null) {
104
+ for (const viewer of [...room.viewers]) {
105
+ write(viewer, "gone", {});
106
+ leave(flow, viewer);
107
+ }
108
+ return;
109
+ }
110
+ if (now !== room.last) {
111
+ room.last = now;
112
+ for (const viewer of room.viewers)
113
+ write(viewer, "change", { at: now });
114
+ }
115
+ else if (room.ticks % HEARTBEAT_EVERY === 0) {
116
+ for (const viewer of room.viewers)
117
+ if (!viewer.response.writableEnded)
118
+ viewer.response.write(": keep-alive\n\n");
119
+ }
120
+ };
121
+ return {
122
+ join(flow, viewer) {
123
+ let room = rooms.get(flow);
124
+ if (room === undefined) {
125
+ let last = null;
126
+ try {
127
+ last = fingerprint(flow);
128
+ }
129
+ catch { /* the first tick reads it */ }
130
+ room = { viewers: new Set(), last, timer: null, ticks: 0, settling: null };
131
+ const created = room;
132
+ room.timer = setInterval(() => tick(flow, created), tickMs);
133
+ room.timer.unref();
134
+ rooms.set(flow, room);
135
+ }
136
+ room.viewers.add(viewer);
137
+ write(viewer, "change", { at: room.last });
138
+ write(viewer, "here", { people: others(room, viewer.name) });
139
+ announce(room);
140
+ const gone = () => leave(flow, viewer);
141
+ viewer.response.once("close", gone);
142
+ },
143
+ close() {
144
+ for (const [flow, room] of [...rooms])
145
+ for (const viewer of [...room.viewers])
146
+ leave(flow, viewer);
147
+ },
148
+ size: () => [...rooms.values()].reduce((sum, room) => sum + room.viewers.size, 0),
149
+ };
150
+ }
@@ -0,0 +1,24 @@
1
+ import { type FlowAct } from "./flow-engine.js";
2
+ import type { FlowCardRow, Store } from "./store.js";
3
+ /** Everyone who may take part in a project's flows: approvers who can reach the project. */
4
+ export declare function flowPeople(store: Store, repo: string): string[];
5
+ /** The people a comment @mentions: known names only, each once, in the order written. */
6
+ export declare function mentionsIn(body: string, people: readonly string[]): string[];
7
+ type CardEvent = {
8
+ key: string;
9
+ subject: string;
10
+ body: string;
11
+ attention?: boolean;
12
+ };
13
+ /** One notification per person, to that person only. The actor never notifies themself. */
14
+ export declare function notifyPeople(store: Store, card: FlowCardRow, people: Iterable<string>, actor: string | null, event: CardEvent, now: Date): string[];
15
+ /** Who follows a card: its owner and its watchers. */
16
+ export declare function cardFollowers(store: Store, card: FlowCardRow): string[];
17
+ /** Make someone (or no one) a card's owner. The new owner follows it and hears so. */
18
+ export declare function assignFlowCard(store: Store, card: FlowCardRow, owner: string | null, actor: string, now: Date): FlowAct;
19
+ export declare function watchFlowCard(store: Store, card: FlowCardRow, name: string, watching: boolean, now: Date): FlowAct;
20
+ /** A comment on a card: keys refused; the people it @mentions, the owner and watchers hear about it; the author and anyone mentioned follow it from now on. */
21
+ export declare function commentOnFlowCard(store: Store, card: FlowCardRow, author: string, text: unknown, now: Date): FlowAct & {
22
+ mentions?: string[];
23
+ };
24
+ export {};
@@ -0,0 +1,91 @@
1
+ /**
2
+ * People on flow cards (v83): who owns a card, who follows it, what was said
3
+ * on it, and who hears about what. A notification about a card goes to the
4
+ * people it concerns — the one who decides, its owner, its watchers, whoever
5
+ * was @mentioned — on their own paired phone or chat, never to everyone.
6
+ * A "Tell the team" zone still posts to everyone; that is what it is for.
7
+ */
8
+ import { scanForSecrets } from "./evidence.js";
9
+ import { flowCardHref } from "./flow-engine.js";
10
+ /** Everyone who may take part in a project's flows: approvers who can reach the project. */
11
+ export function flowPeople(store, repo) {
12
+ return store.listApprovers().map(one => one.name).filter(name => store.accountCanAccess(name, repo));
13
+ }
14
+ /** The people a comment @mentions: known names only, each once, in the order written. */
15
+ export function mentionsIn(body, people) {
16
+ const found = [];
17
+ for (const match of body.matchAll(/(^|[^A-Za-z0-9_.@-])@([A-Za-z0-9][A-Za-z0-9_.-]{0,63})/g)) {
18
+ const name = people.find(one => one.toLowerCase() === match[2].replace(/[.-]+$/, "").toLowerCase());
19
+ if (name !== undefined && !found.includes(name))
20
+ found.push(name);
21
+ }
22
+ return found;
23
+ }
24
+ /** One notification per person, to that person only. The actor never notifies themself. */
25
+ export function notifyPeople(store, card, people, actor, event, now) {
26
+ const flow = store.getFlow(card.flow);
27
+ if (flow === null)
28
+ return [];
29
+ const sent = [];
30
+ for (const person of new Set(people)) {
31
+ if (person === actor || !store.accountCanAccess(person, flow.repo))
32
+ continue;
33
+ const queued = store.enqueueNotification({
34
+ dedupeKey: `flow-card:${card.id}:${event.key}:${person}`, kind: "flow-card", recipient: person,
35
+ ...(event.attention === true ? { pushClass: "attention" } : {}),
36
+ subject: `${flow.name}: ${event.subject}`.slice(0, 200), body: event.body.slice(0, 2000), link: flowCardHref(flow.id, card.id), source: { project: flow.repo },
37
+ }, now);
38
+ if (queued)
39
+ sent.push(person);
40
+ }
41
+ return sent;
42
+ }
43
+ /** Who follows a card: its owner and its watchers. */
44
+ export function cardFollowers(store, card) {
45
+ return [...new Set([...(card.owner === null ? [] : [card.owner]), ...store.flowCardWatchers(card.id)])];
46
+ }
47
+ /** Make someone (or no one) a card's owner. The new owner follows it and hears so. */
48
+ export function assignFlowCard(store, card, owner, actor, now) {
49
+ const flow = store.getFlow(card.flow);
50
+ if (flow === null || card.state !== "active")
51
+ return { ok: false, message: "That card is finished." };
52
+ if (owner !== null && !flowPeople(store, flow.repo).includes(owner))
53
+ return { ok: false, message: `${owner} can't work on this project.` };
54
+ if (owner === card.owner)
55
+ return { ok: true, said: owner === null ? "It has no owner." : `${owner === actor ? "You already own" : `${owner} already owns`} it.`, card: card.id };
56
+ store.setFlowCardOwner(card.id, owner, actor, now);
57
+ if (owner !== null) {
58
+ store.setFlowCardWatcher(card.id, owner, true, now);
59
+ notifyPeople(store, card, [owner], actor, { key: `owner:${now.getTime()}`, subject: `You now own “${card.title}”`, body: `${actor} made you the owner of “${card.title}”. You'll hear when it needs you or finishes.` }, now);
60
+ }
61
+ return { ok: true, said: owner === null ? "It has no owner now." : owner === actor ? "You own it now." : `${owner} owns it now.`, card: card.id };
62
+ }
63
+ export function watchFlowCard(store, card, name, watching, now) {
64
+ store.setFlowCardWatcher(card.id, name, watching, now);
65
+ return { ok: true, said: watching ? "You'll hear about this card." : "You won't hear about this card unless someone mentions you.", card: card.id };
66
+ }
67
+ /** A comment on a card: keys refused; the people it @mentions, the owner and watchers hear about it; the author and anyone mentioned follow it from now on. */
68
+ export function commentOnFlowCard(store, card, author, text, now) {
69
+ const flow = store.getFlow(card.flow);
70
+ if (flow === null)
71
+ return { ok: false, message: "That card is gone." };
72
+ const body = (typeof text === "string" ? text : "").replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, "").trim();
73
+ if (body === "")
74
+ return { ok: false, message: "Write something first." };
75
+ if (body.length > 4000)
76
+ return { ok: false, message: "Keep a comment under 4000 characters." };
77
+ if (scanForSecrets(body).length > 0)
78
+ return { ok: false, message: "That looks like a key or password. Keep secrets out of comments." };
79
+ const mentions = mentionsIn(body, flowPeople(store, flow.repo));
80
+ const followers = cardFollowers(store, card);
81
+ const id = store.transact(() => {
82
+ const made = store.addFlowComment({ card: card.id, author, body, mentions }, now);
83
+ for (const person of [author, ...mentions])
84
+ store.setFlowCardWatcher(card.id, person, true, now);
85
+ return made;
86
+ });
87
+ const quote = body.length > 280 ? `${body.slice(0, 277)}…` : body;
88
+ notifyPeople(store, card, mentions, author, { key: `mention:${id}`, subject: `${author} mentioned you on “${card.title}”`, body: quote, attention: true }, now);
89
+ notifyPeople(store, card, followers.filter(one => !mentions.includes(one)), author, { key: `comment:${id}`, subject: `${author} commented on “${card.title}”`, body: quote }, now);
90
+ return { ok: true, said: mentions.length === 0 ? "Comment added." : `Comment added. ${mentions.join(" and ")} will hear about it.`, card: card.id, mentions };
91
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Replies to a card's email (v91).
3
+ *
4
+ * A Send email step keeps the Message-ID of what it sent and whom it went
5
+ * to. An email that names one of those (In-Reply-To or References) and comes
6
+ * from someone the card wrote to is a reply to that card: it joins the card's
7
+ * discussion, and a card waiting for it in a Wait zone moves on, the reply
8
+ * kept as that zone's output ({{stage.<wait zone>}}). Anyone can copy a
9
+ * Message-ID into a header, so a message from anyone else is never taken as a
10
+ * reply; neither is a machine's (out of office, bounces).
11
+ *
12
+ * The mailbox is read for replies only while some card is in an email
13
+ * conversation, about once a minute, read-only like Inbox triggers. An Inbox
14
+ * trigger reading the same mailbox hands replies here instead of making a new
15
+ * card, and a reply both see is taken once.
16
+ */
17
+ import type { FlowCardRow, Store } from "./store.js";
18
+ import { type InboundMail, type MailReader } from "./mailbox.js";
19
+ /** Where the next email to this card's conversation goes in the thread: its latest message, and the chain before it. */
20
+ export declare function threadOf(store: Store, card: FlowCardRow): {
21
+ inReplyTo: string;
22
+ references: string[];
23
+ people: Set<string>;
24
+ } | null;
25
+ /** What a Send email step sent, kept so a reply can find the card (and the email the card came from, which a reply may name). */
26
+ export declare function recordSent(store: Store, card: FlowCardRow, sent: {
27
+ id: string;
28
+ to: string[];
29
+ }, now: Date): void;
30
+ export type Replied = {
31
+ card: FlowCardRow;
32
+ moved: boolean;
33
+ again: boolean;
34
+ };
35
+ /** Take one email as a reply to the card whose conversation it answers; null when it answers none that is active. */
36
+ export declare function takeReply(store: Store, mail: InboundMail, own: string, now: Date): Replied | null;
37
+ export type ReplyWatchIo = {
38
+ dir: string | null;
39
+ fetch: typeof fetch;
40
+ mail?: MailReader;
41
+ };
42
+ export type ReplyWatch = {
43
+ read: number;
44
+ taken: number;
45
+ problem: string | null;
46
+ };
47
+ /** Read the mailbox for replies to cards in an email conversation, when it is due. */
48
+ export declare function watchFlowReplies(store: Store, now: Date, io: ReplyWatchIo): Promise<ReplyWatch>;
@@ -0,0 +1,113 @@
1
+ import { validateFlowDefinition } from "./flows.js";
2
+ import { mailboxAccess, mailCursorOf, mailCursorText, readThroughImap } from "./mailbox.js";
3
+ import { cardFollowers, notifyPeople } from "./flow-people.js";
4
+ const WATCH_EVERY_MS = 60_000;
5
+ const BACKOFF_MS = [60_000, 5 * 60_000, 15 * 60_000];
6
+ /** A first read (or one after a long pause) looks this many messages back, so a reply that came just before isn't missed. */
7
+ const LOOK_BACK = 50;
8
+ const PER_READ = 50;
9
+ const REPLY_CHARS = 4000;
10
+ const definitionOf = (store, flow) => {
11
+ const row = store.getFlow(flow);
12
+ try {
13
+ return row === null ? null : validateFlowDefinition(JSON.parse(row.definitionJson));
14
+ }
15
+ catch {
16
+ return null;
17
+ }
18
+ };
19
+ /** Everyone a card's conversation is with: whom it wrote to, who wrote back, and who sent the email it came from. */
20
+ function peopleOf(store, card) {
21
+ const people = new Set(store.flowMailOf(card.id).flatMap(one => one.address.split(",")).filter(one => one !== ""));
22
+ if (card.source?.mail?.from)
23
+ people.add(card.source.mail.from.toLowerCase());
24
+ return people;
25
+ }
26
+ /** Where the next email to this card's conversation goes in the thread: its latest message, and the chain before it. */
27
+ export function threadOf(store, card) {
28
+ const source = card.source?.mail;
29
+ const ids = [...(source?.references ?? []), ...(source?.id ? [source.id] : []), ...store.flowMailOf(card.id).map(one => one.messageId)];
30
+ const chain = [...new Set(ids)];
31
+ const latest = chain.at(-1);
32
+ return latest === undefined ? null : { inReplyTo: latest, references: chain.slice(-20), people: peopleOf(store, card) };
33
+ }
34
+ /** What a Send email step sent, kept so a reply can find the card (and the email the card came from, which a reply may name). */
35
+ export function recordSent(store, card, sent, now) {
36
+ if (!/^<[^<>\s]{3,250}>$/.test(sent.id))
37
+ return;
38
+ store.recordFlowMail({ messageId: sent.id, card: card.id, direction: "sent", address: sent.to.map(one => one.toLowerCase()).join(",") }, now);
39
+ const source = card.source?.mail;
40
+ if (source?.id)
41
+ store.recordFlowMail({ messageId: source.id, card: card.id, direction: "received", address: source.from }, now);
42
+ }
43
+ /** Take one email as a reply to the card whose conversation it answers; null when it answers none that is active. */
44
+ export function takeReply(store, mail, own, now) {
45
+ if (mail.automatic || mail.messageId === null || mail.from === "" || mail.from === own.toLowerCase())
46
+ return null;
47
+ const named = [...new Set([mail.inReplyTo, ...[...mail.references].reverse()].filter((one) => one !== null))];
48
+ const seen = new Set();
49
+ for (const known of store.flowMailAmong(named)) {
50
+ if (seen.has(known.card))
51
+ continue;
52
+ seen.add(known.card);
53
+ const card = store.getFlowCard(known.card);
54
+ if (card === null || card.state !== "active" || !peopleOf(store, card).has(mail.from))
55
+ continue;
56
+ // A trigger and the watcher can both read it: it is taken once.
57
+ if (!store.recordFlowMail({ messageId: mail.messageId, card: card.id, direction: "received", address: mail.from }, now))
58
+ return { card, moved: false, again: true };
59
+ const text = mail.text.length > REPLY_CHARS ? `${mail.text.slice(0, REPLY_CHARS).trimEnd()}…` : mail.text;
60
+ const who = mail.fromName === null ? mail.from : `${mail.fromName} <${mail.from}>`;
61
+ store.addFlowComment({ card: card.id, author: mail.from, body: `Replied by email${mail.subject === "" ? "" : ` (“${mail.subject}”)`}:\n\n${text || "(no text)"}`, mentions: [] }, now);
62
+ const definition = definitionOf(store, card.flow);
63
+ const stage = definition?.stages.find(one => one.id === card.stage);
64
+ const waiting = stage?.kind === "wait" && stage.wait?.for === "reply" && stage.next !== null;
65
+ // The people on the card hear about it; it needs them only when the flow wasn't waiting for it.
66
+ const people = card.owner === null ? cardFollowers(store, card) : [card.owner];
67
+ notifyPeople(store, card, people, null, { key: `reply:${mail.messageId}`, subject: `${mail.fromName ?? mail.from} replied to “${card.title}”`, body: text || "(no text)", attention: !waiting }, now);
68
+ if (waiting) {
69
+ store.updateFlowCard(card.id, { outputs: { ...card.outputs, [stage.id]: `From: ${who}\n\n${text}` } }, now);
70
+ const moved = store.moveFlowCard(card.id, { to: stage.next, outcome: "ok", actor: "flow", historyNote: `${mail.from} replied`, expectEntry: card.entry }, now);
71
+ return { card, moved, again: false };
72
+ }
73
+ return { card, moved: false, again: false };
74
+ }
75
+ return null;
76
+ }
77
+ /** Read the mailbox for replies to cards in an email conversation, when it is due. */
78
+ export async function watchFlowReplies(store, now, io) {
79
+ const quiet = { read: 0, taken: 0, problem: null };
80
+ const watch = store.flowMailWatch();
81
+ if (watch.nextAt !== null && Date.parse(watch.nextAt) > now.getTime())
82
+ return quiet;
83
+ if (!store.flowConversationsOpen())
84
+ return quiet;
85
+ const failed = (said) => {
86
+ const failures = watch.failures + 1;
87
+ store.setFlowMailWatch({ cursor: watch.cursor, nextAt: new Date(now.getTime() + BACKOFF_MS[Math.min(failures, BACKOFF_MS.length) - 1]).toISOString(), failures, lastOutcome: said }, now);
88
+ return { read: 0, taken: 0, problem: said };
89
+ };
90
+ const signed = await mailboxAccess(io.dir, io.fetch);
91
+ if (!signed.ok)
92
+ return failed(signed.said);
93
+ const reader = io.mail ?? readThroughImap;
94
+ // After a long pause the mailbox may hold a lot: start again from now, looking a little way back.
95
+ const stale = watch.nextAt === null || now.getTime() - Date.parse(watch.nextAt) > 24 * 60 * 60_000;
96
+ let after = stale ? null : mailCursorOf(watch.cursor);
97
+ if (after === null) {
98
+ const where = await reader(signed.access, "INBOX", null, 0);
99
+ if (!where.ok)
100
+ return failed(where.said);
101
+ after = { validity: where.at.validity, uid: Math.max(0, where.at.uid - LOOK_BACK) };
102
+ }
103
+ const read = await reader(signed.access, "INBOX", after, PER_READ);
104
+ if (!read.ok)
105
+ return failed(read.said);
106
+ let taken = 0;
107
+ for (const mail of read.mails)
108
+ if (takeReply(store, mail, signed.address, now)?.again === false)
109
+ taken++;
110
+ store.setFlowMailWatch({ cursor: mailCursorText(read.at), nextAt: new Date(now.getTime() + (read.more ? 0 : WATCH_EVERY_MS)).toISOString(), failures: 0,
111
+ lastOutcome: taken === 0 ? "No new replies." : `${taken} ${taken === 1 ? "reply" : "replies"} taken.` }, now);
112
+ return { read: read.mails.length, taken, problem: null };
113
+ }
@@ -0,0 +1,38 @@
1
+ import { type ScriptLanguage } from "./flows.js";
2
+ import type { FlowScriptRow, Store } from "./store.js";
3
+ export type ScriptDraft = {
4
+ name: string;
5
+ about: string;
6
+ body: string;
7
+ timeoutMinutes: number;
8
+ language: ScriptLanguage;
9
+ file: string | null;
10
+ };
11
+ /** A script as it would be saved, checked in plain words. Throws. */
12
+ export declare function validateScript(input: {
13
+ name?: unknown;
14
+ about?: unknown;
15
+ body?: unknown;
16
+ timeoutMinutes?: unknown;
17
+ language?: unknown;
18
+ file?: unknown;
19
+ }): ScriptDraft;
20
+ /** What a run is held to. A shell script written here keeps its v84 digest. */
21
+ export declare const scriptDigest: (draft: Pick<ScriptDraft, "body" | "timeoutMinutes"> & Partial<Pick<ScriptDraft, "language" | "file">>) => string;
22
+ export type ScriptSaved = {
23
+ ok: true;
24
+ said: string;
25
+ version: number;
26
+ } | {
27
+ ok: false;
28
+ message: string;
29
+ };
30
+ /** Save a script (a new version when it exists). */
31
+ export declare function saveScript(store: Store, repo: string, input: Parameters<typeof validateScript>[0], actor: string, now: Date): ScriptSaved;
32
+ /** The flows and zones in a project that run each script. */
33
+ export declare function scriptUses(store: Store, repo: string): Map<string, {
34
+ flow: number;
35
+ flowName: string;
36
+ zone: string;
37
+ }[]>;
38
+ export declare function scriptWords(script: FlowScriptRow): string;