@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,103 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ExecutorMeta } from "../../types";
|
|
3
|
+
import { BaseExecutor, type ExecutorResult } from "./base";
|
|
4
|
+
|
|
5
|
+
// ─── Schemas ────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
export const ScriptConfigSchema = z.object({
|
|
8
|
+
runtime: z.enum(["bash", "ts", "python"]),
|
|
9
|
+
script: z.string(),
|
|
10
|
+
args: z.array(z.string()).optional(),
|
|
11
|
+
timeout: z.number().int().min(1000).default(30_000),
|
|
12
|
+
cwd: z.string().optional(),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const ScriptOutputSchema = z.object({
|
|
16
|
+
exitCode: z.number(),
|
|
17
|
+
stdout: z.string(),
|
|
18
|
+
stderr: z.string(),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// ─── Executor ───────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
const DEFAULT_TIMEOUT = 30_000;
|
|
24
|
+
|
|
25
|
+
export class ScriptExecutor extends BaseExecutor<
|
|
26
|
+
typeof ScriptConfigSchema,
|
|
27
|
+
typeof ScriptOutputSchema
|
|
28
|
+
> {
|
|
29
|
+
readonly type = "script";
|
|
30
|
+
readonly mode = "instant" as const;
|
|
31
|
+
readonly configSchema = ScriptConfigSchema;
|
|
32
|
+
readonly outputSchema = ScriptOutputSchema;
|
|
33
|
+
|
|
34
|
+
protected async execute(
|
|
35
|
+
config: z.infer<typeof ScriptConfigSchema>,
|
|
36
|
+
_context: Readonly<Record<string, unknown>>,
|
|
37
|
+
_meta: ExecutorMeta,
|
|
38
|
+
): Promise<ExecutorResult<z.infer<typeof ScriptOutputSchema>>> {
|
|
39
|
+
const timeoutMs = config.timeout ?? DEFAULT_TIMEOUT;
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const result = await Promise.race([this.runScript(config), this.timeoutPromise(timeoutMs)]);
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
status: "success",
|
|
46
|
+
output: result,
|
|
47
|
+
nextPort: result.exitCode === 0 ? "success" : "failure",
|
|
48
|
+
};
|
|
49
|
+
} catch (err) {
|
|
50
|
+
return {
|
|
51
|
+
status: "failed",
|
|
52
|
+
error: `Script execution error: ${err instanceof Error ? err.message : String(err)}`,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private async runScript(config: z.infer<typeof ScriptConfigSchema>): Promise<{
|
|
58
|
+
exitCode: number;
|
|
59
|
+
stdout: string;
|
|
60
|
+
stderr: string;
|
|
61
|
+
}> {
|
|
62
|
+
const { runtime, script, args = [], cwd } = config;
|
|
63
|
+
let cmd: string[];
|
|
64
|
+
|
|
65
|
+
switch (runtime) {
|
|
66
|
+
case "bash":
|
|
67
|
+
cmd = ["bash", "-c", script, ...args];
|
|
68
|
+
break;
|
|
69
|
+
case "ts":
|
|
70
|
+
cmd = ["bun", "-e", script, ...args];
|
|
71
|
+
break;
|
|
72
|
+
case "python":
|
|
73
|
+
cmd = ["python3", "-c", script, ...args];
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const proc = Bun.spawn(cmd, {
|
|
78
|
+
stdout: "pipe",
|
|
79
|
+
stderr: "pipe",
|
|
80
|
+
cwd: cwd ?? undefined,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
84
|
+
new Response(proc.stdout).text(),
|
|
85
|
+
new Response(proc.stderr).text(),
|
|
86
|
+
proc.exited,
|
|
87
|
+
]);
|
|
88
|
+
|
|
89
|
+
return { exitCode, stdout: stdout.trimEnd(), stderr: stderr.trimEnd() };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private timeoutPromise(ms: number): Promise<never> {
|
|
93
|
+
return new Promise((_resolve, reject) => {
|
|
94
|
+
const id = globalThis.setTimeout(() => {
|
|
95
|
+
reject(new Error(`Script timed out after ${ms}ms`));
|
|
96
|
+
}, ms);
|
|
97
|
+
// Ensure the timer doesn't keep the process alive
|
|
98
|
+
if (typeof id === "object" && "unref" in id) {
|
|
99
|
+
(id as NodeJS.Timeout).unref();
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ExecutorMeta } from "../../types";
|
|
3
|
+
import { BaseExecutor, type ExecutorResult } from "./base";
|
|
4
|
+
|
|
5
|
+
// ─── Schemas ────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
export const ValidateConfigSchema = z.object({
|
|
8
|
+
targetNodeId: z.string(),
|
|
9
|
+
prompt: z.string().optional(),
|
|
10
|
+
schema: z.record(z.string(), z.unknown()).optional(),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export const ValidateOutputSchema = z.object({
|
|
14
|
+
pass: z.boolean(),
|
|
15
|
+
reasoning: z.string(),
|
|
16
|
+
confidence: z.number().min(0).max(1),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// ─── Executor ───────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
export class ValidateExecutor extends BaseExecutor<
|
|
22
|
+
typeof ValidateConfigSchema,
|
|
23
|
+
typeof ValidateOutputSchema
|
|
24
|
+
> {
|
|
25
|
+
readonly type = "validate";
|
|
26
|
+
readonly mode = "instant" as const;
|
|
27
|
+
readonly configSchema = ValidateConfigSchema;
|
|
28
|
+
readonly outputSchema = ValidateOutputSchema;
|
|
29
|
+
|
|
30
|
+
protected async execute(
|
|
31
|
+
config: z.infer<typeof ValidateConfigSchema>,
|
|
32
|
+
context: Readonly<Record<string, unknown>>,
|
|
33
|
+
_meta: ExecutorMeta,
|
|
34
|
+
): Promise<ExecutorResult<z.infer<typeof ValidateOutputSchema>>> {
|
|
35
|
+
const targetOutput = context[config.targetNodeId];
|
|
36
|
+
if (targetOutput === undefined) {
|
|
37
|
+
return {
|
|
38
|
+
status: "success",
|
|
39
|
+
output: {
|
|
40
|
+
pass: false,
|
|
41
|
+
reasoning: `Target node "${config.targetNodeId}" has no output in context`,
|
|
42
|
+
confidence: 1,
|
|
43
|
+
},
|
|
44
|
+
nextPort: "fail",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Schema-based validation (no LLM call needed)
|
|
49
|
+
if (config.schema) {
|
|
50
|
+
return this.validateWithSchema(targetOutput, config.schema);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Prompt-based validation (uses LLM)
|
|
54
|
+
if (config.prompt) {
|
|
55
|
+
return this.validateWithLlm(targetOutput, config.prompt, context);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Neither schema nor prompt — just check that output exists
|
|
59
|
+
return {
|
|
60
|
+
status: "success",
|
|
61
|
+
output: { pass: true, reasoning: "Target node output exists", confidence: 1 },
|
|
62
|
+
nextPort: "pass",
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private validateWithSchema(
|
|
67
|
+
targetOutput: unknown,
|
|
68
|
+
schema: Record<string, unknown>,
|
|
69
|
+
): ExecutorResult<z.infer<typeof ValidateOutputSchema>> {
|
|
70
|
+
try {
|
|
71
|
+
// Use JSON Schema validation via Zod's loose parsing:
|
|
72
|
+
// Convert the JSON Schema to a basic check. For full JSON Schema support
|
|
73
|
+
// we'd need ajv, but for now we do structural matching.
|
|
74
|
+
const errors = validateJsonSchemaBasic(targetOutput, schema);
|
|
75
|
+
if (errors.length === 0) {
|
|
76
|
+
return {
|
|
77
|
+
status: "success",
|
|
78
|
+
output: { pass: true, reasoning: "Output matches schema", confidence: 1 },
|
|
79
|
+
nextPort: "pass",
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
status: "success",
|
|
84
|
+
output: {
|
|
85
|
+
pass: false,
|
|
86
|
+
reasoning: `Schema validation failed: ${errors.join("; ")}`,
|
|
87
|
+
confidence: 1,
|
|
88
|
+
},
|
|
89
|
+
nextPort: "fail",
|
|
90
|
+
};
|
|
91
|
+
} catch (err) {
|
|
92
|
+
return {
|
|
93
|
+
status: "success",
|
|
94
|
+
output: {
|
|
95
|
+
pass: false,
|
|
96
|
+
reasoning: `Schema validation error: ${err instanceof Error ? err.message : String(err)}`,
|
|
97
|
+
confidence: 0.5,
|
|
98
|
+
},
|
|
99
|
+
nextPort: "fail",
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private async validateWithLlm(
|
|
105
|
+
targetOutput: unknown,
|
|
106
|
+
prompt: string,
|
|
107
|
+
context: Readonly<Record<string, unknown>>,
|
|
108
|
+
): Promise<ExecutorResult<z.infer<typeof ValidateOutputSchema>>> {
|
|
109
|
+
const interpolatedPrompt = this.deps.interpolate(prompt, context as Record<string, unknown>);
|
|
110
|
+
const outputStr =
|
|
111
|
+
typeof targetOutput === "string" ? targetOutput : JSON.stringify(targetOutput);
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
const { createOpenAI } = await import("@ai-sdk/openai");
|
|
115
|
+
const { generateObject, jsonSchema } = await import("ai");
|
|
116
|
+
|
|
117
|
+
const openrouter = createOpenAI({
|
|
118
|
+
baseURL: "https://openrouter.ai/api/v1",
|
|
119
|
+
apiKey: process.env.OPENROUTER_API_KEY,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const { object } = await generateObject({
|
|
123
|
+
model: openrouter("google/gemini-2.0-flash-001"),
|
|
124
|
+
schema: jsonSchema({
|
|
125
|
+
type: "object",
|
|
126
|
+
properties: {
|
|
127
|
+
pass: { type: "boolean" },
|
|
128
|
+
reasoning: { type: "string" },
|
|
129
|
+
confidence: { type: "number", minimum: 0, maximum: 1 },
|
|
130
|
+
},
|
|
131
|
+
required: ["pass", "reasoning", "confidence"],
|
|
132
|
+
}),
|
|
133
|
+
prompt: `Evaluate the following output against the validation criteria.
|
|
134
|
+
|
|
135
|
+
Criteria: ${interpolatedPrompt}
|
|
136
|
+
|
|
137
|
+
Output to validate:
|
|
138
|
+
${outputStr}
|
|
139
|
+
|
|
140
|
+
Respond with pass (boolean), reasoning (string), and confidence (0-1).`,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const result = object as { pass: boolean; reasoning: string; confidence: number };
|
|
144
|
+
return {
|
|
145
|
+
status: "success",
|
|
146
|
+
output: result,
|
|
147
|
+
nextPort: result.pass ? "pass" : "fail",
|
|
148
|
+
};
|
|
149
|
+
} catch (err) {
|
|
150
|
+
return {
|
|
151
|
+
status: "success",
|
|
152
|
+
output: {
|
|
153
|
+
pass: false,
|
|
154
|
+
reasoning: `LLM validation failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
155
|
+
confidence: 0,
|
|
156
|
+
},
|
|
157
|
+
nextPort: "fail",
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ─── Basic JSON Schema Validator ────────────────────────────
|
|
164
|
+
|
|
165
|
+
function validateJsonSchemaBasic(value: unknown, schema: Record<string, unknown>): string[] {
|
|
166
|
+
const errors: string[] = [];
|
|
167
|
+
|
|
168
|
+
if (schema.type) {
|
|
169
|
+
const expectedType = schema.type as string;
|
|
170
|
+
if (expectedType === "object") {
|
|
171
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
172
|
+
errors.push(`Expected object, got ${Array.isArray(value) ? "array" : typeof value}`);
|
|
173
|
+
return errors;
|
|
174
|
+
}
|
|
175
|
+
// Check properties with const/enum constraints
|
|
176
|
+
if (schema.properties && typeof schema.properties === "object") {
|
|
177
|
+
const props = schema.properties as Record<string, Record<string, unknown>>;
|
|
178
|
+
const obj = value as Record<string, unknown>;
|
|
179
|
+
for (const [key, propSchema] of Object.entries(props)) {
|
|
180
|
+
if ("const" in propSchema && obj[key] !== propSchema.const) {
|
|
181
|
+
errors.push(
|
|
182
|
+
`Property "${key}": expected const ${JSON.stringify(propSchema.const)}, got ${JSON.stringify(obj[key])}`,
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
if ("enum" in propSchema && Array.isArray(propSchema.enum)) {
|
|
186
|
+
if (!propSchema.enum.includes(obj[key])) {
|
|
187
|
+
errors.push(
|
|
188
|
+
`Property "${key}": expected one of ${JSON.stringify(propSchema.enum)}, got ${JSON.stringify(obj[key])}`,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Check required fields
|
|
195
|
+
if (Array.isArray(schema.required)) {
|
|
196
|
+
const obj = value as Record<string, unknown>;
|
|
197
|
+
for (const key of schema.required as string[]) {
|
|
198
|
+
if (!(key in obj)) {
|
|
199
|
+
errors.push(`Missing required property "${key}"`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
} else if (expectedType === "string" && typeof value !== "string") {
|
|
204
|
+
errors.push(`Expected string, got ${typeof value}`);
|
|
205
|
+
} else if (expectedType === "number" && typeof value !== "number") {
|
|
206
|
+
errors.push(`Expected number, got ${typeof value}`);
|
|
207
|
+
} else if (expectedType === "boolean" && typeof value !== "boolean") {
|
|
208
|
+
errors.push(`Expected boolean, got ${typeof value}`);
|
|
209
|
+
} else if (expectedType === "array" && !Array.isArray(value)) {
|
|
210
|
+
errors.push(`Expected array, got ${typeof value}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return errors;
|
|
215
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ExecutorMeta } from "../../types";
|
|
3
|
+
import { BaseExecutor, type ExecutorResult } from "./base";
|
|
4
|
+
|
|
5
|
+
// ─── Schemas ────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
export const VcsConfigSchema = z.object({
|
|
8
|
+
action: z.enum(["create-issue", "create-pr", "comment"]),
|
|
9
|
+
provider: z.enum(["github", "gitlab"]),
|
|
10
|
+
repo: z.string(),
|
|
11
|
+
title: z.string().optional(),
|
|
12
|
+
body: z.string().optional(),
|
|
13
|
+
branch: z.string().optional(),
|
|
14
|
+
baseBranch: z.string().optional(),
|
|
15
|
+
issueNumber: z.number().optional(),
|
|
16
|
+
prNumber: z.number().optional(),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const VcsOutputSchema = z.object({
|
|
20
|
+
url: z.string(),
|
|
21
|
+
id: z.union([z.string(), z.number()]),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// ─── Executor ───────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
export class VcsExecutor extends BaseExecutor<typeof VcsConfigSchema, typeof VcsOutputSchema> {
|
|
27
|
+
readonly type = "vcs";
|
|
28
|
+
readonly mode = "instant" as const;
|
|
29
|
+
readonly configSchema = VcsConfigSchema;
|
|
30
|
+
readonly outputSchema = VcsOutputSchema;
|
|
31
|
+
|
|
32
|
+
protected async execute(
|
|
33
|
+
config: z.infer<typeof VcsConfigSchema>,
|
|
34
|
+
context: Readonly<Record<string, unknown>>,
|
|
35
|
+
_meta: ExecutorMeta,
|
|
36
|
+
): Promise<ExecutorResult<z.infer<typeof VcsOutputSchema>>> {
|
|
37
|
+
// Stub implementation — validate config and return mock output.
|
|
38
|
+
// Real GitHub/GitLab integration will be added in a follow-up.
|
|
39
|
+
const title = config.title
|
|
40
|
+
? this.deps.interpolate(config.title, context as Record<string, unknown>)
|
|
41
|
+
: "";
|
|
42
|
+
const body = config.body
|
|
43
|
+
? this.deps.interpolate(config.body, context as Record<string, unknown>)
|
|
44
|
+
: "";
|
|
45
|
+
|
|
46
|
+
console.log(
|
|
47
|
+
`[vcs] Stub — ${config.action} on ${config.provider}/${config.repo}: title="${title}" body="${body.slice(0, 80)}"`,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const mockId = `stub-${Date.now()}`;
|
|
51
|
+
const mockUrl = `https://${config.provider}.com/${config.repo}/${config.action}/${mockId}`;
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
status: "success",
|
|
55
|
+
output: { url: mockUrl, id: mockId },
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export { findEntryNodes, getSuccessors } from "./definition";
|
|
2
|
+
export { startWorkflowExecution } from "./engine";
|
|
3
|
+
export { workflowEventBus } from "./event-bus";
|
|
4
|
+
export { recoverIncompleteRuns } from "./recovery";
|
|
5
|
+
export { retryFailedRun, setupWorkflowResumeListener } from "./resume";
|
|
6
|
+
export { startRetryPoller, stopRetryPoller } from "./retry-poller";
|
|
7
|
+
export { interpolate } from "./template";
|
|
8
|
+
export { instantiateTemplate, validateTemplateVariables } from "./templates";
|
|
9
|
+
export { handleScheduleTrigger, handleWebhookTrigger } from "./triggers";
|
|
10
|
+
export { snapshotWorkflow } from "./version";
|
|
11
|
+
|
|
12
|
+
import * as db from "../be/db";
|
|
13
|
+
import { workflowEventBus } from "./event-bus";
|
|
14
|
+
import type { ExecutorRegistry } from "./executors/registry";
|
|
15
|
+
import { createExecutorRegistry } from "./executors/registry";
|
|
16
|
+
import { recoverIncompleteRuns } from "./recovery";
|
|
17
|
+
import { setupWorkflowResumeListener } from "./resume";
|
|
18
|
+
import { startRetryPoller } from "./retry-poller";
|
|
19
|
+
import { interpolate } from "./template";
|
|
20
|
+
|
|
21
|
+
// ─── Module-level singleton ────────────────────────────────
|
|
22
|
+
|
|
23
|
+
let _registry: ExecutorRegistry | null = null;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get the executor registry singleton.
|
|
27
|
+
* Throws if called before `initWorkflows()`.
|
|
28
|
+
*/
|
|
29
|
+
export function getExecutorRegistry(): ExecutorRegistry {
|
|
30
|
+
if (!_registry) {
|
|
31
|
+
throw new Error("Workflow engine not initialized — call initWorkflows() first");
|
|
32
|
+
}
|
|
33
|
+
return _registry;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Initialize the workflow engine:
|
|
38
|
+
* 1. Create executor registry with all built-in executors
|
|
39
|
+
* 2. Wire up event bus listeners for task lifecycle resume
|
|
40
|
+
* 3. Recover incomplete runs from previous server lifecycle
|
|
41
|
+
* 4. Start the retry poller for failed steps with pending retries
|
|
42
|
+
*/
|
|
43
|
+
export function initWorkflows(): void {
|
|
44
|
+
// 1. Create the executor registry singleton
|
|
45
|
+
_registry = createExecutorRegistry({
|
|
46
|
+
db,
|
|
47
|
+
eventBus: workflowEventBus,
|
|
48
|
+
interpolate: (template, ctx) => interpolate(template, ctx).result,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// 2. Wire up resume listener (task.completed / task.failed / task.cancelled)
|
|
52
|
+
setupWorkflowResumeListener(workflowEventBus, _registry);
|
|
53
|
+
|
|
54
|
+
// 3. Recover incomplete runs (running + waiting) from previous lifecycle
|
|
55
|
+
recoverIncompleteRuns(_registry).catch((err) => {
|
|
56
|
+
console.error("[workflows] Failed to recover incomplete runs on startup:", err);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// 4. Start retry poller for failed steps with nextRetryAt
|
|
60
|
+
startRetryPoller(_registry);
|
|
61
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { getSwarmConfigs } from "../be/db";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolve workflow input values.
|
|
5
|
+
*
|
|
6
|
+
* Patterns:
|
|
7
|
+
* - `${ENV_VAR}` -> process.env[ENV_VAR]
|
|
8
|
+
* - `secret.NAME` -> look up in DB config store (global scope, isSecret=true)
|
|
9
|
+
* - literal string -> pass through
|
|
10
|
+
*/
|
|
11
|
+
export function resolveInputs(input: Record<string, string>): Record<string, string> {
|
|
12
|
+
const resolved: Record<string, string> = {};
|
|
13
|
+
|
|
14
|
+
for (const [key, value] of Object.entries(input)) {
|
|
15
|
+
resolved[key] = resolveValue(value);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return resolved;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function resolveValue(value: string): string {
|
|
22
|
+
// Env var reference: ${MY_VAR}
|
|
23
|
+
const envMatch = /^\$\{(.+)\}$/.exec(value);
|
|
24
|
+
if (envMatch?.[1]) {
|
|
25
|
+
const envName = envMatch[1];
|
|
26
|
+
const envValue = process.env[envName];
|
|
27
|
+
if (envValue === undefined) {
|
|
28
|
+
throw new Error(`Environment variable "${envName}" is not set`);
|
|
29
|
+
}
|
|
30
|
+
return envValue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Secret reference: secret.NAME
|
|
34
|
+
if (value.startsWith("secret.")) {
|
|
35
|
+
const secretName = value.slice("secret.".length);
|
|
36
|
+
const configs = getSwarmConfigs({ scope: "global", key: secretName });
|
|
37
|
+
const secretConfig = configs.find((c) => c.isSecret);
|
|
38
|
+
if (!secretConfig) {
|
|
39
|
+
throw new Error(`Secret "${secretName}" not found in config store`);
|
|
40
|
+
}
|
|
41
|
+
return secretConfig.value;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Literal
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal hand-rolled JSON Schema validator.
|
|
3
|
+
*
|
|
4
|
+
* Supports the subset needed for workflow I/O schemas:
|
|
5
|
+
* - `type`: "object", "string", "number", "boolean", "array"
|
|
6
|
+
* - `required`: array of required property names
|
|
7
|
+
* - `properties`: map of property name → schema (recursive)
|
|
8
|
+
*
|
|
9
|
+
* Returns an array of validation error strings (empty = valid).
|
|
10
|
+
*/
|
|
11
|
+
export function validateJsonSchema(schema: Record<string, unknown>, data: unknown): string[] {
|
|
12
|
+
const errors: string[] = [];
|
|
13
|
+
validate(schema, data, "", errors);
|
|
14
|
+
return errors;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function validate(
|
|
18
|
+
schema: Record<string, unknown>,
|
|
19
|
+
data: unknown,
|
|
20
|
+
path: string,
|
|
21
|
+
errors: string[],
|
|
22
|
+
): void {
|
|
23
|
+
const prefix = path || "root";
|
|
24
|
+
|
|
25
|
+
// Type check
|
|
26
|
+
if (schema.type !== undefined) {
|
|
27
|
+
const expected = schema.type as string;
|
|
28
|
+
if (!matchesType(expected, data)) {
|
|
29
|
+
errors.push(`${prefix}: expected type "${expected}", got ${typeOf(data)}`);
|
|
30
|
+
return; // No point checking properties of wrong type
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Required fields (only for objects)
|
|
35
|
+
if (Array.isArray(schema.required) && typeof data === "object" && data !== null) {
|
|
36
|
+
const obj = data as Record<string, unknown>;
|
|
37
|
+
for (const key of schema.required as string[]) {
|
|
38
|
+
if (!(key in obj)) {
|
|
39
|
+
errors.push(`${prefix}: missing required property "${key}"`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Enum check
|
|
45
|
+
if (Array.isArray(schema.enum)) {
|
|
46
|
+
const allowed = schema.enum as unknown[];
|
|
47
|
+
if (!allowed.some((v) => JSON.stringify(v) === JSON.stringify(data))) {
|
|
48
|
+
errors.push(
|
|
49
|
+
`${prefix}: value ${JSON.stringify(data)} not in enum [${allowed.map((v) => JSON.stringify(v)).join(", ")}]`,
|
|
50
|
+
);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Const check
|
|
56
|
+
if ("const" in schema) {
|
|
57
|
+
if (JSON.stringify(data) !== JSON.stringify(schema.const)) {
|
|
58
|
+
errors.push(
|
|
59
|
+
`${prefix}: value ${JSON.stringify(data)} does not match const ${JSON.stringify(schema.const)}`,
|
|
60
|
+
);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Recursive property validation (only for objects)
|
|
66
|
+
if (
|
|
67
|
+
schema.properties !== undefined &&
|
|
68
|
+
typeof schema.properties === "object" &&
|
|
69
|
+
schema.properties !== null &&
|
|
70
|
+
typeof data === "object" &&
|
|
71
|
+
data !== null
|
|
72
|
+
) {
|
|
73
|
+
const props = schema.properties as Record<string, Record<string, unknown>>;
|
|
74
|
+
const obj = data as Record<string, unknown>;
|
|
75
|
+
for (const [key, subSchema] of Object.entries(props)) {
|
|
76
|
+
if (key in obj) {
|
|
77
|
+
validate(subSchema, obj[key], path ? `${path}.${key}` : key, errors);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Items validation (for arrays)
|
|
83
|
+
if (
|
|
84
|
+
schema.items !== undefined &&
|
|
85
|
+
typeof schema.items === "object" &&
|
|
86
|
+
schema.items !== null &&
|
|
87
|
+
Array.isArray(data)
|
|
88
|
+
) {
|
|
89
|
+
const itemSchema = schema.items as Record<string, unknown>;
|
|
90
|
+
for (let i = 0; i < data.length; i++) {
|
|
91
|
+
validate(itemSchema, data[i], `${prefix}[${i}]`, errors);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function matchesType(expected: string, data: unknown): boolean {
|
|
97
|
+
switch (expected) {
|
|
98
|
+
case "string":
|
|
99
|
+
return typeof data === "string";
|
|
100
|
+
case "number":
|
|
101
|
+
return typeof data === "number";
|
|
102
|
+
case "boolean":
|
|
103
|
+
return typeof data === "boolean";
|
|
104
|
+
case "array":
|
|
105
|
+
return Array.isArray(data);
|
|
106
|
+
case "object":
|
|
107
|
+
return typeof data === "object" && data !== null && !Array.isArray(data);
|
|
108
|
+
default:
|
|
109
|
+
return true; // Unknown type — don't block
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function typeOf(data: unknown): string {
|
|
114
|
+
if (data === null) return "null";
|
|
115
|
+
if (data === undefined) return "undefined";
|
|
116
|
+
if (Array.isArray(data)) return "array";
|
|
117
|
+
return typeof data;
|
|
118
|
+
}
|