@desplega.ai/agent-swarm 1.112.0 → 1.114.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 (276) hide show
  1. package/README.md +2 -2
  2. package/dist/{actions-eckb4g8r.js → actions-bm8vdxys.js} +7 -8
  3. package/dist/{app-b05sgm02.js → app-bhwdxmvp.js} +5 -5
  4. package/dist/{assistant-7255sbyw.js → assistant-15mp2apr.js} +18 -17
  5. package/dist/{boot-reembed-y1bt3ttn.js → boot-reembed-awr2179r.js} +6 -6
  6. package/dist/{boot-reembed-yv7awg4y.js → boot-reembed-b9sbk87z.js} +5 -5
  7. package/dist/{boot-scrub-logs-ddyaeqar.js → boot-scrub-logs-c1zsaw9m.js} +4 -4
  8. package/dist/{claude-adapter-mma9a1yr.js → claude-adapter-2k45y7p7.js} +2 -2
  9. package/dist/{claude-managed-adapter-pv2nbqy4.js → claude-managed-adapter-kysmkz89.js} +2 -2
  10. package/dist/cli-0kgcv878.js +344 -0
  11. package/dist/cli-0pygq9r1.js +429 -0
  12. package/dist/{cli-7xkwgkrs.js → cli-113wmegp.js} +90 -3
  13. package/dist/{cli-7ga43spr.js → cli-1yjrbg1f.js} +1 -1
  14. package/dist/{cli-56s4ehzw.js → cli-2t4e4ayk.js} +1 -1
  15. package/dist/{cli-0c3n0eba.js → cli-312v3c41.js} +1 -1
  16. package/dist/{cli-ceewqajw.js → cli-46b6kc7f.js} +5 -5
  17. package/dist/cli-49j095n9.js +393 -0
  18. package/dist/{cli-h9jx5mag.js → cli-5afkmcfj.js} +10 -7
  19. package/dist/{cli-76d1vtvq.js → cli-5ktc9fd4.js} +1 -1
  20. package/dist/cli-7rgh0w0k.js +262 -0
  21. package/dist/{cli-9cy6nc5m.js → cli-8fjwym53.js} +1 -1
  22. package/dist/{cli-tg0f2wmz.js → cli-a6tzw6vq.js} +175 -28
  23. package/dist/{cli-q21d49ac.js → cli-bw80ck94.js} +1 -1
  24. package/dist/{cli-709t753c.js → cli-byjcad11.js} +2 -2
  25. package/dist/{cli-15598a4k.js → cli-e2xbxmhd.js} +1808 -302
  26. package/dist/{cli-6wscj9z0.js → cli-e7306swv.js} +14 -14
  27. package/dist/{cli-8f0dwca2.js → cli-f5pzfvwb.js} +6 -5
  28. package/dist/{cli-s9pj3c7z.js → cli-f9n2jg31.js} +2 -2
  29. package/dist/{cli-dcfyyh3t.js → cli-ftyf58xj.js} +2 -2
  30. package/dist/{cli-hm27prrc.js → cli-hq39e630.js} +5 -5
  31. package/dist/{cli-a5e8n5hg.js → cli-hvg05qwm.js} +1 -1
  32. package/dist/cli-jkhwmmgg.js +136 -0
  33. package/dist/{cli-951w7c79.js → cli-jzwtn8rm.js} +136 -21
  34. package/dist/{cli-rp8pca98.js → cli-k6h2zkw3.js} +1 -1
  35. package/dist/{cli-3r5y6ayj.js → cli-pnfyyp6h.js} +1240 -335
  36. package/dist/{cli-94vzr3nq.js → cli-q1z5d5ss.js} +13 -7
  37. package/dist/{cli-pt7c7qxz.js → cli-q4e2x252.js} +3 -3
  38. package/dist/{cli-tch0ypp6.js → cli-r3mtrrzp.js} +16 -16
  39. package/dist/{cli-ywez6yps.js → cli-sq7f72d6.js} +1 -1
  40. package/dist/{cli-r1btc895.js → cli-w3nq88yc.js} +2 -2
  41. package/dist/{cli-30d2ct3k.js → cli-w4wk3kx6.js} +12 -7
  42. package/dist/{cli-anrj584m.js → cli-xz9aq0rf.js} +1 -1
  43. package/dist/{cli-tp7e60s3.js → cli-zmmp2r79.js} +22 -9
  44. package/dist/cli.js +35 -17
  45. package/dist/{codex-adapter-5cmy858w.js → codex-adapter-4z8m9mb5.js} +9 -9
  46. package/dist/{codex-session-runner-46q8mrba.js → codex-session-runner-rbct46dg.js} +9 -9
  47. package/dist/{commands-14g7taf4.js → commands-zk4d6esf.js} +4 -4
  48. package/dist/{db-3tge4jrn.js → db-stn16jp2.js} +4 -4
  49. package/dist/{handlers-sy64egg6.js → handlers-gshprvpf.js} +16 -30
  50. package/dist/{hook-rnkzw8vp.js → hook-amzx9tap.js} +7 -7
  51. package/dist/{http-xx9xptcs.js → http-6g0hfzax.js} +1977 -786
  52. package/dist/{index-wz1ea15p.js → index-2dgfj9av.js} +3 -3
  53. package/dist/{index-ha8e9xn2.js → index-df8fmphk.js} +55 -17
  54. package/dist/{index-zfx5p959.js → index-f03rnnrs.js} +13 -10
  55. package/dist/{index-3wr6v2mm.js → index-jbm7qcqk.js} +12 -9
  56. package/dist/{index-ykvs43z4.js → index-t2snazez.js} +4 -4
  57. package/dist/{index-brma88d4.js → index-ty42rxw9.js} +14 -11
  58. package/dist/{keepalive-rbz05zad.js → keepalive-pm6g2wpw.js} +7 -6
  59. package/dist/{lead-s790v7r0.js → lead-h79fzpzw.js} +33 -29
  60. package/dist/{maintenance-420rmadb.js → maintenance-433zndy1.js} +6 -6
  61. package/dist/{mistral-conversations-26yrnbf1.js → mistral-conversations-7gqnz2wt.js} +7 -7
  62. package/dist/oauth-refresh-sweep-mjsbmsk2.js +114 -0
  63. package/dist/{onboard-jgqamqnw.js → onboard-vdr9hc3f.js} +2 -2
  64. package/dist/{otel-zjd9zaxs.js → otel-g299k41b.js} +2 -2
  65. package/dist/{otel-impl-ch3n3783.js → otel-impl-yswd0fty.js} +1 -1
  66. package/dist/{pi-mono-adapter-kxjxpfgy.js → pi-mono-adapter-vbrvg1p8.js} +16 -108
  67. package/dist/{pricing-refresh-rmtrby6h.js → pricing-refresh-2kk2ap9b.js} +6 -6
  68. package/dist/rbac-roles-2wgh9b5t.js +276 -0
  69. package/dist/rbac-roles-xdc5208b.js +28 -0
  70. package/dist/{seed-pricing-1szjzfj1.js → seed-pricing-m9h69d2t.js} +5 -5
  71. package/dist/{setup-8jfzkyzv.js → setup-eynkvafa.js} +2 -2
  72. package/dist/{worker-40vq0pm8.js → worker-136q8dc2.js} +33 -29
  73. package/openapi.json +1634 -20
  74. package/package.json +6 -5
  75. package/src/agentmail/handlers.ts +16 -6
  76. package/src/agentmail/templates.ts +25 -5
  77. package/src/be/audit-user.ts +28 -4
  78. package/src/be/db-queries/oauth.ts +42 -0
  79. package/src/be/db.ts +104 -11
  80. package/src/be/identity.ts +79 -0
  81. package/src/be/mcp-proxy.ts +132 -0
  82. package/src/be/memory/providers/sqlite-store.ts +5 -1
  83. package/src/be/migrations/108_rbac_permission_audit.sql +26 -0
  84. package/src/be/migrations/109_rbac_roles.sql +79 -0
  85. package/src/be/migrations/111_oauth_credential_bindings.sql +6 -0
  86. package/src/be/migrations/112_script_connections_graphql.sql +96 -0
  87. package/src/be/oauth-credential-bindings.ts +35 -0
  88. package/src/be/oauth-refresh-sweep.ts +159 -0
  89. package/src/be/rbac-audit.ts +246 -0
  90. package/src/be/rbac-roles.ts +417 -0
  91. package/src/be/script-connections.ts +456 -37
  92. package/src/be/script-credential-broker.ts +29 -3
  93. package/src/be/scripts/typecheck.ts +40 -7
  94. package/src/be/users.ts +24 -0
  95. package/src/cli.tsx +17 -0
  96. package/src/github/handlers.ts +10 -9
  97. package/src/github/templates.ts +45 -9
  98. package/src/gitlab/handlers.ts +20 -8
  99. package/src/gitlab/templates.ts +18 -6
  100. package/src/http/all-routes.ts +61 -0
  101. package/src/http/approval-requests.ts +12 -0
  102. package/src/http/config.ts +98 -9
  103. package/src/http/core.ts +30 -3
  104. package/src/http/favorites.ts +5 -0
  105. package/src/http/fs.ts +27 -7
  106. package/src/http/index.ts +50 -0
  107. package/src/http/kv.ts +21 -4
  108. package/src/http/mcp-oauth.ts +2 -0
  109. package/src/http/mcp-servers.ts +6 -3
  110. package/src/http/oauth-generic.ts +105 -0
  111. package/src/http/poll.ts +13 -1
  112. package/src/http/route-def.ts +9 -0
  113. package/src/http/schedules.ts +56 -22
  114. package/src/http/script-connection-proxy.ts +116 -0
  115. package/src/http/script-connections.ts +1657 -0
  116. package/src/http/scripts.ts +54 -7
  117. package/src/http/tasks.ts +16 -14
  118. package/src/http/workflows.ts +13 -2
  119. package/src/http/x.ts +6 -2
  120. package/src/integrations/kapso/inbound.ts +23 -6
  121. package/src/jira/sync.ts +111 -17
  122. package/src/jira/templates.ts +10 -2
  123. package/src/mcp-client/http-client.ts +194 -0
  124. package/src/oauth/app-validation.ts +16 -0
  125. package/src/oauth/ensure-token.ts +69 -14
  126. package/src/oauth/mcp-wrapper.ts +15 -0
  127. package/src/oauth/wrapper.ts +48 -20
  128. package/src/prompts/base-prompt.ts +7 -6
  129. package/src/prompts/session-templates.ts +38 -11
  130. package/src/providers/pi-mono-mcp-client.ts +2 -133
  131. package/src/rbac/admission.ts +44 -0
  132. package/src/rbac/can.ts +44 -0
  133. package/src/rbac/index.ts +15 -0
  134. package/src/rbac/legacy-policy.ts +188 -0
  135. package/src/rbac/permissions.ts +194 -0
  136. package/src/rbac/types.ts +45 -0
  137. package/src/scheduler/scheduler.ts +9 -1
  138. package/src/scripts-runtime/api-client.ts +70 -14
  139. package/src/scripts-runtime/api-types.ts +38 -6
  140. package/src/scripts-runtime/credential-broker/default-bindings.ts +1 -0
  141. package/src/scripts-runtime/credential-broker/types.ts +8 -0
  142. package/src/scripts-runtime/ctx.ts +11 -1
  143. package/src/scripts-runtime/eval-harness.ts +5 -1
  144. package/src/scripts-runtime/executors/types.ts +2 -1
  145. package/src/scripts-runtime/loader.ts +3 -1
  146. package/src/scripts-runtime/mcp-client.ts +87 -0
  147. package/src/scripts-runtime/sdk-allowlist.ts +2 -0
  148. package/src/scripts-runtime/swarm-sdk.ts +81 -0
  149. package/src/scripts-runtime/types/stdlib.d.ts +24 -2
  150. package/src/scripts-runtime/types/swarm-sdk.d.ts +26 -2
  151. package/src/server.ts +14 -0
  152. package/src/slack/assistant.ts +14 -6
  153. package/src/slack/enrich.ts +17 -0
  154. package/src/slack/handlers.ts +8 -22
  155. package/src/slack/thread-buffer.ts +6 -3
  156. package/src/stdio.ts +43 -0
  157. package/src/tests/agentmail-handlers.test.ts +32 -3
  158. package/src/tests/approval-requests.test.ts +61 -0
  159. package/src/tests/audit-user.test.ts +47 -1
  160. package/src/tests/base-prompt.test.ts +7 -4
  161. package/src/tests/credential-broker.test.ts +5 -2
  162. package/src/tests/delete-page-tool.test.ts +197 -0
  163. package/src/tests/github-handlers.test.ts +28 -2
  164. package/src/tests/gitlab-handlers.test.ts +125 -0
  165. package/src/tests/harness-provider-resolution.test.ts +5 -0
  166. package/src/tests/http-api-integration.test.ts +8 -1
  167. package/src/tests/identity.test.ts +117 -0
  168. package/src/tests/jira-sync.test.ts +99 -1
  169. package/src/tests/kapso-inbound.test.ts +7 -0
  170. package/src/tests/mcp-tools-user.test.ts +60 -6
  171. package/src/tests/oauth-credential-bindings.test.ts +490 -0
  172. package/src/tests/oauth-refresh-sweep.test.ts +160 -0
  173. package/src/tests/prompt-template-remaining.test.ts +2 -2
  174. package/src/tests/prompt-template-session.test.ts +21 -8
  175. package/src/tests/rbac-admission-e2e.test.ts +241 -0
  176. package/src/tests/rbac-admission.test.ts +433 -0
  177. package/src/tests/rbac-audit.test.ts +345 -0
  178. package/src/tests/rbac-charact-http.test.ts +272 -0
  179. package/src/tests/rbac-charact-misc-tools.test.ts +428 -0
  180. package/src/tests/rbac-charact-skills.test.ts +492 -0
  181. package/src/tests/rbac-charact-slack.test.ts +283 -0
  182. package/src/tests/rbac-e2e-helpers.ts +308 -0
  183. package/src/tests/rbac-engine.test.ts +474 -0
  184. package/src/tests/rbac-lifecycle-e2e.test.ts +262 -0
  185. package/src/tests/rbac-roles.test.ts +326 -0
  186. package/src/tests/rbac-wire-e2e.test.ts +574 -0
  187. package/src/tests/schedule-http-triage-tools.test.ts +121 -0
  188. package/src/tests/schedule-target-type.test.ts +50 -0
  189. package/src/tests/scheduled-tasks.test.ts +74 -0
  190. package/src/tests/script-connections-http.test.ts +1158 -0
  191. package/src/tests/script-connections-mcp.test.ts +894 -0
  192. package/src/tests/script-connections.test.ts +727 -5
  193. package/src/tests/scripts-external-api.test.ts +49 -1
  194. package/src/tests/scripts-http.test.ts +56 -7
  195. package/src/tests/scripts-runtime-secret-egress.test.ts +1 -0
  196. package/src/tests/scripts-runtime.test.ts +104 -0
  197. package/src/tests/slack-identity-resolution.test.ts +37 -3
  198. package/src/tests/slack-thread-buffer.test.ts +28 -0
  199. package/src/tests/swarm-config-reserved-keys.test.ts +17 -0
  200. package/src/tests/tool-annotations.test.ts +2 -0
  201. package/src/tests/update-schedule-mcp-tool.test.ts +57 -0
  202. package/src/tests/user-token-rest-auth.test.ts +30 -1
  203. package/src/tests/workflow-http-v2.test.ts +80 -0
  204. package/src/tests/workflow-swarm-script.test.ts +44 -0
  205. package/src/tests/workflow-triggers-v2.test.ts +300 -1
  206. package/src/tools/cancel-task.ts +13 -3
  207. package/src/tools/context-diff.ts +12 -1
  208. package/src/tools/context-history.ts +12 -1
  209. package/src/tools/credential-bindings/tool.ts +289 -19
  210. package/src/tools/delete-channel.ts +12 -1
  211. package/src/tools/delete-page.ts +145 -0
  212. package/src/tools/get-task-details.ts +1 -1
  213. package/src/tools/inject-learning.ts +12 -1
  214. package/src/tools/kv/kv-delete.ts +3 -18
  215. package/src/tools/kv/kv-incr.ts +3 -18
  216. package/src/tools/kv/kv-set.ts +3 -20
  217. package/src/tools/kv/kv-write-auth.ts +40 -0
  218. package/src/tools/manage-user.ts +12 -1
  219. package/src/tools/mcp-servers/mcp-server-create.ts +12 -1
  220. package/src/tools/mcp-servers/mcp-server-delete.ts +19 -5
  221. package/src/tools/mcp-servers/mcp-server-install.ts +12 -1
  222. package/src/tools/mcp-servers/mcp-server-uninstall.ts +12 -1
  223. package/src/tools/mcp-servers/mcp-server-update.ts +12 -1
  224. package/src/tools/memory-delete.ts +12 -4
  225. package/src/tools/register-kapso-number.ts +23 -2
  226. package/src/tools/request-human-input.ts +2 -0
  227. package/src/tools/resolve-user.ts +77 -27
  228. package/src/tools/schedules/create-schedule.ts +4 -3
  229. package/src/tools/schedules/index.ts +1 -0
  230. package/src/tools/schedules/list-schedules.ts +36 -2
  231. package/src/tools/schedules/patch-schedule.ts +405 -0
  232. package/src/tools/schedules/update-schedule.ts +2 -2
  233. package/src/tools/script-connections/tool.ts +287 -32
  234. package/src/tools/skills/skill-create.ts +12 -1
  235. package/src/tools/skills/skill-delete.ts +12 -1
  236. package/src/tools/skills/skill-install-remote.ts +12 -1
  237. package/src/tools/skills/skill-install.ts +12 -1
  238. package/src/tools/skills/skill-uninstall.ts +12 -1
  239. package/src/tools/skills/skill-update.ts +25 -2
  240. package/src/tools/slack-delete.ts +8 -1
  241. package/src/tools/slack-post.ts +8 -1
  242. package/src/tools/slack-read.ts +8 -1
  243. package/src/tools/slack-start-thread.ts +8 -1
  244. package/src/tools/slack-update.ts +8 -1
  245. package/src/tools/slack-upload-file.ts +8 -1
  246. package/src/tools/swarm-config/delete-config.ts +28 -1
  247. package/src/tools/swarm-config/get-config.ts +32 -5
  248. package/src/tools/swarm-config/list-config.ts +31 -5
  249. package/src/tools/swarm-config/set-config.ts +38 -1
  250. package/src/tools/task-action.ts +1 -1
  251. package/src/tools/task-tool-ctx.ts +19 -3
  252. package/src/tools/templates.ts +5 -1
  253. package/src/tools/tool-config.ts +4 -2
  254. package/src/tools/update-profile.ts +8 -1
  255. package/src/tools/workflows/create-workflow.ts +8 -1
  256. package/src/tools/workflows/list-workflows.ts +14 -2
  257. package/src/tools/workflows/update-workflow.ts +11 -2
  258. package/src/types.ts +63 -6
  259. package/src/utils/scoped-resource.ts +25 -0
  260. package/src/workflows/executors/human-in-the-loop.ts +1 -0
  261. package/src/workflows/executors/swarm-script.ts +7 -1
  262. package/src/workflows/triggers.ts +146 -18
  263. package/templates/skills/swarm-scripts/SKILL.md +4 -9
  264. package/templates/skills/swarm-scripts/content.md +45 -9
  265. package/dist/cli-52tbq17n.js +0 -771
  266. package/dist/cli-9p0qhead.js +0 -43
  267. package/dist/{anthropic-messages-8nc6r2dw.js → anthropic-messages-kq3pjhbp.js} +6 -6
  268. package/dist/{azure-openai-responses-6yfzw3qw.js → azure-openai-responses-gm1ejtmn.js} +7 -7
  269. package/dist/{cli-vbraamxr.js → cli-6b4wwmm8.js} +9 -9
  270. package/dist/{cli-2fc97xm5.js → cli-ggy8c7tk.js} +3 -3
  271. package/dist/{cli-2r7s8jhp.js → cli-sznberje.js} +3 -3
  272. package/dist/{google-generative-ai-vfq6ymz9.js → google-generative-ai-hyrra2jm.js} +3 -3
  273. package/dist/{google-vertex-mj5y5rfj.js → google-vertex-8bs2pzgn.js} +3 -3
  274. package/dist/{openai-codex-responses-8h6kvfv8.js → openai-codex-responses-3nkvje79.js} +4 -4
  275. package/dist/{openai-completions-x6kjnqjd.js → openai-completions-0asftkwg.js} +11 -11
  276. package/dist/{openai-responses-7jwyz3ds.js → openai-responses-pmatek45.js} +10 -10
