@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
|
@@ -1,934 +0,0 @@
|
|
|
1
|
-
# Runner-Level Polling Implementation Plan
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
Move task polling from inside Claude (MCP tool consuming tokens) to the runner level (TypeScript), so agents are only spawned when there's actual work to do. This reduces token consumption, improves reliability, and enables external event-driven spawning.
|
|
6
|
-
|
|
7
|
-
## Current State Analysis
|
|
8
|
-
|
|
9
|
-
### How It Works Now
|
|
10
|
-
|
|
11
|
-
1. **Runner** (`src/commands/runner.ts:208`): Infinite `while(true)` loop that spawns Claude immediately on each iteration
|
|
12
|
-
2. **Claude**: Receives `/start-worker` or `/start-leader` prompt, then uses `poll-task` MCP tool to wait for tasks
|
|
13
|
-
3. **poll-task** (`src/tools/poll-task.ts`): Polls database every 2 seconds for up to 1 minute, consuming Claude tokens the entire time
|
|
14
|
-
4. **Registration**: Happens inside Claude via `join-swarm` MCP tool
|
|
15
|
-
|
|
16
|
-
### Problems
|
|
17
|
-
|
|
18
|
-
- **Token consumption**: Every poll iteration consumes Claude tokens
|
|
19
|
-
- **Unreliability**: Claude decides when/how to poll, may miss tasks or poll inefficiently
|
|
20
|
-
- **No external control**: Can't trigger Claude spawn from outside events (Slack, webhooks, etc.)
|
|
21
|
-
- **Session persistence**: Claude session stays alive during polling, consuming resources
|
|
22
|
-
|
|
23
|
-
### Key Discoveries
|
|
24
|
-
|
|
25
|
-
- Runner spawns Claude via `Bun.spawn()` at `src/commands/runner.ts:85`
|
|
26
|
-
- Runner options defined at `src/commands/runner.ts:40-47`
|
|
27
|
-
- CLI parsing at `src/cli.tsx:38-101` handles flags like `--yolo`, `--system-prompt`
|
|
28
|
-
- HTTP API at `src/http.ts` already has `/me`, `/ping`, `/close` endpoints
|
|
29
|
-
- Database functions at `src/be/db.ts` have all needed queries (`getOfferedTasksForAgent`, `getPendingTaskForAgent`, `getUnassignedTasksCount`)
|
|
30
|
-
|
|
31
|
-
## Desired End State
|
|
32
|
-
|
|
33
|
-
After this implementation:
|
|
34
|
-
|
|
35
|
-
1. **Runner polls via HTTP API** before spawning Claude
|
|
36
|
-
2. **Claude is only spawned** when there's a trigger (task, mention, etc.)
|
|
37
|
-
3. **`--ai-loop` flag** enables the old behavior for backwards compatibility
|
|
38
|
-
4. **New API endpoints** support agent registration and trigger polling from the runner
|
|
39
|
-
5. **Agents register at runner level** before polling begins
|
|
40
|
-
|
|
41
|
-
### Verification
|
|
42
|
-
|
|
43
|
-
- `bun run worker` without `--ai-loop` should poll via HTTP and only spawn Claude when work arrives
|
|
44
|
-
- `bun run worker --ai-loop` should behave like the current implementation
|
|
45
|
-
- `GET /api/poll` should return triggers when tasks/mentions exist
|
|
46
|
-
- `POST /api/agents` should register a new agent
|
|
47
|
-
|
|
48
|
-
## What We're NOT Doing
|
|
49
|
-
|
|
50
|
-
- **Slack thread subscription changes**: This requires Slack API changes (out of scope)
|
|
51
|
-
- **Session persistence across spawns**: Each spawn will be a new Claude session (as designed)
|
|
52
|
-
- **Removing poll-task MCP tool**: It remains available for AI-loop mode and manual use
|
|
53
|
-
- **Lead-specific trigger types**: Same polling mechanism for both roles initially
|
|
54
|
-
|
|
55
|
-
## Implementation Approach
|
|
56
|
-
|
|
57
|
-
We'll implement this in four phases:
|
|
58
|
-
|
|
59
|
-
1. **Phase 1**: Add HTTP API endpoints for agent registration and trigger polling
|
|
60
|
-
2. **Phase 2**: Add `/review-offered-task` plugin command
|
|
61
|
-
3. **Phase 3**: Update runner to poll via API and spawn Claude on-demand
|
|
62
|
-
4. **Phase 4**: Update CLI and add `--ai-loop` flag for backwards compatibility
|
|
63
|
-
|
|
64
|
-
## Phase 1: HTTP API Endpoints
|
|
65
|
-
|
|
66
|
-
### Overview
|
|
67
|
-
|
|
68
|
-
Add two new HTTP API endpoints to enable runner-level polling.
|
|
69
|
-
|
|
70
|
-
**Important**: Both endpoints use database transactions (`getDb().transaction()`) to ensure:
|
|
71
|
-
- **Atomicity**: Check-and-create/update operations complete as a single unit
|
|
72
|
-
- **Consistency**: Multiple reads (e.g., checking offered tasks, then pending tasks) see a consistent database state
|
|
73
|
-
- **Isolation**: Concurrent requests don't interfere with each other (e.g., two agents trying to claim the same task)
|
|
74
|
-
|
|
75
|
-
### Changes Required
|
|
76
|
-
|
|
77
|
-
#### 1. Add Agent Registration Endpoint
|
|
78
|
-
|
|
79
|
-
**File**: `src/http.ts`
|
|
80
|
-
**Location**: After line 210 (after `/close` endpoint)
|
|
81
|
-
|
|
82
|
-
Add `POST /api/agents` endpoint for runner-level agent registration:
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
// POST /api/agents - Register a new agent (or return existing if already registered)
|
|
86
|
-
if (
|
|
87
|
-
req.method === "POST" &&
|
|
88
|
-
pathSegments[0] === "api" &&
|
|
89
|
-
pathSegments[1] === "agents" &&
|
|
90
|
-
!pathSegments[2]
|
|
91
|
-
) {
|
|
92
|
-
// Parse request body
|
|
93
|
-
const chunks: Buffer[] = [];
|
|
94
|
-
for await (const chunk of req) {
|
|
95
|
-
chunks.push(chunk);
|
|
96
|
-
}
|
|
97
|
-
const body = JSON.parse(Buffer.concat(chunks).toString());
|
|
98
|
-
|
|
99
|
-
// Validate required fields
|
|
100
|
-
if (!body.name || typeof body.name !== "string") {
|
|
101
|
-
res.writeHead(400, { "Content-Type": "application/json" });
|
|
102
|
-
res.end(JSON.stringify({ error: "Missing or invalid 'name' field" }));
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Use X-Agent-ID header if provided, otherwise generate new UUID
|
|
107
|
-
const agentId = myAgentId || crypto.randomUUID();
|
|
108
|
-
|
|
109
|
-
// Use transaction to ensure atomicity of check-and-create/update
|
|
110
|
-
const result = getDb().transaction(() => {
|
|
111
|
-
// Check if agent already exists
|
|
112
|
-
const existingAgent = getAgentById(agentId);
|
|
113
|
-
if (existingAgent) {
|
|
114
|
-
// Update status to idle if offline
|
|
115
|
-
if (existingAgent.status === "offline") {
|
|
116
|
-
updateAgentStatus(existingAgent.id, "idle");
|
|
117
|
-
}
|
|
118
|
-
return { agent: getAgentById(agentId), created: false };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Create new agent
|
|
122
|
-
const agent = createAgent({
|
|
123
|
-
id: agentId,
|
|
124
|
-
name: body.name,
|
|
125
|
-
isLead: body.isLead ?? false,
|
|
126
|
-
status: "idle",
|
|
127
|
-
description: body.description,
|
|
128
|
-
role: body.role,
|
|
129
|
-
capabilities: body.capabilities,
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
return { agent, created: true };
|
|
133
|
-
})();
|
|
134
|
-
|
|
135
|
-
res.writeHead(result.created ? 201 : 200, { "Content-Type": "application/json" });
|
|
136
|
-
res.end(JSON.stringify(result.agent));
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
**Required import**: Add `createAgent` to imports from `./be/db`
|
|
142
|
-
|
|
143
|
-
#### 2. Add Trigger Polling Endpoint
|
|
144
|
-
|
|
145
|
-
**File**: `src/http.ts`
|
|
146
|
-
**Location**: After the agent registration endpoint
|
|
147
|
-
|
|
148
|
-
Add `GET /api/poll` endpoint for runner-level trigger polling:
|
|
149
|
-
|
|
150
|
-
```typescript
|
|
151
|
-
// GET /api/poll - Poll for triggers (tasks, mentions, etc.)
|
|
152
|
-
if (req.method === "GET" && pathSegments[0] === "api" && pathSegments[1] === "poll") {
|
|
153
|
-
if (!myAgentId) {
|
|
154
|
-
res.writeHead(400, { "Content-Type": "application/json" });
|
|
155
|
-
res.end(JSON.stringify({ error: "Missing X-Agent-ID header" }));
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Use transaction for consistent reads across all trigger checks
|
|
160
|
-
const result = getDb().transaction(() => {
|
|
161
|
-
const agent = getAgentById(myAgentId);
|
|
162
|
-
if (!agent) {
|
|
163
|
-
return { error: "Agent not found", status: 404 };
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Check for offered tasks first (highest priority)
|
|
167
|
-
const offeredTasks = getOfferedTasksForAgent(myAgentId);
|
|
168
|
-
if (offeredTasks.length > 0) {
|
|
169
|
-
return {
|
|
170
|
-
trigger: {
|
|
171
|
-
type: "task_offered",
|
|
172
|
-
taskId: offeredTasks[0].id,
|
|
173
|
-
task: offeredTasks[0],
|
|
174
|
-
},
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Check for pending tasks (assigned directly to this agent)
|
|
179
|
-
const pendingTask = getPendingTaskForAgent(myAgentId);
|
|
180
|
-
if (pendingTask) {
|
|
181
|
-
return {
|
|
182
|
-
trigger: {
|
|
183
|
-
type: "task_assigned",
|
|
184
|
-
taskId: pendingTask.id,
|
|
185
|
-
task: pendingTask,
|
|
186
|
-
},
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// For lead agents, check for unread mentions
|
|
191
|
-
if (agent.isLead) {
|
|
192
|
-
const inbox = getInboxSummary(myAgentId);
|
|
193
|
-
if (inbox.mentionsCount > 0) {
|
|
194
|
-
return {
|
|
195
|
-
trigger: {
|
|
196
|
-
type: "unread_mentions",
|
|
197
|
-
mentionsCount: inbox.mentionsCount,
|
|
198
|
-
},
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Check for tasks needing assignment (unassigned tasks in pool)
|
|
203
|
-
const unassignedCount = getUnassignedTasksCount();
|
|
204
|
-
if (unassignedCount > 0) {
|
|
205
|
-
return {
|
|
206
|
-
trigger: {
|
|
207
|
-
type: "pool_tasks_available",
|
|
208
|
-
count: unassignedCount,
|
|
209
|
-
},
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// No trigger found
|
|
215
|
-
return { trigger: null };
|
|
216
|
-
})();
|
|
217
|
-
|
|
218
|
-
// Handle error case
|
|
219
|
-
if ("error" in result) {
|
|
220
|
-
res.writeHead(result.status, { "Content-Type": "application/json" });
|
|
221
|
-
res.end(JSON.stringify({ error: result.error }));
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
226
|
-
res.end(JSON.stringify(result));
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
**Required imports**: Add `getOfferedTasksForAgent`, `getPendingTaskForAgent`, `getUnassignedTasksCount` to imports from `./be/db`
|
|
232
|
-
|
|
233
|
-
### Success Criteria
|
|
234
|
-
|
|
235
|
-
#### Automated Verification:
|
|
236
|
-
- [x] TypeScript compiles without errors: `bun run tsc:check`
|
|
237
|
-
- [x] API returns 400 when X-Agent-ID missing for `/api/poll`
|
|
238
|
-
- [x] API returns 404 when agent doesn't exist
|
|
239
|
-
- [x] API returns trigger when offered task exists
|
|
240
|
-
- [x] API returns trigger when pending task exists
|
|
241
|
-
- [x] API returns `{ trigger: null }` when no work available
|
|
242
|
-
|
|
243
|
-
#### Manual Verification:
|
|
244
|
-
- [ ] Test with curl: `curl -X POST http://localhost:3013/api/agents -H "Content-Type: application/json" -H "X-Agent-ID: test-123" -d '{"name": "test-agent"}'`
|
|
245
|
-
- [ ] Test poll: `curl http://localhost:3013/api/poll -H "X-Agent-ID: test-123"`
|
|
246
|
-
|
|
247
|
-
**Implementation Note**: After completing this phase and all automated verification passes, pause here for manual confirmation before proceeding to Phase 2.
|
|
248
|
-
|
|
249
|
-
---
|
|
250
|
-
|
|
251
|
-
## Phase 2: Review Offered Task Command
|
|
252
|
-
|
|
253
|
-
### Overview
|
|
254
|
-
|
|
255
|
-
Add a new plugin command `/review-offered-task` that guides agents through the process of reviewing and accepting/rejecting offered tasks.
|
|
256
|
-
|
|
257
|
-
### Changes Required
|
|
258
|
-
|
|
259
|
-
#### 1. Create Plugin Command
|
|
260
|
-
|
|
261
|
-
**File**: `plugin/commands/review-offered-task.md` (NEW)
|
|
262
|
-
|
|
263
|
-
```markdown
|
|
264
|
-
---
|
|
265
|
-
description: Review a task that has been offered to you and decide whether to accept or reject it
|
|
266
|
-
argument-hint: [taskId]
|
|
267
|
-
---
|
|
268
|
-
|
|
269
|
-
# Review Offered Task
|
|
270
|
-
|
|
271
|
-
You have been offered a task. Your job is to review it and decide whether to accept or reject it based on your capabilities and current workload.
|
|
272
|
-
|
|
273
|
-
## Workflow
|
|
274
|
-
|
|
275
|
-
1. **Get task details**: Call the `get-task-details` tool with the provided `taskId` to understand what the task involves.
|
|
276
|
-
|
|
277
|
-
2. **Evaluate the task**: Consider:
|
|
278
|
-
- Does this task match your capabilities?
|
|
279
|
-
- Do you have the necessary context or access to complete it?
|
|
280
|
-
- Is the task description clear enough to proceed?
|
|
281
|
-
|
|
282
|
-
3. **Make a decision**:
|
|
283
|
-
- **Accept**: If you can complete this task, call `task-action` with `action: "accept"` and `taskId: "<taskId>"`. Then immediately use `/work-on-task <taskId>` to start working on it.
|
|
284
|
-
- **Reject**: If you cannot complete this task, call `task-action` with `action: "reject"`, `taskId: "<taskId>"`, and provide a `reason` explaining why you're rejecting it (e.g., "Task requires Python expertise which I don't have", "Task description is too vague").
|
|
285
|
-
|
|
286
|
-
## Example Accept Flow
|
|
287
|
-
|
|
288
|
-
\`\`\`
|
|
289
|
-
1. get-task-details taskId="abc-123"
|
|
290
|
-
2. [Review the task details]
|
|
291
|
-
3. task-action action="accept" taskId="abc-123"
|
|
292
|
-
4. /work-on-task abc-123
|
|
293
|
-
\`\`\`
|
|
294
|
-
|
|
295
|
-
## Example Reject Flow
|
|
296
|
-
|
|
297
|
-
\`\`\`
|
|
298
|
-
1. get-task-details taskId="abc-123"
|
|
299
|
-
2. [Review the task details]
|
|
300
|
-
3. task-action action="reject" taskId="abc-123" reason="Task requires access to production database which I don't have"
|
|
301
|
-
4. Reply "DONE" to end the session
|
|
302
|
-
\`\`\`
|
|
303
|
-
|
|
304
|
-
## Important Notes
|
|
305
|
-
|
|
306
|
-
- Always provide a clear reason when rejecting a task - this helps the lead agent reassign it appropriately
|
|
307
|
-
- If you accept, you must immediately start working on the task using `/work-on-task`
|
|
308
|
-
- If you reject, the task returns to the unassigned pool for reassignment
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
### Success Criteria
|
|
312
|
-
|
|
313
|
-
#### Automated Verification:
|
|
314
|
-
- [x] File exists at `plugin/commands/review-offered-task.md`
|
|
315
|
-
- [x] File has valid YAML frontmatter with `description` and `argument-hint`
|
|
316
|
-
|
|
317
|
-
#### Manual Verification:
|
|
318
|
-
- [ ] Command appears in Claude's available commands when running with the plugin
|
|
319
|
-
- [ ] Running `/review-offered-task <id>` provides clear guidance
|
|
320
|
-
|
|
321
|
-
**Implementation Note**: After completing this phase, pause here for manual confirmation before proceeding to Phase 3.
|
|
322
|
-
|
|
323
|
-
---
|
|
324
|
-
|
|
325
|
-
## Phase 3: Runner-Level Polling
|
|
326
|
-
|
|
327
|
-
### Overview
|
|
328
|
-
|
|
329
|
-
Update the runner to poll via HTTP API before spawning Claude, and only spawn when there's a trigger.
|
|
330
|
-
|
|
331
|
-
### Changes Required
|
|
332
|
-
|
|
333
|
-
#### 1. Add Trigger Types
|
|
334
|
-
|
|
335
|
-
**File**: `src/commands/runner.ts`
|
|
336
|
-
**Location**: After line 55 (after `RunClaudeIterationOptions` interface)
|
|
337
|
-
|
|
338
|
-
```typescript
|
|
339
|
-
/** Trigger types returned by the poll API */
|
|
340
|
-
interface Trigger {
|
|
341
|
-
type: "task_assigned" | "task_offered" | "unread_mentions" | "pool_tasks_available";
|
|
342
|
-
taskId?: string;
|
|
343
|
-
task?: unknown;
|
|
344
|
-
mentionsCount?: number;
|
|
345
|
-
count?: number;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/** Options for polling */
|
|
349
|
-
interface PollOptions {
|
|
350
|
-
swarmUrl: string;
|
|
351
|
-
apiKey: string;
|
|
352
|
-
agentId: string;
|
|
353
|
-
pollInterval: number;
|
|
354
|
-
pollTimeout: number;
|
|
355
|
-
}
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
#### 2. Add Registration Function
|
|
359
|
-
|
|
360
|
-
**File**: `src/commands/runner.ts`
|
|
361
|
-
**Location**: After the new interfaces
|
|
362
|
-
|
|
363
|
-
```typescript
|
|
364
|
-
/** Register agent via HTTP API */
|
|
365
|
-
async function registerAgent(opts: {
|
|
366
|
-
swarmUrl: string;
|
|
367
|
-
apiKey: string;
|
|
368
|
-
agentId: string;
|
|
369
|
-
name: string;
|
|
370
|
-
isLead: boolean;
|
|
371
|
-
capabilities?: string[];
|
|
372
|
-
}): Promise<void> {
|
|
373
|
-
const headers: Record<string, string> = {
|
|
374
|
-
"Content-Type": "application/json",
|
|
375
|
-
"X-Agent-ID": opts.agentId,
|
|
376
|
-
};
|
|
377
|
-
if (opts.apiKey) {
|
|
378
|
-
headers["Authorization"] = `Bearer ${opts.apiKey}`;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
const response = await fetch(`${opts.swarmUrl}/api/agents`, {
|
|
382
|
-
method: "POST",
|
|
383
|
-
headers,
|
|
384
|
-
body: JSON.stringify({
|
|
385
|
-
name: opts.name,
|
|
386
|
-
isLead: opts.isLead,
|
|
387
|
-
capabilities: opts.capabilities,
|
|
388
|
-
}),
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
if (!response.ok) {
|
|
392
|
-
const error = await response.text();
|
|
393
|
-
throw new Error(`Failed to register agent: ${response.status} ${error}`);
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
#### 3. Add Poll Function
|
|
399
|
-
|
|
400
|
-
**File**: `src/commands/runner.ts`
|
|
401
|
-
**Location**: After `registerAgent` function
|
|
402
|
-
|
|
403
|
-
```typescript
|
|
404
|
-
/** Poll for triggers via HTTP API */
|
|
405
|
-
async function pollForTrigger(opts: PollOptions): Promise<Trigger | null> {
|
|
406
|
-
const startTime = Date.now();
|
|
407
|
-
const headers: Record<string, string> = {
|
|
408
|
-
"X-Agent-ID": opts.agentId,
|
|
409
|
-
};
|
|
410
|
-
if (opts.apiKey) {
|
|
411
|
-
headers["Authorization"] = `Bearer ${opts.apiKey}`;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
while (Date.now() - startTime < opts.pollTimeout) {
|
|
415
|
-
try {
|
|
416
|
-
const response = await fetch(`${opts.swarmUrl}/api/poll`, {
|
|
417
|
-
method: "GET",
|
|
418
|
-
headers,
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
if (!response.ok) {
|
|
422
|
-
console.warn(`[runner] Poll request failed: ${response.status}`);
|
|
423
|
-
await Bun.sleep(opts.pollInterval);
|
|
424
|
-
continue;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
const data = (await response.json()) as { trigger: Trigger | null };
|
|
428
|
-
if (data.trigger) {
|
|
429
|
-
return data.trigger;
|
|
430
|
-
}
|
|
431
|
-
} catch (error) {
|
|
432
|
-
console.warn(`[runner] Poll request error: ${error}`);
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
await Bun.sleep(opts.pollInterval);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
return null; // Timeout reached, no trigger found
|
|
439
|
-
}
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
#### 4. Add Prompt Builder Function
|
|
443
|
-
|
|
444
|
-
**File**: `src/commands/runner.ts`
|
|
445
|
-
**Location**: After `pollForTrigger` function
|
|
446
|
-
|
|
447
|
-
```typescript
|
|
448
|
-
/** Build prompt based on trigger type */
|
|
449
|
-
function buildPromptForTrigger(trigger: Trigger, defaultPrompt: string): string {
|
|
450
|
-
switch (trigger.type) {
|
|
451
|
-
case "task_assigned":
|
|
452
|
-
// Use the work-on-task command with task ID
|
|
453
|
-
return `/work-on-task ${trigger.taskId}`;
|
|
454
|
-
|
|
455
|
-
case "task_offered":
|
|
456
|
-
// Use the review-offered-task command to accept/reject
|
|
457
|
-
return `/review-offered-task ${trigger.taskId}`;
|
|
458
|
-
|
|
459
|
-
case "unread_mentions":
|
|
460
|
-
// Check messages
|
|
461
|
-
return "/swarm-chat";
|
|
462
|
-
|
|
463
|
-
case "pool_tasks_available":
|
|
464
|
-
// Let lead review and assign tasks
|
|
465
|
-
return defaultPrompt;
|
|
466
|
-
|
|
467
|
-
default:
|
|
468
|
-
return defaultPrompt;
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
```
|
|
472
|
-
|
|
473
|
-
#### 5. Update RunnerOptions Interface
|
|
474
|
-
|
|
475
|
-
**File**: `src/commands/runner.ts`
|
|
476
|
-
**Location**: Line 40-47 (update existing interface)
|
|
477
|
-
|
|
478
|
-
```typescript
|
|
479
|
-
export interface RunnerOptions {
|
|
480
|
-
prompt?: string;
|
|
481
|
-
yolo?: boolean;
|
|
482
|
-
systemPrompt?: string;
|
|
483
|
-
systemPromptFile?: string;
|
|
484
|
-
logsDir?: string;
|
|
485
|
-
additionalArgs?: string[];
|
|
486
|
-
aiLoop?: boolean; // NEW: Use AI-based loop (old behavior)
|
|
487
|
-
}
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
#### 6. Update runAgent Function
|
|
491
|
-
|
|
492
|
-
**File**: `src/commands/runner.ts`
|
|
493
|
-
**Location**: Update the `runAgent` function (lines 138-258)
|
|
494
|
-
|
|
495
|
-
Replace the while loop section (lines 206-257) with:
|
|
496
|
-
|
|
497
|
-
```typescript
|
|
498
|
-
const isAiLoop = opts.aiLoop || process.env.AI_LOOP === "true";
|
|
499
|
-
const apiKey = process.env.API_KEY || "";
|
|
500
|
-
|
|
501
|
-
// Constants for polling
|
|
502
|
-
const POLL_INTERVAL_MS = 2000; // 2 seconds between polls
|
|
503
|
-
const POLL_TIMEOUT_MS = 60000; // 1 minute timeout before retrying
|
|
504
|
-
|
|
505
|
-
let iteration = 0;
|
|
506
|
-
|
|
507
|
-
if (!isAiLoop) {
|
|
508
|
-
// NEW: Runner-level polling mode
|
|
509
|
-
console.log(`[${role}] Mode: runner-level polling (use --ai-loop for AI-based polling)`);
|
|
510
|
-
|
|
511
|
-
// Register agent before starting
|
|
512
|
-
const agentName = process.env.AGENT_NAME || `${role}-${agentId.slice(0, 8)}`;
|
|
513
|
-
try {
|
|
514
|
-
await registerAgent({
|
|
515
|
-
swarmUrl,
|
|
516
|
-
apiKey,
|
|
517
|
-
agentId,
|
|
518
|
-
name: agentName,
|
|
519
|
-
isLead: role === "lead",
|
|
520
|
-
capabilities: config.capabilities,
|
|
521
|
-
});
|
|
522
|
-
console.log(`[${role}] Registered as "${agentName}" (ID: ${agentId})`);
|
|
523
|
-
} catch (error) {
|
|
524
|
-
console.error(`[${role}] Failed to register: ${error}`);
|
|
525
|
-
process.exit(1);
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
while (true) {
|
|
529
|
-
console.log(`\n[${role}] Polling for triggers...`);
|
|
530
|
-
|
|
531
|
-
const trigger = await pollForTrigger({
|
|
532
|
-
swarmUrl,
|
|
533
|
-
apiKey,
|
|
534
|
-
agentId,
|
|
535
|
-
pollInterval: POLL_INTERVAL_MS,
|
|
536
|
-
pollTimeout: POLL_TIMEOUT_MS,
|
|
537
|
-
});
|
|
538
|
-
|
|
539
|
-
if (!trigger) {
|
|
540
|
-
console.log(`[${role}] No trigger found, polling again...`);
|
|
541
|
-
continue;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
console.log(`[${role}] Trigger received: ${trigger.type}`);
|
|
545
|
-
|
|
546
|
-
// Build prompt based on trigger
|
|
547
|
-
const triggerPrompt = buildPromptForTrigger(trigger, prompt);
|
|
548
|
-
|
|
549
|
-
iteration++;
|
|
550
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
551
|
-
const logFile = `${logDir}/${timestamp}.jsonl`;
|
|
552
|
-
|
|
553
|
-
console.log(`\n[${role}] === Iteration ${iteration} ===`);
|
|
554
|
-
console.log(`[${role}] Logging to: ${logFile}`);
|
|
555
|
-
console.log(`[${role}] Prompt: ${triggerPrompt}`);
|
|
556
|
-
|
|
557
|
-
const metadata = {
|
|
558
|
-
type: metadataType,
|
|
559
|
-
sessionId,
|
|
560
|
-
iteration,
|
|
561
|
-
timestamp: new Date().toISOString(),
|
|
562
|
-
prompt: triggerPrompt,
|
|
563
|
-
trigger: trigger.type,
|
|
564
|
-
yolo: isYolo,
|
|
565
|
-
};
|
|
566
|
-
await Bun.write(logFile, `${JSON.stringify(metadata)}\n`);
|
|
567
|
-
|
|
568
|
-
const exitCode = await runClaudeIteration({
|
|
569
|
-
prompt: triggerPrompt,
|
|
570
|
-
logFile,
|
|
571
|
-
systemPrompt: resolvedSystemPrompt,
|
|
572
|
-
additionalArgs: opts.additionalArgs,
|
|
573
|
-
role,
|
|
574
|
-
});
|
|
575
|
-
|
|
576
|
-
if (exitCode !== 0) {
|
|
577
|
-
const errorLog = {
|
|
578
|
-
timestamp: new Date().toISOString(),
|
|
579
|
-
iteration,
|
|
580
|
-
exitCode,
|
|
581
|
-
trigger: trigger.type,
|
|
582
|
-
error: true,
|
|
583
|
-
};
|
|
584
|
-
|
|
585
|
-
const errorsFile = `${logDir}/errors.jsonl`;
|
|
586
|
-
const errorsFileRef = Bun.file(errorsFile);
|
|
587
|
-
const existingErrors = (await errorsFileRef.exists()) ? await errorsFileRef.text() : "";
|
|
588
|
-
await Bun.write(errorsFile, `${existingErrors}${JSON.stringify(errorLog)}\n`);
|
|
589
|
-
|
|
590
|
-
if (!isYolo) {
|
|
591
|
-
console.error(`[${role}] Claude exited with code ${exitCode}. Stopping.`);
|
|
592
|
-
console.error(`[${role}] Error logged to: ${errorsFile}`);
|
|
593
|
-
process.exit(exitCode);
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
console.warn(`[${role}] Claude exited with code ${exitCode}. YOLO mode - continuing...`);
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
console.log(`[${role}] Iteration ${iteration} complete. Polling for next trigger...`);
|
|
600
|
-
}
|
|
601
|
-
} else {
|
|
602
|
-
// Original AI-loop mode (existing behavior)
|
|
603
|
-
console.log(`[${role}] Mode: AI-based polling (legacy)`);
|
|
604
|
-
|
|
605
|
-
while (true) {
|
|
606
|
-
iteration++;
|
|
607
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
608
|
-
const logFile = `${logDir}/${timestamp}.jsonl`;
|
|
609
|
-
|
|
610
|
-
console.log(`\n[${role}] === Iteration ${iteration} ===`);
|
|
611
|
-
console.log(`[${role}] Logging to: ${logFile}`);
|
|
612
|
-
|
|
613
|
-
const metadata = {
|
|
614
|
-
type: metadataType,
|
|
615
|
-
sessionId,
|
|
616
|
-
iteration,
|
|
617
|
-
timestamp: new Date().toISOString(),
|
|
618
|
-
prompt,
|
|
619
|
-
yolo: isYolo,
|
|
620
|
-
};
|
|
621
|
-
await Bun.write(logFile, `${JSON.stringify(metadata)}\n`);
|
|
622
|
-
|
|
623
|
-
const exitCode = await runClaudeIteration({
|
|
624
|
-
prompt,
|
|
625
|
-
logFile,
|
|
626
|
-
systemPrompt: resolvedSystemPrompt,
|
|
627
|
-
additionalArgs: opts.additionalArgs,
|
|
628
|
-
role,
|
|
629
|
-
});
|
|
630
|
-
|
|
631
|
-
if (exitCode !== 0) {
|
|
632
|
-
const errorLog = {
|
|
633
|
-
timestamp: new Date().toISOString(),
|
|
634
|
-
iteration,
|
|
635
|
-
exitCode,
|
|
636
|
-
error: true,
|
|
637
|
-
};
|
|
638
|
-
|
|
639
|
-
const errorsFile = `${logDir}/errors.jsonl`;
|
|
640
|
-
const errorsFileRef = Bun.file(errorsFile);
|
|
641
|
-
const existingErrors = (await errorsFileRef.exists()) ? await errorsFileRef.text() : "";
|
|
642
|
-
await Bun.write(errorsFile, `${existingErrors}${JSON.stringify(errorLog)}\n`);
|
|
643
|
-
|
|
644
|
-
if (!isYolo) {
|
|
645
|
-
console.error(`[${role}] Claude exited with code ${exitCode}. Stopping.`);
|
|
646
|
-
console.error(`[${role}] Error logged to: ${errorsFile}`);
|
|
647
|
-
process.exit(exitCode);
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
console.warn(`[${role}] Claude exited with code ${exitCode}. YOLO mode - continuing...`);
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
console.log(`[${role}] Iteration ${iteration} complete. Starting next iteration...`);
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
```
|
|
657
|
-
|
|
658
|
-
### Success Criteria
|
|
659
|
-
|
|
660
|
-
#### Automated Verification:
|
|
661
|
-
- [x] TypeScript compiles without errors: `bun run tsc:check`
|
|
662
|
-
- [x] Runner starts without `--ai-loop` and logs "runner-level polling"
|
|
663
|
-
- [x] Runner with `--ai-loop` logs "AI-based polling (legacy)"
|
|
664
|
-
|
|
665
|
-
#### Manual Verification:
|
|
666
|
-
- [ ] Start MCP server: `bun run mcp`
|
|
667
|
-
- [ ] In another terminal, start worker: `AGENT_ID=test-worker SWARM_URL=http://localhost:3013 bun run worker`
|
|
668
|
-
- [ ] Verify worker polls and waits (no Claude spawned)
|
|
669
|
-
- [ ] Create a task via API and verify Claude is spawned
|
|
670
|
-
- [ ] Test `--ai-loop` flag works as before
|
|
671
|
-
|
|
672
|
-
**Implementation Note**: After completing this phase and all automated verification passes, pause here for manual confirmation before proceeding to Phase 4.
|
|
673
|
-
|
|
674
|
-
---
|
|
675
|
-
|
|
676
|
-
## Phase 4: CLI Flag and Final Integration
|
|
677
|
-
|
|
678
|
-
### Overview
|
|
679
|
-
|
|
680
|
-
Add the `--ai-loop` CLI flag and update documentation.
|
|
681
|
-
|
|
682
|
-
### Changes Required
|
|
683
|
-
|
|
684
|
-
#### 1. Update CLI Argument Parsing
|
|
685
|
-
|
|
686
|
-
**File**: `src/cli.tsx`
|
|
687
|
-
**Location**: Line 32 (add to ParsedArgs interface)
|
|
688
|
-
|
|
689
|
-
```typescript
|
|
690
|
-
interface ParsedArgs {
|
|
691
|
-
command: string | undefined;
|
|
692
|
-
port: string;
|
|
693
|
-
key: string;
|
|
694
|
-
msg: string;
|
|
695
|
-
headless: boolean;
|
|
696
|
-
dryRun: boolean;
|
|
697
|
-
restore: boolean;
|
|
698
|
-
yes: boolean;
|
|
699
|
-
yolo: boolean;
|
|
700
|
-
systemPrompt: string;
|
|
701
|
-
systemPromptFile: string;
|
|
702
|
-
additionalArgs: string[];
|
|
703
|
-
aiLoop: boolean; // NEW
|
|
704
|
-
}
|
|
705
|
-
```
|
|
706
|
-
|
|
707
|
-
**Location**: Line 47 (add to defaults in parseArgs)
|
|
708
|
-
|
|
709
|
-
```typescript
|
|
710
|
-
let aiLoop = false;
|
|
711
|
-
```
|
|
712
|
-
|
|
713
|
-
**Location**: After line 83 (add flag handling in parseArgs)
|
|
714
|
-
|
|
715
|
-
```typescript
|
|
716
|
-
} else if (arg === "--ai-loop") {
|
|
717
|
-
aiLoop = true;
|
|
718
|
-
}
|
|
719
|
-
```
|
|
720
|
-
|
|
721
|
-
**Location**: Line 99 (add to return object)
|
|
722
|
-
|
|
723
|
-
```typescript
|
|
724
|
-
return {
|
|
725
|
-
command,
|
|
726
|
-
port,
|
|
727
|
-
key,
|
|
728
|
-
msg,
|
|
729
|
-
headless,
|
|
730
|
-
dryRun,
|
|
731
|
-
restore,
|
|
732
|
-
yes,
|
|
733
|
-
yolo,
|
|
734
|
-
systemPrompt,
|
|
735
|
-
systemPromptFile,
|
|
736
|
-
additionalArgs,
|
|
737
|
-
aiLoop, // NEW
|
|
738
|
-
};
|
|
739
|
-
```
|
|
740
|
-
|
|
741
|
-
#### 2. Update WorkerRunner and LeadRunner Components
|
|
742
|
-
|
|
743
|
-
**File**: `src/cli.tsx`
|
|
744
|
-
**Location**: Line 432 (update RunnerProps interface)
|
|
745
|
-
|
|
746
|
-
```typescript
|
|
747
|
-
interface RunnerProps {
|
|
748
|
-
prompt: string;
|
|
749
|
-
yolo: boolean;
|
|
750
|
-
systemPrompt: string;
|
|
751
|
-
systemPromptFile: string;
|
|
752
|
-
additionalArgs: string[];
|
|
753
|
-
aiLoop: boolean; // NEW
|
|
754
|
-
}
|
|
755
|
-
```
|
|
756
|
-
|
|
757
|
-
**Location**: Lines 440-465 (update WorkerRunner)
|
|
758
|
-
|
|
759
|
-
Add `aiLoop` to the destructured props and pass it to `runWorker`:
|
|
760
|
-
|
|
761
|
-
```typescript
|
|
762
|
-
function WorkerRunner({
|
|
763
|
-
prompt,
|
|
764
|
-
yolo,
|
|
765
|
-
systemPrompt,
|
|
766
|
-
systemPromptFile,
|
|
767
|
-
additionalArgs,
|
|
768
|
-
aiLoop, // NEW
|
|
769
|
-
}: RunnerProps) {
|
|
770
|
-
const { exit } = useApp();
|
|
771
|
-
|
|
772
|
-
useEffect(() => {
|
|
773
|
-
runWorker({
|
|
774
|
-
prompt: prompt || undefined,
|
|
775
|
-
yolo,
|
|
776
|
-
systemPrompt: systemPrompt || undefined,
|
|
777
|
-
systemPromptFile: systemPromptFile || undefined,
|
|
778
|
-
additionalArgs,
|
|
779
|
-
logsDir: "./logs",
|
|
780
|
-
aiLoop, // NEW
|
|
781
|
-
}).catch((err) => {
|
|
782
|
-
console.error("[error] Worker encountered an error:", err);
|
|
783
|
-
exit(err);
|
|
784
|
-
});
|
|
785
|
-
}, [prompt, yolo, systemPrompt, systemPromptFile, additionalArgs, aiLoop, exit]);
|
|
786
|
-
|
|
787
|
-
return null;
|
|
788
|
-
}
|
|
789
|
-
```
|
|
790
|
-
|
|
791
|
-
**Location**: Lines 467-486 (update LeadRunner similarly)
|
|
792
|
-
|
|
793
|
-
#### 3. Update Switch Statement
|
|
794
|
-
|
|
795
|
-
**File**: `src/cli.tsx`
|
|
796
|
-
**Location**: Lines 540-559 (update worker and lead cases)
|
|
797
|
-
|
|
798
|
-
```typescript
|
|
799
|
-
case "worker":
|
|
800
|
-
return (
|
|
801
|
-
<WorkerRunner
|
|
802
|
-
prompt={msg}
|
|
803
|
-
yolo={yolo}
|
|
804
|
-
systemPrompt={systemPrompt}
|
|
805
|
-
systemPromptFile={systemPromptFile}
|
|
806
|
-
additionalArgs={additionalArgs}
|
|
807
|
-
aiLoop={aiLoop} // NEW
|
|
808
|
-
/>
|
|
809
|
-
);
|
|
810
|
-
case "lead":
|
|
811
|
-
return (
|
|
812
|
-
<LeadRunner
|
|
813
|
-
prompt={msg}
|
|
814
|
-
yolo={yolo}
|
|
815
|
-
systemPrompt={systemPrompt}
|
|
816
|
-
systemPromptFile={systemPromptFile}
|
|
817
|
-
additionalArgs={additionalArgs}
|
|
818
|
-
aiLoop={aiLoop} // NEW
|
|
819
|
-
/>
|
|
820
|
-
);
|
|
821
|
-
```
|
|
822
|
-
|
|
823
|
-
#### 4. Update Help Text
|
|
824
|
-
|
|
825
|
-
**File**: `src/cli.tsx`
|
|
826
|
-
**Location**: After line 255 (add --ai-loop to worker/lead options)
|
|
827
|
-
|
|
828
|
-
```tsx
|
|
829
|
-
<Box>
|
|
830
|
-
<Box width={30}>
|
|
831
|
-
<Text color="yellow">--ai-loop</Text>
|
|
832
|
-
</Box>
|
|
833
|
-
<Text>Use AI-based polling (legacy mode)</Text>
|
|
834
|
-
</Box>
|
|
835
|
-
```
|
|
836
|
-
|
|
837
|
-
#### 5. Update Environment Variable Documentation
|
|
838
|
-
|
|
839
|
-
**File**: `src/cli.tsx`
|
|
840
|
-
**Location**: After line 336 (add AI_LOOP env var)
|
|
841
|
-
|
|
842
|
-
```tsx
|
|
843
|
-
<Box>
|
|
844
|
-
<Box width={24}>
|
|
845
|
-
<Text color="magenta">AI_LOOP</Text>
|
|
846
|
-
</Box>
|
|
847
|
-
<Text>If "true", use AI-based polling</Text>
|
|
848
|
-
</Box>
|
|
849
|
-
```
|
|
850
|
-
|
|
851
|
-
### Success Criteria
|
|
852
|
-
|
|
853
|
-
#### Automated Verification:
|
|
854
|
-
- [x] TypeScript compiles without errors: `bun run tsc:check`
|
|
855
|
-
- [x] Linting passes: `bun run lint`
|
|
856
|
-
- [x] `bun run worker --help` shows `--ai-loop` option
|
|
857
|
-
|
|
858
|
-
#### Manual Verification:
|
|
859
|
-
- [ ] `bun run worker` defaults to runner-level polling
|
|
860
|
-
- [ ] `bun run worker --ai-loop` uses AI-based polling
|
|
861
|
-
- [ ] `AI_LOOP=true bun run worker` uses AI-based polling
|
|
862
|
-
- [ ] `bun run lead` defaults to runner-level polling
|
|
863
|
-
- [ ] `bun run lead --ai-loop` uses AI-based polling
|
|
864
|
-
|
|
865
|
-
---
|
|
866
|
-
|
|
867
|
-
## Testing Strategy
|
|
868
|
-
|
|
869
|
-
### Unit Tests
|
|
870
|
-
|
|
871
|
-
No new unit tests required - this is primarily integration behavior.
|
|
872
|
-
|
|
873
|
-
### Integration Tests
|
|
874
|
-
|
|
875
|
-
Create a test script to verify the polling mechanism:
|
|
876
|
-
|
|
877
|
-
```bash
|
|
878
|
-
#!/bin/bash
|
|
879
|
-
# test-runner-polling.sh
|
|
880
|
-
|
|
881
|
-
# Start MCP server in background
|
|
882
|
-
bun run mcp &
|
|
883
|
-
MCP_PID=$!
|
|
884
|
-
sleep 2
|
|
885
|
-
|
|
886
|
-
# Start worker with runner-level polling
|
|
887
|
-
AGENT_ID=test-worker SWARM_URL=http://localhost:3013 timeout 10 bun run worker &
|
|
888
|
-
WORKER_PID=$!
|
|
889
|
-
sleep 3
|
|
890
|
-
|
|
891
|
-
# Create a task
|
|
892
|
-
curl -X POST http://localhost:3013/api/tasks \
|
|
893
|
-
-H "Content-Type: application/json" \
|
|
894
|
-
-H "X-Agent-ID: lead-agent" \
|
|
895
|
-
-d '{"task": "Test task", "agentId": "test-worker"}'
|
|
896
|
-
|
|
897
|
-
# Wait for worker to pick up task
|
|
898
|
-
sleep 5
|
|
899
|
-
|
|
900
|
-
# Cleanup
|
|
901
|
-
kill $WORKER_PID $MCP_PID 2>/dev/null
|
|
902
|
-
```
|
|
903
|
-
|
|
904
|
-
### Manual Testing Steps
|
|
905
|
-
|
|
906
|
-
1. Start MCP server: `bun run mcp`
|
|
907
|
-
2. Start worker in new terminal: `AGENT_ID=test-worker SWARM_URL=http://localhost:3013 bun run worker`
|
|
908
|
-
3. Observe: Worker should log "Polling for triggers..." and wait
|
|
909
|
-
4. Create a task via dashboard or API
|
|
910
|
-
5. Observe: Worker should log trigger received and spawn Claude
|
|
911
|
-
6. Test `--ai-loop` mode works as before
|
|
912
|
-
|
|
913
|
-
## Performance Considerations
|
|
914
|
-
|
|
915
|
-
- **Reduced token consumption**: Claude only spawned when there's work (major savings)
|
|
916
|
-
- **Poll interval**: 2 seconds is reasonable; can be tuned via env var if needed
|
|
917
|
-
- **Poll timeout**: 1 minute before retry loop; keeps connections fresh
|
|
918
|
-
- **HTTP overhead**: Minimal compared to Claude session costs
|
|
919
|
-
|
|
920
|
-
## Migration Notes
|
|
921
|
-
|
|
922
|
-
- **Backwards compatible**: `--ai-loop` flag preserves existing behavior
|
|
923
|
-
- **No database changes**: Uses existing tables and queries
|
|
924
|
-
- **No breaking changes**: Existing commands work as before
|
|
925
|
-
|
|
926
|
-
## References
|
|
927
|
-
|
|
928
|
-
- Related research: `thoughts/shared/research/2025-12-22-runner-loop-architecture.md`
|
|
929
|
-
- Runner implementation: `src/commands/runner.ts:138-258`
|
|
930
|
-
- HTTP API: `src/http.ts:72-583`
|
|
931
|
-
- CLI parsing: `src/cli.tsx:38-101`
|
|
932
|
-
- Poll-task MCP tool: `src/tools/poll-task.ts`
|
|
933
|
-
- Work-on-task command: `plugin/commands/work-on-task.md`
|
|
934
|
-
- Review-offered-task command (NEW): `plugin/commands/review-offered-task.md`
|