@desplega.ai/agent-swarm 2.7.2 → 2.7.3

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 (220) hide show
  1. package/README.md +6 -0
  2. package/dist/{acp-adapter-624yge7a.js → acp-adapter-pdzw76ja.js} +1 -1
  3. package/dist/{actions-rd9xn281.js → actions-a90cfpca.js} +21 -21
  4. package/dist/{amp-adapter-k27hc00p.js → amp-adapter-4vtywcjk.js} +2 -2
  5. package/dist/{app-sjm3xc7g.js → app-8k68gygk.js} +3 -3
  6. package/dist/{assistant-6jbzs8wa.js → assistant-ck01q2yg.js} +32 -21
  7. package/dist/{boot-reembed-e2348eqc.js → boot-reembed-33spavpd.js} +1 -1
  8. package/dist/{boot-reembed-w53pd5xt.js → boot-reembed-xzge83a2.js} +1 -1
  9. package/dist/{boot-scrub-sweep-cpy4yg97.js → boot-scrub-sweep-mxvb8dr3.js} +3 -3
  10. package/dist/{boot-seeds-f6j4t6k6.js → boot-seeds-rpm8bb5r.js} +4 -4
  11. package/dist/{claude-adapter-v3ac8esd.js → claude-adapter-q12bcfj9.js} +3 -3
  12. package/dist/{claude-managed-setup-yyrkqvtm.js → claude-managed-setup-11vb6q89.js} +1 -1
  13. package/dist/{claude-sdk-session-85j69v6d.js → claude-sdk-session-gkv1107j.js} +10325 -10243
  14. package/dist/{cli-rs59z1qx.js → cli-07pcqwaj.js} +1 -1
  15. package/dist/{cli-6vq3ymqm.js → cli-0tkm519n.js} +1 -1
  16. package/dist/{cli-s7cm1927.js → cli-0xzbk52h.js} +4 -4
  17. package/dist/{cli-g0zc1b40.js → cli-0zae6bs6.js} +2 -2
  18. package/dist/{cli-p8yrsmfn.js → cli-10kjx0dm.js} +1 -1
  19. package/dist/{cli-7xsq63pe.js → cli-157ykn37.js} +10 -9
  20. package/dist/{cli-vjcj9k2p.js → cli-2h0rfmqk.js} +1 -1
  21. package/dist/{cli-9wasax9f.js → cli-35nzvqaf.js} +1 -1
  22. package/dist/{cli-e1p7dqe1.js → cli-4aydmmdy.js} +24 -3
  23. package/dist/{cli-942pp3bc.js → cli-54ax65rn.js} +3 -3
  24. package/dist/{cli-10cp92df.js → cli-5ke7gxwr.js} +6 -6
  25. package/dist/{cli-femw4q81.js → cli-6151a7dr.js} +2 -2
  26. package/dist/{cli-3cywb44q.js → cli-77eq8txs.js} +85 -3
  27. package/dist/{cli-atpfk4yd.js → cli-7cwrwb5x.js} +5 -5
  28. package/dist/{cli-bfbpvccx.js → cli-8a1k6mat.js} +61 -49
  29. package/dist/{cli-c18941tx.js → cli-8ch3b2r7.js} +3 -3
  30. package/dist/{cli-rs2s1t05.js → cli-9fk56y8c.js} +4 -4
  31. package/dist/{cli-0wx63vvw.js → cli-9km88w11.js} +1 -1
  32. package/dist/{cli-qy0z3mfj.js → cli-9vttw9nz.js} +56 -46
  33. package/dist/{cli-mzgppb7q.js → cli-a0w50zw9.js} +4 -4
  34. package/dist/{cli-z8a4mfz1.js → cli-aqp59jmv.js} +4 -4
  35. package/dist/{cli-5d8wd50e.js → cli-bs0fwb23.js} +1 -1
  36. package/dist/{cli-fa4kxxx3.js → cli-ct5920jb.js} +2 -2
  37. package/dist/{cli-0awbtmv2.js → cli-dek8hqjc.js} +10 -10
  38. package/dist/{cli-qp6adcmw.js → cli-e24w2mvk.js} +1 -1
  39. package/dist/{cli-t3npd8hm.js → cli-ghfhn1qc.js} +1 -1
  40. package/dist/{cli-jmcf8cnz.js → cli-ja369zab.js} +1 -1
  41. package/dist/{cli-wtjg6je3.js → cli-jhh7tbx6.js} +1 -1
  42. package/dist/{cli-e19bgatr.js → cli-jmk31131.js} +2 -2
  43. package/dist/{cli-2cj8fqv1.js → cli-kjcdzea8.js} +1 -1
  44. package/dist/{cli-1xpr5992.js → cli-kjha1q9k.js} +3 -3
  45. package/dist/{cli-9jfty8px.js → cli-ktcdczth.js} +538 -30
  46. package/dist/{cli-exd52qn4.js → cli-mcmpbpcc.js} +2 -2
  47. package/dist/{cli-2m2p3snc.js → cli-mmf43vcp.js} +6 -6
  48. package/dist/{cli-b2rhbaty.js → cli-pnm99spe.js} +10 -10
  49. package/dist/{cli-9jn9cj0q.js → cli-v9jk2k63.js} +1 -1
  50. package/dist/{cli-mt7bxjfd.js → cli-vhgcwppn.js} +1 -1
  51. package/dist/{cli-qa4hgda3.js → cli-vvz64zc5.js} +14 -13
  52. package/dist/{cli-txr0z97c.js → cli-wmhajw68.js} +171 -32
  53. package/dist/{cli-hzrmv8pg.js → cli-x38rmhap.js} +3 -3
  54. package/dist/{cli-hq9hd4hp.js → cli-xz6qjdqj.js} +1 -1
  55. package/dist/{cli-g9ypd5en.js → cli-z52gq55b.js} +4 -0
  56. package/dist/{cli-2qbmjfta.js → cli-z6219sd3.js} +4 -4
  57. package/dist/cli.js +19 -19
  58. package/dist/{codex-adapter-zm1bkdde.js → codex-adapter-46kbvvkx.js} +1 -1
  59. package/dist/{codex-hook-tkag7fxq.js → codex-hook-tm9ecrd5.js} +1 -1
  60. package/dist/{codex-session-runner-8k02mqw2.js → codex-session-runner-qy93hdrv.js} +1 -1
  61. package/dist/{commands-nw1dn4av.js → commands-hwdhacfx.js} +2 -2
  62. package/dist/{controller-3kkkmps0.js → controller-hjza5p1f.js} +3 -3
  63. package/dist/{controllers-connect-n2c4167r.js → controllers-connect-7m25cay2.js} +20 -20
  64. package/dist/{cursor-adapter-h5028emw.js → cursor-adapter-1qh7ps8w.js} +1 -1
  65. package/dist/{db-76y2msnf.js → db-w23k9301.js} +2 -2
  66. package/dist/{db-8rk0p8j1.js → db-wm8by383.js} +3 -3
  67. package/dist/{dispatcher-xp4wsx30.js → dispatcher-en25ebgc.js} +18 -18
  68. package/dist/{dsh-adapter-vyrr31bn.js → dsh-adapter-zkme32vd.js} +1 -1
  69. package/dist/{e2b-eesfj689.js → e2b-9z9mvt2p.js} +1 -1
  70. package/dist/{e2b-03nha1wz.js → e2b-yhvn70es.js} +1 -1
  71. package/dist/{embedding-space-ejefyep1.js → embedding-space-rgf4aypt.js} +6 -6
  72. package/dist/{embeddings-w297xaw0.js → embeddings-z9cmxhx1.js} +1 -1
  73. package/dist/{external-channel-mf9vp1fe.js → external-channel-g6vv85zv.js} +2 -2
  74. package/dist/{grok-adapter-mpzyyprz.js → grok-adapter-f6n1tpq3.js} +2 -2
  75. package/dist/handlers-ss5948rq.js +42 -0
  76. package/dist/{heartbeat-qnaycjzs.js → heartbeat-5xcdzz45.js} +21 -21
  77. package/dist/{hook-h6sqfzxr.js → hook-6423rme3.js} +2 -2
  78. package/dist/{hook-4zqdgea4.js → hook-8dk1csdd.js} +4 -4
  79. package/dist/{http-65ts210h.js → http-6mfh2ww9.js} +255 -60
  80. package/dist/{index-sqe7f6mj.js → index-0js6bgff.js} +1 -1
  81. package/dist/{index-farm1zsn.js → index-0ng1dd1t.js} +10937 -9527
  82. package/dist/{index-k3ewf1jg.js → index-5eyn1wc5.js} +18 -18
  83. package/dist/{index-vp4wa3qn.js → index-71gnebsn.js} +18 -18
  84. package/dist/{index-hdfad00b.js → index-q5gzpjdd.js} +12 -10
  85. package/dist/index-z3b1vfjx.js +44 -0
  86. package/dist/{keepalive-52k6skha.js → keepalive-cymckeg6.js} +3 -3
  87. package/dist/{lead-y9rj0gr1.js → lead-baknj2dh.js} +29 -29
  88. package/dist/{maintenance-f86wqfq6.js → maintenance-dfrnsx3n.js} +1 -1
  89. package/dist/{oauth-refresh-sweep-vddv9ky7.js → oauth-refresh-sweep-5dztk8x6.js} +2 -2
  90. package/dist/{onboard-8z2qk6gq.js → onboard-h36vja6y.js} +11 -6
  91. package/dist/{otel-impl-epet9j18.js → otel-impl-jerq8vz8.js} +1 -1
  92. package/dist/{pricing-refresh-6wm42a51.js → pricing-refresh-t3nx5krn.js} +3 -3
  93. package/dist/{rbac-roles-2kfcs1sc.js → rbac-roles-dw1awawd.js} +2 -2
  94. package/dist/{rbac-roles-13a0vj6d.js → rbac-roles-km0fc3e8.js} +1 -1
  95. package/dist/{registry-ajhexe44.js → registry-hzfh268v.js} +1 -1
  96. package/dist/{render-v2-cy8zsfsf.js → render-v2-65x4ayj8.js} +3 -3
  97. package/dist/{resume-c783qe6b.js → resume-61znk3hj.js} +6 -6
  98. package/dist/{session-access-s4tv0az8.js → session-access-4yc9htrg.js} +4 -4
  99. package/dist/{session-source-backfill-qzapz0ne.js → session-source-backfill-kr5bdjtp.js} +2 -2
  100. package/dist/{setup-st7htx1k.js → setup-9h61yr2p.js} +1 -1
  101. package/dist/{work-objects-ftj4zw70.js → work-objects-x7rb53qn.js} +27 -22
  102. package/dist/{worker-859fk25k.js → worker-7f3khgn0.js} +29 -29
  103. package/openapi.json +134 -3
  104. package/package.json +5 -5
  105. package/src/be/db/agents.ts +16 -1
  106. package/src/be/db/runtime.ts +25 -15
  107. package/src/be/db/session-summaries.ts +120 -0
  108. package/src/be/db/tasks/read.ts +7 -4
  109. package/src/be/db/tasks/search-index.ts +159 -0
  110. package/src/be/db/tasks/write.ts +3 -0
  111. package/src/be/db-queries/slack-inbound.ts +77 -0
  112. package/src/be/db.ts +27 -8
  113. package/src/be/mcp-overflow-sweep.ts +39 -0
  114. package/src/be/migrations/253_session_summaries.sql +300 -0
  115. package/src/be/migrations/254_query_audit_indexes.sql +25 -0
  116. package/src/be/migrations/256_agent_slack_icon.sql +2 -0
  117. package/src/be/migrations/257_agent_tasks_fts.sql +55 -0
  118. package/src/comb/config.ts +6 -2
  119. package/src/comb/requester.ts +69 -0
  120. package/src/comb/review-batch.ts +24 -2
  121. package/src/commands/onboard/agent-fs-version.ts +1 -1
  122. package/src/commands/onboard/compose-generator.ts +7 -2
  123. package/src/commands/onboard/env-generator.ts +8 -3
  124. package/src/commands/runner.ts +41 -24
  125. package/src/fs/agent-fs-provider.ts +9 -0
  126. package/src/heartbeat/heartbeat.ts +13 -6
  127. package/src/http/agents.ts +10 -2
  128. package/src/http/index.ts +15 -0
  129. package/src/http/integrations.ts +20 -0
  130. package/src/http/list-total-cache.ts +62 -0
  131. package/src/http/sessions.ts +9 -2
  132. package/src/http/slack-inbound.ts +1 -0
  133. package/src/http/status.ts +4 -1
  134. package/src/http/tasks.ts +12 -2
  135. package/src/providers/amp-adapter.ts +1 -1
  136. package/src/providers/cursor-adapter.ts +1 -1
  137. package/src/providers/dsh-adapter.ts +1 -1
  138. package/src/queue-stall-alarm.ts +4 -1
  139. package/src/slack/actions.ts +2 -2
  140. package/src/slack/app-icon.ts +50 -0
  141. package/src/slack/app.ts +13 -1
  142. package/src/slack/assistant.ts +22 -1
  143. package/src/slack/event-dedup.test.ts +11 -0
  144. package/src/slack/event-dedup.ts +8 -4
  145. package/src/slack/inbound-dispatch.ts +58 -0
  146. package/src/slack/render-v2.ts +7 -8
  147. package/src/slack/responses.ts +21 -8
  148. package/src/slack/socket-ack.ts +237 -0
  149. package/src/slack/thread-buffer.ts +3 -5
  150. package/src/slack/watcher.ts +2 -2
  151. package/src/slack/work-objects.ts +5 -1
  152. package/src/tests/agent-fs-release-notes.test.ts +40 -0
  153. package/src/tests/agent-slack-icon.test.ts +85 -0
  154. package/src/tests/approval-cancellation-migration.test.ts +2 -0
  155. package/src/tests/asset-key-migration.test.ts +26 -0
  156. package/src/tests/comb-default.test.ts +159 -0
  157. package/src/tests/comb-review-batch.test.ts +192 -4
  158. package/src/tests/comb-status.test.ts +65 -2
  159. package/src/tests/db-agents.test.ts +13 -0
  160. package/src/tests/db-tasks-read.test.ts +10 -15
  161. package/src/tests/deploy-one-box.test.ts +161 -0
  162. package/src/tests/deploy-stubs.ts +68 -0
  163. package/src/tests/docs-index-footprint.test.js +3 -3
  164. package/src/tests/dsh-adapter.test.ts +1 -1
  165. package/src/tests/e2e-codex-auth-chain.test.ts +18 -1
  166. package/src/tests/fixtures/deploy-stubs/bun +3 -0
  167. package/src/tests/fixtures/deploy-stubs/bunx +27 -0
  168. package/src/tests/fixtures/deploy-stubs/curl +26 -0
  169. package/src/tests/fixtures/deploy-stubs/docker +122 -0
  170. package/src/tests/fixtures/onboard/content.compose.yml.txt +5 -5
  171. package/src/tests/fixtures/onboard/dev.compose.yml.txt +4 -4
  172. package/src/tests/fixtures/onboard/full-all.compose.yml.txt +12 -12
  173. package/src/tests/fixtures/onboard/full.compose.yml.txt +12 -12
  174. package/src/tests/fixtures/onboard/research.compose.yml.txt +4 -4
  175. package/src/tests/fixtures/onboard/solo.compose.yml.txt +2 -2
  176. package/src/tests/heartbeat-expiry.test.ts +151 -25
  177. package/src/tests/http-api-integration.test.ts +31 -0
  178. package/src/tests/human-free-reclassify.test.ts +6 -0
  179. package/src/tests/install-sh-bind.test.ts +242 -0
  180. package/src/tests/install-sh-tunnel.test.ts +89 -0
  181. package/src/tests/kv-storage.test.ts +28 -0
  182. package/src/tests/list-endpoint-slimming.test.ts +3 -0
  183. package/src/tests/list-total-cache.test.ts +63 -0
  184. package/src/tests/mcp-overflow-sweep.test.ts +84 -0
  185. package/src/tests/onboard-compose.test.ts +17 -3
  186. package/src/tests/onboard-env.test.ts +13 -0
  187. package/src/tests/onboarding.test.ts +1 -1
  188. package/src/tests/preload.ts +1 -0
  189. package/src/tests/query-audit-plans.test.ts +314 -0
  190. package/src/tests/script-connections.test.ts +6 -0
  191. package/src/tests/session-summaries.test.ts +384 -0
  192. package/src/tests/sessions-tree.test.ts +5 -1
  193. package/src/tests/slack-app-icon.test.ts +90 -0
  194. package/src/tests/slack-external-channel-egress.test.ts +1 -1
  195. package/src/tests/slack-inbound-receipts.test.ts +34 -0
  196. package/src/tests/slack-inline-output.test.ts +29 -2
  197. package/src/tests/slack-render-v2-query-plans.test.ts +3 -2
  198. package/src/tests/slack-render-v2.test.ts +35 -0
  199. package/src/tests/slack-socket-ack.test.ts +553 -0
  200. package/src/tests/task-lineage.test.ts +3 -0
  201. package/src/tests/task-search-filter.test.ts +4 -4
  202. package/src/tests/task-search-fts.test.ts +320 -0
  203. package/src/tests/update-profile-auth.test.ts +28 -0
  204. package/src/tools/get-swarm.ts +1 -0
  205. package/src/tools/get-tasks.ts +6 -1
  206. package/src/tools/join-swarm.ts +1 -0
  207. package/src/tools/my-agent-info.ts +1 -0
  208. package/src/tools/slack-post.ts +2 -2
  209. package/src/tools/slack-reply.ts +2 -2
  210. package/src/tools/slack-start-thread.ts +2 -2
  211. package/src/tools/slack-update.ts +1 -1
  212. package/src/tools/update-profile.ts +20 -4
  213. package/src/tools/utils.ts +3 -4
  214. package/src/types.ts +47 -0
  215. package/src/utils/constants.ts +127 -5
  216. package/templates/official/lead/HEARTBEAT.md +4 -2
  217. package/templates/official/lead/config.json +2 -2
  218. package/templates/skills/swarm-docs/content.md +2 -0
  219. package/dist/handlers-7x8sywgr.js +0 -42
  220. package/dist/index-mc30r1hs.js +0 -44