@@ -0,0 +1,393 @@
1
+ import {
2
+ calculatePKCECodeChallenge,
3
+ generateRandomCodeVerifier,
4
+ generateRandomState
5
+ } from "./cli-0pygq9r1.js";
6
+ import {
7
+ getDb,
8
+ init_date_utils,
9
+ init_db,
10
+ normalizeDateRequired
11
+ } from "./cli-jzwtn8rm.js";
12
+
13
+ // src/be/db-queries/oauth.ts
14
+ init_date_utils();
15
+ init_db();
16
+ function normalizeOAuthApp(row) {
17
+ return {
18
+ ...row,
19
+ createdAt: normalizeDateRequired(row.createdAt),
20
+ updatedAt: normalizeDateRequired(row.updatedAt)
21
+ };
22
+ }
23
+ function normalizeOAuthTokens(row) {
24
+ return {
25
+ ...row,
26
+ createdAt: normalizeDateRequired(row.createdAt),
27
+ updatedAt: normalizeDateRequired(row.updatedAt)
28
+ };
29
+ }
30
+ function getOAuthApp(provider) {
31
+ const row = getDb().query("SELECT * FROM oauth_apps WHERE provider = ?").get(provider);
32
+ return row ? normalizeOAuthApp(row) : null;
33
+ }
34
+ function upsertOAuthApp(provider, data) {
35
+ const metadataProvided = data.metadata !== undefined;
36
+ const sql = metadataProvided ? `INSERT INTO oauth_apps (provider, clientId, clientSecret, authorizeUrl, tokenUrl, redirectUri, scopes, metadata)
37
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
38
+ ON CONFLICT(provider) DO UPDATE SET
39
+ clientId = excluded.clientId,
40
+ clientSecret = excluded.clientSecret,
41
+ authorizeUrl = excluded.authorizeUrl,
42
+ tokenUrl = excluded.tokenUrl,
43
+ redirectUri = excluded.redirectUri,
44
+ scopes = excluded.scopes,
45
+ metadata = excluded.metadata,
46
+ updatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')` : `INSERT INTO oauth_apps (provider, clientId, clientSecret, authorizeUrl, tokenUrl, redirectUri, scopes, metadata)
47
+ VALUES (?, ?, ?, ?, ?, ?, ?, '{}')
48
+ ON CONFLICT(provider) DO UPDATE SET
49
+ clientId = excluded.clientId,
50
+ clientSecret = excluded.clientSecret,
51
+ authorizeUrl = excluded.authorizeUrl,
52
+ tokenUrl = excluded.tokenUrl,
53
+ redirectUri = excluded.redirectUri,
54
+ scopes = excluded.scopes,
55
+ updatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')`;
56
+ if (metadataProvided) {
57
+ getDb().query(sql).run(provider, data.clientId, data.clientSecret, data.authorizeUrl, data.tokenUrl, data.redirectUri, data.scopes, data.metadata);
58
+ } else {
59
+ getDb().query(sql).run(provider, data.clientId, data.clientSecret, data.authorizeUrl, data.tokenUrl, data.redirectUri, data.scopes);
60
+ }
61
+ }
62
+ function getOAuthTokens(provider) {
63
+ const row = getDb().query("SELECT * FROM oauth_tokens WHERE provider = ?").get(provider);
64
+ return row ? normalizeOAuthTokens(row) : null;
65
+ }
66
+ function storeOAuthTokens(provider, data) {
67
+ getDb().query(`INSERT INTO oauth_tokens (provider, accessToken, refreshToken, expiresAt, scope)
68
+ VALUES (?, ?, ?, ?, ?)
69
+ ON CONFLICT(provider) DO UPDATE SET
70
+ accessToken = excluded.accessToken,
71
+ refreshToken = COALESCE(excluded.refreshToken, oauth_tokens.refreshToken),
72
+ expiresAt = excluded.expiresAt,
73
+ scope = COALESCE(excluded.scope, oauth_tokens.scope),
74
+ updatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')`).run(provider, data.accessToken, data.refreshToken ?? null, data.expiresAt, data.scope ?? null);
75
+ }
76
+ function updateOAuthTokensAfterRefresh(provider, expectedRefreshToken, data) {
77
+ const result = getDb().query(`UPDATE oauth_tokens
78
+ SET accessToken = ?,
79
+ refreshToken = ?,
80
+ expiresAt = ?,
81
+ scope = COALESCE(?, scope),
82
+ updatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
83
+ WHERE provider = ? AND refreshToken = ?`).run(data.accessToken, data.refreshToken, data.expiresAt, data.scope ?? null, provider, expectedRefreshToken);
84
+ if (result.changes === 1)
85
+ return;
86
+ const current = getOAuthTokens(provider);
87
+ if (!current) {
88
+ throw new Error(`OAuth token refresh persistence failed for ${provider}: token row missing`);
89
+ }
90
+ if (current.refreshToken !== expectedRefreshToken) {
91
+ throw new Error(`OAuth token refresh persistence failed for ${provider}: stored refresh token changed during refresh`);
92
+ }
93
+ throw new Error(`OAuth token refresh persistence failed for ${provider}: no rows updated`);
94
+ }
95
+ function listOAuthTokenSweepRows() {
96
+ const rows = getDb().query(`SELECT t.provider,
97
+ CASE WHEN a.provider IS NOT NULL THEN 1 ELSE 0 END AS hasApp,
98
+ CASE WHEN t.refreshToken IS NOT NULL AND t.refreshToken != '' THEN 1 ELSE 0 END AS hasRefreshToken,
99
+ t.expiresAt,
100
+ t.updatedAt
101
+ FROM oauth_tokens t
102
+ LEFT JOIN oauth_apps a ON a.provider = t.provider
103
+ ORDER BY t.provider ASC`).all();
104
+ return rows.map((row) => ({
105
+ provider: row.provider,
106
+ hasApp: row.hasApp === 1,
107
+ hasRefreshToken: row.hasRefreshToken === 1,
108
+ expiresAt: normalizeDateRequired(row.expiresAt),
109
+ updatedAt: normalizeDateRequired(row.updatedAt)
110
+ }));
111
+ }
112
+ function deleteOAuthTokens(provider) {
113
+ getDb().query("DELETE FROM oauth_tokens WHERE provider = ?").run(provider);
114
+ }
115
+ function isTokenExpiringSoon(provider, bufferMs = 5 * 60 * 1000) {
116
+ const tokens = getOAuthTokens(provider);
117
+ if (!tokens)
118
+ return true;
119
+ const expiresAt = new Date(tokens.expiresAt).getTime();
120
+ return expiresAt - Date.now() < bufferMs;
121
+ }
122
+ function acquireOAuthRefreshLock(provider, ttlMs) {
123
+ const owner = crypto.randomUUID();
124
+ const now = Date.now();
125
+ const expiresAt = new Date(now + ttlMs).toISOString();
126
+ const nowIso = new Date(now).toISOString();
127
+ getDb().query(`INSERT INTO oauth_refresh_locks (provider, owner, expiresAt, createdAt, updatedAt)
128
+ VALUES (?, ?, ?, ?, ?)
129
+ ON CONFLICT(provider) DO UPDATE SET
130
+ owner = excluded.owner,
131
+ expiresAt = excluded.expiresAt,
132
+ updatedAt = excluded.updatedAt
133
+ WHERE oauth_refresh_locks.expiresAt <= ?`).run(provider, owner, expiresAt, nowIso, nowIso, nowIso);
134
+ const row = getDb().query("SELECT owner FROM oauth_refresh_locks WHERE provider = ?").get(provider);
135
+ return row?.owner === owner ? owner : null;
136
+ }
137
+ function releaseOAuthRefreshLock(provider, owner) {
138
+ getDb().query("DELETE FROM oauth_refresh_locks WHERE provider = ? AND owner = ?").run(provider, owner);
139
+ }
140
+
141
+ // src/oauth/wrapper.ts
142
+ var STATE_TTL_MS = 10 * 60 * 1000;
143
+ var pendingStates = new Map;
144
+ function cleanupExpiredStates() {
145
+ const now = Date.now();
146
+ for (const [key, entry] of pendingStates) {
147
+ if (now - entry.createdAt > STATE_TTL_MS) {
148
+ pendingStates.delete(key);
149
+ }
150
+ }
151
+ }
152
+ async function buildAuthorizationUrl(config) {
153
+ cleanupExpiredStates();
154
+ const state = generateRandomState();
155
+ const codeVerifier = generateRandomCodeVerifier();
156
+ const codeChallenge = await calculatePKCECodeChallenge(codeVerifier);
157
+ pendingStates.set(state, {
158
+ codeVerifier,
159
+ config,
160
+ createdAt: Date.now()
161
+ });
162
+ const url = new URL(config.authorizeUrl);
163
+ url.searchParams.set("client_id", config.clientId);
164
+ url.searchParams.set("redirect_uri", config.redirectUri);
165
+ url.searchParams.set("response_type", "code");
166
+ url.searchParams.set("scope", config.scopes.join(config.scopeSeparator ?? ","));
167
+ url.searchParams.set("state", state);
168
+ url.searchParams.set("code_challenge", codeChallenge);
169
+ url.searchParams.set("code_challenge_method", "S256");
170
+ if (config.extraParams) {
171
+ for (const [key, value] of Object.entries(config.extraParams)) {
172
+ url.searchParams.set(key, value);
173
+ }
174
+ }
175
+ return { url: url.toString(), state, codeVerifier };
176
+ }
177
+ function tokenRequestInit(config, params) {
178
+ const useBasic = config.tokenAuthStyle === "basic";
179
+ const bodyParams = useBasic ? params : { ...params, client_id: config.clientId, client_secret: config.clientSecret };
180
+ const headers = {};
181
+ if (useBasic) {
182
+ headers.Authorization = `Basic ${Buffer.from(`${config.clientId}:${config.clientSecret}`).toString("base64")}`;
183
+ }
184
+ if (config.tokenBodyFormat === "json") {
185
+ headers["Content-Type"] = "application/json";
186
+ return { headers, body: JSON.stringify(bodyParams) };
187
+ }
188
+ headers["Content-Type"] = "application/x-www-form-urlencoded";
189
+ return { headers, body: new URLSearchParams(bodyParams).toString() };
190
+ }
191
+ async function exchangeCode(config, code, state) {
192
+ const pending = pendingStates.get(state);
193
+ if (!pending) {
194
+ throw new Error("Invalid or expired OAuth state");
195
+ }
196
+ pendingStates.delete(state);
197
+ const { codeVerifier } = pending;
198
+ const response = await fetch(config.tokenUrl, {
199
+ method: "POST",
200
+ ...tokenRequestInit(config, {
201
+ grant_type: "authorization_code",
202
+ redirect_uri: config.redirectUri,
203
+ code,
204
+ code_verifier: codeVerifier
205
+ })
206
+ });
207
+ if (!response.ok) {
208
+ const errorText = await response.text();
209
+ throw new Error(`Token exchange failed (${response.status}): ${errorText}`);
210
+ }
211
+ const data = await response.json();
212
+ const expiresAt = data.expires_in ? new Date(Date.now() + data.expires_in * 1000).toISOString() : new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();
213
+ storeOAuthTokens(config.provider, {
214
+ accessToken: data.access_token,
215
+ refreshToken: data.refresh_token ?? null,
216
+ expiresAt,
217
+ scope: data.scope ?? null
218
+ });
219
+ return {
220
+ accessToken: data.access_token,
221
+ refreshToken: data.refresh_token,
222
+ expiresIn: data.expires_in,
223
+ scope: data.scope
224
+ };
225
+ }
226
+ async function refreshAccessToken(config, refreshToken) {
227
+ const response = await fetch(config.tokenUrl, {
228
+ method: "POST",
229
+ ...tokenRequestInit(config, {
230
+ grant_type: "refresh_token",
231
+ refresh_token: refreshToken
232
+ })
233
+ });
234
+ if (!response.ok) {
235
+ const errorText = await response.text();
236
+ throw new Error(`Token refresh failed (${response.status}): ${errorText}`);
237
+ }
238
+ const data = await response.json();
239
+ if (typeof data.access_token !== "string" || data.access_token.length === 0) {
240
+ throw new Error(`Token refresh failed: ${config.provider} response missing access_token`);
241
+ }
242
+ if (config.requiresRefreshTokenRotation && (typeof data.refresh_token !== "string" || data.refresh_token.length === 0)) {
243
+ throw new Error(`Token refresh failed: ${config.provider} response did not include a rotated refresh_token`);
244
+ }
245
+ const expiresAt = data.expires_in ? new Date(Date.now() + data.expires_in * 1000).toISOString() : new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();
246
+ const nextRefreshToken = data.refresh_token ?? refreshToken;
247
+ try {
248
+ updateOAuthTokensAfterRefresh(config.provider, refreshToken, {
249
+ accessToken: data.access_token,
250
+ refreshToken: nextRefreshToken,
251
+ expiresAt,
252
+ scope: data.scope ?? null
253
+ });
254
+ } catch (err) {
255
+ const message = err instanceof Error ? err.message : String(err);
256
+ console.warn(`[OAuth] Refusing to use refreshed ${config.provider} access token because persistence failed: ${message}`);
257
+ throw err;
258
+ }
259
+ return {
260
+ accessToken: data.access_token,
261
+ refreshToken: data.refresh_token,
262
+ expiresIn: data.expires_in,
263
+ scope: data.scope
264
+ };
265
+ }
266
+
267
+ // src/oauth/ensure-token.ts
268
+ function parseMetadata(metadataJson) {
269
+ try {
270
+ const parsed = JSON.parse(metadataJson || "{}");
271
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
272
+ } catch {
273
+ return {};
274
+ }
275
+ }
276
+ function stringRecord(value) {
277
+ if (!value || typeof value !== "object" || Array.isArray(value))
278
+ return;
279
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, String(item)]));
280
+ }
281
+ function oauthAppRowToProviderConfig(app) {
282
+ const metadata = parseMetadata(app.metadata);
283
+ const extraParams = stringRecord(metadata.extraParams) ?? (typeof metadata.actor === "string" ? { actor: metadata.actor } : undefined);
284
+ return {
285
+ provider: app.provider,
286
+ clientId: app.clientId,
287
+ clientSecret: app.clientSecret,
288
+ authorizeUrl: app.authorizeUrl,
289
+ tokenUrl: app.tokenUrl,
290
+ redirectUri: app.redirectUri,
291
+ scopes: app.scopes.split(",").map((scope) => scope.trim()).filter(Boolean),
292
+ extraParams,
293
+ scopeSeparator: " ",
294
+ ...metadata.tokenAuthStyle === "basic" ? { tokenAuthStyle: "basic" } : {},
295
+ ...metadata.tokenBodyFormat === "json" ? { tokenBodyFormat: "json" } : {},
296
+ requiresRefreshTokenRotation: app.provider === "jira"
297
+ };
298
+ }
299
+ var refreshLocks = new Map;
300
+ var REFRESH_LOCK_TTL_MS = 2 * 60 * 1000;
301
+ var REFRESH_LOCK_WAIT_MS = 30 * 1000;
302
+ var REFRESH_LOCK_POLL_MS = 250;
303
+ function getOAuthConfig(provider) {
304
+ const app = getOAuthApp(provider);
305
+ return app ? oauthAppRowToProviderConfig(app) : null;
306
+ }
307
+ async function withProviderRefreshLock(provider, fn) {
308
+ const previous = refreshLocks.get(provider) ?? Promise.resolve();
309
+ let release;
310
+ const current = new Promise((resolve) => {
311
+ release = resolve;
312
+ });
313
+ const next = previous.catch(() => {
314
+ return;
315
+ }).then(() => current);
316
+ refreshLocks.set(provider, next);
317
+ await previous.catch(() => {
318
+ return;
319
+ });
320
+ try {
321
+ return await fn();
322
+ } finally {
323
+ release();
324
+ if (refreshLocks.get(provider) === next) {
325
+ refreshLocks.delete(provider);
326
+ }
327
+ }
328
+ }
329
+ function sleep(ms) {
330
+ return new Promise((resolve) => setTimeout(resolve, ms));
331
+ }
332
+ function tokenRowChanged(current, observed) {
333
+ if (!observed)
334
+ return current !== null;
335
+ if (!current)
336
+ return true;
337
+ return current.accessToken !== observed.accessToken || current.refreshToken !== observed.refreshToken || current.expiresAt !== observed.expiresAt;
338
+ }
339
+ async function ensureToken(provider, bufferMs) {
340
+ try {
341
+ await ensureTokenOrThrow(provider, bufferMs);
342
+ } catch (err) {
343
+ console.error(`[OAuth] Failed to refresh ${provider} token:`, err instanceof Error ? err.message : err);
344
+ }
345
+ }
346
+ var FORCE_REFRESH_BUFFER_MS = 1000 * 60 * 60 * 24 * 365 * 100;
347
+ async function forceRefreshTokenOrThrow(provider) {
348
+ await ensureTokenOrThrow(provider, FORCE_REFRESH_BUFFER_MS);
349
+ }
350
+ async function ensureTokenOrThrow(provider, bufferMs) {
351
+ if (!isTokenExpiringSoon(provider, bufferMs))
352
+ return;
353
+ const observedTokens = getOAuthTokens(provider);
354
+ await withProviderRefreshLock(provider, async () => {
355
+ const waitStartedAt = Date.now();
356
+ while (isTokenExpiringSoon(provider, bufferMs)) {
357
+ const tokens = getOAuthTokens(provider);
358
+ if (tokenRowChanged(tokens, observedTokens))
359
+ return;
360
+ const config = getOAuthConfig(provider);
361
+ if (!config || !tokens?.refreshToken) {
362
+ console.warn(`[OAuth] ${provider} token expiring but cannot refresh (missing config or refresh token)`);
363
+ return;
364
+ }
365
+ const lockOwner = acquireOAuthRefreshLock(provider, REFRESH_LOCK_TTL_MS);
366
+ if (!lockOwner) {
367
+ if (Date.now() - waitStartedAt > REFRESH_LOCK_WAIT_MS) {
368
+ throw new Error(`Timed out waiting for ${provider} OAuth token refresh lock`);
369
+ }
370
+ await sleep(REFRESH_LOCK_POLL_MS);
371
+ continue;
372
+ }
373
+ try {
374
+ const lockedTokens = getOAuthTokens(provider);
375
+ if (!isTokenExpiringSoon(provider, bufferMs) || tokenRowChanged(lockedTokens, observedTokens)) {
376
+ return;
377
+ }
378
+ const lockedConfig = getOAuthConfig(provider);
379
+ if (!lockedConfig || !lockedTokens?.refreshToken) {
380
+ console.warn(`[OAuth] ${provider} token expiring but cannot refresh (missing config or refresh token)`);
381
+ return;
382
+ }
383
+ await refreshAccessToken(lockedConfig, lockedTokens.refreshToken);
384
+ console.log(`[OAuth] ${provider} token refreshed successfully`);
385
+ return;
386
+ } finally {
387
+ releaseOAuthRefreshLock(provider, lockOwner);
388
+ }
389
+ }
390
+ });
391
+ }
392
+
393
+ export { getOAuthApp, upsertOAuthApp, getOAuthTokens, listOAuthTokenSweepRows, deleteOAuthTokens, isTokenExpiringSoon, acquireOAuthRefreshLock, releaseOAuthRefreshLock, buildAuthorizationUrl, exchangeCode, oauthAppRowToProviderConfig, ensureToken, forceRefreshTokenOrThrow, ensureTokenOrThrow };
@@ -1,18 +1,21 @@
1
1
  import {
2
2
  createAdditiveBuffer,
3
3
  extractSlackMessageText
4
- } from "./cli-76d1vtvq.js";
4
+ } from "./cli-5ktc9fd4.js";
5
5
  import {
6
6
  getSlackApp,
7
7
  registerTreeMessage
8
- } from "./cli-hm27prrc.js";
8
+ } from "./cli-hq39e630.js";
9
+ import {
10
+ rewriteSlackMentions
11
+ } from "./cli-w4wk3kx6.js";
9
12
  import {
10
13
  buildBufferFlushBlocks
11
14
  } from "./cli-6xd0bvf8.js";
