@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,230 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
2
|
+
import { unlink } from "node:fs/promises";
|
|
3
|
+
import { closeDb, initDb } from "../be/db";
|
|
4
|
+
import {
|
|
5
|
+
createTrackerAgentMapping,
|
|
6
|
+
createTrackerSync,
|
|
7
|
+
deleteTrackerAgentMapping,
|
|
8
|
+
deleteTrackerSync,
|
|
9
|
+
getAllTrackerAgentMappings,
|
|
10
|
+
getAllTrackerSyncs,
|
|
11
|
+
getTrackerAgentMapping,
|
|
12
|
+
getTrackerAgentMappingByExternalUser,
|
|
13
|
+
getTrackerSync,
|
|
14
|
+
getTrackerSyncByExternalId,
|
|
15
|
+
updateTrackerSync,
|
|
16
|
+
} from "../be/db-queries/tracker";
|
|
17
|
+
|
|
18
|
+
const TEST_DB_PATH = "./test-db-queries-tracker.sqlite";
|
|
19
|
+
|
|
20
|
+
beforeAll(() => {
|
|
21
|
+
initDb(TEST_DB_PATH);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterAll(async () => {
|
|
25
|
+
closeDb();
|
|
26
|
+
await unlink(TEST_DB_PATH).catch(() => {});
|
|
27
|
+
await unlink(`${TEST_DB_PATH}-wal`).catch(() => {});
|
|
28
|
+
await unlink(`${TEST_DB_PATH}-shm`).catch(() => {});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe("Tracker Sync CRUD", () => {
|
|
32
|
+
test("getTrackerSync returns null for unknown mapping", () => {
|
|
33
|
+
expect(getTrackerSync("linear", "task", "nonexistent")).toBeNull();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("createTrackerSync creates a mapping", () => {
|
|
37
|
+
const sync = createTrackerSync({
|
|
38
|
+
provider: "linear",
|
|
39
|
+
entityType: "task",
|
|
40
|
+
swarmId: "task-001",
|
|
41
|
+
externalId: "LIN-123",
|
|
42
|
+
externalIdentifier: "ENG-42",
|
|
43
|
+
externalUrl: "https://linear.app/team/ENG-42",
|
|
44
|
+
syncDirection: "inbound",
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
expect(sync.id).toBeDefined();
|
|
48
|
+
expect(sync.provider).toBe("linear");
|
|
49
|
+
expect(sync.entityType).toBe("task");
|
|
50
|
+
expect(sync.swarmId).toBe("task-001");
|
|
51
|
+
expect(sync.externalId).toBe("LIN-123");
|
|
52
|
+
expect(sync.externalIdentifier).toBe("ENG-42");
|
|
53
|
+
expect(sync.externalUrl).toBe("https://linear.app/team/ENG-42");
|
|
54
|
+
expect(sync.syncDirection).toBe("inbound");
|
|
55
|
+
expect(sync.lastSyncOrigin).toBeNull();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("getTrackerSync retrieves by swarmId", () => {
|
|
59
|
+
const sync = getTrackerSync("linear", "task", "task-001");
|
|
60
|
+
expect(sync).not.toBeNull();
|
|
61
|
+
expect(sync!.externalId).toBe("LIN-123");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("getTrackerSyncByExternalId retrieves by externalId", () => {
|
|
65
|
+
const sync = getTrackerSyncByExternalId("linear", "task", "LIN-123");
|
|
66
|
+
expect(sync).not.toBeNull();
|
|
67
|
+
expect(sync!.swarmId).toBe("task-001");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("updateTrackerSync updates fields", () => {
|
|
71
|
+
const sync = getTrackerSync("linear", "task", "task-001")!;
|
|
72
|
+
updateTrackerSync(sync.id, {
|
|
73
|
+
lastSyncOrigin: "external",
|
|
74
|
+
lastDeliveryId: "delivery-abc",
|
|
75
|
+
syncDirection: "bidirectional",
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const updated = getTrackerSync("linear", "task", "task-001")!;
|
|
79
|
+
expect(updated.lastSyncOrigin).toBe("external");
|
|
80
|
+
expect(updated.lastDeliveryId).toBe("delivery-abc");
|
|
81
|
+
expect(updated.syncDirection).toBe("bidirectional");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("createTrackerSync enforces unique(provider, entityType, swarmId)", () => {
|
|
85
|
+
expect(() =>
|
|
86
|
+
createTrackerSync({
|
|
87
|
+
provider: "linear",
|
|
88
|
+
entityType: "task",
|
|
89
|
+
swarmId: "task-001",
|
|
90
|
+
externalId: "LIN-999",
|
|
91
|
+
}),
|
|
92
|
+
).toThrow();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("createTrackerSync enforces unique(provider, entityType, externalId)", () => {
|
|
96
|
+
expect(() =>
|
|
97
|
+
createTrackerSync({
|
|
98
|
+
provider: "linear",
|
|
99
|
+
entityType: "task",
|
|
100
|
+
swarmId: "task-999",
|
|
101
|
+
externalId: "LIN-123",
|
|
102
|
+
}),
|
|
103
|
+
).toThrow();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("same externalId allowed for different entityTypes", () => {
|
|
107
|
+
const epic = createTrackerSync({
|
|
108
|
+
provider: "linear",
|
|
109
|
+
entityType: "epic",
|
|
110
|
+
swarmId: "epic-001",
|
|
111
|
+
externalId: "LIN-123",
|
|
112
|
+
});
|
|
113
|
+
expect(epic.entityType).toBe("epic");
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test("same swarmId allowed for different providers", () => {
|
|
117
|
+
const jiraSync = createTrackerSync({
|
|
118
|
+
provider: "jira" as "linear", // cast for test — DB doesn't constrain provider values
|
|
119
|
+
entityType: "task",
|
|
120
|
+
swarmId: "task-001",
|
|
121
|
+
externalId: "JIRA-456",
|
|
122
|
+
});
|
|
123
|
+
expect(jiraSync.provider).toBe("jira");
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("getAllTrackerSyncs returns all", () => {
|
|
127
|
+
const all = getAllTrackerSyncs();
|
|
128
|
+
expect(all.length).toBeGreaterThanOrEqual(3);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("getAllTrackerSyncs filters by provider", () => {
|
|
132
|
+
const linear = getAllTrackerSyncs("linear");
|
|
133
|
+
const jira = getAllTrackerSyncs("jira");
|
|
134
|
+
expect(linear.length).toBeGreaterThanOrEqual(2);
|
|
135
|
+
expect(jira.length).toBe(1);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("getAllTrackerSyncs filters by entityType", () => {
|
|
139
|
+
const tasks = getAllTrackerSyncs(undefined, "task");
|
|
140
|
+
const epics = getAllTrackerSyncs(undefined, "epic");
|
|
141
|
+
expect(tasks.length).toBeGreaterThanOrEqual(2);
|
|
142
|
+
expect(epics.length).toBeGreaterThanOrEqual(1);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("deleteTrackerSync removes the mapping", () => {
|
|
146
|
+
const sync = getTrackerSyncByExternalId("jira", "task", "JIRA-456")!;
|
|
147
|
+
deleteTrackerSync(sync.id);
|
|
148
|
+
expect(getTrackerSyncByExternalId("jira", "task", "JIRA-456")).toBeNull();
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe("Tracker Agent Mapping CRUD", () => {
|
|
153
|
+
test("getTrackerAgentMapping returns null for unknown", () => {
|
|
154
|
+
expect(getTrackerAgentMapping("linear", "nonexistent")).toBeNull();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("createTrackerAgentMapping creates a mapping", () => {
|
|
158
|
+
const mapping = createTrackerAgentMapping({
|
|
159
|
+
provider: "linear",
|
|
160
|
+
agentId: "agent-001",
|
|
161
|
+
externalUserId: "lin-user-abc",
|
|
162
|
+
agentName: "Coder Agent",
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
expect(mapping.id).toBeDefined();
|
|
166
|
+
expect(mapping.provider).toBe("linear");
|
|
167
|
+
expect(mapping.agentId).toBe("agent-001");
|
|
168
|
+
expect(mapping.externalUserId).toBe("lin-user-abc");
|
|
169
|
+
expect(mapping.agentName).toBe("Coder Agent");
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("getTrackerAgentMapping retrieves by agentId", () => {
|
|
173
|
+
const mapping = getTrackerAgentMapping("linear", "agent-001");
|
|
174
|
+
expect(mapping).not.toBeNull();
|
|
175
|
+
expect(mapping!.externalUserId).toBe("lin-user-abc");
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("getTrackerAgentMappingByExternalUser retrieves by externalUserId", () => {
|
|
179
|
+
const mapping = getTrackerAgentMappingByExternalUser("linear", "lin-user-abc");
|
|
180
|
+
expect(mapping).not.toBeNull();
|
|
181
|
+
expect(mapping!.agentId).toBe("agent-001");
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("enforces unique(provider, agentId)", () => {
|
|
185
|
+
expect(() =>
|
|
186
|
+
createTrackerAgentMapping({
|
|
187
|
+
provider: "linear",
|
|
188
|
+
agentId: "agent-001",
|
|
189
|
+
externalUserId: "lin-user-xyz",
|
|
190
|
+
agentName: "Duplicate",
|
|
191
|
+
}),
|
|
192
|
+
).toThrow();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test("enforces unique(provider, externalUserId)", () => {
|
|
196
|
+
expect(() =>
|
|
197
|
+
createTrackerAgentMapping({
|
|
198
|
+
provider: "linear",
|
|
199
|
+
agentId: "agent-002",
|
|
200
|
+
externalUserId: "lin-user-abc",
|
|
201
|
+
agentName: "Duplicate",
|
|
202
|
+
}),
|
|
203
|
+
).toThrow();
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("same agentId allowed for different providers", () => {
|
|
207
|
+
const jiraMapping = createTrackerAgentMapping({
|
|
208
|
+
provider: "jira" as "linear",
|
|
209
|
+
agentId: "agent-001",
|
|
210
|
+
externalUserId: "jira-user-abc",
|
|
211
|
+
agentName: "Coder Agent",
|
|
212
|
+
});
|
|
213
|
+
expect(jiraMapping.provider).toBe("jira");
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test("getAllTrackerAgentMappings returns all", () => {
|
|
217
|
+
const all = getAllTrackerAgentMappings();
|
|
218
|
+
expect(all.length).toBeGreaterThanOrEqual(2);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
test("getAllTrackerAgentMappings filters by provider", () => {
|
|
222
|
+
const linear = getAllTrackerAgentMappings("linear");
|
|
223
|
+
expect(linear.length).toBe(1);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test("deleteTrackerAgentMapping removes the mapping", () => {
|
|
227
|
+
deleteTrackerAgentMapping("jira", "agent-001");
|
|
228
|
+
expect(getTrackerAgentMapping("jira", "agent-001")).toBeNull();
|
|
229
|
+
});
|
|
230
|
+
});
|
package/src/tests/epics.test.ts
CHANGED
|
@@ -92,8 +92,8 @@ describe("Epics Integration", () => {
|
|
|
92
92
|
leadAgentId: leadAgent.id,
|
|
93
93
|
researchDocPath: "/thoughts/research/test.md",
|
|
94
94
|
planDocPath: "/thoughts/plans/test.md",
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
vcsRepo: "desplega-ai/agent-swarm",
|
|
96
|
+
vcsMilestone: "v1.0",
|
|
97
97
|
});
|
|
98
98
|
|
|
99
99
|
expect(epic.id).toBeDefined();
|
|
@@ -107,7 +107,7 @@ describe("Epics Integration", () => {
|
|
|
107
107
|
expect(epic.createdByAgentId).toBe(testAgent.id);
|
|
108
108
|
expect(epic.leadAgentId).toBe(leadAgent.id);
|
|
109
109
|
expect(epic.researchDocPath).toBe("/thoughts/research/test.md");
|
|
110
|
-
expect(epic.
|
|
110
|
+
expect(epic.vcsRepo).toBe("desplega-ai/agent-swarm");
|
|
111
111
|
});
|
|
112
112
|
|
|
113
113
|
test("should auto-create a channel when creating an epic", () => {
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
parseStderrForErrors,
|
|
4
|
+
SessionErrorTracker,
|
|
5
|
+
trackErrorFromJson,
|
|
6
|
+
} from "../utils/error-tracker";
|
|
7
|
+
|
|
8
|
+
describe("SessionErrorTracker", () => {
|
|
9
|
+
test("hasErrors returns false when no errors tracked", () => {
|
|
10
|
+
const tracker = new SessionErrorTracker();
|
|
11
|
+
expect(tracker.hasErrors()).toBe(false);
|
|
12
|
+
expect(tracker.getErrors()).toHaveLength(0);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("addApiError tracks an API error", () => {
|
|
16
|
+
const tracker = new SessionErrorTracker();
|
|
17
|
+
tracker.addApiError("rate_limit", "Rate limit exceeded");
|
|
18
|
+
|
|
19
|
+
expect(tracker.hasErrors()).toBe(true);
|
|
20
|
+
const errors = tracker.getErrors();
|
|
21
|
+
expect(errors).toHaveLength(1);
|
|
22
|
+
expect(errors[0]!.type).toBe("api_error");
|
|
23
|
+
expect(errors[0]!.errorCategory).toBe("rate_limit");
|
|
24
|
+
expect(errors[0]!.message).toBe("Rate limit exceeded");
|
|
25
|
+
expect(errors[0]!.timestamp).toBeTruthy();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("addResultError tracks multiple error messages", () => {
|
|
29
|
+
const tracker = new SessionErrorTracker();
|
|
30
|
+
tracker.addResultError("error_max_turns", ["Turn limit reached", "Session ended"]);
|
|
31
|
+
|
|
32
|
+
expect(tracker.getErrors()).toHaveLength(2);
|
|
33
|
+
expect(tracker.getErrors()[0]!.type).toBe("result_error");
|
|
34
|
+
expect(tracker.getErrors()[0]!.errorCategory).toBe("error_max_turns");
|
|
35
|
+
expect(tracker.getErrors()[0]!.message).toBe("Turn limit reached");
|
|
36
|
+
expect(tracker.getErrors()[1]!.message).toBe("Session ended");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("addErrorEvent tracks an error event", () => {
|
|
40
|
+
const tracker = new SessionErrorTracker();
|
|
41
|
+
tracker.addErrorEvent("Something went wrong");
|
|
42
|
+
|
|
43
|
+
const errors = tracker.getErrors();
|
|
44
|
+
expect(errors).toHaveLength(1);
|
|
45
|
+
expect(errors[0]!.type).toBe("api_error");
|
|
46
|
+
expect(errors[0]!.message).toBe("Something went wrong");
|
|
47
|
+
expect(errors[0]!.errorCategory).toBeUndefined();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("addStderrError tracks a stderr error", () => {
|
|
51
|
+
const tracker = new SessionErrorTracker();
|
|
52
|
+
tracker.addStderrError("fatal: connection refused");
|
|
53
|
+
|
|
54
|
+
const errors = tracker.getErrors();
|
|
55
|
+
expect(errors).toHaveLength(1);
|
|
56
|
+
expect(errors[0]!.type).toBe("stderr_error");
|
|
57
|
+
expect(errors[0]!.message).toBe("fatal: connection refused");
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe("buildFailureReason", () => {
|
|
62
|
+
test("returns generic message when no errors", () => {
|
|
63
|
+
const tracker = new SessionErrorTracker();
|
|
64
|
+
expect(tracker.buildFailureReason(1)).toBe("Claude process exited with code 1");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("returns rate limit message", () => {
|
|
68
|
+
const tracker = new SessionErrorTracker();
|
|
69
|
+
tracker.addApiError("rate_limit", "Too many requests");
|
|
70
|
+
expect(tracker.buildFailureReason(1)).toBe("Rate limit hit: Too many requests");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("returns authentication failed message", () => {
|
|
74
|
+
const tracker = new SessionErrorTracker();
|
|
75
|
+
tracker.addApiError("authentication_failed", "Invalid API key");
|
|
76
|
+
expect(tracker.buildFailureReason(1)).toBe("Authentication failed: Invalid API key");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("returns billing error message", () => {
|
|
80
|
+
const tracker = new SessionErrorTracker();
|
|
81
|
+
tracker.addApiError("billing_error", "Insufficient funds");
|
|
82
|
+
expect(tracker.buildFailureReason(1)).toBe("Billing error: Insufficient funds");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("returns server error message", () => {
|
|
86
|
+
const tracker = new SessionErrorTracker();
|
|
87
|
+
tracker.addApiError("server_error", "Service unavailable");
|
|
88
|
+
expect(tracker.buildFailureReason(1)).toBe(
|
|
89
|
+
"Server error (API overloaded): Service unavailable",
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("returns max turns exceeded for result errors", () => {
|
|
94
|
+
const tracker = new SessionErrorTracker();
|
|
95
|
+
tracker.addResultError("error_max_turns", ["Reached 50 turns"]);
|
|
96
|
+
expect(tracker.buildFailureReason(1)).toBe("Max turns exceeded: Reached 50 turns");
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("returns budget limit exceeded for result errors", () => {
|
|
100
|
+
const tracker = new SessionErrorTracker();
|
|
101
|
+
tracker.addResultError("error_max_budget_usd", ["$5.00 limit reached"]);
|
|
102
|
+
expect(tracker.buildFailureReason(1)).toBe("Budget limit exceeded: $5.00 limit reached");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("returns error during execution for result errors", () => {
|
|
106
|
+
const tracker = new SessionErrorTracker();
|
|
107
|
+
tracker.addResultError("error_during_execution", ["Process crashed"]);
|
|
108
|
+
expect(tracker.buildFailureReason(1)).toBe("Error during execution: Process crashed");
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("returns generic session error for unknown result subtype", () => {
|
|
112
|
+
const tracker = new SessionErrorTracker();
|
|
113
|
+
tracker.addResultError("unknown_subtype", ["Something odd"]);
|
|
114
|
+
expect(tracker.buildFailureReason(2)).toBe("Session error (exit code 2): Something odd");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("falls back to session error when only stderr errors present", () => {
|
|
118
|
+
const tracker = new SessionErrorTracker();
|
|
119
|
+
tracker.addStderrError("segfault");
|
|
120
|
+
expect(tracker.buildFailureReason(139)).toBe("Session error (exit code 139): segfault");
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("falls back to session error for error events without category", () => {
|
|
124
|
+
const tracker = new SessionErrorTracker();
|
|
125
|
+
tracker.addErrorEvent("connection timeout");
|
|
126
|
+
expect(tracker.buildFailureReason(1)).toBe("Session error (exit code 1): connection timeout");
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test("shows count of additional errors when multiple unique messages", () => {
|
|
130
|
+
const tracker = new SessionErrorTracker();
|
|
131
|
+
tracker.addApiError("rate_limit", "Error one");
|
|
132
|
+
tracker.addApiError("rate_limit", "Error two");
|
|
133
|
+
tracker.addApiError("rate_limit", "Error three");
|
|
134
|
+
expect(tracker.buildFailureReason(1)).toBe("Rate limit hit: Error one (+2 more error(s))");
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("deduplicates identical error messages in count", () => {
|
|
138
|
+
const tracker = new SessionErrorTracker();
|
|
139
|
+
tracker.addApiError("rate_limit", "Same error");
|
|
140
|
+
tracker.addApiError("rate_limit", "Same error");
|
|
141
|
+
tracker.addApiError("rate_limit", "Different error");
|
|
142
|
+
expect(tracker.buildFailureReason(1)).toBe("Rate limit hit: Same error (+1 more error(s))");
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("uses first api error category as primary", () => {
|
|
146
|
+
const tracker = new SessionErrorTracker();
|
|
147
|
+
tracker.addApiError("rate_limit", "Rate limited");
|
|
148
|
+
tracker.addApiError("server_error", "Server down");
|
|
149
|
+
// First category (rate_limit) wins
|
|
150
|
+
expect(tracker.buildFailureReason(1)).toBe("Rate limit hit: Rate limited (+1 more error(s))");
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe("trackErrorFromJson", () => {
|
|
155
|
+
test("tracks assistant message with API error", () => {
|
|
156
|
+
const tracker = new SessionErrorTracker();
|
|
157
|
+
trackErrorFromJson(
|
|
158
|
+
{
|
|
159
|
+
type: "assistant",
|
|
160
|
+
message: {
|
|
161
|
+
error: "rate_limit",
|
|
162
|
+
content: [{ text: "Rate limit exceeded, please retry" }],
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
tracker,
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const errors = tracker.getErrors();
|
|
169
|
+
expect(errors).toHaveLength(1);
|
|
170
|
+
expect(errors[0]!.type).toBe("api_error");
|
|
171
|
+
expect(errors[0]!.errorCategory).toBe("rate_limit");
|
|
172
|
+
expect(errors[0]!.message).toBe("Rate limit exceeded, please retry");
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("tracks assistant message error with no content, falls back to error string", () => {
|
|
176
|
+
const tracker = new SessionErrorTracker();
|
|
177
|
+
trackErrorFromJson(
|
|
178
|
+
{
|
|
179
|
+
type: "assistant",
|
|
180
|
+
message: { error: "server_error" },
|
|
181
|
+
},
|
|
182
|
+
tracker,
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const errors = tracker.getErrors();
|
|
186
|
+
expect(errors).toHaveLength(1);
|
|
187
|
+
expect(errors[0]!.message).toBe("server_error");
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test("ignores assistant messages without error", () => {
|
|
191
|
+
const tracker = new SessionErrorTracker();
|
|
192
|
+
trackErrorFromJson({ type: "assistant", message: { content: [{ text: "Hello" }] } }, tracker);
|
|
193
|
+
expect(tracker.hasErrors()).toBe(false);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test("tracks explicit error events", () => {
|
|
197
|
+
const tracker = new SessionErrorTracker();
|
|
198
|
+
trackErrorFromJson({ type: "error", error: "Connection lost" }, tracker);
|
|
199
|
+
|
|
200
|
+
const errors = tracker.getErrors();
|
|
201
|
+
expect(errors).toHaveLength(1);
|
|
202
|
+
expect(errors[0]!.type).toBe("api_error");
|
|
203
|
+
expect(errors[0]!.message).toBe("Connection lost");
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("tracks error event with message field fallback", () => {
|
|
207
|
+
const tracker = new SessionErrorTracker();
|
|
208
|
+
trackErrorFromJson({ type: "error", message: "Timeout reached" }, tracker);
|
|
209
|
+
|
|
210
|
+
expect(tracker.getErrors()[0]!.message).toBe("Timeout reached");
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test("tracks error event with JSON fallback when no error or message", () => {
|
|
214
|
+
const tracker = new SessionErrorTracker();
|
|
215
|
+
trackErrorFromJson({ type: "error" }, tracker);
|
|
216
|
+
|
|
217
|
+
expect(tracker.getErrors()[0]!.message).toBe('{"type":"error"}');
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test("tracks result events with is_error true", () => {
|
|
221
|
+
const tracker = new SessionErrorTracker();
|
|
222
|
+
trackErrorFromJson(
|
|
223
|
+
{
|
|
224
|
+
type: "result",
|
|
225
|
+
is_error: true,
|
|
226
|
+
subtype: "error_max_turns",
|
|
227
|
+
errors: ["Max turns reached"],
|
|
228
|
+
},
|
|
229
|
+
tracker,
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
const errors = tracker.getErrors();
|
|
233
|
+
expect(errors).toHaveLength(1);
|
|
234
|
+
expect(errors[0]!.type).toBe("result_error");
|
|
235
|
+
expect(errors[0]!.errorCategory).toBe("error_max_turns");
|
|
236
|
+
expect(errors[0]!.message).toBe("Max turns reached");
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
test("tracks result event falling back to result field when no errors array", () => {
|
|
240
|
+
const tracker = new SessionErrorTracker();
|
|
241
|
+
trackErrorFromJson({ type: "result", is_error: true, result: "Something failed" }, tracker);
|
|
242
|
+
|
|
243
|
+
expect(tracker.getErrors()[0]!.message).toBe("Something failed");
|
|
244
|
+
expect(tracker.getErrors()[0]!.errorCategory).toBe("error_during_execution");
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test("tracks result event with unknown error when no errors or result", () => {
|
|
248
|
+
const tracker = new SessionErrorTracker();
|
|
249
|
+
trackErrorFromJson({ type: "result", is_error: true }, tracker);
|
|
250
|
+
|
|
251
|
+
expect(tracker.getErrors()[0]!.message).toBe("Unknown error");
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test("ignores result events without is_error", () => {
|
|
255
|
+
const tracker = new SessionErrorTracker();
|
|
256
|
+
trackErrorFromJson({ type: "result", result: "All good" }, tracker);
|
|
257
|
+
expect(tracker.hasErrors()).toBe(false);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test("ignores unrelated event types", () => {
|
|
261
|
+
const tracker = new SessionErrorTracker();
|
|
262
|
+
trackErrorFromJson({ type: "content_block_delta", delta: {} }, tracker);
|
|
263
|
+
expect(tracker.hasErrors()).toBe(false);
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
describe("parseStderrForErrors", () => {
|
|
268
|
+
test("ignores empty or whitespace-only stderr", () => {
|
|
269
|
+
const tracker = new SessionErrorTracker();
|
|
270
|
+
parseStderrForErrors("", tracker);
|
|
271
|
+
parseStderrForErrors(" ", tracker);
|
|
272
|
+
expect(tracker.hasErrors()).toBe(false);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
test("detects rate limit errors", () => {
|
|
276
|
+
const tracker = new SessionErrorTracker();
|
|
277
|
+
parseStderrForErrors("Rate limit exceeded for model", tracker);
|
|
278
|
+
|
|
279
|
+
expect(tracker.getErrors()).toHaveLength(1);
|
|
280
|
+
expect(tracker.getErrors()[0]!.message).toBe("Rate limit exceeded for model");
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
test("detects rate_limit with underscore", () => {
|
|
284
|
+
const tracker = new SessionErrorTracker();
|
|
285
|
+
parseStderrForErrors("rate_limit: too many requests", tracker);
|
|
286
|
+
|
|
287
|
+
expect(tracker.hasErrors()).toBe(true);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test("detects 429 status code", () => {
|
|
291
|
+
const tracker = new SessionErrorTracker();
|
|
292
|
+
parseStderrForErrors("HTTP 429 Too Many Requests", tracker);
|
|
293
|
+
|
|
294
|
+
expect(tracker.hasErrors()).toBe(true);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
test("detects authentication errors", () => {
|
|
298
|
+
const tracker = new SessionErrorTracker();
|
|
299
|
+
parseStderrForErrors("Authentication failed: invalid key", tracker);
|
|
300
|
+
|
|
301
|
+
expect(tracker.getErrors()[0]!.message).toBe(
|
|
302
|
+
"Authentication error: Authentication failed: invalid key",
|
|
303
|
+
);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
test("detects unauthorized errors", () => {
|
|
307
|
+
const tracker = new SessionErrorTracker();
|
|
308
|
+
parseStderrForErrors("Unauthorized access attempt", tracker);
|
|
309
|
+
|
|
310
|
+
expect(tracker.getErrors()[0]!.message).toContain("Authentication error:");
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
test("detects 401 status code", () => {
|
|
314
|
+
const tracker = new SessionErrorTracker();
|
|
315
|
+
parseStderrForErrors("HTTP 401 Unauthorized", tracker);
|
|
316
|
+
|
|
317
|
+
expect(tracker.getErrors()[0]!.message).toContain("Authentication error:");
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test("detects billing errors", () => {
|
|
321
|
+
const tracker = new SessionErrorTracker();
|
|
322
|
+
parseStderrForErrors("Billing account suspended", tracker);
|
|
323
|
+
|
|
324
|
+
expect(tracker.getErrors()[0]!.message).toContain("Billing error:");
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
test("detects payment errors", () => {
|
|
328
|
+
const tracker = new SessionErrorTracker();
|
|
329
|
+
parseStderrForErrors("Payment method declined", tracker);
|
|
330
|
+
|
|
331
|
+
expect(tracker.getErrors()[0]!.message).toContain("Billing error:");
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
test("detects generic error keyword", () => {
|
|
335
|
+
const tracker = new SessionErrorTracker();
|
|
336
|
+
parseStderrForErrors("Error: ECONNREFUSED", tracker);
|
|
337
|
+
|
|
338
|
+
expect(tracker.getErrors()[0]!.message).toBe("Error: ECONNREFUSED");
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
test("detects fatal keyword", () => {
|
|
342
|
+
const tracker = new SessionErrorTracker();
|
|
343
|
+
parseStderrForErrors("fatal: unable to access remote", tracker);
|
|
344
|
+
|
|
345
|
+
expect(tracker.getErrors()[0]!.message).toBe("fatal: unable to access remote");
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
test("detects panic keyword", () => {
|
|
349
|
+
const tracker = new SessionErrorTracker();
|
|
350
|
+
parseStderrForErrors("panic: runtime error: index out of range", tracker);
|
|
351
|
+
|
|
352
|
+
expect(tracker.getErrors()[0]!.message).toBe("panic: runtime error: index out of range");
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
test("uses only first line of multiline stderr", () => {
|
|
356
|
+
const tracker = new SessionErrorTracker();
|
|
357
|
+
parseStderrForErrors("Error: something broke\n at function.js:10\n at main.js:5", tracker);
|
|
358
|
+
|
|
359
|
+
expect(tracker.getErrors()[0]!.message).toBe("Error: something broke");
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
test("ignores stderr without recognized error patterns", () => {
|
|
363
|
+
const tracker = new SessionErrorTracker();
|
|
364
|
+
parseStderrForErrors("Debugger attached.\nWaiting for connections...", tracker);
|
|
365
|
+
|
|
366
|
+
expect(tracker.hasErrors()).toBe(false);
|
|
367
|
+
});
|
|
368
|
+
});
|