@desplega.ai/agent-swarm 1.49.0 → 1.52.0

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 (547) hide show
  1. package/README.md +1 -1
  2. package/openapi.json +2070 -728
  3. package/package.json +10 -1
  4. package/src/agentmail/handlers.ts +65 -10
  5. package/src/agentmail/templates.ts +111 -0
  6. package/src/be/db.ts +1233 -7
  7. package/src/be/migrations/014_prompt_templates.sql +33 -0
  8. package/src/be/migrations/015_workflow_workspace.sql +3 -0
  9. package/src/be/migrations/016_active_session_runner_session.sql +4 -0
  10. package/src/be/migrations/017_channel_activity_cursors.sql +6 -0
  11. package/src/be/migrations/018_fix_seed_double_version.sql +30 -0
  12. package/src/be/migrations/019_skills.sql +65 -0
  13. package/src/be/migrations/020_approval_requests.sql +41 -0
  14. package/src/be/seed.ts +62 -0
  15. package/src/be/skill-parser.ts +70 -0
  16. package/src/be/skill-sync.ts +106 -0
  17. package/src/commands/runner.ts +320 -132
  18. package/src/commands/templates.ts +172 -0
  19. package/src/github/handlers.ts +292 -77
  20. package/src/github/mentions-aliases.test.ts +73 -0
  21. package/src/github/mentions.test.ts +3 -3
  22. package/src/github/mentions.ts +32 -6
  23. package/src/github/templates.ts +398 -0
  24. package/src/gitlab/handlers.ts +63 -22
  25. package/src/gitlab/templates.ts +140 -0
  26. package/src/heartbeat/heartbeat.ts +19 -10
  27. package/src/heartbeat/templates.ts +30 -0
  28. package/src/http/active-sessions.ts +27 -0
  29. package/src/http/approval-requests.ts +247 -0
  30. package/src/http/config.ts +3 -3
  31. package/src/http/index.ts +9 -2
  32. package/src/http/poll.ts +135 -14
  33. package/src/http/prompt-templates.ts +412 -0
  34. package/src/http/schedules.ts +35 -0
  35. package/src/http/skills.ts +479 -0
  36. package/src/http/workflows.ts +8 -0
  37. package/src/linear/sync.ts +28 -4
  38. package/src/linear/templates.ts +47 -0
  39. package/src/prompts/base-prompt.ts +41 -490
  40. package/src/prompts/registry.ts +57 -0
  41. package/src/prompts/resolver.ts +296 -0
  42. package/src/prompts/session-templates.ts +604 -0
  43. package/src/providers/claude-adapter.ts +15 -2
  44. package/src/providers/pi-mono-extension.ts +5 -1
  45. package/src/scheduler/scheduler.ts +125 -91
  46. package/src/server.ts +44 -0
  47. package/src/slack/assistant.ts +7 -4
  48. package/src/slack/channel-activity.ts +177 -0
  49. package/src/slack/handlers.ts +21 -6
  50. package/src/slack/templates.ts +55 -0
  51. package/src/tests/approval-requests.test.ts +735 -0
  52. package/src/tests/artifact-sdk.test.ts +12 -12
  53. package/src/tests/base-prompt.test.ts +49 -49
  54. package/src/tests/channel-activity.test.ts +363 -0
  55. package/src/tests/heartbeat.test.ts +1 -0
  56. package/src/tests/linear-webhook.test.ts +7 -3
  57. package/src/tests/pool-session-logs.test.ts +199 -0
  58. package/src/tests/prompt-template-github.test.ts +682 -0
  59. package/src/tests/prompt-template-remaining.test.ts +504 -0
  60. package/src/tests/prompt-template-resolver.test.ts +621 -0
  61. package/src/tests/prompt-template-session.test.ts +363 -0
  62. package/src/tests/prompt-templates-db.test.ts +616 -0
  63. package/src/tests/self-improvement.test.ts +8 -7
  64. package/src/tests/skill-parser.test.ts +178 -0
  65. package/src/tests/skill-sync.test.ts +171 -0
  66. package/src/tests/slack-metadata-inheritance.test.ts +1 -1
  67. package/src/tests/slack-thread-followups.test.ts +1 -1
  68. package/src/tests/structured-output.test.ts +0 -4
  69. package/src/tests/tool-annotations.test.ts +2 -1
  70. package/src/tests/update-profile-agentid.test.ts +248 -0
  71. package/src/tests/update-profile-auth.test.ts +195 -0
  72. package/src/tests/workflow-async-v2.test.ts +126 -4
  73. package/src/tests/workflow-definition-validation.test.ts +76 -0
  74. package/src/tests/workflow-executors.test.ts +4 -2
  75. package/src/tests/workflow-retry-v2.test.ts +1 -1
  76. package/src/tests/workflow-schedule-trigger.test.ts +104 -0
  77. package/src/tests/workflow-workspace.test.ts +272 -0
  78. package/src/tools/prompt-templates/delete.ts +86 -0
  79. package/src/tools/prompt-templates/get.ts +89 -0
  80. package/src/tools/prompt-templates/index.ts +5 -0
  81. package/src/tools/prompt-templates/list.ts +95 -0
  82. package/src/tools/prompt-templates/preview.ts +84 -0
  83. package/src/tools/prompt-templates/set.ts +117 -0
  84. package/src/tools/request-human-input.ts +106 -0
  85. package/src/tools/skills/index.ts +11 -0
  86. package/src/tools/skills/skill-create.ts +105 -0
  87. package/src/tools/skills/skill-delete.ts +67 -0
  88. package/src/tools/skills/skill-get.ts +75 -0
  89. package/src/tools/skills/skill-install-remote.ts +152 -0
  90. package/src/tools/skills/skill-install.ts +101 -0
  91. package/src/tools/skills/skill-list.ts +77 -0
  92. package/src/tools/skills/skill-publish.ts +123 -0
  93. package/src/tools/skills/skill-search.ts +43 -0
  94. package/src/tools/skills/skill-sync-remote.ts +128 -0
  95. package/src/tools/skills/skill-uninstall.ts +60 -0
  96. package/src/tools/skills/skill-update.ts +128 -0
  97. package/src/tools/store-progress.ts +22 -4
  98. package/src/tools/task-action.ts +20 -0
  99. package/src/tools/templates.ts +53 -0
  100. package/src/tools/tool-config.ts +23 -0
  101. package/src/tools/update-profile.ts +106 -34
  102. package/src/tools/workflows/create-workflow.ts +19 -1
  103. package/src/tools/workflows/update-workflow.ts +16 -1
  104. package/src/types.ts +109 -2
  105. package/src/workflows/definition.ts +30 -12
  106. package/src/workflows/engine.ts +40 -14
  107. package/src/workflows/executors/agent-task.ts +14 -3
  108. package/src/workflows/executors/human-in-the-loop.ts +160 -0
  109. package/src/workflows/executors/registry.ts +2 -0
  110. package/src/workflows/index.ts +1 -1
  111. package/src/workflows/recovery.ts +72 -0
  112. package/src/workflows/resume.ts +162 -12
  113. package/src/workflows/triggers.ts +31 -2
  114. package/src/workflows/version.ts +2 -0
  115. package/.claude/settings.json +0 -84
  116. package/.claude/settings.local.json +0 -117
  117. package/.dockerignore +0 -61
  118. package/.editorconfig +0 -15
  119. package/.entire/settings.json +0 -4
  120. package/.env.docker.example +0 -56
  121. package/.env.example +0 -78
  122. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -78
  123. package/.github/ISSUE_TEMPLATE/community-template.yml +0 -77
  124. package/.github/ISSUE_TEMPLATE/config.yml +0 -8
  125. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -60
  126. package/.github/PULL_REQUEST_TEMPLATE/community-template.md +0 -29
  127. package/.github/workflows/ci.yml +0 -52
  128. package/.github/workflows/docker-and-deploy.yml +0 -132
  129. package/.github/workflows/merge-gate.yml +0 -233
  130. package/.opencode/plugins/entire.ts +0 -133
  131. package/.superset/config.json +0 -6
  132. package/.wts-config.json +0 -4
  133. package/.wts-setup.ts +0 -171
  134. package/CHANGELOG.md +0 -447
  135. package/CLAUDE.md +0 -521
  136. package/CONTRIBUTING.md +0 -315
  137. package/DEPLOYMENT.md +0 -622
  138. package/Dockerfile +0 -65
  139. package/Dockerfile.worker +0 -189
  140. package/MCP.md +0 -841
  141. package/UI.md +0 -40
  142. package/api-entrypoint.sh +0 -56
  143. package/assets/agent-swarm-logo-orange.png +0 -0
  144. package/assets/agent-swarm-logo.png +0 -0
  145. package/assets/agent-swarm.mp4 +0 -0
  146. package/assets/agent-swarm.png +0 -0
  147. package/biome.json +0 -39
  148. package/deploy/DEPLOY.md +0 -60
  149. package/deploy/agent-swarm.service +0 -17
  150. package/deploy/docker-push.ts +0 -30
  151. package/deploy/install.ts +0 -85
  152. package/deploy/prod-db.ts +0 -42
  153. package/deploy/uninstall.ts +0 -12
  154. package/deploy/update.ts +0 -21
  155. package/depot.json +0 -1
  156. package/docker-compose.example.yml +0 -350
  157. package/docker-compose.local.yml +0 -119
  158. package/docker-entrypoint.sh +0 -632
  159. package/docs-site/app/api/search/route.ts +0 -4
  160. package/docs-site/app/docs/[[...slug]]/page.tsx +0 -87
  161. package/docs-site/app/docs/layout.tsx +0 -12
  162. package/docs-site/app/globals.css +0 -24
  163. package/docs-site/app/layout.config.tsx +0 -34
  164. package/docs-site/app/layout.tsx +0 -119
  165. package/docs-site/app/llms-full.txt/route.ts +0 -11
  166. package/docs-site/app/llms.mdx/docs/[[...slug]]/route.ts +0 -24
  167. package/docs-site/app/llms.txt/route.ts +0 -8
  168. package/docs-site/app/page.tsx +0 -5
  169. package/docs-site/app/robots.ts +0 -13
  170. package/docs-site/app/sitemap.ts +0 -37
  171. package/docs-site/components/api-page.client.tsx +0 -4
  172. package/docs-site/components/api-page.tsx +0 -7
  173. package/docs-site/components/mdx/mermaid.tsx +0 -55
  174. package/docs-site/content/docs/(documentation)/architecture/agents.mdx +0 -117
  175. package/docs-site/content/docs/(documentation)/architecture/hooks.mdx +0 -77
  176. package/docs-site/content/docs/(documentation)/architecture/memory.mdx +0 -96
  177. package/docs-site/content/docs/(documentation)/architecture/meta.json +0 -4
  178. package/docs-site/content/docs/(documentation)/architecture/overview.mdx +0 -172
  179. package/docs-site/content/docs/(documentation)/concepts/epics.mdx +0 -98
  180. package/docs-site/content/docs/(documentation)/concepts/meta.json +0 -4
  181. package/docs-site/content/docs/(documentation)/concepts/scheduling.mdx +0 -136
  182. package/docs-site/content/docs/(documentation)/concepts/services.mdx +0 -104
  183. package/docs-site/content/docs/(documentation)/concepts/task-lifecycle.mdx +0 -148
  184. package/docs-site/content/docs/(documentation)/concepts/workflows.mdx +0 -209
  185. package/docs-site/content/docs/(documentation)/contributing.mdx +0 -158
  186. package/docs-site/content/docs/(documentation)/getting-started.mdx +0 -157
  187. package/docs-site/content/docs/(documentation)/guides/agentmail-integration.mdx +0 -79
  188. package/docs-site/content/docs/(documentation)/guides/deployment.mdx +0 -171
  189. package/docs-site/content/docs/(documentation)/guides/github-integration.mdx +0 -81
  190. package/docs-site/content/docs/(documentation)/guides/gitlab-integration.mdx +0 -93
  191. package/docs-site/content/docs/(documentation)/guides/linear-integration.mdx +0 -98
  192. package/docs-site/content/docs/(documentation)/guides/meta.json +0 -13
  193. package/docs-site/content/docs/(documentation)/guides/sentry-integration.mdx +0 -52
  194. package/docs-site/content/docs/(documentation)/guides/slack-integration.mdx +0 -179
  195. package/docs-site/content/docs/(documentation)/guides/x402-payments.mdx +0 -154
  196. package/docs-site/content/docs/(documentation)/index.mdx +0 -65
  197. package/docs-site/content/docs/(documentation)/meta.json +0 -19
  198. package/docs-site/content/docs/(documentation)/reference/cli.mdx +0 -241
  199. package/docs-site/content/docs/(documentation)/reference/environment-variables.mdx +0 -205
  200. package/docs-site/content/docs/(documentation)/reference/mcp-tools.mdx +0 -449
  201. package/docs-site/content/docs/(documentation)/reference/meta.json +0 -4
  202. package/docs-site/content/docs/api-reference/active-sessions.mdx +0 -9
  203. package/docs-site/content/docs/api-reference/agents.mdx +0 -9
  204. package/docs-site/content/docs/api-reference/channels.mdx +0 -9
  205. package/docs-site/content/docs/api-reference/config.mdx +0 -9
  206. package/docs-site/content/docs/api-reference/debug.mdx +0 -9
  207. package/docs-site/content/docs/api-reference/ecosystem.mdx +0 -9
  208. package/docs-site/content/docs/api-reference/epics.mdx +0 -9
  209. package/docs-site/content/docs/api-reference/index.mdx +0 -32
  210. package/docs-site/content/docs/api-reference/memory.mdx +0 -9
  211. package/docs-site/content/docs/api-reference/meta.json +0 -25
  212. package/docs-site/content/docs/api-reference/poll.mdx +0 -9
  213. package/docs-site/content/docs/api-reference/repos.mdx +0 -9
  214. package/docs-site/content/docs/api-reference/schedules.mdx +0 -9
  215. package/docs-site/content/docs/api-reference/session-data.mdx +0 -9
  216. package/docs-site/content/docs/api-reference/stats.mdx +0 -9
  217. package/docs-site/content/docs/api-reference/tasks.mdx +0 -9
  218. package/docs-site/content/docs/api-reference/trackers.mdx +0 -9
  219. package/docs-site/content/docs/api-reference/webhooks.mdx +0 -9
  220. package/docs-site/content/docs/api-reference/workflows.mdx +0 -9
  221. package/docs-site/content/docs/meta.json +0 -3
  222. package/docs-site/lib/get-llm-text.ts +0 -10
  223. package/docs-site/lib/openapi.ts +0 -23
  224. package/docs-site/lib/source.ts +0 -8
  225. package/docs-site/mdx-components.tsx +0 -13
  226. package/docs-site/next.config.mjs +0 -29
  227. package/docs-site/package.json +0 -35
  228. package/docs-site/pnpm-lock.yaml +0 -5407
  229. package/docs-site/postcss.config.mjs +0 -8
  230. package/docs-site/public/logo.png +0 -0
  231. package/docs-site/scripts/generate-docs.ts +0 -171
  232. package/docs-site/source.config.ts +0 -17
  233. package/docs-site/tsconfig.json +0 -46
  234. package/ecosystem.config.cjs +0 -66
  235. package/landing/next.config.ts +0 -14
  236. package/landing/package.json +0 -31
  237. package/landing/pnpm-lock.yaml +0 -1091
  238. package/landing/postcss.config.mjs +0 -8
  239. package/landing/public/apple-touch-icon.png +0 -0
  240. package/landing/public/favicon.ico +0 -0
  241. package/landing/public/logo.png +0 -0
  242. package/landing/public/og-image.png +0 -0
  243. package/landing/public/omghost-desplega.svg +0 -30
  244. package/landing/public/omghost-openfort.svg +0 -9
  245. package/landing/src/app/actions/waitlist.ts +0 -25
  246. package/landing/src/app/blog/openfort-hackathon/page.tsx +0 -863
  247. package/landing/src/app/blog/page.tsx +0 -162
  248. package/landing/src/app/blog/swarm-metrics/page.tsx +0 -685
  249. package/landing/src/app/examples/page.tsx +0 -174
  250. package/landing/src/app/examples/x402/page.tsx +0 -456
  251. package/landing/src/app/globals.css +0 -122
  252. package/landing/src/app/layout.tsx +0 -134
  253. package/landing/src/app/page.tsx +0 -27
  254. package/landing/src/app/robots.ts +0 -13
  255. package/landing/src/app/sitemap.ts +0 -44
  256. package/landing/src/components/architecture.tsx +0 -163
  257. package/landing/src/components/cta.tsx +0 -52
  258. package/landing/src/components/features.tsx +0 -160
  259. package/landing/src/components/footer.tsx +0 -100
  260. package/landing/src/components/hero.tsx +0 -217
  261. package/landing/src/components/how-it-works.tsx +0 -165
  262. package/landing/src/components/navbar.tsx +0 -147
  263. package/landing/src/components/waitlist.tsx +0 -110
  264. package/landing/src/components/why-choose.tsx +0 -149
  265. package/landing/src/components/workshops.tsx +0 -328
  266. package/landing/src/lib/utils.ts +0 -6
  267. package/landing/tsconfig.json +0 -41
  268. package/misc/transcripts/2026-03-09-pi-mono-e2e-verification.md +0 -154
  269. package/new-ui/CLAUDE.md +0 -92
  270. package/new-ui/README.md +0 -73
  271. package/new-ui/biome.json +0 -42
  272. package/new-ui/components.json +0 -21
  273. package/new-ui/index.html +0 -25
  274. package/new-ui/package.json +0 -49
  275. package/new-ui/pnpm-lock.yaml +0 -4845
  276. package/new-ui/public/logo.png +0 -0
  277. package/new-ui/src/api/client.ts +0 -814
  278. package/new-ui/src/api/hooks/index.ts +0 -64
  279. package/new-ui/src/api/hooks/use-agents.ts +0 -58
  280. package/new-ui/src/api/hooks/use-channels.ts +0 -115
  281. package/new-ui/src/api/hooks/use-config-api.ts +0 -46
  282. package/new-ui/src/api/hooks/use-costs.ts +0 -122
  283. package/new-ui/src/api/hooks/use-db-query.ts +0 -29
  284. package/new-ui/src/api/hooks/use-epics.ts +0 -75
  285. package/new-ui/src/api/hooks/use-repos.ts +0 -61
  286. package/new-ui/src/api/hooks/use-schedules.ts +0 -81
  287. package/new-ui/src/api/hooks/use-services.ts +0 -16
  288. package/new-ui/src/api/hooks/use-stats.ts +0 -27
  289. package/new-ui/src/api/hooks/use-tasks.ts +0 -89
  290. package/new-ui/src/api/hooks/use-workflows.ts +0 -109
  291. package/new-ui/src/api/types.ts +0 -549
  292. package/new-ui/src/app/App.tsx +0 -13
  293. package/new-ui/src/app/providers.tsx +0 -32
  294. package/new-ui/src/app/router.tsx +0 -52
  295. package/new-ui/src/components/layout/app-header.tsx +0 -47
  296. package/new-ui/src/components/layout/app-sidebar.tsx +0 -128
  297. package/new-ui/src/components/layout/breadcrumbs.tsx +0 -57
  298. package/new-ui/src/components/layout/config-guard.tsx +0 -22
  299. package/new-ui/src/components/layout/root-layout.tsx +0 -40
  300. package/new-ui/src/components/layout/swarm-switcher.tsx +0 -85
  301. package/new-ui/src/components/shared/command-menu.tsx +0 -131
  302. package/new-ui/src/components/shared/data-grid.tsx +0 -141
  303. package/new-ui/src/components/shared/empty-state.tsx +0 -24
  304. package/new-ui/src/components/shared/error-boundary.tsx +0 -72
  305. package/new-ui/src/components/shared/json-viewer.tsx +0 -47
  306. package/new-ui/src/components/shared/name-connection-modal.tsx +0 -99
  307. package/new-ui/src/components/shared/page-skeleton.tsx +0 -16
  308. package/new-ui/src/components/shared/session-log-viewer.tsx +0 -364
  309. package/new-ui/src/components/shared/stats-bar.tsx +0 -132
  310. package/new-ui/src/components/shared/status-badge.tsx +0 -131
  311. package/new-ui/src/components/shared/usage-summary.tsx +0 -179
  312. package/new-ui/src/components/ui/alert-dialog.tsx +0 -176
  313. package/new-ui/src/components/ui/alert.tsx +0 -60
  314. package/new-ui/src/components/ui/avatar.tsx +0 -96
  315. package/new-ui/src/components/ui/badge.tsx +0 -46
  316. package/new-ui/src/components/ui/button.tsx +0 -62
  317. package/new-ui/src/components/ui/card.tsx +0 -75
  318. package/new-ui/src/components/ui/command.tsx +0 -160
  319. package/new-ui/src/components/ui/dialog.tsx +0 -143
  320. package/new-ui/src/components/ui/dropdown-menu.tsx +0 -226
  321. package/new-ui/src/components/ui/input.tsx +0 -21
  322. package/new-ui/src/components/ui/label.tsx +0 -19
  323. package/new-ui/src/components/ui/progress.tsx +0 -26
  324. package/new-ui/src/components/ui/scroll-area.tsx +0 -54
  325. package/new-ui/src/components/ui/select.tsx +0 -175
  326. package/new-ui/src/components/ui/separator.tsx +0 -28
  327. package/new-ui/src/components/ui/sheet.tsx +0 -132
  328. package/new-ui/src/components/ui/sidebar.tsx +0 -691
  329. package/new-ui/src/components/ui/skeleton.tsx +0 -13
  330. package/new-ui/src/components/ui/sonner.tsx +0 -35
  331. package/new-ui/src/components/ui/switch.tsx +0 -33
  332. package/new-ui/src/components/ui/table.tsx +0 -92
  333. package/new-ui/src/components/ui/tabs.tsx +0 -79
  334. package/new-ui/src/components/ui/textarea.tsx +0 -18
  335. package/new-ui/src/components/ui/tooltip.tsx +0 -51
  336. package/new-ui/src/components/workflows/action-node.tsx +0 -53
  337. package/new-ui/src/components/workflows/condition-node.tsx +0 -50
  338. package/new-ui/src/components/workflows/graph-utils.ts +0 -124
  339. package/new-ui/src/components/workflows/json-tree.tsx +0 -189
  340. package/new-ui/src/components/workflows/node-styles.ts +0 -10
  341. package/new-ui/src/components/workflows/step-detail-sheet.tsx +0 -87
  342. package/new-ui/src/components/workflows/trigger-node.tsx +0 -41
  343. package/new-ui/src/components/workflows/workflow-graph.tsx +0 -65
  344. package/new-ui/src/hooks/use-auto-scroll.ts +0 -82
  345. package/new-ui/src/hooks/use-config.ts +0 -203
  346. package/new-ui/src/hooks/use-keyboard-shortcuts.ts +0 -41
  347. package/new-ui/src/hooks/use-mobile.ts +0 -19
  348. package/new-ui/src/hooks/use-theme.ts +0 -60
  349. package/new-ui/src/lib/config.ts +0 -188
  350. package/new-ui/src/lib/slugs.ts +0 -71
  351. package/new-ui/src/lib/utils.ts +0 -120
  352. package/new-ui/src/main.tsx +0 -11
  353. package/new-ui/src/pages/agents/[id]/page.tsx +0 -492
  354. package/new-ui/src/pages/agents/page.tsx +0 -134
  355. package/new-ui/src/pages/chat/page.tsx +0 -674
  356. package/new-ui/src/pages/config/page.tsx +0 -1109
  357. package/new-ui/src/pages/dashboard/page.tsx +0 -454
  358. package/new-ui/src/pages/debug/page.tsx +0 -275
  359. package/new-ui/src/pages/epics/[id]/page.tsx +0 -809
  360. package/new-ui/src/pages/epics/page.tsx +0 -321
  361. package/new-ui/src/pages/not-found/page.tsx +0 -18
  362. package/new-ui/src/pages/repos/page.tsx +0 -369
  363. package/new-ui/src/pages/schedules/[id]/page.tsx +0 -664
  364. package/new-ui/src/pages/schedules/page.tsx +0 -477
  365. package/new-ui/src/pages/services/page.tsx +0 -128
  366. package/new-ui/src/pages/tasks/[id]/page.tsx +0 -670
  367. package/new-ui/src/pages/tasks/page.tsx +0 -592
  368. package/new-ui/src/pages/usage/page.tsx +0 -195
  369. package/new-ui/src/pages/workflow-runs/[id]/page.tsx +0 -363
  370. package/new-ui/src/pages/workflows/[id]/page.tsx +0 -417
  371. package/new-ui/src/pages/workflows/page.tsx +0 -266
  372. package/new-ui/src/styles/ag-grid.css +0 -36
  373. package/new-ui/src/styles/globals.css +0 -213
  374. package/new-ui/test-results/.last-run.json +0 -4
  375. package/new-ui/tsconfig.app.json +0 -34
  376. package/new-ui/tsconfig.json +0 -4
  377. package/new-ui/tsconfig.node.json +0 -26
  378. package/new-ui/vercel.json +0 -4
  379. package/new-ui/vite.config.ts +0 -28
  380. package/plugin/README.md +0 -1
  381. package/plugin/build-pi-skills.ts +0 -233
  382. package/plugin/hooks/hooks.json +0 -71
  383. package/prek.toml +0 -75
  384. package/pyproject.toml +0 -9
  385. package/scripts/check-db-boundary.sh +0 -60
  386. package/scripts/e2e-docker-provider.ts +0 -820
  387. package/scripts/e2e-io-schemas-test.ts +0 -807
  388. package/scripts/e2e-provider-test.ts +0 -220
  389. package/scripts/e2e-workflow-redesign.sh +0 -229
  390. package/scripts/e2e-workflow-test.sh +0 -285
  391. package/scripts/e2e-workflow-test.ts +0 -857
  392. package/scripts/generate-mcp-docs.ts +0 -415
  393. package/scripts/generate-openapi.ts +0 -26
  394. package/scripts/measure-tool-tokens.ts +0 -118
  395. package/scripts/x402-e2e-test.ts +0 -195
  396. package/scripts/x402-test-server.ts +0 -236
  397. package/scripts/x402-testnet-e2e.ts +0 -668
  398. package/slack-manifest.json +0 -88
  399. package/templates-ui/README.md +0 -46
  400. package/templates-ui/components.json +0 -17
  401. package/templates-ui/eslint.config.mjs +0 -18
  402. package/templates-ui/next.config.ts +0 -7
  403. package/templates-ui/package.json +0 -35
  404. package/templates-ui/pnpm-lock.yaml +0 -4571
  405. package/templates-ui/postcss.config.mjs +0 -7
  406. package/templates-ui/public/file.svg +0 -1
  407. package/templates-ui/public/globe.svg +0 -1
  408. package/templates-ui/public/logo.png +0 -0
  409. package/templates-ui/public/next.svg +0 -1
  410. package/templates-ui/public/vercel.svg +0 -1
  411. package/templates-ui/public/window.svg +0 -1
  412. package/templates-ui/src/app/[category]/[name]/page.tsx +0 -89
  413. package/templates-ui/src/app/api/templates/[...slug]/route.ts +0 -52
  414. package/templates-ui/src/app/api/templates/route.ts +0 -18
  415. package/templates-ui/src/app/builder/page.tsx +0 -37
  416. package/templates-ui/src/app/globals.css +0 -94
  417. package/templates-ui/src/app/layout.tsx +0 -79
  418. package/templates-ui/src/app/page.tsx +0 -38
  419. package/templates-ui/src/app/robots.ts +0 -11
  420. package/templates-ui/src/app/sitemap.ts +0 -31
  421. package/templates-ui/src/components/compose-builder.tsx +0 -442
  422. package/templates-ui/src/components/compose-preview.tsx +0 -117
  423. package/templates-ui/src/components/file-preview.tsx +0 -77
  424. package/templates-ui/src/components/footer.tsx +0 -40
  425. package/templates-ui/src/components/header.tsx +0 -41
  426. package/templates-ui/src/components/template-card.tsx +0 -87
  427. package/templates-ui/src/components/template-detail.tsx +0 -125
  428. package/templates-ui/src/components/template-gallery.tsx +0 -263
  429. package/templates-ui/src/components/ui/badge.tsx +0 -36
  430. package/templates-ui/src/components/ui/button.tsx +0 -57
  431. package/templates-ui/src/components/ui/card.tsx +0 -76
  432. package/templates-ui/src/components/ui/separator.tsx +0 -31
  433. package/templates-ui/src/components/ui/tooltip.tsx +0 -32
  434. package/templates-ui/src/lib/compose-generator.ts +0 -241
  435. package/templates-ui/src/lib/templates.ts +0 -137
  436. package/templates-ui/src/lib/utils.ts +0 -6
  437. package/templates-ui/tsconfig.json +0 -34
  438. package/thoughts/research/2026-02-28-openfort-viem-x402-research.md +0 -679
  439. package/thoughts/research/2026-02-28-x402-payments-research.md +0 -686
  440. package/thoughts/researcher/plans/2026-02-20-agent-self-improvement-plan.md +0 -282
  441. package/thoughts/researcher/research/2026-02-20-agent-self-improvement.md +0 -492
  442. package/thoughts/shared/plans/.gitkeep +0 -0
  443. package/thoughts/shared/plans/2025-12-18-slack-integration.md +0 -1195
  444. package/thoughts/shared/plans/2025-12-19-agent-log-streaming.md +0 -732
  445. package/thoughts/shared/plans/2025-12-19-role-based-swarm-plugin.md +0 -361
  446. package/thoughts/shared/plans/2025-12-20-mobile-responsive-ui.md +0 -501
  447. package/thoughts/shared/plans/2025-12-20-startup-team-swarm.md +0 -560
  448. package/thoughts/shared/plans/2025-12-23-runner-level-polling.md +0 -934
  449. package/thoughts/shared/plans/2025-12-23-runner-session-logs.md +0 -1000
  450. package/thoughts/shared/plans/2025-12-23-worker-lead-spawn-triggers.md +0 -568
  451. package/thoughts/shared/plans/2026-01-09-inverse-teleport.md +0 -1516
  452. package/thoughts/shared/plans/2026-01-12-agent-rename-pm2-control.md +0 -1133
  453. package/thoughts/shared/plans/2026-01-12-github-app-integration.md +0 -380
  454. package/thoughts/shared/plans/2026-01-12-lead-inbox-model.md +0 -876
  455. package/thoughts/shared/plans/2026-01-12-ralph-wiggum-integration.md +0 -463
  456. package/thoughts/shared/plans/2026-01-13-agent-concurrency.md +0 -691
  457. package/thoughts/shared/plans/2026-01-13-github-assignment-handling.md +0 -690
  458. package/thoughts/shared/plans/2026-01-13-prevent-duplicate-trigger-processing.md +0 -1071
  459. package/thoughts/shared/plans/2026-01-14-fix-slack-thread-context.md +0 -507
  460. package/thoughts/shared/plans/2026-01-15-scheduled-tasks-implementation.md +0 -565
  461. package/thoughts/shared/plans/2026-01-15-usage-cost-tracking-ui.md +0 -1479
  462. package/thoughts/shared/plans/2026-01-16-epics-feature-implementation.md +0 -1230
  463. package/thoughts/shared/plans/2026-02-26-mcp-tool-context-reduction.md +0 -282
  464. package/thoughts/shared/plans/2026-03-02-claude-context-mode-integration.md +0 -328
  465. package/thoughts/shared/plans/2026-03-02-code-level-heartbeat.md +0 -224
  466. package/thoughts/shared/research/.gitkeep +0 -0
  467. package/thoughts/shared/research/2025-01-09-inverse-teleport-plan-review.md +0 -420
  468. package/thoughts/shared/research/2025-12-18-slack-integration.md +0 -442
  469. package/thoughts/shared/research/2025-12-19-agent-log-streaming.md +0 -339
  470. package/thoughts/shared/research/2025-12-19-agent-secrets-cli-research.md +0 -390
  471. package/thoughts/shared/research/2025-12-21-gemini-cli-integration.md +0 -376
  472. package/thoughts/shared/research/2025-12-22-runner-loop-architecture.md +0 -582
  473. package/thoughts/shared/research/2025-12-22-setup-experience-improvements.md +0 -264
  474. package/thoughts/shared/research/2026-01-13-lead-duplicate-trigger-processing.md +0 -223
  475. package/thoughts/shared/research/2026-01-14-lead-slack-thread-context.md +0 -277
  476. package/thoughts/shared/research/2026-01-15-ai-tracker-agent-swarm-integration.md +0 -376
  477. package/thoughts/shared/research/2026-01-15-auto-starting-processes-in-worker-containers.md +0 -787
  478. package/thoughts/shared/research/2026-01-15-scheduled-tasks.md +0 -390
  479. package/thoughts/shared/research/2026-01-16-epics-feature-research.md +0 -437
  480. package/thoughts/shared/research/2026-02-26-cliffy-mcp-tools.md +0 -159
  481. package/thoughts/shared/research/2026-03-03-database-migration-system-refactor.md +0 -337
  482. package/thoughts/swarm-researcher/plans/2026-02-23-openclaw-improvements-plan.md +0 -778
  483. package/thoughts/swarm-researcher/plans/2026-02-26-artifacts-localtunnel-plan.md +0 -1269
  484. package/thoughts/swarm-researcher/research/2026-02-23-openclaw-vs-agent-swarm-comparison.md +0 -411
  485. package/thoughts/swarm-researcher/research/2026-02-26-artifacts-localtunnel.md +0 -724
  486. package/thoughts/taras/brainstorms/2026-03-20-prompt-template-registry.md +0 -443
  487. package/thoughts/taras/brainstorms/2026-03-20-setup-cli-onboarding.md +0 -307
  488. package/thoughts/taras/plans/2026-01-22-agent-swarm-schemas.md +0 -98
  489. package/thoughts/taras/plans/2026-01-28-per-worker-claude-md.md +0 -617
  490. package/thoughts/taras/plans/2026-01-28-sentry-cli-integration.md +0 -214
  491. package/thoughts/taras/plans/2026-02-20-auto-improvement.md +0 -803
  492. package/thoughts/taras/plans/2026-02-20-env-management.md +0 -538
  493. package/thoughts/taras/plans/2026-02-20-memory-system.md +0 -882
  494. package/thoughts/taras/plans/2026-02-20-repos-knowledge.md +0 -806
  495. package/thoughts/taras/plans/2026-02-20-session-attach.md +0 -647
  496. package/thoughts/taras/plans/2026-02-20-worker-identity.md +0 -820
  497. package/thoughts/taras/plans/2026-02-25-feat-new-ui-visual-redesign-plan.md +0 -768
  498. package/thoughts/taras/plans/2026-03-04-fix-buildSystemPrompt-missing-fields.md +0 -77
  499. package/thoughts/taras/plans/2026-03-04-new-ui-missing-actions.md +0 -543
  500. package/thoughts/taras/plans/2026-03-06-one-time-scheduled-tasks.md +0 -373
  501. package/thoughts/taras/plans/2026-03-08-memory-self-improvement-enhancements.md +0 -512
  502. package/thoughts/taras/plans/2026-03-08-pi-mono-provider-implementation.md +0 -919
  503. package/thoughts/taras/plans/2026-03-09-templates-registry.md +0 -723
  504. package/thoughts/taras/plans/2026-03-10-task-working-directory.md +0 -371
  505. package/thoughts/taras/plans/2026-03-11-archil-per-agent-write-strategy.md +0 -621
  506. package/thoughts/taras/plans/2026-03-12-eliminate-inbox-route-to-tasks.md +0 -61
  507. package/thoughts/taras/plans/2026-03-12-slack-thread-followup-additive.md +0 -488
  508. package/thoughts/taras/plans/2026-03-13-slack-ai-improvements.md +0 -644
  509. package/thoughts/taras/plans/2026-03-16-route-wrapper-openapi.md +0 -636
  510. package/thoughts/taras/plans/2026-03-17-multi-api-config.md +0 -444
  511. package/thoughts/taras/plans/2026-03-18-agent-fs-integration.md +0 -591
  512. package/thoughts/taras/plans/2026-03-18-debug-db-explorer.md +0 -446
  513. package/thoughts/taras/plans/2026-03-18-workflow-redesign.md +0 -987
  514. package/thoughts/taras/plans/2026-03-19-compound-learnings.md +0 -403
  515. package/thoughts/taras/plans/2026-03-19-ticket-tracker-linear-integration.md +0 -860
  516. package/thoughts/taras/plans/2026-03-19-workflow-io-schemas-and-bugs.md +0 -899
  517. package/thoughts/taras/plans/2026-03-20-setup-cli-onboarding.md +0 -874
  518. package/thoughts/taras/plans/2026-03-20-workflow-structured-output-validation-workspace.md +0 -723
  519. package/thoughts/taras/research/2026-01-22-vercel-cli-integration.md +0 -287
  520. package/thoughts/taras/research/2026-01-27-excessive-polling-issue.md +0 -311
  521. package/thoughts/taras/research/2026-01-28-per-worker-claude-md.md +0 -383
  522. package/thoughts/taras/research/2026-01-28-sentry-cli-integration.md +0 -240
  523. package/thoughts/taras/research/2026-02-19-agent-native-swarm-architecture.md +0 -390
  524. package/thoughts/taras/research/2026-02-19-swarm-gaps-implementation.md +0 -594
  525. package/thoughts/taras/research/2026-02-25-dashboard-ui-design-best-practices.md +0 -825
  526. package/thoughts/taras/research/2026-02-26-task-detail-page-redesign.md +0 -393
  527. package/thoughts/taras/research/2026-03-03-new-ui-missing-actions.md +0 -168
  528. package/thoughts/taras/research/2026-03-05-pi-mono-provider-research.md +0 -230
  529. package/thoughts/taras/research/2026-03-06-workflow-engine-design.md +0 -445
  530. package/thoughts/taras/research/2026-03-08-drive-loop-concept.md +0 -375
  531. package/thoughts/taras/research/2026-03-08-pi-mono-deep-dive.md +0 -869
  532. package/thoughts/taras/research/2026-03-09-templates-registry.md +0 -373
  533. package/thoughts/taras/research/2026-03-10-agent-working-directory.md +0 -223
  534. package/thoughts/taras/research/2026-03-10-configurable-event-prompts.md +0 -339
  535. package/thoughts/taras/research/2026-03-11-archil-production-setup.md +0 -181
  536. package/thoughts/taras/research/2026-03-11-archil-shared-disk-write-strategies.md +0 -437
  537. package/thoughts/taras/research/2026-03-13-slack-ai-features.md +0 -258
  538. package/thoughts/taras/research/2026-03-16-openapi-docs-generation.md +0 -335
  539. package/thoughts/taras/research/2026-03-16-route-wrapper-openapi.md +0 -670
  540. package/thoughts/taras/research/2026-03-16-slack-thread-followups-e2e.md +0 -54
  541. package/thoughts/taras/research/2026-03-18-agent-fs-integration.md +0 -558
  542. package/thoughts/taras/research/2026-03-18-linear-integration-finalization.md +0 -526
  543. package/thoughts/taras/research/2026-03-18-workflow-redesign.md +0 -797
  544. package/thoughts/taras/research/2026-03-19-workflow-node-io-schemas-and-bugs.md +0 -563
  545. package/thoughts/taras/research/2026-03-19-workflow-structured-output-validation-workspace.md +0 -486
  546. package/thoughts/taras/research/2026-03-20-prompt-template-registry.md +0 -469
  547. package/tsconfig.json +0 -37
