@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,208 @@
1
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
+ import { unlink } from "node:fs/promises";
3
+ import {
4
+ closeDb,
5
+ createWorkflow,
6
+ getWorkflowVersion,
7
+ getWorkflowVersions,
8
+ initDb,
9
+ updateWorkflow,
10
+ } from "../be/db";
11
+ import type { Workflow } from "../types";
12
+ import { snapshotWorkflow } from "../workflows/version";
13
+
14
+ const TEST_DB_PATH = "./test-workflow-versions.sqlite";
15
+
16
+ // ─── Setup ──────────────────────────────────────────────────
17
+
18
+ beforeAll(() => {
19
+ initDb(TEST_DB_PATH);
20
+ });
21
+
22
+ afterAll(async () => {
23
+ closeDb();
24
+ await unlink(TEST_DB_PATH).catch(() => {});
25
+ await unlink(`${TEST_DB_PATH}-wal`).catch(() => {});
26
+ await unlink(`${TEST_DB_PATH}-shm`).catch(() => {});
27
+ });
28
+
29
+ // ─── Helpers ────────────────────────────────────────────────
30
+
31
+ function makeWorkflow(name?: string): Workflow {
32
+ return createWorkflow({
33
+ name: name ?? `test-wf-${crypto.randomUUID().slice(0, 8)}`,
34
+ definition: {
35
+ nodes: [
36
+ {
37
+ id: "n1",
38
+ type: "notify",
39
+ config: { channel: "swarm", template: "v1" },
40
+ },
41
+ ],
42
+ },
43
+ });
44
+ }
45
+
46
+ // ─── Tests ──────────────────────────────────────────────────
47
+
48
+ describe("snapshotWorkflow", () => {
49
+ test("creates a version snapshot with correct version number", () => {
50
+ const workflow = makeWorkflow();
51
+
52
+ const version = snapshotWorkflow(workflow.id);
53
+
54
+ expect(version.workflowId).toBe(workflow.id);
55
+ expect(version.version).toBe(1);
56
+ expect(version.snapshot.name).toBe(workflow.name);
57
+ expect(version.snapshot.definition).toEqual(workflow.definition);
58
+ expect(version.snapshot.triggers).toEqual([]);
59
+ expect(version.snapshot.enabled).toBe(true);
60
+ expect(version.createdAt).toBeDefined();
61
+ });
62
+
63
+ test("version numbers increment on successive snapshots", () => {
64
+ const workflow = makeWorkflow();
65
+
66
+ const v1 = snapshotWorkflow(workflow.id);
67
+ expect(v1.version).toBe(1);
68
+
69
+ // Update workflow between snapshots
70
+ updateWorkflow(workflow.id, { description: "updated once" });
71
+
72
+ const v2 = snapshotWorkflow(workflow.id);
73
+ expect(v2.version).toBe(2);
74
+
75
+ updateWorkflow(workflow.id, { description: "updated twice" });
76
+
77
+ const v3 = snapshotWorkflow(workflow.id);
78
+ expect(v3.version).toBe(3);
79
+ });
80
+
81
+ test("snapshot contains full workflow state at time of capture", () => {
82
+ const workflow = makeWorkflow();
83
+
84
+ // Take snapshot of initial state
85
+ const v1 = snapshotWorkflow(workflow.id);
86
+ expect(v1.snapshot.description).toBeUndefined();
87
+
88
+ // Update workflow
89
+ updateWorkflow(workflow.id, {
90
+ description: "has description now",
91
+ triggers: [{ type: "webhook", hmacSecret: "secret" }],
92
+ cooldown: { minutes: 30 },
93
+ });
94
+
95
+ // Take snapshot after update
96
+ const v2 = snapshotWorkflow(workflow.id);
97
+ expect(v2.snapshot.description).toBe("has description now");
98
+ expect(v2.snapshot.triggers).toEqual([{ type: "webhook", hmacSecret: "secret" }]);
99
+ expect(v2.snapshot.cooldown).toEqual({ minutes: 30 });
100
+ });
101
+
102
+ test("changedByAgentId is recorded when provided", () => {
103
+ const workflow = makeWorkflow();
104
+ const agentId = crypto.randomUUID();
105
+
106
+ const version = snapshotWorkflow(workflow.id, agentId);
107
+
108
+ expect(version.changedByAgentId).toBe(agentId);
109
+ });
110
+
111
+ test("throws when workflow does not exist", () => {
112
+ expect(() => {
113
+ snapshotWorkflow("00000000-0000-0000-0000-000000000000");
114
+ }).toThrow("Workflow 00000000-0000-0000-0000-000000000000 not found");
115
+ });
116
+ });
117
+
118
+ describe("getWorkflowVersions", () => {
119
+ test("returns versions in descending order", () => {
120
+ const workflow = makeWorkflow();
121
+
122
+ snapshotWorkflow(workflow.id);
123
+ updateWorkflow(workflow.id, { description: "update 1" });
124
+ snapshotWorkflow(workflow.id);
125
+ updateWorkflow(workflow.id, { description: "update 2" });
126
+ snapshotWorkflow(workflow.id);
127
+
128
+ const versions = getWorkflowVersions(workflow.id);
129
+
130
+ expect(versions.length).toBe(3);
131
+ expect(versions[0]!.version).toBe(3);
132
+ expect(versions[1]!.version).toBe(2);
133
+ expect(versions[2]!.version).toBe(1);
134
+ });
135
+
136
+ test("returns empty array for workflow with no versions", () => {
137
+ const workflow = makeWorkflow();
138
+ const versions = getWorkflowVersions(workflow.id);
139
+ expect(versions).toEqual([]);
140
+ });
141
+ });
142
+
143
+ describe("getWorkflowVersion", () => {
144
+ test("returns specific version by number", () => {
145
+ const workflow = makeWorkflow();
146
+
147
+ snapshotWorkflow(workflow.id);
148
+ updateWorkflow(workflow.id, { description: "v2 state" });
149
+ snapshotWorkflow(workflow.id);
150
+
151
+ const v1 = getWorkflowVersion(workflow.id, 1);
152
+ expect(v1).not.toBeNull();
153
+ expect(v1!.version).toBe(1);
154
+ expect(v1!.snapshot.description).toBeUndefined();
155
+
156
+ const v2 = getWorkflowVersion(workflow.id, 2);
157
+ expect(v2).not.toBeNull();
158
+ expect(v2!.version).toBe(2);
159
+ expect(v2!.snapshot.description).toBe("v2 state");
160
+ });
161
+
162
+ test("returns null for non-existent version", () => {
163
+ const workflow = makeWorkflow();
164
+ const result = getWorkflowVersion(workflow.id, 999);
165
+ expect(result).toBeNull();
166
+ });
167
+ });
168
+
169
+ describe("version history workflow (snapshot before update)", () => {
170
+ test("full update cycle: create -> snapshot -> update -> snapshot -> update -> verify history", () => {
171
+ const workflow = makeWorkflow("versioned-workflow");
172
+
173
+ // Snapshot before first update (captures initial state)
174
+ snapshotWorkflow(workflow.id);
175
+ updateWorkflow(workflow.id, {
176
+ description: "first update",
177
+ definition: {
178
+ nodes: [
179
+ {
180
+ id: "n1",
181
+ type: "notify",
182
+ config: { channel: "swarm", template: "v2" },
183
+ },
184
+ ],
185
+ },
186
+ });
187
+
188
+ // Snapshot before second update
189
+ snapshotWorkflow(workflow.id);
190
+ updateWorkflow(workflow.id, {
191
+ description: "second update",
192
+ });
193
+
194
+ // Verify version history
195
+ const versions = getWorkflowVersions(workflow.id);
196
+ expect(versions.length).toBe(2);
197
+
198
+ // v1 should have the initial state (no description)
199
+ const v1 = versions.find((v) => v.version === 1)!;
200
+ expect(v1.snapshot.description).toBeUndefined();
201
+ expect(v1.snapshot.definition.nodes[0]!.config.template).toBe("v1");
202
+
203
+ // v2 should have the first update state
204
+ const v2 = versions.find((v) => v.version === 2)!;
205
+ expect(v2.snapshot.description).toBe("first update");
206
+ expect(v2.snapshot.definition.nodes[0]!.config.template).toBe("v2");
207
+ });
208
+ });
@@ -0,0 +1,272 @@
1
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
+ import { EventEmitter } from "node:events";
3
+ import { unlink } from "node:fs/promises";
4
+ import * as db from "../be/db";
5
+ import {
6
+ closeDb,
7
+ createAgent,
8
+ createWorkflow,
9
+ getWorkflow,
10
+ initDb,
11
+ listWorkflows,
12
+ updateWorkflow,
13
+ } from "../be/db";
14
+ import { WorkflowSchema } from "../types";
15
+ import { startWorkflowExecution } from "../workflows/engine";
16
+ import { createExecutorRegistry } from "../workflows/executors/registry";
17
+
18
+ const TEST_DB_PATH = "./test-wf-workspace.sqlite";
19
+
20
+ beforeAll(async () => {
21
+ try {
22
+ await unlink(TEST_DB_PATH);
23
+ } catch {
24
+ // Ignore
25
+ }
26
+ initDb(TEST_DB_PATH);
27
+
28
+ // Create a test agent for task assignment
29
+ createAgent({ name: "test-workspace-agent", isLead: false, status: "idle" });
30
+ });
31
+
32
+ afterAll(async () => {
33
+ closeDb();
34
+ try {
35
+ await unlink(TEST_DB_PATH);
36
+ await unlink(`${TEST_DB_PATH}-wal`);
37
+ await unlink(`${TEST_DB_PATH}-shm`);
38
+ } catch {
39
+ // Ignore
40
+ }
41
+ });
42
+
43
+ describe("Workflow dir/vcsRepo persistence", () => {
44
+ test("workflow dir and vcsRepo persist through create/get cycle", () => {
45
+ const wf = createWorkflow({
46
+ name: "wf-with-workspace",
47
+ definition: { nodes: [{ id: "n1", type: "agent-task", config: { template: "test" } }] },
48
+ dir: "/tmp/test-workspace",
49
+ vcsRepo: "desplega-ai/landing",
50
+ });
51
+
52
+ expect(wf.dir).toBe("/tmp/test-workspace");
53
+ expect(wf.vcsRepo).toBe("desplega-ai/landing");
54
+
55
+ const fetched = getWorkflow(wf.id);
56
+ expect(fetched).not.toBeNull();
57
+ expect(fetched!.dir).toBe("/tmp/test-workspace");
58
+ expect(fetched!.vcsRepo).toBe("desplega-ai/landing");
59
+ });
60
+
61
+ test("workflow without dir/vcsRepo returns undefined", () => {
62
+ const wf = createWorkflow({
63
+ name: "wf-no-workspace",
64
+ definition: { nodes: [{ id: "n1", type: "agent-task", config: { template: "test" } }] },
65
+ });
66
+
67
+ expect(wf.dir).toBeUndefined();
68
+ expect(wf.vcsRepo).toBeUndefined();
69
+ });
70
+
71
+ test("updateWorkflow can set dir and vcsRepo", () => {
72
+ const wf = createWorkflow({
73
+ name: "wf-update-workspace",
74
+ definition: { nodes: [{ id: "n1", type: "agent-task", config: { template: "test" } }] },
75
+ });
76
+
77
+ const updated = updateWorkflow(wf.id, {
78
+ dir: "/tmp/updated-workspace",
79
+ vcsRepo: "org/repo",
80
+ });
81
+
82
+ expect(updated).not.toBeNull();
83
+ expect(updated!.dir).toBe("/tmp/updated-workspace");
84
+ expect(updated!.vcsRepo).toBe("org/repo");
85
+ });
86
+
87
+ test("updateWorkflow can clear dir and vcsRepo with null", () => {
88
+ const wf = createWorkflow({
89
+ name: "wf-clear-workspace",
90
+ definition: { nodes: [{ id: "n1", type: "agent-task", config: { template: "test" } }] },
91
+ dir: "/tmp/clear-me",
92
+ vcsRepo: "org/clear-me",
93
+ });
94
+
95
+ const updated = updateWorkflow(wf.id, {
96
+ dir: null,
97
+ vcsRepo: null,
98
+ });
99
+
100
+ expect(updated).not.toBeNull();
101
+ expect(updated!.dir).toBeUndefined();
102
+ expect(updated!.vcsRepo).toBeUndefined();
103
+ });
104
+
105
+ test("listWorkflows includes dir and vcsRepo", () => {
106
+ const wf = createWorkflow({
107
+ name: "wf-list-workspace",
108
+ definition: { nodes: [{ id: "n1", type: "agent-task", config: { template: "test" } }] },
109
+ dir: "/tmp/list-test",
110
+ vcsRepo: "org/list-test",
111
+ });
112
+
113
+ const workflows = listWorkflows();
114
+ const found = workflows.find((w) => w.id === wf.id);
115
+ expect(found).not.toBeNull();
116
+ expect(found!.dir).toBe("/tmp/list-test");
117
+ expect(found!.vcsRepo).toBe("org/list-test");
118
+ });
119
+
120
+ test("Workflow type validates dir must start with /", () => {
121
+ const result = WorkflowSchema.shape.dir.safeParse("relative/path");
122
+ expect(result.success).toBe(false);
123
+
124
+ const validResult = WorkflowSchema.shape.dir.safeParse("/absolute/path");
125
+ expect(validResult.success).toBe(true);
126
+ });
127
+ });
128
+
129
+ describe("Agent-task executor workspace inheritance", () => {
130
+ test("agent-task inherits workflow dir when node config omits it", async () => {
131
+ const wf = createWorkflow({
132
+ name: "wf-inherit-dir",
133
+ definition: {
134
+ nodes: [
135
+ {
136
+ id: "task1",
137
+ type: "agent-task",
138
+ config: { template: "Do something" },
139
+ },
140
+ ],
141
+ },
142
+ dir: "/tmp/inherited-workspace",
143
+ vcsRepo: "desplega-ai/inherited",
144
+ });
145
+
146
+ const eventBus = new EventEmitter();
147
+ const registry = createExecutorRegistry({
148
+ db,
149
+ eventBus,
150
+ interpolate: (t) => t,
151
+ });
152
+
153
+ const runId = await startWorkflowExecution(wf, {}, registry);
154
+
155
+ // The workflow run should have been created
156
+ const run = db.getWorkflowRun(runId);
157
+ expect(run).not.toBeNull();
158
+ expect(run!.status).toBe("waiting"); // agent-task is async
159
+
160
+ // Find the task created by the executor
161
+ const steps = db.getWorkflowRunStepsByRunId(runId);
162
+ expect(steps.length).toBe(1);
163
+
164
+ const task = db.getTaskByWorkflowRunStepId(steps[0]!.id);
165
+ expect(task).not.toBeNull();
166
+ expect(task!.dir).toBe("/tmp/inherited-workspace");
167
+ expect(task!.vcsRepo).toBe("desplega-ai/inherited");
168
+ });
169
+
170
+ test("node-level dir overrides workflow-level dir", async () => {
171
+ const wf = createWorkflow({
172
+ name: "wf-override-dir",
173
+ definition: {
174
+ nodes: [
175
+ {
176
+ id: "task1",
177
+ type: "agent-task",
178
+ config: {
179
+ template: "Do something",
180
+ dir: "/tmp/node-specific",
181
+ vcsRepo: "org/node-specific",
182
+ },
183
+ },
184
+ ],
185
+ },
186
+ dir: "/tmp/workflow-level",
187
+ vcsRepo: "org/workflow-level",
188
+ });
189
+
190
+ const eventBus = new EventEmitter();
191
+ const registry = createExecutorRegistry({
192
+ db,
193
+ eventBus,
194
+ interpolate: (t) => t,
195
+ });
196
+
197
+ const runId = await startWorkflowExecution(wf, {}, registry);
198
+ const steps = db.getWorkflowRunStepsByRunId(runId);
199
+ const task = db.getTaskByWorkflowRunStepId(steps[0]!.id);
200
+
201
+ expect(task).not.toBeNull();
202
+ expect(task!.dir).toBe("/tmp/node-specific");
203
+ expect(task!.vcsRepo).toBe("org/node-specific");
204
+ });
205
+
206
+ test("workflow without dir/vcsRepo doesn't affect agent-task nodes", async () => {
207
+ const wf = createWorkflow({
208
+ name: "wf-no-inherit",
209
+ definition: {
210
+ nodes: [
211
+ {
212
+ id: "task1",
213
+ type: "agent-task",
214
+ config: { template: "Do something" },
215
+ },
216
+ ],
217
+ },
218
+ });
219
+
220
+ const eventBus = new EventEmitter();
221
+ const registry = createExecutorRegistry({
222
+ db,
223
+ eventBus,
224
+ interpolate: (t) => t,
225
+ });
226
+
227
+ const runId = await startWorkflowExecution(wf, {}, registry);
228
+ const steps = db.getWorkflowRunStepsByRunId(runId);
229
+ const task = db.getTaskByWorkflowRunStepId(steps[0]!.id);
230
+
231
+ expect(task).not.toBeNull();
232
+ expect(task!.dir).toBeFalsy();
233
+ expect(task!.vcsRepo).toBeFalsy();
234
+ });
235
+ });
236
+
237
+ describe("Workflow interpolation context", () => {
238
+ test("{{workflow.dir}} and {{workflow.vcsRepo}} are available in context", async () => {
239
+ const wf = createWorkflow({
240
+ name: "wf-interpolation",
241
+ definition: {
242
+ nodes: [
243
+ {
244
+ id: "task1",
245
+ type: "agent-task",
246
+ config: {
247
+ template: "Work in {{workflow.dir}} on repo {{workflow.vcsRepo}}",
248
+ },
249
+ },
250
+ ],
251
+ },
252
+ dir: "/tmp/interp-test",
253
+ vcsRepo: "org/interp-repo",
254
+ });
255
+
256
+ const eventBus = new EventEmitter();
257
+ const registry = createExecutorRegistry({
258
+ db,
259
+ eventBus,
260
+ interpolate: (t) => t,
261
+ });
262
+
263
+ const runId = await startWorkflowExecution(wf, {}, registry);
264
+ const steps = db.getWorkflowRunStepsByRunId(runId);
265
+ const task = db.getTaskByWorkflowRunStepId(steps[0]!.id);
266
+
267
+ expect(task).not.toBeNull();
268
+ // The template should have been interpolated with workflow context
269
+ expect(task!.task).toContain("/tmp/interp-test");
270
+ expect(task!.task).toContain("org/interp-repo");
271
+ });
272
+ });
@@ -0,0 +1,117 @@
1
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
2
+ import { createX402Client } from "../x402/client.ts";
3
+
4
+ // A valid test private key (DO NOT use in production — this is a well-known throwaway key)
5
+ const TEST_PRIVATE_KEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
6
+
7
+ describe("createX402Client", () => {
8
+ const originalEnv = { ...process.env };
9
+
10
+ beforeEach(() => {
11
+ delete process.env.EVM_PRIVATE_KEY;
12
+ delete process.env.X402_MAX_AUTO_APPROVE;
13
+ delete process.env.X402_DAILY_LIMIT;
14
+ delete process.env.X402_NETWORK;
15
+ delete process.env.X402_SIGNER_TYPE;
16
+ delete process.env.OPENFORT_API_KEY;
17
+ delete process.env.OPENFORT_WALLET_SECRET;
18
+ });
19
+
20
+ afterEach(() => {
21
+ process.env = { ...originalEnv };
22
+ });
23
+
24
+ test("creates client with viem signer and config overrides", async () => {
25
+ process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
26
+
27
+ const client = await createX402Client({
28
+ maxAutoApprove: 2.5,
29
+ dailyLimit: 25.0,
30
+ });
31
+
32
+ expect(client.fetch).toBeFunction();
33
+ expect(client.x402Client).toBeDefined();
34
+ expect(client.spendingTracker).toBeDefined();
35
+ expect(client.getSpendingSummary).toBeFunction();
36
+ expect(client.walletAddress).toMatch(/^0x[0-9a-fA-F]{40}$/);
37
+ });
38
+
39
+ test("derives a consistent wallet address from private key", async () => {
40
+ process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
41
+
42
+ const client1 = await createX402Client();
43
+ const client2 = await createX402Client();
44
+
45
+ expect(client1.walletAddress).toBe(client2.walletAddress);
46
+ });
47
+
48
+ test("safe config excludes secrets", async () => {
49
+ process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
50
+
51
+ const client = await createX402Client();
52
+
53
+ // config should NOT contain sensitive fields
54
+ expect(client.config).not.toHaveProperty("evmPrivateKey");
55
+ expect(client.config).not.toHaveProperty("openfortApiKey");
56
+ expect(client.config).not.toHaveProperty("openfortWalletSecret");
57
+ expect(client.config.maxAutoApprove).toBe(1.0);
58
+ expect(client.config.dailyLimit).toBe(10.0);
59
+ expect(client.config.network).toBe("eip155:84532");
60
+ expect(client.config.signerType).toBe("viem");
61
+ });
62
+
63
+ test("spending summary reflects tracker state", async () => {
64
+ process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
65
+
66
+ const client = await createX402Client();
67
+ const summary = client.getSpendingSummary();
68
+
69
+ expect(summary.todaySpent).toBe(0);
70
+ expect(summary.todayCount).toBe(0);
71
+ expect(summary.maxPerRequest).toBe(1.0);
72
+ expect(summary.dailyLimit).toBe(10.0);
73
+ expect(summary.dailyRemaining).toBe(10.0);
74
+ });
75
+
76
+ test("applies config overrides over env defaults", async () => {
77
+ process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
78
+ process.env.X402_MAX_AUTO_APPROVE = "3.0";
79
+ process.env.X402_DAILY_LIMIT = "30.0";
80
+
81
+ const client = await createX402Client({
82
+ maxAutoApprove: 7.0,
83
+ dailyLimit: 70.0,
84
+ });
85
+
86
+ expect(client.config.maxAutoApprove).toBe(7.0);
87
+ expect(client.config.dailyLimit).toBe(70.0);
88
+ });
89
+
90
+ test("uses Base Sepolia by default (testnet)", async () => {
91
+ process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
92
+
93
+ const client = await createX402Client();
94
+ expect(client.config.network).toBe("eip155:84532");
95
+ });
96
+
97
+ test("throws when no signer credentials are set", async () => {
98
+ await expect(createX402Client()).rejects.toThrow(
99
+ "x402 payment requires either Openfort credentials",
100
+ );
101
+ });
102
+
103
+ test("auto-detects viem signer when EVM_PRIVATE_KEY is set", async () => {
104
+ process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
105
+
106
+ const client = await createX402Client();
107
+ expect(client.config.signerType).toBe("viem");
108
+ });
109
+
110
+ test("respects explicit X402_SIGNER_TYPE=viem", async () => {
111
+ process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
112
+ process.env.X402_SIGNER_TYPE = "viem";
113
+
114
+ const client = await createX402Client();
115
+ expect(client.config.signerType).toBe("viem");
116
+ });
117
+ });