12
15
  import {
13
16
  createTaskWithSiblingAwareness,
14
17
  slackContextKey
15
- } from "./cli-0c3n0eba.js";
18
+ } from "./cli-312v3c41.js";
16
19
  import {
17
20
  getLatestActiveTaskInThread,
18
21
  getLeadAgent,
@@ -20,7 +23,7 @@ import {
20
23
  init_db,
21
24
  init_registry,
22
25
  registerTemplate
23
- } from "./cli-951w7c79.js";
26
+ } from "./cli-jzwtn8rm.js";
24
27
 
25
28
  // src/slack/event-dedup.ts
26
29
  var DEFAULT_TTL_MS = 300000;
@@ -164,7 +167,7 @@ async function getThreadContextForBuffer(channelId, threadTs) {
164
167
  return `<@${m.user}>: ${text}`;
165
168
  }).join(`
166
169
  `);
167
- return formatted;
170
+ return rewriteSlackMentions(formatted);
168
171
  } catch (error) {
169
172
  console.error("[Slack] Failed to fetch thread context for buffer:", error);
170
173
  return "";
@@ -181,9 +184,9 @@ async function slackFlush(items, key, immediate) {
181
184
  const { channelId, threadTs } = split;
182
185
  const originalRequesterId = items[0].userId;
183
186
  console.log(`[Slack] Flushing buffer: ${key} (${items.length} messages, immediate=${immediate})`);
184
- const combinedText = items.map((m) => m.text).join(`
187
+ const combinedText = rewriteSlackMentions(items.map((m) => m.text).join(`
185
188
  ---
186
- `);
189
+ `));
187
190
  const description = `[Thread follow-up — ${items.length} message(s) buffered]
188
191
 
189
192
  ${combinedText}`;
@@ -3,7 +3,7 @@ import {
3
3
  getAgentWorkingOnThread,
4
4
  getAllAgents,
5
5
  init_db
6
- } from "./cli-951w7c79.js";
6
+ } from "./cli-jzwtn8rm.js";
7
7
 
8
8
  // src/slack/router.ts
9
9
  init_db();