cli-jaw 2.2.19 → 2.2.21

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 (440) hide show
  1. package/README.md +97 -3
  2. package/dist/bin/commands/dispatch.js +62 -16
  3. package/dist/bin/commands/dispatch.js.map +1 -1
  4. package/dist/server.js +14 -0
  5. package/dist/server.js.map +1 -1
  6. package/dist/src/agent/spawn/process-kill.js +96 -2
  7. package/dist/src/agent/spawn/process-kill.js.map +1 -1
  8. package/dist/src/agent/spawn.js +34 -65
  9. package/dist/src/agent/spawn.js.map +1 -1
  10. package/dist/src/bgtask/runner.js +26 -21
  11. package/dist/src/bgtask/runner.js.map +1 -1
  12. package/dist/src/cli/acp-client.js +11 -5
  13. package/dist/src/cli/acp-client.js.map +1 -1
  14. package/dist/src/cli/cli-status-worker.js +22 -3
  15. package/dist/src/cli/cli-status-worker.js.map +1 -1
  16. package/dist/src/cli/cli-status.js +7 -1
  17. package/dist/src/cli/cli-status.js.map +1 -1
  18. package/dist/src/cli/employee-handler.js +3 -2
  19. package/dist/src/cli/employee-handler.js.map +1 -1
  20. package/dist/src/cli/handlers.js +1 -0
  21. package/dist/src/cli/handlers.js.map +1 -1
  22. package/dist/src/code-mode/acp-host.js +22 -10
  23. package/dist/src/code-mode/acp-host.js.map +1 -1
  24. package/dist/src/core/config.js +23 -0
  25. package/dist/src/core/config.js.map +1 -1
  26. package/dist/src/core/db.js +16 -0
  27. package/dist/src/core/db.js.map +1 -1
  28. package/dist/src/core/dispatch-approval-ingress.js +59 -0
  29. package/dist/src/core/dispatch-approval-ingress.js.map +1 -0
  30. package/dist/src/core/dispatch-approval.js +135 -0
  31. package/dist/src/core/dispatch-approval.js.map +1 -0
  32. package/dist/src/core/employees.js +22 -4
  33. package/dist/src/core/employees.js.map +1 -1
  34. package/dist/src/core/runtime-settings.js +27 -0
  35. package/dist/src/core/runtime-settings.js.map +1 -1
  36. package/dist/src/core/serve-log.js +66 -0
  37. package/dist/src/core/serve-log.js.map +1 -0
  38. package/dist/src/core/settings-merge.js +10 -1
  39. package/dist/src/core/settings-merge.js.map +1 -1
  40. package/dist/src/core/windows-shell.js +63 -0
  41. package/dist/src/core/windows-shell.js.map +1 -0
  42. package/dist/src/discord/bot.js +214 -147
  43. package/dist/src/discord/bot.js.map +1 -1
  44. package/dist/src/discord/gateway-supervisor.js +303 -0
  45. package/dist/src/discord/gateway-supervisor.js.map +1 -0
  46. package/dist/src/discord/rest-scheduler.js +448 -0
  47. package/dist/src/discord/rest-scheduler.js.map +1 -0
  48. package/dist/src/discord/send-only-client.js +90 -43
  49. package/dist/src/discord/send-only-client.js.map +1 -1
  50. package/dist/src/manager/lifecycle.js +7 -2
  51. package/dist/src/manager/lifecycle.js.map +1 -1
  52. package/dist/src/manager/notes/capabilities.js +9 -7
  53. package/dist/src/manager/notes/capabilities.js.map +1 -1
  54. package/dist/src/memory/bootstrap.js +5 -1
  55. package/dist/src/memory/bootstrap.js.map +1 -1
  56. package/dist/src/memory/host-toolchain.js +156 -0
  57. package/dist/src/memory/host-toolchain.js.map +1 -0
  58. package/dist/src/messaging/channel-capabilities.js +30 -0
  59. package/dist/src/messaging/channel-capabilities.js.map +1 -0
  60. package/dist/src/messaging/delivery-outcome.js +73 -0
  61. package/dist/src/messaging/delivery-outcome.js.map +1 -0
  62. package/dist/src/messaging/draft-stream.js +154 -0
  63. package/dist/src/messaging/draft-stream.js.map +1 -0
  64. package/dist/src/messaging/runtime.js +3 -9
  65. package/dist/src/messaging/runtime.js.map +1 -1
  66. package/dist/src/messaging/send.js +40 -8
  67. package/dist/src/messaging/send.js.map +1 -1
  68. package/dist/src/messaging/types.js +22 -1
  69. package/dist/src/messaging/types.js.map +1 -1
  70. package/dist/src/notes/search.js +6 -4
  71. package/dist/src/notes/search.js.map +1 -1
  72. package/dist/src/prompt/builder.js +110 -6
  73. package/dist/src/prompt/builder.js.map +1 -1
  74. package/dist/src/prompt/conversation-context.js +23 -0
  75. package/dist/src/prompt/conversation-context.js.map +1 -0
  76. package/dist/src/prompt/templates/a1-system.md +28 -12
  77. package/dist/src/prompt/templates/control-system.md +19 -6
  78. package/dist/src/prompt/templates/employee.md +16 -3
  79. package/dist/src/routes/orchestrate.js +83 -0
  80. package/dist/src/routes/orchestrate.js.map +1 -1
  81. package/dist/src/security/path-guards.js +157 -27
  82. package/dist/src/security/path-guards.js.map +1 -1
  83. package/dist/src/slack/api.js +38 -5
  84. package/dist/src/slack/api.js.map +1 -1
  85. package/dist/src/slack/bot.js +244 -37
  86. package/dist/src/slack/bot.js.map +1 -1
  87. package/dist/src/slack/context.js +192 -0
  88. package/dist/src/slack/context.js.map +1 -0
  89. package/dist/src/slack/conversation.js +275 -0
  90. package/dist/src/slack/conversation.js.map +1 -0
  91. package/dist/src/slack/enrichment-cache.js +334 -0
  92. package/dist/src/slack/enrichment-cache.js.map +1 -0
  93. package/dist/src/slack/history.js +47 -8
  94. package/dist/src/slack/history.js.map +1 -1
  95. package/dist/src/slack/identity.js +99 -190
  96. package/dist/src/slack/identity.js.map +1 -1
  97. package/dist/src/slack/ingress.js +91 -3
  98. package/dist/src/slack/ingress.js.map +1 -1
  99. package/dist/src/slack/progress.js +39 -51
  100. package/dist/src/slack/progress.js.map +1 -1
  101. package/dist/src/slack/thread-tracker.js +88 -0
  102. package/dist/src/slack/thread-tracker.js.map +1 -1
  103. package/dist/src/telegram/bot.js +127 -56
  104. package/dist/src/telegram/bot.js.map +1 -1
  105. package/dist/src/telegram/update-offset.js +152 -0
  106. package/dist/src/telegram/update-offset.js.map +1 -0
  107. package/package.json +1 -1
  108. package/public/dist/assets/{AdvancedExport-c41zCkwB.js → AdvancedExport-IOkupLFE.js} +1 -1
  109. package/public/dist/assets/Agent-DtgCvkB_.js +1 -0
  110. package/public/dist/assets/{Browser-B52Bdaeu.js → Browser-J4TPo4bX.js} +1 -1
  111. package/public/dist/assets/{BrowserPanel-Bh3JpkZO.js → BrowserPanel-C0aa2gja.js} +1 -1
  112. package/public/dist/assets/{ChannelsDiscord-D9FLnZso.js → ChannelsDiscord-D4fD-9hP.js} +1 -1
  113. package/public/dist/assets/{ChannelsSlack-CVNKtoo4.js → ChannelsSlack-_KBwRonM.js} +1 -1
  114. package/public/dist/assets/{ChannelsTelegram-BOCOPrBc.js → ChannelsTelegram-tihzSWVE.js} +1 -1
  115. package/public/dist/assets/{CodeCanvas-CbfPP7Ad.js → CodeCanvas-CaeLVtZi.js} +2 -2
  116. package/public/dist/assets/{DashboardEmbeddingSection-DMgHZQnn.js → DashboardEmbeddingSection-DiqlLiLj.js} +1 -1
  117. package/public/dist/assets/{DashboardMeta-DennaaA_.js → DashboardMeta-Dsj8kEuW.js} +1 -1
  118. package/public/dist/assets/{DesignPanel-DcL369nB.js → DesignPanel-B8CAf6sH.js} +1 -1
  119. package/public/dist/assets/{DiffPanel-B_ljObDk.js → DiffPanel-BTZRq6eG.js} +1 -1
  120. package/public/dist/assets/{Display-hGuSn_W5.js → Display-nkXitDjD.js} +1 -1
  121. package/public/dist/assets/{DocPanel-K8A2pm_1.js → DocPanel-ogNttSee.js} +1 -1
  122. package/public/dist/assets/{Employees-B5YXk5ma.js → Employees-CU_1YnrA.js} +1 -1
  123. package/public/dist/assets/{FolderPanel-CV52EzwG.js → FolderPanel-D0w_zD66.js} +1 -1
  124. package/public/dist/assets/{HealthBadge-megTlF4n.js → HealthBadge-CUaJ1PQH.js} +1 -1
  125. package/public/dist/assets/{Heartbeat-DDmZARWw.js → Heartbeat-BeAP2bMO.js} +1 -1
  126. package/public/dist/assets/{InlineWarn-DDzeHxQw.js → InlineWarn-D-fmcQXD.js} +1 -1
  127. package/public/dist/assets/MarkdownRenderer-B6HbiZ6i.js +1 -0
  128. package/public/dist/assets/{MarkdownRenderer-CXrilOsG.js → MarkdownRenderer-Cd3kkg_s.js} +2 -2
  129. package/public/dist/assets/{Mcp-BHWnJ6SP.js → Mcp-2HD1qR7F.js} +1 -1
  130. package/public/dist/assets/{Memory-CUbviW7N.js → Memory-frrIhLly.js} +1 -1
  131. package/public/dist/assets/{MilkdownWysiwygEditor-BKOCDI4Z.js → MilkdownWysiwygEditor-BkEzO5cz.js} +1 -1
  132. package/public/dist/assets/{ModelProvider-ngg8xTuB.js → ModelProvider-DqUvwyZ6.js} +1 -1
  133. package/public/dist/assets/{Network-AWpSkALD.js → Network-DfzqHi9q.js} +1 -1
  134. package/public/dist/assets/{NotesGraphWorkspace-Dm1xUFl8.js → NotesGraphWorkspace-BRIiraP9.js} +1 -1
  135. package/public/dist/assets/{PanelLayoutProvider-XpTo-i_s.js → PanelLayoutProvider-B9fYsunp.js} +1 -1
  136. package/public/dist/assets/Permissions-ByUy_5DT.js +1 -0
  137. package/public/dist/assets/{Permissions-CnKt44dN.js → Permissions-RgyF1O6q.js} +1 -1
  138. package/public/dist/assets/{Profile-DnIE2ios.js → Profile-DXKtAzfg.js} +1 -1
  139. package/public/dist/assets/{Prompts-B9aKLall.js → Prompts-C7njPWCu.js} +1 -1
  140. package/public/dist/assets/{SpeechKeys-K4Be_o7z.js → SpeechKeys-B7SDWzo9.js} +1 -1
  141. package/public/dist/assets/{TelegramHub-CFwSkzHP.js → TelegramHub-C61X3f-H.js} +1 -1
  142. package/public/dist/assets/{TerminalPanel-CdlFZHAK.js → TerminalPanel-DlUFPyzc.js} +1 -1
  143. package/public/dist/assets/{TransportStatusChips-CjEySMis.js → TransportStatusChips-B0NR0ljO.js} +1 -1
  144. package/public/dist/assets/{app-is76CHGZ.js → app-DUbf-v7B.js} +4 -4
  145. package/public/dist/assets/architecture-7EHR7CIX-Byg-B8Sh.js +1 -0
  146. package/public/dist/assets/{architectureDiagram-3BPJPVTR-q8idz3H3.js → architectureDiagram-3BPJPVTR-DA7niVYs.js} +1 -1
  147. package/public/dist/assets/bgtask-badge-B8KhuBa7.js +1 -0
  148. package/public/dist/assets/{bgtask-badge-B0B1nXUs.js → bgtask-badge-jIH69Dp3.js} +1 -1
  149. package/public/dist/assets/{blockDiagram-GPEHLZMM-DGB0dsia.js → blockDiagram-GPEHLZMM-czRsW1WP.js} +1 -1
  150. package/public/dist/assets/{bounded-set-CFlZiEF4.js → bounded-set-DXkYOGnQ.js} +1 -1
  151. package/public/dist/assets/{c4Diagram-AAUBKEIU-ChP5YfVt.js → c4Diagram-AAUBKEIU-zoRyRo1y.js} +1 -1
  152. package/public/dist/assets/channel-Cr7Dmg2t.js +1 -0
  153. package/public/dist/assets/{chunk-2J33WTMH-D3OPoEHg.js → chunk-2J33WTMH-DMaZjiDe.js} +1 -1
  154. package/public/dist/assets/{chunk-3OPIFGDE-CULJ8ZHF.js → chunk-3OPIFGDE-fm0Uteda.js} +1 -1
  155. package/public/dist/assets/{chunk-4BX2VUAB-DGgktZYr.js → chunk-4BX2VUAB-DU36Vmpr.js} +1 -1
  156. package/public/dist/assets/{chunk-4EGX6M5U-BD3v8KR4.js → chunk-4EGX6M5U-CYPeQu4F.js} +1 -1
  157. package/public/dist/assets/chunk-55IACEB6-Dkm6BnqN.js +1 -0
  158. package/public/dist/assets/{chunk-5DO6E6H7-B-FbGqHn.js → chunk-5DO6E6H7-CIcLA1n6.js} +1 -1
  159. package/public/dist/assets/{chunk-5ZQYHXKU-DVpWOoGS.js → chunk-5ZQYHXKU-NjOvV6Nd.js} +1 -1
  160. package/public/dist/assets/{chunk-727SXJPM-CZjR7q6H.js → chunk-727SXJPM-CUOujQg0.js} +1 -1
  161. package/public/dist/assets/{chunk-AQP2D5EJ-BlGjnlsV.js → chunk-AQP2D5EJ-2nFXTQ0W.js} +1 -1
  162. package/public/dist/assets/{chunk-BR22UD5L-MK8KuB9X.js → chunk-BR22UD5L-BoyFFQuR.js} +1 -1
  163. package/public/dist/assets/{chunk-BSJP7CBP-ypXC4wBv.js → chunk-BSJP7CBP-B1MMwNrU.js} +1 -1
  164. package/public/dist/assets/{chunk-CSCIHK7Q-CmvetykJ.js → chunk-CSCIHK7Q-C0MOgWVt.js} +1 -1
  165. package/public/dist/assets/{chunk-FHYWG6QK-Do5csWDm.js → chunk-FHYWG6QK-CmUWtJPn.js} +1 -1
  166. package/public/dist/assets/{chunk-FMBD7UC4-BXpT25MP.js → chunk-FMBD7UC4-BEz4FhFn.js} +1 -1
  167. package/public/dist/assets/{chunk-KSCS5N6A-DtlfLqto.js → chunk-KSCS5N6A-B2XGqWQY.js} +1 -1
  168. package/public/dist/assets/{chunk-L5ZTLDWV-Czv9NkHn.js → chunk-L5ZTLDWV-CfZ2hrJ2.js} +1 -1
  169. package/public/dist/assets/{chunk-LZXEDZCA-vD7oFdiq.js → chunk-LZXEDZCA-BXuFCBsZ.js} +1 -1
  170. package/public/dist/assets/{chunk-MPE355IW-2ei0PVn0.js → chunk-MPE355IW-BdSiU-oV.js} +1 -1
  171. package/public/dist/assets/{chunk-MZUSXYTE-JO_qTk4K.js → chunk-MZUSXYTE-VYfI8Uwx.js} +1 -1
  172. package/public/dist/assets/{chunk-N66VUXT2-BXL-FniY.js → chunk-N66VUXT2-DJVNyglo.js} +1 -1
  173. package/public/dist/assets/{chunk-ND2GUHAM-B9SIO-4a.js → chunk-ND2GUHAM-1k8TCCsJ.js} +1 -1
  174. package/public/dist/assets/{chunk-NZK2D7GU-CqOo06-Z.js → chunk-NZK2D7GU-CkYWftT8.js} +1 -1
  175. package/public/dist/assets/{chunk-O5CBEL6O-BWbe_grt.js → chunk-O5CBEL6O-B5g0NbhD.js} +1 -1
  176. package/public/dist/assets/{chunk-PUPMXCY4-aFTMGBaR.js → chunk-PUPMXCY4-DJKmByz8.js} +1 -1
  177. package/public/dist/assets/chunk-QZHKN3VN-C6ktI6EQ.js +1 -0
  178. package/public/dist/assets/{chunk-UIBZB4QT-S8EH0jZR.js → chunk-UIBZB4QT-DgLbPJ3_.js} +1 -1
  179. package/public/dist/assets/{chunk-WCWK7LTN-EgrNk7Dj.js → chunk-WCWK7LTN-DWxi0w0a.js} +1 -1
  180. package/public/dist/assets/chunk-WU5MYG2G-Cwe6QZ3_.js +1 -0
  181. package/public/dist/assets/{chunk-XPW4576I-8oydVjY6.js → chunk-XPW4576I-CaTDAC52.js} +1 -1
  182. package/public/dist/assets/classDiagram-4FO5ZUOK-BzLBk9sv.js +1 -0
  183. package/public/dist/assets/classDiagram-v2-Q7XG4LA2-9K8wUz3g.js +1 -0
  184. package/public/dist/assets/{copy-text-BDs2wKjA.js → copy-text-Dy0kfmb9.js} +1 -1
  185. package/public/dist/assets/{cose-bilkent-S5V4N54A-PNmvcq_6.js → cose-bilkent-S5V4N54A-B9Tcz6qW.js} +1 -1
  186. package/public/dist/assets/{dagre-BM42HDAG-BP_m3uo9.js → dagre-BM42HDAG-OH37BMnf.js} +1 -1
  187. package/public/dist/assets/{dagre-Ct2n78X9.js → dagre-BsKKQnyU.js} +1 -1
  188. package/public/dist/assets/{diagram-2AECGRRQ-DhgfR-ol.js → diagram-2AECGRRQ-B1t73Wn1.js} +1 -1
  189. package/public/dist/assets/{diagram-5GNKFQAL-BRLvmdeK.js → diagram-5GNKFQAL-DBGIcSxH.js} +1 -1
  190. package/public/dist/assets/{diagram-KO2AKTUF-Co3C18-Q.js → diagram-KO2AKTUF-uRuKS97A.js} +1 -1
  191. package/public/dist/assets/{diagram-LMA3HP47-3SwoWQij.js → diagram-LMA3HP47-XMEHnr3B.js} +1 -1
  192. package/public/dist/assets/{diagram-OG6HWLK6-bjEryAd3.js → diagram-OG6HWLK6-B_vRUJSJ.js} +1 -1
  193. package/public/dist/assets/{dist-BvQlb9-o.js → dist-BCCaGGDY.js} +1 -1
  194. package/public/dist/assets/{dist-CvzAXxlb.js → dist-BPE4W9iX.js} +1 -1
  195. package/public/dist/assets/{dist-CFU9RsAu.js → dist-BQMBTYXL.js} +1 -1
  196. package/public/dist/assets/{dist-BlMOeJym.js → dist-BaPGPaX4.js} +1 -1
  197. package/public/dist/assets/{dist-B6T-R4xY.js → dist-Bg80xGMJ.js} +1 -1
  198. package/public/dist/assets/{dist-CS1XLdz3.js → dist-BspKh_Zg.js} +1 -1
  199. package/public/dist/assets/{dist-qUky5WRy.js → dist-CBnlLSQZ.js} +1 -1
  200. package/public/dist/assets/{dist-BMC_dTfR.js → dist-CD7tjeNO.js} +1 -1
  201. package/public/dist/assets/{dist-w2YzIhc5.js → dist-CINTuhik.js} +1 -1
  202. package/public/dist/assets/{dist-cBBDKBli.js → dist-CTpw6PFT.js} +1 -1
  203. package/public/dist/assets/{dist-BqzMcuh8.js → dist-CczLsP0o.js} +1 -1
  204. package/public/dist/assets/{dist-ph7PUr0c.js → dist-CdfDDy4r.js} +1 -1
  205. package/public/dist/assets/{dist-D8SW_REQ.js → dist-CgIOBybm.js} +1 -1
  206. package/public/dist/assets/dist-Cl_pRobr.js +1 -0
  207. package/public/dist/assets/{dist-DTcoHNXr.js → dist-CruwQXwE.js} +1 -1
  208. package/public/dist/assets/{dist-BDPUxeoi.js → dist-CuL30i1H.js} +1 -1
  209. package/public/dist/assets/{dist-DMZVNaIe.js → dist-CvE8Qa9r.js} +1 -1
  210. package/public/dist/assets/{dist-B8V2LYzt.js → dist-Cy3mcP1e.js} +1 -1
  211. package/public/dist/assets/{dist-C7pD0dEn.js → dist-CzCFEnHw.js} +1 -1
  212. package/public/dist/assets/{dist-DStWZVZ0.js → dist-D2h9T4I9.js} +1 -1
  213. package/public/dist/assets/{dist-DmjSXJAP.js → dist-D3ShDeDU.js} +1 -1
  214. package/public/dist/assets/{dist-CC2vK_6S.js → dist-D8Zky4R1.js} +1 -1
  215. package/public/dist/assets/{dist-DN-hkAIC.js → dist-DKd_hdkE.js} +1 -1
  216. package/public/dist/assets/{dist-CjzfPsGt.js → dist-DLOg6n0b.js} +1 -1
  217. package/public/dist/assets/{dist-DdJuxxG7.js → dist-DS7cuuIk.js} +1 -1
  218. package/public/dist/assets/dist-DW0I56_o.js +1 -0
  219. package/public/dist/assets/{dist-BSf40pae.js → dist-JnCmAxGR.js} +1 -1
  220. package/public/dist/assets/{dist-DhgwoIqj.js → dist-TombgBki.js} +1 -1
  221. package/public/dist/assets/dist-hBRIxDzG.js +1 -0
  222. package/public/dist/assets/dist-z5Z70wW8.js +1 -0
  223. package/public/dist/assets/{dockerfile-C0jniLkw.js → dockerfile-DkX5AHzr.js} +1 -1
  224. package/public/dist/assets/{employees-eiW0cC8z.js → employees-BNy8a6XX.js} +1 -1
  225. package/public/dist/assets/{erDiagram-TEJ5UH35-DQBxHU1q.js → erDiagram-TEJ5UH35-CTHxg4ER.js} +1 -1
  226. package/public/dist/assets/{error-normalize-BzeO0SXE.js → error-normalize-CLRJh19F.js} +1 -1
  227. package/public/dist/assets/eventmodeling-FCH6USID-LckY84Wp.js +1 -0
  228. package/public/dist/assets/{factor-nzjoQ9cK.js → factor-Xro2mWdw.js} +1 -1
  229. package/public/dist/assets/{fields-zkeByFQW.js → fields-BwOMlwS0.js} +1 -1
  230. package/public/dist/assets/{flowDiagram-I6XJVG4X-BN90fCt5.js → flowDiagram-I6XJVG4X-DgCs6PPU.js} +1 -1
  231. package/public/dist/assets/{ganttDiagram-6RSMTGT7-B-JAlIhh.js → ganttDiagram-6RSMTGT7-DGjdFJRc.js} +1 -1
  232. package/public/dist/assets/gitGraph-WXDBUCRP-DXhEIZXY.js +1 -0
  233. package/public/dist/assets/{gitGraphDiagram-PVQCEYII-CLL2G5U-.js → gitGraphDiagram-PVQCEYII-DvCWiClL.js} +1 -1
  234. package/public/dist/assets/{graphlib-B6dRm8vZ.js → graphlib-B06FTUqA.js} +1 -1
  235. package/public/dist/assets/{iframe-renderer-C7qQJX4c.js → iframe-renderer-C6Zwg9w4.js} +2 -2
  236. package/public/dist/assets/iframe-renderer-DBmV8gCQ.js +1 -0
  237. package/public/dist/assets/info-J43DQDTF-iXM3vzuR.js +1 -0
  238. package/public/dist/assets/{infoDiagram-5YYISTIA-CftYDPfc.js → infoDiagram-5YYISTIA-DxkbyTf_.js} +1 -1
  239. package/public/dist/assets/{ishikawaDiagram-YF4QCWOH-BVa5AJbz.js → ishikawaDiagram-YF4QCWOH-fyJrRZTW.js} +1 -1
  240. package/public/dist/assets/javascript-DZFdG8BN.js +1 -0
  241. package/public/dist/assets/{journeyDiagram-JHISSGLW-BeUKm6ME.js → journeyDiagram-JHISSGLW-Dd6CvR-c.js} +1 -1
  242. package/public/dist/assets/{kanban-definition-UN3LZRKU-K5DYNY4p.js → kanban-definition-UN3LZRKU-C2ZH4LXA.js} +1 -1
  243. package/public/dist/assets/{manager-Bjuh1jpq.js → manager-DzCR6Pam.js} +4 -4
  244. package/public/dist/assets/{memory--Q8Tb5SZ.js → memory-C4O44HMr.js} +1 -1
  245. package/public/dist/assets/memory-Dt_Ji6aP.js +1 -0
  246. package/public/dist/assets/mermaid-loader-CylkLQP5.js +1 -0
  247. package/public/dist/assets/{mermaid-parser.core-Cz70RgAa.js → mermaid-parser.core-C-9KB617.js} +1 -1
  248. package/public/dist/assets/{mermaid.core-Dj5GOPe1.js → mermaid.core-8XY13b72.js} +2 -2
  249. package/public/dist/assets/mermaid.core-BEuf6y5_.js +1 -0
  250. package/public/dist/assets/{message-history-CfAHmCDW.js → message-history-DCxD21J1.js} +1 -1
  251. package/public/dist/assets/message-history-DyISauiv.js +1 -0
  252. package/public/dist/assets/{mindmap-definition-RKZ34NQL-PsH0E_3e.js → mindmap-definition-RKZ34NQL-DUQBUbUA.js} +1 -1
  253. package/public/dist/assets/{nsis-BI3I3OhH.js → nsis-iX94j4T9.js} +1 -1
  254. package/public/dist/assets/packet-YPE3B663-SclsNpNx.js +1 -0
  255. package/public/dist/assets/{page-shell-LF7vVVfG.js → page-shell-GpE8A-FA.js} +1 -1
  256. package/public/dist/assets/pie-LRSECV5Y-CF43gDO6.js +1 -0
  257. package/public/dist/assets/{pieDiagram-4H26LBE5-Dtwtlr0z.js → pieDiagram-4H26LBE5-ChOXpmZ5.js} +1 -1
  258. package/public/dist/assets/{pug-DHfNwv1w.js → pug-C8nPBT90.js} +1 -1
  259. package/public/dist/assets/{quadrantDiagram-W4KKPZXB-CAFUbaV6.js → quadrantDiagram-W4KKPZXB-lbpz07e4.js} +1 -1
  260. package/public/dist/assets/radar-GUYGQ44K-BsylzLX_.js +1 -0
  261. package/public/dist/assets/{render-BDso7Yb5.js → render-A--hkukv.js} +2 -2
  262. package/public/dist/assets/{requirementDiagram-4Y6WPE33-CvBM4AjK.js → requirementDiagram-4Y6WPE33-CrApoE_l.js} +1 -1
  263. package/public/dist/assets/{sankeyDiagram-5OEKKPKP-cordQgRs.js → sankeyDiagram-5OEKKPKP-Df1lU-mT.js} +1 -1
  264. package/public/dist/assets/{sequenceDiagram-3UESZ5HK-DDAqRdga.js → sequenceDiagram-3UESZ5HK-CelQN5jY.js} +1 -1
  265. package/public/dist/assets/settings-3ZdoKHIf.js +56 -0
  266. package/public/dist/assets/settings-C6Pku2GC.js +1 -0
  267. package/public/dist/assets/{settings-core-BxuFkt4a.js → settings-core-CQe1uP6x.js} +17 -17
  268. package/public/dist/assets/settings-core-DqwLJkgP.js +1 -0
  269. package/public/dist/assets/settings-types-DPhhM-cj.js +1 -0
  270. package/public/dist/assets/{sidebar-BNT58qR0.js → sidebar-DxFp_449.js} +3 -3
  271. package/public/dist/assets/{skills-CwRBcm3m.js → skills-BU4q8Q8n.js} +1 -1
  272. package/public/dist/assets/skills-x2gH-1Ry.js +1 -0
  273. package/public/dist/assets/{slash-commands-cm0U58n7.js → slash-commands-BiXOgZ5B.js} +1 -1
  274. package/public/dist/assets/slash-commands-s8eR7Kd1.js +1 -0
  275. package/public/dist/assets/{stateDiagram-AJRCARHV-DUaoSRgZ.js → stateDiagram-AJRCARHV-CeyXWXrg.js} +1 -1
  276. package/public/dist/assets/stateDiagram-v2-BHNVJYJU-Bhb8zTjh.js +1 -0
  277. package/public/dist/assets/{timeline-definition-PNZ67QCA-D85QNy9b.js → timeline-definition-PNZ67QCA-DP0lPzQ_.js} +1 -1
  278. package/public/dist/assets/{trace-drawer-BuwO4m2P.js → trace-drawer-2BTQCor6.js} +1 -1
  279. package/public/dist/assets/treeView-BLDUP644-DHq0vQpf.js +1 -0
  280. package/public/dist/assets/treemap-LRROVOQU-vKngXIla.js +1 -0
  281. package/public/dist/assets/ui-CB0L33o0.js +1 -0
  282. package/public/dist/assets/{ui-C-LHMki1.js → ui-Csy42uNW.js} +1 -1
  283. package/public/dist/assets/{vennDiagram-CIIHVFJN-CQSILdx8.js → vennDiagram-CIIHVFJN-WB9mzv1f.js} +1 -1
  284. package/public/dist/assets/wardley-L42UT6IY-B1jQOSA5.js +1 -0
  285. package/public/dist/assets/{wardleyDiagram-YWT4CUSO-BZEVMlJ4.js → wardleyDiagram-YWT4CUSO-CapVnCz5.js} +1 -1
  286. package/public/dist/assets/{wiki-link-suggestions-Dp6kBQVu.js → wiki-link-suggestions-cvpqJp6c.js} +1 -1
  287. package/public/dist/assets/{xychartDiagram-2RQKCTM6-C8573Tgs.js → xychartDiagram-2RQKCTM6-DduDB3Cd.js} +1 -1
  288. package/public/dist/index.html +1 -1
  289. package/public/dist/manager/index.html +1 -1
  290. package/public/js/features/settings-cli-status.ts +11 -5
  291. package/public/js/features/settings-types.ts +35 -3
  292. package/public/manager/src/settings/cli-status-polling.ts +84 -0
  293. package/public/manager/src/settings/pages/Agent.tsx +111 -16
  294. package/scripts/install-officecli.ps1 +38 -2
  295. package/scripts/install.ps1 +1 -1
  296. package/public/dist/assets/Agent-nMPZsMfN.js +0 -1
  297. package/public/dist/assets/MarkdownRenderer-DZVh_xX2.js +0 -1
  298. package/public/dist/assets/Permissions-DNT0TxYL.js +0 -1
  299. package/public/dist/assets/architecture-7EHR7CIX-D-6Nx315.js +0 -1
  300. package/public/dist/assets/bgtask-badge-B2jUZ5mC.js +0 -1
  301. package/public/dist/assets/channel-ByNDsZsH.js +0 -1
  302. package/public/dist/assets/chunk-55IACEB6-CQFLXxVc.js +0 -1
  303. package/public/dist/assets/chunk-QZHKN3VN-Becu19mF.js +0 -1
  304. package/public/dist/assets/chunk-WU5MYG2G-CkoHFn0F.js +0 -1
  305. package/public/dist/assets/classDiagram-4FO5ZUOK-DVGoKviY.js +0 -1
  306. package/public/dist/assets/classDiagram-v2-Q7XG4LA2-BIZeptY-.js +0 -1
  307. package/public/dist/assets/dist-BmXnOAlo.js +0 -1
  308. package/public/dist/assets/dist-DLY5I6dK.js +0 -1
  309. package/public/dist/assets/dist-DPHcMCqI.js +0 -1
  310. package/public/dist/assets/dist-xHOEvyuU.js +0 -1
  311. package/public/dist/assets/eventmodeling-FCH6USID-BB1OVDLb.js +0 -1
  312. package/public/dist/assets/gitGraph-WXDBUCRP-DAWTa5Fn.js +0 -1
  313. package/public/dist/assets/iframe-renderer-D7PB_yrC.js +0 -1
  314. package/public/dist/assets/info-J43DQDTF-C530y5-j.js +0 -1
  315. package/public/dist/assets/javascript-DbM-pSY-.js +0 -1
  316. package/public/dist/assets/memory-rsKN0aa2.js +0 -1
  317. package/public/dist/assets/mermaid-loader-Bd9rYyxD.js +0 -1
  318. package/public/dist/assets/mermaid.core-TSG49mwm.js +0 -1
  319. package/public/dist/assets/message-history-BttkY77h.js +0 -1
  320. package/public/dist/assets/packet-YPE3B663-BHcxn4sy.js +0 -1
  321. package/public/dist/assets/pie-LRSECV5Y-DjigSia_.js +0 -1
  322. package/public/dist/assets/radar-GUYGQ44K-DPCrmsHJ.js +0 -1
  323. package/public/dist/assets/settings-CqnIqxkG.js +0 -56
  324. package/public/dist/assets/settings-core-CdZ7oKhM.js +0 -1
  325. package/public/dist/assets/settings-pPMHNs0G.js +0 -1
  326. package/public/dist/assets/skills-DiVoaVdS.js +0 -1
  327. package/public/dist/assets/slash-commands-Bx4saHwR.js +0 -1
  328. package/public/dist/assets/stateDiagram-v2-BHNVJYJU-BAesfdhr.js +0 -1
  329. package/public/dist/assets/treeView-BLDUP644-DmufUMul.js +0 -1
  330. package/public/dist/assets/treemap-LRROVOQU-Cg48uw_D.js +0 -1
  331. package/public/dist/assets/ui-XPQDPe-5.js +0 -1
  332. package/public/dist/assets/wardley-L42UT6IY-QZOEXU7f.js +0 -1
  333. /package/public/dist/assets/{agent-meta-Y3DE6sxh.js → agent-meta-Bl-Q0EgC.js} +0 -0
  334. /package/public/dist/assets/{api-B25zNNFJ.js → api-FOqKQ9fm.js} +0 -0
  335. /package/public/dist/assets/{apl-2tE96F_Y.js → apl-CYLd9I-9.js} +0 -0
  336. /package/public/dist/assets/{asciiarmor-ynSKiC17.js → asciiarmor-7YwhfGDq.js} +0 -0
  337. /package/public/dist/assets/{asn1-CfqO1VY8.js → asn1-BlhHp3qx.js} +0 -0
  338. /package/public/dist/assets/{asterisk-DSiRJoqT.js → asterisk-Q0-IBwUt.js} +0 -0
  339. /package/public/dist/assets/{brainfuck-DTcanv-8.js → brainfuck-CM8jf4Gu.js} +0 -0
  340. /package/public/dist/assets/{chunk-AGHRB4JF-BXLzSehp.js → chunk-AGHRB4JF-Cdp9MZGh.js} +0 -0
  341. /package/public/dist/assets/{chunk-NNHCCRGN-D69GtSOc.js → chunk-NNHCCRGN-ChI2WAS0.js} +0 -0
  342. /package/public/dist/assets/{clike-qn72CMAj.js → clike-BcV5UqGE.js} +0 -0
  343. /package/public/dist/assets/{clojure-m8yDiYVc.js → clojure-XHu9GAjV.js} +0 -0
  344. /package/public/dist/assets/{cmake-4AHAWHiF.js → cmake-DhPsEu0W.js} +0 -0
  345. /package/public/dist/assets/{cobol-CxxJP5eX.js → cobol-BEekiT-v.js} +0 -0
  346. /package/public/dist/assets/{coffeescript-BAB3zi48.js → coffeescript-Bgk4ZVWF.js} +0 -0
  347. /package/public/dist/assets/{commonlisp-BPbWuAds.js → commonlisp-Dw4PRJwx.js} +0 -0
  348. /package/public/dist/assets/{crystal-CGuSsWYR.js → crystal-CJ-iCD_G.js} +0 -0
  349. /package/public/dist/assets/{css-DszbR74r.js → css-BDUaiSMY.js} +0 -0
  350. /package/public/dist/assets/{cypher-GUnmv522.js → cypher-CJ05ZgAu.js} +0 -0
  351. /package/public/dist/assets/{cytoscape.esm-D_XyYSBG.js → cytoscape.esm-PBXWcYR1.js} +0 -0
  352. /package/public/dist/assets/{d-Cfm0cznj.js → d-BfHF1VVF.js} +0 -0
  353. /package/public/dist/assets/{desktop-bridge-CvdhnJQo.js → desktop-bridge-DtydAvqu.js} +0 -0
  354. /package/public/dist/assets/{diff-C6rPA7NX.js → diff-BVcHwfdB.js} +0 -0
  355. /package/public/dist/assets/{dist-AgQwqBLq.js → dist-BbhtVnRz.js} +0 -0
  356. /package/public/dist/assets/{dtd-Dxh5tS6M.js → dtd-Bg0TgBY9.js} +0 -0
  357. /package/public/dist/assets/{dylan-BdIVFR1j.js → dylan-BQ0i5j3T.js} +0 -0
  358. /package/public/dist/assets/{ebnf-iU-8xYFu.js → ebnf-QSFUkOiT.js} +0 -0
  359. /package/public/dist/assets/{ecl-DjbzOHI6.js → ecl-oXh4vhiy.js} +0 -0
  360. /package/public/dist/assets/{eiffel-B2ID8LZ3.js → eiffel-S15DDWzw.js} +0 -0
  361. /package/public/dist/assets/{elm-B6vPcfMj.js → elm-B746ZFPi.js} +0 -0
  362. /package/public/dist/assets/{erlang-nDQwRdZV.js → erlang-GRIYhTbY.js} +0 -0
  363. /package/public/dist/assets/{fcl-Bf86o55I.js → fcl-DjQMeb0v.js} +0 -0
  364. /package/public/dist/assets/{folder-drag-payload-Bhln9Mk2.js → folder-drag-payload-CJ0dxhZa.js} +0 -0
  365. /package/public/dist/assets/{forth-CeQJji0n.js → forth-DNnBFTm6.js} +0 -0
  366. /package/public/dist/assets/{fortran-Dm_CqDsH.js → fortran-yg6K9z9n.js} +0 -0
  367. /package/public/dist/assets/{gas-e3EfgE3p.js → gas-fbsH19hy.js} +0 -0
  368. /package/public/dist/assets/{gherkin-Dn_7tSzg.js → gherkin-BCy9haeT.js} +0 -0
  369. /package/public/dist/assets/{groovy-LaKuGRkK.js → groovy-Cm4gdIYU.js} +0 -0
  370. /package/public/dist/assets/{haskell-D9nNX9Mr.js → haskell-Dq28dVw2.js} +0 -0
  371. /package/public/dist/assets/{haxe-Rp176QXJ.js → haxe-BrZpr4Ca.js} +0 -0
  372. /package/public/dist/assets/{http-BOeYLbuM.js → http-B3zr0y0o.js} +0 -0
  373. /package/public/dist/assets/{idl-DHv3vdme.js → idl-C9CL9hdG.js} +0 -0
  374. /package/public/dist/assets/{javascript-Dk2fbl1a.js → javascript-DD7UxIxH.js} +0 -0
  375. /package/public/dist/assets/{jsx-runtime-gFMgZ0TQ.js → jsx-runtime-CYoNlHAD.js} +0 -0
  376. /package/public/dist/assets/{julia-D7CKCk5I.js → julia-CjwfSXBk.js} +0 -0
  377. /package/public/dist/assets/{livescript-gRbr9rhj.js → livescript-vRjI6jFU.js} +0 -0
  378. /package/public/dist/assets/{lua-CgZ_7bxf.js → lua-CxVmDfKg.js} +0 -0
  379. /package/public/dist/assets/{mathematica-B6bTyoab.js → mathematica-DJZPFt8k.js} +0 -0
  380. /package/public/dist/assets/{mbox-C8oQj1cJ.js → mbox-CxBBnlIA.js} +0 -0
  381. /package/public/dist/assets/{mirc-v6L6kZuh.js → mirc-CBWc0vcU.js} +0 -0
  382. /package/public/dist/assets/{mllike-CWu4RdWO.js → mllike-DYddHpeS.js} +0 -0
  383. /package/public/dist/assets/{modelica-B3NBpX1d.js → modelica-B94rrYMn.js} +0 -0
  384. /package/public/dist/assets/{mscgen-C8u7qRYw.js → mscgen-D0PO0iPT.js} +0 -0
  385. /package/public/dist/assets/{mumps-DHjVG4PS.js → mumps-BdPrWvs5.js} +0 -0
  386. /package/public/dist/assets/{nginx-BMt87X3t.js → nginx-C7cLiM4x.js} +0 -0
  387. /package/public/dist/assets/{notes-graph-settings-BgNrT_58.js → notes-graph-settings-Cl4lMj-A.js} +0 -0
  388. /package/public/dist/assets/{ntriples-C8U-Jud2.js → ntriples-DLMpvgb1.js} +0 -0
  389. /package/public/dist/assets/{octave-Bq37AoFm.js → octave-DeJPElAr.js} +0 -0
  390. /package/public/dist/assets/{oz-D6HxSRn3.js → oz-4dtXWqwe.js} +0 -0
  391. /package/public/dist/assets/{pascal-BBqiAVg6.js → pascal-TdeXcL-o.js} +0 -0
  392. /package/public/dist/assets/{path-utils-LsJeDCKF.js → path-utils-CHwADH-r.js} +0 -0
  393. /package/public/dist/assets/{perl-sHANlXjx.js → perl-DfpfXWOH.js} +0 -0
  394. /package/public/dist/assets/{pig-Cufgew--.js → pig-xQ4essgV.js} +0 -0
  395. /package/public/dist/assets/{powershell--Q4mDip6.js → powershell-Dfw2t4-B.js} +0 -0
  396. /package/public/dist/assets/{properties-DoVpJ-kT.js → properties-CrJLOvU2.js} +0 -0
  397. /package/public/dist/assets/{protobuf-B5OiV2Zv.js → protobuf-BYv78GYU.js} +0 -0
  398. /package/public/dist/assets/{provider-icons-VDfahiUp.js → provider-icons-CXA2mnPO.js} +0 -0
  399. /package/public/dist/assets/{puppet-Ce_CFfqW.js → puppet-DnsvBfcg.js} +0 -0
  400. /package/public/dist/assets/{python-pK7Wt6QH.js → python-mfoZJSDM.js} +0 -0
  401. /package/public/dist/assets/{q-Dd3Ltku0.js → q-BrTIu4PU.js} +0 -0
  402. /package/public/dist/assets/{r-CsX__2f0.js → r-FO7GgXB8.js} +0 -0
  403. /package/public/dist/assets/{rough.esm--LLpAgPj.js → rough.esm-DeGVhNS9.js} +0 -0
  404. /package/public/dist/assets/{rpm-D78AjDAl.js → rpm-D8Wbdep5.js} +0 -0
  405. /package/public/dist/assets/{ruby-D_-KI498.js → ruby-Cg1fwXaw.js} +0 -0
  406. /package/public/dist/assets/{sas-D-GUPiy4.js → sas-Ch1GEx-n.js} +0 -0
  407. /package/public/dist/assets/{scheme-DF9WwQDv.js → scheme-DGFmPoR2.js} +0 -0
  408. /package/public/dist/assets/{settings-client-CjbBShxm.js → settings-client-D9KY2Ufl.js} +0 -0
  409. /package/public/dist/assets/{shell-BTUwbV-w.js → shell-BBoIO9l0.js} +0 -0
  410. /package/public/dist/assets/{sieve--Z-EbGZo.js → sieve-8oEe6gDx.js} +0 -0
  411. /package/public/dist/assets/{simple-mode-BUow4bpn.js → simple-mode-BNw0K2rL.js} +0 -0
  412. /package/public/dist/assets/{smalltalk-C2YIwVx3.js → smalltalk-ChbxX23N.js} +0 -0
  413. /package/public/dist/assets/{solr-CYVq4fbf.js → solr-BwGyzi2H.js} +0 -0
  414. /package/public/dist/assets/{sparql-Ccd4fsFv.js → sparql-D9wgprRx.js} +0 -0
  415. /package/public/dist/assets/{spreadsheet-DW0WgMrS.js → spreadsheet-BySehl32.js} +0 -0
  416. /package/public/dist/assets/{sql-C71Zp6qn.js → sql-B6Phvk1R.js} +0 -0
  417. /package/public/dist/assets/{stex-CKuX0g_6.js → stex-32iK7T_9.js} +0 -0
  418. /package/public/dist/assets/{stylus-CBH8s0NO.js → stylus-C689wDNM.js} +0 -0
  419. /package/public/dist/assets/{swift-CfZoxKRA.js → swift-DZwxTp-L.js} +0 -0
  420. /package/public/dist/assets/{tcl-D5MGbeQu.js → tcl-BSOjIY_8.js} +0 -0
  421. /package/public/dist/assets/{textile-DJ3U30FW.js → textile-xOWO1SH7.js} +0 -0
  422. /package/public/dist/assets/{tiddlywiki-_fe1dHUq.js → tiddlywiki-B8jhOxrf.js} +0 -0
  423. /package/public/dist/assets/{tiki-Dd1udTrQ.js → tiki-OG7n6UAo.js} +0 -0
  424. /package/public/dist/assets/{toml-xpw8pqjz.js → toml-DkxT-aUR.js} +0 -0
  425. /package/public/dist/assets/{troff-CgWiec8m.js → troff-vE5gOX7Y.js} +0 -0
  426. /package/public/dist/assets/{ttcn-CSwmFrer.js → ttcn-CPOduycD.js} +0 -0
  427. /package/public/dist/assets/{ttcn-cfg-B5HVIC6z.js → ttcn-cfg-DmA__-R_.js} +0 -0
  428. /package/public/dist/assets/{turtle-Cl_SuWQk.js → turtle-CEzrJHdY.js} +0 -0
  429. /package/public/dist/assets/{vb-BT131bSf.js → vb-Cii5IQTv.js} +0 -0
  430. /package/public/dist/assets/{vbscript-D6S8_XkU.js → vbscript-DcZWGZ_S.js} +0 -0
  431. /package/public/dist/assets/{velocity-9HkI645n.js → velocity-BEag7EnK.js} +0 -0
  432. /package/public/dist/assets/{vendor-utils-DJY0EWnQ.js → vendor-utils-BK07iQND.js} +0 -0
  433. /package/public/dist/assets/{verilog-BzMguKeI.js → verilog-DMw8DKoT.js} +0 -0
  434. /package/public/dist/assets/{vhdl-bHScWzT1.js → vhdl-M4wLPuJt.js} +0 -0
  435. /package/public/dist/assets/{w3c-keyname-a_sRwNLm.js → w3c-keyname-hgmz1BF7.js} +0 -0
  436. /package/public/dist/assets/{webidl-CbgaVHNS.js → webidl-CjehKbx5.js} +0 -0
  437. /package/public/dist/assets/{wiki-link-resolver-DyFzBTIQ.js → wiki-link-resolver-N9fDy5zP.js} +0 -0
  438. /package/public/dist/assets/{xquery-DWZPmAiC.js → xquery-CYbd_YmJ.js} +0 -0
  439. /package/public/dist/assets/{yacas-CEdW4z4K.js → yacas-ClBNsli2.js} +0 -0
  440. /package/public/dist/assets/{z80-CMH3qxNg.js → z80-nGsPT_fm.js} +0 -0
