@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.
- package/README.md +1 -1
- package/openapi.json +2070 -728
- package/package.json +10 -1
- package/src/agentmail/handlers.ts +65 -10
- package/src/agentmail/templates.ts +111 -0
- package/src/be/db.ts +1233 -7
- package/src/be/migrations/014_prompt_templates.sql +33 -0
- package/src/be/migrations/015_workflow_workspace.sql +3 -0
- package/src/be/migrations/016_active_session_runner_session.sql +4 -0
- package/src/be/migrations/017_channel_activity_cursors.sql +6 -0
- package/src/be/migrations/018_fix_seed_double_version.sql +30 -0
- package/src/be/migrations/019_skills.sql +65 -0
- package/src/be/migrations/020_approval_requests.sql +41 -0
- package/src/be/seed.ts +62 -0
- package/src/be/skill-parser.ts +70 -0
- package/src/be/skill-sync.ts +106 -0
- package/src/commands/runner.ts +320 -132
- package/src/commands/templates.ts +172 -0
- package/src/github/handlers.ts +292 -77
- package/src/github/mentions-aliases.test.ts +73 -0
- package/src/github/mentions.test.ts +3 -3
- package/src/github/mentions.ts +32 -6
- package/src/github/templates.ts +398 -0
- package/src/gitlab/handlers.ts +63 -22
- package/src/gitlab/templates.ts +140 -0
- package/src/heartbeat/heartbeat.ts +19 -10
- package/src/heartbeat/templates.ts +30 -0
- package/src/http/active-sessions.ts +27 -0
- package/src/http/approval-requests.ts +247 -0
- package/src/http/config.ts +3 -3
- package/src/http/index.ts +9 -2
- package/src/http/poll.ts +135 -14
- package/src/http/prompt-templates.ts +412 -0
- package/src/http/schedules.ts +35 -0
- package/src/http/skills.ts +479 -0
- package/src/http/workflows.ts +8 -0
- package/src/linear/sync.ts +28 -4
- package/src/linear/templates.ts +47 -0
- package/src/prompts/base-prompt.ts +41 -490
- package/src/prompts/registry.ts +57 -0
- package/src/prompts/resolver.ts +296 -0
- package/src/prompts/session-templates.ts +604 -0
- package/src/providers/claude-adapter.ts +15 -2
- package/src/providers/pi-mono-extension.ts +5 -1
- package/src/scheduler/scheduler.ts +125 -91
- package/src/server.ts +44 -0
- package/src/slack/assistant.ts +7 -4
- package/src/slack/channel-activity.ts +177 -0
- package/src/slack/handlers.ts +21 -6
- package/src/slack/templates.ts +55 -0
- package/src/tests/approval-requests.test.ts +735 -0
- package/src/tests/artifact-sdk.test.ts +12 -12
- package/src/tests/base-prompt.test.ts +49 -49
- package/src/tests/channel-activity.test.ts +363 -0
- package/src/tests/heartbeat.test.ts +1 -0
- package/src/tests/linear-webhook.test.ts +7 -3
- package/src/tests/pool-session-logs.test.ts +199 -0
- package/src/tests/prompt-template-github.test.ts +682 -0
- package/src/tests/prompt-template-remaining.test.ts +504 -0
- package/src/tests/prompt-template-resolver.test.ts +621 -0
- package/src/tests/prompt-template-session.test.ts +363 -0
- package/src/tests/prompt-templates-db.test.ts +616 -0
- package/src/tests/self-improvement.test.ts +8 -7
- package/src/tests/skill-parser.test.ts +178 -0
- package/src/tests/skill-sync.test.ts +171 -0
- package/src/tests/slack-metadata-inheritance.test.ts +1 -1
- package/src/tests/slack-thread-followups.test.ts +1 -1
- package/src/tests/structured-output.test.ts +0 -4
- package/src/tests/tool-annotations.test.ts +2 -1
- package/src/tests/update-profile-agentid.test.ts +248 -0
- package/src/tests/update-profile-auth.test.ts +195 -0
- package/src/tests/workflow-async-v2.test.ts +126 -4
- package/src/tests/workflow-definition-validation.test.ts +76 -0
- package/src/tests/workflow-executors.test.ts +4 -2
- package/src/tests/workflow-retry-v2.test.ts +1 -1
- package/src/tests/workflow-schedule-trigger.test.ts +104 -0
- package/src/tests/workflow-workspace.test.ts +272 -0
- package/src/tools/prompt-templates/delete.ts +86 -0
- package/src/tools/prompt-templates/get.ts +89 -0
- package/src/tools/prompt-templates/index.ts +5 -0
- package/src/tools/prompt-templates/list.ts +95 -0
- package/src/tools/prompt-templates/preview.ts +84 -0
- package/src/tools/prompt-templates/set.ts +117 -0
- package/src/tools/request-human-input.ts +106 -0
- package/src/tools/skills/index.ts +11 -0
- package/src/tools/skills/skill-create.ts +105 -0
- package/src/tools/skills/skill-delete.ts +67 -0
- package/src/tools/skills/skill-get.ts +75 -0
- package/src/tools/skills/skill-install-remote.ts +152 -0
- package/src/tools/skills/skill-install.ts +101 -0
- package/src/tools/skills/skill-list.ts +77 -0
- package/src/tools/skills/skill-publish.ts +123 -0
- package/src/tools/skills/skill-search.ts +43 -0
- package/src/tools/skills/skill-sync-remote.ts +128 -0
- package/src/tools/skills/skill-uninstall.ts +60 -0
- package/src/tools/skills/skill-update.ts +128 -0
- package/src/tools/store-progress.ts +22 -4
- package/src/tools/task-action.ts +20 -0
- package/src/tools/templates.ts +53 -0
- package/src/tools/tool-config.ts +23 -0
- package/src/tools/update-profile.ts +106 -34
- package/src/tools/workflows/create-workflow.ts +19 -1
- package/src/tools/workflows/update-workflow.ts +16 -1
- package/src/types.ts +109 -2
- package/src/workflows/definition.ts +30 -12
- package/src/workflows/engine.ts +40 -14
- package/src/workflows/executors/agent-task.ts +14 -3
- package/src/workflows/executors/human-in-the-loop.ts +160 -0
- package/src/workflows/executors/registry.ts +2 -0
- package/src/workflows/index.ts +1 -1
- package/src/workflows/recovery.ts +72 -0
- package/src/workflows/resume.ts +162 -12
- package/src/workflows/triggers.ts +31 -2
- package/src/workflows/version.ts +2 -0
- package/.claude/settings.json +0 -84
- package/.claude/settings.local.json +0 -117
- package/.dockerignore +0 -61
- package/.editorconfig +0 -15
- package/.entire/settings.json +0 -4
- package/.env.docker.example +0 -56
- package/.env.example +0 -78
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -78
- package/.github/ISSUE_TEMPLATE/community-template.yml +0 -77
- package/.github/ISSUE_TEMPLATE/config.yml +0 -8
- package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -60
- package/.github/PULL_REQUEST_TEMPLATE/community-template.md +0 -29
- package/.github/workflows/ci.yml +0 -52
- package/.github/workflows/docker-and-deploy.yml +0 -132
- package/.github/workflows/merge-gate.yml +0 -233
- package/.opencode/plugins/entire.ts +0 -133
- package/.superset/config.json +0 -6
- package/.wts-config.json +0 -4
- package/.wts-setup.ts +0 -171
- package/CHANGELOG.md +0 -447
- package/CLAUDE.md +0 -521
- package/CONTRIBUTING.md +0 -315
- package/DEPLOYMENT.md +0 -622
- package/Dockerfile +0 -65
- package/Dockerfile.worker +0 -189
- package/MCP.md +0 -841
- package/UI.md +0 -40
- package/api-entrypoint.sh +0 -56
- package/assets/agent-swarm-logo-orange.png +0 -0
- package/assets/agent-swarm-logo.png +0 -0
- package/assets/agent-swarm.mp4 +0 -0
- package/assets/agent-swarm.png +0 -0
- package/biome.json +0 -39
- package/deploy/DEPLOY.md +0 -60
- package/deploy/agent-swarm.service +0 -17
- package/deploy/docker-push.ts +0 -30
- package/deploy/install.ts +0 -85
- package/deploy/prod-db.ts +0 -42
- package/deploy/uninstall.ts +0 -12
- package/deploy/update.ts +0 -21
- package/depot.json +0 -1
- package/docker-compose.example.yml +0 -350
- package/docker-compose.local.yml +0 -119
- package/docker-entrypoint.sh +0 -632
- package/docs-site/app/api/search/route.ts +0 -4
- package/docs-site/app/docs/[[...slug]]/page.tsx +0 -87
- package/docs-site/app/docs/layout.tsx +0 -12
- package/docs-site/app/globals.css +0 -24
- package/docs-site/app/layout.config.tsx +0 -34
- package/docs-site/app/layout.tsx +0 -119
- package/docs-site/app/llms-full.txt/route.ts +0 -11
- package/docs-site/app/llms.mdx/docs/[[...slug]]/route.ts +0 -24
- package/docs-site/app/llms.txt/route.ts +0 -8
- package/docs-site/app/page.tsx +0 -5
- package/docs-site/app/robots.ts +0 -13
- package/docs-site/app/sitemap.ts +0 -37
- package/docs-site/components/api-page.client.tsx +0 -4
- package/docs-site/components/api-page.tsx +0 -7
- package/docs-site/components/mdx/mermaid.tsx +0 -55
- package/docs-site/content/docs/(documentation)/architecture/agents.mdx +0 -117
- package/docs-site/content/docs/(documentation)/architecture/hooks.mdx +0 -77
- package/docs-site/content/docs/(documentation)/architecture/memory.mdx +0 -96
- package/docs-site/content/docs/(documentation)/architecture/meta.json +0 -4
- package/docs-site/content/docs/(documentation)/architecture/overview.mdx +0 -172
- package/docs-site/content/docs/(documentation)/concepts/epics.mdx +0 -98
- package/docs-site/content/docs/(documentation)/concepts/meta.json +0 -4
- package/docs-site/content/docs/(documentation)/concepts/scheduling.mdx +0 -136
- package/docs-site/content/docs/(documentation)/concepts/services.mdx +0 -104
- package/docs-site/content/docs/(documentation)/concepts/task-lifecycle.mdx +0 -148
- package/docs-site/content/docs/(documentation)/concepts/workflows.mdx +0 -209
- package/docs-site/content/docs/(documentation)/contributing.mdx +0 -158
- package/docs-site/content/docs/(documentation)/getting-started.mdx +0 -157
- package/docs-site/content/docs/(documentation)/guides/agentmail-integration.mdx +0 -79
- package/docs-site/content/docs/(documentation)/guides/deployment.mdx +0 -171
- package/docs-site/content/docs/(documentation)/guides/github-integration.mdx +0 -81
- package/docs-site/content/docs/(documentation)/guides/gitlab-integration.mdx +0 -93
- package/docs-site/content/docs/(documentation)/guides/linear-integration.mdx +0 -98
- package/docs-site/content/docs/(documentation)/guides/meta.json +0 -13
- package/docs-site/content/docs/(documentation)/guides/sentry-integration.mdx +0 -52
- package/docs-site/content/docs/(documentation)/guides/slack-integration.mdx +0 -179
- package/docs-site/content/docs/(documentation)/guides/x402-payments.mdx +0 -154
- package/docs-site/content/docs/(documentation)/index.mdx +0 -65
- package/docs-site/content/docs/(documentation)/meta.json +0 -19
- package/docs-site/content/docs/(documentation)/reference/cli.mdx +0 -241
- package/docs-site/content/docs/(documentation)/reference/environment-variables.mdx +0 -205
- package/docs-site/content/docs/(documentation)/reference/mcp-tools.mdx +0 -449
- package/docs-site/content/docs/(documentation)/reference/meta.json +0 -4
- package/docs-site/content/docs/api-reference/active-sessions.mdx +0 -9
- package/docs-site/content/docs/api-reference/agents.mdx +0 -9
- package/docs-site/content/docs/api-reference/channels.mdx +0 -9
- package/docs-site/content/docs/api-reference/config.mdx +0 -9
- package/docs-site/content/docs/api-reference/debug.mdx +0 -9
- package/docs-site/content/docs/api-reference/ecosystem.mdx +0 -9
- package/docs-site/content/docs/api-reference/epics.mdx +0 -9
- package/docs-site/content/docs/api-reference/index.mdx +0 -32
- package/docs-site/content/docs/api-reference/memory.mdx +0 -9
- package/docs-site/content/docs/api-reference/meta.json +0 -25
- package/docs-site/content/docs/api-reference/poll.mdx +0 -9
- package/docs-site/content/docs/api-reference/repos.mdx +0 -9
- package/docs-site/content/docs/api-reference/schedules.mdx +0 -9
- package/docs-site/content/docs/api-reference/session-data.mdx +0 -9
- package/docs-site/content/docs/api-reference/stats.mdx +0 -9
- package/docs-site/content/docs/api-reference/tasks.mdx +0 -9
- package/docs-site/content/docs/api-reference/trackers.mdx +0 -9
- package/docs-site/content/docs/api-reference/webhooks.mdx +0 -9
- package/docs-site/content/docs/api-reference/workflows.mdx +0 -9
- package/docs-site/content/docs/meta.json +0 -3
- package/docs-site/lib/get-llm-text.ts +0 -10
- package/docs-site/lib/openapi.ts +0 -23
- package/docs-site/lib/source.ts +0 -8
- package/docs-site/mdx-components.tsx +0 -13
- package/docs-site/next.config.mjs +0 -29
- package/docs-site/package.json +0 -35
- package/docs-site/pnpm-lock.yaml +0 -5407
- package/docs-site/postcss.config.mjs +0 -8
- package/docs-site/public/logo.png +0 -0
- package/docs-site/scripts/generate-docs.ts +0 -171
- package/docs-site/source.config.ts +0 -17
- package/docs-site/tsconfig.json +0 -46
- package/ecosystem.config.cjs +0 -66
- package/landing/next.config.ts +0 -14
- package/landing/package.json +0 -31
- package/landing/pnpm-lock.yaml +0 -1091
- package/landing/postcss.config.mjs +0 -8
- package/landing/public/apple-touch-icon.png +0 -0
- package/landing/public/favicon.ico +0 -0
- package/landing/public/logo.png +0 -0
- package/landing/public/og-image.png +0 -0
- package/landing/public/omghost-desplega.svg +0 -30
- package/landing/public/omghost-openfort.svg +0 -9
- package/landing/src/app/actions/waitlist.ts +0 -25
- package/landing/src/app/blog/openfort-hackathon/page.tsx +0 -863
- package/landing/src/app/blog/page.tsx +0 -162
- package/landing/src/app/blog/swarm-metrics/page.tsx +0 -685
- package/landing/src/app/examples/page.tsx +0 -174
- package/landing/src/app/examples/x402/page.tsx +0 -456
- package/landing/src/app/globals.css +0 -122
- package/landing/src/app/layout.tsx +0 -134
- package/landing/src/app/page.tsx +0 -27
- package/landing/src/app/robots.ts +0 -13
- package/landing/src/app/sitemap.ts +0 -44
- package/landing/src/components/architecture.tsx +0 -163
- package/landing/src/components/cta.tsx +0 -52
- package/landing/src/components/features.tsx +0 -160
- package/landing/src/components/footer.tsx +0 -100
- package/landing/src/components/hero.tsx +0 -217
- package/landing/src/components/how-it-works.tsx +0 -165
- package/landing/src/components/navbar.tsx +0 -147
- package/landing/src/components/waitlist.tsx +0 -110
- package/landing/src/components/why-choose.tsx +0 -149
- package/landing/src/components/workshops.tsx +0 -328
- package/landing/src/lib/utils.ts +0 -6
- package/landing/tsconfig.json +0 -41
- package/misc/transcripts/2026-03-09-pi-mono-e2e-verification.md +0 -154
- package/new-ui/CLAUDE.md +0 -92
- package/new-ui/README.md +0 -73
- package/new-ui/biome.json +0 -42
- package/new-ui/components.json +0 -21
- package/new-ui/index.html +0 -25
- package/new-ui/package.json +0 -49
- package/new-ui/pnpm-lock.yaml +0 -4845
- package/new-ui/public/logo.png +0 -0
- package/new-ui/src/api/client.ts +0 -814
- package/new-ui/src/api/hooks/index.ts +0 -64
- package/new-ui/src/api/hooks/use-agents.ts +0 -58
- package/new-ui/src/api/hooks/use-channels.ts +0 -115
- package/new-ui/src/api/hooks/use-config-api.ts +0 -46
- package/new-ui/src/api/hooks/use-costs.ts +0 -122
- package/new-ui/src/api/hooks/use-db-query.ts +0 -29
- package/new-ui/src/api/hooks/use-epics.ts +0 -75
- package/new-ui/src/api/hooks/use-repos.ts +0 -61
- package/new-ui/src/api/hooks/use-schedules.ts +0 -81
- package/new-ui/src/api/hooks/use-services.ts +0 -16
- package/new-ui/src/api/hooks/use-stats.ts +0 -27
- package/new-ui/src/api/hooks/use-tasks.ts +0 -89
- package/new-ui/src/api/hooks/use-workflows.ts +0 -109
- package/new-ui/src/api/types.ts +0 -549
- package/new-ui/src/app/App.tsx +0 -13
- package/new-ui/src/app/providers.tsx +0 -32
- package/new-ui/src/app/router.tsx +0 -52
- package/new-ui/src/components/layout/app-header.tsx +0 -47
- package/new-ui/src/components/layout/app-sidebar.tsx +0 -128
- package/new-ui/src/components/layout/breadcrumbs.tsx +0 -57
- package/new-ui/src/components/layout/config-guard.tsx +0 -22
- package/new-ui/src/components/layout/root-layout.tsx +0 -40
- package/new-ui/src/components/layout/swarm-switcher.tsx +0 -85
- package/new-ui/src/components/shared/command-menu.tsx +0 -131
- package/new-ui/src/components/shared/data-grid.tsx +0 -141
- package/new-ui/src/components/shared/empty-state.tsx +0 -24
- package/new-ui/src/components/shared/error-boundary.tsx +0 -72
- package/new-ui/src/components/shared/json-viewer.tsx +0 -47
- package/new-ui/src/components/shared/name-connection-modal.tsx +0 -99
- package/new-ui/src/components/shared/page-skeleton.tsx +0 -16
- package/new-ui/src/components/shared/session-log-viewer.tsx +0 -364
- package/new-ui/src/components/shared/stats-bar.tsx +0 -132
- package/new-ui/src/components/shared/status-badge.tsx +0 -131
- package/new-ui/src/components/shared/usage-summary.tsx +0 -179
- package/new-ui/src/components/ui/alert-dialog.tsx +0 -176
- package/new-ui/src/components/ui/alert.tsx +0 -60
- package/new-ui/src/components/ui/avatar.tsx +0 -96
- package/new-ui/src/components/ui/badge.tsx +0 -46
- package/new-ui/src/components/ui/button.tsx +0 -62
- package/new-ui/src/components/ui/card.tsx +0 -75
- package/new-ui/src/components/ui/command.tsx +0 -160
- package/new-ui/src/components/ui/dialog.tsx +0 -143
- package/new-ui/src/components/ui/dropdown-menu.tsx +0 -226
- package/new-ui/src/components/ui/input.tsx +0 -21
- package/new-ui/src/components/ui/label.tsx +0 -19
- package/new-ui/src/components/ui/progress.tsx +0 -26
- package/new-ui/src/components/ui/scroll-area.tsx +0 -54
- package/new-ui/src/components/ui/select.tsx +0 -175
- package/new-ui/src/components/ui/separator.tsx +0 -28
- package/new-ui/src/components/ui/sheet.tsx +0 -132
- package/new-ui/src/components/ui/sidebar.tsx +0 -691
- package/new-ui/src/components/ui/skeleton.tsx +0 -13
- package/new-ui/src/components/ui/sonner.tsx +0 -35
- package/new-ui/src/components/ui/switch.tsx +0 -33
- package/new-ui/src/components/ui/table.tsx +0 -92
- package/new-ui/src/components/ui/tabs.tsx +0 -79
- package/new-ui/src/components/ui/textarea.tsx +0 -18
- package/new-ui/src/components/ui/tooltip.tsx +0 -51
- package/new-ui/src/components/workflows/action-node.tsx +0 -53
- package/new-ui/src/components/workflows/condition-node.tsx +0 -50
- package/new-ui/src/components/workflows/graph-utils.ts +0 -124
- package/new-ui/src/components/workflows/json-tree.tsx +0 -189
- package/new-ui/src/components/workflows/node-styles.ts +0 -10
- package/new-ui/src/components/workflows/step-detail-sheet.tsx +0 -87
- package/new-ui/src/components/workflows/trigger-node.tsx +0 -41
- package/new-ui/src/components/workflows/workflow-graph.tsx +0 -65
- package/new-ui/src/hooks/use-auto-scroll.ts +0 -82
- package/new-ui/src/hooks/use-config.ts +0 -203
- package/new-ui/src/hooks/use-keyboard-shortcuts.ts +0 -41
- package/new-ui/src/hooks/use-mobile.ts +0 -19
- package/new-ui/src/hooks/use-theme.ts +0 -60
- package/new-ui/src/lib/config.ts +0 -188
- package/new-ui/src/lib/slugs.ts +0 -71
- package/new-ui/src/lib/utils.ts +0 -120
- package/new-ui/src/main.tsx +0 -11
- package/new-ui/src/pages/agents/[id]/page.tsx +0 -492
- package/new-ui/src/pages/agents/page.tsx +0 -134
- package/new-ui/src/pages/chat/page.tsx +0 -674
- package/new-ui/src/pages/config/page.tsx +0 -1109
- package/new-ui/src/pages/dashboard/page.tsx +0 -454
- package/new-ui/src/pages/debug/page.tsx +0 -275
- package/new-ui/src/pages/epics/[id]/page.tsx +0 -809
- package/new-ui/src/pages/epics/page.tsx +0 -321
- package/new-ui/src/pages/not-found/page.tsx +0 -18
- package/new-ui/src/pages/repos/page.tsx +0 -369
- package/new-ui/src/pages/schedules/[id]/page.tsx +0 -664
- package/new-ui/src/pages/schedules/page.tsx +0 -477
- package/new-ui/src/pages/services/page.tsx +0 -128
- package/new-ui/src/pages/tasks/[id]/page.tsx +0 -670
- package/new-ui/src/pages/tasks/page.tsx +0 -592
- package/new-ui/src/pages/usage/page.tsx +0 -195
- package/new-ui/src/pages/workflow-runs/[id]/page.tsx +0 -363
- package/new-ui/src/pages/workflows/[id]/page.tsx +0 -417
- package/new-ui/src/pages/workflows/page.tsx +0 -266
- package/new-ui/src/styles/ag-grid.css +0 -36
- package/new-ui/src/styles/globals.css +0 -213
- package/new-ui/test-results/.last-run.json +0 -4
- package/new-ui/tsconfig.app.json +0 -34
- package/new-ui/tsconfig.json +0 -4
- package/new-ui/tsconfig.node.json +0 -26
- package/new-ui/vercel.json +0 -4
- package/new-ui/vite.config.ts +0 -28
- package/plugin/README.md +0 -1
- package/plugin/build-pi-skills.ts +0 -233
- package/plugin/hooks/hooks.json +0 -71
- package/prek.toml +0 -75
- package/pyproject.toml +0 -9
- package/scripts/check-db-boundary.sh +0 -60
- package/scripts/e2e-docker-provider.ts +0 -820
- package/scripts/e2e-io-schemas-test.ts +0 -807
- package/scripts/e2e-provider-test.ts +0 -220
- package/scripts/e2e-workflow-redesign.sh +0 -229
- package/scripts/e2e-workflow-test.sh +0 -285
- package/scripts/e2e-workflow-test.ts +0 -857
- package/scripts/generate-mcp-docs.ts +0 -415
- package/scripts/generate-openapi.ts +0 -26
- package/scripts/measure-tool-tokens.ts +0 -118
- package/scripts/x402-e2e-test.ts +0 -195
- package/scripts/x402-test-server.ts +0 -236
- package/scripts/x402-testnet-e2e.ts +0 -668
- package/slack-manifest.json +0 -88
- package/templates-ui/README.md +0 -46
- package/templates-ui/components.json +0 -17
- package/templates-ui/eslint.config.mjs +0 -18
- package/templates-ui/next.config.ts +0 -7
- package/templates-ui/package.json +0 -35
- package/templates-ui/pnpm-lock.yaml +0 -4571
- package/templates-ui/postcss.config.mjs +0 -7
- package/templates-ui/public/file.svg +0 -1
- package/templates-ui/public/globe.svg +0 -1
- package/templates-ui/public/logo.png +0 -0
- package/templates-ui/public/next.svg +0 -1
- package/templates-ui/public/vercel.svg +0 -1
- package/templates-ui/public/window.svg +0 -1
- package/templates-ui/src/app/[category]/[name]/page.tsx +0 -89
- package/templates-ui/src/app/api/templates/[...slug]/route.ts +0 -52
- package/templates-ui/src/app/api/templates/route.ts +0 -18
- package/templates-ui/src/app/builder/page.tsx +0 -37
- package/templates-ui/src/app/globals.css +0 -94
- package/templates-ui/src/app/layout.tsx +0 -79
- package/templates-ui/src/app/page.tsx +0 -38
- package/templates-ui/src/app/robots.ts +0 -11
- package/templates-ui/src/app/sitemap.ts +0 -31
- package/templates-ui/src/components/compose-builder.tsx +0 -442
- package/templates-ui/src/components/compose-preview.tsx +0 -117
- package/templates-ui/src/components/file-preview.tsx +0 -77
- package/templates-ui/src/components/footer.tsx +0 -40
- package/templates-ui/src/components/header.tsx +0 -41
- package/templates-ui/src/components/template-card.tsx +0 -87
- package/templates-ui/src/components/template-detail.tsx +0 -125
- package/templates-ui/src/components/template-gallery.tsx +0 -263
- package/templates-ui/src/components/ui/badge.tsx +0 -36
- package/templates-ui/src/components/ui/button.tsx +0 -57
- package/templates-ui/src/components/ui/card.tsx +0 -76
- package/templates-ui/src/components/ui/separator.tsx +0 -31
- package/templates-ui/src/components/ui/tooltip.tsx +0 -32
- package/templates-ui/src/lib/compose-generator.ts +0 -241
- package/templates-ui/src/lib/templates.ts +0 -137
- package/templates-ui/src/lib/utils.ts +0 -6
- package/templates-ui/tsconfig.json +0 -34
- package/thoughts/research/2026-02-28-openfort-viem-x402-research.md +0 -679
- package/thoughts/research/2026-02-28-x402-payments-research.md +0 -686
- package/thoughts/researcher/plans/2026-02-20-agent-self-improvement-plan.md +0 -282
- package/thoughts/researcher/research/2026-02-20-agent-self-improvement.md +0 -492
- package/thoughts/shared/plans/.gitkeep +0 -0
- package/thoughts/shared/plans/2025-12-18-slack-integration.md +0 -1195
- package/thoughts/shared/plans/2025-12-19-agent-log-streaming.md +0 -732
- package/thoughts/shared/plans/2025-12-19-role-based-swarm-plugin.md +0 -361
- package/thoughts/shared/plans/2025-12-20-mobile-responsive-ui.md +0 -501
- package/thoughts/shared/plans/2025-12-20-startup-team-swarm.md +0 -560
- package/thoughts/shared/plans/2025-12-23-runner-level-polling.md +0 -934
- package/thoughts/shared/plans/2025-12-23-runner-session-logs.md +0 -1000
- package/thoughts/shared/plans/2025-12-23-worker-lead-spawn-triggers.md +0 -568
- package/thoughts/shared/plans/2026-01-09-inverse-teleport.md +0 -1516
- package/thoughts/shared/plans/2026-01-12-agent-rename-pm2-control.md +0 -1133
- package/thoughts/shared/plans/2026-01-12-github-app-integration.md +0 -380
- package/thoughts/shared/plans/2026-01-12-lead-inbox-model.md +0 -876
- package/thoughts/shared/plans/2026-01-12-ralph-wiggum-integration.md +0 -463
- package/thoughts/shared/plans/2026-01-13-agent-concurrency.md +0 -691
- package/thoughts/shared/plans/2026-01-13-github-assignment-handling.md +0 -690
- package/thoughts/shared/plans/2026-01-13-prevent-duplicate-trigger-processing.md +0 -1071
- package/thoughts/shared/plans/2026-01-14-fix-slack-thread-context.md +0 -507
- package/thoughts/shared/plans/2026-01-15-scheduled-tasks-implementation.md +0 -565
- package/thoughts/shared/plans/2026-01-15-usage-cost-tracking-ui.md +0 -1479
- package/thoughts/shared/plans/2026-01-16-epics-feature-implementation.md +0 -1230
- package/thoughts/shared/plans/2026-02-26-mcp-tool-context-reduction.md +0 -282
- package/thoughts/shared/plans/2026-03-02-claude-context-mode-integration.md +0 -328
- package/thoughts/shared/plans/2026-03-02-code-level-heartbeat.md +0 -224
- package/thoughts/shared/research/.gitkeep +0 -0
- package/thoughts/shared/research/2025-01-09-inverse-teleport-plan-review.md +0 -420
- package/thoughts/shared/research/2025-12-18-slack-integration.md +0 -442
- package/thoughts/shared/research/2025-12-19-agent-log-streaming.md +0 -339
- package/thoughts/shared/research/2025-12-19-agent-secrets-cli-research.md +0 -390
- package/thoughts/shared/research/2025-12-21-gemini-cli-integration.md +0 -376
- package/thoughts/shared/research/2025-12-22-runner-loop-architecture.md +0 -582
- package/thoughts/shared/research/2025-12-22-setup-experience-improvements.md +0 -264
- package/thoughts/shared/research/2026-01-13-lead-duplicate-trigger-processing.md +0 -223
- package/thoughts/shared/research/2026-01-14-lead-slack-thread-context.md +0 -277
- package/thoughts/shared/research/2026-01-15-ai-tracker-agent-swarm-integration.md +0 -376
- package/thoughts/shared/research/2026-01-15-auto-starting-processes-in-worker-containers.md +0 -787
- package/thoughts/shared/research/2026-01-15-scheduled-tasks.md +0 -390
- package/thoughts/shared/research/2026-01-16-epics-feature-research.md +0 -437
- package/thoughts/shared/research/2026-02-26-cliffy-mcp-tools.md +0 -159
- package/thoughts/shared/research/2026-03-03-database-migration-system-refactor.md +0 -337
- package/thoughts/swarm-researcher/plans/2026-02-23-openclaw-improvements-plan.md +0 -778
- package/thoughts/swarm-researcher/plans/2026-02-26-artifacts-localtunnel-plan.md +0 -1269
- package/thoughts/swarm-researcher/research/2026-02-23-openclaw-vs-agent-swarm-comparison.md +0 -411
- package/thoughts/swarm-researcher/research/2026-02-26-artifacts-localtunnel.md +0 -724
- package/thoughts/taras/brainstorms/2026-03-20-prompt-template-registry.md +0 -443
- package/thoughts/taras/brainstorms/2026-03-20-setup-cli-onboarding.md +0 -307
- package/thoughts/taras/plans/2026-01-22-agent-swarm-schemas.md +0 -98
- package/thoughts/taras/plans/2026-01-28-per-worker-claude-md.md +0 -617
- package/thoughts/taras/plans/2026-01-28-sentry-cli-integration.md +0 -214
- package/thoughts/taras/plans/2026-02-20-auto-improvement.md +0 -803
- package/thoughts/taras/plans/2026-02-20-env-management.md +0 -538
- package/thoughts/taras/plans/2026-02-20-memory-system.md +0 -882
- package/thoughts/taras/plans/2026-02-20-repos-knowledge.md +0 -806
- package/thoughts/taras/plans/2026-02-20-session-attach.md +0 -647
- package/thoughts/taras/plans/2026-02-20-worker-identity.md +0 -820
- package/thoughts/taras/plans/2026-02-25-feat-new-ui-visual-redesign-plan.md +0 -768
- package/thoughts/taras/plans/2026-03-04-fix-buildSystemPrompt-missing-fields.md +0 -77
- package/thoughts/taras/plans/2026-03-04-new-ui-missing-actions.md +0 -543
- package/thoughts/taras/plans/2026-03-06-one-time-scheduled-tasks.md +0 -373
- package/thoughts/taras/plans/2026-03-08-memory-self-improvement-enhancements.md +0 -512
- package/thoughts/taras/plans/2026-03-08-pi-mono-provider-implementation.md +0 -919
- package/thoughts/taras/plans/2026-03-09-templates-registry.md +0 -723
- package/thoughts/taras/plans/2026-03-10-task-working-directory.md +0 -371
- package/thoughts/taras/plans/2026-03-11-archil-per-agent-write-strategy.md +0 -621
- package/thoughts/taras/plans/2026-03-12-eliminate-inbox-route-to-tasks.md +0 -61
- package/thoughts/taras/plans/2026-03-12-slack-thread-followup-additive.md +0 -488
- package/thoughts/taras/plans/2026-03-13-slack-ai-improvements.md +0 -644
- package/thoughts/taras/plans/2026-03-16-route-wrapper-openapi.md +0 -636
- package/thoughts/taras/plans/2026-03-17-multi-api-config.md +0 -444
- package/thoughts/taras/plans/2026-03-18-agent-fs-integration.md +0 -591
- package/thoughts/taras/plans/2026-03-18-debug-db-explorer.md +0 -446
- package/thoughts/taras/plans/2026-03-18-workflow-redesign.md +0 -987
- package/thoughts/taras/plans/2026-03-19-compound-learnings.md +0 -403
- package/thoughts/taras/plans/2026-03-19-ticket-tracker-linear-integration.md +0 -860
- package/thoughts/taras/plans/2026-03-19-workflow-io-schemas-and-bugs.md +0 -899
- package/thoughts/taras/plans/2026-03-20-setup-cli-onboarding.md +0 -874
- package/thoughts/taras/plans/2026-03-20-workflow-structured-output-validation-workspace.md +0 -723
- package/thoughts/taras/research/2026-01-22-vercel-cli-integration.md +0 -287
- package/thoughts/taras/research/2026-01-27-excessive-polling-issue.md +0 -311
- package/thoughts/taras/research/2026-01-28-per-worker-claude-md.md +0 -383
- package/thoughts/taras/research/2026-01-28-sentry-cli-integration.md +0 -240
- package/thoughts/taras/research/2026-02-19-agent-native-swarm-architecture.md +0 -390
- package/thoughts/taras/research/2026-02-19-swarm-gaps-implementation.md +0 -594
- package/thoughts/taras/research/2026-02-25-dashboard-ui-design-best-practices.md +0 -825
- package/thoughts/taras/research/2026-02-26-task-detail-page-redesign.md +0 -393
- package/thoughts/taras/research/2026-03-03-new-ui-missing-actions.md +0 -168
- package/thoughts/taras/research/2026-03-05-pi-mono-provider-research.md +0 -230
- package/thoughts/taras/research/2026-03-06-workflow-engine-design.md +0 -445
- package/thoughts/taras/research/2026-03-08-drive-loop-concept.md +0 -375
- package/thoughts/taras/research/2026-03-08-pi-mono-deep-dive.md +0 -869
- package/thoughts/taras/research/2026-03-09-templates-registry.md +0 -373
- package/thoughts/taras/research/2026-03-10-agent-working-directory.md +0 -223
- package/thoughts/taras/research/2026-03-10-configurable-event-prompts.md +0 -339
- package/thoughts/taras/research/2026-03-11-archil-production-setup.md +0 -181
- package/thoughts/taras/research/2026-03-11-archil-shared-disk-write-strategies.md +0 -437
- package/thoughts/taras/research/2026-03-13-slack-ai-features.md +0 -258
- package/thoughts/taras/research/2026-03-16-openapi-docs-generation.md +0 -335
- package/thoughts/taras/research/2026-03-16-route-wrapper-openapi.md +0 -670
- package/thoughts/taras/research/2026-03-16-slack-thread-followups-e2e.md +0 -54
- package/thoughts/taras/research/2026-03-18-agent-fs-integration.md +0 -558
- package/thoughts/taras/research/2026-03-18-linear-integration-finalization.md +0 -526
- package/thoughts/taras/research/2026-03-18-workflow-redesign.md +0 -797
- package/thoughts/taras/research/2026-03-19-workflow-node-io-schemas-and-bugs.md +0 -563
- package/thoughts/taras/research/2026-03-19-workflow-structured-output-validation-workspace.md +0 -486
- package/thoughts/taras/research/2026-03-20-prompt-template-registry.md +0 -469
- 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`
|