@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,490 @@
1
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
+ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
3
+ import http from "node:http";
4
+ import type { TemplateResponse } from "../../templates/schema.ts";
5
+ import { interpolate } from "../workflows/template.ts";
6
+
7
+ const CACHE_DIR = "/tmp/test-template-cache";
8
+
9
+ const mockTemplate: TemplateResponse = {
10
+ config: {
11
+ name: "coder",
12
+ displayName: "Coder",
13
+ description: "Test coder template",
14
+ version: "1.0.0",
15
+ category: "official",
16
+ icon: "code",
17
+ author: "Test <test@test.com>",
18
+ createdAt: "2026-03-09",
19
+ lastUpdatedAt: "2026-03-09",
20
+ agentDefaults: {
21
+ role: "worker",
22
+ capabilities: ["typescript", "react"],
23
+ maxTasks: 3,
24
+ },
25
+ files: {
26
+ claudeMd: "CLAUDE.md",
27
+ soulMd: "SOUL.md",
28
+ identityMd: "IDENTITY.md",
29
+ toolsMd: "TOOLS.md",
30
+ setupScript: "start-up.sh",
31
+ },
32
+ },
33
+ files: {
34
+ claudeMd: "# {{agent.name}} - {{agent.role}} Agent",
35
+ soulMd: "You are {{agent.name}}, a {{agent.role}} agent.",
36
+ identityMd: "Name: {{agent.name}}\nCapabilities: {{agent.capabilities}}",
37
+ toolsMd: "# Tools for {{agent.name}}",
38
+ setupScript: '#!/bin/bash\necho "Template: {{agent.role}}"',
39
+ },
40
+ };
41
+
42
+ let server: http.Server;
43
+ let serverPort: number;
44
+ let fetchCount = 0;
45
+
46
+ beforeAll(async () => {
47
+ await mkdir(CACHE_DIR, { recursive: true });
48
+
49
+ server = http.createServer((_req, res) => {
50
+ fetchCount++;
51
+ const url = _req.url || "";
52
+
53
+ if (url.includes("/api/templates/official/coder")) {
54
+ res.writeHead(200, { "Content-Type": "application/json" });
55
+ res.end(JSON.stringify(mockTemplate));
56
+ } else {
57
+ res.writeHead(404, { "Content-Type": "application/json" });
58
+ res.end(JSON.stringify({ error: "Not found" }));
59
+ }
60
+ });
61
+
62
+ await new Promise<void>((resolve) => {
63
+ server.listen(0, () => {
64
+ const addr = server.address();
65
+ serverPort = typeof addr === "object" && addr ? addr.port : 0;
66
+ resolve();
67
+ });
68
+ });
69
+ });
70
+
71
+ afterAll(async () => {
72
+ server.close();
73
+ await rm(CACHE_DIR, { recursive: true, force: true });
74
+ });
75
+
76
+ describe("Template interpolation", () => {
77
+ test("interpolates {{agent.name}} and {{agent.role}}", () => {
78
+ const result = interpolate("Hello {{agent.name}}, you are a {{agent.role}}", {
79
+ agent: { name: "TestBot", role: "worker" },
80
+ }).result;
81
+ expect(result).toBe("Hello TestBot, you are a worker");
82
+ });
83
+
84
+ test("replaces unknown placeholders with empty string", () => {
85
+ const result = interpolate("Hello {{agent.unknown}}", {
86
+ agent: { name: "TestBot" },
87
+ }).result;
88
+ expect(result).toBe("Hello ");
89
+ });
90
+
91
+ test("handles capabilities join", () => {
92
+ const ctx = {
93
+ agent: {
94
+ name: "Coder",
95
+ role: "worker",
96
+ capabilities: "typescript, react",
97
+ },
98
+ };
99
+ const result = interpolate("Caps: {{agent.capabilities}}", ctx).result;
100
+ expect(result).toBe("Caps: typescript, react");
101
+ });
102
+ });
103
+
104
+ describe("Template fetch and cache", () => {
105
+ test("fetches template from registry", async () => {
106
+ fetchCount = 0;
107
+ const resp = await fetch(`http://localhost:${serverPort}/api/templates/official/coder`);
108
+ expect(resp.ok).toBe(true);
109
+ const template = (await resp.json()) as TemplateResponse;
110
+ expect(template.config.name).toBe("coder");
111
+ expect(template.files.claudeMd).toContain("{{agent.name}}");
112
+ expect(fetchCount).toBe(1);
113
+ });
114
+
115
+ test("returns 404 for nonexistent template", async () => {
116
+ const resp = await fetch(`http://localhost:${serverPort}/api/templates/official/nonexistent`);
117
+ expect(resp.status).toBe(404);
118
+ });
119
+
120
+ test("caching: write and read from cache", async () => {
121
+ const cachePath = `${CACHE_DIR}/official_coder.json`;
122
+ await writeFile(cachePath, JSON.stringify(mockTemplate), "utf-8");
123
+
124
+ const cached = await readFile(cachePath, "utf-8");
125
+ const parsed = JSON.parse(cached) as TemplateResponse;
126
+ expect(parsed.config.name).toBe("coder");
127
+ expect(parsed.files.soulMd).toContain("{{agent.name}}");
128
+ });
129
+ });
130
+
131
+ describe("Template idempotency", () => {
132
+ test("first boot: empty profile fields get template content", () => {
133
+ let soulMd: string | undefined;
134
+ let identityMd: string | undefined;
135
+
136
+ const ctx = {
137
+ agent: { name: "MyAgent", role: "worker", capabilities: "ts, react" },
138
+ };
139
+
140
+ // Simulate: profile fields are empty, apply template
141
+ if (!soulMd) soulMd = interpolate(mockTemplate.files.soulMd, ctx).result;
142
+ if (!identityMd) identityMd = interpolate(mockTemplate.files.identityMd, ctx).result;
143
+
144
+ expect(soulMd).toBe("You are MyAgent, a worker agent.");
145
+ expect(identityMd).toContain("MyAgent");
146
+ });
147
+
148
+ test("second boot: existing profile fields are preserved (template NOT re-applied)", () => {
149
+ const existingSoul = "I am a customized soul that the agent edited.";
150
+ let soulMd: string | undefined = existingSoul;
151
+
152
+ const ctx = {
153
+ agent: { name: "MyAgent", role: "worker", capabilities: "ts, react" },
154
+ };
155
+
156
+ // Simulate: profile already exists, guard prevents template application
157
+ if (!soulMd) soulMd = interpolate(mockTemplate.files.soulMd, ctx).result;
158
+
159
+ // Original content preserved
160
+ expect(soulMd).toBe(existingSoul);
161
+ });
162
+
163
+ test("partial profile: only missing fields get template content", () => {
164
+ let soulMd: string | undefined = "Existing soul";
165
+ let claudeMd: string | undefined;
166
+
167
+ const ctx = {
168
+ agent: { name: "MyAgent", role: "worker", capabilities: "ts, react" },
169
+ };
170
+
171
+ if (!soulMd) soulMd = interpolate(mockTemplate.files.soulMd, ctx).result;
172
+ if (!claudeMd) claudeMd = interpolate(mockTemplate.files.claudeMd, ctx).result;
173
+
174
+ expect(soulMd).toBe("Existing soul");
175
+ expect(claudeMd).toBe("# MyAgent - worker Agent");
176
+ });
177
+
178
+ test("TEMPLATE_ID set but registry unreachable: falls back to defaults", () => {
179
+ // Simulate: fetch returned null, fallback to default
180
+ const template: TemplateResponse | null = null;
181
+ let soulMd: string | undefined;
182
+
183
+ if (template) {
184
+ soulMd = interpolate(template.files.soulMd, {}).result;
185
+ }
186
+
187
+ // Template not applied, soulMd still undefined -> fallback will generate default
188
+ expect(soulMd).toBeUndefined();
189
+ });
190
+ });
191
+
192
+ // ---------------------------------------------------------------------------
193
+ // Template registration defaults — tests the priority logic from runner.ts
194
+ // that applies template agentDefaults before registration
195
+ // ---------------------------------------------------------------------------
196
+
197
+ describe("Template registration defaults", () => {
198
+ // Helper: simulates the agentName priority chain from runner.ts
199
+ function resolveAgentName(
200
+ envName: string | undefined,
201
+ templateDisplayName: string | undefined,
202
+ role: string,
203
+ agentId: string,
204
+ ): string {
205
+ return envName || templateDisplayName || `${role}-${agentId.slice(0, 8)}`;
206
+ }
207
+
208
+ // ---- name priority ----
209
+
210
+ test("name: AGENT_NAME env takes precedence over template displayName", () => {
211
+ const name = resolveAgentName("my-custom-name", "Coder", "worker", "abc12345-dead-beef");
212
+ expect(name).toBe("my-custom-name");
213
+ });
214
+
215
+ test("name: template displayName used when AGENT_NAME not set", () => {
216
+ const name = resolveAgentName(undefined, "Coder", "worker", "abc12345-dead-beef");
217
+ expect(name).toBe("Coder");
218
+ });
219
+
220
+ test("name: falls back to role-id when no env name and no template", () => {
221
+ const name = resolveAgentName(undefined, undefined, "worker", "abc12345-dead-beef");
222
+ expect(name).toBe("worker-abc12345");
223
+ });
224
+
225
+ test("name: template role feeds into fallback name when role overridden", () => {
226
+ // If template overrides role from "worker" to "coder", the fallback name uses the new role
227
+ const name = resolveAgentName(undefined, undefined, "coder", "abc12345-dead-beef");
228
+ expect(name).toBe("coder-abc12345");
229
+ });
230
+
231
+ // ---- role priority ----
232
+
233
+ test("role: template role overrides generic 'worker' default", () => {
234
+ let role = "worker";
235
+ const configRole = "worker";
236
+ const defaults = { role: "coder", capabilities: ["typescript"], maxTasks: 3 };
237
+
238
+ if (configRole === "worker" && defaults.role) {
239
+ role = defaults.role;
240
+ }
241
+
242
+ expect(role).toBe("coder");
243
+ });
244
+
245
+ test("role: explicit 'lead' config is NOT overridden by template", () => {
246
+ let role = "lead";
247
+ const configRole = "lead";
248
+ const defaults = { role: "coder", capabilities: ["typescript"], maxTasks: 3 };
249
+
250
+ if (configRole === "worker" && defaults.role) {
251
+ role = defaults.role;
252
+ }
253
+
254
+ expect(role).toBe("lead");
255
+ });
256
+
257
+ test("role: stays 'worker' when template has no role", () => {
258
+ let role = "worker";
259
+ const configRole = "worker";
260
+ const defaults = { role: "", capabilities: [], maxTasks: 1 };
261
+
262
+ if (configRole === "worker" && defaults.role) {
263
+ role = defaults.role;
264
+ }
265
+
266
+ expect(role).toBe("worker");
267
+ });
268
+
269
+ // ---- capabilities priority ----
270
+
271
+ test("capabilities: template caps used when config has none", () => {
272
+ let capabilities: string[] | undefined;
273
+ const defaults = { capabilities: ["typescript", "react"] };
274
+
275
+ if (!capabilities?.length && defaults.capabilities?.length) {
276
+ capabilities = defaults.capabilities;
277
+ }
278
+
279
+ expect(capabilities).toEqual(["typescript", "react"]);
280
+ });
281
+
282
+ test("capabilities: config caps take precedence over template", () => {
283
+ let capabilities: string[] | undefined = ["python", "django"];
284
+ const defaults = { capabilities: ["typescript", "react"] };
285
+
286
+ if (!capabilities?.length && defaults.capabilities?.length) {
287
+ capabilities = defaults.capabilities;
288
+ }
289
+
290
+ expect(capabilities).toEqual(["python", "django"]);
291
+ });
292
+
293
+ test("capabilities: empty array config still gets template caps", () => {
294
+ let capabilities: string[] | undefined = [];
295
+ const defaults = { capabilities: ["typescript", "react"] };
296
+
297
+ if (!capabilities?.length && defaults.capabilities?.length) {
298
+ capabilities = defaults.capabilities;
299
+ }
300
+
301
+ expect(capabilities).toEqual(["typescript", "react"]);
302
+ });
303
+
304
+ // ---- maxTasks priority ----
305
+
306
+ test("maxTasks: env var takes precedence over template and default", () => {
307
+ const envMaxTasks = "5";
308
+ const templateMaxTasks = 3;
309
+ const defaultMaxTasks = 1;
310
+
311
+ const maxConcurrent = envMaxTasks
312
+ ? parseInt(envMaxTasks, 10)
313
+ : (templateMaxTasks ?? defaultMaxTasks);
314
+
315
+ expect(maxConcurrent).toBe(5);
316
+ });
317
+
318
+ test("maxTasks: template value used when env not set", () => {
319
+ const envMaxTasks = "";
320
+ const templateMaxTasks = 3;
321
+ const defaultMaxTasks = 1;
322
+
323
+ const maxConcurrent = envMaxTasks
324
+ ? parseInt(envMaxTasks, 10)
325
+ : (templateMaxTasks ?? defaultMaxTasks);
326
+
327
+ expect(maxConcurrent).toBe(3);
328
+ });
329
+
330
+ test("maxTasks: hardcoded default used when no env and no template", () => {
331
+ const envMaxTasks = "";
332
+ const templateMaxTasks = undefined;
333
+ const defaultMaxTasks = 1;
334
+
335
+ const maxConcurrent = envMaxTasks
336
+ ? parseInt(envMaxTasks, 10)
337
+ : (templateMaxTasks ?? defaultMaxTasks);
338
+
339
+ expect(maxConcurrent).toBe(1);
340
+ });
341
+
342
+ // ---- isLead priority ----
343
+
344
+ test("isLead: config lead role takes precedence", () => {
345
+ const configRole = "lead";
346
+ const templateIsLead = false;
347
+
348
+ const isLead = configRole === "lead" || (templateIsLead ?? false);
349
+ expect(isLead).toBe(true);
350
+ });
351
+
352
+ test("isLead: template isLead=true used when config is worker", () => {
353
+ const configRole = "worker";
354
+ const templateIsLead = true;
355
+
356
+ const isLead = configRole === "lead" || (templateIsLead ?? false);
357
+ expect(isLead).toBe(true);
358
+ });
359
+
360
+ test("isLead: defaults to false when config is worker and template has no isLead", () => {
361
+ const configRole = "worker";
362
+ const templateIsLead = undefined;
363
+
364
+ const isLead = configRole === "lead" || (templateIsLead ?? false);
365
+ expect(isLead).toBe(false);
366
+ });
367
+
368
+ // ---- combined flow ----
369
+
370
+ test("full flow: template with agentDefaults applies all fallbacks", () => {
371
+ const configRole = "worker";
372
+ const template: TemplateResponse = {
373
+ ...mockTemplate,
374
+ config: {
375
+ ...mockTemplate.config,
376
+ displayName: "Research Assistant",
377
+ agentDefaults: {
378
+ role: "researcher",
379
+ capabilities: ["web-search", "analysis"],
380
+ maxTasks: 4,
381
+ isLead: false,
382
+ },
383
+ },
384
+ };
385
+
386
+ // Apply role
387
+ let role = configRole;
388
+ if (configRole === "worker" && template.config.agentDefaults.role) {
389
+ role = template.config.agentDefaults.role;
390
+ }
391
+
392
+ // Apply capabilities
393
+ let capabilities: string[] | undefined;
394
+ const defaults = template.config.agentDefaults;
395
+ if (!capabilities?.length && defaults.capabilities?.length) {
396
+ capabilities = defaults.capabilities;
397
+ }
398
+
399
+ // Apply maxTasks (no env var)
400
+ const maxConcurrent = defaults.maxTasks ?? 1;
401
+
402
+ // Apply isLead
403
+ const isLead = configRole === "lead" || (defaults.isLead ?? false);
404
+
405
+ // Apply name
406
+ const agentName = resolveAgentName(undefined, template.config.displayName, role, "abc12345");
407
+
408
+ expect(role).toBe("researcher");
409
+ expect(capabilities).toEqual(["web-search", "analysis"]);
410
+ expect(maxConcurrent).toBe(4);
411
+ expect(isLead).toBe(false);
412
+ expect(agentName).toBe("Research Assistant");
413
+ });
414
+
415
+ test("full flow: env/config overrides beat template defaults", () => {
416
+ const configRole = "lead";
417
+ const template: TemplateResponse = {
418
+ ...mockTemplate,
419
+ config: {
420
+ ...mockTemplate.config,
421
+ displayName: "Coder",
422
+ agentDefaults: {
423
+ role: "coder",
424
+ capabilities: ["typescript"],
425
+ maxTasks: 3,
426
+ isLead: false,
427
+ },
428
+ },
429
+ };
430
+
431
+ // Apply role — lead is NOT overridden
432
+ let role = configRole;
433
+ if (configRole === "worker" && template.config.agentDefaults.role) {
434
+ role = template.config.agentDefaults.role;
435
+ }
436
+
437
+ // Config capabilities take precedence
438
+ let capabilities: string[] | undefined = ["python"];
439
+ const defaults = template.config.agentDefaults;
440
+ if (!capabilities?.length && defaults.capabilities?.length) {
441
+ capabilities = defaults.capabilities;
442
+ }
443
+
444
+ // Env var takes precedence for maxTasks
445
+ const envMaxTasks = "10";
446
+ const maxConcurrent = envMaxTasks ? parseInt(envMaxTasks, 10) : (defaults.maxTasks ?? 1);
447
+
448
+ // isLead from config role
449
+ const isLead = configRole === "lead" || (defaults.isLead ?? false);
450
+
451
+ // AGENT_NAME takes precedence
452
+ const agentName = resolveAgentName("my-lead", template.config.displayName, role, "abc12345");
453
+
454
+ expect(role).toBe("lead");
455
+ expect(capabilities).toEqual(["python"]);
456
+ expect(maxConcurrent).toBe(10);
457
+ expect(isLead).toBe(true);
458
+ expect(agentName).toBe("my-lead");
459
+ });
460
+
461
+ test("full flow: no template — all values use config/hardcoded defaults", () => {
462
+ const configRole = "worker";
463
+ const cachedTemplate: TemplateResponse | null = null;
464
+
465
+ let role = configRole;
466
+ let capabilities: string[] | undefined;
467
+
468
+ if (cachedTemplate?.config.agentDefaults) {
469
+ const defaults = cachedTemplate.config.agentDefaults;
470
+ if (configRole === "worker" && defaults.role) role = defaults.role;
471
+ if (!capabilities?.length && defaults.capabilities?.length)
472
+ capabilities = defaults.capabilities;
473
+ }
474
+
475
+ const isLead = configRole === "lead" || (cachedTemplate?.config.agentDefaults?.isLead ?? false);
476
+ const maxConcurrent = cachedTemplate?.config.agentDefaults?.maxTasks ?? (isLead ? 2 : 1);
477
+ const agentName = resolveAgentName(
478
+ undefined,
479
+ cachedTemplate?.config.displayName,
480
+ role,
481
+ "abc12345",
482
+ );
483
+
484
+ expect(role).toBe("worker");
485
+ expect(capabilities).toBeUndefined();
486
+ expect(maxConcurrent).toBe(1);
487
+ expect(isLead).toBe(false);
488
+ expect(agentName).toBe("worker-abc12345");
489
+ });
490
+ });