stageflow 0.33.0 → 0.36.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 +3 -3
- package/dist/agent/adapterSpill.d.ts +14 -0
- package/dist/agent/adapterSpill.js +83 -0
- package/dist/agent/agentBackend.d.ts +2 -2
- package/dist/agent/agentBackend.js +2 -2
- package/dist/agent/claudeAdapter.d.ts +13 -2
- package/dist/agent/claudeAdapter.js +56 -6
- package/dist/agent/cursorProvider.d.ts +3 -0
- package/dist/agent/cursorProvider.js +23 -6
- package/dist/agent/fakeAgent.d.ts +3 -3
- package/dist/agent/piAdapter.d.ts +2 -2
- package/dist/agent/piAdapter.js +125 -15
- package/dist/agent/piIsolatedMcp.d.ts +1 -0
- package/dist/agent/piIsolatedMcp.js +19 -1
- package/dist/agent/piIsolatedMcpProbe.d.ts +11 -0
- package/dist/agent/piIsolatedMcpProbe.js +20 -0
- package/dist/agent/port.d.ts +4 -2
- package/dist/agent/providerAuth.js +36 -3
- package/dist/agent/{resolveAgentPort.d.ts → resolveStagePort.d.ts} +8 -8
- package/dist/agent/{resolveAgentPort.js → resolveStagePort.js} +11 -11
- package/dist/agent/stageTurnDriver.d.ts +33 -0
- package/dist/agent/stageTurnDriver.js +64 -0
- package/dist/agent/toolOutputBudget.d.ts +46 -0
- package/dist/agent/toolOutputBudget.js +97 -0
- package/dist/agent/toolOutputBudgetExtension.d.ts +22 -0
- package/dist/agent/toolOutputBudgetExtension.js +141 -0
- package/dist/agent/toolOutputSpill.d.ts +34 -0
- package/dist/agent/toolOutputSpill.js +85 -0
- package/dist/browser/agentBrowserLiveViewRelay.d.ts +41 -0
- package/dist/browser/agentBrowserLiveViewRelay.js +801 -0
- package/dist/browser/anchor.d.ts +2 -0
- package/dist/browser/anchor.js +2 -1
- package/dist/browser/auditSink.d.ts +8 -0
- package/dist/browser/browserHost.d.ts +29 -0
- package/dist/browser/browserSweep.d.ts +4 -1
- package/dist/browser/browserSweep.js +7 -0
- package/dist/browser/browserTeardown.d.ts +1 -0
- package/dist/browser/browserTeardown.js +32 -2
- package/dist/browser/containerBrowserEndpoint.d.ts +11 -0
- package/dist/browser/containerBrowserEndpoint.js +57 -0
- package/dist/browser/containerBrowserHost.d.ts +24 -0
- package/dist/browser/containerBrowserHost.js +147 -0
- package/dist/browser/dockerSandboxOrchestrator.d.ts +26 -0
- package/dist/browser/dockerSandboxOrchestrator.js +142 -0
- package/dist/browser/fakeLiveViewRelay.d.ts +15 -0
- package/dist/browser/fakeLiveViewRelay.js +94 -0
- package/dist/browser/fakeLiveViewSource.d.ts +6 -0
- package/dist/browser/fakeLiveViewSource.js +16 -0
- package/dist/browser/fakeRemoteBrowserHost.d.ts +2 -1
- package/dist/browser/fakeRemoteBrowserHost.js +2 -1
- package/dist/browser/fakeSandboxOrchestrator.d.ts +9 -0
- package/dist/browser/fakeSandboxOrchestrator.js +44 -0
- package/dist/browser/gateHandoff.d.ts +0 -2
- package/dist/browser/gateHandoff.js +5 -11
- package/dist/browser/hostCapabilities.d.ts +23 -0
- package/dist/browser/hostCapabilities.js +23 -0
- package/dist/browser/humanLogin.d.ts +2 -2
- package/dist/browser/humanLogin.js +11 -2
- package/dist/browser/liveViewPersisted.d.ts +11 -0
- package/dist/browser/liveViewPersisted.js +22 -0
- package/dist/browser/liveViewRelay.d.ts +76 -0
- package/dist/browser/liveViewRelay.js +1 -0
- package/dist/browser/liveViewSessions.d.ts +25 -0
- package/dist/browser/liveViewSessions.js +139 -0
- package/dist/browser/liveViewSource.d.ts +25 -0
- package/dist/browser/liveViewSource.js +7 -0
- package/dist/browser/liveViewTickets.d.ts +46 -0
- package/dist/browser/liveViewTickets.js +122 -0
- package/dist/browser/localBrowserHost.d.ts +10 -0
- package/dist/browser/localBrowserHost.js +53 -7
- package/dist/browser/ownerScope.d.ts +10 -0
- package/dist/browser/ownerScope.js +6 -0
- package/dist/browser/profileStore.d.ts +5 -2
- package/dist/browser/profileStore.js +3 -5
- package/dist/browser/sandboxOrchestrator.d.ts +60 -0
- package/dist/browser/sandboxOrchestrator.js +8 -0
- package/dist/browser/sessionApiSandboxOrchestrator.d.ts +34 -0
- package/dist/browser/sessionApiSandboxOrchestrator.js +108 -0
- package/dist/browser/stageBrowserEnv.d.ts +7 -0
- package/dist/browser/stageBrowserEnv.js +53 -15
- package/dist/browser/stageHandoff.d.ts +47 -0
- package/dist/browser/stageHandoff.js +101 -0
- package/dist/browser/stageProfileLock.d.ts +1 -0
- package/dist/browser/stageProfileLock.js +1 -3
- package/dist/browser/volumeProfileStore.d.ts +7 -0
- package/dist/browser/volumeProfileStore.js +35 -0
- package/dist/channels/config.d.ts +11 -0
- package/dist/channels/config.js +95 -0
- package/dist/channels/configWriter.d.ts +40 -0
- package/dist/channels/configWriter.js +148 -0
- package/dist/channels/connectionEdits.d.ts +34 -0
- package/dist/channels/connectionEdits.js +53 -0
- package/dist/channels/errorInfo.d.ts +18 -0
- package/dist/channels/errorInfo.js +71 -0
- package/dist/channels/errors.d.ts +12 -0
- package/dist/channels/errors.js +13 -0
- package/dist/channels/health.d.ts +41 -0
- package/dist/channels/health.js +99 -0
- package/dist/channels/host.d.ts +55 -0
- package/dist/channels/host.js +185 -0
- package/dist/channels/http.d.ts +31 -0
- package/dist/channels/http.js +79 -0
- package/dist/channels/index.d.ts +10 -0
- package/dist/channels/index.js +9 -0
- package/dist/channels/ledger.d.ts +37 -0
- package/dist/channels/ledger.js +95 -0
- package/dist/channels/providers/agentmail.d.ts +26 -0
- package/dist/channels/providers/agentmail.js +81 -0
- package/dist/channels/providers/kit.d.ts +40 -0
- package/dist/channels/providers/kit.js +78 -0
- package/dist/channels/providers/photonImessage.d.ts +45 -0
- package/dist/channels/providers/photonImessage.js +152 -0
- package/dist/channels/providers/photonWhatsapp.d.ts +49 -0
- package/dist/channels/providers/photonWhatsapp.js +146 -0
- package/dist/channels/providers/slack.d.ts +25 -0
- package/dist/channels/providers/slack.js +101 -0
- package/dist/channels/providers/telegram.d.ts +21 -0
- package/dist/channels/providers/telegram.js +100 -0
- package/dist/channels/providers.d.ts +5 -0
- package/dist/channels/providers.js +22 -0
- package/dist/channels/registry.d.ts +54 -0
- package/dist/channels/registry.js +186 -0
- package/dist/channels/secretStore.d.ts +21 -0
- package/dist/channels/secretStore.js +75 -0
- package/dist/channels/secrets.d.ts +15 -0
- package/dist/channels/secrets.js +50 -0
- package/dist/channels/service.d.ts +54 -0
- package/dist/channels/service.js +307 -0
- package/dist/channels/stageChannels.d.ts +45 -0
- package/dist/channels/stageChannels.js +110 -0
- package/dist/channels/types.d.ts +142 -0
- package/dist/channels/types.js +1 -0
- package/dist/cli/browserCommand.d.ts +3 -1
- package/dist/cli/browserCommand.js +25 -20
- package/dist/cli/doctorCommand.js +3 -1
- package/dist/cli/resolveCliProjectRoot.d.ts +7 -0
- package/dist/cli/resolveCliProjectRoot.js +27 -0
- package/dist/cli/runCommand.d.ts +1 -1
- package/dist/cli/runCommand.js +59 -17
- package/dist/cli/skillsCommand.d.ts +20 -0
- package/dist/cli/skillsCommand.js +74 -31
- package/dist/cli/validateCommand.d.ts +1 -1
- package/dist/cli/validateCommand.js +22 -4
- package/dist/cli.js +4 -4
- package/dist/config/browseCatalog.d.ts +2 -0
- package/dist/config/browseCatalog.js +6 -0
- package/dist/config/catalogRelativePath.d.ts +4 -0
- package/dist/config/catalogRelativePath.js +37 -9
- package/dist/config/createStage.d.ts +1 -0
- package/dist/config/createStage.js +11 -2
- package/dist/config/createTask.d.ts +30 -0
- package/dist/config/createTask.js +161 -0
- package/dist/config/createTrigger.d.ts +15 -0
- package/dist/config/createTrigger.js +32 -25
- package/dist/config/draftPackage.d.ts +42 -0
- package/dist/config/draftPackage.js +220 -23
- package/dist/config/ensureCatalogScanRoot.d.ts +2 -1
- package/dist/config/ensureCatalogScanRoot.js +6 -2
- package/dist/config/findTaskInCatalog.d.ts +33 -0
- package/dist/config/findTaskInCatalog.js +69 -0
- package/dist/config/hostConfig.d.ts +21 -0
- package/dist/config/hostConfig.js +114 -1
- package/dist/config/importTask.d.ts +19 -0
- package/dist/config/importTask.js +133 -0
- package/dist/config/installSkillRequest.d.ts +40 -0
- package/dist/config/installSkillRequest.js +286 -0
- package/dist/config/loadOutcome.d.ts +11 -6
- package/dist/config/loadPipeline.js +27 -4
- package/dist/config/loadStage.js +17 -0
- package/dist/config/loadStageflowManifest.js +4 -1
- package/dist/config/loadTask.js +2 -0
- package/dist/config/loadTrigger.js +2 -0
- package/dist/config/mergePipelineIncludes.d.ts +3 -0
- package/dist/config/mergePipelineIncludes.js +30 -0
- package/dist/config/normalizePipelineStageEntry.js +10 -1
- package/dist/config/pipelineStageKeys.js +1 -0
- package/dist/config/printTargetYaml.js +0 -1
- package/dist/config/publishDraftPackage.d.ts +5 -1
- package/dist/config/publishDraftPackage.js +4 -1
- package/dist/config/resolveCatalogRoots.d.ts +4 -1
- package/dist/config/resolveCatalogRoots.js +18 -1
- package/dist/config/skillUsageIndex.d.ts +6 -0
- package/dist/config/skillUsageIndex.js +39 -0
- package/dist/config/stageBrowser.js +13 -0
- package/dist/config/triggerAdapterStatus.d.ts +11 -0
- package/dist/config/triggerAdapterStatus.js +90 -0
- package/dist/config/triggerCatalog.d.ts +41 -2
- package/dist/config/triggerCatalog.js +107 -15
- package/dist/config/updateTask.d.ts +30 -0
- package/dist/config/updateTask.js +119 -0
- package/dist/config/updateTrigger.d.ts +38 -0
- package/dist/config/updateTrigger.js +220 -0
- package/dist/config/validateCatalog.d.ts +9 -2
- package/dist/config/validateCatalog.js +71 -7
- package/dist/config/workshopCatalogFilenames.d.ts +37 -0
- package/dist/config/workshopCatalogFilenames.js +125 -0
- package/dist/config/workshopCatalogRepair.d.ts +7 -0
- package/dist/config/workshopCatalogRepair.js +144 -0
- package/dist/config/yamlParsePosition.d.ts +4 -0
- package/dist/config/yamlParsePosition.js +9 -0
- package/dist/errors/codes.d.ts +1 -1
- package/dist/errors/codes.js +1 -0
- package/dist/hosted/runtime.d.ts +2 -2
- package/dist/hosted/types.d.ts +1 -1
- package/dist/hosted/types.js +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/mcp/catalogTools.js +1 -0
- package/dist/mcp/getStartedTool.js +15 -6
- package/dist/mcp/triggerTools.js +2 -8
- package/dist/operatorAgent/agentPort.d.ts +11 -0
- package/dist/operatorAgent/agentPort.js +12 -0
- package/dist/operatorAgent/index.d.ts +1 -0
- package/dist/operatorAgent/index.js +1 -0
- package/dist/operatorAgent/piModel.js +26 -6
- package/dist/operatorAgent/profiles/workshopAuthorPlaybook.d.ts +1 -1
- package/dist/operatorAgent/profiles/workshopAuthorPlaybook.js +4 -2
- package/dist/operatorAgent/profiles/workshopAuthorTools.js +103 -16
- package/dist/package-meta.d.ts +1 -1
- package/dist/package-meta.js +1 -1
- package/dist/preflight/channelChecks.d.ts +17 -0
- package/dist/preflight/channelChecks.js +106 -0
- package/dist/preflight/pipelinePreflight.d.ts +9 -2
- package/dist/preflight/pipelinePreflight.js +9 -1
- package/dist/project/ensureProjectRootsFromEnv.d.ts +3 -0
- package/dist/project/ensureProjectRootsFromEnv.js +22 -0
- package/dist/project/globalHome.d.ts +1 -0
- package/dist/project/globalHome.js +18 -0
- package/dist/project/workspaceCatalog.d.ts +10 -0
- package/dist/project/workspaceCatalog.js +91 -0
- package/dist/runstore/backup.js +14 -4
- package/dist/runstore/port.d.ts +11 -1
- package/dist/runstore/restore.js +5 -2
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +8 -0
- package/dist/runstore/sqlite/SqliteRunStore.js +29 -9
- package/dist/runstore/sqlite/migrations/012-trigger-fires.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/012-trigger-fires.js +18 -0
- package/dist/runstore/sqlite/migrations/index.js +2 -0
- package/dist/runstore/stageSnapshot.d.ts +3 -1
- package/dist/runstore/stageSnapshot.js +19 -0
- package/dist/runstore/workspaceLayout.js +27 -0
- package/dist/runstore/writeContainedArtifact.d.ts +1 -0
- package/dist/runstore/writeContainedArtifact.js +52 -0
- package/dist/runtime/credentialBinding.js +14 -6
- package/dist/runtime/emailSource.js +20 -28
- package/dist/runtime/githubPollSource.js +20 -28
- package/dist/runtime/pipelineRunner.d.ts +4 -4
- package/dist/runtime/pipelineRunner.js +3 -1
- package/dist/runtime/pipelineScheduler.d.ts +2 -2
- package/dist/runtime/pipelineScheduler.js +3 -0
- package/dist/runtime/repositoryMaterialize.d.ts +1 -1
- package/dist/runtime/resumeReconstruct.d.ts +2 -2
- package/dist/runtime/resumeTimedOut.d.ts +2 -2
- package/dist/runtime/runManager.d.ts +18 -2
- package/dist/runtime/runManager.js +99 -31
- package/dist/runtime/runRetryCoordinator.d.ts +2 -2
- package/dist/runtime/scheduleSource.js +15 -24
- package/dist/runtime/stageAttemptBootstrap.d.ts +2 -2
- package/dist/runtime/stageAttemptBootstrap.js +26 -1
- package/dist/runtime/stageProcessLauncher.js +33 -3
- package/dist/runtime/stageRoots.js +8 -1
- package/dist/runtime/stageRunner.d.ts +2 -2
- package/dist/runtime/stageRunner.js +8 -2
- package/dist/runtime/stageWorker.js +2 -2
- package/dist/runtime/triggerPort.d.ts +5 -3
- package/dist/runtime/triggerRunner.d.ts +1 -0
- package/dist/runtime/triggerRunner.js +27 -20
- package/dist/runtime/webhookAccept.d.ts +25 -0
- package/dist/runtime/webhookAccept.js +56 -0
- package/dist/server/bootstrap.d.ts +10 -2
- package/dist/server/bootstrap.js +19 -1
- package/dist/server/channelRoutes.d.ts +9 -0
- package/dist/server/channelRoutes.js +88 -0
- package/dist/server/controlToken.d.ts +1 -1
- package/dist/server/controlToken.js +18 -2
- package/dist/server/healthSurfaces.d.ts +12 -0
- package/dist/server/healthSurfaces.js +27 -6
- package/dist/server/http.d.ts +19 -10
- package/dist/server/http.js +616 -85
- package/dist/server/liveViewPath.d.ts +9 -0
- package/dist/server/liveViewPath.js +8 -0
- package/dist/server/liveViewRoutes.d.ts +58 -0
- package/dist/server/liveViewRoutes.js +565 -0
- package/dist/server/mcpHost.d.ts +4 -2
- package/dist/server/mcpHost.js +2 -0
- package/dist/server/readCatalogFile.d.ts +29 -0
- package/dist/server/readCatalogFile.js +215 -0
- package/dist/server/triggerRoutes.d.ts +1 -0
- package/dist/server/triggerRoutes.js +200 -73
- package/dist/tools/sendMessage.d.ts +21 -0
- package/dist/tools/sendMessage.js +25 -0
- package/dist/tools/writeStageArtifact.d.ts +9 -0
- package/dist/tools/writeStageArtifact.js +2 -47
- package/dist/types/pipeline.d.ts +5 -2
- package/dist/types/stage.d.ts +14 -1
- package/dist/types/stageflowManifest.d.ts +1 -1
- package/dist/ui/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/dist/ui/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/dist/ui/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/dist/ui/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/dist/ui/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
- package/dist/ui/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
- package/dist/ui/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
- package/dist/ui/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
- package/dist/ui/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
- package/dist/ui/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
- package/dist/ui/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/dist/ui/assets/index-BOhqnPNg.js +260 -0
- package/dist/ui/assets/{index-Bv4p1aPK.css → index-Clv4sJpU.css} +1 -1
- package/dist/ui/index.html +4 -4
- package/dist/workshop/autosave.d.ts +2 -2
- package/dist/workshop/autosave.js +4 -6
- package/dist/workshop/buildStore.d.ts +2 -0
- package/dist/workshop/chatAttachments.d.ts +27 -0
- package/dist/workshop/chatAttachments.js +98 -0
- package/dist/workshop/chatTurn.d.ts +5 -2
- package/dist/workshop/chatTurn.js +22 -18
- package/dist/workshop/sessionMutations.d.ts +17 -0
- package/dist/workshop/sessionMutations.js +107 -0
- package/dist/workshop/sessionStore.d.ts +10 -0
- package/dist/workshop/sessionStore.js +52 -0
- package/dist/workshop/workshopPin.d.ts +4 -3
- package/dist/workshop/workshopPin.js +26 -6
- package/dist/workshop/workshopTranscriptTurn.d.ts +8 -0
- package/dist/workshop/workshopTranscriptTurn.js +46 -0
- package/examples/README.md +1 -1
- package/examples/archify-on-pr/README.md +1 -1
- package/examples/archify-on-pr/archify-on-pr.pipeline.yaml +0 -1
- package/examples/archify-on-pr/author-diagrams.yaml +1 -0
- package/examples/channels-smoke/README.md +12 -0
- package/examples/channels-smoke/channels-smoke.pipeline.yaml +11 -0
- package/examples/channels-smoke/channels-smoke.task.yaml +3 -0
- package/examples/channels-smoke/send-email.yaml +32 -0
- package/examples/channels-smoke/send-text.yaml +31 -0
- package/examples/conditional-fork/branch-a.yaml +1 -1
- package/examples/conditional-fork/decide.yaml +2 -1
- package/examples/feature-loop/{implement.yaml → feature-implement.yaml} +1 -1
- package/examples/feature-loop/feature-loop.pipeline.yaml +10 -10
- package/examples/feature-loop/{plan.yaml → feature-plan.yaml} +1 -1
- package/examples/feature-loop/{review.yaml → feature-review.yaml} +1 -1
- package/examples/feedback-loop/{implement.yaml → feedback-implement.yaml} +1 -1
- package/examples/feedback-loop/feedback-loop-wait-human.pipeline.yaml +9 -9
- package/examples/feedback-loop/feedback-loop.pipeline.yaml +9 -9
- package/examples/feedback-loop/{plan.yaml → feedback-plan.yaml} +1 -1
- package/examples/feedback-loop/{review.yaml → feedback-review.yaml} +1 -1
- package/examples/generic-fan-in/{research.yaml → fan-in-research.yaml} +1 -1
- package/examples/generic-fan-in/generic-fan-in-accepted.pipeline.yaml +3 -3
- package/examples/generic-fan-in/generic-fan-in.pipeline.yaml +3 -3
- package/examples/hello-world/{research.yaml → hello-research.yaml} +1 -1
- package/examples/hello-world/hello.pipeline.yaml +2 -2
- package/examples/mcp-hitl-tour/{review.yaml → mcp-hitl-review.yaml} +1 -1
- package/examples/mcp-hitl-tour/mcp-hitl-tour.pipeline.yaml +3 -3
- package/examples/oss-issue-contribution/oss-explain-fix.yaml +1 -0
- package/examples/oss-issue-contribution/oss-explain-issue.yaml +1 -0
- package/examples/oss-issue-contribution/oss-issue-contribution.pipeline.yaml +0 -2
- package/examples/stageflow.yaml +6 -0
- package/examples/triggers/sample-github-pr.trigger.yaml +12 -0
- package/examples/triggers/sample-inbox-email.trigger.yaml +14 -0
- package/examples/triggers/sample-manual-hello.trigger.yaml +5 -0
- package/examples/triggers/sample-nightly-hello.trigger.yaml +8 -0
- package/examples/triggers/sample-signed-webhook.trigger.yaml +11 -0
- package/examples/triggers-readiness/README.md +48 -0
- package/examples/triggers-readiness/readiness-emit.yaml +18 -0
- package/examples/triggers-readiness/readiness.pipeline.yaml +4 -0
- package/examples/triggers-readiness/readiness.task.yaml +6 -0
- package/examples/triggers-readiness/stageflow.yaml +13 -0
- package/examples/triggers-readiness/triggers/readiness-dynamic-manual.trigger.yaml +4 -0
- package/examples/triggers-readiness/triggers/readiness-email.trigger.yaml +12 -0
- package/examples/triggers-readiness/triggers/readiness-github-pr.trigger.yaml +12 -0
- package/examples/triggers-readiness/triggers/readiness-manual.trigger.yaml +5 -0
- package/examples/triggers-readiness/triggers/readiness-schedule.trigger.yaml +8 -0
- package/examples/triggers-readiness/triggers/readiness-webhook.trigger.yaml +11 -0
- package/package.json +8 -3
- package/skills/stageflow/references/control-surface.md +1 -1
- package/skills/stageflow-author/references/catalog-write-conventions.md +2 -2
- package/skills/stageflow-run/SKILL.md +1 -1
- package/skills/stageflow-run/references/mcp-call.md +1 -1
- package/skills/stageflow-setup/SKILL.md +1 -1
- package/dist/ui/assets/index-59cjF0OA.js +0 -133
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { access, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
1
|
+
import { access, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { loadPipelineOutcome } from "./loadPipeline.js";
|
|
@@ -6,6 +6,8 @@ import { parseTaskFile } from "./loadTask.js";
|
|
|
6
6
|
import { stringifyTargetYaml } from "./printTargetYaml.js";
|
|
7
7
|
import { readYamlObject } from "./readYamlObject.js";
|
|
8
8
|
import { buildValidationResult, findingsFromLoadIssues, loadPipelineValidated, validatePipeline, } from "./validateCatalog.js";
|
|
9
|
+
import { normalizeDraftCatalogFilenames, taskIdFromDraftTask, } from "./workshopCatalogFilenames.js";
|
|
10
|
+
import { reconcileWorkshopCatalogPackageDir } from "./workshopCatalogRepair.js";
|
|
9
11
|
function isPlainObject(value) {
|
|
10
12
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
11
13
|
}
|
|
@@ -15,10 +17,57 @@ function normalizeStageRelPath(stagePath) {
|
|
|
15
17
|
function pipelineHasExternalUses(pipeline) {
|
|
16
18
|
return pipeline.stages.some((stage) => typeof stage.uses === "string" && stage.uses.trim().length > 0);
|
|
17
19
|
}
|
|
20
|
+
function stripUsesWrapperSkill(stages) {
|
|
21
|
+
return stages.map((stage) => {
|
|
22
|
+
if (typeof stage.uses !== "string" || stage.skill === undefined)
|
|
23
|
+
return stage;
|
|
24
|
+
const { skill: _skill, ...rest } = stage;
|
|
25
|
+
return rest;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/** Move uses-wrapper skill: onto the matching stage artifact body, then clear the wrapper. */
|
|
29
|
+
export function hoistUsesWrapperSkills(draft) {
|
|
30
|
+
const artifacts = draft.stages ? [...draft.stages] : [];
|
|
31
|
+
const byPath = new Map(artifacts.map((artifact, index) => [
|
|
32
|
+
normalizeStageRelPath(artifact.path),
|
|
33
|
+
index,
|
|
34
|
+
]));
|
|
35
|
+
const stages = draft.pipeline.stages.map((stage) => {
|
|
36
|
+
if (typeof stage.uses !== "string" || stage.skill === undefined)
|
|
37
|
+
return stage;
|
|
38
|
+
const skill = typeof stage.skill === "string" && stage.skill.trim()
|
|
39
|
+
? stage.skill.trim()
|
|
40
|
+
: undefined;
|
|
41
|
+
if (skill === undefined) {
|
|
42
|
+
const { skill: _skill, ...rest } = stage;
|
|
43
|
+
return rest;
|
|
44
|
+
}
|
|
45
|
+
const key = normalizeStageRelPath(stage.uses);
|
|
46
|
+
const index = byPath.get(key);
|
|
47
|
+
if (index !== undefined) {
|
|
48
|
+
const current = artifacts[index];
|
|
49
|
+
const bodySkill = current.body.skill;
|
|
50
|
+
const bodyHasSkill = typeof bodySkill === "string" && bodySkill.trim().length > 0;
|
|
51
|
+
if (!bodyHasSkill) {
|
|
52
|
+
artifacts[index] = {
|
|
53
|
+
...current,
|
|
54
|
+
body: { ...current.body, skill },
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const { skill: _skill, ...rest } = stage;
|
|
59
|
+
return rest;
|
|
60
|
+
});
|
|
61
|
+
return {
|
|
62
|
+
...draft,
|
|
63
|
+
pipeline: { ...draft.pipeline, stages },
|
|
64
|
+
...(artifacts.length > 0 ? { stages: artifacts } : {}),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
18
67
|
function pipelineDocument(pipeline) {
|
|
19
68
|
const doc = {
|
|
20
69
|
id: pipeline.id,
|
|
21
|
-
stages: pipeline.stages,
|
|
70
|
+
stages: stripUsesWrapperSkill(pipeline.stages),
|
|
22
71
|
};
|
|
23
72
|
if (pipeline.agent !== undefined)
|
|
24
73
|
doc.agent = pipeline.agent;
|
|
@@ -28,6 +77,8 @@ function pipelineDocument(pipeline) {
|
|
|
28
77
|
doc.schemas = pipeline.schemas;
|
|
29
78
|
if (pipeline.requires !== undefined)
|
|
30
79
|
doc.requires = pipeline.requires;
|
|
80
|
+
if (pipeline.channels !== undefined)
|
|
81
|
+
doc.channels = pipeline.channels;
|
|
31
82
|
return doc;
|
|
32
83
|
}
|
|
33
84
|
function resolveDirectory(projectRoot, directory) {
|
|
@@ -48,9 +99,10 @@ async function fileExists(filePath) {
|
|
|
48
99
|
}
|
|
49
100
|
}
|
|
50
101
|
async function materializeDraft(draft, dir, pipelineFilename) {
|
|
102
|
+
const migrated = hoistUsesWrapperSkills(draft);
|
|
51
103
|
await mkdir(dir, { recursive: true });
|
|
52
|
-
await writeFile(path.join(dir, pipelineFilename), stringifyTargetYaml(pipelineDocument(
|
|
53
|
-
for (const stage of
|
|
104
|
+
await writeFile(path.join(dir, pipelineFilename), stringifyTargetYaml(pipelineDocument(migrated.pipeline)), "utf8");
|
|
105
|
+
for (const stage of migrated.stages ?? []) {
|
|
54
106
|
const rel = normalizeStageRelPath(stage.path);
|
|
55
107
|
const stagePath = path.join(dir, rel);
|
|
56
108
|
await mkdir(path.dirname(stagePath), { recursive: true });
|
|
@@ -114,6 +166,7 @@ export async function validateDraftPackage(draft, options = {}) {
|
|
|
114
166
|
...(draft.pipeline.requires !== undefined
|
|
115
167
|
? { requires: draft.pipeline.requires }
|
|
116
168
|
: {}),
|
|
169
|
+
...(draft.pipeline.channels !== undefined ? { channels: draft.pipeline.channels } : {}),
|
|
117
170
|
};
|
|
118
171
|
const result = await loadPipelineValidated(inline, {
|
|
119
172
|
cwd,
|
|
@@ -185,11 +238,13 @@ function resolveDraftWriteTarget(projectRoot, input) {
|
|
|
185
238
|
error: "directory must be inside the project root",
|
|
186
239
|
};
|
|
187
240
|
}
|
|
188
|
-
const
|
|
189
|
-
if (!isPlainObject(
|
|
241
|
+
const rawDraft = input.draft;
|
|
242
|
+
if (!isPlainObject(rawDraft?.pipeline) || typeof rawDraft.pipeline.id !== "string") {
|
|
190
243
|
return { ok: false, status: 400, error: "draft.pipeline.id is required" };
|
|
191
244
|
}
|
|
192
|
-
const
|
|
245
|
+
const normalized = normalizeDraftCatalogFilenames(rawDraft, input.pipelineFilename?.trim());
|
|
246
|
+
const draft = hoistUsesWrapperSkills(normalized.draft);
|
|
247
|
+
const pipelineFilename = normalized.pipelineFilename;
|
|
193
248
|
const pipelineAbsPath = path.join(packageDirectory, path.basename(pipelineFilename));
|
|
194
249
|
const pipelineRelPath = path
|
|
195
250
|
.relative(projectRoot, pipelineAbsPath)
|
|
@@ -223,9 +278,17 @@ async function gateDraftWrite(projectRoot, draft, allowInvalid) {
|
|
|
223
278
|
findings: validation.findings,
|
|
224
279
|
};
|
|
225
280
|
}
|
|
226
|
-
|
|
281
|
+
function resolveDraftWriteFiles(projectRoot, target) {
|
|
227
282
|
const { packageDirectory, draft, pipelineAbsPath, pipelineRelPath } = target;
|
|
228
|
-
const
|
|
283
|
+
const toRel = (abs) => path.relative(projectRoot, abs).replace(/\\/g, "/");
|
|
284
|
+
const files = [
|
|
285
|
+
{
|
|
286
|
+
kind: "pipeline",
|
|
287
|
+
absPath: pipelineAbsPath,
|
|
288
|
+
relPath: pipelineRelPath,
|
|
289
|
+
content: stringifyTargetYaml(pipelineDocument(draft.pipeline)),
|
|
290
|
+
},
|
|
291
|
+
];
|
|
229
292
|
for (const stage of draft.stages ?? []) {
|
|
230
293
|
const rel = normalizeStageRelPath(stage.path);
|
|
231
294
|
if (!rel || path.isAbsolute(rel) || rel.split(/[/\\]/).includes("..")) {
|
|
@@ -244,23 +307,39 @@ async function writeDraftPackageFiles(projectRoot, target, allowInvalid) {
|
|
|
244
307
|
error: `Stage path escapes package directory (${stage.path})`,
|
|
245
308
|
};
|
|
246
309
|
}
|
|
310
|
+
files.push({
|
|
311
|
+
kind: "stage",
|
|
312
|
+
absPath: stageAbs,
|
|
313
|
+
relPath: toRel(stageAbs),
|
|
314
|
+
content: stringifyTargetYaml(stage.body),
|
|
315
|
+
});
|
|
247
316
|
}
|
|
317
|
+
if (draft.task) {
|
|
318
|
+
const taskAbs = path.join(packageDirectory, path.basename(draft.task.filename));
|
|
319
|
+
files.push({
|
|
320
|
+
kind: "task",
|
|
321
|
+
absPath: taskAbs,
|
|
322
|
+
relPath: toRel(taskAbs),
|
|
323
|
+
content: stringifyTargetYaml(draft.task.body),
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
return { ok: true, files };
|
|
327
|
+
}
|
|
328
|
+
async function writeDraftPackageFiles(projectRoot, target, allowInvalid) {
|
|
329
|
+
const { packageDirectory, draft, pipelineRelPath } = target;
|
|
330
|
+
const resolved = resolveDraftWriteFiles(projectRoot, target);
|
|
331
|
+
if (!resolved.ok)
|
|
332
|
+
return resolved;
|
|
248
333
|
try {
|
|
249
334
|
await mkdir(packageDirectory, { recursive: true });
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const stageAbs = path.resolve(packageDirectory, rel);
|
|
254
|
-
await mkdir(path.dirname(stageAbs), { recursive: true });
|
|
255
|
-
await writeFile(stageAbs, stringifyTargetYaml(stage.body), "utf8");
|
|
256
|
-
stagePaths.push(path.relative(projectRoot, stageAbs).replace(/\\/g, "/"));
|
|
257
|
-
}
|
|
258
|
-
let taskPath;
|
|
259
|
-
if (draft.task) {
|
|
260
|
-
const taskAbs = path.join(packageDirectory, path.basename(draft.task.filename));
|
|
261
|
-
await writeFile(taskAbs, stringifyTargetYaml(draft.task.body), "utf8");
|
|
262
|
-
taskPath = path.relative(projectRoot, taskAbs).replace(/\\/g, "/");
|
|
335
|
+
for (const file of resolved.files) {
|
|
336
|
+
await mkdir(path.dirname(file.absPath), { recursive: true });
|
|
337
|
+
await writeFile(file.absPath, file.content, "utf8");
|
|
263
338
|
}
|
|
339
|
+
const stagePaths = resolved.files
|
|
340
|
+
.filter((file) => file.kind === "stage")
|
|
341
|
+
.map((file) => file.relPath);
|
|
342
|
+
const taskPath = resolved.files.find((file) => file.kind === "task")?.relPath;
|
|
264
343
|
const loadOutcome = await loadPipelineOutcome(pipelineRelPath, {
|
|
265
344
|
cwd: projectRoot,
|
|
266
345
|
});
|
|
@@ -274,6 +353,11 @@ async function writeDraftPackageFiles(projectRoot, target, allowInvalid) {
|
|
|
274
353
|
error: loadOutcome.issues[0]?.message ?? "Failed to load written pipeline",
|
|
275
354
|
};
|
|
276
355
|
}
|
|
356
|
+
const taskId = draft.task ? taskIdFromDraftTask(draft.task) : null;
|
|
357
|
+
await reconcileWorkshopCatalogPackageDir(packageDirectory, draft.pipeline.id, taskId, {
|
|
358
|
+
pipelineBasename: path.basename(target.pipelineAbsPath),
|
|
359
|
+
taskBasename: draft.task ? path.basename(draft.task.filename) : null,
|
|
360
|
+
});
|
|
277
361
|
return {
|
|
278
362
|
ok: true,
|
|
279
363
|
pipeline,
|
|
@@ -287,10 +371,22 @@ async function writeDraftPackageFiles(projectRoot, target, allowInvalid) {
|
|
|
287
371
|
return { ok: false, status: 500, error: message };
|
|
288
372
|
}
|
|
289
373
|
}
|
|
374
|
+
async function prepareDraftPackageDirectory(target) {
|
|
375
|
+
const taskId = target.draft.task
|
|
376
|
+
? taskIdFromDraftTask(target.draft.task)
|
|
377
|
+
: null;
|
|
378
|
+
await reconcileWorkshopCatalogPackageDir(target.packageDirectory, target.draft.pipeline.id, taskId, {
|
|
379
|
+
pipelineBasename: path.basename(target.pipelineAbsPath),
|
|
380
|
+
taskBasename: target.draft.task
|
|
381
|
+
? path.basename(path.join(target.packageDirectory, path.basename(target.draft.task.filename)))
|
|
382
|
+
: null,
|
|
383
|
+
});
|
|
384
|
+
}
|
|
290
385
|
export async function overwriteDraftPackage(projectRoot, input) {
|
|
291
386
|
const resolved = resolveDraftWriteTarget(projectRoot, input);
|
|
292
387
|
if (!resolved.ok)
|
|
293
388
|
return resolved;
|
|
389
|
+
await prepareDraftPackageDirectory(resolved.value);
|
|
294
390
|
if (!(await fileExists(resolved.value.pipelineAbsPath))) {
|
|
295
391
|
return {
|
|
296
392
|
ok: false,
|
|
@@ -307,6 +403,7 @@ export async function createDraftPackage(projectRoot, input) {
|
|
|
307
403
|
const resolved = resolveDraftWriteTarget(projectRoot, input);
|
|
308
404
|
if (!resolved.ok)
|
|
309
405
|
return resolved;
|
|
406
|
+
await prepareDraftPackageDirectory(resolved.value);
|
|
310
407
|
if (await fileExists(resolved.value.pipelineAbsPath)) {
|
|
311
408
|
return {
|
|
312
409
|
ok: false,
|
|
@@ -319,6 +416,104 @@ export async function createDraftPackage(projectRoot, input) {
|
|
|
319
416
|
return blocked;
|
|
320
417
|
return writeDraftPackageFiles(projectRoot, resolved.value, input.allowInvalid);
|
|
321
418
|
}
|
|
419
|
+
function splitLines(text) {
|
|
420
|
+
if (!text)
|
|
421
|
+
return [];
|
|
422
|
+
return (text.endsWith("\n") ? text.slice(0, -1) : text).split("\n");
|
|
423
|
+
}
|
|
424
|
+
export function countLineChanges(before, after) {
|
|
425
|
+
const a = splitLines(before);
|
|
426
|
+
const b = splitLines(after);
|
|
427
|
+
let start = 0;
|
|
428
|
+
while (start < a.length && start < b.length && a[start] === b[start])
|
|
429
|
+
start += 1;
|
|
430
|
+
let endA = a.length;
|
|
431
|
+
let endB = b.length;
|
|
432
|
+
while (endA > start && endB > start && a[endA - 1] === b[endB - 1]) {
|
|
433
|
+
endA -= 1;
|
|
434
|
+
endB -= 1;
|
|
435
|
+
}
|
|
436
|
+
const midA = a.slice(start, endA);
|
|
437
|
+
const midB = b.slice(start, endB);
|
|
438
|
+
let prev = new Uint32Array(midB.length + 1);
|
|
439
|
+
let curr = new Uint32Array(midB.length + 1);
|
|
440
|
+
for (const lineA of midA) {
|
|
441
|
+
for (let j = 1; j <= midB.length; j += 1) {
|
|
442
|
+
curr[j] =
|
|
443
|
+
lineA === midB[j - 1] ? prev[j - 1] + 1 : Math.max(prev[j], curr[j - 1]);
|
|
444
|
+
}
|
|
445
|
+
[prev, curr] = [curr, prev];
|
|
446
|
+
}
|
|
447
|
+
const common = prev[midB.length];
|
|
448
|
+
return { added: midB.length - common, removed: midA.length - common };
|
|
449
|
+
}
|
|
450
|
+
async function readExisting(filePath) {
|
|
451
|
+
try {
|
|
452
|
+
return await readFile(filePath, "utf8");
|
|
453
|
+
}
|
|
454
|
+
catch {
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
export async function planDraftPackage(projectRoot, input, options = {}) {
|
|
459
|
+
const resolved = resolveDraftWriteTarget(projectRoot, input);
|
|
460
|
+
if (!resolved.ok)
|
|
461
|
+
return resolved;
|
|
462
|
+
const writeFiles = resolveDraftWriteFiles(projectRoot, resolved.value);
|
|
463
|
+
if (!writeFiles.ok)
|
|
464
|
+
return writeFiles;
|
|
465
|
+
const files = [];
|
|
466
|
+
for (const file of writeFiles.files) {
|
|
467
|
+
const existing = await readExisting(file.absPath);
|
|
468
|
+
if (existing === null) {
|
|
469
|
+
files.push({
|
|
470
|
+
path: file.relPath,
|
|
471
|
+
kind: file.kind,
|
|
472
|
+
action: "new",
|
|
473
|
+
added: splitLines(file.content).length,
|
|
474
|
+
removed: 0,
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
else if (existing === file.content) {
|
|
478
|
+
files.push({
|
|
479
|
+
path: file.relPath,
|
|
480
|
+
kind: file.kind,
|
|
481
|
+
action: "unchanged",
|
|
482
|
+
added: 0,
|
|
483
|
+
removed: 0,
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
else {
|
|
487
|
+
files.push({
|
|
488
|
+
path: file.relPath,
|
|
489
|
+
kind: file.kind,
|
|
490
|
+
action: "overwrite",
|
|
491
|
+
...countLineChanges(existing, file.content),
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
const { pipelineRelPath, packageDirectory, draft } = resolved.value;
|
|
496
|
+
const pipelineIdTaken = (options.mode ?? "create") === "create" &&
|
|
497
|
+
(options.catalogPipelines ?? []).some((listing) => listing.id === draft.pipeline.id &&
|
|
498
|
+
listing.path.replace(/\\/g, "/") !== pipelineRelPath);
|
|
499
|
+
return {
|
|
500
|
+
ok: true,
|
|
501
|
+
pipelinePath: pipelineRelPath,
|
|
502
|
+
directory: path.relative(projectRoot, packageDirectory).replace(/\\/g, "/") || ".",
|
|
503
|
+
files,
|
|
504
|
+
pipelineIdTaken,
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
export function parsePlanDraftPackageBody(body) {
|
|
508
|
+
const parsed = parseCreateDraftPackageBody(body);
|
|
509
|
+
if ("ok" in parsed)
|
|
510
|
+
return parsed;
|
|
511
|
+
const mode = isPlainObject(body) ? body.mode : undefined;
|
|
512
|
+
if (mode !== undefined && mode !== "create" && mode !== "overwrite") {
|
|
513
|
+
return { ok: false, status: 400, error: 'mode must be "create" or "overwrite"' };
|
|
514
|
+
}
|
|
515
|
+
return { ...parsed, mode: mode ?? "create" };
|
|
516
|
+
}
|
|
322
517
|
export function parseDraftPackageBody(body) {
|
|
323
518
|
if (!isPlainObject(body)) {
|
|
324
519
|
return { ok: false, status: 400, error: "JSON object body required" };
|
|
@@ -524,6 +719,7 @@ export async function loadDraftPackage(projectRoot, pipelineRelPath, options = {
|
|
|
524
719
|
...(raw.model !== undefined ? { model: raw.model } : {}),
|
|
525
720
|
...(raw.schemas !== undefined ? { schemas: raw.schemas } : {}),
|
|
526
721
|
...(raw.requires !== undefined ? { requires: raw.requires } : {}),
|
|
722
|
+
...(raw.channels !== undefined ? { channels: raw.channels } : {}),
|
|
527
723
|
},
|
|
528
724
|
...(stageArtifacts.length > 0 ? { stages: stageArtifacts } : {}),
|
|
529
725
|
};
|
|
@@ -540,9 +736,10 @@ export async function loadDraftPackage(projectRoot, pipelineRelPath, options = {
|
|
|
540
736
|
draft.task = loaded.task;
|
|
541
737
|
attachedTaskPath = loaded.taskPath;
|
|
542
738
|
}
|
|
739
|
+
const migrated = hoistUsesWrapperSkills(draft);
|
|
543
740
|
return {
|
|
544
741
|
ok: true,
|
|
545
|
-
draft,
|
|
742
|
+
draft: migrated,
|
|
546
743
|
destination: { directory, pipelineFilename },
|
|
547
744
|
pipelinePath,
|
|
548
745
|
...(attachedTaskPath !== undefined ? { taskPath: attachedTaskPath } : {}),
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import type { CatalogRootKind } from "./resolveCatalogRoots.js";
|
|
1
2
|
/** Directory scanned for workshop-authored pipelines and tasks. */
|
|
2
3
|
export declare const WORKSHOP_PACKAGE_ROOT = "workshop";
|
|
3
4
|
export declare function normalizeCatalogDir(directory: string): string;
|
|
4
5
|
/** Untitled workshop saves land here so Run can see them without a new catalog edit. */
|
|
5
|
-
export declare function defaultWorkshopPackageDirectory(pipelineId: string | undefined): string;
|
|
6
|
+
export declare function defaultWorkshopPackageDirectory(pipelineId: string | undefined, catalogRootKind?: CatalogRootKind): string;
|
|
6
7
|
/**
|
|
7
8
|
* Catalog root that covers this package directory.
|
|
8
9
|
* Packages under `workshop/` share one root. Any other folder is listed itself
|
|
@@ -7,13 +7,17 @@ export function normalizeCatalogDir(directory) {
|
|
|
7
7
|
return directory.replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/\/+$/, "");
|
|
8
8
|
}
|
|
9
9
|
/** Untitled workshop saves land here so Run can see them without a new catalog edit. */
|
|
10
|
-
export function defaultWorkshopPackageDirectory(pipelineId) {
|
|
10
|
+
export function defaultWorkshopPackageDirectory(pipelineId, catalogRootKind) {
|
|
11
11
|
const slug = (pipelineId ?? "")
|
|
12
12
|
.toLowerCase()
|
|
13
13
|
.replace(/[^a-z0-9]+/g, "-")
|
|
14
14
|
.replace(/^-+|-+$/g, "")
|
|
15
15
|
.slice(0, 40);
|
|
16
|
-
|
|
16
|
+
const id = slug || "untitled";
|
|
17
|
+
if (catalogRootKind === "workspace") {
|
|
18
|
+
return id;
|
|
19
|
+
}
|
|
20
|
+
return `${WORKSHOP_PACKAGE_ROOT}/${id}`;
|
|
17
21
|
}
|
|
18
22
|
/**
|
|
19
23
|
* Catalog root that covers this package directory.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { TaskFile } from "../types/task.js";
|
|
2
|
+
import { type ResolveCatalogRootsOptions } from "./resolveCatalogRoots.js";
|
|
3
|
+
export type TaskDetail = TaskFile & {
|
|
4
|
+
path: string;
|
|
5
|
+
};
|
|
6
|
+
export type TaskDetailWithRoot = TaskDetail & {
|
|
7
|
+
project_root: string;
|
|
8
|
+
};
|
|
9
|
+
export type FindTaskInCatalogMultiResult = {
|
|
10
|
+
ok: true;
|
|
11
|
+
task: TaskDetailWithRoot;
|
|
12
|
+
} | {
|
|
13
|
+
ok: false;
|
|
14
|
+
status: 404;
|
|
15
|
+
error: string;
|
|
16
|
+
} | {
|
|
17
|
+
ok: false;
|
|
18
|
+
status: 400;
|
|
19
|
+
error: string;
|
|
20
|
+
code: "unknown_project_root";
|
|
21
|
+
} | {
|
|
22
|
+
ok: false;
|
|
23
|
+
status: 409;
|
|
24
|
+
error: string;
|
|
25
|
+
code: "ambiguous_task";
|
|
26
|
+
project_roots: string[];
|
|
27
|
+
};
|
|
28
|
+
export declare function findTaskInProjectRoot(projectRoot: string, taskId: string): Promise<TaskDetail | null>;
|
|
29
|
+
export declare function findTaskInCatalogMulti(options: ResolveCatalogRootsOptions & {
|
|
30
|
+
taskId: string;
|
|
31
|
+
projectRootFilter?: string;
|
|
32
|
+
}): Promise<FindTaskInCatalogMultiResult>;
|
|
33
|
+
export declare function findTaskInCatalog(cwd: string, taskId: string): Promise<TaskDetail | null>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { getCatalogScanPaths } from "./browseCatalog.js";
|
|
3
|
+
import { loadTaskOutcome } from "./loadTask.js";
|
|
4
|
+
import { listTasksMultiProject } from "./multiProjectCatalog.js";
|
|
5
|
+
import { catalogContextFromStageflow } from "./resolveCatalogContext.js";
|
|
6
|
+
import { findCatalogRoot, } from "./resolveCatalogRoots.js";
|
|
7
|
+
import { resolveStageflowContext } from "../project/resolveStageflowContext.js";
|
|
8
|
+
export async function findTaskInProjectRoot(projectRoot, taskId) {
|
|
9
|
+
const ctx = catalogContextFromStageflow(await resolveStageflowContext(projectRoot));
|
|
10
|
+
const scanPaths = await getCatalogScanPaths(ctx);
|
|
11
|
+
if (!scanPaths || ctx.projectRoot === null) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
const root = ctx.projectRoot;
|
|
15
|
+
for (const filePath of scanPaths.taskPaths) {
|
|
16
|
+
const outcome = await loadTaskOutcome(filePath);
|
|
17
|
+
if (!outcome.ok || outcome.value.id !== taskId) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
...outcome.value,
|
|
22
|
+
path: path.relative(root, filePath).replace(/\\/g, "/"),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
export async function findTaskInCatalogMulti(options) {
|
|
28
|
+
const { taskId, projectRootFilter, ...rootOptions } = options;
|
|
29
|
+
const listed = await listTasksMultiProject({
|
|
30
|
+
...rootOptions,
|
|
31
|
+
projectRootFilter,
|
|
32
|
+
});
|
|
33
|
+
if (projectRootFilter !== undefined &&
|
|
34
|
+
listed.root_errors.some((e) => e.code === "unknown_project_root")) {
|
|
35
|
+
return {
|
|
36
|
+
ok: false,
|
|
37
|
+
status: 400,
|
|
38
|
+
error: listed.root_errors[0].message,
|
|
39
|
+
code: "unknown_project_root",
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const matches = listed.items.filter((t) => t.id === taskId);
|
|
43
|
+
if (matches.length === 0) {
|
|
44
|
+
return { ok: false, status: 404, error: `Task not found: ${taskId}` };
|
|
45
|
+
}
|
|
46
|
+
const projectRoots = [...new Set(matches.map((m) => m.project_root))];
|
|
47
|
+
if (projectRoots.length > 1) {
|
|
48
|
+
return {
|
|
49
|
+
ok: false,
|
|
50
|
+
status: 409,
|
|
51
|
+
error: `Task id is ambiguous across catalog roots: ${taskId}`,
|
|
52
|
+
code: "ambiguous_task",
|
|
53
|
+
project_roots: projectRoots.sort((a, b) => a.localeCompare(b)),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const wireRoot = projectRoots[0];
|
|
57
|
+
const catalogRoot = findCatalogRoot(listed.roots, wireRoot);
|
|
58
|
+
if (catalogRoot === undefined) {
|
|
59
|
+
return { ok: false, status: 404, error: `Task not found: ${taskId}` };
|
|
60
|
+
}
|
|
61
|
+
const detail = await findTaskInProjectRoot(catalogRoot.path, taskId);
|
|
62
|
+
if (!detail) {
|
|
63
|
+
return { ok: false, status: 404, error: `Task not found: ${taskId}` };
|
|
64
|
+
}
|
|
65
|
+
return { ok: true, task: { ...detail, project_root: wireRoot } };
|
|
66
|
+
}
|
|
67
|
+
export async function findTaskInCatalog(cwd, taskId) {
|
|
68
|
+
return findTaskInProjectRoot(cwd, taskId);
|
|
69
|
+
}
|
|
@@ -9,6 +9,14 @@ export declare const KNOWN_STAGEFLOW_ENV_KEYS: Set<string>;
|
|
|
9
9
|
export type CallerQuotaConfig = {
|
|
10
10
|
maxConcurrent: number;
|
|
11
11
|
};
|
|
12
|
+
export declare const DEFAULT_BROWSER_DIALOG_TIMEOUT_SECONDS = 60;
|
|
13
|
+
export type BrowserContainerConfig = {
|
|
14
|
+
image: string;
|
|
15
|
+
shmSize: string;
|
|
16
|
+
memory: string;
|
|
17
|
+
pidsLimit: number;
|
|
18
|
+
};
|
|
19
|
+
export declare const DEFAULT_BROWSER_CONTAINER_IMAGE = "stageflow-browser-sandbox:local";
|
|
12
20
|
export type HostConfig = {
|
|
13
21
|
maxConcurrentRuns: number;
|
|
14
22
|
maxConcurrentRunsPerProject: number | undefined;
|
|
@@ -22,6 +30,18 @@ export type HostConfig = {
|
|
|
22
30
|
callers: Record<string, CallerQuotaConfig>;
|
|
23
31
|
/** Domains no browser stage may use (`browser.blocked_sites` in config.yaml). */
|
|
24
32
|
browserBlockedSites: string[];
|
|
33
|
+
/** Chrome launch arguments (`browser.launch_args`); empty when unset. */
|
|
34
|
+
browserLaunchArgs: string[];
|
|
35
|
+
/** Explicit Chrome path (`browser.executable_path`); undefined when unset. */
|
|
36
|
+
browserExecutablePath: string | undefined;
|
|
37
|
+
/** Seconds an unanswered live view page dialog waits before the Host dismisses it (`browser.dialog_timeout_seconds`). */
|
|
38
|
+
browserDialogTimeoutSeconds: number;
|
|
39
|
+
/** Where shared profile browsers run (`browser.host`): this machine, or one container per run. */
|
|
40
|
+
browserHost: "local" | "container";
|
|
41
|
+
/** Per-owner adapter override (`browser.owner_hosts`, owner scope to host); scopes absent here use `browserHost`. */
|
|
42
|
+
browserOwnerHosts: Record<string, "local" | "container">;
|
|
43
|
+
/** Container host settings (`browser.container`); defaults apply when unset. */
|
|
44
|
+
browserContainer: BrowserContainerConfig;
|
|
25
45
|
/** Absolute path of config.yaml when loaded; undefined if absent. */
|
|
26
46
|
configFilePath: string | undefined;
|
|
27
47
|
warnings: string[];
|
|
@@ -45,6 +65,7 @@ export type HostConfigPublicEcho = {
|
|
|
45
65
|
callers: Record<string, CallerQuotaConfig>;
|
|
46
66
|
secrets: HostConfigSecretsEcho;
|
|
47
67
|
};
|
|
68
|
+
export declare function browserHostForOwner(config: Pick<HostConfig, "browserHost" | "browserOwnerHosts">, scope: string): "local" | "container";
|
|
48
69
|
/**
|
|
49
70
|
* Assemble HostConfig once at boot. Precedence: overrides (CLI flags) > env > file > default.
|
|
50
71
|
*/
|