@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,860 +0,0 @@
1
- ---
2
- date: 2026-03-19
3
- planner: claude
4
- topic: "Ticket Tracker Integration — Linear First"
5
- branch: linear-integration-foundation
6
- pr: 161
7
- status: completed
8
- autonomy: verbose
9
- commit_per_phase: true
10
- research: thoughts/taras/research/2026-03-18-linear-integration-finalization.md
11
- ---
12
-
13
- # Ticket Tracker Integration — Linear First
14
-
15
- ## Overview
16
-
17
- Nuke the existing Linear prototype on the `linear-integration-foundation` branch and rebuild from scratch with:
18
- 1. A **generic OAuth module** (`src/oauth/` + `src/be/db-queries/oauth.ts`) — reusable across the entire swarm, not just trackers
19
- 2. A **generic tracker abstraction** (convention-based: generic DB tables + provider directory + route pattern)
20
- 3. **Linear as the first provider** — OAuth, webhooks, AgentSessionEvent, bidirectional sync
21
-
22
- Single PR (#161), nuked and rebuilt from scratch.
23
-
24
- ## Current State Analysis
25
-
26
- **Existing code on branch** (to be deleted):
27
- - `src/linear/` (5 files): app.ts, client.ts, oauth.ts, types.ts, index.ts
28
- - `src/http/linear.ts`: OAuth authorize + callback routes at `/api/linear/*`
29
- - `src/be/migrations/008_linear_integration.sql`: Linear-specific tables (`linear_oauth_tokens`, `linear_sync`, `linear_agent_mapping`)
30
- - Wired into `src/http/index.ts` (init + route handler) and `src/http/core.ts` (auth bypass)
31
- - `openapi.json` has Linear routes registered
32
- - `src/types.ts:66` has `"linear"` in `AgentTaskSourceSchema`
33
-
34
- **What's missing:**
35
- - No webhook handler / AgentSessionEvent support
36
- - No sync logic (inbound or outbound)
37
- - No MCP tools
38
- - No generic tracker abstraction (tables are Linear-specific)
39
- - No `src/be/db-queries/` modules (queries inline in oauth.ts)
40
- - `actor=app` missing from OAuth URL
41
- - Manual PKCE implementation (plan: adopt `oauth4webapi`)
42
- - OAuth scopes include `admin` (should be dropped)
43
-
44
- **Patterns to follow** (from research):
45
- - Init lifecycle: `isXxxEnabled()` / `initXxx()` / `resetXxx()` — from `src/github/app.ts`
46
- - HTTP routes: `route()` factory + `handleXxx()` → `Promise<boolean>` — from `src/http/linear.ts`
47
- - Webhook handling: signature verify → parse body → dispatch — from `src/http/webhooks.ts`
48
- - Task creation: `createTaskExtended()` with source/type metadata — from `src/github/handlers.ts`
49
- - MCP tools: `registerXxxTool(server)` via `createToolRegistrar` + Zod — from `src/tools/get-task-details.ts`
50
- - Tool grouping: subdirectory with barrel index — from `src/tools/epics/`
51
- - Tool registration: in `src/server.ts`, add to `DEFERRED_TOOLS` in `src/tools/tool-config.ts`
52
-
53
- ## Desired End State
54
-
55
- After all phases:
56
- 1. Generic `oauth_apps` + `oauth_tokens` tables serve any OAuth provider in the swarm
57
- 2. Generic `tracker_sync` + `tracker_agent_mapping` tables serve any ticket tracker
58
- 3. `src/oauth/wrapper.ts` provides reusable OAuth 2.0 + PKCE via `oauth4webapi`
59
- 4. Linear integration fully works: OAuth, webhooks, AgentSessionEvent, bidirectional sync
60
- 5. 6 MCP tools for tracker management
61
- 6. Setup documentation in `.env.example` + inline code comments
62
- 7. Full test coverage: unit + integration + manual E2E
63
-
64
- ### Key Discoveries:
65
- - Migration 008 is safe to replace (branch not merged to main, no production DBs)
66
- - `src/http/core.ts:85-87` handles auth bypass for OAuth callback — needs updating for new route paths
67
- - `src/http/index.ts:96` calls `handleLinear()` in handler chain — needs replacing with `handleTrackers()`
68
- - `src/http/index.ts:190` calls `initLinear()` on startup — keep same pattern
69
- - `src/server.ts:114-180` registers all MCP tools — new tracker tools go here
70
- - `src/tools/tool-config.ts` classifies tools as CORE or DEFERRED — tracker tools are DEFERRED
71
- - `createTaskExtended()` in `src/be/db.ts` is the universal task creation function
72
- - `route()` in `src/http/route-def.ts` auto-registers routes for OpenAPI generation
73
-
74
- ## Quick Verification Reference
75
-
76
- Common commands:
77
- - `bun run lint:fix` — Biome lint + format
78
- - `bun run tsc:check` — TypeScript type check
79
- - `bun test` — Run all unit tests
80
- - `bun test src/tests/<file>.test.ts` — Run specific test
81
-
82
- Key files (after implementation):
83
- - `src/be/migrations/008_tracker_integration.sql` — Generic tables
84
- - `src/be/db-queries/oauth.ts` — Generic OAuth CRUD
85
- - `src/be/db-queries/tracker.ts` — Tracker sync/mapping CRUD
86
- - `src/oauth/wrapper.ts` — Generic OAuth wrapper (oauth4webapi)
87
- - `src/linear/` — Linear-specific code (app, oauth, client, webhook, sync, types)
88
- - `src/http/trackers/linear.ts` — Linear HTTP routes
89
- - `src/tools/tracker/` — Tracker MCP tools
90
-
91
- ## What We're NOT Doing
92
-
93
- - **Dashboard UI for Linear** — deferred to a separate PR
94
- - **Jira/Trello/Asana providers** — architecture supports them, but only Linear implemented
95
- - **History sync** — only incremental, triggered by app assignment/@mention
96
- - **Multi-workspace** — single Linear workspace per swarm
97
- - **Abstract interfaces / factory pattern** — convention-based abstraction only (matches VCS pattern)
98
-
99
- ## Implementation Approach
100
-
101
- **Nuke and rebuild**: Delete all existing Linear code, replace migration 008, build fresh with generic abstractions from day 1.
102
-
103
- **Key design decisions** (agreed with Taras):
104
- - `oauth4webapi` for generic OAuth wrapper (serves entire swarm, not just trackers)
105
- - Generic OAuth module in `src/oauth/` + `src/be/db-queries/oauth.ts` (separate from tracker code)
106
- - Fire-and-forget promise for 10-second AgentSessionEvent timeout
107
- - `Linear-Delivery` header dedup for loop prevention (not timing window)
108
- - Routes at `/api/trackers/linear/*` (OAuth flow accessed via tracker routes, backed by generic internals)
109
- - Drop `admin` scope — minimum viable: `read,write,issues:create,comments:create,app:assignable,app:mentionable`
110
-
111
- ---
112
-
113
- ## Phase 1: Nuke + Generic Foundation
114
-
115
- ### Overview
116
- Delete all existing Linear code. Create new migration 008 with generic tables. Build the generic DB query layer for OAuth and tracker sync/mapping. Add `TrackerProvider` type.
117
-
118
- ### Changes Required:
119
-
120
- #### 1. Delete existing Linear code
121
- **Files to delete**:
122
- - `src/linear/app.ts`
123
- - `src/linear/client.ts`
124
- - `src/linear/oauth.ts`
125
- - `src/linear/types.ts`
126
- - `src/linear/index.ts`
127
- - `src/http/linear.ts`
128
- - `src/be/migrations/008_linear_integration.sql`
129
-
130
- #### 2. Remove Linear references from HTTP wiring
131
- **File**: `src/http/index.ts`
132
- **Changes**:
133
- - Remove import of `handleLinear` (line ~23)
134
- - Remove `handleLinear` from handler chain (line ~96)
135
- - Remove `initLinear()` call from startup (line ~190) — will be re-added in Phase 2
136
-
137
- **File**: `src/http/core.ts`
138
- **Changes**:
139
- - Remove import of `initLinear`/`resetLinear` from `../linear` (line ~14)
140
- - Remove auth bypass for `/api/linear/authorize` and `/api/linear/callback` (lines ~85-87)
141
- - Remove `resetLinear()` call from config reload (lines ~112-113)
142
-
143
- **File**: `openapi.json`
144
- **Changes**:
145
- - Remove Linear route entries (will be auto-regenerated when new routes are added)
146
-
147
- #### 3. Create new migration
148
- **File**: `src/be/migrations/008_tracker_integration.sql`
149
- **Changes**: Replace the old Linear-specific migration with generic tables:
150
-
151
- ```sql
152
- -- Generic OAuth application configuration (one row per provider)
153
- CREATE TABLE IF NOT EXISTS oauth_apps (
154
- id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
155
- provider TEXT NOT NULL UNIQUE,
156
- clientId TEXT NOT NULL,
157
- clientSecret TEXT NOT NULL,
158
- authorizeUrl TEXT NOT NULL,
159
- tokenUrl TEXT NOT NULL,
160
- redirectUri TEXT NOT NULL,
161
- scopes TEXT NOT NULL,
162
- metadata TEXT DEFAULT '{}',
163
- createdAt TEXT NOT NULL DEFAULT (datetime('now')),
164
- updatedAt TEXT NOT NULL DEFAULT (datetime('now'))
165
- );
166
-
167
- -- Generic OAuth token storage (one active token set per provider)
168
- CREATE TABLE IF NOT EXISTS oauth_tokens (
169
- id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
170
- provider TEXT NOT NULL UNIQUE,
171
- accessToken TEXT NOT NULL,
172
- refreshToken TEXT,
173
- expiresAt TEXT NOT NULL,
174
- scope TEXT,
175
- createdAt TEXT NOT NULL DEFAULT (datetime('now')),
176
- updatedAt TEXT NOT NULL DEFAULT (datetime('now')),
177
- FOREIGN KEY (provider) REFERENCES oauth_apps(provider)
178
- );
179
-
180
- -- Generic tracker entity mapping
181
- CREATE TABLE IF NOT EXISTS tracker_sync (
182
- id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
183
- provider TEXT NOT NULL,
184
- entityType TEXT NOT NULL CHECK (entityType IN ('task', 'epic')),
185
- providerEntityType TEXT,
186
- swarmId TEXT NOT NULL,
187
- externalId TEXT NOT NULL,
188
- externalIdentifier TEXT,
189
- externalUrl TEXT,
190
- lastSyncedAt TEXT NOT NULL DEFAULT (datetime('now')),
191
- lastSyncOrigin TEXT CHECK (lastSyncOrigin IN ('swarm', 'external')),
192
- lastDeliveryId TEXT,
193
- syncDirection TEXT NOT NULL DEFAULT 'inbound',
194
- createdAt TEXT NOT NULL DEFAULT (datetime('now')),
195
- UNIQUE(provider, entityType, swarmId),
196
- UNIQUE(provider, entityType, externalId)
197
- );
198
-
199
- -- Generic agent-to-external-user mapping
200
- CREATE TABLE IF NOT EXISTS tracker_agent_mapping (
201
- id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
202
- provider TEXT NOT NULL,
203
- agentId TEXT NOT NULL,
204
- externalUserId TEXT NOT NULL,
205
- agentName TEXT NOT NULL,
206
- createdAt TEXT NOT NULL DEFAULT (datetime('now')),
207
- UNIQUE(provider, agentId),
208
- UNIQUE(provider, externalUserId)
209
- );
210
-
211
- -- Indexes
212
- CREATE INDEX IF NOT EXISTS idx_oauth_tokens_provider ON oauth_tokens(provider);
213
- CREATE INDEX IF NOT EXISTS idx_tracker_sync_swarm ON tracker_sync(provider, entityType, swarmId);
214
- CREATE INDEX IF NOT EXISTS idx_tracker_sync_external ON tracker_sync(provider, entityType, externalId);
215
- CREATE INDEX IF NOT EXISTS idx_tracker_agent_agentId ON tracker_agent_mapping(provider, agentId);
216
- ```
217
-
218
- Plus the `agent_tasks` table recreation with `'linear'` in the source CHECK constraint. **Copy lines 54-114 from the current `008_linear_integration.sql`** — this is a 60-line block that: creates `agent_tasks_new` with the updated CHECK, copies data via `INSERT INTO ... SELECT * FROM`, drops the old table, renames, and recreates all indexes. Do not write this from scratch — the column listing and index definitions must exactly match the existing table.
219
-
220
- #### 4. Create tracker types
221
- **File**: `src/tracker/types.ts` (new)
222
- **Changes**: Define `TrackerProvider` type and shared interfaces:
223
- ```typescript
224
- export type TrackerProvider = "linear"; // extend as providers are added
225
-
226
- export interface TrackerSync { /* matches tracker_sync table */ }
227
- export interface TrackerAgentMapping { /* matches tracker_agent_mapping table */ }
228
- ```
229
-
230
- #### 5. Create generic OAuth DB query layer
231
- **File**: `src/be/db-queries/oauth.ts` (new)
232
- **Changes**: All OAuth DB functions, provider-parameterized:
233
- - `getOAuthApp(provider)`, `upsertOAuthApp(provider, data)`
234
- - `getOAuthTokens(provider)`, `storeOAuthTokens(provider, data)`, `deleteOAuthTokens(provider)`
235
- - `isTokenExpiringSoon(provider, bufferMs?)`
236
-
237
- #### 6. Create tracker DB query layer
238
- **File**: `src/be/db-queries/tracker.ts` (new)
239
- **Changes**: All tracker sync/mapping DB functions:
240
- - `getTrackerSync(provider, entityType, swarmId)`, `getTrackerSyncByExternalId(...)`, `createTrackerSync(...)`, `updateTrackerSync(...)`, `deleteTrackerSync(id)`, `getAllTrackerSyncs(provider?, entityType?)`
241
- - `getTrackerAgentMapping(provider, agentId)`, `getTrackerAgentMappingByExternalUser(...)`, `createTrackerAgentMapping(...)`, `deleteTrackerAgentMapping(...)`, `getAllTrackerAgentMappings(provider?)`
242
-
243
- #### 7. Unit tests
244
- **File**: `src/tests/db-queries-oauth.test.ts` (new)
245
- **Changes**: Test all OAuth DB CRUD operations with isolated test DB
246
-
247
- **File**: `src/tests/db-queries-tracker.test.ts` (new)
248
- **Changes**: Test all tracker sync/mapping CRUD operations, uniqueness constraints, provider filtering
249
-
250
- ### Success Criteria:
251
-
252
- #### Automated Verification:
253
- - [ ] TypeScript compiles: `bun run tsc:check`
254
- - [ ] Lint passes: `bun run lint:fix`
255
- - [ ] OAuth DB tests pass: `bun test src/tests/db-queries-oauth.test.ts`
256
- - [ ] Tracker DB tests pass: `bun test src/tests/db-queries-tracker.test.ts`
257
- - [ ] All existing tests still pass: `bun test`
258
- - [ ] Server starts cleanly: `bun run start:http` (check no crash, migration applies)
259
- - [ ] Fresh DB works: `rm -f agent-swarm-db.sqlite* && bun run start:http`
260
- - [ ] OpenAPI spec regenerated: `bun run docs:openapi` (commit the updated `openapi.json`)
261
-
262
- #### Manual Verification:
263
- - [ ] Verify migration creates all 4 generic tables (inspect with `sqlite3`)
264
- - [ ] Verify `agent_tasks` still works with `'linear'` source
265
- - [ ] Verify no leftover Linear references: `grep -r "linear_oauth_tokens\|linear_sync\|linear_agent_mapping" src/`
266
- - [ ] Verify old routes are gone: `curl http://localhost:3013/api/linear/authorize` returns 404
267
-
268
- **Implementation Note**: After completing this phase, pause for manual confirmation. Commit after verification passes.
269
-
270
- ---
271
-
272
- ## Phase 2: Generic OAuth Wrapper + Linear OAuth
273
-
274
- ### Overview
275
- Install `oauth4webapi`. Build a generic OAuth 2.0 + PKCE wrapper. Implement Linear-specific OAuth (with `actor=app`, correct scopes). Create HTTP routes at `/api/trackers/linear/`. Wire into server startup.
276
-
277
- ### Changes Required:
278
-
279
- #### 1. Install oauth4webapi
280
- **Command**: `bun add oauth4webapi`
281
-
282
- #### 2. Create generic OAuth wrapper
283
- **File**: `src/oauth/wrapper.ts` (new)
284
- **Changes**: Thin wrapper (~100-150 lines) around `oauth4webapi`:
285
- - `OAuthProviderConfig` interface: endpoints, clientId, scopes, PKCE method, extra params
286
- - `buildAuthorizationUrl(config)` → URL + state + codeVerifier (stored in-memory with TTL cleanup)
287
- - `exchangeCode(config, code, state)` → tokens (persisted via `src/be/db-queries/oauth.ts`)
288
- - `refreshToken(config, provider)` → refreshed tokens (persisted)
289
-
290
- In-memory pending state map with 10-minute TTL (same pattern as current `oauth.ts` but generic).
291
-
292
- **File**: `src/oauth/index.ts` (new barrel)
293
-
294
- #### 3. Create Linear app lifecycle
295
- **File**: `src/linear/app.ts` (new — same pattern as before)
296
- **Changes**: `isLinearEnabled()`, `initLinear()`, `resetLinear()` following GitHub pattern.
297
- - Check `LINEAR_DISABLE`, `LINEAR_ENABLED`, `LINEAR_CLIENT_ID`
298
- - On init: upsert the `oauth_apps` row for Linear with endpoints, scopes, metadata
299
-
300
- #### 4. Create Linear OAuth config
301
- **File**: `src/linear/oauth.ts` (new)
302
- **Changes**: Linear-specific OAuth configuration:
303
- - Provider config object with Linear endpoints, scopes (`read,write,issues:create,comments:create,app:assignable,app:mentionable` — no `admin`), `actor=app` in metadata
304
- - `getLinearAuthorizationUrl()` → calls generic `buildAuthorizationUrl()` with Linear config
305
- - `handleLinearCallback(code, state)` → calls generic `exchangeCode()` with Linear config
306
-
307
- #### 5. Create Linear client wrapper
308
- **File**: `src/linear/client.ts` (new — similar to before)
309
- **Changes**: `@linear/sdk` wrapper with auto-refresh:
310
- - `getLinearClient()` — reads tokens from generic `oauth_tokens` via `getOAuthTokens("linear")`
311
- - `withLinearClient(fn)` — auto-retry on auth errors, uses generic `refreshToken()`
312
- - `resetLinearClient()`
313
-
314
- #### 6. Create Linear types
315
- **File**: `src/linear/types.ts` (new)
316
- **Changes**: Linear-specific types:
317
- - `LinearTokenResponse` (OAuth token endpoint response shape)
318
- - Linear webhook event types (for Phase 3)
319
-
320
- **File**: `src/linear/index.ts` (new barrel)
321
-
322
- #### 7. Create HTTP route handler
323
- **File**: `src/http/trackers/linear.ts` (new)
324
- **Changes**: Define routes using `route()` factory (following `src/http/linear.ts` / `src/http/webhooks.ts` pattern):
325
-
326
- ```typescript
327
- const linearAuthorize = route({
328
- method: "get",
329
- path: "/api/trackers/linear/authorize",
330
- pattern: ["api", "trackers", "linear", "authorize"],
331
- summary: "Redirect to Linear OAuth consent screen",
332
- tags: ["Trackers"],
333
- responses: {
334
- 302: { description: "Redirect to Linear OAuth" },
335
- 500: { description: "Failed to generate authorization URL" },
336
- 503: { description: "Linear integration not configured" },
337
- },
338
- });
339
-
340
- const linearCallback = route({
341
- method: "get",
342
- path: "/api/trackers/linear/callback",
343
- pattern: ["api", "trackers", "linear", "callback"],
344
- summary: "Handle Linear OAuth callback",
345
- tags: ["Trackers"],
346
- auth: { apiKey: false },
347
- query: z.object({
348
- code: z.string(),
349
- state: z.string(),
350
- }),
351
- responses: {
352
- 200: { description: "OAuth complete" },
353
- 400: { description: "Invalid state or code" },
354
- 500: { description: "Token exchange failed" },
355
- },
356
- });
357
-
358
- const linearStatus = route({
359
- method: "get",
360
- path: "/api/trackers/linear/status",
361
- pattern: ["api", "trackers", "linear", "status"],
362
- summary: "Linear connection status, token expiry, workspace info, expected webhook URL",
363
- tags: ["Trackers"],
364
- responses: {
365
- 200: { description: "Connection status" },
366
- 503: { description: "Linear integration not configured" },
367
- },
368
- });
369
- ```
370
-
371
- - Handler: `export async function handleLinearTracker(req, res, pathSegments): Promise<boolean>`
372
- - Uses `match()` only for authorize/status (no body/params), `parse()` for callback (query params)
373
-
374
- **File**: `src/http/trackers/index.ts` (new barrel)
375
- **Changes**: Aggregate tracker handlers:
376
- ```typescript
377
- export async function handleTrackers(req, res, pathSegments): Promise<boolean> {
378
- return await handleLinearTracker(req, res, pathSegments);
379
- // Future: || await handleJiraTracker(...)
380
- }
381
- ```
382
-
383
- #### 8. Wire into server
384
- **File**: `src/http/index.ts`
385
- **Changes**:
386
- - Import `handleTrackers` from `./trackers`
387
- - Add `() => handleTrackers(req, res, pathSegments)` to handler chain
388
- - Import `initLinear` from `../linear`
389
- - Add `initLinear()` call in server listen callback
390
-
391
- **File**: `src/http/core.ts`
392
- **Changes**:
393
- - Import `initLinear`/`resetLinear` from `../linear`
394
- - Add auth bypass for `/api/trackers/linear/callback` only
395
- - Add `resetLinear()` to config reload
396
-
397
- #### 9. Update .env.example
398
- **File**: `.env.example`
399
- **Changes**: Update Linear env vars section to match new architecture, document `LINEAR_SIGNING_SECRET` for Phase 3
400
-
401
- #### 10. Unit tests
402
- **File**: `src/tests/oauth-wrapper.test.ts` (new)
403
- **Changes**: Test generic OAuth wrapper:
404
- - `buildAuthorizationUrl()` generates correct URL with PKCE
405
- - State TTL cleanup works
406
- - Token persistence via DB functions
407
-
408
- ### Success Criteria:
409
-
410
- #### Automated Verification:
411
- - [ ] TypeScript compiles: `bun run tsc:check`
412
- - [ ] Lint passes: `bun run lint:fix`
413
- - [ ] OAuth wrapper tests pass: `bun test src/tests/oauth-wrapper.test.ts`
414
- - [ ] All existing tests pass: `bun test`
415
- - [ ] Server starts cleanly: `bun run start:http`
416
- - [ ] OpenAPI spec regenerated: `bun run docs:openapi` (commit the updated `openapi.json`)
417
-
418
- #### Manual Verification:
419
- - [ ] `GET /api/trackers/linear/authorize` returns 302 redirect to `linear.app/oauth/authorize` with `actor=app` in URL
420
- - [ ] Redirect URL contains correct scopes (no `admin`), `code_challenge_method=S256`
421
- - [ ] `GET /api/trackers/linear/status` returns connection status (should show "not connected" before OAuth)
422
- - [ ] `GET /api/trackers/linear/callback` with invalid state returns 400
423
- - [ ] Old routes `/api/linear/*` still return 404
424
- - [ ] `oauth_apps` row for "linear" is created on server startup (check via `sqlite3`)
425
-
426
- **Implementation Note**: After completing this phase, pause for manual confirmation. Commit after verification passes.
427
-
428
- ---
429
-
430
- ## Phase 3: Webhook + Inbound Sync
431
-
432
- ### Overview
433
- Implement Linear webhook handling with signature verification, AgentSessionEvent processing, and inbound sync (Linear issues → swarm tasks, projects → epics). Fire-and-forget for heavy work. Linear-Delivery header dedup.
434
-
435
- ### Changes Required:
436
-
437
- #### 1. Create webhook handler
438
- **File**: `src/linear/webhook.ts` (new)
439
- **Changes**:
440
- - `verifyLinearWebhook(rawBody, signature, secret)` — HMAC-SHA256 with timing-safe comparison
441
- - `handleLinearWebhook(rawBody, headers)` — main dispatcher:
442
- 1. Verify signature using `LINEAR_SIGNING_SECRET`
443
- 2. Check `Linear-Delivery` header for dedup (store in `tracker_sync.lastDeliveryId` or separate in-memory set with TTL)
444
- 3. Parse event type from body
445
- 4. Dispatch to appropriate handler
446
- - `handleAgentSessionEvent(event)` — the primary entry point:
447
- 1. Respond immediately (fire-and-forget pattern)
448
- 2. In deferred promise: create swarm task via `createTaskExtended()` with `source: "linear"`
449
- 3. Update AgentSession state via Linear API (`pending` → `active`)
450
- - `handleIssueUpdate(event)` — status change sync
451
- - `handleIssueDelete(event)` — cancel corresponding swarm task
452
-
453
- #### 2. Create inbound sync logic
454
- **File**: `src/linear/sync.ts` (new)
455
- **Changes**:
456
- - Status mapping: Linear states → swarm task statuses
457
- - Backlog → skip (don't create task)
458
- - Todo → `unassigned`
459
- - In Progress → `in_progress`
460
- - Done → `completed`
461
- - Cancelled → `cancelled`
462
- - Polymorphic mapping heuristics:
463
- - Issue (no sub-issues) → 1 Task
464
- - Issue (with sub-issues) → 1 Epic + N Tasks
465
- - Project → 1 Epic, project issues → N Tasks under epic
466
- - `syncIssueToTask(issue)` — creates/updates task, creates `tracker_sync` mapping
467
- - `syncIssueToEpic(issue)` — creates/updates epic, syncs sub-issues as tasks
468
- - Uses `createTrackerSync()` from generic DB layer
469
-
470
- #### 3. Add webhook route
471
- **File**: `src/http/trackers/linear.ts`
472
- **Changes**: Add webhook route using `route()` factory (follows `src/http/webhooks.ts` pattern — no body schema, manual raw body reading for signature verification):
473
-
474
- ```typescript
475
- const linearWebhook = route({
476
- method: "post",
477
- path: "/api/trackers/linear/webhook",
478
- pattern: ["api", "trackers", "linear", "webhook"],
479
- summary: "Handle Linear webhook events (signature-verified)",
480
- tags: ["Trackers"],
481
- auth: { apiKey: false },
482
- responses: {
483
- 200: { description: "Event accepted" },
484
- 401: { description: "Invalid signature" },
485
- 503: { description: "Linear integration not configured" },
486
- },
487
- });
488
- ```
489
-
490
- - Uses `match()` only (no `parse()`) — raw body is read manually for HMAC signature verification (same pattern as `githubWebhook` in `src/http/webhooks.ts`)
491
- - Fire-and-forget pattern: respond 200 immediately, run heavy work in deferred promise
492
- - **Error handling**: Wrap deferred work in try/catch — log errors via `console.error` with webhook event context. Do not silently swallow failures. If `createTaskExtended()` fails, log the full error + webhook payload for debugging.
493
-
494
- **File**: `src/http/core.ts`
495
- **Changes**:
496
- - Add auth bypass for `/api/trackers/linear/webhook`
497
-
498
- #### 4. Dedup storage
499
- **File**: `src/linear/webhook.ts`
500
- **Changes**:
501
- - In-memory `Set<string>` with TTL for `Linear-Delivery` header values
502
- - TTL of 5 minutes (covers Linear's retry window)
503
- - Cleanup on each new webhook arrival
504
-
505
- #### 5. Integration tests
506
- **File**: `src/tests/linear-webhook.test.ts` (new)
507
- **Changes**:
508
- - Test signature verification (valid/invalid/missing)
509
- - Test AgentSessionEvent → task creation
510
- - Test dedup (same delivery ID rejected)
511
- - Test status mapping (all Linear states)
512
- - Test fire-and-forget pattern (200 response before task creation completes)
513
- - Mock `@linear/sdk` API calls
514
-
515
- ### Success Criteria:
516
-
517
- #### Automated Verification:
518
- - [ ] TypeScript compiles: `bun run tsc:check`
519
- - [ ] Lint passes: `bun run lint:fix`
520
- - [ ] Webhook tests pass: `bun test src/tests/linear-webhook.test.ts`
521
- - [ ] All existing tests pass: `bun test`
522
- - [ ] OpenAPI spec regenerated: `bun run docs:openapi` (commit the updated `openapi.json`)
523
-
524
- #### Manual Verification:
525
- - [ ] `POST /api/trackers/linear/webhook` with invalid signature returns 401
526
- - [ ] `POST /api/trackers/linear/webhook` with valid signature returns 200
527
- - [ ] Duplicate `Linear-Delivery` header is rejected
528
- - [ ] AgentSessionEvent creates a swarm task with `source: "linear"`
529
- - [ ] Response arrives within 1-2 seconds (fire-and-forget works)
530
-
531
- **Implementation Note**: After completing this phase, pause for manual confirmation. Full webhook testing requires ngrok/cloudflared for real Linear webhooks (Phase 6). This phase uses mocked webhooks. Commit after verification passes.
532
-
533
- ---
534
-
535
- ## Phase 4: MCP Tools + Outbound Sync
536
-
537
- ### Overview
538
- Create 6 MCP tools for tracker management. Implement outbound sync (swarm task status changes → Linear issue updates). Loop prevention with delivery ID tracking.
539
-
540
- ### Changes Required:
541
-
542
- #### 1. Create tracker MCP tools
543
- **Directory**: `src/tools/tracker/` (new)
544
-
545
- **File**: `src/tools/tracker/tracker-status.ts`
546
- - Show all connected trackers and their OAuth status (token expiry, workspace info)
547
- - Read-only, uses `getOAuthTokens()` + `getOAuthApp()`
548
-
549
- **File**: `src/tools/tracker/tracker-link-task.ts`
550
- - Link a swarm task to an external issue (manual override)
551
- - Creates `tracker_sync` row with `entityType: "task"`
552
-
553
- **File**: `src/tools/tracker/tracker-link-epic.ts`
554
- - Link a swarm epic to an external issue/project
555
- - Creates `tracker_sync` row with `entityType: "epic"`
556
-
557
- **File**: `src/tools/tracker/tracker-unlink.ts`
558
- - Remove a sync mapping by ID
559
- - Destructive, uses `deleteTrackerSync()`
560
-
561
- **File**: `src/tools/tracker/tracker-sync-status.ts`
562
- - Show all sync mappings with their state (last sync time, direction, origin)
563
- - Read-only, uses `getAllTrackerSyncs()`
564
-
565
- **File**: `src/tools/tracker/tracker-map-agent.ts`
566
- - Map a swarm agent to an external user (for assignment sync)
567
- - Creates `tracker_agent_mapping` row
568
-
569
- **File**: `src/tools/tracker/index.ts` (barrel)
570
-
571
- #### 2. Register tools
572
- **File**: `src/server.ts`
573
- **Changes**: Import and register all 6 tracker tools in a new `// Tracker` section
574
-
575
- **File**: `src/tools/tool-config.ts`
576
- **Changes**: Add all 6 tools to `DEFERRED_TOOLS` set:
577
- ```typescript
578
- // Tracker (6)
579
- "tracker-status",
580
- "tracker-link-task",
581
- "tracker-link-epic",
582
- "tracker-unlink",
583
- "tracker-sync-status",
584
- "tracker-map-agent",
585
- ```
586
-
587
- #### 3. Outbound sync via event bus (not db.ts modification)
588
- **File**: `src/linear/outbound.ts` (new)
589
- **Changes**: Subscribe to `workflowEventBus` events and sync to Linear:
590
- - `initLinearOutboundSync()` — called from `initLinear()`, subscribes to event bus
591
- - `teardownLinearOutboundSync()` — called from `resetLinear()`, unsubscribes
592
- - Event handlers (each checks for `tracker_sync` mapping before acting):
593
- - `task.completed` → mark Linear issue Done + add completion comment
594
- - `task.failed` → add failure comment on Linear issue
595
- - `task.cancelled` → update Linear issue status
596
- - `task.progress` → add progress comment on Linear issue (new event, see below)
597
-
598
- **File**: `src/workflows/event-bus.ts`
599
- **Changes**: No code changes needed — the event bus is generic. But `db.ts` needs a new emission:
600
-
601
- **File**: `src/be/db.ts`
602
- **Changes** (minimal — only add missing event emissions, no integration-specific imports):
603
- - In `updateTaskProgress()`: add `workflowEventBus.emit("task.progress", { taskId, progress })` via dynamic import (same pattern as existing `task.completed`/`task.failed` emissions)
604
- - This keeps `db.ts` integration-agnostic — it emits generic events, listeners decide what to do
605
-
606
- **File**: `src/linear/sync.ts`
607
- **Changes**: Add outbound sync functions called by `outbound.ts` handlers:
608
- - `syncTaskCompletionToLinear(taskId, output)` — mark issue Done + add completion comment
609
- - `syncTaskFailureToLinear(taskId, reason)` — add failure comment on Linear issue
610
- - `syncTaskProgressToLinear(taskId, progress)` — add comment on Linear issue
611
-
612
- **Rationale**: This follows the existing pattern — `db.ts` has zero integration-specific imports today. GitHub is inbound-only, Slack polls the DB, Workflows subscribe to the event bus. Linear outbound sync subscribes to the same event bus, keeping `db.ts` clean.
613
-
614
- #### 4. Loop prevention
615
- **File**: `src/linear/outbound.ts`
616
- **Changes**:
617
- - Before outbound sync: check `tracker_sync.lastSyncOrigin`
618
- - If `lastSyncOrigin = 'external'` and `lastSyncedAt` within 5s → skip (belt-and-suspenders with delivery ID)
619
- - After outbound sync: update `lastSyncOrigin = 'swarm'`, `lastSyncedAt = now()`
620
- - Primary dedup is `Linear-Delivery` header (Phase 3), this is fallback only
621
-
622
- #### 5. Unit tests
623
- **File**: `src/tests/tracker-tools.test.ts` (new)
624
- **Changes**: Test all 6 MCP tools via direct function calls (not full HTTP)
625
-
626
- **File**: `src/tests/linear-outbound-sync.test.ts` (new)
627
- **Changes**: Test outbound sync functions with mocked Linear API
628
-
629
- ### Success Criteria:
630
-
631
- #### Automated Verification:
632
- - [ ] TypeScript compiles: `bun run tsc:check`
633
- - [ ] Lint passes: `bun run lint:fix`
634
- - [ ] Tracker tools tests pass: `bun test src/tests/tracker-tools.test.ts`
635
- - [ ] Outbound sync tests pass: `bun test src/tests/linear-outbound-sync.test.ts`
636
- - [ ] All existing tests pass: `bun test`
637
- - [ ] OpenAPI spec regenerated: `bun run docs:openapi` (commit the updated `openapi.json`)
638
-
639
- #### Manual Verification:
640
- - [ ] MCP tool `tracker-status` returns connected tracker info (or "no trackers connected")
641
- - [ ] MCP tool `tracker-link-task` creates a sync mapping in DB
642
- - [ ] MCP tool `tracker-sync-status` shows the mapping just created
643
- - [ ] MCP tool `tracker-unlink` removes the mapping
644
- - [ ] Tools appear in DEFERRED_TOOLS and are discoverable via Tool Search
645
-
646
- **Implementation Note**: After completing this phase, pause for manual confirmation. Outbound sync to real Linear requires OAuth tokens (Phase 6). Commit after verification passes.
647
-
648
- ---
649
-
650
- ## Phase 5: Documentation + Setup Guide
651
-
652
- ### Overview
653
- Document the Linear integration setup process. Update `.env.example` with all required variables. Add inline code comments for non-obvious decisions. Update CLAUDE.md if needed.
654
-
655
- ### Changes Required:
656
-
657
- #### 1. Update .env.example
658
- **File**: `.env.example`
659
- **Changes**: Complete Linear section with all required/optional env vars:
660
- ```bash
661
- # ── Linear Integration ──
662
- # LINEAR_DISABLE=true # Set to disable Linear integration
663
- # LINEAR_CLIENT_ID= # OAuth app client ID (Settings > API > OAuth applications)
664
- # LINEAR_CLIENT_SECRET= # OAuth app client secret (shown once on creation)
665
- # LINEAR_REDIRECT_URI=http://localhost:3013/api/trackers/linear/callback
666
- # LINEAR_SIGNING_SECRET= # Webhook HMAC verification secret
667
- # LINEAR_TEAM_ID= # Optional: scope to a specific team
668
- ```
669
-
670
- #### 2. Add setup documentation
671
- **File**: `src/linear/README.md` (new)
672
- **Changes**: Step-by-step Linear app setup:
673
- 1. Create OAuth Application at `linear.app/settings/api/applications`
674
- 2. Configure callback URLs
675
- 3. Enable webhooks + Agent session events
676
- 4. Copy credentials to `.env`
677
- 5. Run OAuth flow: `curl -H "Authorization: Bearer $API_KEY" http://localhost:3013/api/trackers/linear/authorize`
678
- 6. Verify connection: `curl -H "Authorization: Bearer $API_KEY" http://localhost:3013/api/trackers/linear/status`
679
-
680
- #### 3. Add architecture notes
681
- **File**: `src/oauth/README.md` (new)
682
- **Changes**: Brief doc explaining generic OAuth module:
683
- - How `oauth_apps` + `oauth_tokens` tables work
684
- - How to add a new OAuth provider
685
- - How `oauth4webapi` wrapper is used
686
-
687
- #### 4. Update MCP.md
688
- **File**: `MCP.md`
689
- **Changes**: Add tracker tools section with descriptions
690
-
691
- ### Success Criteria:
692
-
693
- #### Automated Verification:
694
- - [ ] Lint passes: `bun run lint:fix`
695
- - [ ] All tests pass: `bun test`
696
-
697
- #### Manual Verification:
698
- - [ ] `.env.example` has complete Linear section with comments
699
- - [ ] `src/linear/README.md` is clear and actionable
700
- - [ ] `src/oauth/README.md` explains the generic pattern
701
- - [ ] MCP.md includes tracker tools
702
-
703
- **Implementation Note**: After completing this phase, pause for manual confirmation. Commit after verification passes.
704
-
705
- ---
706
-
707
- ## Phase 6: Full End-to-End Testing
708
-
709
- ### Overview
710
- Comprehensive testing split into two categories: automated tests Claude can run independently, and manual tests requiring Taras's help (real Linear workspace, ngrok, etc.).
711
-
712
- ### Automated E2E (Claude can run):
713
-
714
- #### 1. Server startup E2E
715
- ```bash
716
- # Fresh DB + server start
717
- rm -f agent-swarm-db.sqlite*
718
- bun run start:http &
719
- sleep 2
720
-
721
- # Verify tables exist
722
- sqlite3 agent-swarm-db.sqlite ".tables" | grep -E "oauth_apps|oauth_tokens|tracker_sync|tracker_agent_mapping"
723
-
724
- # Verify no old tables
725
- sqlite3 agent-swarm-db.sqlite ".tables" | grep -v "linear_oauth_tokens\|linear_sync\|linear_agent_mapping"
726
-
727
- # Verify routes respond
728
- curl -s -o /dev/null -w "%{http_code}" http://localhost:3013/api/trackers/linear/status
729
- # Expected: 503 (not configured) or 200
730
-
731
- # Verify old routes gone
732
- curl -s -o /dev/null -w "%{http_code}" http://localhost:3013/api/linear/authorize
733
- # Expected: 404
734
-
735
- kill $(lsof -ti :3013)
736
- ```
737
-
738
- #### 2. Full test suite
739
- ```bash
740
- bun test
741
- bun run tsc:check
742
- bun run lint:fix
743
- ```
744
-
745
- #### 3. MCP tool integration test
746
- ```bash
747
- # Start server, initialize MCP session, call tracker-status tool
748
- # (Using the MCP Streamable HTTP test pattern from CLAUDE.md)
749
- ```
750
-
751
- ### Manual E2E (Taras helps):
752
-
753
- #### 1. OAuth Flow
754
- - [x] Set `LINEAR_CLIENT_ID`, `LINEAR_CLIENT_SECRET`, `LINEAR_REDIRECT_URI`, `LINEAR_SIGNING_SECRET` in `.env`
755
- - [x] Start server: `bun run start:http`
756
- - [x] Visit `http://localhost:3013/api/trackers/linear/authorize` in browser
757
- - [x] Authorize the app (must be workspace admin for `actor=app`)
758
- - [x] Verify callback success page
759
- - [x] Check status: `curl -H "Authorization: Bearer $API_KEY" http://localhost:3013/api/trackers/linear/status`
760
- - [x] Verify `oauth_tokens` row exists: `sqlite3 agent-swarm-db.sqlite "SELECT provider, scope, expiresAt FROM oauth_tokens"`
761
-
762
- #### 2. Inbound Sync (requires ngrok/cloudflared)
763
-
764
- > **Webhook setup is manual.** Linear doesn't have an API to programmatically register webhooks for OAuth apps. You configure the webhook URL once in Linear's app settings (Settings > API > OAuth applications > your app > Webhook URL + enable "Agent session events"). The `/status` endpoint will display the expected webhook URL so you know what to configure. For local dev, use a tunnel URL.
765
-
766
- - [x] Start tunnel: `ngrok http 3013` (or `cloudflared tunnel --url http://localhost:3013`)
767
- - [x] In Linear app settings, set Webhook URL to `<tunnel-url>/api/trackers/linear/webhook` and enable "Agent session events"
768
- - [x] @mention the app in a Linear comment → verify swarm task created
769
- - [x] Delegate issue to app → verify swarm task via `AgentSessionEvent`
770
- - [x] Change status in Linear → verify swarm task status updates
771
- - [x] Delete issue → verify task cancelled
772
-
773
- #### 3. Outbound Sync
774
- - [x] Complete swarm task → verify Linear issue marked "Done"
775
- - [x] Fail swarm task → verify Linear comment with failure info
776
- - [x] Task progress update → verify Linear comment
777
-
778
- #### 4. Edge Cases
779
- - [ ] Token expires (wait 24hr or manually expire) → verify auto-refresh
780
- - [ ] Duplicate webhooks (replay same delivery) → verify idempotent
781
- - [ ] Invalid webhook signature → verify 401
782
- - [ ] Server restart mid-sync → verify no data loss
783
-
784
- ### Success Criteria:
785
-
786
- #### Automated Verification:
787
- - [ ] All tests pass: `bun test`
788
- - [ ] TypeScript compiles: `bun run tsc:check`
789
- - [ ] Lint passes: `bun run lint:fix`
790
- - [ ] Server startup E2E passes (fresh DB)
791
- - [ ] OpenAPI spec is fresh: check `openapi.json` includes tracker routes
792
-
793
- #### Manual Verification:
794
- - [x] Full OAuth flow works with real Linear workspace
795
- - [x] @mention creates swarm task
796
- - [x] Bidirectional status sync works
797
- - [ ] Duplicate webhook delivery is deduplicated
798
- - [ ] Token auto-refresh works
799
-
800
- **Implementation Note**: Automated E2E runs first. Manual E2E requires Taras to set up Linear app credentials and ngrok tunnel.
801
-
802
- ---
803
-
804
- ## Testing Strategy
805
-
806
- | Layer | What | Where |
807
- |-------|------|-------|
808
- | Unit | OAuth DB CRUD | `src/tests/db-queries-oauth.test.ts` |
809
- | Unit | Tracker sync/mapping CRUD | `src/tests/db-queries-tracker.test.ts` |
810
- | Unit | OAuth wrapper (PKCE, URL generation) | `src/tests/oauth-wrapper.test.ts` |
811
- | Unit | MCP tracker tools | `src/tests/tracker-tools.test.ts` |
812
- | Unit | Outbound sync functions | `src/tests/linear-outbound-sync.test.ts` |
813
- | Integration | Webhook signature + dispatch | `src/tests/linear-webhook.test.ts` |
814
- | Integration | Inbound sync (mocked Linear API) | `src/tests/linear-webhook.test.ts` |
815
- | E2E (automated) | Server startup, fresh DB, routes | Phase 6 automated section |
816
- | E2E (manual) | Real OAuth, webhooks, bidirectional sync | Phase 6 manual section |
817
-
818
- ## References
819
-
820
- - Research: `thoughts/taras/research/2026-03-18-linear-integration-finalization.md`
821
- - PR: #161 on `linear-integration-foundation` branch
822
- - Linear Agent Interaction SDK: https://linear.app/docs/agent-interaction-sdk
823
- - `oauth4webapi`: https://github.com/panva/oauth4webapi
824
- - `@linear/sdk`: https://www.npmjs.com/package/@linear/sdk
825
-
826
- ---
827
-
828
- ## Review Errata
829
-
830
- _Reviewed: 2026-03-19 by Claude_
831
-
832
- ### Critical
833
-
834
- - [x] **Phase 4 Outbound Sync: Architecture breaks `db.ts` isolation pattern.** — RESOLVED: Rewrote Phase 4 §3 to use `workflowEventBus` subscription in `src/linear/outbound.ts` instead of modifying `db.ts` directly. The plan proposes adding Linear-specific sync calls directly into `src/be/db.ts` (`completeTask()`, `failTask()`, `updateTaskProgress()`). Today, `db.ts` has **zero integration-specific imports** — only `bun:sqlite`, types, and the migration runner. The existing event bus (`workflowEventBus`) is consumed via dynamic import specifically to avoid coupling. No existing integration (GitHub, Slack, Workflows) modifies these functions — GitHub is inbound-only (calls db functions as a consumer), Slack polls the DB every 3s, Workflows subscribe to the event bus. **Recommended approach**: Emit new events from `db.ts` (e.g., `task.completed` already exists) and subscribe to them in a new `src/linear/outbound.ts` module — consistent with the workflow pattern and keeps `db.ts` integration-agnostic. The `workflowEventBus` already emits `task.completed` and `task.created`; extend it with `task.failed`, `task.cancelled`, `task.progress` and subscribe from the Linear module.
835
-
836
- ### Important
837
-
838
- - [x] **Migration 008 `agent_tasks` table recreation SQL not shown.** — RESOLVED: Added explicit reference to copy lines 54-114 from current migration in Phase 1 §3. The plan mentions "Plus the `agent_tasks` table recreation with `'linear'` in the source CHECK" but doesn't include the SQL. The current migration 008 has 60+ lines of table recreation (CREATE new → INSERT SELECT → DROP old → ALTER RENAME → recreate indexes). The plan should either include the full SQL inline or explicitly reference "copy lines 54-114 from current `008_linear_integration.sql`" so the implementer doesn't miss columns or indexes.
839
-
840
- - [x] **OpenAPI spec regeneration step missing from phase verification.** — RESOLVED: Added `bun run docs:openapi` to Automated Verification in Phases 1-4. Phase 1 removes Linear routes from `openapi.json` and Phase 6 checks that tracker routes are present, but no phase runs `bun run docs:openapi` to regenerate the static file. The CI merge gate enforces freshness (`scripts/generate-openapi.ts`). Each phase that adds or removes routes should include `bun run docs:openapi` in its Automated Verification checklist, and the resulting `openapi.json` changes should be committed.
841
-
842
- - [x] **Phase 3 fire-and-forget error handling unspecified.** — RESOLVED: Added explicit error handling guidance in Phase 3 §3 (try/catch + console.error with context). The plan says "respond 200 immediately, run heavy work in unresolved promise" but doesn't address what happens when the deferred work fails (e.g., `createTaskExtended()` throws, Linear API call fails). At minimum: log errors. Consider whether failed task creation should be retried or surfaced. The existing event bus emissions in `db.ts` wrap in `try {} catch {}` that silently swallow errors — this is a known weak pattern that shouldn't be replicated.
843
-
844
- ### Minor
845
-
846
- - [x] **Frontmatter missing `planner` field.** Plan template requires `planner:` in frontmatter — auto-fixed.
847
- - [ ] **`server.ts` tool registration range inaccurate.** Plan says lines 114-180; actual range is 114-208 (includes memory + workflow capability blocks). Won't affect implementation but worth correcting for accuracy.
848
- - [ ] **`tracker_sync.syncDirection` lacks CHECK constraint.** Column defaults to `'inbound'` but unlike `entityType` (which has `CHECK IN ('task', 'epic')`), `syncDirection` has no constraint validating allowed values. Add `CHECK (syncDirection IN ('inbound', 'outbound', 'bidirectional'))`.
849
- - [ ] **`tracker_sync.lastSyncOrigin` nullability ambiguous.** Column has `CHECK (lastSyncOrigin IN ('swarm', 'external'))` but is nullable. The plan should clarify: is NULL the "never synced" state? If so, document it. If not, add `NOT NULL DEFAULT 'swarm'`.
850
- - [ ] **In-memory PKCE state and webhook dedup lost on restart.** OAuth pending state map (Phase 2) and dedup set (Phase 3) are in-memory with TTL. Server restart during OAuth flow = flow fails; restart during webhook replay window = duplicates slip through. Acceptable trade-off for single-instance deployment but should be documented as a known limitation.
851
-
852
- ### Codebase Reference Accuracy
853
-
854
- All 11 file:line references were verified. 10/11 are accurate. One inaccuracy:
855
- - `src/server.ts:114-180` → actual tool registration range is **114-208**
856
-
857
- Additional confirmations:
858
- - `@linear/sdk` is already in `package.json` (v77.0.0) — no install needed
859
- - `src/be/db-queries/` directory does not exist yet (plan creates it — correct)
860
- - `openapi.json` is auto-generated via `route()` registry + `scripts/generate-openapi.ts`