@desplega.ai/agent-swarm 1.20.0 → 1.51.2
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 +271 -169
- package/openapi.json +5015 -0
- package/package.json +40 -7
- package/plugin/commands/close-issue.md +7 -3
- package/plugin/commands/create-pr.md +18 -12
- package/plugin/commands/implement-issue.md +7 -3
- package/plugin/commands/respond-github.md +8 -4
- package/plugin/commands/review-pr.md +44 -10
- package/plugin/commands/start-leader.md +1 -3
- package/plugin/commands/start-worker.md +1 -3
- package/plugin/commands/work-on-task.md +22 -3
- package/plugin/pi-skills/close-issue/SKILL.md +90 -0
- package/plugin/pi-skills/create-pr/SKILL.md +99 -0
- package/plugin/pi-skills/implement-issue/SKILL.md +135 -0
- package/plugin/pi-skills/investigate-sentry-issue/SKILL.md +138 -0
- package/plugin/pi-skills/respond-github/SKILL.md +98 -0
- package/plugin/pi-skills/review-offered-task/SKILL.md +45 -0
- package/plugin/pi-skills/review-pr/SKILL.md +261 -0
- package/plugin/pi-skills/start-leader/SKILL.md +121 -0
- package/plugin/pi-skills/start-worker/SKILL.md +60 -0
- package/plugin/pi-skills/swarm-chat/SKILL.md +82 -0
- package/plugin/pi-skills/todos/SKILL.md +66 -0
- package/plugin/pi-skills/work-on-task/SKILL.md +65 -0
- package/plugin/skills/artifacts/examples/approval-flow.ts +34 -0
- package/plugin/skills/artifacts/examples/hono-dashboard.ts +31 -0
- package/plugin/skills/artifacts/examples/multi-artifact.ts +20 -0
- package/plugin/skills/artifacts/examples/static-report.sh +17 -0
- package/plugin/skills/artifacts/skill.md +71 -0
- package/src/agentmail/app.ts +65 -0
- package/src/agentmail/handlers.ts +262 -0
- package/src/agentmail/index.ts +9 -0
- package/src/agentmail/templates.ts +111 -0
- package/src/agentmail/types.ts +51 -0
- package/src/artifact-sdk/browser-sdk.ts +30 -0
- package/src/artifact-sdk/index.ts +2 -0
- package/src/artifact-sdk/localtunnel.d.ts +20 -0
- package/src/artifact-sdk/port.ts +12 -0
- package/src/artifact-sdk/server.ts +156 -0
- package/src/artifact-sdk/tunnel.ts +19 -0
- package/src/be/chunking.ts +193 -0
- package/src/be/db-queries/oauth.ts +90 -0
- package/src/be/db-queries/tracker.ts +182 -0
- package/src/be/db.ts +3327 -784
- package/src/be/embedding.ts +80 -0
- package/src/be/migrations/001_initial.sql +409 -0
- package/src/be/migrations/002_one_time_schedules.sql +59 -0
- package/src/be/migrations/003_workflows.sql +51 -0
- package/src/be/migrations/004_workflow_source.sql +81 -0
- package/src/be/migrations/005_epic_next_steps.sql +2 -0
- package/src/be/migrations/006_vcs_provider.sql +94 -0
- package/src/be/migrations/007_task_dir.sql +2 -0
- package/src/be/migrations/008_workflow_redesign.sql +85 -0
- package/src/be/migrations/009_tracker_integration.sql +144 -0
- package/src/be/migrations/010_step_diagnostics.sql +1 -0
- package/src/be/migrations/011_step_next_port.sql +1 -0
- package/src/be/migrations/012_trigger_schema.sql +1 -0
- package/src/be/migrations/013_task_output_schema.sql +2 -0
- 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/runner.ts +188 -0
- package/src/be/seed.ts +62 -0
- package/src/cli.tsx +231 -299
- package/src/commands/artifact.ts +241 -0
- package/src/commands/onboard/compose-generator.ts +169 -0
- package/src/commands/onboard/env-generator.ts +79 -0
- package/src/commands/onboard/manifest.ts +37 -0
- package/src/commands/onboard/presets.ts +85 -0
- package/src/commands/onboard/service-names.ts +47 -0
- package/src/commands/onboard/steps/core-credentials.tsx +111 -0
- package/src/commands/onboard/steps/custom-templates.tsx +168 -0
- package/src/commands/onboard/steps/generate.tsx +154 -0
- package/src/commands/onboard/steps/harness-credentials.tsx +195 -0
- package/src/commands/onboard/steps/harness.tsx +21 -0
- package/src/commands/onboard/steps/health-check.tsx +171 -0
- package/src/commands/onboard/steps/integration-github.tsx +105 -0
- package/src/commands/onboard/steps/integration-gitlab.tsx +79 -0
- package/src/commands/onboard/steps/integration-menu.tsx +58 -0
- package/src/commands/onboard/steps/integration-sentry.tsx +79 -0
- package/src/commands/onboard/steps/integration-slack.tsx +165 -0
- package/src/commands/onboard/steps/post-connect.tsx +145 -0
- package/src/commands/onboard/steps/post-dashboard.tsx +34 -0
- package/src/commands/onboard/steps/post-task.tsx +103 -0
- package/src/commands/onboard/steps/prereq-check.tsx +178 -0
- package/src/commands/onboard/steps/review.tsx +82 -0
- package/src/commands/onboard/steps/start.tsx +97 -0
- package/src/commands/onboard/templates.ts +34 -0
- package/src/commands/onboard/types.ts +259 -0
- package/src/commands/onboard.tsx +425 -0
- package/src/commands/runner.ts +1540 -630
- package/src/commands/setup.tsx +23 -38
- package/src/commands/shared/client-config.ts +41 -0
- package/src/commands/templates.ts +172 -0
- package/src/github/app.ts +8 -0
- package/src/github/handlers.ts +384 -151
- package/src/github/index.ts +1 -0
- 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/github/types.ts +1 -0
- package/src/gitlab/auth.ts +63 -0
- package/src/gitlab/handlers.ts +368 -0
- package/src/gitlab/index.ts +19 -0
- package/src/gitlab/reactions.ts +104 -0
- package/src/gitlab/templates.ts +140 -0
- package/src/gitlab/types.ts +130 -0
- package/src/heartbeat/heartbeat.ts +434 -0
- package/src/heartbeat/index.ts +1 -0
- package/src/heartbeat/templates.ts +30 -0
- package/src/hooks/hook.ts +555 -4
- package/src/hooks/tool-loop-detection.test.ts +158 -0
- package/src/hooks/tool-loop-detection.ts +167 -0
- package/src/http/active-sessions.ts +199 -0
- package/src/http/agents.ts +328 -0
- package/src/http/config.ts +191 -0
- package/src/http/core.ts +309 -0
- package/src/http/db-query.ts +91 -0
- package/src/http/ecosystem.ts +63 -0
- package/src/http/epics.ts +460 -0
- package/src/http/index.ts +216 -0
- package/src/http/mcp.ts +77 -0
- package/src/http/memory.ts +168 -0
- package/src/http/openapi.ts +109 -0
- package/src/http/poll.ts +299 -0
- package/src/http/prompt-templates.ts +412 -0
- package/src/http/repos.ts +195 -0
- package/src/http/route-def.ts +123 -0
- package/src/http/schedules.ts +426 -0
- package/src/http/session-data.ts +241 -0
- package/src/http/stats.ts +174 -0
- package/src/http/tasks.ts +468 -0
- package/src/http/trackers/index.ts +10 -0
- package/src/http/trackers/linear.ts +187 -0
- package/src/http/types.ts +12 -0
- package/src/http/utils.ts +87 -0
- package/src/http/webhooks.ts +432 -0
- package/src/http/workflows.ts +530 -0
- package/src/http.ts +1 -1890
- package/src/linear/README.md +65 -0
- package/src/linear/app.ts +48 -0
- package/src/linear/client.ts +18 -0
- package/src/linear/index.ts +1 -0
- package/src/linear/oauth.ts +35 -0
- package/src/linear/outbound.ts +212 -0
- package/src/linear/sync.ts +567 -0
- package/src/linear/templates.ts +47 -0
- package/src/linear/types.ts +7 -0
- package/src/linear/webhook.ts +104 -0
- package/src/oauth/README.md +66 -0
- package/src/oauth/index.ts +6 -0
- package/src/oauth/wrapper.ts +204 -0
- package/src/prompts/base-prompt.ts +150 -265
- package/src/prompts/defaults.ts +196 -0
- 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 +442 -0
- package/src/providers/index.ts +24 -0
- package/src/providers/pi-mono-adapter.ts +442 -0
- package/src/providers/pi-mono-extension.ts +624 -0
- package/src/providers/pi-mono-mcp-client.ts +124 -0
- package/src/providers/types.ts +75 -0
- package/src/scheduler/scheduler.test.ts +2 -0
- package/src/scheduler/scheduler.ts +231 -40
- package/src/server.ts +97 -6
- package/src/slack/HEURISTICS.md +105 -0
- package/src/slack/actions.ts +133 -0
- package/src/slack/app.ts +7 -0
- package/src/slack/assistant.ts +118 -0
- package/src/slack/blocks.ts +233 -0
- package/src/slack/channel-activity.ts +177 -0
- package/src/slack/commands.ts +31 -17
- package/src/slack/files.ts +1 -1
- package/src/slack/handlers.test.ts +114 -1
- package/src/slack/handlers.ts +230 -55
- package/src/slack/responses.ts +120 -67
- package/src/slack/router.ts +17 -99
- package/src/slack/templates.ts +55 -0
- package/src/slack/thread-buffer.ts +213 -0
- package/src/slack/watcher.ts +119 -4
- package/src/tests/agent-activity.test.ts +247 -0
- package/src/tests/agentmail-filters.test.ts +97 -0
- package/src/tests/artifact-sdk.test.ts +800 -0
- package/src/tests/base-prompt.test.ts +264 -0
- package/src/tests/build-pi-skills.test.ts +127 -0
- package/src/tests/channel-activity.test.ts +363 -0
- package/src/tests/claude-adapter.test.ts +126 -0
- package/src/tests/context-versioning.test.ts +425 -0
- package/src/tests/db-queries-oauth.test.ts +197 -0
- package/src/tests/db-queries-tracker.test.ts +230 -0
- package/src/tests/epics.test.ts +3 -3
- package/src/tests/error-tracker.test.ts +368 -0
- package/src/tests/fetch-resolved-env.test.ts +167 -0
- package/src/tests/generate-default-claude-md.test.ts +9 -1
- package/src/tests/generate-identity-templates.test.ts +124 -0
- package/src/tests/gitlab-auth.test.ts +109 -0
- package/src/tests/gitlab-handlers.test.ts +691 -0
- package/src/tests/gitlab-vcs-db.test.ts +177 -0
- package/src/tests/heartbeat.test.ts +364 -0
- package/src/tests/http-api-integration.test.ts +1698 -0
- package/src/tests/linear-outbound-sync.test.ts +200 -0
- package/src/tests/linear-webhook.test.ts +406 -0
- package/src/tests/match-route.test.ts +187 -0
- package/src/tests/memory.test.ts +737 -0
- package/src/tests/migration-runner-regressions.test.ts +86 -0
- package/src/tests/model-control.test.ts +338 -0
- package/src/tests/oauth-wrapper.test.ts +147 -0
- package/src/tests/onboard-compose.test.ts +138 -0
- package/src/tests/onboard-env.test.ts +174 -0
- package/src/tests/onboard-manifest.test.ts +137 -0
- package/src/tests/pi-mono-adapter.test.ts +234 -0
- package/src/tests/pool-session-logs.test.ts +199 -0
- package/src/tests/progress-dedup.test.ts +98 -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/provider-adapter.test.ts +122 -0
- package/src/tests/provider-command-format.test.ts +98 -0
- package/src/tests/reload-config.test.ts +170 -0
- package/src/tests/runner-polling-api.test.ts +25 -20
- package/src/tests/scheduled-tasks.test.ts +104 -0
- package/src/tests/scheduler-backoff.test.ts +166 -0
- package/src/tests/self-improvement.test.ts +541 -0
- package/src/tests/session-attach.test.ts +536 -0
- package/src/tests/session-costs.test.ts +267 -1
- package/src/tests/slack-actions.test.ts +133 -0
- package/src/tests/slack-assistant.test.ts +136 -0
- package/src/tests/slack-blocks.test.ts +246 -0
- package/src/tests/slack-metadata-inheritance.test.ts +243 -0
- package/src/tests/slack-queue-offline.test.ts +174 -0
- package/src/tests/slack-router.test.ts +181 -0
- package/src/tests/slack-thread-buffer.test.ts +305 -0
- package/src/tests/slack-thread-followups.test.ts +298 -0
- package/src/tests/slack-watcher.test.ts +101 -0
- package/src/tests/structured-output.test.ts +307 -0
- package/src/tests/swarm-repos.test.ts +198 -0
- package/src/tests/task-cancellation.test.ts +6 -4
- package/src/tests/task-working-dir.test.ts +176 -0
- package/src/tests/template-fetch.test.ts +490 -0
- package/src/tests/tool-annotations.test.ts +371 -0
- package/src/tests/tracker-tools.test.ts +184 -0
- package/src/tests/update-profile-agentid.test.ts +248 -0
- package/src/tests/update-profile-api.test.ts +143 -3
- package/src/tests/update-profile-auth.test.ts +195 -0
- package/src/tests/validation-adapters.test.ts +86 -0
- package/src/tests/vcs-provider.test.ts +27 -0
- package/src/tests/workflow-agent-task.test.ts +196 -0
- package/src/tests/workflow-async-v2.test.ts +508 -0
- package/src/tests/workflow-convergence.test.ts +541 -0
- package/src/tests/workflow-definition-validation.test.ts +366 -0
- package/src/tests/workflow-engine-v2.test.ts +691 -0
- package/src/tests/workflow-executors.test.ts +736 -0
- package/src/tests/workflow-http-v2.test.ts +599 -0
- package/src/tests/workflow-integration-io.test.ts +902 -0
- package/src/tests/workflow-io-schemas.test.ts +624 -0
- package/src/tests/workflow-registry.test.ts +592 -0
- package/src/tests/workflow-retry-v2.test.ts +401 -0
- package/src/tests/workflow-retry-validation.test.ts +282 -0
- package/src/tests/workflow-schedule-trigger.test.ts +104 -0
- package/src/tests/workflow-template.test.ts +288 -0
- package/src/tests/workflow-trigger-schema.test.ts +359 -0
- package/src/tests/workflow-triggers-v2.test.ts +264 -0
- package/src/tests/workflow-versions.test.ts +208 -0
- package/src/tests/workflow-workspace.test.ts +272 -0
- package/src/tests/x402-client.test.ts +117 -0
- package/src/tests/x402-config.test.ts +182 -0
- package/src/tests/x402-spending-tracker.test.ts +185 -0
- package/src/tools/cancel-task.ts +2 -0
- package/src/tools/context-diff.ts +171 -0
- package/src/tools/context-history.ts +138 -0
- package/src/tools/create-channel.ts +1 -0
- package/src/tools/db-query.ts +78 -0
- package/src/tools/delete-channel.ts +132 -0
- package/src/tools/epics/assign-task-to-epic.ts +1 -0
- package/src/tools/epics/create-epic.ts +3 -2
- package/src/tools/epics/delete-epic.ts +2 -0
- package/src/tools/epics/get-epic-details.ts +2 -0
- package/src/tools/epics/list-epics.ts +2 -0
- package/src/tools/epics/unassign-task-from-epic.ts +1 -0
- package/src/tools/epics/update-epic.ts +7 -4
- package/src/tools/get-swarm.ts +2 -0
- package/src/tools/get-task-details.ts +2 -0
- package/src/tools/get-tasks.ts +27 -1
- package/src/tools/inject-learning.ts +106 -0
- package/src/tools/join-swarm.ts +17 -7
- package/src/tools/list-channels.ts +2 -0
- package/src/tools/list-services.ts +2 -0
- package/src/tools/memory-get.ts +56 -0
- package/src/tools/memory-search.ts +131 -0
- package/src/tools/my-agent-info.ts +2 -0
- package/src/tools/poll-task.ts +2 -20
- package/src/tools/post-message.ts +1 -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/read-messages.ts +2 -0
- package/src/tools/register-agentmail-inbox.ts +166 -0
- package/src/tools/register-service.ts +2 -0
- package/src/tools/schedules/create-schedule.ts +134 -24
- package/src/tools/schedules/delete-schedule.ts +2 -0
- package/src/tools/schedules/list-schedules.ts +20 -4
- package/src/tools/schedules/run-schedule-now.ts +1 -0
- package/src/tools/schedules/update-schedule.ts +49 -17
- package/src/tools/send-task.ts +132 -10
- package/src/tools/slack-download-file.ts +4 -2
- package/src/tools/slack-list-channels.ts +2 -0
- package/src/tools/slack-post.ts +2 -0
- package/src/tools/slack-read.ts +2 -0
- package/src/tools/slack-reply.ts +2 -0
- package/src/tools/slack-upload-file.ts +2 -0
- package/src/tools/store-progress.ts +205 -4
- package/src/tools/swarm-config/delete-config.ts +87 -0
- package/src/tools/swarm-config/get-config.ts +108 -0
- package/src/tools/swarm-config/index.ts +4 -0
- package/src/tools/swarm-config/list-config.ts +99 -0
- package/src/tools/swarm-config/set-config.ts +118 -0
- package/src/tools/task-action.ts +50 -5
- package/src/tools/task-dedup.ts +97 -0
- package/src/tools/templates.ts +53 -0
- package/src/tools/tool-config.ts +124 -0
- package/src/tools/tracker/index.ts +6 -0
- package/src/tools/tracker/tracker-link-epic.ts +64 -0
- package/src/tools/tracker/tracker-link-task.ts +64 -0
- package/src/tools/tracker/tracker-map-agent.ts +57 -0
- package/src/tools/tracker/tracker-status.ts +56 -0
- package/src/tools/tracker/tracker-sync-status.ts +42 -0
- package/src/tools/tracker/tracker-unlink.ts +41 -0
- package/src/tools/unregister-service.ts +2 -0
- package/src/tools/update-profile.ts +172 -17
- package/src/tools/update-service-status.ts +2 -0
- package/src/tools/utils.ts +10 -1
- package/src/tools/workflows/create-workflow.ts +129 -0
- package/src/tools/workflows/delete-workflow.ts +42 -0
- package/src/tools/workflows/get-workflow-run.ts +59 -0
- package/src/tools/workflows/get-workflow.ts +53 -0
- package/src/tools/workflows/index.ts +9 -0
- package/src/tools/workflows/list-workflow-runs.ts +48 -0
- package/src/tools/workflows/list-workflows.ts +42 -0
- package/src/tools/workflows/retry-workflow-run.ts +40 -0
- package/src/tools/workflows/trigger-workflow.ts +96 -0
- package/src/tools/workflows/update-workflow.ts +133 -0
- package/src/tracker/types.ts +51 -0
- package/src/types.ts +530 -14
- package/src/utils/credentials.test.ts +156 -0
- package/src/utils/credentials.ts +50 -0
- package/src/utils/error-tracker.ts +190 -0
- package/src/vcs/index.ts +15 -0
- package/src/vcs/types.ts +5 -0
- package/src/workflows/checkpoint.ts +121 -0
- package/src/workflows/cooldown.ts +28 -0
- package/src/workflows/definition.ts +235 -0
- package/src/workflows/engine.ts +580 -0
- package/src/workflows/event-bus.ts +29 -0
- package/src/workflows/executors/agent-task.ts +103 -0
- package/src/workflows/executors/base.ts +86 -0
- package/src/workflows/executors/code-match.ts +88 -0
- package/src/workflows/executors/index.ts +16 -0
- package/src/workflows/executors/notify.ts +93 -0
- package/src/workflows/executors/property-match.ts +104 -0
- package/src/workflows/executors/raw-llm.ts +83 -0
- package/src/workflows/executors/registry.ts +76 -0
- package/src/workflows/executors/script.ts +103 -0
- package/src/workflows/executors/validate.ts +215 -0
- package/src/workflows/executors/vcs.ts +58 -0
- package/src/workflows/index.ts +61 -0
- package/src/workflows/input.ts +46 -0
- package/src/workflows/json-schema-validator.ts +118 -0
- package/src/workflows/recovery.ts +139 -0
- package/src/workflows/resume.ts +229 -0
- package/src/workflows/retry-poller.ts +216 -0
- package/src/workflows/template.ts +74 -0
- package/src/workflows/templates.ts +86 -0
- package/src/workflows/triggers.ts +124 -0
- package/src/workflows/validation.ts +104 -0
- package/src/workflows/version.ts +44 -0
- package/src/x402/cli.ts +140 -0
- package/src/x402/client.ts +192 -0
- package/src/x402/config.ts +131 -0
- package/src/x402/index.ts +37 -0
- package/src/x402/openfort-signer.ts +83 -0
- package/src/x402/spending-tracker.ts +109 -0
- package/templates/official/coder/CLAUDE.md +49 -0
- package/templates/official/coder/IDENTITY.md +28 -0
- package/templates/official/coder/SOUL.md +43 -0
- package/templates/official/coder/TOOLS.md +40 -0
- package/templates/official/coder/config.json +23 -0
- package/templates/official/coder/start-up.sh +23 -0
- package/templates/official/content-reviewer/CLAUDE.md +68 -0
- package/templates/official/content-reviewer/IDENTITY.md +28 -0
- package/templates/official/content-reviewer/SOUL.md +44 -0
- package/templates/official/content-reviewer/TOOLS.md +37 -0
- package/templates/official/content-reviewer/config.json +23 -0
- package/templates/official/content-reviewer/start-up.sh +23 -0
- package/templates/official/content-strategist/CLAUDE.md +63 -0
- package/templates/official/content-strategist/IDENTITY.md +33 -0
- package/templates/official/content-strategist/SOUL.md +48 -0
- package/templates/official/content-strategist/TOOLS.md +47 -0
- package/templates/official/content-strategist/config.json +23 -0
- package/templates/official/content-strategist/start-up.sh +23 -0
- package/templates/official/content-writer/CLAUDE.md +72 -0
- package/templates/official/content-writer/IDENTITY.md +30 -0
- package/templates/official/content-writer/SOUL.md +46 -0
- package/templates/official/content-writer/TOOLS.md +44 -0
- package/templates/official/content-writer/config.json +23 -0
- package/templates/official/content-writer/start-up.sh +23 -0
- package/templates/official/forward-deployed-engineer/CLAUDE.md +54 -0
- package/templates/official/forward-deployed-engineer/IDENTITY.md +37 -0
- package/templates/official/forward-deployed-engineer/SOUL.md +55 -0
- package/templates/official/forward-deployed-engineer/config.json +21 -0
- package/templates/official/lead/CLAUDE.md +33 -0
- package/templates/official/lead/IDENTITY.md +36 -0
- package/templates/official/lead/SOUL.md +51 -0
- package/templates/official/lead/config.json +22 -0
- package/templates/official/researcher/CLAUDE.md +46 -0
- package/templates/official/researcher/IDENTITY.md +28 -0
- package/templates/official/researcher/SOUL.md +43 -0
- package/templates/official/researcher/config.json +21 -0
- package/templates/official/reviewer/CLAUDE.md +63 -0
- package/templates/official/reviewer/IDENTITY.md +28 -0
- package/templates/official/reviewer/SOUL.md +45 -0
- package/templates/official/reviewer/config.json +21 -0
- package/templates/official/tester/CLAUDE.md +53 -0
- package/templates/official/tester/IDENTITY.md +28 -0
- package/templates/official/tester/SOUL.md +55 -0
- package/templates/official/tester/config.json +21 -0
- package/templates/schema.ts +35 -0
- package/.claude/settings.local.json +0 -115
- package/.dockerignore +0 -61
- package/.editorconfig +0 -15
- package/.env.docker.example +0 -39
- package/.env.example +0 -40
- package/.github/workflows/ci.yml +0 -76
- package/.github/workflows/docker-and-deploy.yml +0 -117
- package/.wts-config.json +0 -4
- package/.wts-setup.ts +0 -102
- package/CLAUDE.md +0 -104
- package/CONTRIBUTING.md +0 -270
- package/DEPLOYMENT.md +0 -605
- package/Dockerfile +0 -57
- package/Dockerfile.worker +0 -157
- package/FAQ.md +0 -19
- package/MCP.md +0 -406
- package/UI.md +0 -40
- 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/docker-compose.example.yml +0 -159
- package/docker-entrypoint.sh +0 -352
- package/ecosystem.config.cjs +0 -66
- package/plugin/README.md +0 -1
- package/plugin/hooks/hooks.json +0 -71
- package/pyproject.toml +0 -9
- package/scripts/generate-mcp-docs.ts +0 -415
- package/slack-manifest.json +0 -71
- package/src/tests/get-inbox-message.test.ts +0 -145
- package/src/tools/get-inbox-message.ts +0 -89
- package/src/tools/inbox-delegate.ts +0 -113
- 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/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/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/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/tsconfig.json +0 -37
- package/ui/CLAUDE.md +0 -49
- package/ui/bun.lock +0 -771
- package/ui/index.html +0 -22
- package/ui/package-lock.json +0 -5290
- package/ui/package.json +0 -33
- package/ui/pnpm-lock.yaml +0 -3341
- package/ui/postcss.config.js +0 -6
- package/ui/public/logo.png +0 -0
- package/ui/src/App.tsx +0 -63
- package/ui/src/components/ActivityFeed.tsx +0 -440
- package/ui/src/components/AgentDetailPanel.tsx +0 -733
- package/ui/src/components/AgentsPanel.tsx +0 -815
- package/ui/src/components/ChatPanel.tsx +0 -1920
- package/ui/src/components/ConfigModal.tsx +0 -253
- package/ui/src/components/Dashboard.tsx +0 -832
- package/ui/src/components/EditAgentProfileModal.tsx +0 -433
- package/ui/src/components/EpicDetailPage.tsx +0 -741
- package/ui/src/components/EpicsPanel.tsx +0 -566
- package/ui/src/components/Header.tsx +0 -160
- package/ui/src/components/JsonViewer.tsx +0 -171
- package/ui/src/components/ScheduledTaskDetailPanel.tsx +0 -517
- package/ui/src/components/ScheduledTasksPanel.tsx +0 -639
- package/ui/src/components/ServicesPanel.tsx +0 -622
- package/ui/src/components/SessionLogPanel.tsx +0 -1219
- package/ui/src/components/StatsBar.tsx +0 -321
- package/ui/src/components/StatusBadge.tsx +0 -168
- package/ui/src/components/TaskDetailPanel.tsx +0 -903
- package/ui/src/components/TasksPanel.tsx +0 -614
- package/ui/src/components/UsageCharts.tsx +0 -216
- package/ui/src/components/UsageTab.tsx +0 -394
- package/ui/src/hooks/queries.ts +0 -353
- package/ui/src/hooks/useAutoScroll.ts +0 -83
- package/ui/src/index.css +0 -257
- package/ui/src/lib/api.ts +0 -268
- package/ui/src/lib/config.ts +0 -35
- package/ui/src/lib/contentPreview.ts +0 -208
- package/ui/src/lib/theme.ts +0 -214
- package/ui/src/lib/utils.ts +0 -88
- package/ui/src/main.tsx +0 -28
- package/ui/src/types/api.ts +0 -323
- package/ui/src/vite-env.d.ts +0 -1
- package/ui/tailwind.config.js +0 -37
- package/ui/tsconfig.json +0 -31
- package/ui/vite.config.ts +0 -35
- /package/{thoughts/shared/plans → templates/community}/.gitkeep +0 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Linear Integration
|
|
2
|
+
|
|
3
|
+
Bidirectional sync between Agent Swarm and Linear. Webhook-driven inbound (Linear issues become swarm tasks) and event-bus-driven outbound (task completion/failure posts comments back to Linear).
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
1. **Create OAuth Application** at `linear.app/settings/api/applications`
|
|
8
|
+
2. **Set callback URL** to your server's `/api/trackers/linear/callback`
|
|
9
|
+
- Local: `http://localhost:3013/api/trackers/linear/callback`
|
|
10
|
+
- Production: `https://your-domain.com/api/trackers/linear/callback`
|
|
11
|
+
3. **Set Actor** to "Application" (enables `actor=app` in OAuth flow)
|
|
12
|
+
4. **Enable webhooks** and select "Issue" events in the app settings
|
|
13
|
+
5. **Copy credentials** to `.env`:
|
|
14
|
+
```bash
|
|
15
|
+
LINEAR_CLIENT_ID=<from app settings>
|
|
16
|
+
LINEAR_CLIENT_SECRET=<shown once on creation>
|
|
17
|
+
LINEAR_SIGNING_SECRET=<from webhook settings>
|
|
18
|
+
# LINEAR_TEAM_ID=<optional: scope to a specific team>
|
|
19
|
+
```
|
|
20
|
+
6. **Start server**: `bun run start:http`
|
|
21
|
+
7. **Run OAuth flow**: visit `http://localhost:3013/api/trackers/linear/authorize` in your browser
|
|
22
|
+
8. **Verify connection**:
|
|
23
|
+
```bash
|
|
24
|
+
curl -H "Authorization: Bearer $API_KEY" http://localhost:3013/api/trackers/linear/status
|
|
25
|
+
```
|
|
26
|
+
9. **Local webhook testing**: use ngrok or cloudflared to create a tunnel, then configure the public URL as the webhook URL in your Linear app settings:
|
|
27
|
+
```bash
|
|
28
|
+
ngrok http 3013
|
|
29
|
+
# Then set webhook URL in Linear to: https://<ngrok-id>.ngrok.io/api/trackers/linear/webhook
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Scopes
|
|
33
|
+
|
|
34
|
+
The OAuth flow requests these scopes:
|
|
35
|
+
|
|
36
|
+
| Scope | Purpose |
|
|
37
|
+
|-------|---------|
|
|
38
|
+
| `read` | Read workspace data (teams, issues, users) |
|
|
39
|
+
| `write` | Update issues and projects |
|
|
40
|
+
| `issues:create` | Create new issues |
|
|
41
|
+
| `comments:create` | Add comments to issues |
|
|
42
|
+
| `app:assignable` | App appears in the assignee dropdown |
|
|
43
|
+
| `app:mentionable` | App can be @mentioned in issues and comments |
|
|
44
|
+
|
|
45
|
+
## Architecture
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
src/linear/
|
|
49
|
+
app.ts # Initialization, env config, route registration
|
|
50
|
+
client.ts # Linear GraphQL API client wrapper
|
|
51
|
+
oauth.ts # OAuth route handlers (authorize, callback, status)
|
|
52
|
+
webhook.ts # Inbound webhook handler (issue events -> swarm tasks)
|
|
53
|
+
outbound.ts # Outbound sync (event bus -> Linear comments)
|
|
54
|
+
sync.ts # Sync helpers (status mapping, etc.)
|
|
55
|
+
types.ts # TypeScript types for Linear payloads
|
|
56
|
+
index.ts # Public exports
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Key design decisions:**
|
|
60
|
+
|
|
61
|
+
- **Generic OAuth layer** (`src/oauth/`, `oauth_apps`, `oauth_tokens` tables) serves any provider. Linear-specific code only lives in `src/linear/`.
|
|
62
|
+
- **Generic tracker tables** (`tracker_sync`, `tracker_agent_mapping`) serve any tracker. The `provider` column distinguishes Linear from future integrations.
|
|
63
|
+
- **Inbound**: Webhook events create swarm tasks via `createTaskExtended(source: "linear")`. The webhook handler verifies HMAC signatures using `LINEAR_SIGNING_SECRET`.
|
|
64
|
+
- **Outbound**: Subscribes to the workflow event bus for `task.completed` and `task.failed` events. Posts completion/failure comments back to the linked Linear issue.
|
|
65
|
+
- **Loop prevention**: A 5-second window prevents outbound sync from firing immediately after an inbound webhook (checked via `lastSyncOrigin` + `lastSyncedAt` on the tracker_sync row).
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { upsertOAuthApp } from "../be/db-queries/oauth";
|
|
2
|
+
import { initLinearOutboundSync, teardownLinearOutboundSync } from "./outbound";
|
|
3
|
+
|
|
4
|
+
let initialized = false;
|
|
5
|
+
|
|
6
|
+
export function isLinearEnabled(): boolean {
|
|
7
|
+
const disabled = process.env.LINEAR_DISABLE;
|
|
8
|
+
if (disabled === "true" || disabled === "1") return false;
|
|
9
|
+
const enabled = process.env.LINEAR_ENABLED;
|
|
10
|
+
if (enabled === "false" || enabled === "0") return false;
|
|
11
|
+
return !!process.env.LINEAR_CLIENT_ID;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function resetLinear(): void {
|
|
15
|
+
teardownLinearOutboundSync();
|
|
16
|
+
initialized = false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function initLinear(): boolean {
|
|
20
|
+
if (initialized) return isLinearEnabled();
|
|
21
|
+
initialized = true;
|
|
22
|
+
|
|
23
|
+
if (!isLinearEnabled()) {
|
|
24
|
+
console.log("[Linear] Integration disabled or LINEAR_CLIENT_ID not set");
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const clientId = process.env.LINEAR_CLIENT_ID!;
|
|
29
|
+
const clientSecret = process.env.LINEAR_CLIENT_SECRET ?? "";
|
|
30
|
+
const redirectUri =
|
|
31
|
+
process.env.LINEAR_REDIRECT_URI ??
|
|
32
|
+
`http://localhost:${process.env.PORT || "3013"}/api/trackers/linear/callback`;
|
|
33
|
+
|
|
34
|
+
upsertOAuthApp("linear", {
|
|
35
|
+
clientId,
|
|
36
|
+
clientSecret,
|
|
37
|
+
authorizeUrl: "https://linear.app/oauth/authorize",
|
|
38
|
+
tokenUrl: "https://api.linear.app/oauth/token",
|
|
39
|
+
redirectUri,
|
|
40
|
+
scopes: "read,write,issues:create,comments:create,app:assignable,app:mentionable",
|
|
41
|
+
metadata: JSON.stringify({ actor: "app" }),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
initLinearOutboundSync();
|
|
45
|
+
|
|
46
|
+
console.log("[Linear] Integration initialized");
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { LinearClient } from "@linear/sdk";
|
|
2
|
+
import { getOAuthTokens } from "../be/db-queries/oauth";
|
|
3
|
+
|
|
4
|
+
let linearClient: LinearClient | null = null;
|
|
5
|
+
|
|
6
|
+
export function getLinearClient(): LinearClient | null {
|
|
7
|
+
const tokens = getOAuthTokens("linear");
|
|
8
|
+
if (!tokens) return null;
|
|
9
|
+
|
|
10
|
+
if (!linearClient) {
|
|
11
|
+
linearClient = new LinearClient({ accessToken: tokens.accessToken });
|
|
12
|
+
}
|
|
13
|
+
return linearClient;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function resetLinearClient(): void {
|
|
17
|
+
linearClient = null;
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { initLinear, isLinearEnabled, resetLinear } from "./app";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { getOAuthApp } from "../be/db-queries/oauth";
|
|
2
|
+
import { buildAuthorizationUrl, exchangeCode, type OAuthProviderConfig } from "../oauth/wrapper";
|
|
3
|
+
|
|
4
|
+
export function getLinearOAuthConfig(): OAuthProviderConfig | null {
|
|
5
|
+
const app = getOAuthApp("linear");
|
|
6
|
+
if (!app) return null;
|
|
7
|
+
|
|
8
|
+
const metadata = JSON.parse(app.metadata || "{}");
|
|
9
|
+
return {
|
|
10
|
+
provider: "linear",
|
|
11
|
+
clientId: app.clientId,
|
|
12
|
+
clientSecret: app.clientSecret,
|
|
13
|
+
authorizeUrl: app.authorizeUrl,
|
|
14
|
+
tokenUrl: app.tokenUrl,
|
|
15
|
+
redirectUri: app.redirectUri,
|
|
16
|
+
scopes: app.scopes.split(","),
|
|
17
|
+
extraParams: metadata.actor ? { actor: metadata.actor } : {},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function getLinearAuthorizationUrl(): Promise<string | null> {
|
|
22
|
+
const config = getLinearOAuthConfig();
|
|
23
|
+
if (!config) return null;
|
|
24
|
+
const result = await buildAuthorizationUrl(config);
|
|
25
|
+
return result.url;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function handleLinearCallback(
|
|
29
|
+
code: string,
|
|
30
|
+
state: string,
|
|
31
|
+
): Promise<{ accessToken: string; refreshToken?: string; expiresIn?: number; scope?: string }> {
|
|
32
|
+
const config = getLinearOAuthConfig();
|
|
33
|
+
if (!config) throw new Error("Linear OAuth not configured");
|
|
34
|
+
return exchangeCode(config, code, state);
|
|
35
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { getTrackerSync, updateTrackerSync } from "../be/db-queries/tracker";
|
|
2
|
+
import { workflowEventBus } from "../workflows/event-bus";
|
|
3
|
+
import { getLinearClient } from "./client";
|
|
4
|
+
import {
|
|
5
|
+
endAgentSession,
|
|
6
|
+
postAgentSessionAction,
|
|
7
|
+
postAgentSessionThought,
|
|
8
|
+
taskSessionMap,
|
|
9
|
+
} from "./sync";
|
|
10
|
+
|
|
11
|
+
let subscribed = false;
|
|
12
|
+
|
|
13
|
+
const LOOP_PREVENTION_WINDOW_MS = 5_000;
|
|
14
|
+
|
|
15
|
+
export function initLinearOutboundSync(): void {
|
|
16
|
+
if (subscribed) return;
|
|
17
|
+
subscribed = true;
|
|
18
|
+
|
|
19
|
+
workflowEventBus.on("task.created", handleTaskCreated);
|
|
20
|
+
workflowEventBus.on("task.completed", handleTaskCompleted);
|
|
21
|
+
workflowEventBus.on("task.failed", handleTaskFailed);
|
|
22
|
+
workflowEventBus.on("task.cancelled", handleTaskCancelled);
|
|
23
|
+
workflowEventBus.on("task.progress", handleTaskProgress);
|
|
24
|
+
console.log("[Linear] Outbound sync subscribed to event bus");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function teardownLinearOutboundSync(): void {
|
|
28
|
+
if (!subscribed) return;
|
|
29
|
+
subscribed = false;
|
|
30
|
+
|
|
31
|
+
workflowEventBus.off("task.created", handleTaskCreated);
|
|
32
|
+
workflowEventBus.off("task.completed", handleTaskCompleted);
|
|
33
|
+
workflowEventBus.off("task.failed", handleTaskFailed);
|
|
34
|
+
workflowEventBus.off("task.cancelled", handleTaskCancelled);
|
|
35
|
+
workflowEventBus.off("task.progress", handleTaskProgress);
|
|
36
|
+
console.log("[Linear] Outbound sync unsubscribed from event bus");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function handleTaskCreated(data: unknown): Promise<void> {
|
|
40
|
+
const { taskId, source } = data as { taskId: string; source?: string };
|
|
41
|
+
if (!taskId) return;
|
|
42
|
+
|
|
43
|
+
// Only post action activities for Linear-sourced tasks that have an AgentSession
|
|
44
|
+
if (source !== "linear") return;
|
|
45
|
+
|
|
46
|
+
const sessionId = taskSessionMap.get(taskId);
|
|
47
|
+
if (!sessionId) return;
|
|
48
|
+
|
|
49
|
+
postAgentSessionAction(sessionId, "Processing", `Task ${taskId} assigned to agent`).catch(
|
|
50
|
+
(err) => {
|
|
51
|
+
console.error(`[Linear Outbound] Failed to post action activity for task ${taskId}:`, err);
|
|
52
|
+
},
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function handleTaskProgress(data: unknown): Promise<void> {
|
|
57
|
+
const { taskId, progress } = data as { taskId: string; progress?: string };
|
|
58
|
+
if (!taskId || !progress) return;
|
|
59
|
+
|
|
60
|
+
const sessionId = taskSessionMap.get(taskId);
|
|
61
|
+
if (!sessionId) return;
|
|
62
|
+
|
|
63
|
+
postAgentSessionThought(sessionId, progress).catch((err) => {
|
|
64
|
+
console.error(`[Linear Outbound] Failed to post progress thought for task ${taskId}:`, err);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function handleTaskCompleted(data: unknown): Promise<void> {
|
|
69
|
+
const { taskId, output } = data as { taskId: string; output?: string };
|
|
70
|
+
if (!taskId) return;
|
|
71
|
+
|
|
72
|
+
const sync = getTrackerSync("linear", "task", taskId);
|
|
73
|
+
if (!sync) return;
|
|
74
|
+
|
|
75
|
+
if (shouldSkipForLoopPrevention(sync)) return;
|
|
76
|
+
|
|
77
|
+
const sessionId = taskSessionMap.get(taskId);
|
|
78
|
+
const body = output ? `Task completed.\n\n${output.slice(0, 2000)}` : "Task completed.";
|
|
79
|
+
|
|
80
|
+
// Prefer AgentSession activity (shows in the agent panel) over issue comment (avoids duplication)
|
|
81
|
+
if (sessionId) {
|
|
82
|
+
endAgentSession(sessionId, body, "response").catch((err) => {
|
|
83
|
+
console.error(`[Linear Outbound] Failed to end AgentSession for task ${taskId}:`, err);
|
|
84
|
+
});
|
|
85
|
+
taskSessionMap.delete(taskId);
|
|
86
|
+
console.log(`[Linear Outbound] Posted completion response to AgentSession for task ${taskId}`);
|
|
87
|
+
} else {
|
|
88
|
+
// No session — fall back to issue comment
|
|
89
|
+
try {
|
|
90
|
+
const client = getLinearClient();
|
|
91
|
+
if (!client) {
|
|
92
|
+
console.log("[Linear Outbound] No Linear client available, skipping sync for", taskId);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const comment = output
|
|
96
|
+
? `Task completed by swarm agent.\n\nOutput:\n${output.slice(0, 2000)}`
|
|
97
|
+
: "Task completed by swarm agent.";
|
|
98
|
+
await client.createComment({ issueId: sync.externalId, body: comment });
|
|
99
|
+
console.log(`[Linear Outbound] Posted completion comment for task ${taskId}`);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error(
|
|
102
|
+
`[Linear Outbound] Failed to sync task completion for ${taskId}:`,
|
|
103
|
+
error instanceof Error ? error.message : error,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
updateTrackerSync(sync.id, {
|
|
109
|
+
lastSyncOrigin: "swarm",
|
|
110
|
+
lastSyncedAt: new Date().toISOString(),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function handleTaskFailed(data: unknown): Promise<void> {
|
|
115
|
+
const { taskId, failureReason } = data as { taskId: string; failureReason?: string };
|
|
116
|
+
if (!taskId) return;
|
|
117
|
+
|
|
118
|
+
const sync = getTrackerSync("linear", "task", taskId);
|
|
119
|
+
if (!sync) return;
|
|
120
|
+
|
|
121
|
+
if (shouldSkipForLoopPrevention(sync)) return;
|
|
122
|
+
|
|
123
|
+
const sessionId = taskSessionMap.get(taskId);
|
|
124
|
+
const body = failureReason ? `Task failed.\n\n${failureReason.slice(0, 2000)}` : "Task failed.";
|
|
125
|
+
|
|
126
|
+
// Prefer AgentSession error activity over issue comment (avoids duplication)
|
|
127
|
+
if (sessionId) {
|
|
128
|
+
endAgentSession(sessionId, body, "error").catch((err) => {
|
|
129
|
+
console.error(`[Linear Outbound] Failed to end AgentSession for task ${taskId}:`, err);
|
|
130
|
+
});
|
|
131
|
+
taskSessionMap.delete(taskId);
|
|
132
|
+
console.log(`[Linear Outbound] Posted failure error to AgentSession for task ${taskId}`);
|
|
133
|
+
} else {
|
|
134
|
+
// No session — fall back to issue comment
|
|
135
|
+
try {
|
|
136
|
+
const client = getLinearClient();
|
|
137
|
+
if (!client) {
|
|
138
|
+
console.log("[Linear Outbound] No Linear client available, skipping sync for", taskId);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const comment = failureReason
|
|
142
|
+
? `Task failed.\n\nReason:\n${failureReason.slice(0, 2000)}`
|
|
143
|
+
: "Task failed.";
|
|
144
|
+
await client.createComment({ issueId: sync.externalId, body: comment });
|
|
145
|
+
console.log(`[Linear Outbound] Posted failure comment for task ${taskId}`);
|
|
146
|
+
} catch (error) {
|
|
147
|
+
console.error(
|
|
148
|
+
`[Linear Outbound] Failed to sync task failure for ${taskId}:`,
|
|
149
|
+
error instanceof Error ? error.message : error,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
updateTrackerSync(sync.id, {
|
|
155
|
+
lastSyncOrigin: "swarm",
|
|
156
|
+
lastSyncedAt: new Date().toISOString(),
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function handleTaskCancelled(data: unknown): Promise<void> {
|
|
161
|
+
const { taskId } = data as { taskId: string };
|
|
162
|
+
if (!taskId) return;
|
|
163
|
+
|
|
164
|
+
const sync = getTrackerSync("linear", "task", taskId);
|
|
165
|
+
if (!sync) return;
|
|
166
|
+
|
|
167
|
+
if (shouldSkipForLoopPrevention(sync)) return;
|
|
168
|
+
|
|
169
|
+
const sessionId = taskSessionMap.get(taskId);
|
|
170
|
+
const body = "Task cancelled.";
|
|
171
|
+
|
|
172
|
+
if (sessionId) {
|
|
173
|
+
endAgentSession(sessionId, body, "error").catch((err) => {
|
|
174
|
+
console.error(
|
|
175
|
+
`[Linear Outbound] Failed to end AgentSession for cancelled task ${taskId}:`,
|
|
176
|
+
err,
|
|
177
|
+
);
|
|
178
|
+
});
|
|
179
|
+
taskSessionMap.delete(taskId);
|
|
180
|
+
console.log(`[Linear Outbound] Posted cancellation to AgentSession for task ${taskId}`);
|
|
181
|
+
} else {
|
|
182
|
+
try {
|
|
183
|
+
const client = getLinearClient();
|
|
184
|
+
if (!client) {
|
|
185
|
+
console.log("[Linear Outbound] No Linear client available, skipping sync for", taskId);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
await client.createComment({ issueId: sync.externalId, body: "Task cancelled by swarm." });
|
|
189
|
+
console.log(`[Linear Outbound] Posted cancellation comment for task ${taskId}`);
|
|
190
|
+
} catch (error) {
|
|
191
|
+
console.error(
|
|
192
|
+
`[Linear Outbound] Failed to sync task cancellation for ${taskId}:`,
|
|
193
|
+
error instanceof Error ? error.message : error,
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
updateTrackerSync(sync.id, {
|
|
199
|
+
lastSyncOrigin: "swarm",
|
|
200
|
+
lastSyncedAt: new Date().toISOString(),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function shouldSkipForLoopPrevention(sync: {
|
|
205
|
+
lastSyncOrigin: string | null;
|
|
206
|
+
lastSyncedAt: string;
|
|
207
|
+
}): boolean {
|
|
208
|
+
if (sync.lastSyncOrigin !== "external") return false;
|
|
209
|
+
const lastSyncTime = new Date(sync.lastSyncedAt).getTime();
|
|
210
|
+
if (Number.isNaN(lastSyncTime)) return false;
|
|
211
|
+
return Date.now() - lastSyncTime < LOOP_PREVENTION_WINDOW_MS;
|
|
212
|
+
}
|