@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,567 @@
|
|
|
1
|
+
import { cancelTask, createTaskExtended, getAllAgents, getTaskById } from "../be/db";
|
|
2
|
+
import { getOAuthTokens } from "../be/db-queries/oauth";
|
|
3
|
+
import {
|
|
4
|
+
createTrackerSync,
|
|
5
|
+
deleteTrackerSync,
|
|
6
|
+
getTrackerSyncByExternalId,
|
|
7
|
+
updateTrackerSync,
|
|
8
|
+
} from "../be/db-queries/tracker";
|
|
9
|
+
import { resolveTemplate } from "../prompts/resolver";
|
|
10
|
+
// Side-effect import: registers all Linear event templates in the in-memory registry
|
|
11
|
+
import "./templates";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* In-memory map: swarmTaskId → Linear agentSessionId.
|
|
15
|
+
* Used by outbound sync to post activities back to the AgentSession.
|
|
16
|
+
* Not persisted — sessions are ephemeral and tied to the process lifetime.
|
|
17
|
+
*/
|
|
18
|
+
export const taskSessionMap = new Map<string, string>();
|
|
19
|
+
|
|
20
|
+
const AGENT_ACTIVITY_MUTATION = `
|
|
21
|
+
mutation AgentActivityCreate($input: AgentActivityCreateInput!) {
|
|
22
|
+
agentActivityCreate(input: $input) { success }
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
const AGENT_SESSION_UPDATE_MUTATION = `
|
|
27
|
+
mutation AgentSessionUpdate($id: String!, $input: AgentSessionUpdateInput!) {
|
|
28
|
+
agentSessionUpdate(id: $id, input: $input) { success }
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Low-level helper to post an activity to a Linear AgentSession via GraphQL.
|
|
34
|
+
*
|
|
35
|
+
* Activity types and their effect on session state:
|
|
36
|
+
* - `thought` — internal note (dimmed), session becomes active
|
|
37
|
+
* - `action` — tool invocation, session becomes active
|
|
38
|
+
* - `response` — final result, session auto-completes
|
|
39
|
+
* - `error` — error message, session transitions to error state
|
|
40
|
+
*
|
|
41
|
+
* No `signal` parameter is needed — Linear derives session state from the activity type.
|
|
42
|
+
*/
|
|
43
|
+
async function postAgentActivity(
|
|
44
|
+
sessionId: string,
|
|
45
|
+
content:
|
|
46
|
+
| { type: "thought" | "response" | "error"; body: string }
|
|
47
|
+
| { type: "action"; action: string; parameter?: string; result?: string },
|
|
48
|
+
): Promise<boolean> {
|
|
49
|
+
const tokens = getOAuthTokens("linear");
|
|
50
|
+
if (!tokens) {
|
|
51
|
+
console.log("[Linear Sync] No OAuth tokens, cannot post AgentSession activity");
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const input = {
|
|
56
|
+
agentSessionId: sessionId,
|
|
57
|
+
content,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const res = await fetch("https://api.linear.app/graphql", {
|
|
61
|
+
method: "POST",
|
|
62
|
+
headers: {
|
|
63
|
+
"Content-Type": "application/json",
|
|
64
|
+
Authorization: `Bearer ${tokens.accessToken}`,
|
|
65
|
+
},
|
|
66
|
+
body: JSON.stringify({
|
|
67
|
+
query: AGENT_ACTIVITY_MUTATION,
|
|
68
|
+
variables: { input },
|
|
69
|
+
}),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (!res.ok) {
|
|
73
|
+
console.error(
|
|
74
|
+
`[Linear Sync] Failed to post activity to AgentSession ${sessionId}: ${res.status} ${res.statusText}`,
|
|
75
|
+
);
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const result = (await res.json()) as {
|
|
80
|
+
data?: { agentActivityCreate?: { success: boolean } };
|
|
81
|
+
errors?: unknown[];
|
|
82
|
+
};
|
|
83
|
+
if (result.errors) {
|
|
84
|
+
console.error("[Linear Sync] GraphQL errors posting AgentSession activity:", result.errors);
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Update an AgentSession via the agentSessionUpdate mutation.
|
|
93
|
+
* Used to set externalUrls, plan, etc.
|
|
94
|
+
*/
|
|
95
|
+
async function updateAgentSession(
|
|
96
|
+
sessionId: string,
|
|
97
|
+
input: Record<string, unknown>,
|
|
98
|
+
): Promise<boolean> {
|
|
99
|
+
const tokens = getOAuthTokens("linear");
|
|
100
|
+
if (!tokens) {
|
|
101
|
+
console.log("[Linear Sync] No OAuth tokens, cannot update AgentSession");
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const res = await fetch("https://api.linear.app/graphql", {
|
|
106
|
+
method: "POST",
|
|
107
|
+
headers: {
|
|
108
|
+
"Content-Type": "application/json",
|
|
109
|
+
Authorization: `Bearer ${tokens.accessToken}`,
|
|
110
|
+
},
|
|
111
|
+
body: JSON.stringify({
|
|
112
|
+
query: AGENT_SESSION_UPDATE_MUTATION,
|
|
113
|
+
variables: { id: sessionId, input },
|
|
114
|
+
}),
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (!res.ok) {
|
|
118
|
+
console.error(
|
|
119
|
+
`[Linear Sync] Failed to update AgentSession ${sessionId}: ${res.status} ${res.statusText}`,
|
|
120
|
+
);
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const result = (await res.json()) as {
|
|
125
|
+
data?: { agentSessionUpdate?: { success: boolean } };
|
|
126
|
+
errors?: unknown[];
|
|
127
|
+
};
|
|
128
|
+
if (result.errors) {
|
|
129
|
+
console.error("[Linear Sync] GraphQL errors updating AgentSession:", result.errors);
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Acknowledge a Linear AgentSession by posting a thought activity.
|
|
138
|
+
* Creating an activity transitions the session from "pending" to "active".
|
|
139
|
+
*/
|
|
140
|
+
async function acknowledgeAgentSession(sessionId: string, message: string): Promise<void> {
|
|
141
|
+
const ok = await postAgentActivity(sessionId, { type: "thought", body: message });
|
|
142
|
+
if (ok) {
|
|
143
|
+
console.log(`[Linear Sync] AgentSession ${sessionId} acknowledged`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Post a response activity to a Linear AgentSession (visible as a comment).
|
|
149
|
+
*/
|
|
150
|
+
export async function postAgentSessionResponse(sessionId: string, body: string): Promise<void> {
|
|
151
|
+
await postAgentActivity(sessionId, { type: "response", body });
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Post a thought activity to a Linear AgentSession (dimmed internal thinking).
|
|
156
|
+
*/
|
|
157
|
+
export async function postAgentSessionThought(sessionId: string, body: string): Promise<void> {
|
|
158
|
+
await postAgentActivity(sessionId, { type: "thought", body });
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Post an error activity to a Linear AgentSession.
|
|
163
|
+
*/
|
|
164
|
+
export async function postAgentSessionError(sessionId: string, body: string): Promise<void> {
|
|
165
|
+
await postAgentActivity(sessionId, { type: "error", body });
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* End a Linear AgentSession by posting a response or error activity.
|
|
170
|
+
* A `response` activity auto-completes the session; an `error` activity marks it as errored.
|
|
171
|
+
* No explicit signal is needed — Linear derives state from the activity type.
|
|
172
|
+
*/
|
|
173
|
+
export async function endAgentSession(
|
|
174
|
+
sessionId: string,
|
|
175
|
+
body: string,
|
|
176
|
+
type: "response" | "error" = "response",
|
|
177
|
+
): Promise<void> {
|
|
178
|
+
await postAgentActivity(sessionId, { type, body });
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Post an action activity to a Linear AgentSession (tool invocation).
|
|
183
|
+
*/
|
|
184
|
+
export async function postAgentSessionAction(
|
|
185
|
+
sessionId: string,
|
|
186
|
+
action: string,
|
|
187
|
+
parameter?: string,
|
|
188
|
+
result?: string,
|
|
189
|
+
): Promise<void> {
|
|
190
|
+
const content: { type: "action"; action: string; parameter?: string; result?: string } = {
|
|
191
|
+
type: "action",
|
|
192
|
+
action,
|
|
193
|
+
};
|
|
194
|
+
if (parameter) content.parameter = parameter;
|
|
195
|
+
if (result) content.result = result;
|
|
196
|
+
await postAgentActivity(sessionId, content);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Set externalUrls on an AgentSession so users can click through to the swarm dashboard.
|
|
201
|
+
*/
|
|
202
|
+
export async function updateAgentSessionExternalUrls(
|
|
203
|
+
sessionId: string,
|
|
204
|
+
urls: { label: string; url: string }[],
|
|
205
|
+
): Promise<void> {
|
|
206
|
+
const ok = await updateAgentSession(sessionId, { externalUrls: urls });
|
|
207
|
+
if (ok) {
|
|
208
|
+
console.log(`[Linear Sync] Set externalUrls on AgentSession ${sessionId}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Status mapping: Linear state names → swarm task statuses
|
|
213
|
+
const LINEAR_STATUS_MAP: Record<string, string> = {
|
|
214
|
+
Backlog: "skip",
|
|
215
|
+
Todo: "unassigned",
|
|
216
|
+
"In Progress": "in_progress",
|
|
217
|
+
Done: "completed",
|
|
218
|
+
Canceled: "cancelled",
|
|
219
|
+
Cancelled: "cancelled",
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
export function mapLinearStatusToSwarm(linearStateName: string): string | null {
|
|
223
|
+
return LINEAR_STATUS_MAP[linearStateName] ?? null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Find the lead agent to receive Linear tasks.
|
|
228
|
+
* Returns null if no lead is available (task will go to pool).
|
|
229
|
+
*/
|
|
230
|
+
function findLeadAgent() {
|
|
231
|
+
const agents = getAllAgents();
|
|
232
|
+
const onlineLead = agents.find((a) => a.isLead && a.status !== "offline");
|
|
233
|
+
if (onlineLead) return onlineLead;
|
|
234
|
+
return agents.find((a) => a.isLead) ?? null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Handle AgentSession events from Linear.
|
|
239
|
+
* These are fired when an issue is assigned to the Linear agent integration,
|
|
240
|
+
* triggering a new swarm task.
|
|
241
|
+
*/
|
|
242
|
+
export async function handleAgentSessionEvent(event: Record<string, unknown>): Promise<void> {
|
|
243
|
+
// Linear sends AgentSessionEvent with agentSession.issue (not data.issue)
|
|
244
|
+
const agentSession = event.agentSession as Record<string, unknown> | undefined;
|
|
245
|
+
const data = agentSession ?? (event.data as Record<string, unknown> | undefined);
|
|
246
|
+
if (!data) {
|
|
247
|
+
console.log("[Linear Sync] AgentSession event has no agentSession/data, skipping");
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const issue = data.issue as Record<string, unknown> | undefined;
|
|
252
|
+
if (!issue) {
|
|
253
|
+
console.log("[Linear Sync] AgentSession event has no issue data, skipping");
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const issueId = String(issue.id ?? "");
|
|
258
|
+
const issueIdentifier = String(issue.identifier ?? "");
|
|
259
|
+
const issueTitle = String(issue.title ?? "");
|
|
260
|
+
const issueUrl = String(issue.url ?? "");
|
|
261
|
+
const issueDescription = issue.description ? String(issue.description) : "";
|
|
262
|
+
const sessionUrl = agentSession ? String(agentSession.url ?? "") : "";
|
|
263
|
+
|
|
264
|
+
if (!issueId) {
|
|
265
|
+
console.log("[Linear Sync] AgentSession event has no issue ID, skipping");
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Check if we already track this issue
|
|
270
|
+
const existing = getTrackerSyncByExternalId("linear", "task", issueId);
|
|
271
|
+
if (existing) {
|
|
272
|
+
console.log(
|
|
273
|
+
`[Linear Sync] Issue ${issueIdentifier} already tracked as task ${existing.swarmId}, skipping`,
|
|
274
|
+
);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const lead = findLeadAgent();
|
|
279
|
+
|
|
280
|
+
const sessionSection = sessionUrl ? `\nSession: ${sessionUrl}` : "";
|
|
281
|
+
const descriptionSection = issueDescription ? `\nDescription:\n${issueDescription}\n` : "";
|
|
282
|
+
const assignedResult = resolveTemplate("linear.issue.assigned", {
|
|
283
|
+
issue_identifier: issueIdentifier,
|
|
284
|
+
issue_title: issueTitle,
|
|
285
|
+
issue_url: issueUrl,
|
|
286
|
+
session_section: sessionSection,
|
|
287
|
+
description_section: descriptionSection,
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
if (assignedResult.skipped) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const task = createTaskExtended(assignedResult.text, {
|
|
295
|
+
agentId: lead?.id ?? "",
|
|
296
|
+
source: "linear",
|
|
297
|
+
taskType: "linear-issue",
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
createTrackerSync({
|
|
301
|
+
provider: "linear",
|
|
302
|
+
entityType: "task",
|
|
303
|
+
providerEntityType: "Issue",
|
|
304
|
+
swarmId: task.id,
|
|
305
|
+
externalId: issueId,
|
|
306
|
+
externalIdentifier: issueIdentifier,
|
|
307
|
+
externalUrl: issueUrl,
|
|
308
|
+
lastSyncOrigin: "external",
|
|
309
|
+
syncDirection: "inbound",
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// Track the AgentSession so outbound sync can post activities to it
|
|
313
|
+
const sessionId = agentSession ? String(agentSession.id ?? "") : "";
|
|
314
|
+
if (sessionId) {
|
|
315
|
+
taskSessionMap.set(task.id, sessionId);
|
|
316
|
+
|
|
317
|
+
// Acknowledge the AgentSession (pending → active)
|
|
318
|
+
acknowledgeAgentSession(
|
|
319
|
+
sessionId,
|
|
320
|
+
`Task received by Agent Swarm (${task.id}). Processing...`,
|
|
321
|
+
).catch((err) => {
|
|
322
|
+
console.error("[Linear Sync] Failed to acknowledge AgentSession:", err);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// Set externalUrls so users can click through to the swarm dashboard
|
|
326
|
+
const dashboardUrl = process.env.SWARM_DASHBOARD_URL || process.env.APP_URL;
|
|
327
|
+
if (dashboardUrl) {
|
|
328
|
+
updateAgentSessionExternalUrls(sessionId, [
|
|
329
|
+
{ label: "View in Agent Swarm", url: `${dashboardUrl}/tasks/${task.id}` },
|
|
330
|
+
]).catch((err) => {
|
|
331
|
+
console.error("[Linear Sync] Failed to set externalUrls on AgentSession:", err);
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
console.log(
|
|
337
|
+
`[Linear Sync] Created task ${task.id} for ${issueIdentifier} -> ${lead?.name ?? "unassigned"}`,
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Handle Issue update events from Linear webhooks.
|
|
343
|
+
* Updates swarm task status when a tracked Linear issue changes state.
|
|
344
|
+
*/
|
|
345
|
+
export async function handleIssueUpdate(
|
|
346
|
+
event: Record<string, unknown>,
|
|
347
|
+
deliveryId?: string,
|
|
348
|
+
): Promise<void> {
|
|
349
|
+
const data = event.data as Record<string, unknown> | undefined;
|
|
350
|
+
if (!data) return;
|
|
351
|
+
|
|
352
|
+
const issueId = String(data.id ?? "");
|
|
353
|
+
if (!issueId) return;
|
|
354
|
+
|
|
355
|
+
const sync = getTrackerSyncByExternalId("linear", "task", issueId);
|
|
356
|
+
if (!sync) {
|
|
357
|
+
// We don't track this issue — ignore
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Check if the status (state) changed
|
|
362
|
+
const updatedFrom = event.updatedFrom as Record<string, unknown> | undefined;
|
|
363
|
+
if (!updatedFrom) return;
|
|
364
|
+
|
|
365
|
+
const state = data.state as Record<string, unknown> | undefined;
|
|
366
|
+
if (!state) return;
|
|
367
|
+
|
|
368
|
+
const stateName = String(state.name ?? "");
|
|
369
|
+
const swarmStatus = mapLinearStatusToSwarm(stateName);
|
|
370
|
+
|
|
371
|
+
if (!swarmStatus) {
|
|
372
|
+
console.log(
|
|
373
|
+
`[Linear Sync] Unknown Linear status "${stateName}" for issue ${issueId}, skipping`,
|
|
374
|
+
);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Update tracker_sync metadata
|
|
379
|
+
updateTrackerSync(sync.id, {
|
|
380
|
+
lastSyncOrigin: "external",
|
|
381
|
+
lastSyncedAt: new Date().toISOString(),
|
|
382
|
+
lastDeliveryId: deliveryId ?? null,
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
// Map status to swarm actions
|
|
386
|
+
if (swarmStatus === "cancelled") {
|
|
387
|
+
const task = getTaskById(sync.swarmId);
|
|
388
|
+
if (task && !["completed", "failed", "cancelled"].includes(task.status)) {
|
|
389
|
+
cancelTask(sync.swarmId, `Linear issue cancelled`);
|
|
390
|
+
console.log(
|
|
391
|
+
`[Linear Sync] Cancelled task ${sync.swarmId} (Linear issue ${data.identifier ?? issueId} cancelled)`,
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (swarmStatus === "completed") {
|
|
398
|
+
// We don't auto-complete tasks from Linear — the agent decides when work is done
|
|
399
|
+
console.log(
|
|
400
|
+
`[Linear Sync] Linear issue ${data.identifier ?? issueId} marked Done — not auto-completing task ${sync.swarmId}`,
|
|
401
|
+
);
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// For skip / unassigned / in_progress — log but don't force status changes
|
|
406
|
+
console.log(
|
|
407
|
+
`[Linear Sync] Issue ${data.identifier ?? issueId} status → ${stateName} (mapped: ${swarmStatus})`,
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Handle Issue delete events from Linear webhooks.
|
|
413
|
+
* Cancels the swarm task if the tracked Linear issue is removed.
|
|
414
|
+
*/
|
|
415
|
+
export async function handleIssueDelete(event: Record<string, unknown>): Promise<void> {
|
|
416
|
+
const data = event.data as Record<string, unknown> | undefined;
|
|
417
|
+
if (!data) return;
|
|
418
|
+
|
|
419
|
+
const issueId = String(data.id ?? "");
|
|
420
|
+
if (!issueId) return;
|
|
421
|
+
|
|
422
|
+
const sync = getTrackerSyncByExternalId("linear", "task", issueId);
|
|
423
|
+
if (!sync) return;
|
|
424
|
+
|
|
425
|
+
const task = getTaskById(sync.swarmId);
|
|
426
|
+
if (task && !["completed", "failed", "cancelled"].includes(task.status)) {
|
|
427
|
+
cancelTask(sync.swarmId, "Linear issue deleted");
|
|
428
|
+
console.log(`[Linear Sync] Cancelled task ${sync.swarmId} (Linear issue ${issueId} deleted)`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Handle "prompted" AgentSession events — user sent a follow-up message
|
|
434
|
+
* in the Linear agent chat UI.
|
|
435
|
+
*/
|
|
436
|
+
export async function handleAgentSessionPrompted(event: Record<string, unknown>): Promise<void> {
|
|
437
|
+
const agentSession = event.agentSession as Record<string, unknown> | undefined;
|
|
438
|
+
if (!agentSession) {
|
|
439
|
+
console.log("[Linear Sync] Prompted event has no agentSession, skipping");
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const sessionId = String(agentSession.id ?? "");
|
|
444
|
+
const issue = agentSession.issue as Record<string, unknown> | undefined;
|
|
445
|
+
|
|
446
|
+
// User message is in event.agentActivity.content.body (not agentSession.comment.body)
|
|
447
|
+
const agentActivity = event.agentActivity as Record<string, unknown> | undefined;
|
|
448
|
+
const activityContent = agentActivity?.content as Record<string, unknown> | undefined;
|
|
449
|
+
const userMessage = activityContent ? String(activityContent.body ?? "") : "";
|
|
450
|
+
const activitySignal = agentActivity ? String(agentActivity.signal ?? "") : "";
|
|
451
|
+
|
|
452
|
+
if (!issue) {
|
|
453
|
+
console.log("[Linear Sync] Prompted event has no issue data, skipping");
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
const issueId = String(issue.id ?? "");
|
|
458
|
+
const issueIdentifier = String(issue.identifier ?? "");
|
|
459
|
+
const issueTitle = String(issue.title ?? "");
|
|
460
|
+
const issueUrl = String(issue.url ?? "");
|
|
461
|
+
|
|
462
|
+
// Handle stop signal — cancel the active task
|
|
463
|
+
if (activitySignal === "stop") {
|
|
464
|
+
const existing = getTrackerSyncByExternalId("linear", "task", issueId);
|
|
465
|
+
if (existing) {
|
|
466
|
+
const existingTask = getTaskById(existing.swarmId);
|
|
467
|
+
if (existingTask && !["completed", "failed", "cancelled"].includes(existingTask.status)) {
|
|
468
|
+
cancelTask(existing.swarmId, "Stopped by user from Linear");
|
|
469
|
+
console.log(`[Linear Sync] Cancelled task ${existing.swarmId} (stop signal from Linear)`);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
if (sessionId) {
|
|
473
|
+
endAgentSession(sessionId, "Task cancelled by user.", "response").catch((err) => {
|
|
474
|
+
console.error("[Linear Sync] Failed to end session on stop:", err);
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (!issueId || !userMessage) {
|
|
481
|
+
console.log("[Linear Sync] Prompted event missing issue ID or message, skipping");
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Look up existing tracker_sync for this issue
|
|
486
|
+
const existing = getTrackerSyncByExternalId("linear", "task", issueId);
|
|
487
|
+
|
|
488
|
+
if (existing) {
|
|
489
|
+
const existingTask = getTaskById(existing.swarmId);
|
|
490
|
+
|
|
491
|
+
// If the task is still in progress, acknowledge but don't create a new one
|
|
492
|
+
if (existingTask && !["completed", "failed", "cancelled"].includes(existingTask.status)) {
|
|
493
|
+
console.log(`[Linear Sync] Prompted on in-progress task ${existing.swarmId}, acknowledging`);
|
|
494
|
+
if (sessionId) {
|
|
495
|
+
postAgentSessionThought(
|
|
496
|
+
sessionId,
|
|
497
|
+
"Message received, but the agent is currently working on this task. Your message will be considered when possible.",
|
|
498
|
+
).catch((err) => {
|
|
499
|
+
console.error("[Linear Sync] Failed to post thought for prompted event:", err);
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// Task is completed/failed/cancelled or doesn't exist — create a new follow-up task
|
|
507
|
+
const lead = findLeadAgent();
|
|
508
|
+
|
|
509
|
+
const followupResult = resolveTemplate("linear.issue.followup", {
|
|
510
|
+
issue_identifier: issueIdentifier,
|
|
511
|
+
issue_title: issueTitle,
|
|
512
|
+
issue_url: issueUrl,
|
|
513
|
+
user_message: userMessage,
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
if (followupResult.skipped) {
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const task = createTaskExtended(followupResult.text, {
|
|
521
|
+
agentId: lead?.id ?? "",
|
|
522
|
+
source: "linear",
|
|
523
|
+
taskType: "linear-issue",
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
// Repoint the existing tracker_sync to the new follow-up task (can't create a
|
|
527
|
+
// duplicate due to UNIQUE(provider, entityType, externalId) constraint)
|
|
528
|
+
if (existing) {
|
|
529
|
+
deleteTrackerSync(existing.id);
|
|
530
|
+
}
|
|
531
|
+
createTrackerSync({
|
|
532
|
+
provider: "linear",
|
|
533
|
+
entityType: "task",
|
|
534
|
+
providerEntityType: "Issue",
|
|
535
|
+
swarmId: task.id,
|
|
536
|
+
externalId: issueId,
|
|
537
|
+
externalIdentifier: issueIdentifier,
|
|
538
|
+
externalUrl: issueUrl,
|
|
539
|
+
lastSyncOrigin: "external",
|
|
540
|
+
syncDirection: "inbound",
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
// Track session and acknowledge
|
|
544
|
+
if (sessionId) {
|
|
545
|
+
taskSessionMap.set(task.id, sessionId);
|
|
546
|
+
acknowledgeAgentSession(
|
|
547
|
+
sessionId,
|
|
548
|
+
`Follow-up task created (${task.id}). Processing your message...`,
|
|
549
|
+
).catch((err) => {
|
|
550
|
+
console.error("[Linear Sync] Failed to acknowledge prompted AgentSession:", err);
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
// Set externalUrls for the follow-up task
|
|
554
|
+
const dashboardUrl = process.env.SWARM_DASHBOARD_URL || process.env.APP_URL;
|
|
555
|
+
if (dashboardUrl) {
|
|
556
|
+
updateAgentSessionExternalUrls(sessionId, [
|
|
557
|
+
{ label: "View in Agent Swarm", url: `${dashboardUrl}/tasks/${task.id}` },
|
|
558
|
+
]).catch((err) => {
|
|
559
|
+
console.error("[Linear Sync] Failed to set externalUrls on prompted AgentSession:", err);
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
console.log(
|
|
565
|
+
`[Linear Sync] Created follow-up task ${task.id} for ${issueIdentifier} (prompted) -> ${lead?.name ?? "unassigned"}`,
|
|
566
|
+
);
|
|
567
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linear event prompt template definitions.
|
|
3
|
+
*
|
|
4
|
+
* Each template is registered at module load time via registerTemplate().
|
|
5
|
+
* Handlers import this module for the side-effect of registration.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { registerTemplate } from "../prompts/registry";
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Issue events
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
registerTemplate({
|
|
15
|
+
eventType: "linear.issue.assigned",
|
|
16
|
+
header: "[Linear {{issue_identifier}}] {{issue_title}}",
|
|
17
|
+
defaultBody: `Source: Linear (Agent Session)
|
|
18
|
+
URL: {{issue_url}}{{session_section}}
|
|
19
|
+
{{description_section}}`,
|
|
20
|
+
variables: [
|
|
21
|
+
{ name: "issue_identifier", description: "Linear issue identifier (e.g. ENG-123)" },
|
|
22
|
+
{ name: "issue_title", description: "Issue title" },
|
|
23
|
+
{ name: "issue_url", description: "Issue URL on Linear" },
|
|
24
|
+
{ name: "session_section", description: "Session URL line or empty string" },
|
|
25
|
+
{ name: "description_section", description: "Description section or empty string" },
|
|
26
|
+
],
|
|
27
|
+
category: "event",
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
registerTemplate({
|
|
31
|
+
eventType: "linear.issue.followup",
|
|
32
|
+
header: "[Linear {{issue_identifier}}] Follow-up: {{issue_title}}",
|
|
33
|
+
defaultBody: `Source: Linear (Agent Session follow-up)
|
|
34
|
+
URL: {{issue_url}}
|
|
35
|
+
|
|
36
|
+
User message:
|
|
37
|
+
{{user_message}}
|
|
38
|
+
|
|
39
|
+
Original issue: {{issue_identifier}} \u2014 {{issue_title}}`,
|
|
40
|
+
variables: [
|
|
41
|
+
{ name: "issue_identifier", description: "Linear issue identifier (e.g. ENG-123)" },
|
|
42
|
+
{ name: "issue_title", description: "Issue title" },
|
|
43
|
+
{ name: "issue_url", description: "Issue URL on Linear" },
|
|
44
|
+
{ name: "user_message", description: "Follow-up message from user" },
|
|
45
|
+
],
|
|
46
|
+
category: "event",
|
|
47
|
+
});
|