@desplega.ai/agent-swarm 1.20.0 → 1.51.2

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 (561) hide show
  1. package/README.md +271 -169
  2. package/openapi.json +5015 -0
  3. package/package.json +40 -7
  4. package/plugin/commands/close-issue.md +7 -3
  5. package/plugin/commands/create-pr.md +18 -12
  6. package/plugin/commands/implement-issue.md +7 -3
  7. package/plugin/commands/respond-github.md +8 -4
  8. package/plugin/commands/review-pr.md +44 -10
  9. package/plugin/commands/start-leader.md +1 -3
  10. package/plugin/commands/start-worker.md +1 -3
  11. package/plugin/commands/work-on-task.md +22 -3
  12. package/plugin/pi-skills/close-issue/SKILL.md +90 -0
  13. package/plugin/pi-skills/create-pr/SKILL.md +99 -0
  14. package/plugin/pi-skills/implement-issue/SKILL.md +135 -0
  15. package/plugin/pi-skills/investigate-sentry-issue/SKILL.md +138 -0
  16. package/plugin/pi-skills/respond-github/SKILL.md +98 -0
  17. package/plugin/pi-skills/review-offered-task/SKILL.md +45 -0
  18. package/plugin/pi-skills/review-pr/SKILL.md +261 -0
  19. package/plugin/pi-skills/start-leader/SKILL.md +121 -0
  20. package/plugin/pi-skills/start-worker/SKILL.md +60 -0
  21. package/plugin/pi-skills/swarm-chat/SKILL.md +82 -0
  22. package/plugin/pi-skills/todos/SKILL.md +66 -0
  23. package/plugin/pi-skills/work-on-task/SKILL.md +65 -0
  24. package/plugin/skills/artifacts/examples/approval-flow.ts +34 -0
  25. package/plugin/skills/artifacts/examples/hono-dashboard.ts +31 -0
  26. package/plugin/skills/artifacts/examples/multi-artifact.ts +20 -0
  27. package/plugin/skills/artifacts/examples/static-report.sh +17 -0
  28. package/plugin/skills/artifacts/skill.md +71 -0
  29. package/src/agentmail/app.ts +65 -0
  30. package/src/agentmail/handlers.ts +262 -0
  31. package/src/agentmail/index.ts +9 -0
  32. package/src/agentmail/templates.ts +111 -0
  33. package/src/agentmail/types.ts +51 -0
  34. package/src/artifact-sdk/browser-sdk.ts +30 -0
  35. package/src/artifact-sdk/index.ts +2 -0
  36. package/src/artifact-sdk/localtunnel.d.ts +20 -0
  37. package/src/artifact-sdk/port.ts +12 -0
  38. package/src/artifact-sdk/server.ts +156 -0
  39. package/src/artifact-sdk/tunnel.ts +19 -0
  40. package/src/be/chunking.ts +193 -0
  41. package/src/be/db-queries/oauth.ts +90 -0
  42. package/src/be/db-queries/tracker.ts +182 -0
  43. package/src/be/db.ts +3327 -784
  44. package/src/be/embedding.ts +80 -0
  45. package/src/be/migrations/001_initial.sql +409 -0
  46. package/src/be/migrations/002_one_time_schedules.sql +59 -0
  47. package/src/be/migrations/003_workflows.sql +51 -0
  48. package/src/be/migrations/004_workflow_source.sql +81 -0
  49. package/src/be/migrations/005_epic_next_steps.sql +2 -0
  50. package/src/be/migrations/006_vcs_provider.sql +94 -0
  51. package/src/be/migrations/007_task_dir.sql +2 -0
  52. package/src/be/migrations/008_workflow_redesign.sql +85 -0
  53. package/src/be/migrations/009_tracker_integration.sql +144 -0
  54. package/src/be/migrations/010_step_diagnostics.sql +1 -0
  55. package/src/be/migrations/011_step_next_port.sql +1 -0
  56. package/src/be/migrations/012_trigger_schema.sql +1 -0
  57. package/src/be/migrations/013_task_output_schema.sql +2 -0
  58. package/src/be/migrations/014_prompt_templates.sql +33 -0
  59. package/src/be/migrations/015_workflow_workspace.sql +3 -0
  60. package/src/be/migrations/016_active_session_runner_session.sql +4 -0
  61. package/src/be/migrations/017_channel_activity_cursors.sql +6 -0
  62. package/src/be/migrations/018_fix_seed_double_version.sql +30 -0
  63. package/src/be/migrations/runner.ts +188 -0
  64. package/src/be/seed.ts +62 -0
  65. package/src/cli.tsx +231 -299
  66. package/src/commands/artifact.ts +241 -0
  67. package/src/commands/onboard/compose-generator.ts +169 -0
  68. package/src/commands/onboard/env-generator.ts +79 -0
  69. package/src/commands/onboard/manifest.ts +37 -0
  70. package/src/commands/onboard/presets.ts +85 -0
  71. package/src/commands/onboard/service-names.ts +47 -0
  72. package/src/commands/onboard/steps/core-credentials.tsx +111 -0
  73. package/src/commands/onboard/steps/custom-templates.tsx +168 -0
  74. package/src/commands/onboard/steps/generate.tsx +154 -0
  75. package/src/commands/onboard/steps/harness-credentials.tsx +195 -0
  76. package/src/commands/onboard/steps/harness.tsx +21 -0
  77. package/src/commands/onboard/steps/health-check.tsx +171 -0
  78. package/src/commands/onboard/steps/integration-github.tsx +105 -0
  79. package/src/commands/onboard/steps/integration-gitlab.tsx +79 -0
  80. package/src/commands/onboard/steps/integration-menu.tsx +58 -0
  81. package/src/commands/onboard/steps/integration-sentry.tsx +79 -0
  82. package/src/commands/onboard/steps/integration-slack.tsx +165 -0
  83. package/src/commands/onboard/steps/post-connect.tsx +145 -0
  84. package/src/commands/onboard/steps/post-dashboard.tsx +34 -0
  85. package/src/commands/onboard/steps/post-task.tsx +103 -0
  86. package/src/commands/onboard/steps/prereq-check.tsx +178 -0
  87. package/src/commands/onboard/steps/review.tsx +82 -0
  88. package/src/commands/onboard/steps/start.tsx +97 -0
  89. package/src/commands/onboard/templates.ts +34 -0
  90. package/src/commands/onboard/types.ts +259 -0
  91. package/src/commands/onboard.tsx +425 -0
  92. package/src/commands/runner.ts +1540 -630
  93. package/src/commands/setup.tsx +23 -38
  94. package/src/commands/shared/client-config.ts +41 -0
  95. package/src/commands/templates.ts +172 -0
  96. package/src/github/app.ts +8 -0
  97. package/src/github/handlers.ts +384 -151
  98. package/src/github/index.ts +1 -0
  99. package/src/github/mentions-aliases.test.ts +73 -0
  100. package/src/github/mentions.test.ts +3 -3
  101. package/src/github/mentions.ts +32 -6
  102. package/src/github/templates.ts +398 -0
  103. package/src/github/types.ts +1 -0
  104. package/src/gitlab/auth.ts +63 -0
  105. package/src/gitlab/handlers.ts +368 -0
  106. package/src/gitlab/index.ts +19 -0
  107. package/src/gitlab/reactions.ts +104 -0
  108. package/src/gitlab/templates.ts +140 -0
  109. package/src/gitlab/types.ts +130 -0
  110. package/src/heartbeat/heartbeat.ts +434 -0
  111. package/src/heartbeat/index.ts +1 -0
  112. package/src/heartbeat/templates.ts +30 -0
  113. package/src/hooks/hook.ts +555 -4
  114. package/src/hooks/tool-loop-detection.test.ts +158 -0
  115. package/src/hooks/tool-loop-detection.ts +167 -0
  116. package/src/http/active-sessions.ts +199 -0
  117. package/src/http/agents.ts +328 -0
  118. package/src/http/config.ts +191 -0
  119. package/src/http/core.ts +309 -0
  120. package/src/http/db-query.ts +91 -0
  121. package/src/http/ecosystem.ts +63 -0
  122. package/src/http/epics.ts +460 -0
  123. package/src/http/index.ts +216 -0
  124. package/src/http/mcp.ts +77 -0
  125. package/src/http/memory.ts +168 -0
  126. package/src/http/openapi.ts +109 -0
  127. package/src/http/poll.ts +299 -0
  128. package/src/http/prompt-templates.ts +412 -0
  129. package/src/http/repos.ts +195 -0
  130. package/src/http/route-def.ts +123 -0
  131. package/src/http/schedules.ts +426 -0
  132. package/src/http/session-data.ts +241 -0
  133. package/src/http/stats.ts +174 -0
  134. package/src/http/tasks.ts +468 -0
  135. package/src/http/trackers/index.ts +10 -0
  136. package/src/http/trackers/linear.ts +187 -0
  137. package/src/http/types.ts +12 -0
  138. package/src/http/utils.ts +87 -0
  139. package/src/http/webhooks.ts +432 -0
  140. package/src/http/workflows.ts +530 -0
  141. package/src/http.ts +1 -1890
  142. package/src/linear/README.md +65 -0
  143. package/src/linear/app.ts +48 -0
  144. package/src/linear/client.ts +18 -0
  145. package/src/linear/index.ts +1 -0
  146. package/src/linear/oauth.ts +35 -0
  147. package/src/linear/outbound.ts +212 -0
  148. package/src/linear/sync.ts +567 -0
  149. package/src/linear/templates.ts +47 -0
  150. package/src/linear/types.ts +7 -0
  151. package/src/linear/webhook.ts +104 -0
  152. package/src/oauth/README.md +66 -0
  153. package/src/oauth/index.ts +6 -0
  154. package/src/oauth/wrapper.ts +204 -0
  155. package/src/prompts/base-prompt.ts +150 -265
  156. package/src/prompts/defaults.ts +196 -0
  157. package/src/prompts/registry.ts +57 -0
  158. package/src/prompts/resolver.ts +296 -0
  159. package/src/prompts/session-templates.ts +604 -0
  160. package/src/providers/claude-adapter.ts +442 -0
  161. package/src/providers/index.ts +24 -0
  162. package/src/providers/pi-mono-adapter.ts +442 -0
  163. package/src/providers/pi-mono-extension.ts +624 -0
  164. package/src/providers/pi-mono-mcp-client.ts +124 -0
  165. package/src/providers/types.ts +75 -0
  166. package/src/scheduler/scheduler.test.ts +2 -0
  167. package/src/scheduler/scheduler.ts +231 -40
  168. package/src/server.ts +97 -6
  169. package/src/slack/HEURISTICS.md +105 -0
  170. package/src/slack/actions.ts +133 -0
  171. package/src/slack/app.ts +7 -0
  172. package/src/slack/assistant.ts +118 -0
  173. package/src/slack/blocks.ts +233 -0
  174. package/src/slack/channel-activity.ts +177 -0
  175. package/src/slack/commands.ts +31 -17
  176. package/src/slack/files.ts +1 -1
  177. package/src/slack/handlers.test.ts +114 -1
  178. package/src/slack/handlers.ts +230 -55
  179. package/src/slack/responses.ts +120 -67
  180. package/src/slack/router.ts +17 -99
  181. package/src/slack/templates.ts +55 -0
  182. package/src/slack/thread-buffer.ts +213 -0
  183. package/src/slack/watcher.ts +119 -4
  184. package/src/tests/agent-activity.test.ts +247 -0
  185. package/src/tests/agentmail-filters.test.ts +97 -0
  186. package/src/tests/artifact-sdk.test.ts +800 -0
  187. package/src/tests/base-prompt.test.ts +264 -0
  188. package/src/tests/build-pi-skills.test.ts +127 -0
  189. package/src/tests/channel-activity.test.ts +363 -0
  190. package/src/tests/claude-adapter.test.ts +126 -0
  191. package/src/tests/context-versioning.test.ts +425 -0
  192. package/src/tests/db-queries-oauth.test.ts +197 -0
  193. package/src/tests/db-queries-tracker.test.ts +230 -0
  194. package/src/tests/epics.test.ts +3 -3
  195. package/src/tests/error-tracker.test.ts +368 -0
  196. package/src/tests/fetch-resolved-env.test.ts +167 -0
  197. package/src/tests/generate-default-claude-md.test.ts +9 -1
  198. package/src/tests/generate-identity-templates.test.ts +124 -0
  199. package/src/tests/gitlab-auth.test.ts +109 -0
  200. package/src/tests/gitlab-handlers.test.ts +691 -0
  201. package/src/tests/gitlab-vcs-db.test.ts +177 -0
  202. package/src/tests/heartbeat.test.ts +364 -0
  203. package/src/tests/http-api-integration.test.ts +1698 -0
  204. package/src/tests/linear-outbound-sync.test.ts +200 -0
  205. package/src/tests/linear-webhook.test.ts +406 -0
  206. package/src/tests/match-route.test.ts +187 -0
  207. package/src/tests/memory.test.ts +737 -0
  208. package/src/tests/migration-runner-regressions.test.ts +86 -0
  209. package/src/tests/model-control.test.ts +338 -0
  210. package/src/tests/oauth-wrapper.test.ts +147 -0
  211. package/src/tests/onboard-compose.test.ts +138 -0
  212. package/src/tests/onboard-env.test.ts +174 -0
  213. package/src/tests/onboard-manifest.test.ts +137 -0
  214. package/src/tests/pi-mono-adapter.test.ts +234 -0
  215. package/src/tests/pool-session-logs.test.ts +199 -0
  216. package/src/tests/progress-dedup.test.ts +98 -0
  217. package/src/tests/prompt-template-github.test.ts +682 -0
  218. package/src/tests/prompt-template-remaining.test.ts +504 -0
  219. package/src/tests/prompt-template-resolver.test.ts +621 -0
  220. package/src/tests/prompt-template-session.test.ts +363 -0
  221. package/src/tests/prompt-templates-db.test.ts +616 -0
  222. package/src/tests/provider-adapter.test.ts +122 -0
  223. package/src/tests/provider-command-format.test.ts +98 -0
  224. package/src/tests/reload-config.test.ts +170 -0
  225. package/src/tests/runner-polling-api.test.ts +25 -20
  226. package/src/tests/scheduled-tasks.test.ts +104 -0
  227. package/src/tests/scheduler-backoff.test.ts +166 -0
  228. package/src/tests/self-improvement.test.ts +541 -0
  229. package/src/tests/session-attach.test.ts +536 -0
  230. package/src/tests/session-costs.test.ts +267 -1
  231. package/src/tests/slack-actions.test.ts +133 -0
  232. package/src/tests/slack-assistant.test.ts +136 -0
  233. package/src/tests/slack-blocks.test.ts +246 -0
  234. package/src/tests/slack-metadata-inheritance.test.ts +243 -0
  235. package/src/tests/slack-queue-offline.test.ts +174 -0
  236. package/src/tests/slack-router.test.ts +181 -0
  237. package/src/tests/slack-thread-buffer.test.ts +305 -0
  238. package/src/tests/slack-thread-followups.test.ts +298 -0
  239. package/src/tests/slack-watcher.test.ts +101 -0
  240. package/src/tests/structured-output.test.ts +307 -0
  241. package/src/tests/swarm-repos.test.ts +198 -0
  242. package/src/tests/task-cancellation.test.ts +6 -4
  243. package/src/tests/task-working-dir.test.ts +176 -0
  244. package/src/tests/template-fetch.test.ts +490 -0
  245. package/src/tests/tool-annotations.test.ts +371 -0
  246. package/src/tests/tracker-tools.test.ts +184 -0
  247. package/src/tests/update-profile-agentid.test.ts +248 -0
  248. package/src/tests/update-profile-api.test.ts +143 -3
  249. package/src/tests/update-profile-auth.test.ts +195 -0
  250. package/src/tests/validation-adapters.test.ts +86 -0
  251. package/src/tests/vcs-provider.test.ts +27 -0
  252. package/src/tests/workflow-agent-task.test.ts +196 -0
  253. package/src/tests/workflow-async-v2.test.ts +508 -0
  254. package/src/tests/workflow-convergence.test.ts +541 -0
  255. package/src/tests/workflow-definition-validation.test.ts +366 -0
  256. package/src/tests/workflow-engine-v2.test.ts +691 -0
  257. package/src/tests/workflow-executors.test.ts +736 -0
  258. package/src/tests/workflow-http-v2.test.ts +599 -0
  259. package/src/tests/workflow-integration-io.test.ts +902 -0
  260. package/src/tests/workflow-io-schemas.test.ts +624 -0
  261. package/src/tests/workflow-registry.test.ts +592 -0
  262. package/src/tests/workflow-retry-v2.test.ts +401 -0
  263. package/src/tests/workflow-retry-validation.test.ts +282 -0
  264. package/src/tests/workflow-schedule-trigger.test.ts +104 -0
  265. package/src/tests/workflow-template.test.ts +288 -0
  266. package/src/tests/workflow-trigger-schema.test.ts +359 -0
  267. package/src/tests/workflow-triggers-v2.test.ts +264 -0
  268. package/src/tests/workflow-versions.test.ts +208 -0
  269. package/src/tests/workflow-workspace.test.ts +272 -0
  270. package/src/tests/x402-client.test.ts +117 -0
  271. package/src/tests/x402-config.test.ts +182 -0
  272. package/src/tests/x402-spending-tracker.test.ts +185 -0
  273. package/src/tools/cancel-task.ts +2 -0
  274. package/src/tools/context-diff.ts +171 -0
  275. package/src/tools/context-history.ts +138 -0
  276. package/src/tools/create-channel.ts +1 -0
  277. package/src/tools/db-query.ts +78 -0
  278. package/src/tools/delete-channel.ts +132 -0
  279. package/src/tools/epics/assign-task-to-epic.ts +1 -0
  280. package/src/tools/epics/create-epic.ts +3 -2
  281. package/src/tools/epics/delete-epic.ts +2 -0
  282. package/src/tools/epics/get-epic-details.ts +2 -0
  283. package/src/tools/epics/list-epics.ts +2 -0
  284. package/src/tools/epics/unassign-task-from-epic.ts +1 -0
  285. package/src/tools/epics/update-epic.ts +7 -4
  286. package/src/tools/get-swarm.ts +2 -0
  287. package/src/tools/get-task-details.ts +2 -0
  288. package/src/tools/get-tasks.ts +27 -1
  289. package/src/tools/inject-learning.ts +106 -0
  290. package/src/tools/join-swarm.ts +17 -7
  291. package/src/tools/list-channels.ts +2 -0
  292. package/src/tools/list-services.ts +2 -0
  293. package/src/tools/memory-get.ts +56 -0
  294. package/src/tools/memory-search.ts +131 -0
  295. package/src/tools/my-agent-info.ts +2 -0
  296. package/src/tools/poll-task.ts +2 -20
  297. package/src/tools/post-message.ts +1 -0
  298. package/src/tools/prompt-templates/delete.ts +86 -0
  299. package/src/tools/prompt-templates/get.ts +89 -0
  300. package/src/tools/prompt-templates/index.ts +5 -0
  301. package/src/tools/prompt-templates/list.ts +95 -0
  302. package/src/tools/prompt-templates/preview.ts +84 -0
  303. package/src/tools/prompt-templates/set.ts +117 -0
  304. package/src/tools/read-messages.ts +2 -0
  305. package/src/tools/register-agentmail-inbox.ts +166 -0
  306. package/src/tools/register-service.ts +2 -0
  307. package/src/tools/schedules/create-schedule.ts +134 -24
  308. package/src/tools/schedules/delete-schedule.ts +2 -0
  309. package/src/tools/schedules/list-schedules.ts +20 -4
  310. package/src/tools/schedules/run-schedule-now.ts +1 -0
  311. package/src/tools/schedules/update-schedule.ts +49 -17
  312. package/src/tools/send-task.ts +132 -10
  313. package/src/tools/slack-download-file.ts +4 -2
  314. package/src/tools/slack-list-channels.ts +2 -0
  315. package/src/tools/slack-post.ts +2 -0
  316. package/src/tools/slack-read.ts +2 -0
  317. package/src/tools/slack-reply.ts +2 -0
  318. package/src/tools/slack-upload-file.ts +2 -0
  319. package/src/tools/store-progress.ts +205 -4
  320. package/src/tools/swarm-config/delete-config.ts +87 -0
  321. package/src/tools/swarm-config/get-config.ts +108 -0
  322. package/src/tools/swarm-config/index.ts +4 -0
  323. package/src/tools/swarm-config/list-config.ts +99 -0
  324. package/src/tools/swarm-config/set-config.ts +118 -0
  325. package/src/tools/task-action.ts +50 -5
  326. package/src/tools/task-dedup.ts +97 -0
  327. package/src/tools/templates.ts +53 -0
  328. package/src/tools/tool-config.ts +124 -0
  329. package/src/tools/tracker/index.ts +6 -0
  330. package/src/tools/tracker/tracker-link-epic.ts +64 -0
  331. package/src/tools/tracker/tracker-link-task.ts +64 -0
  332. package/src/tools/tracker/tracker-map-agent.ts +57 -0
  333. package/src/tools/tracker/tracker-status.ts +56 -0
  334. package/src/tools/tracker/tracker-sync-status.ts +42 -0
  335. package/src/tools/tracker/tracker-unlink.ts +41 -0
  336. package/src/tools/unregister-service.ts +2 -0
  337. package/src/tools/update-profile.ts +172 -17
  338. package/src/tools/update-service-status.ts +2 -0
  339. package/src/tools/utils.ts +10 -1
  340. package/src/tools/workflows/create-workflow.ts +129 -0
  341. package/src/tools/workflows/delete-workflow.ts +42 -0
  342. package/src/tools/workflows/get-workflow-run.ts +59 -0
  343. package/src/tools/workflows/get-workflow.ts +53 -0
  344. package/src/tools/workflows/index.ts +9 -0
  345. package/src/tools/workflows/list-workflow-runs.ts +48 -0
  346. package/src/tools/workflows/list-workflows.ts +42 -0
  347. package/src/tools/workflows/retry-workflow-run.ts +40 -0
  348. package/src/tools/workflows/trigger-workflow.ts +96 -0
  349. package/src/tools/workflows/update-workflow.ts +133 -0
  350. package/src/tracker/types.ts +51 -0
  351. package/src/types.ts +530 -14
  352. package/src/utils/credentials.test.ts +156 -0
  353. package/src/utils/credentials.ts +50 -0
  354. package/src/utils/error-tracker.ts +190 -0
  355. package/src/vcs/index.ts +15 -0
  356. package/src/vcs/types.ts +5 -0
  357. package/src/workflows/checkpoint.ts +121 -0
  358. package/src/workflows/cooldown.ts +28 -0
  359. package/src/workflows/definition.ts +235 -0
  360. package/src/workflows/engine.ts +580 -0
  361. package/src/workflows/event-bus.ts +29 -0
  362. package/src/workflows/executors/agent-task.ts +103 -0
  363. package/src/workflows/executors/base.ts +86 -0
  364. package/src/workflows/executors/code-match.ts +88 -0
  365. package/src/workflows/executors/index.ts +16 -0
  366. package/src/workflows/executors/notify.ts +93 -0
  367. package/src/workflows/executors/property-match.ts +104 -0
  368. package/src/workflows/executors/raw-llm.ts +83 -0
  369. package/src/workflows/executors/registry.ts +76 -0
  370. package/src/workflows/executors/script.ts +103 -0
  371. package/src/workflows/executors/validate.ts +215 -0
  372. package/src/workflows/executors/vcs.ts +58 -0
  373. package/src/workflows/index.ts +61 -0
  374. package/src/workflows/input.ts +46 -0
  375. package/src/workflows/json-schema-validator.ts +118 -0
  376. package/src/workflows/recovery.ts +139 -0
  377. package/src/workflows/resume.ts +229 -0
  378. package/src/workflows/retry-poller.ts +216 -0
  379. package/src/workflows/template.ts +74 -0
  380. package/src/workflows/templates.ts +86 -0
  381. package/src/workflows/triggers.ts +124 -0
  382. package/src/workflows/validation.ts +104 -0
  383. package/src/workflows/version.ts +44 -0
  384. package/src/x402/cli.ts +140 -0
  385. package/src/x402/client.ts +192 -0
  386. package/src/x402/config.ts +131 -0
  387. package/src/x402/index.ts +37 -0
  388. package/src/x402/openfort-signer.ts +83 -0
  389. package/src/x402/spending-tracker.ts +109 -0
  390. package/templates/official/coder/CLAUDE.md +49 -0
  391. package/templates/official/coder/IDENTITY.md +28 -0
  392. package/templates/official/coder/SOUL.md +43 -0
  393. package/templates/official/coder/TOOLS.md +40 -0
  394. package/templates/official/coder/config.json +23 -0
  395. package/templates/official/coder/start-up.sh +23 -0
  396. package/templates/official/content-reviewer/CLAUDE.md +68 -0
  397. package/templates/official/content-reviewer/IDENTITY.md +28 -0
  398. package/templates/official/content-reviewer/SOUL.md +44 -0
  399. package/templates/official/content-reviewer/TOOLS.md +37 -0
  400. package/templates/official/content-reviewer/config.json +23 -0
  401. package/templates/official/content-reviewer/start-up.sh +23 -0
  402. package/templates/official/content-strategist/CLAUDE.md +63 -0
  403. package/templates/official/content-strategist/IDENTITY.md +33 -0
  404. package/templates/official/content-strategist/SOUL.md +48 -0
  405. package/templates/official/content-strategist/TOOLS.md +47 -0
  406. package/templates/official/content-strategist/config.json +23 -0
  407. package/templates/official/content-strategist/start-up.sh +23 -0
  408. package/templates/official/content-writer/CLAUDE.md +72 -0
  409. package/templates/official/content-writer/IDENTITY.md +30 -0
  410. package/templates/official/content-writer/SOUL.md +46 -0
  411. package/templates/official/content-writer/TOOLS.md +44 -0
  412. package/templates/official/content-writer/config.json +23 -0
  413. package/templates/official/content-writer/start-up.sh +23 -0
  414. package/templates/official/forward-deployed-engineer/CLAUDE.md +54 -0
  415. package/templates/official/forward-deployed-engineer/IDENTITY.md +37 -0
  416. package/templates/official/forward-deployed-engineer/SOUL.md +55 -0
  417. package/templates/official/forward-deployed-engineer/config.json +21 -0
  418. package/templates/official/lead/CLAUDE.md +33 -0
  419. package/templates/official/lead/IDENTITY.md +36 -0
  420. package/templates/official/lead/SOUL.md +51 -0
  421. package/templates/official/lead/config.json +22 -0
  422. package/templates/official/researcher/CLAUDE.md +46 -0
  423. package/templates/official/researcher/IDENTITY.md +28 -0
  424. package/templates/official/researcher/SOUL.md +43 -0
  425. package/templates/official/researcher/config.json +21 -0
  426. package/templates/official/reviewer/CLAUDE.md +63 -0
  427. package/templates/official/reviewer/IDENTITY.md +28 -0
  428. package/templates/official/reviewer/SOUL.md +45 -0
  429. package/templates/official/reviewer/config.json +21 -0
  430. package/templates/official/tester/CLAUDE.md +53 -0
  431. package/templates/official/tester/IDENTITY.md +28 -0
  432. package/templates/official/tester/SOUL.md +55 -0
  433. package/templates/official/tester/config.json +21 -0
  434. package/templates/schema.ts +35 -0
  435. package/.claude/settings.local.json +0 -115
  436. package/.dockerignore +0 -61
  437. package/.editorconfig +0 -15
  438. package/.env.docker.example +0 -39
  439. package/.env.example +0 -40
  440. package/.github/workflows/ci.yml +0 -76
  441. package/.github/workflows/docker-and-deploy.yml +0 -117
  442. package/.wts-config.json +0 -4
  443. package/.wts-setup.ts +0 -102
  444. package/CLAUDE.md +0 -104
  445. package/CONTRIBUTING.md +0 -270
  446. package/DEPLOYMENT.md +0 -605
  447. package/Dockerfile +0 -57
  448. package/Dockerfile.worker +0 -157
  449. package/FAQ.md +0 -19
  450. package/MCP.md +0 -406
  451. package/UI.md +0 -40
  452. package/assets/agent-swarm-logo-orange.png +0 -0
  453. package/assets/agent-swarm-logo.png +0 -0
  454. package/assets/agent-swarm.mp4 +0 -0
  455. package/assets/agent-swarm.png +0 -0
  456. package/biome.json +0 -39
  457. package/deploy/DEPLOY.md +0 -60
  458. package/deploy/agent-swarm.service +0 -17
  459. package/deploy/docker-push.ts +0 -30
  460. package/deploy/install.ts +0 -85
  461. package/deploy/prod-db.ts +0 -42
  462. package/deploy/uninstall.ts +0 -12
  463. package/deploy/update.ts +0 -21
  464. package/docker-compose.example.yml +0 -159
  465. package/docker-entrypoint.sh +0 -352
  466. package/ecosystem.config.cjs +0 -66
  467. package/plugin/README.md +0 -1
  468. package/plugin/hooks/hooks.json +0 -71
  469. package/pyproject.toml +0 -9
  470. package/scripts/generate-mcp-docs.ts +0 -415
  471. package/slack-manifest.json +0 -71
  472. package/src/tests/get-inbox-message.test.ts +0 -145
  473. package/src/tools/get-inbox-message.ts +0 -89
  474. package/src/tools/inbox-delegate.ts +0 -113
  475. package/thoughts/shared/plans/2025-12-18-slack-integration.md +0 -1195
  476. package/thoughts/shared/plans/2025-12-19-agent-log-streaming.md +0 -732
  477. package/thoughts/shared/plans/2025-12-19-role-based-swarm-plugin.md +0 -361
  478. package/thoughts/shared/plans/2025-12-20-mobile-responsive-ui.md +0 -501
  479. package/thoughts/shared/plans/2025-12-20-startup-team-swarm.md +0 -560
  480. package/thoughts/shared/plans/2025-12-23-runner-level-polling.md +0 -934
  481. package/thoughts/shared/plans/2025-12-23-runner-session-logs.md +0 -1000
  482. package/thoughts/shared/plans/2025-12-23-worker-lead-spawn-triggers.md +0 -568
  483. package/thoughts/shared/plans/2026-01-09-inverse-teleport.md +0 -1516
  484. package/thoughts/shared/plans/2026-01-12-agent-rename-pm2-control.md +0 -1133
  485. package/thoughts/shared/plans/2026-01-12-github-app-integration.md +0 -380
  486. package/thoughts/shared/plans/2026-01-12-lead-inbox-model.md +0 -876
  487. package/thoughts/shared/plans/2026-01-12-ralph-wiggum-integration.md +0 -463
  488. package/thoughts/shared/plans/2026-01-13-agent-concurrency.md +0 -691
  489. package/thoughts/shared/plans/2026-01-13-github-assignment-handling.md +0 -690
  490. package/thoughts/shared/plans/2026-01-13-prevent-duplicate-trigger-processing.md +0 -1071
  491. package/thoughts/shared/plans/2026-01-14-fix-slack-thread-context.md +0 -507
  492. package/thoughts/shared/plans/2026-01-15-scheduled-tasks-implementation.md +0 -565
  493. package/thoughts/shared/plans/2026-01-15-usage-cost-tracking-ui.md +0 -1479
  494. package/thoughts/shared/plans/2026-01-16-epics-feature-implementation.md +0 -1230
  495. package/thoughts/shared/research/.gitkeep +0 -0
  496. package/thoughts/shared/research/2025-01-09-inverse-teleport-plan-review.md +0 -420
  497. package/thoughts/shared/research/2025-12-18-slack-integration.md +0 -442
  498. package/thoughts/shared/research/2025-12-19-agent-log-streaming.md +0 -339
  499. package/thoughts/shared/research/2025-12-19-agent-secrets-cli-research.md +0 -390
  500. package/thoughts/shared/research/2025-12-21-gemini-cli-integration.md +0 -376
  501. package/thoughts/shared/research/2025-12-22-runner-loop-architecture.md +0 -582
  502. package/thoughts/shared/research/2025-12-22-setup-experience-improvements.md +0 -264
  503. package/thoughts/shared/research/2026-01-13-lead-duplicate-trigger-processing.md +0 -223
  504. package/thoughts/shared/research/2026-01-14-lead-slack-thread-context.md +0 -277
  505. package/thoughts/shared/research/2026-01-15-ai-tracker-agent-swarm-integration.md +0 -376
  506. package/thoughts/shared/research/2026-01-15-auto-starting-processes-in-worker-containers.md +0 -787
  507. package/thoughts/shared/research/2026-01-15-scheduled-tasks.md +0 -390
  508. package/thoughts/shared/research/2026-01-16-epics-feature-research.md +0 -437
  509. package/thoughts/taras/plans/2026-01-22-agent-swarm-schemas.md +0 -98
  510. package/thoughts/taras/plans/2026-01-28-per-worker-claude-md.md +0 -617
  511. package/thoughts/taras/plans/2026-01-28-sentry-cli-integration.md +0 -214
  512. package/thoughts/taras/research/2026-01-22-vercel-cli-integration.md +0 -287
  513. package/thoughts/taras/research/2026-01-27-excessive-polling-issue.md +0 -311
  514. package/thoughts/taras/research/2026-01-28-per-worker-claude-md.md +0 -383
  515. package/thoughts/taras/research/2026-01-28-sentry-cli-integration.md +0 -240
  516. package/tsconfig.json +0 -37
  517. package/ui/CLAUDE.md +0 -49
  518. package/ui/bun.lock +0 -771
  519. package/ui/index.html +0 -22
  520. package/ui/package-lock.json +0 -5290
  521. package/ui/package.json +0 -33
  522. package/ui/pnpm-lock.yaml +0 -3341
  523. package/ui/postcss.config.js +0 -6
  524. package/ui/public/logo.png +0 -0
  525. package/ui/src/App.tsx +0 -63
  526. package/ui/src/components/ActivityFeed.tsx +0 -440
  527. package/ui/src/components/AgentDetailPanel.tsx +0 -733
  528. package/ui/src/components/AgentsPanel.tsx +0 -815
  529. package/ui/src/components/ChatPanel.tsx +0 -1920
  530. package/ui/src/components/ConfigModal.tsx +0 -253
  531. package/ui/src/components/Dashboard.tsx +0 -832
  532. package/ui/src/components/EditAgentProfileModal.tsx +0 -433
  533. package/ui/src/components/EpicDetailPage.tsx +0 -741
  534. package/ui/src/components/EpicsPanel.tsx +0 -566
  535. package/ui/src/components/Header.tsx +0 -160
  536. package/ui/src/components/JsonViewer.tsx +0 -171
  537. package/ui/src/components/ScheduledTaskDetailPanel.tsx +0 -517
  538. package/ui/src/components/ScheduledTasksPanel.tsx +0 -639
  539. package/ui/src/components/ServicesPanel.tsx +0 -622
  540. package/ui/src/components/SessionLogPanel.tsx +0 -1219
  541. package/ui/src/components/StatsBar.tsx +0 -321
  542. package/ui/src/components/StatusBadge.tsx +0 -168
  543. package/ui/src/components/TaskDetailPanel.tsx +0 -903
  544. package/ui/src/components/TasksPanel.tsx +0 -614
  545. package/ui/src/components/UsageCharts.tsx +0 -216
  546. package/ui/src/components/UsageTab.tsx +0 -394
  547. package/ui/src/hooks/queries.ts +0 -353
  548. package/ui/src/hooks/useAutoScroll.ts +0 -83
  549. package/ui/src/index.css +0 -257
  550. package/ui/src/lib/api.ts +0 -268
  551. package/ui/src/lib/config.ts +0 -35
  552. package/ui/src/lib/contentPreview.ts +0 -208
  553. package/ui/src/lib/theme.ts +0 -214
  554. package/ui/src/lib/utils.ts +0 -88
  555. package/ui/src/main.tsx +0 -28
  556. package/ui/src/types/api.ts +0 -323
  557. package/ui/src/vite-env.d.ts +0 -1
  558. package/ui/tailwind.config.js +0 -37
  559. package/ui/tsconfig.json +0 -31
  560. package/ui/vite.config.ts +0 -35
  561. /package/{thoughts/shared/plans → templates/community}/.gitkeep +0 -0
