agor-live 0.21.2 → 0.22.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 (431) hide show
  1. package/dist/cli/commands/branch/env/restart.js +1 -1
  2. package/dist/cli/commands/branch/env/start.js +1 -1
  3. package/dist/cli/commands/branch/env/stop.js +1 -1
  4. package/dist/core/api/index.cjs +5 -1
  5. package/dist/core/api/index.d.ts +6 -1
  6. package/dist/core/api/index.d.ts.map +1 -1
  7. package/dist/core/api/index.js +5 -1
  8. package/dist/core/claude/index.cjs +162 -14
  9. package/dist/core/claude/index.js +166 -18
  10. package/dist/core/client/index.cjs +43 -3
  11. package/dist/core/client/index.js +37 -3
  12. package/dist/core/config/browser.cjs +2 -2
  13. package/dist/core/config/browser.js +2 -2
  14. package/dist/core/config/config-manager.d.ts.map +1 -1
  15. package/dist/core/config/constants.d.ts +1 -1
  16. package/dist/core/config/index.cjs +174 -20
  17. package/dist/core/config/index.js +178 -24
  18. package/dist/core/config/types.d.ts +8 -0
  19. package/dist/core/config/types.d.ts.map +1 -1
  20. package/dist/core/db/index.cjs +495 -86
  21. package/dist/core/db/index.js +482 -75
  22. package/dist/core/db/repositories/artifacts.d.ts.map +1 -1
  23. package/dist/core/db/repositories/branches.d.ts +13 -1
  24. package/dist/core/db/repositories/branches.d.ts.map +1 -1
  25. package/dist/core/db/repositories/gateway-channels.d.ts.map +1 -1
  26. package/dist/core/db/repositories/index.d.ts +1 -0
  27. package/dist/core/db/repositories/index.d.ts.map +1 -1
  28. package/dist/core/db/repositories/session-relationships.d.ts +30 -0
  29. package/dist/core/db/repositories/session-relationships.d.ts.map +1 -0
  30. package/dist/core/db/repositories/users.d.ts +11 -0
  31. package/dist/core/db/repositories/users.d.ts.map +1 -1
  32. package/dist/core/db/schema.d.ts +421 -4
  33. package/dist/core/db/schema.d.ts.map +1 -1
  34. package/dist/core/db/schema.postgres.d.ts +226 -2
  35. package/dist/core/db/schema.postgres.d.ts.map +1 -1
  36. package/dist/core/db/schema.sqlite.d.ts +228 -2
  37. package/dist/core/db/schema.sqlite.d.ts.map +1 -1
  38. package/dist/core/drizzle/postgres/0050_artifact_source_session.sql +3 -0
  39. package/dist/core/drizzle/postgres/0051_session_relationships.sql +26 -0
  40. package/dist/core/drizzle/postgres/meta/_journal.json +14 -0
  41. package/dist/core/drizzle/sqlite/0059_artifact_source_session.sql +2 -0
  42. package/dist/core/drizzle/sqlite/0060_session_relationships.sql +23 -0
  43. package/dist/core/drizzle/sqlite/meta/_journal.json +14 -0
  44. package/dist/core/gateway/connector-registry.d.ts.map +1 -1
  45. package/dist/core/gateway/connector.d.ts +22 -0
  46. package/dist/core/gateway/connector.d.ts.map +1 -1
  47. package/dist/core/gateway/connectors/slack.d.ts +35 -3
  48. package/dist/core/gateway/connectors/slack.d.ts.map +1 -1
  49. package/dist/core/gateway/connectors/teams.d.ts +107 -0
  50. package/dist/core/gateway/connectors/teams.d.ts.map +1 -0
  51. package/dist/core/gateway/context.d.ts.map +1 -1
  52. package/dist/core/gateway/index.cjs +552 -52
  53. package/dist/core/gateway/index.d.ts +3 -2
  54. package/dist/core/gateway/index.d.ts.map +1 -1
  55. package/dist/core/gateway/index.js +544 -52
  56. package/dist/core/gateway/system-message.d.ts +21 -0
  57. package/dist/core/gateway/system-message.d.ts.map +1 -1
  58. package/dist/core/index.cjs +616 -127
  59. package/dist/core/index.js +597 -116
  60. package/dist/core/mcp/index.cjs +146 -9
  61. package/dist/core/mcp/index.js +146 -9
  62. package/dist/core/mcp/template-resolver.d.ts.map +1 -1
  63. package/dist/core/seed/index.cjs +375 -59
  64. package/dist/core/seed/index.js +378 -62
  65. package/dist/core/sessions/index.cjs +19 -0
  66. package/dist/core/sessions/index.js +19 -0
  67. package/dist/core/templates/agor-system-prompt.md +21 -53
  68. package/dist/core/templates/session-context.cjs +2 -73
  69. package/dist/core/templates/session-context.d.ts +9 -53
  70. package/dist/core/templates/session-context.d.ts.map +1 -1
  71. package/dist/core/templates/session-context.js +2 -72
  72. package/dist/core/tools/mcp/jwt-auth.cjs +2 -20
  73. package/dist/core/tools/mcp/jwt-auth.d.ts.map +1 -1
  74. package/dist/core/tools/mcp/jwt-auth.js +2 -20
  75. package/dist/core/tools/mcp/oauth-mcp-transport.cjs +2 -15
  76. package/dist/core/tools/mcp/oauth-mcp-transport.d.ts.map +1 -1
  77. package/dist/core/tools/mcp/oauth-mcp-transport.js +2 -15
  78. package/dist/core/tools/mcp/oauth-refresh.cjs +167 -19
  79. package/dist/core/tools/mcp/oauth-refresh.js +167 -19
  80. package/dist/core/types/artifact.d.ts +5 -1
  81. package/dist/core/types/artifact.d.ts.map +1 -1
  82. package/dist/core/types/branch.d.ts +14 -0
  83. package/dist/core/types/branch.d.ts.map +1 -1
  84. package/dist/core/types/gateway.d.ts +1 -1
  85. package/dist/core/types/gateway.d.ts.map +1 -1
  86. package/dist/core/types/id.d.ts +1 -0
  87. package/dist/core/types/id.d.ts.map +1 -1
  88. package/dist/core/types/index.cjs +36 -0
  89. package/dist/core/types/index.js +30 -0
  90. package/dist/core/types/session.d.ts +65 -1
  91. package/dist/core/types/session.d.ts.map +1 -1
  92. package/dist/core/types/task.d.ts +9 -0
  93. package/dist/core/types/task.d.ts.map +1 -1
  94. package/dist/core/unix/index.cjs +371 -55
  95. package/dist/core/unix/index.js +374 -58
  96. package/dist/core/unix/unix-integration-service.d.ts +10 -7
  97. package/dist/core/unix/unix-integration-service.d.ts.map +1 -1
  98. package/dist/core/utils/permission-mode-mapper.cjs +19 -0
  99. package/dist/core/utils/permission-mode-mapper.js +19 -0
  100. package/dist/daemon/declarations.d.ts +7 -0
  101. package/dist/daemon/declarations.d.ts.map +1 -1
  102. package/dist/daemon/hooks/gateway-route.d.ts.map +1 -1
  103. package/dist/daemon/hooks/gateway-route.js +53 -1
  104. package/dist/daemon/index.js +3760 -2107
  105. package/dist/daemon/main.js +3760 -2107
  106. package/dist/daemon/mcp/server.js +155 -17
  107. package/dist/daemon/mcp/tools/analytics.js +6 -7
  108. package/dist/daemon/mcp/tools/artifacts.d.ts.map +1 -1
  109. package/dist/daemon/mcp/tools/artifacts.js +7 -7
  110. package/dist/daemon/mcp/tools/boards.js +6 -7
  111. package/dist/daemon/mcp/tools/branches.js +6 -7
  112. package/dist/daemon/mcp/tools/card-types.js +6 -7
  113. package/dist/daemon/mcp/tools/cards.js +6 -7
  114. package/dist/daemon/mcp/tools/environment.d.ts.map +1 -1
  115. package/dist/daemon/mcp/tools/environment.js +19 -12
  116. package/dist/daemon/mcp/tools/knowledge.js +6 -7
  117. package/dist/daemon/mcp/tools/mcp-servers.js +6 -7
  118. package/dist/daemon/mcp/tools/messages.js +6 -7
  119. package/dist/daemon/mcp/tools/proxies.js +6 -7
  120. package/dist/daemon/mcp/tools/repos.js +6 -7
  121. package/dist/daemon/mcp/tools/schedules.js +6 -7
  122. package/dist/daemon/mcp/tools/search.js +6 -7
  123. package/dist/daemon/mcp/tools/sessions.d.ts.map +1 -1
  124. package/dist/daemon/mcp/tools/sessions.js +140 -11
  125. package/dist/daemon/mcp/tools/tasks.js +6 -7
  126. package/dist/daemon/mcp/tools/users.js +6 -7
  127. package/dist/daemon/mcp/tools/widgets.js +7 -8
  128. package/dist/daemon/register-hooks.d.ts +5 -1
  129. package/dist/daemon/register-hooks.d.ts.map +1 -1
  130. package/dist/daemon/register-hooks.js +404 -179
  131. package/dist/daemon/register-routes.d.ts.map +1 -1
  132. package/dist/daemon/register-routes.js +360 -162
  133. package/dist/daemon/register-services.d.ts.map +1 -1
  134. package/dist/daemon/register-services.js +1928 -671
  135. package/dist/daemon/services/artifacts.d.ts +10 -1
  136. package/dist/daemon/services/artifacts.d.ts.map +1 -1
  137. package/dist/daemon/services/artifacts.js +25 -1
  138. package/dist/daemon/services/branches.d.ts +11 -1
  139. package/dist/daemon/services/branches.d.ts.map +1 -1
  140. package/dist/daemon/services/branches.js +470 -184
  141. package/dist/daemon/services/claude-models.js +879 -339
  142. package/dist/daemon/services/gateway.d.ts +58 -2
  143. package/dist/daemon/services/gateway.d.ts.map +1 -1
  144. package/dist/daemon/services/gateway.js +590 -47
  145. package/dist/daemon/services/groups.d.ts +2 -0
  146. package/dist/daemon/services/groups.d.ts.map +1 -1
  147. package/dist/daemon/services/groups.js +56 -0
  148. package/dist/daemon/services/mcp-servers.d.ts.map +1 -1
  149. package/dist/daemon/services/mcp-servers.js +0 -6
  150. package/dist/daemon/services/scheduler.d.ts.map +1 -1
  151. package/dist/daemon/services/scheduler.js +6 -2
  152. package/dist/daemon/services/sessions.d.ts +11 -3
  153. package/dist/daemon/services/sessions.d.ts.map +1 -1
  154. package/dist/daemon/services/sessions.js +68 -7
  155. package/dist/daemon/services/tasks.d.ts +13 -2
  156. package/dist/daemon/services/tasks.d.ts.map +1 -1
  157. package/dist/daemon/services/tasks.js +42 -26
  158. package/dist/daemon/startup.js +6 -2
  159. package/dist/daemon/utils/session-stop.d.ts +43 -0
  160. package/dist/daemon/utils/session-stop.d.ts.map +1 -0
  161. package/dist/daemon/utils/session-stop.js +102 -0
  162. package/dist/daemon/utils/session-task-state.d.ts +7 -2
  163. package/dist/daemon/utils/session-task-state.d.ts.map +1 -1
  164. package/dist/daemon/utils/session-task-state.js +9 -3
  165. package/dist/daemon/utils/session-tasks.d.ts +4 -4
  166. package/dist/daemon/utils/session-tasks.d.ts.map +1 -1
  167. package/dist/daemon/utils/session-tasks.js +4 -8
  168. package/dist/executor/commands/environment.d.ts +13 -0
  169. package/dist/executor/commands/environment.d.ts.map +1 -0
  170. package/dist/executor/commands/environment.js +287 -0
  171. package/dist/executor/commands/index.d.ts.map +1 -1
  172. package/dist/executor/commands/index.js +5 -1
  173. package/dist/executor/commands/unix.d.ts +8 -1
  174. package/dist/executor/commands/unix.d.ts.map +1 -1
  175. package/dist/executor/commands/unix.js +157 -2
  176. package/dist/executor/payload-types.d.ts +201 -5
  177. package/dist/executor/payload-types.d.ts.map +1 -1
  178. package/dist/executor/payload-types.js +98 -0
  179. package/dist/executor/sdk-handlers/base/mcp-scoping.d.ts.map +1 -1
  180. package/dist/executor/sdk-handlers/base/mcp-scoping.js +14 -0
  181. package/dist/executor/sdk-handlers/claude/message-processor.d.ts.map +1 -1
  182. package/dist/executor/sdk-handlers/claude/message-processor.js +0 -1
  183. package/dist/executor/sdk-handlers/claude/query-builder.d.ts +1 -0
  184. package/dist/executor/sdk-handlers/claude/query-builder.d.ts.map +1 -1
  185. package/dist/executor/sdk-handlers/claude/query-builder.js +91 -39
  186. package/dist/executor/sdk-handlers/codex/prompt-service.d.ts +12 -5
  187. package/dist/executor/sdk-handlers/codex/prompt-service.d.ts.map +1 -1
  188. package/dist/executor/sdk-handlers/codex/prompt-service.js +72 -30
  189. package/dist/executor/sdk-handlers/copilot/prompt-service.d.ts +2 -4
  190. package/dist/executor/sdk-handlers/copilot/prompt-service.d.ts.map +1 -1
  191. package/dist/executor/sdk-handlers/copilot/prompt-service.js +4 -13
  192. package/dist/executor/sdk-handlers/gemini/prompt-service.d.ts +2 -4
  193. package/dist/executor/sdk-handlers/gemini/prompt-service.d.ts.map +1 -1
  194. package/dist/executor/sdk-handlers/gemini/prompt-service.js +4 -13
  195. package/dist/ui/assets/App-DcEY8Ota.js +3 -0
  196. package/dist/ui/assets/App-DcEY8Ota.js.gz +0 -0
  197. package/dist/ui/assets/{ArtifactConsentModal-ParNk5kW.js → ArtifactConsentModal-CiCbK9iv.js} +1 -1
  198. package/dist/ui/assets/ArtifactConsentModal-CiCbK9iv.js.gz +0 -0
  199. package/dist/ui/assets/ArtifactFullscreenPage-CfsTEGKd.js +9 -0
  200. package/dist/ui/assets/ArtifactFullscreenPage-CfsTEGKd.js.gz +0 -0
  201. package/dist/ui/assets/AutocompleteTextarea-BAFFH_5e.js +18 -0
  202. package/dist/ui/assets/AutocompleteTextarea-BAFFH_5e.js.gz +0 -0
  203. package/dist/ui/assets/BoardObjectNodes-D-O6bZIG.js +34 -0
  204. package/dist/ui/assets/BoardObjectNodes-D-O6bZIG.js.gz +0 -0
  205. package/dist/ui/assets/{CodeEditor.inner-D51Z_CLQ.js → CodeEditor.inner-DBgsP4tn.js} +2 -2
  206. package/dist/ui/assets/CodeEditor.inner-DBgsP4tn.js.gz +0 -0
  207. package/dist/ui/assets/ConversationView-CUWR0gR6.js +1 -0
  208. package/dist/ui/assets/ConversationView-CUWR0gR6.js.gz +0 -0
  209. package/dist/ui/assets/KnowledgePage-B2bzlXfn.js +24 -0
  210. package/dist/ui/assets/KnowledgePage-B2bzlXfn.js.gz +0 -0
  211. package/dist/ui/assets/MarketingScreenshotPage-9Qd7eZsm.css +1 -0
  212. package/dist/ui/assets/MarketingScreenshotPage-zv5RUCuV.js +143 -0
  213. package/dist/ui/assets/MarketingScreenshotPage-zv5RUCuV.js.gz +0 -0
  214. package/dist/ui/assets/MobileApp-VgVnsnsN.js +1 -0
  215. package/dist/ui/assets/MobileApp-VgVnsnsN.js.gz +0 -0
  216. package/dist/ui/assets/SessionCanvas-f1-1Gbcw.js +20 -0
  217. package/dist/ui/assets/SessionCanvas-f1-1Gbcw.js.gz +0 -0
  218. package/dist/ui/assets/{App-BAdBsEnV.css → SessionCanvas-mEmYGZhC.css} +1 -1
  219. package/dist/ui/assets/SessionCanvas-mEmYGZhC.css.gz +0 -0
  220. package/dist/ui/assets/{StreamdownDemoPage-B9wbgp2s.js → StreamdownDemoPage-wzWaqWwr.js} +1 -1
  221. package/dist/ui/assets/StreamdownDemoPage-wzWaqWwr.js.gz +0 -0
  222. package/dist/ui/assets/{ThemeSwitcher-ubn6IOz9.js → ThemeSwitcher-Dly2y9pi.js} +1 -1
  223. package/dist/ui/assets/ThemeSwitcher-Dly2y9pi.js.gz +0 -0
  224. package/dist/ui/assets/antd-CfbbHJOz.js +401 -0
  225. package/dist/ui/assets/antd-CfbbHJOz.js.gz +0 -0
  226. package/dist/ui/assets/architecture-U656AL7Q-CykGFbQU.js +1 -0
  227. package/dist/ui/assets/{architectureDiagram-VXUJARFQ-ChmZt3zk.js → architectureDiagram-VXUJARFQ-C8HXAenz.js} +1 -1
  228. package/dist/ui/assets/architectureDiagram-VXUJARFQ-C8HXAenz.js.gz +0 -0
  229. package/dist/ui/assets/{blockDiagram-VD42YOAC-CzGHAHao.js → blockDiagram-VD42YOAC-BhZaEN19.js} +1 -1
  230. package/dist/ui/assets/blockDiagram-VD42YOAC-BhZaEN19.js.gz +0 -0
  231. package/dist/ui/assets/{c4Diagram-YG6GDRKO-DscJyaWN.js → c4Diagram-YG6GDRKO-Dk_UH-sY.js} +1 -1
  232. package/dist/ui/assets/c4Diagram-YG6GDRKO-Dk_UH-sY.js.gz +0 -0
  233. package/dist/ui/assets/channel-D6_nUWlW.js +1 -0
  234. package/dist/ui/assets/{chunk-4BX2VUAB-DoWpTvP8.js → chunk-4BX2VUAB-XprbG2TG.js} +1 -1
  235. package/dist/ui/assets/chunk-55IACEB6-ByzqIgSb.js +1 -0
  236. package/dist/ui/assets/{chunk-ABZYJK2D-RzDCrjE6.js → chunk-ABZYJK2D-BJcrryHK.js} +1 -1
  237. package/dist/ui/assets/chunk-ABZYJK2D-BJcrryHK.js.gz +0 -0
  238. package/dist/ui/assets/{chunk-AGHRB4JF-jidCS5Of.js → chunk-AGHRB4JF-DvxmfbM0.js} +1 -1
  239. package/dist/ui/assets/chunk-AGHRB4JF-DvxmfbM0.js.gz +0 -0
  240. package/dist/ui/assets/{chunk-ATLVNIR6-BEIIfJtC.js → chunk-ATLVNIR6-DbeJ0OrR.js} +1 -1
  241. package/dist/ui/assets/chunk-ATLVNIR6-DbeJ0OrR.js.gz +0 -0
  242. package/dist/ui/assets/{chunk-B4BG7PRW-B8b6dQQ2.js → chunk-B4BG7PRW-C53q2ggf.js} +1 -1
  243. package/dist/ui/assets/chunk-B4BG7PRW-C53q2ggf.js.gz +0 -0
  244. package/dist/ui/assets/{chunk-CVBHYZKI-D-mQAfrk.js → chunk-CVBHYZKI-B3EBSlb3.js} +1 -1
  245. package/dist/ui/assets/{chunk-DI55MBZ5-BfATX3V8.js → chunk-DI55MBZ5-vIyNEQN-.js} +1 -1
  246. package/dist/ui/assets/chunk-DI55MBZ5-vIyNEQN-.js.gz +0 -0
  247. package/dist/ui/assets/chunk-EXTU4WIE-B3ObkuOm.js +1 -0
  248. package/dist/ui/assets/{chunk-FMBD7UC4-fqXscNvc.js → chunk-FMBD7UC4-rddmfK-Z.js} +1 -1
  249. package/dist/ui/assets/{chunk-HN2XXSSU-BCHvD80g.js → chunk-HN2XXSSU-Dttqcg3b.js} +1 -1
  250. package/dist/ui/assets/chunk-HN2XXSSU-Dttqcg3b.js.gz +0 -0
  251. package/dist/ui/assets/{chunk-JA3XYJ7Z-Cp6dqHnY.js → chunk-JA3XYJ7Z-DbNDev3D.js} +1 -1
  252. package/dist/ui/assets/chunk-JA3XYJ7Z-DbNDev3D.js.gz +0 -0
  253. package/dist/ui/assets/{chunk-JZLCHNYA-cKMooY3y.js → chunk-JZLCHNYA-EUmx2y4H.js} +1 -1
  254. package/dist/ui/assets/chunk-JZLCHNYA-EUmx2y4H.js.gz +0 -0
  255. package/dist/ui/assets/{chunk-MI3HLSF2-BlzO5wOE.js → chunk-MI3HLSF2-65n9Mkyc.js} +1 -1
  256. package/dist/ui/assets/chunk-MI3HLSF2-65n9Mkyc.js.gz +0 -0
  257. package/dist/ui/assets/chunk-N4CR4FBY-mv5koXqW.js +2 -0
  258. package/dist/ui/assets/chunk-N4CR4FBY-mv5koXqW.js.gz +0 -0
  259. package/dist/ui/assets/{chunk-QN33PNHL-DIHGQ_pd.js → chunk-QN33PNHL-DsRKK6NR.js} +1 -1
  260. package/dist/ui/assets/{chunk-QXUST7PY-C9l0muI0.js → chunk-QXUST7PY-BCYnMiS3.js} +1 -1
  261. package/dist/ui/assets/chunk-QXUST7PY-BCYnMiS3.js.gz +0 -0
  262. package/dist/ui/assets/chunk-QZHKN3VN-HucAw4xW.js +1 -0
  263. package/dist/ui/assets/{chunk-S3R3BYOJ-VJiLzt2o.js → chunk-S3R3BYOJ-CWMEa9Dc.js} +1 -1
  264. package/dist/ui/assets/chunk-S3R3BYOJ-CWMEa9Dc.js.gz +0 -0
  265. package/dist/ui/assets/{chunk-TZMSLE5B-DZwI0C_2.js → chunk-TZMSLE5B-BuQUQcTr.js} +1 -1
  266. package/dist/ui/assets/chunk-TZMSLE5B-BuQUQcTr.js.gz +0 -0
  267. package/dist/ui/assets/classDiagram-2ON5EDUG-CUT3rPTB.js +1 -0
  268. package/dist/ui/assets/classDiagram-v2-WZHVMYZB-CUT3rPTB.js +1 -0
  269. package/dist/ui/assets/{cose-bilkent-S5V4N54A-Ipik-oSD.js → cose-bilkent-S5V4N54A-CnPB3ARO.js} +1 -1
  270. package/dist/ui/assets/cose-bilkent-S5V4N54A-CnPB3ARO.js.gz +0 -0
  271. package/dist/ui/assets/cursor-QEb7m-rN.png +0 -0
  272. package/dist/ui/assets/{dagre-6UL2VRFP-BDpyWQnh.js → dagre-6UL2VRFP-DhS-k_Se.js} +1 -1
  273. package/dist/ui/assets/dagre-6UL2VRFP-DhS-k_Se.js.gz +0 -0
  274. package/dist/ui/assets/{dagre-CgA4KhUX.js → dagre-KgLoHEuy.js} +1 -1
  275. package/dist/ui/assets/dagre-KgLoHEuy.js.gz +0 -0
  276. package/dist/ui/assets/{diagram-PSM6KHXK-B4GRzxLJ.js → diagram-PSM6KHXK-BZg3MJmb.js} +1 -1
  277. package/dist/ui/assets/diagram-PSM6KHXK-BZg3MJmb.js.gz +0 -0
  278. package/dist/ui/assets/{diagram-QEK2KX5R-BWPW28XI.js → diagram-QEK2KX5R-BPCitvbo.js} +1 -1
  279. package/dist/ui/assets/diagram-QEK2KX5R-BPCitvbo.js.gz +0 -0
  280. package/dist/ui/assets/{diagram-S2PKOQOG-BIHhcGoV.js → diagram-S2PKOQOG-NW4uK6sx.js} +1 -1
  281. package/dist/ui/assets/diagram-S2PKOQOG-NW4uK6sx.js.gz +0 -0
  282. package/dist/ui/assets/{editor-C-HJ7Yw0.js → editor-CzFWIUw2.js} +1 -1
  283. package/dist/ui/assets/editor-CzFWIUw2.js.gz +0 -0
  284. package/dist/ui/assets/{emoji-D8F6B62m.js → emoji-Dkz4Zzv_.js} +1 -1
  285. package/dist/ui/assets/emoji-Dkz4Zzv_.js.gz +0 -0
  286. package/dist/ui/assets/{erDiagram-Q2GNP2WA-ubTaAFcK.js → erDiagram-Q2GNP2WA-me1fboaf.js} +1 -1
  287. package/dist/ui/assets/erDiagram-Q2GNP2WA-me1fboaf.js.gz +0 -0
  288. package/dist/ui/assets/{flowDiagram-NV44I4VS-BHLCTYjI.js → flowDiagram-NV44I4VS-DzE8dGsh.js} +1 -1
  289. package/dist/ui/assets/flowDiagram-NV44I4VS-DzE8dGsh.js.gz +0 -0
  290. package/dist/ui/assets/{ganttDiagram-LVOFAZNH-ClC3pay1.js → ganttDiagram-LVOFAZNH-CFQD09Mi.js} +2 -2
  291. package/dist/ui/assets/ganttDiagram-LVOFAZNH-CFQD09Mi.js.gz +0 -0
  292. package/dist/ui/assets/{gitGraph-F6HP7TQM-DghoobE6.js → gitGraph-F6HP7TQM-CfFE_uAC.js} +1 -1
  293. package/dist/ui/assets/{gitGraphDiagram-NY62KEGX-Clqpiswu.js → gitGraphDiagram-NY62KEGX-CaVoxU4C.js} +1 -1
  294. package/dist/ui/assets/gitGraphDiagram-NY62KEGX-CaVoxU4C.js.gz +0 -0
  295. package/dist/ui/assets/index-BN5_Qq7R.js +324 -0
  296. package/dist/ui/assets/index-BN5_Qq7R.js.gz +0 -0
  297. package/dist/ui/assets/index-DxuPq13l.css +1 -0
  298. package/dist/ui/assets/index-DxuPq13l.css.gz +0 -0
  299. package/dist/ui/assets/{info-NVLQJR56-0ZldEXPQ.js → info-NVLQJR56-i_xHYg3f.js} +1 -1
  300. package/dist/ui/assets/{infoDiagram-ER5ION4S-DMmPX-il.js → infoDiagram-ER5ION4S-2NL93b78.js} +1 -1
  301. package/dist/ui/assets/{journeyDiagram-XKPGCS4Q-CrVickA2.js → journeyDiagram-XKPGCS4Q-CZF-2DHU.js} +1 -1
  302. package/dist/ui/assets/journeyDiagram-XKPGCS4Q-CZF-2DHU.js.gz +0 -0
  303. package/dist/ui/assets/{kanban-definition-3W4ZIXB7-C_BsdHYL.js → kanban-definition-3W4ZIXB7-CfvJIOny.js} +1 -1
  304. package/dist/ui/assets/kanban-definition-3W4ZIXB7-CfvJIOny.js.gz +0 -0
  305. package/dist/ui/assets/{line-CfBP7Yic.js → line-DDv8kOJk.js} +1 -1
  306. package/dist/ui/assets/{linear-BsjageUB.js → linear-Daef-l29.js} +1 -1
  307. package/dist/ui/assets/linear-Daef-l29.js.gz +0 -0
  308. package/dist/ui/assets/{mermaid-parser.core-DZdP-NFq.js → mermaid-parser.core-CdK9QgYV.js} +2 -2
  309. package/dist/ui/assets/mermaid-parser.core-CdK9QgYV.js.gz +0 -0
  310. package/dist/ui/assets/{mermaid.core-TNrI0pHG.js → mermaid.core-D6GS9mU-.js} +3 -3
  311. package/dist/ui/assets/mermaid.core-D6GS9mU-.js.gz +0 -0
  312. package/dist/ui/assets/message-SqLqNYcv.js +36 -0
  313. package/dist/ui/assets/message-SqLqNYcv.js.gz +0 -0
  314. package/dist/ui/assets/{mindmap-definition-VGOIOE7T-BbmaUjMY.js → mindmap-definition-VGOIOE7T-Cb3QMflX.js} +1 -1
  315. package/dist/ui/assets/mindmap-definition-VGOIOE7T-Cb3QMflX.js.gz +0 -0
  316. package/dist/ui/assets/{packet-BFZMPI3H-D_ZhkXuT.js → packet-BFZMPI3H-Bm2uwz4i.js} +1 -1
  317. package/dist/ui/assets/{particles-Dv28pjOd.js → particles-DsJFOarW.js} +1 -1
  318. package/dist/ui/assets/particles-DsJFOarW.js.gz +0 -0
  319. package/dist/ui/assets/{pie-7BOR55EZ-Dn0Q3qNx.js → pie-7BOR55EZ-5i17tVnF.js} +1 -1
  320. package/dist/ui/assets/{pieDiagram-ADFJNKIX-BbyjfYu8.js → pieDiagram-ADFJNKIX-BxIwQWvw.js} +1 -1
  321. package/dist/ui/assets/pieDiagram-ADFJNKIX-BxIwQWvw.js.gz +0 -0
  322. package/dist/ui/assets/{quadrantDiagram-AYHSOK5B-Bc3GqMKz.js → quadrantDiagram-AYHSOK5B-B5HPe4ga.js} +1 -1
  323. package/dist/ui/assets/quadrantDiagram-AYHSOK5B-B5HPe4ga.js.gz +0 -0
  324. package/dist/ui/assets/{radar-NHE76QYJ-BHwoAy1q.js → radar-NHE76QYJ-BTn-tq0k.js} +1 -1
  325. package/dist/ui/assets/{reactflow-BVYPxNhc.js → reactflow-Bf74ngoo.js} +2 -2
  326. package/dist/ui/assets/reactflow-Bf74ngoo.js.gz +0 -0
  327. package/dist/ui/assets/{requirementDiagram-UZGBJVZJ-BQaKKL09.js → requirementDiagram-UZGBJVZJ-YfI6llkX.js} +1 -1
  328. package/dist/ui/assets/requirementDiagram-UZGBJVZJ-YfI6llkX.js.gz +0 -0
  329. package/dist/ui/assets/{sandpack-BQW_FQ7G.js → sandpack-D7koO5op.js} +1 -1
  330. package/dist/ui/assets/sandpack-D7koO5op.js.gz +0 -0
  331. package/dist/ui/assets/{sankeyDiagram-TZEHDZUN-DiJvDvhb.js → sankeyDiagram-TZEHDZUN-DOk_B10B.js} +1 -1
  332. package/dist/ui/assets/sankeyDiagram-TZEHDZUN-DOk_B10B.js.gz +0 -0
  333. package/dist/ui/assets/{sequenceDiagram-WL72ISMW-Dw32824o.js → sequenceDiagram-WL72ISMW-DAe4Um17.js} +1 -1
  334. package/dist/ui/assets/sequenceDiagram-WL72ISMW-DAe4Um17.js.gz +0 -0
  335. package/dist/ui/assets/{stateDiagram-FKZM4ZOC-BCOpNdHV.js → stateDiagram-FKZM4ZOC-CCesDu_C.js} +1 -1
  336. package/dist/ui/assets/stateDiagram-FKZM4ZOC-CCesDu_C.js.gz +0 -0
  337. package/dist/ui/assets/stateDiagram-v2-4FDKWEC3-CMlIrsoO.js +1 -0
  338. package/dist/ui/assets/{syntax-VJrU5BEu.js → syntax-C-M-8jOU.js} +1 -1
  339. package/dist/ui/assets/syntax-C-M-8jOU.js.gz +0 -0
  340. package/dist/ui/assets/{theme-DZtFA8b4.js → theme-BQZdiqwv.js} +1 -1
  341. package/dist/ui/assets/{timeline-definition-IT6M3QCI-Jh_WZzXv.js → timeline-definition-IT6M3QCI-D6P5txjT.js} +1 -1
  342. package/dist/ui/assets/timeline-definition-IT6M3QCI-D6P5txjT.js.gz +0 -0
  343. package/dist/ui/assets/{treemap-KMMF4GRG-CPYIgjxE.js → treemap-KMMF4GRG-Bitm3gy4.js} +1 -1
  344. package/dist/ui/assets/{knowledgeRoutes-CivaUqha.js → useUserLocalStorage-Ckb8HsIw.js} +1 -1
  345. package/dist/ui/assets/useUserLocalStorage-Ckb8HsIw.js.gz +0 -0
  346. package/dist/ui/assets/{xychartDiagram-PRI3JC2R-CERc7Rdb.js → xychartDiagram-PRI3JC2R-CsybjUbd.js} +1 -1
  347. package/dist/ui/assets/xychartDiagram-PRI3JC2R-CsybjUbd.js.gz +0 -0
  348. package/dist/ui/index.html +13 -11
  349. package/dist/ui/index.html.gz +0 -0
  350. package/package.json +10 -9
  351. package/dist/ui/assets/App-9s2WHM6S.js +0 -22
  352. package/dist/ui/assets/App-9s2WHM6S.js.gz +0 -0
  353. package/dist/ui/assets/App-BAdBsEnV.css.gz +0 -0
  354. package/dist/ui/assets/ArtifactConsentModal-ParNk5kW.js.gz +0 -0
  355. package/dist/ui/assets/ArtifactFullscreenPage-VQxLMCiN.js +0 -9
  356. package/dist/ui/assets/ArtifactFullscreenPage-VQxLMCiN.js.gz +0 -0
  357. package/dist/ui/assets/AutocompleteTextarea-3RchrIgk.js +0 -18
  358. package/dist/ui/assets/AutocompleteTextarea-3RchrIgk.js.gz +0 -0
  359. package/dist/ui/assets/CodeEditor.inner-D51Z_CLQ.js.gz +0 -0
  360. package/dist/ui/assets/ConversationView-Dyddw2b1.js +0 -34
  361. package/dist/ui/assets/ConversationView-Dyddw2b1.js.gz +0 -0
  362. package/dist/ui/assets/KnowledgePage-CdftslnF.js +0 -24
  363. package/dist/ui/assets/KnowledgePage-CdftslnF.js.gz +0 -0
  364. package/dist/ui/assets/MobileApp-BdBMpnJ1.js +0 -1
  365. package/dist/ui/assets/MobileApp-BdBMpnJ1.js.gz +0 -0
  366. package/dist/ui/assets/StreamdownDemoPage-B9wbgp2s.js.gz +0 -0
  367. package/dist/ui/assets/ThemeSwitcher-ubn6IOz9.js.gz +0 -0
  368. package/dist/ui/assets/antd-C-HfEC4E.js +0 -400
  369. package/dist/ui/assets/antd-C-HfEC4E.js.gz +0 -0
  370. package/dist/ui/assets/architecture-U656AL7Q-dkBewUpN.js +0 -1
  371. package/dist/ui/assets/architectureDiagram-VXUJARFQ-ChmZt3zk.js.gz +0 -0
  372. package/dist/ui/assets/blockDiagram-VD42YOAC-CzGHAHao.js.gz +0 -0
  373. package/dist/ui/assets/c4Diagram-YG6GDRKO-DscJyaWN.js.gz +0 -0
  374. package/dist/ui/assets/channel-DvRQqEqC.js +0 -1
  375. package/dist/ui/assets/chunk-55IACEB6-DojF2pZN.js +0 -1
  376. package/dist/ui/assets/chunk-ABZYJK2D-RzDCrjE6.js.gz +0 -0
  377. package/dist/ui/assets/chunk-AGHRB4JF-jidCS5Of.js.gz +0 -0
  378. package/dist/ui/assets/chunk-ATLVNIR6-BEIIfJtC.js.gz +0 -0
  379. package/dist/ui/assets/chunk-B4BG7PRW-B8b6dQQ2.js.gz +0 -0
  380. package/dist/ui/assets/chunk-DI55MBZ5-BfATX3V8.js.gz +0 -0
  381. package/dist/ui/assets/chunk-EXTU4WIE-BKt6lPJM.js +0 -1
  382. package/dist/ui/assets/chunk-HN2XXSSU-BCHvD80g.js.gz +0 -0
  383. package/dist/ui/assets/chunk-JA3XYJ7Z-Cp6dqHnY.js.gz +0 -0
  384. package/dist/ui/assets/chunk-JZLCHNYA-cKMooY3y.js.gz +0 -0
  385. package/dist/ui/assets/chunk-MI3HLSF2-BlzO5wOE.js.gz +0 -0
  386. package/dist/ui/assets/chunk-N4CR4FBY-pASDorUx.js +0 -2
  387. package/dist/ui/assets/chunk-N4CR4FBY-pASDorUx.js.gz +0 -0
  388. package/dist/ui/assets/chunk-QXUST7PY-C9l0muI0.js.gz +0 -0
  389. package/dist/ui/assets/chunk-QZHKN3VN-CZskCFCf.js +0 -1
  390. package/dist/ui/assets/chunk-S3R3BYOJ-VJiLzt2o.js.gz +0 -0
  391. package/dist/ui/assets/chunk-TZMSLE5B-DZwI0C_2.js.gz +0 -0
  392. package/dist/ui/assets/classDiagram-2ON5EDUG-BFASUbmZ.js +0 -1
  393. package/dist/ui/assets/classDiagram-v2-WZHVMYZB-BFASUbmZ.js +0 -1
  394. package/dist/ui/assets/cose-bilkent-S5V4N54A-Ipik-oSD.js.gz +0 -0
  395. package/dist/ui/assets/dagre-6UL2VRFP-BDpyWQnh.js.gz +0 -0
  396. package/dist/ui/assets/dagre-CgA4KhUX.js.gz +0 -0
  397. package/dist/ui/assets/diagram-PSM6KHXK-B4GRzxLJ.js.gz +0 -0
  398. package/dist/ui/assets/diagram-QEK2KX5R-BWPW28XI.js.gz +0 -0
  399. package/dist/ui/assets/diagram-S2PKOQOG-BIHhcGoV.js.gz +0 -0
  400. package/dist/ui/assets/editor-C-HJ7Yw0.js.gz +0 -0
  401. package/dist/ui/assets/emoji-D8F6B62m.js.gz +0 -0
  402. package/dist/ui/assets/erDiagram-Q2GNP2WA-ubTaAFcK.js.gz +0 -0
  403. package/dist/ui/assets/flowDiagram-NV44I4VS-BHLCTYjI.js.gz +0 -0
  404. package/dist/ui/assets/ganttDiagram-LVOFAZNH-ClC3pay1.js.gz +0 -0
  405. package/dist/ui/assets/gitGraphDiagram-NY62KEGX-Clqpiswu.js.gz +0 -0
  406. package/dist/ui/assets/index-D9OElx9A.css +0 -1
  407. package/dist/ui/assets/index-D9OElx9A.css.gz +0 -0
  408. package/dist/ui/assets/index-DxPuzG7E.js +0 -350
  409. package/dist/ui/assets/index-DxPuzG7E.js.gz +0 -0
  410. package/dist/ui/assets/journeyDiagram-XKPGCS4Q-CrVickA2.js.gz +0 -0
  411. package/dist/ui/assets/kanban-definition-3W4ZIXB7-C_BsdHYL.js.gz +0 -0
  412. package/dist/ui/assets/knowledgeRoutes-CivaUqha.js.gz +0 -0
  413. package/dist/ui/assets/linear-BsjageUB.js.gz +0 -0
  414. package/dist/ui/assets/mermaid-parser.core-DZdP-NFq.js.gz +0 -0
  415. package/dist/ui/assets/mermaid.core-TNrI0pHG.js.gz +0 -0
  416. package/dist/ui/assets/message-BtWWJ9Af.js +0 -36
  417. package/dist/ui/assets/message-BtWWJ9Af.js.gz +0 -0
  418. package/dist/ui/assets/mindmap-definition-VGOIOE7T-BbmaUjMY.js.gz +0 -0
  419. package/dist/ui/assets/particles-Dv28pjOd.js.gz +0 -0
  420. package/dist/ui/assets/pieDiagram-ADFJNKIX-BbyjfYu8.js.gz +0 -0
  421. package/dist/ui/assets/quadrantDiagram-AYHSOK5B-Bc3GqMKz.js.gz +0 -0
  422. package/dist/ui/assets/reactflow-BVYPxNhc.js.gz +0 -0
  423. package/dist/ui/assets/requirementDiagram-UZGBJVZJ-BQaKKL09.js.gz +0 -0
  424. package/dist/ui/assets/sandpack-BQW_FQ7G.js.gz +0 -0
  425. package/dist/ui/assets/sankeyDiagram-TZEHDZUN-DiJvDvhb.js.gz +0 -0
  426. package/dist/ui/assets/sequenceDiagram-WL72ISMW-Dw32824o.js.gz +0 -0
  427. package/dist/ui/assets/stateDiagram-FKZM4ZOC-BCOpNdHV.js.gz +0 -0
  428. package/dist/ui/assets/stateDiagram-v2-4FDKWEC3-Cuqwvgfg.js +0 -1
  429. package/dist/ui/assets/syntax-VJrU5BEu.js.gz +0 -0
  430. package/dist/ui/assets/timeline-definition-IT6M3QCI-Jh_WZzXv.js.gz +0 -0
  431. package/dist/ui/assets/xychartDiagram-PRI3JC2R-CERc7Rdb.js.gz +0 -0
