stageflow 0.25.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 +10 -3
- package/dist/a2a/contracts.d.ts +1 -0
- package/dist/a2a/contracts.js +1 -0
- package/dist/a2a/registry.d.ts +2 -0
- package/dist/a2a/registry.js +20 -1
- package/dist/a2a/server.d.ts +7 -0
- package/dist/a2a/server.js +5 -2
- package/dist/a2a/service.d.ts +1 -1
- package/dist/a2a/service.js +57 -8
- package/dist/a2a/store.d.ts +8 -5
- package/dist/a2a/store.js +24 -67
- 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/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 +1 -0
- package/dist/cli/runStageCommand.js +44 -25
- package/dist/cli/runsCommand.d.ts +1 -1
- package/dist/cli/runsCommand.js +162 -8
- package/dist/cli.js +171 -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 +456 -80
- 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 +18 -1
- package/dist/runstore/createStore.js +64 -5
- 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 +111 -13
- 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 +28 -3
- package/dist/runstore/sqlite/SqliteRunStore.js +352 -219
- 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 +277 -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/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 +36 -1
- package/dist/runtime/pipelineRunner.js +178 -17
- package/dist/runtime/pipelineScheduler.d.ts +15 -0
- package/dist/runtime/pipelineScheduler.js +135 -27
- package/dist/runtime/reloadRunCatalog.js +6 -1
- package/dist/runtime/repositoryMaterialize.d.ts +47 -0
- package/dist/runtime/repositoryMaterialize.js +235 -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 +158 -4
- package/dist/runtime/runManager.js +1596 -79
- 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 +36 -2
- package/dist/server/bootstrap.js +209 -5
- 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 +103 -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 +5 -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
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { accessSync, constants, writeFileSync, unlinkSync } from "node:fs";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { promisify } from "node:util";
|
|
4
|
+
import { globalStageflowHome } from "../project/globalHome.js";
|
|
5
|
+
const execFileAsync = promisify(execFile);
|
|
6
|
+
const READYZ_TTL_MS = 4_000;
|
|
7
|
+
let readyzCache;
|
|
8
|
+
export function resetReadyzCacheForTests() {
|
|
9
|
+
readyzCache = undefined;
|
|
10
|
+
}
|
|
11
|
+
export function livezBody() {
|
|
12
|
+
return { ok: true, status: "live" };
|
|
13
|
+
}
|
|
14
|
+
async function checkGitPresent() {
|
|
15
|
+
try {
|
|
16
|
+
await execFileAsync("git", ["--version"], {
|
|
17
|
+
timeout: 5_000,
|
|
18
|
+
windowsHide: true,
|
|
19
|
+
});
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export async function probeGitVersion() {
|
|
27
|
+
try {
|
|
28
|
+
const { stdout } = await execFileAsync("git", ["--version"], {
|
|
29
|
+
timeout: 5_000,
|
|
30
|
+
windowsHide: true,
|
|
31
|
+
});
|
|
32
|
+
return stdout.trim();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function checkHomeWritable(home) {
|
|
39
|
+
try {
|
|
40
|
+
accessSync(home, constants.W_OK);
|
|
41
|
+
const probe = `${home}/.stageflow-write-probe-${process.pid}`;
|
|
42
|
+
writeFileSync(probe, "ok");
|
|
43
|
+
unlinkSync(probe);
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function checkStoreOpenable(store) {
|
|
51
|
+
try {
|
|
52
|
+
await store.listRuns();
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function checkMigrationsComplete(store) {
|
|
60
|
+
const connection = store.connection;
|
|
61
|
+
if (connection === undefined || typeof connection.pragma !== "function") {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const version = connection.pragma("user_version", { simple: true });
|
|
66
|
+
return typeof version === "number" && version >= 0;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export async function runReadyzChecks(options) {
|
|
73
|
+
const now = options.now ?? Date.now();
|
|
74
|
+
if (!options.bypassCache &&
|
|
75
|
+
readyzCache !== undefined &&
|
|
76
|
+
readyzCache.expiresAt > now) {
|
|
77
|
+
return readyzCache.result;
|
|
78
|
+
}
|
|
79
|
+
const home = options.homeDir ?? globalStageflowHome();
|
|
80
|
+
const checks = {
|
|
81
|
+
store_openable: await checkStoreOpenable(options.store),
|
|
82
|
+
home_writable: checkHomeWritable(home),
|
|
83
|
+
migrations_complete: checkMigrationsComplete(options.store),
|
|
84
|
+
git_present: await checkGitPresent(),
|
|
85
|
+
};
|
|
86
|
+
let code;
|
|
87
|
+
if (!checks.store_openable)
|
|
88
|
+
code = "store_not_openable";
|
|
89
|
+
else if (!checks.home_writable)
|
|
90
|
+
code = "home_not_writable";
|
|
91
|
+
else if (!checks.migrations_complete)
|
|
92
|
+
code = "migrations_incomplete";
|
|
93
|
+
else if (!checks.git_present)
|
|
94
|
+
code = "git_not_present";
|
|
95
|
+
const result = {
|
|
96
|
+
ready: code === undefined,
|
|
97
|
+
checks,
|
|
98
|
+
...(code !== undefined ? { code } : {}),
|
|
99
|
+
};
|
|
100
|
+
readyzCache = { expiresAt: now + READYZ_TTL_MS, result };
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
export function readSchemaHealth(store) {
|
|
104
|
+
const connection = store.connection;
|
|
105
|
+
if (connection === undefined || typeof connection.pragma !== "function") {
|
|
106
|
+
return {
|
|
107
|
+
user_version: null,
|
|
108
|
+
schema_migrations: "unknown",
|
|
109
|
+
note: "Slot 1 schema reporting stub — store has no sqlite connection",
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const user_version = connection.pragma("user_version", {
|
|
114
|
+
simple: true,
|
|
115
|
+
});
|
|
116
|
+
let schema_migrations = "unknown";
|
|
117
|
+
if (typeof connection.prepare === "function") {
|
|
118
|
+
try {
|
|
119
|
+
connection.prepare(`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'schema_migrations'`).get();
|
|
120
|
+
schema_migrations = "present";
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
schema_migrations = "absent";
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return { user_version, schema_migrations };
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return {
|
|
130
|
+
user_version: null,
|
|
131
|
+
schema_migrations: "unknown",
|
|
132
|
+
note: "Slot 1 schema reporting stub — pragma failed",
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Stable network-facing error codes (snake_case). Keep strings unchanged once shipped. */
|
|
2
|
+
export declare const BUSY_CAPACITY: "busy_capacity";
|
|
3
|
+
export declare const BUSY_CHECKOUT: "busy_checkout";
|
|
4
|
+
/** Per-caller concurrency quota: queued when under global capacity; reject when queue full. */
|
|
5
|
+
export declare const BUSY_CALLER_QUOTA: "busy_caller_quota";
|
|
6
|
+
export declare const ABORTED: "aborted";
|
|
7
|
+
export declare const NETWORK_ERROR_CODES: readonly ["busy_capacity", "busy_checkout", "busy_caller_quota", "aborted", "unknown_project_root", "absolute_path_not_allowed", "path_outside_project_root", "catalog_root_unreadable", "ensure_project_not_allowed", "config_invalid", "config_unknown_key", "provider_not_configured", "a2a_configuration_error", "untrusted_config_origin", "command_not_on_path", "missing_tool", "tool_version_mismatch", "unknown_version", "secret_unavailable", "not_ready", "internal_error", "retry_in_progress", "hitl_not_retriable", "run_not_retryable", "stage_not_failed", "manual_recovery_required", "run_not_found", "stage_not_found", "artifact_not_found", "artifact_path_denied", "envelope_not_found", "insufficient_disk", "disk_check_failed", "shutting_down", "start.token_rejected", "inline_pipeline_too_large", "skills_invalid_name", "skills_invalid_path", "skills_missing_skill_md", "skills_payload_too_large", "pinned_sha_unavailable", "store_integrity_failed", "store_unsupported_filesystem", "tmpdir_unusable", "backup_insufficient_disk"];
|
|
8
|
+
export type NetworkErrorCode = (typeof NETWORK_ERROR_CODES)[number] | string;
|
|
9
|
+
export type NetworkErrorBody = {
|
|
10
|
+
code: NetworkErrorCode;
|
|
11
|
+
error: string;
|
|
12
|
+
} & Record<string, unknown>;
|
|
13
|
+
export declare function networkError(code: NetworkErrorCode, error: string, detail?: Record<string, unknown>): NetworkErrorBody;
|
|
14
|
+
export declare function codeOrInternal(code: string | undefined): NetworkErrorCode;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** Stable network-facing error codes (snake_case). Keep strings unchanged once shipped. */
|
|
2
|
+
export const BUSY_CAPACITY = "busy_capacity";
|
|
3
|
+
export const BUSY_CHECKOUT = "busy_checkout";
|
|
4
|
+
/** Per-caller concurrency quota: queued when under global capacity; reject when queue full. */
|
|
5
|
+
export const BUSY_CALLER_QUOTA = "busy_caller_quota";
|
|
6
|
+
export const ABORTED = "aborted";
|
|
7
|
+
export const NETWORK_ERROR_CODES = [
|
|
8
|
+
BUSY_CAPACITY,
|
|
9
|
+
BUSY_CHECKOUT,
|
|
10
|
+
BUSY_CALLER_QUOTA,
|
|
11
|
+
ABORTED,
|
|
12
|
+
"unknown_project_root",
|
|
13
|
+
"absolute_path_not_allowed",
|
|
14
|
+
"path_outside_project_root",
|
|
15
|
+
"catalog_root_unreadable",
|
|
16
|
+
"ensure_project_not_allowed",
|
|
17
|
+
"config_invalid",
|
|
18
|
+
"config_unknown_key",
|
|
19
|
+
"provider_not_configured",
|
|
20
|
+
"a2a_configuration_error",
|
|
21
|
+
"untrusted_config_origin",
|
|
22
|
+
"command_not_on_path",
|
|
23
|
+
"missing_tool",
|
|
24
|
+
"tool_version_mismatch",
|
|
25
|
+
"unknown_version",
|
|
26
|
+
"secret_unavailable",
|
|
27
|
+
"not_ready",
|
|
28
|
+
"internal_error",
|
|
29
|
+
"retry_in_progress",
|
|
30
|
+
"hitl_not_retriable",
|
|
31
|
+
"run_not_retryable",
|
|
32
|
+
"stage_not_failed",
|
|
33
|
+
"manual_recovery_required",
|
|
34
|
+
"run_not_found",
|
|
35
|
+
"stage_not_found",
|
|
36
|
+
"artifact_not_found",
|
|
37
|
+
"artifact_path_denied",
|
|
38
|
+
"envelope_not_found",
|
|
39
|
+
"insufficient_disk",
|
|
40
|
+
"disk_check_failed",
|
|
41
|
+
"shutting_down",
|
|
42
|
+
"start.token_rejected",
|
|
43
|
+
"inline_pipeline_too_large",
|
|
44
|
+
"skills_invalid_name",
|
|
45
|
+
"skills_invalid_path",
|
|
46
|
+
"skills_missing_skill_md",
|
|
47
|
+
"skills_payload_too_large",
|
|
48
|
+
"pinned_sha_unavailable",
|
|
49
|
+
"store_integrity_failed",
|
|
50
|
+
"store_unsupported_filesystem",
|
|
51
|
+
"tmpdir_unusable",
|
|
52
|
+
"backup_insufficient_disk",
|
|
53
|
+
];
|
|
54
|
+
export function networkError(code, error, detail) {
|
|
55
|
+
return { code, error, ...detail };
|
|
56
|
+
}
|
|
57
|
+
export function codeOrInternal(code) {
|
|
58
|
+
return code && code.length > 0 ? code : "internal_error";
|
|
59
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function setBareCacheRemoteUrlOverrideForTests(override: ((repository: string) => string | undefined) | null): void;
|
|
2
|
+
export declare function resetBareCacheStateForTests(): void;
|
|
3
|
+
export declare function githubHttpsRemoteUrl(repository: string): string;
|
|
4
|
+
export declare function bareCachePath(repository: string): string;
|
|
5
|
+
export declare function remoteUrlForRepository(repository: string): string;
|
|
6
|
+
export type EnsureBareCacheResult = {
|
|
7
|
+
cachePath: string;
|
|
8
|
+
fetched: boolean;
|
|
9
|
+
};
|
|
10
|
+
export type EnsureBareCacheOptions = {
|
|
11
|
+
env?: NodeJS.ProcessEnv;
|
|
12
|
+
signal?: AbortSignal;
|
|
13
|
+
};
|
|
14
|
+
export declare function ensureBareCache(repository: string, ref: string, options?: EnsureBareCacheOptions): Promise<EnsureBareCacheResult>;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { closeSync, existsSync, mkdirSync, openSync, statSync, unlinkSync, writeSync, } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { ensureGlobalHome, globalStageflowHome } from "../project/globalHome.js";
|
|
4
|
+
import { hostGitAskpassEnv } from "./credentials.js";
|
|
5
|
+
import { catFileCommit, cloneBare, configureBareOriginFetch, pruneNonStageflowLocalHeads, remoteUpdate, } from "./operations.js";
|
|
6
|
+
const FETCH_TIMEOUT_MS = 300_000;
|
|
7
|
+
const LOCK_POLL_MS = 50;
|
|
8
|
+
const FULL_SHA_RE = /^[0-9a-f]{40}$/i;
|
|
9
|
+
const mutexTails = new Map();
|
|
10
|
+
let remoteUrlOverride = null;
|
|
11
|
+
export function setBareCacheRemoteUrlOverrideForTests(override) {
|
|
12
|
+
remoteUrlOverride = override;
|
|
13
|
+
}
|
|
14
|
+
export function resetBareCacheStateForTests() {
|
|
15
|
+
mutexTails.clear();
|
|
16
|
+
remoteUrlOverride = null;
|
|
17
|
+
}
|
|
18
|
+
export function githubHttpsRemoteUrl(repository) {
|
|
19
|
+
return `https://github.com/${repository}.git`;
|
|
20
|
+
}
|
|
21
|
+
export function bareCachePath(repository) {
|
|
22
|
+
const [owner, repo] = repository.split("/");
|
|
23
|
+
return path.join(globalStageflowHome(), "repos", "github.com", owner, `${repo}.git`);
|
|
24
|
+
}
|
|
25
|
+
export function remoteUrlForRepository(repository) {
|
|
26
|
+
const overridden = remoteUrlOverride?.(repository);
|
|
27
|
+
if (overridden)
|
|
28
|
+
return overridden;
|
|
29
|
+
return githubHttpsRemoteUrl(repository);
|
|
30
|
+
}
|
|
31
|
+
function isFullCommitSha(ref) {
|
|
32
|
+
return FULL_SHA_RE.test(ref);
|
|
33
|
+
}
|
|
34
|
+
function isFileUrl(url) {
|
|
35
|
+
return url.startsWith("file:");
|
|
36
|
+
}
|
|
37
|
+
function fetchLockPath(cachePath) {
|
|
38
|
+
if (existsSync(cachePath)) {
|
|
39
|
+
return path.join(cachePath, ".stageflow-fetch.lock");
|
|
40
|
+
}
|
|
41
|
+
return `${cachePath}.stageflow-fetch.lock`;
|
|
42
|
+
}
|
|
43
|
+
function sleep(ms) {
|
|
44
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
45
|
+
}
|
|
46
|
+
async function withInProcessMutex(key, fn) {
|
|
47
|
+
const prev = mutexTails.get(key) ?? Promise.resolve();
|
|
48
|
+
let release;
|
|
49
|
+
const gate = new Promise((resolve) => {
|
|
50
|
+
release = resolve;
|
|
51
|
+
});
|
|
52
|
+
const tail = prev.then(() => gate);
|
|
53
|
+
mutexTails.set(key, tail);
|
|
54
|
+
await prev.catch(() => undefined);
|
|
55
|
+
try {
|
|
56
|
+
return await fn();
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
release();
|
|
60
|
+
if (mutexTails.get(key) === tail) {
|
|
61
|
+
mutexTails.delete(key);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function tryReclaimStaleLock(lockPath, staleMs) {
|
|
66
|
+
try {
|
|
67
|
+
const st = statSync(lockPath);
|
|
68
|
+
if (Date.now() - st.mtimeMs > staleMs) {
|
|
69
|
+
unlinkSync(lockPath);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// gone or unreadable
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function acquireExclusiveLock(lockPath, staleMs) {
|
|
77
|
+
mkdirSync(path.dirname(lockPath), { recursive: true });
|
|
78
|
+
for (;;) {
|
|
79
|
+
try {
|
|
80
|
+
const fd = openSync(lockPath, "wx");
|
|
81
|
+
writeSync(fd, `${JSON.stringify({ pid: process.pid, startedAt: Date.now() })}\n`, 0, "utf8");
|
|
82
|
+
return fd;
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
const err = error;
|
|
86
|
+
if (err.code !== "EEXIST")
|
|
87
|
+
throw error;
|
|
88
|
+
tryReclaimStaleLock(lockPath, staleMs);
|
|
89
|
+
await sleep(LOCK_POLL_MS);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function releaseExclusiveLock(fd, lockPath) {
|
|
94
|
+
try {
|
|
95
|
+
closeSync(fd);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// ignore
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
unlinkSync(lockPath);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// ignore
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async function withExclusiveLock(lockPath, staleMs, fn) {
|
|
108
|
+
const fd = await acquireExclusiveLock(lockPath, staleMs);
|
|
109
|
+
try {
|
|
110
|
+
return await fn();
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
releaseExclusiveLock(fd, lockPath);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
export async function ensureBareCache(repository, ref, options) {
|
|
117
|
+
ensureGlobalHome();
|
|
118
|
+
const cachePath = bareCachePath(repository);
|
|
119
|
+
const url = remoteUrlForRepository(repository);
|
|
120
|
+
const requireToken = !isFileUrl(url);
|
|
121
|
+
return withInProcessMutex(cachePath, async () => {
|
|
122
|
+
const lockPath = fetchLockPath(cachePath);
|
|
123
|
+
return withExclusiveLock(lockPath, FETCH_TIMEOUT_MS, async () => {
|
|
124
|
+
const askpassEnv = hostGitAskpassEnv({
|
|
125
|
+
env: options?.env,
|
|
126
|
+
requireToken,
|
|
127
|
+
});
|
|
128
|
+
const gitEnv = { ...askpassEnv, ...options?.env };
|
|
129
|
+
const callOpts = { env: gitEnv, signal: options?.signal };
|
|
130
|
+
mkdirSync(path.dirname(cachePath), { recursive: true });
|
|
131
|
+
if (!existsSync(cachePath)) {
|
|
132
|
+
await cloneBare(url, cachePath, callOpts);
|
|
133
|
+
await remoteUpdate(cachePath, callOpts);
|
|
134
|
+
await pruneNonStageflowLocalHeads(cachePath, callOpts);
|
|
135
|
+
return { cachePath, fetched: true };
|
|
136
|
+
}
|
|
137
|
+
await configureBareOriginFetch(cachePath, callOpts);
|
|
138
|
+
if (isFullCommitSha(ref)) {
|
|
139
|
+
const present = await catFileCommit(cachePath, ref, callOpts);
|
|
140
|
+
if (present) {
|
|
141
|
+
await pruneNonStageflowLocalHeads(cachePath, callOpts);
|
|
142
|
+
return { cachePath, fetched: false };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
await remoteUpdate(cachePath, callOpts);
|
|
146
|
+
await pruneNonStageflowLocalHeads(cachePath, callOpts);
|
|
147
|
+
return { cachePath, fetched: true };
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function readHostGithubToken(env?: NodeJS.ProcessEnv): string | undefined;
|
|
2
|
+
export declare function askpassHelperPath(home?: string): string;
|
|
3
|
+
export declare function ensureAskpassHelper(home?: string): string;
|
|
4
|
+
export type HostGitAskpassEnvOptions = {
|
|
5
|
+
env?: NodeJS.ProcessEnv;
|
|
6
|
+
requireToken?: boolean;
|
|
7
|
+
home?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function hostGitAskpassEnv(options?: HostGitAskpassEnvOptions): NodeJS.ProcessEnv;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { GitError } from "./errors.js";
|
|
4
|
+
import { ensureGlobalHome, globalStageflowHome } from "../project/globalHome.js";
|
|
5
|
+
const ASKPASS_BASENAME = "git-askpass";
|
|
6
|
+
const ASKPASS_SCRIPT = `#!/bin/sh
|
|
7
|
+
prompt=\${1-}
|
|
8
|
+
case "\$prompt" in
|
|
9
|
+
*Username*|*username*)
|
|
10
|
+
printf '%s\\n' 'x-access-token'
|
|
11
|
+
;;
|
|
12
|
+
*)
|
|
13
|
+
token=\${GITHUB_TOKEN-}
|
|
14
|
+
if [ -z "\$token" ]; then
|
|
15
|
+
token=\${GH_TOKEN-}
|
|
16
|
+
fi
|
|
17
|
+
if [ -z "\$token" ] && [ -n "\${GITHUB_TOKEN_FILE-}" ] && [ -f "\$GITHUB_TOKEN_FILE" ]; then
|
|
18
|
+
token=\$(cat "\$GITHUB_TOKEN_FILE")
|
|
19
|
+
fi
|
|
20
|
+
if [ -z "\$token" ] && [ -n "\${GH_TOKEN_FILE-}" ] && [ -f "\$GH_TOKEN_FILE" ]; then
|
|
21
|
+
token=\$(cat "\$GH_TOKEN_FILE")
|
|
22
|
+
fi
|
|
23
|
+
printf '%s\\n' "\$token"
|
|
24
|
+
;;
|
|
25
|
+
esac
|
|
26
|
+
`;
|
|
27
|
+
export function readHostGithubToken(env = process.env) {
|
|
28
|
+
for (const key of ["GITHUB_TOKEN", "GH_TOKEN"]) {
|
|
29
|
+
const value = env[key]?.trim();
|
|
30
|
+
if (value)
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
for (const key of ["GITHUB_TOKEN_FILE", "GH_TOKEN_FILE"]) {
|
|
34
|
+
const file = env[key]?.trim();
|
|
35
|
+
if (!file)
|
|
36
|
+
continue;
|
|
37
|
+
try {
|
|
38
|
+
const value = readFileSync(file, "utf8").trim();
|
|
39
|
+
if (value)
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// ignore unreadable files; fall through
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
export function askpassHelperPath(home = globalStageflowHome()) {
|
|
49
|
+
return path.join(home, ASKPASS_BASENAME);
|
|
50
|
+
}
|
|
51
|
+
export function ensureAskpassHelper(home) {
|
|
52
|
+
const resolvedHome = home ?? ensureGlobalHome();
|
|
53
|
+
mkdirSync(resolvedHome, { recursive: true });
|
|
54
|
+
const askpass = askpassHelperPath(resolvedHome);
|
|
55
|
+
if (!existsSync(askpass)) {
|
|
56
|
+
writeFileSync(askpass, ASKPASS_SCRIPT, { encoding: "utf8", mode: 0o700 });
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
chmodSync(askpass, 0o700);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// best-effort on non-POSIX
|
|
63
|
+
}
|
|
64
|
+
return askpass;
|
|
65
|
+
}
|
|
66
|
+
export function hostGitAskpassEnv(options = {}) {
|
|
67
|
+
const sourceEnv = options.env ?? process.env;
|
|
68
|
+
const home = options.home ?? ensureGlobalHome();
|
|
69
|
+
const askpass = ensureAskpassHelper(home);
|
|
70
|
+
const token = readHostGithubToken(sourceEnv);
|
|
71
|
+
const requireToken = options.requireToken !== false;
|
|
72
|
+
if (requireToken && !token) {
|
|
73
|
+
throw new GitError("git authentication failed", {
|
|
74
|
+
code: "auth_failed",
|
|
75
|
+
argv: [],
|
|
76
|
+
stderr: "GITHUB_TOKEN (or GH_TOKEN / GITHUB_TOKEN_FILE / GH_TOKEN_FILE) is required for repository binding (clone/fetch and later push/PR). Set it on the Host process environment before start.",
|
|
77
|
+
exitCode: null,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const out = {
|
|
81
|
+
GIT_ASKPASS: askpass,
|
|
82
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
83
|
+
};
|
|
84
|
+
if (token) {
|
|
85
|
+
out.GITHUB_TOKEN = token;
|
|
86
|
+
}
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type GitErrorCode = "auth_failed" | "ref_not_found" | "repo_not_found" | "network" | "disk_full" | "git_missing" | "timeout" | "unknown";
|
|
2
|
+
export declare class GitError extends Error {
|
|
3
|
+
readonly code: GitErrorCode;
|
|
4
|
+
readonly argv: string[];
|
|
5
|
+
readonly stderr: string;
|
|
6
|
+
readonly exitCode: number | null;
|
|
7
|
+
constructor(message: string, options: {
|
|
8
|
+
code: GitErrorCode;
|
|
9
|
+
argv: string[];
|
|
10
|
+
stderr: string;
|
|
11
|
+
exitCode: number | null;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export declare function redactGitText(text: string, env?: NodeJS.ProcessEnv): string;
|
|
15
|
+
export declare function classifyGitFailure(input: {
|
|
16
|
+
stderr: string;
|
|
17
|
+
exitCode: number | null;
|
|
18
|
+
errno?: string | null;
|
|
19
|
+
timedOut?: boolean;
|
|
20
|
+
}): GitErrorCode;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export class GitError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
argv;
|
|
4
|
+
stderr;
|
|
5
|
+
exitCode;
|
|
6
|
+
constructor(message, options) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "GitError";
|
|
9
|
+
this.code = options.code;
|
|
10
|
+
this.argv = options.argv;
|
|
11
|
+
this.stderr = options.stderr;
|
|
12
|
+
this.exitCode = options.exitCode;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const URL_CREDENTIALS = /:\/\/([^/\s]*?):([^/\s]*?)@/g;
|
|
16
|
+
const TOKEN_PATTERNS = [
|
|
17
|
+
/\bghp_[A-Za-z0-9_]{20,}\b/g,
|
|
18
|
+
/\bgho_[A-Za-z0-9_]{20,}\b/g,
|
|
19
|
+
/\bghu_[A-Za-z0-9_]{20,}\b/g,
|
|
20
|
+
/\bghs_[A-Za-z0-9_]{20,}\b/g,
|
|
21
|
+
/\bghr_[A-Za-z0-9_]{20,}\b/g,
|
|
22
|
+
/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g,
|
|
23
|
+
/\bglpat-[A-Za-z0-9_\-]{20,}\b/g,
|
|
24
|
+
/\bxox[baprs]-[A-Za-z0-9\-]{10,}\b/g,
|
|
25
|
+
/\bBearer\s+[A-Za-z0-9\-._~+/]+=*/gi,
|
|
26
|
+
];
|
|
27
|
+
const ENV_SECRET_KEYS = [
|
|
28
|
+
"GITHUB_TOKEN",
|
|
29
|
+
"GH_TOKEN",
|
|
30
|
+
"GITHUB_TOKEN_FILE",
|
|
31
|
+
"GH_TOKEN_FILE",
|
|
32
|
+
];
|
|
33
|
+
export function redactGitText(text, env = process.env) {
|
|
34
|
+
let out = text.replace(URL_CREDENTIALS, "://$1:***@");
|
|
35
|
+
for (const pattern of TOKEN_PATTERNS) {
|
|
36
|
+
out = out.replace(pattern, "***");
|
|
37
|
+
}
|
|
38
|
+
for (const key of ENV_SECRET_KEYS) {
|
|
39
|
+
const value = env[key];
|
|
40
|
+
if (typeof value === "string" && value.length >= 8 && !key.endsWith("_FILE")) {
|
|
41
|
+
out = out.split(value).join("***");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
export function classifyGitFailure(input) {
|
|
47
|
+
if (input.errno === "ENOENT")
|
|
48
|
+
return "git_missing";
|
|
49
|
+
if (input.timedOut)
|
|
50
|
+
return "timeout";
|
|
51
|
+
const stderr = input.stderr;
|
|
52
|
+
const lower = stderr.toLowerCase();
|
|
53
|
+
if (/authentication failed/i.test(stderr) ||
|
|
54
|
+
/could not read username/i.test(stderr) ||
|
|
55
|
+
/could not read password/i.test(stderr) ||
|
|
56
|
+
/invalid username or password/i.test(stderr) ||
|
|
57
|
+
/authentication required/i.test(stderr) ||
|
|
58
|
+
/access denied/i.test(stderr) ||
|
|
59
|
+
/terminal prompts disabled/i.test(stderr)) {
|
|
60
|
+
return "auth_failed";
|
|
61
|
+
}
|
|
62
|
+
// GitHub hides private repos behind "not found"; treat as auth-suspicion.
|
|
63
|
+
if (/remote:\s*repository not found/i.test(stderr) ||
|
|
64
|
+
(/repository ['`].*['`] not found/i.test(stderr) && /github\.com/i.test(stderr))) {
|
|
65
|
+
return "auth_failed";
|
|
66
|
+
}
|
|
67
|
+
if (/couldn't find remote ref/i.test(stderr) ||
|
|
68
|
+
/unknown revision/i.test(stderr) ||
|
|
69
|
+
/bad revision/i.test(stderr) ||
|
|
70
|
+
/invalid refspec/i.test(stderr) ||
|
|
71
|
+
/needed a single revision/i.test(stderr) ||
|
|
72
|
+
/not a valid object name/i.test(stderr) ||
|
|
73
|
+
/ambiguous argument .* unknown revision/i.test(stderr)) {
|
|
74
|
+
return "ref_not_found";
|
|
75
|
+
}
|
|
76
|
+
if (/does not appear to be a git repository/i.test(stderr) ||
|
|
77
|
+
/not a git repository/i.test(stderr) ||
|
|
78
|
+
/repository .* does not exist/i.test(stderr) ||
|
|
79
|
+
(/fatal: repository ['`].*['`] not found/i.test(stderr) && !/github\.com/i.test(stderr))) {
|
|
80
|
+
return "repo_not_found";
|
|
81
|
+
}
|
|
82
|
+
if (/could not resolve host/i.test(stderr) ||
|
|
83
|
+
/failed to connect/i.test(stderr) ||
|
|
84
|
+
/connection refused/i.test(stderr) ||
|
|
85
|
+
/network is unreachable/i.test(stderr) ||
|
|
86
|
+
/timed out/i.test(lower) ||
|
|
87
|
+
/unable to access/i.test(stderr)) {
|
|
88
|
+
return "network";
|
|
89
|
+
}
|
|
90
|
+
if (/no space left on device/i.test(stderr) || /disk quota exceeded/i.test(stderr)) {
|
|
91
|
+
return "disk_full";
|
|
92
|
+
}
|
|
93
|
+
return "unknown";
|
|
94
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type RunGitOptions = {
|
|
2
|
+
args: string[];
|
|
3
|
+
cwd?: string;
|
|
4
|
+
env?: NodeJS.ProcessEnv;
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
maxBuffer?: number;
|
|
7
|
+
gitBin?: string;
|
|
8
|
+
signal?: AbortSignal;
|
|
9
|
+
};
|
|
10
|
+
export type RunGitResult = {
|
|
11
|
+
stdout: string;
|
|
12
|
+
stderr: string;
|
|
13
|
+
exitCode: number;
|
|
14
|
+
};
|
|
15
|
+
export declare function runGitSync(options: RunGitOptions): RunGitResult;
|
|
16
|
+
export declare function runGit(options: RunGitOptions): Promise<RunGitResult>;
|