@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,166 @@
1
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
+ import { unlink } from "node:fs/promises";
3
+ import {
4
+ closeDb,
5
+ createScheduledTask,
6
+ getScheduledTaskById,
7
+ initDb,
8
+ updateScheduledTask,
9
+ } from "../be/db";
10
+
11
+ const TEST_DB_PATH = "./test-scheduler-backoff.sqlite";
12
+
13
+ describe("scheduler exponential backoff", () => {
14
+ beforeAll(() => {
15
+ initDb(TEST_DB_PATH);
16
+ });
17
+
18
+ afterAll(async () => {
19
+ closeDb();
20
+ try {
21
+ await unlink(TEST_DB_PATH);
22
+ await unlink(`${TEST_DB_PATH}-wal`);
23
+ await unlink(`${TEST_DB_PATH}-shm`);
24
+ } catch {
25
+ // ignore
26
+ }
27
+ });
28
+
29
+ test("new scheduled tasks have consecutiveErrors = 0", () => {
30
+ const schedule = createScheduledTask({
31
+ name: "backoff-test-1",
32
+ taskTemplate: "Test task",
33
+ intervalMs: 60000,
34
+ });
35
+
36
+ expect(schedule.consecutiveErrors).toBe(0);
37
+ expect(schedule.lastErrorAt).toBeUndefined();
38
+ expect(schedule.lastErrorMessage).toBeUndefined();
39
+ });
40
+
41
+ test("updateScheduledTask can set error tracking fields", () => {
42
+ const schedule = createScheduledTask({
43
+ name: "backoff-test-2",
44
+ taskTemplate: "Test task",
45
+ intervalMs: 60000,
46
+ });
47
+
48
+ const now = new Date().toISOString();
49
+ const updated = updateScheduledTask(schedule.id, {
50
+ consecutiveErrors: 3,
51
+ lastErrorAt: now,
52
+ lastErrorMessage: "Connection refused",
53
+ });
54
+
55
+ expect(updated).not.toBeNull();
56
+ expect(updated!.consecutiveErrors).toBe(3);
57
+ expect(updated!.lastErrorAt).toBe(now);
58
+ expect(updated!.lastErrorMessage).toBe("Connection refused");
59
+ });
60
+
61
+ test("error tracking can be reset to 0 on success", () => {
62
+ const schedule = createScheduledTask({
63
+ name: "backoff-test-3",
64
+ taskTemplate: "Test task",
65
+ intervalMs: 60000,
66
+ });
67
+
68
+ // Simulate errors
69
+ updateScheduledTask(schedule.id, {
70
+ consecutiveErrors: 4,
71
+ lastErrorAt: new Date().toISOString(),
72
+ lastErrorMessage: "Some error",
73
+ });
74
+
75
+ // Simulate successful execution — reset errors
76
+ const updated = updateScheduledTask(schedule.id, {
77
+ consecutiveErrors: 0,
78
+ lastErrorAt: null,
79
+ lastErrorMessage: null,
80
+ });
81
+
82
+ expect(updated!.consecutiveErrors).toBe(0);
83
+ expect(updated!.lastErrorAt).toBeUndefined();
84
+ expect(updated!.lastErrorMessage).toBeUndefined();
85
+ });
86
+
87
+ test("schedule can be auto-disabled via enabled = false", () => {
88
+ const schedule = createScheduledTask({
89
+ name: "backoff-test-4",
90
+ taskTemplate: "Test task",
91
+ intervalMs: 60000,
92
+ });
93
+
94
+ expect(schedule.enabled).toBe(true);
95
+
96
+ // Simulate auto-disable after MAX_CONSECUTIVE_ERRORS
97
+ const updated = updateScheduledTask(schedule.id, {
98
+ consecutiveErrors: 5,
99
+ lastErrorAt: new Date().toISOString(),
100
+ lastErrorMessage: "Repeated failure",
101
+ enabled: false,
102
+ });
103
+
104
+ expect(updated!.enabled).toBe(false);
105
+ expect(updated!.consecutiveErrors).toBe(5);
106
+ });
107
+
108
+ test("nextRunAt can be pushed forward for backoff", () => {
109
+ const schedule = createScheduledTask({
110
+ name: "backoff-test-5",
111
+ taskTemplate: "Test task",
112
+ intervalMs: 60000,
113
+ });
114
+
115
+ const now = new Date();
116
+ const backoffMs = 300_000; // 5 minutes
117
+ const backoffTime = new Date(now.getTime() + backoffMs).toISOString();
118
+
119
+ const updated = updateScheduledTask(schedule.id, {
120
+ consecutiveErrors: 2,
121
+ lastErrorAt: now.toISOString(),
122
+ lastErrorMessage: "Timeout",
123
+ nextRunAt: backoffTime,
124
+ });
125
+
126
+ expect(updated!.nextRunAt).toBe(backoffTime);
127
+ expect(updated!.consecutiveErrors).toBe(2);
128
+ });
129
+
130
+ test("error message is truncated to 500 chars", () => {
131
+ const schedule = createScheduledTask({
132
+ name: "backoff-test-6",
133
+ taskTemplate: "Test task",
134
+ intervalMs: 60000,
135
+ });
136
+
137
+ const longMessage = "x".repeat(1000);
138
+ const updated = updateScheduledTask(schedule.id, {
139
+ consecutiveErrors: 1,
140
+ lastErrorAt: new Date().toISOString(),
141
+ lastErrorMessage: longMessage.slice(0, 500),
142
+ });
143
+
144
+ expect(updated!.lastErrorMessage!.length).toBe(500);
145
+ });
146
+
147
+ test("consecutiveErrors persists across reads", () => {
148
+ const schedule = createScheduledTask({
149
+ name: "backoff-test-7",
150
+ taskTemplate: "Test task",
151
+ intervalMs: 60000,
152
+ });
153
+
154
+ updateScheduledTask(schedule.id, {
155
+ consecutiveErrors: 3,
156
+ lastErrorAt: new Date().toISOString(),
157
+ lastErrorMessage: "Error 3",
158
+ });
159
+
160
+ // Read back from DB
161
+ const reloaded = getScheduledTaskById(schedule.id);
162
+ expect(reloaded).not.toBeNull();
163
+ expect(reloaded!.consecutiveErrors).toBe(3);
164
+ expect(reloaded!.lastErrorMessage).toBe("Error 3");
165
+ });
166
+ });
@@ -0,0 +1,541 @@
1
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
+ import { unlink } from "node:fs/promises";
3
+ import {
4
+ closeDb,
5
+ completeTask,
6
+ createAgent,
7
+ createEpic,
8
+ createMemory,
9
+ createTaskExtended,
10
+ failTask,
11
+ getAgentById,
12
+ initDb,
13
+ searchMemoriesByVector,
14
+ updateMemoryEmbedding,
15
+ } from "../be/db";
16
+ import { serializeEmbedding } from "../be/embedding";
17
+ import { getBasePrompt } from "../prompts/base-prompt";
18
+
19
+ const TEST_DB_PATH = "./test-self-improvement.sqlite";
20
+
21
+ describe("Self-Improvement Mechanisms", () => {
22
+ const leadId = "aaaa0000-0000-4000-8000-000000000001";
23
+ const workerId = "bbbb0000-0000-4000-8000-000000000002";
24
+ const otherWorkerId = "cccc0000-0000-4000-8000-000000000003";
25
+
26
+ beforeAll(async () => {
27
+ for (const suffix of ["", "-wal", "-shm"]) {
28
+ try {
29
+ await unlink(TEST_DB_PATH + suffix);
30
+ } catch {
31
+ // File doesn't exist
32
+ }
33
+ }
34
+
35
+ closeDb();
36
+ initDb(TEST_DB_PATH);
37
+
38
+ createAgent({ id: leadId, name: "Test Lead", isLead: true, status: "idle" });
39
+ createAgent({ id: workerId, name: "Test Worker", isLead: false, status: "idle" });
40
+ createAgent({ id: otherWorkerId, name: "Other Worker", isLead: false, status: "idle" });
41
+ });
42
+
43
+ afterAll(async () => {
44
+ closeDb();
45
+ for (const suffix of ["", "-wal", "-shm"]) {
46
+ try {
47
+ await unlink(TEST_DB_PATH + suffix);
48
+ } catch {
49
+ // File doesn't exist
50
+ }
51
+ }
52
+ });
53
+
54
+ // ==========================================================================
55
+ // P2: store-progress memory indexing for completed and failed tasks
56
+ // ==========================================================================
57
+
58
+ describe("store-progress memory indexing", () => {
59
+ test("completed task creates agent-scoped memory with output", () => {
60
+ const task = createTaskExtended("Test task for completion", {
61
+ agentId: workerId,
62
+ source: "mcp",
63
+ priority: 50,
64
+ });
65
+
66
+ const output = "Successfully completed the task with great results";
67
+ completeTask(task.id, output);
68
+
69
+ // Simulate what store-progress does: create memory for completed task
70
+ const taskContent = `Task: ${task.task}\n\nOutput:\n${output}`;
71
+ const memory = createMemory({
72
+ agentId: workerId,
73
+ content: taskContent,
74
+ name: `Task: ${task.task.slice(0, 80)}`,
75
+ scope: "agent",
76
+ source: "task_completion",
77
+ sourceTaskId: task.id,
78
+ });
79
+
80
+ expect(memory.scope).toBe("agent");
81
+ expect(memory.source).toBe("task_completion");
82
+ expect(memory.sourceTaskId).toBe(task.id);
83
+ expect(memory.content).toContain("Output:");
84
+ expect(memory.content).toContain(output);
85
+ expect(memory.content).not.toContain("undefined");
86
+ });
87
+
88
+ test("completed task with undefined output uses fallback", () => {
89
+ const task = createTaskExtended("Task without output", {
90
+ agentId: workerId,
91
+ source: "mcp",
92
+ priority: 50,
93
+ });
94
+
95
+ const output: string | undefined = undefined;
96
+ completeTask(task.id, output);
97
+
98
+ // Simulate store-progress logic with undefined guard
99
+ const taskContent = `Task: ${task.task}\n\nOutput:\n${output || "(no output)"}`;
100
+
101
+ expect(taskContent).toContain("(no output)");
102
+ expect(taskContent).not.toContain("undefined");
103
+ });
104
+
105
+ test("failed task creates memory with failure reason", () => {
106
+ const task = createTaskExtended("Task that will fail", {
107
+ agentId: workerId,
108
+ source: "mcp",
109
+ priority: 50,
110
+ });
111
+
112
+ const failureReason = "Could not connect to external API";
113
+ failTask(task.id, failureReason);
114
+
115
+ // Simulate store-progress failed task memory creation
116
+ const taskContent = `Task: ${task.task}\n\nFailure reason:\n${failureReason}\n\nThis task failed. Learn from this to avoid repeating the mistake.`;
117
+ const memory = createMemory({
118
+ agentId: workerId,
119
+ content: taskContent,
120
+ name: `Task: ${task.task.slice(0, 80)}`,
121
+ scope: "agent",
122
+ source: "task_completion",
123
+ sourceTaskId: task.id,
124
+ });
125
+
126
+ expect(memory.source).toBe("task_completion");
127
+ expect(memory.content).toContain("Failure reason:");
128
+ expect(memory.content).toContain(failureReason);
129
+ expect(memory.content).toContain("Learn from this");
130
+ });
131
+
132
+ test("failed task with undefined failureReason uses fallback", () => {
133
+ const failureReason: string | undefined = undefined;
134
+
135
+ // Simulate store-progress logic with undefined guard
136
+ const taskContent = `Task: Some task\n\nFailure reason:\n${failureReason || "No reason provided"}\n\nThis task failed.`;
137
+
138
+ expect(taskContent).toContain("No reason provided");
139
+ expect(taskContent).not.toContain("undefined");
140
+ });
141
+
142
+ test("short task content is skipped (< 30 chars)", () => {
143
+ // Simulate the length check in store-progress
144
+ const shortContent = "Task: X\n\nOutput:\n";
145
+ expect(shortContent.length).toBeLessThan(30);
146
+ // In store-progress, this would return early without creating memory
147
+ });
148
+ });
149
+
150
+ // ==========================================================================
151
+ // P3: Swarm memory auto-promotion
152
+ // ==========================================================================
153
+
154
+ describe("swarm memory auto-promotion", () => {
155
+ test("research task type promotes to swarm scope", () => {
156
+ const task = createTaskExtended("Research best practices for testing", {
157
+ agentId: workerId,
158
+ source: "mcp",
159
+ priority: 50,
160
+ taskType: "research",
161
+ });
162
+
163
+ completeTask(task.id, "Found several useful patterns");
164
+
165
+ // Simulate the shouldShareWithSwarm logic
166
+ const shouldShareWithSwarm =
167
+ task.taskType === "research" ||
168
+ task.tags?.includes("knowledge") ||
169
+ task.tags?.includes("shared");
170
+
171
+ expect(shouldShareWithSwarm).toBe(true);
172
+
173
+ // Verify swarm memory can be created
174
+ const swarmMemory = createMemory({
175
+ agentId: workerId,
176
+ scope: "swarm",
177
+ name: `Shared: ${task.task.slice(0, 80)}`,
178
+ content: `Task completed by agent ${workerId}:\n\nTask: ${task.task}\n\nOutput:\nFound several useful patterns`,
179
+ source: "task_completion",
180
+ sourceTaskId: task.id,
181
+ });
182
+
183
+ expect(swarmMemory.scope).toBe("swarm");
184
+ expect(swarmMemory.source).toBe("task_completion");
185
+ });
186
+
187
+ test("knowledge-tagged task promotes to swarm scope", () => {
188
+ const task = createTaskExtended("Document API conventions", {
189
+ agentId: workerId,
190
+ source: "mcp",
191
+ priority: 50,
192
+ tags: ["knowledge"],
193
+ });
194
+
195
+ const shouldShareWithSwarm =
196
+ task.taskType === "research" ||
197
+ task.tags?.includes("knowledge") ||
198
+ task.tags?.includes("shared");
199
+
200
+ expect(shouldShareWithSwarm).toBe(true);
201
+ });
202
+
203
+ test("shared-tagged task promotes to swarm scope", () => {
204
+ const task = createTaskExtended("Build shared utility", {
205
+ agentId: workerId,
206
+ source: "mcp",
207
+ priority: 50,
208
+ tags: ["shared", "utility"],
209
+ });
210
+
211
+ const shouldShareWithSwarm =
212
+ task.taskType === "research" ||
213
+ task.tags?.includes("knowledge") ||
214
+ task.tags?.includes("shared");
215
+
216
+ expect(shouldShareWithSwarm).toBe(true);
217
+ });
218
+
219
+ test("epic-linked task promotes to swarm scope", () => {
220
+ const epic = createEpic({
221
+ name: "Test Epic for Promotion",
222
+ goal: "Test that epic-linked tasks promote to swarm scope",
223
+ createdByAgentId: leadId,
224
+ });
225
+
226
+ const task = createTaskExtended("Implement feature X for epic", {
227
+ agentId: workerId,
228
+ source: "mcp",
229
+ priority: 50,
230
+ taskType: "implementation",
231
+ epicId: epic.id,
232
+ });
233
+
234
+ const shouldShareWithSwarm =
235
+ task.taskType === "research" ||
236
+ task.tags?.includes("knowledge") ||
237
+ task.tags?.includes("shared") ||
238
+ task.epicId != null;
239
+
240
+ expect(shouldShareWithSwarm).toBe(true);
241
+ });
242
+
243
+ test("regular task without epicId does NOT promote to swarm scope", () => {
244
+ const task = createTaskExtended("Fix a typo", {
245
+ agentId: workerId,
246
+ source: "mcp",
247
+ priority: 50,
248
+ taskType: "quick-fix",
249
+ tags: ["bug-fix"],
250
+ });
251
+
252
+ const shouldShareWithSwarm =
253
+ task.taskType === "research" ||
254
+ task.tags?.includes("knowledge") ||
255
+ task.tags?.includes("shared") ||
256
+ task.epicId != null;
257
+
258
+ expect(shouldShareWithSwarm).toBe(false);
259
+ });
260
+
261
+ test("failed task does NOT promote to swarm scope", () => {
262
+ const task = createTaskExtended("Research something", {
263
+ agentId: workerId,
264
+ source: "mcp",
265
+ priority: 50,
266
+ taskType: "research",
267
+ });
268
+
269
+ const status = "failed";
270
+ // In store-progress, shouldShareWithSwarm only fires for status === "completed"
271
+ const shouldShareWithSwarm =
272
+ status === "completed" &&
273
+ (task.taskType === "research" ||
274
+ task.tags?.includes("knowledge") ||
275
+ task.tags?.includes("shared") ||
276
+ task.epicId != null);
277
+
278
+ expect(shouldShareWithSwarm).toBe(false);
279
+ });
280
+ });
281
+
282
+ // ==========================================================================
283
+ // P6: inject-learning tool
284
+ // ==========================================================================
285
+
286
+ describe("inject-learning tool logic", () => {
287
+ test("lead agent can inject learning into worker memory (swarm-scoped)", () => {
288
+ const callerAgent = getAgentById(leadId);
289
+ expect(callerAgent).not.toBeNull();
290
+ expect(callerAgent!.isLead).toBe(true);
291
+
292
+ const category = "best-practice";
293
+ const learning = "Always run lint before committing";
294
+ const content = `[Lead Feedback — ${category}]\n\n${learning}`;
295
+
296
+ const memory = createMemory({
297
+ agentId: workerId,
298
+ scope: "swarm",
299
+ name: `Lead feedback: ${category} — ${learning.slice(0, 60)}`,
300
+ content,
301
+ source: "manual",
302
+ });
303
+
304
+ expect(memory.agentId).toBe(workerId);
305
+ expect(memory.scope).toBe("swarm");
306
+ expect(memory.content).toContain("[Lead Feedback — best-practice]");
307
+ expect(memory.content).toContain(learning);
308
+ });
309
+
310
+ test("non-lead agent is rejected", () => {
311
+ const callerAgent = getAgentById(workerId);
312
+ expect(callerAgent).not.toBeNull();
313
+ expect(callerAgent!.isLead).toBe(false);
314
+
315
+ // In the tool handler, this check prevents non-leads from injecting
316
+ const canInject = callerAgent!.isLead;
317
+ expect(canInject).toBe(false);
318
+ });
319
+
320
+ test("injected learning is visible to target worker in memory search", () => {
321
+ // Create memory with embedding for searchability
322
+ const content = "[Lead Feedback — mistake-pattern]\n\nNever force-push to main branch";
323
+ const memory = createMemory({
324
+ agentId: workerId,
325
+ scope: "agent",
326
+ name: "Lead feedback: mistake-pattern — Never force-push to main branch",
327
+ content,
328
+ source: "manual",
329
+ });
330
+
331
+ const embedding = new Float32Array([0.7, 0.3, 0.0]);
332
+ updateMemoryEmbedding(memory.id, serializeEmbedding(embedding));
333
+
334
+ // Worker can find it via search
335
+ const results = searchMemoriesByVector(new Float32Array([0.7, 0.3, 0.0]), workerId, {
336
+ isLead: false,
337
+ scope: "agent",
338
+ });
339
+
340
+ const found = results.find((r) => r.id === memory.id);
341
+ expect(found).toBeDefined();
342
+ expect(found!.content).toContain("Never force-push");
343
+ });
344
+
345
+ test("injected learning is NOT visible to other workers", () => {
346
+ const content = "[Lead Feedback — preference]\n\nUse bun instead of npm";
347
+ const memory = createMemory({
348
+ agentId: workerId,
349
+ scope: "agent",
350
+ name: "Lead feedback: preference — Use bun instead of npm",
351
+ content,
352
+ source: "manual",
353
+ });
354
+
355
+ const embedding = new Float32Array([0.2, 0.8, 0.1]);
356
+ updateMemoryEmbedding(memory.id, serializeEmbedding(embedding));
357
+
358
+ // Other worker should NOT see it
359
+ const results = searchMemoriesByVector(new Float32Array([0.2, 0.8, 0.1]), otherWorkerId, {
360
+ isLead: false,
361
+ scope: "agent",
362
+ });
363
+
364
+ const found = results.find((r) => r.id === memory.id);
365
+ expect(found).toBeUndefined();
366
+ });
367
+
368
+ test("learning categories are properly formatted", () => {
369
+ const categories = ["mistake-pattern", "best-practice", "codebase-knowledge", "preference"];
370
+
371
+ for (const category of categories) {
372
+ const content = `[Lead Feedback — ${category}]\n\nSome learning`;
373
+ expect(content).toContain(`[Lead Feedback — ${category}]`);
374
+ }
375
+ });
376
+ });
377
+
378
+ // ==========================================================================
379
+ // P7: Memory search agent ID security
380
+ // ==========================================================================
381
+
382
+ describe("memory search agent ID security", () => {
383
+ test("agent can only search their own memories (not others)", () => {
384
+ // Create private memories for worker and other worker
385
+ const workerMemory = createMemory({
386
+ agentId: workerId,
387
+ scope: "agent",
388
+ name: "Worker Private Secret",
389
+ content: "My secret API key pattern",
390
+ source: "manual",
391
+ });
392
+ updateMemoryEmbedding(workerMemory.id, serializeEmbedding(new Float32Array([0.5, 0.5, 0.0])));
393
+
394
+ const otherMemory = createMemory({
395
+ agentId: otherWorkerId,
396
+ scope: "agent",
397
+ name: "Other Worker Secret",
398
+ content: "Other agent's private data",
399
+ source: "manual",
400
+ });
401
+ updateMemoryEmbedding(otherMemory.id, serializeEmbedding(new Float32Array([0.5, 0.5, 0.0])));
402
+
403
+ // Worker searching with their own ID should see their memory but not other's
404
+ const workerResults = searchMemoriesByVector(new Float32Array([0.5, 0.5, 0.0]), workerId, {
405
+ isLead: false,
406
+ scope: "all",
407
+ });
408
+
409
+ const workerNames = workerResults.map((r) => r.name);
410
+ expect(workerNames).toContain("Worker Private Secret");
411
+ expect(workerNames).not.toContain("Other Worker Secret");
412
+ });
413
+
414
+ test("missing agent ID should be rejected (endpoint logic)", () => {
415
+ // Simulate the endpoint logic: searchAgentId = myAgentId (from header only)
416
+ const myAgentId: string | undefined = undefined;
417
+ const searchAgentId = myAgentId; // No fallback to body.agentId
418
+
419
+ // The endpoint requires both query and searchAgentId
420
+ const isValid = !!searchAgentId;
421
+ expect(isValid).toBe(false);
422
+ });
423
+
424
+ test("agent ID from header is used, not from body", () => {
425
+ // Simulate the fixed logic
426
+ const headerAgentId = workerId;
427
+ const _bodyAgentId = otherWorkerId; // attacker trying to access other agent's memories
428
+
429
+ // Fixed code: searchAgentId = myAgentId (from header only)
430
+ const searchAgentId = headerAgentId; // NOT: headerAgentId || bodyAgentId
431
+
432
+ expect(searchAgentId).toBe(workerId);
433
+ expect(searchAgentId).not.toBe(otherWorkerId);
434
+ });
435
+ });
436
+
437
+ // ==========================================================================
438
+ // P2: Self-awareness in base prompt
439
+ // ==========================================================================
440
+
441
+ describe("base prompt self-awareness", () => {
442
+ test("base prompt includes 'How You Are Built' section", async () => {
443
+ const prompt = await getBasePrompt({
444
+ role: "worker",
445
+ agentId: workerId,
446
+ swarmUrl: "test.example.com",
447
+ });
448
+
449
+ expect(prompt).toContain("### How You Are Built");
450
+ expect(prompt).toContain("desplega-ai/agent-swarm");
451
+ expect(prompt).toContain("src/commands/runner.ts");
452
+ expect(prompt).toContain("src/hooks/hook.ts");
453
+ });
454
+
455
+ test("self-awareness section includes change proposal instructions", async () => {
456
+ const prompt = await getBasePrompt({
457
+ role: "worker",
458
+ agentId: workerId,
459
+ swarmUrl: "test.example.com",
460
+ });
461
+
462
+ expect(prompt).toContain("Proposing changes");
463
+ expect(prompt).toContain("@tarasyarema");
464
+ });
465
+
466
+ test("self-awareness is included for both worker and lead roles", async () => {
467
+ const workerPrompt = await getBasePrompt({
468
+ role: "worker",
469
+ agentId: workerId,
470
+ swarmUrl: "test.example.com",
471
+ });
472
+
473
+ const leadPrompt = await getBasePrompt({
474
+ role: "lead",
475
+ agentId: leadId,
476
+ swarmUrl: "test.example.com",
477
+ });
478
+
479
+ expect(workerPrompt).toContain("### How You Are Built");
480
+ expect(leadPrompt).toContain("### How You Are Built");
481
+ });
482
+ });
483
+
484
+ // ==========================================================================
485
+ // P4: Session summary "no significant learnings" filter
486
+ // ==========================================================================
487
+
488
+ describe("session summary filtering", () => {
489
+ test("'no significant learnings' response is filtered out", () => {
490
+ const summary = "No significant learnings.";
491
+
492
+ const shouldIndex =
493
+ summary &&
494
+ summary.length > 20 &&
495
+ !summary.trim().toLowerCase().includes("no significant learnings");
496
+
497
+ expect(shouldIndex).toBe(false);
498
+ });
499
+
500
+ test("summary with actual learnings passes filter", () => {
501
+ const summary =
502
+ "- Discovered that the API requires Bearer prefix on auth headers\n- Found that bun test runs faster with --bail flag";
503
+
504
+ const shouldIndex =
505
+ summary &&
506
+ summary.length > 20 &&
507
+ !summary.trim().toLowerCase().includes("no significant learnings");
508
+
509
+ expect(shouldIndex).toBe(true);
510
+ });
511
+
512
+ test("very short summary is filtered out", () => {
513
+ const summary = "Done.";
514
+
515
+ const shouldIndex =
516
+ summary &&
517
+ summary.length > 20 &&
518
+ !summary.trim().toLowerCase().includes("no significant learnings");
519
+
520
+ expect(shouldIndex).toBe(false);
521
+ });
522
+
523
+ test("case-insensitive matching for 'no significant learnings'", () => {
524
+ const variants = [
525
+ "No Significant Learnings.",
526
+ "NO SIGNIFICANT LEARNINGS",
527
+ "no significant learnings",
528
+ " No significant learnings. ",
529
+ ];
530
+
531
+ for (const summary of variants) {
532
+ const shouldIndex =
533
+ summary &&
534
+ summary.length > 20 &&
535
+ !summary.trim().toLowerCase().includes("no significant learnings");
536
+
537
+ expect(shouldIndex).toBe(false);
538
+ }
539
+ });
540
+ });
541
+ });