@@ -1,4 +1,5 @@
1
1
  // src/services/gateway.ts
2
+ import { PublicBaseUrlNotConfiguredError, requirePublicBaseUrl } from "@agor/core/config";
2
3
  import {
3
4
  GatewayChannelRepository,
4
5
  MCPServerRepository,
@@ -9,7 +10,9 @@ import {
9
10
  } from "@agor/core/db";
10
11
  import {
11
12
  formatGatewayContext,
12
- formatGatewaySystemMessage,
13
+ formatGatewayFollowUpRoutingMessage,
14
+ formatGatewaySessionCreatedMessage,
15
+ formatGatewaySystemPayload,
13
16
  getConnector,
14
17
  hasConnector,
15
18
  normalizeOutbound,
@@ -17,6 +20,7 @@ import {
17
20
  } from "@agor/core/gateway";
18
21
  import { resolveSessionDefaults } from "@agor/core/sessions";
19
22
  import { SessionStatus } from "@agor/core/types";
23
+ import { getSessionUrl } from "@agor/core/utils/url";
20
24
  function hasListeningConfig(channel) {
21
25
  const config = channel.config;
22
26
  switch (channel.channel_type) {
@@ -24,10 +28,15 @@ function hasListeningConfig(channel) {
24
28
  return !!config.app_token;
25
29
  case "github":
26
30
  return !!(config.app_id && config.private_key && config.installation_id && config.watch_repos?.length);
31
+ case "teams":
32
+ return !!(config.app_id && config.app_password);
27
33
  default:
28
34
  return false;
29
35
  }
30
36
  }
37
+ function isSlackThinkingPlaceholder(text) {
38
+ return /^thinking\s*\.{3}$/i.test(text.trim());
39
+ }
31
40
  function buildGitHubInitialPrompt(threadId, text, metadata) {
32
41
  try {
33
42
  const { owner, repo, number } = parseGitHubThreadId(threadId);
@@ -102,6 +111,26 @@ function buildGatewayContext(channel, data) {
102
111
  extras
103
112
  };
104
113
  }
114
+ case "teams": {
115
+ const conversationType = meta.teams_conversation_type;
116
+ const isPersonal = conversationType === "personal";
117
+ let channelKind;
118
+ if (isPersonal) {
119
+ channelKind = "DM";
120
+ } else if (conversationType === "channel") {
121
+ channelKind = "Channel";
122
+ } else if (conversationType === "groupChat") {
123
+ channelKind = "Group Chat";
124
+ }
125
+ const channelName = isPersonal ? void 0 : meta.teams_channel_name ?? meta.teams_team_name ?? void 0;
126
+ return {
127
+ platform: "teams",
128
+ channelName,
129
+ channelKind,
130
+ userName: meta.teams_user_name ?? void 0,
131
+ userEmail: meta.teams_user_email ?? void 0
132
+ };
133
+ }
105
134
  default:
106
135
  return {
107
136
  platform: channel.channel_type,
@@ -109,7 +138,7 @@ function buildGatewayContext(channel, data) {
109
138
  };
110
139
  }
111
140
  }
112
- var GatewayService = class {
141
+ var GatewayService = class _GatewayService {
113
142
  channelRepo;
114
143
  threadMapRepo;
115
144
  usersRepo;
@@ -133,6 +162,21 @@ var GatewayService = class {
133
162
  * previous one — only the final message matters.
134
163
  */
135
164
  githubMessageBuffer = /* @__PURE__ */ new Map();
165
+ /**
166
+ * Slack status updates are serialized and lightly throttled so concurrent
167
+ * tool/message hooks do not race while deleting/reposting the transient row.
168
+ * Terminal states always bypass this throttle.
169
+ */
170
+ slackProgressLastUpdate = /* @__PURE__ */ new Map();
171
+ slackProgressQueues = /* @__PURE__ */ new Map();
172
+ slackStreamsByTask = /* @__PURE__ */ new Map();
173
+ slackStreamStatusRefreshLast = /* @__PURE__ */ new Map();
174
+ slackStreamedMessageIds = /* @__PURE__ */ new Set();
175
+ slackStreamedTaskIds = /* @__PURE__ */ new Set();
176
+ slackStreamTaskByMessage = /* @__PURE__ */ new Map();
177
+ static SLACK_PROGRESS_MIN_UPDATE_MS = 2500;
178
+ static SLACK_STREAM_STATUS_REFRESH_MS = 300;
179
+ static SLACK_STREAMED_MESSAGE_CACHE_MAX = 500;
136
180
  constructor(db, app) {
137
181
  this.channelRepo = new GatewayChannelRepository(db);
138
182
  this.threadMapRepo = new ThreadSessionMapRepository(db);
@@ -153,21 +197,479 @@ var GatewayService = class {
153
197
  );
154
198
  }
155
199
  /**
156
- * Send a debug/system message to the platform thread (fire-and-forget).
200
+ * Send a system message to the platform thread (fire-and-forget).
157
201
  * Useful for giving the user visibility into what's happening.
158
202
  */
159
- sendDebugMessage(channel, threadId, text) {
203
+ sendSystemMessage(channel, threadId, text, opts) {
160
204
  if (channel.channel_type === "github") return;
205
+ if (channel.channel_type === "slack" && opts?.suppressSlack) return;
161
206
  if (!hasConnector(channel.channel_type)) return;
162
207
  try {
163
- const connector = getConnector(channel.channel_type, channel.config);
208
+ const connector = this.activeListeners.get(channel.id) ?? getConnector(channel.channel_type, channel.config);
164
209
  connector.sendMessage({
165
210
  threadId,
166
- text: formatGatewaySystemMessage(channel.channel_type, text)
211
+ ...formatGatewaySystemPayload(channel.channel_type, text)
167
212
  }).catch((err) => console.warn("[gateway] Debug message failed:", err));
168
213
  } catch {
169
214
  }
170
215
  }
216
+ truncateSlackInline(value, maxChars = 70) {
217
+ const singleLine = value.replace(/\s+/g, " ").trim();
218
+ if (singleLine.length <= maxChars) return singleLine;
219
+ return `${singleLine.slice(0, Math.max(0, maxChars - 1))}\u2026`;
220
+ }
221
+ formatSlackLoadingMessage(text) {
222
+ return this.truncateSlackInline(text, 50);
223
+ }
224
+ makeSlackThreadIdForMessage(rootThreadId, messageTs) {
225
+ const lastHyphen = rootThreadId.lastIndexOf("-");
226
+ if (lastHyphen === -1) return null;
227
+ const channelId = rootThreadId.slice(0, lastHyphen);
228
+ if (!channelId || !messageTs) return null;
229
+ return `${channelId}-${messageTs}`;
230
+ }
231
+ async addSlackThreadAlias(mapping, messageTs, reason) {
232
+ const aliasThreadId = this.makeSlackThreadIdForMessage(mapping.thread_id, messageTs);
233
+ if (!aliasThreadId || aliasThreadId === mapping.thread_id) return;
234
+ const freshMapping = await this.threadMapRepo.findById(mapping.id);
235
+ const metadata = (freshMapping ?? mapping).metadata ?? {};
236
+ const aliases = Array.isArray(metadata.slack_thread_aliases) ? metadata.slack_thread_aliases.filter((alias) => typeof alias === "string") : [];
237
+ if (aliases.includes(aliasThreadId)) return;
238
+ await this.threadMapRepo.updateMetadata(mapping.id, {
239
+ ...metadata,
240
+ slack_thread_aliases: [...aliases, aliasThreadId].slice(-50),
241
+ slack_thread_alias_last_reason: reason
242
+ });
243
+ }
244
+ getActiveSlackThreadId(mapping) {
245
+ const metadata = mapping.metadata ?? {};
246
+ return typeof metadata.slack_active_thread_id === "string" ? metadata.slack_active_thread_id : mapping.thread_id;
247
+ }
248
+ pickSlackRoutingMetadata(metadata) {
249
+ return {
250
+ ...typeof metadata.slack_active_thread_id === "string" ? { slack_active_thread_id: metadata.slack_active_thread_id } : {},
251
+ ...Array.isArray(metadata.slack_thread_aliases) ? { slack_thread_aliases: metadata.slack_thread_aliases } : {},
252
+ ...typeof metadata.slack_thread_alias_last_reason === "string" ? { slack_thread_alias_last_reason: metadata.slack_thread_alias_last_reason } : {}
253
+ };
254
+ }
255
+ async findSlackThreadAliasMapping(channelId, threadId) {
256
+ const mappings = channelId ? await this.threadMapRepo.findByChannel(channelId, "active") : (await this.threadMapRepo.findAll()).filter((mapping) => mapping.status === "active");
257
+ return mappings.find((mapping) => {
258
+ const metadata = mapping.metadata ?? {};
259
+ return Array.isArray(metadata.slack_thread_aliases) && metadata.slack_thread_aliases.includes(threadId);
260
+ }) ?? null;
261
+ }
262
+ parseGatewayTodos(raw) {
263
+ const candidate = typeof raw === "string" ? (() => {
264
+ try {
265
+ return JSON.parse(raw);
266
+ } catch {
267
+ return null;
268
+ }
269
+ })() : raw;
270
+ if (!Array.isArray(candidate)) return [];
271
+ return candidate.map((item) => {
272
+ if (!item || typeof item !== "object") return null;
273
+ const record = item;
274
+ const content = typeof record.content === "string" ? record.content : typeof record.activeForm === "string" ? record.activeForm : null;
275
+ if (!content) return null;
276
+ const status = record.status;
277
+ if (status !== "pending" && status !== "in_progress" && status !== "completed" && status !== "stopped" && status !== "unknown") {
278
+ return { content, status: "pending" };
279
+ }
280
+ return {
281
+ content,
282
+ ...typeof record.activeForm === "string" ? { activeForm: record.activeForm } : {},
283
+ status
284
+ };
285
+ }).filter((item) => item !== null);
286
+ }
287
+ formatSlackToolSummary(toolName, input) {
288
+ if (!toolName) return "Waiting for the agent...";
289
+ const str = (value) => typeof value === "string" && value.trim().length > 0 ? value : void 0;
290
+ const preview = (value, maxChars = 70) => {
291
+ const text = str(value);
292
+ return text ? this.truncateSlackInline(text, maxChars) : void 0;
293
+ };
294
+ const withPreview = (value) => value ? `\`${toolName}\` ${value}` : `\`${toolName}\``;
295
+ if (toolName === "TodoWrite") {
296
+ const todos = this.parseGatewayTodos(input?.todos);
297
+ if (todos.length > 0) {
298
+ const completed = todos.filter((todo) => todo.status === "completed").length;
299
+ const inProgress = todos.filter((todo) => todo.status === "in_progress").length;
300
+ const parts = [`${completed}/${todos.length} done`];
301
+ if (inProgress > 0) parts.push(`${inProgress} in progress`);
302
+ return withPreview(parts.join(", "));
303
+ }
304
+ }
305
+ switch (toolName) {
306
+ case "Read":
307
+ case "Write":
308
+ case "Edit":
309
+ case "NotebookEdit":
310
+ return withPreview(preview(input?.file_path));
311
+ case "Bash":
312
+ case "exec_command":
313
+ return withPreview(preview(input?.description) ?? preview(input?.command));
314
+ case "Grep":
315
+ case "Glob":
316
+ return withPreview(preview(input?.pattern));
317
+ case "ToolSearch":
318
+ case "WebSearch":
319
+ case "web_search":
320
+ return withPreview(preview(input?.query));
321
+ case "WebFetch":
322
+ return withPreview(preview(input?.url));
323
+ case "Agent":
324
+ return withPreview(preview(input?.description));
325
+ case "Skill":
326
+ case "SlashCommand":
327
+ return withPreview(preview(input?.skill) ?? preview(input?.name));
328
+ case "Task":
329
+ return withPreview(preview(str(input?.prompt)?.split("\n")[0], 100));
330
+ case "edit_files": {
331
+ const changes = input?.changes;
332
+ if (Array.isArray(changes) && changes.length > 0) {
333
+ if (changes.length === 1) {
334
+ const change = changes[0];
335
+ const kind = str(change.kind) ?? "update";
336
+ const path = str(change.path) ?? "";
337
+ return withPreview(this.truncateSlackInline(`${kind} ${path}`.trim(), 70));
338
+ }
339
+ return withPreview(`${changes.length} files`);
340
+ }
341
+ break;
342
+ }
343
+ }
344
+ return `\`${toolName}\``;
345
+ }
346
+ buildSlackAssistantStatus(data, existingMetadata) {
347
+ if (data.state === "done") return "";
348
+ if (data.state === "failed") return "ran into an error.";
349
+ if (data.state === "queued") {
350
+ const position = typeof data.queue_position === "number" ? ` at position ${data.queue_position}` : "";
351
+ return `is queued${position}.`;
352
+ }
353
+ const latestToolName = data.tool_name ?? (typeof existingMetadata.slack_status_tool_name === "string" ? existingMetadata.slack_status_tool_name : void 0);
354
+ return latestToolName ? `is using ${this.truncateSlackInline(latestToolName, 40)}.` : "is working on your request.";
355
+ }
356
+ buildSlackAssistantLoadingMessage(data, existingMetadata) {
357
+ if (data.state === "done") return void 0;
358
+ if (data.state === "failed") return this.formatSlackLoadingMessage("Agor ran into an error.");
359
+ if (data.state === "queued") return this.formatSlackLoadingMessage("Queued in Agor\u2026");
360
+ const latestToolSummary = data.tool_name || data.tool_input ? this.formatSlackToolSummary(data.tool_name, data.tool_input) : typeof existingMetadata.slack_status_tool_summary === "string" ? existingMetadata.slack_status_tool_summary : void 0;
361
+ if (latestToolSummary) {
362
+ return this.formatSlackLoadingMessage(`Using ${latestToolSummary.replace(/`/g, "")}\u2026`);
363
+ }
364
+ const latestToolName = data.tool_name ?? (typeof existingMetadata.slack_status_tool_name === "string" ? existingMetadata.slack_status_tool_name : void 0);
365
+ if (latestToolName) {
366
+ return this.formatSlackLoadingMessage(`Using ${latestToolName}\u2026`);
367
+ }
368
+ return this.formatSlackLoadingMessage("Working in Agor\u2026");
369
+ }
370
+ stripSlackProgressMetadata(metadata) {
371
+ const {
372
+ slack_status_message_ts: _statusTs,
373
+ slack_status_started_at: _startedAt,
374
+ slack_status_tool_name: _toolName,
375
+ slack_status_tool_summary: _toolSummary,
376
+ slack_status_todos: _todos,
377
+ slack_status_state: _state,
378
+ slack_status_task_id: _taskId,
379
+ ...rest
380
+ } = metadata;
381
+ return rest;
382
+ }
383
+ stripSlackProgressMessageMetadata(metadata) {
384
+ const { slack_status_message_ts: _statusTs, ...rest } = metadata;
385
+ return rest;
386
+ }
387
+ async refreshSlackAssistantStatusAfterStreamStart(threadId, connector, sessionId, taskId, metadata) {
388
+ if (!connector.setThreadStatus) return;
389
+ const progress = {
390
+ session_id: sessionId,
391
+ state: "working",
392
+ ...taskId ? { task_id: taskId } : {}
393
+ };
394
+ const loadingMessage = this.buildSlackAssistantLoadingMessage(progress, metadata) ?? this.formatSlackLoadingMessage("Writing response\u2026");
395
+ await connector.setThreadStatus({
396
+ threadId,
397
+ status: this.buildSlackAssistantStatus(progress, metadata),
398
+ loadingMessages: [loadingMessage],
399
+ iconEmoji: ":hourglass_flowing_sand:"
400
+ });
401
+ if (taskId) {
402
+ this.slackStreamStatusRefreshLast.set(taskId, Date.now());
403
+ }
404
+ }
405
+ async refreshSlackAssistantStatusAfterStreamAppend(threadId, connector, sessionId, taskId, metadata) {
406
+ if (!taskId) return;
407
+ const now = Date.now();
408
+ const lastRefresh = this.slackStreamStatusRefreshLast.get(taskId) ?? 0;
409
+ if (now - lastRefresh < _GatewayService.SLACK_STREAM_STATUS_REFRESH_MS) return;
410
+ this.slackStreamStatusRefreshLast.set(taskId, now);
411
+ await this.refreshSlackAssistantStatusAfterStreamStart(
412
+ threadId,
413
+ connector,
414
+ sessionId,
415
+ taskId,
416
+ metadata
417
+ );
418
+ }
419
+ /**
420
+ * Update Slack's native assistant status/stream chrome for a gateway thread.
421
+ *
422
+ * We expose a short, Slack-safe tool summary and TodoWrite plan state, never
423
+ * raw JSON args/results. Raw tool inputs are already persisted in Agor's
424
+ * transcript; Slack receives only a compact truncated preview.
425
+ */
426
+ async updateProgress(data) {
427
+ const previous = this.slackProgressQueues.get(data.session_id) ?? Promise.resolve();
428
+ const next = previous.catch(() => void 0).then(() => this.updateProgressNow(data));
429
+ this.slackProgressQueues.set(data.session_id, next);
430
+ try {
431
+ await next;
432
+ } finally {
433
+ if (this.slackProgressQueues.get(data.session_id) === next) {
434
+ this.slackProgressQueues.delete(data.session_id);
435
+ }
436
+ }
437
+ }
438
+ wasMessageStreamedToSlack(messageId) {
439
+ return this.slackStreamedMessageIds.has(messageId);
440
+ }
441
+ wasTaskStreamedToSlack(taskId) {
442
+ return !!taskId && this.slackStreamedTaskIds.has(taskId);
443
+ }
444
+ markMessageStreamedToSlack(messageId) {
445
+ this.slackStreamedMessageIds.add(messageId);
446
+ if (this.slackStreamedMessageIds.size > _GatewayService.SLACK_STREAMED_MESSAGE_CACHE_MAX) {
447
+ const oldest = this.slackStreamedMessageIds.values().next().value;
448
+ if (oldest) this.slackStreamedMessageIds.delete(oldest);
449
+ }
450
+ }
451
+ markTaskStreamedToSlack(taskId) {
452
+ if (!taskId) return;
453
+ this.slackStreamedTaskIds.add(taskId);
454
+ if (this.slackStreamedTaskIds.size > _GatewayService.SLACK_STREAMED_MESSAGE_CACHE_MAX) {
455
+ const oldest = this.slackStreamedTaskIds.values().next().value;
456
+ if (oldest) this.slackStreamedTaskIds.delete(oldest);
457
+ }
458
+ }
459
+ async stopSlackTaskStream(taskId, connector) {
460
+ if (!taskId) return;
461
+ const stream = this.slackStreamsByTask.get(taskId);
462
+ if (!stream) return;
463
+ if (!stream.hasContent && connector.deleteMessage) {
464
+ await connector.deleteMessage({
465
+ threadId: stream.threadId,
466
+ messageId: stream.ts
467
+ });
468
+ this.slackStreamsByTask.delete(taskId);
469
+ this.slackStreamStatusRefreshLast.delete(taskId);
470
+ return;
471
+ }
472
+ const streamConnector = connector;
473
+ if (!streamConnector.stopStream) return;
474
+ await streamConnector.stopStream({
475
+ threadId: stream.threadId,
476
+ ts: stream.ts
477
+ });
478
+ this.slackStreamsByTask.delete(taskId);
479
+ this.slackStreamStatusRefreshLast.delete(taskId);
480
+ }
481
+ async updateProgressNow(data) {
482
+ if (!this.hasActiveChannels) return;
483
+ const mapping = await this.threadMapRepo.findBySession(data.session_id);
484
+ if (!mapping) return;
485
+ const channel = await this.channelRepo.findById(mapping.channel_id);
486
+ if (!channel?.enabled || channel.channel_type !== "slack") return;
487
+ const now = Date.now();
488
+ const isTerminal = data.state === "done" || data.state === "failed";
489
+ const metadata = mapping.metadata ?? {};
490
+ const isNewTask = typeof data.task_id === "string" && data.task_id !== metadata.slack_status_task_id;
491
+ const isRestartingAfterTerminal = (data.state === "queued" || data.state === "working") && (metadata.slack_status_state === "done" || metadata.slack_status_state === "failed");
492
+ const lastUpdate = this.slackProgressLastUpdate.get(data.session_id) ?? 0;
493
+ if (!isTerminal && !data.tool_name && !isNewTask && !isRestartingAfterTerminal && now - lastUpdate < _GatewayService.SLACK_PROGRESS_MIN_UPDATE_MS) {
494
+ return;
495
+ }
496
+ this.slackProgressLastUpdate.set(data.session_id, now);
497
+ const statusStartedAt = isNewTask || isRestartingAfterTerminal ? new Date(now).toISOString() : typeof metadata.slack_status_started_at === "string" ? metadata.slack_status_started_at : new Date(now).toISOString();
498
+ const toolTodos = data.tool_name === "TodoWrite" ? this.parseGatewayTodos(data.tool_input?.todos) : [];
499
+ const toolSummary = data.tool_name || data.tool_input ? this.formatSlackToolSummary(data.tool_name, data.tool_input) : void 0;
500
+ const baseMetadata = isNewTask || isRestartingAfterTerminal ? this.stripSlackProgressMetadata(metadata) : metadata;
501
+ const metadataWithStart = {
502
+ ...baseMetadata,
503
+ slack_status_started_at: statusStartedAt,
504
+ slack_status_state: data.state,
505
+ ...data.task_id ? { slack_status_task_id: data.task_id } : {},
506
+ ...data.tool_name ? { slack_status_tool_name: data.tool_name } : {},
507
+ ...toolSummary ? { slack_status_tool_summary: toolSummary } : {},
508
+ ...toolTodos.length > 0 ? { slack_status_todos: toolTodos } : {}
509
+ };
510
+ const connector = this.activeListeners.get(channel.id) ?? getConnector(channel.channel_type, channel.config);
511
+ const activeTaskId = typeof metadata.slack_status_task_id === "string" ? metadata.slack_status_task_id : void 0;
512
+ try {
513
+ if (isTerminal) {
514
+ try {
515
+ await this.stopSlackTaskStream(activeTaskId, connector);
516
+ } catch (error) {
517
+ console.warn("[gateway] Failed to stop Slack task stream:", error);
518
+ }
519
+ }
520
+ const freshMapping = await this.threadMapRepo.findById(mapping.id);
521
+ const freshMetadata = freshMapping?.metadata ?? {};
522
+ const metadataForWrite = {
523
+ ...isTerminal ? this.stripSlackProgressMetadata(metadataWithStart) : this.stripSlackProgressMessageMetadata(metadataWithStart),
524
+ ...this.pickSlackRoutingMetadata(freshMetadata)
525
+ };
526
+ const slackThreadId = typeof metadataForWrite.slack_active_thread_id === "string" ? metadataForWrite.slack_active_thread_id : mapping.thread_id;
527
+ await this.threadMapRepo.updateMetadata(mapping.id, metadataForWrite);
528
+ if (!connector.setThreadStatus) return;
529
+ try {
530
+ const loadingMessage = this.buildSlackAssistantLoadingMessage(data, metadataWithStart);
531
+ await connector.setThreadStatus({
532
+ threadId: slackThreadId,
533
+ status: this.buildSlackAssistantStatus(data, metadataWithStart),
534
+ loadingMessages: loadingMessage ? [loadingMessage] : void 0,
535
+ iconEmoji: ":hourglass_flowing_sand:"
536
+ });
537
+ } catch (error) {
538
+ console.warn("[gateway] Failed to set Slack assistant status:", error);
539
+ }
540
+ } catch (error) {
541
+ console.warn("[gateway] Failed to update Slack progress status:", error);
542
+ }
543
+ }
544
+ async handleMessageStreamingEvent(event, data) {
545
+ if (!this.hasActiveChannels) return;
546
+ const sessionId = typeof data.session_id === "string" ? data.session_id : void 0;
547
+ const messageId = typeof data.message_id === "string" ? data.message_id : void 0;
548
+ const taskId = typeof data.task_id === "string" ? data.task_id : void 0;
549
+ if (!sessionId || !messageId) return;
550
+ if (event === "streaming:start") {
551
+ if (taskId) {
552
+ this.slackStreamTaskByMessage.set(messageId, taskId);
553
+ }
554
+ return;
555
+ }
556
+ const taskKey = taskId ?? this.slackStreamTaskByMessage.get(messageId) ?? messageId;
557
+ const mapping = await this.threadMapRepo.findBySession(sessionId);
558
+ if (!mapping) return;
559
+ const channel = await this.channelRepo.findById(mapping.channel_id);
560
+ if (!channel?.enabled || channel.channel_type !== "slack") return;
561
+ const connector = this.activeListeners.get(channel.id) ?? getConnector(channel.channel_type, channel.config);
562
+ const streamConnector = connector;
563
+ if (!streamConnector.startStream || !streamConnector.appendStream) {
564
+ return;
565
+ }
566
+ try {
567
+ const metadata = mapping.metadata ?? {};
568
+ const slackThreadId = this.getActiveSlackThreadId(mapping);
569
+ const recipientUserId = typeof metadata.slack_user_id === "string" ? metadata.slack_user_id : void 0;
570
+ const recipientTeamId = typeof metadata.slack_team_id === "string" ? metadata.slack_team_id : void 0;
571
+ if (event === "streaming:chunk") {
572
+ const chunk = typeof data.chunk === "string" ? data.chunk : "";
573
+ if (!chunk) return;
574
+ if (isSlackThinkingPlaceholder(chunk)) {
575
+ return;
576
+ }
577
+ const existing = this.slackStreamsByTask.get(taskKey);
578
+ if (!existing) {
579
+ const ts = await streamConnector.startStream({
580
+ threadId: slackThreadId,
581
+ text: chunk,
582
+ recipientUserId,
583
+ recipientTeamId
584
+ });
585
+ this.slackStreamsByTask.set(taskKey, {
586
+ threadId: slackThreadId,
587
+ ts,
588
+ hasContent: true,
589
+ taskId: taskKey,
590
+ lastMessageId: messageId
591
+ });
592
+ await this.addSlackThreadAlias(mapping, ts, "stream");
593
+ try {
594
+ await this.refreshSlackAssistantStatusAfterStreamStart(
595
+ slackThreadId,
596
+ connector,
597
+ sessionId,
598
+ taskKey,
599
+ metadata
600
+ );
601
+ } catch (error) {
602
+ console.warn("[gateway] Failed to refresh Slack status after stream start:", error);
603
+ }
604
+ this.markMessageStreamedToSlack(messageId);
605
+ this.markTaskStreamedToSlack(taskKey);
606
+ return;
607
+ }
608
+ const text = existing.hasContent && existing.lastMessageId && existing.lastMessageId !== messageId ? `
609
+
610
+ ${chunk}` : chunk;
611
+ await streamConnector.appendStream({
612
+ threadId: existing.threadId,
613
+ ts: existing.ts,
614
+ text
615
+ });
616
+ try {
617
+ await this.refreshSlackAssistantStatusAfterStreamAppend(
618
+ existing.threadId,
619
+ connector,
620
+ sessionId,
621
+ taskKey,
622
+ metadata
623
+ );
624
+ } catch (error) {
625
+ console.warn("[gateway] Failed to refresh Slack status after stream append:", error);
626
+ }
627
+ existing.hasContent = true;
628
+ existing.lastMessageId = messageId;
629
+ this.markMessageStreamedToSlack(messageId);
630
+ this.markTaskStreamedToSlack(taskKey);
631
+ return;
632
+ }
633
+ if (event === "streaming:end") {
634
+ const existing = this.slackStreamsByTask.get(taskKey);
635
+ if (existing?.hasContent) {
636
+ this.markMessageStreamedToSlack(messageId);
637
+ this.markTaskStreamedToSlack(taskKey);
638
+ }
639
+ this.slackStreamTaskByMessage.delete(messageId);
640
+ return;
641
+ }
642
+ if (event === "streaming:error") {
643
+ this.slackStreamTaskByMessage.delete(messageId);
644
+ }
645
+ } catch (error) {
646
+ this.slackStreamsByTask.delete(taskKey);
647
+ this.slackStreamTaskByMessage.delete(messageId);
648
+ console.warn("[gateway] Failed to mirror message stream to Slack:", error);
649
+ }
650
+ }
651
+ async fetchExistingSessionUrlForGatewayUser(sessionId, user) {
652
+ try {
653
+ const baseUrl = await requirePublicBaseUrl();
654
+ return getSessionUrl(sessionId, baseUrl);
655
+ } catch (error) {
656
+ if (!(error instanceof PublicBaseUrlNotConfiguredError)) {
657
+ console.warn("[gateway] Failed to build public session URL:", error);
658
+ }
659
+ }
660
+ try {
661
+ const sessionsService = this.app.service("sessions");
662
+ const sessionWithUrl = await sessionsService.get(sessionId, { user });
663
+ const sessionUrl = sessionWithUrl.url || null;
664
+ if (!sessionUrl) return null;
665
+ const hostname = new URL(sessionUrl).hostname;
666
+ if (hostname === "0.0.0.0") return null;
667
+ return sessionUrl;
668
+ } catch (error) {
669
+ console.warn("[gateway] Failed to fetch session URL:", error);
670
+ return null;
671
+ }
672
+ }
171
673
  /**
172
674
  * Inbound routing: platform → session
173
675
  *
@@ -182,12 +684,27 @@ var GatewayService = class {
182
684
  if (!channel.enabled) {
183
685
  throw new Error("Channel is disabled");
184
686
  }
185
- const existingMapping = await this.threadMapRepo.findByChannelAndThread(
687
+ let existingMapping = await this.threadMapRepo.findByChannelAndThread(
186
688
  channel.id,
187
689
  data.thread_id
188
690
  );
691
+ if (!existingMapping && channel.channel_type === "slack") {
692
+ existingMapping = await this.findSlackThreadAliasMapping(channel.id, data.thread_id);
693
+ if (existingMapping) {
694
+ console.log(
695
+ `[gateway] Found Slack thread alias: ${data.thread_id} \u2192 ${existingMapping.thread_id}`
696
+ );
697
+ }
698
+ }
699
+ if (existingMapping && channel.channel_type === "slack") {
700
+ console.log(
701
+ `[gateway] Slack inbound thread ${data.thread_id} \u2192 session ${shortId(existingMapping.session_id)} (root ${existingMapping.thread_id})`
702
+ );
703
+ }
189
704
  if (!existingMapping) {
190
- const otherChannelMapping = await this.threadMapRepo.findByThread(data.thread_id);
705
+ const exactThreadMapping = await this.threadMapRepo.findByThread(data.thread_id);
706
+ const aliasThreadMapping = channel.channel_type === "slack" ? await this.findSlackThreadAliasMapping(void 0, data.thread_id) : null;
707
+ const otherChannelMapping = exactThreadMapping && exactThreadMapping.channel_id !== channel.id ? exactThreadMapping : aliasThreadMapping && aliasThreadMapping.channel_id !== channel.id ? aliasThreadMapping : null;
191
708
  if (otherChannelMapping) {
192
709
  console.log(
193
710
  `[gateway] IGNORED: Thread ${data.thread_id} owned by channel ${shortId(otherChannelMapping.channel_id)}, not ours (${shortId(channel.id)}). Silently dropping.`
@@ -220,7 +737,7 @@ var GatewayService = class {
220
737
  console.error(
221
738
  `[gateway] Channel "${channel.name}" has no agor_user_id and alignment is OFF. Cannot process message.`
222
739
  );
223
- this.sendDebugMessage(channel, data.thread_id, errMsg);
740
+ this.sendSystemMessage(channel, data.thread_id, errMsg);
224
741
  if (channel.channel_type === "github" && data.metadata?.processing_comment_id) {
225
742
  try {
226
743
  const connector = getConnector(channel.channel_type, channel.config);
@@ -244,7 +761,7 @@ var GatewayService = class {
244
761
  if (alignSlackUsers) {
245
762
  if (data.metadata?.slack_user_email && typeof data.metadata.slack_user_email === "string") {
246
763
  const email = data.metadata.slack_user_email.toLowerCase().trim();
247
- const matchedUser = await this.usersRepo.findByEmail(email);
764
+ const matchedUser = await this.usersRepo.findByEmailForAlignment(email);
248
765
  if (matchedUser) {
249
766
  console.log(
250
767
  `[gateway] Slack user aligned: ${email} \u2192 Agor user ${shortId(matchedUser.user_id)} (${matchedUser.name || matchedUser.email})`
@@ -252,7 +769,7 @@ var GatewayService = class {
252
769
  user = await usersService.get(matchedUser.user_id);
253
770
  } else {
254
771
  console.log(`[gateway] Slack user alignment failed: no Agor user with email ${email}`);
255
- this.sendDebugMessage(
772
+ this.sendSystemMessage(
256
773
  channel,
257
774
  data.thread_id,
258
775
  `User ${email} doesn't have an Agor account. Ask an admin to create an account with this email, or disable user alignment.`
@@ -267,7 +784,7 @@ var GatewayService = class {
267
784
  console.log(
268
785
  `[gateway] Slack user alignment failed: could not resolve email for Slack user ${data.user_name ?? "unknown"} (thread=${data.thread_id})`
269
786
  );
270
- this.sendDebugMessage(
787
+ this.sendSystemMessage(
271
788
  channel,
272
789
  data.thread_id,
273
790
  "Couldn't resolve your Slack identity. The bot may be missing the `users:read.email` scope, or your Slack profile has no email. Ask an admin to check the bot's scopes."
@@ -285,7 +802,7 @@ var GatewayService = class {
285
802
  const userMap = channelConfig.user_map;
286
803
  const mappedEmail = githubLogin && userMap?.[githubLogin] ? userMap[githubLogin].toLowerCase().trim() : null;
287
804
  if (mappedEmail) {
288
- const matchedUser = await this.usersRepo.findByEmail(mappedEmail);
805
+ const matchedUser = await this.usersRepo.findByEmailForAlignment(mappedEmail);
289
806
  if (matchedUser) {
290
807
  console.log(
291
808
  `[gateway] GitHub user aligned via user_map: ${githubLogin} \u2192 ${mappedEmail} \u2192 Agor user ${shortId(matchedUser.user_id)}`
@@ -301,7 +818,7 @@ var GatewayService = class {
301
818
  if (!resolved) {
302
819
  const githubEmail = data.metadata?.github_user_email && typeof data.metadata.github_user_email === "string" ? data.metadata.github_user_email.toLowerCase().trim() : null;
303
820
  if (githubEmail) {
304
- const matchedUser = await this.usersRepo.findByEmail(githubEmail);
821
+ const matchedUser = await this.usersRepo.findByEmailForAlignment(githubEmail);
305
822
  if (matchedUser) {
306
823
  console.log(
307
824
  `[gateway] GitHub user aligned via email: ${githubLogin} (${githubEmail}) \u2192 Agor user ${shortId(matchedUser.user_id)}`
@@ -359,24 +876,34 @@ var GatewayService = class {
359
876
  if (existingMapping) {
360
877
  sessionId = existingMapping.session_id;
361
878
  await this.threadMapRepo.updateLastMessage(existingMapping.id);
362
- if (data.metadata?.processing_comment_id) {
363
- const updatedMetadata = {
364
- ...existingMapping.metadata ?? {},
365
- processing_comment_id: data.metadata.processing_comment_id
366
- };
367
- await this.threadMapRepo.updateMetadata(existingMapping.id, updatedMetadata);
879
+ const existingMetadata = existingMapping.metadata ?? {};
880
+ await this.threadMapRepo.updateMetadata(existingMapping.id, {
881
+ ...existingMetadata,
882
+ ...data.metadata?.processing_comment_id ? { processing_comment_id: data.metadata.processing_comment_id } : {},
883
+ ...typeof data.metadata?.slack_user_id === "string" ? { slack_user_id: data.metadata.slack_user_id } : {},
884
+ ...typeof data.metadata?.slack_team_id === "string" ? { slack_team_id: data.metadata.slack_team_id } : {},
885
+ ...channel.channel_type === "slack" ? { slack_active_thread_id: data.thread_id } : {}
886
+ });
887
+ if (channel.channel_type === "slack") {
888
+ console.log(
889
+ `[gateway] Slack active outbound thread for session ${shortId(sessionId)} set to ${data.thread_id}`
890
+ );
891
+ }
892
+ const sessionUrl = await this.fetchExistingSessionUrlForGatewayUser(sessionId, user);
893
+ if (sessionUrl) {
894
+ this.sendSystemMessage(
895
+ channel,
896
+ data.thread_id,
897
+ formatGatewayFollowUpRoutingMessage(sessionId, sessionUrl)
898
+ );
368
899
  }
369
- this.sendDebugMessage(
370
- channel,
371
- data.thread_id,
372
- `Received follow-up, routing to session ${shortId(sessionId)}...`
373
- );
374
900
  } else {
375
901
  const sessionsService = this.app.service("sessions");
376
- this.sendDebugMessage(
902
+ this.sendSystemMessage(
377
903
  channel,
378
904
  data.thread_id,
379
- `Creating new ${agenticTool} session (${permissionMode} mode)...`
905
+ `Creating new ${agenticTool} session (${permissionMode} mode)...`,
906
+ { suppressSlack: true }
380
907
  );
381
908
  const gatewaySource = {
382
909
  channel_id: channel.id,
@@ -452,19 +979,16 @@ var GatewayService = class {
452
979
  session_id: session.session_id,
453
980
  branch_id: channel.target_branch_id,
454
981
  status: "active",
455
- metadata: data.metadata ?? null
982
+ metadata: channel.channel_type === "slack" ? { ...data.metadata ?? {}, slack_active_thread_id: data.thread_id } : data.metadata ?? null
456
983
  });
457
- let sessionUrl = null;
458
- try {
459
- const sessionsService2 = this.app.service("sessions");
460
- const sessionWithUrl = await sessionsService2.get(sessionId, { user });
461
- sessionUrl = sessionWithUrl.url || null;
462
- } catch (error) {
463
- console.warn("[gateway] Failed to fetch session URL:", error);
984
+ const sessionUrl = await this.fetchExistingSessionUrlForGatewayUser(sessionId, user);
985
+ if (sessionUrl) {
986
+ this.sendSystemMessage(
987
+ channel,
988
+ data.thread_id,
989
+ formatGatewaySessionCreatedMessage(sessionId, sessionUrl)
990
+ );
464
991
  }
465
- const sessionIdShort = shortId(sessionId);
466
- const message = sessionUrl ? `Session created: ${sessionUrl}` : `Session ${sessionIdShort} created, sending prompt to agent...`;
467
- this.sendDebugMessage(channel, data.thread_id, message);
468
992
  if (channel.channel_type === "github" && data.metadata?.processing_comment_id) {
469
993
  try {
470
994
  const connector = getConnector(channel.channel_type, channel.config);
@@ -507,19 +1031,36 @@ ${promptText}`;
507
1031
  console.log(
508
1032
  `[gateway] Message queued for session ${shortId(sessionId)} at position ${task.queue_position}`
509
1033
  );
510
- this.sendDebugMessage(
1034
+ this.sendSystemMessage(
511
1035
  channel,
512
1036
  data.thread_id,
513
- `Session is busy, message queued at position ${task.queue_position}`
1037
+ `Session is busy, message queued at position ${task.queue_position}`,
1038
+ { suppressSlack: true }
514
1039
  );
1040
+ void this.updateProgress({
1041
+ session_id: sessionId,
1042
+ state: "queued",
1043
+ task_id: task.task_id,
1044
+ queue_position: task.queue_position
1045
+ });
515
1046
  } else {
516
1047
  console.log(
517
1048
  `[gateway] Prompt sent to session ${shortId(sessionId)} via /sessions/:id/prompt`
518
1049
  );
1050
+ void this.updateProgress({
1051
+ session_id: sessionId,
1052
+ state: "working",
1053
+ task_id: task.task_id
1054
+ });
519
1055
  }
520
1056
  } catch (error) {
521
1057
  console.error("[gateway] Failed to send prompt to session:", error);
522
- this.sendDebugMessage(channel, data.thread_id, `Error sending prompt: ${error}`);
1058
+ this.sendSystemMessage(channel, data.thread_id, `Error sending prompt: ${error}`);
1059
+ void this.updateProgress({
1060
+ session_id: sessionId,
1061
+ state: "failed",
1062
+ error_message: error instanceof Error ? error.message : String(error)
1063
+ });
523
1064
  }
524
1065
  return {
525
1066
  success: true,
@@ -562,19 +1103,21 @@ ${promptText}`;
562
1103
  return { routed: true, channelType: "github" };
563
1104
  }
564
1105
  try {
565
- const connector = getConnector(channel.channel_type, channel.config);
1106
+ const connector = this.activeListeners.get(channel.id) ?? getConnector(channel.channel_type, channel.config);
566
1107
  const { text, blocks } = normalizeOutbound(
567
1108
  connector.formatMessage ? connector.formatMessage(data.message) : data.message
568
1109
  );
569
- await connector.sendMessage({
570
- threadId: mapping.thread_id,
1110
+ const threadId = channel.channel_type === "slack" ? this.getActiveSlackThreadId(mapping) : mapping.thread_id;
1111
+ const sentTs = await connector.sendMessage({
1112
+ threadId,
571
1113
  text,
572
1114
  blocks,
573
1115
  metadata: data.metadata
574
1116
  });
575
- console.log(
576
- `[gateway] Routed message to ${channel.channel_type} thread ${mapping.thread_id}`
577
- );
1117
+ if (channel.channel_type === "slack") {
1118
+ await this.addSlackThreadAlias(mapping, sentTs, "message");
1119
+ }
1120
+ console.log(`[gateway] Routed message to ${channel.channel_type} thread ${threadId}`);
578
1121
  } catch (error) {
579
1122
  console.error(`[gateway] Failed to route message to ${channel.channel_type}:`, error);
580
1123
  return { routed: false, channelType: channel.channel_type };