@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
@@ -0,0 +1,122 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { createProviderAdapter } from "../providers";
3
+ import { ClaudeAdapter } from "../providers/claude-adapter";
4
+ import { PiMonoAdapter } from "../providers/pi-mono-adapter";
5
+ import type { CostData, ProviderEvent } from "../providers/types";
6
+
7
+ describe("createProviderAdapter", () => {
8
+ test("returns ClaudeAdapter for 'claude'", () => {
9
+ const adapter = createProviderAdapter("claude");
10
+ expect(adapter).toBeInstanceOf(ClaudeAdapter);
11
+ expect(adapter.name).toBe("claude");
12
+ });
13
+
14
+ test("returns PiMonoAdapter for 'pi'", () => {
15
+ const adapter = createProviderAdapter("pi");
16
+ expect(adapter).toBeInstanceOf(PiMonoAdapter);
17
+ expect(adapter.name).toBe("pi");
18
+ });
19
+
20
+ test("throws for unknown provider", () => {
21
+ expect(() => createProviderAdapter("unknown")).toThrow(
22
+ 'Unknown HARNESS_PROVIDER: "unknown". Supported: claude, pi',
23
+ );
24
+ });
25
+
26
+ test("throws for empty string", () => {
27
+ expect(() => createProviderAdapter("")).toThrow("Unknown HARNESS_PROVIDER");
28
+ });
29
+ });
30
+
31
+ describe("ProviderEvent type narrowing", () => {
32
+ test("session_init event has sessionId", () => {
33
+ const event: ProviderEvent = { type: "session_init", sessionId: "abc-123" };
34
+ if (event.type === "session_init") {
35
+ expect(event.sessionId).toBe("abc-123");
36
+ }
37
+ });
38
+
39
+ test("result event has cost data", () => {
40
+ const cost: CostData = {
41
+ sessionId: "sess-1",
42
+ agentId: "agent-1",
43
+ totalCostUsd: 0.05,
44
+ inputTokens: 1000,
45
+ outputTokens: 500,
46
+ cacheReadTokens: 200,
47
+ cacheWriteTokens: 100,
48
+ durationMs: 5000,
49
+ numTurns: 3,
50
+ model: "opus",
51
+ isError: false,
52
+ };
53
+ const event: ProviderEvent = { type: "result", cost, isError: false };
54
+ if (event.type === "result") {
55
+ expect(event.cost.totalCostUsd).toBe(0.05);
56
+ expect(event.cost.inputTokens).toBe(1000);
57
+ expect(event.cost.outputTokens).toBe(500);
58
+ }
59
+ });
60
+
61
+ test("error event has message", () => {
62
+ const event: ProviderEvent = { type: "error", message: "boom", category: "api_error" };
63
+ if (event.type === "error") {
64
+ expect(event.message).toBe("boom");
65
+ expect(event.category).toBe("api_error");
66
+ }
67
+ });
68
+
69
+ test("raw_log event has content string", () => {
70
+ const event: ProviderEvent = { type: "raw_log", content: "some output" };
71
+ if (event.type === "raw_log") {
72
+ expect(event.content).toBe("some output");
73
+ }
74
+ });
75
+ });
76
+
77
+ describe("CostData shape", () => {
78
+ test("matches expected API fields", () => {
79
+ const cost: CostData = {
80
+ sessionId: "sess-1",
81
+ taskId: "task-1",
82
+ agentId: "agent-1",
83
+ totalCostUsd: 0.12,
84
+ inputTokens: 2000,
85
+ outputTokens: 1000,
86
+ cacheReadTokens: 500,
87
+ cacheWriteTokens: 300,
88
+ durationMs: 10000,
89
+ numTurns: 5,
90
+ model: "claude-opus-4-20250514",
91
+ isError: false,
92
+ };
93
+
94
+ // All required fields present
95
+ expect(cost.sessionId).toBe("sess-1");
96
+ expect(cost.taskId).toBe("task-1");
97
+ expect(cost.agentId).toBe("agent-1");
98
+ expect(cost.totalCostUsd).toBeGreaterThan(0);
99
+ expect(cost.durationMs).toBeGreaterThanOrEqual(0);
100
+ expect(cost.numTurns).toBeGreaterThan(0);
101
+ expect(cost.model).toBeTruthy();
102
+ expect(typeof cost.isError).toBe("boolean");
103
+ });
104
+
105
+ test("optional fields can be undefined", () => {
106
+ const cost: CostData = {
107
+ sessionId: "",
108
+ agentId: "agent-1",
109
+ totalCostUsd: 0,
110
+ durationMs: 0,
111
+ numTurns: 0,
112
+ model: "opus",
113
+ isError: false,
114
+ };
115
+
116
+ expect(cost.taskId).toBeUndefined();
117
+ expect(cost.inputTokens).toBeUndefined();
118
+ expect(cost.outputTokens).toBeUndefined();
119
+ expect(cost.cacheReadTokens).toBeUndefined();
120
+ expect(cost.cacheWriteTokens).toBeUndefined();
121
+ });
122
+ });
@@ -0,0 +1,98 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { ClaudeAdapter } from "../providers/claude-adapter";
3
+ import { createProviderAdapter } from "../providers/index";
4
+ import { PiMonoAdapter } from "../providers/pi-mono-adapter";
5
+
6
+ describe("ProviderAdapter.formatCommand", () => {
7
+ const claude = new ClaudeAdapter();
8
+ const pi = new PiMonoAdapter();
9
+
10
+ test("claude formats commands with / prefix", () => {
11
+ expect(claude.formatCommand("work-on-task")).toBe("/work-on-task");
12
+ expect(claude.formatCommand("review-offered-task")).toBe("/review-offered-task");
13
+ expect(claude.formatCommand("swarm-chat")).toBe("/swarm-chat");
14
+ });
15
+
16
+ test("pi formats commands with /skill: prefix", () => {
17
+ expect(pi.formatCommand("work-on-task")).toBe("/skill:work-on-task");
18
+ expect(pi.formatCommand("review-offered-task")).toBe("/skill:review-offered-task");
19
+ expect(pi.formatCommand("swarm-chat")).toBe("/skill:swarm-chat");
20
+ });
21
+
22
+ test("adapter name matches expected provider", () => {
23
+ expect(claude.name).toBe("claude");
24
+ expect(pi.name).toBe("pi");
25
+ });
26
+
27
+ test("createProviderAdapter returns adapters that implement formatCommand", () => {
28
+ const claudeAdapter = createProviderAdapter("claude");
29
+ const piAdapter = createProviderAdapter("pi");
30
+ expect(typeof claudeAdapter.formatCommand).toBe("function");
31
+ expect(typeof piAdapter.formatCommand).toBe("function");
32
+ expect(claudeAdapter.formatCommand("work-on-task")).toBe("/work-on-task");
33
+ expect(piAdapter.formatCommand("work-on-task")).toBe("/skill:work-on-task");
34
+ });
35
+ });
36
+
37
+ describe("regression: pi worker prompt must use /skill: prefix", () => {
38
+ const pi = new PiMonoAdapter();
39
+ const claude = new ClaudeAdapter();
40
+
41
+ function simulateTaskAssignedPrompt(
42
+ adapter: { formatCommand: (cmd: string) => string },
43
+ taskId: string,
44
+ taskDesc: string,
45
+ ): string {
46
+ let prompt = `${adapter.formatCommand("work-on-task")} ${taskId}`;
47
+ prompt += `\n\nTask: "${taskDesc}"`;
48
+ prompt += `\n\nWhen done, use \`store-progress\` with status: "completed" and include your output.`;
49
+ return prompt;
50
+ }
51
+
52
+ function simulateTaskOfferedPrompt(
53
+ adapter: { formatCommand: (cmd: string) => string },
54
+ taskId: string,
55
+ taskDesc: string,
56
+ ): string {
57
+ let prompt = `${adapter.formatCommand("review-offered-task")} ${taskId}`;
58
+ prompt += `\n\nA task has been offered to you:\n"${taskDesc}"`;
59
+ prompt += `\n\nAccept if you have capacity and skills. Reject with a reason if you cannot handle it.`;
60
+ return prompt;
61
+ }
62
+
63
+ function simulateResumePrompt(
64
+ adapter: { formatCommand: (cmd: string) => string },
65
+ taskId: string,
66
+ ): string {
67
+ return `${adapter.formatCommand("work-on-task")} ${taskId}\n\n**RESUMED TASK**`;
68
+ }
69
+
70
+ test("pi task_assigned prompt starts with /skill:work-on-task", () => {
71
+ const prompt = simulateTaskAssignedPrompt(pi, "abc-123", "Review the PR");
72
+ expect(prompt).toStartWith("/skill:work-on-task abc-123");
73
+ expect(prompt).not.toStartWith("/work-on-task abc-123");
74
+ });
75
+
76
+ test("pi task_offered prompt starts with /skill:review-offered-task", () => {
77
+ const prompt = simulateTaskOfferedPrompt(pi, "def-456", "Check deployment");
78
+ expect(prompt).toStartWith("/skill:review-offered-task def-456");
79
+ expect(prompt).not.toStartWith("/review-offered-task def-456");
80
+ });
81
+
82
+ test("pi resume prompt starts with /skill:work-on-task", () => {
83
+ const prompt = simulateResumePrompt(pi, "ghi-789");
84
+ expect(prompt).toStartWith("/skill:work-on-task ghi-789");
85
+ });
86
+
87
+ test("claude task_assigned prompt starts with /work-on-task (no /skill:)", () => {
88
+ const prompt = simulateTaskAssignedPrompt(claude, "abc-123", "Review the PR");
89
+ expect(prompt).toStartWith("/work-on-task abc-123");
90
+ expect(prompt).not.toContain("/skill:");
91
+ });
92
+
93
+ test("claude task_offered prompt starts with /review-offered-task (no /skill:)", () => {
94
+ const prompt = simulateTaskOfferedPrompt(claude, "def-456", "Check deployment");
95
+ expect(prompt).toStartWith("/review-offered-task def-456");
96
+ expect(prompt).not.toContain("/skill:");
97
+ });
98
+ });
@@ -0,0 +1,170 @@
1
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
+ import { unlink } from "node:fs/promises";
3
+ import { createServer as createHttpServer, type Server } from "node:http";
4
+ import { initAgentMail, resetAgentMail } from "../agentmail";
5
+ import { closeDb, getResolvedConfig, initDb, upsertSwarmConfig } from "../be/db";
6
+ import { initGitHub, resetGitHub } from "../github";
7
+
8
+ const TEST_DB_PATH = "./test-reload-config.sqlite";
9
+ const TEST_PORT = 13023;
10
+
11
+ /**
12
+ * Mirrors the loadGlobalConfigsIntoEnv logic from http.ts
13
+ */
14
+ function loadGlobalConfigsIntoEnv(override = false): string[] {
15
+ const globalConfigs = getResolvedConfig();
16
+ const updated: string[] = [];
17
+ for (const config of globalConfigs) {
18
+ if (override || !process.env[config.key]) {
19
+ process.env[config.key] = config.value;
20
+ updated.push(config.key);
21
+ }
22
+ }
23
+ return updated;
24
+ }
25
+
26
+ // Minimal HTTP handler for the reload-config endpoint
27
+ function createTestServer(): Server {
28
+ return createHttpServer(async (req, res) => {
29
+ if (req.method === "POST" && req.url === "/internal/reload-config") {
30
+ try {
31
+ const updated = loadGlobalConfigsIntoEnv(true);
32
+
33
+ const integrations: string[] = [];
34
+
35
+ resetAgentMail();
36
+ if (initAgentMail()) integrations.push("agentmail");
37
+
38
+ resetGitHub();
39
+ if (initGitHub()) integrations.push("github");
40
+
41
+ res.writeHead(200, { "Content-Type": "application/json" });
42
+ res.end(
43
+ JSON.stringify({
44
+ success: true,
45
+ configsLoaded: updated.length,
46
+ keysUpdated: updated,
47
+ integrationsReinitialized: integrations,
48
+ }),
49
+ );
50
+ } catch (e) {
51
+ const message = e instanceof Error ? e.message : String(e);
52
+ res.writeHead(500, { "Content-Type": "application/json" });
53
+ res.end(JSON.stringify({ error: "Failed to reload config", details: message }));
54
+ }
55
+ return;
56
+ }
57
+
58
+ res.writeHead(404, { "Content-Type": "application/json" });
59
+ res.end(JSON.stringify({ error: "Not found" }));
60
+ });
61
+ }
62
+
63
+ describe("reload-config", () => {
64
+ let server: Server;
65
+ const baseUrl = `http://localhost:${TEST_PORT}`;
66
+
67
+ // Track env keys we set so we can clean them up
68
+ const envKeysToClean: string[] = [];
69
+
70
+ beforeAll(async () => {
71
+ initDb(TEST_DB_PATH);
72
+
73
+ server = createTestServer();
74
+ await new Promise<void>((resolve) => {
75
+ server.listen(TEST_PORT, () => resolve());
76
+ });
77
+ });
78
+
79
+ afterAll(async () => {
80
+ server.close();
81
+ closeDb();
82
+ // Clean up env vars we set
83
+ for (const key of envKeysToClean) {
84
+ delete process.env[key];
85
+ }
86
+ await unlink(TEST_DB_PATH).catch(() => {});
87
+ });
88
+
89
+ test("POST /internal/reload-config returns 200 with empty DB", async () => {
90
+ const res = await fetch(`${baseUrl}/internal/reload-config`, { method: "POST" });
91
+ expect(res.status).toBe(200);
92
+ const body = await res.json();
93
+ expect(body.success).toBe(true);
94
+ expect(body.configsLoaded).toBe(0);
95
+ expect(body.keysUpdated).toEqual([]);
96
+ });
97
+
98
+ test("loadGlobalConfigsIntoEnv loads DB configs into process.env", () => {
99
+ const testKey = `__TEST_RELOAD_KEY_${Date.now()}`;
100
+ envKeysToClean.push(testKey);
101
+
102
+ upsertSwarmConfig({
103
+ scope: "global",
104
+ key: testKey,
105
+ value: "test-value-123",
106
+ });
107
+
108
+ const updated = loadGlobalConfigsIntoEnv(false);
109
+ expect(updated).toContain(testKey);
110
+ expect(process.env[testKey]).toBe("test-value-123");
111
+ });
112
+
113
+ test("loadGlobalConfigsIntoEnv does not override existing env vars when override=false", () => {
114
+ const testKey = `__TEST_NO_OVERRIDE_${Date.now()}`;
115
+ envKeysToClean.push(testKey);
116
+
117
+ process.env[testKey] = "original-value";
118
+
119
+ upsertSwarmConfig({
120
+ scope: "global",
121
+ key: testKey,
122
+ value: "db-value",
123
+ });
124
+
125
+ const updated = loadGlobalConfigsIntoEnv(false);
126
+ expect(updated).not.toContain(testKey);
127
+ expect(process.env[testKey]).toBe("original-value");
128
+ });
129
+
130
+ test("loadGlobalConfigsIntoEnv overrides existing env vars when override=true", () => {
131
+ const testKey = `__TEST_OVERRIDE_${Date.now()}`;
132
+ envKeysToClean.push(testKey);
133
+
134
+ process.env[testKey] = "original-value";
135
+
136
+ upsertSwarmConfig({
137
+ scope: "global",
138
+ key: testKey,
139
+ value: "new-db-value",
140
+ });
141
+
142
+ const updated = loadGlobalConfigsIntoEnv(true);
143
+ expect(updated).toContain(testKey);
144
+ expect(process.env[testKey]).toBe("new-db-value");
145
+ });
146
+
147
+ test("POST /internal/reload-config loads configs and returns summary", async () => {
148
+ const testKey = `__TEST_RELOAD_ENDPOINT_${Date.now()}`;
149
+ envKeysToClean.push(testKey);
150
+
151
+ upsertSwarmConfig({
152
+ scope: "global",
153
+ key: testKey,
154
+ value: "endpoint-test-value",
155
+ });
156
+
157
+ const res = await fetch(`${baseUrl}/internal/reload-config`, { method: "POST" });
158
+ expect(res.status).toBe(200);
159
+ const body = await res.json();
160
+ expect(body.success).toBe(true);
161
+ expect(body.configsLoaded).toBeGreaterThan(0);
162
+ expect(body.keysUpdated).toContain(testKey);
163
+ expect(process.env[testKey]).toBe("endpoint-test-value");
164
+ });
165
+
166
+ test("unknown endpoint returns 404", async () => {
167
+ const res = await fetch(`${baseUrl}/nonexistent`, { method: "POST" });
168
+ expect(res.status).toBe(404);
169
+ });
170
+ });
@@ -108,17 +108,21 @@ async function handleRequest(
108
108
  };
