@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
@@ -731,8 +731,8 @@ describe("artifact CLI command", () => {
731
731
  // ─── Base prompt tests ──────────────────────────────────────────────────
732
732
 
733
733
  describe("base prompt artifacts mention", () => {
734
- test("includes artifacts mention when capability is set", () => {
735
- const prompt = getBasePrompt({
734
+ test("includes artifacts mention when capability is set", async () => {
735
+ const prompt = await getBasePrompt({
736
736
  role: "worker",
737
737
  agentId: "test-agent-id",
738
738
  swarmUrl: "https://test.swarm.example.com",
@@ -743,8 +743,8 @@ describe("base prompt artifacts mention", () => {
743
743
  expect(prompt).toContain("/workspace/personal/artifacts/");
744
744
  });
745
745
 
746
- test("excludes artifacts mention without capability", () => {
747
- const prompt = getBasePrompt({
746
+ test("excludes artifacts mention without capability", async () => {
747
+ const prompt = await getBasePrompt({
748
748
  role: "worker",
749
749
  agentId: "test-agent-id",
750
750
  swarmUrl: "https://test.swarm.example.com",
@@ -754,8 +754,8 @@ describe("base prompt artifacts mention", () => {
754
754
  expect(prompt).not.toContain("/artifacts");
755
755
  });
756
756
 
757
- test("includes artifacts mention when no capabilities specified (default)", () => {
758
- const prompt = getBasePrompt({
757
+ test("includes artifacts mention when no capabilities specified (default)", async () => {
758
+ const prompt = await getBasePrompt({
759
759
  role: "worker",
760
760
  agentId: "test-agent-id",
761
761
  swarmUrl: "https://test.swarm.example.com",
@@ -764,8 +764,8 @@ describe("base prompt artifacts mention", () => {
764
764
  expect(prompt).toContain("/artifacts");
765
765
  });
766
766
 
767
- test("does NOT inline full artifact docs (those go in the skill)", () => {
768
- const prompt = getBasePrompt({
767
+ test("does NOT inline full artifact docs (those go in the skill)", async () => {
768
+ const prompt = await getBasePrompt({
769
769
  role: "worker",
770
770
  agentId: "test-agent-id",
771
771
  swarmUrl: "https://test.swarm.example.com",
@@ -776,8 +776,8 @@ describe("base prompt artifacts mention", () => {
776
776
  expect(prompt).not.toContain("SwarmSDK");
777
777
  });
778
778
 
779
- test("mentions localtunnel concept", () => {
780
- const prompt = getBasePrompt({
779
+ test("mentions localtunnel concept", async () => {
780
+ const prompt = await getBasePrompt({
781
781
  role: "worker",
782
782
  agentId: "test-agent-id",
783
783
  swarmUrl: "https://test.swarm.example.com",
@@ -787,8 +787,8 @@ describe("base prompt artifacts mention", () => {
787
787
  expect(prompt).toContain("localtunnel");
788
788
  });
789
789
 
790
- test("mentions artifact storage path", () => {
791
- const prompt = getBasePrompt({
790
+ test("mentions artifact storage path", async () => {
791
+ const prompt = await getBasePrompt({
792
792
  role: "worker",
793
793
  agentId: "test-agent-id",
794
794
  swarmUrl: "https://test.swarm.example.com",
@@ -12,25 +12,25 @@ const minimalArgs: BasePromptArgs = {
12
12
  // Basic fields
13
13
  // ---------------------------------------------------------------------------
14
14
  describe("getBasePrompt — basic fields", () => {
15
- test("includes role and agentId", () => {
16
- const result = getBasePrompt(minimalArgs);
15
+ test("includes role and agentId", async () => {
16
+ const result = await getBasePrompt(minimalArgs);
17
17
  expect(result).toContain("worker");
18
18
  expect(result).toContain("agent-abc-123");
19
19
  });
20
20
 
21
- test("lead role gets lead prompt", () => {
22
- const result = getBasePrompt({ ...minimalArgs, role: "lead" });
21
+ test("lead role gets lead prompt", async () => {
22
+ const result = await getBasePrompt({ ...minimalArgs, role: "lead" });
23
23
  expect(result).toContain("lead agent");
24
24
  expect(result).toContain("coordinator");
25
25
  });
26
26
 
27
- test("worker role gets worker prompt", () => {
28
- const result = getBasePrompt(minimalArgs);
27
+ test("worker role gets worker prompt", async () => {
28
+ const result = await getBasePrompt(minimalArgs);
29
29
  expect(result).toContain("worker agent");
30
30
  });
31
31
 
32
- test("includes swarmUrl and agentId in services section", () => {
33
- const result = getBasePrompt(minimalArgs);
32
+ test("includes swarmUrl and agentId in services section", async () => {
33
+ const result = await getBasePrompt(minimalArgs);
34
34
  expect(result).toContain("swarm.example.com");
35
35
  expect(result).toContain(`https://agent-abc-123.swarm.example.com`);
36
36
  });
@@ -40,13 +40,13 @@ describe("getBasePrompt — basic fields", () => {
40
40
  // Identity fields (name, description, soulMd, identityMd)
41
41
  // ---------------------------------------------------------------------------
42
42
  describe("getBasePrompt — identity fields", () => {
43
- test("includes name when provided", () => {
44
- const result = getBasePrompt({ ...minimalArgs, name: "TestAgent" });
43
+ test("includes name when provided", async () => {
44
+ const result = await getBasePrompt({ ...minimalArgs, name: "TestAgent" });
45
45
  expect(result).toContain("**Name:** TestAgent");
46
46
  });
47
47
 
48
- test("includes description when name provided", () => {
49
- const result = getBasePrompt({
48
+ test("includes description when name provided", async () => {
49
+ const result = await getBasePrompt({
50
50
  ...minimalArgs,
51
51
  name: "TestAgent",
52
52
  description: "A helpful agent",
@@ -54,16 +54,16 @@ describe("getBasePrompt — identity fields", () => {
54
54
  expect(result).toContain("**Description:** A helpful agent");
55
55
  });
56
56
 
57
- test("does not include description without name", () => {
58
- const result = getBasePrompt({
57
+ test("does not include description without name", async () => {
58
+ const result = await getBasePrompt({
59
59
  ...minimalArgs,
60
60
  description: "A helpful agent",
61
61
  });
62
62
  expect(result).not.toContain("**Description:**");
63
63
  });
64
64
 
65
- test("includes soulMd content", () => {
66
- const result = getBasePrompt({
65
+ test("includes soulMd content", async () => {
66
+ const result = await getBasePrompt({
67
67
  ...minimalArgs,
68
68
  soulMd: "I am a creative soul.",
69
69
  });
@@ -71,8 +71,8 @@ describe("getBasePrompt — identity fields", () => {
71
71
  expect(result).toContain("I am a creative soul.");
72
72
  });
73
73
 
74
- test("includes identityMd content", () => {
75
- const result = getBasePrompt({
74
+ test("includes identityMd content", async () => {
75
+ const result = await getBasePrompt({
76
76
  ...minimalArgs,
77
77
  identityMd: "Identity content here.",
78
78
  });
@@ -80,8 +80,8 @@ describe("getBasePrompt — identity fields", () => {
80
80
  expect(result).toContain("Identity content here.");
81
81
  });
82
82
 
83
- test("no identity section when none provided", () => {
84
- const result = getBasePrompt(minimalArgs);
83
+ test("no identity section when none provided", async () => {
84
+ const result = await getBasePrompt(minimalArgs);
85
85
  expect(result).not.toContain("## Your Identity");
86
86
  });
87
87
  });
@@ -90,8 +90,8 @@ describe("getBasePrompt — identity fields", () => {
90
90
  // claudeMd and toolsMd injection
91
91
  // ---------------------------------------------------------------------------
92
92
  describe("getBasePrompt — claudeMd and toolsMd injection", () => {
93
- test("includes claudeMd under Agent Instructions", () => {
94
- const result = getBasePrompt({
93
+ test("includes claudeMd under Agent Instructions", async () => {
94
+ const result = await getBasePrompt({
95
95
  ...minimalArgs,
96
96
  claudeMd: "Follow these rules.",
97
97
  });
@@ -99,8 +99,8 @@ describe("getBasePrompt — claudeMd and toolsMd injection", () => {
99
99
  expect(result).toContain("Follow these rules.");
100
100
  });
101
101
 
102
- test("includes toolsMd under Tools & Capabilities", () => {
103
- const result = getBasePrompt({
102
+ test("includes toolsMd under Tools & Capabilities", async () => {
103
+ const result = await getBasePrompt({
104
104
  ...minimalArgs,
105
105
  toolsMd: "You can use curl.",
106
106
  });
@@ -108,8 +108,8 @@ describe("getBasePrompt — claudeMd and toolsMd injection", () => {
108
108
  expect(result).toContain("You can use curl.");
109
109
  });
110
110
 
111
- test("both claudeMd and toolsMd coexist", () => {
112
- const result = getBasePrompt({
111
+ test("both claudeMd and toolsMd coexist", async () => {
112
+ const result = await getBasePrompt({
113
113
  ...minimalArgs,
114
114
  claudeMd: "Agent instructions content",
115
115
  toolsMd: "Tools content",
@@ -120,8 +120,8 @@ describe("getBasePrompt — claudeMd and toolsMd injection", () => {
120
120
  expect(result).toContain("Tools content");
121
121
  });
122
122
 
123
- test("neither present when not provided", () => {
124
- const result = getBasePrompt(minimalArgs);
123
+ test("neither present when not provided", async () => {
124
+ const result = await getBasePrompt(minimalArgs);
125
125
  expect(result).not.toContain("## Agent Instructions");
126
126
  expect(result).not.toContain("## Your Tools & Capabilities");
127
127
  });
@@ -131,8 +131,8 @@ describe("getBasePrompt — claudeMd and toolsMd injection", () => {
131
131
  // repoContext
132
132
  // ---------------------------------------------------------------------------
133
133
  describe("getBasePrompt — repoContext", () => {
134
- test("includes repo claudeMd with clone path", () => {
135
- const result = getBasePrompt({
134
+ test("includes repo claudeMd with clone path", async () => {
135
+ const result = await getBasePrompt({
136
136
  ...minimalArgs,
137
137
  repoContext: {
138
138
  claudeMd: "Repo-specific rules here.",
@@ -144,8 +144,8 @@ describe("getBasePrompt — repoContext", () => {
144
144
  expect(result).toContain("Repo-specific rules here.");
145
145
  });
146
146
 
147
- test("shows warning when provided", () => {
148
- const result = getBasePrompt({
147
+ test("shows warning when provided", async () => {
148
+ const result = await getBasePrompt({
149
149
  ...minimalArgs,
150
150
  repoContext: {
151
151
  claudeMd: "Rules",
@@ -156,8 +156,8 @@ describe("getBasePrompt — repoContext", () => {
156
156
  expect(result).toContain("WARNING: Repo is stale");
157
157
  });
158
158
 
159
- test("shows 'no CLAUDE.md' message when claudeMd is null and no warning", () => {
160
- const result = getBasePrompt({
159
+ test("shows 'no CLAUDE.md' message when claudeMd is null and no warning", async () => {
160
+ const result = await getBasePrompt({
161
161
  ...minimalArgs,
162
162
  repoContext: {
163
163
  claudeMd: null,
@@ -172,21 +172,21 @@ describe("getBasePrompt — repoContext", () => {
172
172
  // Capabilities
173
173
  // ---------------------------------------------------------------------------
174
174
  describe("getBasePrompt — capabilities", () => {
175
- test("services section included by default", () => {
176
- const result = getBasePrompt(minimalArgs);
175
+ test("services section included by default", async () => {
176
+ const result = await getBasePrompt(minimalArgs);
177
177
  expect(result).toContain("Service Registry");
178
178
  });
179
179
 
180
- test("services section excluded when capabilities don't include services", () => {
181
- const result = getBasePrompt({
180
+ test("services section excluded when capabilities don't include services", async () => {
181
+ const result = await getBasePrompt({
182
182
  ...minimalArgs,
183
183
  capabilities: ["artifacts"],
184
184
  });
185
185
  expect(result).not.toContain("Service Registry");
186
186
  });
187
187
 
188
- test("capabilities list rendered", () => {
189
- const result = getBasePrompt({
188
+ test("capabilities list rendered", async () => {
189
+ const result = await getBasePrompt({
190
190
  ...minimalArgs,
191
191
  capabilities: ["services", "artifacts"],
192
192
  });
@@ -202,8 +202,8 @@ describe("getBasePrompt — capabilities", () => {
202
202
  describe("getBasePrompt — truncation", () => {
203
203
  const bigString = (n: number) => "x".repeat(n);
204
204
 
205
- test("claudeMd truncated when exceeding per-section limit (20k chars)", () => {
206
- const result = getBasePrompt({
205
+ test("claudeMd truncated when exceeding per-section limit (20k chars)", async () => {
206
+ const result = await getBasePrompt({
207
207
  ...minimalArgs,
208
208
  claudeMd: bigString(25_000),
209
209
  });
@@ -212,8 +212,8 @@ describe("getBasePrompt — truncation", () => {
212
212
  expect(result).not.toContain(bigString(25_000));
213
213
  });
214
214
 
215
- test("toolsMd truncated when exceeding per-section limit", () => {
216
- const result = getBasePrompt({
215
+ test("toolsMd truncated when exceeding per-section limit", async () => {
216
+ const result = await getBasePrompt({
217
217
  ...minimalArgs,
218
218
  toolsMd: bigString(25_000),
219
219
  });
@@ -221,18 +221,18 @@ describe("getBasePrompt — truncation", () => {
221
221
  expect(result).not.toContain(bigString(25_000));
222
222
  });
223
223
 
224
- test("total budget respected — tools truncated before claudeMd", () => {
224
+ test("total budget respected — tools truncated before claudeMd", async () => {
225
225
  // Use soulMd to eat up most of the 150k total budget so that
226
226
  // truncatable sections (claudeMd, toolsMd) must compete for the remainder.
227
227
  // soulMd is part of `prompt` which counts toward protectedLength.
228
- const baseResult = getBasePrompt(minimalArgs);
228
+ const baseResult = await getBasePrompt(minimalArgs);
229
229
  const staticLength = baseResult.length; // ~12-13k for static content
230
230
 
231
231
  // Leave exactly enough budget for claudeMd but not toolsMd.
232
232
  // Total budget = 150k - protectedLength.
233
233
  // We want: protectedLength ≈ 150k - 18k = 132k, so claudeMd (15k) fits but toolsMd doesn't.
234
234
  const soulSize = 132_000 - staticLength;
235
- const result = getBasePrompt({
235
+ const result = await getBasePrompt({
236
236
  ...minimalArgs,
237
237
  soulMd: bigString(Math.max(0, soulSize)),
238
238
  claudeMd: bigString(15_000),
@@ -248,9 +248,9 @@ describe("getBasePrompt — truncation", () => {
248
248
  expect(hasToolsTruncation || !hasToolsHeader).toBe(true);
249
249
  });
250
250
 
251
- test("repo context never truncated", () => {
251
+ test("repo context never truncated", async () => {
252
252
  const hugeRepoClaudeMd = bigString(30_000);
253
- const result = getBasePrompt({
253
+ const result = await getBasePrompt({
254
254
  ...minimalArgs,
255
255
  repoContext: {
256
256
  claudeMd: hugeRepoClaudeMd,
@@ -0,0 +1,363 @@
1
+ import { afterAll, beforeAll, describe, expect, mock, setDefaultTimeout, test } from "bun:test";
2
+ import { unlinkSync } from "node:fs";
3
+ import { createServer as createHttpServer, type Server } from "node:http";
4
+
5
+ // Migrations + mock.module + @slack/bolt resolution can take >5s on cold start
6
+ setDefaultTimeout(30_000);
7
+
8
+ // ─── Mock Slack client (must be before channel-activity import) ─────────────
9
+
10
+ // Mutable mock implementation — changed per test via reassignment
11
+ let historyImpl: (args: Record<string, unknown>) => Promise<{
12
+ messages?: Array<Record<string, unknown>>;
13
+ }> = () => Promise.resolve({ messages: [] });
14
+
15
+ mock.module("../slack/app", () => ({
16
+ getSlackApp: () => ({
17
+ client: {
18
+ auth: { test: () => Promise.resolve({ user_id: "UBOT123" }) },
19
+ conversations: {
20
+ history: (args: Record<string, unknown>) => historyImpl(args),
21
+ list: () =>
22
+ Promise.resolve({
23
+ channels: [
24
+ { id: "C001", name: "general", is_member: true },
25
+ { id: "C002", name: "random", is_member: true },
26
+ { id: "C003", name: "archived", is_member: false },
27
+ ],
28
+ response_metadata: {},
29
+ }),
30
+ },
31
+ },
32
+ }),
33
+ }));
34
+
35
+ import {
36
+ closeDb,
37
+ getAllChannelActivityCursors,
38
+ getChannelActivityCursor,
39
+ initDb,
40
+ upsertChannelActivityCursor,
41
+ } from "../be/db";
42
+ import { fetchChannelActivity } from "../slack/channel-activity";
43
+
44
+ const TEST_DB_PATH = `./test-channel-activity-${process.pid}.sqlite`;
45
+
46
+ beforeAll(() => {
47
+ initDb(TEST_DB_PATH);
48
+ });
49
+
50
+ afterAll(() => {
51
+ closeDb();
52
+ for (const suffix of ["", "-wal", "-shm"]) {
53
+ try {
54
+ unlinkSync(`${TEST_DB_PATH}${suffix}`);
55
+ } catch {
56
+ // ignore
57
+ }
58
+ }
59
+ });
60
+
61
+ // ─── DB Functions ──────────────────────────────────────────────────────────────
62
+
63
+ describe("Channel Activity Cursors — DB functions", () => {
64
+ test("getChannelActivityCursor returns null for non-existent channel", () => {
65
+ const cursor = getChannelActivityCursor("C_NONEXISTENT");
66
+ expect(cursor).toBeNull();
67
+ });
68
+
69
+ test("getAllChannelActivityCursors returns an array", () => {
70
+ const cursors = getAllChannelActivityCursors();
71
+ expect(Array.isArray(cursors)).toBe(true);
72
+ });
73
+
74
+ test("upsertChannelActivityCursor inserts a new cursor", () => {
75
+ upsertChannelActivityCursor("C_INSERT_TEST", "1711111111.000001");
76
+ const cursor = getChannelActivityCursor("C_INSERT_TEST");
77
+ expect(cursor).not.toBeNull();
78
+ expect(cursor!.channelId).toBe("C_INSERT_TEST");
79
+ expect(cursor!.lastSeenTs).toBe("1711111111.000001");
80
+ expect(cursor!.updatedAt).toBeTruthy();
81
+ });
82
+
83
+ test("upsertChannelActivityCursor updates existing cursor", () => {
84
+ upsertChannelActivityCursor("C_UPDATE_TEST", "1711111111.000001");
85
+ upsertChannelActivityCursor("C_UPDATE_TEST", "1711111111.000099");
86
+ const after = getChannelActivityCursor("C_UPDATE_TEST");
87
+ expect(after!.lastSeenTs).toBe("1711111111.000099");
88
+ });
89
+
90
+ test("getAllChannelActivityCursors returns all inserted cursors", () => {
91
+ upsertChannelActivityCursor("C_ALL_1", "1711111111.000001");
92
+ upsertChannelActivityCursor("C_ALL_2", "1711111111.000002");
93
+ const ids = getAllChannelActivityCursors().map((c) => c.channelId);
94
+ expect(ids).toContain("C_ALL_1");
95
+ expect(ids).toContain("C_ALL_2");
96
+ });
97
+
98
+ test("channelId is primary key — no duplicates", () => {
99
+ upsertChannelActivityCursor("C_PK_TEST", "1711111111.000001");
100
+ upsertChannelActivityCursor("C_PK_TEST", "1711111111.000002");
101
+ upsertChannelActivityCursor("C_PK_TEST", "1711111111.000003");
102
+ const cursors = getAllChannelActivityCursors().filter((c) => c.channelId === "C_PK_TEST");
103
+ expect(cursors.length).toBe(1);
104
+ expect(cursors[0].lastSeenTs).toBe("1711111111.000003");
105
+ });
106
+ });
107
+
108
+ // ─── Cursor Commit Endpoint ─────────────────────────────────────────────────
109
+
110
+ describe("Channel Activity — cursor commit endpoint", () => {
111
+ let server: Server;
112
+ const TEST_PORT = 13099;
113
+
114
+ beforeAll(async () => {
115
+ server = createHttpServer(async (req, res) => {
116
+ if (req.method === "POST" && req.url === "/api/channel-activity/commit-cursors") {
117
+ const body = await new Promise<string>((resolve) => {
118
+ let data = "";
119
+ req.on("data", (chunk: Buffer) => {
120
+ data += chunk.toString();
121
+ });
122
+ req.on("end", () => resolve(data));
123
+ });
124
+
125
+ try {
126
+ const parsed = JSON.parse(body) as {
127
+ cursorUpdates?: Array<{ channelId: string; ts: string }>;
128
+ };
129
+
130
+ if (!parsed.cursorUpdates || !Array.isArray(parsed.cursorUpdates)) {
131
+ res.writeHead(400, { "Content-Type": "application/json" });
132
+ res.end(JSON.stringify({ error: "Missing cursorUpdates array" }));
133
+ return;
134
+ }
135
+
136
+ for (const { channelId, ts } of parsed.cursorUpdates) {
137
+ if (channelId && ts) {
138
+ upsertChannelActivityCursor(channelId, ts);
139
+ }
140
+ }
141
+
142
+ res.writeHead(200, { "Content-Type": "application/json" });
143
+ res.end(JSON.stringify({ success: true, committed: parsed.cursorUpdates.length }));
144
+ } catch (err) {
145
+ res.writeHead(400, { "Content-Type": "application/json" });
146
+ res.end(JSON.stringify({ error: `Invalid request: ${err}` }));
147
+ }
148
+ return;
149
+ }
150
+
151
+ res.writeHead(404);
152
+ res.end("Not Found");
153
+ });
154
+
155
+ await new Promise<void>((resolve) => {
156
+ server.listen(TEST_PORT, () => resolve());
157
+ });
158
+ });
159
+
160
+ afterAll(() => {
161
+ server.close();
162
+ });
163
+
164
+ test("commits cursor updates successfully", async () => {
165
+ const resp = await fetch(`http://localhost:${TEST_PORT}/api/channel-activity/commit-cursors`, {
166
+ method: "POST",
167
+ headers: { "Content-Type": "application/json" },
168
+ body: JSON.stringify({
169
+ cursorUpdates: [
170
+ { channelId: "C_COMMIT_1", ts: "1711222222.000001" },
171
+ { channelId: "C_COMMIT_2", ts: "1711222222.000002" },
172
+ ],
173
+ }),
174
+ });
175
+
176
+ expect(resp.status).toBe(200);
177
+ const data = (await resp.json()) as { success: boolean; committed: number };
178
+ expect(data.success).toBe(true);
179
+ expect(data.committed).toBe(2);
180
+
181
+ expect(getChannelActivityCursor("C_COMMIT_1")!.lastSeenTs).toBe("1711222222.000001");
182
+ expect(getChannelActivityCursor("C_COMMIT_2")!.lastSeenTs).toBe("1711222222.000002");
183
+ });
184
+
185
+ test("rejects request without cursorUpdates array", async () => {
186
+ const resp = await fetch(`http://localhost:${TEST_PORT}/api/channel-activity/commit-cursors`, {
187
+ method: "POST",
188
+ headers: { "Content-Type": "application/json" },
189
+ body: JSON.stringify({ foo: "bar" }),
190
+ });
191
+ expect(resp.status).toBe(400);
192
+ });
193
+
194
+ test("rejects invalid JSON body", async () => {
195
+ const resp = await fetch(`http://localhost:${TEST_PORT}/api/channel-activity/commit-cursors`, {
196
+ method: "POST",
197
+ headers: { "Content-Type": "application/json" },
198
+ body: "not json",
199
+ });
200
+ expect(resp.status).toBe(400);
201
+ });
202
+
203
+ test("skips entries with missing channelId or ts", async () => {
204
+ const resp = await fetch(`http://localhost:${TEST_PORT}/api/channel-activity/commit-cursors`, {
205
+ method: "POST",
206
+ headers: { "Content-Type": "application/json" },
207
+ body: JSON.stringify({
208
+ cursorUpdates: [
209
+ { channelId: "C_VALID", ts: "1711333333.000001" },
210
+ { channelId: "", ts: "1711333333.000002" },
211
+ { channelId: "C_NO_TS", ts: "" },
212
+ ],
213
+ }),
214
+ });
215
+
216
+ expect(resp.status).toBe(200);
217
+ expect(getChannelActivityCursor("C_VALID")!.lastSeenTs).toBe("1711333333.000001");
218
+ expect(getChannelActivityCursor("C_NO_TS")).toBeNull();
219
+ });
220
+ });
221
+
222
+ // ─── fetchChannelActivity (mocked Slack) ─────────────────────────────────────
223
+
224
+ describe("Channel Activity — fetchChannelActivity", () => {
225
+ test("cold-start: channels without cursor get seed cursors, no messages", async () => {
226
+ historyImpl = () =>
227
+ Promise.resolve({
228
+ messages: [{ ts: "1711000000.000100", user: "U123", text: "Latest" }],
229
+ });
230
+
231
+ const result = await fetchChannelActivity(new Map());
232
+
233
+ // Cold start should NOT return messages (prevents flood)
234
+ expect(result.messages).toHaveLength(0);
235
+ // Should have seed cursors for bot-member channels (C001 and C002; C003 is_member=false)
236
+ expect(result.seedCursors.size).toBe(2);
237
+ expect(result.seedCursors.get("C001")).toBe("1711000000.000100");
238
+ expect(result.seedCursors.get("C002")).toBe("1711000000.000100");
239
+ });
240
+
241
+ test("incremental: returns messages newer than cursor, sorted oldest-first", async () => {
242
+ historyImpl = () =>
243
+ Promise.resolve({
244
+ messages: [
245
+ { ts: "1711000000.000050", user: "U123", text: "At cursor" },
246
+ { ts: "1711000000.000060", user: "U456", text: "Newer 2" },
247
+ { ts: "1711000000.000055", user: "U789", text: "Newer 1" },
248
+ ],
249
+ });
250
+
251
+ const cursors = new Map([
252
+ ["C001", "1711000000.000050"],
253
+ ["C002", "1711000000.000050"],
254
+ ]);
255
+ const result = await fetchChannelActivity(cursors);
256
+
257
+ // Cursor message skipped, 2 newer per channel × 2 channels = 4
258
+ const c001msgs = result.messages.filter((m) => m.channelId === "C001");
259
+ expect(c001msgs).toHaveLength(2);
260
+ // Sorted oldest-first
261
+ expect(Number.parseFloat(result.messages[0].ts)).toBeLessThanOrEqual(
262
+ Number.parseFloat(result.messages[result.messages.length - 1].ts),
263
+ );
264
+ });
265
+
266
+ test("filters bot messages, thread replies, empty text, own bot user", async () => {
267
+ historyImpl = () =>
268
+ Promise.resolve({
269
+ messages: [
270
+ { ts: "1711000000.000051", user: "U123", text: "Valid message" },
271
+ { ts: "1711000000.000052", user: "U456", text: "Bot msg", bot_id: "B001" },
272
+ { ts: "1711000000.000053", user: "U789", text: "Bot subtype", subtype: "bot_message" },
273
+ { ts: "1711000000.000054", user: "UBOT123", text: "Own bot msg" },
274
+ { ts: "1711000000.000055", user: "U111", text: "" },
275
+ {
276
+ ts: "1711000000.000056",
277
+ user: "U222",
278
+ text: "Thread reply",
279
+ thread_ts: "1711000000.000001",
280
+ },
281
+ {
282
+ ts: "1711000000.000057",
283
+ user: "U333",
284
+ text: "Thread parent",
285
+ thread_ts: "1711000000.000057",
286
+ },
287
+ { ts: "1711000000.000058", user: undefined, text: "No user" },
288
+ ],
289
+ });
290
+
291
+ const cursors = new Map([["C001", "1711000000.000050"]]);
292
+ const result = await fetchChannelActivity(cursors, ["C001"]);
293
+
294
+ const texts = result.messages.map((m) => m.text);
295
+ expect(texts).toContain("Valid message");
296
+ expect(texts).toContain("Thread parent");
297
+ expect(texts).not.toContain("Bot msg");
298
+ expect(texts).not.toContain("Bot subtype");
299
+ expect(texts).not.toContain("Own bot msg");
300
+ expect(texts).not.toContain("Thread reply");
301
+ expect(texts).not.toContain("No user");
302
+ });
303
+
304
+ test("allowedChannelIds restricts which channels are processed", async () => {
305
+ historyImpl = () =>
306
+ Promise.resolve({
307
+ messages: [{ ts: "1711000000.000100", user: "U123", text: "Hello" }],
308
+ });
309
+
310
+ const cursors = new Map([
311
+ ["C001", "1711000000.000050"],
312
+ ["C002", "1711000000.000050"],
313
+ ]);
314
+ const result = await fetchChannelActivity(cursors, ["C001"]);
315
+
316
+ const channelIds = new Set(result.messages.map((m) => m.channelId));
317
+ expect(channelIds.has("C001")).toBe(true);
318
+ expect(channelIds.has("C002")).toBe(false);
319
+ });
320
+
321
+ test("gracefully handles errors from conversations.history", async () => {
322
+ historyImpl = () => Promise.reject(new Error("channel_not_found"));
323
+
324
+ const cursors = new Map([["C001", "1711000000.000050"]]);
325
+ const result = await fetchChannelActivity(cursors, ["C001"]);
326
+
327
+ // Should not throw — errors are caught and logged
328
+ expect(result.messages).toHaveLength(0);
329
+ });
330
+
331
+ test("includes channelName in returned messages", async () => {
332
+ historyImpl = () =>
333
+ Promise.resolve({
334
+ messages: [{ ts: "1711000000.000051", user: "U123", text: "Hi" }],
335
+ });
336
+
337
+ const cursors = new Map([["C001", "1711000000.000050"]]);
338
+ const result = await fetchChannelActivity(cursors, ["C001"]);
339
+
340
+ expect(result.messages[0].channelName).toBe("general");
341
+ expect(result.messages[0].channelId).toBe("C001");
342
+ });
343
+ });
344
+
345
+ // ─── Migration ──────────────────────────────────────────────────────────────
346
+
347
+ describe("Channel Activity — migration 015", () => {
348
+ test("channel_activity_cursors table exists and has correct schema", () => {
349
+ upsertChannelActivityCursor("C_SCHEMA_TEST", "1711999999.000001");
350
+ const cursor = getChannelActivityCursor("C_SCHEMA_TEST");
351
+ expect(cursor).not.toBeNull();
352
+ expect(cursor!.channelId).toBe("C_SCHEMA_TEST");
353
+ expect(cursor!.lastSeenTs).toBe("1711999999.000001");
354
+ expect(cursor!.updatedAt).toBeTruthy();
355
+ });
356
+
357
+ test("channelId is PRIMARY KEY — duplicate insert updates instead of failing", () => {
358
+ upsertChannelActivityCursor("C_PK_MIG", "1711000000.000001");
359
+ upsertChannelActivityCursor("C_PK_MIG", "1711000000.000999");
360
+ const cursor = getChannelActivityCursor("C_PK_MIG");
361
+ expect(cursor!.lastSeenTs).toBe("1711000000.000999");
362
+ });
363
+ });