@@ -10,6 +10,7 @@
10
10
  // bursty tool events would otherwise burn the budget and get throttled.
11
11
  // - Best-effort. A failed status post/edit must never break the answer path.
12
12
  import { slackApi, describeSlackError } from './api.js';
13
+ import { startDraftStream } from '../messaging/draft-stream.js';
13
14
  import { toMrkdwn } from './format.js';
14
15
  /** Minimum gap between chat.update calls for one run (Slack tier limit). */
15
16
  const EDIT_INTERVAL_MS = 1200;
@@ -33,66 +34,53 @@ export function statusFromToolEvent(data, fallback) {
33
34
  }
34
35
  export async function startSlackProgress(token, target, initialText, options = {}) {
35
36
  const fetchOpts = options.fetchImpl ? { fetchImpl: options.fetchImpl } : {};
36
- let messageTs = null;
37
- let done = false;
38
- let lastSentAt = 0;
39
- let pendingText = null;
40
- let flushTimer = null;
41
- const post = await slackApi(token, 'chat.postMessage', {
42
- channel: target.targetId,
43
- text: toMrkdwn(truncateStatus(initialText)),
44
- ...(target.threadId ? { thread_ts: target.threadId } : {}),
45
- }, fetchOpts);
46
- if (post.ok && post.data?.ts)
47
- messageTs = post.data.ts;
48
- const flush = async () => {
49
- if (done || !messageTs || pendingText === null)
50
- return;
51
- const text = pendingText;
52
- pendingText = null;
53
- lastSentAt = Date.now();
54
- await slackApi(token, 'chat.update', { channel: target.targetId, ts: messageTs, text: toMrkdwn(text) }, fetchOpts).catch(() => ({ ok: false, error: 'update_failed' }));
55
- };
56
- const schedule = () => {
57
- if (done || flushTimer || pendingText === null)
58
- return;
59
- const wait = Math.max(0, EDIT_INTERVAL_MS - (Date.now() - lastSentAt));
60
- flushTimer = setTimeout(() => {
61
- flushTimer = null;
62
- void flush().finally(() => { if (pendingText !== null)
63
- schedule(); });
64
- }, wait);
65
- // A pending edit must never hold the process open.
66
- flushTimer.unref?.();
37
+ const transport = {
38
+ async post(text) {
39
+ const result = await slackApi(token, 'chat.postMessage', {
40
+ channel: target.targetId,
41
+ text,
42
+ ...(target.threadId ? { thread_ts: target.threadId } : {}),
43
+ }, fetchOpts);
44
+ return result.ok && result.data?.ts ? result.data.ts : null;
45
+ },
46
+ async edit(ts, text) {
47
+ const result = await slackApi(token, 'chat.update', { channel: target.targetId, ts, text }, fetchOpts);
48
+ if (!result.ok) {
49
+ throw Object.assign(new Error(result.error || 'chat_update_failed'), {
50
+ slackData: result.data,
51
+ });
52
+ }
53
+ },
54
+ async remove(ts) {
55
+ const result = await slackApi(token, 'chat.delete', { channel: target.targetId, ts }, fetchOpts);
56
+ if (!result.ok) {
57
+ throw Object.assign(new Error(result.error || 'chat_delete_failed'), {
58
+ slackData: result.data,
59
+ });
60
+ }
61
+ },
67
62
  };
63
+ const stream = await startDraftStream(transport, toMrkdwn(truncateStatus(initialText)), {
64
+ minEditIntervalMs: EDIT_INTERVAL_MS,
65
+ maxChars: MAX_STATUS_LEN,
66
+ ...options.draftClock,
67
+ onError(operation, error) {
68
+ const typed = error;
69
+ describeSlackError(typed.message || `${operation}_failed`, typed.slackData);
70
+ },
71
+ });
68
72
  return {
69
73
  update(text) {
70
- if (done || !messageTs)
71
- return;
72
74
  const next = truncateStatus(text);
73
- if (!next)
74
- return;
75
- pendingText = next;
76
- schedule();
75
+ if (next)
76
+ stream.update(toMrkdwn(next));
77
77
  },
78
78
  async finish() {
79
- done = true;
80
- pendingText = null;
81
- if (flushTimer) {
82
- clearTimeout(flushTimer);
83
- flushTimer = null;
84
- }
85
- if (!messageTs)
86
- return;
87
- const ts = messageTs;
88
- messageTs = null;
89
79
  // The answer arrives as its own message, so the status placeholder
90
80
  // is deleted rather than left as a stale "working…" line.
91
- const result = await slackApi(token, 'chat.delete', { channel: target.targetId, ts }, fetchOpts);
92
- if (!result.ok)
93
- describeSlackError(result.error || 'chat_delete_failed', result.data);
81
+ await stream.discard();
94
82
  },
95
- ts() { return messageTs; },
83
+ ts() { return stream.handle(); },
96
84
  };
97
85
  }
98
86
  //# sourceMappingURL=progress.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"progress.js","sourceRoot":"","sources":["../../../src/slack/progress.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../../../src/slack/progress.ts"],"names":[],"mappings":"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"}
@@ -78,6 +78,94 @@ export function isThreadParticipated(channel, threadTs) {
78
78
  return false;
79
79
  return load().has(threadKey(channel, threadTs));
80
80
  }
81
+ /** key -> current owner and whether history was actually injected. */
82
+ const prefetchClaimed = new Map();
83
+ const PREFETCH_CLAIM_CAP = 500;
84
+ let prefetchToken = 0;
85
+ let prefetchUse = 0;
86
+ function prefetchKey(channel, threadTs, owner) {
87
+ return `${threadKey(channel, threadTs)}:${owner.global}:${owner.scope}`;
88
+ }
89
+ /**
90
+ * Claim the one-time prefetch for a thread.
91
+ *
92
+ * Returns a token on success and 0 when the thread is already claimed.
93
+ * Synchronous test-and-set: the caller runs it before any `await`, so two
94
+ * envelopes arriving in the same tick cannot both win.
95
+ *
96
+ * The token exists because releasing is asynchronous. Without it a late
97
+ * release from an abandoned attempt would delete whichever claim happened to
98
+ * hold the key by then — the classic ABA: A claims, A times out and releases,
99
+ * B claims, A's straggler releases B's claim, and the thread gets prefetched
100
+ * twice.
101
+ */
102
+ export function claimThreadPrefetch(channel, threadTs, owner) {
103
+ if (!channel || !threadTs)
104
+ return 0;
105
+ const key = prefetchKey(channel, threadTs, owner);
106
+ const existing = prefetchClaimed.get(key);
107
+ if (existing) {
108
+ existing.lastUsed = ++prefetchUse;
109
+ return 0;
110
+ }
111
+ if (prefetchClaimed.size >= PREFETCH_CLAIM_CAP) {
112
+ // Active owners are singleflight locks, not cache entries. Evicting one
113
+ // lets another envelope claim the same live thread and inject history
114
+ // twice. Only completed claims may give ground under pressure.
115
+ let removed = 0;
116
+ const target = Math.floor(PREFETCH_CLAIM_CAP / 2);
117
+ const completed = [...prefetchClaimed.entries()]
118
+ .filter(([, claim]) => claim.committed)
119
+ .sort((a, b) => a[1].lastUsed - b[1].lastUsed);
120
+ for (const [stale] of completed) {
121
+ prefetchClaimed.delete(stale);
122
+ removed += 1;
123
+ if (removed >= target)
124
+ break;
125
+ }
126
+ // All bounded slots can legitimately be in flight. Decline rather than
127
+ // queue or violate singleflight; a later message can retry after one
128
+ // owner commits or releases.
129
+ if (prefetchClaimed.size >= PREFETCH_CLAIM_CAP)
130
+ return 0;
131
+ }
132
+ const token = ++prefetchToken;
133
+ prefetchClaimed.set(key, { token, committed: false, lastUsed: ++prefetchUse });
134
+ return token;
135
+ }
136
+ /** Mark that this owner actually injected history; completed claims are evictable. */
137
+ export function commitThreadPrefetch(channel, threadTs, owner, token) {
138
+ if (!channel || !threadTs || !token)
139
+ return false;
140
+ const claim = prefetchClaimed.get(prefetchKey(channel, threadTs, owner));
141
+ if (!claim || claim.token !== token)
142
+ return false;
143
+ claim.committed = true;
144
+ claim.lastUsed = ++prefetchUse;
145
+ return true;
146
+ }
147
+ /**
148
+ * Give a claim back when no history was actually injected.
149
+ *
150
+ * Without this a failed or skipped first attempt would silently consume the
151
+ * thread's only chance: every later message would see the thread as already
152
+ * prefetched and the agent would never receive the earlier conversation.
153
+ *
154
+ * Only the CURRENT owner may release. A stale token is a no-op.
155
+ */
156
+ export function releaseThreadPrefetch(channel, threadTs, owner, token) {
157
+ if (!channel || !threadTs || !token)
158
+ return;
159
+ const key = prefetchKey(channel, threadTs, owner);
160
+ if (prefetchClaimed.get(key)?.token !== token)
161
+ return;
162
+ prefetchClaimed.delete(key);
163
+ }
164
+ export function resetThreadPrefetchClaims() {
165
+ prefetchClaimed.clear();
166
+ prefetchToken = 0;
167
+ prefetchUse = 0;
168
+ }
81
169
  /** Test hook: point the store at a temp file and drop the cache. */
82
170
  export function resetThreadTrackerForTest(filePath) {
83
171
  threads = null;
@@ -1 +1 @@
1
- {"version":3,"file":"thread-tracker.js","sourceRoot":"","sources":["../../../src/slack/thread-tracker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"thread-tracker.js","sourceRoot":"","sources":["../../../src/slack/thread-tracker.ts"],"names":[],"mappings":"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"}
@@ -26,6 +26,8 @@ import { getLastActiveTarget, registerTransport, setLastActiveTarget, setLatestS
26
26
  import { registerSendTransport, sendChannelOutput } from '../messaging/send.js';
27
27
  import { escapeHtmlTg, createForwarderLifecycle, createTelegramForwarder, relayTelegramImages, } from './forwarder.js';
28
28
  import { sendTelegramMarkdown } from './rich-message.js';
29
+ import { db } from '../core/db.js';
30
+ import { TelegramDurablePoller, TelegramUpdateOffsetStore } from './update-offset.js';
29
31
  export { escapeHtmlTg, markdownToTelegramHtml, chunkTelegramMessage, createForwarderLifecycle, createTelegramForwarder, } from './forwarder.js';
30
32
  // Re-exported from collect.ts (extracted in Phase B)
31
33
  import { orchestrateAndCollect, orchestrateAndCollectData } from '../orchestrator/collect.js';
@@ -33,8 +35,8 @@ import { log } from '../core/logger.js';
33
35
  export { orchestrateAndCollect };
34
36
  import { startPendingElicitation, handleElicitationCallback, discardPendingElicitation, } from './elicitation-buttons.js';
35
37
  import { redactOutboundPayload, redactOutboundText, logErrorText, userErrorText } from '../messaging/redact.js';
36
- import { createSeenSet, DELIVERY_DEDUPE_TTL_MS } from '../messaging/dedupe.js';
37
38
  import { sendWithRetryPolicy } from '../messaging/retry.js';
39
+ import { handleApprovalCommand, registerProductionTransport } from '../core/dispatch-approval-ingress.js';
38
40
  // ─── State ───────────────────────────────────────────
39
41
  export let telegramBot = null;
40
42
  export const telegramActiveChatIds = new Set();
@@ -43,6 +45,8 @@ let tgInitLock = false;
43
45
  let tg409RetryCount = 0;
44
46
  const TG_MAX_RETRIES = 3;
45
47
  let botUsername = null;
48
+ let telegramPoller = null;
49
+ const telegramFinalDeliveryFailures = new Set();
46
50
  /**
47
51
  * The bot's own user id, learned from getMe at startup.
48
52
  *
@@ -50,6 +54,24 @@ let botUsername = null;
50
54
  * the is_bot flag, which is why those are two separate checks.
51
55
  */
52
56
  let botUserId = null;
57
+ export function setTelegramBotUserIdForTest(value) { botUserId = value; }
58
+ let telegramApprovalIngress = null;
59
+ function createTelegramPollingIngress() {
60
+ const transport = Object.freeze({ platform: 'telegram' });
61
+ registerProductionTransport(transport);
62
+ return transport;
63
+ }
64
+ export function handleTelegramUpdate(update, transport = telegramApprovalIngress) {
65
+ const message = update['message'];
66
+ const text = typeof message?.text === 'string' ? message.text : '';
67
+ const fromIdRaw = message?.from?.id;
68
+ const fromId = typeof fromIdRaw === 'number' ? fromIdRaw : undefined;
69
+ const approval = handleApprovalCommand(transport, {
70
+ ...update,
71
+ __jawSelf: isSelfEcho({ fromId, isBot: message?.from?.is_bot, botUserId, allowBots: settings["telegram"]?.allowBots }),
72
+ }, text);
73
+ return approval.handled;
74
+ }
53
75
  /**
54
76
  * Whether an update should be dropped as our own output or another bot's.
55
77
  *
@@ -66,8 +88,7 @@ export function isSelfEcho(input) {
66
88
  return true;
67
89
  return false;
68
90
  }
69
- /** Redelivered update_ids, so a reconnect replay does not run the agent twice. */
70
- const telegramSeenUpdates = createSeenSet(DELIVERY_DEDUPE_TTL_MS);
91
+ const telegramUpdateOffsets = new TelegramUpdateOffsetStore(db);
71
92
  let targetReplyForwarderInstalled = false;
72
93
  const telegramForwarderLifecycle = createForwarderLifecycle({
73
94
  addListener: addBroadcastListener,
@@ -155,6 +176,16 @@ export async function shutdownTelegram() {
155
176
  tgRetryTimer = null;
156
177
  }
157
178
  detachTelegramForwarder();
179
+ if (telegramPoller) {
180
+ const oldPoller = telegramPoller;
181
+ telegramPoller = null;
182
+ try {
183
+ await oldPoller.stop();
184
+ }
185
+ catch (e) {
186
+ log.warn('[telegram:poller-stop]', logErrorText(e));
187
+ }
188
+ }
158
189
  if (!telegramBot)
159
190
  return;
160
191
  const old = telegramBot;
@@ -364,6 +395,11 @@ async function _initTelegramInner() {
364
395
  await new Promise(r => setTimeout(r, 2000));
365
396
  }
366
397
  }
398
+ const stoppingPoller = telegramPoller?.stop().catch((e) => {
399
+ log.warn('[telegram:poller-stop]', logErrorText(e));
400
+ });
401
+ telegramPoller = null;
402
+ await stoppingPoller;
367
403
  const envToken = process.env["TELEGRAM_TOKEN"];
368
404
  if (envToken)
369
405
  settings["telegram"].token = envToken;
@@ -467,38 +503,21 @@ async function _initTelegramInner() {
467
503
  }
468
504
  await next();
469
505
  });
470
- // Drop a redelivered update. grammY replays from the last committed offset
471
- // after a reconnect, so the same update_id can arrive twice — and each one
472
- // would start another agent run.
473
- //
474
- // Placed AFTER the allowlist and mention gates deliberately: dedupe
475
- // upstream of them lets traffic we never process fill the seen-set — memory
476
- // an outsider controls, and a budget an unmentioned group message can
477
- // exhaust before a real one arrives. A duplicate that WOULD be processed
478
- // passes both gates too, so nothing is lost by checking later.
479
- bot.use(async (ctx, next) => {
480
- const updateId = ctx.update?.update_id;
481
- if (updateId !== undefined && telegramSeenUpdates.seen(String(updateId))) {
482
- log.info(`[tg:duplicate] update_id=${updateId}`);
483
- return;
484
- }
485
- await next();
486
- });
487
506
  bot.command('start', (ctx) => ctx.reply(t('tg.connected', {}, currentLocale())));
488
507
  bot.command('id', (ctx) => ctx.reply(`Chat ID: <code>${ctx.chat?.id ?? ''}</code>`, { parse_mode: 'HTML' }));
489
508
  // Inline-keyboard elicitation answers (single_select fences → buttons).
490
509
  bot.callbackQuery(/^elic:/, async (ctx) => {
491
510
  const cbChatId = ctx.chat?.id;
492
511
  if (!cbChatId) {
493
- await ctx.answerCallbackQuery().catch(() => { });
512
+ await ctx.answerCallbackQuery();
494
513
  return;
495
514
  }
496
515
  const result = handleElicitationCallback(String(cbChatId), ctx.callbackQuery.data ?? '');
497
516
  if (result.kind === 'stale') {
498
- await ctx.answerCallbackQuery({ text: t('tg.elicitationExpired', {}, currentLocale()) }).catch(() => { });
517
+ await ctx.answerCallbackQuery({ text: t('tg.elicitationExpired', {}, currentLocale()) });
499
518
  return;
500
519
  }
501
- await ctx.answerCallbackQuery({ text: redactOutboundText(result.ack) }).catch(() => { });
520
+ await ctx.answerCallbackQuery({ text: redactOutboundText(result.ack) });
502
521
  // Best-effort: freeze the tapped question's keyboard so the choice reads as taken.
503
522
  await ctx.editMessageReplyMarkup({ reply_markup: { inline_keyboard: [] } }).catch(() => { });
504
523
  if (result.kind === 'complete') {
@@ -533,22 +552,54 @@ async function _initTelegramInner() {
533
552
  };
534
553
  if (result.action === 'queued') {
535
554
  log.info(`[tg:queue] agent busy, queued (${result.pending} pending)`);
536
- await ctx.reply(t('tg.queued', { count: result.pending }, currentLocale()));
537
555
  // 큐 처리 후 응답을 이 채팅으로 전달 — requestId로 request-level 격리
538
556
  const requestId = result.requestId;
539
- const queueHandler = (type, data) => {
540
- if (type === 'orchestrate_done' && data["text"] && data["origin"] === 'telegram' && data["requestId"] === requestId) {
557
+ const finalDeliveryControl = {};
558
+ const finalDelivery = new Promise((resolve, reject) => {
559
+ let timer;
560
+ let settled = false;
561
+ const cleanup = () => {
562
+ clearTimeout(timer);
541
563
  removeBroadcastListener(queueHandler);
542
- sendTelegramMarkdown(ctx.api, chat.id, String(data["text"]), replyOptsOf(ctx))
543
- .then(async () => {
544
- await relayTelegramImages(bot, chat.id, String(data["text"]), responseTarget);
545
- await sendElicitationKeyboards(chat.id, data["elicitationSpecs"]);
564
+ };
565
+ finalDeliveryControl.cancel = (reason) => {
566
+ if (settled)
567
+ return;
568
+ settled = true;
569
+ cleanup();
570
+ reject(reason);
571
+ };
572
+ const queueHandler = (type, data) => {
573
+ if (type !== 'orchestrate_done' || !data["text"] || data["origin"] !== 'telegram' || data["requestId"] !== requestId)
574
+ return;
575
+ if (settled)
576
+ return;
577
+ settled = true;
578
+ cleanup();
579
+ void sendTelegramMarkdown(ctx.api, chat.id, String(data["text"]), replyOptsOf(ctx))
580
+ .then(() => {
581
+ resolve();
582
+ void relayTelegramImages(bot, chat.id, String(data["text"]), responseTarget).catch(() => { });
583
+ void sendElicitationKeyboards(chat.id, data["elicitationSpecs"]).catch(() => { });
546
584
  })
547
- .catch(() => { });
548
- }
549
- };
550
- addBroadcastListener(queueHandler);
551
- setTimeout(() => removeBroadcastListener(queueHandler), 300000);
585
+ .catch(reject);
586
+ };
587
+ timer = setTimeout(() => {
588
+ finalDeliveryControl.cancel?.(new Error('telegram_queue_delivery_timeout'));
589
+ }, 300000);
590
+ addBroadcastListener(queueHandler);
591
+ });
592
+ void finalDelivery.catch(() => { });
593
+ try {
594
+ await ctx.reply(t('tg.queued', { count: result.pending }, currentLocale()));
595
+ await finalDelivery;
596
+ }
597
+ catch (error) {
598
+ finalDeliveryControl.cancel?.(error);
599
+ await finalDelivery.catch(() => { });
600
+ telegramFinalDeliveryFailures.add(ctx.update.update_id);
601
+ throw error;
602
+ }
552
603
  return;
553
604
  }
554
605
  if (result.action === 'rejected') {
@@ -649,6 +700,7 @@ async function _initTelegramInner() {
649
700
  } : null;
650
701
  if (toolHandler)
651
702
  addBroadcastListener(toolHandler);
703
+ let finalDeliveryStarted = false;
652
704
  try {
653
705
  const { text: collectedText, data: doneData } = await orchestrateAndCollectData(prompt, stripUndefined({
654
706
  origin: 'telegram', chatId: chat.id, requestId: submitRequestId, _skipInsert: true,
@@ -667,10 +719,11 @@ async function _initTelegramInner() {
667
719
  if (statusMsgId) {
668
720
  ctx.api.deleteMessage(chat.id, statusMsgId).catch(() => { });
669
721
  }
722
+ finalDeliveryStarted = true;
670
723
  await sendTelegramMarkdown(ctx.api, chat.id, collectedText, replyOptsOf(ctx));
671
- await relayTelegramImages(bot, chat.id, collectedText, responseTarget);
672
- await sendElicitationKeyboards(chat.id, doneData["elicitationSpecs"]);
673
724
  log.info(`[tg:out] ${chat.id}: ${redactOutboundText(collectedText).slice(0, 80)}`);
725
+ void relayTelegramImages(bot, chat.id, collectedText, responseTarget).catch(() => { });
726
+ void sendElicitationKeyboards(chat.id, doneData["elicitationSpecs"]).catch(() => { });
674
727
  }
675
728
  catch (err) {
676
729
  clearInterval(typingInterval);
@@ -685,6 +738,8 @@ async function _initTelegramInner() {
685
738
  }
686
739
  log.error('[tg:error]', logErrorText(err));
687
740
  await ctx.reply(`❌ Error: ${userErrorText(err)}`);
741
+ if (finalDeliveryStarted)
742
+ telegramFinalDeliveryFailures.add(ctx.update.update_id);
688
743
  }
689
744
  }
690
745
  bot.on('message:text', async (ctx) => {
@@ -742,7 +797,7 @@ async function _initTelegramInner() {
742
797
  }
743
798
  return;
744
799
  }
745
- tgOrchestrate(ctx, text, text);
800
+ await tgOrchestrate(ctx, text, text);
746
801
  });
747
802
  bot.on('message:photo', async (ctx) => {
748
803
  const photos = ctx.message.photo;
@@ -757,7 +812,7 @@ async function _initTelegramInner() {
757
812
  }));
758
813
  const filePath = saveUpload(dlResult["buffer"], `photo${dlResult["ext"]}`);
759
814
  const prompt = buildMediaPrompt(filePath, caption);
760
- tgOrchestrate(ctx, prompt, `${t('tg.imageCaption', { caption }, currentLocale())}`);
815
+ await tgOrchestrate(ctx, prompt, `${t('tg.imageCaption', { caption }, currentLocale())}`);
761
816
  }
762
817
  catch (err) {
763
818
  log.error('[tg:photo:error]', logErrorText(err));
@@ -776,14 +831,14 @@ async function _initTelegramInner() {
776
831
  }));
777
832
  const filePath = saveUpload(dlResult["buffer"], doc.file_name || 'document');
778
833
  const prompt = buildMediaPrompt(filePath, caption);
779
- tgOrchestrate(ctx, prompt, `[📎 ${doc.file_name || 'file'}] ${caption}`);
834
+ await tgOrchestrate(ctx, prompt, `[📎 ${doc.file_name || 'file'}] ${caption}`);
780
835
  }
781
836
  catch (err) {
782
837
  log.error('[tg:doc:error]', logErrorText(err));
783
838
  await ctx.reply(t('tg.fileFail', { msg: userErrorText(err) }, currentLocale()));
784
839
  }
785
840
  });
786
- bot.on('message:voice', (ctx) => handleVoice(ctx, currentLocale, tgOrchestrate));
841
+ bot.on('message:voice', async (ctx) => { await handleVoice(ctx, currentLocale, tgOrchestrate); });
787
842
  // Identity first: the self-echo guard needs it, and the refusal below has
788
843
  // to happen BEFORE anything is attached. Returning after attaching left the
789
844
  // forwarder wired to a bot that never starts, still trying to send.
@@ -794,17 +849,17 @@ async function _initTelegramInner() {
794
849
  botUserId = null;
795
850
  try {
796
851
  const me = await bot.api.getMe();
852
+ bot.botInfo = me;
797
853
  botUsername = me.username || null;
798
854
  botUserId = me.id ?? null;
799
855
  }
800
856
  catch (err) {
801
857
  log.warn('[tg] getMe failed; bot identity unknown', logErrorText(err));
802
858
  }
803
- // Without an identity the guard has only the is_bot flag to work with — and
804
- // allowBots turns that off. Starting anyway would leave the loop this guard
805
- // exists to prevent wide open, so refuse instead.
806
- if (botUserId === null && settings["telegram"]?.allowBots) {
807
- log.error('[tg] refusing to start: allowBots is on but the bot identity could not be read');
859
+ // The durable offset is scoped by bot identity, so polling must not start
860
+ // when getMe cannot provide that identity.
861
+ if (botUserId === null) {
862
+ log.error(logErrorText('[tg] refusing to start durable polling: bot identity could not be read'));
808
863
  return;
809
864
  }
810
865
  // ─── Global Forwarding: non-Telegram responses → Telegram ───
@@ -814,18 +869,34 @@ async function _initTelegramInner() {
814
869
  void syncTelegramCommands(bot).catch((e) => {
815
870
  log.warn('[tg:commands] setMyCommands failed:', logErrorText(e));
816
871
  });
817
- try {
818
- await bot.api.raw.deleteWebhook({ drop_pending_updates: true });
819
- }
820
- catch { /* best effort */ }
821
- bot.start({
822
- drop_pending_updates: true,
872
+ const poller = new TelegramDurablePoller({
873
+ api: bot.api,
874
+ key: String(botUserId),
875
+ store: telegramUpdateOffsets,
876
+ handleUpdateThroughFinalDelivery: async (update) => {
877
+ try {
878
+ if (handleTelegramUpdate(update, telegramApprovalIngress))
879
+ return;
880
+ await bot.handleUpdate(update);
881
+ if (telegramFinalDeliveryFailures.has(update.update_id)) {
882
+ throw new Error('telegram_final_delivery_failed');
883
+ }
884
+ }
885
+ finally {
886
+ telegramFinalDeliveryFailures.delete(update.update_id);
887
+ }
888
+ },
823
889
  onStart: (info) => {
824
890
  tg409RetryCount = 0;
825
- log.info(`[tg] @${info.username} polling active`);
891
+ const skipped = info.skippedThroughUpdateId === null ? '' : `; skipped through update ${info.skippedThroughUpdateId}`;
892
+ log.info(`[tg] ✅ @${botUsername ?? botUserId} durable polling active at offset ${info.nextOffset}${skipped}`);
826
893
  },
827
- }).catch((err) => {
828
- const is409 = err?.error_code === 409 || err?.message?.includes('409');
894
+ });
895
+ telegramPoller = poller;
896
+ telegramApprovalIngress = createTelegramPollingIngress();
897
+ poller.start().catch((err) => {
898
+ const telegramError = err;
899
+ const is409 = telegramError.error_code === 409 || telegramError.message?.includes('409');
829
900
  if (is409) {
830
901
  tg409RetryCount++;
831
902
  if (tg409RetryCount > TG_MAX_RETRIES) {
@@ -839,7 +910,7 @@ async function _initTelegramInner() {
839
910
  }
840
911
  }
841
912
  else {
842
- log.error('[tg:fatal]', logErrorText(err));
913
+ log.error('[tg:fatal] Telegram durability bootstrap/polling failed; no uncommitted backlog consumed', logErrorText(err));
843
914
  }
844
915
  });
845
916
  telegramBot = bot;