@@ -1,820 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * Docker-based E2E Provider Test
4
- *
5
- * Builds the Docker worker image, starts a local API server with a clean DB,
6
- * registers agents, creates tasks, and runs Docker workers against them.
7
- * Tests both Claude and pi-mono providers with the same image.
8
- *
9
- * Test scenarios (each can be run independently via --test flag):
10
- * 1. basic — Worker picks up task, completes it, cost + session recorded
11
- * 2. cancel — Cancel a task mid-execution, verify tool_call is blocked
12
- * 3. resume — Pause a task, restart worker, verify it resumes
13
- * 4. tool-loop — Feed a task that triggers tool loop detection
14
- * 5. summarize — Verify session summarization produces a memory entry
15
- *
16
- * Usage:
17
- * bun scripts/e2e-docker-provider.ts --provider claude
18
- * bun scripts/e2e-docker-provider.ts --provider pi
19
- * bun scripts/e2e-docker-provider.ts --provider both
20
- * bun scripts/e2e-docker-provider.ts --provider claude --test basic
21
- * bun scripts/e2e-docker-provider.ts --provider claude --test basic,cancel
22
- * E2E_PORT=13099 bun scripts/e2e-docker-provider.ts --provider both --test basic
23
- */
24
- import { $, type Subprocess } from "bun";
25
-
26
- // ─── Arg Parsing ─────────────────────────────────────────────────────────────
27
- function parseArg(name: string, fallback: string): string {
28
- const flag = process.argv.find((a) => a.startsWith(`--${name}=`));
29
- if (flag) return flag.split("=")[1]!;
30
- const idx = process.argv.indexOf(`--${name}`);
31
- if (idx >= 0 && process.argv[idx + 1]) return process.argv[idx + 1]!;
32
- return fallback;
33
- }
34
-
35
- // ─── Config ──────────────────────────────────────────────────────────────────
36
- const PORT = process.env.E2E_PORT || "13099";
37
- const API_KEY = process.env.API_KEY || "123123";
38
- const BASE_URL = `http://localhost:${PORT}`;
39
- const DB_PATH = `/tmp/e2e-docker-${Date.now()}.sqlite`;
40
- const DOCKER_IMAGE = "agent-swarm-worker:e2e";
41
- const CONTAINER_PREFIX = "e2e-docker";
42
- const WORKER_PORT_BASE = 13200; // Docker host port for workers
43
-
44
- const PROVIDER_ARG = parseArg("provider", "claude");
45
- const TEST_ARG = parseArg("test", "all");
46
- const SKIP_BUILD = process.argv.includes("--skip-build");
47
- const TIMEOUT_MS = Number.parseInt(process.env.E2E_TIMEOUT || "120000", 10); // 2 min per test
48
-
49
- if (!["claude", "pi", "both"].includes(PROVIDER_ARG)) {
50
- console.error(`Invalid --provider: ${PROVIDER_ARG}. Supported: claude, pi, both`);
51
- process.exit(1);
52
- }
53
-
54
- const PROVIDERS = PROVIDER_ARG === "both" ? ["claude", "pi"] : [PROVIDER_ARG];
55
- const ALL_TESTS = ["basic", "cancel", "resume", "tool-loop", "summarize"];
56
- const TESTS_TO_RUN = TEST_ARG === "all" ? ALL_TESTS : TEST_ARG.split(",");
57
-
58
- for (const t of TESTS_TO_RUN) {
59
- if (!ALL_TESTS.includes(t)) {
60
- console.error(`Unknown test: ${t}. Available: ${ALL_TESTS.join(", ")}`);
61
- process.exit(1);
62
- }
63
- }
64
-
65
- // ─── State ───────────────────────────────────────────────────────────────────
66
- let apiProc: Subprocess | null = null;
67
- const activeContainers: string[] = [];
68
- let pass = 0;
69
- let fail = 0;
70
- let skip = 0;
71
- let cleaningUp = false;
72
-
73
- // ─── Helpers ─────────────────────────────────────────────────────────────────
74
- function log(msg: string) {
75
- console.log(`\x1b[1;36m[E2E-Docker]\x1b[0m ${msg}`);
76
- }
77
- function logPass(name: string) {
78
- console.log(`\x1b[1;32m ✓ PASS\x1b[0m ${name}`);
79
- pass++;
80
- }
81
- function logFail(name: string, detail: string) {
82
- console.log(`\x1b[1;31m ✗ FAIL\x1b[0m ${name}: ${detail}`);
83
- fail++;
84
- }
85
- function logSkip(name: string, reason: string) {
86
- console.log(`\x1b[1;33m ○ SKIP\x1b[0m ${name}: ${reason}`);
87
- skip++;
88
- }
89
- function logSection(title: string) {
90
- console.log(`\n\x1b[1;35m═══ ${title} ═══\x1b[0m`);
91
- }
92
-
93
- async function api(method: string, path: string, body?: unknown, agentId?: string) {
94
- const headers: Record<string, string> = {
95
- Authorization: `Bearer ${API_KEY}`,
96
- "Content-Type": "application/json",
97
- };
98
- if (agentId) headers["X-Agent-ID"] = agentId;
99
-
100
- const resp = await fetch(`${BASE_URL}${path}`, {
101
- method,
102
- headers,
103
- body: body ? JSON.stringify(body) : undefined,
104
- });
105
- if (!resp.ok) {
106
- const text = await resp.text();
107
- throw new Error(`API ${method} ${path} returned ${resp.status}: ${text}`);
108
- }
109
- return resp.json();
110
- }
111
-
112
- async function apiSafe(method: string, path: string, body?: unknown, agentId?: string) {
113
- try {
114
- return await api(method, path, body, agentId);
115
- } catch (err) {
116
- return { error: String(err) };
117
- }
118
- }
119
-
120
- async function waitForApi(maxWaitMs = 15000): Promise<boolean> {
121
- const start = Date.now();
122
- while (Date.now() - start < maxWaitMs) {
123
- try {
124
- const resp = await fetch(`${BASE_URL}/health`);
125
- if (resp.ok) return true;
126
- } catch {}
127
- await Bun.sleep(500);
128
- }
129
- return false;
130
- }
131
-
132
- /** Poll a condition until it's true or timeout */
133
- async function pollUntil(
134
- fn: () => Promise<boolean>,
135
- timeoutMs: number,
136
- intervalMs = 2000,
137
- ): Promise<boolean> {
138
- const start = Date.now();
139
- while (Date.now() - start < timeoutMs) {
140
- if (await fn()) return true;
141
- await Bun.sleep(intervalMs);
142
- }
143
- return false;
144
- }
145
-
146
- /** Start a Docker worker container for the given provider */
147
- async function startWorker(
148
- provider: string,
149
- agentId: string,
150
- hostPort: number,
151
- extraEnv: Record<string, string> = {},
152
- ): Promise<string> {
153
- const containerName = `${CONTAINER_PREFIX}-${provider}-${Date.now()}`;
154
-
155
- const envFlags: string[] = [
156
- "-e",
157
- `HARNESS_PROVIDER=${provider}`,
158
- "-e",
159
- `API_KEY=${API_KEY}`,
160
- "-e",
161
- `AGENT_ID=${agentId}`,
162
- "-e",
163
- `MCP_BASE_URL=http://host.docker.internal:${PORT}`,
164
- "-e",
165
- "AGENT_ROLE=worker",
166
- "-e",
167
- "YOLO=true",
168
- "-e",
169
- "STARTUP_SCRIPT_STRICT=false",
170
- "-e",
171
- "SLACK_DISABLE=true",
172
- "-e",
173
- "GITHUB_DISABLE=true",
174
- "-e",
175
- "MAX_CONCURRENT_TASKS=1",
176
- ];
177
-
178
- // Provider-specific auth
179
- if (provider === "claude") {
180
- const token = process.env.CLAUDE_CODE_OAUTH_TOKEN;
181
- if (!token) throw new Error("CLAUDE_CODE_OAUTH_TOKEN required for claude provider");
182
- envFlags.push("-e", `CLAUDE_CODE_OAUTH_TOKEN=${token}`);
183
- } else if (provider === "pi") {
184
- // pi-mono can use OPENROUTER_API_KEY or ANTHROPIC_API_KEY
185
- const orKey = process.env.OPENROUTER_API_KEY;
186
- const antKey = process.env.ANTHROPIC_API_KEY;
187
- if (orKey) envFlags.push("-e", `OPENROUTER_API_KEY=${orKey}`);
188
- if (antKey) envFlags.push("-e", `ANTHROPIC_API_KEY=${antKey}`);
189
- if (!orKey && !antKey)
190
- throw new Error("OPENROUTER_API_KEY or ANTHROPIC_API_KEY required for pi provider");
191
- }
192
-
193
- for (const [k, v] of Object.entries(extraEnv)) {
194
- envFlags.push("-e", `${k}=${v}`);
195
- }
196
-
197
- const args = [
198
- "docker",
199
- "run",
200
- "--rm",
201
- "-d",
202
- "--name",
203
- containerName,
204
- ...envFlags,
205
- "-p",
206
- `${hostPort}:3000`,
207
- DOCKER_IMAGE,
208
- ];
209
-
210
- const result = await $`${args}`.text();
211
- const containerId = result.trim().slice(0, 12);
212
- activeContainers.push(containerName);
213
- log(`Started container ${containerName} (${containerId}) on port ${hostPort}`);
214
- return containerName;
215
- }
216
-
217
- /** Get Docker container logs */
218
- async function containerLogs(name: string, tail = 50): Promise<string> {
219
- try {
220
- return await $`docker logs --tail ${tail} ${name} 2>&1`.text();
221
- } catch {
222
- return "<no logs available>";
223
- }
224
- }
225
-
226
- /** Stop and remove a Docker container */
227
- async function stopContainer(name: string): Promise<void> {
228
- try {
229
- await $`docker stop -t 5 ${name} 2>/dev/null`.quiet();
230
- } catch {}
231
- const idx = activeContainers.indexOf(name);
232
- if (idx >= 0) activeContainers.splice(idx, 1);
233
- }
234
-
235
- async function cleanup() {
236
- if (cleaningUp) return;
237
- cleaningUp = true;
238
- log("Cleaning up...");
239
-
240
- // Stop all containers
241
- for (const name of [...activeContainers]) {
242
- await stopContainer(name);
243
- }
244
-
245
- // Stop API server
246
- if (apiProc) {
247
- apiProc.kill("SIGTERM");
248
- await apiProc.exited.catch(() => {});
249
- }
250
-
251
- // Remove temp DB files
252
- for (const suffix of ["", "-wal", "-shm"]) {
253
- try {
254
- await $`rm -f ${DB_PATH}${suffix}`.quiet();
255
- } catch {}
256
- }
257
- }
258
-
259
- process.on("SIGINT", async () => {
260
- await cleanup();
261
- process.exit(1);
262
- });
263
- process.on("SIGTERM", async () => {
264
- await cleanup();
265
- process.exit(1);
266
- });
267
-
268
- // ─── Test Implementations ────────────────────────────────────────────────────
269
-
270
- /** Test: basic — Worker picks up task, completes, cost + session recorded */
271
- async function testBasic(provider: string, portOffset: number) {
272
- const testName = `[${provider}] basic`;
273
- logSection(`${testName}: Task completion + cost recording`);
274
-
275
- // Register agent
276
- const joinResult = await api("POST", "/api/agents", {
277
- name: `e2e-${provider}-basic`,
278
- role: "worker",
279
- status: "online",
280
- harnessProvider: provider,
281
- });
282
- const agentId = joinResult?.agent?.id || joinResult?.id || joinResult?.id;
283
- if (!agentId) {
284
- logFail(testName, `Agent registration failed: ${JSON.stringify(joinResult)}`);
285
- return;
286
- }
287
- logPass(`${testName}: Agent registered ${agentId.slice(0, 8)}`);
288
-
289
- // Create task
290
- const taskResult = await api("POST", "/api/tasks", {
291
- task: "Say 'hello world' and nothing else. Do not use any tools. Just output text.",
292
- agentId,
293
- source: "api",
294
- });
295
- const taskId = taskResult?.task?.id || taskResult?.id || taskResult?.id;
296
- if (!taskId) {
297
- logFail(testName, `Task creation failed: ${JSON.stringify(taskResult)}`);
298
- return;
299
- }
300
- logPass(`${testName}: Task created ${taskId.slice(0, 8)}`);
301
-
302
- // Start worker container
303
- const hostPort = WORKER_PORT_BASE + portOffset;
304
- let containerName: string;
305
- try {
306
- containerName = await startWorker(provider, agentId, hostPort);
307
- } catch (err) {
308
- logFail(testName, `Container start failed: ${err}`);
309
- return;
310
- }
311
-
312
- // Poll until task completes or timeout
313
- const completed = await pollUntil(async () => {
314
- const details = await apiSafe("GET", `/api/tasks/${taskId}`);
315
- const status = details?.task?.status || details?.status;
316
- if (status === "completed" || status === "failed") return true;
317
- return false;
318
- }, TIMEOUT_MS);
319
-
320
- // Check results
321
- const finalTask = await apiSafe("GET", `/api/tasks/${taskId}`);
322
- const status = finalTask?.task?.status || finalTask?.status;
323
-
324
- if (!completed) {
325
- const logs = await containerLogs(containerName);
326
- logFail(
327
- testName,
328
- `Timed out after ${TIMEOUT_MS / 1000}s. Status: ${status}\nLast logs:\n${logs}`,
329
- );
330
- await stopContainer(containerName);
331
- return;
332
- }
333
-
334
- if (status === "completed") {
335
- logPass(`${testName}: Task completed`);
336
- } else {
337
- logFail(testName, `Task status: ${status} (expected completed)`);
338
- }
339
-
340
- // Check session ID
341
- const sessionId = finalTask?.task?.claudeSessionId || finalTask?.claudeSessionId;
342
- if (sessionId) {
343
- logPass(`${testName}: Session ID recorded (${sessionId.slice(0, 8)})`);
344
- } else {
345
- logFail(testName, "No session ID on task");
346
- }
347
-
348
- // Wait for runner to finish post-completion work (cost save, log flush, etc.)
349
- // The task may be marked "completed" by hooks before the runner's
350
- // waitForCompletion() resolves and saves cost data.
351
- await Bun.sleep(10000);
352
-
353
- // Grab container logs before checking cost (for diagnostics)
354
- const workerLogs = await containerLogs(containerName, 200);
355
- const diagLines = workerLogs
356
- .split("\n")
357
- .filter(
358
- (l) =>
359
- l.includes("cost") ||
360
- l.includes("Cost") ||
361
- l.includes("result") ||
362
- l.includes("save") ||
363
- l.includes("[runner]") ||
364
- l.includes("exit"),
365
- );
366
- if (diagLines.length > 0) {
367
- log(`${testName}: Diagnostic log lines:\n${diagLines.join("\n")}`);
368
- } else {
369
- log(`${testName}: DIAG: No diagnostic lines found. Total log lines: ${workerLogs.split("\n").length}`);
370
- // Show last 20 lines for debugging
371
- const lastLines = workerLogs.split("\n").slice(-20).join("\n");
372
- log(`${testName}: Last 20 lines:\n${lastLines}`);
373
- }
374
-
375
- // Poll for cost data (may take time if Stop hook runs summarization)
376
- let costEntries: Array<{ totalCostUsd: number }> = [];
377
- const costFound = await pollUntil(async () => {
378
- const costs = await apiSafe("GET", `/api/session-costs?agentId=${agentId}`);
379
- costEntries = costs?.costs || [];
380
- if (costEntries.length > 0) return true;
381
- // Also check unfiltered
382
- const allCosts = await apiSafe("GET", "/api/session-costs");
383
- const allEntries = allCosts?.costs || [];
384
- if (allEntries.length > 0) {
385
- log(
386
- `${testName}: DIAG: No costs for agentId=${agentId}, but ${allEntries.length} total. Sample: ${JSON.stringify(allEntries[0])}`,
387
- );
388
- return true; // Cost exists, just wrong agentId filter
389
- }
390
- return false;
391
- }, 30000, 3000);
392
-
393
- if (costEntries.length > 0) {
394
- const total = costEntries.reduce(
395
- (sum: number, c: { totalCostUsd: number }) => sum + c.totalCostUsd,
396
- 0,
397
- );
398
- logPass(`${testName}: Cost recorded ($${total.toFixed(4)}, ${costEntries.length} entries)`);
399
- } else if (costFound) {
400
- logSkip(`${testName}: Cost data`, "Costs exist but not linked to this agentId");
401
- } else {
402
- logFail(testName, "No cost data recorded (polled for 30s)");
403
- }
404
-
405
- // Check session logs
406
- const logs = await apiSafe("GET", `/api/session-logs?taskId=${taskId}`);
407
- const logEntries = logs?.logs || [];
408
- if (logEntries.length > 0) {
409
- logPass(`${testName}: Session logs recorded (${logEntries.length} entries)`);
410
- } else {
411
- logSkip(`${testName}: Session logs`, "No log entries (may be expected for trivial tasks)");
412
- }
413
-
414
- await stopContainer(containerName);
415
- }
416
-
417
- /** Test: cancel — Cancel a task mid-execution, verify blocking */
418
- async function testCancel(provider: string, portOffset: number) {
419
- const testName = `[${provider}] cancel`;
420
- logSection(`${testName}: Task cancellation mid-execution`);
421
-
422
- // Register agent
423
- const joinResult = await api("POST", "/api/agents", {
424
- name: `e2e-${provider}-cancel`,
425
- role: "worker",
426
- status: "online",
427
- harnessProvider: provider,
428
- });
429
- const agentId = joinResult?.agent?.id || joinResult?.id;
430
- if (!agentId) {
431
- logFail(testName, `Agent registration failed`);
432
- return;
433
- }
434
-
435
- // Create a task that takes a while (uses tools, so cancellation hook fires)
436
- const taskResult = await api("POST", "/api/tasks", {
437
- task: "List all files in the current directory recursively. Then create a file called 'test-output.txt' with the listing.",
438
- agentId,
439
- source: "api",
440
- });
441
- const taskId = taskResult?.task?.id || taskResult?.id;
442
- if (!taskId) {
443
- logFail(testName, `Task creation failed`);
444
- return;
445
- }
446
- logPass(`${testName}: Task created ${taskId.slice(0, 8)}`);
447
-
448
- // Start worker
449
- const hostPort = WORKER_PORT_BASE + portOffset;
450
- let containerName: string;
451
- try {
452
- containerName = await startWorker(provider, agentId, hostPort);
453
- } catch (err) {
454
- logFail(testName, `Container start failed: ${err}`);
455
- return;
456
- }
457
-
458
- // Wait for task to start (status changes from pending/assigned to in_progress)
459
- const started = await pollUntil(async () => {
460
- const details = await apiSafe("GET", `/api/tasks/${taskId}`);
461
- return details?.task?.status || details?.status === "in_progress";
462
- }, 30000);
463
-
464
- if (!started) {
465
- // Even if not in_progress, try cancelling anyway after a delay
466
- await Bun.sleep(10000);
467
- }
468
-
469
- // Cancel the task
470
- log(`${testName}: Cancelling task...`);
471
- await apiSafe("POST", `/api/tasks/${taskId}/cancel`, { reason: "E2E cancellation test" });
472
-
473
- // Poll until task reaches cancelled/completed/failed state
474
- const finished = await pollUntil(async () => {
475
- const details = await apiSafe("GET", `/api/tasks/${taskId}`);
476
- const s = details?.task?.status || details?.status;
477
- return s === "cancelled" || s === "completed" || s === "failed";
478
- }, TIMEOUT_MS);
479
-
480
- const finalTask = await apiSafe("GET", `/api/tasks/${taskId}`);
481
- const finalStatus = finalTask?.task?.status || finalTask?.status;
482
-
483
- if (finalStatus === "cancelled") {
484
- logPass(`${testName}: Task cancelled successfully`);
485
- } else if (finished) {
486
- logFail(testName, `Task ended with status: ${finalStatus} (expected cancelled)`);
487
- } else {
488
- logFail(testName, `Timed out waiting for cancellation. Status: ${finalStatus}`);
489
- }
490
-
491
- await stopContainer(containerName);
492
- }
493
-
494
- /** Test: resume — Pause a task, restart worker, verify it resumes */
495
- async function testResume(provider: string, portOffset: number) {
496
- const testName = `[${provider}] resume`;
497
- logSection(`${testName}: Session resume after restart`);
498
-
499
- // Register agent
500
- const joinResult = await api("POST", "/api/agents", {
501
- name: `e2e-${provider}-resume`,
502
- role: "worker",
503
- status: "online",
504
- harnessProvider: provider,
505
- });
506
- const agentId = joinResult?.agent?.id || joinResult?.id;
507
- if (!agentId) {
508
- logFail(testName, `Agent registration failed`);
509
- return;
510
- }
511
-
512
- // Create a multi-step task
513
- const taskResult = await api("POST", "/api/tasks", {
514
- task: "Step 1: Create a file /workspace/resume-test-1.txt with content 'step1'. Step 2: Create a file /workspace/resume-test-2.txt with content 'step2'. Step 3: Create a file /workspace/resume-test-3.txt with content 'step3'.",
515
- agentId,
516
- source: "api",
517
- });
518
- const taskId = taskResult?.task?.id || taskResult?.id;
519
- if (!taskId) {
520
- logFail(testName, `Task creation failed`);
521
- return;
522
- }
523
- logPass(`${testName}: Task created ${taskId.slice(0, 8)}`);
524
-
525
- // Start worker
526
- const hostPort = WORKER_PORT_BASE + portOffset;
527
- let containerName: string;
528
- try {
529
- containerName = await startWorker(provider, agentId, hostPort);
530
- } catch (err) {
531
- logFail(testName, `Container start failed: ${err}`);
532
- return;
533
- }
534
-
535
- // Wait for task to start
536
- const started = await pollUntil(async () => {
537
- const details = await apiSafe("GET", `/api/tasks/${taskId}`);
538
- return details?.task?.status || details?.status === "in_progress";
539
- }, 30000);
540
-
541
- if (!started) {
542
- logFail(testName, "Task never reached in_progress");
543
- await stopContainer(containerName);
544
- return;
545
- }
546
-
547
- // Wait a bit, then kill the container abruptly
548
- await Bun.sleep(5000);
549
- const taskBefore = await apiSafe("GET", `/api/tasks/${taskId}`);
550
- const sessionIdBefore = taskBefore?.task?.claudeSessionId || taskBefore?.claudeSessionId;
551
- log(`${testName}: Session ID before restart: ${sessionIdBefore?.slice(0, 8) || "none"}`);
552
-
553
- // Kill container (simulates crash)
554
- await stopContainer(containerName);
555
- log(`${testName}: Container killed. Restarting...`);
556
- await Bun.sleep(2000);
557
-
558
- // Reset task to assigned so worker picks it up again
559
- // The runner should detect the existing sessionId and --resume
560
- await apiSafe("POST", `/api/tasks/${taskId}/reassign`, { assigneeId: agentId });
561
-
562
- // Start new worker
563
- try {
564
- containerName = await startWorker(provider, agentId, hostPort);
565
- } catch (err) {
566
- logFail(testName, `Container restart failed: ${err}`);
567
- return;
568
- }
569
-
570
- // Wait for task to complete
571
- const completed = await pollUntil(async () => {
572
- const details = await apiSafe("GET", `/api/tasks/${taskId}`);
573
- const s = details?.task?.status || details?.status;
574
- return s === "completed" || s === "failed";
575
- }, TIMEOUT_MS);
576
-
577
- const finalTask = await apiSafe("GET", `/api/tasks/${taskId}`);
578
- const finalStatus = finalTask?.task?.status || finalTask?.status;
579
- const sessionIdAfter = finalTask?.task?.claudeSessionId || finalTask?.claudeSessionId;
580
-
581
- if (completed && finalStatus === "completed") {
582
- logPass(`${testName}: Task completed after resume`);
583
- } else {
584
- logFail(testName, `Task status: ${finalStatus}`);
585
- }
586
-
587
- // Check if session ID changed (it may or may not, depending on resume support)
588
- if (sessionIdBefore && sessionIdAfter) {
589
- if (sessionIdBefore === sessionIdAfter) {
590
- logPass(`${testName}: Same session ID — resume worked`);
591
- } else {
592
- logSkip(
593
- `${testName}: Session ID changed`,
594
- "Provider may not support resume or session was stale",
595
- );
596
- }
597
- }
598
-
599
- await stopContainer(containerName);
600
- }
601
-
602
- /** Test: tool-loop — Trigger tool loop detection */
603
- async function testToolLoop(provider: string, portOffset: number) {
604
- const testName = `[${provider}] tool-loop`;
605
- logSection(`${testName}: Tool loop detection`);
606
-
607
- // Register agent
608
- const joinResult = await api("POST", "/api/agents", {
609
- name: `e2e-${provider}-loop`,
610
- role: "worker",
611
- status: "online",
612
- harnessProvider: provider,
613
- });
614
- const agentId = joinResult?.agent?.id || joinResult?.id;
615
- if (!agentId) {
616
- logFail(testName, `Agent registration failed`);
617
- return;
618
- }
619
-
620
- // Create a task likely to trigger tool loops
621
- const taskResult = await api("POST", "/api/tasks", {
622
- task: "Read the file /workspace/nonexistent-file.txt and tell me its contents. Keep trying until you succeed. Do not give up.",
623
- agentId,
624
- source: "api",
625
- });
626
- const taskId = taskResult?.task?.id || taskResult?.id;
627
- if (!taskId) {
628
- logFail(testName, `Task creation failed`);
629
- return;
630
- }
631
- logPass(`${testName}: Task created ${taskId.slice(0, 8)}`);
632
-
633
- // Start worker
634
- const hostPort = WORKER_PORT_BASE + portOffset;
635
- let containerName: string;
636
- try {
637
- containerName = await startWorker(provider, agentId, hostPort);
638
- } catch (err) {
639
- logFail(testName, `Container start failed: ${err}`);
640
- return;
641
- }
642
-
643
- // Wait for task to complete/fail (loop detection should stop it)
644
- const completed = await pollUntil(async () => {
645
- const details = await apiSafe("GET", `/api/tasks/${taskId}`);
646
- const s = details?.task?.status || details?.status;
647
- return s === "completed" || s === "failed";
648
- }, TIMEOUT_MS);
649
-
650
- // Check container logs for loop detection markers
651
- const logs = await containerLogs(containerName, 200);
652
- const loopDetected =
653
- logs.includes("LOOP DETECTED") || logs.includes("loop") || logs.includes("blocked");
654
-
655
- if (loopDetected) {
656
- logPass(`${testName}: Tool loop detection triggered`);
657
- } else if (completed) {
658
- logSkip(`${testName}: Loop detection`, "Task completed without triggering loop detection");
659
- } else {
660
- logFail(testName, "Task timed out without loop detection");
661
- }
662
-
663
- await stopContainer(containerName);
664
- }
665
-
666
- /** Test: summarize — Verify session summarization produces memory entry */
667
- async function testSummarize(provider: string, portOffset: number) {
668
- const testName = `[${provider}] summarize`;
669
- logSection(`${testName}: Session summarization`);
670
-
671
- // Register agent
672
- const joinResult = await api("POST", "/api/agents", {
673
- name: `e2e-${provider}-summarize`,
674
- role: "worker",
675
- status: "online",
676
- harnessProvider: provider,
677
- });
678
- const agentId = joinResult?.agent?.id || joinResult?.id;
679
- if (!agentId) {
680
- logFail(testName, `Agent registration failed`);
681
- return;
682
- }
683
-
684
- // Create a task with enough substance to summarize
685
- const taskResult = await api("POST", "/api/tasks", {
686
- task: "Create a file /workspace/summary-test.txt explaining what 2+2 equals and why. Use the Write tool.",
687
- agentId,
688
- source: "api",
689
- });
690
- const taskId = taskResult?.task?.id || taskResult?.id;
691
- if (!taskId) {
692
- logFail(testName, `Task creation failed`);
693
- return;
694
- }
695
- logPass(`${testName}: Task created ${taskId.slice(0, 8)}`);
696
-
697
- // Start worker
698
- const hostPort = WORKER_PORT_BASE + portOffset;
699
- let containerName: string;
700
- try {
701
- containerName = await startWorker(provider, agentId, hostPort);
702
- } catch (err) {
703
- logFail(testName, `Container start failed: ${err}`);
704
- return;
705
- }
706
-
707
- // Wait for task to complete
708
- const completed = await pollUntil(async () => {
709
- const details = await apiSafe("GET", `/api/tasks/${taskId}`);
710
- const s = details?.task?.status || details?.status;
711
- return s === "completed" || s === "failed";
712
- }, TIMEOUT_MS);
713
-
714
- if (!completed) {
715
- logFail(testName, "Task timed out");
716
- await stopContainer(containerName);
717
- return;
718
- }
719
-
720
- // Wait a bit for summarization to complete (runs in Stop hook)
721
- await Bun.sleep(10000);
722
-
723
- // Check for memory entries from this agent
724
- const memories = await apiSafe("GET", `/api/memory?agentId=${agentId}`);
725
- const memEntries = memories?.memories || memories?.entries || [];
726
-
727
- if (memEntries.length > 0) {
728
- logPass(`${testName}: Memory entry created (${memEntries.length} entries)`);
729
- } else {
730
- logSkip(
731
- `${testName}: Memory entry`,
732
- "No memory entries found (summarization may have failed silently)",
733
- );
734
- }
735
-
736
- await stopContainer(containerName);
737
- }
738
-
739
- // ─── Test Router ─────────────────────────────────────────────────────────────
740
- const TEST_FUNCTIONS: Record<string, (provider: string, portOffset: number) => Promise<void>> = {
741
- basic: testBasic,
742
- cancel: testCancel,
743
- resume: testResume,
744
- "tool-loop": testToolLoop,
745
- summarize: testSummarize,
746
- };
747
-
748
- // ─── Main ────────────────────────────────────────────────────────────────────
749
- async function main() {
750
- log(`Providers: ${PROVIDERS.join(", ")}`);
751
- log(`Tests: ${TESTS_TO_RUN.join(", ")}`);
752
- log(`API port: ${PORT}, DB: ${DB_PATH}`);
753
- log(`Timeout per test: ${TIMEOUT_MS / 1000}s`);
754
-
755
- // 1. Build Docker image (unless --skip-build)
756
- if (!SKIP_BUILD) {
757
- logSection("Building Docker image");
758
- try {
759
- await $`docker build -f Dockerfile.worker -t ${DOCKER_IMAGE} .`.quiet();
760
- logPass("Docker image built");
761
- } catch (err) {
762
- logFail("Docker build", String(err));
763
- process.exit(1);
764
- }
765
- } else {
766
- log("Skipping Docker build (--skip-build)");
767
- }
768
-
769
- // 2. Start API server
770
- logSection("Starting API server");
771
- apiProc = Bun.spawn(["bun", "run", "src/http.ts"], {
772
- env: {
773
- ...process.env,
774
- PORT,
775
- API_KEY,
776
- DATABASE_PATH: DB_PATH,
777
- SLACK_DISABLE: "true",
778
- GITHUB_DISABLE: "true",
779
- },
780
- stdout: "pipe",
781
- stderr: "pipe",
782
- });
783
-
784
- if (!(await waitForApi())) {
785
- logFail("API startup", "Server did not become healthy within 15s");
786
- await cleanup();
787
- process.exit(1);
788
- }
789
- logPass("API server started");
790
-
791
- // 3. Run tests for each provider
792
- let portOffset = 0;
793
- for (const provider of PROVIDERS) {
794
- logSection(`Provider: ${provider}`);
795
- for (const testName of TESTS_TO_RUN) {
796
- const testFn = TEST_FUNCTIONS[testName];
797
- if (!testFn) continue;
798
- try {
799
- await testFn(provider, portOffset++);
800
- } catch (err) {
801
- logFail(`[${provider}] ${testName}`, `Unhandled error: ${err}`);
802
- }
803
- }
804
- }
805
-
806
- // 4. Summary
807
- logSection("Results");
808
- log(
809
- `\x1b[1;32m${pass} passed\x1b[0m, \x1b[1;31m${fail} failed\x1b[0m, \x1b[1;33m${skip} skipped\x1b[0m`,
810
- );
811
-
812
- await cleanup();
813
- process.exit(fail > 0 ? 1 : 0);
814
- }
815
-
816
- main().catch(async (err) => {
817
- console.error("E2E test error:", err);
818
- await cleanup();
819
- process.exit(1);
820
- });