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
|
@@ -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>;
|
package/dist/git/exec.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { execFile, execFileSync } from "node:child_process";
|
|
2
|
+
import { classifyGitFailure, GitError, redactGitText, } from "./errors.js";
|
|
3
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
4
|
+
const DEFAULT_MAX_BUFFER = 16 * 1024 * 1024;
|
|
5
|
+
function buildEnv(extra) {
|
|
6
|
+
return {
|
|
7
|
+
...process.env,
|
|
8
|
+
...extra,
|
|
9
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function toErrorMessage(code) {
|
|
13
|
+
switch (code) {
|
|
14
|
+
case "auth_failed":
|
|
15
|
+
return "git authentication failed";
|
|
16
|
+
case "ref_not_found":
|
|
17
|
+
return "git ref not found";
|
|
18
|
+
case "repo_not_found":
|
|
19
|
+
return "git repository not found";
|
|
20
|
+
case "network":
|
|
21
|
+
return "git network error";
|
|
22
|
+
case "disk_full":
|
|
23
|
+
return "git disk full";
|
|
24
|
+
case "git_missing":
|
|
25
|
+
return "git binary not found";
|
|
26
|
+
case "timeout":
|
|
27
|
+
return "git command timed out";
|
|
28
|
+
default:
|
|
29
|
+
return "git command failed";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function fail(options) {
|
|
33
|
+
const stderr = redactGitText(options.stderrRaw, options.env);
|
|
34
|
+
const code = classifyGitFailure({
|
|
35
|
+
stderr: options.stderrRaw,
|
|
36
|
+
exitCode: options.exitCode,
|
|
37
|
+
errno: options.errno,
|
|
38
|
+
timedOut: options.timedOut,
|
|
39
|
+
});
|
|
40
|
+
throw new GitError(toErrorMessage(code), {
|
|
41
|
+
code,
|
|
42
|
+
argv: options.argv,
|
|
43
|
+
stderr,
|
|
44
|
+
exitCode: options.exitCode,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function normalizeStderr(stderr) {
|
|
48
|
+
if (Buffer.isBuffer(stderr))
|
|
49
|
+
return stderr.toString("utf8").trim();
|
|
50
|
+
if (typeof stderr === "string")
|
|
51
|
+
return stderr.trim();
|
|
52
|
+
return "";
|
|
53
|
+
}
|
|
54
|
+
export function runGitSync(options) {
|
|
55
|
+
const gitBin = options.gitBin ?? "git";
|
|
56
|
+
const argv = [gitBin, ...options.args];
|
|
57
|
+
const env = buildEnv(options.env);
|
|
58
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
59
|
+
try {
|
|
60
|
+
const stdout = execFileSync(gitBin, options.args, {
|
|
61
|
+
cwd: options.cwd,
|
|
62
|
+
env,
|
|
63
|
+
encoding: "utf8",
|
|
64
|
+
timeout: timeoutMs,
|
|
65
|
+
maxBuffer: options.maxBuffer ?? DEFAULT_MAX_BUFFER,
|
|
66
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
67
|
+
});
|
|
68
|
+
return { stdout, stderr: "", exitCode: 0 };
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
const err = error;
|
|
72
|
+
const timedOut = err.killed === true ||
|
|
73
|
+
err.signal === "SIGTERM" ||
|
|
74
|
+
(typeof err.message === "string" && /TIMEDOUT|timed out/i.test(err.message));
|
|
75
|
+
fail({
|
|
76
|
+
argv,
|
|
77
|
+
stderrRaw: normalizeStderr(err.stderr) || (timedOut ? "git command timed out" : err.message),
|
|
78
|
+
exitCode: typeof err.status === "number" ? err.status : null,
|
|
79
|
+
errno: err.code ?? null,
|
|
80
|
+
timedOut,
|
|
81
|
+
env,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export function runGit(options) {
|
|
86
|
+
const gitBin = options.gitBin ?? "git";
|
|
87
|
+
const argv = [gitBin, ...options.args];
|
|
88
|
+
const env = buildEnv(options.env);
|
|
89
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
90
|
+
return new Promise((resolve, reject) => {
|
|
91
|
+
execFile(gitBin, options.args, {
|
|
92
|
+
cwd: options.cwd,
|
|
93
|
+
env,
|
|
94
|
+
encoding: "utf8",
|
|
95
|
+
timeout: timeoutMs,
|
|
96
|
+
maxBuffer: options.maxBuffer ?? DEFAULT_MAX_BUFFER,
|
|
97
|
+
signal: options.signal,
|
|
98
|
+
killSignal: "SIGTERM",
|
|
99
|
+
}, (error, stdout, stderr) => {
|
|
100
|
+
if (!error) {
|
|
101
|
+
resolve({
|
|
102
|
+
stdout: typeof stdout === "string" ? stdout : String(stdout ?? ""),
|
|
103
|
+
stderr: normalizeStderr(stderr),
|
|
104
|
+
exitCode: 0,
|
|
105
|
+
});
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const err = error;
|
|
109
|
+
const timedOut = err.killed === true ||
|
|
110
|
+
err.signal === "SIGTERM" ||
|
|
111
|
+
err.code === "ETIMEDOUT" ||
|
|
112
|
+
(typeof err.message === "string" && /TIMEDOUT|timed out/i.test(err.message));
|
|
113
|
+
const errno = typeof err.code === "string" ? err.code : null;
|
|
114
|
+
const exitCode = typeof err.status === "number"
|
|
115
|
+
? err.status
|
|
116
|
+
: typeof err.code === "number"
|
|
117
|
+
? err.code
|
|
118
|
+
: null;
|
|
119
|
+
try {
|
|
120
|
+
fail({
|
|
121
|
+
argv,
|
|
122
|
+
stderrRaw: normalizeStderr(stderr) ||
|
|
123
|
+
(timedOut ? "git command timed out" : err.message),
|
|
124
|
+
exitCode,
|
|
125
|
+
errno,
|
|
126
|
+
timedOut,
|
|
127
|
+
env,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
catch (gitError) {
|
|
131
|
+
reject(gitError);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type GitCallOptions = {
|
|
2
|
+
env?: NodeJS.ProcessEnv;
|
|
3
|
+
gitBin?: string;
|
|
4
|
+
signal?: AbortSignal;
|
|
5
|
+
};
|
|
6
|
+
export declare const BARE_ORIGIN_FETCH_HEADS = "+refs/heads/*:refs/remotes/origin/*";
|
|
7
|
+
export declare const BARE_ORIGIN_FETCH_TAGS = "+refs/tags/*:refs/tags/*";
|
|
8
|
+
export declare function configureBareOriginFetch(repoDir: string, opts?: GitCallOptions): Promise<void>;
|
|
9
|
+
export declare function pruneNonStageflowLocalHeads(repoDir: string, opts?: GitCallOptions): Promise<void>;
|
|
10
|
+
export declare function cloneBare(url: string, dest: string, opts?: GitCallOptions): Promise<void>;
|
|
11
|
+
export declare function fetch(repoDir: string, refspecs?: string[], opts?: GitCallOptions): Promise<void>;
|
|
12
|
+
export declare function remoteUpdate(repoDir: string, opts?: GitCallOptions): Promise<void>;
|
|
13
|
+
export declare function resolveRef(repoDir: string, ref: string, opts?: GitCallOptions): Promise<string>;
|
|
14
|
+
export declare function catFileCommit(repoDir: string, sha: string, opts?: GitCallOptions): Promise<boolean>;
|
|
15
|
+
export declare function worktreeAdd(repoDir: string, input: {
|
|
16
|
+
worktreePath: string;
|
|
17
|
+
branch: string;
|
|
18
|
+
startPoint: string;
|
|
19
|
+
}, opts?: GitCallOptions): Promise<void>;
|
|
20
|
+
export declare function worktreeRemove(repoDir: string, worktreePath: string, opts?: GitCallOptions): Promise<void>;
|
|
21
|
+
export declare function worktreePrune(repoDir: string, opts?: GitCallOptions): Promise<void>;
|
|
22
|
+
export declare function deleteBranch(repoDir: string, branch: string, opts?: GitCallOptions): Promise<void>;
|
|
23
|
+
export declare function revParse(repoDir: string, args: string[], opts?: GitCallOptions): Promise<string>;
|
|
24
|
+
export declare function diff(repoDir: string, args?: string[], opts?: GitCallOptions): Promise<string>;
|
|
25
|
+
export declare function statusPorcelain(repoDir: string, pathspec?: string, opts?: GitCallOptions): string;
|
|
26
|
+
export declare function statusPorcelainZ(repoDir: string, opts?: GitCallOptions): Promise<string>;
|
|
27
|
+
export declare function lsFilesOthersZ(repoDir: string, opts?: GitCallOptions): Promise<string>;
|
|
28
|
+
export declare function checkRefFormat(branchName: string, opts?: GitCallOptions): Promise<boolean>;
|
|
29
|
+
export declare function revParseSync(cwd: string, args: string[], opts?: GitCallOptions): string;
|