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,142 @@
|
|
|
1
|
+
import { listModelsForContext, listPipelinesForContext, listTasksForContext, } from "./browseCatalog.js";
|
|
2
|
+
import { loadStageflowManifestOutcome, } from "./loadStageflowManifest.js";
|
|
3
|
+
import { findCatalogRoot, isRootReadable, resolveCatalogRoots, } from "./resolveCatalogRoots.js";
|
|
4
|
+
import { catalogContextFromStageflow } from "./resolveCatalogContext.js";
|
|
5
|
+
import { resolveStageflowContext } from "../project/resolveStageflowContext.js";
|
|
6
|
+
async function catalogContextForRoot(root) {
|
|
7
|
+
if (root.kind === "seeded") {
|
|
8
|
+
const outcome = await loadStageflowManifestOutcome(root.path);
|
|
9
|
+
if (!outcome.ok) {
|
|
10
|
+
return {
|
|
11
|
+
projectRoot: root.path,
|
|
12
|
+
manifest: null,
|
|
13
|
+
manifestStatus: "invalid",
|
|
14
|
+
issues: outcome.issues,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
projectRoot: root.path,
|
|
19
|
+
manifest: outcome.value,
|
|
20
|
+
manifestStatus: "ok",
|
|
21
|
+
issues: [],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return catalogContextFromStageflow(await resolveStageflowContext(root.path));
|
|
25
|
+
}
|
|
26
|
+
async function selectRoots(options) {
|
|
27
|
+
const roots = await resolveCatalogRoots(options);
|
|
28
|
+
const root_errors = [];
|
|
29
|
+
if (options.projectRootFilter !== undefined) {
|
|
30
|
+
const match = findCatalogRoot(roots, options.projectRootFilter);
|
|
31
|
+
if (match === undefined) {
|
|
32
|
+
return {
|
|
33
|
+
roots,
|
|
34
|
+
selected: [],
|
|
35
|
+
root_errors: [
|
|
36
|
+
{
|
|
37
|
+
project_root: options.projectRootFilter,
|
|
38
|
+
code: "unknown_project_root",
|
|
39
|
+
message: `Unknown project_root: ${options.projectRootFilter}`,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (!(await isRootReadable(match.path))) {
|
|
45
|
+
return {
|
|
46
|
+
roots,
|
|
47
|
+
selected: [],
|
|
48
|
+
root_errors: [
|
|
49
|
+
{
|
|
50
|
+
project_root: match.project_root,
|
|
51
|
+
code: "catalog_root_unreadable",
|
|
52
|
+
message: `Catalog root is unreadable: ${match.project_root}`,
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return { roots, selected: [match], root_errors };
|
|
58
|
+
}
|
|
59
|
+
const selected = [];
|
|
60
|
+
for (const root of roots) {
|
|
61
|
+
if (!(await isRootReadable(root.path))) {
|
|
62
|
+
root_errors.push({
|
|
63
|
+
project_root: root.project_root,
|
|
64
|
+
code: "catalog_root_unreadable",
|
|
65
|
+
message: `Catalog root is unreadable: ${root.project_root}`,
|
|
66
|
+
});
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
selected.push(root);
|
|
70
|
+
}
|
|
71
|
+
return { roots, selected, root_errors };
|
|
72
|
+
}
|
|
73
|
+
export async function listPipelinesMultiProject(options) {
|
|
74
|
+
const { roots, selected, root_errors } = await selectRoots(options);
|
|
75
|
+
const items = [];
|
|
76
|
+
for (const root of selected) {
|
|
77
|
+
try {
|
|
78
|
+
const ctx = await catalogContextForRoot(root);
|
|
79
|
+
const pipelines = await listPipelinesForContext(ctx);
|
|
80
|
+
for (const p of pipelines) {
|
|
81
|
+
items.push({ ...p, project_root: root.project_root });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
root_errors.push({
|
|
86
|
+
project_root: root.project_root,
|
|
87
|
+
code: "catalog_root_unreadable",
|
|
88
|
+
message: err instanceof Error ? err.message : String(err),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return { items, root_errors, roots };
|
|
93
|
+
}
|
|
94
|
+
export async function listTasksMultiProject(options) {
|
|
95
|
+
const { roots, selected, root_errors } = await selectRoots(options);
|
|
96
|
+
const items = [];
|
|
97
|
+
for (const root of selected) {
|
|
98
|
+
try {
|
|
99
|
+
const ctx = await catalogContextForRoot(root);
|
|
100
|
+
const tasks = await listTasksForContext(ctx);
|
|
101
|
+
for (const t of tasks) {
|
|
102
|
+
items.push({ ...t, project_root: root.project_root });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
root_errors.push({
|
|
107
|
+
project_root: root.project_root,
|
|
108
|
+
code: "catalog_root_unreadable",
|
|
109
|
+
message: err instanceof Error ? err.message : String(err),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return { items, root_errors, roots };
|
|
114
|
+
}
|
|
115
|
+
export async function listModelsMultiProject(options) {
|
|
116
|
+
const { roots, selected, root_errors } = await selectRoots(options);
|
|
117
|
+
const items = [];
|
|
118
|
+
const modelSet = new Set();
|
|
119
|
+
for (const root of selected) {
|
|
120
|
+
try {
|
|
121
|
+
const ctx = await catalogContextForRoot(root);
|
|
122
|
+
const models = await listModelsForContext(ctx);
|
|
123
|
+
for (const id of models) {
|
|
124
|
+
modelSet.add(id);
|
|
125
|
+
items.push({ id, project_root: root.project_root });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
root_errors.push({
|
|
130
|
+
project_root: root.project_root,
|
|
131
|
+
code: "catalog_root_unreadable",
|
|
132
|
+
message: err instanceof Error ? err.message : String(err),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
items,
|
|
138
|
+
models: [...modelSet].sort((a, b) => a.localeCompare(b)),
|
|
139
|
+
root_errors,
|
|
140
|
+
roots,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { loadFailure, loadSuccess } from "./loadOutcome.js";
|
|
9
9
|
import { parseStageMcp } from "./loadStage.js";
|
|
10
|
+
import { parseStageSecrets } from "../runtime/stageSecretDecl.js";
|
|
11
|
+
import { parseToolRequires } from "./toolRequires.js";
|
|
10
12
|
import { legacyAuthoringRejected, presentLegacyKeys } from "./legacyYaml.js";
|
|
11
13
|
import { compileTargetContract, dialectFromKeys, mixedDialectIssue, } from "./yamlDialect.js";
|
|
12
14
|
import { BODY_KEYS, isAllowedPipelineStageEntryKey, } from "./pipelineStageKeys.js";
|
|
@@ -39,7 +41,11 @@ function extractBodyRaw(raw) {
|
|
|
39
41
|
return body;
|
|
40
42
|
}
|
|
41
43
|
function hasBodyKey(raw) {
|
|
42
|
-
return Object.keys(raw).some((key) => BODY_KEYS.has(key) &&
|
|
44
|
+
return Object.keys(raw).some((key) => BODY_KEYS.has(key) &&
|
|
45
|
+
key !== "skill" &&
|
|
46
|
+
key !== "mcp" &&
|
|
47
|
+
key !== "secrets" &&
|
|
48
|
+
key !== "requires");
|
|
43
49
|
}
|
|
44
50
|
function readSkill(raw) {
|
|
45
51
|
if (raw.skill === undefined)
|
|
@@ -112,6 +118,17 @@ export function normalizePipelineStageEntries(rawEntries, ctx) {
|
|
|
112
118
|
if (!mcpOutcome.ok)
|
|
113
119
|
return mcpOutcome;
|
|
114
120
|
const mcp = mcpOutcome.value;
|
|
121
|
+
const secretsOutcome = parseStageSecrets(raw.secrets, `entry at index ${index} in ${declaringPath}`);
|
|
122
|
+
if (!secretsOutcome.ok)
|
|
123
|
+
return secretsOutcome;
|
|
124
|
+
const secrets = secretsOutcome.value;
|
|
125
|
+
const requiresOutcome = parseToolRequires(raw.requires, `stage entry at index ${index} in ${declaringPath}`, {
|
|
126
|
+
code: "stage.invalid_requires",
|
|
127
|
+
category: "stage",
|
|
128
|
+
});
|
|
129
|
+
if (!requiresOutcome.ok)
|
|
130
|
+
return requiresOutcome;
|
|
131
|
+
const requires = requiresOutcome.value;
|
|
115
132
|
if (uses && hasBody) {
|
|
116
133
|
return loadFailure([
|
|
117
134
|
{
|
|
@@ -339,6 +356,8 @@ export function normalizePipelineStageEntries(rawEntries, ctx) {
|
|
|
339
356
|
...(entryFlag !== undefined ? { entry: entryFlag } : {}),
|
|
340
357
|
...(skill !== undefined ? { skill } : {}),
|
|
341
358
|
...(mcp !== undefined ? { mcp } : {}),
|
|
359
|
+
...(secrets !== undefined ? { secrets } : {}),
|
|
360
|
+
...(requires !== undefined ? { requires } : {}),
|
|
342
361
|
...(cloneCap !== undefined ? { clone_cap: cloneCap } : {}),
|
|
343
362
|
...(cloneMode !== undefined ? { clone_mode: cloneMode } : {}),
|
|
344
363
|
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { RunStore } from "../runstore/port.js";
|
|
2
|
+
export type CatalogRootKind = "registered" | "seeded";
|
|
3
|
+
export type CatalogRoot = {
|
|
4
|
+
/** Wire id: absolute path for registered; symbolic id for seeded (e.g. "examples"). */
|
|
5
|
+
project_root: string;
|
|
6
|
+
/** Absolute filesystem path used for browsing. */
|
|
7
|
+
path: string;
|
|
8
|
+
kind: CatalogRootKind;
|
|
9
|
+
read_only: boolean;
|
|
10
|
+
};
|
|
11
|
+
export type ResolveCatalogRootsOptions = {
|
|
12
|
+
store: RunStore;
|
|
13
|
+
/** Unused for catalog membership; retained so call sites may still pass Host cwd. */
|
|
14
|
+
bootCwd?: string;
|
|
15
|
+
/** Optional seeded roots (U10); default none. */
|
|
16
|
+
seededRoots?: Array<{
|
|
17
|
+
id: string;
|
|
18
|
+
path: string;
|
|
19
|
+
}>;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Root set = registered store roots ∪ seeded roots.
|
|
23
|
+
* Wire project_root for seeded is the symbolic id; store/capacity use absolute paths.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveCatalogRoots(options: ResolveCatalogRootsOptions): Promise<CatalogRoot[]>;
|
|
26
|
+
export declare function isRootReadable(rootPath: string): Promise<boolean>;
|
|
27
|
+
export declare function findCatalogRoot(roots: CatalogRoot[], projectRoot: string): CatalogRoot | undefined;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { realpathSync, constants } from "node:fs";
|
|
3
|
+
import { access } from "node:fs/promises";
|
|
4
|
+
function realOrResolve(p) {
|
|
5
|
+
const resolved = path.resolve(p);
|
|
6
|
+
try {
|
|
7
|
+
return realpathSync(resolved);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return resolved;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Root set = registered store roots ∪ seeded roots.
|
|
15
|
+
* Wire project_root for seeded is the symbolic id; store/capacity use absolute paths.
|
|
16
|
+
*/
|
|
17
|
+
export async function resolveCatalogRoots(options) {
|
|
18
|
+
const roots = [];
|
|
19
|
+
const seenPaths = new Set();
|
|
20
|
+
const seededRoots = options.seededRoots ??
|
|
21
|
+
(await import("./seededCatalog.js")).defaultSeededRoots();
|
|
22
|
+
let registered = [];
|
|
23
|
+
try {
|
|
24
|
+
registered = await options.store.listRegisteredProjects();
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
registered = [];
|
|
28
|
+
}
|
|
29
|
+
for (const root of registered) {
|
|
30
|
+
const abs = realOrResolve(root);
|
|
31
|
+
if (seenPaths.has(abs))
|
|
32
|
+
continue;
|
|
33
|
+
seenPaths.add(abs);
|
|
34
|
+
roots.push({
|
|
35
|
+
project_root: abs,
|
|
36
|
+
path: abs,
|
|
37
|
+
kind: "registered",
|
|
38
|
+
read_only: false,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
for (const seeded of seededRoots) {
|
|
42
|
+
const abs = realOrResolve(seeded.path);
|
|
43
|
+
if (seenPaths.has(abs))
|
|
44
|
+
continue;
|
|
45
|
+
seenPaths.add(abs);
|
|
46
|
+
roots.push({
|
|
47
|
+
project_root: seeded.id,
|
|
48
|
+
path: abs,
|
|
49
|
+
kind: "seeded",
|
|
50
|
+
read_only: true,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return roots;
|
|
54
|
+
}
|
|
55
|
+
export async function isRootReadable(rootPath) {
|
|
56
|
+
try {
|
|
57
|
+
await access(rootPath, constants.R_OK);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export function findCatalogRoot(roots, projectRoot) {
|
|
65
|
+
if (!path.isAbsolute(projectRoot)) {
|
|
66
|
+
return roots.find((r) => r.project_root === projectRoot);
|
|
67
|
+
}
|
|
68
|
+
const normalized = realOrResolve(projectRoot);
|
|
69
|
+
const resolved = path.resolve(projectRoot);
|
|
70
|
+
return roots.find((r) => r.project_root === projectRoot ||
|
|
71
|
+
r.path === projectRoot ||
|
|
72
|
+
r.project_root === resolved ||
|
|
73
|
+
r.path === resolved ||
|
|
74
|
+
r.project_root === normalized ||
|
|
75
|
+
r.path === normalized);
|
|
76
|
+
}
|
|
@@ -8,6 +8,12 @@ export type ModelSelection = {
|
|
|
8
8
|
/** Stage yaml / inline `model`; overrides pipeline/global. */
|
|
9
9
|
stage?: string;
|
|
10
10
|
};
|
|
11
|
+
export type ModelAuthoredTier = "stage" | "pipeline" | "global";
|
|
12
|
+
export type ResolvedModelSelection = {
|
|
13
|
+
model: string;
|
|
14
|
+
tier: ModelAuthoredTier;
|
|
15
|
+
};
|
|
16
|
+
export declare function modelAuthoredTier(selection: ModelSelection): ModelAuthoredTier;
|
|
11
17
|
/**
|
|
12
18
|
* stage > pipeline > global. No silent hardcoded fallback — unset is a load error.
|
|
13
19
|
* Present-but-empty / whitespace follows parseModelField (load failure, not "").
|
|
@@ -15,6 +21,6 @@ export type ModelSelection = {
|
|
|
15
21
|
export declare function resolveModelOutcome(selection: ModelSelection, ctx: {
|
|
16
22
|
stageId: string;
|
|
17
23
|
pipelineId: string;
|
|
18
|
-
}): LoadOutcome<
|
|
24
|
+
}): LoadOutcome<ResolvedModelSelection>;
|
|
19
25
|
/** The global tier's model id from an already-loaded manifest, or undefined when missing/unset. */
|
|
20
26
|
export declare function globalModelFromManifest(loaded: LoadedManifest | null): string | undefined;
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { loadFailure, loadSuccess } from "./loadOutcome.js";
|
|
2
2
|
import { parseModelField } from "./modelField.js";
|
|
3
|
+
export function modelAuthoredTier(selection) {
|
|
4
|
+
if (selection.stage !== undefined)
|
|
5
|
+
return "stage";
|
|
6
|
+
if (selection.pipeline !== undefined)
|
|
7
|
+
return "pipeline";
|
|
8
|
+
return "global";
|
|
9
|
+
}
|
|
3
10
|
/**
|
|
4
11
|
* stage > pipeline > global. No silent hardcoded fallback — unset is a load error.
|
|
5
12
|
* Present-but-empty / whitespace follows parseModelField (load failure, not "").
|
|
@@ -27,7 +34,10 @@ export function resolveModelOutcome(selection, ctx) {
|
|
|
27
34
|
},
|
|
28
35
|
]);
|
|
29
36
|
}
|
|
30
|
-
return loadSuccess(
|
|
37
|
+
return loadSuccess({
|
|
38
|
+
model: parsed.value,
|
|
39
|
+
tier: modelAuthoredTier(selection),
|
|
40
|
+
});
|
|
31
41
|
}
|
|
32
42
|
/** The global tier's model id from an already-loaded manifest, or undefined when missing/unset. */
|
|
33
43
|
export function globalModelFromManifest(loaded) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type StageMcpErrorCode = "missing_catalog" | "unknown_server" | "reserved_name" | "unresolved_var" | "invalid_config" | "connect_failed";
|
|
1
|
+
export type StageMcpErrorCode = "missing_catalog" | "unknown_server" | "reserved_name" | "unresolved_var" | "invalid_config" | "untrusted_config_origin" | "connect_failed";
|
|
2
2
|
export declare class StageMcpError extends Error {
|
|
3
3
|
readonly code: StageMcpErrorCode;
|
|
4
4
|
constructor(message: string, code: StageMcpErrorCode);
|
|
@@ -15,6 +15,7 @@ export type InspectedMcpCatalog = {
|
|
|
15
15
|
};
|
|
16
16
|
export declare function mcpCatalogPath(projectRoot: string): string;
|
|
17
17
|
export declare function parseMcpCatalog(raw: string, catalogPath?: string): McpCatalogServers;
|
|
18
|
+
export declare function mcpCatalogExists(projectRoot: string): Promise<boolean>;
|
|
18
19
|
export declare function loadMcpCatalog(projectRoot: string): Promise<InspectedMcpCatalog>;
|
|
19
20
|
export type ProjectMcpCatalogTransport = "stdio" | "http";
|
|
20
21
|
export type ProjectMcpCatalogEntry = {
|
|
@@ -32,4 +33,11 @@ export declare function resolveStageMcpServers(options: {
|
|
|
32
33
|
projectRoot: string;
|
|
33
34
|
allowlist?: readonly string[];
|
|
34
35
|
env: NodeJS.ProcessEnv;
|
|
36
|
+
stageId?: string;
|
|
37
|
+
bindingKind?: "repository" | "checkout" | "none";
|
|
38
|
+
trustWorkspaceConfig?: string[];
|
|
39
|
+
/** Host project root used for trust_workspace_config allowlist matching. */
|
|
40
|
+
trustProjectRoot?: string;
|
|
41
|
+
/** When true, .mcp.json is treated as workspace-sourced. */
|
|
42
|
+
workspaceSourced?: boolean;
|
|
35
43
|
}): Promise<ResolvedMcpServers>;
|
|
@@ -51,6 +51,18 @@ export function parseMcpCatalog(raw, catalogPath = MCP_CATALOG_FILENAME) {
|
|
|
51
51
|
}
|
|
52
52
|
return servers;
|
|
53
53
|
}
|
|
54
|
+
export async function mcpCatalogExists(projectRoot) {
|
|
55
|
+
try {
|
|
56
|
+
await readFile(mcpCatalogPath(projectRoot), "utf8");
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
const code = err.code;
|
|
61
|
+
if (code === "ENOENT")
|
|
62
|
+
return false;
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
54
66
|
export async function loadMcpCatalog(projectRoot) {
|
|
55
67
|
const catalogPath = mcpCatalogPath(projectRoot);
|
|
56
68
|
let raw;
|
|
@@ -108,7 +120,7 @@ export function assertMcpAllowlistKnown(servers, allowlist) {
|
|
|
108
120
|
const INTERPOLATION_TOKEN = /\$\{([^}]*)\}/g;
|
|
109
121
|
const ENV_VAR_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
110
122
|
const ENV_VAR_WITH_DEFAULT = /^([A-Za-z_][A-Za-z0-9_]*):-(.*)$/;
|
|
111
|
-
function interpolateString(value, env, serverName) {
|
|
123
|
+
function interpolateString(value, env, serverName, stageId) {
|
|
112
124
|
return value.replace(INTERPOLATION_TOKEN, (_match, inner) => {
|
|
113
125
|
const withDefault = ENV_VAR_WITH_DEFAULT.exec(inner);
|
|
114
126
|
if (withDefault) {
|
|
@@ -120,24 +132,27 @@ function interpolateString(value, env, serverName) {
|
|
|
120
132
|
if (found !== undefined) {
|
|
121
133
|
return found;
|
|
122
134
|
}
|
|
123
|
-
|
|
135
|
+
const stagePart = stageId !== undefined ? ` (stage "${stageId}")` : "";
|
|
136
|
+
throw new StageMcpError(`Unresolved MCP catalog variable "${inner}" for server "${serverName}"${stagePart}. Declare it in secrets: (use as: env for tokens needed in MCP env) or use \${${inner}:-default}.`, "unresolved_var");
|
|
124
137
|
}
|
|
125
138
|
throw new StageMcpError(`MCP catalog server "${serverName}" has an invalid interpolation form`, "invalid_config");
|
|
126
139
|
});
|
|
127
140
|
}
|
|
128
|
-
function interpolateField(key, value, env, serverName) {
|
|
141
|
+
function interpolateField(key, value, env, serverName, stageId) {
|
|
129
142
|
if ((key === "command" || key === "url" || key === "cwd") && typeof value === "string") {
|
|
130
|
-
return interpolateString(value, env, serverName);
|
|
143
|
+
return interpolateString(value, env, serverName, stageId);
|
|
131
144
|
}
|
|
132
145
|
if (key === "args" && Array.isArray(value)) {
|
|
133
|
-
return value.map((item) => typeof item === "string"
|
|
146
|
+
return value.map((item) => typeof item === "string"
|
|
147
|
+
? interpolateString(item, env, serverName, stageId)
|
|
148
|
+
: item);
|
|
134
149
|
}
|
|
135
150
|
if ((key === "env" || key === "headers") && isPlainObject(value)) {
|
|
136
151
|
const copied = {};
|
|
137
152
|
for (const [field, fieldValue] of Object.entries(value)) {
|
|
138
153
|
copied[field] =
|
|
139
154
|
typeof fieldValue === "string"
|
|
140
|
-
? interpolateString(fieldValue, env, serverName)
|
|
155
|
+
? interpolateString(fieldValue, env, serverName, stageId)
|
|
141
156
|
: fieldValue;
|
|
142
157
|
}
|
|
143
158
|
return copied;
|
|
@@ -185,10 +200,10 @@ function stampSpawnRoot(resolved, projectRoot, serverName) {
|
|
|
185
200
|
}
|
|
186
201
|
return resolved;
|
|
187
202
|
}
|
|
188
|
-
function interpolateServer(entry, env, serverName, projectRoot) {
|
|
203
|
+
function interpolateServer(entry, env, serverName, projectRoot, stageId) {
|
|
189
204
|
const resolved = {};
|
|
190
205
|
for (const [key, value] of Object.entries(entry)) {
|
|
191
|
-
resolved[key] = interpolateField(key, value, env, serverName);
|
|
206
|
+
resolved[key] = interpolateField(key, value, env, serverName, stageId);
|
|
192
207
|
}
|
|
193
208
|
return stampSpawnRoot(resolved, projectRoot, serverName);
|
|
194
209
|
}
|
|
@@ -197,11 +212,23 @@ export async function resolveStageMcpServers(options) {
|
|
|
197
212
|
if (allowlist.length === 0) {
|
|
198
213
|
return {};
|
|
199
214
|
}
|
|
215
|
+
if (options.workspaceSourced === true) {
|
|
216
|
+
const { decideWorkspaceConfigTrust } = await import("./configOrigin.js");
|
|
217
|
+
const decision = decideWorkspaceConfigTrust({
|
|
218
|
+
bindingKind: options.bindingKind ?? "none",
|
|
219
|
+
projectRoot: options.trustProjectRoot ?? options.projectRoot,
|
|
220
|
+
trustWorkspaceConfig: options.trustWorkspaceConfig,
|
|
221
|
+
source: "workspace",
|
|
222
|
+
});
|
|
223
|
+
if (!decision.allow) {
|
|
224
|
+
throw new StageMcpError(decision.message ?? "untrusted_config_origin", "untrusted_config_origin");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
200
227
|
const catalog = await loadMcpCatalog(options.projectRoot);
|
|
201
228
|
assertMcpAllowlistKnown(catalog.servers, allowlist);
|
|
202
229
|
const resolved = {};
|
|
203
230
|
for (const name of allowlist) {
|
|
204
|
-
resolved[name] = interpolateServer(catalog.servers[name], options.env, name, options.projectRoot);
|
|
231
|
+
resolved[name] = interpolateServer(catalog.servers[name], options.env, name, options.projectRoot, options.stageId);
|
|
205
232
|
}
|
|
206
233
|
return resolved;
|
|
207
234
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare class SecretFromEnvError extends Error {
|
|
2
|
+
readonly code = "config_invalid";
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Read a secret from `NAME` or `NAME_FILE`. Both set → error.
|
|
7
|
+
* File values trim exactly one trailing newline (`\n` or `\r\n`).
|
|
8
|
+
*/
|
|
9
|
+
export declare function readSecretFromEnvOrFile(env: NodeJS.ProcessEnv, name: string): string | undefined;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
export class SecretFromEnvError extends Error {
|
|
3
|
+
code = "config_invalid";
|
|
4
|
+
constructor(message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "SecretFromEnvError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Read a secret from `NAME` or `NAME_FILE`. Both set → error.
|
|
11
|
+
* File values trim exactly one trailing newline (`\n` or `\r\n`).
|
|
12
|
+
*/
|
|
13
|
+
export function readSecretFromEnvOrFile(env, name) {
|
|
14
|
+
const fileKey = `${name}_FILE`;
|
|
15
|
+
const plain = env[name];
|
|
16
|
+
const filePath = env[fileKey];
|
|
17
|
+
const hasPlain = plain !== undefined && plain.length > 0;
|
|
18
|
+
const hasFile = filePath !== undefined && filePath.length > 0;
|
|
19
|
+
if (hasPlain && hasFile) {
|
|
20
|
+
throw new SecretFromEnvError(`Set only one of ${name} or ${fileKey}, not both`);
|
|
21
|
+
}
|
|
22
|
+
if (hasFile) {
|
|
23
|
+
try {
|
|
24
|
+
return readFileSync(filePath, "utf8").replace(/\r?\n$/, "");
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
28
|
+
throw new SecretFromEnvError(`Failed to read ${fileKey}=${filePath}: ${detail}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (hasPlain)
|
|
32
|
+
return plain;
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Symbolic wire id for the packaged examples catalog root. */
|
|
2
|
+
export declare const SEEDED_EXAMPLES_ID = "examples";
|
|
3
|
+
/**
|
|
4
|
+
* Absolute path to packaged `examples/` when present next to the package root.
|
|
5
|
+
* Does not git-init; callers build CatalogContext with fixed projectRoot + manifest.
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveSeededExamplesPath(fromUrl?: string): string | undefined;
|
|
8
|
+
export declare function defaultSeededRoots(): Array<{
|
|
9
|
+
id: string;
|
|
10
|
+
path: string;
|
|
11
|
+
}>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
/** Symbolic wire id for the packaged examples catalog root. */
|
|
5
|
+
export const SEEDED_EXAMPLES_ID = "examples";
|
|
6
|
+
/**
|
|
7
|
+
* Absolute path to packaged `examples/` when present next to the package root.
|
|
8
|
+
* Does not git-init; callers build CatalogContext with fixed projectRoot + manifest.
|
|
9
|
+
*/
|
|
10
|
+
export function resolveSeededExamplesPath(fromUrl = import.meta.url) {
|
|
11
|
+
const here = path.dirname(fileURLToPath(fromUrl));
|
|
12
|
+
const candidates = [
|
|
13
|
+
path.resolve(here, "../../examples"),
|
|
14
|
+
path.resolve(here, "../../../examples"),
|
|
15
|
+
path.resolve(process.cwd(), "examples"),
|
|
16
|
+
];
|
|
17
|
+
for (const candidate of candidates) {
|
|
18
|
+
if (existsSync(path.join(candidate, "README.md"))) {
|
|
19
|
+
return candidate;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
export function defaultSeededRoots() {
|
|
25
|
+
const examples = resolveSeededExamplesPath();
|
|
26
|
+
if (examples === undefined)
|
|
27
|
+
return [];
|
|
28
|
+
return [{ id: SEEDED_EXAMPLES_ID, path: examples }];
|
|
29
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type LoadOutcome } from "./loadOutcome.js";
|
|
2
|
+
export type ToolRequirement = {
|
|
3
|
+
tool: string;
|
|
4
|
+
version?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function parseToolRequires(raw: unknown, label: string, options: {
|
|
7
|
+
code: "pipeline.invalid_requires" | "stage.invalid_requires";
|
|
8
|
+
category: "pipeline" | "stage";
|
|
9
|
+
pipelineId?: string;
|
|
10
|
+
stageId?: string;
|
|
11
|
+
}): LoadOutcome<ToolRequirement[] | undefined>;
|
|
12
|
+
/**
|
|
13
|
+
* Merge requirement lists: same tool → intersect version ranges (stricter).
|
|
14
|
+
* Non-intersecting ranges fail with pipeline.requires_conflict.
|
|
15
|
+
*/
|
|
16
|
+
export declare function mergeToolRequires(lists: Array<readonly ToolRequirement[] | undefined>, ctx: {
|
|
17
|
+
pipelineId: string;
|
|
18
|
+
label?: string;
|
|
19
|
+
}): LoadOutcome<ToolRequirement[]>;
|
|
20
|
+
export declare function collectEffectiveRequires(options: {
|
|
21
|
+
pipelineRequires?: readonly ToolRequirement[];
|
|
22
|
+
stageRequires: Array<readonly ToolRequirement[] | undefined>;
|
|
23
|
+
pipelineId: string;
|
|
24
|
+
}): LoadOutcome<ToolRequirement[]>;
|