stageflow 0.23.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -5
- package/dist/a2a/configDiscovery.d.ts +9 -0
- package/dist/a2a/configDiscovery.js +18 -0
- package/dist/a2a/contracts.d.ts +94 -0
- package/dist/a2a/contracts.js +164 -0
- package/dist/a2a/limits.d.ts +14 -0
- package/dist/a2a/limits.js +29 -0
- package/dist/a2a/registry.d.ts +46 -0
- package/dist/a2a/registry.js +178 -0
- package/dist/a2a/server.d.ts +36 -0
- package/dist/a2a/server.js +344 -0
- package/dist/a2a/service.d.ts +97 -0
- package/dist/a2a/service.js +545 -0
- package/dist/a2a/store.d.ts +109 -0
- package/dist/a2a/store.js +202 -0
- package/dist/agent/activity.d.ts +3 -0
- package/dist/agent/bootProviderConfig.d.ts +21 -0
- package/dist/agent/bootProviderConfig.js +74 -0
- package/dist/agent/piAdapter.d.ts +9 -1
- package/dist/agent/piAdapter.js +58 -3
- package/dist/agent/piIsolatedMcp.d.ts +2 -0
- package/dist/agent/piIsolatedMcp.js +10 -2
- package/dist/agent/port.d.ts +6 -0
- package/dist/agent/streamLogRedact.d.ts +1 -1
- package/dist/agent/streamLogRedact.js +4 -11
- package/dist/cli/a2aCommand.d.ts +8 -0
- package/dist/cli/a2aCommand.js +131 -0
- package/dist/cli/artifactCommand.js +9 -16
- package/dist/cli/backupCommand.d.ts +9 -0
- package/dist/cli/backupCommand.js +111 -0
- package/dist/cli/debugRunCommand.d.ts +10 -0
- package/dist/cli/debugRunCommand.js +109 -0
- package/dist/cli/doctorCommand.d.ts +32 -0
- package/dist/cli/doctorCommand.js +453 -0
- package/dist/cli/envelopeCommand.js +9 -2
- package/dist/cli/exportAllCommand.d.ts +55 -0
- package/dist/cli/exportAllCommand.js +218 -0
- package/dist/cli/exportRunCommand.js +23 -21
- package/dist/cli/hostClient.d.ts +21 -3
- package/dist/cli/hostClient.js +93 -12
- package/dist/cli/initTemplates.d.ts +1 -1
- package/dist/cli/initTemplates.js +8 -1
- package/dist/cli/resolveSafeOutPath.d.ts +2 -0
- package/dist/cli/resolveSafeOutPath.js +40 -0
- package/dist/cli/restoreCommand.d.ts +10 -0
- package/dist/cli/restoreCommand.js +90 -0
- package/dist/cli/runCommand.d.ts +3 -2
- package/dist/cli/runCommand.js +93 -11
- package/dist/cli/runOutput.d.ts +4 -0
- package/dist/cli/runOutput.js +33 -7
- package/dist/cli/runStageCommand.d.ts +34 -0
- package/dist/cli/runStageCommand.js +426 -0
- package/dist/cli/runsCommand.d.ts +1 -1
- package/dist/cli/runsCommand.js +162 -8
- package/dist/cli.js +190 -30
- package/dist/config/catalogRelativePath.d.ts +62 -0
- package/dist/config/catalogRelativePath.js +118 -0
- package/dist/config/configOrigin.d.ts +27 -0
- package/dist/config/configOrigin.js +59 -0
- package/dist/config/hostConfig.d.ts +55 -0
- package/dist/config/hostConfig.js +333 -0
- package/dist/config/listSkills.d.ts +26 -0
- package/dist/config/listSkills.js +190 -3
- package/dist/config/loadOutcome.d.ts +1 -1
- package/dist/config/loadPipeline.js +23 -2
- package/dist/config/loadStage.js +18 -0
- package/dist/config/loadTask.d.ts +2 -0
- package/dist/config/loadTask.js +57 -18
- package/dist/config/materializeStageModels.js +5 -1
- package/dist/config/mergePipelineIncludes.d.ts +3 -0
- package/dist/config/mergePipelineIncludes.js +19 -0
- package/dist/config/migrateYaml.js +6 -11
- package/dist/config/multiProjectCatalog.d.ts +30 -0
- package/dist/config/multiProjectCatalog.js +142 -0
- package/dist/config/normalizePipelineStageEntry.js +20 -1
- package/dist/config/pipelineStageKeys.js +2 -0
- package/dist/config/resolveCatalogRoots.d.ts +27 -0
- package/dist/config/resolveCatalogRoots.js +76 -0
- package/dist/config/resolveModel.d.ts +7 -1
- package/dist/config/resolveModel.js +11 -1
- package/dist/config/resolveStageMcpServers.d.ts +9 -1
- package/dist/config/resolveStageMcpServers.js +36 -9
- package/dist/config/secretFromEnvOrFile.d.ts +9 -0
- package/dist/config/secretFromEnvOrFile.js +34 -0
- package/dist/config/seededCatalog.d.ts +11 -0
- package/dist/config/seededCatalog.js +29 -0
- package/dist/config/toolRequires.d.ts +24 -0
- package/dist/config/toolRequires.js +115 -0
- package/dist/config/validateCatalog.d.ts +5 -1
- package/dist/config/validateCatalog.js +140 -1
- package/dist/diagnostics/checks.d.ts +39 -0
- package/dist/diagnostics/checks.js +135 -0
- package/dist/errors/codes.d.ts +14 -0
- package/dist/errors/codes.js +59 -0
- package/dist/git/cache.d.ts +14 -0
- package/dist/git/cache.js +150 -0
- package/dist/git/credentials.d.ts +9 -0
- package/dist/git/credentials.js +88 -0
- package/dist/git/errors.d.ts +20 -0
- package/dist/git/errors.js +94 -0
- package/dist/git/exec.d.ts +16 -0
- package/dist/git/exec.js +135 -0
- package/dist/git/operations.d.ts +29 -0
- package/dist/git/operations.js +153 -0
- package/dist/git/version.d.ts +1 -0
- package/dist/git/version.js +10 -0
- package/dist/logging/audit.d.ts +16 -0
- package/dist/logging/audit.js +19 -0
- package/dist/logging/commonWords.d.ts +2 -0
- package/dist/logging/commonWords.js +13 -0
- package/dist/logging/logger.d.ts +49 -0
- package/dist/logging/logger.js +193 -0
- package/dist/logging/namedSecrets.d.ts +6 -0
- package/dist/logging/namedSecrets.js +58 -0
- package/dist/logging/redact.d.ts +13 -0
- package/dist/logging/redact.js +88 -0
- package/dist/mcp/catalogTools.js +591 -76
- package/dist/mcp/checkoutTools.d.ts +52 -0
- package/dist/mcp/checkoutTools.js +332 -0
- package/dist/mcp/controlTools.js +179 -5
- package/dist/mcp/deps.d.ts +1 -0
- package/dist/mcp/getStartedTool.d.ts +3 -0
- package/dist/mcp/getStartedTool.js +62 -0
- package/dist/mcp/readArtifact.d.ts +11 -0
- package/dist/mcp/readArtifact.js +46 -30
- package/dist/mcp/server.js +1 -0
- package/dist/mcp/tools.js +4 -0
- package/dist/net/proxy.d.ts +14 -0
- package/dist/net/proxy.js +78 -0
- package/dist/package-meta.d.ts +2 -1
- package/dist/package-meta.js +2 -1
- package/dist/preflight/bash.d.ts +8 -0
- package/dist/preflight/bash.js +34 -0
- package/dist/preflight/claudeRoot.d.ts +11 -0
- package/dist/preflight/claudeRoot.js +23 -0
- package/dist/preflight/mcpCommands.d.ts +8 -0
- package/dist/preflight/mcpCommands.js +36 -0
- package/dist/preflight/pipelinePreflight.d.ts +40 -0
- package/dist/preflight/pipelinePreflight.js +192 -0
- package/dist/preflight/tls.d.ts +6 -0
- package/dist/preflight/tls.js +18 -0
- package/dist/preflight/toolchain.d.ts +45 -0
- package/dist/preflight/toolchain.js +219 -0
- package/dist/project/findProjectRoot.js +3 -4
- package/dist/project/globalHome.d.ts +7 -0
- package/dist/project/globalHome.js +63 -2
- package/dist/project/resolveProjectContext.js +2 -2
- package/dist/project/resolveStageflowContext.js +2 -2
- package/dist/projection/projectRun.d.ts +2 -1
- package/dist/projection/projectRun.js +1 -0
- package/dist/runstore/assertTmpdir.d.ts +1 -0
- package/dist/runstore/assertTmpdir.js +21 -0
- package/dist/runstore/backup.d.ts +52 -0
- package/dist/runstore/backup.js +292 -0
- package/dist/runstore/createStore.d.ts +27 -0
- package/dist/runstore/createStore.js +75 -7
- package/dist/runstore/debugBundle.d.ts +60 -0
- package/dist/runstore/debugBundle.js +143 -0
- package/dist/runstore/diskUsage.d.ts +50 -0
- package/dist/runstore/diskUsage.js +214 -0
- package/dist/runstore/exportRunPayload.d.ts +8 -0
- package/dist/runstore/exportRunPayload.js +23 -0
- package/dist/runstore/normalizeCatalogPath.d.ts +1 -0
- package/dist/runstore/normalizeCatalogPath.js +10 -0
- package/dist/runstore/paths.d.ts +5 -0
- package/dist/runstore/paths.js +145 -1
- package/dist/runstore/port.d.ts +119 -8
- package/dist/runstore/port.js +8 -1
- package/dist/runstore/restore.d.ts +81 -0
- package/dist/runstore/restore.js +355 -0
- package/dist/runstore/retention.d.ts +27 -0
- package/dist/runstore/retention.js +74 -0
- package/dist/runstore/runManifest.d.ts +146 -0
- package/dist/runstore/runManifest.js +288 -0
- package/dist/runstore/runProjection.d.ts +3 -1
- package/dist/runstore/runProjection.js +63 -1
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +37 -3
- package/dist/runstore/sqlite/SqliteRunStore.js +401 -227
- package/dist/runstore/sqlite/applyStorePragmas.d.ts +39 -0
- package/dist/runstore/sqlite/applyStorePragmas.js +145 -0
- package/dist/runstore/sqlite/migrations/001-baseline.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/001-baseline.js +10 -0
- package/dist/runstore/sqlite/migrations/002-repository-binding.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/002-repository-binding.js +29 -0
- package/dist/runstore/sqlite/migrations/003-run-lifecycle.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/003-run-lifecycle.js +28 -0
- package/dist/runstore/sqlite/migrations/004-auto-resume-count.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/004-auto-resume-count.js +19 -0
- package/dist/runstore/sqlite/migrations/005-config-origins.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/005-config-origins.js +19 -0
- package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/006-pipeline-body-and-caller.js +28 -0
- package/dist/runstore/sqlite/migrations/007-projects-registry.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/007-projects-registry.js +31 -0
- package/dist/runstore/sqlite/migrations/index.d.ts +21 -0
- package/dist/runstore/sqlite/migrations/index.js +72 -0
- package/dist/runstore/sqlite/schema.d.ts +20 -1
- package/dist/runstore/sqlite/schema.js +283 -1
- package/dist/runstore/sqlite/storeOpenError.d.ts +6 -0
- package/dist/runstore/sqlite/storeOpenError.js +11 -0
- package/dist/runstore/sqlite/storeSchemaError.d.ts +5 -0
- package/dist/runstore/sqlite/storeSchemaError.js +8 -0
- package/dist/runstore/stageExecution.js +3 -0
- package/dist/runstore/storeFilesystem.d.ts +32 -0
- package/dist/runstore/storeFilesystem.js +148 -0
- package/dist/runstore/submission.d.ts +11 -0
- package/dist/runstore/submission.js +7 -0
- package/dist/runstore/trackProjection.js +2 -0
- package/dist/runstore/workspaceLayout.d.ts +13 -0
- package/dist/runstore/workspaceLayout.js +76 -0
- package/dist/runtime/completionCheckRunner.d.ts +3 -0
- package/dist/runtime/completionCheckRunner.js +45 -7
- package/dist/runtime/containerLimits.d.ts +16 -0
- package/dist/runtime/containerLimits.js +84 -0
- package/dist/runtime/credentialMaterialisation.d.ts +28 -0
- package/dist/runtime/credentialMaterialisation.js +128 -0
- package/dist/runtime/gitCheckoutCapability.js +7 -13
- package/dist/runtime/pipelineRunner.d.ts +38 -1
- package/dist/runtime/pipelineRunner.js +179 -15
- package/dist/runtime/pipelineScheduler.d.ts +15 -0
- package/dist/runtime/pipelineScheduler.js +167 -42
- package/dist/runtime/reloadRunCatalog.js +12 -1
- package/dist/runtime/repositoryMaterialize.d.ts +47 -0
- package/dist/runtime/repositoryMaterialize.js +235 -0
- package/dist/runtime/resolveEnvelopeRef.d.ts +30 -0
- package/dist/runtime/resolveEnvelopeRef.js +79 -0
- package/dist/runtime/resumeTimedOut.d.ts +1 -1
- package/dist/runtime/resumeTimedOut.js +5 -2
- package/dist/runtime/runChangeBus.js +9 -0
- package/dist/runtime/runDeletion.d.ts +7 -0
- package/dist/runtime/runDeletion.js +37 -0
- package/dist/runtime/runManager.d.ts +179 -4
- package/dist/runtime/runManager.js +1644 -83
- package/dist/runtime/runRetentionSweep.d.ts +31 -0
- package/dist/runtime/runRetentionSweep.js +328 -0
- package/dist/runtime/runRetryCoordinator.d.ts +2 -0
- package/dist/runtime/runRetryCoordinator.js +19 -2
- package/dist/runtime/runSkills.d.ts +40 -0
- package/dist/runtime/runSkills.js +173 -0
- package/dist/runtime/stageAttemptBootstrap.d.ts +5 -1
- package/dist/runtime/stageAttemptBootstrap.js +195 -24
- package/dist/runtime/stageCacheEnv.d.ts +6 -0
- package/dist/runtime/stageCacheEnv.js +34 -0
- package/dist/runtime/stageConcurrency.d.ts +2 -1
- package/dist/runtime/stageConcurrency.js +4 -2
- package/dist/runtime/stageEnvironment.d.ts +38 -0
- package/dist/runtime/stageEnvironment.js +193 -0
- package/dist/runtime/stageProcessLauncher.d.ts +18 -0
- package/dist/runtime/stageProcessLauncher.js +194 -38
- package/dist/runtime/stageRecovery.d.ts +3 -1
- package/dist/runtime/stageRecovery.js +19 -4
- package/dist/runtime/stageRoots.d.ts +38 -1
- package/dist/runtime/stageRoots.js +118 -0
- package/dist/runtime/stageRunner.d.ts +1 -0
- package/dist/runtime/stageRunner.js +3 -1
- package/dist/runtime/stageSecretDecl.d.ts +9 -0
- package/dist/runtime/stageSecretDecl.js +102 -0
- package/dist/runtime/stageSecrets.d.ts +40 -0
- package/dist/runtime/stageSecrets.js +181 -0
- package/dist/runtime/stageWorker.d.ts +3 -2
- package/dist/runtime/stageWorker.js +58 -10
- package/dist/runtime/stageWorkerProtocol.d.ts +5 -0
- package/dist/runtime/stageWorkerProtocol.js +8 -0
- package/dist/runtime/startPayload.d.ts +32 -0
- package/dist/runtime/startPayload.js +59 -0
- package/dist/runtime/taskInput.js +14 -5
- package/dist/runtime/verifiedStageExecution.d.ts +1 -0
- package/dist/runtime/verifiedStageExecution.js +2 -1
- package/dist/runtime/workspaceBinding.d.ts +20 -0
- package/dist/runtime/workspaceBinding.js +60 -0
- package/dist/server/allowedHosts.d.ts +19 -0
- package/dist/server/allowedHosts.js +179 -0
- package/dist/server/bootstrap.d.ts +38 -2
- package/dist/server/bootstrap.js +219 -4
- package/dist/server/controlToken.d.ts +47 -0
- package/dist/server/controlToken.js +241 -0
- package/dist/server/createHttpHost.d.ts +11 -2
- package/dist/server/createHttpHost.js +109 -10
- package/dist/server/ensureGlobalService.d.ts +5 -1
- package/dist/server/ensureGlobalService.js +35 -1
- package/dist/server/healthSurfaces.d.ts +6 -0
- package/dist/server/healthSurfaces.js +98 -0
- package/dist/server/http.d.ts +12 -1
- package/dist/server/http.js +1085 -485
- package/dist/server/listenHost.d.ts +5 -0
- package/dist/server/listenHost.js +56 -0
- package/dist/server/mcpHost.d.ts +10 -1
- package/dist/server/mcpHost.js +36 -6
- package/dist/server/operatorResults.d.ts +2 -2
- package/dist/server/operatorResults.js +40 -29
- package/dist/server/requestAuthContext.d.ts +12 -0
- package/dist/server/requestAuthContext.js +21 -0
- package/dist/server/shutdown.d.ts +69 -0
- package/dist/server/shutdown.js +219 -0
- package/dist/types/pipeline.d.ts +7 -0
- package/dist/types/stage.d.ts +8 -0
- package/dist/types/task.d.ts +8 -0
- package/dist/ui/assets/index-B6hlSXXn.js +120 -0
- package/dist/ui/index.html +1 -1
- package/examples/README.md +98 -0
- package/examples/archify-on-pr/README.md +213 -0
- package/examples/archify-on-pr/archify-on-pr.pipeline.yaml +19 -0
- package/examples/archify-on-pr/archify-on-pr.task.yaml +19 -0
- package/examples/archify-on-pr/author-diagrams.yaml +106 -0
- package/examples/archify-on-pr/detect-changes.yaml +89 -0
- package/examples/ci-validate/README.md +35 -0
- package/examples/ci-validate/check.yaml +13 -0
- package/examples/ci-validate/ci-demo.pipeline.yaml +4 -0
- package/examples/ci-validate/validate.sh +5 -0
- package/examples/compliance-review-demo/README.md +125 -0
- package/examples/compliance-review-demo/compliance-review-demo.pipeline.yaml +29 -0
- package/examples/compliance-review-demo/connect-account.yaml +47 -0
- package/examples/compliance-review-demo/map-to-control.yaml +123 -0
- package/examples/compliance-review-demo/poll-bucket-config.yaml +103 -0
- package/examples/compliance-review-demo/publish-report.yaml +79 -0
- package/examples/compliance-review-demo/review-verdict.yaml +122 -0
- package/examples/compliance-review-demo/run-compliance-check.yaml +96 -0
- package/examples/compliance-review-demo/store-evidence.yaml +143 -0
- package/examples/conditional-fork/README.md +89 -0
- package/examples/conditional-fork/branch-a.yaml +13 -0
- package/examples/conditional-fork/branch-b.yaml +13 -0
- package/examples/conditional-fork/decide.yaml +35 -0
- package/examples/conditional-fork/fork-demo.pipeline.yaml +20 -0
- package/examples/conditional-fork/fork-demo.task.yaml +8 -0
- package/examples/context7-mcp/README.md +42 -0
- package/examples/context7-mcp/context7-mcp.pipeline.yaml +15 -0
- package/examples/context7-mcp/context7-mcp.task.yaml +4 -0
- package/examples/context7-mcp/fetch-docs.yaml +52 -0
- package/examples/context7-mcp/resolve-library.yaml +31 -0
- package/examples/context7-mcp/write-brief.yaml +52 -0
- package/examples/feature-loop/README.md +104 -0
- package/examples/feature-loop/address-feedback.yaml +148 -0
- package/examples/feature-loop/align.yaml +116 -0
- package/examples/feature-loop/decompose.yaml +86 -0
- package/examples/feature-loop/default-model-hierarchy.task.yaml +58 -0
- package/examples/feature-loop/feature-loop.pipeline.yaml +140 -0
- package/examples/feature-loop/feature-loop.task.yaml +25 -0
- package/examples/feature-loop/implement.yaml +128 -0
- package/examples/feature-loop/plan.yaml +111 -0
- package/examples/feature-loop/publish.yaml +167 -0
- package/examples/feature-loop/review.yaml +146 -0
- package/examples/feature-loop/verify.yaml +106 -0
- package/examples/feedback-loop/README.md +72 -0
- package/examples/feedback-loop/VERIFY.md +208 -0
- package/examples/feedback-loop/continue-only.task.yaml +4 -0
- package/examples/feedback-loop/exhaust-require-continue.task.yaml +6 -0
- package/examples/feedback-loop/exhaust-wait-human.task.yaml +11 -0
- package/examples/feedback-loop/feedback-loop-wait-human.pipeline.yaml +23 -0
- package/examples/feedback-loop/feedback-loop.pipeline.yaml +23 -0
- package/examples/feedback-loop/feedback-loop.task.yaml +4 -0
- package/examples/feedback-loop/implement.yaml +14 -0
- package/examples/feedback-loop/plan.yaml +14 -0
- package/examples/feedback-loop/review.yaml +15 -0
- package/examples/feedback-loop/send-back-once.task.yaml +6 -0
- package/examples/feedback-loop/submit.yaml +12 -0
- package/examples/generic-fan-in/README.md +151 -0
- package/examples/generic-fan-in/clarify.yaml +18 -0
- package/examples/generic-fan-in/generic-fan-in-accepted.pipeline.yaml +19 -0
- package/examples/generic-fan-in/generic-fan-in-accepted.task.yaml +8 -0
- package/examples/generic-fan-in/generic-fan-in.pipeline.yaml +18 -0
- package/examples/generic-fan-in/generic-fan-in.task.yaml +9 -0
- package/examples/generic-fan-in/research.yaml +45 -0
- package/examples/generic-fan-in/synthesize.yaml +66 -0
- package/examples/generic-fan-in/validation.yaml +45 -0
- package/examples/github-release/README.md +78 -0
- package/examples/github-release/draft-release-notes.yaml +64 -0
- package/examples/github-release/github-release.pipeline.yaml +11 -0
- package/examples/github-release/github-release.task.yaml +13 -0
- package/examples/github-release/publish-github-release.yaml +64 -0
- package/examples/hello-world/README.md +28 -0
- package/examples/hello-world/hello.pipeline.yaml +4 -0
- package/examples/hello-world/my-task.task.yaml +6 -0
- package/examples/hello-world/research.yaml +18 -0
- package/examples/mcp-hitl-tour/README.md +113 -0
- package/examples/mcp-hitl-tour/draft-angle.yaml +33 -0
- package/examples/mcp-hitl-tour/draft-short.yaml +32 -0
- package/examples/mcp-hitl-tour/emit-angles.yaml +45 -0
- package/examples/mcp-hitl-tour/gather.yaml +31 -0
- package/examples/mcp-hitl-tour/intake.yaml +62 -0
- package/examples/mcp-hitl-tour/mcp-hitl-tour-exhaust.task.yaml +13 -0
- package/examples/mcp-hitl-tour/mcp-hitl-tour.pipeline.yaml +54 -0
- package/examples/mcp-hitl-tour/mcp-hitl-tour.task.yaml +16 -0
- package/examples/mcp-hitl-tour/polish.yaml +33 -0
- package/examples/mcp-hitl-tour/review.yaml +17 -0
- package/examples/mcp-hitl-tour/ship.yaml +25 -0
- package/examples/oss-issue-contribution/README.md +218 -0
- package/examples/oss-issue-contribution/oss-address-review-feedback.yaml +117 -0
- package/examples/oss-issue-contribution/oss-approve-contribution.yaml +181 -0
- package/examples/oss-issue-contribution/oss-approve-plan.yaml +111 -0
- package/examples/oss-issue-contribution/oss-explain-fix.yaml +108 -0
- package/examples/oss-issue-contribution/oss-explain-issue.yaml +114 -0
- package/examples/oss-issue-contribution/oss-implement-source-fix.yaml +171 -0
- package/examples/oss-issue-contribution/oss-investigate-area.yaml +116 -0
- package/examples/oss-issue-contribution/oss-issue-contribution.pipeline.yaml +125 -0
- package/examples/oss-issue-contribution/oss-issue-intake.yaml +106 -0
- package/examples/oss-issue-contribution/oss-plan-investigation.yaml +112 -0
- package/examples/oss-issue-contribution/oss-plan-review.yaml +109 -0
- package/examples/oss-issue-contribution/oss-reproduce-issue.yaml +140 -0
- package/examples/oss-issue-contribution/oss-review-change.yaml +107 -0
- package/examples/oss-issue-contribution/oss-verify-fix.yaml +130 -0
- package/examples/oss-issue-contribution/oss-write-regression-test.yaml +135 -0
- package/examples/oss-issue-contribution/pi-7629.task.yaml +79 -0
- package/examples/oss-issue-contribution/pi-8919.task.yaml +75 -0
- package/examples/oss-issue-contribution/pydantic-ai-7971.task.yaml +53 -0
- package/examples/oss-quick-fix/README.md +65 -0
- package/examples/oss-quick-fix/implement-fix.yaml +84 -0
- package/examples/oss-quick-fix/oss-quick-fix.pipeline.yaml +35 -0
- package/examples/oss-quick-fix/oss-quick-fix.task.yaml +19 -0
- package/examples/oss-quick-fix/ship-fix.yaml +81 -0
- package/examples/oss-quick-fix/understand-issue.yaml +67 -0
- package/examples/oss-quick-fix/verify-fix.yaml +73 -0
- package/examples/plan-review/README.md +37 -0
- package/examples/plan-review/plan-review-followup.yaml +13 -0
- package/examples/plan-review/plan-review.pipeline.yaml +9 -0
- package/examples/plan-review/plan-review.task.yaml +9 -0
- package/examples/plan-review/plan-review.yaml +25 -0
- package/examples/playwright-mcp/README.md +39 -0
- package/examples/playwright-mcp/playwright-mcp.pipeline.yaml +5 -0
- package/examples/playwright-mcp/playwright-mcp.task.yaml +4 -0
- package/examples/playwright-mcp/screenshot.yaml +40 -0
- package/examples/retry-tour/README.md +75 -0
- package/examples/retry-tour/retry-tour.pipeline.yaml +122 -0
- package/examples/retry-tour/retry-tour.task.yaml +9 -0
- package/examples/route-if-tour/README.md +202 -0
- package/examples/route-if-tour/route-if-tour.pipeline.yaml +950 -0
- package/examples/route-if-tour/route-if-tour.task.yaml +4 -0
- package/examples/route-wiring-smoke-test/01-core-routing.pipeline.yaml +168 -0
- package/examples/route-wiring-smoke-test/02-on-gating.pipeline.yaml +44 -0
- package/examples/route-wiring-smoke-test/03-two-entry-points.pipeline.yaml +28 -0
- package/examples/route-wiring-smoke-test/04-entry-false-equivalent-to-omitted.pipeline.yaml +27 -0
- package/examples/route-wiring-smoke-test/05-fork-choice.pipeline.yaml +110 -0
- package/examples/route-wiring-smoke-test/06-fan-out-fan-in.pipeline.yaml +82 -0
- package/examples/route-wiring-smoke-test/07-loop-human-decision.pipeline.yaml +82 -0
- package/examples/route-wiring-smoke-test/08-skip-fallback-and-multi-on-gate.pipeline.yaml +77 -0
- package/examples/route-wiring-smoke-test/09-multi-loop-targets.pipeline.yaml +102 -0
- package/examples/route-wiring-smoke-test/10-uses-dialect-fork.pipeline.yaml +23 -0
- package/examples/route-wiring-smoke-test/11-sequential-io-handoff.pipeline.yaml +37 -0
- package/examples/route-wiring-smoke-test/12-complex-io-schemas.pipeline.yaml +138 -0
- package/examples/route-wiring-smoke-test/13-ref-io-handoff.pipeline.yaml +84 -0
- package/examples/route-wiring-smoke-test/14-if-eq-gating.pipeline.yaml +50 -0
- package/examples/route-wiring-smoke-test/15-if-all-gated.pipeline.yaml +37 -0
- package/examples/route-wiring-smoke-test/16-if-composition.pipeline.yaml +65 -0
- package/examples/route-wiring-smoke-test/17-if-join.pipeline.yaml +80 -0
- package/examples/route-wiring-smoke-test/README.md +377 -0
- package/examples/route-wiring-smoke-test/rejected/01-reject-legacy-needs.pipeline.yaml +26 -0
- package/examples/route-wiring-smoke-test/rejected/02-reject-legacy-fork.pipeline.yaml +25 -0
- package/examples/route-wiring-smoke-test/rejected/03-reject-legacy-feedback-loop.pipeline.yaml +30 -0
- package/examples/route-wiring-smoke-test/rejected/04-reject-missing-entry.pipeline.yaml +24 -0
- package/examples/route-wiring-smoke-test/rejected/05-reject-unreachable.pipeline.yaml +35 -0
- package/examples/route-wiring-smoke-test/rejected/06-reject-allow-none-without-route-select.pipeline.yaml +37 -0
- package/examples/route-wiring-smoke-test/rejected/07-reject-cycle.pipeline.yaml +27 -0
- package/examples/route-wiring-smoke-test/rejected/08-reject-loop-non-ancestor.pipeline.yaml +42 -0
- package/examples/route-wiring-smoke-test/rejected/09-reject-route-select-leaf.pipeline.yaml +26 -0
- package/examples/route-wiring-smoke-test/rejected/12-reject-loop-replay-unsafe.pipeline.yaml +55 -0
- package/examples/route-wiring-smoke-test/rejected/13-reject-multiple-loop-entries.pipeline.yaml +51 -0
- package/examples/route-wiring-smoke-test/rejected/14-reject-duplicate-stage-id.pipeline.yaml +35 -0
- package/examples/route-wiring-smoke-test/rejected/15-reject-unknown-route-target.pipeline.yaml +15 -0
- package/examples/route-wiring-smoke-test/rejected/16-reject-malformed-route-item.pipeline.yaml +15 -0
- package/examples/route-wiring-smoke-test/rejected/17-reject-io-incompatible.pipeline.yaml +33 -0
- package/examples/route-wiring-smoke-test/rejected/18-reject-nested-io.pipeline.yaml +51 -0
- package/examples/route-wiring-smoke-test/rejected/19-reject-array-item-io.pipeline.yaml +55 -0
- package/examples/route-wiring-smoke-test/rejected/20-reject-closed-io.pipeline.yaml +36 -0
- package/examples/route-wiring-smoke-test/rejected/21-reject-ref-io.pipeline.yaml +42 -0
- package/examples/route-wiring-smoke-test/rejected/22-reject-if-unknown-field.pipeline.yaml +33 -0
- package/examples/route-wiring-smoke-test/rejected/23-reject-if-optional-field.pipeline.yaml +32 -0
- package/examples/route-wiring-smoke-test/rejected/24-reject-if-empty-all.pipeline.yaml +31 -0
- package/examples/route-wiring-smoke-test/rejected/25-reject-if-gt-on-string.pipeline.yaml +33 -0
- package/examples/route-wiring-smoke-test/rejected/26-reject-if-optional-nested.pipeline.yaml +36 -0
- package/examples/route-wiring-smoke-test/rejected/27-reject-if-on-loop.pipeline.yaml +63 -0
- package/examples/route-wiring-smoke-test/rejected/29-reject-if-on-failed.pipeline.yaml +46 -0
- package/examples/route-wiring-smoke-test/smoke-test.task.yaml +4 -0
- package/examples/route-wiring-smoke-test/stages/branch-a.yaml +12 -0
- package/examples/route-wiring-smoke-test/stages/branch-b.yaml +12 -0
- package/examples/route-wiring-smoke-test/stages/decide.yaml +12 -0
- package/examples/route-wiring-smoke-test/stages/finish.yaml +12 -0
- package/examples/ship-feature/README.md +190 -0
- package/examples/ship-feature/feat-address-feedback.yaml +119 -0
- package/examples/ship-feature/feat-implement.yaml +180 -0
- package/examples/ship-feature/feat-plan.yaml +120 -0
- package/examples/ship-feature/feat-review.yaml +109 -0
- package/examples/ship-feature/feat-ship.yaml +203 -0
- package/examples/ship-feature/ship-feature.pipeline.yaml +44 -0
- package/examples/ship-feature/ship-feature.task.yaml +78 -0
- package/examples/stage-mcp/README.md +144 -0
- package/examples/stage-mcp/echo-mcp.mjs +20 -0
- package/examples/stage-mcp/stage-mcp-dead.pipeline.yaml +5 -0
- package/examples/stage-mcp/stage-mcp-dead.task.yaml +3 -0
- package/examples/stage-mcp/stage-mcp-missing-var.pipeline.yaml +5 -0
- package/examples/stage-mcp/stage-mcp-missing-var.task.yaml +3 -0
- package/examples/stage-mcp/stage-mcp.pipeline.yaml +5 -0
- package/examples/stage-mcp/stage-mcp.task.yaml +4 -0
- package/examples/stage-mcp/use-echo.yaml +20 -0
- package/examples/verify-tour/README.md +80 -0
- package/examples/verify-tour/verify-tour.pipeline.yaml +162 -0
- package/examples/verify-tour/verify-tour.task.yaml +11 -0
- package/package.json +6 -1
- package/skills/stageflow/SKILL.md +6 -6
- package/skills/stageflow/references/control-surface.md +11 -5
- package/skills/stageflow/scripts/detect-host.mjs +14 -1
- package/skills/stageflow/scripts/detect-host.test.mjs +29 -1
- package/skills/stageflow-author/SKILL.md +4 -3
- package/skills/stageflow-author/references/catalog-mapping.md +16 -0
- package/skills/stageflow-author/references/catalog-write-conventions.md +1 -1
- package/skills/stageflow-run/SKILL.md +20 -12
- package/skills/stageflow-run/references/mcp-call.md +9 -1
- package/skills/stageflow-run/references/task-and-pipeline-selection.md +16 -5
- package/skills/stageflow-run/scripts/mcp-call.mjs +46 -6
- package/skills/stageflow-run/scripts/mcp-call.test.mjs +64 -0
- package/skills/stageflow-session-capture/references/catalog-authoring.md +2 -0
- package/skills/stageflow-setup/SKILL.md +40 -8
- package/dist/ui/assets/index-Da5EHU6M.js +0 -119
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { resolveStoreRoot } from "../runstore/paths.js";
|
|
5
|
+
import { MESSAGE_TOMBSTONE_RETENTION_MS, TERMINAL_RETENTION_MS } from "./limits.js";
|
|
6
|
+
function nowIso() {
|
|
7
|
+
return new Date().toISOString();
|
|
8
|
+
}
|
|
9
|
+
export class A2aStore {
|
|
10
|
+
db;
|
|
11
|
+
artifactsRoot;
|
|
12
|
+
ownsConnection;
|
|
13
|
+
/**
|
|
14
|
+
* Uses the SqliteRunStore connection to the same `state.db` file so the two stores share one
|
|
15
|
+
* transaction domain. The Host must open the run store in migrate mode before constructing
|
|
16
|
+
* A2aStore. Additive `kind` / `result_stage_id` columns for run_stage are applied here.
|
|
17
|
+
*/
|
|
18
|
+
constructor(rootDir, connection) {
|
|
19
|
+
this.db = connection;
|
|
20
|
+
this.ownsConnection = false;
|
|
21
|
+
this.migrateAddStandaloneColumns();
|
|
22
|
+
this.artifactsRoot = path.join(resolveStoreRoot(rootDir), "a2a-artifacts");
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Additive migration for a `state.db` created before the run_stage A2A
|
|
26
|
+
* operation existed: `CREATE TABLE IF NOT EXISTS` above never alters an
|
|
27
|
+
* already-existing a2a_tasks table, so a pre-existing one is missing these
|
|
28
|
+
* two columns. Same PRAGMA table_info-guarded ADD COLUMN pattern as
|
|
29
|
+
* src/runstore/sqlite/SqliteRunStore.ts.
|
|
30
|
+
*/
|
|
31
|
+
migrateAddStandaloneColumns() {
|
|
32
|
+
const cols = this.db.prepare(`PRAGMA table_info(a2a_tasks)`).all();
|
|
33
|
+
if (!cols.some((c) => c.name === "kind")) {
|
|
34
|
+
this.db.exec(`ALTER TABLE a2a_tasks ADD COLUMN kind TEXT NOT NULL DEFAULT 'invoke'`);
|
|
35
|
+
}
|
|
36
|
+
if (!cols.some((c) => c.name === "result_stage_id")) {
|
|
37
|
+
this.db.exec(`ALTER TABLE a2a_tasks ADD COLUMN result_stage_id TEXT`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
close() {
|
|
41
|
+
if (this.ownsConnection)
|
|
42
|
+
this.db.close();
|
|
43
|
+
}
|
|
44
|
+
ensureContext(callerId, contextId) {
|
|
45
|
+
if (contextId) {
|
|
46
|
+
const row = this.db
|
|
47
|
+
.prepare("SELECT caller_id FROM a2a_contexts WHERE context_id = ?")
|
|
48
|
+
.get(contextId);
|
|
49
|
+
if (row && row.caller_id !== callerId) {
|
|
50
|
+
throw new Error("Context belongs to a different caller");
|
|
51
|
+
}
|
|
52
|
+
if (row)
|
|
53
|
+
return contextId;
|
|
54
|
+
this.db
|
|
55
|
+
.prepare("INSERT INTO a2a_contexts (context_id, caller_id, created_at) VALUES (?, ?, ?)")
|
|
56
|
+
.run(contextId, callerId, nowIso());
|
|
57
|
+
return contextId;
|
|
58
|
+
}
|
|
59
|
+
const generated = randomUUID();
|
|
60
|
+
this.db
|
|
61
|
+
.prepare("INSERT INTO a2a_contexts (context_id, caller_id, created_at) VALUES (?, ?, ?)")
|
|
62
|
+
.run(generated, callerId, nowIso());
|
|
63
|
+
return generated;
|
|
64
|
+
}
|
|
65
|
+
getMessage(callerId, messageId) {
|
|
66
|
+
const row = this.db
|
|
67
|
+
.prepare("SELECT task_id AS taskId, request_hash AS requestHash, outcome_json AS outcomeJson FROM a2a_messages WHERE caller_id = ? AND message_id = ?")
|
|
68
|
+
.get(callerId, messageId);
|
|
69
|
+
if (!row)
|
|
70
|
+
return undefined;
|
|
71
|
+
return { taskId: row.taskId, requestHash: row.requestHash, outcome: row.outcomeJson ? JSON.parse(row.outcomeJson) : undefined };
|
|
72
|
+
}
|
|
73
|
+
recordMessage(params) {
|
|
74
|
+
this.db
|
|
75
|
+
.prepare("INSERT INTO a2a_messages (caller_id, message_id, task_id, operation, request_hash, outcome_json, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)")
|
|
76
|
+
.run(params.callerId, params.messageId, params.taskId, params.operation, params.requestHash, JSON.stringify(params.outcome), nowIso());
|
|
77
|
+
}
|
|
78
|
+
getTaskBySubmissionKey(key) {
|
|
79
|
+
return this.db.prepare("SELECT * FROM a2a_tasks WHERE submission_key = ?").get(key);
|
|
80
|
+
}
|
|
81
|
+
createTask(params) {
|
|
82
|
+
const at = nowIso();
|
|
83
|
+
this.db
|
|
84
|
+
.prepare(`INSERT INTO a2a_tasks
|
|
85
|
+
(task_id, context_id, caller_id, publication_id, publication_revision, submission_key, run_id, state, result_json, kind, result_stage_id, created_at, updated_at)
|
|
86
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, 'submitted', NULL, ?, ?, ?, ?)`)
|
|
87
|
+
.run(params.taskId, params.contextId, params.callerId, params.publicationId, params.publicationRevision, params.submissionKey, params.runId, params.kind ?? "invoke", params.resultStageId ?? null, at, at);
|
|
88
|
+
return this.getTask(params.taskId);
|
|
89
|
+
}
|
|
90
|
+
getTask(taskId) {
|
|
91
|
+
return this.db.prepare("SELECT * FROM a2a_tasks WHERE task_id = ?").get(taskId);
|
|
92
|
+
}
|
|
93
|
+
listTasksForCaller(callerId, contextId) {
|
|
94
|
+
if (contextId) {
|
|
95
|
+
return this.db
|
|
96
|
+
.prepare("SELECT * FROM a2a_tasks WHERE caller_id = ? AND context_id = ? ORDER BY created_at ASC")
|
|
97
|
+
.all(callerId, contextId);
|
|
98
|
+
}
|
|
99
|
+
return this.db
|
|
100
|
+
.prepare("SELECT * FROM a2a_tasks WHERE caller_id = ? ORDER BY created_at ASC")
|
|
101
|
+
.all(callerId);
|
|
102
|
+
}
|
|
103
|
+
getArtifact(taskId, artifactId) {
|
|
104
|
+
return this.db
|
|
105
|
+
.prepare("SELECT * FROM a2a_artifacts WHERE task_id = ? AND artifact_id = ?")
|
|
106
|
+
.get(taskId, artifactId);
|
|
107
|
+
}
|
|
108
|
+
listArtifacts(taskId) {
|
|
109
|
+
return this.db.prepare("SELECT * FROM a2a_artifacts WHERE task_id = ?").all(taskId);
|
|
110
|
+
}
|
|
111
|
+
/** Freezes a successful outcome exactly once; a second call for an already-terminal task is a no-op. */
|
|
112
|
+
async freezeCompleted(taskId, result) {
|
|
113
|
+
return this.freeze(taskId, "completed", result);
|
|
114
|
+
}
|
|
115
|
+
/** Freezes a failure exactly once; a second call for an already-terminal task is a no-op. */
|
|
116
|
+
async freezeFailed(taskId) {
|
|
117
|
+
return this.freeze(taskId, "failed", undefined);
|
|
118
|
+
}
|
|
119
|
+
async freeze(taskId, state, result) {
|
|
120
|
+
const current = this.getTask(taskId);
|
|
121
|
+
if (!current || current.state === "completed" || current.state === "failed")
|
|
122
|
+
return;
|
|
123
|
+
const artifactRows = [];
|
|
124
|
+
if (result) {
|
|
125
|
+
for (const artifact of result.artifacts) {
|
|
126
|
+
const artifactId = randomUUID();
|
|
127
|
+
const hash = createHash("sha256").update(artifact.bytes).digest("hex");
|
|
128
|
+
const dir = path.join(this.artifactsRoot, taskId);
|
|
129
|
+
await mkdir(dir, { recursive: true });
|
|
130
|
+
const contentPath = path.join(dir, artifactId);
|
|
131
|
+
await writeFile(contentPath, artifact.bytes);
|
|
132
|
+
artifactRows.push({
|
|
133
|
+
artifact_id: artifactId,
|
|
134
|
+
task_id: taskId,
|
|
135
|
+
name: artifact.name,
|
|
136
|
+
media_type: artifact.mediaType ?? null,
|
|
137
|
+
size: artifact.bytes.length,
|
|
138
|
+
content_path: contentPath,
|
|
139
|
+
hash,
|
|
140
|
+
created_at: nowIso(),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const resultJson = result ? JSON.stringify({ summary: result.summary, payload: result.payload }) : null;
|
|
145
|
+
const transact = this.db.transaction(() => {
|
|
146
|
+
const outcome = this.db
|
|
147
|
+
.prepare("UPDATE a2a_tasks SET state = ?, result_json = ?, updated_at = ? WHERE task_id = ? AND state NOT IN ('completed', 'failed')")
|
|
148
|
+
.run(state, resultJson, nowIso(), taskId);
|
|
149
|
+
if (outcome.changes === 0)
|
|
150
|
+
return;
|
|
151
|
+
for (const row of artifactRows) {
|
|
152
|
+
this.db
|
|
153
|
+
.prepare("INSERT INTO a2a_artifacts (artifact_id, task_id, name, media_type, size, content_path, hash, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
|
|
154
|
+
.run(row.artifact_id, row.task_id, row.name, row.media_type, row.size, row.content_path, row.hash, row.created_at);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
transact();
|
|
158
|
+
}
|
|
159
|
+
countNonterminal(callerId) {
|
|
160
|
+
const row = this.db
|
|
161
|
+
.prepare("SELECT COUNT(*) AS n FROM a2a_tasks WHERE caller_id = ? AND state NOT IN ('completed', 'failed')")
|
|
162
|
+
.get(callerId);
|
|
163
|
+
return row.n;
|
|
164
|
+
}
|
|
165
|
+
/** Deletes terminal tasks (and their frozen artifact files) and message tombstones older than the retention window. */
|
|
166
|
+
async pruneExpired(now, terminalRetentionMs = TERMINAL_RETENTION_MS, messageRetentionMs = MESSAGE_TOMBSTONE_RETENTION_MS) {
|
|
167
|
+
const terminalCutoff = new Date(now.getTime() - terminalRetentionMs).toISOString();
|
|
168
|
+
const messageCutoff = new Date(now.getTime() - messageRetentionMs).toISOString();
|
|
169
|
+
const expiredTasks = this.db
|
|
170
|
+
.prepare("SELECT task_id FROM a2a_tasks WHERE state IN ('completed', 'failed') AND updated_at < ?")
|
|
171
|
+
.all(terminalCutoff);
|
|
172
|
+
for (const { task_id: taskId } of expiredTasks) {
|
|
173
|
+
for (const artifact of this.listArtifacts(taskId)) {
|
|
174
|
+
await unlink(artifact.content_path).catch(() => undefined);
|
|
175
|
+
}
|
|
176
|
+
this.db.transaction(() => {
|
|
177
|
+
this.db.prepare("DELETE FROM a2a_artifacts WHERE task_id = ?").run(taskId);
|
|
178
|
+
this.db.prepare("DELETE FROM a2a_messages WHERE task_id = ?").run(taskId);
|
|
179
|
+
this.db.prepare("DELETE FROM a2a_tasks WHERE task_id = ?").run(taskId);
|
|
180
|
+
})();
|
|
181
|
+
}
|
|
182
|
+
const removedMessages = this.db.prepare("DELETE FROM a2a_messages WHERE created_at < ?").run(messageCutoff).changes;
|
|
183
|
+
return { removedTasks: expiredTasks.length, removedMessages };
|
|
184
|
+
}
|
|
185
|
+
/** Deletes every A2A task (and frozen artifact files) bound to a Stageflow run. */
|
|
186
|
+
async deleteByRunId(runId) {
|
|
187
|
+
const tasks = this.db
|
|
188
|
+
.prepare("SELECT task_id FROM a2a_tasks WHERE run_id = ?")
|
|
189
|
+
.all(runId);
|
|
190
|
+
for (const { task_id: taskId } of tasks) {
|
|
191
|
+
for (const artifact of this.listArtifacts(taskId)) {
|
|
192
|
+
await unlink(artifact.content_path).catch(() => undefined);
|
|
193
|
+
}
|
|
194
|
+
this.db.transaction(() => {
|
|
195
|
+
this.db.prepare("DELETE FROM a2a_artifacts WHERE task_id = ?").run(taskId);
|
|
196
|
+
this.db.prepare("DELETE FROM a2a_messages WHERE task_id = ?").run(taskId);
|
|
197
|
+
this.db.prepare("DELETE FROM a2a_tasks WHERE task_id = ?").run(taskId);
|
|
198
|
+
})();
|
|
199
|
+
}
|
|
200
|
+
return { removedTasks: tasks.length };
|
|
201
|
+
}
|
|
202
|
+
}
|
package/dist/agent/activity.d.ts
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ProviderAuthContext } from "./providerAuth.js";
|
|
2
|
+
export type BootProviderResult = {
|
|
3
|
+
configured: string[];
|
|
4
|
+
failures: Array<{
|
|
5
|
+
providerId: string;
|
|
6
|
+
code: string;
|
|
7
|
+
message: string;
|
|
8
|
+
}>;
|
|
9
|
+
};
|
|
10
|
+
export type BootProviderOptions = {
|
|
11
|
+
cwd: string;
|
|
12
|
+
env?: NodeJS.ProcessEnv;
|
|
13
|
+
requireProviders?: string[];
|
|
14
|
+
authContext?: ProviderAuthContext;
|
|
15
|
+
logError?: (message: string) => void;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Configure providers from STAGEFLOW_PROVIDER_<ID>_API_KEY / _FILE at Host boot.
|
|
19
|
+
* Soft-fails unreadable/rejected keys by default; requireProviders makes missing ids fatal.
|
|
20
|
+
*/
|
|
21
|
+
export declare function bootProviderConfig(options: BootProviderOptions): Promise<BootProviderResult>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { loginWithApiKey, } from "./providerAuth.js";
|
|
2
|
+
import { readSecretFromEnvOrFile, SecretFromEnvError, } from "../config/secretFromEnvOrFile.js";
|
|
3
|
+
const PROVIDER_KEY_RE = /^STAGEFLOW_PROVIDER_([A-Za-z0-9_]+)_API_KEY$/;
|
|
4
|
+
const PROVIDER_FILE_RE = /^STAGEFLOW_PROVIDER_([A-Za-z0-9_]+)_API_KEY_FILE$/;
|
|
5
|
+
function discoverProviders(env) {
|
|
6
|
+
const byLower = new Map();
|
|
7
|
+
for (const key of Object.keys(env)) {
|
|
8
|
+
let envId;
|
|
9
|
+
const plain = key.match(PROVIDER_KEY_RE);
|
|
10
|
+
if (plain)
|
|
11
|
+
envId = plain[1];
|
|
12
|
+
else {
|
|
13
|
+
const file = key.match(PROVIDER_FILE_RE);
|
|
14
|
+
if (file)
|
|
15
|
+
envId = file[1];
|
|
16
|
+
}
|
|
17
|
+
if (envId === undefined)
|
|
18
|
+
continue;
|
|
19
|
+
const providerId = envId.toLowerCase().replace(/_/g, "-");
|
|
20
|
+
if (!byLower.has(providerId)) {
|
|
21
|
+
byLower.set(providerId, { envId, providerId });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return [...byLower.values()].sort((a, b) => a.providerId.localeCompare(b.providerId));
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Configure providers from STAGEFLOW_PROVIDER_<ID>_API_KEY / _FILE at Host boot.
|
|
28
|
+
* Soft-fails unreadable/rejected keys by default; requireProviders makes missing ids fatal.
|
|
29
|
+
*/
|
|
30
|
+
export async function bootProviderConfig(options) {
|
|
31
|
+
const env = options.env ?? process.env;
|
|
32
|
+
const logError = options.logError ?? ((message) => console.error(message));
|
|
33
|
+
const configured = [];
|
|
34
|
+
const failures = [];
|
|
35
|
+
for (const { envId, providerId } of discoverProviders(env)) {
|
|
36
|
+
const envName = `STAGEFLOW_PROVIDER_${envId}_API_KEY`;
|
|
37
|
+
let secret;
|
|
38
|
+
try {
|
|
39
|
+
secret = readSecretFromEnvOrFile(env, envName);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
43
|
+
if (err instanceof SecretFromEnvError &&
|
|
44
|
+
message.includes("not both")) {
|
|
45
|
+
throw err;
|
|
46
|
+
}
|
|
47
|
+
const code = err instanceof SecretFromEnvError ? err.code : "config_invalid";
|
|
48
|
+
failures.push({ providerId, code, message });
|
|
49
|
+
logError(`stageflow: provider ${providerId} boot failed: ${message}`);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (secret === undefined)
|
|
53
|
+
continue;
|
|
54
|
+
try {
|
|
55
|
+
await loginWithApiKey(options.cwd, providerId, secret, options.authContext);
|
|
56
|
+
configured.push(providerId);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
60
|
+
failures.push({
|
|
61
|
+
providerId,
|
|
62
|
+
code: "provider_not_configured",
|
|
63
|
+
message,
|
|
64
|
+
});
|
|
65
|
+
logError(`stageflow: provider ${providerId} boot failed: ${message}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const required = (options.requireProviders ?? []).map((id) => id.toLowerCase());
|
|
69
|
+
const missing = required.filter((id) => !configured.includes(id));
|
|
70
|
+
if (missing.length > 0) {
|
|
71
|
+
throw new Error(`STAGEFLOW_REQUIRE_PROVIDERS: missing configured providers: ${missing.join(", ")}`);
|
|
72
|
+
}
|
|
73
|
+
return { configured, failures };
|
|
74
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AgentSession, type EventBus, type InlineExtension, DefaultResourceLoader, SessionManager, SettingsManager } from "@earendil-works/pi-coding-agent";
|
|
1
|
+
import { type AgentSession, type EventBus, type ExtensionFactory, type InlineExtension, DefaultResourceLoader, SessionManager, SettingsManager } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { StageRoots } from "../runtime/stageRoots.js";
|
|
3
3
|
import { type AskOperatorPrompt, type AskOperatorWaitBridge } from "../tools/askOperator.js";
|
|
4
4
|
import "./cursorProvider.js";
|
|
@@ -6,6 +6,14 @@ import { type StageActivityObserver } from "./activityObserver.js";
|
|
|
6
6
|
import type { AgentPort, OpaqueAnswer, StageHandle, StageHandleCloseOptions, StageRunInput, StageRunResult } from "./port.js";
|
|
7
7
|
import type { StageGateKind } from "../types/stage.js";
|
|
8
8
|
import { type StageUsage } from "../types/usage.js";
|
|
9
|
+
import { STAGEFLOW_PATH_DENIED } from "../runstore/workspaceLayout.js";
|
|
10
|
+
export { STAGEFLOW_PATH_DENIED };
|
|
11
|
+
export declare const STAGEFLOW_PATH_DENY_EXTENSION_NAME = "stageflow-path-deny";
|
|
12
|
+
export declare function createDurableRootPathDenyExtension(options: {
|
|
13
|
+
runWorkspaceDir: string;
|
|
14
|
+
durableRoot: string;
|
|
15
|
+
checkoutRoot?: string;
|
|
16
|
+
}): ExtensionFactory;
|
|
9
17
|
/**
|
|
10
18
|
* Stage tool allowlist for sealed Pi sessions.
|
|
11
19
|
* Includes `ask_operator` unless `gateKinds` is an empty list (R6).
|
package/dist/agent/piAdapter.js
CHANGED
|
@@ -49,6 +49,36 @@ import { createStageActivityObserver, } from "./activityObserver.js";
|
|
|
49
49
|
import { DEFAULT_STAGE_TIMEOUT_MS, runtimeStageId, runStageViaOpen } from "./port.js";
|
|
50
50
|
import { addModelUsage, emptyStageUsage } from "../types/usage.js";
|
|
51
51
|
import { TIMEOUT_ABORT_TOOL_RESULT, composeTimeoutResumePrompt, stageTimeoutReason, } from "./stageTimeout.js";
|
|
52
|
+
import { globalStageflowHome } from "../project/globalHome.js";
|
|
53
|
+
import { durableRootFileToolDenial, STAGEFLOW_PATH_DENIED, } from "../runstore/workspaceLayout.js";
|
|
54
|
+
export { STAGEFLOW_PATH_DENIED };
|
|
55
|
+
export const STAGEFLOW_PATH_DENY_EXTENSION_NAME = "stageflow-path-deny";
|
|
56
|
+
const PATH_DENY_FILE_TOOLS = new Set(["read", "write", "edit"]);
|
|
57
|
+
export function createDurableRootPathDenyExtension(options) {
|
|
58
|
+
const { runWorkspaceDir, durableRoot, checkoutRoot } = options;
|
|
59
|
+
const allowlistedRoots = checkoutRoot !== undefined && checkoutRoot !== ""
|
|
60
|
+
? [checkoutRoot]
|
|
61
|
+
: undefined;
|
|
62
|
+
return (pi) => {
|
|
63
|
+
pi.on("tool_call", async (event, ctx) => {
|
|
64
|
+
if (!PATH_DENY_FILE_TOOLS.has(event.toolName)) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
const rawPath = event.input.path;
|
|
68
|
+
if (typeof rawPath !== "string" || rawPath.trim().length === 0) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
const candidate = path.isAbsolute(rawPath)
|
|
72
|
+
? rawPath
|
|
73
|
+
: path.resolve(ctx.cwd, rawPath);
|
|
74
|
+
const reason = await durableRootFileToolDenial(candidate, runWorkspaceDir, durableRoot, allowlistedRoots);
|
|
75
|
+
if (reason !== undefined) {
|
|
76
|
+
return { block: true, reason };
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
}
|
|
52
82
|
/**
|
|
53
83
|
* Stage tool allowlist for sealed Pi sessions.
|
|
54
84
|
* Includes `ask_operator` unless `gateKinds` is an empty list (R6).
|
|
@@ -825,6 +855,19 @@ async function prepareStageSessionWiring(input, sessionManager, existingAskWaitC
|
|
|
825
855
|
restoreProvider?.();
|
|
826
856
|
return { ok: false, reason };
|
|
827
857
|
};
|
|
858
|
+
const extensionFactories = [
|
|
859
|
+
{
|
|
860
|
+
name: STAGEFLOW_PATH_DENY_EXTENSION_NAME,
|
|
861
|
+
factory: createDurableRootPathDenyExtension({
|
|
862
|
+
runWorkspaceDir: roots.runWorkspaceDir,
|
|
863
|
+
durableRoot: globalStageflowHome(),
|
|
864
|
+
...(roots.checkoutRoot !== undefined
|
|
865
|
+
? { checkoutRoot: roots.checkoutRoot }
|
|
866
|
+
: {}),
|
|
867
|
+
}),
|
|
868
|
+
},
|
|
869
|
+
...(attached.extensionFactories ?? []),
|
|
870
|
+
];
|
|
828
871
|
const loader = createSealedResourceLoader({
|
|
829
872
|
cwd: roots.cwd,
|
|
830
873
|
agentDir: roots.agentDir,
|
|
@@ -834,9 +877,7 @@ async function prepareStageSessionWiring(input, sessionManager, existingAskWaitC
|
|
|
834
877
|
...(input.skillFilePath !== undefined
|
|
835
878
|
? { additionalSkillPaths: [input.skillFilePath] }
|
|
836
879
|
: {}),
|
|
837
|
-
|
|
838
|
-
? { extensionFactories: attached.extensionFactories }
|
|
839
|
-
: {}),
|
|
880
|
+
extensionFactories,
|
|
840
881
|
...(attached.eventBus !== undefined ? { eventBus: attached.eventBus } : {}),
|
|
841
882
|
});
|
|
842
883
|
await loader.reload();
|
|
@@ -943,6 +984,13 @@ export async function reconstructStageSessionForAnswer(input, answer) {
|
|
|
943
984
|
if (resolved.thinkingLevel) {
|
|
944
985
|
session.setThinkingLevel(resolved.thinkingLevel);
|
|
945
986
|
}
|
|
987
|
+
await input.onResolvedModel?.({
|
|
988
|
+
stageId: runtimeStageId(input),
|
|
989
|
+
model: resolved.model.id,
|
|
990
|
+
...(resolved.thinkingLevel !== undefined
|
|
991
|
+
? { thinkingLevel: resolved.thinkingLevel }
|
|
992
|
+
: {}),
|
|
993
|
+
});
|
|
946
994
|
const liveSession = session;
|
|
947
995
|
return {
|
|
948
996
|
session: liveSession,
|
|
@@ -1011,6 +1059,13 @@ async function bindStageSession(input, sessionManager, wiring) {
|
|
|
1011
1059
|
if (resolved.thinkingLevel) {
|
|
1012
1060
|
session.setThinkingLevel(resolved.thinkingLevel);
|
|
1013
1061
|
}
|
|
1062
|
+
await input.onResolvedModel?.({
|
|
1063
|
+
stageId: runtimeStageId(input),
|
|
1064
|
+
model: resolved.model.id,
|
|
1065
|
+
...(resolved.thinkingLevel !== undefined
|
|
1066
|
+
? { thinkingLevel: resolved.thinkingLevel }
|
|
1067
|
+
: {}),
|
|
1068
|
+
});
|
|
1014
1069
|
}
|
|
1015
1070
|
catch (err) {
|
|
1016
1071
|
await shutdownSession(session);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type EventBus, type InlineExtension } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { type ResolvedMcpServers } from "../config/resolveStageMcpServers.js";
|
|
3
3
|
export declare const STAGEFLOW_PI_MCP_EXTENSION_NAME = "stageflow-mcp";
|
|
4
|
+
export declare function jitiFsCacheDir(): string;
|
|
5
|
+
export declare function resetCreateMcpAdapterCacheForTests(): void;
|
|
4
6
|
type IsolatedMcpServerEntry = Record<string, unknown> & {
|
|
5
7
|
lifecycle: "lazy" | "eager";
|
|
6
8
|
directTools: true;
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import { createEventBus, } from "@earendil-works/pi-coding-agent";
|
|
2
3
|
import { StageMcpError, } from "../config/resolveStageMcpServers.js";
|
|
4
|
+
import { globalStageflowHome } from "../project/globalHome.js";
|
|
3
5
|
export const STAGEFLOW_PI_MCP_EXTENSION_NAME = "stageflow-mcp";
|
|
4
6
|
const MCP_STATUS_EVENT = "pi-mcp-adapter/status/v1";
|
|
5
|
-
const DEFAULT_ISOLATED_MCP_CONNECT_TIMEOUT_MS =
|
|
7
|
+
const DEFAULT_ISOLATED_MCP_CONNECT_TIMEOUT_MS = 30_000;
|
|
6
8
|
const STATUS_POLL_MS = 50;
|
|
7
9
|
const PI_MCP_ADAPTER_SPEC = "pi-mcp-adapter";
|
|
10
|
+
export function jitiFsCacheDir() {
|
|
11
|
+
return path.join(globalStageflowHome(), "cache", "jiti");
|
|
12
|
+
}
|
|
13
|
+
export function resetCreateMcpAdapterCacheForTests() {
|
|
14
|
+
cachedCreateMcpAdapter = undefined;
|
|
15
|
+
}
|
|
8
16
|
const ISOLATED_MCP_SETTINGS = {
|
|
9
17
|
directTools: true,
|
|
10
18
|
elicitation: false,
|
|
@@ -58,7 +66,7 @@ async function loadCreateMcpAdapter() {
|
|
|
58
66
|
// Node does not type-strip .ts under node_modules.
|
|
59
67
|
}
|
|
60
68
|
const { createJiti } = await import("jiti/static");
|
|
61
|
-
const jiti = createJiti(import.meta.url);
|
|
69
|
+
const jiti = createJiti(import.meta.url, { fsCache: jitiFsCacheDir() });
|
|
62
70
|
const mod = (await jiti.import(PI_MCP_ADAPTER_SPEC));
|
|
63
71
|
cachedCreateMcpAdapter = mod.createMcpAdapter;
|
|
64
72
|
return cachedCreateMcpAdapter;
|
package/dist/agent/port.d.ts
CHANGED
|
@@ -75,6 +75,12 @@ export type StageRunInput = {
|
|
|
75
75
|
repairContext?: StageRepairContext;
|
|
76
76
|
/** Live attempt-scoped QA trail; read at emit execute time, not bootstrap time. */
|
|
77
77
|
readQaTrail?: () => QaExchange[] | Promise<QaExchange[]>;
|
|
78
|
+
/** Optional: record the provider-resolved model after resolveCliModel. */
|
|
79
|
+
onResolvedModel?: (info: {
|
|
80
|
+
stageId: string;
|
|
81
|
+
model: string;
|
|
82
|
+
thinkingLevel?: string;
|
|
83
|
+
}) => void | Promise<void>;
|
|
78
84
|
};
|
|
79
85
|
export declare function runtimeStageId(input: Pick<StageRunInput, "stage" | "stageId">): string;
|
|
80
86
|
export type StageRunResult = {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/** Scrub
|
|
1
|
+
/** Scrub secret-shaped substrings and registered values before text is persisted. */
|
|
2
2
|
export declare function redactSecrets(text: string): string;
|
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
/\b[A-Za-z_]*KEY[A-Za-z_]*\s*[:=]\s*['"]?[A-Za-z0-9+/_-]{16,}['"]?/gi,
|
|
5
|
-
];
|
|
6
|
-
/** Scrub common secret-shaped substrings before text is persisted or returned. */
|
|
1
|
+
import { redactString } from "../logging/redact.js";
|
|
2
|
+
import { getNamedSecrets } from "../logging/namedSecrets.js";
|
|
3
|
+
/** Scrub secret-shaped substrings and registered values before text is persisted. */
|
|
7
4
|
export function redactSecrets(text) {
|
|
8
|
-
|
|
9
|
-
for (const pattern of SECRET_PATTERNS) {
|
|
10
|
-
out = out.replace(pattern, "[redacted]");
|
|
11
|
-
}
|
|
12
|
-
return out;
|
|
5
|
+
return redactString(text, { namedSecrets: getNamedSecrets() });
|
|
13
6
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const A2A_USAGE = "sf a2a validate [--config <path>]\nsf a2a list [--config <path>]\nsf a2a add-caller <id> [--config <path>] [--token-env <NAME>]\n\nValidate or inspect an A2A publication configuration, or register a new caller.\n--config defaults to <project-root>/a2a.yaml when omitted -- the same file\nSTAGEFLOW_A2A_CONFIG would point at if set. Caller credentials are read from\nthe environment variables named in the configuration; add-caller only writes\nthe caller's id and its token_env name to the file, never a secret value.";
|
|
2
|
+
export declare function runA2aCommand(args: string[], options: {
|
|
3
|
+
cwd: string;
|
|
4
|
+
projectRoot?: string;
|
|
5
|
+
env?: NodeJS.ProcessEnv;
|
|
6
|
+
log?: (line: string) => void;
|
|
7
|
+
error?: (line: string) => void;
|
|
8
|
+
}): Promise<number>;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
3
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
4
|
+
import { parse, stringify } from "yaml";
|
|
5
|
+
import { loadPublicationRegistry } from "../a2a/registry.js";
|
|
6
|
+
import { a2aConfigPathFor, resolveA2aConfigPath } from "../a2a/configDiscovery.js";
|
|
7
|
+
export const A2A_USAGE = `sf a2a validate [--config <path>]
|
|
8
|
+
sf a2a list [--config <path>]
|
|
9
|
+
sf a2a add-caller <id> [--config <path>] [--token-env <NAME>]
|
|
10
|
+
|
|
11
|
+
Validate or inspect an A2A publication configuration, or register a new caller.
|
|
12
|
+
--config defaults to <project-root>/a2a.yaml when omitted -- the same file
|
|
13
|
+
STAGEFLOW_A2A_CONFIG would point at if set. Caller credentials are read from
|
|
14
|
+
the environment variables named in the configuration; add-caller only writes
|
|
15
|
+
the caller's id and its token_env name to the file, never a secret value.`;
|
|
16
|
+
const SCAFFOLD = { version: 1, callers: [], publications: [] };
|
|
17
|
+
function deriveTokenEnvName(callerId) {
|
|
18
|
+
const normalized = callerId
|
|
19
|
+
.trim()
|
|
20
|
+
.toUpperCase()
|
|
21
|
+
.replace(/[^A-Z0-9]+/g, "_")
|
|
22
|
+
.replace(/^_+|_+$/g, "");
|
|
23
|
+
return (normalized || "CALLER") + "_TOKEN";
|
|
24
|
+
}
|
|
25
|
+
function parseFlags(args) {
|
|
26
|
+
let config;
|
|
27
|
+
let tokenEnv;
|
|
28
|
+
const positionals = [];
|
|
29
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
30
|
+
if (args[i] === "--config") {
|
|
31
|
+
config = args[(i += 1)];
|
|
32
|
+
}
|
|
33
|
+
else if (args[i] === "--token-env") {
|
|
34
|
+
tokenEnv = args[(i += 1)];
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
positionals.push(args[i]);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return { config, tokenEnv, positionals };
|
|
41
|
+
}
|
|
42
|
+
async function addCaller(configPath, callerId, tokenEnvOverride) {
|
|
43
|
+
let raw;
|
|
44
|
+
try {
|
|
45
|
+
raw = await readFile(configPath, "utf8");
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
raw = undefined;
|
|
49
|
+
}
|
|
50
|
+
const config = raw ? (parse(raw) ?? {}) : { ...SCAFFOLD };
|
|
51
|
+
if (typeof config !== "object" || Array.isArray(config)) {
|
|
52
|
+
throw new Error(configPath + " does not contain a YAML mapping");
|
|
53
|
+
}
|
|
54
|
+
if (config.version === undefined)
|
|
55
|
+
config.version = 1;
|
|
56
|
+
if (config.callers === undefined)
|
|
57
|
+
config.callers = [];
|
|
58
|
+
if (config.publications === undefined)
|
|
59
|
+
config.publications = [];
|
|
60
|
+
const callers = config.callers;
|
|
61
|
+
if (!Array.isArray(callers)) {
|
|
62
|
+
throw new Error('"callers" in ' + configPath + " is not a list");
|
|
63
|
+
}
|
|
64
|
+
if (callers.some((entry) => entry && typeof entry === "object" && entry.id === callerId)) {
|
|
65
|
+
throw new Error('Caller "' + callerId + '" already exists in ' + configPath);
|
|
66
|
+
}
|
|
67
|
+
const tokenEnv = tokenEnvOverride ?? deriveTokenEnvName(callerId);
|
|
68
|
+
callers.push({ id: callerId, token_env: tokenEnv });
|
|
69
|
+
await mkdir(path.dirname(configPath), { recursive: true });
|
|
70
|
+
await writeFile(configPath, stringify(config));
|
|
71
|
+
const token = randomBytes(24).toString("hex");
|
|
72
|
+
return { tokenEnv, token, created: raw === undefined };
|
|
73
|
+
}
|
|
74
|
+
export async function runA2aCommand(args, options) {
|
|
75
|
+
const log = options.log ?? console.log;
|
|
76
|
+
const error = options.error ?? console.error;
|
|
77
|
+
const env = options.env ?? process.env;
|
|
78
|
+
const projectRoot = options.projectRoot ?? options.cwd;
|
|
79
|
+
if (args[0] === "--help" || args[0] === "-h") {
|
|
80
|
+
log(A2A_USAGE);
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
const sub = args[0];
|
|
84
|
+
if (sub !== "validate" && sub !== "list" && sub !== "add-caller") {
|
|
85
|
+
error(A2A_USAGE);
|
|
86
|
+
return 1;
|
|
87
|
+
}
|
|
88
|
+
const { config, tokenEnv, positionals } = parseFlags(args.slice(1));
|
|
89
|
+
if (sub === "add-caller") {
|
|
90
|
+
if (positionals.length !== 1 || !positionals[0]) {
|
|
91
|
+
error(A2A_USAGE);
|
|
92
|
+
return 1;
|
|
93
|
+
}
|
|
94
|
+
const configPath = config ? path.resolve(options.cwd, config) : a2aConfigPathFor(projectRoot);
|
|
95
|
+
try {
|
|
96
|
+
const result = await addCaller(configPath, positionals[0], tokenEnv);
|
|
97
|
+
log(JSON.stringify({ ok: true, configPath, callerId: positionals[0], tokenEnv: result.tokenEnv, created: result.created }));
|
|
98
|
+
log('Generated a token for caller "' + positionals[0] + '". Export it before starting the host (or store it in your secrets manager):');
|
|
99
|
+
log(" export " + result.tokenEnv + "=" + result.token);
|
|
100
|
+
if (result.created) {
|
|
101
|
+
log("Created " + configPath + " with no publications yet -- add at least one under `publications:` before this config can be loaded.");
|
|
102
|
+
}
|
|
103
|
+
return 0;
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
error(err instanceof Error ? err.message : String(err));
|
|
107
|
+
return 1;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (positionals.length !== 0) {
|
|
111
|
+
error(A2A_USAGE);
|
|
112
|
+
return 1;
|
|
113
|
+
}
|
|
114
|
+
const configPath = config ? path.resolve(options.cwd, config) : resolveA2aConfigPath(projectRoot, env);
|
|
115
|
+
if (!configPath) {
|
|
116
|
+
error("No A2A configuration found. Pass --config <path>, or create " + a2aConfigPathFor(projectRoot) + ".");
|
|
117
|
+
return 1;
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
const registry = await loadPublicationRegistry(configPath, env);
|
|
121
|
+
log(JSON.stringify({ ok: true, configPath: registry.configPath, publicUrl: registry.publicUrl, mode: "discovery", publications: registry.summaries() }));
|
|
122
|
+
if (sub === "list") {
|
|
123
|
+
log("Configuration validated locally. An already-running host must be restarted explicitly to pick up changes.");
|
|
124
|
+
}
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
error(err instanceof Error ? err.message : String(err));
|
|
129
|
+
return 1;
|
|
130
|
+
}
|
|
131
|
+
}
|