@desplega.ai/agent-swarm 1.145.0 → 1.147.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 (221) hide show
  1. package/README.md +2 -1
  2. package/dist/{acp-adapter-580t41c0.js → acp-adapter-9n319wqc.js} +61 -6
  3. package/dist/{actions-m662tjng.js → actions-2vxqvpr9.js} +9 -8
  4. package/dist/{app-zb3rndm8.js → app-w066xfy0.js} +6 -5
  5. package/dist/assistant-kt31dj2h.js +236 -0
  6. package/dist/{boot-reembed-072x00vn.js → boot-reembed-az5rassp.js} +7 -6
  7. package/dist/{boot-reembed-65zz2smt.js → boot-reembed-j3mm3rfz.js} +8 -7
  8. package/dist/{boot-scrub-logs-yz0ams04.js → boot-scrub-logs-b6h54817.js} +4 -4
  9. package/dist/{claude-adapter-paj270y2.js → claude-adapter-w1z04ann.js} +8 -6
  10. package/dist/{claude-managed-setup-w619jncn.js → claude-managed-setup-f5pmsyrp.js} +24 -3
  11. package/dist/{claude-sdk-session-swt80j9z.js → claude-sdk-session-f0cc1kec.js} +8 -6
  12. package/dist/{cli-dt553ktb.js → cli-0b6y7kxm.js} +1 -1
  13. package/dist/{cli-bxdhw615.js → cli-12fz972k.js} +4 -4
  14. package/dist/{cli-s2f20r5w.js → cli-1th1728g.js} +2 -2
  15. package/dist/{cli-rs6ec3b9.js → cli-3tgwnf43.js} +3 -3
  16. package/dist/{cli-gxnzc6wh.js → cli-4nr988h6.js} +1 -1
  17. package/dist/{cli-axs8e6d4.js → cli-53s590z8.js} +1 -1
  18. package/dist/{cli-ygbjp3z8.js → cli-54wwve05.js} +5 -4
  19. package/dist/{cli-v0asr5yv.js → cli-719k9j2c.js} +2 -2
  20. package/dist/{cli-anktweqr.js → cli-89xfd7f9.js} +21 -47
  21. package/dist/{cli-q34a0e10.js → cli-8v0g1yc8.js} +1 -1
  22. package/dist/cli-9d8ntetj.js +42 -0
  23. package/dist/{cli-z9fprcrf.js → cli-atcve9y8.js} +881 -738
  24. package/dist/{cli-jmb7g47h.js → cli-b5bq9crk.js} +14 -31
  25. package/dist/cli-d8brzxjb.js +190 -0
  26. package/dist/{cli-gzky0gkr.js → cli-de14znh8.js} +2 -2
  27. package/dist/{cli-xytwff7f.js → cli-dttph1bw.js} +2 -2
  28. package/dist/cli-ep19k3mb.js +19 -0
  29. package/dist/{cli-m1xa8be7.js → cli-f146mn5s.js} +7 -50
  30. package/dist/{cli-1fj0chdk.js → cli-f7dsy61y.js} +5 -3
  31. package/dist/{cli-f567d5c1.js → cli-ftht3zzj.js} +2782 -2589
  32. package/dist/{cli-a0g1gbt5.js → cli-hbv0kq6w.js} +2 -2
  33. package/dist/{cli-fhsz3twr.js → cli-jsp14b6c.js} +171 -1
  34. package/dist/{cli-7fnkj1hj.js → cli-kpv03zhj.js} +21 -17
  35. package/dist/{cli-m4j6trn4.js → cli-m8yrsg97.js} +2 -2
  36. package/dist/cli-m9sxbkhm.js +779 -0
  37. package/dist/cli-mmemxxdc.js +823 -0
  38. package/dist/{cli-tqtvj5pt.js → cli-n8508nre.js} +1 -1
  39. package/dist/{cli-z96t0thj.js → cli-p1d5b073.js} +37 -2
  40. package/dist/{cli-gh8y8f36.js → cli-rw51bq3j.js} +13 -10
  41. package/dist/{cli-59ej1c07.js → cli-smby5m17.js} +7 -6
  42. package/dist/{cli-65vqzz3v.js → cli-tzvk9haz.js} +94 -372
  43. package/dist/{cli-dc9k2ba9.js → cli-w9kb3bk1.js} +1 -1
  44. package/dist/{cli-kpev657q.js → cli-y6b6fb76.js} +25 -3
  45. package/dist/{cli-123q2get.js → cli-yz3djrm0.js} +9 -9
  46. package/dist/{cli-wvp6bvy4.js → cli-zhjmqxzh.js} +1 -1
  47. package/dist/cli.js +13 -13
  48. package/dist/{codex-adapter-k98vaw2r.js → codex-adapter-zw4dwsx7.js} +2 -2
  49. package/dist/{codex-hook-9pf19cks.js → codex-hook-bw8p5nh4.js} +2 -2
  50. package/dist/{codex-session-runner-tngtphx7.js → codex-session-runner-k981s65v.js} +2 -2
  51. package/dist/{commands-y8nbr3fv.js → commands-sykrxx7e.js} +4 -4
  52. package/dist/{db-30p4h2t1.js → db-sfbsc8wt.js} +6 -4
  53. package/dist/handlers-0aspcejm.js +603 -0
  54. package/dist/{hook-dcw4jfbj.js → hook-4nvqj2sb.js} +7 -5
  55. package/dist/{hook-21jexvfx.js → hook-hxccs7m5.js} +24 -49
  56. package/dist/{http-r4kq5g8d.js → http-y06z517d.js} +230 -94
  57. package/dist/{index-q3qja6ta.js → index-hssww7kj.js} +15 -14
  58. package/dist/{index-gay66b9w.js → index-k8znfx0z.js} +13 -12
  59. package/dist/{index-53zyht4z.js → index-tce1rss4.js} +371 -110
  60. package/dist/{index-nqvf26za.js → index-x5j894zf.js} +14 -13
  61. package/dist/{keepalive-xs8fa55y.js → keepalive-w733ax66.js} +6 -6
  62. package/dist/{lead-d9m2t4s0.js → lead-75bjqa9d.js} +29 -27
  63. package/dist/{maintenance-3zh82g6z.js → maintenance-w4f1zjck.js} +8 -7
  64. package/dist/{oauth-refresh-sweep-03snsye5.js → oauth-refresh-sweep-wdetky26.js} +5 -5
  65. package/dist/{onboard-0cg1925x.js → onboard-bb5net8s.js} +2 -2
  66. package/dist/{otel-impl-0ab95z27.js → otel-impl-0w7c14ap.js} +1 -1
  67. package/dist/{pi-mono-adapter-dtkz4e7j.js → pi-mono-adapter-2has4gnp.js} +12 -2
  68. package/dist/{pricing-refresh-e5jhzz4j.js → pricing-refresh-9nzsrgcq.js} +6 -6
  69. package/dist/{rbac-roles-p1mf40z3.js → rbac-roles-r3hqjp09.js} +5 -5
  70. package/dist/{rbac-roles-2w3cmrkc.js → rbac-roles-z1jrffbt.js} +4 -4
  71. package/dist/{registry-9kdck5ye.js → registry-v5wytg0s.js} +1 -2
  72. package/dist/{render-v2-xhawry3k.js → render-v2-vbr89fnb.js} +6 -5
  73. package/dist/{seed-pricing-t223sw91.js → seed-pricing-g62hy1pk.js} +7 -5
  74. package/dist/{setup-zcs0rce7.js → setup-gnfqnptp.js} +2 -2
  75. package/dist/{worker-qnp2ka62.js → worker-kznxp4qm.js} +29 -27
  76. package/openapi.json +263 -12
  77. package/package.json +1 -1
  78. package/plugin/commands/start-worker.md +4 -9
  79. package/plugin/pi-skills/start-worker/SKILL.md +4 -9
  80. package/src/be/db/agents.ts +556 -0
  81. package/src/be/db/context-versions.ts +117 -0
  82. package/src/be/db/runtime.ts +406 -0
  83. package/src/be/db/tasks/read.ts +1167 -0
  84. package/src/be/db/tasks/write.ts +953 -0
  85. package/src/be/db.ts +584 -3429
  86. package/src/be/migrations/147_scheduled_tasks_parent_task.sql +7 -0
  87. package/src/be/migrations/148_pages_svg.sql +123 -0
  88. package/src/be/migrations/149_session_tokens.sql +24 -0
  89. package/src/be/scripts/typecheck.ts +1 -0
  90. package/src/be/seed-pricing.ts +13 -8
  91. package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
  92. package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
  93. package/src/be/seed-scripts/catalog/star-history-refresh.ts +101 -0
  94. package/src/be/seed-scripts/catalog/star-history-renderer.ts +119 -0
  95. package/src/be/seed-scripts/index.ts +17 -0
  96. package/src/be/seed-skills/index.ts +14 -0
  97. package/src/be/swarm-config-guard.ts +5 -2
  98. package/src/be/task-attachment-store.ts +70 -0
  99. package/src/be/users.ts +77 -0
  100. package/src/commands/attachments-section.ts +37 -0
  101. package/src/commands/claude-managed-setup.ts +45 -3
  102. package/src/commands/claude-md-session.ts +408 -0
  103. package/src/commands/context-preamble.ts +15 -3
  104. package/src/commands/profile-sync.ts +205 -5
  105. package/src/commands/provider-credentials.ts +60 -27
  106. package/src/commands/runner.ts +63 -58
  107. package/src/commands/templates.ts +25 -2
  108. package/src/hooks/hook.ts +26 -67
  109. package/src/http/agents.ts +40 -1
  110. package/src/http/auth.ts +13 -1
  111. package/src/http/fs.ts +21 -51
  112. package/src/http/index.ts +2 -0
  113. package/src/http/mcp.ts +32 -0
  114. package/src/http/pages-public.ts +20 -4
  115. package/src/http/pages.ts +11 -3
  116. package/src/http/poll.ts +4 -0
  117. package/src/http/repos.ts +3 -3
  118. package/src/http/sessions.ts +82 -0
  119. package/src/http/tasks.ts +10 -2
  120. package/src/http/utils.ts +79 -1
  121. package/src/prompts/session-templates.ts +12 -8
  122. package/src/providers/acp-adapter.ts +62 -8
  123. package/src/providers/pi-mono-adapter.ts +23 -6
  124. package/src/providers/pricing-sources.md +11 -0
  125. package/src/scheduler/scheduler.test.ts +49 -2
  126. package/src/scheduler/scheduler.ts +4 -0
  127. package/src/scripts-runtime/sdk-allowlist.ts +1 -0
  128. package/src/scripts-runtime/types/stdlib.d.ts +8 -0
  129. package/src/scripts-runtime/types/swarm-sdk.d.ts +8 -0
  130. package/src/server.ts +2 -0
  131. package/src/slack/assistant.ts +87 -46
  132. package/src/slack/handlers.test.ts +1 -3
  133. package/src/slack/handlers.ts +102 -87
  134. package/src/slack/inbound-files.ts +466 -0
  135. package/src/slack/templates.ts +14 -0
  136. package/src/tasks/task-terminal-effects.ts +158 -0
  137. package/src/tests/acp-adapter.test.ts +369 -117
  138. package/src/tests/budget-claim-gate.test.ts +1 -0
  139. package/src/tests/build-pi-skills.test.ts +5 -7
  140. package/src/tests/claude-managed-setup.test.ts +52 -4
  141. package/src/tests/claude-md-session.test.ts +603 -0
  142. package/src/tests/codex-skill-resolver.test.ts +19 -0
  143. package/src/tests/context-versioning.test.ts +107 -0
  144. package/src/tests/cors-allowlist.test.ts +309 -0
  145. package/src/tests/credential-check.test.ts +157 -14
  146. package/src/tests/db-agents.test.ts +91 -0
  147. package/src/tests/db-context-versions.test.ts +37 -0
  148. package/src/tests/db-extraction-contract.test.ts +45 -0
  149. package/src/tests/db-runtime.test.ts +70 -0
  150. package/src/tests/db-task-read-contract.test.ts +624 -0
  151. package/src/tests/db-task-write-contract.test.ts +653 -0
  152. package/src/tests/db-tasks-read.test.ts +183 -0
  153. package/src/tests/db-tasks-write.test.ts +230 -0
  154. package/src/tests/defer-task.test.ts +389 -0
  155. package/src/tests/docs-index-footprint.test.js +2 -2
  156. package/src/tests/e2e-visuals-stage.test.ts +151 -0
  157. package/src/tests/file-lock.test.ts +144 -0
  158. package/src/tests/fixtures/file-lock-holder.ts +13 -0
  159. package/src/tests/fixtures/hold-file-lock.ts +25 -0
  160. package/src/tests/heartbeat-expiry.test.ts +188 -0
  161. package/src/tests/http-api-integration.test.ts +78 -1
  162. package/src/tests/pages-public-html.test.ts +43 -0
  163. package/src/tests/pages-svg-migration.test.ts +42 -0
  164. package/src/tests/preload.ts +4 -1
  165. package/src/tests/profile-sync-warning.test.ts +16 -0
  166. package/src/tests/profile-sync.test.ts +126 -0
  167. package/src/tests/prompt-template-session.test.ts +20 -4
  168. package/src/tests/provider-registration.test.ts +93 -0
  169. package/src/tests/rbac-e2e-helpers.test.ts +53 -0
  170. package/src/tests/rbac-e2e-helpers.ts +19 -2
  171. package/src/tests/reload-config.test.ts +26 -0
  172. package/src/tests/routing-affinity-inventory.test.ts +1 -1
  173. package/src/tests/runner-attachments-section.test.ts +22 -2
  174. package/src/tests/runner-context-preamble.test.ts +30 -0
  175. package/src/tests/runner-deployment-resume.test.ts +107 -0
  176. package/src/tests/runner-repo-autostash.test.ts +12 -0
  177. package/src/tests/script-connections.test.ts +4 -0
  178. package/src/tests/seed-scripts.test.ts +2 -2
  179. package/src/tests/session-tokens.test.ts +279 -0
  180. package/src/tests/slack-file-tools-attachments.test.ts +408 -0
  181. package/src/tests/slack-inbound-files.test.ts +847 -0
  182. package/src/tests/star-history-refresh.test.ts +102 -0
  183. package/src/tests/swarm-config-reserved-keys.test.ts +21 -0
  184. package/src/tests/swarm-repos.test.ts +20 -0
  185. package/src/tests/tool-annotations.test.ts +4 -3
  186. package/src/tests/ui-logs-parser.test.ts +176 -0
  187. package/src/tools/create-page.ts +4 -2
  188. package/src/tools/defer-task.ts +239 -0
  189. package/src/tools/repos/update-repo.ts +2 -2
  190. package/src/tools/schedules/create-schedule.ts +1 -0
  191. package/src/tools/schedules/list-schedules.ts +1 -0
  192. package/src/tools/schedules/patch-schedule.ts +1 -0
  193. package/src/tools/schedules/update-schedule.ts +1 -0
  194. package/src/tools/slack-download-file.ts +60 -29
  195. package/src/tools/slack-read.ts +73 -32
  196. package/src/tools/store-progress.ts +16 -146
  197. package/src/tools/tool-config.ts +1 -0
  198. package/src/tools/utils.ts +21 -0
  199. package/src/types.ts +37 -4
  200. package/src/utils/acp-session-token.ts +56 -0
  201. package/src/utils/file-lock.ts +111 -0
  202. package/src/utils/heartbeat-expiry.ts +78 -0
  203. package/src/utils/request-auth-context.ts +2 -0
  204. package/src/utils/task-attachment-links.ts +22 -0
  205. package/templates/skills/code-quality/content.md +8 -5
  206. package/templates/skills/download-task-attachment/content.md +2 -1
  207. package/{plugin/pi-skills → templates/skills}/review-offered-task/SKILL.md +5 -5
  208. package/templates/skills/review-offered-task/config.json +14 -0
  209. package/{plugin/commands/review-offered-task.md → templates/skills/review-offered-task/content.md} +3 -8
  210. package/templates/skills/scheduling/content.md +4 -0
  211. package/templates/skills/slack-interaction/content.md +2 -2
  212. package/templates/skills/work-on-task/SKILL.md +16 -0
  213. package/templates/skills/work-on-task/config.json +14 -0
  214. package/templates/skills/work-on-task/content.md +11 -0
  215. package/dist/assistant-0qt42nzg.js +0 -212
  216. package/dist/cli-fs1kkqgr.js +0 -317
  217. package/dist/cli-jnf5zghe.js +0 -269
  218. package/dist/cli-n1q8q14d.js +0 -177
  219. package/dist/handlers-yfp1qn81.js +0 -592
  220. package/plugin/commands/work-on-task.md +0 -39
  221. package/plugin/pi-skills/work-on-task/SKILL.md +0 -39