109
109
  }
110
110
 
111
- if (agent.isLead) {
112
- const inbox = getInboxSummary(myAgentId);
113
- if (inbox.mentionsCount > 0) {
114
- return {
115
- trigger: {
116
- type: "unread_mentions",
117
- mentionsCount: inbox.mentionsCount,
118
- },
119
- };
120
- }
111
+ // Check for unread mentions - all agents can be woken by @mentions
112
+ const inbox = getInboxSummary(myAgentId);
113
+ if (inbox.mentionsCount > 0) {
114
+ return {
115
+ trigger: {
116
+ type: "unread_mentions",
117
+ mentionsCount: inbox.mentionsCount,
118
+ },
119
+ };
120
+ }
121
121
 
122
+ if (agent.isLead) {
123
+ // Lead-specific triggers would go here (inbox, epics, etc.)
124
+ } else {
125
+ // Worker-specific: check for unassigned tasks in pool
122
126
  const unassignedCount = getUnassignedTasksCount();
123
127
  if (unassignedCount > 0) {
124
128
  return {
@@ -454,7 +458,7 @@ describe("Runner-Level Polling API", () => {
454
458
  expect(data.trigger.taskId).toBe(task.id);
455
459
  });
456
460
 
457
- test("should return pool_tasks_available for lead when unassigned tasks exist", async () => {
461
+ test("lead should NOT see pool_tasks_available (pool tasks are worker-only)", async () => {
458
462
  const leadId = "test-lead-poll";
459
463
 
460
464
  // Create lead agent
@@ -487,13 +491,12 @@ describe("Runner-Level Polling API", () => {
487
491
  status?: string;
488
492
  trigger?: unknown;
489
493
  };
490
- expect(data.trigger).not.toBeNull();
491
- expect(data.trigger.type).toBe("pool_tasks_available");
492
- expect(data.trigger.count).toBeGreaterThan(0);
494
+ // Leads don't see pool_tasks_available — only workers do
495
+ expect(data.trigger).toBeNull();
493
496
  });
494
497
 
495
- test("worker should NOT see pool_tasks_available trigger", async () => {
496
- const workerId = "test-worker-no-pool";
498
+ test("worker should see pool_tasks_available trigger when unassigned tasks exist", async () => {
499
+ const workerId = "test-worker-pool";
497
500
 
498
501
  // Create worker agent (not lead)
499
502
  await fetch(`${baseUrl}/api/agents`, {
@@ -502,7 +505,7 @@ describe("Runner-Level Polling API", () => {
502
505
  "Content-Type": "application/json",
503
506
  "X-Agent-ID": workerId,
504
507
  },
505
- body: JSON.stringify({ name: "Worker No Pool Access", isLead: false }),
508
+ body: JSON.stringify({ name: "Worker Pool Access", isLead: false }),
506
509
  });
507
510
 
508
511
  // There's already an unassigned task from previous test
@@ -519,10 +522,12 @@ describe("Runner-Level Polling API", () => {
519
522
  id?: string;
520
523
  name?: string;
521
524
  status?: string;
522
- trigger?: unknown;
525
+ trigger?: { type: string; count?: number };
523
526
  };
524
- // Worker should NOT see pool tasks
525
- expect(data.trigger).toBeNull();
527
+ // Workers should see pool tasks so they can compete to claim them
528
+ expect(data.trigger).not.toBeNull();
529
+ expect(data.trigger!.type).toBe("pool_tasks_available");
530
+ expect(data.trigger!.count).toBeGreaterThan(0);
526
531
  });
527
532
  });
528
533
  });
@@ -498,4 +498,108 @@ describe("Scheduled Tasks Integration", () => {
498
498
  expect(tasks.count).toBe(2);
499
499
  });
500
500
  });
501
+
502
+ describe("One-Time Schedules", () => {
503
+ test("create one-time schedule with delayMs computes nextRunAt", () => {
504
+ const before = Date.now();
505
+ const schedule = createScheduledTask({
506
+ name: "one-time-delay-test",
507
+ taskTemplate: "One-time delay task",
508
+ scheduleType: "one_time",
509
+ nextRunAt: new Date(before + 60000).toISOString(),
510
+ createdByAgentId: testAgent.id,
511
+ });
512
+
513
+ expect(schedule.scheduleType).toBe("one_time");
514
+ expect(schedule.nextRunAt).toBeDefined();
515
+ expect(schedule.enabled).toBe(true);
516
+ expect(schedule.cronExpression).toBeUndefined();
517
+ expect(schedule.intervalMs).toBeUndefined();
518
+ });
519
+
520
+ test("create one-time schedule with runAt stores nextRunAt", () => {
521
+ const runAt = new Date(Date.now() + 120000).toISOString();
522
+ const schedule = createScheduledTask({
523
+ name: "one-time-runat-test",
524
+ taskTemplate: "One-time runAt task",
525
+ scheduleType: "one_time",
526
+ nextRunAt: runAt,
527
+ createdByAgentId: testAgent.id,
528
+ });
529
+
530
+ expect(schedule.scheduleType).toBe("one_time");
531
+ expect(schedule.nextRunAt).toBe(runAt);
532
+ });
533
+
534
+ test("one-time schedule does not require cronExpression or intervalMs", () => {
535
+ const schedule = createScheduledTask({
536
+ name: "one-time-no-cron-test",
537
+ taskTemplate: "No cron needed",
538
+ scheduleType: "one_time",
539
+ nextRunAt: new Date(Date.now() + 60000).toISOString(),
540
+ });
541
+
542
+ expect(schedule.scheduleType).toBe("one_time");
543
+ expect(schedule.cronExpression).toBeUndefined();
544
+ expect(schedule.intervalMs).toBeUndefined();
545
+ });
546
+
547
+ test("executing one-time schedule auto-disables it", async () => {
548
+ const schedule = createScheduledTask({
549
+ name: "one-time-exec-test",
550
+ taskTemplate: "Execute and disable",
551
+ scheduleType: "one_time",
552
+ nextRunAt: new Date(Date.now() - 1000).toISOString(), // due now
553
+ createdByAgentId: testAgent.id,
554
+ });
555
+
556
+ // Run it manually
557
+ await runScheduleNow(schedule.id);
558
+
559
+ const updated = getScheduledTaskById(schedule.id);
560
+ expect(updated).not.toBeNull();
561
+ expect(updated!.enabled).toBe(false);
562
+ expect(updated!.lastRunAt).toBeDefined();
563
+ expect(updated!.nextRunAt).toBeUndefined();
564
+ });
565
+
566
+ test("one-time schedules hidden by default in list", () => {
567
+ // The executed one-time schedule from the previous test should be hidden
568
+ const allSchedules = getScheduledTasks({ hideCompleted: true });
569
+ const executedOneTime = allSchedules.find((s) => s.name === "one-time-exec-test");
570
+ expect(executedOneTime).toBeUndefined();
571
+
572
+ // But visible when hideCompleted is false
573
+ const allIncluding = getScheduledTasks({ hideCompleted: false });
574
+ const found = allIncluding.find((s) => s.name === "one-time-exec-test");
575
+ expect(found).toBeDefined();
576
+ expect(found!.scheduleType).toBe("one_time");
577
+ });
578
+
579
+ test("filter by scheduleType works", () => {
580
+ const oneTimeOnly = getScheduledTasks({
581
+ scheduleType: "one_time",
582
+ hideCompleted: false,
583
+ });
584
+ expect(oneTimeOnly.length).toBeGreaterThan(0);
585
+ for (const s of oneTimeOnly) {
586
+ expect(s.scheduleType).toBe("one_time");
587
+ }
588
+
589
+ const recurringOnly = getScheduledTasks({ scheduleType: "recurring" });
590
+ for (const s of recurringOnly) {
591
+ expect(s.scheduleType).toBe("recurring");
592
+ }
593
+ });
594
+
595
+ test("existing recurring schedules default to scheduleType recurring", () => {
596
+ const schedule = createScheduledTask({
597
+ name: "recurring-default-test",
598
+ taskTemplate: "Should be recurring",
599
+ cronExpression: "0 * * * *",
600
+ });
601
+
602
+ expect(schedule.scheduleType).toBe("recurring");
603
+ });
604
+ });
501
605
  });