@@ -1,6 +1,9 @@
1
1
  import {
2
2
  slackContextKey,
3
3
  init_context_key,
4
+ encryptSecret,
5
+ decryptSecret,
6
+ getEncryptionKey,
4
7
  init_crypto,
5
8
  getDbClient2,
6
9
  getAgentById2,
@@ -47,10 +50,10 @@ import {
47
50
  checkDependencies2,
48
51
  emitBuiltInIntegrationConnectedOnce2,
49
52
  init_db3
50
- } from "./cli-txr0z97c.js";
53
+ } from "./cli-wmhajw68.js";
51
54
  import {
52
55
  getChannelBlockReason2
53
- } from "./cli-6vq3ymqm.js";
56
+ } from "./cli-0tkm519n.js";
54
57
  import {
55
58
  require_dist5,
56
59
  require_axios,
@@ -67,11 +70,11 @@ import {
67
70
  import {
68
71
  isTerminalTaskStatus,
69
72
  init_types2
70
- } from "./cli-e1p7dqe1.js";
73
+ } from "./cli-4aydmmdy.js";
71
74
  import {
72
75
  taskAttachmentDisplayUrl,
73
76
  init_task_attachment_links
74
- } from "./cli-0wx63vvw.js";
77
+ } from "./cli-9km88w11.js";
75
78
  import {
76
79
  getSlackConfiguration,
77
80
  init_config
@@ -93,7 +96,7 @@ import {
93
96
  import {
94
97
  getAppUrl,
95
98
  init_constants2
96
- } from "./cli-3cywb44q.js";
99
+ } from "./cli-77eq8txs.js";
97
100
  import {
98
101
  isEnvFlagEnabled,
99
102
  init_env_flag
@@ -6005,8 +6008,9 @@ function installSlackExternalChannelGuard() {
6005
6008
  }
6006
6009
 
6007
6010
  // src/slack/inbound-dispatch.ts
6008
- import { AsyncLocalStorage } from "node:async_hooks";
6009
6011
  init_crypto();
6012
+ import { AsyncLocalStorage } from "node:async_hooks";
6013
+ import { createHash } from "node:crypto";
6010
6014
 
6011
6015
  // src/be/db-queries/slack-inbound.ts
6012
6016
  init_db3();
@@ -6026,6 +6030,176 @@ var SLACK_INBOUND_LIMITS = {
6026
6030
  maxAttempts: 3,
6027
6031
  retryBackoffMs: 30000
6028
6032
  };
6033
+ function toReceipt(row) {
6034
+ return {
6035
+ id: row.id,
6036
+ dedupKey: row.dedup_key,
6037
+ transport: row.transport,
6038
+ kind: row.kind,
6039
+ payloadType: row.payload_type,
6040
+ apiAppId: row.api_app_id,
6041
+ eventId: row.event_id,
6042
+ payloadCiphertext: row.payload_ciphertext,
6043
+ payloadBytes: row.payload_bytes,
6044
+ retryNum: row.retry_num,
6045
+ retryReason: row.retry_reason,
6046
+ state: row.state,
6047
+ attempts: row.attempts,
6048
+ duplicateCount: row.duplicate_count,
6049
+ outcomeCode: row.outcome_code,
6050
+ errorCode: row.error_code,
6051
+ receivedAt: row.received_at,
6052
+ availableAt: row.available_at,
6053
+ claimedAt: row.claimed_at,
6054
+ completedAt: row.completed_at,
6055
+ lastDuplicateAt: row.last_duplicate_at,
6056
+ payloadErasedAt: row.payload_erased_at
6057
+ };
6058
+ }
6059
+ async function admitSlackInboundReceipt(input, now = new Date, limits = SLACK_INBOUND_LIMITS) {
6060
+ const nowIso = now.toISOString();
6061
+ return getDbClient2().transaction(async (tx) => {
6062
+ const duplicate = await tx.get(`UPDATE slack_inbound_receipts
6063
+ SET duplicate_count = duplicate_count + 1, last_duplicate_at = ?, updated_at = ?
6064
+ WHERE dedup_key = ?
6065
+ RETURNING *`, [nowIso, nowIso, input.dedupKey]);
6066
+ if (duplicate)
6067
+ return { status: "duplicate", receipt: toReceipt(duplicate) };
6068
+ if (input.payloadBytes > limits.maxPayloadBytes) {
6069
+ return { status: "rejected", reason: "payload_too_large" };
6070
+ }
6071
+ const backlog = await tx.get(`SELECT COUNT(*) AS receipts, SUM(payload_bytes) AS bytes
6072
+ FROM slack_inbound_receipts
6073
+ WHERE state IN ('pending', 'processing')`);
6074
+ const receipts = backlog?.receipts ?? 0;
6075
+ const bytes = backlog?.bytes ?? 0;
6076
+ if (receipts >= limits.maxBacklogReceipts || bytes + input.payloadBytes > limits.maxBacklogBytes) {
6077
+ return { status: "rejected", reason: "backlog_full" };
6078
+ }
6079
+ const inserted = await tx.get(`INSERT INTO slack_inbound_receipts (
6080
+ id, dedup_key, transport, kind, payload_type, api_app_id, event_id,
6081
+ payload_ciphertext, payload_bytes, retry_num, retry_reason,
6082
+ received_at, available_at, created_at, updated_at
6083
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6084
+ ON CONFLICT(dedup_key) DO NOTHING
6085
+ RETURNING *`, [
6086
+ crypto.randomUUID(),
6087
+ input.dedupKey,
6088
+ input.transport,
6089
+ input.kind,
6090
+ input.payloadType,
6091
+ input.apiAppId ?? null,
6092
+ input.eventId ?? null,
6093
+ input.payloadCiphertext,
6094
+ input.payloadBytes,
6095
+ input.retryNum ?? null,
6096
+ input.retryReason ?? null,
6097
+ nowIso,
6098
+ nowIso,
6099
+ nowIso,
6100
+ nowIso
6101
+ ]);
6102
+ if (inserted)
6103
+ return { status: "admitted", receipt: toReceipt(inserted) };
6104
+ const winner = await tx.get("SELECT * FROM slack_inbound_receipts WHERE dedup_key = ?", [input.dedupKey]);
6105
+ if (!winner)
6106
+ throw new Error("Slack inbound receipt vanished during admission");
6107
+ return { status: "duplicate", receipt: toReceipt(winner) };
6108
+ });
6109
+ }
6110
+ async function recordSlackInboundInline(input, now = new Date) {
6111
+ const nowIso = now.toISOString();
6112
+ const inserted = await getDbClient2().get(`INSERT INTO slack_inbound_receipts (
6113
+ id, dedup_key, transport, kind, payload_type, api_app_id, event_id,
6114
+ payload_bytes, retry_num, retry_reason, state, attempts, outcome_code,
6115
+ received_at, available_at, completed_at, payload_erased_at, created_at, updated_at
6116
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?, 'processed', 1, 'ran_inline', ?, ?, ?, ?, ?, ?)
6117
+ ON CONFLICT(dedup_key) DO NOTHING
6118
+ RETURNING id`, [
6119
+ crypto.randomUUID(),
6120
+ input.dedupKey,
6121
+ input.transport,
6122
+ input.kind,
6123
+ input.payloadType,
6124
+ input.apiAppId ?? null,
6125
+ input.eventId ?? null,
6126
+ input.retryNum ?? null,
6127
+ input.retryReason ?? null,
6128
+ nowIso,
6129
+ nowIso,
6130
+ nowIso,
6131
+ nowIso,
6132
+ nowIso,
6133
+ nowIso
6134
+ ]);
6135
+ if (inserted)
6136
+ return "recorded";
6137
+ await touchSlackInboundDuplicate(input.dedupKey, now);
6138
+ return "duplicate";
6139
+ }
6140
+ async function touchSlackInboundDuplicate(dedupKey, now = new Date) {
6141
+ const nowIso = now.toISOString();
6142
+ const row = await getDbClient2().get(`UPDATE slack_inbound_receipts
6143
+ SET duplicate_count = duplicate_count + 1, last_duplicate_at = ?, updated_at = ?
6144
+ WHERE dedup_key = ?
6145
+ RETURNING id`, [nowIso, nowIso, dedupKey]);
6146
+ return row !== null && row !== undefined;
6147
+ }
6148
+ async function claimSlackInboundReceipt(now = new Date, id) {
6149
+ const nowIso = now.toISOString();
6150
+ const row = id ? await getDbClient2().get(`UPDATE slack_inbound_receipts
6151
+ SET state = 'processing', attempts = attempts + 1, claimed_at = ?, updated_at = ?
6152
+ WHERE id = ? AND state = 'pending' AND available_at <= ?
6153
+ RETURNING *`, [nowIso, nowIso, id, nowIso]) : await getDbClient2().get(`UPDATE slack_inbound_receipts
6154
+ SET state = 'processing', attempts = attempts + 1, claimed_at = ?, updated_at = ?
6155
+ WHERE id = (
6156
+ SELECT id FROM slack_inbound_receipts
6157
+ WHERE state = 'pending' AND available_at <= ?
6158
+ ORDER BY received_at, id
6159
+ LIMIT 1
6160
+ )
6161
+ AND state = 'pending'
6162
+ RETURNING *`, [nowIso, nowIso, nowIso]);
6163
+ return row ? toReceipt(row) : null;
6164
+ }
6165
+ async function completeSlackInboundReceipt(id, outcome, now = new Date) {
6166
+ const nowIso = now.toISOString();
6167
+ const erase = outcome.state === "processed" || outcome.state === "ignored";
6168
+ const { changes } = await getDbClient2().run(`UPDATE slack_inbound_receipts
6169
+ SET state = ?, outcome_code = ?, error_code = ?, completed_at = ?, updated_at = ?,
6170
+ payload_ciphertext = CASE WHEN ? THEN NULL ELSE payload_ciphertext END,
6171
+ payload_erased_at = CASE WHEN ? THEN ? ELSE payload_erased_at END
6172
+ WHERE id = ? AND state = 'processing'`, [
6173
+ outcome.state,
6174
+ outcome.outcomeCode ?? null,
6175
+ outcome.errorCode ?? null,
6176
+ outcome.state === "uncertain" ? null : nowIso,
6177
+ nowIso,
6178
+ erase ? 1 : 0,
6179
+ erase ? 1 : 0,
6180
+ nowIso,
6181
+ id
6182
+ ]);
6183
+ return changes > 0;
6184
+ }
6185
+ async function releaseSlackInboundReceipt(id, errorCode, availableAt, now = new Date) {
6186
+ const nowIso = now.toISOString();
6187
+ const { changes } = await getDbClient2().run(`UPDATE slack_inbound_receipts
6188
+ SET state = 'pending', error_code = ?, available_at = ?, claimed_at = NULL, updated_at = ?
6189
+ WHERE id = ? AND state = 'processing'`, [errorCode, availableAt.toISOString(), nowIso, id]);
6190
+ return changes > 0;
6191
+ }
6192
+ async function getNextSlackInboundAvailableAt() {
6193
+ const row = await getDbClient2().get(`SELECT MIN(available_at) AS next FROM slack_inbound_receipts WHERE state = 'pending'`);
6194
+ return row?.next ? new Date(row.next) : null;
6195
+ }
6196
+ async function markInterruptedSlackInboundReceiptsUncertain(now = new Date) {
6197
+ const nowIso = now.toISOString();
6198
+ const { changes } = await getDbClient2().run(`UPDATE slack_inbound_receipts
6199
+ SET state = 'uncertain', error_code = 'interrupted_during_processing', updated_at = ?
6200
+ WHERE state = 'processing'`, [nowIso]);
6201
+ return changes;
6202
+ }
6029
6203
  async function getSlackInboundReceiptStats(uncertainLimit = 20) {
6030
6204
  const db = getDbClient2();
6031
6205
  return db.transaction(async (tx) => {
@@ -6122,6 +6296,7 @@ function emptyCounters() {
6122
6296
  ignored: 0,
6123
6297
  failed: 0,
6124
6298
  uncertain: 0,
6299
+ ackNotReady: 0,
6125
6300
  lastOutcomeAt: null,
6126
6301
  lastFailure: null
6127
6302
  };
@@ -6140,6 +6315,9 @@ function recordOutcome(transport, outcome) {
6140
6315
  console.warn(`[Slack] inbound ${transport} delivery ${outcome.state}: ${outcome.code}`);
6141
6316
  }
6142
6317
  }
6318
+ function recordSlackSocketAckNotReady() {
6319
+ counters.socket.ackNotReady += 1;
6320
+ }
6143
6321
  function slackInboundOutcomeMiddleware() {
6144
6322
  return async ({ next }) => {
6145
6323
  const existing = deliveryStorage.getStore();
@@ -6166,6 +6344,213 @@ function slackInboundOutcomeMiddleware() {
6166
6344
  });
6167
6345
  };
6168
6346
  }
6347
+ async function runAdmittedSlackDelivery(transport, fn, options = {}) {
6348
+ const state = newDeliveryState(transport, true);
6349
+ try {
6350
+ await deliveryStorage.run(state, fn);
6351
+ } catch (error) {
6352
+ return resolveSlackInboundOutcome(state, error);
6353
+ }
6354
+ if (options.requireBoltDispatch && !state.dispatched) {
6355
+ return { state: "failed", code: "not_dispatched" };
6356
+ }
6357
+ return resolveSlackInboundOutcome(state);
6358
+ }
6359
+ function sha256(value) {
6360
+ return createHash("sha256").update(value).digest("hex");
6361
+ }
6362
+ function stringField(body, key) {
6363
+ const value = body[key];
6364
+ return typeof value === "string" && value.length > 0 ? value : null;
6365
+ }
6366
+ function computeSlackInboundKey(kind, rawBody, body) {
6367
+ if (!body || typeof body !== "object")
6368
+ return { ok: false, reason: "malformed" };
6369
+ const record = body;
6370
+ const payloadType = stringField(record, "type") ?? (kind === "command" ? "command" : null);
6371
+ if (!payloadType)
6372
+ return { ok: false, reason: "malformed" };
6373
+ const apiAppId = stringField(record, "api_app_id");
6374
+ if (kind === "event" && payloadType === "event_callback") {
6375
+ const eventId = stringField(record, "event_id");
6376
+ if (!eventId)
6377
+ return { ok: false, reason: "missing_event_id" };
6378
+ return {
6379
+ ok: true,
6380
+ dedupKey: `event:${apiAppId ?? "-"}:${eventId}`,
6381
+ payloadType,
6382
+ apiAppId,
6383
+ eventId
6384
+ };
6385
+ }
6386
+ return {
6387
+ ok: true,
6388
+ dedupKey: `${kind}:${payloadType}:${sha256(rawBody)}`,
6389
+ payloadType,
6390
+ apiAppId,
6391
+ eventId: null
6392
+ };
6393
+ }
6394
+ function socketEventKey(body) {
6395
+ if (body?.type !== "event_callback")
6396
+ return null;
6397
+ const key = computeSlackInboundKey("event", "", body);
6398
+ return key.ok ? key : null;
6399
+ }
6400
+ async function isSlackSocketEventStored(body, now = new Date) {
6401
+ const key = socketEventKey(body);
6402
+ return key ? touchSlackInboundDuplicate(key.dedupKey, now) : false;
6403
+ }
6404
+ async function recordSlackSocketEventRanInline(body, retry = {}, now = new Date) {
6405
+ const key = socketEventKey(body);
6406
+ if (!key)
6407
+ return "invalid";
6408
+ return recordSlackInboundInline({
6409
+ dedupKey: key.dedupKey,
6410
+ transport: "socket",
6411
+ kind: "event",
6412
+ payloadType: key.payloadType,
6413
+ apiAppId: key.apiAppId,
6414
+ eventId: key.eventId,
6415
+ retryNum: retry.retryNum,
6416
+ retryReason: retry.retryReason
6417
+ }, now);
6418
+ }
6419
+ async function admitSlackInbound(input, now = new Date) {
6420
+ const key = computeSlackInboundKey(input.kind, input.rawBody, input.body);
6421
+ if (!key.ok)
6422
+ return { status: "invalid", reason: key.reason };
6423
+ const payloadBytes = Buffer.byteLength(input.rawBody, "utf8");
6424
+ if (payloadBytes > SLACK_INBOUND_LIMITS.maxPayloadBytes) {
6425
+ return { status: "rejected", reason: "payload_too_large" };
6426
+ }
6427
+ return admitSlackInboundReceipt({
6428
+ dedupKey: key.dedupKey,
6429
+ transport: input.transport,
6430
+ kind: input.kind,
6431
+ payloadType: key.payloadType,
6432
+ apiAppId: key.apiAppId,
6433
+ eventId: key.eventId,
6434
+ payloadCiphertext: encryptSecret(input.rawBody, getEncryptionKey()),
6435
+ payloadBytes,
6436
+ retryNum: input.retryNum ?? null,
6437
+ retryReason: input.retryReason ?? null
6438
+ }, now);
6439
+ }
6440
+ async function processNextSlackInboundReceipt(processor, options = {}) {
6441
+ const now = options.now ?? (() => new Date);
6442
+ const receipt = await claimSlackInboundReceipt(now());
6443
+ if (!receipt)
6444
+ return null;
6445
+ let rawBody;
6446
+ try {
6447
+ if (!receipt.payloadCiphertext)
6448
+ throw new Error("payload already erased");
6449
+ rawBody = decryptSecret(receipt.payloadCiphertext, getEncryptionKey());
6450
+ } catch {
6451
+ const outcome = { state: "failed", code: "payload_unreadable" };
6452
+ await completeSlackInboundReceipt(receipt.id, { state: "failed", errorCode: outcome.code }, now());
6453
+ recordOutcome(receipt.transport, outcome);
6454
+ return { receiptId: receipt.id, outcome, state: "failed" };
6455
+ }
6456
+ const outcome = await runAdmittedSlackDelivery(receipt.transport, () => processor({ receipt, rawBody }), { requireBoltDispatch: options.requireBoltDispatch });
6457
+ recordOutcome(receipt.transport, outcome);
6458
+ if (outcome.state === "failed" && receipt.attempts < SLACK_INBOUND_LIMITS.maxAttempts) {
6459
+ const availableAt = new Date(now().getTime() + SLACK_INBOUND_LIMITS.retryBackoffMs * receipt.attempts);
6460
+ await releaseSlackInboundReceipt(receipt.id, outcome.code, availableAt, now());
6461
+ return { receiptId: receipt.id, outcome, state: "pending" };
6462
+ }
6463
+ await completeSlackInboundReceipt(receipt.id, {
6464
+ state: outcome.state,
6465
+ outcomeCode: outcome.state === "processed" || outcome.state === "ignored" ? outcome.code : null,
6466
+ errorCode: outcome.state === "failed" || outcome.state === "uncertain" ? outcome.code : null
6467
+ }, now());
6468
+ return { receiptId: receipt.id, outcome, state: outcome.state };
6469
+ }
6470
+ var defaultTimer = (fn, delayMs) => {
6471
+ const handle = setTimeout(fn, delayMs);
6472
+ handle.unref?.();
6473
+ return () => clearTimeout(handle);
6474
+ };
6475
+ var MIN_REARM_MS = 250;
6476
+ function createSlackInboundDrain(processor, options = {}) {
6477
+ const maxPerPass = options.maxPerPass ?? 50;
6478
+ const now = options.now ?? (() => new Date);
6479
+ const setTimer = options.setTimer ?? defaultTimer;
6480
+ let running = null;
6481
+ let again = false;
6482
+ let stopped = false;
6483
+ let cancelTimer = null;
6484
+ const clearTimer = () => {
6485
+ cancelTimer?.();
6486
+ cancelTimer = null;
6487
+ };
6488
+ const pass = async () => {
6489
+ for (let i = 0;i < maxPerPass; i++) {
6490
+ const result = await processNextSlackInboundReceipt(processor, {
6491
+ now,
6492
+ requireBoltDispatch: options.requireBoltDispatch
6493
+ });
6494
+ if (!result)
6495
+ return;
6496
+ }
6497
+ };
6498
+ const armRetryTimer = async () => {
6499
+ const next = await getNextSlackInboundAvailableAt();
6500
+ if (!next || stopped)
6501
+ return;
6502
+ const delayMs = Math.max(next.getTime() - now().getTime(), MIN_REARM_MS);
6503
+ cancelTimer = setTimer(() => {
6504
+ cancelTimer = null;
6505
+ drain.wake();
6506
+ }, delayMs);
6507
+ };
6508
+ const loop = async () => {
6509
+ do {
6510
+ again = false;
6511
+ clearTimer();
6512
+ try {
6513
+ await pass();
6514
+ } catch (error) {
6515
+ console.error("[Slack] inbound drain pass failed:", scrubSecrets(String(error)));
6516
+ return;
6517
+ }
6518
+ if (again)
6519
+ continue;
6520
+ try {
6521
+ await armRetryTimer();
6522
+ } catch (error) {
6523
+ console.error("[Slack] inbound drain could not arm retry:", scrubSecrets(String(error)));
6524
+ }
6525
+ } while (again);
6526
+ };
6527
+ const drain = {
6528
+ wake() {
6529
+ if (stopped)
6530
+ return Promise.resolve();
6531
+ if (running) {
6532
+ again = true;
6533
+ return running;
6534
+ }
6535
+ running = loop().finally(() => {
6536
+ running = null;
6537
+ });
6538
+ return running;
6539
+ },
6540
+ stop() {
6541
+ stopped = true;
6542
+ clearTimer();
6543
+ }
6544
+ };
6545
+ return drain;
6546
+ }
6547
+ async function recoverSlackInboundAfterRestart(now = new Date) {
6548
+ const interrupted = await markInterruptedSlackInboundReceiptsUncertain(now);
6549
+ if (interrupted > 0) {
6550
+ console.warn(`[Slack] ${interrupted} inbound receipt(s) were interrupted mid-processing and are now uncertain`);
6551
+ }
6552
+ return interrupted;
6553
+ }
6169
6554
  async function getSlackInboundDiagnostics() {
6170
6555
  const config = getSlackConfiguration();
6171
6556
  return {
@@ -6180,6 +6565,117 @@ async function getSlackInboundDiagnostics() {
6180
6565
  };
6181
6566
  }
6182
6567
 
6568
+ // src/slack/socket-ack.ts
6569
+ var NOT_READY_MESSAGE = "Failed to send a WebSocket message as the client is not ready";
6570
+ function isSocketNotReadyError(error) {
6571
+ return error instanceof Error && error.message === NOT_READY_MESSAGE;
6572
+ }
6573
+ var ORDER_DEPENDENT_EVENTS = new Set(["assistant_thread_context_changed"]);
6574
+ function isOrderDependentEvent(body) {
6575
+ const type = body?.event?.type;
6576
+ return typeof type === "string" && ORDER_DEPENDENT_EVENTS.has(type);
6577
+ }
6578
+ function tolerateSocketNotReadyAcks(client, options) {
6579
+ const emit = client.emit.bind(client);
6580
+ const deliver = (event, args) => emit(event, ...args);
6581
+ client.emit = (event, ...args) => {
6582
+ const payload = args[0];
6583
+ if (event !== "slack_event" || payload?.type !== "events_api" || typeof payload.ack !== "function") {
6584
+ return deliver(event, args);
6585
+ }
6586
+ const ack = payload.ack;
6587
+ const envelope = payload.envelope_id ?? "unknown";
6588
+ payload.ack = async (response) => {
6589
+ try {
6590
+ await ack(response);
6591
+ } catch (error) {
6592
+ if (!isSocketNotReadyError(error))
6593
+ throw error;
6594
+ recordSlackSocketAckNotReady();
6595
+ const disposition = await dispose(payload, envelope);
6596
+ if (disposition === "drain") {
6597
+ options.onAdmitted();
6598
+ throw error;
6599
+ }
6600
+ if (disposition === "drop")
6601
+ throw error;
6602
+ console.warn(`[Slack] socket ack failed (client not ready), processing inline: envelope_id=${envelope}`);
6603
+ }
6604
+ };
6605
+ if (typeof payload.retry_num !== "number" || payload.retry_num < 1) {
6606
+ return deliver(event, args);
6607
+ }
6608
+ (async () => {
6609
+ let stored = false;
6610
+ try {
6611
+ stored = await isSlackSocketEventStored(payload.body);
6612
+ } catch (storeError) {
6613
+ console.warn("[Slack] could not check stored event key, processing:", storeError);
6614
+ }
6615
+ if (!stored) {
6616
+ deliver(event, args);
6617
+ return;
6618
+ }
6619
+ console.log(`[Slack] dropping redelivery of a stored event: envelope_id=${envelope}`);
6620
+ try {
6621
+ await ack();
6622
+ } catch (error) {
6623
+ console.warn("[Slack] ack of a dropped redelivery failed:", error);
6624
+ }
6625
+ })();
6626
+ return client.listenerCount(event) > 0;
6627
+ };
6628
+ }
6629
+ async function dispose(payload, envelope) {
6630
+ if (isOrderDependentEvent(payload.body)) {
6631
+ rememberInline(payload, envelope);
6632
+ return "inline";
6633
+ }
6634
+ try {
6635
+ const result = await admitSlackInbound({
6636
+ transport: "socket",
6637
+ kind: "event",
6638
+ rawBody: JSON.stringify(payload.body),
6639
+ body: payload.body,
6640
+ retryNum: payload.retry_num,
6641
+ retryReason: payload.retry_reason
6642
+ });
6643
+ if (result.status === "admitted" || result.status === "duplicate") {
6644
+ console.warn(`[Slack] socket ack failed (client not ready), event stored for the drain: envelope_id=${envelope}`);
6645
+ return "drain";
6646
+ }
6647
+ console.warn(`[Slack] could not store unacked event (${result.reason}): envelope_id=${envelope}`);
6648
+ } catch (storeError) {
6649
+ console.warn("[Slack] could not persist unacked event:", storeError);
6650
+ }
6651
+ return "inline";
6652
+ }
6653
+ async function rememberInline(payload, envelope) {
6654
+ try {
6655
+ const result = await recordSlackSocketEventRanInline(payload.body, {
6656
+ retryNum: payload.retry_num,
6657
+ retryReason: payload.retry_reason
6658
+ });
6659
+ if (result === "duplicate") {
6660
+ console.warn(`[Slack] inline event key was already stored: envelope_id=${envelope}`);
6661
+ }
6662
+ } catch (storeError) {
6663
+ console.warn("[Slack] could not remember unacked inline event:", storeError);
6664
+ }
6665
+ }
6666
+ function installSocketAckRecovery(client, app) {
6667
+ const drain = createSlackInboundDrain(async ({ receipt, rawBody }) => {
6668
+ await app.processEvent({
6669
+ body: JSON.parse(rawBody),
6670
+ ack: async () => {},
6671
+ retryNum: receipt.retryNum ?? undefined,
6672
+ retryReason: receipt.retryReason ?? undefined
6673
+ });
6674
+ }, { requireBoltDispatch: true });
6675
+ tolerateSocketNotReadyAcks(client, { onAdmitted: () => void drain.wake() });
6676
+ return drain;
6677
+ }
6678
+
6183
6679
  // src/slack/socket-mode-guard.ts
6184
6680
  init_env_flag();
6185
6681
  var SLACK_DEV_SOCKET_MODE_OPT_IN = "SLACK_ALLOW_DEV_SOCKET_MODE";
@@ -6240,7 +6736,7 @@ async function initOtel(serviceRole = process.env.AGENT_ROLE || "api") {
6240
6736
  return;
6241
6737
  initialized = true;
6242
6738
  try {
6243
- const impl = await import("./otel-impl-epet9j18.js");
6739
+ const impl = await import("./otel-impl-jerq8vz8.js");
6244
6740
  await impl.boot(serviceRole, {
6245
6741
  exportConsoleLogs: serviceRole === "api" && isApiLogExportEnabled()
6246
6742
  });
@@ -7616,7 +8112,7 @@ async function sendInlineTaskOutput(task) {
7616
8112
 
7617
8113
  `),
7618
8114
  username: getAgentDisplayName(agent),
7619
- icon_emoji: getAgentEmoji(agent),
8115
+ icon: getAgentSlackIcon(agent),
7620
8116
  blocks: batch.map((chunk) => ({
7621
8117
  type: "section",
7622
8118
  text: { type: "mrkdwn", text: chunk }
@@ -7669,7 +8165,7 @@ async function sendTaskResponse(task) {
7669
8165
  thread_ts: task.slackThreadTs,
7670
8166
  text: task.slackReplySent || i > 0 ? `${completedStatusIcon()} ${agentName} completed${i > 0 ? ` (continued ${i + 1}/${blockBatches.length})` : ""}` : body,
7671
8167
  username: getAgentDisplayName(agent),
7672
- icon_emoji: getAgentEmoji(agent),
8168
+ icon: getAgentSlackIcon(agent),
7673
8169
  blocks: blockBatches[i]
7674
8170
  });
7675
8171
  }
@@ -7681,7 +8177,7 @@ async function sendTaskResponse(task) {
7681
8177
  thread_ts: task.slackThreadTs,
7682
8178
  text: `Task failed: ${reason}`,
7683
8179
  username: getAgentDisplayName(agent),
7684
- icon_emoji: getAgentEmoji(agent),
8180
+ icon: getAgentSlackIcon(agent),
7685
8181
  blocks
7686
8182
  });
7687
8183
  } else if (task.status === "cancelled") {
@@ -7691,7 +8187,7 @@ async function sendTaskResponse(task) {
7691
8187
  thread_ts: task.slackThreadTs,
7692
8188
  text: "Task cancelled",
7693
8189
  username: getAgentDisplayName(agent),
7694
- icon_emoji: getAgentEmoji(agent),
8190
+ icon: getAgentSlackIcon(agent),
7695
8191
  blocks
7696
8192
  });
7697
8193
  }
@@ -7718,7 +8214,7 @@ async function sendProgressUpdate(task, progress) {
7718
8214
  thread_ts: task.slackThreadTs,
7719
8215
  text: progress,
7720
8216
  username: getAgentDisplayName(agent),
7721
- icon_emoji: getAgentEmoji(agent),
8217
+ icon: getAgentSlackIcon(agent),
7722
8218
  blocks
7723
8219
  });
7724
8220
  } catch (error) {
@@ -7809,7 +8305,7 @@ async function updateToFinal(task, messageTs) {
7809
8305
  thread_ts: task.slackThreadTs ?? messageTs,
7810
8306
  text: `${completedStatusIcon()} ${agentName} completed (continued ${i + 1}/${completionBlockBatches.length})`,
7811
8307
  username: getAgentDisplayName(agent),
7812
- icon_emoji: getAgentEmoji(agent),
8308
+ icon: getAgentSlackIcon(agent),
7813
8309
  blocks: completionBlockBatches[i]
7814
8310
  });
7815
8311
  }
@@ -7861,11 +8357,20 @@ async function sendWithPersona(client, options) {
7861
8357
  unfurl_links: false,
7862
8358
  unfurl_media: false,
7863
8359
  username: options.username,
7864
- icon_emoji: options.icon_emoji,
8360
+ ...options.icon,
7865
8361
  blocks
7866
8362
  });
7867
8363
  return result.ts;
7868
8364
  }
8365
+ function getAgentSlackIcon(agent) {
8366
+ if (agent.slackIcon?.type === "url")
8367
+ return { icon_url: agent.slackIcon.url };
8368
+ if (agent.slackIcon?.type === "emoji")
8369
+ return { icon_emoji: agent.slackIcon.emoji };
8370
+ if (agent.slackIcon?.type === "app")
8371
+ return {};
8372
+ return { icon_emoji: getAgentEmoji(agent) };
8373
+ }
7869
8374
  function getAgentEmoji(agent) {
7870
8375
  if (agent.isLead)
7871
8376
  return ":crown:";
@@ -8620,7 +9125,7 @@ async function createThreadTree(task) {
8620
9125
  blocks: treeBlocks(text),
8621
9126
  unfurl_links: false,
8622
9127
  unfurl_media: false,
8623
- ...agent ? { username: getAgentDisplayName(agent), icon_emoji: getAgentEmoji(agent) } : {},
9128
+ ...agent ? { username: getAgentDisplayName(agent), ...getAgentSlackIcon(agent) } : {},
8624
9129
  metadata: {
8625
9130
  event_type: SLACK_RENDER_METADATA_EVENT,
8626
9131
  event_payload: { message_id: reservation.id, kind: "tree" }
@@ -9035,10 +9540,8 @@ async function streamOutcomeCard(task, tree, options) {
9035
9540
  markdown_text: presentation
9036
9541
  };
9037
9542
  const agent = task.agentId ? await getAgentById2(task.agentId) : undefined;
9038
- if (agent) {
9039
- startPayload.username = getAgentDisplayName(agent);
9040
- startPayload.icon_emoji = getAgentEmoji(agent);
9041
- }
9543
+ const persona = agent ? { username: getAgentDisplayName(agent), ...getAgentSlackIcon(agent) } : {};
9544
+ Object.assign(startPayload, persona);
9042
9545
  if (!task.slackChannelId.startsWith("D") && task.slackUserId) {
9043
9546
  const teamId = await slackTeamId(app.client);
9044
9547
  if (teamId) {
@@ -9081,8 +9584,7 @@ async function streamOutcomeCard(task, tree, options) {
9081
9584
  thread_ts: task.slackThreadTs,
9082
9585
  text: presentation,
9083
9586
  blocks: [{ type: "markdown", text: presentation }, ...captions],
9084
- ...startPayload.username ? { username: startPayload.username } : {},
9085
- ...startPayload.icon_emoji ? { icon_emoji: startPayload.icon_emoji } : {}
9587
+ ...persona
9086
9588
  });
9087
9589
  deliveredViaFallback = true;
9088
9590
  }
@@ -9721,7 +10223,7 @@ async function postInitialDMTreeMessage(task) {
9721
10223
  unfurl_links: false,
9722
10224
  unfurl_media: false,
9723
10225
  username: getAgentDisplayName(agent),
9724
- icon_emoji: getAgentEmoji(agent),
10226
+ ...getAgentSlackIcon(agent),
9725
10227
  blocks
9726
10228
  });
9727
10229
  if (result.ts) {
@@ -10018,6 +10520,7 @@ function stopTaskWatcher() {
10018
10520
  var app = null;
10019
10521
  var receiver = null;
10020
10522
  var initialized2 = false;
10523
+ var inboundDrain = null;
10021
10524
  var SOCKET_EVENT_STATES = {
10022
10525
  connecting: "connecting",
10023
10526
  reconnecting: "connecting",
@@ -10083,19 +10586,20 @@ async function initSlackApp2() {
10083
10586
  logLevel,
10084
10587
  ...clientOptions ? { clientOptions } : {}
10085
10588
  });
10589
+ inboundDrain = installSocketAckRecovery(receiver.client, app);
10086
10590
  initialized2 = true;
10087
10591
  app.use(slackInboundOutcomeMiddleware());
10088
- const { registerMessageHandler } = await import("./handlers-7x8sywgr.js");
10089
- const { registerCommandHandler } = await import("./commands-nw1dn4av.js");
10090
- const { registerActionHandlers } = await import("./actions-rd9xn281.js");
10091
- const { registerWorkObjectHandlers } = await import("./work-objects-ftj4zw70.js");
10592
+ const { registerMessageHandler } = await import("./handlers-ss5948rq.js");
10593
+ const { registerCommandHandler } = await import("./commands-hwdhacfx.js");
10594
+ const { registerActionHandlers } = await import("./actions-a90cfpca.js");
10595
+ const { registerWorkObjectHandlers } = await import("./work-objects-x7rb53qn.js");
10092
10596
  registerMessageHandler(app);
10093
10597
  registerCommandHandler(app);
10094
10598
  registerActionHandlers(app);
10095
10599
  registerWorkObjectHandlers(app);
10096
- const { createAssistant } = await import("./assistant-6jbzs8wa.js");
10600
+ const { createAssistant } = await import("./assistant-ck01q2yg.js");
10097
10601
  app.assistant(createAssistant());
10098
- const { isBlockExternalEnabled, scanExternalChannelsOnBoot } = await import("./external-channel-mf9vp1fe.js");
10602
+ const { isBlockExternalEnabled, scanExternalChannelsOnBoot } = await import("./external-channel-g6vv85zv.js");
10099
10603
  if (isBlockExternalEnabled()) {
10100
10604
  scanExternalChannelsOnBoot(app.client).catch((error) => {
10101
10605
  console.error("[Slack] External channel boot scan failed:", error);
@@ -10108,11 +10612,13 @@ async function startSlackApp2() {
10108
10612
  await initSlackApp2();
10109
10613
  }
10110
10614
  if (app) {
10111
- const { isSlackRenderV2Enabled } = await import("./render-v2-cy8zsfsf.js");
10615
+ const { isSlackRenderV2Enabled } = await import("./render-v2-65x4ayj8.js");
10112
10616
  if (isSlackRenderV2Enabled())
10113
10617
  await ensureSlackRenderV2Activation2();
10618
+ await recoverSlackInboundAfterRestart();
10114
10619
  await app.start();
10115
10620
  console.log("[Slack] Bot connected via Socket Mode");
10621
+ inboundDrain?.wake();
10116
10622
  await emitBuiltInIntegrationConnectedOnce2("slack");
10117
10623
  await startTaskWatcher();
10118
10624
  return true;
@@ -10121,6 +10627,8 @@ async function startSlackApp2() {
10121
10627
  }
10122
10628
  async function stopSlackApp2() {
10123
10629
  stopTaskWatcher();
10630
+ inboundDrain?.stop();
10631
+ inboundDrain = null;
10124
10632
  if (app) {
10125
10633
  await app.stop();
10126
10634
  app = null;
@@ -10131,4 +10639,4 @@ async function stopSlackApp2() {
10131
10639
  initialized2 = false;
10132
10640
  }
10133
10641
 
10134
- export { require_dist4, getSlackConnectionState, noteSlackInboundSideEffect, ignoreSlackInbound, reportSlackInboundFailure, isAdmittedSlackDelivery, getSlackInboundDiagnostics, terminalReactionEvent, isPollTracingEnabled, initOtel, withSpan2, startSpan2, withSpanContext2, withRemoteContext2, injectTraceContext2, recordSessionCost2, recordDbRetentionSweep2, recordDbRetentionStatement2, slackTaskOutput, ackSlackMessage, getTaskLink, getTaskUrl, markdownToSlack, buildMrkdwnSectionBlocks, buildCaptionBlock, buildCancelledBlocks, buildBufferFlushBlocks, buildTreeBlocks, taskCitationIssues, stripInvalidTaskCitations, taskCitationSourceGroups, renderTaskCitations, taskCitationWarnings, MAX_TASK_CITATIONS, CitationInputSchema, TaskCitationSchema, upsertTaskCitations, getTaskCitations, getTaskCitationsForTasks, hasTaskCitationCheckRefusal, initialize, ensure, getAgentDisplayName, getAgentEmoji, markSlackSessionProcessing, isSlackRenderV2Enabled2, callSlackWithRetry2, ensureSlackThreadTree2, slackErrorCode2, processSlackRenderV22, registerTreeMessage, getSlackApp2, initSlackApp2, startSlackApp2, stopSlackApp2 };
10642
+ export { require_dist4, getSlackConnectionState, noteSlackInboundSideEffect, ignoreSlackInbound, reportSlackInboundFailure, isAdmittedSlackDelivery, getSlackInboundDiagnostics, terminalReactionEvent, isPollTracingEnabled, initOtel, withSpan2, startSpan2, withSpanContext2, withRemoteContext2, injectTraceContext2, recordSessionCost2, recordDbRetentionSweep2, recordDbRetentionStatement2, slackTaskOutput, ackSlackMessage, getTaskLink, getTaskUrl, markdownToSlack, buildMrkdwnSectionBlocks, buildCaptionBlock, buildCancelledBlocks, buildBufferFlushBlocks, buildTreeBlocks, taskCitationIssues, stripInvalidTaskCitations, taskCitationSourceGroups, renderTaskCitations, taskCitationWarnings, MAX_TASK_CITATIONS, CitationInputSchema, TaskCitationSchema, upsertTaskCitations, getTaskCitations, getTaskCitationsForTasks, hasTaskCitationCheckRefusal, initialize, ensure, getAgentDisplayName, getAgentSlackIcon, markSlackSessionProcessing, isSlackRenderV2Enabled2, callSlackWithRetry2, ensureSlackThreadTree2, slackErrorCode2, processSlackRenderV22, registerTreeMessage, getSlackApp2, initSlackApp2, startSlackApp2, stopSlackApp2 };