@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,1133 +0,0 @@
1
- # Agent Renaming & PM2 Control from Frontend Implementation Plan
2
-
3
- ## Overview
4
-
5
- Implement two features to enhance frontend management capabilities:
6
- 1. **Agent name editing** - Allow changing agent names directly from the UI
7
- 2. **PM2 process control** - Stop/Start/Restart/Rename PM2 processes and view logs from the frontend
8
-
9
- Since agents run on separate machines (distributed architecture), PM2 control requires a **command queue system** where the backend queues commands and agents poll for them, execute locally, and report results.
10
-
11
- ## Current State Analysis
12
-
13
- ### Key Discoveries:
14
-
15
- - Agent names are stored in SQLite `agents` table but can only be set at registration time via `POST /api/agents` (`src/http.ts:227-279`)
16
- - `updateAgentProfile()` function exists at `src/be/db.ts:1256-1286` but only updates `description`, `role`, `capabilities` - NOT `name`
17
- - No PATCH endpoint exists for agents
18
- - Services are tracked in `services` table with status (starting, healthy, unhealthy, stopped) at `src/be/db.ts:134-155`
19
- - MCP tools exist for agents to register/unregister/update their own services at `src/tools/services.ts`
20
- - Agents poll for triggers via `GET /api/poll` at `src/http.ts:282-379` with runner implementation at `src/commands/runner.ts:237-277`
21
- - Frontend uses React Query hooks at `ui/src/hooks/queries.ts` and API client at `ui/src/lib/api.ts`
22
- - ServicesPanel at `ui/src/components/ServicesPanel.tsx` is currently read-only display
23
-
24
- ## Desired End State
25
-
26
- 1. **Agent name editing**: Users can click an edit button next to agent name in AgentDetailPanel, modify the name inline, and save. The change persists to the database and UI updates immediately.
27
-
28
- 2. **PM2 control**: ServicesPanel displays action buttons (Stop, Start, Restart, Logs) for each service. Clicking a button:
29
- - Creates a command in the database
30
- - Agent polls and receives the command
31
- - Agent executes PM2 command locally
32
- - Agent reports result back to backend
33
- - Frontend shows command status and result
34
-
35
- 3. **Log viewing**: A modal displays PM2 logs for a service with stdout/stderr filtering and auto-refresh.
36
-
37
- ## What We're NOT Doing
38
-
39
- - WebSocket-based real-time updates (using polling for simplicity)
40
- - Agent-to-agent direct communication for PM2 control
41
- - PM2 process configuration editing (only lifecycle control)
42
- - Bulk operations on multiple services at once
43
- - Historical command audit UI (just current command status)
44
-
45
- ## Implementation Approach
46
-
47
- The implementation follows a layered approach:
48
- 1. Backend database and API changes first
49
- 2. Agent-side command execution
50
- 3. Frontend UI components
51
-
52
- For PM2 control, we use a command queue pattern since agents are distributed. This reuses the existing polling mechanism, extending the `Trigger` type to include `command_pending`.
53
-
54
- ---
55
-
56
- ## Phase 1: Agent Name Editing - Backend
57
-
58
- ### Overview
59
- Add database function and API endpoint to update agent names.
60
-
61
- ### Changes Required:
62
-
63
- #### 1. Database function for name update
64
- **File**: `src/be/db.ts`
65
- **Changes**: Add `updateAgentName()` function after `updateAgentProfile()` (around line 1286)
66
-
67
- ```typescript
68
- export function updateAgentName(id: string, newName: string): Agent | null {
69
- const agent = getAgentById(id);
70
- if (!agent) return null;
71
-
72
- const now = new Date().toISOString();
73
- const row = getDb()
74
- .prepare<AgentRow, [string, string, string]>(
75
- `UPDATE agents SET name = ?, lastUpdatedAt = ? WHERE id = ? RETURNING *`,
76
- )
77
- .get(newName, now, id);
78
-
79
- if (row) {
80
- try {
81
- createLogEntry({
82
- eventType: "agent_profile_update",
83
- agentId: id,
84
- oldValue: agent.name,
85
- newValue: newName,
86
- metadata: { field: "name" },
87
- });
88
- } catch {}
89
- }
90
-
91
- return row ? rowToAgent(row) : null;
92
- }
93
- ```
94
-
95
- #### 2. PATCH endpoint for agents
96
- **File**: `src/http.ts`
97
- **Changes**: Add PATCH handler after GET `/api/agents/:id` endpoint (around line 527)
98
-
99
- ```typescript
100
- // PATCH /api/agents/:id - Update agent properties
101
- if (
102
- req.method === "PATCH" &&
103
- pathSegments[0] === "api" &&
104
- pathSegments[1] === "agents" &&
105
- pathSegments[2]
106
- ) {
107
- const agentId = pathSegments[2];
108
-
109
- const chunks: Buffer[] = [];
110
- for await (const chunk of req) {
111
- chunks.push(chunk);
112
- }
113
- const body = JSON.parse(Buffer.concat(chunks).toString());
114
-
115
- const agent = getAgentById(agentId);
116
- if (!agent) {
117
- res.writeHead(404, { "Content-Type": "application/json" });
118
- res.end(JSON.stringify({ error: "Agent not found" }));
119
- return;
120
- }
121
-
122
- let updated = agent;
123
-
124
- // Update name if provided
125
- if (body.name && typeof body.name === "string") {
126
- const result = updateAgentName(agentId, body.name);
127
- if (result) updated = result;
128
- }
129
-
130
- // Update profile fields if provided
131
- if (body.description || body.role || body.capabilities) {
132
- const result = updateAgentProfile(agentId, {
133
- description: body.description,
134
- role: body.role,
135
- capabilities: body.capabilities,
136
- });
137
- if (result) updated = result;
138
- }
139
-
140
- res.writeHead(200, { "Content-Type": "application/json" });
141
- res.end(JSON.stringify(updated));
142
- return;
143
- }
144
- ```
145
-
146
- #### 3. Update imports in http.ts
147
- **File**: `src/http.ts`
148
- **Changes**: Add `updateAgentName` to imports from `./be/db`
149
-
150
- ### Success Criteria:
151
-
152
- #### Automated Verification:
153
- - [ ] TypeScript compiles: `bun run build` or `bunx tsc --noEmit`
154
- - [ ] Server starts without errors: `bun run src/http.ts`
155
- - [ ] API test: `curl -X PATCH http://localhost:3013/api/agents/<id> -H "Content-Type: application/json" -d '{"name":"new-name"}'`
156
-
157
- #### Manual Verification:
158
- - [ ] Agent name is updated in database after PATCH request
159
- - [ ] Agent log entry is created with `agent_profile_update` event
160
-
161
- **Implementation Note**: After completing this phase and all automated verification passes, pause here for manual confirmation before proceeding to Phase 2.
162
-
163
- ---
164
-
165
- ## Phase 2: Agent Name Editing - Frontend
166
-
167
- ### Overview
168
- Add API method, React Query mutation, and inline edit UI for agent names.
169
-
170
- ### Changes Required:
171
-
172
- #### 1. API method for updating agents
173
- **File**: `ui/src/lib/api.ts`
174
- **Changes**: Add `updateAgent` method to `ApiClient` class
175
-
176
- ```typescript
177
- async updateAgent(
178
- id: string,
179
- updates: { name?: string; description?: string; role?: string; capabilities?: string[] },
180
- ): Promise<Agent> {
181
- const res = await this.request(`/api/agents/${id}`, {
182
- method: "PATCH",
183
- headers: { "Content-Type": "application/json" },
184
- body: JSON.stringify(updates),
185
- });
186
- if (!res.ok) throw new Error("Failed to update agent");
187
- return res.json();
188
- }
189
- ```
190
-
191
- #### 2. React Query mutation hook
192
- **File**: `ui/src/hooks/queries.ts`
193
- **Changes**: Add `useUpdateAgent` hook
194
-
195
- ```typescript
196
- export function useUpdateAgent() {
197
- const queryClient = useQueryClient();
198
- return useMutation({
199
- mutationFn: ({
200
- id,
201
- updates,
202
- }: {
203
- id: string;
204
- updates: { name?: string; description?: string; role?: string };
205
- }) => api.updateAgent(id, updates),
206
- onSuccess: (_, variables) => {
207
- queryClient.invalidateQueries({ queryKey: ["agents"] });
208
- queryClient.invalidateQueries({ queryKey: ["agent", variables.id] });
209
- },
210
- });
211
- }
212
- ```
213
-
214
- #### 3. Add edit UI to AgentDetailPanel
215
- **File**: `ui/src/components/AgentDetailPanel.tsx`
216
- **Changes**: Add inline edit capability for agent name
217
-
218
- - Add `useState` for edit mode and name value
219
- - Add edit icon button next to agent name
220
- - When editing, show input field with save/cancel buttons
221
- - Call `useUpdateAgent` mutation on save
222
-
223
- ### Success Criteria:
224
-
225
- #### Automated Verification:
226
- - [ ] Frontend builds: `cd ui && bun run build`
227
- - [ ] TypeScript compiles: `cd ui && bunx tsc --noEmit`
228
-
229
- #### Manual Verification:
230
- - [ ] Edit button appears next to agent name in detail panel
231
- - [ ] Clicking edit shows input field with current name
232
- - [ ] Saving updates the name and closes edit mode
233
- - [ ] Cancel discards changes
234
- - [ ] Agent list refreshes with new name
235
-
236
- **Implementation Note**: After completing this phase and all automated verification passes, pause here for manual confirmation before proceeding to Phase 3.
237
-
238
- ---
239
-
240
- ## Phase 3: Command Queue System - Database & Types
241
-
242
- ### Overview
243
- Add database table and types for the command queue system.
244
-
245
- ### Changes Required:
246
-
247
- #### 1. Add command types
248
- **File**: `src/types.ts`
249
- **Changes**: Add command-related types
250
-
251
- ```typescript
252
- // Command types for PM2 control
253
- export type CommandType = "pm2_start" | "pm2_stop" | "pm2_restart" | "pm2_rename" | "pm2_logs";
254
- export type CommandStatus = "pending" | "in_progress" | "completed" | "failed" | "expired";
255
-
256
- export interface AgentCommand {
257
- id: string;
258
- agentId: string;
259
- serviceId?: string;
260
- commandType: CommandType;
261
- payload?: Record<string, unknown>;
262
- status: CommandStatus;
263
- result?: string;
264
- createdAt: string;
265
- startedAt?: string;
266
- completedAt?: string;
267
- expiresAt: string;
268
- createdBy: string;
269
- }
270
- ```
271
-
272
- #### 2. Add agent_commands table
273
- **File**: `src/be/db.ts`
274
- **Changes**: Add table creation in schema initialization (after services table)
275
-
276
- ```typescript
277
- database.run(`
278
- CREATE TABLE IF NOT EXISTS agent_commands (
279
- id TEXT PRIMARY KEY,
280
- agentId TEXT NOT NULL,
281
- serviceId TEXT,
282
- commandType TEXT NOT NULL CHECK(commandType IN ('pm2_start', 'pm2_stop', 'pm2_restart', 'pm2_rename', 'pm2_logs')),
283
- payload TEXT,
284
- status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'in_progress', 'completed', 'failed', 'expired')),
285
- result TEXT,
286
- createdAt TEXT NOT NULL,
287
- startedAt TEXT,
288
- completedAt TEXT,
289
- expiresAt TEXT NOT NULL,
290
- createdBy TEXT,
291
- FOREIGN KEY (agentId) REFERENCES agents(id) ON DELETE CASCADE,
292
- FOREIGN KEY (serviceId) REFERENCES services(id) ON DELETE SET NULL
293
- )
294
- `);
295
- ```
296
-
297
- Add indexes:
298
- ```typescript
299
- database.run(`CREATE INDEX IF NOT EXISTS idx_agent_commands_agentId ON agent_commands(agentId)`);
300
- database.run(`CREATE INDEX IF NOT EXISTS idx_agent_commands_status ON agent_commands(status)`);
301
- database.run(`CREATE INDEX IF NOT EXISTS idx_agent_commands_createdAt ON agent_commands(createdAt)`);
302
- ```
303
-
304
- #### 3. Add CRUD functions for commands
305
- **File**: `src/be/db.ts`
306
- **Changes**: Add command management functions
307
-
308
- ```typescript
309
- // Command row type
310
- type CommandRow = {
311
- id: string;
312
- agentId: string;
313
- serviceId: string | null;
314
- commandType: CommandType;
315
- payload: string | null;
316
- status: CommandStatus;
317
- result: string | null;
318
- createdAt: string;
319
- startedAt: string | null;
320
- completedAt: string | null;
321
- expiresAt: string;
322
- createdBy: string | null;
323
- };
324
-
325
- function rowToCommand(row: CommandRow): AgentCommand {
326
- return {
327
- id: row.id,
328
- agentId: row.agentId,
329
- serviceId: row.serviceId ?? undefined,
330
- commandType: row.commandType,
331
- payload: row.payload ? JSON.parse(row.payload) : undefined,
332
- status: row.status,
333
- result: row.result ?? undefined,
334
- createdAt: row.createdAt,
335
- startedAt: row.startedAt ?? undefined,
336
- completedAt: row.completedAt ?? undefined,
337
- expiresAt: row.expiresAt,
338
- createdBy: row.createdBy ?? undefined,
339
- };
340
- }
341
-
342
- export interface CreateCommandOptions {
343
- serviceId?: string;
344
- payload?: Record<string, unknown>;
345
- createdBy?: string;
346
- expiresInMs?: number; // Default 5 minutes
347
- }
348
-
349
- export function createCommand(
350
- agentId: string,
351
- commandType: CommandType,
352
- options?: CreateCommandOptions,
353
- ): AgentCommand {
354
- const id = crypto.randomUUID();
355
- const now = new Date().toISOString();
356
- const expiresAt = new Date(Date.now() + (options?.expiresInMs ?? 5 * 60 * 1000)).toISOString();
357
-
358
- const row = getDb()
359
- .prepare<CommandRow, (string | null)[]>(
360
- `INSERT INTO agent_commands (id, agentId, serviceId, commandType, payload, status, createdAt, expiresAt, createdBy)
361
- VALUES (?, ?, ?, ?, ?, 'pending', ?, ?, ?) RETURNING *`,
362
- )
363
- .get(
364
- id,
365
- agentId,
366
- options?.serviceId ?? null,
367
- commandType,
368
- options?.payload ? JSON.stringify(options.payload) : null,
369
- now,
370
- expiresAt,
371
- options?.createdBy ?? null,
372
- );
373
-
374
- if (!row) throw new Error("Failed to create command");
375
- return rowToCommand(row);
376
- }
377
-
378
- export function getCommandById(id: string): AgentCommand | null {
379
- const row = getDb()
380
- .prepare<CommandRow, [string]>("SELECT * FROM agent_commands WHERE id = ?")
381
- .get(id);
382
- return row ? rowToCommand(row) : null;
383
- }
384
-
385
- export function getPendingCommandsForAgent(agentId: string): AgentCommand[] {
386
- const now = new Date().toISOString();
387
- return getDb()
388
- .prepare<CommandRow, [string, string]>(
389
- `SELECT * FROM agent_commands
390
- WHERE agentId = ? AND status = 'pending' AND expiresAt > ?
391
- ORDER BY createdAt ASC`,
392
- )
393
- .all(agentId, now)
394
- .map(rowToCommand);
395
- }
396
-
397
- export function updateCommandStatus(
398
- id: string,
399
- status: CommandStatus,
400
- result?: string,
401
- ): AgentCommand | null {
402
- const now = new Date().toISOString();
403
- const timestampField = status === "in_progress" ? "startedAt" : "completedAt";
404
-
405
- const row = getDb()
406
- .prepare<CommandRow, [CommandStatus, string | null, string, string]>(
407
- `UPDATE agent_commands
408
- SET status = ?, result = ?, ${timestampField} = ?
409
- WHERE id = ? RETURNING *`,
410
- )
411
- .get(status, result ?? null, now, id);
412
-
413
- return row ? rowToCommand(row) : null;
414
- }
415
-
416
- export interface CommandFilters {
417
- agentId?: string;
418
- status?: CommandStatus;
419
- serviceId?: string;
420
- }
421
-
422
- export function getAllCommands(filters?: CommandFilters): AgentCommand[] {
423
- const conditions: string[] = [];
424
- const params: string[] = [];
425
-
426
- if (filters?.agentId) {
427
- conditions.push("agentId = ?");
428
- params.push(filters.agentId);
429
- }
430
- if (filters?.status) {
431
- conditions.push("status = ?");
432
- params.push(filters.status);
433
- }
434
- if (filters?.serviceId) {
435
- conditions.push("serviceId = ?");
436
- params.push(filters.serviceId);
437
- }
438
-
439
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
440
- const query = `SELECT * FROM agent_commands ${whereClause} ORDER BY createdAt DESC LIMIT 100`;
441
-
442
- return getDb()
443
- .prepare<CommandRow, string[]>(query)
444
- .all(...params)
445
- .map(rowToCommand);
446
- }
447
-
448
- export function deleteCommand(id: string): boolean {
449
- const result = getDb().run("DELETE FROM agent_commands WHERE id = ?", [id]);
450
- return result.changes > 0;
451
- }
452
- ```
453
-
454
- ### Success Criteria:
455
-
456
- #### Automated Verification:
457
- - [ ] TypeScript compiles: `bunx tsc --noEmit`
458
- - [ ] Server starts and initializes database: `bun run src/http.ts`
459
- - [ ] Database has new table: `sqlite3 agent-swarm-db.sqlite ".schema agent_commands"`
460
-
461
- #### Manual Verification:
462
- - [ ] Table created with correct schema
463
- - [ ] Indexes created
464
-
465
- **Implementation Note**: After completing this phase and all automated verification passes, pause here for manual confirmation before proceeding to Phase 4.
466
-
467
- ---
468
-
469
- ## Phase 4: Command Queue System - API Endpoints
470
-
471
- ### Overview
472
- Add REST endpoints for command management.
473
-
474
- ### Changes Required:
475
-
476
- #### 1. Add command endpoints
477
- **File**: `src/http.ts`
478
- **Changes**: Add command CRUD endpoints
479
-
480
- ```typescript
481
- // POST /api/commands - Create a new command
482
- if (
483
- req.method === "POST" &&
484
- pathSegments[0] === "api" &&
485
- pathSegments[1] === "commands" &&
486
- !pathSegments[2]
487
- ) {
488
- const chunks: Buffer[] = [];
489
- for await (const chunk of req) {
490
- chunks.push(chunk);
491
- }
492
- const body = JSON.parse(Buffer.concat(chunks).toString());
493
-
494
- if (!body.agentId || !body.commandType) {
495
- res.writeHead(400, { "Content-Type": "application/json" });
496
- res.end(JSON.stringify({ error: "Missing agentId or commandType" }));
497
- return;
498
- }
499
-
500
- // Verify agent exists
501
- const agent = getAgentById(body.agentId);
502
- if (!agent) {
503
- res.writeHead(404, { "Content-Type": "application/json" });
504
- res.end(JSON.stringify({ error: "Agent not found" }));
505
- return;
506
- }
507
-
508
- const command = createCommand(body.agentId, body.commandType, {
509
- serviceId: body.serviceId,
510
- payload: body.payload,
511
- createdBy: myAgentId || "frontend",
512
- });
513
-
514
- res.writeHead(201, { "Content-Type": "application/json" });
515
- res.end(JSON.stringify(command));
516
- return;
517
- }
518
-
519
- // GET /api/commands - List commands
520
- if (
521
- req.method === "GET" &&
522
- pathSegments[0] === "api" &&
523
- pathSegments[1] === "commands" &&
524
- !pathSegments[2]
525
- ) {
526
- const agentId = queryParams.get("agentId") || undefined;
527
- const status = queryParams.get("status") as CommandStatus | undefined;
528
- const serviceId = queryParams.get("serviceId") || undefined;
529
-
530
- const commands = getAllCommands({ agentId, status, serviceId });
531
- res.writeHead(200, { "Content-Type": "application/json" });
532
- res.end(JSON.stringify({ commands }));
533
- return;
534
- }
535
-
536
- // GET /api/commands/:id - Get single command
537
- if (
538
- req.method === "GET" &&
539
- pathSegments[0] === "api" &&
540
- pathSegments[1] === "commands" &&
541
- pathSegments[2] &&
542
- !pathSegments[3]
543
- ) {
544
- const command = getCommandById(pathSegments[2]);
545
- if (!command) {
546
- res.writeHead(404, { "Content-Type": "application/json" });
547
- res.end(JSON.stringify({ error: "Command not found" }));
548
- return;
549
- }
550
-
551
- res.writeHead(200, { "Content-Type": "application/json" });
552
- res.end(JSON.stringify(command));
553
- return;
554
- }
555
-
556
- // POST /api/commands/:id/result - Agent reports command result
557
- if (
558
- req.method === "POST" &&
559
- pathSegments[0] === "api" &&
560
- pathSegments[1] === "commands" &&
561
- pathSegments[2] &&
562
- pathSegments[3] === "result"
563
- ) {
564
- const commandId = pathSegments[2];
565
- const command = getCommandById(commandId);
566
-
567
- if (!command) {
568
- res.writeHead(404, { "Content-Type": "application/json" });
569
- res.end(JSON.stringify({ error: "Command not found" }));
570
- return;
571
- }
572
-
573
- const chunks: Buffer[] = [];
574
- for await (const chunk of req) {
575
- chunks.push(chunk);
576
- }
577
- const body = JSON.parse(Buffer.concat(chunks).toString());
578
-
579
- const status = body.success ? "completed" : "failed";
580
- const updated = updateCommandStatus(commandId, status, JSON.stringify(body.result || body.error));
581
-
582
- res.writeHead(200, { "Content-Type": "application/json" });
583
- res.end(JSON.stringify(updated));
584
- return;
585
- }
586
-
587
- // DELETE /api/commands/:id - Cancel pending command
588
- if (
589
- req.method === "DELETE" &&
590
- pathSegments[0] === "api" &&
591
- pathSegments[1] === "commands" &&
592
- pathSegments[2]
593
- ) {
594
- const command = getCommandById(pathSegments[2]);
595
-
596
- if (!command) {
597
- res.writeHead(404, { "Content-Type": "application/json" });
598
- res.end(JSON.stringify({ error: "Command not found" }));
599
- return;
600
- }
601
-
602
- if (command.status !== "pending") {
603
- res.writeHead(400, { "Content-Type": "application/json" });
604
- res.end(JSON.stringify({ error: "Can only cancel pending commands" }));
605
- return;
606
- }
607
-
608
- deleteCommand(pathSegments[2]);
609
- res.writeHead(204);
610
- res.end();
611
- return;
612
- }
613
- ```
614
-
615
- #### 2. Extend poll endpoint for commands
616
- **File**: `src/http.ts`
617
- **Changes**: Add command trigger to poll response (in the transaction, after other trigger checks)
618
-
619
- ```typescript
620
- // Check for pending commands (before returning null trigger)
621
- const pendingCommands = getPendingCommandsForAgent(myAgentId);
622
- if (pendingCommands.length > 0) {
623
- const cmd = pendingCommands[0];
624
- // Mark as in_progress
625
- updateCommandStatus(cmd.id, "in_progress");
626
- return {
627
- trigger: {
628
- type: "command_pending",
629
- commandId: cmd.id,
630
- command: cmd,
631
- },
632
- };
633
- }
634
- ```
635
-
636
- #### 3. Update imports
637
- **File**: `src/http.ts`
638
- **Changes**: Add new imports from `./be/db`
639
-
640
- ```typescript
641
- import {
642
- // ... existing imports
643
- createCommand,
644
- getCommandById,
645
- getPendingCommandsForAgent,
646
- updateCommandStatus,
647
- getAllCommands,
648
- deleteCommand,
649
- } from "./be/db";
650
- ```
651
-
652
- ### Success Criteria:
653
-
654
- #### Automated Verification:
655
- - [ ] TypeScript compiles: `bunx tsc --noEmit`
656
- - [ ] Create command: `curl -X POST http://localhost:3013/api/commands -H "Content-Type: application/json" -d '{"agentId":"<id>","commandType":"pm2_stop","payload":{"processName":"test"}}'`
657
- - [ ] List commands: `curl http://localhost:3013/api/commands`
658
-
659
- #### Manual Verification:
660
- - [ ] Command appears in database after creation
661
- - [ ] Poll endpoint returns command_pending trigger
662
- - [ ] Command status updates to in_progress after poll
663
-
664
- **Implementation Note**: After completing this phase and all automated verification passes, pause here for manual confirmation before proceeding to Phase 5.
665
-
666
- ---
667
-
668
- ## Phase 5: Agent-Side Command Execution
669
-
670
- ### Overview
671
- Add PM2 command execution on the agent side.
672
-
673
- ### Changes Required:
674
-
675
- #### 1. Create PM2 executor module
676
- **File**: `src/commands/pm2-executor.ts` (new file)
677
- **Changes**: Create new module
678
-
679
- ```typescript
680
- export interface CommandResult {
681
- success: boolean;
682
- message?: string;
683
- data?: unknown;
684
- error?: string;
685
- }
686
-
687
- export async function executePm2Command(
688
- commandType: string,
689
- payload: Record<string, unknown>,
690
- ): Promise<CommandResult> {
691
- const processName = payload.processName as string;
692
-
693
- if (!processName) {
694
- return { success: false, error: "Missing processName in payload" };
695
- }
696
-
697
- try {
698
- switch (commandType) {
699
- case "pm2_stop":
700
- await Bun.$`pm2 stop ${processName}`.quiet();
701
- return { success: true, message: `Stopped ${processName}` };
702
-
703
- case "pm2_start":
704
- await Bun.$`pm2 start ${processName}`.quiet();
705
- return { success: true, message: `Started ${processName}` };
706
-
707
- case "pm2_restart":
708
- await Bun.$`pm2 restart ${processName}`.quiet();
709
- return { success: true, message: `Restarted ${processName}` };
710
-
711
- case "pm2_rename": {
712
- const newName = payload.newName as string;
713
- if (!newName) {
714
- return { success: false, error: "Missing newName for rename" };
715
- }
716
- // PM2 doesn't have rename, so we delete and restart with new name
717
- const jlist = await Bun.$`pm2 jlist`.json();
718
- const proc = (jlist as Array<{ name: string; pm2_env: { pm_exec_path: string } }>).find(
719
- (p) => p.name === processName,
720
- );
721
- if (!proc) {
722
- return { success: false, error: `Process ${processName} not found` };
723
- }
724
- await Bun.$`pm2 delete ${processName}`.quiet();
725
- await Bun.$`pm2 start ${proc.pm2_env.pm_exec_path} --name ${newName}`.quiet();
726
- return { success: true, message: `Renamed ${processName} to ${newName}` };
727
- }
728
-
729
- case "pm2_logs": {
730
- const lines = (payload.lines as number) || 100;
731
- const output = await Bun.$`pm2 logs ${processName} --lines ${lines} --nostream`.text();
732
- return { success: true, data: { logs: output } };
733
- }
734
-
735
- default:
736
- return { success: false, error: `Unknown command type: ${commandType}` };
737
- }
738
- } catch (error) {
739
- return { success: false, error: String(error) };
740
- }
741
- }
742
-
743
- export async function reportCommandResult(
744
- apiUrl: string,
745
- apiKey: string,
746
- agentId: string,
747
- commandId: string,
748
- result: CommandResult,
749
- ): Promise<void> {
750
- const headers: Record<string, string> = {
751
- "Content-Type": "application/json",
752
- "X-Agent-ID": agentId,
753
- };
754
- if (apiKey) {
755
- headers.Authorization = `Bearer ${apiKey}`;
756
- }
757
-
758
- try {
759
- await fetch(`${apiUrl}/api/commands/${commandId}/result`, {
760
- method: "POST",
761
- headers,
762
- body: JSON.stringify(result),
763
- });
764
- } catch (error) {
765
- console.warn(`[pm2-executor] Failed to report result: ${error}`);
766
- }
767
- }
768
- ```
769
-
770
- #### 2. Extend trigger types in runner
771
- **File**: `src/commands/runner.ts`
772
- **Changes**: Add command_pending to Trigger interface (around line 174)
773
-
774
- ```typescript
775
- interface Trigger {
776
- type:
777
- | "task_assigned"
778
- | "task_offered"
779
- | "unread_mentions"
780
- | "pool_tasks_available"
781
- | "tasks_finished"
782
- | "command_pending"; // Add this
783
- taskId?: string;
784
- task?: unknown;
785
- mentionsCount?: number;
786
- count?: number;
787
- tasks?: Array<{
788
- id: string;
789
- agentId?: string;
790
- task: string;
791
- status: string;
792
- }>;
793
- // Add command fields
794
- commandId?: string;
795
- command?: {
796
- id: string;
797
- commandType: string;
798
- serviceId?: string;
799
- payload?: Record<string, unknown>;
800
- };
801
- }
802
- ```
803
-
804
- #### 3. Handle command execution in poll loop
805
- **File**: `src/commands/runner.ts`
806
- **Changes**: Add command handling in the poll loop (after trigger check, before building prompt)
807
-
808
- Add import at top:
809
- ```typescript
810
- import { executePm2Command, reportCommandResult } from "./pm2-executor";
811
- ```
812
-
813
- Add in poll loop (around line 570, after `console.log(`[${role}] Trigger received: ${trigger.type}`);`):
814
- ```typescript
815
- // Handle command triggers directly (no Claude needed)
816
- if (trigger.type === "command_pending" && trigger.command && trigger.commandId) {
817
- console.log(`[${role}] Executing command: ${trigger.command.commandType}`);
818
- const result = await executePm2Command(
819
- trigger.command.commandType,
820
- trigger.command.payload || {},
821
- );
822
- console.log(`[${role}] Command result: ${result.success ? "success" : "failed"}`);
823
- await reportCommandResult(apiUrl, apiKey, agentId, trigger.commandId, result);
824
- console.log(`[${role}] Command result reported, polling for next trigger...`);
825
- continue; // Skip Claude iteration for commands
826
- }
827
- ```
828
-
829
- ### Success Criteria:
830
-
831
- #### Automated Verification:
832
- - [ ] TypeScript compiles: `bunx tsc --noEmit`
833
- - [ ] PM2 executor module can be imported: `bun -e "import './src/commands/pm2-executor'"`
834
-
835
- #### Manual Verification:
836
- - [ ] Start a test PM2 process: `pm2 start --name test-process "sleep 3600"`
837
- - [ ] Create stop command via API
838
- - [ ] Agent polls and executes command
839
- - [ ] PM2 process is stopped
840
- - [ ] Command status updated to completed
841
-
842
- **Implementation Note**: After completing this phase and all automated verification passes, pause here for manual confirmation before proceeding to Phase 6.
843
-
844
- ---
845
-
846
- ## Phase 6: Frontend PM2 Controls
847
-
848
- ### Overview
849
- Add command API methods, React Query hooks, and action buttons to ServicesPanel.
850
-
851
- ### Changes Required:
852
-
853
- #### 1. Add frontend types
854
- **File**: `ui/src/types/api.ts`
855
- **Changes**: Add command types
856
-
857
- ```typescript
858
- export type CommandType = "pm2_start" | "pm2_stop" | "pm2_restart" | "pm2_rename" | "pm2_logs";
859
- export type CommandStatus = "pending" | "in_progress" | "completed" | "failed" | "expired";
860
-
861
- export interface AgentCommand {
862
- id: string;
863
- agentId: string;
864
- serviceId?: string;
865
- commandType: CommandType;
866
- payload?: Record<string, unknown>;
867
- status: CommandStatus;
868
- result?: string;
869
- createdAt: string;
870
- startedAt?: string;
871
- completedAt?: string;
872
- expiresAt: string;
873
- createdBy?: string;
874
- }
875
- ```
876
-
877
- #### 2. Add command API methods
878
- **File**: `ui/src/lib/api.ts`
879
- **Changes**: Add command methods to ApiClient
880
-
881
- ```typescript
882
- async createCommand(params: {
883
- agentId: string;
884
- commandType: CommandType;
885
- serviceId?: string;
886
- payload?: Record<string, unknown>;
887
- }): Promise<AgentCommand> {
888
- const res = await this.request("/api/commands", {
889
- method: "POST",
890
- headers: { "Content-Type": "application/json" },
891
- body: JSON.stringify(params),
892
- });
893
- if (!res.ok) throw new Error("Failed to create command");
894
- return res.json();
895
- }
896
-
897
- async getCommand(id: string): Promise<AgentCommand> {
898
- const res = await this.request(`/api/commands/${id}`);
899
- if (!res.ok) throw new Error("Failed to get command");
900
- return res.json();
901
- }
902
-
903
- async getCommands(filters?: {
904
- agentId?: string;
905
- status?: string;
906
- serviceId?: string;
907
- }): Promise<{ commands: AgentCommand[] }> {
908
- const params = new URLSearchParams();
909
- if (filters?.agentId) params.set("agentId", filters.agentId);
910
- if (filters?.status) params.set("status", filters.status);
911
- if (filters?.serviceId) params.set("serviceId", filters.serviceId);
912
- const query = params.toString();
913
- const res = await this.request(`/api/commands${query ? `?${query}` : ""}`);
914
- if (!res.ok) throw new Error("Failed to get commands");
915
- return res.json();
916
- }
917
-
918
- async cancelCommand(id: string): Promise<void> {
919
- const res = await this.request(`/api/commands/${id}`, { method: "DELETE" });
920
- if (!res.ok) throw new Error("Failed to cancel command");
921
- }
922
- ```
923
-
924
- #### 3. Add React Query hooks for commands
925
- **File**: `ui/src/hooks/queries.ts`
926
- **Changes**: Add command hooks
927
-
928
- ```typescript
929
- export function useCreateCommand() {
930
- const queryClient = useQueryClient();
931
- return useMutation({
932
- mutationFn: (params: {
933
- agentId: string;
934
- commandType: CommandType;
935
- serviceId?: string;
936
- payload?: Record<string, unknown>;
937
- }) => api.createCommand(params),
938
- onSuccess: () => {
939
- queryClient.invalidateQueries({ queryKey: ["commands"] });
940
- },
941
- });
942
- }
943
-
944
- export function useCommand(id: string | undefined) {
945
- return useQuery({
946
- queryKey: ["command", id],
947
- queryFn: () => (id ? api.getCommand(id) : null),
948
- enabled: !!id,
949
- refetchInterval: 2000, // Poll for status updates
950
- });
951
- }
952
-
953
- export function useCommands(filters?: { agentId?: string; status?: string; serviceId?: string }) {
954
- return useQuery({
955
- queryKey: ["commands", filters],
956
- queryFn: () => api.getCommands(filters),
957
- select: (data) => data.commands,
958
- refetchInterval: 5000,
959
- });
960
- }
961
- ```
962
-
963
- #### 4. Add action buttons to ServicesPanel
964
- **File**: `ui/src/components/ServicesPanel.tsx`
965
- **Changes**: Add actions column with Stop/Start/Restart buttons
966
-
967
- Add imports:
968
- ```typescript
969
- import IconButton from "@mui/joy/IconButton";
970
- import Tooltip from "@mui/joy/Tooltip";
971
- import { useCreateCommand } from "../hooks/queries";
972
- // Icons (use MUI Joy icons or simple text for now)
973
- ```
974
-
975
- Add action column to table header:
976
- ```typescript
977
- <th style={{ width: "12%" }}>ACTIONS</th>
978
- ```
979
-
980
- Add action buttons to each row:
981
- ```typescript
982
- const createCommand = useCreateCommand();
983
-
984
- // In table row
985
- <td>
986
- <Box sx={{ display: "flex", gap: 0.5 }}>
987
- <Tooltip title="Stop">
988
- <IconButton
989
- size="sm"
990
- variant="soft"
991
- color="danger"
992
- onClick={() => createCommand.mutate({
993
- agentId: service.agentId,
994
- commandType: "pm2_stop",
995
- serviceId: service.id,
996
- payload: { processName: service.name },
997
- })}
998
- disabled={service.status === "stopped"}
999
- >
1000
-
1001
- </IconButton>
1002
- </Tooltip>
1003
- <Tooltip title="Start">
1004
- <IconButton
1005
- size="sm"
1006
- variant="soft"
1007
- color="success"
1008
- onClick={() => createCommand.mutate({
1009
- agentId: service.agentId,
1010
- commandType: "pm2_start",
1011
- serviceId: service.id,
1012
- payload: { processName: service.name },
1013
- })}
1014
- disabled={service.status === "healthy"}
1015
- >
1016
-
1017
- </IconButton>
1018
- </Tooltip>
1019
- <Tooltip title="Restart">
1020
- <IconButton
1021
- size="sm"
1022
- variant="soft"
1023
- color="warning"
1024
- onClick={() => createCommand.mutate({
1025
- agentId: service.agentId,
1026
- commandType: "pm2_restart",
1027
- serviceId: service.id,
1028
- payload: { processName: service.name },
1029
- })}
1030
- >
1031
-
1032
- </IconButton>
1033
- </Tooltip>
1034
- </Box>
1035
- </td>
1036
- ```
1037
-
1038
- ### Success Criteria:
1039
-
1040
- #### Automated Verification:
1041
- - [ ] Frontend builds: `cd ui && bun run build`
1042
- - [ ] TypeScript compiles: `cd ui && bunx tsc --noEmit`
1043
-
1044
- #### Manual Verification:
1045
- - [ ] Action buttons appear in services table
1046
- - [ ] Clicking Stop creates a command
1047
- - [ ] Command appears in database
1048
- - [ ] Agent executes command
1049
- - [ ] Service status updates
1050
-
1051
- **Implementation Note**: After completing this phase and all automated verification passes, the core functionality is complete. Phase 7 (Log Viewer) is optional but recommended.
1052
-
1053
- ---
1054
-
1055
- ## Phase 7: Log Viewer Modal (Optional Enhancement)
1056
-
1057
- ### Overview
1058
- Add a modal to view PM2 logs for a service.
1059
-
1060
- ### Changes Required:
1061
-
1062
- #### 1. Create LogViewerModal component
1063
- **File**: `ui/src/components/LogViewerModal.tsx` (new file)
1064
-
1065
- Modal that:
1066
- - Opens when clicking Logs button on a service
1067
- - Creates a pm2_logs command to fetch logs
1068
- - Displays logs in a scrollable, monospace view
1069
- - Has stdout/stderr filter tabs
1070
- - Auto-refreshes while open
1071
-
1072
- #### 2. Add logs button to ServicesPanel
1073
- **File**: `ui/src/components/ServicesPanel.tsx`
1074
- **Changes**: Add logs button and modal state
1075
-
1076
- ### Success Criteria:
1077
-
1078
- #### Manual Verification:
1079
- - [ ] Logs button opens modal
1080
- - [ ] Logs are displayed
1081
- - [ ] Filter tabs work
1082
- - [ ] Modal closes properly
1083
-
1084
- ---
1085
-
1086
- ## Testing Strategy
1087
-
1088
- ### Unit Tests:
1089
- - Database CRUD functions for commands
1090
- - PM2 executor command handling
1091
- - API endpoint request/response validation
1092
-
1093
- ### Integration Tests:
1094
- - Full command flow: create → poll → execute → report
1095
- - Frontend command creation → backend → agent → result
1096
-
1097
- ### Manual Testing Steps:
1098
- 1. Create an agent and a service via API
1099
- 2. Start a PM2 process manually: `pm2 start --name test "sleep 3600"`
1100
- 3. Click Stop in UI → verify process stops
1101
- 4. Click Start → verify process starts
1102
- 5. Click Restart → verify restart
1103
- 6. Edit agent name → verify update
1104
-
1105
- ## Performance Considerations
1106
-
1107
- - Commands expire after 5 minutes to prevent stale commands
1108
- - Poll interval is 2 seconds to balance responsiveness and load
1109
- - Log fetching is on-demand, not streamed continuously
1110
- - Frontend polls command status every 2 seconds while a command is pending
1111
-
1112
- ## References
1113
-
1114
- - Existing polling mechanism: `src/commands/runner.ts:237-277`
1115
- - Service table schema: `src/be/db.ts:134-155`
1116
- - Agent profile update pattern: `src/be/db.ts:1256-1286`
1117
- - Frontend React Query patterns: `ui/src/hooks/queries.ts`
1118
-
1119
- ## File Summary
1120
-
1121
- | File | Action | Description |
1122
- |------|--------|-------------|
1123
- | `src/types.ts` | Modify | Add command types |
1124
- | `src/be/db.ts` | Modify | Add table, CRUD functions |
1125
- | `src/http.ts` | Modify | Add PATCH agent, command endpoints |
1126
- | `src/commands/pm2-executor.ts` | Create | PM2 command execution |
1127
- | `src/commands/runner.ts` | Modify | Handle command triggers |
1128
- | `ui/src/types/api.ts` | Modify | Add command types |
1129
- | `ui/src/lib/api.ts` | Modify | Add command API methods |
1130
- | `ui/src/hooks/queries.ts` | Modify | Add command hooks |
1131
- | `ui/src/components/ServicesPanel.tsx` | Modify | Add action buttons |
1132
- | `ui/src/components/AgentDetailPanel.tsx` | Modify | Add name editing |
1133
- | `ui/src/components/LogViewerModal.tsx` | Create | Optional log viewer |