@@ -1,78 +1,18 @@
1
1
  import { getAgentById, getAgentWorkingOnThread, getAllAgents } from "../be/db";
2
2
  import type { AgentMatch } from "./types";
3
3
 
4
- interface ThreadContext {
4
+ export interface ThreadContext {
5
5
  channelId: string;
6
6
  threadTs: string;
7
7
  }
8
8
 
9
- // Common 3-letter words to exclude from matching
10
- const COMMON_WORDS = new Set([
11
- "the",
12
- "and",
13
- "for",
14
- "are",
15
- "but",
16
- "not",
17
- "you",
18
- "all",
19
- "can",
20
- "had",
21
- "her",
22
- "was",
23
- "one",
24
- "our",
25
- "out",
26
- "has",
27
- "his",
28
- "how",
29
- "its",
30
- "let",
31
- "may",
32
- "new",
33
- "now",
34
- "old",
35
- "see",
36
- "way",
37
- "who",
38
- "boy",
39
- "did",
40
- "get",
41
- "say",
42
- "she",
43
- "too",
44
- "use",
45
- "hey",
46
- "hi",
47
- "hello",
48
- "please",
49
- "help",
50
- ]);
51
-
52
- /**
53
- * Check if a word is suitable for agent name matching.
54
- * Allows 3+ char words if they're not common words.
55
- * Always allows uppercase words (CEO, CTO, etc).
56
- */
57
- function isMatchableWord(word: string): boolean {
58
- if (word.length < 3) return false;
59
- // Always allow fully uppercase words (acronyms like CEO, CTO)
60
- if (word === word.toUpperCase() && word.length >= 3) return true;
61
- // Allow 3+ char words that aren't common
62
- if (word.length >= 3 && !COMMON_WORDS.has(word.toLowerCase())) return true;
63
- return false;
64
- }
65
-
66
9
  /**
67
10
  * Routes a Slack message to the appropriate agent(s) based on mentions.
68
11
  *
69
12
  * Routing rules:
70
13
  * - `swarm#<uuid>` → exact agent by ID
71
14
  * - `swarm#all` → all non-lead agents
72
- * - Partial name match (3+ chars, not common words) → agent by name
73
- * - Multiple partial matches → route to lead (let lead decide)
74
- * - Thread follow-up (no match but agent working on thread) → route to that agent
75
- * - Bot @mention only → lead agent
15
+ * - Everything else lead agent
76
16
  */
77
17
  export function routeMessage(
78
18
  text: string,
@@ -104,46 +44,28 @@ export function routeMessage(
104
44
  }
105
45
  }
106
46
 
107
- // Check for partial name matches (3+ chars, not common words)
108
- if (matches.length === 0) {
109
- for (const agent of agents) {
110
- const nameWords = agent.name.split(/\s+/).filter(isMatchableWord);
111
- for (const word of nameWords) {
112
- const regex = new RegExp(`\\b${escapeRegex(word)}\\b`, "i");
113
- if (regex.test(text)) {
114
- if (!matches.some((m) => m.agent.id === agent.id)) {
115
- matches.push({ agent, matchedText: word });
116
- }
117
- break;
118
- }
119
- }
120
- }
121
-
122
- // If multiple agents matched a partial name, route to lead instead (let lead decide)
123
- if (matches.length > 1) {
124
- const lead = agents.find((a) => a.isLead);
125
- if (lead) {
126
- const matchedWords = matches.map((m) => m.matchedText).join(", ");
127
- const matchedAgents = matches.map((m) => m.agent.name).join(", ");
128
- return [
129
- {
130
- agent: lead,
131
- matchedText: `ambiguous match "${matchedWords}" (could be: ${matchedAgents})`,
132
- },
133
- ];
134
- }
135
- }
136
- }
137
-
138
- // Thread follow-up: If no matches and we're in a thread, check if an agent is working on it
47
+ // Thread follow-up route to agent already working in this thread
139
48
  if (matches.length === 0 && threadContext) {
140
49
  const workingAgent = getAgentWorkingOnThread(threadContext.channelId, threadContext.threadTs);
141
50
  if (workingAgent && workingAgent.status !== "offline") {
51
+ console.log(
52
+ `[Slack] Thread follow-up: routing to agent ${workingAgent.name} (${workingAgent.id}) in thread ${threadContext.threadTs}`,
53
+ );
142
54
  matches.push({ agent: workingAgent, matchedText: "thread follow-up" });
55
+ } else if (workingAgent) {
56
+ // Agent is offline but thread has history — route to lead without requiring @mention
57
+ console.log(
58
+ `[Slack] Thread follow-up: agent ${workingAgent.name} is offline, routing to lead`,
59
+ );
60
+ const allAgents = getAllAgents();
61
+ const lead = allAgents.find((a) => a.isLead && a.status !== "offline");
62
+ if (lead) {
63
+ matches.push({ agent: lead, matchedText: "thread follow-up (lead fallback)" });
64
+ }
143
65
  }
144
66
  }
145
67
 
146
- // If only bot was mentioned and no agents matched, route to lead
68
+ // Default to lead for everything else
147
69
  if (matches.length === 0 && botMentioned) {
148
70
  const lead = agents.find((a) => a.isLead);
149
71
  if (lead) {
@@ -154,10 +76,6 @@ export function routeMessage(
154
76
  return matches;
155
77
  }
156
78
 
157
- function escapeRegex(str: string): string {
158
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
159
- }
160
-
161
79
  /**
162
80
  * Extracts the task description from a message, removing bot mentions and agent references.
163
81
  */
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Slack event prompt template definitions.
3
+ *
4
+ * Each template is registered at module load time via registerTemplate().
5
+ * Handlers import this module for the side-effect of registration.
6
+ */
7
+
8
+ import { registerTemplate } from "../prompts/registry";
9
+
10
+ // ============================================================================
11
+ // Assistant messages (Slack UI messages, not agent prompts)
12
+ // ============================================================================
13
+
14
+ registerTemplate({
15
+ eventType: "slack.assistant.greeting",
16
+ header: "",
17
+ defaultBody: "Hi! I'm your Agent Swarm assistant. How can I help?",
18
+ variables: [],
19
+ category: "system",
20
+ });
21
+
22
+ registerTemplate({
23
+ eventType: "slack.assistant.suggested_prompts",
24
+ header: "",
25
+ defaultBody: `Try these:
26
+ - Check status: What's the current status of all agents?
27
+ - Assign a task: Can you help me with...
28
+ - List recent tasks: Show me the most recent tasks`,
29
+ variables: [],
30
+ category: "system",
31
+ });
32
+
33
+ registerTemplate({
34
+ eventType: "slack.assistant.offline",
35
+ header: "",
36
+ defaultBody:
37
+ "No agents are available right now. Your request has been queued and will be processed when agents come back online.",
38
+ variables: [],
39
+ category: "system",
40
+ });
41
+
42
+ registerTemplate({
43
+ eventType: "slack.message.thread_context",
44
+ header: "",
45
+ defaultBody: `<thread_context>
46
+ {{thread_messages}}
47
+ </thread_context>`,
48
+ variables: [
49
+ {
50
+ name: "thread_messages",
51
+ description: "Formatted thread messages (user: text pairs)",
52
+ },
53
+ ],
54
+ category: "system",
55
+ });
@@ -0,0 +1,213 @@
1
+ import {
2
+ createTaskExtended,
3
+ getLatestActiveTaskInThread,
4
+ getLeadAgent,
5
+ getMostRecentTaskInThread,
6
+ } from "../be/db";
7
+ import { getSlackApp } from "./app";
8
+ import { buildBufferFlushBlocks } from "./blocks";
9
+
10
+ interface BufferedMessage {
11
+ text: string;
12
+ userId: string;
13
+ ts: string;
14
+ }
15
+
16
+ interface BufferedThread {
17
+ channelId: string;
18
+ threadTs: string;
19
+ messages: BufferedMessage[];
20
+ timer: Timer;
21
+ slackUserId: string; // original requester (first message sender)
22
+ }
23
+
24
+ const threadBuffers = new Map<string, BufferedThread>();
25
+
26
+ const BUFFER_TIMEOUT_MS = Number(process.env.ADDITIVE_SLACK_BUFFER_MS) || 10_000;
27
+
28
+ function makeKey(channelId: string, threadTs: string): string {
29
+ return `${channelId}:${threadTs}`;
30
+ }
31
+
32
+ /**
33
+ * Add a message to the thread buffer. Resets the debounce timer.
34
+ */
35
+ export function bufferThreadMessage(
36
+ channelId: string,
37
+ threadTs: string,
38
+ text: string,
39
+ userId: string,
40
+ ts: string,
41
+ ): void {
42
+ const key = makeKey(channelId, threadTs);
43
+ const existing = threadBuffers.get(key);
44
+
45
+ if (existing) {
46
+ // Append to existing buffer, reset timer
47
+ existing.messages.push({ text, userId, ts });
48
+ clearTimeout(existing.timer);
49
+ existing.timer = setTimeout(() => flushBuffer(key, false), BUFFER_TIMEOUT_MS);
50
+ console.log(
51
+ `[Slack] Buffer append: ${key} (${existing.messages.length} messages, timer reset to ${BUFFER_TIMEOUT_MS}ms)`,
52
+ );
53
+ } else {
54
+ // Create new buffer entry
55
+ const timer = setTimeout(() => flushBuffer(key, false), BUFFER_TIMEOUT_MS);
56
+ threadBuffers.set(key, {
57
+ channelId,
58
+ threadTs,
59
+ messages: [{ text, userId, ts }],
60
+ timer,
61
+ slackUserId: userId,
62
+ });
63
+ console.log(`[Slack] Buffer created: ${key} (timer set to ${BUFFER_TIMEOUT_MS}ms)`);
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Check if a thread currently has a pending buffer.
69
+ */
70
+ export function isThreadBuffered(channelId: string, threadTs: string): boolean {
71
+ return threadBuffers.has(makeKey(channelId, threadTs));
72
+ }
73
+
74
+ /**
75
+ * Get the number of messages currently in the buffer for a thread key.
76
+ */
77
+ export function getBufferMessageCount(key: string): number {
78
+ return threadBuffers.get(key)?.messages.length ?? 0;
79
+ }
80
+
81
+ /**
82
+ * Instantly flush the buffer (used by !now command). Clears the debounce timer
83
+ * and flushes with immediate=true (no dependsOn).
84
+ */
85
+ export async function instantFlush(key: string): Promise<void> {
86
+ const buffer = threadBuffers.get(key);
87
+ if (buffer) {
88
+ clearTimeout(buffer.timer);
89
+ console.log(`[Slack] Instant flush triggered: ${key}`);
90
+ }
91
+ await flushBuffer(key, true);
92
+ }
93
+
94
+ /**
95
+ * Fetch thread context from Slack for the buffer flush task description.
96
+ */
97
+ async function getThreadContextForBuffer(channelId: string, threadTs: string): Promise<string> {
98
+ const app = getSlackApp();
99
+ if (!app) return "";
100
+
101
+ try {
102
+ const result = await app.client.conversations.replies({
103
+ channel: channelId,
104
+ ts: threadTs,
105
+ limit: 20,
106
+ });
107
+
108
+ const messages = result.messages || [];
109
+ if (messages.length === 0) return "";
110
+
111
+ const formatted = messages
112
+ .filter((m) => m.text)
113
+ .map((m) => {
114
+ const msg = m as Record<string, unknown>;
115
+ const isBotMessage = msg.bot_id !== undefined || msg.subtype === "bot_message";
116
+ if (isBotMessage) {
117
+ const truncated = m.text && m.text.length > 500 ? `${m.text.slice(0, 500)}...` : m.text;
118
+ return `[Agent]: ${truncated}`;
119
+ }
120
+ return `<@${m.user}>: ${m.text}`;
121
+ })
122
+ .join("\n");
123
+
124
+ return formatted;
125
+ } catch (error) {
126
+ console.error("[Slack] Failed to fetch thread context for buffer:", error);
127
+ return "";
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Flush the buffer: concatenate messages, create task with optional dependency chaining.
133
+ * @param key - The buffer key (channelId:threadTs)
134
+ * @param immediate - If true, skip dependency chaining (used by !now)
135
+ */
136
+ async function flushBuffer(key: string, immediate = false): Promise<void> {
137
+ const buffer = threadBuffers.get(key);
138
+ if (!buffer || buffer.messages.length === 0) {
139
+ threadBuffers.delete(key);
140
+ return;
141
+ }
142
+
143
+ console.log(
144
+ `[Slack] Flushing buffer: ${key} (${buffer.messages.length} messages, immediate=${immediate})`,
145
+ );
146
+
147
+ // Build combined task description
148
+ const combinedText = buffer.messages.map((m) => m.text).join("\n---\n");
149
+ const description = `[Thread follow-up — ${buffer.messages.length} message(s) buffered]\n\n${combinedText}`;
150
+
151
+ // Find the latest active task in this thread for dependency chaining
152
+ const latestActiveTask = getLatestActiveTaskInThread(buffer.channelId, buffer.threadTs);
153
+ if (latestActiveTask) {
154
+ console.log(
155
+ `[Slack] Dependency chaining: latest active task ${latestActiveTask.id} (status: ${latestActiveTask.status})`,
156
+ );
157
+ }
158
+
159
+ const lead = getLeadAgent();
160
+
161
+ // Thread context for the task
162
+ const threadContext = await getThreadContextForBuffer(buffer.channelId, buffer.threadTs);
163
+ const fullDescription = threadContext
164
+ ? `<thread_context>\n${threadContext}\n</thread_context>\n\n${description}`
165
+ : description;
166
+
167
+ // Always pending. If !now was used (immediate=true), no dependency.
168
+ // Otherwise, depend on the latest active task so it queues naturally.
169
+ const dependsOn = !immediate && latestActiveTask ? [latestActiveTask.id] : undefined;
170
+
171
+ const mostRecentTask = getMostRecentTaskInThread(buffer.channelId, buffer.threadTs);
172
+ const task = createTaskExtended(fullDescription, {
173
+ agentId: lead?.id,
174
+ source: "slack",
175
+ slackChannelId: buffer.channelId,
176
+ slackThreadTs: buffer.threadTs,
177
+ slackUserId: buffer.slackUserId,
178
+ dependsOn,
179
+ parentTaskId: mostRecentTask?.id,
180
+ });
181
+
182
+ console.log(
183
+ `[Slack] Buffer flushed → task ${task.id} (dependsOn: ${dependsOn ? dependsOn.join(", ") : "none"})`,
184
+ );
185
+
186
+ // Slack feedback with Block Kit
187
+ const app = getSlackApp();
188
+ if (app) {
189
+ const hasDependency = !immediate && !!latestActiveTask;
190
+ const blocks = buildBufferFlushBlocks({
191
+ messageCount: buffer.messages.length,
192
+ taskId: task.id,
193
+ hasDependency,
194
+ });
195
+ const fallbackText = hasDependency
196
+ ? `${buffer.messages.length} follow-up message(s) queued pending completion of current task`
197
+ : `${buffer.messages.length} follow-up message(s) batched into task`;
198
+
199
+ try {
200
+ await app.client.chat.postMessage({
201
+ channel: buffer.channelId,
202
+ thread_ts: buffer.threadTs,
203
+ text: fallbackText,
204
+ // biome-ignore lint/suspicious/noExplicitAny: Block Kit objects
205
+ blocks: blocks as any,
206
+ });
207
+ } catch (error) {
208
+ console.error("[Slack] Failed to post buffer flush feedback:", error);
209
+ }
210
+ }
211
+
212
+ threadBuffers.delete(key);
213
+ }
@@ -1,6 +1,11 @@
1
1
  import { getCompletedSlackTasks, getInProgressSlackTasks } from "../be/db";
2
2
  import { getSlackApp } from "./app";
3
- import { sendProgressUpdate, sendTaskResponse } from "./responses";
3
+ import {
4
+ sendProgressUpdate,
5
+ sendTaskResponse,
6
+ updateProgressInPlace,
7
+ updateToFinal,
8
+ } from "./responses";
4
9
 
5
10
  let watcherInterval: ReturnType<typeof setInterval> | null = null;
6
11
  let isProcessing = false;
@@ -18,6 +23,48 @@ const pendingSends = new Set<string>();
18
23
  const lastSendTime = new Map<string, number>();
19
24
  const MIN_SEND_INTERVAL = 1000; // Don't send for same task within 1 second
20
25
 
26
+ // Track task message timestamps for chat.update (taskId -> message info)
27
+ // This is THE message that evolves: assignment → progress → completion
28
+ const taskMessages = new Map<string, { channelId: string; threadTs: string; messageTs: string }>();
29
+
30
+ /**
31
+ * Register the initial message ts for a task (called by handlers.ts after posting assignment).
32
+ * This allows the watcher to update the same message through the task lifecycle.
33
+ */
34
+ export function registerTaskMessage(
35
+ taskId: string,
36
+ channelId: string,
37
+ threadTs: string,
38
+ messageTs: string,
39
+ ): void {
40
+ taskMessages.set(taskId, { channelId, threadTs, messageTs });
41
+ }
42
+
43
+ /**
44
+ * Check if a channel is a DM (assistant thread). DM channels start with "D".
45
+ */
46
+ function isDMChannel(channelId: string): boolean {
47
+ return channelId.startsWith("D");
48
+ }
49
+
50
+ /**
51
+ * Set the assistant thread status (typing indicator) for DM channels.
52
+ */
53
+ async function setAssistantStatus(channelId: string, threadTs: string, status: string) {
54
+ const app = getSlackApp();
55
+ if (!app) return;
56
+
57
+ try {
58
+ await app.client.assistant.threads.setStatus({
59
+ channel_id: channelId,
60
+ thread_ts: threadTs,
61
+ status,
62
+ });
63
+ } catch (error) {
64
+ console.error(`[Slack] Failed to set assistant status:`, error);
65
+ }
66
+ }
67
+
21
68
  /**
22
69
  * Start watching for Slack task updates and sending responses.
23
70
  */
@@ -52,6 +99,51 @@ export function startTaskWatcher(intervalMs = 3000): void {
52
99
  const lastSent = lastSendTime.get(progressKey);
53
100
  if (lastSent && now - lastSent < MIN_SEND_INTERVAL) continue;
54
101
 
102
+ const isDM = task.slackChannelId && isDMChannel(task.slackChannelId);
103
+
104
+ if (isDM && task.slackChannelId && task.slackThreadTs) {
105
+ // DM/assistant thread: use setStatus for typing indicator
106
+ const progressText = task.progress || "Processing your request...";
107
+ if (progressText !== sentProgress.get(task.id)) {
108
+ pendingSends.add(progressKey);
109
+ sentProgress.set(task.id, progressText);
110
+ lastSendTime.set(progressKey, now);
111
+ try {
112
+ await setAssistantStatus(task.slackChannelId, task.slackThreadTs, progressText);
113
+ console.log(`[Slack] Set assistant status for task ${task.id.slice(0, 8)}`);
114
+ } catch (error) {
115
+ sentProgress.delete(task.id);
116
+ lastSendTime.delete(progressKey);
117
+ console.error(`[Slack] Failed to set assistant status:`, error);
118
+ } finally {
119
+ pendingSends.delete(progressKey);
120
+ }
121
+ }
122
+ continue;
123
+ }
124
+
125
+ // Channel thread: use chat.update on the evolving message
126
+ const tracked = taskMessages.get(task.id);
127
+
128
+ // If we have a tracked message but haven't sent any progress yet,
129
+ // update assignment message to "In Progress" state immediately
130
+ if (tracked && !sentProgress.has(task.id) && !task.progress) {
131
+ pendingSends.add(progressKey);
132
+ sentProgress.set(task.id, "__in_progress__");
133
+ lastSendTime.set(progressKey, now);
134
+ try {
135
+ await updateProgressInPlace(task, "Starting...", tracked.messageTs);
136
+ console.log(`[Slack] Updated to in-progress for task ${task.id.slice(0, 8)}`);
137
+ } catch (error) {
138
+ sentProgress.delete(task.id);
139
+ lastSendTime.delete(progressKey);
140
+ console.error(`[Slack] Failed to update to in-progress:`, error);
141
+ } finally {
142
+ pendingSends.delete(progressKey);
143
+ }
144
+ continue;
145
+ }
146
+
55
147
  const lastSentProgress = sentProgress.get(task.id);
56
148
  // Only send if progress exists and is different from last sent
57
149
  if (task.progress && task.progress !== lastSentProgress) {
@@ -60,8 +152,23 @@ export function startTaskWatcher(intervalMs = 3000): void {
60
152
  sentProgress.set(task.id, task.progress);
61
153
  lastSendTime.set(progressKey, now);
62
154
  try {
63
- await sendProgressUpdate(task, task.progress);
64
- console.log(`[Slack] Sent progress update for task ${task.id.slice(0, 8)}`);
155
+ if (tracked) {
156
+ // Update the existing message in-place via chat.update
157
+ await updateProgressInPlace(task, task.progress, tracked.messageTs);
158
+ console.log(`[Slack] Updated progress in-place for task ${task.id.slice(0, 8)}`);
159
+ } else {
160
+ // No tracked message (e.g., multi-task assignment or server restart)
161
+ // Post a new progress message and track its ts
162
+ const messageTs = await sendProgressUpdate(task, task.progress);
163
+ if (messageTs && task.slackChannelId && task.slackThreadTs) {
164
+ taskMessages.set(task.id, {
165
+ channelId: task.slackChannelId,
166
+ threadTs: task.slackThreadTs,
167
+ messageTs,
168
+ });
169
+ }
170
+ console.log(`[Slack] Sent initial progress for task ${task.id.slice(0, 8)}`);
171
+ }
65
172
  } catch (error) {
66
173
  // If send fails, clear markers so we can retry
67
174
  sentProgress.delete(task.id);
@@ -88,7 +195,15 @@ export function startTaskWatcher(intervalMs = 3000): void {
88
195
  notifiedCompletions.set(task.id, now);
89
196
  lastSendTime.set(completionKey, now);
90
197
  try {
91
- await sendTaskResponse(task);
198
+ const tracked = taskMessages.get(task.id);
199
+ if (tracked) {
200
+ // Channel thread: update the same message to its final state
201
+ await updateToFinal(task, tracked.messageTs);
202
+ taskMessages.delete(task.id);
203
+ } else {
204
+ // DM or untracked: post completion as a new message
205
+ await sendTaskResponse(task);
206
+ }
92
207
  // Clean up progress tracking
93
208
  sentProgress.delete(task.id);
94
209
  console.log(`[Slack] Sent ${task.status} response for task ${task.id.slice(0, 8)}`);