lastlight 0.1.15 → 0.2.1
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 +265 -118
- package/agent-context/rules.md +62 -9
- package/agent-context/security.md +69 -0
- package/config/default.yaml +89 -0
- package/deploy/.env.production.example +20 -2
- package/deploy/entrypoint.sh +16 -17
- package/deploy/native/README.md +160 -0
- package/deploy/native/install.sh +110 -0
- package/deploy/native/lastlight.env.example +95 -0
- package/deploy/native/lastlight.service +50 -0
- package/deploy/sandbox-entrypoint.sh +59 -42
- package/dist/admin/auth.d.ts +1 -1
- package/dist/admin/auth.js +3 -1
- package/dist/admin/auth.js.map +1 -1
- package/dist/admin/chat-session-reader.d.ts +11 -14
- package/dist/admin/chat-session-reader.js +27 -51
- package/dist/admin/chat-session-reader.js.map +1 -1
- package/dist/admin/docker.d.ts +37 -0
- package/dist/admin/docker.js +86 -1
- package/dist/admin/docker.js.map +1 -1
- package/dist/admin/index.js +38 -3
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/log-search.test.d.ts +1 -0
- package/dist/admin/log-search.test.js +78 -0
- package/dist/admin/log-search.test.js.map +1 -0
- package/dist/admin/routes.d.ts +52 -3
- package/dist/admin/routes.js +780 -63
- package/dist/admin/routes.js.map +1 -1
- package/dist/admin/routes.test.js +680 -14
- package/dist/admin/routes.test.js.map +1 -1
- package/dist/admin/server-logs.test.d.ts +1 -0
- package/dist/admin/server-logs.test.js +58 -0
- package/dist/admin/server-logs.test.js.map +1 -0
- package/dist/admin/sessions.d.ts +26 -39
- package/dist/admin/sessions.js +86 -310
- package/dist/admin/sessions.js.map +1 -1
- package/dist/admin/sessions.test.d.ts +1 -0
- package/dist/admin/sessions.test.js +78 -0
- package/dist/admin/sessions.test.js.map +1 -0
- package/dist/admin/version.d.ts +15 -0
- package/dist/admin/version.js +73 -0
- package/dist/admin/version.js.map +1 -0
- package/dist/admin/version.test.d.ts +1 -0
- package/dist/admin/version.test.js +71 -0
- package/dist/admin/version.test.js.map +1 -0
- package/dist/cli-config.d.ts +55 -0
- package/dist/cli-config.js +119 -0
- package/dist/cli-config.js.map +1 -0
- package/dist/cli-config.test.d.ts +1 -0
- package/dist/cli-config.test.js +92 -0
- package/dist/cli-config.test.js.map +1 -0
- package/dist/cli-format.d.ts +19 -0
- package/dist/cli-format.js +107 -0
- package/dist/cli-format.js.map +1 -0
- package/dist/cli-server.d.ts +73 -0
- package/dist/cli-server.js +347 -0
- package/dist/cli-server.js.map +1 -0
- package/dist/cli-server.test.d.ts +1 -0
- package/dist/cli-server.test.js +38 -0
- package/dist/cli-server.test.js.map +1 -0
- package/dist/cli-timeline.d.ts +35 -0
- package/dist/cli-timeline.js +373 -0
- package/dist/cli-timeline.js.map +1 -0
- package/dist/cli-timeline.test.d.ts +1 -0
- package/dist/cli-timeline.test.js +104 -0
- package/dist/cli-timeline.test.js.map +1 -0
- package/dist/cli.d.ts +0 -19
- package/dist/cli.js +910 -194
- package/dist/cli.js.map +1 -1
- package/dist/config-overlay.test.d.ts +1 -0
- package/dist/config-overlay.test.js +112 -0
- package/dist/config-overlay.test.js.map +1 -0
- package/dist/config-resolve.d.ts +28 -0
- package/dist/config-resolve.js +47 -0
- package/dist/config-resolve.js.map +1 -0
- package/dist/config-resolve.test.d.ts +1 -0
- package/dist/config-resolve.test.js +68 -0
- package/dist/config-resolve.test.js.map +1 -0
- package/dist/config.d.ts +62 -49
- package/dist/config.js +452 -76
- package/dist/config.js.map +1 -1
- package/dist/config.test.js +201 -32
- package/dist/config.test.js.map +1 -1
- package/dist/connectors/github-webhook.js +83 -5
- package/dist/connectors/github-webhook.js.map +1 -1
- package/dist/connectors/github-webhook.test.d.ts +1 -0
- package/dist/connectors/github-webhook.test.js +156 -0
- package/dist/connectors/github-webhook.test.js.map +1 -0
- package/dist/connectors/messaging/session-manager.d.ts +18 -0
- package/dist/connectors/messaging/session-manager.js +83 -2
- package/dist/connectors/messaging/session-manager.js.map +1 -1
- package/dist/connectors/messaging/session-manager.test.d.ts +1 -0
- package/dist/connectors/messaging/session-manager.test.js +144 -0
- package/dist/connectors/messaging/session-manager.test.js.map +1 -0
- package/dist/connectors/slack/connector.d.ts +9 -0
- package/dist/connectors/slack/connector.js +15 -0
- package/dist/connectors/slack/connector.js.map +1 -1
- package/dist/connectors/slack/mrkdwn.js +81 -0
- package/dist/connectors/slack/mrkdwn.js.map +1 -1
- package/dist/connectors/slack/mrkdwn.test.js +49 -0
- package/dist/connectors/slack/mrkdwn.test.js.map +1 -1
- package/dist/connectors/types.d.ts +1 -1
- package/dist/cron/fanout.d.ts +33 -0
- package/dist/cron/fanout.js +55 -0
- package/dist/cron/fanout.js.map +1 -0
- package/dist/cron/fanout.test.d.ts +1 -0
- package/dist/cron/fanout.test.js +73 -0
- package/dist/cron/fanout.test.js.map +1 -0
- package/dist/cron/jobs.d.ts +5 -0
- package/dist/cron/jobs.js +10 -3
- package/dist/cron/jobs.js.map +1 -1
- package/dist/cron/scheduler.d.ts +12 -0
- package/dist/cron/scheduler.js +27 -1
- package/dist/cron/scheduler.js.map +1 -1
- package/dist/engine/agent-executor.d.ts +158 -0
- package/dist/engine/agent-executor.js +1140 -0
- package/dist/engine/agent-executor.js.map +1 -0
- package/dist/engine/agent-executor.test.d.ts +1 -0
- package/dist/engine/agent-executor.test.js +395 -0
- package/dist/engine/agent-executor.test.js.map +1 -0
- package/dist/engine/chat-runner.d.ts +123 -0
- package/dist/engine/chat-runner.js +379 -0
- package/dist/engine/chat-runner.js.map +1 -0
- package/dist/engine/chat-runner.test.d.ts +1 -0
- package/dist/engine/chat-runner.test.js +104 -0
- package/dist/engine/chat-runner.test.js.map +1 -0
- package/dist/engine/chat-skills.d.ts +45 -0
- package/dist/engine/chat-skills.js +184 -0
- package/dist/engine/chat-skills.js.map +1 -0
- package/dist/engine/chat-skills.test.d.ts +1 -0
- package/dist/engine/chat-skills.test.js +20 -0
- package/dist/engine/chat-skills.test.js.map +1 -0
- package/dist/engine/chat.d.ts +20 -23
- package/dist/engine/chat.js +251 -155
- package/dist/engine/chat.js.map +1 -1
- package/dist/engine/chat.test.d.ts +1 -0
- package/dist/engine/chat.test.js +42 -0
- package/dist/engine/chat.test.js.map +1 -0
- package/dist/engine/classifier.d.ts +35 -2
- package/dist/engine/classifier.js +170 -31
- package/dist/engine/classifier.js.map +1 -1
- package/dist/engine/classifier.test.d.ts +1 -0
- package/dist/engine/classifier.test.js +115 -0
- package/dist/engine/classifier.test.js.map +1 -0
- package/dist/engine/dispatcher.d.ts +60 -0
- package/dist/engine/dispatcher.js +601 -0
- package/dist/engine/dispatcher.js.map +1 -0
- package/dist/engine/dispatcher.test.d.ts +1 -0
- package/dist/engine/dispatcher.test.js +511 -0
- package/dist/engine/dispatcher.test.js.map +1 -0
- package/dist/engine/event-shim.d.ts +117 -0
- package/dist/engine/event-shim.js +435 -0
- package/dist/engine/event-shim.js.map +1 -0
- package/dist/engine/event-shim.test.d.ts +1 -0
- package/dist/engine/event-shim.test.js +194 -0
- package/dist/engine/event-shim.test.js.map +1 -0
- package/dist/engine/git-auth.d.ts +13 -17
- package/dist/engine/git-auth.js +99 -42
- package/dist/engine/git-auth.js.map +1 -1
- package/dist/engine/git-auth.test.d.ts +1 -0
- package/dist/engine/git-auth.test.js +117 -0
- package/dist/engine/git-auth.test.js.map +1 -0
- package/dist/engine/github-app-client.d.ts +7 -0
- package/dist/engine/github-app-client.js +16 -0
- package/dist/engine/github-app-client.js.map +1 -0
- package/dist/engine/github-app-client.test.d.ts +1 -0
- package/dist/engine/github-app-client.test.js +44 -0
- package/dist/engine/github-app-client.test.js.map +1 -0
- package/dist/engine/github-tools.d.ts +12 -0
- package/dist/engine/github-tools.js +261 -0
- package/dist/engine/github-tools.js.map +1 -0
- package/dist/engine/github.d.ts +1027 -43
- package/dist/engine/github.js +153 -14
- package/dist/engine/github.js.map +1 -1
- package/dist/engine/llm.d.ts +47 -0
- package/dist/engine/llm.js +221 -0
- package/dist/engine/llm.js.map +1 -0
- package/dist/engine/llm.test.d.ts +1 -0
- package/dist/engine/llm.test.js +189 -0
- package/dist/engine/llm.test.js.map +1 -0
- package/dist/engine/profiles.d.ts +249 -0
- package/dist/engine/profiles.js +42 -0
- package/dist/engine/profiles.js.map +1 -0
- package/dist/engine/router.d.ts +12 -6
- package/dist/engine/router.js +339 -81
- package/dist/engine/router.js.map +1 -1
- package/dist/engine/router.test.js +428 -78
- package/dist/engine/router.test.js.map +1 -1
- package/dist/engine/screen.d.ts +41 -0
- package/dist/engine/screen.js +93 -0
- package/dist/engine/screen.js.map +1 -0
- package/dist/engine/screen.test.d.ts +1 -0
- package/dist/engine/screen.test.js +82 -0
- package/dist/engine/screen.test.js.map +1 -0
- package/dist/index.js +377 -432
- package/dist/index.js.map +1 -1
- package/dist/managed-repos.d.ts +7 -9
- package/dist/managed-repos.js +12 -15
- package/dist/managed-repos.js.map +1 -1
- package/dist/managed-repos.test.js +24 -19
- package/dist/managed-repos.test.js.map +1 -1
- package/dist/notify/index.d.ts +15 -0
- package/dist/notify/index.js +6 -0
- package/dist/notify/index.js.map +1 -0
- package/dist/notify/model.d.ts +57 -0
- package/dist/notify/model.js +89 -0
- package/dist/notify/model.js.map +1 -0
- package/dist/notify/model.test.d.ts +1 -0
- package/dist/notify/model.test.js +109 -0
- package/dist/notify/model.test.js.map +1 -0
- package/dist/notify/notifier.d.ts +17 -0
- package/dist/notify/notifier.js +87 -0
- package/dist/notify/notifier.js.map +1 -0
- package/dist/notify/notifier.test.d.ts +1 -0
- package/dist/notify/notifier.test.js +100 -0
- package/dist/notify/notifier.test.js.map +1 -0
- package/dist/notify/render.d.ts +21 -0
- package/dist/notify/render.js +59 -0
- package/dist/notify/render.js.map +1 -0
- package/dist/notify/render.test.d.ts +1 -0
- package/dist/notify/render.test.js +65 -0
- package/dist/notify/render.test.js.map +1 -0
- package/dist/notify/transports/github.d.ts +26 -0
- package/dist/notify/transports/github.js +26 -0
- package/dist/notify/transports/github.js.map +1 -0
- package/dist/notify/transports/slack.d.ts +26 -0
- package/dist/notify/transports/slack.js +28 -0
- package/dist/notify/transports/slack.js.map +1 -0
- package/dist/notify/transports.test.d.ts +1 -0
- package/dist/notify/transports.test.js +71 -0
- package/dist/notify/transports.test.js.map +1 -0
- package/dist/notify/types.d.ts +95 -0
- package/dist/notify/types.js +16 -0
- package/dist/notify/types.js.map +1 -0
- package/dist/sandbox/docker-compose.test.d.ts +1 -0
- package/dist/sandbox/docker-compose.test.js +128 -0
- package/dist/sandbox/docker-compose.test.js.map +1 -0
- package/dist/sandbox/docker.d.ts +97 -9
- package/dist/sandbox/docker.js +192 -41
- package/dist/sandbox/docker.js.map +1 -1
- package/dist/sandbox/docker.test.d.ts +1 -0
- package/dist/sandbox/docker.test.js +137 -0
- package/dist/sandbox/docker.test.js.map +1 -0
- package/dist/sandbox/egress-allowlist.d.ts +69 -0
- package/dist/sandbox/egress-allowlist.js +164 -0
- package/dist/sandbox/egress-allowlist.js.map +1 -0
- package/dist/sandbox/egress-allowlist.test.d.ts +1 -0
- package/dist/sandbox/egress-allowlist.test.js +65 -0
- package/dist/sandbox/egress-allowlist.test.js.map +1 -0
- package/dist/sandbox/egress-firewall-config.d.ts +127 -0
- package/dist/sandbox/egress-firewall-config.js +434 -0
- package/dist/sandbox/egress-firewall-config.js.map +1 -0
- package/dist/sandbox/egress-firewall-config.test.d.ts +1 -0
- package/dist/sandbox/egress-firewall-config.test.js +244 -0
- package/dist/sandbox/egress-firewall-config.test.js.map +1 -0
- package/dist/sandbox/images.d.ts +23 -0
- package/dist/sandbox/images.js +55 -0
- package/dist/sandbox/images.js.map +1 -0
- package/dist/sandbox/index.d.ts +82 -3
- package/dist/sandbox/index.js +223 -93
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/index.test.d.ts +1 -0
- package/dist/sandbox/index.test.js +157 -0
- package/dist/sandbox/index.test.js.map +1 -0
- package/dist/session-log.d.ts +63 -0
- package/dist/session-log.js +290 -0
- package/dist/session-log.js.map +1 -0
- package/dist/session-log.test.d.ts +1 -0
- package/dist/session-log.test.js +85 -0
- package/dist/session-log.test.js.map +1 -0
- package/dist/setup.d.ts +30 -1
- package/dist/setup.js +241 -25
- package/dist/setup.js.map +1 -1
- package/dist/setup.test.js +138 -6
- package/dist/setup.test.js.map +1 -1
- package/dist/state/approval-store.d.ts +86 -0
- package/dist/state/approval-store.js +140 -0
- package/dist/state/approval-store.js.map +1 -0
- package/dist/state/build-assets.d.ts +50 -0
- package/dist/state/build-assets.js +154 -0
- package/dist/state/build-assets.js.map +1 -0
- package/dist/state/build-assets.test.d.ts +1 -0
- package/dist/state/build-assets.test.js +106 -0
- package/dist/state/build-assets.test.js.map +1 -0
- package/dist/state/db.d.ts +65 -333
- package/dist/state/db.js +112 -835
- package/dist/state/db.js.map +1 -1
- package/dist/state/db.test.js +127 -91
- package/dist/state/db.test.js.map +1 -1
- package/dist/state/execution-store.d.ts +257 -0
- package/dist/state/execution-store.js +527 -0
- package/dist/state/execution-store.js.map +1 -0
- package/dist/state/migrate.d.ts +15 -0
- package/dist/state/migrate.js +175 -0
- package/dist/state/migrate.js.map +1 -0
- package/dist/state/workflow-run-store.d.ts +195 -0
- package/dist/state/workflow-run-store.js +363 -0
- package/dist/state/workflow-run-store.js.map +1 -0
- package/dist/state/workflow-run-store.test.d.ts +1 -0
- package/dist/state/workflow-run-store.test.js +264 -0
- package/dist/state/workflow-run-store.test.js.map +1 -0
- package/dist/telemetry/index.d.ts +38 -0
- package/dist/telemetry/index.js +253 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/index.test.d.ts +1 -0
- package/dist/telemetry/index.test.js +73 -0
- package/dist/telemetry/index.test.js.map +1 -0
- package/dist/telemetry/pi-events.d.ts +12 -0
- package/dist/telemetry/pi-events.js +134 -0
- package/dist/telemetry/pi-events.js.map +1 -0
- package/dist/telemetry/pi-events.test.d.ts +1 -0
- package/dist/telemetry/pi-events.test.js +69 -0
- package/dist/telemetry/pi-events.test.js.map +1 -0
- package/dist/workflows/dag.d.ts +13 -1
- package/dist/workflows/dag.js +7 -3
- package/dist/workflows/dag.js.map +1 -1
- package/dist/workflows/dag.test.js +22 -0
- package/dist/workflows/dag.test.js.map +1 -1
- package/dist/workflows/golden-build.test.d.ts +1 -0
- package/dist/workflows/golden-build.test.js +45 -0
- package/dist/workflows/golden-build.test.js.map +1 -0
- package/dist/workflows/loader-overlay.test.d.ts +1 -0
- package/dist/workflows/loader-overlay.test.js +101 -0
- package/dist/workflows/loader-overlay.test.js.map +1 -0
- package/dist/workflows/loader.d.ts +36 -11
- package/dist/workflows/loader.js +311 -87
- package/dist/workflows/loader.js.map +1 -1
- package/dist/workflows/loader.test.js +114 -10
- package/dist/workflows/loader.test.js.map +1 -1
- package/dist/workflows/loop-eval.js +2 -0
- package/dist/workflows/loop-eval.js.map +1 -1
- package/dist/workflows/loop-eval.test.js +14 -0
- package/dist/workflows/loop-eval.test.js.map +1 -1
- package/dist/workflows/phase-executor.d.ts +145 -0
- package/dist/workflows/phase-executor.js +691 -0
- package/dist/workflows/phase-executor.js.map +1 -0
- package/dist/workflows/phase-executor.test.d.ts +1 -0
- package/dist/workflows/phase-executor.test.js +434 -0
- package/dist/workflows/phase-executor.test.js.map +1 -0
- package/dist/workflows/phase-ref.d.ts +44 -0
- package/dist/workflows/phase-ref.js +78 -0
- package/dist/workflows/phase-ref.js.map +1 -0
- package/dist/workflows/phase-ref.test.d.ts +1 -0
- package/dist/workflows/phase-ref.test.js +24 -0
- package/dist/workflows/phase-ref.test.js.map +1 -0
- package/dist/workflows/resume.d.ts +5 -11
- package/dist/workflows/resume.js +88 -7
- package/dist/workflows/resume.js.map +1 -1
- package/dist/workflows/runner.d.ts +34 -27
- package/dist/workflows/runner.js +252 -930
- package/dist/workflows/runner.js.map +1 -1
- package/dist/workflows/runner.test.js +346 -35
- package/dist/workflows/runner.test.js.map +1 -1
- package/dist/workflows/schema.d.ts +52 -10
- package/dist/workflows/schema.js +147 -7
- package/dist/workflows/schema.js.map +1 -1
- package/dist/workflows/simple.d.ts +67 -3
- package/dist/workflows/simple.js +248 -87
- package/dist/workflows/simple.js.map +1 -1
- package/dist/workflows/simple.test.d.ts +1 -0
- package/dist/workflows/simple.test.js +107 -0
- package/dist/workflows/simple.test.js.map +1 -0
- package/dist/workflows/templates.d.ts +29 -0
- package/dist/workflows/templates.js +42 -4
- package/dist/workflows/templates.js.map +1 -1
- package/dist/workflows/templates.test.js +103 -0
- package/dist/workflows/templates.test.js.map +1 -1
- package/dist/workflows/triggers.d.ts +21 -0
- package/dist/workflows/triggers.js +44 -0
- package/dist/workflows/triggers.js.map +1 -0
- package/dist/workflows/verdict.d.ts +19 -0
- package/dist/workflows/verdict.js +30 -0
- package/dist/workflows/verdict.js.map +1 -0
- package/dist/workflows/verdict.test.d.ts +1 -0
- package/dist/workflows/verdict.test.js +44 -0
- package/dist/workflows/verdict.test.js.map +1 -0
- package/dist/worktree/manager.d.ts +1 -1
- package/dist/worktree/manager.js +14 -14
- package/dist/worktree/manager.js.map +1 -1
- package/dist/worktree/manager.test.d.ts +1 -0
- package/dist/worktree/manager.test.js +87 -0
- package/dist/worktree/manager.test.js.map +1 -0
- package/docker-compose.yml +206 -5
- package/package.json +19 -9
- package/sandbox.Dockerfile +97 -18
- package/skills/README.md +40 -0
- package/skills/browser-qa/SKILL.md +193 -0
- package/skills/browser-qa/scripts/agent-browser.mjs +380 -0
- package/skills/building/SKILL.md +95 -0
- package/skills/chat/SKILL.md +30 -11
- package/skills/code-review/SKILL.md +59 -0
- package/skills/debug-production/SKILL.md +108 -0
- package/skills/demo/SKILL.md +194 -0
- package/skills/demo/scripts/compose-demo.sh +205 -0
- package/skills/issue-answer/SKILL.md +90 -0
- package/skills/issue-comment/SKILL.md +38 -24
- package/skills/issue-triage/SKILL.md +103 -37
- package/skills/issue-triage/references/AGENT-BRIEF.md +61 -0
- package/skills/pr-comment/SKILL.md +64 -0
- package/skills/pr-review/SKILL.md +65 -49
- package/skills/qa-test/SKILL.md +97 -0
- package/skills/repo-health/SKILL.md +48 -45
- package/skills/security-feedback/SKILL.md +173 -0
- package/skills/security-feedback/references/templates.md +77 -0
- package/skills/security-review/SKILL.md +213 -0
- package/skills/security-review/references/issue-format.md +302 -0
- package/skills/verify/SKILL.md +118 -0
- package/workflows/answer.yaml +37 -0
- package/workflows/build.yaml +32 -22
- package/workflows/cron-security.yaml +6 -0
- package/workflows/demo.yaml +55 -0
- package/workflows/explore.yaml +9 -0
- package/workflows/pr-comment.yaml +16 -0
- package/workflows/pr-fix.yaml +3 -0
- package/workflows/pr-review.yaml +4 -1
- package/workflows/prompts/answer.md +67 -0
- package/workflows/prompts/architect.md +24 -7
- package/workflows/prompts/demo.md +100 -0
- package/workflows/prompts/executor.md +29 -20
- package/workflows/prompts/explore-ask.md +51 -22
- package/workflows/prompts/explore-publish.md +2 -2
- package/workflows/prompts/explore-read.md +24 -10
- package/workflows/prompts/explore-synthesize.md +15 -8
- package/workflows/prompts/fix.md +9 -10
- package/workflows/prompts/guardrails.md +26 -8
- package/workflows/prompts/pr-fix.md +6 -7
- package/workflows/prompts/pr.md +11 -10
- package/workflows/prompts/qa-browser.md +95 -0
- package/workflows/prompts/qa-synth.md +44 -0
- package/workflows/prompts/qa-test.md +60 -0
- package/workflows/prompts/re-reviewer.md +8 -9
- package/workflows/prompts/reviewer.md +10 -9
- package/workflows/prompts/verify-browser.md +93 -0
- package/workflows/prompts/verify-synth.md +44 -0
- package/workflows/prompts/verify.md +63 -0
- package/workflows/qa-test.yaml +87 -0
- package/workflows/security-feedback.yaml +25 -0
- package/workflows/security-review.yaml +29 -0
- package/workflows/verify.yaml +85 -0
- package/deploy/mcp-config.tmpl.json +0 -14
- package/dist/cron/rate-limits.d.ts +0 -26
- package/dist/cron/rate-limits.js +0 -193
- package/dist/cron/rate-limits.js.map +0 -1
- package/dist/engine/executor.d.ts +0 -75
- package/dist/engine/executor.js +0 -292
- package/dist/engine/executor.js.map +0 -1
- package/mcp-github-app/package.json +0 -18
- package/mcp-github-app/src/auth.js +0 -66
- package/mcp-github-app/src/github.js +0 -371
- package/mcp-github-app/src/index.js +0 -534
- package/skills/devops/webhook-subscriptions/SKILL.md +0 -180
- package/skills/github/DESCRIPTION.md +0 -3
- package/skills/github/codebase-inspection/SKILL.md +0 -115
- package/skills/github/github-auth/SKILL.md +0 -54
- package/skills/github/github-auth/scripts/gh-env.sh +0 -66
- package/skills/github/github-code-review/SKILL.md +0 -480
- package/skills/github/github-code-review/references/review-output-template.md +0 -74
- package/skills/github/github-issues/SKILL.md +0 -369
- package/skills/github/github-issues/templates/bug-report.md +0 -35
- package/skills/github/github-issues/templates/feature-request.md +0 -31
- package/skills/github/github-pr-workflow/SKILL.md +0 -395
- package/skills/github/github-pr-workflow/references/ci-troubleshooting.md +0 -183
- package/skills/github/github-pr-workflow/references/conventional-commits.md +0 -71
- package/skills/github/github-pr-workflow/templates/pr-body-bugfix.md +0 -35
- package/skills/github/github-pr-workflow/templates/pr-body-feature.md +0 -33
- package/skills/github/github-repo-management/SKILL.md +0 -515
- package/skills/github/github-repo-management/references/github-api-cheatsheet.md +0 -161
- package/skills/github-orchestrator/SKILL.md +0 -103
- package/skills/mcp/DESCRIPTION.md +0 -3
- package/skills/mcp/mcporter/SKILL.md +0 -122
- package/skills/mcp/native-mcp/SKILL.md +0 -356
- package/skills/software-development/architect/SKILL.md +0 -154
- package/skills/software-development/assure-guardrails/SKILL.md +0 -239
- package/skills/software-development/plan/SKILL.md +0 -64
- package/skills/software-development/requesting-code-review/SKILL.md +0 -291
- package/skills/software-development/subagent-driven-development/SKILL.md +0 -433
- package/skills/software-development/systematic-debugging/SKILL.md +0 -366
- package/skills/software-development/test-driven-development/SKILL.md +0 -342
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aggregate root for a workflow run's lifecycle. Owns the `workflow_runs`
|
|
3
|
+
* table (including the `phase_history` JSON column) and the named, atomic
|
|
4
|
+
* transitions a run moves through: create → pause-for-approval →
|
|
5
|
+
* resume/finish, plus gate resolution and the socratic reply append.
|
|
6
|
+
*
|
|
7
|
+
* Carved out of the old `StateDb` god-class (issue #97). The deepening: every
|
|
8
|
+
* multi-step mutation that previously lived as an un-guarded read-modify-write
|
|
9
|
+
* chain in `index.ts` / `admin/routes.ts` / `phase-executor.ts` is now a
|
|
10
|
+
* single named operation wrapped in ONE `better-sqlite3` transaction — a throw
|
|
11
|
+
* partway through rolls the whole thing back, so a run can never be left
|
|
12
|
+
* marked `running` with its gate unresolved (the hazard the issue calls out).
|
|
13
|
+
*
|
|
14
|
+
* Constructed with an injected {@link ApprovalStore}: an approval has no life
|
|
15
|
+
* independent of its run, so the cross-table ops call the approval store's
|
|
16
|
+
* single-table writes from inside this store's transaction. Both stores MUST
|
|
17
|
+
* be built from the same `Database` — better-sqlite3 transactions are
|
|
18
|
+
* per-connection.
|
|
19
|
+
*
|
|
20
|
+
* The long-running re-dispatch (`dispatchWorkflow`, which spawns a Docker
|
|
21
|
+
* sandbox for minutes) is deliberately NOT part of any transaction here —
|
|
22
|
+
* better-sqlite3 transactions are synchronous. The atomic boundary is the DB
|
|
23
|
+
* mutations only; the caller dispatches after the transaction commits.
|
|
24
|
+
*/
|
|
25
|
+
export class WorkflowRunStore {
|
|
26
|
+
db;
|
|
27
|
+
approvals;
|
|
28
|
+
constructor(db, deps) {
|
|
29
|
+
this.db = db;
|
|
30
|
+
this.approvals = deps.approvals;
|
|
31
|
+
}
|
|
32
|
+
// ── Plain single-mutation operations ───────────────────────────
|
|
33
|
+
/** Create a new workflow run record */
|
|
34
|
+
createRun(run) {
|
|
35
|
+
const now = new Date().toISOString();
|
|
36
|
+
this.db.prepare(`
|
|
37
|
+
INSERT INTO workflow_runs (id, workflow_name, trigger_id, repo, issue_number, current_phase, phase_history, status, context, scratch, started_at, updated_at)
|
|
38
|
+
VALUES (?, ?, ?, ?, ?, ?, '[]', ?, ?, ?, ?, ?)
|
|
39
|
+
`).run(run.id, run.workflowName, run.triggerId, run.repo ?? null, run.issueNumber ?? null, run.currentPhase, run.status, run.context ? JSON.stringify(run.context) : null, run.scratch ? JSON.stringify(run.scratch) : null, run.startedAt, now);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Top-level merge of `patch` into the workflow run's scratch state.
|
|
43
|
+
* Loop iterations can append to `scratch.socratic.qa` without clobbering
|
|
44
|
+
* other keys.
|
|
45
|
+
*
|
|
46
|
+
* Throws if `patch` is not JSON-serializable (e.g. it contains a BigInt) —
|
|
47
|
+
* which is exactly how the atomic ops prove their rollback: a poison patch
|
|
48
|
+
* makes `JSON.stringify` throw mid-transaction.
|
|
49
|
+
*/
|
|
50
|
+
mergeScratch(id, patch) {
|
|
51
|
+
const now = new Date().toISOString();
|
|
52
|
+
const row = this.db
|
|
53
|
+
.prepare(`SELECT scratch FROM workflow_runs WHERE id = ?`)
|
|
54
|
+
.get(id);
|
|
55
|
+
if (!row)
|
|
56
|
+
return;
|
|
57
|
+
const current = row.scratch ? JSON.parse(row.scratch) : {};
|
|
58
|
+
const merged = { ...current, ...patch };
|
|
59
|
+
// Stringify BEFORE the UPDATE so a non-serializable patch throws without
|
|
60
|
+
// having mutated the row — keeps the op all-or-nothing even outside a txn.
|
|
61
|
+
const serialized = JSON.stringify(merged);
|
|
62
|
+
this.db
|
|
63
|
+
.prepare(`UPDATE workflow_runs SET scratch = ?, updated_at = ? WHERE id = ?`)
|
|
64
|
+
.run(serialized, now, id);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Update the current phase and append to phase history. This is the single
|
|
68
|
+
* seam through which all phase-history writes flow (issue #97 defers the
|
|
69
|
+
* full `phase_history`/`executions` reconciliation to a follow-up, but
|
|
70
|
+
* routes every write through here so that future change touches one method
|
|
71
|
+
* instead of ~10 call sites).
|
|
72
|
+
*/
|
|
73
|
+
appendPhase(id, phase, entry) {
|
|
74
|
+
const now = new Date().toISOString();
|
|
75
|
+
const row = this.db.prepare(`SELECT phase_history FROM workflow_runs WHERE id = ?`).get(id);
|
|
76
|
+
if (!row)
|
|
77
|
+
return;
|
|
78
|
+
const history = JSON.parse(row.phase_history);
|
|
79
|
+
history.push(entry);
|
|
80
|
+
this.db.prepare(`
|
|
81
|
+
UPDATE workflow_runs SET current_phase = ?, phase_history = ?, updated_at = ? WHERE id = ?
|
|
82
|
+
`).run(phase, JSON.stringify(history), now, id);
|
|
83
|
+
}
|
|
84
|
+
/** Get a single workflow run by ID */
|
|
85
|
+
getRun(id) {
|
|
86
|
+
const row = this.db.prepare(`SELECT * FROM workflow_runs WHERE id = ?`).get(id);
|
|
87
|
+
return row ? this.deserialize(row) : null;
|
|
88
|
+
}
|
|
89
|
+
/** Find the most recent active (running or paused) workflow run for a trigger */
|
|
90
|
+
getByTrigger(triggerId) {
|
|
91
|
+
const row = this.db.prepare(`
|
|
92
|
+
SELECT * FROM workflow_runs
|
|
93
|
+
WHERE trigger_id = ? AND status IN ('running', 'paused')
|
|
94
|
+
ORDER BY started_at DESC
|
|
95
|
+
LIMIT 1
|
|
96
|
+
`).get(triggerId);
|
|
97
|
+
return row ? this.deserialize(row) : null;
|
|
98
|
+
}
|
|
99
|
+
/** List all active (running or paused) workflow runs */
|
|
100
|
+
listActive() {
|
|
101
|
+
const rows = this.db.prepare(`
|
|
102
|
+
SELECT * FROM workflow_runs WHERE status IN ('running', 'paused') ORDER BY started_at DESC
|
|
103
|
+
`).all();
|
|
104
|
+
return rows.map((r) => this.deserialize(r));
|
|
105
|
+
}
|
|
106
|
+
/** List recent workflow runs, ordered by start time descending */
|
|
107
|
+
listRecent(limit = 20) {
|
|
108
|
+
const rows = this.db.prepare(`
|
|
109
|
+
SELECT * FROM workflow_runs ORDER BY started_at DESC LIMIT ?
|
|
110
|
+
`).all(limit);
|
|
111
|
+
return rows.map((r) => this.deserialize(r));
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* List workflow runs with pagination + filters. Returns the page slice
|
|
115
|
+
* AND the post-filter total so the dashboard knows how many remain.
|
|
116
|
+
*
|
|
117
|
+
* - sinceIso filters `started_at >= sinceIso` (used for the header date range).
|
|
118
|
+
* - workflowName filters by exact `workflow_name`.
|
|
119
|
+
* - statuses filters to one of the workflow statuses (`running`, `paused`,
|
|
120
|
+
* `succeeded`, `failed`, `cancelled`). Used for the dashboard's "live"
|
|
121
|
+
* filter, which maps to ['running','paused'].
|
|
122
|
+
*/
|
|
123
|
+
list(opts = {}) {
|
|
124
|
+
const limit = opts.limit ?? 20;
|
|
125
|
+
const offset = opts.offset ?? 0;
|
|
126
|
+
const where = [];
|
|
127
|
+
const params = [];
|
|
128
|
+
if (opts.sinceIso) {
|
|
129
|
+
where.push("started_at >= ?");
|
|
130
|
+
params.push(opts.sinceIso);
|
|
131
|
+
}
|
|
132
|
+
if (opts.workflowName) {
|
|
133
|
+
where.push("workflow_name = ?");
|
|
134
|
+
params.push(opts.workflowName);
|
|
135
|
+
}
|
|
136
|
+
if (opts.statuses && opts.statuses.length > 0) {
|
|
137
|
+
where.push(`status IN (${opts.statuses.map(() => "?").join(",")})`);
|
|
138
|
+
params.push(...opts.statuses);
|
|
139
|
+
}
|
|
140
|
+
const whereClause = where.length > 0 ? `WHERE ${where.join(" AND ")}` : "";
|
|
141
|
+
const total = this.db
|
|
142
|
+
.prepare(`SELECT COUNT(*) as c FROM workflow_runs ${whereClause}`)
|
|
143
|
+
.get(...params).c;
|
|
144
|
+
// Explicit column list — the heavy JSON blobs (`context`, `scratch`)
|
|
145
|
+
// can each be many MB on long-running build runs and
|
|
146
|
+
// the dashboard list view doesn't read them. Returning them turned a
|
|
147
|
+
// 20-row page into a 14MB payload. The single-row endpoint
|
|
148
|
+
// (`getRun`) still uses `SELECT *` so the detail panel keeps
|
|
149
|
+
// the full row when the user picks one.
|
|
150
|
+
const rows = this.db
|
|
151
|
+
.prepare(`SELECT
|
|
152
|
+
id, workflow_name, trigger_id, repo, issue_number,
|
|
153
|
+
current_phase, phase_history, status,
|
|
154
|
+
restart_count, started_at, updated_at, finished_at
|
|
155
|
+
FROM workflow_runs
|
|
156
|
+
${whereClause}
|
|
157
|
+
ORDER BY started_at DESC
|
|
158
|
+
LIMIT ? OFFSET ?`)
|
|
159
|
+
.all(...params, limit, offset);
|
|
160
|
+
return {
|
|
161
|
+
runs: rows.map((r) => this.deserialize(r)),
|
|
162
|
+
total,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/** Distinct workflow_name values, sorted alphabetically. */
|
|
166
|
+
distinctNames() {
|
|
167
|
+
const rows = this.db
|
|
168
|
+
.prepare(`SELECT DISTINCT workflow_name FROM workflow_runs ORDER BY workflow_name ASC`)
|
|
169
|
+
.all();
|
|
170
|
+
return rows.map((r) => r.workflow_name);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Mark a workflow run as finished. Plain status flip when called with just
|
|
174
|
+
* `{ error }`; when a `terminalMarker` is supplied (the runner's
|
|
175
|
+
* `on_success.set_phase`), the phase-history append and the status flip
|
|
176
|
+
* happen in ONE transaction so the dashboard never sees the terminal phase
|
|
177
|
+
* without the finished status, or vice versa.
|
|
178
|
+
*/
|
|
179
|
+
finishRun(id, status, opts = {}) {
|
|
180
|
+
const apply = () => {
|
|
181
|
+
if (opts.terminalMarker) {
|
|
182
|
+
this.appendPhase(id, opts.terminalMarker.phase, {
|
|
183
|
+
phase: opts.terminalMarker.phase,
|
|
184
|
+
timestamp: new Date().toISOString(),
|
|
185
|
+
success: true,
|
|
186
|
+
summary: opts.terminalMarker.summary,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
this.flipFinished(id, status, opts.error);
|
|
190
|
+
};
|
|
191
|
+
if (opts.terminalMarker) {
|
|
192
|
+
this.db.transaction(apply)();
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
apply();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
flipFinished(id, status, error) {
|
|
199
|
+
const now = new Date().toISOString();
|
|
200
|
+
this.db.prepare(`
|
|
201
|
+
UPDATE workflow_runs SET status = ?, finished_at = ?, updated_at = ?, context = CASE
|
|
202
|
+
WHEN ? IS NOT NULL THEN json_patch(COALESCE(context, '{}'), json_object('error', ?))
|
|
203
|
+
ELSE context
|
|
204
|
+
END WHERE id = ?
|
|
205
|
+
`).run(status, now, now, error ?? null, error ?? null, id);
|
|
206
|
+
}
|
|
207
|
+
/** Cancel a workflow run */
|
|
208
|
+
cancelRun(id) {
|
|
209
|
+
const now = new Date().toISOString();
|
|
210
|
+
this.db.prepare(`
|
|
211
|
+
UPDATE workflow_runs SET status = 'cancelled', updated_at = ?, finished_at = ? WHERE id = ?
|
|
212
|
+
`).run(now, now, id);
|
|
213
|
+
}
|
|
214
|
+
/** Pause a workflow run (waiting for approval) */
|
|
215
|
+
setPaused(id) {
|
|
216
|
+
const now = new Date().toISOString();
|
|
217
|
+
this.db.prepare(`
|
|
218
|
+
UPDATE workflow_runs SET status = 'paused', updated_at = ? WHERE id = ?
|
|
219
|
+
`).run(now, id);
|
|
220
|
+
}
|
|
221
|
+
/** Resume a paused workflow run (set back to running) */
|
|
222
|
+
setRunning(id) {
|
|
223
|
+
const now = new Date().toISOString();
|
|
224
|
+
this.db.prepare(`
|
|
225
|
+
UPDATE workflow_runs SET status = 'running', updated_at = ? WHERE id = ?
|
|
226
|
+
`).run(now, id);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Increment the restart counter and return the new value. Used by
|
|
230
|
+
* `resumeOrphanedWorkflows` to enforce a retry budget so a run that
|
|
231
|
+
* crashes the host (agent OOM, etc.) eventually self-terminates instead
|
|
232
|
+
* of being re-dispatched on every boot.
|
|
233
|
+
*/
|
|
234
|
+
incrementRestartCount(id) {
|
|
235
|
+
const now = new Date().toISOString();
|
|
236
|
+
this.db.prepare(`
|
|
237
|
+
UPDATE workflow_runs
|
|
238
|
+
SET restart_count = COALESCE(restart_count, 0) + 1, updated_at = ?
|
|
239
|
+
WHERE id = ?
|
|
240
|
+
`).run(now, id);
|
|
241
|
+
const row = this.db.prepare(`SELECT restart_count FROM workflow_runs WHERE id = ?`)
|
|
242
|
+
.get(id);
|
|
243
|
+
return row?.restart_count ?? 0;
|
|
244
|
+
}
|
|
245
|
+
deserialize(row) {
|
|
246
|
+
return {
|
|
247
|
+
id: row.id,
|
|
248
|
+
workflowName: row.workflow_name,
|
|
249
|
+
triggerId: row.trigger_id,
|
|
250
|
+
repo: row.repo,
|
|
251
|
+
issueNumber: row.issue_number,
|
|
252
|
+
currentPhase: row.current_phase,
|
|
253
|
+
phaseHistory: JSON.parse(row.phase_history),
|
|
254
|
+
status: row.status,
|
|
255
|
+
context: row.context ? JSON.parse(row.context) : undefined,
|
|
256
|
+
scratch: row.scratch ? JSON.parse(row.scratch) : undefined,
|
|
257
|
+
restartCount: typeof row.restart_count === "number" ? row.restart_count : 0,
|
|
258
|
+
startedAt: row.started_at,
|
|
259
|
+
updatedAt: row.updated_at,
|
|
260
|
+
finishedAt: row.finished_at,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
// ── Named atomic lifecycle operations ──────────────────────────
|
|
264
|
+
//
|
|
265
|
+
// Each wraps ONE better-sqlite3 transaction. The long-running re-dispatch
|
|
266
|
+
// (`dispatchWorkflow`) stays OUT of these — the caller dispatches after the
|
|
267
|
+
// transaction commits.
|
|
268
|
+
/**
|
|
269
|
+
* Resolve a socratic reply gate and resume the run, atomically: the reply
|
|
270
|
+
* gate flips `pending → approved` (recording the reply text), the caller's
|
|
271
|
+
* scratch patch merges in, and the run goes back to `running` — all in one
|
|
272
|
+
* transaction. A throw anywhere rolls the whole thing back, so the run can
|
|
273
|
+
* never be left `running` with its gate unresolved or its reply lost (the
|
|
274
|
+
* hazard issue #97 calls out).
|
|
275
|
+
*
|
|
276
|
+
* The reply-gate resolve is guarded by `kind = 'reply' AND status = 'pending'`
|
|
277
|
+
* (see {@link ApprovalStore.resolveReplyGate}); if it changes zero rows —
|
|
278
|
+
* because a racing reply already resolved the gate — this throws and the
|
|
279
|
+
* transaction aborts, which is the double-reply concurrency guard.
|
|
280
|
+
*
|
|
281
|
+
* The caller (`index.ts`) computes the explore-domain `scratch.socratic.qa`
|
|
282
|
+
* patch and passes it in; the generic store stays ignorant of that shape.
|
|
283
|
+
*/
|
|
284
|
+
/**
|
|
285
|
+
* Pause a run for an approval gate, atomically: create the pending approval,
|
|
286
|
+
* optionally merge a scratch patch (loops persist their iteration state
|
|
287
|
+
* here), append the `waiting_approval` phase marker, and flip the run to
|
|
288
|
+
* `paused` — all in one transaction. Covers the standard post-phase gate,
|
|
289
|
+
* the reviewer-loop gate, and the interactive generic-loop gate.
|
|
290
|
+
*
|
|
291
|
+
* The marker is appended BEFORE the approval insert so that an insert
|
|
292
|
+
* failure provably rolls back the phase-history write (the injected
|
|
293
|
+
* ApprovalStore participates in the same transaction); ordering is invisible
|
|
294
|
+
* outside the transaction.
|
|
295
|
+
*/
|
|
296
|
+
pauseForApproval(runId, approval, marker, scratchPatch) {
|
|
297
|
+
this.db.transaction(() => {
|
|
298
|
+
this.appendPhase(runId, marker.phase, {
|
|
299
|
+
phase: marker.phase,
|
|
300
|
+
timestamp: new Date().toISOString(),
|
|
301
|
+
success: true,
|
|
302
|
+
summary: marker.summary,
|
|
303
|
+
});
|
|
304
|
+
if (scratchPatch)
|
|
305
|
+
this.mergeScratch(runId, scratchPatch);
|
|
306
|
+
this.approvals.create(approval);
|
|
307
|
+
this.setPaused(runId);
|
|
308
|
+
})();
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Approve a gate and resume its run, atomically. Reads the approval to find
|
|
312
|
+
* its run, records the `approved` response, and flips the run back to
|
|
313
|
+
* `running` in one transaction; returns the run so the caller can dispatch.
|
|
314
|
+
* Used by the GitHub/Slack path (`index.ts`), which validates the dispatch
|
|
315
|
+
* target BEFORE calling this so the flip to `running` is always followed by a
|
|
316
|
+
* dispatch. The dashboard path does NOT use this — it can't prove a dispatch
|
|
317
|
+
* will follow before responding, so it records the approval and lets
|
|
318
|
+
* `resumeWorkflow` flip the run only as part of an actual dispatch.
|
|
319
|
+
*/
|
|
320
|
+
resolveGateAndResume(approvalId, responder) {
|
|
321
|
+
return this.db.transaction(() => {
|
|
322
|
+
const approval = this.approvals.getById(approvalId);
|
|
323
|
+
if (!approval)
|
|
324
|
+
throw new Error(`approval ${approvalId} not found`);
|
|
325
|
+
const changed = this.approvals.respond(approvalId, "approved", responder);
|
|
326
|
+
if (changed !== 1) {
|
|
327
|
+
throw new Error(`approval ${approvalId} is not pending (already resolved?)`);
|
|
328
|
+
}
|
|
329
|
+
this.setRunning(approval.workflowRunId);
|
|
330
|
+
return this.getRun(approval.workflowRunId);
|
|
331
|
+
})();
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Reject a gate and fail its run, atomically: record the `rejected` response
|
|
335
|
+
* (with reason) and flip the run to `failed` in one transaction. Returns the
|
|
336
|
+
* run (or null if the approval's run was already gone).
|
|
337
|
+
*/
|
|
338
|
+
resolveGateAndFail(approvalId, responder, reason) {
|
|
339
|
+
return this.db.transaction(() => {
|
|
340
|
+
const approval = this.approvals.getById(approvalId);
|
|
341
|
+
if (!approval)
|
|
342
|
+
throw new Error(`approval ${approvalId} not found`);
|
|
343
|
+
const changed = this.approvals.respond(approvalId, "rejected", responder, reason);
|
|
344
|
+
if (changed !== 1) {
|
|
345
|
+
throw new Error(`approval ${approvalId} is not pending (already resolved?)`);
|
|
346
|
+
}
|
|
347
|
+
this.flipFinished(approval.workflowRunId, "failed", `Rejected: ${reason || "no reason given"}`);
|
|
348
|
+
return this.getRun(approval.workflowRunId);
|
|
349
|
+
})();
|
|
350
|
+
}
|
|
351
|
+
resolveReplyGateAndResume(runId, approvalId, replyText, responder, scratchPatch) {
|
|
352
|
+
return this.db.transaction(() => {
|
|
353
|
+
const changed = this.approvals.resolveReplyGate(approvalId, replyText, responder);
|
|
354
|
+
if (changed !== 1) {
|
|
355
|
+
throw new Error(`reply gate ${approvalId} is not pending (already resolved?)`);
|
|
356
|
+
}
|
|
357
|
+
this.mergeScratch(runId, scratchPatch);
|
|
358
|
+
this.setRunning(runId);
|
|
359
|
+
return this.getRun(runId);
|
|
360
|
+
})();
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
//# sourceMappingURL=workflow-run-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-run-store.js","sourceRoot":"","sources":["../../src/state/workflow-run-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import Database from "better-sqlite3";
|
|
3
|
+
import { randomUUID } from "crypto";
|
|
4
|
+
import { StateDb } from "./db.js";
|
|
5
|
+
import { migrate } from "./migrate.js";
|
|
6
|
+
import { ApprovalStore } from "./approval-store.js";
|
|
7
|
+
import { WorkflowRunStore } from "./workflow-run-store.js";
|
|
8
|
+
let db;
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
db = new StateDb(":memory:");
|
|
11
|
+
});
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
db.close();
|
|
14
|
+
});
|
|
15
|
+
/** Create a fresh run and return its id. */
|
|
16
|
+
function makeRun(overrides = {}) {
|
|
17
|
+
const id = randomUUID();
|
|
18
|
+
db.runs.createRun({
|
|
19
|
+
id,
|
|
20
|
+
workflowName: "explore",
|
|
21
|
+
triggerId: `slack:${id}`,
|
|
22
|
+
currentPhase: "socratic",
|
|
23
|
+
status: "running",
|
|
24
|
+
startedAt: new Date().toISOString(),
|
|
25
|
+
...overrides,
|
|
26
|
+
});
|
|
27
|
+
return id;
|
|
28
|
+
}
|
|
29
|
+
describe("pauseForApproval", () => {
|
|
30
|
+
it("creates the approval, appends the marker, merges scratch, and pauses — in one step", () => {
|
|
31
|
+
const runId = makeRun();
|
|
32
|
+
const approvalId = randomUUID();
|
|
33
|
+
db.runs.pauseForApproval(runId, {
|
|
34
|
+
id: approvalId,
|
|
35
|
+
workflowRunId: runId,
|
|
36
|
+
gate: "post_architect",
|
|
37
|
+
summary: "Plan ready",
|
|
38
|
+
kind: "approve",
|
|
39
|
+
artifact: "architect-plan.md",
|
|
40
|
+
createdAt: new Date().toISOString(),
|
|
41
|
+
}, { phase: "waiting_approval", summary: "Waiting for approval: post_architect" }, { socratic: { iteration: 2 } });
|
|
42
|
+
const run = db.runs.getRun(runId);
|
|
43
|
+
expect(run.status).toBe("paused");
|
|
44
|
+
expect(run.currentPhase).toBe("waiting_approval");
|
|
45
|
+
expect(run.phaseHistory.at(-1).phase).toBe("waiting_approval");
|
|
46
|
+
expect(run.scratch).toEqual({ socratic: { iteration: 2 } });
|
|
47
|
+
const approval = db.approvals.getById(approvalId);
|
|
48
|
+
expect(approval.status).toBe("pending");
|
|
49
|
+
expect(approval.gate).toBe("post_architect");
|
|
50
|
+
expect(approval.artifact).toBe("architect-plan.md");
|
|
51
|
+
});
|
|
52
|
+
it("rolls back the phase-history append when the approval store throws (injected collaborator)", () => {
|
|
53
|
+
// Build a store stack on a raw shared connection so we can inject a fake
|
|
54
|
+
// ApprovalStore whose create() throws as the last txn step.
|
|
55
|
+
const raw = new Database(":memory:");
|
|
56
|
+
migrate(raw);
|
|
57
|
+
const realApprovals = new ApprovalStore(raw);
|
|
58
|
+
const seed = new WorkflowRunStore(raw, { approvals: realApprovals });
|
|
59
|
+
const runId = randomUUID();
|
|
60
|
+
seed.createRun({
|
|
61
|
+
id: runId,
|
|
62
|
+
workflowName: "build",
|
|
63
|
+
triggerId: "owner/repo#1",
|
|
64
|
+
currentPhase: "architect",
|
|
65
|
+
status: "running",
|
|
66
|
+
startedAt: new Date().toISOString(),
|
|
67
|
+
});
|
|
68
|
+
const throwingApprovals = {
|
|
69
|
+
create() {
|
|
70
|
+
throw new Error("approval insert failed");
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
const runs = new WorkflowRunStore(raw, { approvals: throwingApprovals });
|
|
74
|
+
expect(() => runs.pauseForApproval(runId, {
|
|
75
|
+
id: randomUUID(),
|
|
76
|
+
workflowRunId: runId,
|
|
77
|
+
gate: "post_architect",
|
|
78
|
+
summary: "Plan ready",
|
|
79
|
+
createdAt: new Date().toISOString(),
|
|
80
|
+
}, { phase: "waiting_approval" })).toThrow("approval insert failed");
|
|
81
|
+
// The appendPhase that ran before the throwing collaborator must be rolled
|
|
82
|
+
// back: the run is still running with empty phase history.
|
|
83
|
+
const run = seed.getRun(runId);
|
|
84
|
+
expect(run.status).toBe("running");
|
|
85
|
+
expect(run.phaseHistory).toEqual([]);
|
|
86
|
+
raw.close();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe("finishRun with a terminal marker", () => {
|
|
90
|
+
it("appends the on_success phase marker and flips status in one step", () => {
|
|
91
|
+
const runId = makeRun();
|
|
92
|
+
db.runs.finishRun(runId, "succeeded", { terminalMarker: { phase: "done", summary: "PR #5" } });
|
|
93
|
+
const run = db.runs.getRun(runId);
|
|
94
|
+
expect(run.status).toBe("succeeded");
|
|
95
|
+
expect(run.finishedAt).toBeTruthy();
|
|
96
|
+
expect(run.currentPhase).toBe("done");
|
|
97
|
+
const last = run.phaseHistory.at(-1);
|
|
98
|
+
expect(last.phase).toBe("done");
|
|
99
|
+
expect(last.summary).toBe("PR #5");
|
|
100
|
+
expect(last.success).toBe(true);
|
|
101
|
+
});
|
|
102
|
+
it("plain finish (no marker) flips status without touching phase history", () => {
|
|
103
|
+
const runId = makeRun();
|
|
104
|
+
db.runs.finishRun(runId, "failed", { error: "boom" });
|
|
105
|
+
const run = db.runs.getRun(runId);
|
|
106
|
+
expect(run.status).toBe("failed");
|
|
107
|
+
expect(run.phaseHistory).toEqual([]);
|
|
108
|
+
expect(run.context).toEqual({ error: "boom" });
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
describe("resolveGateAndResume — approve path", () => {
|
|
112
|
+
it("approves the gate and sets the run running, returning the run", () => {
|
|
113
|
+
const runId = makeRun({ status: "paused" });
|
|
114
|
+
const approvalId = randomUUID();
|
|
115
|
+
db.approvals.create({
|
|
116
|
+
id: approvalId,
|
|
117
|
+
workflowRunId: runId,
|
|
118
|
+
gate: "post_architect",
|
|
119
|
+
summary: "Plan ready",
|
|
120
|
+
createdAt: new Date().toISOString(),
|
|
121
|
+
});
|
|
122
|
+
const run = db.runs.resolveGateAndResume(approvalId, "bob");
|
|
123
|
+
expect(run.id).toBe(runId);
|
|
124
|
+
expect(run.status).toBe("running");
|
|
125
|
+
const approval = db.approvals.getById(approvalId);
|
|
126
|
+
expect(approval.status).toBe("approved");
|
|
127
|
+
expect(approval.respondedBy).toBe("bob");
|
|
128
|
+
});
|
|
129
|
+
it("throws on an unknown approval id", () => {
|
|
130
|
+
expect(() => db.runs.resolveGateAndResume("no-such-approval", "bob")).toThrow();
|
|
131
|
+
});
|
|
132
|
+
it("does not resume a stale approval that was already resolved", () => {
|
|
133
|
+
const runId = makeRun({ status: "paused" });
|
|
134
|
+
const approvalId = randomUUID();
|
|
135
|
+
db.approvals.create({
|
|
136
|
+
id: approvalId,
|
|
137
|
+
workflowRunId: runId,
|
|
138
|
+
gate: "post_architect",
|
|
139
|
+
summary: "Plan ready",
|
|
140
|
+
createdAt: new Date().toISOString(),
|
|
141
|
+
});
|
|
142
|
+
db.runs.resolveGateAndFail(approvalId, "carol", "plan incomplete");
|
|
143
|
+
expect(() => db.runs.resolveGateAndResume(approvalId, "bob")).toThrow("not pending");
|
|
144
|
+
expect(db.runs.getRun(runId).status).toBe("failed");
|
|
145
|
+
expect(db.approvals.getById(approvalId).status).toBe("rejected");
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
describe("resolveGateAndFail — reject path", () => {
|
|
149
|
+
it("does not fail a stale approval that was already approved", () => {
|
|
150
|
+
const runId = makeRun({ status: "paused" });
|
|
151
|
+
const approvalId = randomUUID();
|
|
152
|
+
db.approvals.create({
|
|
153
|
+
id: approvalId,
|
|
154
|
+
workflowRunId: runId,
|
|
155
|
+
gate: "post_architect",
|
|
156
|
+
summary: "Plan ready",
|
|
157
|
+
createdAt: new Date().toISOString(),
|
|
158
|
+
});
|
|
159
|
+
db.runs.resolveGateAndResume(approvalId, "bob");
|
|
160
|
+
expect(() => db.runs.resolveGateAndFail(approvalId, "carol", "too late")).toThrow("not pending");
|
|
161
|
+
expect(db.runs.getRun(runId).status).toBe("running");
|
|
162
|
+
expect(db.approvals.getById(approvalId).status).toBe("approved");
|
|
163
|
+
});
|
|
164
|
+
it("rejects the gate and fails the run", () => {
|
|
165
|
+
const runId = makeRun({ status: "paused" });
|
|
166
|
+
const approvalId = randomUUID();
|
|
167
|
+
db.approvals.create({
|
|
168
|
+
id: approvalId,
|
|
169
|
+
workflowRunId: runId,
|
|
170
|
+
gate: "post_architect",
|
|
171
|
+
summary: "Plan ready",
|
|
172
|
+
createdAt: new Date().toISOString(),
|
|
173
|
+
});
|
|
174
|
+
const run = db.runs.resolveGateAndFail(approvalId, "carol", "plan incomplete");
|
|
175
|
+
expect(run.id).toBe(runId);
|
|
176
|
+
expect(run.status).toBe("failed");
|
|
177
|
+
const approval = db.approvals.getById(approvalId);
|
|
178
|
+
expect(approval.status).toBe("rejected");
|
|
179
|
+
expect(approval.respondedBy).toBe("carol");
|
|
180
|
+
expect(approval.response).toBe("plan incomplete");
|
|
181
|
+
expect(db.runs.getRun(runId).context).toEqual({ error: "Rejected: plan incomplete" });
|
|
182
|
+
});
|
|
183
|
+
it("records a fallback error annotation when rejection has no reason", () => {
|
|
184
|
+
const runId = makeRun({ status: "paused" });
|
|
185
|
+
const approvalId = randomUUID();
|
|
186
|
+
db.approvals.create({
|
|
187
|
+
id: approvalId,
|
|
188
|
+
workflowRunId: runId,
|
|
189
|
+
gate: "post_architect",
|
|
190
|
+
summary: "Plan ready",
|
|
191
|
+
createdAt: new Date().toISOString(),
|
|
192
|
+
});
|
|
193
|
+
const run = db.runs.resolveGateAndFail(approvalId, "carol");
|
|
194
|
+
expect(run.status).toBe("failed");
|
|
195
|
+
expect(run.context).toEqual({ error: "Rejected: no reason given" });
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
describe("resolveReplyGateAndResume — the socratic explore-reply atomic op", () => {
|
|
199
|
+
it("resolves the reply gate, merges scratch, and sets the run running in one step", () => {
|
|
200
|
+
const runId = makeRun({ status: "paused" });
|
|
201
|
+
const approvalId = randomUUID();
|
|
202
|
+
db.approvals.create({
|
|
203
|
+
id: approvalId,
|
|
204
|
+
workflowRunId: runId,
|
|
205
|
+
gate: "socratic_1",
|
|
206
|
+
summary: "What problem are we solving?",
|
|
207
|
+
kind: "reply",
|
|
208
|
+
createdAt: new Date().toISOString(),
|
|
209
|
+
});
|
|
210
|
+
const scratchPatch = { socratic: { qa: [{ question: "Q1", answer: "A1" }] } };
|
|
211
|
+
const run = db.runs.resolveReplyGateAndResume(runId, approvalId, "A1", "alice", scratchPatch);
|
|
212
|
+
// Returns the resumed run
|
|
213
|
+
expect(run).not.toBeNull();
|
|
214
|
+
expect(run.id).toBe(runId);
|
|
215
|
+
expect(run.status).toBe("running");
|
|
216
|
+
// Gate resolved with the reply text recorded
|
|
217
|
+
const approval = db.approvals.getById(approvalId);
|
|
218
|
+
expect(approval.status).toBe("approved");
|
|
219
|
+
expect(approval.response).toBe("A1");
|
|
220
|
+
expect(approval.respondedBy).toBe("alice");
|
|
221
|
+
// Scratch merged
|
|
222
|
+
const reloaded = db.runs.getRun(runId);
|
|
223
|
+
expect(reloaded.status).toBe("running");
|
|
224
|
+
expect(reloaded.scratch).toEqual(scratchPatch);
|
|
225
|
+
});
|
|
226
|
+
it("double-reply concurrency guard: a second resolve throws and leaves the run paused", () => {
|
|
227
|
+
const runId = makeRun({ status: "paused" });
|
|
228
|
+
const approvalId = randomUUID();
|
|
229
|
+
db.approvals.create({
|
|
230
|
+
id: approvalId,
|
|
231
|
+
workflowRunId: runId,
|
|
232
|
+
gate: "socratic_1",
|
|
233
|
+
summary: "Q",
|
|
234
|
+
kind: "reply",
|
|
235
|
+
createdAt: new Date().toISOString(),
|
|
236
|
+
});
|
|
237
|
+
db.runs.resolveReplyGateAndResume(runId, approvalId, "first", "alice", {});
|
|
238
|
+
db.runs.setPaused(runId); // pretend it paused again on the next iteration
|
|
239
|
+
// A racing second reply against the already-resolved gate must not resume.
|
|
240
|
+
expect(() => db.runs.resolveReplyGateAndResume(runId, approvalId, "second", "bob", {})).toThrow();
|
|
241
|
+
expect(db.runs.getRun(runId).status).toBe("paused");
|
|
242
|
+
});
|
|
243
|
+
it("rolls back the gate resolution when the scratch patch is not serializable", () => {
|
|
244
|
+
const runId = makeRun({ status: "paused" });
|
|
245
|
+
const approvalId = randomUUID();
|
|
246
|
+
db.approvals.create({
|
|
247
|
+
id: approvalId,
|
|
248
|
+
workflowRunId: runId,
|
|
249
|
+
gate: "socratic_1",
|
|
250
|
+
summary: "Q",
|
|
251
|
+
kind: "reply",
|
|
252
|
+
createdAt: new Date().toISOString(),
|
|
253
|
+
});
|
|
254
|
+
// A BigInt makes JSON.stringify throw mid-transaction (natural poison input).
|
|
255
|
+
const poison = { socratic: { n: BigInt(1) } };
|
|
256
|
+
expect(() => db.runs.resolveReplyGateAndResume(runId, approvalId, "A1", "alice", poison)).toThrow();
|
|
257
|
+
// Nothing applied: gate still pending, run still paused, scratch untouched.
|
|
258
|
+
expect(db.approvals.getById(approvalId).status).toBe("pending");
|
|
259
|
+
const reloaded = db.runs.getRun(runId);
|
|
260
|
+
expect(reloaded.status).toBe("paused");
|
|
261
|
+
expect(reloaded.scratch).toBeUndefined();
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
//# sourceMappingURL=workflow-run-store.test.js.map
|