stageflow 0.23.0 → 0.27.0
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 +24 -5
- package/dist/a2a/configDiscovery.d.ts +9 -0
- package/dist/a2a/configDiscovery.js +18 -0
- package/dist/a2a/contracts.d.ts +94 -0
- package/dist/a2a/contracts.js +164 -0
- package/dist/a2a/limits.d.ts +14 -0
- package/dist/a2a/limits.js +29 -0
- package/dist/a2a/registry.d.ts +46 -0
- package/dist/a2a/registry.js +178 -0
- package/dist/a2a/server.d.ts +36 -0
- package/dist/a2a/server.js +344 -0
- package/dist/a2a/service.d.ts +97 -0
- package/dist/a2a/service.js +545 -0
- package/dist/a2a/store.d.ts +109 -0
- package/dist/a2a/store.js +202 -0
- package/dist/agent/activity.d.ts +3 -0
- package/dist/agent/bootProviderConfig.d.ts +21 -0
- package/dist/agent/bootProviderConfig.js +74 -0
- package/dist/agent/piAdapter.d.ts +9 -1
- package/dist/agent/piAdapter.js +58 -3
- package/dist/agent/piIsolatedMcp.d.ts +2 -0
- package/dist/agent/piIsolatedMcp.js +10 -2
- package/dist/agent/port.d.ts +6 -0
- package/dist/agent/streamLogRedact.d.ts +1 -1
- package/dist/agent/streamLogRedact.js +4 -11
- package/dist/cli/a2aCommand.d.ts +8 -0
- package/dist/cli/a2aCommand.js +131 -0
- package/dist/cli/artifactCommand.js +9 -16
- package/dist/cli/backupCommand.d.ts +9 -0
- package/dist/cli/backupCommand.js +111 -0
- package/dist/cli/debugRunCommand.d.ts +10 -0
- package/dist/cli/debugRunCommand.js +109 -0
- package/dist/cli/doctorCommand.d.ts +32 -0
- package/dist/cli/doctorCommand.js +453 -0
- package/dist/cli/envelopeCommand.js +9 -2
- package/dist/cli/exportAllCommand.d.ts +55 -0
- package/dist/cli/exportAllCommand.js +218 -0
- package/dist/cli/exportRunCommand.js +23 -21
- package/dist/cli/hostClient.d.ts +21 -3
- package/dist/cli/hostClient.js +93 -12
- package/dist/cli/initTemplates.d.ts +1 -1
- package/dist/cli/initTemplates.js +8 -1
- package/dist/cli/resolveSafeOutPath.d.ts +2 -0
- package/dist/cli/resolveSafeOutPath.js +40 -0
- package/dist/cli/restoreCommand.d.ts +10 -0
- package/dist/cli/restoreCommand.js +90 -0
- package/dist/cli/runCommand.d.ts +3 -2
- package/dist/cli/runCommand.js +93 -11
- package/dist/cli/runOutput.d.ts +4 -0
- package/dist/cli/runOutput.js +33 -7
- package/dist/cli/runStageCommand.d.ts +34 -0
- package/dist/cli/runStageCommand.js +426 -0
- package/dist/cli/runsCommand.d.ts +1 -1
- package/dist/cli/runsCommand.js +162 -8
- package/dist/cli.js +190 -30
- package/dist/config/catalogRelativePath.d.ts +62 -0
- package/dist/config/catalogRelativePath.js +118 -0
- package/dist/config/configOrigin.d.ts +27 -0
- package/dist/config/configOrigin.js +59 -0
- package/dist/config/hostConfig.d.ts +55 -0
- package/dist/config/hostConfig.js +333 -0
- package/dist/config/listSkills.d.ts +26 -0
- package/dist/config/listSkills.js +190 -3
- package/dist/config/loadOutcome.d.ts +1 -1
- package/dist/config/loadPipeline.js +23 -2
- package/dist/config/loadStage.js +18 -0
- package/dist/config/loadTask.d.ts +2 -0
- package/dist/config/loadTask.js +57 -18
- package/dist/config/materializeStageModels.js +5 -1
- package/dist/config/mergePipelineIncludes.d.ts +3 -0
- package/dist/config/mergePipelineIncludes.js +19 -0
- package/dist/config/migrateYaml.js +6 -11
- package/dist/config/multiProjectCatalog.d.ts +30 -0
- package/dist/config/multiProjectCatalog.js +142 -0
- package/dist/config/normalizePipelineStageEntry.js +20 -1
- package/dist/config/pipelineStageKeys.js +2 -0
- package/dist/config/resolveCatalogRoots.d.ts +27 -0
- package/dist/config/resolveCatalogRoots.js +76 -0
- package/dist/config/resolveModel.d.ts +7 -1
- package/dist/config/resolveModel.js +11 -1
- package/dist/config/resolveStageMcpServers.d.ts +9 -1
- package/dist/config/resolveStageMcpServers.js +36 -9
- package/dist/config/secretFromEnvOrFile.d.ts +9 -0
- package/dist/config/secretFromEnvOrFile.js +34 -0
- package/dist/config/seededCatalog.d.ts +11 -0
- package/dist/config/seededCatalog.js +29 -0
- package/dist/config/toolRequires.d.ts +24 -0
- package/dist/config/toolRequires.js +115 -0
- package/dist/config/validateCatalog.d.ts +5 -1
- package/dist/config/validateCatalog.js +140 -1
- package/dist/diagnostics/checks.d.ts +39 -0
- package/dist/diagnostics/checks.js +135 -0
- package/dist/errors/codes.d.ts +14 -0
- package/dist/errors/codes.js +59 -0
- package/dist/git/cache.d.ts +14 -0
- package/dist/git/cache.js +150 -0
- package/dist/git/credentials.d.ts +9 -0
- package/dist/git/credentials.js +88 -0
- package/dist/git/errors.d.ts +20 -0
- package/dist/git/errors.js +94 -0
- package/dist/git/exec.d.ts +16 -0
- package/dist/git/exec.js +135 -0
- package/dist/git/operations.d.ts +29 -0
- package/dist/git/operations.js +153 -0
- package/dist/git/version.d.ts +1 -0
- package/dist/git/version.js +10 -0
- package/dist/logging/audit.d.ts +16 -0
- package/dist/logging/audit.js +19 -0
- package/dist/logging/commonWords.d.ts +2 -0
- package/dist/logging/commonWords.js +13 -0
- package/dist/logging/logger.d.ts +49 -0
- package/dist/logging/logger.js +193 -0
- package/dist/logging/namedSecrets.d.ts +6 -0
- package/dist/logging/namedSecrets.js +58 -0
- package/dist/logging/redact.d.ts +13 -0
- package/dist/logging/redact.js +88 -0
- package/dist/mcp/catalogTools.js +591 -76
- package/dist/mcp/checkoutTools.d.ts +52 -0
- package/dist/mcp/checkoutTools.js +332 -0
- package/dist/mcp/controlTools.js +179 -5
- package/dist/mcp/deps.d.ts +1 -0
- package/dist/mcp/getStartedTool.d.ts +3 -0
- package/dist/mcp/getStartedTool.js +62 -0
- package/dist/mcp/readArtifact.d.ts +11 -0
- package/dist/mcp/readArtifact.js +46 -30
- package/dist/mcp/server.js +1 -0
- package/dist/mcp/tools.js +4 -0
- package/dist/net/proxy.d.ts +14 -0
- package/dist/net/proxy.js +78 -0
- package/dist/package-meta.d.ts +2 -1
- package/dist/package-meta.js +2 -1
- package/dist/preflight/bash.d.ts +8 -0
- package/dist/preflight/bash.js +34 -0
- package/dist/preflight/claudeRoot.d.ts +11 -0
- package/dist/preflight/claudeRoot.js +23 -0
- package/dist/preflight/mcpCommands.d.ts +8 -0
- package/dist/preflight/mcpCommands.js +36 -0
- package/dist/preflight/pipelinePreflight.d.ts +40 -0
- package/dist/preflight/pipelinePreflight.js +192 -0
- package/dist/preflight/tls.d.ts +6 -0
- package/dist/preflight/tls.js +18 -0
- package/dist/preflight/toolchain.d.ts +45 -0
- package/dist/preflight/toolchain.js +219 -0
- package/dist/project/findProjectRoot.js +3 -4
- package/dist/project/globalHome.d.ts +7 -0
- package/dist/project/globalHome.js +63 -2
- package/dist/project/resolveProjectContext.js +2 -2
- package/dist/project/resolveStageflowContext.js +2 -2
- package/dist/projection/projectRun.d.ts +2 -1
- package/dist/projection/projectRun.js +1 -0
- package/dist/runstore/assertTmpdir.d.ts +1 -0
- package/dist/runstore/assertTmpdir.js +21 -0
- package/dist/runstore/backup.d.ts +52 -0
- package/dist/runstore/backup.js +292 -0
- package/dist/runstore/createStore.d.ts +27 -0
- package/dist/runstore/createStore.js +75 -7
- package/dist/runstore/debugBundle.d.ts +60 -0
- package/dist/runstore/debugBundle.js +143 -0
- package/dist/runstore/diskUsage.d.ts +50 -0
- package/dist/runstore/diskUsage.js +214 -0
- package/dist/runstore/exportRunPayload.d.ts +8 -0
- package/dist/runstore/exportRunPayload.js +23 -0
- package/dist/runstore/normalizeCatalogPath.d.ts +1 -0
- package/dist/runstore/normalizeCatalogPath.js +10 -0
- package/dist/runstore/paths.d.ts +5 -0
- package/dist/runstore/paths.js +145 -1
- package/dist/runstore/port.d.ts +119 -8
- package/dist/runstore/port.js +8 -1
- package/dist/runstore/restore.d.ts +81 -0
- package/dist/runstore/restore.js +355 -0
- package/dist/runstore/retention.d.ts +27 -0
- package/dist/runstore/retention.js +74 -0
- package/dist/runstore/runManifest.d.ts +146 -0
- package/dist/runstore/runManifest.js +288 -0
- package/dist/runstore/runProjection.d.ts +3 -1
- package/dist/runstore/runProjection.js +63 -1
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +37 -3
- package/dist/runstore/sqlite/SqliteRunStore.js +401 -227
- package/dist/runstore/sqlite/applyStorePragmas.d.ts +39 -0
- package/dist/runstore/sqlite/applyStorePragmas.js +145 -0
- package/dist/runstore/sqlite/migrations/001-baseline.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/001-baseline.js +10 -0
- package/dist/runstore/sqlite/migrations/002-repository-binding.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/002-repository-binding.js +29 -0
- package/dist/runstore/sqlite/migrations/003-run-lifecycle.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/003-run-lifecycle.js +28 -0
- package/dist/runstore/sqlite/migrations/004-auto-resume-count.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/004-auto-resume-count.js +19 -0
- package/dist/runstore/sqlite/migrations/005-config-origins.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/005-config-origins.js +19 -0
- package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.js +28 -0
- package/dist/runstore/sqlite/migrations/007-projects-registry.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/007-projects-registry.js +31 -0
- package/dist/runstore/sqlite/migrations/index.d.ts +21 -0
- package/dist/runstore/sqlite/migrations/index.js +72 -0
- package/dist/runstore/sqlite/schema.d.ts +20 -1
- package/dist/runstore/sqlite/schema.js +283 -1
- package/dist/runstore/sqlite/storeOpenError.d.ts +6 -0
- package/dist/runstore/sqlite/storeOpenError.js +11 -0
- package/dist/runstore/sqlite/storeSchemaError.d.ts +5 -0
- package/dist/runstore/sqlite/storeSchemaError.js +8 -0
- package/dist/runstore/stageExecution.js +3 -0
- package/dist/runstore/storeFilesystem.d.ts +32 -0
- package/dist/runstore/storeFilesystem.js +148 -0
- package/dist/runstore/submission.d.ts +11 -0
- package/dist/runstore/submission.js +7 -0
- package/dist/runstore/trackProjection.js +2 -0
- package/dist/runstore/workspaceLayout.d.ts +13 -0
- package/dist/runstore/workspaceLayout.js +76 -0
- package/dist/runtime/completionCheckRunner.d.ts +3 -0
- package/dist/runtime/completionCheckRunner.js +45 -7
- package/dist/runtime/containerLimits.d.ts +16 -0
- package/dist/runtime/containerLimits.js +84 -0
- package/dist/runtime/credentialMaterialisation.d.ts +28 -0
- package/dist/runtime/credentialMaterialisation.js +128 -0
- package/dist/runtime/gitCheckoutCapability.js +7 -13
- package/dist/runtime/pipelineRunner.d.ts +38 -1
- package/dist/runtime/pipelineRunner.js +179 -15
- package/dist/runtime/pipelineScheduler.d.ts +15 -0
- package/dist/runtime/pipelineScheduler.js +167 -42
- package/dist/runtime/reloadRunCatalog.js +12 -1
- package/dist/runtime/repositoryMaterialize.d.ts +47 -0
- package/dist/runtime/repositoryMaterialize.js +235 -0
- package/dist/runtime/resolveEnvelopeRef.d.ts +30 -0
- package/dist/runtime/resolveEnvelopeRef.js +79 -0
- package/dist/runtime/resumeTimedOut.d.ts +1 -1
- package/dist/runtime/resumeTimedOut.js +5 -2
- package/dist/runtime/runChangeBus.js +9 -0
- package/dist/runtime/runDeletion.d.ts +7 -0
- package/dist/runtime/runDeletion.js +37 -0
- package/dist/runtime/runManager.d.ts +179 -4
- package/dist/runtime/runManager.js +1644 -83
- package/dist/runtime/runRetentionSweep.d.ts +31 -0
- package/dist/runtime/runRetentionSweep.js +328 -0
- package/dist/runtime/runRetryCoordinator.d.ts +2 -0
- package/dist/runtime/runRetryCoordinator.js +19 -2
- package/dist/runtime/runSkills.d.ts +40 -0
- package/dist/runtime/runSkills.js +173 -0
- package/dist/runtime/stageAttemptBootstrap.d.ts +5 -1
- package/dist/runtime/stageAttemptBootstrap.js +195 -24
- package/dist/runtime/stageCacheEnv.d.ts +6 -0
- package/dist/runtime/stageCacheEnv.js +34 -0
- package/dist/runtime/stageConcurrency.d.ts +2 -1
- package/dist/runtime/stageConcurrency.js +4 -2
- package/dist/runtime/stageEnvironment.d.ts +38 -0
- package/dist/runtime/stageEnvironment.js +193 -0
- package/dist/runtime/stageProcessLauncher.d.ts +18 -0
- package/dist/runtime/stageProcessLauncher.js +194 -38
- package/dist/runtime/stageRecovery.d.ts +3 -1
- package/dist/runtime/stageRecovery.js +19 -4
- package/dist/runtime/stageRoots.d.ts +38 -1
- package/dist/runtime/stageRoots.js +118 -0
- package/dist/runtime/stageRunner.d.ts +1 -0
- package/dist/runtime/stageRunner.js +3 -1
- package/dist/runtime/stageSecretDecl.d.ts +9 -0
- package/dist/runtime/stageSecretDecl.js +102 -0
- package/dist/runtime/stageSecrets.d.ts +40 -0
- package/dist/runtime/stageSecrets.js +181 -0
- package/dist/runtime/stageWorker.d.ts +3 -2
- package/dist/runtime/stageWorker.js +58 -10
- package/dist/runtime/stageWorkerProtocol.d.ts +5 -0
- package/dist/runtime/stageWorkerProtocol.js +8 -0
- package/dist/runtime/startPayload.d.ts +32 -0
- package/dist/runtime/startPayload.js +59 -0
- package/dist/runtime/taskInput.js +14 -5
- package/dist/runtime/verifiedStageExecution.d.ts +1 -0
- package/dist/runtime/verifiedStageExecution.js +2 -1
- package/dist/runtime/workspaceBinding.d.ts +20 -0
- package/dist/runtime/workspaceBinding.js +60 -0
- package/dist/server/allowedHosts.d.ts +19 -0
- package/dist/server/allowedHosts.js +179 -0
- package/dist/server/bootstrap.d.ts +38 -2
- package/dist/server/bootstrap.js +219 -4
- package/dist/server/controlToken.d.ts +47 -0
- package/dist/server/controlToken.js +241 -0
- package/dist/server/createHttpHost.d.ts +11 -2
- package/dist/server/createHttpHost.js +109 -10
- package/dist/server/ensureGlobalService.d.ts +5 -1
- package/dist/server/ensureGlobalService.js +35 -1
- package/dist/server/healthSurfaces.d.ts +6 -0
- package/dist/server/healthSurfaces.js +98 -0
- package/dist/server/http.d.ts +12 -1
- package/dist/server/http.js +1085 -485
- package/dist/server/listenHost.d.ts +5 -0
- package/dist/server/listenHost.js +56 -0
- package/dist/server/mcpHost.d.ts +10 -1
- package/dist/server/mcpHost.js +36 -6
- package/dist/server/operatorResults.d.ts +2 -2
- package/dist/server/operatorResults.js +40 -29
- package/dist/server/requestAuthContext.d.ts +12 -0
- package/dist/server/requestAuthContext.js +21 -0
- package/dist/server/shutdown.d.ts +69 -0
- package/dist/server/shutdown.js +219 -0
- package/dist/types/pipeline.d.ts +7 -0
- package/dist/types/stage.d.ts +8 -0
- package/dist/types/task.d.ts +8 -0
- package/dist/ui/assets/index-B6hlSXXn.js +120 -0
- package/dist/ui/index.html +1 -1
- package/examples/README.md +98 -0
- package/examples/archify-on-pr/README.md +213 -0
- package/examples/archify-on-pr/archify-on-pr.pipeline.yaml +19 -0
- package/examples/archify-on-pr/archify-on-pr.task.yaml +19 -0
- package/examples/archify-on-pr/author-diagrams.yaml +106 -0
- package/examples/archify-on-pr/detect-changes.yaml +89 -0
- package/examples/ci-validate/README.md +35 -0
- package/examples/ci-validate/check.yaml +13 -0
- package/examples/ci-validate/ci-demo.pipeline.yaml +4 -0
- package/examples/ci-validate/validate.sh +5 -0
- package/examples/compliance-review-demo/README.md +125 -0
- package/examples/compliance-review-demo/compliance-review-demo.pipeline.yaml +29 -0
- package/examples/compliance-review-demo/connect-account.yaml +47 -0
- package/examples/compliance-review-demo/map-to-control.yaml +123 -0
- package/examples/compliance-review-demo/poll-bucket-config.yaml +103 -0
- package/examples/compliance-review-demo/publish-report.yaml +79 -0
- package/examples/compliance-review-demo/review-verdict.yaml +122 -0
- package/examples/compliance-review-demo/run-compliance-check.yaml +96 -0
- package/examples/compliance-review-demo/store-evidence.yaml +143 -0
- package/examples/conditional-fork/README.md +89 -0
- package/examples/conditional-fork/branch-a.yaml +13 -0
- package/examples/conditional-fork/branch-b.yaml +13 -0
- package/examples/conditional-fork/decide.yaml +35 -0
- package/examples/conditional-fork/fork-demo.pipeline.yaml +20 -0
- package/examples/conditional-fork/fork-demo.task.yaml +8 -0
- package/examples/context7-mcp/README.md +42 -0
- package/examples/context7-mcp/context7-mcp.pipeline.yaml +15 -0
- package/examples/context7-mcp/context7-mcp.task.yaml +4 -0
- package/examples/context7-mcp/fetch-docs.yaml +52 -0
- package/examples/context7-mcp/resolve-library.yaml +31 -0
- package/examples/context7-mcp/write-brief.yaml +52 -0
- package/examples/feature-loop/README.md +104 -0
- package/examples/feature-loop/address-feedback.yaml +148 -0
- package/examples/feature-loop/align.yaml +116 -0
- package/examples/feature-loop/decompose.yaml +86 -0
- package/examples/feature-loop/default-model-hierarchy.task.yaml +58 -0
- package/examples/feature-loop/feature-loop.pipeline.yaml +140 -0
- package/examples/feature-loop/feature-loop.task.yaml +25 -0
- package/examples/feature-loop/implement.yaml +128 -0
- package/examples/feature-loop/plan.yaml +111 -0
- package/examples/feature-loop/publish.yaml +167 -0
- package/examples/feature-loop/review.yaml +146 -0
- package/examples/feature-loop/verify.yaml +106 -0
- package/examples/feedback-loop/README.md +72 -0
- package/examples/feedback-loop/VERIFY.md +208 -0
- package/examples/feedback-loop/continue-only.task.yaml +4 -0
- package/examples/feedback-loop/exhaust-require-continue.task.yaml +6 -0
- package/examples/feedback-loop/exhaust-wait-human.task.yaml +11 -0
- package/examples/feedback-loop/feedback-loop-wait-human.pipeline.yaml +23 -0
- package/examples/feedback-loop/feedback-loop.pipeline.yaml +23 -0
- package/examples/feedback-loop/feedback-loop.task.yaml +4 -0
- package/examples/feedback-loop/implement.yaml +14 -0
- package/examples/feedback-loop/plan.yaml +14 -0
- package/examples/feedback-loop/review.yaml +15 -0
- package/examples/feedback-loop/send-back-once.task.yaml +6 -0
- package/examples/feedback-loop/submit.yaml +12 -0
- package/examples/generic-fan-in/README.md +151 -0
- package/examples/generic-fan-in/clarify.yaml +18 -0
- package/examples/generic-fan-in/generic-fan-in-accepted.pipeline.yaml +19 -0
- package/examples/generic-fan-in/generic-fan-in-accepted.task.yaml +8 -0
- package/examples/generic-fan-in/generic-fan-in.pipeline.yaml +18 -0
- package/examples/generic-fan-in/generic-fan-in.task.yaml +9 -0
- package/examples/generic-fan-in/research.yaml +45 -0
- package/examples/generic-fan-in/synthesize.yaml +66 -0
- package/examples/generic-fan-in/validation.yaml +45 -0
- package/examples/github-release/README.md +78 -0
- package/examples/github-release/draft-release-notes.yaml +64 -0
- package/examples/github-release/github-release.pipeline.yaml +11 -0
- package/examples/github-release/github-release.task.yaml +13 -0
- package/examples/github-release/publish-github-release.yaml +64 -0
- package/examples/hello-world/README.md +28 -0
- package/examples/hello-world/hello.pipeline.yaml +4 -0
- package/examples/hello-world/my-task.task.yaml +6 -0
- package/examples/hello-world/research.yaml +18 -0
- package/examples/mcp-hitl-tour/README.md +113 -0
- package/examples/mcp-hitl-tour/draft-angle.yaml +33 -0
- package/examples/mcp-hitl-tour/draft-short.yaml +32 -0
- package/examples/mcp-hitl-tour/emit-angles.yaml +45 -0
- package/examples/mcp-hitl-tour/gather.yaml +31 -0
- package/examples/mcp-hitl-tour/intake.yaml +62 -0
- package/examples/mcp-hitl-tour/mcp-hitl-tour-exhaust.task.yaml +13 -0
- package/examples/mcp-hitl-tour/mcp-hitl-tour.pipeline.yaml +54 -0
- package/examples/mcp-hitl-tour/mcp-hitl-tour.task.yaml +16 -0
- package/examples/mcp-hitl-tour/polish.yaml +33 -0
- package/examples/mcp-hitl-tour/review.yaml +17 -0
- package/examples/mcp-hitl-tour/ship.yaml +25 -0
- package/examples/oss-issue-contribution/README.md +218 -0
- package/examples/oss-issue-contribution/oss-address-review-feedback.yaml +117 -0
- package/examples/oss-issue-contribution/oss-approve-contribution.yaml +181 -0
- package/examples/oss-issue-contribution/oss-approve-plan.yaml +111 -0
- package/examples/oss-issue-contribution/oss-explain-fix.yaml +108 -0
- package/examples/oss-issue-contribution/oss-explain-issue.yaml +114 -0
- package/examples/oss-issue-contribution/oss-implement-source-fix.yaml +171 -0
- package/examples/oss-issue-contribution/oss-investigate-area.yaml +116 -0
- package/examples/oss-issue-contribution/oss-issue-contribution.pipeline.yaml +125 -0
- package/examples/oss-issue-contribution/oss-issue-intake.yaml +106 -0
- package/examples/oss-issue-contribution/oss-plan-investigation.yaml +112 -0
- package/examples/oss-issue-contribution/oss-plan-review.yaml +109 -0
- package/examples/oss-issue-contribution/oss-reproduce-issue.yaml +140 -0
- package/examples/oss-issue-contribution/oss-review-change.yaml +107 -0
- package/examples/oss-issue-contribution/oss-verify-fix.yaml +130 -0
- package/examples/oss-issue-contribution/oss-write-regression-test.yaml +135 -0
- package/examples/oss-issue-contribution/pi-7629.task.yaml +79 -0
- package/examples/oss-issue-contribution/pi-8919.task.yaml +75 -0
- package/examples/oss-issue-contribution/pydantic-ai-7971.task.yaml +53 -0
- package/examples/oss-quick-fix/README.md +65 -0
- package/examples/oss-quick-fix/implement-fix.yaml +84 -0
- package/examples/oss-quick-fix/oss-quick-fix.pipeline.yaml +35 -0
- package/examples/oss-quick-fix/oss-quick-fix.task.yaml +19 -0
- package/examples/oss-quick-fix/ship-fix.yaml +81 -0
- package/examples/oss-quick-fix/understand-issue.yaml +67 -0
- package/examples/oss-quick-fix/verify-fix.yaml +73 -0
- package/examples/plan-review/README.md +37 -0
- package/examples/plan-review/plan-review-followup.yaml +13 -0
- package/examples/plan-review/plan-review.pipeline.yaml +9 -0
- package/examples/plan-review/plan-review.task.yaml +9 -0
- package/examples/plan-review/plan-review.yaml +25 -0
- package/examples/playwright-mcp/README.md +39 -0
- package/examples/playwright-mcp/playwright-mcp.pipeline.yaml +5 -0
- package/examples/playwright-mcp/playwright-mcp.task.yaml +4 -0
- package/examples/playwright-mcp/screenshot.yaml +40 -0
- package/examples/retry-tour/README.md +75 -0
- package/examples/retry-tour/retry-tour.pipeline.yaml +122 -0
- package/examples/retry-tour/retry-tour.task.yaml +9 -0
- package/examples/route-if-tour/README.md +202 -0
- package/examples/route-if-tour/route-if-tour.pipeline.yaml +950 -0
- package/examples/route-if-tour/route-if-tour.task.yaml +4 -0
- package/examples/route-wiring-smoke-test/01-core-routing.pipeline.yaml +168 -0
- package/examples/route-wiring-smoke-test/02-on-gating.pipeline.yaml +44 -0
- package/examples/route-wiring-smoke-test/03-two-entry-points.pipeline.yaml +28 -0
- package/examples/route-wiring-smoke-test/04-entry-false-equivalent-to-omitted.pipeline.yaml +27 -0
- package/examples/route-wiring-smoke-test/05-fork-choice.pipeline.yaml +110 -0
- package/examples/route-wiring-smoke-test/06-fan-out-fan-in.pipeline.yaml +82 -0
- package/examples/route-wiring-smoke-test/07-loop-human-decision.pipeline.yaml +82 -0
- package/examples/route-wiring-smoke-test/08-skip-fallback-and-multi-on-gate.pipeline.yaml +77 -0
- package/examples/route-wiring-smoke-test/09-multi-loop-targets.pipeline.yaml +102 -0
- package/examples/route-wiring-smoke-test/10-uses-dialect-fork.pipeline.yaml +23 -0
- package/examples/route-wiring-smoke-test/11-sequential-io-handoff.pipeline.yaml +37 -0
- package/examples/route-wiring-smoke-test/12-complex-io-schemas.pipeline.yaml +138 -0
- package/examples/route-wiring-smoke-test/13-ref-io-handoff.pipeline.yaml +84 -0
- package/examples/route-wiring-smoke-test/14-if-eq-gating.pipeline.yaml +50 -0
- package/examples/route-wiring-smoke-test/15-if-all-gated.pipeline.yaml +37 -0
- package/examples/route-wiring-smoke-test/16-if-composition.pipeline.yaml +65 -0
- package/examples/route-wiring-smoke-test/17-if-join.pipeline.yaml +80 -0
- package/examples/route-wiring-smoke-test/README.md +377 -0
- package/examples/route-wiring-smoke-test/rejected/01-reject-legacy-needs.pipeline.yaml +26 -0
- package/examples/route-wiring-smoke-test/rejected/02-reject-legacy-fork.pipeline.yaml +25 -0
- package/examples/route-wiring-smoke-test/rejected/03-reject-legacy-feedback-loop.pipeline.yaml +30 -0
- package/examples/route-wiring-smoke-test/rejected/04-reject-missing-entry.pipeline.yaml +24 -0
- package/examples/route-wiring-smoke-test/rejected/05-reject-unreachable.pipeline.yaml +35 -0
- package/examples/route-wiring-smoke-test/rejected/06-reject-allow-none-without-route-select.pipeline.yaml +37 -0
- package/examples/route-wiring-smoke-test/rejected/07-reject-cycle.pipeline.yaml +27 -0
- package/examples/route-wiring-smoke-test/rejected/08-reject-loop-non-ancestor.pipeline.yaml +42 -0
- package/examples/route-wiring-smoke-test/rejected/09-reject-route-select-leaf.pipeline.yaml +26 -0
- package/examples/route-wiring-smoke-test/rejected/12-reject-loop-replay-unsafe.pipeline.yaml +55 -0
- package/examples/route-wiring-smoke-test/rejected/13-reject-multiple-loop-entries.pipeline.yaml +51 -0
- package/examples/route-wiring-smoke-test/rejected/14-reject-duplicate-stage-id.pipeline.yaml +35 -0
- package/examples/route-wiring-smoke-test/rejected/15-reject-unknown-route-target.pipeline.yaml +15 -0
- package/examples/route-wiring-smoke-test/rejected/16-reject-malformed-route-item.pipeline.yaml +15 -0
- package/examples/route-wiring-smoke-test/rejected/17-reject-io-incompatible.pipeline.yaml +33 -0
- package/examples/route-wiring-smoke-test/rejected/18-reject-nested-io.pipeline.yaml +51 -0
- package/examples/route-wiring-smoke-test/rejected/19-reject-array-item-io.pipeline.yaml +55 -0
- package/examples/route-wiring-smoke-test/rejected/20-reject-closed-io.pipeline.yaml +36 -0
- package/examples/route-wiring-smoke-test/rejected/21-reject-ref-io.pipeline.yaml +42 -0
- package/examples/route-wiring-smoke-test/rejected/22-reject-if-unknown-field.pipeline.yaml +33 -0
- package/examples/route-wiring-smoke-test/rejected/23-reject-if-optional-field.pipeline.yaml +32 -0
- package/examples/route-wiring-smoke-test/rejected/24-reject-if-empty-all.pipeline.yaml +31 -0
- package/examples/route-wiring-smoke-test/rejected/25-reject-if-gt-on-string.pipeline.yaml +33 -0
- package/examples/route-wiring-smoke-test/rejected/26-reject-if-optional-nested.pipeline.yaml +36 -0
- package/examples/route-wiring-smoke-test/rejected/27-reject-if-on-loop.pipeline.yaml +63 -0
- package/examples/route-wiring-smoke-test/rejected/29-reject-if-on-failed.pipeline.yaml +46 -0
- package/examples/route-wiring-smoke-test/smoke-test.task.yaml +4 -0
- package/examples/route-wiring-smoke-test/stages/branch-a.yaml +12 -0
- package/examples/route-wiring-smoke-test/stages/branch-b.yaml +12 -0
- package/examples/route-wiring-smoke-test/stages/decide.yaml +12 -0
- package/examples/route-wiring-smoke-test/stages/finish.yaml +12 -0
- package/examples/ship-feature/README.md +190 -0
- package/examples/ship-feature/feat-address-feedback.yaml +119 -0
- package/examples/ship-feature/feat-implement.yaml +180 -0
- package/examples/ship-feature/feat-plan.yaml +120 -0
- package/examples/ship-feature/feat-review.yaml +109 -0
- package/examples/ship-feature/feat-ship.yaml +203 -0
- package/examples/ship-feature/ship-feature.pipeline.yaml +44 -0
- package/examples/ship-feature/ship-feature.task.yaml +78 -0
- package/examples/stage-mcp/README.md +144 -0
- package/examples/stage-mcp/echo-mcp.mjs +20 -0
- package/examples/stage-mcp/stage-mcp-dead.pipeline.yaml +5 -0
- package/examples/stage-mcp/stage-mcp-dead.task.yaml +3 -0
- package/examples/stage-mcp/stage-mcp-missing-var.pipeline.yaml +5 -0
- package/examples/stage-mcp/stage-mcp-missing-var.task.yaml +3 -0
- package/examples/stage-mcp/stage-mcp.pipeline.yaml +5 -0
- package/examples/stage-mcp/stage-mcp.task.yaml +4 -0
- package/examples/stage-mcp/use-echo.yaml +20 -0
- package/examples/verify-tour/README.md +80 -0
- package/examples/verify-tour/verify-tour.pipeline.yaml +162 -0
- package/examples/verify-tour/verify-tour.task.yaml +11 -0
- package/package.json +6 -1
- package/skills/stageflow/SKILL.md +6 -6
- package/skills/stageflow/references/control-surface.md +11 -5
- package/skills/stageflow/scripts/detect-host.mjs +14 -1
- package/skills/stageflow/scripts/detect-host.test.mjs +29 -1
- package/skills/stageflow-author/SKILL.md +4 -3
- package/skills/stageflow-author/references/catalog-mapping.md +16 -0
- package/skills/stageflow-author/references/catalog-write-conventions.md +1 -1
- package/skills/stageflow-run/SKILL.md +20 -12
- package/skills/stageflow-run/references/mcp-call.md +9 -1
- package/skills/stageflow-run/references/task-and-pipeline-selection.md +16 -5
- package/skills/stageflow-run/scripts/mcp-call.mjs +46 -6
- package/skills/stageflow-run/scripts/mcp-call.test.mjs +64 -0
- package/skills/stageflow-session-capture/references/catalog-authoring.md +2 -0
- package/skills/stageflow-setup/SKILL.md +40 -8
- package/dist/ui/assets/index-Da5EHU6M.js +0 -119
|
@@ -1,189 +1,20 @@
|
|
|
1
1
|
import Database from "better-sqlite3";
|
|
2
|
+
import { existsSync, statSync } from "node:fs";
|
|
2
3
|
import { mkdir } from "node:fs/promises";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { projectRunDetail, projectRunSummary, orderStageSnapshots } from "../runProjection.js";
|
|
5
|
-
import { normalizeCatalogPath } from "../normalizeCatalogPath.js";
|
|
6
|
+
import { normalizeCatalogPath, normalizeProjectRoot } from "../normalizeCatalogPath.js";
|
|
6
7
|
import { buildStageSnapshotFromStore } from "../stageSnapshot.js";
|
|
7
8
|
import { parsePipelineDagSnapshot } from "../pipelineDagSnapshot.js";
|
|
8
9
|
import { newRunId, runWorkspaceDir } from "../paths.js";
|
|
9
10
|
import { attemptAgentDir, attemptArtifactsDir, stageDir, } from "../workspaceLayout.js";
|
|
10
11
|
import { importDiskRunsIfEmpty } from "./migrateFromDisk.js";
|
|
11
|
-
import {
|
|
12
|
+
import { applyPendingMigrations, assertSchemaVersion, } from "./migrations/index.js";
|
|
13
|
+
import { StoreSchemaError } from "./storeSchemaError.js";
|
|
14
|
+
import { applyStorePragmas } from "./applyStorePragmas.js";
|
|
15
|
+
import { RunSubmissionExistsError } from "../submission.js";
|
|
16
|
+
const EXECUTION_SELECT_COLS = `run_id, stage_id, attempt, status, verification_outcome, started_at, finished_at, envelope_json, cost_usd, usage_json, auto_resume_count`;
|
|
12
17
|
const ensuredStageDirs = new Set();
|
|
13
|
-
const DEFAULT_SQLITE_BUSY_TIMEOUT_MS = 5000;
|
|
14
|
-
function readSqliteBusyTimeoutMs() {
|
|
15
|
-
const raw = process.env.STAGEFLOW_SQLITE_BUSY_TIMEOUT_MS;
|
|
16
|
-
if (raw === undefined || raw.trim() === "") {
|
|
17
|
-
return DEFAULT_SQLITE_BUSY_TIMEOUT_MS;
|
|
18
|
-
}
|
|
19
|
-
const parsed = Number.parseInt(raw, 10);
|
|
20
|
-
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
21
|
-
return DEFAULT_SQLITE_BUSY_TIMEOUT_MS;
|
|
22
|
-
}
|
|
23
|
-
return parsed;
|
|
24
|
-
}
|
|
25
|
-
function ensureCheckoutRootColumn(db) {
|
|
26
|
-
const cols = db.prepare(`PRAGMA table_info(runs)`).all();
|
|
27
|
-
if (!cols.some((c) => c.name === "checkout_root")) {
|
|
28
|
-
db.exec(`ALTER TABLE runs ADD COLUMN checkout_root TEXT`);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
function ensureCiIdentityColumns(db) {
|
|
32
|
-
const cols = db.prepare(`PRAGMA table_info(runs)`).all();
|
|
33
|
-
const names = new Set(cols.map((c) => c.name));
|
|
34
|
-
for (const name of ["git_sha", "ci_pr_url", "ci_job_url"]) {
|
|
35
|
-
if (!names.has(name)) {
|
|
36
|
-
db.exec(`ALTER TABLE runs ADD COLUMN ${name} TEXT`);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
function ensurePipelineDagColumn(db) {
|
|
41
|
-
const cols = db.prepare(`PRAGMA table_info(runs)`).all();
|
|
42
|
-
if (!cols.some((c) => c.name === "pipeline_dag_json")) {
|
|
43
|
-
db.exec(`ALTER TABLE runs ADD COLUMN pipeline_dag_json TEXT`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
function ensureRunLocatorColumns(db) {
|
|
47
|
-
const cols = db.prepare(`PRAGMA table_info(runs)`).all();
|
|
48
|
-
const names = new Set(cols.map((c) => c.name));
|
|
49
|
-
for (const name of ["pipeline_path", "task_path", "project_root"]) {
|
|
50
|
-
if (!names.has(name)) {
|
|
51
|
-
db.exec(`ALTER TABLE runs ADD COLUMN ${name} TEXT`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
function ensureStageExecutionsTable(db) {
|
|
56
|
-
db.exec(`
|
|
57
|
-
CREATE TABLE IF NOT EXISTS stage_executions (
|
|
58
|
-
run_id TEXT NOT NULL,
|
|
59
|
-
stage_id TEXT NOT NULL,
|
|
60
|
-
attempt INTEGER NOT NULL,
|
|
61
|
-
status TEXT NOT NULL,
|
|
62
|
-
verification_outcome TEXT NOT NULL DEFAULT 'not_run',
|
|
63
|
-
started_at TEXT,
|
|
64
|
-
finished_at TEXT,
|
|
65
|
-
envelope_json TEXT,
|
|
66
|
-
PRIMARY KEY (run_id, stage_id, attempt),
|
|
67
|
-
FOREIGN KEY (run_id) REFERENCES runs(run_id)
|
|
68
|
-
);
|
|
69
|
-
CREATE INDEX IF NOT EXISTS idx_stage_executions_run_stage
|
|
70
|
-
ON stage_executions (run_id, stage_id, attempt);
|
|
71
|
-
`);
|
|
72
|
-
}
|
|
73
|
-
function ensureStageExecutionVerificationOutcomeColumn(db) {
|
|
74
|
-
const cols = db
|
|
75
|
-
.prepare(`PRAGMA table_info(stage_executions)`)
|
|
76
|
-
.all();
|
|
77
|
-
if (!cols.some((c) => c.name === "verification_outcome")) {
|
|
78
|
-
db.exec(`ALTER TABLE stage_executions ADD COLUMN verification_outcome TEXT NOT NULL DEFAULT 'not_run'`);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
function ensureStageExecutionCostColumns(db) {
|
|
82
|
-
const cols = db
|
|
83
|
-
.prepare(`PRAGMA table_info(stage_executions)`)
|
|
84
|
-
.all();
|
|
85
|
-
const names = new Set(cols.map((c) => c.name));
|
|
86
|
-
if (!names.has("cost_usd")) {
|
|
87
|
-
db.exec(`ALTER TABLE stage_executions ADD COLUMN cost_usd REAL`);
|
|
88
|
-
}
|
|
89
|
-
if (!names.has("usage_json")) {
|
|
90
|
-
db.exec(`ALTER TABLE stage_executions ADD COLUMN usage_json TEXT`);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
function backfillVerificationOutcomes(db) {
|
|
94
|
-
db.exec(`
|
|
95
|
-
UPDATE stage_executions
|
|
96
|
-
SET verification_outcome = CASE
|
|
97
|
-
WHEN status = 'succeeded'
|
|
98
|
-
AND EXISTS (
|
|
99
|
-
SELECT 1 FROM verification_check_results AS check_result
|
|
100
|
-
WHERE check_result.run_id = stage_executions.run_id
|
|
101
|
-
AND check_result.stage_id = stage_executions.stage_id
|
|
102
|
-
AND check_result.attempt = stage_executions.attempt
|
|
103
|
-
)
|
|
104
|
-
AND NOT EXISTS (
|
|
105
|
-
SELECT 1 FROM verification_check_results AS check_result
|
|
106
|
-
WHERE check_result.run_id = stage_executions.run_id
|
|
107
|
-
AND check_result.stage_id = stage_executions.stage_id
|
|
108
|
-
AND check_result.attempt = stage_executions.attempt
|
|
109
|
-
AND check_result.status != 'passed'
|
|
110
|
-
)
|
|
111
|
-
THEN 'passed'
|
|
112
|
-
WHEN status = 'failed'
|
|
113
|
-
AND EXISTS (
|
|
114
|
-
SELECT 1 FROM verification_check_results AS check_result
|
|
115
|
-
WHERE check_result.run_id = stage_executions.run_id
|
|
116
|
-
AND check_result.stage_id = stage_executions.stage_id
|
|
117
|
-
AND check_result.attempt = stage_executions.attempt
|
|
118
|
-
)
|
|
119
|
-
THEN 'failed'
|
|
120
|
-
ELSE verification_outcome
|
|
121
|
-
END
|
|
122
|
-
WHERE verification_outcome = 'not_run';
|
|
123
|
-
`);
|
|
124
|
-
}
|
|
125
|
-
function ensureStageEventsAttemptColumn(db) {
|
|
126
|
-
const cols = db
|
|
127
|
-
.prepare(`PRAGMA table_info(stage_events)`)
|
|
128
|
-
.all();
|
|
129
|
-
if (!cols.some((c) => c.name === "attempt")) {
|
|
130
|
-
db.exec(`ALTER TABLE stage_events ADD COLUMN attempt INTEGER NOT NULL DEFAULT 1`);
|
|
131
|
-
db.exec(`
|
|
132
|
-
CREATE INDEX IF NOT EXISTS idx_stage_events_run_stage_attempt_at
|
|
133
|
-
ON stage_events (run_id, stage_id, attempt, at);
|
|
134
|
-
`);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
function ensureVerificationCheckResultsTable(db) {
|
|
138
|
-
db.exec(`
|
|
139
|
-
CREATE TABLE IF NOT EXISTS verification_check_results (
|
|
140
|
-
run_id TEXT NOT NULL,
|
|
141
|
-
stage_id TEXT NOT NULL,
|
|
142
|
-
attempt INTEGER NOT NULL,
|
|
143
|
-
check_id TEXT NOT NULL,
|
|
144
|
-
check_type TEXT NOT NULL,
|
|
145
|
-
status TEXT NOT NULL,
|
|
146
|
-
started_at TEXT,
|
|
147
|
-
finished_at TEXT,
|
|
148
|
-
evidence_json TEXT,
|
|
149
|
-
PRIMARY KEY (run_id, stage_id, attempt, check_id),
|
|
150
|
-
FOREIGN KEY (run_id, stage_id, attempt)
|
|
151
|
-
REFERENCES stage_executions(run_id, stage_id, attempt)
|
|
152
|
-
);
|
|
153
|
-
CREATE INDEX IF NOT EXISTS idx_verification_check_results_execution
|
|
154
|
-
ON verification_check_results (run_id, stage_id, attempt, check_id);
|
|
155
|
-
`);
|
|
156
|
-
}
|
|
157
|
-
function ensureFeedbackReplayStagePassEnvelopeColumn(db) {
|
|
158
|
-
const cols = db
|
|
159
|
-
.prepare(`PRAGMA table_info(feedback_replay_stage_passes)`)
|
|
160
|
-
.all();
|
|
161
|
-
if (cols.length === 0)
|
|
162
|
-
return;
|
|
163
|
-
if (!cols.some((c) => c.name === "emitted_envelope_json")) {
|
|
164
|
-
db.exec(`ALTER TABLE feedback_replay_stage_passes ADD COLUMN emitted_envelope_json TEXT`);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
function ensureFeedbackReplayStagePassSessionOriginColumn(db) {
|
|
168
|
-
const cols = db
|
|
169
|
-
.prepare(`PRAGMA table_info(feedback_replay_stage_passes)`)
|
|
170
|
-
.all();
|
|
171
|
-
if (cols.length === 0)
|
|
172
|
-
return;
|
|
173
|
-
if (!cols.some((c) => c.name === "session_origin_attempt")) {
|
|
174
|
-
db.exec(`ALTER TABLE feedback_replay_stage_passes ADD COLUMN session_origin_attempt INTEGER`);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
function ensureFeedbackLoopDeferredSendBackColumn(db) {
|
|
178
|
-
const cols = db
|
|
179
|
-
.prepare(`PRAGMA table_info(feedback_loops)`)
|
|
180
|
-
.all();
|
|
181
|
-
if (cols.length === 0)
|
|
182
|
-
return;
|
|
183
|
-
if (!cols.some((c) => c.name === "deferred_send_back_json")) {
|
|
184
|
-
db.exec(`ALTER TABLE feedback_loops ADD COLUMN deferred_send_back_json TEXT`);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
18
|
function executionFromRow(row) {
|
|
188
19
|
return {
|
|
189
20
|
run_id: row.run_id,
|
|
@@ -197,7 +28,10 @@ function executionFromRow(row) {
|
|
|
197
28
|
? JSON.parse(row.envelope_json)
|
|
198
29
|
: null,
|
|
199
30
|
...(row.cost_usd != null ? { cost_usd: row.cost_usd } : {}),
|
|
200
|
-
...(row.usage_json != null
|
|
31
|
+
...(row.usage_json != null
|
|
32
|
+
? { usage: JSON.parse(row.usage_json) }
|
|
33
|
+
: {}),
|
|
34
|
+
auto_resume_count: row.auto_resume_count ?? 0,
|
|
201
35
|
};
|
|
202
36
|
}
|
|
203
37
|
function verificationCheckResultFromRow(row) {
|
|
@@ -293,38 +127,57 @@ export class SqliteRunStore {
|
|
|
293
127
|
storeRoot;
|
|
294
128
|
db;
|
|
295
129
|
migratePromise;
|
|
296
|
-
constructor(storeRoot) {
|
|
130
|
+
constructor(storeRoot, options) {
|
|
297
131
|
this.storeRoot = storeRoot;
|
|
132
|
+
const openerMode = options?.openerMode ??
|
|
133
|
+
(process.env.VITEST === "true" ? "migrate" : "assert");
|
|
298
134
|
const dbPath = path.join(storeRoot, "state.db");
|
|
135
|
+
if (openerMode === "assert") {
|
|
136
|
+
if (!existsSync(dbPath)) {
|
|
137
|
+
throw new StoreSchemaError("store_schema_migration_required: database file is missing", "store_schema_migration_required");
|
|
138
|
+
}
|
|
139
|
+
this.db = new Database(dbPath);
|
|
140
|
+
applyStorePragmas(this.db);
|
|
141
|
+
assertSchemaVersion(this.db);
|
|
142
|
+
this.migratePromise = Promise.resolve();
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
299
145
|
this.db = new Database(dbPath);
|
|
300
|
-
this.db
|
|
301
|
-
this.db
|
|
302
|
-
this.db.exec(SCHEMA_SQL);
|
|
303
|
-
ensureCheckoutRootColumn(this.db);
|
|
304
|
-
ensureCiIdentityColumns(this.db);
|
|
305
|
-
ensurePipelineDagColumn(this.db);
|
|
306
|
-
ensureRunLocatorColumns(this.db);
|
|
307
|
-
ensureStageExecutionsTable(this.db);
|
|
308
|
-
ensureStageExecutionVerificationOutcomeColumn(this.db);
|
|
309
|
-
ensureStageExecutionCostColumns(this.db);
|
|
310
|
-
ensureStageEventsAttemptColumn(this.db);
|
|
311
|
-
ensureVerificationCheckResultsTable(this.db);
|
|
312
|
-
ensureFeedbackReplayStagePassEnvelopeColumn(this.db);
|
|
313
|
-
ensureFeedbackReplayStagePassSessionOriginColumn(this.db);
|
|
314
|
-
ensureFeedbackLoopDeferredSendBackColumn(this.db);
|
|
315
|
-
backfillVerificationOutcomes(this.db);
|
|
146
|
+
applyStorePragmas(this.db);
|
|
147
|
+
applyPendingMigrations(this.db);
|
|
316
148
|
this.migratePromise = importDiskRunsIfEmpty(this.db, storeRoot).then(() => undefined);
|
|
317
149
|
}
|
|
318
150
|
/** Await one-shot disk import before catalog reads (create paths also wait). */
|
|
319
151
|
async ready() {
|
|
320
152
|
await this.migratePromise;
|
|
321
153
|
}
|
|
154
|
+
async close() {
|
|
155
|
+
await this.ready();
|
|
156
|
+
this.db.pragma("wal_checkpoint(TRUNCATE)");
|
|
157
|
+
this.db.close();
|
|
158
|
+
}
|
|
159
|
+
async snapshotInto(destPath) {
|
|
160
|
+
await this.ready();
|
|
161
|
+
const userVersion = this.db.pragma("user_version", {
|
|
162
|
+
simple: true,
|
|
163
|
+
});
|
|
164
|
+
const escaped = destPath.replace(/'/g, "''");
|
|
165
|
+
this.db.exec(`VACUUM INTO '${escaped}'`);
|
|
166
|
+
return { userVersion };
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* The connection this store owns, for the one caller allowed to share it: the composition root
|
|
170
|
+
* wiring the A2A tables into the same `state.db` file. Not part of the `RunStore` interface.
|
|
171
|
+
*/
|
|
172
|
+
get connection() {
|
|
173
|
+
return this.db;
|
|
174
|
+
}
|
|
322
175
|
getWorkspaceDir(runId) {
|
|
323
176
|
return runWorkspaceDir(this.storeRoot, runId);
|
|
324
177
|
}
|
|
325
178
|
async createRun(input) {
|
|
326
179
|
await this.ready();
|
|
327
|
-
const runId = newRunId();
|
|
180
|
+
const runId = input.runId ?? newRunId();
|
|
328
181
|
const workspaceDir = this.getWorkspaceDir(runId);
|
|
329
182
|
await mkdir(path.join(workspaceDir, "stages"), { recursive: true });
|
|
330
183
|
const now = new Date().toISOString();
|
|
@@ -337,45 +190,265 @@ export class SqliteRunStore {
|
|
|
337
190
|
const projectRoot = input.projectRoot
|
|
338
191
|
? normalizeCatalogPath(input.projectRoot)
|
|
339
192
|
: null;
|
|
340
|
-
|
|
341
|
-
.
|
|
342
|
-
|
|
193
|
+
const pipelineBody = input.pipelineBody ??
|
|
194
|
+
(input.inlinePipeline !== undefined
|
|
195
|
+
? JSON.stringify(input.inlinePipeline)
|
|
196
|
+
: null);
|
|
197
|
+
const pipelineSource = input.pipelineSource ??
|
|
198
|
+
(pipelineBody != null && pipelinePath == null ? "inline" : null);
|
|
199
|
+
this.db.transaction(() => {
|
|
200
|
+
if (input.submission) {
|
|
201
|
+
const existing = this.readSubmission(input.submission.key);
|
|
202
|
+
if (existing)
|
|
203
|
+
throw new RunSubmissionExistsError(existing);
|
|
204
|
+
}
|
|
205
|
+
this.db
|
|
206
|
+
.prepare(`INSERT INTO runs
|
|
207
|
+
(run_id, pipeline_id, task_id, task_yaml, status, created_at, updated_at, checkout_root, pipeline_dag_json, git_sha, ci_pr_url, ci_job_url, pipeline_path, task_path, project_root, repository, ref, resolved_sha, run_branch, git_author_name, git_author_email, pipeline_source, pipeline_body, caller_id, run_manifest, skip_gates)
|
|
343
208
|
VALUES
|
|
344
|
-
(@run_id, @pipeline_id, @task_id, @task_yaml, @status, @created_at, @updated_at, @checkout_root, @pipeline_dag_json, @git_sha, @ci_pr_url, @ci_job_url, @pipeline_path, @task_path, @project_root)`)
|
|
209
|
+
(@run_id, @pipeline_id, @task_id, @task_yaml, @status, @created_at, @updated_at, @checkout_root, @pipeline_dag_json, @git_sha, @ci_pr_url, @ci_job_url, @pipeline_path, @task_path, @project_root, @repository, @ref, @resolved_sha, @run_branch, @git_author_name, @git_author_email, @pipeline_source, @pipeline_body, @caller_id, @run_manifest, @skip_gates)`)
|
|
210
|
+
.run({
|
|
211
|
+
run_id: runId,
|
|
212
|
+
pipeline_id: input.pipelineId,
|
|
213
|
+
task_id: input.taskId ?? null,
|
|
214
|
+
task_yaml: input.taskYaml,
|
|
215
|
+
status: input.status ?? "running",
|
|
216
|
+
created_at: now,
|
|
217
|
+
updated_at: now,
|
|
218
|
+
checkout_root: input.checkoutRoot ?? null,
|
|
219
|
+
pipeline_dag_json: input.pipelineDag
|
|
220
|
+
? JSON.stringify(input.pipelineDag)
|
|
221
|
+
: null,
|
|
222
|
+
git_sha: input.gitSha ?? null,
|
|
223
|
+
ci_pr_url: input.ciPrUrl ?? null,
|
|
224
|
+
ci_job_url: input.ciJobUrl ?? null,
|
|
225
|
+
pipeline_path: pipelinePath,
|
|
226
|
+
task_path: taskPath,
|
|
227
|
+
project_root: projectRoot,
|
|
228
|
+
repository: input.repository ?? null,
|
|
229
|
+
ref: input.ref ?? null,
|
|
230
|
+
resolved_sha: input.resolvedSha ?? null,
|
|
231
|
+
run_branch: input.runBranch ?? null,
|
|
232
|
+
git_author_name: input.gitAuthorName ?? null,
|
|
233
|
+
git_author_email: input.gitAuthorEmail ?? null,
|
|
234
|
+
pipeline_source: pipelineSource,
|
|
235
|
+
pipeline_body: pipelineBody,
|
|
236
|
+
caller_id: input.callerId ?? null,
|
|
237
|
+
run_manifest: input.runManifest !== undefined
|
|
238
|
+
? JSON.stringify(input.runManifest)
|
|
239
|
+
: null,
|
|
240
|
+
skip_gates: input.skipGates === undefined ? null : input.skipGates ? 1 : 0,
|
|
241
|
+
});
|
|
242
|
+
if (input.submission) {
|
|
243
|
+
this.db.prepare("INSERT INTO run_submissions (submission_key, request_hash, run_id) VALUES (?, ?, ?)")
|
|
244
|
+
.run(input.submission.key, input.submission.requestHash, runId);
|
|
245
|
+
}
|
|
246
|
+
})();
|
|
247
|
+
return { runId, workspaceDir };
|
|
248
|
+
}
|
|
249
|
+
readSubmission(key) {
|
|
250
|
+
const row = this.db.prepare("SELECT submission_key AS key, request_hash AS requestHash, run_id AS runId FROM run_submissions WHERE submission_key = ?")
|
|
251
|
+
.get(key);
|
|
252
|
+
return row ?? null;
|
|
253
|
+
}
|
|
254
|
+
async getRunBySubmission(key) {
|
|
255
|
+
await this.ready();
|
|
256
|
+
return this.readSubmission(key);
|
|
257
|
+
}
|
|
258
|
+
async updateRunStatus(runId, status) {
|
|
259
|
+
await this.ready();
|
|
260
|
+
const now = new Date().toISOString();
|
|
261
|
+
const isTerminal = status === "succeeded" || status === "failed" || status === "cancelled";
|
|
262
|
+
const result = isTerminal
|
|
263
|
+
? this.db
|
|
264
|
+
.prepare(`UPDATE runs SET status = @status, updated_at = @updated_at,
|
|
265
|
+
finished_at = COALESCE(finished_at, @finished_at)
|
|
266
|
+
WHERE run_id = @run_id`)
|
|
267
|
+
.run({
|
|
268
|
+
run_id: runId,
|
|
269
|
+
status,
|
|
270
|
+
updated_at: now,
|
|
271
|
+
finished_at: now,
|
|
272
|
+
})
|
|
273
|
+
: this.db
|
|
274
|
+
.prepare(`UPDATE runs SET status = @status, updated_at = @updated_at WHERE run_id = @run_id`)
|
|
275
|
+
.run({
|
|
276
|
+
run_id: runId,
|
|
277
|
+
status,
|
|
278
|
+
updated_at: now,
|
|
279
|
+
});
|
|
280
|
+
if (result.changes === 0) {
|
|
281
|
+
throw new Error(`Run not found: ${runId}`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
async tryUpdateRunStatus(runId, status, expectedStatus) {
|
|
285
|
+
await this.ready();
|
|
286
|
+
const now = new Date().toISOString();
|
|
287
|
+
const isTerminal = status === "succeeded" || status === "failed" || status === "cancelled";
|
|
288
|
+
const result = isTerminal
|
|
289
|
+
? this.db
|
|
290
|
+
.prepare(`UPDATE runs SET status = @status, updated_at = @updated_at,
|
|
291
|
+
finished_at = COALESCE(finished_at, @finished_at)
|
|
292
|
+
WHERE run_id = @run_id AND status = @expected_status`)
|
|
293
|
+
.run({
|
|
294
|
+
run_id: runId,
|
|
295
|
+
status,
|
|
296
|
+
expected_status: expectedStatus,
|
|
297
|
+
updated_at: now,
|
|
298
|
+
finished_at: now,
|
|
299
|
+
})
|
|
300
|
+
: this.db
|
|
301
|
+
.prepare(`UPDATE runs SET status = @status, updated_at = @updated_at
|
|
302
|
+
WHERE run_id = @run_id AND status = @expected_status`)
|
|
303
|
+
.run({
|
|
304
|
+
run_id: runId,
|
|
305
|
+
status,
|
|
306
|
+
expected_status: expectedStatus,
|
|
307
|
+
updated_at: now,
|
|
308
|
+
});
|
|
309
|
+
if (result.changes > 0)
|
|
310
|
+
return true;
|
|
311
|
+
const exists = this.db
|
|
312
|
+
.prepare(`SELECT 1 AS ok FROM runs WHERE run_id = ?`)
|
|
313
|
+
.get(runId);
|
|
314
|
+
if (exists === undefined) {
|
|
315
|
+
throw new Error(`Run not found: ${runId}`);
|
|
316
|
+
}
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
async patchRunWorkspaceBinding(runId, patch) {
|
|
320
|
+
await this.ready();
|
|
321
|
+
const sets = ["updated_at = @updated_at"];
|
|
322
|
+
const params = {
|
|
323
|
+
run_id: runId,
|
|
324
|
+
updated_at: new Date().toISOString(),
|
|
325
|
+
};
|
|
326
|
+
if (patch.checkoutRoot !== undefined) {
|
|
327
|
+
sets.push("checkout_root = @checkout_root");
|
|
328
|
+
params.checkout_root = patch.checkoutRoot;
|
|
329
|
+
}
|
|
330
|
+
if (patch.repository !== undefined) {
|
|
331
|
+
sets.push("repository = @repository");
|
|
332
|
+
params.repository = patch.repository;
|
|
333
|
+
}
|
|
334
|
+
if (patch.ref !== undefined) {
|
|
335
|
+
sets.push("ref = @ref");
|
|
336
|
+
params.ref = patch.ref;
|
|
337
|
+
}
|
|
338
|
+
if (patch.resolvedSha !== undefined) {
|
|
339
|
+
sets.push("resolved_sha = @resolved_sha");
|
|
340
|
+
params.resolved_sha = patch.resolvedSha;
|
|
341
|
+
}
|
|
342
|
+
if (patch.runBranch !== undefined) {
|
|
343
|
+
sets.push("run_branch = @run_branch");
|
|
344
|
+
params.run_branch = patch.runBranch;
|
|
345
|
+
}
|
|
346
|
+
if (sets.length === 1) {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const result = this.db
|
|
350
|
+
.prepare(`UPDATE runs SET ${sets.join(", ")} WHERE run_id = @run_id`)
|
|
351
|
+
.run(params);
|
|
352
|
+
if (result.changes === 0) {
|
|
353
|
+
throw new Error(`Run not found: ${runId}`);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
async appendConfigOrigins(runId, origins) {
|
|
357
|
+
await this.ready();
|
|
358
|
+
if (origins.length === 0)
|
|
359
|
+
return;
|
|
360
|
+
const row = this.getRunRow(runId);
|
|
361
|
+
const existing = row.config_origins_json
|
|
362
|
+
? JSON.parse(row.config_origins_json)
|
|
363
|
+
: [];
|
|
364
|
+
const keyOf = (o) => `${o.name}\0${o.origin}\0${o.path ?? ""}`;
|
|
365
|
+
const seen = new Set(existing.map(keyOf));
|
|
366
|
+
const merged = [...existing];
|
|
367
|
+
for (const origin of origins) {
|
|
368
|
+
const key = keyOf(origin);
|
|
369
|
+
if (seen.has(key))
|
|
370
|
+
continue;
|
|
371
|
+
seen.add(key);
|
|
372
|
+
merged.push(origin);
|
|
373
|
+
}
|
|
374
|
+
if (merged.length === existing.length)
|
|
375
|
+
return;
|
|
376
|
+
const result = this.db
|
|
377
|
+
.prepare(`UPDATE runs SET config_origins_json = @config_origins_json, updated_at = @updated_at WHERE run_id = @run_id`)
|
|
345
378
|
.run({
|
|
346
379
|
run_id: runId,
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
task_yaml: input.taskYaml,
|
|
350
|
-
status: "running",
|
|
351
|
-
created_at: now,
|
|
352
|
-
updated_at: now,
|
|
353
|
-
checkout_root: input.checkoutRoot ?? null,
|
|
354
|
-
pipeline_dag_json: input.pipelineDag
|
|
355
|
-
? JSON.stringify(input.pipelineDag)
|
|
356
|
-
: null,
|
|
357
|
-
git_sha: input.gitSha ?? null,
|
|
358
|
-
ci_pr_url: input.ciPrUrl ?? null,
|
|
359
|
-
ci_job_url: input.ciJobUrl ?? null,
|
|
360
|
-
pipeline_path: pipelinePath,
|
|
361
|
-
task_path: taskPath,
|
|
362
|
-
project_root: projectRoot,
|
|
380
|
+
config_origins_json: JSON.stringify(merged),
|
|
381
|
+
updated_at: new Date().toISOString(),
|
|
363
382
|
});
|
|
364
|
-
|
|
383
|
+
if (result.changes === 0) {
|
|
384
|
+
throw new Error(`Run not found: ${runId}`);
|
|
385
|
+
}
|
|
365
386
|
}
|
|
366
|
-
async
|
|
387
|
+
async setCancelReason(runId, reason) {
|
|
367
388
|
await this.ready();
|
|
368
389
|
const result = this.db
|
|
369
|
-
.prepare(`UPDATE runs SET
|
|
390
|
+
.prepare(`UPDATE runs SET cancel_reason = @cancel_reason, updated_at = @updated_at WHERE run_id = @run_id`)
|
|
370
391
|
.run({
|
|
371
392
|
run_id: runId,
|
|
372
|
-
|
|
393
|
+
cancel_reason: reason,
|
|
373
394
|
updated_at: new Date().toISOString(),
|
|
374
395
|
});
|
|
375
396
|
if (result.changes === 0) {
|
|
376
397
|
throw new Error(`Run not found: ${runId}`);
|
|
377
398
|
}
|
|
378
399
|
}
|
|
400
|
+
async setRunDiskUsage(runId, diskBytes, measuredAt) {
|
|
401
|
+
await this.ready();
|
|
402
|
+
const result = this.db
|
|
403
|
+
.prepare(`UPDATE runs SET disk_bytes = @disk_bytes, disk_measured_at = @disk_measured_at
|
|
404
|
+
WHERE run_id = @run_id`)
|
|
405
|
+
.run({
|
|
406
|
+
run_id: runId,
|
|
407
|
+
disk_bytes: diskBytes,
|
|
408
|
+
disk_measured_at: measuredAt,
|
|
409
|
+
});
|
|
410
|
+
if (result.changes === 0) {
|
|
411
|
+
throw new Error(`Run not found: ${runId}`);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
async setSlimmedAt(runId, slimmedAt) {
|
|
415
|
+
await this.ready();
|
|
416
|
+
const result = this.db
|
|
417
|
+
.prepare(`UPDATE runs SET slimmed_at = @slimmed_at WHERE run_id = @run_id`)
|
|
418
|
+
.run({
|
|
419
|
+
run_id: runId,
|
|
420
|
+
slimmed_at: slimmedAt,
|
|
421
|
+
});
|
|
422
|
+
if (result.changes === 0) {
|
|
423
|
+
throw new Error(`Run not found: ${runId}`);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
async deleteRun(runId) {
|
|
427
|
+
await this.ready();
|
|
428
|
+
const deleteAll = this.db.transaction(() => {
|
|
429
|
+
const exists = this.db
|
|
430
|
+
.prepare(`SELECT 1 AS ok FROM runs WHERE run_id = ?`)
|
|
431
|
+
.get(runId);
|
|
432
|
+
if (exists === undefined) {
|
|
433
|
+
throw new Error(`Run not found: ${runId}`);
|
|
434
|
+
}
|
|
435
|
+
this.db.prepare(`DELETE FROM stage_events WHERE run_id = ?`).run(runId);
|
|
436
|
+
this.db
|
|
437
|
+
.prepare(`DELETE FROM verification_check_results WHERE run_id = ?`)
|
|
438
|
+
.run(runId);
|
|
439
|
+
this.db.prepare(`DELETE FROM stage_executions WHERE run_id = ?`).run(runId);
|
|
440
|
+
this.db
|
|
441
|
+
.prepare(`DELETE FROM feedback_replay_stage_passes WHERE run_id = ?`)
|
|
442
|
+
.run(runId);
|
|
443
|
+
this.db.prepare(`DELETE FROM fork_generations WHERE run_id = ?`).run(runId);
|
|
444
|
+
this.db.prepare(`DELETE FROM feedback_replays WHERE run_id = ?`).run(runId);
|
|
445
|
+
this.db.prepare(`DELETE FROM feedback_loops WHERE run_id = ?`).run(runId);
|
|
446
|
+
this.db.prepare(`DELETE FROM stages WHERE run_id = ?`).run(runId);
|
|
447
|
+
this.db.prepare(`DELETE FROM run_submissions WHERE run_id = ?`).run(runId);
|
|
448
|
+
this.db.prepare(`DELETE FROM runs WHERE run_id = ?`).run(runId);
|
|
449
|
+
});
|
|
450
|
+
deleteAll();
|
|
451
|
+
}
|
|
379
452
|
async updatePipelineDag(runId, dag) {
|
|
380
453
|
await this.ready();
|
|
381
454
|
const result = this.db
|
|
@@ -397,6 +470,25 @@ export class SqliteRunStore {
|
|
|
397
470
|
await this.ready();
|
|
398
471
|
return this.getRunRow(runId).task_yaml;
|
|
399
472
|
}
|
|
473
|
+
async readPipelineBody(runId) {
|
|
474
|
+
await this.ready();
|
|
475
|
+
return this.getRunRow(runId).pipeline_body;
|
|
476
|
+
}
|
|
477
|
+
async updateRunManifest(runId, manifest) {
|
|
478
|
+
await this.ready();
|
|
479
|
+
const result = this.db
|
|
480
|
+
.prepare(`UPDATE runs SET run_manifest = @run_manifest, updated_at = @updated_at WHERE run_id = @run_id`)
|
|
481
|
+
.run({
|
|
482
|
+
run_id: runId,
|
|
483
|
+
run_manifest: manifest === null || manifest === undefined
|
|
484
|
+
? null
|
|
485
|
+
: JSON.stringify(manifest),
|
|
486
|
+
updated_at: new Date().toISOString(),
|
|
487
|
+
});
|
|
488
|
+
if (result.changes === 0) {
|
|
489
|
+
throw new Error(`Run not found: ${runId}`);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
400
492
|
async ensureStageWorkspace(runId, stageId) {
|
|
401
493
|
await this.ready();
|
|
402
494
|
this.getRunRow(runId);
|
|
@@ -447,7 +539,7 @@ export class SqliteRunStore {
|
|
|
447
539
|
verification_outcome: "not_run",
|
|
448
540
|
});
|
|
449
541
|
const row = this.db
|
|
450
|
-
.prepare(`SELECT
|
|
542
|
+
.prepare(`SELECT ${EXECUTION_SELECT_COLS}
|
|
451
543
|
FROM stage_executions
|
|
452
544
|
WHERE run_id = ? AND stage_id = ? AND attempt = ?`)
|
|
453
545
|
.get(runId, stageId, attempt);
|
|
@@ -457,7 +549,7 @@ export class SqliteRunStore {
|
|
|
457
549
|
async listStageExecutions(runId, stageId) {
|
|
458
550
|
await this.ready();
|
|
459
551
|
const rows = this.db
|
|
460
|
-
.prepare(`SELECT
|
|
552
|
+
.prepare(`SELECT ${EXECUTION_SELECT_COLS}
|
|
461
553
|
FROM stage_executions
|
|
462
554
|
WHERE run_id = ? AND stage_id = ?
|
|
463
555
|
ORDER BY attempt ASC`)
|
|
@@ -467,7 +559,7 @@ export class SqliteRunStore {
|
|
|
467
559
|
async getLatestStageExecution(runId, stageId) {
|
|
468
560
|
await this.ready();
|
|
469
561
|
const row = this.db
|
|
470
|
-
.prepare(`SELECT
|
|
562
|
+
.prepare(`SELECT ${EXECUTION_SELECT_COLS}
|
|
471
563
|
FROM stage_executions
|
|
472
564
|
WHERE run_id = ? AND stage_id = ?
|
|
473
565
|
ORDER BY attempt DESC
|
|
@@ -486,7 +578,7 @@ export class SqliteRunStore {
|
|
|
486
578
|
async getStageExecution(runId, stageId, attempt) {
|
|
487
579
|
await this.ready();
|
|
488
580
|
const row = this.db
|
|
489
|
-
.prepare(`SELECT
|
|
581
|
+
.prepare(`SELECT ${EXECUTION_SELECT_COLS}
|
|
490
582
|
FROM stage_executions
|
|
491
583
|
WHERE run_id = ? AND stage_id = ? AND attempt = ?`)
|
|
492
584
|
.get(runId, stageId, attempt);
|
|
@@ -495,6 +587,21 @@ export class SqliteRunStore {
|
|
|
495
587
|
}
|
|
496
588
|
return executionFromRow(row);
|
|
497
589
|
}
|
|
590
|
+
async listInterruptedStageExecutions() {
|
|
591
|
+
await this.ready();
|
|
592
|
+
const rows = this.db
|
|
593
|
+
.prepare(`SELECT ${EXECUTION_SELECT_COLS}
|
|
594
|
+
FROM stage_executions e
|
|
595
|
+
WHERE e.status = 'interrupted'
|
|
596
|
+
AND e.attempt = (
|
|
597
|
+
SELECT MAX(e2.attempt)
|
|
598
|
+
FROM stage_executions e2
|
|
599
|
+
WHERE e2.run_id = e.run_id AND e2.stage_id = e.stage_id
|
|
600
|
+
)
|
|
601
|
+
ORDER BY e.run_id ASC, e.stage_id ASC, e.attempt ASC`)
|
|
602
|
+
.all();
|
|
603
|
+
return rows.map(executionFromRow);
|
|
604
|
+
}
|
|
498
605
|
async updateStageExecution(runId, stageId, attempt, patch) {
|
|
499
606
|
await this.ready();
|
|
500
607
|
const sets = [];
|
|
@@ -532,6 +639,10 @@ export class SqliteRunStore {
|
|
|
532
639
|
sets.push("usage_json = @usage_json");
|
|
533
640
|
params.usage_json = JSON.stringify(patch.usage);
|
|
534
641
|
}
|
|
642
|
+
if (patch.auto_resume_count !== undefined) {
|
|
643
|
+
sets.push("auto_resume_count = @auto_resume_count");
|
|
644
|
+
params.auto_resume_count = patch.auto_resume_count;
|
|
645
|
+
}
|
|
535
646
|
if (sets.length === 0)
|
|
536
647
|
return;
|
|
537
648
|
const result = this.db
|
|
@@ -708,9 +819,13 @@ export class SqliteRunStore {
|
|
|
708
819
|
clauses.push("(pipeline_id = ? OR pipeline_path = ? OR pipeline_path = ?)");
|
|
709
820
|
params.push(pipeline, pipeline, normalized);
|
|
710
821
|
}
|
|
822
|
+
if (filter?.caller_id !== undefined) {
|
|
823
|
+
clauses.push("caller_id = ?");
|
|
824
|
+
params.push(filter.caller_id);
|
|
825
|
+
}
|
|
711
826
|
const where = clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "";
|
|
712
827
|
const rows = this.db
|
|
713
|
-
.prepare(`SELECT run_id, pipeline_id, task_id, task_yaml, status, created_at, updated_at, checkout_root, pipeline_dag_json, git_sha, ci_pr_url, ci_job_url, pipeline_path, task_path, project_root
|
|
828
|
+
.prepare(`SELECT run_id, pipeline_id, task_id, task_yaml, status, created_at, updated_at, checkout_root, pipeline_dag_json, git_sha, ci_pr_url, ci_job_url, pipeline_path, task_path, project_root, repository, ref, resolved_sha, run_branch, git_author_name, git_author_email, cancel_reason, finished_at, slimmed_at, disk_bytes, disk_measured_at, config_origins_json, pipeline_source, pipeline_body, caller_id, run_manifest, skip_gates
|
|
714
829
|
FROM runs ${where} ORDER BY created_at DESC`)
|
|
715
830
|
.all(...params);
|
|
716
831
|
const summaries = [];
|
|
@@ -724,10 +839,34 @@ export class SqliteRunStore {
|
|
|
724
839
|
}
|
|
725
840
|
return summaries;
|
|
726
841
|
}
|
|
727
|
-
async
|
|
842
|
+
async ensureProject(absPath) {
|
|
843
|
+
await this.ready();
|
|
844
|
+
const resolved = path.resolve(absPath);
|
|
845
|
+
let st;
|
|
846
|
+
try {
|
|
847
|
+
st = statSync(resolved);
|
|
848
|
+
}
|
|
849
|
+
catch {
|
|
850
|
+
throw new Error(`project_root does not exist: ${resolved}`);
|
|
851
|
+
}
|
|
852
|
+
if (!st.isDirectory()) {
|
|
853
|
+
throw new Error(`project_root is not a directory: ${resolved}`);
|
|
854
|
+
}
|
|
855
|
+
const normalized = normalizeProjectRoot(absPath);
|
|
856
|
+
if (normalized === path.parse(normalized).root) {
|
|
857
|
+
throw new Error(`project_root must not be filesystem root: ${normalized}`);
|
|
858
|
+
}
|
|
859
|
+
const now = new Date().toISOString();
|
|
860
|
+
this.db
|
|
861
|
+
.prepare(`INSERT INTO projects (project_root, created_at) VALUES (?, ?)
|
|
862
|
+
ON CONFLICT(project_root) DO NOTHING`)
|
|
863
|
+
.run(normalized, now);
|
|
864
|
+
return normalized;
|
|
865
|
+
}
|
|
866
|
+
async listRegisteredProjects() {
|
|
728
867
|
await this.ready();
|
|
729
868
|
const rows = this.db
|
|
730
|
-
.prepare(`SELECT
|
|
869
|
+
.prepare(`SELECT project_root FROM projects ORDER BY project_root`)
|
|
731
870
|
.all();
|
|
732
871
|
return rows.map((row) => row.project_root);
|
|
733
872
|
}
|
|
@@ -1138,12 +1277,47 @@ export class SqliteRunStore {
|
|
|
1138
1277
|
...(row.pipeline_path != null ? { pipeline_path: row.pipeline_path } : {}),
|
|
1139
1278
|
...(row.task_path != null ? { task_path: row.task_path } : {}),
|
|
1140
1279
|
...(row.project_root != null ? { project_root: row.project_root } : {}),
|
|
1280
|
+
...(row.repository != null ? { repository: row.repository } : {}),
|
|
1281
|
+
...(row.ref != null ? { ref: row.ref } : {}),
|
|
1282
|
+
...(row.resolved_sha != null ? { resolved_sha: row.resolved_sha } : {}),
|
|
1283
|
+
...(row.run_branch != null ? { run_branch: row.run_branch } : {}),
|
|
1284
|
+
...(row.git_author_name != null
|
|
1285
|
+
? { git_author_name: row.git_author_name }
|
|
1286
|
+
: {}),
|
|
1287
|
+
...(row.git_author_email != null
|
|
1288
|
+
? { git_author_email: row.git_author_email }
|
|
1289
|
+
: {}),
|
|
1290
|
+
...(row.cancel_reason != null ? { cancel_reason: row.cancel_reason } : {}),
|
|
1291
|
+
...(row.finished_at != null ? { finished_at: row.finished_at } : {}),
|
|
1292
|
+
...(row.slimmed_at != null ? { slimmed_at: row.slimmed_at } : {}),
|
|
1293
|
+
...(row.disk_bytes != null ? { disk_bytes: row.disk_bytes } : {}),
|
|
1294
|
+
...(row.disk_measured_at != null
|
|
1295
|
+
? { disk_measured_at: row.disk_measured_at }
|
|
1296
|
+
: {}),
|
|
1297
|
+
...(row.config_origins_json
|
|
1298
|
+
? {
|
|
1299
|
+
config_origins: JSON.parse(row.config_origins_json),
|
|
1300
|
+
}
|
|
1301
|
+
: {}),
|
|
1302
|
+
...(row.pipeline_source === "inline" || row.pipeline_source === "path"
|
|
1303
|
+
? { pipeline_source: row.pipeline_source }
|
|
1304
|
+
: {}),
|
|
1305
|
+
...(row.caller_id != null ? { caller_id: row.caller_id } : {}),
|
|
1306
|
+
...(row.run_manifest
|
|
1307
|
+
? { run_manifest: JSON.parse(row.run_manifest) }
|
|
1308
|
+
: {}),
|
|
1309
|
+
...(row.skip_gates != null ? { skip_gates: row.skip_gates !== 0 } : {}),
|
|
1141
1310
|
...(pipeline_dag ? { pipeline_dag } : {}),
|
|
1311
|
+
...(row.pipeline_body
|
|
1312
|
+
? {
|
|
1313
|
+
inline_pipeline: JSON.parse(row.pipeline_body),
|
|
1314
|
+
}
|
|
1315
|
+
: {}),
|
|
1142
1316
|
};
|
|
1143
1317
|
}
|
|
1144
1318
|
getRunRow(runId) {
|
|
1145
1319
|
const row = this.db
|
|
1146
|
-
.prepare(`SELECT run_id, pipeline_id, task_id, task_yaml, status, created_at, updated_at, checkout_root, pipeline_dag_json, git_sha, ci_pr_url, ci_job_url, pipeline_path, task_path, project_root
|
|
1320
|
+
.prepare(`SELECT run_id, pipeline_id, task_id, task_yaml, status, created_at, updated_at, checkout_root, pipeline_dag_json, git_sha, ci_pr_url, ci_job_url, pipeline_path, task_path, project_root, repository, ref, resolved_sha, run_branch, git_author_name, git_author_email, cancel_reason, finished_at, slimmed_at, disk_bytes, disk_measured_at, config_origins_json, pipeline_source, pipeline_body, caller_id, run_manifest, skip_gates
|
|
1147
1321
|
FROM runs WHERE run_id = ?`)
|
|
1148
1322
|
.get(runId);
|
|
1149
1323
|
if (!row)
|