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,52 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/server";
|
|
2
|
+
import type { RunMeta, RunStore } from "../runstore/port.js";
|
|
3
|
+
import type { McpToolDeps } from "./deps.js";
|
|
4
|
+
export declare const CHECKOUT_CHANGES_CAP = 500;
|
|
5
|
+
export declare const DEFAULT_DIFF_MAX_BYTES = 262144;
|
|
6
|
+
export type CheckoutChangeStatus = "added" | "untracked" | "modified" | "deleted";
|
|
7
|
+
export type CheckoutChangeEntry = {
|
|
8
|
+
path: string;
|
|
9
|
+
status: CheckoutChangeStatus;
|
|
10
|
+
};
|
|
11
|
+
export type CheckoutVisibilityCode = "run_not_bound" | "checkout_reclaimed" | "not_a_git_repository";
|
|
12
|
+
export type CheckoutVisibilityError = {
|
|
13
|
+
ok: false;
|
|
14
|
+
code: CheckoutVisibilityCode;
|
|
15
|
+
error: string;
|
|
16
|
+
status: number;
|
|
17
|
+
};
|
|
18
|
+
export type BoundCheckout = {
|
|
19
|
+
ok: true;
|
|
20
|
+
runId: string;
|
|
21
|
+
meta: RunMeta;
|
|
22
|
+
checkoutRoot: string;
|
|
23
|
+
isGit: boolean;
|
|
24
|
+
};
|
|
25
|
+
export declare function resolveBoundCheckout(store: RunStore, runId: string): Promise<BoundCheckout | CheckoutVisibilityError>;
|
|
26
|
+
export declare function parseStatusPorcelainZ(output: string): CheckoutChangeEntry[];
|
|
27
|
+
export declare function listCheckoutChanges(store: RunStore, runId: string): Promise<{
|
|
28
|
+
ok: true;
|
|
29
|
+
changes: CheckoutChangeEntry[];
|
|
30
|
+
truncated: boolean;
|
|
31
|
+
} | CheckoutVisibilityError>;
|
|
32
|
+
export type GetRunDiffInput = {
|
|
33
|
+
mode?: "stat" | "patch";
|
|
34
|
+
path?: string;
|
|
35
|
+
maxBytes?: number;
|
|
36
|
+
};
|
|
37
|
+
export type GetRunDiffSuccess = {
|
|
38
|
+
ok: true;
|
|
39
|
+
mode: "stat" | "patch";
|
|
40
|
+
base_sha: string;
|
|
41
|
+
base_source: "resolved_sha" | "HEAD";
|
|
42
|
+
content: string;
|
|
43
|
+
truncated: boolean;
|
|
44
|
+
untracked: string[];
|
|
45
|
+
};
|
|
46
|
+
export declare function getRunDiff(store: RunStore, runId: string, input?: GetRunDiffInput): Promise<GetRunDiffSuccess | CheckoutVisibilityError>;
|
|
47
|
+
export declare function readCheckoutFileBytes(store: RunStore, runId: string, relativePath: string): Promise<{
|
|
48
|
+
ok: true;
|
|
49
|
+
bytes: Buffer;
|
|
50
|
+
path: string;
|
|
51
|
+
} | CheckoutVisibilityError>;
|
|
52
|
+
export declare function registerCheckoutTools(server: McpServer, deps: McpToolDeps): void;
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { lstat, readdir, readFile, readlink } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { diff, lsFilesOthersZ, revParse, statusPorcelainZ, } from "../git/operations.js";
|
|
7
|
+
import { projectRunBindingDetail } from "../runstore/runProjection.js";
|
|
8
|
+
import { mapStoreLookupError } from "../server/operatorResults.js";
|
|
9
|
+
import { assertSafeRunId, CHECKOUT_PATH_MESSAGES, classifyArtifactContent, resolveContainedRelativePath, } from "./readArtifact.js";
|
|
10
|
+
import { imageResult, textResult } from "./toolResults.js";
|
|
11
|
+
export const CHECKOUT_CHANGES_CAP = 500;
|
|
12
|
+
export const DEFAULT_DIFF_MAX_BYTES = 262_144;
|
|
13
|
+
async function detectGitCheckout(root) {
|
|
14
|
+
try {
|
|
15
|
+
const inside = await revParse(root, ["--is-inside-work-tree"]);
|
|
16
|
+
return inside === "true";
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export async function resolveBoundCheckout(store, runId) {
|
|
23
|
+
assertSafeRunId(runId);
|
|
24
|
+
let meta;
|
|
25
|
+
try {
|
|
26
|
+
meta = await store.readRunMeta(runId);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
const mapped = mapStoreLookupError(err, { policy: "run" });
|
|
30
|
+
throw new Error(mapped.error);
|
|
31
|
+
}
|
|
32
|
+
const binding = projectRunBindingDetail(meta);
|
|
33
|
+
if (binding.kind === "unbound") {
|
|
34
|
+
return {
|
|
35
|
+
ok: false,
|
|
36
|
+
code: "run_not_bound",
|
|
37
|
+
error: "run is not bound to a checkout",
|
|
38
|
+
status: 400,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const checkoutRoot = meta.checkout_root?.trim();
|
|
42
|
+
if (!checkoutRoot) {
|
|
43
|
+
return {
|
|
44
|
+
ok: false,
|
|
45
|
+
code: "checkout_reclaimed",
|
|
46
|
+
error: "checkout has been reclaimed",
|
|
47
|
+
status: 404,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (!existsSync(checkoutRoot)) {
|
|
51
|
+
return {
|
|
52
|
+
ok: false,
|
|
53
|
+
code: "checkout_reclaimed",
|
|
54
|
+
error: "checkout has been reclaimed",
|
|
55
|
+
status: 404,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const isGit = await detectGitCheckout(checkoutRoot);
|
|
59
|
+
return { ok: true, runId, meta, checkoutRoot, isGit };
|
|
60
|
+
}
|
|
61
|
+
function nulSplit(output) {
|
|
62
|
+
return output.split("\0").filter((part) => part.length > 0);
|
|
63
|
+
}
|
|
64
|
+
export function parseStatusPorcelainZ(output) {
|
|
65
|
+
const parts = nulSplit(output);
|
|
66
|
+
const changes = [];
|
|
67
|
+
for (let i = 0; i < parts.length; i += 1) {
|
|
68
|
+
const entry = parts[i];
|
|
69
|
+
if (entry.length < 3)
|
|
70
|
+
continue;
|
|
71
|
+
const xy = entry.slice(0, 2);
|
|
72
|
+
const firstPath = entry.slice(3);
|
|
73
|
+
const isRenameOrCopy = xy[0] === "R" || xy[0] === "C";
|
|
74
|
+
let filePath = firstPath;
|
|
75
|
+
if (isRenameOrCopy) {
|
|
76
|
+
const next = parts[i + 1];
|
|
77
|
+
if (next !== undefined) {
|
|
78
|
+
filePath = next;
|
|
79
|
+
i += 1;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (xy === "??") {
|
|
83
|
+
changes.push({ path: filePath, status: "untracked" });
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (xy === "!!")
|
|
87
|
+
continue;
|
|
88
|
+
if (xy.includes("D") && !isRenameOrCopy) {
|
|
89
|
+
changes.push({ path: filePath, status: "deleted" });
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (xy[0] === "A" || xy[1] === "A" || isRenameOrCopy) {
|
|
93
|
+
changes.push({ path: filePath, status: "added" });
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
changes.push({ path: filePath, status: "modified" });
|
|
97
|
+
}
|
|
98
|
+
return changes;
|
|
99
|
+
}
|
|
100
|
+
function capChanges(changes) {
|
|
101
|
+
if (changes.length <= CHECKOUT_CHANGES_CAP) {
|
|
102
|
+
return { changes, truncated: false };
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
changes: changes.slice(0, CHECKOUT_CHANGES_CAP),
|
|
106
|
+
truncated: true,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
async function fingerprintFile(root, relativePath) {
|
|
110
|
+
const target = path.join(root, relativePath);
|
|
111
|
+
try {
|
|
112
|
+
const stats = await lstat(target);
|
|
113
|
+
if (stats.isSymbolicLink()) {
|
|
114
|
+
const targetPath = await readlink(target);
|
|
115
|
+
return `link:${createHash("sha256").update(targetPath).digest("hex")}`;
|
|
116
|
+
}
|
|
117
|
+
if (!stats.isFile())
|
|
118
|
+
return `other:${stats.mode}:${stats.size}`;
|
|
119
|
+
const contents = await readFile(target);
|
|
120
|
+
return `file:${createHash("sha256").update(contents).digest("hex")}`;
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
if (error.code === "ENOENT")
|
|
124
|
+
return "missing";
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async function listNonGitFiles(root, relativeDir = "") {
|
|
129
|
+
const absDir = relativeDir ? path.join(root, relativeDir) : root;
|
|
130
|
+
let entries;
|
|
131
|
+
try {
|
|
132
|
+
entries = await readdir(absDir, { withFileTypes: true });
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
if (error.code === "ENOENT")
|
|
136
|
+
return [];
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
139
|
+
const files = [];
|
|
140
|
+
for (const entry of entries) {
|
|
141
|
+
if (entry.name === ".pi-agent" || entry.name === ".git")
|
|
142
|
+
continue;
|
|
143
|
+
const rel = relativeDir ? path.join(relativeDir, entry.name) : entry.name;
|
|
144
|
+
if (entry.name === "auth.json")
|
|
145
|
+
continue;
|
|
146
|
+
if (entry.isSymbolicLink() || entry.isFile()) {
|
|
147
|
+
files.push(rel.split(path.sep).join("/"));
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (entry.isDirectory()) {
|
|
151
|
+
files.push(...(await listNonGitFiles(root, rel)));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return files;
|
|
155
|
+
}
|
|
156
|
+
async function listNonGitChanges(checkoutRoot) {
|
|
157
|
+
const files = (await listNonGitFiles(checkoutRoot)).sort();
|
|
158
|
+
const changes = [];
|
|
159
|
+
for (const file of files) {
|
|
160
|
+
const fingerprint = await fingerprintFile(checkoutRoot, file);
|
|
161
|
+
if (fingerprint === "missing")
|
|
162
|
+
continue;
|
|
163
|
+
changes.push({ path: file, status: "untracked" });
|
|
164
|
+
if (changes.length > CHECKOUT_CHANGES_CAP)
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
return capChanges(changes);
|
|
168
|
+
}
|
|
169
|
+
export async function listCheckoutChanges(store, runId) {
|
|
170
|
+
const bound = await resolveBoundCheckout(store, runId);
|
|
171
|
+
if (!bound.ok)
|
|
172
|
+
return bound;
|
|
173
|
+
if (!bound.isGit) {
|
|
174
|
+
const listed = await listNonGitChanges(bound.checkoutRoot);
|
|
175
|
+
return { ok: true, ...listed };
|
|
176
|
+
}
|
|
177
|
+
const porcelain = await statusPorcelainZ(bound.checkoutRoot);
|
|
178
|
+
return { ok: true, ...capChanges(parseStatusPorcelainZ(porcelain)) };
|
|
179
|
+
}
|
|
180
|
+
export async function getRunDiff(store, runId, input = {}) {
|
|
181
|
+
const bound = await resolveBoundCheckout(store, runId);
|
|
182
|
+
if (!bound.ok)
|
|
183
|
+
return bound;
|
|
184
|
+
if (!bound.isGit) {
|
|
185
|
+
return {
|
|
186
|
+
ok: false,
|
|
187
|
+
code: "not_a_git_repository",
|
|
188
|
+
error: "checkout is not a git repository",
|
|
189
|
+
status: 400,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
const mode = input.mode ?? "stat";
|
|
193
|
+
const maxBytes = typeof input.maxBytes === "number" && Number.isFinite(input.maxBytes)
|
|
194
|
+
? Math.max(0, Math.floor(input.maxBytes))
|
|
195
|
+
: DEFAULT_DIFF_MAX_BYTES;
|
|
196
|
+
let baseSha = bound.meta.resolved_sha?.trim() || undefined;
|
|
197
|
+
let baseSource = "resolved_sha";
|
|
198
|
+
if (!baseSha) {
|
|
199
|
+
baseSha = await revParse(bound.checkoutRoot, ["HEAD"]);
|
|
200
|
+
baseSource = "HEAD";
|
|
201
|
+
}
|
|
202
|
+
const pathArgs = input.path !== undefined && input.path.trim().length > 0
|
|
203
|
+
? ["--", input.path]
|
|
204
|
+
: ["--"];
|
|
205
|
+
const diffArgs = mode === "patch"
|
|
206
|
+
? ["--patch", "--no-color", baseSha, ...pathArgs]
|
|
207
|
+
: ["--stat", baseSha, ...pathArgs];
|
|
208
|
+
let content = await diff(bound.checkoutRoot, diffArgs);
|
|
209
|
+
const othersRaw = await lsFilesOthersZ(bound.checkoutRoot);
|
|
210
|
+
let untracked = nulSplit(othersRaw);
|
|
211
|
+
if (input.path !== undefined && input.path.trim().length > 0) {
|
|
212
|
+
const filter = input.path.replace(/\\/g, "/");
|
|
213
|
+
untracked = untracked.filter((file) => file === filter || file.startsWith(`${filter}/`));
|
|
214
|
+
}
|
|
215
|
+
let truncated = false;
|
|
216
|
+
if (mode === "patch" && content.length > maxBytes) {
|
|
217
|
+
content = content.slice(0, maxBytes);
|
|
218
|
+
truncated = true;
|
|
219
|
+
}
|
|
220
|
+
if (untracked.length > CHECKOUT_CHANGES_CAP) {
|
|
221
|
+
untracked = untracked.slice(0, CHECKOUT_CHANGES_CAP);
|
|
222
|
+
truncated = true;
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
ok: true,
|
|
226
|
+
mode,
|
|
227
|
+
base_sha: baseSha,
|
|
228
|
+
base_source: baseSource,
|
|
229
|
+
content,
|
|
230
|
+
truncated,
|
|
231
|
+
untracked,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
export async function readCheckoutFileBytes(store, runId, relativePath) {
|
|
235
|
+
const bound = await resolveBoundCheckout(store, runId);
|
|
236
|
+
if (!bound.ok)
|
|
237
|
+
return bound;
|
|
238
|
+
const realPath = await resolveContainedRelativePath(bound.checkoutRoot, relativePath, CHECKOUT_PATH_MESSAGES);
|
|
239
|
+
return { ok: true, bytes: await readFile(realPath), path: relativePath };
|
|
240
|
+
}
|
|
241
|
+
function visibilityErrorResult(err) {
|
|
242
|
+
return textResult({ error: err.error, code: err.code, status: err.status }, true);
|
|
243
|
+
}
|
|
244
|
+
export function registerCheckoutTools(server, deps) {
|
|
245
|
+
const { store } = deps;
|
|
246
|
+
server.registerTool("list_checkout_changes", {
|
|
247
|
+
description: "List dirty/untracked paths in the run's bound checkout. Repository and git path bindings use git status; non-git path bindings use filesystem fingerprints. Unbound → run_not_bound; reclaimed checkout → checkout_reclaimed. Caps at 500 entries with truncated: true.",
|
|
248
|
+
inputSchema: z.object({
|
|
249
|
+
runId: z.string(),
|
|
250
|
+
}),
|
|
251
|
+
}, async ({ runId }) => {
|
|
252
|
+
try {
|
|
253
|
+
const result = await listCheckoutChanges(store, runId);
|
|
254
|
+
if (!result.ok)
|
|
255
|
+
return visibilityErrorResult(result);
|
|
256
|
+
return textResult({
|
|
257
|
+
runId,
|
|
258
|
+
changes: result.changes,
|
|
259
|
+
truncated: result.truncated,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
const mapped = mapStoreLookupError(err, { policy: "run" });
|
|
264
|
+
return textResult({ error: mapped.error, status: mapped.status }, true);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
server.registerTool("get_run_diff", {
|
|
268
|
+
description: "Diff the run's bound git checkout against its recorded base SHA (resolved_sha). mode defaults to stat; patch enforces maxBytes (default 262144) with truncated: true. Unbound → run_not_bound; non-git path → not_a_git_repository; reclaimed → checkout_reclaimed.",
|
|
269
|
+
inputSchema: z.object({
|
|
270
|
+
runId: z.string(),
|
|
271
|
+
mode: z.enum(["stat", "patch"]).optional(),
|
|
272
|
+
path: z.string().optional(),
|
|
273
|
+
maxBytes: z.number().optional(),
|
|
274
|
+
}),
|
|
275
|
+
}, async ({ runId, mode, path: filterPath, maxBytes }) => {
|
|
276
|
+
try {
|
|
277
|
+
const result = await getRunDiff(store, runId, {
|
|
278
|
+
mode,
|
|
279
|
+
path: filterPath,
|
|
280
|
+
maxBytes,
|
|
281
|
+
});
|
|
282
|
+
if (!result.ok)
|
|
283
|
+
return visibilityErrorResult(result);
|
|
284
|
+
return textResult({
|
|
285
|
+
runId,
|
|
286
|
+
mode: result.mode,
|
|
287
|
+
base_sha: result.base_sha,
|
|
288
|
+
base_source: result.base_source,
|
|
289
|
+
content: result.content,
|
|
290
|
+
truncated: result.truncated,
|
|
291
|
+
untracked: result.untracked,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
catch (err) {
|
|
295
|
+
const mapped = mapStoreLookupError(err, { policy: "run" });
|
|
296
|
+
return textResult({ error: mapped.error, status: mapped.status }, true);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
server.registerTool("read_checkout_file", {
|
|
300
|
+
description: "Read a file from the run's bound checkout by relative path (contained under checkout_root). Same deny-list as read_artifact (.pi-agent, auth.json, traversal). Images return an MCP image block; UTF-8 returns JSON { runId, path, content }.",
|
|
301
|
+
inputSchema: z.object({
|
|
302
|
+
runId: z.string(),
|
|
303
|
+
path: z.string(),
|
|
304
|
+
}),
|
|
305
|
+
}, async ({ runId, path: relativePath }) => {
|
|
306
|
+
try {
|
|
307
|
+
const result = await readCheckoutFileBytes(store, runId, relativePath);
|
|
308
|
+
if (!result.ok)
|
|
309
|
+
return visibilityErrorResult(result);
|
|
310
|
+
const classified = classifyArtifactContent(relativePath, result.bytes);
|
|
311
|
+
if (classified.kind === "image") {
|
|
312
|
+
return imageResult(classified.mimeType, result.bytes, {
|
|
313
|
+
runId,
|
|
314
|
+
path: relativePath,
|
|
315
|
+
mimeType: classified.mimeType,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
if (classified.kind === "utf8") {
|
|
319
|
+
return textResult({
|
|
320
|
+
runId,
|
|
321
|
+
path: relativePath,
|
|
322
|
+
content: result.bytes.toString("utf8"),
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
return textResult({ error: "Checkout file is not valid UTF-8 text", status: 400 }, true);
|
|
326
|
+
}
|
|
327
|
+
catch (err) {
|
|
328
|
+
const mapped = mapStoreLookupError(err, { policy: "artifact" });
|
|
329
|
+
return textResult({ error: mapped.error, status: mapped.status }, true);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
}
|
package/dist/mcp/controlTools.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { writeAudit } from "../logging/audit.js";
|
|
4
|
+
import { logger as rootLogger } from "../logging/logger.js";
|
|
3
5
|
import { findProjectRoot } from "../project/findProjectRoot.js";
|
|
4
6
|
import { mapRetryStageFailure, mapStartFailure, mapStoreLookupError, } from "../server/operatorResults.js";
|
|
7
|
+
import { callerIdFromRequestAuth, getRequestAuth, } from "../server/requestAuthContext.js";
|
|
5
8
|
import { attemptStreamLogPath } from "../runstore/workspaceLayout.js";
|
|
6
9
|
import { parseAskOperatorAnswer } from "../tools/askOperator.js";
|
|
7
10
|
import { readStreamLogTail } from "./tailStreamLog.js";
|
|
8
11
|
import { textResult } from "./toolResults.js";
|
|
9
12
|
import { projectWaitingGates } from "./waitingGates.js";
|
|
10
13
|
import { readStageVerificationHistory } from "../runstore/verificationHistory.js";
|
|
14
|
+
const auditLog = rootLogger.child({ component: "audit" });
|
|
11
15
|
export function registerControlTools(server, deps) {
|
|
12
16
|
const { manager, store, cwd } = deps;
|
|
13
17
|
server.registerTool("list_waiting", {
|
|
@@ -51,12 +55,33 @@ export function registerControlTools(server, deps) {
|
|
|
51
55
|
}
|
|
52
56
|
catch (err) {
|
|
53
57
|
const message = err instanceof Error ? err.message : String(err);
|
|
58
|
+
writeAudit(auditLog, {
|
|
59
|
+
caller_id: callerIdFromRequestAuth(),
|
|
60
|
+
surface: getRequestAuth()?.surface ?? "mcp",
|
|
61
|
+
action: "answer_gate",
|
|
62
|
+
target_run_id: runId,
|
|
63
|
+
outcome: "error",
|
|
64
|
+
});
|
|
54
65
|
return textResult({ error: message, status: 400 }, true);
|
|
55
66
|
}
|
|
56
67
|
const result = await manager.deliverAnswer(runId, stageId, parsed);
|
|
57
68
|
if (!result.ok) {
|
|
69
|
+
writeAudit(auditLog, {
|
|
70
|
+
caller_id: callerIdFromRequestAuth(),
|
|
71
|
+
surface: getRequestAuth()?.surface ?? "mcp",
|
|
72
|
+
action: "answer_gate",
|
|
73
|
+
target_run_id: runId,
|
|
74
|
+
outcome: "error",
|
|
75
|
+
});
|
|
58
76
|
return textResult({ error: result.reason, status: result.status }, true);
|
|
59
77
|
}
|
|
78
|
+
writeAudit(auditLog, {
|
|
79
|
+
caller_id: callerIdFromRequestAuth(),
|
|
80
|
+
surface: getRequestAuth()?.surface ?? "mcp",
|
|
81
|
+
action: "answer_gate",
|
|
82
|
+
target_run_id: runId,
|
|
83
|
+
outcome: "ok",
|
|
84
|
+
});
|
|
60
85
|
return textResult({ ok: true });
|
|
61
86
|
});
|
|
62
87
|
server.registerTool("decide_feedback_loop", {
|
|
@@ -233,8 +258,23 @@ export function registerControlTools(server, deps) {
|
|
|
233
258
|
}, async ({ runId, stageId }) => {
|
|
234
259
|
const result = await manager.retryStage(runId, stageId);
|
|
235
260
|
if (!result.ok) {
|
|
261
|
+
writeAudit(auditLog, {
|
|
262
|
+
caller_id: callerIdFromRequestAuth(),
|
|
263
|
+
surface: getRequestAuth()?.surface ?? "mcp",
|
|
264
|
+
action: "retry_stage",
|
|
265
|
+
target_run_id: runId,
|
|
266
|
+
outcome: "error",
|
|
267
|
+
...(result.code !== undefined ? { error_code: result.code } : {}),
|
|
268
|
+
});
|
|
236
269
|
return textResult({ ...mapRetryStageFailure(result), status: result.status }, true);
|
|
237
270
|
}
|
|
271
|
+
writeAudit(auditLog, {
|
|
272
|
+
caller_id: callerIdFromRequestAuth(),
|
|
273
|
+
surface: getRequestAuth()?.surface ?? "mcp",
|
|
274
|
+
action: "retry_stage",
|
|
275
|
+
target_run_id: runId,
|
|
276
|
+
outcome: "ok",
|
|
277
|
+
});
|
|
238
278
|
return textResult({
|
|
239
279
|
runId: result.runId,
|
|
240
280
|
stageId: result.stageId,
|
|
@@ -242,7 +282,7 @@ export function registerControlTools(server, deps) {
|
|
|
242
282
|
});
|
|
243
283
|
});
|
|
244
284
|
server.registerTool("resume_stage", {
|
|
245
|
-
description: "Resume a stage that failed because it timed out, continuing the same attempt/session (same as POST .../resume). Does not start a new attempt — use retry_stage to start over.",
|
|
285
|
+
description: "Resume an interrupted stage or a stage that failed because it timed out, continuing the same attempt/session (same as POST .../resume). Does not start a new attempt — use retry_stage to start over.",
|
|
246
286
|
inputSchema: z.object({
|
|
247
287
|
runId: z.string(),
|
|
248
288
|
stageId: z.string(),
|
|
@@ -250,8 +290,23 @@ export function registerControlTools(server, deps) {
|
|
|
250
290
|
}, async ({ runId, stageId }) => {
|
|
251
291
|
const result = await manager.resumeTimedOutStage(runId, stageId);
|
|
252
292
|
if (!result.ok) {
|
|
293
|
+
writeAudit(auditLog, {
|
|
294
|
+
caller_id: callerIdFromRequestAuth(),
|
|
295
|
+
surface: getRequestAuth()?.surface ?? "mcp",
|
|
296
|
+
action: "resume_stage",
|
|
297
|
+
target_run_id: runId,
|
|
298
|
+
outcome: "error",
|
|
299
|
+
...(result.code !== undefined ? { error_code: result.code } : {}),
|
|
300
|
+
});
|
|
253
301
|
return textResult({ ...mapRetryStageFailure(result), status: result.status }, true);
|
|
254
302
|
}
|
|
303
|
+
writeAudit(auditLog, {
|
|
304
|
+
caller_id: callerIdFromRequestAuth(),
|
|
305
|
+
surface: getRequestAuth()?.surface ?? "mcp",
|
|
306
|
+
action: "resume_stage",
|
|
307
|
+
target_run_id: runId,
|
|
308
|
+
outcome: "ok",
|
|
309
|
+
});
|
|
255
310
|
return textResult({
|
|
256
311
|
runId: result.runId,
|
|
257
312
|
stageId: result.stageId,
|
|
@@ -259,7 +314,7 @@ export function registerControlTools(server, deps) {
|
|
|
259
314
|
});
|
|
260
315
|
});
|
|
261
316
|
server.registerTool("abandon_stage", {
|
|
262
|
-
description: "Abandon a running stage (marks it failed
|
|
317
|
+
description: "Abandon a running stage (marks it failed). Does not dismiss HITL — waiting stages return 409; answer them with answer_gate. Prefer cancel_run to stop an entire run.",
|
|
263
318
|
inputSchema: z.object({
|
|
264
319
|
runId: z.string(),
|
|
265
320
|
stageId: z.string(),
|
|
@@ -268,27 +323,146 @@ export function registerControlTools(server, deps) {
|
|
|
268
323
|
const result = await manager.abandonStage(runId, stageId);
|
|
269
324
|
if (!result.ok) {
|
|
270
325
|
const fail = result;
|
|
326
|
+
writeAudit(auditLog, {
|
|
327
|
+
caller_id: callerIdFromRequestAuth(),
|
|
328
|
+
surface: getRequestAuth()?.surface ?? "mcp",
|
|
329
|
+
action: "abandon_stage",
|
|
330
|
+
target_run_id: runId,
|
|
331
|
+
outcome: "error",
|
|
332
|
+
});
|
|
271
333
|
return textResult({ error: fail.reason, status: fail.status }, true);
|
|
272
334
|
}
|
|
335
|
+
writeAudit(auditLog, {
|
|
336
|
+
caller_id: callerIdFromRequestAuth(),
|
|
337
|
+
surface: getRequestAuth()?.surface ?? "mcp",
|
|
338
|
+
action: "abandon_stage",
|
|
339
|
+
target_run_id: runId,
|
|
340
|
+
outcome: "ok",
|
|
341
|
+
});
|
|
273
342
|
return textResult({
|
|
274
343
|
ok: true,
|
|
275
344
|
runId: result.runId,
|
|
276
345
|
stageId: result.stageId,
|
|
277
346
|
});
|
|
278
347
|
});
|
|
348
|
+
server.registerTool("cancel_run", {
|
|
349
|
+
description: "Cancel a non-terminal run (marks it cancelled, terminalizes pending/running/waiting stages, releases the checkout lease). Signals live stage workers via process-group kill (SIGTERM, then SIGKILL escalation) so agent grandchildren are included. Reason is required free-text and stored on the run as cancel_reason.",
|
|
350
|
+
inputSchema: z.object({
|
|
351
|
+
runId: z.string(),
|
|
352
|
+
reason: z.string().min(1),
|
|
353
|
+
}),
|
|
354
|
+
}, async ({ runId, reason }) => {
|
|
355
|
+
const result = await manager.cancelRun(runId, reason);
|
|
356
|
+
if (!result.ok) {
|
|
357
|
+
const fail = result;
|
|
358
|
+
writeAudit(auditLog, {
|
|
359
|
+
caller_id: callerIdFromRequestAuth(),
|
|
360
|
+
surface: getRequestAuth()?.surface ?? "mcp",
|
|
361
|
+
action: "cancel_run",
|
|
362
|
+
target_run_id: runId,
|
|
363
|
+
outcome: "error",
|
|
364
|
+
});
|
|
365
|
+
return textResult({ error: fail.reason, status: fail.status }, true);
|
|
366
|
+
}
|
|
367
|
+
writeAudit(auditLog, {
|
|
368
|
+
caller_id: callerIdFromRequestAuth(),
|
|
369
|
+
surface: getRequestAuth()?.surface ?? "mcp",
|
|
370
|
+
action: "cancel_run",
|
|
371
|
+
target_run_id: runId,
|
|
372
|
+
outcome: "ok",
|
|
373
|
+
});
|
|
374
|
+
return textResult({
|
|
375
|
+
ok: true,
|
|
376
|
+
runId: result.runId,
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
server.registerTool("delete_run", {
|
|
380
|
+
description: "Hard-delete a terminal run (store rows, workspace, worktree, run branch, and A2A tasks/artifacts). Active runs (created/queued/running) require force: true, which cancels first then deletes. Irreversible.",
|
|
381
|
+
inputSchema: z.object({
|
|
382
|
+
runId: z.string(),
|
|
383
|
+
force: z.boolean().optional(),
|
|
384
|
+
}),
|
|
385
|
+
}, async ({ runId, force }) => {
|
|
386
|
+
const result = await manager.deleteRun(runId, {
|
|
387
|
+
force,
|
|
388
|
+
channel: "mcp",
|
|
389
|
+
});
|
|
390
|
+
if (!result.ok) {
|
|
391
|
+
const fail = result;
|
|
392
|
+
writeAudit(auditLog, {
|
|
393
|
+
caller_id: callerIdFromRequestAuth(),
|
|
394
|
+
surface: getRequestAuth()?.surface ?? "mcp",
|
|
395
|
+
action: "delete_run",
|
|
396
|
+
target_run_id: runId,
|
|
397
|
+
outcome: "error",
|
|
398
|
+
});
|
|
399
|
+
return textResult({ error: fail.reason, status: fail.status }, true);
|
|
400
|
+
}
|
|
401
|
+
writeAudit(auditLog, {
|
|
402
|
+
caller_id: callerIdFromRequestAuth(),
|
|
403
|
+
surface: getRequestAuth()?.surface ?? "mcp",
|
|
404
|
+
action: "delete_run",
|
|
405
|
+
target_run_id: runId,
|
|
406
|
+
outcome: "ok",
|
|
407
|
+
});
|
|
408
|
+
return textResult({
|
|
409
|
+
ok: true,
|
|
410
|
+
runId: result.runId,
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
server.registerTool("gc_runs", {
|
|
414
|
+
description: "Run retention GC (SLIM then PURGE then bare-cache eviction). Default execute: false is dry-run (report candidates only). execute: true is irreversible bulk reclaim — slimmed/purged runIds and evicted bare caches are returned in the report.",
|
|
415
|
+
inputSchema: z.object({
|
|
416
|
+
execute: z.boolean().optional(),
|
|
417
|
+
}),
|
|
418
|
+
}, async ({ execute }) => {
|
|
419
|
+
const result = await manager.gcRuns({
|
|
420
|
+
execute: execute === true,
|
|
421
|
+
channel: "mcp",
|
|
422
|
+
});
|
|
423
|
+
if (!result.ok) {
|
|
424
|
+
const fail = result;
|
|
425
|
+
return textResult({ error: fail.reason, status: fail.status }, true);
|
|
426
|
+
}
|
|
427
|
+
return textResult({
|
|
428
|
+
slimmed: result.slimmed,
|
|
429
|
+
purged: result.purged,
|
|
430
|
+
bareCachesEvicted: result.bareCachesEvicted,
|
|
431
|
+
});
|
|
432
|
+
});
|
|
279
433
|
server.registerTool("rerun", {
|
|
280
|
-
description: "Start a new run from a completed or failed run's pipeline/task locators. Returns { runId } for the new run.",
|
|
434
|
+
description: "Start a new run from a completed or failed run's pipeline/task locators. Optional pinned: true replays the prior resolved_sha for repository bindings. Returns { runId } for the new run.",
|
|
281
435
|
inputSchema: z.object({
|
|
282
436
|
runId: z.string(),
|
|
437
|
+
pinned: z.boolean().optional(),
|
|
283
438
|
}),
|
|
284
|
-
}, async ({ runId }) => {
|
|
285
|
-
const
|
|
439
|
+
}, async ({ runId, pinned }) => {
|
|
440
|
+
const callerId = callerIdFromRequestAuth();
|
|
441
|
+
const result = await manager.rerun(runId, {
|
|
442
|
+
...(pinned !== undefined ? { pinned } : {}),
|
|
443
|
+
callerId,
|
|
444
|
+
});
|
|
286
445
|
if (!result.ok) {
|
|
446
|
+
writeAudit(auditLog, {
|
|
447
|
+
caller_id: callerId,
|
|
448
|
+
surface: getRequestAuth()?.surface ?? "mcp",
|
|
449
|
+
action: "rerun",
|
|
450
|
+
target_run_id: runId,
|
|
451
|
+
outcome: "error",
|
|
452
|
+
...(result.code !== undefined ? { error_code: result.code } : {}),
|
|
453
|
+
});
|
|
287
454
|
return textResult({
|
|
288
455
|
...mapStartFailure(result),
|
|
289
456
|
...(result.status !== undefined ? { status: result.status } : {}),
|
|
290
457
|
}, true);
|
|
291
458
|
}
|
|
459
|
+
writeAudit(auditLog, {
|
|
460
|
+
caller_id: callerId,
|
|
461
|
+
surface: getRequestAuth()?.surface ?? "mcp",
|
|
462
|
+
action: "rerun",
|
|
463
|
+
target_run_id: result.runId,
|
|
464
|
+
outcome: "ok",
|
|
465
|
+
});
|
|
292
466
|
return textResult({ runId: result.runId });
|
|
293
467
|
});
|
|
294
468
|
}
|
package/dist/mcp/deps.d.ts
CHANGED