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,204 @@
1
+ /** Microsoft Teams through the Bot Framework REST surface: app credentials
2
+ * kept in an owner-only file, an outbound token per call, and inbound
3
+ * activities proved by the Bot Framework's signed token. No SDK. */
4
+ import { chmodSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { createPublicKey, randomBytes, verify as verifySignature } from "node:crypto";
7
+ import { ChatDeliveryError, chatHash } from "./chat-delivery-state.js";
8
+ import { chatObject as object } from "./chat-delivery.js";
9
+ export class TeamsError extends ChatDeliveryError {
10
+ }
11
+ export const teamsCredentialFile = (dir) => join(dir, "teams-connection.json");
12
+ const GUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
13
+ export const teamsGuid = (v) => typeof v === "string" && GUID.test(v);
14
+ const validSecret = (v) => typeof v === "string" && /^[A-Za-z0-9._~-]{16,200}$/.test(v);
15
+ export function teamsIdentity(app, tenant) {
16
+ return { installation: chatHash(`teams:${app.toLowerCase()}:${tenant.toLowerCase()}`), team: tenant.toLowerCase(), app: app.toLowerCase(), bot: `28:${app.toLowerCase()}`, workspace: "Microsoft Teams" };
17
+ }
18
+ export function loadTeamsCredentials(dir) {
19
+ try {
20
+ const v = JSON.parse(readFileSync(teamsCredentialFile(dir), "utf8"));
21
+ const identity = teamsGuid(v.app) && teamsGuid(v.tenant) ? teamsIdentity(v.app, v.tenant) : null;
22
+ return identity !== null && validSecret(v.secret) && v.installation === identity.installation && v.bot === identity.bot ? { ...identity, tenant: identity.team, secret: v.secret } : null;
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ export function saveTeamsCredentials(dir, value) {
29
+ const target = teamsCredentialFile(dir), temp = `${target}.${randomBytes(8).toString("hex")}.tmp`;
30
+ try {
31
+ writeFileSync(temp, JSON.stringify(value) + "\n", { mode: 0o600, flag: "wx" });
32
+ chmodSync(temp, 0o600);
33
+ renameSync(temp, target);
34
+ }
35
+ finally {
36
+ rmSync(temp, { force: true });
37
+ }
38
+ }
39
+ export function clearTeamsCredentials(dir) {
40
+ rmSync(teamsCredentialFile(dir), { force: true });
41
+ }
42
+ const TOKEN_URL = "https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token";
43
+ const OPENID = "https://login.botframework.com/v1/.well-known/openidconfiguration";
44
+ const ISSUERS = new Set(["https://api.botframework.com"]);
45
+ let cachedToken = null;
46
+ /** A bot access token for outbound calls (client credentials), cached until shortly before expiry. */
47
+ export async function teamsAccessToken(credentials, fetcher = fetch, now = Date.now()) {
48
+ if (cachedToken !== null && cachedToken.app === credentials.app && cachedToken.expires > now + 60_000)
49
+ return cachedToken.value;
50
+ let response;
51
+ try {
52
+ response = await fetcher(TOKEN_URL, {
53
+ method: "POST",
54
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
55
+ body: new URLSearchParams({ grant_type: "client_credentials", client_id: credentials.app, client_secret: credentials.secret, scope: "https://api.botframework.com/.default" }),
56
+ redirect: "error",
57
+ signal: AbortSignal.timeout(15_000),
58
+ });
59
+ }
60
+ catch {
61
+ throw new TeamsError("Microsoft sign-in is unreachable", 15_000, true);
62
+ }
63
+ if (response.status === 401 || response.status === 400)
64
+ throw new TeamsError("Microsoft rejected the app credentials. Check the app id, tenant and secret.", 300_000);
65
+ if (!response.ok)
66
+ throw new TeamsError("Microsoft sign-in failed", 15_000, true);
67
+ const data = object(await response.json().catch(() => ({})));
68
+ if (typeof data.access_token !== "string")
69
+ throw new TeamsError("Microsoft returned no access token", 15_000, true);
70
+ cachedToken = { app: credentials.app, value: data.access_token, expires: now + Math.max(60, Number(data.expires_in ?? 3600)) * 1000 };
71
+ return cachedToken.value;
72
+ }
73
+ export function forgetTeamsToken() { cachedToken = null; }
74
+ /** Outbound Bot Framework calls: only conversation routes, only under an https service URL Microsoft named in a signed token. */
75
+ export function teamsApi(credentials, fetcher = fetch) {
76
+ return async (method, serviceUrl, path, body) => {
77
+ if (!/^\/v3\/conversations\/[A-Za-z0-9:@._%-]+(?:\/activities(?:\/[A-Za-z0-9:._%-]+)?|\/members(?:\/[A-Za-z0-9:._%-]+)?)$/.test(path))
78
+ throw new TeamsError("Invalid Teams request");
79
+ let base;
80
+ try {
81
+ base = new URL(serviceUrl);
82
+ }
83
+ catch {
84
+ throw new TeamsError("Invalid Teams service URL");
85
+ }
86
+ if (base.protocol !== "https:" || base.username || base.password || base.search || base.hash)
87
+ throw new TeamsError("Invalid Teams service URL");
88
+ const token = await teamsAccessToken(credentials, fetcher);
89
+ let response;
90
+ try {
91
+ response = await fetcher(`${base.origin}${base.pathname.replace(/\/$/, "")}${path}`, {
92
+ method,
93
+ headers: { Authorization: `Bearer ${token}`, ...(body ? { "Content-Type": "application/json" } : {}) },
94
+ ...(body ? { body: JSON.stringify(body) } : {}),
95
+ redirect: "error",
96
+ signal: AbortSignal.timeout(15_000),
97
+ });
98
+ }
99
+ catch {
100
+ throw new TeamsError("Teams is unreachable", 15_000, true);
101
+ }
102
+ if (response.status === 401) {
103
+ forgetTeamsToken();
104
+ throw new TeamsError("Teams rejected the bot token", 30_000);
105
+ }
106
+ if (response.status === 429)
107
+ throw new TeamsError("Teams asked to slow down", Math.max(5, Number(response.headers.get("retry-after") ?? 5)) * 1000);
108
+ if (!response.ok)
109
+ throw new TeamsError(`Teams refused the request (${response.status})`, 15_000, response.status >= 500);
110
+ const text = await response.text();
111
+ if (text.trim() === "")
112
+ return {};
113
+ try {
114
+ return object(JSON.parse(text));
115
+ }
116
+ catch {
117
+ return {};
118
+ }
119
+ };
120
+ }
121
+ /** Confirm the app can sign in; the tenant and app id shape the installation identity. */
122
+ export async function checkTeamsCredentials(app, tenant, secret, fetcher = fetch) {
123
+ if (!teamsGuid(app) || !teamsGuid(tenant))
124
+ throw new TeamsError("Enter the app (client) id and the directory (tenant) id from Microsoft Entra");
125
+ if (!validSecret(secret))
126
+ throw new TeamsError("Enter the app's client secret");
127
+ const identity = teamsIdentity(app, tenant);
128
+ forgetTeamsToken();
129
+ await teamsAccessToken({ app: identity.app, secret }, fetcher);
130
+ return { ...identity, tenant: identity.team, secret };
131
+ }
132
+ let keyCache = null;
133
+ async function signingKeys(fetcher, now) {
134
+ if (keyCache !== null && keyCache.fetched + 86_400_000 > now)
135
+ return keyCache.keys;
136
+ const config = object(await (await fetcher(OPENID, { signal: AbortSignal.timeout(15_000) })).json());
137
+ if (typeof config.jwks_uri !== "string" || !config.jwks_uri.startsWith("https://"))
138
+ throw new TeamsError("Bot Framework key metadata is unavailable", 15_000, true);
139
+ const jwks = object(await (await fetcher(config.jwks_uri, { signal: AbortSignal.timeout(15_000) })).json());
140
+ const keys = Array.isArray(jwks.keys) ? jwks.keys : [];
141
+ keyCache = { fetched: now, keys };
142
+ return keys;
143
+ }
144
+ export function forgetTeamsKeys() { keyCache = null; }
145
+ const b64url = (value) => Buffer.from(value.replace(/-/g, "+").replace(/_/g, "/"), "base64");
146
+ /**
147
+ * Prove an inbound activity came from the Bot Framework for this app: an
148
+ * RS256 token from the Bot Framework issuer, for this app id, not expired,
149
+ * signed by a published key. The serviceurl claim must match the activity
150
+ * so a stolen token cannot redirect replies.
151
+ */
152
+ export async function verifyTeamsToken(header, appId, fetcher = fetch, now = Date.now()) {
153
+ const match = /^Bearer ([A-Za-z0-9_-]+)\.([A-Za-z0-9_-]+)\.([A-Za-z0-9_-]+)$/.exec(header ?? "");
154
+ if (match === null)
155
+ return null;
156
+ let head, claims;
157
+ try {
158
+ head = object(JSON.parse(b64url(match[1]).toString("utf8")));
159
+ claims = object(JSON.parse(b64url(match[2]).toString("utf8")));
160
+ }
161
+ catch {
162
+ return null;
163
+ }
164
+ if (head.alg !== "RS256" || typeof head.kid !== "string")
165
+ return null;
166
+ if (typeof claims.iss !== "string" || !ISSUERS.has(claims.iss))
167
+ return null;
168
+ const audience = Array.isArray(claims.aud) ? claims.aud : [claims.aud];
169
+ if (!audience.some(one => typeof one === "string" && one.toLowerCase() === appId.toLowerCase()))
170
+ return null;
171
+ if (typeof claims.exp !== "number" || claims.exp * 1000 < now - 300_000)
172
+ return null;
173
+ if (typeof claims.nbf === "number" && claims.nbf * 1000 > now + 300_000)
174
+ return null;
175
+ let keys;
176
+ try {
177
+ keys = await signingKeys(fetcher, now);
178
+ }
179
+ catch {
180
+ return null;
181
+ }
182
+ let key = keys.find(one => one.kid === head.kid);
183
+ if (key === undefined && keyCache !== null) {
184
+ keyCache = null;
185
+ try {
186
+ key = (await signingKeys(fetcher, now)).find(one => one.kid === head.kid);
187
+ }
188
+ catch {
189
+ return null;
190
+ }
191
+ }
192
+ if (key === undefined || key.kty !== "RSA" || typeof key.n !== "string" || typeof key.e !== "string")
193
+ return null;
194
+ try {
195
+ const publicKey = createPublicKey({ key: { kty: "RSA", n: key.n, e: key.e }, format: "jwk" });
196
+ const ok = verifySignature("RSA-SHA256", Buffer.from(`${match[1]}.${match[2]}`, "utf8"), publicKey, b64url(match[3]));
197
+ if (!ok)
198
+ return null;
199
+ }
200
+ catch {
201
+ return null;
202
+ }
203
+ return { appId, serviceUrl: typeof claims.serviceurl === "string" ? claims.serviceurl : null };
204
+ }
@@ -0,0 +1,26 @@
1
+ import { ChatState, type ChatIdentity } from "./chat-delivery-state.js";
2
+ import { type ChatDeliveryOptions } from "./chat-delivery.js";
3
+ import { type TeamsApi } from "./teams-api.js";
4
+ export type TeamsChatOptions = Omit<ChatDeliveryOptions, "state" | "label" | "member" | "partSize" | "maxProposal"> & {
5
+ api: TeamsApi;
6
+ };
7
+ export declare const teamsUserId: (v: unknown) => v is string;
8
+ /** A conversation id; a channel post's carries its thread as ";messageid=<first message>" (v89). */
9
+ export declare const teamsConversationId: (v: unknown) => v is string;
10
+ export declare function teamsMember(api: TeamsApi, state: ChatState, installation: string, member: string, channel: string): Promise<boolean>;
11
+ export declare const teamsDelivery: (options: TeamsChatOptions) => ChatDeliveryOptions;
12
+ export declare const processTeamsEvent: (options: TeamsChatOptions) => Promise<boolean>;
13
+ export declare const planTeamsRooms: (options: TeamsChatOptions) => Promise<void>;
14
+ export declare const planTeamsNotifications: (options: TeamsChatOptions) => Promise<void>;
15
+ /**
16
+ * Save one Bot Framework activity before it is acknowledged: a personal
17
+ * message (or `pair <code>`), a channel message where the bot was mentioned,
18
+ * or an Adaptive Card submit carrying one of our tokens. The token that
19
+ * authenticated the request is never stored; only the service URL the
20
+ * conversation replies through is kept, per conversation.
21
+ */
22
+ export declare function receiveTeams(state: ChatState, identity: ChatIdentity, raw: unknown, serviceUrlClaim: string | null, now: Date): boolean;
23
+ /** One Adaptive Card: plain text, then the buttons (submit tokens, or one link). */
24
+ export declare function teamsCard(text: string, actions: Record<string, unknown>[]): Record<string, unknown>;
25
+ /** Send the next pending part: a plain message, an edit, or a card with its tokens. */
26
+ export declare function deliverTeamsPart(options: TeamsChatOptions): Promise<boolean>;
@@ -0,0 +1,215 @@
1
+ /** Microsoft Teams on the shared chat layer: activities in, Adaptive Cards
2
+ * out, the same durable receipts, rooms and commands as every other channel. */
3
+ import { chatQuestionButtons } from "./teammate-question.js";
4
+ import { ChatState, chatHash } from "./chat-delivery-state.js";
5
+ import { channelAccess, chatObject as object, planChatNotifications, planRoomMessages, processChatEvent } from "./chat-delivery.js";
6
+ import { roomCommand } from "./chat-rooms.js";
7
+ import { MATE_MESSAGE_MAX_CHARS } from "./mate.js";
8
+ import { armedCardText, armedYesLabel, proposalLink, proposalOutcomeText, proposalPreview } from "./chat-channel.js";
9
+ import { chatFlowButtons } from "./chat-flow.js";
10
+ import { channelInbox } from "./chat-inbox.js";
11
+ import { chatResultHref } from "./chat-controls.js";
12
+ import { TeamsError } from "./teams-api.js";
13
+ const serviceKey = (conversation) => `serviceUrl:${conversation}`;
14
+ export const teamsUserId = (v) => typeof v === "string" && /^29:[A-Za-z0-9_=-]{10,200}$/.test(v);
15
+ /** A conversation id; a channel post's carries its thread as ";messageid=<first message>" (v89). */
16
+ export const teamsConversationId = (v) => typeof v === "string" && /^[A-Za-z0-9:@._%-]{8,300}(;messageid=[0-9]{1,20})?$/.test(v);
17
+ const validServiceUrl = (v) => {
18
+ if (typeof v !== "string")
19
+ return false;
20
+ try {
21
+ const url = new URL(v);
22
+ return url.protocol === "https:" && !url.username && !url.password && !url.search && !url.hash;
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ };
28
+ export async function teamsMember(api, state, installation, member, channel) {
29
+ const serviceUrl = state.meta(installation, serviceKey(channel));
30
+ if (serviceUrl === null)
31
+ return false;
32
+ try {
33
+ const found = await api("GET", serviceUrl, `/v3/conversations/${encodeURIComponent(channel)}/members/${encodeURIComponent(member)}`);
34
+ return found.id === member;
35
+ }
36
+ catch (error) {
37
+ if (error instanceof TeamsError && error.uncertain)
38
+ throw error;
39
+ return false;
40
+ }
41
+ }
42
+ export const teamsDelivery = (options) => {
43
+ const state = new ChatState(options.store, "teams");
44
+ return {
45
+ ...options,
46
+ state,
47
+ label: "Teams",
48
+ member: (member, channel) => teamsMember(options.api, state, options.identity.installation, member, channel),
49
+ partSize: 3500,
50
+ maxProposal: 6000,
51
+ };
52
+ };
53
+ export const processTeamsEvent = (options) => processChatEvent(teamsDelivery(options));
54
+ export const planTeamsRooms = (options) => planRoomMessages(teamsDelivery(options));
55
+ export const planTeamsNotifications = (options) => planChatNotifications(teamsDelivery(options));
56
+ /** Strip the bot's own mention from channel text; Teams delivers channel messages only when the bot is mentioned. */
57
+ function withoutMentions(text) {
58
+ return text.replace(/<at>[^<]*<\/at>/g, "").replace(/\s+/g, " ").trim();
59
+ }
60
+ /**
61
+ * Save one Bot Framework activity before it is acknowledged: a personal
62
+ * message (or `pair <code>`), a channel message where the bot was mentioned,
63
+ * or an Adaptive Card submit carrying one of our tokens. The token that
64
+ * authenticated the request is never stored; only the service URL the
65
+ * conversation replies through is kept, per conversation.
66
+ */
67
+ export function receiveTeams(state, identity, raw, serviceUrlClaim, now) {
68
+ const activity = object(raw);
69
+ if (activity.type !== "message")
70
+ return false;
71
+ const conversation = object(activity.conversation), from = object(activity.from), recipient = object(activity.recipient);
72
+ const channel = conversation.id, member = from.id, id = activity.id;
73
+ const isRoom = conversation.conversationType === "channel" || conversation.conversationType === "groupChat";
74
+ if (!teamsConversationId(channel) || !teamsUserId(member) || typeof id !== "string" || id.length > 200)
75
+ return false;
76
+ if (recipient.id !== identity.bot || (typeof conversation.tenantId === "string" && conversation.tenantId.toLowerCase() !== identity.team))
77
+ return false;
78
+ if (!validServiceUrl(activity.serviceUrl) || (serviceUrlClaim !== null && serviceUrlClaim.replace(/\/$/, "") !== activity.serviceUrl.replace(/\/$/, "")))
79
+ return false;
80
+ if (!isRoom && conversation.conversationType !== "personal")
81
+ return false;
82
+ const value = object(activity.value);
83
+ const submitted = typeof value.so === "string" && /^[a-f0-9]{32}$/.test(value.so) ? value.so : null;
84
+ let kind, payload, eventId;
85
+ if (submitted !== null) {
86
+ kind = "action";
87
+ payload = { token: submitted };
88
+ eventId = chatHash(`${identity.installation}:action:${member}:${activity.replyToId ?? id}:${submitted}`);
89
+ }
90
+ else {
91
+ if (typeof activity.text !== "string")
92
+ return false;
93
+ const text = isRoom ? withoutMentions(activity.text) : activity.text.trim();
94
+ const pair = /^pair ([a-f0-9]{32})$/.exec(text);
95
+ kind = pair ? "pair" : "message";
96
+ payload = pair ? { hash: chatHash(pair[1]) } : { text: text.slice(0, MATE_MESSAGE_MAX_CHARS + 1), originalLength: text.length,
97
+ ...(Array.isArray(activity.attachments) && activity.attachments.length > 0 ? { unsupported: "Incoming files are not supported yet. Describe the request in a message; saved result screenshots open from their links." } : {}) };
98
+ eventId = chatHash(`${identity.installation}:message:${id}`);
99
+ }
100
+ // v89: a channel that feeds a flow takes anyone's message (as a card, with no say over anything); "flow 12" connects one.
101
+ const inbox = isRoom && kind === "message" ? channelInbox(state.store, "teams", identity.installation, channel, String(payload.text ?? "")) : { watched: false, command: false };
102
+ const roomish = isRoom && (state.room(identity.installation, channel) !== null || (kind === "message" && roomCommand(String(payload.text ?? "")) !== null) || inbox.watched || inbox.command);
103
+ if (isRoom && !roomish)
104
+ return false;
105
+ const binding = state.bindingFor(identity.installation, member);
106
+ const open = inbox.watched && !inbox.command;
107
+ if (kind === "pair" ? !!binding || isRoom : !open && (!binding || !state.live(binding) || (binding.channel !== channel && !roomish)))
108
+ return false;
109
+ return state.store.transact(() => {
110
+ state.setMeta(identity.installation, serviceKey(channel), activity.serviceUrl, now);
111
+ return state.enqueue({
112
+ id: eventId, installation: identity.installation, binding: kind === "pair" || binding === null ? null : binding.id, kind, channel, member,
113
+ ts: submitted !== null ? String(activity.replyToId ?? id) : id, thread: submitted !== null ? String(activity.replyToId ?? id) : id,
114
+ payload: JSON.stringify(payload), created: now.toISOString(),
115
+ });
116
+ });
117
+ }
118
+ function openUrlAction(origin, target) {
119
+ if (!origin || !target || !target.path.startsWith("/") || target.path.startsWith("//"))
120
+ return [];
121
+ try {
122
+ const url = new URL(origin);
123
+ if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash)
124
+ return [];
125
+ return [{ type: "Action.OpenUrl", title: target.label.slice(0, 80), url: url.origin + target.path }];
126
+ }
127
+ catch {
128
+ return [];
129
+ }
130
+ }
131
+ /** One Adaptive Card: plain text, then the buttons (submit tokens, or one link). */
132
+ export function teamsCard(text, actions) {
133
+ return {
134
+ type: "message",
135
+ attachments: [{
136
+ contentType: "application/vnd.microsoft.card.adaptive",
137
+ content: { type: "AdaptiveCard", version: "1.4", $schema: "http://adaptivecards.io/schemas/adaptive-card.json",
138
+ body: [{ type: "TextBlock", text: text.slice(0, 6000), wrap: true }], ...(actions.length ? { actions } : {}) },
139
+ }],
140
+ };
141
+ }
142
+ /** Send the next pending part: a plain message, an edit, or a card with its tokens. */
143
+ export async function deliverTeamsPart(options) {
144
+ const shared = teamsDelivery(options), state = shared.state, { store, identity } = options, now = options.clock?.() ?? new Date();
145
+ if (!options.current() || !state.owns(identity.installation, options.owner, now))
146
+ return false;
147
+ const row = state.prepare("SELECT p.* FROM chat_part p JOIN chat_event e ON e.id=p.event WHERE e.installation=? AND p.state='pending' AND (e.kind!='notice' OR ?=1) AND (p.next_at IS NULL OR p.next_at<=?) ORDER BY p.created,p.id LIMIT 1").get(identity.installation, options.canNotify?.() === false ? 0 : 1, now.toISOString());
148
+ if (!row)
149
+ return false;
150
+ const event = state.event(row.event), binding = event.binding === null ? null : state.bindingById(event.binding);
151
+ if (!binding || new Date(row.created).getTime() + 86_400_000 < now.getTime()) {
152
+ state.prepare("UPDATE chat_part SET state='dropped',problem='Delivery expired or access changed; open the saved chat' WHERE id=?").run(row.id);
153
+ return true;
154
+ }
155
+ try {
156
+ const session = event.session === null ? null : store.getMateSession(event.session);
157
+ const repos = await channelAccess(shared, binding, session?.ceilingDigest);
158
+ if (event.kind === "notice" && options.canNotify?.() === false)
159
+ return false;
160
+ const content = JSON.parse(row.payload);
161
+ const destination = content.channel ?? binding.channel;
162
+ const serviceUrl = state.meta(identity.installation, serviceKey(destination));
163
+ if (serviceUrl === null)
164
+ throw new TeamsError("This Teams conversation has no known service address yet; send it a message first", 60_000);
165
+ if (content.task && !repos.includes(store.lookupRef(content.task)?.repo ?? ""))
166
+ throw new TeamsError("Connected projects changed");
167
+ let text = content.text, actions = [];
168
+ if (content.image) {
169
+ text = `${content.text}\n\nScreenshots open from the saved result.`;
170
+ actions = openUrlAction(options.origin(), { label: "Open result", path: chatResultHref(content.image.taskId, content.image.run, "checks") });
171
+ }
172
+ if (content.proposal) {
173
+ const proposal = store.getMateProposal(content.proposal);
174
+ if (!proposal)
175
+ text = "This proposal is unavailable.";
176
+ else if (proposal.state !== "pending")
177
+ text = proposalOutcomeText(proposal);
178
+ else {
179
+ const preview = proposalPreview(store, proposal, repos, "teams");
180
+ text = content.phase === "armed" ? armedCardText(proposal, preview.text) : preview.text.replace("\n\nConfirm or Dismiss below. Nothing changes until you confirm.", "");
181
+ if (preview.buttons && preview.text.length <= 6000) {
182
+ actions = state.prepare("SELECT token,phase FROM chat_action WHERE part=? AND consumed IS NULL AND expires>? ORDER BY rowid").all(row.id, now.toISOString())
183
+ .map(action => ({ type: "Action.Submit", title: action.phase === "yes" ? armedYesLabel(proposal) : action.phase === "cancel" ? "Cancel" : action.phase === "dismiss" ? "Dismiss" : "Confirm", data: { so: String(action.token) } }));
184
+ if (!actions.length)
185
+ text = "This confirmation expired. Ask for a fresh proposal.";
186
+ }
187
+ else {
188
+ actions = openUrlAction(options.origin(), proposalLink(store, proposal, repos, "teams") ?? { label: "Review action", path: "/chat" });
189
+ text = "Review the full action in Toolroll before confirming.";
190
+ }
191
+ }
192
+ }
193
+ else if (!content.image) {
194
+ // A flow decision (v88): Approve / Edit / Send back, then the link.
195
+ const flow = content.flow ? chatFlowButtons(state, row.id, now).map(one => ({ type: "Action.Submit", title: one.label, data: { so: one.token }, ...(one.action === "approve" ? { style: "positive" } : {}) })) : [];
196
+ // A teammate's question (v93): its options, then "Answer in words".
197
+ const asked = content.question ? chatQuestionButtons(state, row.id, now).map(one => ({ type: "Action.Submit", title: one.label.slice(0, 80), data: { so: one.token } })) : [];
198
+ actions = [...flow, ...asked, ...openUrlAction(options.origin(), content.link)];
199
+ }
200
+ const target = content.edit ?? row.message;
201
+ const body = actions.length || content.proposal ? teamsCard(text, actions) : { type: "message", text, textFormat: "plain" };
202
+ const answer = await options.api(target ? "PUT" : "POST", serviceUrl, `/v3/conversations/${encodeURIComponent(destination)}/activities${target ? `/${encodeURIComponent(target)}` : ""}`, body);
203
+ const messageId = target ?? (typeof answer.id === "string" ? answer.id : null);
204
+ if (messageId === null)
205
+ throw new TeamsError("Teams did not confirm the message", 15_000, true);
206
+ state.prepare("UPDATE chat_part SET state='sent',message=?,attempts=attempts+1,next_at=NULL,problem=NULL WHERE id=?").run(messageId, row.id);
207
+ return true;
208
+ }
209
+ catch (error) {
210
+ const problem = error instanceof TeamsError ? error : new TeamsError("Teams delivery failed", 15_000, true);
211
+ state.prepare("UPDATE chat_part SET attempts=attempts+1,uncertain=?,next_at=?,problem=?,state=CASE WHEN attempts>=20 THEN 'dropped' ELSE state END WHERE id=?")
212
+ .run(problem.uncertain ? 1 : 0, new Date(now.getTime() + problem.retryMs).toISOString(), problem.message, row.id);
213
+ return true;
214
+ }
215
+ }
@@ -0,0 +1,12 @@
1
+ /** Settings → Teams: connect the Entra app once (operator), then each
2
+ * teammate pairs their own Teams account. The messaging endpoint the bot
3
+ * registration must point at is shown here; it has to be reachable from the
4
+ * internet, which a tailnet-only address is not. */
5
+ import type { Store } from "./store.js";
6
+ export declare function teamsSettingsHtml(store: Store, dir: string, csrf: string, options?: {
7
+ code?: string;
8
+ problem?: string;
9
+ now?: Date;
10
+ who?: string;
11
+ publicUrl?: string | null;
12
+ }): string;
@@ -0,0 +1,57 @@
1
+ import { ChatState } from "./chat-delivery-state.js";
2
+ import { loadTeamsCredentials } from "./teams-api.js";
3
+ import { loadPrimary } from "./webhooks.js";
4
+ import { TEAMS_MESSAGES_PATH } from "./teams.js";
5
+ const escape = (text) => text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
6
+ export function teamsSettingsHtml(store, dir, csrf, options = {}) {
7
+ const credentials = loadTeamsCredentials(dir), state = new ChatState(store, "teams");
8
+ const bindings = credentials ? state.bindings(credentials.installation).filter(one => state.live(one)) : [];
9
+ const binding = options.who === undefined ? null : bindings.find(one => one.approver === options.who) ?? null;
10
+ const others = bindings.length - (binding === null ? 0 : 1);
11
+ const runtime = credentials ? state.db.prepare("SELECT connected,problem,lease_until FROM teams_runtime WHERE installation=?").get(credentials.installation) : null;
12
+ const now = options.now ?? new Date();
13
+ const live = runtime && typeof runtime.lease_until === "string" && runtime.lease_until > now.toISOString() && runtime.connected;
14
+ const hidden = `<input type="hidden" name="csrf" value="${escape(csrf)}">`;
15
+ const password = '<label>Your Toolroll password<input style="min-height:44px" type="password" name="password" autocomplete="current-password" required></label>';
16
+ const post = (action, content) => `<form method="post" action="/settings/teams/${action}" class="card">${hidden}${content}</form>`;
17
+ const endpoint = options.publicUrl ? `${options.publicUrl.replace(/\/$/, "")}${TEAMS_MESSAGES_PATH}` : null;
18
+ let content = "";
19
+ if (!credentials) {
20
+ content =
21
+ "<p>Manage projects and review results in a Teams chat, and let a channel follow a team conversation.</p>" +
22
+ '<details open><summary>Register the bot</summary><ol><li>In <a href="https://portal.azure.com" target="_blank" rel="noopener noreferrer">Azure</a>, create an <em>Azure Bot</em> with a new single-tenant app registration; note the app (client) id and the directory (tenant) id, and create a client secret.</li>' +
23
+ `<li>Set its messaging endpoint to <code>${endpoint === null ? "https://your-public-address" + TEAMS_MESSAGES_PATH : escape(endpoint)}</code>. Microsoft must reach it from the internet: a tailnet-only address needs Tailscale Funnel (or another public tunnel) on that path.</li>` +
24
+ "<li>Enable the Microsoft Teams channel on the bot, then add the app to Teams (personal scope; team scope for channels).</li></ol></details>" +
25
+ post("connect", '<label>App (client) id<input style="min-height:44px" type="text" name="app-id" autocomplete="off" required></label>' +
26
+ '<label>Directory (tenant) id<input style="min-height:44px" type="text" name="tenant" autocomplete="off" required></label>' +
27
+ '<label>Client secret<input style="min-height:44px" type="password" name="secret" autocomplete="off" required></label>' +
28
+ password + '<p class="meta">The secret stays on this installation. Next, pair your own Teams account.</p><button type="submit">Connect Teams</button>');
29
+ }
30
+ else {
31
+ content = `<p><strong>Microsoft Teams</strong> · ${live ? "Signed in" : "Waiting for sign-in"}</p>`;
32
+ if (endpoint !== null)
33
+ content += `<p class="meta">Messaging endpoint: <code>${escape(endpoint)}</code> — must be reachable from the internet.</p>`;
34
+ if (runtime?.problem)
35
+ content += `<p role="status">${escape(String(runtime.problem))}</p>`;
36
+ if (!live && !runtime?.problem)
37
+ content += "<p>Keep the Toolroll worker running to answer Teams messages.</p>";
38
+ if (options.code) {
39
+ content += "<h2>Pair your account</h2><p>Send this to the Toolroll bot in a personal Teams chat. It expires in 10 minutes.</p>" +
40
+ `<label>Pairing message<input type="text" readonly value="pair ${escape(options.code)}" autocomplete="off" style="width:100%;max-width:100%;font-size:14px;min-height:44px"></label>` +
41
+ '<a class="button-link" style="min-height:44px;white-space:nowrap" href="/settings/teams">Check connection</a>';
42
+ }
43
+ else if (binding && state.live(binding)) {
44
+ content += `<p>Your Teams account is paired.${others ? ` ${others} teammate${others === 1 ? " is" : "s are"} paired too.` : ""}</p>` +
45
+ "<p>Try “What needs my attention?” or send <code>status</code>. In a channel, mention the bot with <code>team</code> to follow a conversation.</p>" +
46
+ '<p><a href="/chat">Open saved chat</a></p>' +
47
+ (loadPrimary(process.env, dir) === "teams" ? "<p>Task updates are sent here.</p>" : post("alerts", '<button type="submit">Send task updates here</button>')) +
48
+ post("unpair", password + '<p class="meta">Unpairing ends every open button in your chat. Teammates are unaffected.</p><button type="submit">Unpair my account</button>');
49
+ }
50
+ else {
51
+ content += post("pair", "<h2>Pair your account</h2><p>Your paired Teams account can read your connected projects and confirm proposed changes. Password approvals still open in Toolroll." +
52
+ (others ? ` ${others} teammate${others === 1 ? " is" : "s are"} already paired.` : "") + "</p>" + password + '<button type="submit">Create pairing code</button>');
53
+ }
54
+ content += "<details><summary>Connection settings</summary>" + post("disconnect", password + '<button type="submit">Disconnect Teams</button>') + "</details>";
55
+ }
56
+ return `<section style="max-width:42rem;overflow-wrap:anywhere"><p><a href="/settings">Settings</a></p><h1>Teams</h1>${options.problem ? `<p class="problem" role="alert">${escape(options.problem)}</p>` : ""}${content}</section>`;
57
+ }
@@ -0,0 +1,21 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import { chatObject as object } from "./chat-delivery.js";
3
+ import { type TeamsChatOptions } from "./teams-chat.js";
4
+ import type { Store } from "./store.js";
5
+ export declare const TEAMS_ACTIVITY_BYTES: number;
6
+ export declare const TEAMS_MESSAGES_PATH = "/teams/messages";
7
+ /** The receiver: prove the Bot Framework token for this app, save the activity, acknowledge. Nothing runs here. */
8
+ export declare function handleTeamsHttp(request: IncomingMessage, response: ServerResponse, options: {
9
+ store: Store;
10
+ dir: string;
11
+ fetcher?: typeof fetch;
12
+ clock?: () => Date;
13
+ }): Promise<boolean>;
14
+ /** The worker-side loop: a lease per installation, one pass a second. */
15
+ export declare function followTeams(options: Omit<TeamsChatOptions, "identity" | "api" | "owner" | "current"> & {
16
+ dir: string;
17
+ signal: AbortSignal;
18
+ notifications: () => boolean;
19
+ fetcher?: typeof fetch;
20
+ }): Promise<void>;
21
+ export { object };