@@ -1,269 +0,0 @@
1
- import {
2
- getAgentById,
3
- getAgentWorkingOnThread,
4
- getAllAgents,
5
- init_db
6
- } from "./cli-f567d5c1.js";
7
- import {
8
- init_env_flag,
9
- isEnvFlagEnabled
10
- } from "./cli-ej6gbxfb.js";
11
-
12
- // src/slack/router.ts
13
- init_db();
14
- init_env_flag();
15
- function hasOtherUserMention(text, botUserId) {
16
- const mentions = text.match(/<@([A-Z0-9]+)>/g) ?? [];
17
- return mentions.some((m) => m !== `<@${botUserId}>`);
18
- }
19
- async function routeMessage(text, botUserId, botMentioned, threadContext) {
20
- const matches = [];
21
- const requireMentionForThreadFollowup = isEnvFlagEnabled("SLACK_THREAD_FOLLOWUP_REQUIRE_MENTION", false);
22
- const agents = (await getAllAgents()).filter((a) => a.status !== "offline");
23
- const idMatches = text.matchAll(/swarm#([a-f0-9-]{36})/gi);
24
- for (const match of idMatches) {
25
- const agentId = match[1];
26
- if (!agentId)
27
- continue;
28
- const agent = await getAgentById(agentId);
29
- if (agent && agent.status !== "offline") {
30
- matches.push({ agent, matchedText: match[0] });
31
- }
32
- }
33
- if (/swarm#all/i.test(text)) {
34
- const nonLeadAgents = agents.filter((a) => !a.isLead);
35
- for (const agent of nonLeadAgents) {
36
- if (!matches.some((m) => m.agent.id === agent.id)) {
37
- matches.push({ agent, matchedText: "swarm#all" });
38
- }
39
- }
40
- }
41
- if (matches.length === 0 && threadContext && (!requireMentionForThreadFollowup || botMentioned)) {
42
- if (!botMentioned && hasOtherUserMention(text, botUserId)) {
43
- console.log(`[Slack] Skipping thread follow-up in ${threadContext.channelId}/${threadContext.threadTs}: message mentions another user`);
44
- return matches;
45
- }
46
- const workingAgent = await getAgentWorkingOnThread(threadContext.channelId, threadContext.threadTs);
47
- if (workingAgent && workingAgent.status !== "offline") {
48
- console.log(`[Slack] Thread follow-up: routing to agent ${workingAgent.name} (${workingAgent.id}) in thread ${threadContext.threadTs}`);
49
- matches.push({ agent: workingAgent, matchedText: "thread follow-up" });
50
- } else if (workingAgent) {
51
- console.log(`[Slack] Thread follow-up: agent ${workingAgent.name} is offline, routing to lead`);
52
- const allAgents = await getAllAgents();
53
- const lead = allAgents.find((a) => a.isLead && a.status !== "offline");
54
- if (lead) {
55
- matches.push({ agent: lead, matchedText: "thread follow-up (lead fallback)" });
56
- }
57
- }
58
- }
59
- if (matches.length === 0 && botMentioned) {
60
- const lead = agents.find((a) => a.isLead);
61
- if (lead) {
62
- matches.push({ agent: lead, matchedText: "@bot" });
63
- }
64
- }
65
- return matches;
66
- }
67
- function extractTaskFromMessage(text, botUserId) {
68
- return text.replace(new RegExp(`<@${botUserId}>`, "g"), "").replace(/swarm#[a-f0-9-]{36}/gi, "").replace(/swarm#all/gi, "").trim();
69
- }
70
-
71
- // src/slack/message-text.ts
72
- function collectRichTextParts(node, parts) {
73
- if (node == null || typeof node !== "object")
74
- return;
75
- const n = node;
76
- if (n.type === "text" && n.text) {
77
- parts.push(n.text);
78
- }
79
- if (Array.isArray(n.elements)) {
80
- for (const child of n.elements) {
81
- collectRichTextParts(child, parts);
82
- }
83
- }
84
- }
85
- function extractSlackMessageText(msg) {
86
- const topText = msg.text?.trim() ?? "";
87
- const attachmentParts = [];
88
- if (Array.isArray(msg.attachments) && msg.attachments.length > 0) {
89
- for (const raw of msg.attachments) {
90
- if (raw == null || typeof raw !== "object")
91
- continue;
92
- const a = raw;
93
- const attParts = [];
94
- const titleText = a.title_link && a.title ? `<${a.title_link}|${a.title}>` : a.title;
95
- const seenPrimary = new Set;
96
- for (const part of [a.pretext, titleText, a.text, a.fallback]) {
97
- const s = part?.trim();
98
- if (s && !seenPrimary.has(s)) {
99
- seenPrimary.add(s);
100
- attParts.push(s);
101
- }
102
- }
103
- if (Array.isArray(a.fields)) {
104
- for (const field of a.fields) {
105
- if (field == null || typeof field !== "object")
106
- continue;
107
- const f = field;
108
- if (f.title && f.value)
109
- attParts.push(`${f.title}: ${f.value}`);
110
- else if (f.title)
111
- attParts.push(f.title);
112
- else if (f.value)
113
- attParts.push(f.value);
114
- }
115
- }
116
- if (Array.isArray(a.actions)) {
117
- for (const action of a.actions) {
118
- if (action == null || typeof action !== "object")
119
- continue;
120
- const act = action;
121
- if (act.url) {
122
- attParts.push(act.text ? `<${act.url}|${act.text}>` : act.url);
123
- }
124
- }
125
- }
126
- if (attParts.length > 0)
127
- attachmentParts.push(attParts.join(`
128
- `));
129
- }
130
- }
131
- const blockParts = [];
132
- if (Array.isArray(msg.blocks) && msg.blocks.length > 0) {
133
- for (const rawBlock of msg.blocks) {
134
- if (rawBlock == null || typeof rawBlock !== "object")
135
- continue;
136
- const block = rawBlock;
137
- if (block.type === "section") {
138
- if (block.text?.text)
139
- blockParts.push(block.text.text);
140
- if (Array.isArray(block.fields)) {
141
- for (const field of block.fields) {
142
- if (field != null && typeof field === "object" && field.text) {
143
- blockParts.push(field.text);
144
- }
145
- }
146
- }
147
- } else if (block.type === "rich_text" && Array.isArray(block.elements)) {
148
- for (const el of block.elements) {
149
- collectRichTextParts(el, blockParts);
150
- }
151
- } else if (block.type === "header") {
152
- if (block.text?.text)
153
- blockParts.push(block.text.text);
154
- } else if (block.type === "context" && Array.isArray(block.elements)) {
155
- for (const el of block.elements) {
156
- if (el == null || typeof el !== "object")
157
- continue;
158
- const e = el;
159
- if (e.text)
160
- blockParts.push(e.text);
161
- }
162
- } else if (block.type === "actions" && Array.isArray(block.elements)) {
163
- for (const el of block.elements) {
164
- if (el == null || typeof el !== "object")
165
- continue;
166
- const e = el;
167
- const label = e.text?.text;
168
- const url = e.url;
169
- if (label && url)
170
- blockParts.push(`<${url}|${label}>`);
171
- else if (label)
172
- blockParts.push(label);
173
- else if (url)
174
- blockParts.push(url);
175
- }
176
- }
177
- }
178
- }
179
- const bodyText = [...attachmentParts, ...blockParts].filter(Boolean).join(`
180
- `);
181
- const bodyLines = new Set(bodyText.split(`
182
- `).map((l) => l.trim()).filter(Boolean));
183
- if (topText && !bodyLines.has(topText)) {
184
- return bodyText ? `${topText}
185
- ${bodyText}` : topText;
186
- }
187
- return bodyText || topText;
188
- }
189
- function parseSlackTs(input) {
190
- const trimmed = input.trim();
191
- if (/^\d{6,}\.\d{1,}$/.test(trimmed))
192
- return trimmed;
193
- const m = trimmed.match(/p?(\d{10})(\d{6})(?:\D|$)/);
194
- if (m)
195
- return `${m[1]}.${m[2]}`;
196
- return trimmed;
197
- }
198
-
199
- // src/tasks/additive-buffer.ts
200
- function createAdditiveBuffer(options) {
201
- const { timeoutMs, onFlush, label } = options;
202
- if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
203
- throw new Error(`additive-buffer: timeoutMs must be a positive number, got ${timeoutMs}`);
204
- }
205
- const buffers = new Map;
206
- const prefix = label ? `[buffer:${label}]` : "[buffer]";
207
- function scheduleFlush(key) {
208
- return setTimeout(() => {
209
- doFlush(key, "timer");
210
- }, timeoutMs);
211
- }
212
- async function doFlush(key, reason) {
213
- const entry = buffers.get(key);
214
- if (!entry || entry.items.length === 0) {
215
- buffers.delete(key);
216
- return;
217
- }
218
- clearTimeout(entry.timer);
219
- buffers.delete(key);
220
- try {
221
- await onFlush(entry.items, key, reason);
222
- } catch (error) {
223
- console.error(`${prefix} onFlush threw for key=${key}:`, error);
224
- }
225
- }
226
- return {
227
- enqueue(contextKey, item) {
228
- if (!contextKey) {
229
- throw new Error("additive-buffer: contextKey is required");
230
- }
231
- const existing = buffers.get(contextKey);
232
- if (existing) {
233
- clearTimeout(existing.timer);
234
- existing.items.push(item);
235
- existing.timer = scheduleFlush(contextKey);
236
- console.log(`${prefix} append: ${contextKey} (${existing.items.length} items, timer reset to ${timeoutMs}ms)`);
237
- } else {
238
- const entry = {
239
- items: [item],
240
- timer: scheduleFlush(contextKey)
241
- };
242
- buffers.set(contextKey, entry);
243
- console.log(`${prefix} created: ${contextKey} (timer set to ${timeoutMs}ms)`);
244
- }
245
- },
246
- isBuffered(contextKey) {
247
- return buffers.has(contextKey);
248
- },
249
- count(contextKey) {
250
- return buffers.get(contextKey)?.items.length ?? 0;
251
- },
252
- instantFlush(contextKey) {
253
- return doFlush(contextKey, "manual");
254
- },
255
- cancel(contextKey) {
256
- const entry = buffers.get(contextKey);
257
- if (!entry)
258
- return false;
259
- clearTimeout(entry.timer);
260
- buffers.delete(contextKey);
261
- return true;
262
- },
263
- keys() {
264
- return Array.from(buffers.keys());
265
- }
266
- };
267
- }
268
-
269
- export { createAdditiveBuffer, hasOtherUserMention, routeMessage, extractTaskFromMessage, extractSlackMessageText, parseSlackTs };
@@ -1,177 +0,0 @@
1
- import {
2
- AgentFsProvider,
3
- FilesError,
4
- providerPath
5
- } from "./cli-fhsz3twr.js";
6
-
7
- // src/fs/local-fs-provider.ts
8
- import { mkdir, readdir, rm, stat } from "node:fs/promises";
9
- import { dirname, join, relative, sep } from "node:path";
10
- var DEFAULT_ROOT_DIR = "./data/fs";
11
-
12
- class LocalFsProvider {
13
- id = "local-fs";
14
- capabilities = {
15
- signedUrl: { supported: false }
16
- };
17
- rootDir;
18
- constructor(options = {}) {
19
- this.rootDir = options.rootDir ?? process.env.AGENT_FS_LOCAL_DIR ?? DEFAULT_ROOT_DIR;
20
- }
21
- async upload(scope, body, options = {}) {
22
- const target = this.localPath(scope);
23
- await mkdir(dirname(target), { recursive: true });
24
- if (options.ifNoneMatch === "*" && await this.exists(scope)) {
25
- throw new FilesError("Conflict", "File already exists");
26
- }
27
- await Bun.write(target, await new Response(body).arrayBuffer());
28
- if (options.contentType) {
29
- await Bun.write(this.metaPath(target), JSON.stringify({ contentType: options.contentType }));
30
- }
31
- return this.head(scope);
32
- }
33
- async download(scope) {
34
- const target = this.localPath(scope);
35
- if (!await this.exists(scope)) {
36
- throw new FilesError("NotFound", "File not found");
37
- }
38
- return new Response(Bun.file(target));
39
- }
40
- async head(scope) {
41
- const target = this.localPath(scope);
42
- try {
43
- const info = await stat(target);
44
- const storedContentType = await this.readStoredContentType(target);
45
- return {
46
- providerId: this.id,
47
- key: providerPath(scope),
48
- taskId: scope.taskId,
49
- name: scope.name,
50
- contentType: storedContentType ?? Bun.file(target).type ?? undefined,
51
- sizeBytes: info.size,
52
- updatedAt: info.mtime.toISOString()
53
- };
54
- } catch (error) {
55
- if (error.code === "ENOENT") {
56
- throw new FilesError("NotFound", "File not found", { cause: error });
57
- }
58
- throw new FilesError("Provider", "Unable to read file metadata", { cause: error });
59
- }
60
- }
61
- async exists(scope) {
62
- try {
63
- await stat(this.localPath(scope));
64
- return true;
65
- } catch (error) {
66
- if (error.code === "ENOENT") {
67
- return false;
68
- }
69
- throw new FilesError("Provider", "Unable to check file existence", { cause: error });
70
- }
71
- }
72
- async delete(scope) {
73
- const target = this.localPath(scope);
74
- await rm(target, { force: true });
75
- await rm(this.metaPath(target), { force: true });
76
- }
77
- async copy(source, destination) {
78
- const sourceHead = await this.head(source);
79
- const response = await this.download(source);
80
- await this.upload(destination, await response.arrayBuffer(), {
81
- contentType: sourceHead.contentType
82
- });
83
- return this.head(destination);
84
- }
85
- async move(source, destination) {
86
- const copied = await this.copy(source, destination);
87
- await this.delete(source);
88
- return copied;
89
- }
90
- async list(options) {
91
- const taskRoot = join(this.rootDir, "tasks", encodeURIComponent(options.taskId));
92
- const files = [];
93
- await this.walk(taskRoot, async (path) => {
94
- const rel = relative(taskRoot, path).split(sep).join("/");
95
- const name = decodePath(rel);
96
- if (options.prefix && !name.startsWith(options.prefix)) {
97
- return;
98
- }
99
- files.push(await this.head({ taskId: options.taskId, name }));
100
- });
101
- return typeof options.limit === "number" ? files.slice(0, options.limit) : files;
102
- }
103
- async* listAll(options) {
104
- for (const item of await this.list(options)) {
105
- yield item;
106
- }
107
- }
108
- async url(scope) {
109
- return `/api/fs/tasks/${encodeURIComponent(scope.taskId)}/files/${encodeURIComponent(scope.name)}/raw`;
110
- }
111
- async signedUploadUrl() {
112
- throw new FilesError("ReadOnly", "local-fs does not support signed upload URLs");
113
- }
114
- localPath(scope) {
115
- return join(this.rootDir, providerPath(scope));
116
- }
117
- metaPath(target) {
118
- return `${target}.meta.json`;
119
- }
120
- async readStoredContentType(target) {
121
- try {
122
- const metaFile = Bun.file(this.metaPath(target));
123
- if (!await metaFile.exists()) {
124
- return;
125
- }
126
- const meta = await metaFile.json();
127
- return typeof meta?.contentType === "string" ? meta.contentType : undefined;
128
- } catch {
129
- return;
130
- }
131
- }
132
- async walk(dir, visit) {
133
- let entries;
134
- try {
135
- entries = await readdir(dir, { withFileTypes: true });
136
- } catch (error) {
137
- if (error.code === "ENOENT") {
138
- return;
139
- }
140
- throw new FilesError("Provider", "Unable to list files", { cause: error });
141
- }
142
- for (const entry of entries) {
143
- const path = join(dir, entry.name);
144
- if (entry.isDirectory()) {
145
- await this.walk(path, visit);
146
- } else if (entry.isFile() && !entry.name.endsWith(".meta.json")) {
147
- await visit(path);
148
- }
149
- }
150
- }
151
- }
152
- function decodePath(path) {
153
- return path.split("/").map((part) => decodeURIComponent(part)).join("/");
154
- }
155
-
156
- // src/fs/registry.ts
157
- var memoizedProvider = null;
158
- function getFileStorageProvider() {
159
- if (!memoizedProvider) {
160
- memoizedProvider = selectProvider();
161
- }
162
- return memoizedProvider;
163
- }
164
- function selectProvider() {
165
- if (process.env.AGENT_FS_API_URL && (process.env.API_AGENT_FS_API_KEY || process.env.AGENT_FS_API_KEY)) {
166
- return new AgentFsProvider;
167
- }
168
- return new LocalFsProvider;
169
- }
170
- function resetFileStorageProvider() {
171
- memoizedProvider = null;
172
- }
173
- function resetFileStorageProviderForTests() {
174
- resetFileStorageProvider();
175
- }
176
-
177
- export { getFileStorageProvider, selectProvider, resetFileStorageProvider, resetFileStorageProviderForTests };