stageflow 0.32.0 → 0.35.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 +4 -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 +50 -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/fakeAgent.js +0 -6
- package/dist/agent/piAdapter.d.ts +2 -2
- package/dist/agent/piAdapter.js +116 -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 +2 -2
- package/dist/agent/providerAuth.d.ts +6 -0
- package/dist/agent/providerAuth.js +86 -17
- package/dist/agent/{resolveAgentPort.d.ts → resolveStagePort.d.ts} +8 -6
- package/dist/agent/{resolveAgentPort.js → resolveStagePort.js} +13 -9
- 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/cli/browserCommand.d.ts +3 -1
- package/dist/cli/browserCommand.js +25 -20
- 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 +41 -0
- package/dist/config/draftPackage.js +216 -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 +113 -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/listConfig.d.ts +0 -16
- package/dist/config/listConfig.js +0 -3
- package/dist/config/loadOutcome.d.ts +11 -6
- package/dist/config/loadPipeline.js +0 -1
- package/dist/config/loadStage.js +2 -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.js +3 -0
- package/dist/config/normalizePipelineStageEntry.js +10 -1
- 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 +6 -2
- package/dist/config/validateCatalog.js +48 -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/hosted/containment.d.ts +3 -0
- package/dist/hosted/containment.js +36 -0
- package/dist/hosted/errors.d.ts +21 -0
- package/dist/hosted/errors.js +30 -0
- package/dist/hosted/packageSkills.d.ts +3 -0
- package/dist/hosted/packageSkills.js +80 -0
- package/dist/hosted/runtime.d.ts +12 -0
- package/dist/hosted/runtime.js +596 -0
- package/dist/hosted/sequencer.d.ts +28 -0
- package/dist/hosted/sequencer.js +129 -0
- package/dist/hosted/translate.d.ts +3 -0
- package/dist/hosted/translate.js +43 -0
- package/dist/hosted/types.d.ts +108 -0
- package/dist/hosted/types.js +10 -0
- package/dist/index.d.ts +9 -1
- package/dist/index.js +6 -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/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/projection/projectRun.d.ts +0 -1
- package/dist/projection/projectRun.js +0 -1
- 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/containerLimits.d.ts +0 -3
- package/dist/runtime/containerLimits.js +0 -5
- package/dist/runtime/credentialBinding.d.ts +3 -0
- package/dist/runtime/credentialBinding.js +23 -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/pipelineScheduler.d.ts +2 -2
- package/dist/runtime/pipelineScheduler.js +3 -0
- 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 +95 -30
- package/dist/runtime/runRetentionSweep.d.ts +0 -2
- package/dist/runtime/runRetentionSweep.js +0 -8
- 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 +10 -1
- package/dist/runtime/stageProcessLauncher.js +2 -2
- package/dist/runtime/stageRoots.js +12 -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 +7 -2
- package/dist/server/bootstrap.js +15 -1
- 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 +605 -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/readEmail.d.ts +3 -3
- package/dist/tools/writeStageArtifact.d.ts +9 -0
- package/dist/tools/writeStageArtifact.js +2 -47
- package/dist/types/pipeline.d.ts +1 -1
- package/dist/types/stage.d.ts +1 -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-BoFPkKFg.js +256 -0
- package/dist/ui/assets/{index-Bv4p1aPK.css → index-CIPbbBUi.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/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 +9 -1
- 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,3 +1,4 @@
|
|
|
1
|
+
import { addModelUsage, emptyStageUsage } from "../types/usage.js";
|
|
1
2
|
import { derivePendingPrompt } from "../hitl/qaTrail.js";
|
|
2
3
|
import { stageStatusFromEvents } from "./port.js";
|
|
3
4
|
import { listArtifactNames } from "./workspaceLayout.js";
|
|
@@ -19,6 +20,7 @@ export async function buildStageSnapshotFromStore(store, runId, stageId, workspa
|
|
|
19
20
|
let envelope;
|
|
20
21
|
let attempt_count;
|
|
21
22
|
let cost_usd;
|
|
23
|
+
let usage;
|
|
22
24
|
if (latest !== null) {
|
|
23
25
|
events = await store.listStageEvents(runId, stageId, latest.attempt);
|
|
24
26
|
status = stageStatusFromEvents(events);
|
|
@@ -26,6 +28,7 @@ export async function buildStageSnapshotFromStore(store, runId, stageId, workspa
|
|
|
26
28
|
attempt_count = await store.countStageAttempts(runId, stageId);
|
|
27
29
|
const executions = await store.listStageExecutions(runId, stageId);
|
|
28
30
|
cost_usd = sumStageExecutionCost(executions);
|
|
31
|
+
usage = mergeStageExecutionUsage(executions);
|
|
29
32
|
}
|
|
30
33
|
else {
|
|
31
34
|
events = await store.listStageEvents(runId, stageId);
|
|
@@ -46,8 +49,24 @@ export async function buildStageSnapshotFromStore(store, runId, stageId, workspa
|
|
|
46
49
|
attempt_count,
|
|
47
50
|
...(pending ? { pending_prompt: pending } : {}),
|
|
48
51
|
...(cost_usd !== undefined ? { cost_usd } : {}),
|
|
52
|
+
...(usage !== undefined ? { usage } : {}),
|
|
49
53
|
};
|
|
50
54
|
}
|
|
55
|
+
export function mergeStageExecutionUsage(executions) {
|
|
56
|
+
const usages = executions
|
|
57
|
+
.map((e) => e.usage)
|
|
58
|
+
.filter((u) => u !== undefined);
|
|
59
|
+
if (usages.length === 0)
|
|
60
|
+
return undefined;
|
|
61
|
+
const merged = emptyStageUsage();
|
|
62
|
+
for (const u of usages) {
|
|
63
|
+
for (const [model, breakdown] of Object.entries(u.models)) {
|
|
64
|
+
addModelUsage(merged, model, breakdown);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
merged.costUsd = usages.reduce((sum, u) => sum + u.costUsd, 0);
|
|
68
|
+
return merged;
|
|
69
|
+
}
|
|
51
70
|
/** Sum cost across every attempt — retries are real spend too, so a stage's total isn't just its latest attempt. */
|
|
52
71
|
function sumStageExecutionCost(executions) {
|
|
53
72
|
const costs = executions.map((e) => e.cost_usd).filter((c) => c !== undefined);
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { access, lstat, mkdir, readdir, realpath } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { globalCredentialRoot } from "../project/globalHome.js";
|
|
4
|
+
import { STAGEFLOW_AGENT_AUTH_PATH_ENV } from "../runtime/credentialBinding.js";
|
|
5
|
+
import { SF_STAGE_WORKER } from "../runtime/stageWorkerProtocol.js";
|
|
3
6
|
export { stageDir } from "./paths.js";
|
|
4
7
|
export function guardStageId(stageId) {
|
|
5
8
|
if (stageId.includes("..") ||
|
|
@@ -101,6 +104,15 @@ export async function resolveEffectiveRealPath(candidatePath) {
|
|
|
101
104
|
}
|
|
102
105
|
}
|
|
103
106
|
}
|
|
107
|
+
function credentialRootForFileToolDenial() {
|
|
108
|
+
if (process.env[SF_STAGE_WORKER] === "1") {
|
|
109
|
+
const stamped = process.env[STAGEFLOW_AGENT_AUTH_PATH_ENV]?.trim();
|
|
110
|
+
if (!stamped)
|
|
111
|
+
return undefined;
|
|
112
|
+
return path.resolve(path.dirname(stamped), "..");
|
|
113
|
+
}
|
|
114
|
+
return globalCredentialRoot();
|
|
115
|
+
}
|
|
104
116
|
export async function durableRootFileToolDenial(candidatePath, runWorkspaceDir, durableRoot, allowlistedRoots) {
|
|
105
117
|
const fileReal = await resolveEffectiveRealPath(candidatePath);
|
|
106
118
|
if (fileReal === undefined) {
|
|
@@ -137,6 +149,21 @@ export async function durableRootFileToolDenial(candidatePath, runWorkspaceDir,
|
|
|
137
149
|
if (isInsideDir(fileReal, durableReal)) {
|
|
138
150
|
return STAGEFLOW_PATH_DENIED;
|
|
139
151
|
}
|
|
152
|
+
const credentialRoot = credentialRootForFileToolDenial();
|
|
153
|
+
if (credentialRoot !== undefined) {
|
|
154
|
+
let credentialReal;
|
|
155
|
+
try {
|
|
156
|
+
credentialReal = await realpath(credentialRoot);
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
credentialReal = path.resolve(credentialRoot);
|
|
160
|
+
}
|
|
161
|
+
if (credentialReal !== durableReal &&
|
|
162
|
+
!isInsideDir(credentialReal, durableReal) &&
|
|
163
|
+
isInsideDir(fileReal, credentialReal)) {
|
|
164
|
+
return STAGEFLOW_PATH_DENIED;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
140
167
|
return undefined;
|
|
141
168
|
}
|
|
142
169
|
export function resolveArtifactTarget(runWorkspaceDir, stageId, attempt, relativePath) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function writeContainedArtifact(runWorkspaceDir: string, artifactsDirectory: string, absolutePath: string, content: string): Promise<void>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atomic write of one file under a stage attempt's artifacts directory.
|
|
3
|
+
* Refuses symlinked or hard-linked targets and any path that resolves outside
|
|
4
|
+
* the artifacts directory.
|
|
5
|
+
*/
|
|
6
|
+
import { randomBytes } from "node:crypto";
|
|
7
|
+
import { lstat, realpath, rename, unlink, writeFile } from "node:fs/promises";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { ensureRealArtifactsDir, isInsideDir, resolveContainedParent, } from "./workspaceLayout.js";
|
|
10
|
+
async function assertSafeWriteTarget(targetPath) {
|
|
11
|
+
try {
|
|
12
|
+
const st = await lstat(targetPath);
|
|
13
|
+
if (st.isSymbolicLink()) {
|
|
14
|
+
throw new Error("path escapes the stage artifacts directory");
|
|
15
|
+
}
|
|
16
|
+
if (st.nlink > 1) {
|
|
17
|
+
throw new Error("refusing to overwrite hard-linked file");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
if (err.code !== "ENOENT") {
|
|
22
|
+
throw err;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export async function writeContainedArtifact(runWorkspaceDir, artifactsDirectory, absolutePath, content) {
|
|
27
|
+
const { realArtifacts } = await ensureRealArtifactsDir(runWorkspaceDir, artifactsDirectory);
|
|
28
|
+
const relativeToArtifacts = path.relative(artifactsDirectory, absolutePath);
|
|
29
|
+
const parent = await resolveContainedParent(realArtifacts, relativeToArtifacts);
|
|
30
|
+
const baseName = path.basename(absolutePath);
|
|
31
|
+
const targetPath = path.join(parent, baseName);
|
|
32
|
+
await assertSafeWriteTarget(targetPath);
|
|
33
|
+
const tmpName = `.sf-artifact-${randomBytes(8).toString("hex")}.tmp`;
|
|
34
|
+
const tmpPath = path.join(parent, tmpName);
|
|
35
|
+
try {
|
|
36
|
+
await writeFile(tmpPath, content, "utf8");
|
|
37
|
+
await rename(tmpPath, targetPath);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
try {
|
|
41
|
+
await unlink(tmpPath);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// best-effort cleanup
|
|
45
|
+
}
|
|
46
|
+
throw err;
|
|
47
|
+
}
|
|
48
|
+
const realWritten = await realpath(targetPath);
|
|
49
|
+
if (!isInsideDir(realWritten, realArtifacts)) {
|
|
50
|
+
throw new Error("path escapes the stage artifacts directory");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import os from "node:os";
|
|
2
1
|
export type ContainerLimits = {
|
|
3
2
|
memoryLimitBytes: number | undefined;
|
|
4
3
|
maxActiveStageProcesses: number;
|
|
@@ -12,5 +11,3 @@ export declare function readContainerMemoryLimit(roots?: readonly string[]): {
|
|
|
12
11
|
export declare function deriveContainerLimits(memoryLimitBytes: number | undefined, source?: ContainerLimits["source"]): ContainerLimits;
|
|
13
12
|
export declare function getContainerLimits(): ContainerLimits;
|
|
14
13
|
export declare function resetContainerLimitsForTests(): void;
|
|
15
|
-
/** Test hook: prove sizing never consults os.totalmem. */
|
|
16
|
-
export declare function assertNoOsTotalmemInSizing(): typeof os.totalmem;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { readFileSync, existsSync } from "node:fs";
|
|
2
|
-
import os from "node:os";
|
|
3
2
|
const HOST_RESERVE_MIB = 512;
|
|
4
3
|
const WORKER_BUDGET_MIB = 512;
|
|
5
4
|
const MAX_CAP = 8;
|
|
@@ -78,7 +77,3 @@ export function getContainerLimits() {
|
|
|
78
77
|
export function resetContainerLimitsForTests() {
|
|
79
78
|
cached = undefined;
|
|
80
79
|
}
|
|
81
|
-
/** Test hook: prove sizing never consults os.totalmem. */
|
|
82
|
-
export function assertNoOsTotalmemInSizing() {
|
|
83
|
-
return os.totalmem;
|
|
84
|
-
}
|
|
@@ -19,5 +19,8 @@ export declare function stageflowAgentAuthPath(override?: string): string;
|
|
|
19
19
|
export declare function piHomeAuthPath(override?: string): string;
|
|
20
20
|
export declare function isUsableAuthFile(authPath: string): boolean;
|
|
21
21
|
export declare function ensureSfOwnedAuthStore(): string;
|
|
22
|
+
/** Use this auth file for credential binding and do not create the operator home. */
|
|
23
|
+
export declare function runWithExplicitAuthPath<T>(authPath: string, fn: () => Promise<T>): Promise<T>;
|
|
24
|
+
export declare function currentExplicitAuthPath(): string | undefined;
|
|
22
25
|
export declare function resolveCredentialBinding(ctx: ProjectContext | string, _options?: ResolveCredentialBindingOptions): CredentialBinding;
|
|
23
26
|
export { readCredentialSourceFromFile, writeCredentialSourceToFile, } from "./settingsFile.js";
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { chmodSync, existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
3
|
import path from "node:path";
|
|
3
|
-
import { ensureGlobalHome } from "../project/globalHome.js";
|
|
4
|
+
import { ensureGlobalHome, globalCredentialRoot } from "../project/globalHome.js";
|
|
4
5
|
import { resolveProjectContext, } from "../project/resolveProjectContext.js";
|
|
5
6
|
import { parseCredentialSource, readCredentialSourceFromContext, writeCredentialSourceToContext, } from "./settingsFile.js";
|
|
6
7
|
export { parseCredentialSource, readCredentialSourceFromContext, writeCredentialSourceToContext, };
|
|
7
8
|
export function sfOwnedAgentDir() {
|
|
8
|
-
return path.join(
|
|
9
|
+
return path.join(globalCredentialRoot(), "agent");
|
|
9
10
|
}
|
|
10
11
|
export function sfOwnedAuthPath() {
|
|
11
12
|
return path.join(sfOwnedAgentDir(), "auth.json");
|
|
@@ -41,7 +42,15 @@ export function isUsableAuthFile(authPath) {
|
|
|
41
42
|
}
|
|
42
43
|
export function ensureSfOwnedAuthStore() {
|
|
43
44
|
ensureGlobalHome();
|
|
44
|
-
const
|
|
45
|
+
const agentDir = sfOwnedAgentDir();
|
|
46
|
+
mkdirSync(agentDir, { recursive: true });
|
|
47
|
+
try {
|
|
48
|
+
chmodSync(agentDir, 0o700);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// best-effort on non-POSIX
|
|
52
|
+
}
|
|
53
|
+
const authPath = path.join(agentDir, "auth.json");
|
|
45
54
|
if (!existsSync(authPath)) {
|
|
46
55
|
writeFileSync(authPath, "{}\n", { encoding: "utf8", mode: 0o600 });
|
|
47
56
|
}
|
|
@@ -53,13 +62,21 @@ export function ensureSfOwnedAuthStore() {
|
|
|
53
62
|
}
|
|
54
63
|
return authPath;
|
|
55
64
|
}
|
|
65
|
+
const explicitAuthPath = new AsyncLocalStorage();
|
|
66
|
+
/** Use this auth file for credential binding and do not create the operator home. */
|
|
67
|
+
export function runWithExplicitAuthPath(authPath, fn) {
|
|
68
|
+
return explicitAuthPath.run(path.resolve(authPath), fn);
|
|
69
|
+
}
|
|
70
|
+
export function currentExplicitAuthPath() {
|
|
71
|
+
return explicitAuthPath.getStore();
|
|
72
|
+
}
|
|
56
73
|
export function resolveCredentialBinding(ctx, _options = {}) {
|
|
74
|
+
const explicit = currentExplicitAuthPath();
|
|
57
75
|
const projectCtx = typeof ctx === "string" ? resolveProjectContext(ctx) : ctx;
|
|
58
76
|
const persisted = readCredentialSourceFromContext(projectCtx);
|
|
59
|
-
const authPath = ensureSfOwnedAuthStore();
|
|
60
77
|
return {
|
|
61
78
|
source: "sf_owned",
|
|
62
|
-
authPath,
|
|
79
|
+
authPath: explicit ?? sfOwnedAuthPath(),
|
|
63
80
|
provisional: persisted === undefined,
|
|
64
81
|
};
|
|
65
82
|
}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
1
|
import { ImapFlow } from "imapflow";
|
|
3
|
-
import {
|
|
4
|
-
import { loadTriggerOutcome } from "../config/loadTrigger.js";
|
|
5
|
-
import { catalogContextFromStageflow } from "../config/resolveCatalogContext.js";
|
|
2
|
+
import { listCatalogTriggerMatches, triggerStoreId, } from "../config/triggerCatalog.js";
|
|
6
3
|
import { readSecretFromEnvOrFile } from "../config/secretFromEnvOrFile.js";
|
|
7
|
-
import { resolveStageflowContext } from "../project/resolveStageflowContext.js";
|
|
8
4
|
import { matchesEventFilter } from "./triggerEventMatch.js";
|
|
9
5
|
export const DEFAULT_EMAIL_RECONNECT_BASE_DELAY_MS = 1_000;
|
|
10
6
|
export const DEFAULT_EMAIL_RECONNECT_MAX_DELAY_MS = 30_000;
|
|
@@ -122,20 +118,17 @@ export class EmailSource {
|
|
|
122
118
|
}
|
|
123
119
|
async start(onFire) {
|
|
124
120
|
this.stopped = false;
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const groups =
|
|
121
|
+
const catalogTriggers = await listCatalogTriggerMatches({
|
|
122
|
+
store: this.store,
|
|
123
|
+
bootCwd: this.cwd,
|
|
124
|
+
sourceRootsOnly: true,
|
|
125
|
+
});
|
|
126
|
+
const groups = this.discover(catalogTriggers);
|
|
131
127
|
for (const [mailboxKey, group] of groups) {
|
|
132
128
|
for (const match of group.matches) {
|
|
133
|
-
const definitionRef = projectRoot !== undefined
|
|
134
|
-
? path.relative(projectRoot, match.path).replace(/\\/g, "/")
|
|
135
|
-
: match.path;
|
|
136
129
|
await this.store.upsertTrigger({
|
|
137
|
-
id: match.definition.id,
|
|
138
|
-
definitionRef,
|
|
130
|
+
id: triggerStoreId(match.project_root, match.definition.id),
|
|
131
|
+
definitionRef: match.definition_ref,
|
|
139
132
|
enabled: true,
|
|
140
133
|
});
|
|
141
134
|
}
|
|
@@ -161,13 +154,10 @@ export class EmailSource {
|
|
|
161
154
|
}
|
|
162
155
|
this.connections.clear();
|
|
163
156
|
}
|
|
164
|
-
|
|
157
|
+
discover(catalogTriggers) {
|
|
165
158
|
const groups = new Map();
|
|
166
|
-
for (const
|
|
167
|
-
const
|
|
168
|
-
if (!outcome.ok)
|
|
169
|
-
continue;
|
|
170
|
-
const definition = outcome.value;
|
|
159
|
+
for (const match of catalogTriggers) {
|
|
160
|
+
const definition = match.definition;
|
|
171
161
|
if (definition.kind !== "event" || !definition.enabled)
|
|
172
162
|
continue;
|
|
173
163
|
const source = definition.event?.source;
|
|
@@ -181,7 +171,7 @@ export class EmailSource {
|
|
|
181
171
|
}
|
|
182
172
|
const mailboxKey = mailboxKeyFor(config);
|
|
183
173
|
const group = groups.get(mailboxKey) ?? { config, matches: [] };
|
|
184
|
-
group.matches.push(
|
|
174
|
+
group.matches.push(match);
|
|
185
175
|
groups.set(mailboxKey, group);
|
|
186
176
|
}
|
|
187
177
|
return groups;
|
|
@@ -274,20 +264,22 @@ export class EmailSource {
|
|
|
274
264
|
date: message.date,
|
|
275
265
|
text: message.text,
|
|
276
266
|
};
|
|
277
|
-
for (const
|
|
267
|
+
for (const match of conn.group.matches) {
|
|
268
|
+
const { definition } = match;
|
|
278
269
|
if (!matchesEventFilter(definition.event?.match, summary))
|
|
279
270
|
continue;
|
|
280
|
-
await this.fireSafely(conn.onFire,
|
|
271
|
+
await this.fireSafely(conn.onFire, match, message, summary);
|
|
281
272
|
}
|
|
282
273
|
}
|
|
283
274
|
if (maxUid > sinceUid) {
|
|
284
275
|
await this.store.setTriggerAdapterState(mailboxKey, "uid", String(maxUid));
|
|
285
276
|
}
|
|
286
277
|
}
|
|
287
|
-
async fireSafely(onFire,
|
|
278
|
+
async fireSafely(onFire, match, message, summary) {
|
|
279
|
+
const definition = match.definition;
|
|
288
280
|
try {
|
|
289
281
|
if (definition.task !== undefined) {
|
|
290
|
-
await onFire({ triggerId: definition.id });
|
|
282
|
+
await onFire({ triggerId: definition.id, project_root: match.project_root });
|
|
291
283
|
return;
|
|
292
284
|
}
|
|
293
285
|
const task = {
|
|
@@ -295,7 +287,7 @@ export class EmailSource {
|
|
|
295
287
|
goal: `Handle email: ${message.subject}`,
|
|
296
288
|
input: summary,
|
|
297
289
|
};
|
|
298
|
-
await onFire({ triggerId: definition.id, task });
|
|
290
|
+
await onFire({ triggerId: definition.id, project_root: match.project_root, task });
|
|
299
291
|
}
|
|
300
292
|
catch (err) {
|
|
301
293
|
this.logError(`email: firing trigger "${definition.id}" failed: ${errMsg(err)}`);
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
1
|
import { Octokit } from "octokit";
|
|
3
|
-
import {
|
|
4
|
-
import { loadTriggerOutcome } from "../config/loadTrigger.js";
|
|
5
|
-
import { catalogContextFromStageflow } from "../config/resolveCatalogContext.js";
|
|
2
|
+
import { listCatalogTriggerMatches, triggerStoreId, } from "../config/triggerCatalog.js";
|
|
6
3
|
import { readSecretFromEnvOrFile } from "../config/secretFromEnvOrFile.js";
|
|
7
|
-
import { resolveStageflowContext } from "../project/resolveStageflowContext.js";
|
|
8
4
|
import { matchesEventFilter } from "./triggerEventMatch.js";
|
|
9
5
|
export const DEFAULT_GITHUB_POLL_INTERVAL_MS = 60_000;
|
|
10
6
|
export const DEFAULT_GITHUB_TOKEN_SECRET = "GITHUB_TOKEN";
|
|
@@ -166,33 +162,27 @@ export class GithubPollSource {
|
|
|
166
162
|
* instead of waiting on real interval timers.
|
|
167
163
|
*/
|
|
168
164
|
async tick(onFire) {
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const groups =
|
|
165
|
+
const catalogTriggers = await listCatalogTriggerMatches({
|
|
166
|
+
store: this.store,
|
|
167
|
+
bootCwd: this.cwd,
|
|
168
|
+
sourceRootsOnly: true,
|
|
169
|
+
});
|
|
170
|
+
const groups = this.discover(catalogTriggers);
|
|
175
171
|
for (const [repo, matches] of groups) {
|
|
176
172
|
for (const match of matches) {
|
|
177
|
-
const definitionRef = projectRoot !== undefined
|
|
178
|
-
? path.relative(projectRoot, match.path).replace(/\\/g, "/")
|
|
179
|
-
: match.path;
|
|
180
173
|
await this.store.upsertTrigger({
|
|
181
|
-
id: match.definition.id,
|
|
182
|
-
definitionRef,
|
|
174
|
+
id: triggerStoreId(match.project_root, match.definition.id),
|
|
175
|
+
definitionRef: match.definition_ref,
|
|
183
176
|
enabled: true,
|
|
184
177
|
});
|
|
185
178
|
}
|
|
186
179
|
await this.pollRepo(repo, matches, onFire);
|
|
187
180
|
}
|
|
188
181
|
}
|
|
189
|
-
|
|
182
|
+
discover(catalogTriggers) {
|
|
190
183
|
const groups = new Map();
|
|
191
|
-
for (const
|
|
192
|
-
const
|
|
193
|
-
if (!outcome.ok)
|
|
194
|
-
continue;
|
|
195
|
-
const definition = outcome.value;
|
|
184
|
+
for (const match of catalogTriggers) {
|
|
185
|
+
const definition = match.definition;
|
|
196
186
|
if (definition.kind !== "event" || !definition.enabled)
|
|
197
187
|
continue;
|
|
198
188
|
const source = definition.event?.source;
|
|
@@ -205,7 +195,7 @@ export class GithubPollSource {
|
|
|
205
195
|
continue;
|
|
206
196
|
}
|
|
207
197
|
const list = groups.get(repo) ?? [];
|
|
208
|
-
list.push(
|
|
198
|
+
list.push(match);
|
|
209
199
|
groups.set(repo, list);
|
|
210
200
|
}
|
|
211
201
|
return groups;
|
|
@@ -256,18 +246,20 @@ export class GithubPollSource {
|
|
|
256
246
|
const newItems = response.items.filter((item) => isNewerThanCursor(item, cursor)).reverse();
|
|
257
247
|
for (const item of newItems) {
|
|
258
248
|
const summary = normalizeGithubItem(item, repo);
|
|
259
|
-
for (const
|
|
249
|
+
for (const match of matches) {
|
|
250
|
+
const { definition } = match;
|
|
260
251
|
if (!matchesEventFilter(definition.event?.match, summary))
|
|
261
252
|
continue;
|
|
262
|
-
await this.fireSafely(onFire,
|
|
253
|
+
await this.fireSafely(onFire, match, summary);
|
|
263
254
|
}
|
|
264
255
|
}
|
|
265
256
|
await this.store.setTriggerAdapterState(adapterId, "cursor", JSON.stringify({ updatedAt: newest.updated_at, number: newest.number }));
|
|
266
257
|
}
|
|
267
|
-
async fireSafely(onFire,
|
|
258
|
+
async fireSafely(onFire, match, summary) {
|
|
259
|
+
const definition = match.definition;
|
|
268
260
|
try {
|
|
269
261
|
if (definition.task !== undefined) {
|
|
270
|
-
await onFire({ triggerId: definition.id });
|
|
262
|
+
await onFire({ triggerId: definition.id, project_root: match.project_root });
|
|
271
263
|
return;
|
|
272
264
|
}
|
|
273
265
|
const task = {
|
|
@@ -275,7 +267,7 @@ export class GithubPollSource {
|
|
|
275
267
|
goal: `Handle PR #${summary.number}: ${summary.title}`,
|
|
276
268
|
input: summary,
|
|
277
269
|
};
|
|
278
|
-
await onFire({ triggerId: definition.id, task });
|
|
270
|
+
await onFire({ triggerId: definition.id, project_root: match.project_root, task });
|
|
279
271
|
}
|
|
280
272
|
catch (err) {
|
|
281
273
|
this.logError(`github poll: firing trigger "${definition.id}" failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RunSubmission } from "../runstore/submission.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { StagePort } from "../agent/port.js";
|
|
3
3
|
import { type ValidationFinding } from "../config/validateCatalog.js";
|
|
4
4
|
import type { RunStore } from "../runstore/port.js";
|
|
5
5
|
import type { StageEnvelope } from "../types/envelope.js";
|
|
@@ -54,7 +54,7 @@ export type PreparedPipeline = {
|
|
|
54
54
|
workspaceDir: string;
|
|
55
55
|
created?: boolean;
|
|
56
56
|
};
|
|
57
|
-
agent:
|
|
57
|
+
agent: StagePort;
|
|
58
58
|
store: RunStore;
|
|
59
59
|
cwd: string;
|
|
60
60
|
projectRoot: string;
|
|
@@ -81,7 +81,7 @@ export type ExecuteStagesOptions = {
|
|
|
81
81
|
};
|
|
82
82
|
export declare function executeStages(prepared: PreparedPipeline, options?: ExecuteStagesOptions): Promise<PipelineRunResult>;
|
|
83
83
|
export declare function runPipeline(options: {
|
|
84
|
-
agent:
|
|
84
|
+
agent: StagePort;
|
|
85
85
|
store: RunStore;
|
|
86
86
|
taskPath?: string;
|
|
87
87
|
taskYaml?: string;
|
|
@@ -101,7 +101,7 @@ export declare function runPipeline(options: {
|
|
|
101
101
|
export declare function startPipeline(options: {
|
|
102
102
|
dispatchKey?: string;
|
|
103
103
|
submission?: RunSubmission;
|
|
104
|
-
agent:
|
|
104
|
+
agent: StagePort;
|
|
105
105
|
store: RunStore;
|
|
106
106
|
taskPath?: string;
|
|
107
107
|
taskYaml?: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { StagePort } from "../agent/port.js";
|
|
2
2
|
import type { RunPipelineDagSnapshot, RunStore, StageSnapshot } from "../runstore/port.js";
|
|
3
3
|
import type { StageBrowserSupport } from "../browser/browserHost.js";
|
|
4
4
|
import type { StageEnvelope } from "../types/envelope.js";
|
|
@@ -17,7 +17,7 @@ type SchedulerPreparedPipeline = {
|
|
|
17
17
|
runId: string;
|
|
18
18
|
workspaceDir: string;
|
|
19
19
|
};
|
|
20
|
-
agent:
|
|
20
|
+
agent: StagePort;
|
|
21
21
|
store: RunStore;
|
|
22
22
|
cwd: string;
|
|
23
23
|
projectRoot?: string;
|
|
@@ -2,6 +2,7 @@ import { normalizeForkChoice } from "../envelope/forkChoice.js";
|
|
|
2
2
|
import { refreshRunDiskUsage } from "../runstore/diskUsage.js";
|
|
3
3
|
import { buildPipelineDagSnapshotFromLoaded } from "../runstore/pipelineDagSnapshot.js";
|
|
4
4
|
import { defaultStageBrowserSupport, resolveStageBrowserEnv, } from "../browser/stageBrowserEnv.js";
|
|
5
|
+
import { runOwnerScope } from "../browser/ownerScope.js";
|
|
5
6
|
import { teardownRunBrowsers, teardownStageBrowser, } from "../browser/browserTeardown.js";
|
|
6
7
|
import { isHumanLoginStage } from "../browser/humanLogin.js";
|
|
7
8
|
import { createRunLiveness } from "../browser/runLiveness.js";
|
|
@@ -856,6 +857,7 @@ export async function runPipelineDag(options) {
|
|
|
856
857
|
let acquired;
|
|
857
858
|
try {
|
|
858
859
|
acquired = await acquireStageProfile(prepared.browser ?? defaultStageBrowserSupport(), {
|
|
860
|
+
scope: runOwnerScope(prepared.browser ?? defaultStageBrowserSupport(), { runId: run.runId }),
|
|
859
861
|
profile,
|
|
860
862
|
owner: { runId: run.runId, stageId },
|
|
861
863
|
isRunLive: createRunLiveness(store),
|
|
@@ -944,6 +946,7 @@ export async function runPipelineDag(options) {
|
|
|
944
946
|
browserEnv = await resolveStageBrowserEnv(prepared.browser ?? defaultStageBrowserSupport(), {
|
|
945
947
|
runId: run.runId,
|
|
946
948
|
stageId,
|
|
949
|
+
scope: runOwnerScope(prepared.browser ?? defaultStageBrowserSupport(), { runId: run.runId }),
|
|
947
950
|
runDir: run.workspaceDir,
|
|
948
951
|
browser: stage.browser,
|
|
949
952
|
attempt,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { StagePort, OpaqueAnswer } from "../agent/port.js";
|
|
2
2
|
import type { RunStore, RunMeta } from "../runstore/port.js";
|
|
3
3
|
import type { LoadedPipeline } from "../types/pipeline.js";
|
|
4
4
|
import type { TaskFile } from "../types/task.js";
|
|
@@ -10,7 +10,7 @@ export type PreparedResumeContext = {
|
|
|
10
10
|
runId: string;
|
|
11
11
|
stageId: string;
|
|
12
12
|
opaqueAnswer: OpaqueAnswer;
|
|
13
|
-
agent:
|
|
13
|
+
agent: StagePort;
|
|
14
14
|
store: RunStore;
|
|
15
15
|
hitl: StageHitlController;
|
|
16
16
|
executionMode: StageExecutionMode;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { StagePort } from "../agent/port.js";
|
|
2
2
|
import type { RunStore } from "../runstore/port.js";
|
|
3
3
|
import type { StageExecutionMode } from "./stageConcurrency.js";
|
|
4
4
|
import type { StageProcessLauncher } from "./stageProcessLauncher.js";
|
|
@@ -7,7 +7,7 @@ import { type OperatorCatalog } from "./stageAttemptBootstrap.js";
|
|
|
7
7
|
export type ResumeTimedOutContext = {
|
|
8
8
|
runId: string;
|
|
9
9
|
stageId: string;
|
|
10
|
-
agent:
|
|
10
|
+
agent: StagePort;
|
|
11
11
|
store: RunStore;
|
|
12
12
|
hitl: StageHitlController;
|
|
13
13
|
executionMode: StageExecutionMode;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type RunSubmission } from "../runstore/submission.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { StagePort, OpaqueAnswer } from "../agent/port.js";
|
|
3
3
|
import type { InlinePipelineDefinition } from "../types/pipeline.js";
|
|
4
4
|
import { type DiskBreakdown, type FreeSpaceReader } from "../runstore/diskUsage.js";
|
|
5
5
|
import { type RunStore } from "../runstore/port.js";
|
|
@@ -155,6 +155,9 @@ export declare class RunManager {
|
|
|
155
155
|
private readonly queuedDone;
|
|
156
156
|
private admissionDrainInFlight;
|
|
157
157
|
private readonly resumeInFlight;
|
|
158
|
+
private readonly gateClosedListeners;
|
|
159
|
+
private readonly beforeBrowserTeardownListeners;
|
|
160
|
+
private readonly shutdownListeners;
|
|
158
161
|
private readonly retryInFlight;
|
|
159
162
|
private readonly retryStartOwner;
|
|
160
163
|
private readonly retryStartWaiters;
|
|
@@ -176,7 +179,7 @@ export declare class RunManager {
|
|
|
176
179
|
private readonly isGitProject;
|
|
177
180
|
private acceptingWork;
|
|
178
181
|
constructor(options: {
|
|
179
|
-
agent:
|
|
182
|
+
agent: StagePort;
|
|
180
183
|
store: RunStore;
|
|
181
184
|
cwd?: string;
|
|
182
185
|
projectRoot?: string;
|
|
@@ -239,6 +242,7 @@ export declare class RunManager {
|
|
|
239
242
|
hasActiveWorker(runId: string, stageId: string): boolean;
|
|
240
243
|
sweepBrowserSessions(): Promise<{
|
|
241
244
|
closed: string[];
|
|
245
|
+
released: string[];
|
|
242
246
|
}>;
|
|
243
247
|
reconcileOrphanedStages(): Promise<{
|
|
244
248
|
reconciled: Array<{
|
|
@@ -267,6 +271,18 @@ export declare class RunManager {
|
|
|
267
271
|
}>>;
|
|
268
272
|
/** Rebuild in-memory admission queue from persisted `queued` rows (R27). */
|
|
269
273
|
reenqueuePersistedQueuedRuns(): Promise<void>;
|
|
274
|
+
/** Called when a stage's gate stops accepting operator input (answered, abandoned) or a run is cancelled (no stage id). */
|
|
275
|
+
onGateClosed(listener: (runId: string, stageId?: string) => void): () => void;
|
|
276
|
+
/** Awaited (bounded by the browser support) before a stage's or run's browser is torn down; stageId absent means the whole run. */
|
|
277
|
+
beforeBrowserTeardown(listener: (input: {
|
|
278
|
+
runId: string;
|
|
279
|
+
stageId?: string;
|
|
280
|
+
}) => Promise<void> | void): () => void;
|
|
281
|
+
/** Called once the Host stops accepting work (drain start). */
|
|
282
|
+
onShutdown(listener: () => void): () => void;
|
|
283
|
+
private browserSupport;
|
|
284
|
+
private browserOption;
|
|
285
|
+
private notifyGateClosed;
|
|
270
286
|
abandonStage(runId: string, stageId: string): Promise<AbandonStageResult>;
|
|
271
287
|
cancelRun(runId: string, reason: string): Promise<CancelRunResult>;
|
|
272
288
|
setA2aStore(store: A2aStore): void;
|