stageflow 0.25.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -3
- package/dist/a2a/contracts.d.ts +1 -0
- package/dist/a2a/contracts.js +1 -0
- package/dist/a2a/registry.d.ts +2 -0
- package/dist/a2a/registry.js +20 -1
- package/dist/a2a/server.d.ts +7 -0
- package/dist/a2a/server.js +5 -2
- package/dist/a2a/service.d.ts +1 -1
- package/dist/a2a/service.js +57 -8
- package/dist/a2a/store.d.ts +8 -5
- package/dist/a2a/store.js +24 -67
- package/dist/agent/activity.d.ts +3 -0
- package/dist/agent/bootProviderConfig.d.ts +21 -0
- package/dist/agent/bootProviderConfig.js +74 -0
- package/dist/agent/piAdapter.d.ts +9 -1
- package/dist/agent/piAdapter.js +58 -3
- package/dist/agent/piIsolatedMcp.d.ts +2 -0
- package/dist/agent/piIsolatedMcp.js +10 -2
- package/dist/agent/port.d.ts +6 -0
- package/dist/agent/streamLogRedact.d.ts +1 -1
- package/dist/agent/streamLogRedact.js +4 -11
- package/dist/cli/artifactCommand.js +9 -16
- package/dist/cli/backupCommand.d.ts +9 -0
- package/dist/cli/backupCommand.js +111 -0
- package/dist/cli/debugRunCommand.d.ts +10 -0
- package/dist/cli/debugRunCommand.js +109 -0
- package/dist/cli/doctorCommand.d.ts +32 -0
- package/dist/cli/doctorCommand.js +453 -0
- package/dist/cli/envelopeCommand.js +9 -2
- package/dist/cli/exportAllCommand.d.ts +55 -0
- package/dist/cli/exportAllCommand.js +218 -0
- package/dist/cli/exportRunCommand.js +23 -21
- package/dist/cli/hostClient.d.ts +21 -3
- package/dist/cli/hostClient.js +93 -12
- package/dist/cli/initTemplates.d.ts +1 -1
- package/dist/cli/initTemplates.js +8 -1
- package/dist/cli/resolveSafeOutPath.d.ts +2 -0
- package/dist/cli/resolveSafeOutPath.js +40 -0
- package/dist/cli/restoreCommand.d.ts +10 -0
- package/dist/cli/restoreCommand.js +90 -0
- package/dist/cli/runCommand.d.ts +3 -2
- package/dist/cli/runCommand.js +93 -11
- package/dist/cli/runOutput.d.ts +4 -0
- package/dist/cli/runOutput.js +33 -7
- package/dist/cli/runStageCommand.d.ts +1 -0
- package/dist/cli/runStageCommand.js +44 -25
- package/dist/cli/runsCommand.d.ts +1 -1
- package/dist/cli/runsCommand.js +162 -8
- package/dist/cli.js +171 -30
- package/dist/config/catalogRelativePath.d.ts +62 -0
- package/dist/config/catalogRelativePath.js +118 -0
- package/dist/config/configOrigin.d.ts +27 -0
- package/dist/config/configOrigin.js +59 -0
- package/dist/config/hostConfig.d.ts +55 -0
- package/dist/config/hostConfig.js +333 -0
- package/dist/config/listSkills.d.ts +26 -0
- package/dist/config/listSkills.js +190 -3
- package/dist/config/loadOutcome.d.ts +1 -1
- package/dist/config/loadPipeline.js +23 -2
- package/dist/config/loadStage.js +18 -0
- package/dist/config/loadTask.d.ts +2 -0
- package/dist/config/loadTask.js +57 -18
- package/dist/config/materializeStageModels.js +5 -1
- package/dist/config/mergePipelineIncludes.d.ts +3 -0
- package/dist/config/mergePipelineIncludes.js +19 -0
- package/dist/config/migrateYaml.js +6 -11
- package/dist/config/multiProjectCatalog.d.ts +30 -0
- package/dist/config/multiProjectCatalog.js +142 -0
- package/dist/config/normalizePipelineStageEntry.js +20 -1
- package/dist/config/pipelineStageKeys.js +2 -0
- package/dist/config/resolveCatalogRoots.d.ts +27 -0
- package/dist/config/resolveCatalogRoots.js +76 -0
- package/dist/config/resolveModel.d.ts +7 -1
- package/dist/config/resolveModel.js +11 -1
- package/dist/config/resolveStageMcpServers.d.ts +9 -1
- package/dist/config/resolveStageMcpServers.js +36 -9
- package/dist/config/secretFromEnvOrFile.d.ts +9 -0
- package/dist/config/secretFromEnvOrFile.js +34 -0
- package/dist/config/seededCatalog.d.ts +11 -0
- package/dist/config/seededCatalog.js +29 -0
- package/dist/config/toolRequires.d.ts +24 -0
- package/dist/config/toolRequires.js +115 -0
- package/dist/config/validateCatalog.d.ts +5 -1
- package/dist/config/validateCatalog.js +140 -1
- package/dist/diagnostics/checks.d.ts +39 -0
- package/dist/diagnostics/checks.js +135 -0
- package/dist/errors/codes.d.ts +14 -0
- package/dist/errors/codes.js +59 -0
- package/dist/git/cache.d.ts +14 -0
- package/dist/git/cache.js +150 -0
- package/dist/git/credentials.d.ts +9 -0
- package/dist/git/credentials.js +88 -0
- package/dist/git/errors.d.ts +20 -0
- package/dist/git/errors.js +94 -0
- package/dist/git/exec.d.ts +16 -0
- package/dist/git/exec.js +135 -0
- package/dist/git/operations.d.ts +29 -0
- package/dist/git/operations.js +153 -0
- package/dist/git/version.d.ts +1 -0
- package/dist/git/version.js +10 -0
- package/dist/logging/audit.d.ts +16 -0
- package/dist/logging/audit.js +19 -0
- package/dist/logging/commonWords.d.ts +2 -0
- package/dist/logging/commonWords.js +13 -0
- package/dist/logging/logger.d.ts +49 -0
- package/dist/logging/logger.js +193 -0
- package/dist/logging/namedSecrets.d.ts +6 -0
- package/dist/logging/namedSecrets.js +58 -0
- package/dist/logging/redact.d.ts +13 -0
- package/dist/logging/redact.js +88 -0
- package/dist/mcp/catalogTools.js +456 -80
- package/dist/mcp/checkoutTools.d.ts +52 -0
- package/dist/mcp/checkoutTools.js +332 -0
- package/dist/mcp/controlTools.js +179 -5
- package/dist/mcp/deps.d.ts +1 -0
- package/dist/mcp/getStartedTool.d.ts +3 -0
- package/dist/mcp/getStartedTool.js +62 -0
- package/dist/mcp/readArtifact.d.ts +11 -0
- package/dist/mcp/readArtifact.js +46 -30
- package/dist/mcp/server.js +1 -0
- package/dist/mcp/tools.js +4 -0
- package/dist/net/proxy.d.ts +14 -0
- package/dist/net/proxy.js +78 -0
- package/dist/package-meta.d.ts +2 -1
- package/dist/package-meta.js +2 -1
- package/dist/preflight/bash.d.ts +8 -0
- package/dist/preflight/bash.js +34 -0
- package/dist/preflight/claudeRoot.d.ts +11 -0
- package/dist/preflight/claudeRoot.js +23 -0
- package/dist/preflight/mcpCommands.d.ts +8 -0
- package/dist/preflight/mcpCommands.js +36 -0
- package/dist/preflight/pipelinePreflight.d.ts +40 -0
- package/dist/preflight/pipelinePreflight.js +192 -0
- package/dist/preflight/tls.d.ts +6 -0
- package/dist/preflight/tls.js +18 -0
- package/dist/preflight/toolchain.d.ts +45 -0
- package/dist/preflight/toolchain.js +219 -0
- package/dist/project/findProjectRoot.js +3 -4
- package/dist/project/globalHome.d.ts +7 -0
- package/dist/project/globalHome.js +63 -2
- package/dist/project/resolveProjectContext.js +2 -2
- package/dist/project/resolveStageflowContext.js +2 -2
- package/dist/projection/projectRun.d.ts +2 -1
- package/dist/projection/projectRun.js +1 -0
- package/dist/runstore/assertTmpdir.d.ts +1 -0
- package/dist/runstore/assertTmpdir.js +21 -0
- package/dist/runstore/backup.d.ts +52 -0
- package/dist/runstore/backup.js +292 -0
- package/dist/runstore/createStore.d.ts +18 -1
- package/dist/runstore/createStore.js +64 -5
- package/dist/runstore/debugBundle.d.ts +60 -0
- package/dist/runstore/debugBundle.js +143 -0
- package/dist/runstore/diskUsage.d.ts +50 -0
- package/dist/runstore/diskUsage.js +214 -0
- package/dist/runstore/exportRunPayload.d.ts +8 -0
- package/dist/runstore/exportRunPayload.js +23 -0
- package/dist/runstore/normalizeCatalogPath.d.ts +1 -0
- package/dist/runstore/normalizeCatalogPath.js +10 -0
- package/dist/runstore/paths.d.ts +5 -0
- package/dist/runstore/paths.js +145 -1
- package/dist/runstore/port.d.ts +111 -13
- package/dist/runstore/port.js +8 -1
- package/dist/runstore/restore.d.ts +81 -0
- package/dist/runstore/restore.js +355 -0
- package/dist/runstore/retention.d.ts +27 -0
- package/dist/runstore/retention.js +74 -0
- package/dist/runstore/runManifest.d.ts +146 -0
- package/dist/runstore/runManifest.js +288 -0
- package/dist/runstore/runProjection.d.ts +3 -1
- package/dist/runstore/runProjection.js +63 -1
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +28 -3
- package/dist/runstore/sqlite/SqliteRunStore.js +352 -219
- package/dist/runstore/sqlite/applyStorePragmas.d.ts +39 -0
- package/dist/runstore/sqlite/applyStorePragmas.js +145 -0
- package/dist/runstore/sqlite/migrations/001-baseline.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/001-baseline.js +10 -0
- package/dist/runstore/sqlite/migrations/002-repository-binding.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/002-repository-binding.js +29 -0
- package/dist/runstore/sqlite/migrations/003-run-lifecycle.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/003-run-lifecycle.js +28 -0
- package/dist/runstore/sqlite/migrations/004-auto-resume-count.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/004-auto-resume-count.js +19 -0
- package/dist/runstore/sqlite/migrations/005-config-origins.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/005-config-origins.js +19 -0
- package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.js +28 -0
- package/dist/runstore/sqlite/migrations/007-projects-registry.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/007-projects-registry.js +31 -0
- package/dist/runstore/sqlite/migrations/index.d.ts +21 -0
- package/dist/runstore/sqlite/migrations/index.js +72 -0
- package/dist/runstore/sqlite/schema.d.ts +20 -1
- package/dist/runstore/sqlite/schema.js +277 -1
- package/dist/runstore/sqlite/storeOpenError.d.ts +6 -0
- package/dist/runstore/sqlite/storeOpenError.js +11 -0
- package/dist/runstore/sqlite/storeSchemaError.d.ts +5 -0
- package/dist/runstore/sqlite/storeSchemaError.js +8 -0
- package/dist/runstore/stageExecution.js +3 -0
- package/dist/runstore/storeFilesystem.d.ts +32 -0
- package/dist/runstore/storeFilesystem.js +148 -0
- package/dist/runstore/trackProjection.js +2 -0
- package/dist/runstore/workspaceLayout.d.ts +13 -0
- package/dist/runstore/workspaceLayout.js +76 -0
- package/dist/runtime/completionCheckRunner.d.ts +3 -0
- package/dist/runtime/completionCheckRunner.js +45 -7
- package/dist/runtime/containerLimits.d.ts +16 -0
- package/dist/runtime/containerLimits.js +84 -0
- package/dist/runtime/credentialMaterialisation.d.ts +28 -0
- package/dist/runtime/credentialMaterialisation.js +128 -0
- package/dist/runtime/gitCheckoutCapability.js +7 -13
- package/dist/runtime/pipelineRunner.d.ts +36 -1
- package/dist/runtime/pipelineRunner.js +178 -17
- package/dist/runtime/pipelineScheduler.d.ts +15 -0
- package/dist/runtime/pipelineScheduler.js +135 -27
- package/dist/runtime/reloadRunCatalog.js +6 -1
- package/dist/runtime/repositoryMaterialize.d.ts +47 -0
- package/dist/runtime/repositoryMaterialize.js +235 -0
- package/dist/runtime/resumeTimedOut.d.ts +1 -1
- package/dist/runtime/resumeTimedOut.js +5 -2
- package/dist/runtime/runChangeBus.js +9 -0
- package/dist/runtime/runDeletion.d.ts +7 -0
- package/dist/runtime/runDeletion.js +37 -0
- package/dist/runtime/runManager.d.ts +158 -4
- package/dist/runtime/runManager.js +1596 -79
- package/dist/runtime/runRetentionSweep.d.ts +31 -0
- package/dist/runtime/runRetentionSweep.js +328 -0
- package/dist/runtime/runRetryCoordinator.d.ts +2 -0
- package/dist/runtime/runRetryCoordinator.js +19 -2
- package/dist/runtime/runSkills.d.ts +40 -0
- package/dist/runtime/runSkills.js +173 -0
- package/dist/runtime/stageAttemptBootstrap.d.ts +5 -1
- package/dist/runtime/stageAttemptBootstrap.js +195 -24
- package/dist/runtime/stageCacheEnv.d.ts +6 -0
- package/dist/runtime/stageCacheEnv.js +34 -0
- package/dist/runtime/stageConcurrency.d.ts +2 -1
- package/dist/runtime/stageConcurrency.js +4 -2
- package/dist/runtime/stageEnvironment.d.ts +38 -0
- package/dist/runtime/stageEnvironment.js +193 -0
- package/dist/runtime/stageProcessLauncher.d.ts +18 -0
- package/dist/runtime/stageProcessLauncher.js +194 -38
- package/dist/runtime/stageRecovery.d.ts +3 -1
- package/dist/runtime/stageRecovery.js +19 -4
- package/dist/runtime/stageRoots.d.ts +38 -1
- package/dist/runtime/stageRoots.js +118 -0
- package/dist/runtime/stageRunner.d.ts +1 -0
- package/dist/runtime/stageRunner.js +3 -1
- package/dist/runtime/stageSecretDecl.d.ts +9 -0
- package/dist/runtime/stageSecretDecl.js +102 -0
- package/dist/runtime/stageSecrets.d.ts +40 -0
- package/dist/runtime/stageSecrets.js +181 -0
- package/dist/runtime/stageWorker.d.ts +3 -2
- package/dist/runtime/stageWorker.js +58 -10
- package/dist/runtime/stageWorkerProtocol.d.ts +5 -0
- package/dist/runtime/stageWorkerProtocol.js +8 -0
- package/dist/runtime/startPayload.d.ts +32 -0
- package/dist/runtime/startPayload.js +59 -0
- package/dist/runtime/taskInput.js +14 -5
- package/dist/runtime/verifiedStageExecution.d.ts +1 -0
- package/dist/runtime/verifiedStageExecution.js +2 -1
- package/dist/runtime/workspaceBinding.d.ts +20 -0
- package/dist/runtime/workspaceBinding.js +60 -0
- package/dist/server/allowedHosts.d.ts +19 -0
- package/dist/server/allowedHosts.js +179 -0
- package/dist/server/bootstrap.d.ts +36 -2
- package/dist/server/bootstrap.js +209 -5
- package/dist/server/controlToken.d.ts +47 -0
- package/dist/server/controlToken.js +241 -0
- package/dist/server/createHttpHost.d.ts +11 -2
- package/dist/server/createHttpHost.js +103 -10
- package/dist/server/ensureGlobalService.d.ts +5 -1
- package/dist/server/ensureGlobalService.js +35 -1
- package/dist/server/healthSurfaces.d.ts +6 -0
- package/dist/server/healthSurfaces.js +98 -0
- package/dist/server/http.d.ts +12 -1
- package/dist/server/http.js +1085 -485
- package/dist/server/listenHost.d.ts +5 -0
- package/dist/server/listenHost.js +56 -0
- package/dist/server/mcpHost.d.ts +10 -1
- package/dist/server/mcpHost.js +36 -6
- package/dist/server/operatorResults.d.ts +2 -2
- package/dist/server/operatorResults.js +40 -29
- package/dist/server/requestAuthContext.d.ts +12 -0
- package/dist/server/requestAuthContext.js +21 -0
- package/dist/server/shutdown.d.ts +69 -0
- package/dist/server/shutdown.js +219 -0
- package/dist/types/pipeline.d.ts +7 -0
- package/dist/types/stage.d.ts +8 -0
- package/dist/types/task.d.ts +8 -0
- package/dist/ui/assets/index-B6hlSXXn.js +120 -0
- package/dist/ui/index.html +1 -1
- package/examples/README.md +98 -0
- package/examples/archify-on-pr/README.md +213 -0
- package/examples/archify-on-pr/archify-on-pr.pipeline.yaml +19 -0
- package/examples/archify-on-pr/archify-on-pr.task.yaml +19 -0
- package/examples/archify-on-pr/author-diagrams.yaml +106 -0
- package/examples/archify-on-pr/detect-changes.yaml +89 -0
- package/examples/ci-validate/README.md +35 -0
- package/examples/ci-validate/check.yaml +13 -0
- package/examples/ci-validate/ci-demo.pipeline.yaml +4 -0
- package/examples/ci-validate/validate.sh +5 -0
- package/examples/compliance-review-demo/README.md +125 -0
- package/examples/compliance-review-demo/compliance-review-demo.pipeline.yaml +29 -0
- package/examples/compliance-review-demo/connect-account.yaml +47 -0
- package/examples/compliance-review-demo/map-to-control.yaml +123 -0
- package/examples/compliance-review-demo/poll-bucket-config.yaml +103 -0
- package/examples/compliance-review-demo/publish-report.yaml +79 -0
- package/examples/compliance-review-demo/review-verdict.yaml +122 -0
- package/examples/compliance-review-demo/run-compliance-check.yaml +96 -0
- package/examples/compliance-review-demo/store-evidence.yaml +143 -0
- package/examples/conditional-fork/README.md +89 -0
- package/examples/conditional-fork/branch-a.yaml +13 -0
- package/examples/conditional-fork/branch-b.yaml +13 -0
- package/examples/conditional-fork/decide.yaml +35 -0
- package/examples/conditional-fork/fork-demo.pipeline.yaml +20 -0
- package/examples/conditional-fork/fork-demo.task.yaml +8 -0
- package/examples/context7-mcp/README.md +42 -0
- package/examples/context7-mcp/context7-mcp.pipeline.yaml +15 -0
- package/examples/context7-mcp/context7-mcp.task.yaml +4 -0
- package/examples/context7-mcp/fetch-docs.yaml +52 -0
- package/examples/context7-mcp/resolve-library.yaml +31 -0
- package/examples/context7-mcp/write-brief.yaml +52 -0
- package/examples/feature-loop/README.md +104 -0
- package/examples/feature-loop/address-feedback.yaml +148 -0
- package/examples/feature-loop/align.yaml +116 -0
- package/examples/feature-loop/decompose.yaml +86 -0
- package/examples/feature-loop/default-model-hierarchy.task.yaml +58 -0
- package/examples/feature-loop/feature-loop.pipeline.yaml +140 -0
- package/examples/feature-loop/feature-loop.task.yaml +25 -0
- package/examples/feature-loop/implement.yaml +128 -0
- package/examples/feature-loop/plan.yaml +111 -0
- package/examples/feature-loop/publish.yaml +167 -0
- package/examples/feature-loop/review.yaml +146 -0
- package/examples/feature-loop/verify.yaml +106 -0
- package/examples/feedback-loop/README.md +72 -0
- package/examples/feedback-loop/VERIFY.md +208 -0
- package/examples/feedback-loop/continue-only.task.yaml +4 -0
- package/examples/feedback-loop/exhaust-require-continue.task.yaml +6 -0
- package/examples/feedback-loop/exhaust-wait-human.task.yaml +11 -0
- package/examples/feedback-loop/feedback-loop-wait-human.pipeline.yaml +23 -0
- package/examples/feedback-loop/feedback-loop.pipeline.yaml +23 -0
- package/examples/feedback-loop/feedback-loop.task.yaml +4 -0
- package/examples/feedback-loop/implement.yaml +14 -0
- package/examples/feedback-loop/plan.yaml +14 -0
- package/examples/feedback-loop/review.yaml +15 -0
- package/examples/feedback-loop/send-back-once.task.yaml +6 -0
- package/examples/feedback-loop/submit.yaml +12 -0
- package/examples/generic-fan-in/README.md +151 -0
- package/examples/generic-fan-in/clarify.yaml +18 -0
- package/examples/generic-fan-in/generic-fan-in-accepted.pipeline.yaml +19 -0
- package/examples/generic-fan-in/generic-fan-in-accepted.task.yaml +8 -0
- package/examples/generic-fan-in/generic-fan-in.pipeline.yaml +18 -0
- package/examples/generic-fan-in/generic-fan-in.task.yaml +9 -0
- package/examples/generic-fan-in/research.yaml +45 -0
- package/examples/generic-fan-in/synthesize.yaml +66 -0
- package/examples/generic-fan-in/validation.yaml +45 -0
- package/examples/github-release/README.md +78 -0
- package/examples/github-release/draft-release-notes.yaml +64 -0
- package/examples/github-release/github-release.pipeline.yaml +11 -0
- package/examples/github-release/github-release.task.yaml +13 -0
- package/examples/github-release/publish-github-release.yaml +64 -0
- package/examples/hello-world/README.md +28 -0
- package/examples/hello-world/hello.pipeline.yaml +4 -0
- package/examples/hello-world/my-task.task.yaml +6 -0
- package/examples/hello-world/research.yaml +18 -0
- package/examples/mcp-hitl-tour/README.md +113 -0
- package/examples/mcp-hitl-tour/draft-angle.yaml +33 -0
- package/examples/mcp-hitl-tour/draft-short.yaml +32 -0
- package/examples/mcp-hitl-tour/emit-angles.yaml +45 -0
- package/examples/mcp-hitl-tour/gather.yaml +31 -0
- package/examples/mcp-hitl-tour/intake.yaml +62 -0
- package/examples/mcp-hitl-tour/mcp-hitl-tour-exhaust.task.yaml +13 -0
- package/examples/mcp-hitl-tour/mcp-hitl-tour.pipeline.yaml +54 -0
- package/examples/mcp-hitl-tour/mcp-hitl-tour.task.yaml +16 -0
- package/examples/mcp-hitl-tour/polish.yaml +33 -0
- package/examples/mcp-hitl-tour/review.yaml +17 -0
- package/examples/mcp-hitl-tour/ship.yaml +25 -0
- package/examples/oss-issue-contribution/README.md +218 -0
- package/examples/oss-issue-contribution/oss-address-review-feedback.yaml +117 -0
- package/examples/oss-issue-contribution/oss-approve-contribution.yaml +181 -0
- package/examples/oss-issue-contribution/oss-approve-plan.yaml +111 -0
- package/examples/oss-issue-contribution/oss-explain-fix.yaml +108 -0
- package/examples/oss-issue-contribution/oss-explain-issue.yaml +114 -0
- package/examples/oss-issue-contribution/oss-implement-source-fix.yaml +171 -0
- package/examples/oss-issue-contribution/oss-investigate-area.yaml +116 -0
- package/examples/oss-issue-contribution/oss-issue-contribution.pipeline.yaml +125 -0
- package/examples/oss-issue-contribution/oss-issue-intake.yaml +106 -0
- package/examples/oss-issue-contribution/oss-plan-investigation.yaml +112 -0
- package/examples/oss-issue-contribution/oss-plan-review.yaml +109 -0
- package/examples/oss-issue-contribution/oss-reproduce-issue.yaml +140 -0
- package/examples/oss-issue-contribution/oss-review-change.yaml +107 -0
- package/examples/oss-issue-contribution/oss-verify-fix.yaml +130 -0
- package/examples/oss-issue-contribution/oss-write-regression-test.yaml +135 -0
- package/examples/oss-issue-contribution/pi-7629.task.yaml +79 -0
- package/examples/oss-issue-contribution/pi-8919.task.yaml +75 -0
- package/examples/oss-issue-contribution/pydantic-ai-7971.task.yaml +53 -0
- package/examples/oss-quick-fix/README.md +65 -0
- package/examples/oss-quick-fix/implement-fix.yaml +84 -0
- package/examples/oss-quick-fix/oss-quick-fix.pipeline.yaml +35 -0
- package/examples/oss-quick-fix/oss-quick-fix.task.yaml +19 -0
- package/examples/oss-quick-fix/ship-fix.yaml +81 -0
- package/examples/oss-quick-fix/understand-issue.yaml +67 -0
- package/examples/oss-quick-fix/verify-fix.yaml +73 -0
- package/examples/plan-review/README.md +37 -0
- package/examples/plan-review/plan-review-followup.yaml +13 -0
- package/examples/plan-review/plan-review.pipeline.yaml +9 -0
- package/examples/plan-review/plan-review.task.yaml +9 -0
- package/examples/plan-review/plan-review.yaml +25 -0
- package/examples/playwright-mcp/README.md +39 -0
- package/examples/playwright-mcp/playwright-mcp.pipeline.yaml +5 -0
- package/examples/playwright-mcp/playwright-mcp.task.yaml +4 -0
- package/examples/playwright-mcp/screenshot.yaml +40 -0
- package/examples/retry-tour/README.md +75 -0
- package/examples/retry-tour/retry-tour.pipeline.yaml +122 -0
- package/examples/retry-tour/retry-tour.task.yaml +9 -0
- package/examples/route-if-tour/README.md +202 -0
- package/examples/route-if-tour/route-if-tour.pipeline.yaml +950 -0
- package/examples/route-if-tour/route-if-tour.task.yaml +4 -0
- package/examples/route-wiring-smoke-test/01-core-routing.pipeline.yaml +168 -0
- package/examples/route-wiring-smoke-test/02-on-gating.pipeline.yaml +44 -0
- package/examples/route-wiring-smoke-test/03-two-entry-points.pipeline.yaml +28 -0
- package/examples/route-wiring-smoke-test/04-entry-false-equivalent-to-omitted.pipeline.yaml +27 -0
- package/examples/route-wiring-smoke-test/05-fork-choice.pipeline.yaml +110 -0
- package/examples/route-wiring-smoke-test/06-fan-out-fan-in.pipeline.yaml +82 -0
- package/examples/route-wiring-smoke-test/07-loop-human-decision.pipeline.yaml +82 -0
- package/examples/route-wiring-smoke-test/08-skip-fallback-and-multi-on-gate.pipeline.yaml +77 -0
- package/examples/route-wiring-smoke-test/09-multi-loop-targets.pipeline.yaml +102 -0
- package/examples/route-wiring-smoke-test/10-uses-dialect-fork.pipeline.yaml +23 -0
- package/examples/route-wiring-smoke-test/11-sequential-io-handoff.pipeline.yaml +37 -0
- package/examples/route-wiring-smoke-test/12-complex-io-schemas.pipeline.yaml +138 -0
- package/examples/route-wiring-smoke-test/13-ref-io-handoff.pipeline.yaml +84 -0
- package/examples/route-wiring-smoke-test/14-if-eq-gating.pipeline.yaml +50 -0
- package/examples/route-wiring-smoke-test/15-if-all-gated.pipeline.yaml +37 -0
- package/examples/route-wiring-smoke-test/16-if-composition.pipeline.yaml +65 -0
- package/examples/route-wiring-smoke-test/17-if-join.pipeline.yaml +80 -0
- package/examples/route-wiring-smoke-test/README.md +377 -0
- package/examples/route-wiring-smoke-test/rejected/01-reject-legacy-needs.pipeline.yaml +26 -0
- package/examples/route-wiring-smoke-test/rejected/02-reject-legacy-fork.pipeline.yaml +25 -0
- package/examples/route-wiring-smoke-test/rejected/03-reject-legacy-feedback-loop.pipeline.yaml +30 -0
- package/examples/route-wiring-smoke-test/rejected/04-reject-missing-entry.pipeline.yaml +24 -0
- package/examples/route-wiring-smoke-test/rejected/05-reject-unreachable.pipeline.yaml +35 -0
- package/examples/route-wiring-smoke-test/rejected/06-reject-allow-none-without-route-select.pipeline.yaml +37 -0
- package/examples/route-wiring-smoke-test/rejected/07-reject-cycle.pipeline.yaml +27 -0
- package/examples/route-wiring-smoke-test/rejected/08-reject-loop-non-ancestor.pipeline.yaml +42 -0
- package/examples/route-wiring-smoke-test/rejected/09-reject-route-select-leaf.pipeline.yaml +26 -0
- package/examples/route-wiring-smoke-test/rejected/12-reject-loop-replay-unsafe.pipeline.yaml +55 -0
- package/examples/route-wiring-smoke-test/rejected/13-reject-multiple-loop-entries.pipeline.yaml +51 -0
- package/examples/route-wiring-smoke-test/rejected/14-reject-duplicate-stage-id.pipeline.yaml +35 -0
- package/examples/route-wiring-smoke-test/rejected/15-reject-unknown-route-target.pipeline.yaml +15 -0
- package/examples/route-wiring-smoke-test/rejected/16-reject-malformed-route-item.pipeline.yaml +15 -0
- package/examples/route-wiring-smoke-test/rejected/17-reject-io-incompatible.pipeline.yaml +33 -0
- package/examples/route-wiring-smoke-test/rejected/18-reject-nested-io.pipeline.yaml +51 -0
- package/examples/route-wiring-smoke-test/rejected/19-reject-array-item-io.pipeline.yaml +55 -0
- package/examples/route-wiring-smoke-test/rejected/20-reject-closed-io.pipeline.yaml +36 -0
- package/examples/route-wiring-smoke-test/rejected/21-reject-ref-io.pipeline.yaml +42 -0
- package/examples/route-wiring-smoke-test/rejected/22-reject-if-unknown-field.pipeline.yaml +33 -0
- package/examples/route-wiring-smoke-test/rejected/23-reject-if-optional-field.pipeline.yaml +32 -0
- package/examples/route-wiring-smoke-test/rejected/24-reject-if-empty-all.pipeline.yaml +31 -0
- package/examples/route-wiring-smoke-test/rejected/25-reject-if-gt-on-string.pipeline.yaml +33 -0
- package/examples/route-wiring-smoke-test/rejected/26-reject-if-optional-nested.pipeline.yaml +36 -0
- package/examples/route-wiring-smoke-test/rejected/27-reject-if-on-loop.pipeline.yaml +63 -0
- package/examples/route-wiring-smoke-test/rejected/29-reject-if-on-failed.pipeline.yaml +46 -0
- package/examples/route-wiring-smoke-test/smoke-test.task.yaml +4 -0
- package/examples/route-wiring-smoke-test/stages/branch-a.yaml +12 -0
- package/examples/route-wiring-smoke-test/stages/branch-b.yaml +12 -0
- package/examples/route-wiring-smoke-test/stages/decide.yaml +12 -0
- package/examples/route-wiring-smoke-test/stages/finish.yaml +12 -0
- package/examples/ship-feature/README.md +190 -0
- package/examples/ship-feature/feat-address-feedback.yaml +119 -0
- package/examples/ship-feature/feat-implement.yaml +180 -0
- package/examples/ship-feature/feat-plan.yaml +120 -0
- package/examples/ship-feature/feat-review.yaml +109 -0
- package/examples/ship-feature/feat-ship.yaml +203 -0
- package/examples/ship-feature/ship-feature.pipeline.yaml +44 -0
- package/examples/ship-feature/ship-feature.task.yaml +78 -0
- package/examples/stage-mcp/README.md +144 -0
- package/examples/stage-mcp/echo-mcp.mjs +20 -0
- package/examples/stage-mcp/stage-mcp-dead.pipeline.yaml +5 -0
- package/examples/stage-mcp/stage-mcp-dead.task.yaml +3 -0
- package/examples/stage-mcp/stage-mcp-missing-var.pipeline.yaml +5 -0
- package/examples/stage-mcp/stage-mcp-missing-var.task.yaml +3 -0
- package/examples/stage-mcp/stage-mcp.pipeline.yaml +5 -0
- package/examples/stage-mcp/stage-mcp.task.yaml +4 -0
- package/examples/stage-mcp/use-echo.yaml +20 -0
- package/examples/verify-tour/README.md +80 -0
- package/examples/verify-tour/verify-tour.pipeline.yaml +162 -0
- package/examples/verify-tour/verify-tour.task.yaml +11 -0
- package/package.json +5 -1
- package/skills/stageflow/SKILL.md +6 -6
- package/skills/stageflow/references/control-surface.md +11 -5
- package/skills/stageflow/scripts/detect-host.mjs +14 -1
- package/skills/stageflow/scripts/detect-host.test.mjs +29 -1
- package/skills/stageflow-author/SKILL.md +4 -3
- package/skills/stageflow-author/references/catalog-mapping.md +16 -0
- package/skills/stageflow-author/references/catalog-write-conventions.md +1 -1
- package/skills/stageflow-run/SKILL.md +20 -12
- package/skills/stageflow-run/references/mcp-call.md +9 -1
- package/skills/stageflow-run/references/task-and-pipeline-selection.md +16 -5
- package/skills/stageflow-run/scripts/mcp-call.mjs +46 -6
- package/skills/stageflow-run/scripts/mcp-call.test.mjs +64 -0
- package/skills/stageflow-session-capture/references/catalog-authoring.md +2 -0
- package/skills/stageflow-setup/SKILL.md +40 -8
- package/dist/ui/assets/index-Da5EHU6M.js +0 -119
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export declare class HostConfigError extends Error {
|
|
2
|
+
readonly code: "config_unknown_key" | "config_invalid";
|
|
3
|
+
readonly key?: string;
|
|
4
|
+
constructor(message: string, code: "config_unknown_key" | "config_invalid", key?: string);
|
|
5
|
+
}
|
|
6
|
+
/** Env keys that are known STAGEFLOW_* (or dynamic families) so unknown-key check accepts them. */
|
|
7
|
+
export declare const KNOWN_STAGEFLOW_ENV_KEYS: Set<string>;
|
|
8
|
+
/** Per-caller concurrent-active quota from host `callers:` config. */
|
|
9
|
+
export type CallerQuotaConfig = {
|
|
10
|
+
maxConcurrent: number;
|
|
11
|
+
};
|
|
12
|
+
export type HostConfig = {
|
|
13
|
+
maxConcurrentRuns: number;
|
|
14
|
+
maxConcurrentRunsPerProject: number | undefined;
|
|
15
|
+
maxQueued: number;
|
|
16
|
+
requireProviders: string[];
|
|
17
|
+
trustWorkspaceConfig: string[];
|
|
18
|
+
allowUnknownConfig: boolean;
|
|
19
|
+
controlToken: string | undefined;
|
|
20
|
+
readToken: string | undefined;
|
|
21
|
+
/** caller_id → quota; empty when unset. */
|
|
22
|
+
callers: Record<string, CallerQuotaConfig>;
|
|
23
|
+
/** Absolute path of config.yaml when loaded; undefined if absent. */
|
|
24
|
+
configFilePath: string | undefined;
|
|
25
|
+
warnings: string[];
|
|
26
|
+
/** True when maxConcurrentRuns came from override, env, or file (not bare default). */
|
|
27
|
+
maxConcurrentRunsExplicit: boolean;
|
|
28
|
+
};
|
|
29
|
+
export type HostConfigOverrides = {
|
|
30
|
+
maxConcurrentRuns?: number;
|
|
31
|
+
};
|
|
32
|
+
export type HostConfigSecretsEcho = {
|
|
33
|
+
controlToken: "set" | "unset";
|
|
34
|
+
readToken: "set" | "unset";
|
|
35
|
+
};
|
|
36
|
+
export type HostConfigPublicEcho = {
|
|
37
|
+
maxConcurrentRuns: number;
|
|
38
|
+
maxConcurrentRunsPerProject: number | undefined;
|
|
39
|
+
maxQueued: number;
|
|
40
|
+
requireProviders: string[];
|
|
41
|
+
trustWorkspaceConfig: string[];
|
|
42
|
+
allowUnknownConfig: boolean;
|
|
43
|
+
callers: Record<string, CallerQuotaConfig>;
|
|
44
|
+
secrets: HostConfigSecretsEcho;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Assemble HostConfig once at boot. Precedence: overrides (CLI flags) > env > file > default.
|
|
48
|
+
*/
|
|
49
|
+
export declare function loadHostConfig(options?: {
|
|
50
|
+
env?: NodeJS.ProcessEnv;
|
|
51
|
+
homeDir?: string;
|
|
52
|
+
overrides?: HostConfigOverrides;
|
|
53
|
+
configFilePath?: string | null;
|
|
54
|
+
}): HostConfig;
|
|
55
|
+
export declare function redactHostConfig(config: HostConfig): HostConfigPublicEcho;
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parse as parseYaml } from "yaml";
|
|
4
|
+
import { globalStageflowHome } from "../project/globalHome.js";
|
|
5
|
+
import { readSecretFromEnvOrFile } from "./secretFromEnvOrFile.js";
|
|
6
|
+
export class HostConfigError extends Error {
|
|
7
|
+
code;
|
|
8
|
+
key;
|
|
9
|
+
constructor(message, code, key) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "HostConfigError";
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.key = key;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** Env keys that are known STAGEFLOW_* (or dynamic families) so unknown-key check accepts them. */
|
|
17
|
+
export const KNOWN_STAGEFLOW_ENV_KEYS = new Set([
|
|
18
|
+
"STAGEFLOW_HOME",
|
|
19
|
+
"STAGEFLOW_BIND",
|
|
20
|
+
"STAGEFLOW_ALLOWED_HOSTS",
|
|
21
|
+
"STAGEFLOW_CONTROL_TOKEN",
|
|
22
|
+
"STAGEFLOW_CONTROL_TOKEN_FILE",
|
|
23
|
+
"STAGEFLOW_READ_TOKEN",
|
|
24
|
+
"STAGEFLOW_READ_TOKEN_FILE",
|
|
25
|
+
"STAGEFLOW_ALLOW_UNKNOWN_CONFIG",
|
|
26
|
+
"STAGEFLOW_MAX_CONCURRENT_RUNS",
|
|
27
|
+
"STAGEFLOW_MAX_CONCURRENT_RUNS_PER_PROJECT",
|
|
28
|
+
"STAGEFLOW_MAX_QUEUED",
|
|
29
|
+
"STAGEFLOW_REQUIRE_PROVIDERS",
|
|
30
|
+
"STAGEFLOW_A2A_CONFIG",
|
|
31
|
+
"STAGEFLOW_ACTIVITY_TEXT_LIMIT",
|
|
32
|
+
"STAGEFLOW_ACTIVITY_VERBOSE",
|
|
33
|
+
"STAGEFLOW_CURSOR_EXTENSION",
|
|
34
|
+
"STAGEFLOW_NO_OPEN",
|
|
35
|
+
"STAGEFLOW_OPERATOR_CWD",
|
|
36
|
+
"STAGEFLOW_OPERATOR_AGENT_DIR",
|
|
37
|
+
"STAGEFLOW_LEGACY_YAML",
|
|
38
|
+
"STAGEFLOW_LOG_FORMAT",
|
|
39
|
+
"STAGEFLOW_LOG_LEVEL",
|
|
40
|
+
"STAGEFLOW_LOG_MAX_LINE_BYTES",
|
|
41
|
+
"STAGEFLOW_MCP_STATELESS",
|
|
42
|
+
"STAGEFLOW_DISK_WARN_BYTES",
|
|
43
|
+
"STAGEFLOW_MIN_FREE_DISK_BYTES",
|
|
44
|
+
"STAGEFLOW_BARE_CACHE_TTL_MS",
|
|
45
|
+
"STAGEFLOW_SLIM_ARTIFACT_MAX_BYTES",
|
|
46
|
+
"STAGEFLOW_SQLITE_BUSY_TIMEOUT_MS",
|
|
47
|
+
"STAGEFLOW_RUN_BRANCH_TEMPLATE",
|
|
48
|
+
"STAGEFLOW_AUTO_RESUME_INTERRUPTED",
|
|
49
|
+
"STAGEFLOW_MAX_AUTO_RESUMES",
|
|
50
|
+
"STAGEFLOW_RETRY_ROOT_WAIT_TIMEOUT_MS",
|
|
51
|
+
"STAGEFLOW_MAX_ACTIVE_STAGES_PER_RUN",
|
|
52
|
+
"STAGEFLOW_MAX_ACTIVE_STAGE_PROCESSES",
|
|
53
|
+
"STAGEFLOW_STAGE_EXECUTION",
|
|
54
|
+
"STAGEFLOW_STAGE_ENV_ALLOW",
|
|
55
|
+
"STAGEFLOW_STAGE_ENV_PASSTHROUGH",
|
|
56
|
+
"STAGEFLOW_GC_INTERVAL_MS",
|
|
57
|
+
"STAGEFLOW_MAX_CONNECTIONS",
|
|
58
|
+
"STAGEFLOW_REQUEST_TIMEOUT_MS",
|
|
59
|
+
"STAGEFLOW_AUTOSTART_TIMEOUT_MS",
|
|
60
|
+
"STAGEFLOW_NO_AUTOSTART",
|
|
61
|
+
"STAGEFLOW_SERVICE_PORT",
|
|
62
|
+
"STAGEFLOW_SHUTDOWN_GRACE_MS",
|
|
63
|
+
"STAGEFLOW_TOOLCHAIN_MANIFEST",
|
|
64
|
+
"STAGEFLOW_SECRET_REGISTRY",
|
|
65
|
+
"STAGEFLOW_BUILD_SHA",
|
|
66
|
+
]);
|
|
67
|
+
const KNOWN_ENV_PREFIXES = [
|
|
68
|
+
"STAGEFLOW_PROVIDER_",
|
|
69
|
+
"STAGEFLOW_SLIM_",
|
|
70
|
+
"STAGEFLOW_PURGE_",
|
|
71
|
+
"STAGEFLOW_CONTROL_TOKEN_",
|
|
72
|
+
];
|
|
73
|
+
const FILE_KEY_TO_FIELD = {
|
|
74
|
+
max_concurrent_runs: "maxConcurrentRuns",
|
|
75
|
+
max_concurrent_runs_per_project: "maxConcurrentRunsPerProject",
|
|
76
|
+
max_queued: "maxQueued",
|
|
77
|
+
require_providers: "requireProviders",
|
|
78
|
+
trust_workspace_config: "trustWorkspaceConfig",
|
|
79
|
+
allow_unknown_config: "allowUnknownConfig",
|
|
80
|
+
callers: "callers",
|
|
81
|
+
};
|
|
82
|
+
const DEFAULT_MAX_CONCURRENT = 3;
|
|
83
|
+
const DEFAULT_MAX_QUEUED = 32;
|
|
84
|
+
function isKnownStageflowEnvKey(key) {
|
|
85
|
+
if (KNOWN_STAGEFLOW_ENV_KEYS.has(key))
|
|
86
|
+
return true;
|
|
87
|
+
return KNOWN_ENV_PREFIXES.some((prefix) => key.startsWith(prefix));
|
|
88
|
+
}
|
|
89
|
+
function parsePositiveInt(raw, key, opts) {
|
|
90
|
+
const n = Number.parseInt(raw, 10);
|
|
91
|
+
const min = opts?.allowZero ? 0 : 1;
|
|
92
|
+
if (!Number.isFinite(n) || n < min || String(n) !== raw.trim()) {
|
|
93
|
+
throw new HostConfigError(`Invalid value for ${key}: ${JSON.stringify(raw)}`, "config_invalid", key);
|
|
94
|
+
}
|
|
95
|
+
return n;
|
|
96
|
+
}
|
|
97
|
+
function parseStringList(raw) {
|
|
98
|
+
return raw
|
|
99
|
+
.split(",")
|
|
100
|
+
.map((s) => s.trim())
|
|
101
|
+
.filter((s) => s.length > 0);
|
|
102
|
+
}
|
|
103
|
+
function parseBool(raw, key) {
|
|
104
|
+
const normalized = raw.trim().toLowerCase();
|
|
105
|
+
if (normalized === "1" || normalized === "true")
|
|
106
|
+
return true;
|
|
107
|
+
if (normalized === "0" || normalized === "false" || normalized === "") {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
throw new HostConfigError(`Invalid boolean for ${key}: ${JSON.stringify(raw)}`, "config_invalid", key);
|
|
111
|
+
}
|
|
112
|
+
function assertUnknownEnvKeys(env, allowUnknown, warnings) {
|
|
113
|
+
for (const key of Object.keys(env)) {
|
|
114
|
+
if (!key.startsWith("STAGEFLOW_"))
|
|
115
|
+
continue;
|
|
116
|
+
if (isKnownStageflowEnvKey(key))
|
|
117
|
+
continue;
|
|
118
|
+
const message = `Unknown environment variable ${key}`;
|
|
119
|
+
if (allowUnknown) {
|
|
120
|
+
warnings.push(message);
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
throw new HostConfigError(message, "config_unknown_key", key);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function loadFileLayers(filePath) {
|
|
127
|
+
const warnings = [];
|
|
128
|
+
if (filePath === undefined || !existsSync(filePath)) {
|
|
129
|
+
return { values: {}, warnings };
|
|
130
|
+
}
|
|
131
|
+
let raw;
|
|
132
|
+
try {
|
|
133
|
+
raw = parseYaml(readFileSync(filePath, "utf8"));
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
137
|
+
throw new HostConfigError(`Invalid config file ${filePath}: ${detail}`, "config_invalid");
|
|
138
|
+
}
|
|
139
|
+
if (raw === null || raw === undefined) {
|
|
140
|
+
return { values: {}, warnings };
|
|
141
|
+
}
|
|
142
|
+
if (typeof raw !== "object" || Array.isArray(raw)) {
|
|
143
|
+
throw new HostConfigError(`config.yaml must be a mapping`, "config_invalid");
|
|
144
|
+
}
|
|
145
|
+
const values = {};
|
|
146
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
147
|
+
const field = FILE_KEY_TO_FIELD[key];
|
|
148
|
+
if (field === undefined) {
|
|
149
|
+
throw new HostConfigError(`Unknown config key "${key}" in ${filePath}`, "config_unknown_key", key);
|
|
150
|
+
}
|
|
151
|
+
values[field] = value;
|
|
152
|
+
}
|
|
153
|
+
return { values, warnings };
|
|
154
|
+
}
|
|
155
|
+
function coerceFileNumber(value, key) {
|
|
156
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
157
|
+
return value;
|
|
158
|
+
}
|
|
159
|
+
if (typeof value === "string") {
|
|
160
|
+
return parsePositiveInt(value, key, {
|
|
161
|
+
allowZero: key.includes("queued") || key.includes("per_project"),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
throw new HostConfigError(`Invalid value for ${key}`, "config_invalid", key);
|
|
165
|
+
}
|
|
166
|
+
function coerceFileStringList(value, key) {
|
|
167
|
+
if (Array.isArray(value) && value.every((v) => typeof v === "string")) {
|
|
168
|
+
return value.map((v) => v.trim()).filter((v) => v.length > 0);
|
|
169
|
+
}
|
|
170
|
+
if (typeof value === "string")
|
|
171
|
+
return parseStringList(value);
|
|
172
|
+
throw new HostConfigError(`Invalid value for ${key}; expected string list`, "config_invalid", key);
|
|
173
|
+
}
|
|
174
|
+
function coerceFileBool(value, key) {
|
|
175
|
+
if (typeof value === "boolean")
|
|
176
|
+
return value;
|
|
177
|
+
if (typeof value === "string")
|
|
178
|
+
return parseBool(value, key);
|
|
179
|
+
throw new HostConfigError(`Invalid boolean for ${key}`, "config_invalid", key);
|
|
180
|
+
}
|
|
181
|
+
function coerceCallers(value, key) {
|
|
182
|
+
if (value === null || value === undefined)
|
|
183
|
+
return {};
|
|
184
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
185
|
+
throw new HostConfigError(`Invalid value for ${key}; expected mapping of caller_id → { max_concurrent }`, "config_invalid", key);
|
|
186
|
+
}
|
|
187
|
+
const out = {};
|
|
188
|
+
for (const [rawId, rawEntry] of Object.entries(value)) {
|
|
189
|
+
const callerId = rawId.trim().toLowerCase();
|
|
190
|
+
if (callerId.length === 0) {
|
|
191
|
+
throw new HostConfigError(`Invalid empty caller id in ${key}`, "config_invalid", key);
|
|
192
|
+
}
|
|
193
|
+
if (rawEntry === null ||
|
|
194
|
+
typeof rawEntry !== "object" ||
|
|
195
|
+
Array.isArray(rawEntry)) {
|
|
196
|
+
throw new HostConfigError(`Invalid value for ${key}.${rawId}; expected { max_concurrent }`, "config_invalid", key);
|
|
197
|
+
}
|
|
198
|
+
const entry = rawEntry;
|
|
199
|
+
if (entry.max_concurrent === undefined) {
|
|
200
|
+
throw new HostConfigError(`Missing max_concurrent for ${key}.${rawId}`, "config_invalid", key);
|
|
201
|
+
}
|
|
202
|
+
const n = coerceFileNumber(entry.max_concurrent, `${key}.${rawId}.max_concurrent`);
|
|
203
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
204
|
+
throw new HostConfigError(`Invalid max_concurrent for ${key}.${rawId}`, "config_invalid", key);
|
|
205
|
+
}
|
|
206
|
+
for (const sub of Object.keys(entry)) {
|
|
207
|
+
if (sub !== "max_concurrent") {
|
|
208
|
+
throw new HostConfigError(`Unknown key "${sub}" under ${key}.${rawId}`, "config_unknown_key", sub);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
out[callerId] = { maxConcurrent: n };
|
|
212
|
+
}
|
|
213
|
+
return out;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Assemble HostConfig once at boot. Precedence: overrides (CLI flags) > env > file > default.
|
|
217
|
+
*/
|
|
218
|
+
export function loadHostConfig(options) {
|
|
219
|
+
const env = options?.env ?? process.env;
|
|
220
|
+
const warnings = [];
|
|
221
|
+
const homeDir = options?.homeDir ?? globalStageflowHome();
|
|
222
|
+
const configFilePath = options?.configFilePath === null
|
|
223
|
+
? undefined
|
|
224
|
+
: (options?.configFilePath ?? path.join(homeDir, "config.yaml"));
|
|
225
|
+
const allowUnknownFromEnv = env.STAGEFLOW_ALLOW_UNKNOWN_CONFIG;
|
|
226
|
+
const allowUnknownConfig = allowUnknownFromEnv !== undefined && allowUnknownFromEnv.length > 0
|
|
227
|
+
? parseBool(allowUnknownFromEnv, "STAGEFLOW_ALLOW_UNKNOWN_CONFIG")
|
|
228
|
+
: false;
|
|
229
|
+
if (allowUnknownConfig) {
|
|
230
|
+
warnings.push("STAGEFLOW_ALLOW_UNKNOWN_CONFIG=1: unknown STAGEFLOW_* keys will warn instead of failing boot");
|
|
231
|
+
}
|
|
232
|
+
assertUnknownEnvKeys(env, allowUnknownConfig, warnings);
|
|
233
|
+
const file = loadFileLayers(configFilePath !== undefined && existsSync(configFilePath)
|
|
234
|
+
? configFilePath
|
|
235
|
+
: undefined);
|
|
236
|
+
warnings.push(...file.warnings);
|
|
237
|
+
let maxConcurrentRuns = DEFAULT_MAX_CONCURRENT;
|
|
238
|
+
let maxConcurrentRunsExplicit = false;
|
|
239
|
+
if (file.values.maxConcurrentRuns !== undefined) {
|
|
240
|
+
const n = coerceFileNumber(file.values.maxConcurrentRuns, "max_concurrent_runs");
|
|
241
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
242
|
+
throw new HostConfigError(`Invalid value for max_concurrent_runs`, "config_invalid", "max_concurrent_runs");
|
|
243
|
+
}
|
|
244
|
+
maxConcurrentRuns = n;
|
|
245
|
+
maxConcurrentRunsExplicit = true;
|
|
246
|
+
}
|
|
247
|
+
if (env.STAGEFLOW_MAX_CONCURRENT_RUNS !== undefined) {
|
|
248
|
+
maxConcurrentRuns = parsePositiveInt(env.STAGEFLOW_MAX_CONCURRENT_RUNS, "STAGEFLOW_MAX_CONCURRENT_RUNS");
|
|
249
|
+
maxConcurrentRunsExplicit = true;
|
|
250
|
+
}
|
|
251
|
+
if (options?.overrides?.maxConcurrentRuns !== undefined) {
|
|
252
|
+
maxConcurrentRuns = options.overrides.maxConcurrentRuns;
|
|
253
|
+
maxConcurrentRunsExplicit = true;
|
|
254
|
+
}
|
|
255
|
+
let maxConcurrentRunsPerProject;
|
|
256
|
+
if (file.values.maxConcurrentRunsPerProject !== undefined) {
|
|
257
|
+
const n = coerceFileNumber(file.values.maxConcurrentRunsPerProject, "max_concurrent_runs_per_project");
|
|
258
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
259
|
+
throw new HostConfigError(`Invalid value for max_concurrent_runs_per_project`, "config_invalid", "max_concurrent_runs_per_project");
|
|
260
|
+
}
|
|
261
|
+
maxConcurrentRunsPerProject = n;
|
|
262
|
+
}
|
|
263
|
+
if (env.STAGEFLOW_MAX_CONCURRENT_RUNS_PER_PROJECT !== undefined) {
|
|
264
|
+
maxConcurrentRunsPerProject = parsePositiveInt(env.STAGEFLOW_MAX_CONCURRENT_RUNS_PER_PROJECT, "STAGEFLOW_MAX_CONCURRENT_RUNS_PER_PROJECT");
|
|
265
|
+
}
|
|
266
|
+
let maxQueued = DEFAULT_MAX_QUEUED;
|
|
267
|
+
if (file.values.maxQueued !== undefined) {
|
|
268
|
+
const n = coerceFileNumber(file.values.maxQueued, "max_queued");
|
|
269
|
+
if (!Number.isInteger(n) || n < 0) {
|
|
270
|
+
throw new HostConfigError(`Invalid value for max_queued`, "config_invalid", "max_queued");
|
|
271
|
+
}
|
|
272
|
+
maxQueued = n;
|
|
273
|
+
}
|
|
274
|
+
if (env.STAGEFLOW_MAX_QUEUED !== undefined) {
|
|
275
|
+
maxQueued = parsePositiveInt(env.STAGEFLOW_MAX_QUEUED, "STAGEFLOW_MAX_QUEUED", {
|
|
276
|
+
allowZero: true,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
let requireProviders = [];
|
|
280
|
+
if (file.values.requireProviders !== undefined) {
|
|
281
|
+
requireProviders = coerceFileStringList(file.values.requireProviders, "require_providers");
|
|
282
|
+
}
|
|
283
|
+
if (env.STAGEFLOW_REQUIRE_PROVIDERS !== undefined) {
|
|
284
|
+
requireProviders = parseStringList(env.STAGEFLOW_REQUIRE_PROVIDERS);
|
|
285
|
+
}
|
|
286
|
+
let trustWorkspaceConfig = [];
|
|
287
|
+
if (file.values.trustWorkspaceConfig !== undefined) {
|
|
288
|
+
trustWorkspaceConfig = coerceFileStringList(file.values.trustWorkspaceConfig, "trust_workspace_config");
|
|
289
|
+
}
|
|
290
|
+
let allowUnknownFromFile = allowUnknownConfig;
|
|
291
|
+
if (file.values.allowUnknownConfig !== undefined) {
|
|
292
|
+
allowUnknownFromFile = coerceFileBool(file.values.allowUnknownConfig, "allow_unknown_config");
|
|
293
|
+
}
|
|
294
|
+
// Env already applied above for the unknown-key scan; file cannot enable after the fact.
|
|
295
|
+
void allowUnknownFromFile;
|
|
296
|
+
const controlToken = readSecretFromEnvOrFile(env, "STAGEFLOW_CONTROL_TOKEN");
|
|
297
|
+
const readToken = readSecretFromEnvOrFile(env, "STAGEFLOW_READ_TOKEN");
|
|
298
|
+
let callers = {};
|
|
299
|
+
if (file.values.callers !== undefined) {
|
|
300
|
+
callers = coerceCallers(file.values.callers, "callers");
|
|
301
|
+
}
|
|
302
|
+
return {
|
|
303
|
+
maxConcurrentRuns,
|
|
304
|
+
maxConcurrentRunsPerProject,
|
|
305
|
+
maxQueued,
|
|
306
|
+
requireProviders,
|
|
307
|
+
trustWorkspaceConfig,
|
|
308
|
+
allowUnknownConfig,
|
|
309
|
+
controlToken,
|
|
310
|
+
readToken,
|
|
311
|
+
callers,
|
|
312
|
+
configFilePath: configFilePath !== undefined && existsSync(configFilePath)
|
|
313
|
+
? configFilePath
|
|
314
|
+
: undefined,
|
|
315
|
+
warnings,
|
|
316
|
+
maxConcurrentRunsExplicit,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
export function redactHostConfig(config) {
|
|
320
|
+
return {
|
|
321
|
+
maxConcurrentRuns: config.maxConcurrentRuns,
|
|
322
|
+
maxConcurrentRunsPerProject: config.maxConcurrentRunsPerProject,
|
|
323
|
+
maxQueued: config.maxQueued,
|
|
324
|
+
requireProviders: [...config.requireProviders],
|
|
325
|
+
trustWorkspaceConfig: [...config.trustWorkspaceConfig],
|
|
326
|
+
allowUnknownConfig: config.allowUnknownConfig,
|
|
327
|
+
callers: { ...config.callers },
|
|
328
|
+
secrets: {
|
|
329
|
+
controlToken: config.controlToken ? "set" : "unset",
|
|
330
|
+
readToken: config.readToken ? "set" : "unset",
|
|
331
|
+
},
|
|
332
|
+
};
|
|
333
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export type SkillScope = "user" | "project" | "temporary";
|
|
2
|
+
/** Skill resolution origin — separate from ConfigOriginKind. */
|
|
3
|
+
export type SkillOrigin = "run" | "checkout" | "host";
|
|
2
4
|
export type SkillListing = {
|
|
3
5
|
name: string;
|
|
4
6
|
description: string;
|
|
@@ -7,6 +9,7 @@ export type SkillListing = {
|
|
|
7
9
|
scope: SkillScope;
|
|
8
10
|
source: string;
|
|
9
11
|
disableModelInvocation: boolean;
|
|
12
|
+
origin?: SkillOrigin;
|
|
10
13
|
};
|
|
11
14
|
export type SkillDiagnostic = {
|
|
12
15
|
message: string;
|
|
@@ -19,11 +22,34 @@ export type SkillCatalog = {
|
|
|
19
22
|
export type ListSkillsOptions = {
|
|
20
23
|
cwd: string;
|
|
21
24
|
agentDir: string;
|
|
25
|
+
/** Materialized run skills root: `$STAGEFLOW_HOME/runs/<runId>/skills`. */
|
|
26
|
+
runSkillsDir?: string;
|
|
27
|
+
/** Checkout / worktree root whose `.pi/skills` is the checkout tier. */
|
|
28
|
+
checkoutRoot?: string;
|
|
22
29
|
};
|
|
23
30
|
export type ResolvedSkill = {
|
|
24
31
|
name: string;
|
|
25
32
|
filePath: string;
|
|
26
33
|
baseDir: string;
|
|
34
|
+
scope: SkillScope;
|
|
35
|
+
source: string;
|
|
36
|
+
origin: SkillOrigin;
|
|
37
|
+
};
|
|
38
|
+
export type SkillOriginListing = {
|
|
39
|
+
name: string;
|
|
40
|
+
description: string;
|
|
41
|
+
origin: SkillOrigin;
|
|
27
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* Resolve a skill by name. Search order: run skills → checkout `.pi/skills` → host agentDir.
|
|
45
|
+
*/
|
|
28
46
|
export declare function resolveSkillByName(name: string, options: ListSkillsOptions): Promise<ResolvedSkill | undefined>;
|
|
29
47
|
export declare function listSkills(options: ListSkillsOptions): Promise<SkillCatalog>;
|
|
48
|
+
/**
|
|
49
|
+
* List skills with SkillOrigin. When runSkillsDir is set, run-tier skills win on name.
|
|
50
|
+
* Precedence for the merged view: run → checkout → host.
|
|
51
|
+
*/
|
|
52
|
+
export declare function listSkillsWithOrigin(options: ListSkillsOptions): Promise<{
|
|
53
|
+
skills: SkillOriginListing[];
|
|
54
|
+
diagnostics: SkillDiagnostic[];
|
|
55
|
+
}>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { access } from "node:fs/promises";
|
|
1
|
+
import { access, readFile, readdir } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
2
3
|
import { DefaultResourceLoader, SettingsManager, } from "@earendil-works/pi-coding-agent";
|
|
3
|
-
function toListing(skill) {
|
|
4
|
+
function toListing(skill, origin) {
|
|
4
5
|
return {
|
|
5
6
|
name: skill.name,
|
|
6
7
|
description: skill.description,
|
|
@@ -9,8 +10,39 @@ function toListing(skill) {
|
|
|
9
10
|
scope: skill.sourceInfo.scope,
|
|
10
11
|
source: skill.sourceInfo.source,
|
|
11
12
|
disableModelInvocation: skill.disableModelInvocation,
|
|
13
|
+
...(origin !== undefined ? { origin } : {}),
|
|
12
14
|
};
|
|
13
15
|
}
|
|
16
|
+
function isUnderRoot(candidate, root) {
|
|
17
|
+
const resolvedRoot = path.resolve(root);
|
|
18
|
+
const resolved = path.resolve(candidate);
|
|
19
|
+
const rel = path.relative(resolvedRoot, resolved);
|
|
20
|
+
return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
|
|
21
|
+
}
|
|
22
|
+
async function pathExists(filePath) {
|
|
23
|
+
try {
|
|
24
|
+
await access(filePath);
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function descriptionFromSkillMd(content) {
|
|
32
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
|
|
33
|
+
if (!match)
|
|
34
|
+
return undefined;
|
|
35
|
+
const block = match[1];
|
|
36
|
+
const descLine = /^description:\s*(.*)$/m.exec(block);
|
|
37
|
+
if (!descLine)
|
|
38
|
+
return undefined;
|
|
39
|
+
let value = descLine[1].trim();
|
|
40
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
41
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
42
|
+
value = value.slice(1, -1);
|
|
43
|
+
}
|
|
44
|
+
return value.length > 0 ? value : undefined;
|
|
45
|
+
}
|
|
14
46
|
async function openSkillCatalogLoader(options) {
|
|
15
47
|
const settingsManager = SettingsManager.create(options.cwd, options.agentDir, {
|
|
16
48
|
projectTrusted: true,
|
|
@@ -23,7 +55,67 @@ async function openSkillCatalogLoader(options) {
|
|
|
23
55
|
await loader.reload();
|
|
24
56
|
return loader;
|
|
25
57
|
}
|
|
58
|
+
async function resolveRunSkill(name, runSkillsDir) {
|
|
59
|
+
if (name.includes("/") || name.includes("\\") || name.includes("\0")) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
const baseDir = path.join(runSkillsDir, name);
|
|
63
|
+
const filePath = path.join(baseDir, "SKILL.md");
|
|
64
|
+
if (!(await pathExists(filePath)))
|
|
65
|
+
return undefined;
|
|
66
|
+
return {
|
|
67
|
+
name,
|
|
68
|
+
filePath,
|
|
69
|
+
baseDir,
|
|
70
|
+
scope: "temporary",
|
|
71
|
+
source: "run",
|
|
72
|
+
origin: "run",
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async function resolveCheckoutSkill(name, checkoutRoot) {
|
|
76
|
+
if (name.includes("/") || name.includes("\\") || name.includes("\0")) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
const baseDir = path.join(checkoutRoot, ".pi", "skills", name);
|
|
80
|
+
const filePath = path.join(baseDir, "SKILL.md");
|
|
81
|
+
if (!(await pathExists(filePath)))
|
|
82
|
+
return undefined;
|
|
83
|
+
return {
|
|
84
|
+
name,
|
|
85
|
+
filePath,
|
|
86
|
+
baseDir,
|
|
87
|
+
scope: "project",
|
|
88
|
+
source: "checkout",
|
|
89
|
+
origin: "checkout",
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function originForLoaderSkill(skill, options) {
|
|
93
|
+
if (options.checkoutRoot !== undefined &&
|
|
94
|
+
isUnderRoot(skill.filePath, path.join(options.checkoutRoot, ".pi", "skills"))) {
|
|
95
|
+
return "checkout";
|
|
96
|
+
}
|
|
97
|
+
if (isUnderRoot(skill.filePath, path.join(options.agentDir, "skills"))) {
|
|
98
|
+
return "host";
|
|
99
|
+
}
|
|
100
|
+
if (skill.sourceInfo.scope === "project") {
|
|
101
|
+
return "checkout";
|
|
102
|
+
}
|
|
103
|
+
return "host";
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Resolve a skill by name. Search order: run skills → checkout `.pi/skills` → host agentDir.
|
|
107
|
+
*/
|
|
26
108
|
export async function resolveSkillByName(name, options) {
|
|
109
|
+
if (options.runSkillsDir !== undefined) {
|
|
110
|
+
const run = await resolveRunSkill(name, options.runSkillsDir);
|
|
111
|
+
if (run)
|
|
112
|
+
return run;
|
|
113
|
+
}
|
|
114
|
+
if (options.checkoutRoot !== undefined) {
|
|
115
|
+
const checkout = await resolveCheckoutSkill(name, options.checkoutRoot);
|
|
116
|
+
if (checkout)
|
|
117
|
+
return checkout;
|
|
118
|
+
}
|
|
27
119
|
const loader = await openSkillCatalogLoader(options);
|
|
28
120
|
const match = loader.getSkills().skills.find((skill) => skill.name === name);
|
|
29
121
|
if (!match)
|
|
@@ -34,10 +126,24 @@ export async function resolveSkillByName(name, options) {
|
|
|
34
126
|
catch {
|
|
35
127
|
return undefined;
|
|
36
128
|
}
|
|
129
|
+
if (options.checkoutRoot !== undefined &&
|
|
130
|
+
isUnderRoot(match.filePath, path.join(options.checkoutRoot, ".pi", "skills"))) {
|
|
131
|
+
return {
|
|
132
|
+
name: match.name,
|
|
133
|
+
filePath: match.filePath,
|
|
134
|
+
baseDir: match.baseDir,
|
|
135
|
+
scope: match.sourceInfo.scope,
|
|
136
|
+
source: match.sourceInfo.source,
|
|
137
|
+
origin: "checkout",
|
|
138
|
+
};
|
|
139
|
+
}
|
|
37
140
|
return {
|
|
38
141
|
name: match.name,
|
|
39
142
|
filePath: match.filePath,
|
|
40
143
|
baseDir: match.baseDir,
|
|
144
|
+
scope: match.sourceInfo.scope,
|
|
145
|
+
source: match.sourceInfo.source,
|
|
146
|
+
origin: originForLoaderSkill(match, options),
|
|
41
147
|
};
|
|
42
148
|
}
|
|
43
149
|
export async function listSkills(options) {
|
|
@@ -45,7 +151,7 @@ export async function listSkills(options) {
|
|
|
45
151
|
const { skills, diagnostics } = loader.getSkills();
|
|
46
152
|
return {
|
|
47
153
|
skills: skills
|
|
48
|
-
.map(toListing)
|
|
154
|
+
.map((skill) => toListing(skill, originForLoaderSkill(skill, options)))
|
|
49
155
|
.sort((a, b) => a.name.localeCompare(b.name)),
|
|
50
156
|
diagnostics: diagnostics.map((d) => ({
|
|
51
157
|
message: d.message,
|
|
@@ -53,3 +159,84 @@ export async function listSkills(options) {
|
|
|
53
159
|
})),
|
|
54
160
|
};
|
|
55
161
|
}
|
|
162
|
+
async function listRunSkillOrigins(runSkillsDir) {
|
|
163
|
+
let names;
|
|
164
|
+
try {
|
|
165
|
+
names = await readdir(runSkillsDir);
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
const out = [];
|
|
171
|
+
for (const name of names) {
|
|
172
|
+
if (name.includes("/") || name.includes("\\") || name.includes("\0")) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
const filePath = path.join(runSkillsDir, name, "SKILL.md");
|
|
176
|
+
try {
|
|
177
|
+
const content = await readFile(filePath, "utf8");
|
|
178
|
+
const description = descriptionFromSkillMd(content);
|
|
179
|
+
if (description === undefined)
|
|
180
|
+
continue;
|
|
181
|
+
out.push({ name, description, origin: "run" });
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// skip unreadable / incomplete packs
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return out;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* List skills with SkillOrigin. When runSkillsDir is set, run-tier skills win on name.
|
|
191
|
+
* Precedence for the merged view: run → checkout → host.
|
|
192
|
+
*/
|
|
193
|
+
export async function listSkillsWithOrigin(options) {
|
|
194
|
+
const byName = new Map();
|
|
195
|
+
const hostCatalog = await listSkills({
|
|
196
|
+
cwd: options.cwd,
|
|
197
|
+
agentDir: options.agentDir,
|
|
198
|
+
...(options.checkoutRoot !== undefined
|
|
199
|
+
? { checkoutRoot: options.checkoutRoot }
|
|
200
|
+
: {}),
|
|
201
|
+
});
|
|
202
|
+
for (const skill of hostCatalog.skills) {
|
|
203
|
+
const origin = skill.origin ??
|
|
204
|
+
(skill.scope === "project" ? "checkout" : "host");
|
|
205
|
+
byName.set(skill.name, {
|
|
206
|
+
name: skill.name,
|
|
207
|
+
description: skill.description,
|
|
208
|
+
origin,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
if (options.checkoutRoot !== undefined) {
|
|
212
|
+
let checkoutNames = [];
|
|
213
|
+
try {
|
|
214
|
+
checkoutNames = await readdir(path.join(options.checkoutRoot, ".pi", "skills"));
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
checkoutNames = [];
|
|
218
|
+
}
|
|
219
|
+
for (const name of checkoutNames) {
|
|
220
|
+
const filePath = path.join(options.checkoutRoot, ".pi", "skills", name, "SKILL.md");
|
|
221
|
+
try {
|
|
222
|
+
const content = await readFile(filePath, "utf8");
|
|
223
|
+
const description = descriptionFromSkillMd(content);
|
|
224
|
+
if (description === undefined)
|
|
225
|
+
continue;
|
|
226
|
+
byName.set(name, { name, description, origin: "checkout" });
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
// skip
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (options.runSkillsDir !== undefined) {
|
|
234
|
+
for (const skill of await listRunSkillOrigins(options.runSkillsDir)) {
|
|
235
|
+
byName.set(skill.name, skill);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
skills: [...byName.values()].sort((a, b) => a.name.localeCompare(b.name)),
|
|
240
|
+
diagnostics: hostCatalog.diagnostics,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ValidationFindingCode } from "./validateCatalog.js";
|
|
2
|
-
export type TaskLoadCode = "task.invalid_shape" | "task.load_error";
|
|
2
|
+
export type TaskLoadCode = "task.invalid_shape" | "task.load_error" | "task.binding_conflict" | "task.repository_ref_required" | "task.ref_without_repository" | "task.repository_invalid";
|
|
3
3
|
export type LoadIssue = {
|
|
4
4
|
code: ValidationFindingCode;
|
|
5
5
|
message: string;
|