stageflow 0.2.0 → 0.8.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 +179 -14
- package/dist/agent/activity.d.ts +12 -1
- package/dist/agent/activity.js +37 -2
- package/dist/agent/activityObserver.d.ts +5 -1
- package/dist/agent/activityObserver.js +174 -11
- package/dist/agent/cursorProvider.d.ts +1 -10
- package/dist/agent/cursorProvider.js +18 -10
- package/dist/agent/fakeAgent.js +15 -7
- package/dist/agent/piAdapter.d.ts +18 -1
- package/dist/agent/piAdapter.js +115 -45
- package/dist/agent/port.d.ts +7 -0
- package/dist/agent/port.js +3 -0
- package/dist/agent/providerAuth.js +12 -7
- package/dist/catalog/displayCatalogPath.d.ts +12 -0
- package/dist/catalog/displayCatalogPath.js +28 -0
- package/dist/cli/artifactCommand.d.ts +10 -0
- package/dist/cli/artifactCommand.js +120 -0
- package/dist/cli/envelopeCommand.d.ts +32 -0
- package/dist/cli/envelopeCommand.js +285 -0
- package/dist/cli/exportRunCommand.d.ts +10 -0
- package/dist/cli/exportRunCommand.js +150 -0
- package/dist/cli/handoffFormat.d.ts +22 -0
- package/dist/cli/handoffFormat.js +61 -0
- package/dist/cli/initCommand.d.ts +9 -0
- package/dist/cli/initCommand.js +71 -0
- package/dist/cli/initTemplates.d.ts +3 -0
- package/dist/cli/initTemplates.js +19 -0
- package/dist/cli/operatorCatalog.d.ts +10 -0
- package/dist/cli/operatorCatalog.js +16 -0
- package/dist/cli/runCommand.d.ts +7 -1
- package/dist/cli/runCommand.js +83 -11
- package/dist/cli/runOutput.d.ts +4 -1
- package/dist/cli/runOutput.js +36 -8
- package/dist/cli/skillsCommand.d.ts +16 -0
- package/dist/cli/skillsCommand.js +459 -0
- package/dist/cli/validateCommand.d.ts +1 -1
- package/dist/cli/validateCommand.js +20 -3
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +128 -22
- package/dist/config/browseCatalog.d.ts +45 -0
- package/dist/config/browseCatalog.js +170 -0
- package/dist/config/createPipeline.d.ts +12 -3
- package/dist/config/createPipeline.js +292 -100
- package/dist/config/createStage.d.ts +10 -4
- package/dist/config/createStage.js +44 -14
- package/dist/config/listConfig.d.ts +14 -19
- package/dist/config/listConfig.js +26 -191
- package/dist/config/listModelsFromManifest.d.ts +2 -0
- package/dist/config/listModelsFromManifest.js +4 -0
- package/dist/config/loadOutcome.d.ts +4 -0
- package/dist/config/loadPipeline.d.ts +1 -15
- package/dist/config/loadPipeline.js +88 -142
- package/dist/config/loadStage.d.ts +4 -0
- package/dist/config/loadStage.js +60 -32
- package/dist/config/loadStageflowManifest.d.ts +5 -0
- package/dist/config/loadStageflowManifest.js +157 -0
- package/dist/config/mergePipelineIncludes.d.ts +9 -0
- package/dist/config/mergePipelineIncludes.js +141 -0
- package/dist/config/normalizePipelineStageEntry.d.ts +18 -0
- package/dist/config/normalizePipelineStageEntry.js +210 -0
- package/dist/config/pipelineStageKeys.d.ts +4 -0
- package/dist/config/pipelineStageKeys.js +14 -0
- package/dist/config/resolveCatalogContext.d.ts +13 -0
- package/dist/config/resolveCatalogContext.js +13 -0
- package/dist/config/resolveForkEmitContext.d.ts +4 -0
- package/dist/config/resolveForkEmitContext.js +34 -0
- package/dist/config/resolvePipelineDag.d.ts +5 -1
- package/dist/config/resolvePipelineDag.js +86 -36
- package/dist/config/scanCatalogPaths.d.ts +4 -0
- package/dist/config/scanCatalogPaths.js +83 -0
- package/dist/config/validateCatalog.d.ts +22 -4
- package/dist/config/validateCatalog.js +169 -132
- package/dist/envelope/check.d.ts +2 -0
- package/dist/envelope/check.js +58 -0
- package/dist/envelope/cloneForks.d.ts +2 -0
- package/dist/envelope/cloneForks.js +62 -0
- package/dist/envelope/forkChoice.d.ts +3 -0
- package/dist/envelope/forkChoice.js +47 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/mcp/catalogTools.d.ts +3 -0
- package/dist/mcp/catalogTools.js +187 -0
- package/dist/mcp/controlTools.d.ts +3 -0
- package/dist/mcp/controlTools.js +147 -0
- package/dist/mcp/deps.d.ts +11 -0
- package/dist/mcp/deps.js +1 -0
- package/dist/mcp/projectRun.d.ts +1 -37
- package/dist/mcp/projectRun.js +1 -57
- package/dist/mcp/resources.d.ts +5 -0
- package/dist/mcp/resources.js +45 -0
- package/dist/mcp/server.d.ts +16 -3
- package/dist/mcp/server.js +159 -3
- package/dist/mcp/toolResults.d.ts +7 -0
- package/dist/mcp/toolResults.js +6 -0
- package/dist/mcp/tools.d.ts +2 -7
- package/dist/mcp/tools.js +52 -86
- package/dist/mcp/waitRun.d.ts +46 -0
- package/dist/mcp/waitRun.js +146 -0
- package/dist/mcp/waitingGates.d.ts +12 -0
- package/dist/mcp/waitingGates.js +83 -0
- package/dist/project/findProjectRoot.d.ts +2 -0
- package/dist/project/findProjectRoot.js +51 -0
- package/dist/project/globalHome.d.ts +2 -0
- package/dist/project/globalHome.js +19 -0
- package/dist/project/resolveProjectContext.d.ts +9 -0
- package/dist/project/resolveProjectContext.js +38 -0
- package/dist/project/resolveStageflowContext.d.ts +11 -0
- package/dist/project/resolveStageflowContext.js +66 -0
- package/dist/projection/projectRun.d.ts +44 -0
- package/dist/projection/projectRun.js +71 -0
- package/dist/prompt/priorEnvelope.d.ts +1 -1
- package/dist/prompt/priorEnvelope.js +4 -1
- package/dist/runstore/normalizeCatalogPath.d.ts +1 -0
- package/dist/runstore/normalizeCatalogPath.js +4 -0
- package/dist/runstore/paths.js +2 -0
- package/dist/runstore/pipelineDagSnapshot.d.ts +9 -0
- package/dist/runstore/pipelineDagSnapshot.js +90 -1
- package/dist/runstore/port.d.ts +22 -2
- package/dist/runstore/port.js +4 -1
- package/dist/runstore/runProjection.d.ts +1 -1
- package/dist/runstore/runProjection.js +25 -4
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +3 -2
- package/dist/runstore/sqlite/SqliteRunStore.js +65 -7
- package/dist/runstore/sqlite/schema.d.ts +1 -1
- package/dist/runstore/sqlite/schema.js +4 -1
- package/dist/runstore/stageInstanceId.d.ts +4 -0
- package/dist/runstore/stageInstanceId.js +23 -0
- package/dist/runstore/syntheticStageSnapshot.d.ts +1 -1
- package/dist/runstore/syntheticStageSnapshot.js +2 -1
- package/dist/runstore/trackProjection.js +28 -12
- package/dist/runstore/workspaceLayout.d.ts +1 -0
- package/dist/runstore/workspaceLayout.js +1 -1
- package/dist/runtime/cloneSchedule.d.ts +18 -0
- package/dist/runtime/cloneSchedule.js +233 -0
- package/dist/runtime/credentialBinding.d.ts +8 -6
- package/dist/runtime/credentialBinding.js +18 -24
- package/dist/runtime/envelopeRouting.d.ts +2 -1
- package/dist/runtime/envelopeRouting.js +80 -13
- package/dist/runtime/pipelineRunner.d.ts +3 -0
- package/dist/runtime/pipelineRunner.js +15 -1
- package/dist/runtime/pipelineScheduler.d.ts +8 -2
- package/dist/runtime/pipelineScheduler.js +215 -39
- package/dist/runtime/reloadRunCatalog.d.ts +5 -0
- package/dist/runtime/reloadRunCatalog.js +44 -0
- package/dist/runtime/resumeReconstruct.d.ts +1 -0
- package/dist/runtime/resumeReconstruct.js +31 -10
- package/dist/runtime/runChangeBus.d.ts +18 -0
- package/dist/runtime/runChangeBus.js +83 -0
- package/dist/runtime/runManager.d.ts +4 -0
- package/dist/runtime/runManager.js +36 -16
- package/dist/runtime/settingsFile.d.ts +12 -0
- package/dist/runtime/settingsFile.js +87 -6
- package/dist/runtime/stageAttemptBootstrap.d.ts +1 -0
- package/dist/runtime/stageAttemptBootstrap.js +18 -7
- package/dist/runtime/stageProcessLauncher.js +3 -0
- package/dist/runtime/stageRecovery.js +3 -1
- package/dist/runtime/stageRunner.d.ts +1 -0
- package/dist/runtime/stageRunner.js +17 -15
- package/dist/runtime/stageWorker.js +13 -10
- package/dist/server/bootstrap.d.ts +32 -0
- package/dist/server/bootstrap.js +56 -0
- package/dist/server/createHttpHost.d.ts +34 -0
- package/dist/server/createHttpHost.js +70 -0
- package/dist/server/http.d.ts +6 -13
- package/dist/server/http.js +297 -352
- package/dist/server/mcpHost.d.ts +22 -0
- package/dist/server/mcpHost.js +21 -0
- package/dist/server/operatorResults.d.ts +13 -0
- package/dist/server/operatorResults.js +22 -0
- package/dist/tools/emitStageEnvelope.d.ts +12 -1
- package/dist/tools/emitStageEnvelope.js +27 -1
- package/dist/types/envelope.d.ts +3 -0
- package/dist/types/forkChoice.d.ts +30 -0
- package/dist/types/forkChoice.js +1 -0
- package/dist/types/pipeline.d.ts +59 -2
- package/dist/types/stageflowManifest.d.ts +23 -0
- package/dist/types/stageflowManifest.js +1 -0
- package/dist/ui/assets/{index-DCsDopak.css → index-C3N7MXAC.css} +1 -1
- package/dist/ui/assets/index-CSoGDA3A.js +118 -0
- package/dist/ui/index.html +3 -2
- package/dist/ui/stageflow-icon.svg +12 -0
- package/package.json +8 -5
- package/skills/install-suite.sh +107 -0
- package/skills/stageflow/SKILL.md +26 -0
- package/skills/stageflow/references/control-surface.md +26 -0
- package/skills/stageflow/scripts/detect-host.mjs +54 -0
- package/skills/stageflow/scripts/detect-host.test.mjs +97 -0
- package/skills/stageflow-author/SKILL.md +58 -0
- package/skills/stageflow-author/assets/examples/branch-decision/hotfix.yaml +10 -0
- package/skills/stageflow-author/assets/examples/branch-decision/release-gate.pipeline.yaml +12 -0
- package/skills/stageflow-author/assets/examples/branch-decision/run-tests.yaml +13 -0
- package/skills/stageflow-author/assets/examples/branch-decision/ship.yaml +10 -0
- package/skills/stageflow-author/assets/examples/linear-review/draft.yaml +9 -0
- package/skills/stageflow-author/assets/examples/linear-review/publish.yaml +10 -0
- package/skills/stageflow-author/assets/examples/linear-review/review-loop.pipeline.yaml +10 -0
- package/skills/stageflow-author/assets/examples/linear-review/review.yaml +15 -0
- package/skills/stageflow-author/assets/examples/non-sdlc-digest/gather.yaml +9 -0
- package/skills/stageflow-author/assets/examples/non-sdlc-digest/research-digest.pipeline.yaml +10 -0
- package/skills/stageflow-author/assets/examples/non-sdlc-digest/send.yaml +10 -0
- package/skills/stageflow-author/assets/examples/non-sdlc-digest/summarize.yaml +9 -0
- package/skills/stageflow-author/references/catalog-mapping.md +131 -0
- package/skills/stageflow-author/references/catalog-write-conventions.md +29 -0
- package/skills/stageflow-author/references/stage-prompt-template.md +55 -0
- package/skills/stageflow-author/references/validate-and-report.md +38 -0
- package/skills/stageflow-delegate/SKILL.md +18 -0
- package/skills/stageflow-delegate/references/authoring-or-run.md +15 -0
- package/skills/stageflow-delegate/references/example-walkthrough.md +30 -0
- package/skills/stageflow-delegate/references/pattern-detection.md +44 -0
- package/skills/stageflow-run/SKILL.md +151 -0
- package/skills/stageflow-run/references/mcp-call.md +17 -0
- package/skills/stageflow-run/references/task-and-pipeline-selection.md +52 -0
- package/skills/stageflow-run/scripts/mcp-call.mjs +299 -0
- package/skills/stageflow-run/scripts/mcp-call.test.mjs +271 -0
- package/skills/stageflow-session-capture/SKILL.md +94 -0
- package/skills/stageflow-session-capture/assets/example-pipeline/example.pipeline.yaml +7 -0
- package/skills/stageflow-session-capture/assets/example-pipeline/implement.yaml +8 -0
- package/skills/stageflow-session-capture/assets/example-pipeline/research.yaml +8 -0
- package/skills/stageflow-session-capture/references/catalog-authoring.md +40 -0
- package/skills/stageflow-session-capture/references/transcript-sources.md +25 -0
- package/skills/stageflow-session-capture/scripts/check-provider-gate.mjs +43 -0
- package/skills/stageflow-session-capture/scripts/locate-session-transcript.mjs +141 -0
- package/skills/stageflow-session-capture/scripts/resolve-catalog-id.mjs +119 -0
- package/skills/stageflow-setup/SKILL.md +110 -0
- package/dist/ui/assets/index-Cry0Tpfx.js +0 -118
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export class RunChangeBus {
|
|
2
|
+
listeners = new Set();
|
|
3
|
+
on(listener) {
|
|
4
|
+
this.listeners.add(listener);
|
|
5
|
+
return () => {
|
|
6
|
+
this.listeners.delete(listener);
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
off(listener) {
|
|
10
|
+
this.listeners.delete(listener);
|
|
11
|
+
}
|
|
12
|
+
emit(event) {
|
|
13
|
+
for (const listener of [...this.listeners]) {
|
|
14
|
+
try {
|
|
15
|
+
listener(event);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// Listener isolation: one throw must not block others.
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function createRunChangeBus() {
|
|
24
|
+
return new RunChangeBus();
|
|
25
|
+
}
|
|
26
|
+
const WRAPPED_MARKER = Symbol.for("stageflow.wrapRunStoreWithChangeBus");
|
|
27
|
+
const BUS_MARKER = Symbol.for("stageflow.runChangeBus");
|
|
28
|
+
export function isRunStoreWrapped(store) {
|
|
29
|
+
return store[WRAPPED_MARKER] === true;
|
|
30
|
+
}
|
|
31
|
+
export function getRunChangeBusFromWrappedStore(store) {
|
|
32
|
+
const bus = store[BUS_MARKER];
|
|
33
|
+
return bus instanceof RunChangeBus ? bus : undefined;
|
|
34
|
+
}
|
|
35
|
+
export function wrapRunStoreWithChangeBus(store, bus) {
|
|
36
|
+
if (isRunStoreWrapped(store)) {
|
|
37
|
+
const bound = getRunChangeBusFromWrappedStore(store);
|
|
38
|
+
if (bound !== bus) {
|
|
39
|
+
throw new Error("runChangeBus does not match the bus already bound to the provided store");
|
|
40
|
+
}
|
|
41
|
+
return store;
|
|
42
|
+
}
|
|
43
|
+
const createRun = async (input) => {
|
|
44
|
+
const created = await store.createRun(input);
|
|
45
|
+
bus.emit({ runId: created.runId, kind: "created" });
|
|
46
|
+
return created;
|
|
47
|
+
};
|
|
48
|
+
const updateRunStatus = async (runId, status) => {
|
|
49
|
+
await store.updateRunStatus(runId, status);
|
|
50
|
+
bus.emit({ runId, kind: "status" });
|
|
51
|
+
};
|
|
52
|
+
const appendStageEvent = async (runId, stageId, event, options) => {
|
|
53
|
+
await store.appendStageEvent(runId, stageId, event, options);
|
|
54
|
+
if (event.event === "waiting_for_input" || event.event === "resumed") {
|
|
55
|
+
bus.emit({ runId, kind: "waiting" });
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const boundCache = new Map();
|
|
59
|
+
return new Proxy(store, {
|
|
60
|
+
get(target, prop, receiver) {
|
|
61
|
+
if (prop === WRAPPED_MARKER)
|
|
62
|
+
return true;
|
|
63
|
+
if (prop === BUS_MARKER)
|
|
64
|
+
return bus;
|
|
65
|
+
if (prop === "createRun")
|
|
66
|
+
return createRun;
|
|
67
|
+
if (prop === "updateRunStatus")
|
|
68
|
+
return updateRunStatus;
|
|
69
|
+
if (prop === "appendStageEvent")
|
|
70
|
+
return appendStageEvent;
|
|
71
|
+
const cached = boundCache.get(prop);
|
|
72
|
+
if (cached !== undefined)
|
|
73
|
+
return cached;
|
|
74
|
+
const value = Reflect.get(target, prop, receiver);
|
|
75
|
+
if (typeof value === "function") {
|
|
76
|
+
const bound = value.bind(target);
|
|
77
|
+
boundCache.set(prop, bound);
|
|
78
|
+
return bound;
|
|
79
|
+
}
|
|
80
|
+
return value;
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
@@ -61,10 +61,14 @@ export declare class RunManager {
|
|
|
61
61
|
private readonly retryCoordinator;
|
|
62
62
|
private readonly retryTracking;
|
|
63
63
|
private readonly cwd;
|
|
64
|
+
private readonly projectRoot;
|
|
65
|
+
private readonly isGitProject;
|
|
64
66
|
constructor(options: {
|
|
65
67
|
agent: AgentPort;
|
|
66
68
|
store: RunStore;
|
|
67
69
|
cwd?: string;
|
|
70
|
+
projectRoot?: string;
|
|
71
|
+
isGitProject?: boolean;
|
|
68
72
|
operatorCatalog?: OperatorCatalog;
|
|
69
73
|
seams?: HitlSeams;
|
|
70
74
|
maxConcurrent?: number;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { readFile, realpath } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { normalizeCatalogPath } from "../runstore/normalizeCatalogPath.js";
|
|
5
|
+
import { loadRunContext } from "./resumeReconstruct.js";
|
|
5
6
|
import { loadTaskFromYaml } from "../config/loadTask.js";
|
|
6
7
|
import { PipelineValidationError, startPipeline, } from "./pipelineRunner.js";
|
|
7
8
|
import { resumeRun } from "./pipelineScheduler.js";
|
|
8
9
|
import { RunRetryCoordinator, } from "./runRetryCoordinator.js";
|
|
9
10
|
import { readMaxActiveStageProcesses, readMaxActiveStagesPerRun, readStageExecutionMode, } from "./stageConcurrency.js";
|
|
10
11
|
import { StageProcessLauncher } from "./stageProcessLauncher.js";
|
|
11
|
-
import { INVALID_SLOT_COUNT_MESSAGE, parseSlotCount,
|
|
12
|
+
import { INVALID_SLOT_COUNT_MESSAGE, parseSlotCount, projectSettingsContext, readMaxConcurrentFromContext, writeMaxConcurrentToContext, } from "./settingsFile.js";
|
|
12
13
|
import { StageHitlController, waitKey, } from "./stageHitl.js";
|
|
13
14
|
import { resolveAndValidateCheckout, } from "./stageRoots.js";
|
|
14
15
|
import { orchestrateAnswerResume } from "./answerResume.js";
|
|
@@ -79,12 +80,17 @@ export class RunManager {
|
|
|
79
80
|
},
|
|
80
81
|
};
|
|
81
82
|
cwd;
|
|
83
|
+
projectRoot;
|
|
84
|
+
isGitProject;
|
|
82
85
|
constructor(options) {
|
|
83
86
|
this.options = options;
|
|
84
87
|
this.cwd = options.cwd ?? process.cwd();
|
|
88
|
+
this.projectRoot = options.projectRoot ?? this.cwd;
|
|
89
|
+
this.isGitProject = options.isGitProject ?? false;
|
|
90
|
+
const settingsCtx = projectSettingsContext(this.cwd, this.projectRoot, this.isGitProject);
|
|
85
91
|
this.maxConcurrent =
|
|
86
92
|
options.maxConcurrent ??
|
|
87
|
-
|
|
93
|
+
readMaxConcurrentFromContext(settingsCtx) ??
|
|
88
94
|
parseMaxConcurrent(process.env.STAGEFLOW_MAX_CONCURRENT_RUNS);
|
|
89
95
|
this.maxActiveStagesPerRun = readMaxActiveStagesPerRun(process.env, options.maxActiveStagesPerRun);
|
|
90
96
|
this.executionMode = readStageExecutionMode(process.env, options.executionMode);
|
|
@@ -106,7 +112,7 @@ export class RunManager {
|
|
|
106
112
|
throw new Error(INVALID_SLOT_COUNT_MESSAGE);
|
|
107
113
|
}
|
|
108
114
|
this.maxConcurrent = parsed;
|
|
109
|
-
|
|
115
|
+
writeMaxConcurrentToContext(projectSettingsContext(this.cwd, this.projectRoot, this.isGitProject), parsed);
|
|
110
116
|
return this.getHealth();
|
|
111
117
|
}
|
|
112
118
|
getActiveCount() {
|
|
@@ -355,17 +361,32 @@ export class RunManager {
|
|
|
355
361
|
}
|
|
356
362
|
async rerun(runId) {
|
|
357
363
|
const cwd = this.options.cwd ?? process.cwd();
|
|
358
|
-
let
|
|
364
|
+
let pipeline;
|
|
359
365
|
let taskYaml;
|
|
366
|
+
let rerunCwd = cwd;
|
|
367
|
+
let rerunProjectRoot;
|
|
360
368
|
try {
|
|
361
369
|
const meta = await this.options.store.readRunMeta(runId);
|
|
362
|
-
|
|
370
|
+
if (!meta.pipeline_path) {
|
|
371
|
+
return {
|
|
372
|
+
ok: false,
|
|
373
|
+
reason: `Run ${runId} is missing pipeline_path; re-run requires stored catalog locators.`,
|
|
374
|
+
status: 400,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
pipeline = normalizeCatalogPath(meta.pipeline_path);
|
|
378
|
+
rerunCwd = meta.project_root
|
|
379
|
+
? normalizeCatalogPath(meta.project_root)
|
|
380
|
+
: cwd;
|
|
381
|
+
rerunProjectRoot = meta.project_root
|
|
382
|
+
? normalizeCatalogPath(meta.project_root)
|
|
383
|
+
: undefined;
|
|
363
384
|
taskYaml = await this.options.store.readTaskYaml(runId);
|
|
364
385
|
}
|
|
365
386
|
catch {
|
|
366
387
|
return { ok: false, reason: `Run not found: ${runId}`, status: 404 };
|
|
367
388
|
}
|
|
368
|
-
return this.reserveAndStartPipeline(taskYaml,
|
|
389
|
+
return this.reserveAndStartPipeline(taskYaml, pipeline, `run ${runId} task`, rerunCwd, undefined, undefined, undefined, rerunProjectRoot);
|
|
369
390
|
}
|
|
370
391
|
async retryStage(runId, stageId) {
|
|
371
392
|
const retryKey = waitKey(runId, stageId);
|
|
@@ -489,7 +510,6 @@ export class RunManager {
|
|
|
489
510
|
}
|
|
490
511
|
}
|
|
491
512
|
async resumeViaSubprocess(runId, stageId, opaqueAnswer) {
|
|
492
|
-
const cwd = this.options.cwd ?? process.cwd();
|
|
493
513
|
const store = this.options.store;
|
|
494
514
|
const launcher = this.stageProcessLauncher;
|
|
495
515
|
if (!launcher) {
|
|
@@ -504,7 +524,7 @@ export class RunManager {
|
|
|
504
524
|
const launchResult = await launcher.launch({
|
|
505
525
|
runId,
|
|
506
526
|
stageId,
|
|
507
|
-
rootDir:
|
|
527
|
+
rootDir: this.projectRoot,
|
|
508
528
|
mode: "resume",
|
|
509
529
|
resumeAnswer: opaqueAnswer,
|
|
510
530
|
attempt,
|
|
@@ -531,10 +551,7 @@ export class RunManager {
|
|
|
531
551
|
catch {
|
|
532
552
|
// downstream resume may read envelope from store
|
|
533
553
|
}
|
|
534
|
-
const meta = await store.
|
|
535
|
-
const taskYaml = await store.readTaskYaml(runId);
|
|
536
|
-
const task = loadTaskFromYaml(taskYaml, `run ${runId} task`);
|
|
537
|
-
const loaded = await loadPipeline(meta.pipeline_id, { cwd });
|
|
554
|
+
const { meta, task, loaded } = await loadRunContext(store, runId, this.cwd);
|
|
538
555
|
const rest = await resumeRun({
|
|
539
556
|
prepared: {
|
|
540
557
|
task,
|
|
@@ -542,7 +559,8 @@ export class RunManager {
|
|
|
542
559
|
run: { runId, workspaceDir: store.getWorkspaceDir(runId) },
|
|
543
560
|
agent: this.options.agent,
|
|
544
561
|
store,
|
|
545
|
-
cwd,
|
|
562
|
+
cwd: this.cwd,
|
|
563
|
+
projectRoot: this.projectRoot,
|
|
546
564
|
checkoutRoot: meta.checkout_root,
|
|
547
565
|
hitl: this.hitl,
|
|
548
566
|
operatorCatalog: this.options.operatorCatalog,
|
|
@@ -590,6 +608,7 @@ export class RunManager {
|
|
|
590
608
|
executionMode: this.executionMode,
|
|
591
609
|
stageProcessLauncher: this.stageProcessLauncher,
|
|
592
610
|
cwd: this.cwd,
|
|
611
|
+
factoryCwd: this.projectRoot,
|
|
593
612
|
maxActiveStagesPerRun: this.maxActiveStagesPerRun,
|
|
594
613
|
operatorCatalog: this.options.operatorCatalog,
|
|
595
614
|
});
|
|
@@ -598,7 +617,7 @@ export class RunManager {
|
|
|
598
617
|
this.attachedWaiting.delete(`${runId}\0${stageId}`);
|
|
599
618
|
}
|
|
600
619
|
}
|
|
601
|
-
async reserveAndStartPipeline(taskYaml,
|
|
620
|
+
async reserveAndStartPipeline(taskYaml, pipeline, taskLabel, cwd, checkoutOverride, skipGates, ciIdentity, projectRoot) {
|
|
602
621
|
let checkoutKey;
|
|
603
622
|
try {
|
|
604
623
|
const task = loadTaskFromYaml(taskYaml, taskLabel);
|
|
@@ -623,8 +642,9 @@ export class RunManager {
|
|
|
623
642
|
agent: this.options.agent,
|
|
624
643
|
store: this.options.store,
|
|
625
644
|
taskYaml,
|
|
626
|
-
pipeline
|
|
645
|
+
pipeline,
|
|
627
646
|
cwd,
|
|
647
|
+
projectRoot: projectRoot ?? this.projectRoot,
|
|
628
648
|
checkoutOverride,
|
|
629
649
|
gitSha: ciIdentity?.gitSha,
|
|
630
650
|
ciPrUrl: ciIdentity?.ciPrUrl,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { ProjectContext } from "../project/resolveProjectContext.js";
|
|
2
|
+
import type { StageflowContext } from "../project/resolveStageflowContext.js";
|
|
1
3
|
export declare const SETTINGS_FILE_NAME = "settings.json";
|
|
2
4
|
export declare const INVALID_SLOT_COUNT_MESSAGE = "maxConcurrent must be an integer >= 1";
|
|
3
5
|
export declare const INVALID_CREDENTIAL_SOURCE_MESSAGE = "credentialSource must be \"pi_home\" or \"sf_owned\"";
|
|
@@ -6,12 +8,22 @@ export type FactorySettings = {
|
|
|
6
8
|
maxConcurrent?: number;
|
|
7
9
|
credentialSource?: CredentialSource;
|
|
8
10
|
};
|
|
11
|
+
export declare function globalSettingsFilePath(): string;
|
|
12
|
+
export declare function settingsFilePathForContext(ctx: ProjectContext | StageflowContext): string;
|
|
9
13
|
export declare function settingsFilePath(cwd: string): string;
|
|
10
14
|
export declare function parseSlotCount(value: unknown): number | undefined;
|
|
11
15
|
export declare function parseCredentialSource(value: unknown): CredentialSource | undefined;
|
|
16
|
+
export declare function readCredentialSourceFromContext(ctx: ProjectContext): CredentialSource | undefined;
|
|
17
|
+
export declare function readPersistedCredentialSourceFromContext(ctx: ProjectContext): CredentialSource | undefined;
|
|
18
|
+
export declare function readFactorySettingsForContext(ctx: ProjectContext): FactorySettings;
|
|
12
19
|
export declare function readFactorySettings(cwd: string): FactorySettings;
|
|
20
|
+
export declare function writeFactorySettingsForContext(ctx: ProjectContext, patch: FactorySettings): void;
|
|
13
21
|
export declare function writeFactorySettings(cwd: string, patch: FactorySettings): void;
|
|
22
|
+
export declare function readMaxConcurrentFromContext(ctx: ProjectContext): number | undefined;
|
|
14
23
|
export declare function readMaxConcurrentFromFile(cwd: string): number | undefined;
|
|
24
|
+
export declare function writeMaxConcurrentToContext(ctx: ProjectContext, maxConcurrent: number): void;
|
|
15
25
|
export declare function writeMaxConcurrentToFile(cwd: string, maxConcurrent: number): void;
|
|
16
26
|
export declare function readCredentialSourceFromFile(cwd: string): CredentialSource | undefined;
|
|
27
|
+
export declare function writeCredentialSourceToContext(ctx: ProjectContext, credentialSource: CredentialSource): void;
|
|
17
28
|
export declare function writeCredentialSourceToFile(cwd: string, credentialSource: CredentialSource): void;
|
|
29
|
+
export declare function projectSettingsContext(cwd: string, projectRoot: string, isGitProject: boolean): ProjectContext;
|
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
4
|
+
import { globalStageflowHome } from "../project/globalHome.js";
|
|
3
5
|
import { storeRootFor } from "../runstore/paths.js";
|
|
4
6
|
export const SETTINGS_FILE_NAME = "settings.json";
|
|
5
7
|
export const INVALID_SLOT_COUNT_MESSAGE = "maxConcurrent must be an integer >= 1";
|
|
6
8
|
export const INVALID_CREDENTIAL_SOURCE_MESSAGE = 'credentialSource must be "pi_home" or "sf_owned"';
|
|
9
|
+
export function globalSettingsFilePath() {
|
|
10
|
+
return path.join(globalStageflowHome(), SETTINGS_FILE_NAME);
|
|
11
|
+
}
|
|
12
|
+
export function settingsFilePathForContext(ctx) {
|
|
13
|
+
if (ctx.isGitProject) {
|
|
14
|
+
return path.join(storeRootFor(ctx.projectRoot), SETTINGS_FILE_NAME);
|
|
15
|
+
}
|
|
16
|
+
if (path.resolve(ctx.projectRoot) === path.resolve(os.homedir())) {
|
|
17
|
+
return path.join(ctx.globalHome, SETTINGS_FILE_NAME);
|
|
18
|
+
}
|
|
19
|
+
return path.join(storeRootFor(ctx.projectRoot), SETTINGS_FILE_NAME);
|
|
20
|
+
}
|
|
7
21
|
export function settingsFilePath(cwd) {
|
|
8
|
-
return path.join(storeRootFor(cwd), SETTINGS_FILE_NAME);
|
|
22
|
+
return path.join(storeRootFor(path.resolve(cwd)), SETTINGS_FILE_NAME);
|
|
9
23
|
}
|
|
10
24
|
export function parseSlotCount(value) {
|
|
11
25
|
if (typeof value !== "number" || !Number.isInteger(value) || value < 1) {
|
|
@@ -19,8 +33,7 @@ export function parseCredentialSource(value) {
|
|
|
19
33
|
}
|
|
20
34
|
return undefined;
|
|
21
35
|
}
|
|
22
|
-
function
|
|
23
|
-
const filePath = settingsFilePath(cwd);
|
|
36
|
+
function readRawSettingsFromFile(filePath) {
|
|
24
37
|
if (!existsSync(filePath))
|
|
25
38
|
return {};
|
|
26
39
|
try {
|
|
@@ -34,8 +47,10 @@ function readRawSettings(cwd) {
|
|
|
34
47
|
return {};
|
|
35
48
|
}
|
|
36
49
|
}
|
|
37
|
-
|
|
38
|
-
|
|
50
|
+
function readRawSettings(ctx) {
|
|
51
|
+
return readRawSettingsFromFile(settingsFilePathForContext(ctx));
|
|
52
|
+
}
|
|
53
|
+
function parseFactorySettingsFromRaw(raw) {
|
|
39
54
|
const settings = {};
|
|
40
55
|
const maxConcurrent = parseSlotCount(raw.maxConcurrent);
|
|
41
56
|
if (maxConcurrent !== undefined) {
|
|
@@ -47,6 +62,54 @@ export function readFactorySettings(cwd) {
|
|
|
47
62
|
}
|
|
48
63
|
return settings;
|
|
49
64
|
}
|
|
65
|
+
export function readCredentialSourceFromContext(ctx) {
|
|
66
|
+
if (ctx.isGitProject) {
|
|
67
|
+
const fromProject = parseCredentialSource(readRawSettingsFromFile(settingsFilePathForContext(ctx)).credentialSource);
|
|
68
|
+
if (fromProject !== undefined) {
|
|
69
|
+
return fromProject;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return parseCredentialSource(readRawSettingsFromFile(globalSettingsFilePath()).credentialSource);
|
|
73
|
+
}
|
|
74
|
+
export function readPersistedCredentialSourceFromContext(ctx) {
|
|
75
|
+
return parseCredentialSource(readRawSettingsFromFile(settingsFilePathForContext(ctx)).credentialSource);
|
|
76
|
+
}
|
|
77
|
+
export function readFactorySettingsForContext(ctx) {
|
|
78
|
+
return parseFactorySettingsFromRaw(readRawSettings(ctx));
|
|
79
|
+
}
|
|
80
|
+
export function readFactorySettings(cwd) {
|
|
81
|
+
return parseFactorySettingsFromRaw(readRawSettingsFromFile(settingsFilePath(cwd)));
|
|
82
|
+
}
|
|
83
|
+
function ensureSettingsDirForContext(ctx) {
|
|
84
|
+
mkdirSync(path.dirname(settingsFilePathForContext(ctx)), { recursive: true });
|
|
85
|
+
}
|
|
86
|
+
export function writeFactorySettingsForContext(ctx, patch) {
|
|
87
|
+
if (patch.credentialSource !== undefined &&
|
|
88
|
+
parseCredentialSource(patch.credentialSource) === undefined) {
|
|
89
|
+
throw new Error(INVALID_CREDENTIAL_SOURCE_MESSAGE);
|
|
90
|
+
}
|
|
91
|
+
if (patch.maxConcurrent !== undefined &&
|
|
92
|
+
parseSlotCount(patch.maxConcurrent) === undefined) {
|
|
93
|
+
throw new Error(INVALID_SLOT_COUNT_MESSAGE);
|
|
94
|
+
}
|
|
95
|
+
const current = readFactorySettingsForContext(ctx);
|
|
96
|
+
const next = { ...current };
|
|
97
|
+
if (patch.maxConcurrent !== undefined) {
|
|
98
|
+
next.maxConcurrent = patch.maxConcurrent;
|
|
99
|
+
}
|
|
100
|
+
if (patch.credentialSource !== undefined) {
|
|
101
|
+
next.credentialSource = patch.credentialSource;
|
|
102
|
+
}
|
|
103
|
+
const out = {};
|
|
104
|
+
if (next.maxConcurrent !== undefined) {
|
|
105
|
+
out.maxConcurrent = next.maxConcurrent;
|
|
106
|
+
}
|
|
107
|
+
if (next.credentialSource !== undefined) {
|
|
108
|
+
out.credentialSource = next.credentialSource;
|
|
109
|
+
}
|
|
110
|
+
ensureSettingsDirForContext(ctx);
|
|
111
|
+
writeFileSync(settingsFilePathForContext(ctx), `${JSON.stringify(out, null, 2)}\n`, "utf8");
|
|
112
|
+
}
|
|
50
113
|
export function writeFactorySettings(cwd, patch) {
|
|
51
114
|
if (patch.credentialSource !== undefined &&
|
|
52
115
|
parseCredentialSource(patch.credentialSource) === undefined) {
|
|
@@ -71,18 +134,36 @@ export function writeFactorySettings(cwd, patch) {
|
|
|
71
134
|
if (next.credentialSource !== undefined) {
|
|
72
135
|
out.credentialSource = next.credentialSource;
|
|
73
136
|
}
|
|
74
|
-
|
|
137
|
+
const root = path.resolve(cwd);
|
|
138
|
+
mkdirSync(storeRootFor(root), { recursive: true });
|
|
75
139
|
writeFileSync(settingsFilePath(cwd), `${JSON.stringify(out, null, 2)}\n`, "utf8");
|
|
76
140
|
}
|
|
141
|
+
export function readMaxConcurrentFromContext(ctx) {
|
|
142
|
+
return readFactorySettingsForContext(ctx).maxConcurrent;
|
|
143
|
+
}
|
|
77
144
|
export function readMaxConcurrentFromFile(cwd) {
|
|
78
145
|
return readFactorySettings(cwd).maxConcurrent;
|
|
79
146
|
}
|
|
147
|
+
export function writeMaxConcurrentToContext(ctx, maxConcurrent) {
|
|
148
|
+
writeFactorySettingsForContext(ctx, { maxConcurrent });
|
|
149
|
+
}
|
|
80
150
|
export function writeMaxConcurrentToFile(cwd, maxConcurrent) {
|
|
81
151
|
writeFactorySettings(cwd, { maxConcurrent });
|
|
82
152
|
}
|
|
83
153
|
export function readCredentialSourceFromFile(cwd) {
|
|
84
154
|
return readFactorySettings(cwd).credentialSource;
|
|
85
155
|
}
|
|
156
|
+
export function writeCredentialSourceToContext(ctx, credentialSource) {
|
|
157
|
+
writeFactorySettingsForContext(ctx, { credentialSource });
|
|
158
|
+
}
|
|
86
159
|
export function writeCredentialSourceToFile(cwd, credentialSource) {
|
|
87
160
|
writeFactorySettings(cwd, { credentialSource });
|
|
88
161
|
}
|
|
162
|
+
export function projectSettingsContext(cwd, projectRoot, isGitProject) {
|
|
163
|
+
return {
|
|
164
|
+
invocationCwd: path.resolve(cwd),
|
|
165
|
+
projectRoot: path.resolve(projectRoot),
|
|
166
|
+
globalHome: globalStageflowHome(),
|
|
167
|
+
isGitProject,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolveSkillByName } from "../config/listSkills.js";
|
|
2
|
+
import { resolveCloneEmitContext, resolveForkEmitContext } from "../config/resolveForkEmitContext.js";
|
|
2
3
|
import { buildCompletedEnvelopesFromRun, resolvePriorEnvelope, } from "./envelopeRouting.js";
|
|
3
4
|
import { resumeSessionFilePath } from "./stageAttemptContext.js";
|
|
4
5
|
import { buildStageRoots, rootsForStageWorker, withResolvedAuthPath, } from "./stageRoots.js";
|
|
@@ -38,38 +39,48 @@ async function openStageWithOperatorCatalog(agent, input, catalog) {
|
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
|
-
function resolveAttemptRoots(input) {
|
|
42
|
+
function resolveAttemptRoots(input, stageId) {
|
|
42
43
|
const baseRoots = input.roots ??
|
|
43
44
|
(input.workerRoots
|
|
44
|
-
? rootsForStageWorker(input.workspaceDir,
|
|
45
|
-
: buildStageRoots(input.workspaceDir,
|
|
45
|
+
? rootsForStageWorker(input.workspaceDir, stageId, input.stage.model, input.checkoutRoot, input.attemptCtx)
|
|
46
|
+
: buildStageRoots(input.workspaceDir, stageId, input.checkoutRoot, input.attemptCtx));
|
|
46
47
|
return input.factoryCwd !== undefined
|
|
47
48
|
? withResolvedAuthPath(baseRoots, input.factoryCwd)
|
|
48
49
|
: baseRoots;
|
|
49
50
|
}
|
|
50
51
|
export async function openStageAttempt(input) {
|
|
52
|
+
const stageId = input.stageId ?? input.stage.id;
|
|
53
|
+
const definitionId = input.stage.id;
|
|
51
54
|
const completedEnvelopes = input.completedEnvelopes ??
|
|
52
|
-
(await buildCompletedEnvelopesFromRun(input.store, input.runId));
|
|
55
|
+
(await buildCompletedEnvelopesFromRun(input.store, input.runId, undefined, input.dag));
|
|
53
56
|
const priorResult = await resolvePriorEnvelope({
|
|
54
57
|
dag: input.dag,
|
|
55
|
-
stageId
|
|
58
|
+
stageId,
|
|
56
59
|
completedEnvelopes,
|
|
57
60
|
store: input.store,
|
|
58
61
|
runId: input.runId,
|
|
59
62
|
});
|
|
60
63
|
if (!priorResult.ok)
|
|
61
64
|
return priorResult;
|
|
62
|
-
const roots = resolveAttemptRoots(input);
|
|
65
|
+
const roots = resolveAttemptRoots(input, stageId);
|
|
63
66
|
const attempt = input.attemptCtx?.attempt ?? 1;
|
|
64
67
|
const resumeToken = input.resumeToken ??
|
|
65
|
-
resumeSessionFilePath(input.workspaceDir,
|
|
68
|
+
resumeSessionFilePath(input.workspaceDir, stageId, attempt);
|
|
69
|
+
const forkEmitContext = resolveForkEmitContext(input.dag, definitionId);
|
|
70
|
+
const cloneEmitContext = resolveCloneEmitContext(input.dag, definitionId);
|
|
66
71
|
const opened = await openStageWithOperatorCatalog(input.agent, {
|
|
67
72
|
roots,
|
|
68
73
|
stage: input.stage,
|
|
74
|
+
stageId,
|
|
69
75
|
task: input.task,
|
|
70
76
|
priorEnvelope: priorResult.prior,
|
|
77
|
+
...(priorResult.joinPriors !== undefined
|
|
78
|
+
? { priorEnvelopes: priorResult.joinPriors }
|
|
79
|
+
: {}),
|
|
71
80
|
resumeToken,
|
|
72
81
|
onActivity: input.onActivity,
|
|
82
|
+
forkEmitContext,
|
|
83
|
+
cloneEmitContext,
|
|
73
84
|
}, input.operatorCatalog);
|
|
74
85
|
if (!opened.ok)
|
|
75
86
|
return opened;
|
|
@@ -132,6 +132,9 @@ export class StageProcessLauncher {
|
|
|
132
132
|
if (input.sessionFilePath !== undefined) {
|
|
133
133
|
args.push("--session-file", input.sessionFilePath);
|
|
134
134
|
}
|
|
135
|
+
if (input.operatorCatalog?.cwd !== undefined) {
|
|
136
|
+
args.push("--operator-cwd", input.operatorCatalog.cwd);
|
|
137
|
+
}
|
|
135
138
|
if (input.operatorCatalog?.agentDir !== undefined) {
|
|
136
139
|
args.push("--operator-agent-dir", input.operatorCatalog.agentDir);
|
|
137
140
|
}
|
|
@@ -34,9 +34,11 @@ export async function failStageAsInterrupted(options) {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
export async function syncRunStatusFromStages(store, runId) {
|
|
37
|
+
const meta = await store.readRunMeta(runId);
|
|
38
|
+
if (meta.status === "succeeded")
|
|
39
|
+
return;
|
|
37
40
|
const run = await store.readRun(runId);
|
|
38
41
|
const derived = deriveStatusFromStages(run.stages);
|
|
39
|
-
const meta = await store.readRunMeta(runId);
|
|
40
42
|
if ((meta.status ?? "created") !== derived) {
|
|
41
43
|
await store.updateRunStatus(runId, derived);
|
|
42
44
|
}
|
|
@@ -114,28 +114,29 @@ export async function runStageYieldLoop(options) {
|
|
|
114
114
|
}
|
|
115
115
|
export async function runStage(options) {
|
|
116
116
|
const { agent, store, runId, stage, task, dag, checkoutRoot, workspaceDir, hitl, skipStarted, existingHandle, workerMode, roots: rootsOverride, attemptCtx, factoryCwd, operatorCatalog, completedEnvelopes, skipGates, } = options;
|
|
117
|
+
const stageId = options.stageId ?? stage.id;
|
|
117
118
|
const attemptOpt = attemptCtx?.eventOptions();
|
|
118
119
|
const baseRoots = rootsOverride ??
|
|
119
|
-
buildStageRoots(workspaceDir ?? store.getWorkspaceDir(runId),
|
|
120
|
+
buildStageRoots(workspaceDir ?? store.getWorkspaceDir(runId), stageId, checkoutRoot, attemptCtx);
|
|
120
121
|
const roots = factoryCwd !== undefined
|
|
121
122
|
? withResolvedAuthPath(baseRoots, factoryCwd)
|
|
122
123
|
: baseRoots;
|
|
123
124
|
const attempt = attemptCtx?.attempt ?? 1;
|
|
124
|
-
await ensureStageExecutionForAttempt(store, runId,
|
|
125
|
-
await store.ensureAttemptWorkspace(runId,
|
|
125
|
+
await ensureStageExecutionForAttempt(store, runId, stageId, attempt);
|
|
126
|
+
await store.ensureAttemptWorkspace(runId, stageId, attempt);
|
|
126
127
|
if (!skipStarted) {
|
|
127
128
|
await appendLifecycleEventAndPatchExecution({
|
|
128
129
|
store,
|
|
129
130
|
runId,
|
|
130
|
-
stageId
|
|
131
|
+
stageId,
|
|
131
132
|
event: { event: "started" },
|
|
132
133
|
attemptCtx,
|
|
133
134
|
});
|
|
134
135
|
}
|
|
135
|
-
console.error(`Running stage ${
|
|
136
|
+
console.error(`Running stage ${stageId} (${stage.model})...`);
|
|
136
137
|
let activityChain = Promise.resolve();
|
|
137
138
|
const enqueueActivity = (event) => {
|
|
138
|
-
activityChain = activityChain.then(() => store.appendStageEvent(runId,
|
|
139
|
+
activityChain = activityChain.then(() => store.appendStageEvent(runId, stageId, event, attemptOpt));
|
|
139
140
|
};
|
|
140
141
|
let handle;
|
|
141
142
|
if (existingHandle) {
|
|
@@ -147,12 +148,13 @@ export async function runStage(options) {
|
|
|
147
148
|
store,
|
|
148
149
|
runId,
|
|
149
150
|
stage,
|
|
151
|
+
stageId,
|
|
150
152
|
task,
|
|
151
153
|
dag: dag ?? {
|
|
152
154
|
nodes: [
|
|
153
|
-
{ id:
|
|
155
|
+
{ id: stageId, needs: null, ancestors: [], stageIndex: 0 },
|
|
154
156
|
],
|
|
155
|
-
roots: [
|
|
157
|
+
roots: [stageId],
|
|
156
158
|
childrenOf: {},
|
|
157
159
|
},
|
|
158
160
|
checkoutRoot,
|
|
@@ -170,11 +172,11 @@ export async function runStage(options) {
|
|
|
170
172
|
await appendLifecycleEventAndPatchExecution({
|
|
171
173
|
store,
|
|
172
174
|
runId,
|
|
173
|
-
stageId
|
|
175
|
+
stageId,
|
|
174
176
|
event: { event: "failed", reason: opened.reason },
|
|
175
177
|
attemptCtx,
|
|
176
178
|
});
|
|
177
|
-
console.error(`Stage ${
|
|
179
|
+
console.error(`Stage ${stageId} failed: ${opened.reason}`);
|
|
178
180
|
return { ok: false, reason: opened.reason };
|
|
179
181
|
}
|
|
180
182
|
handle = opened.handle;
|
|
@@ -184,7 +186,7 @@ export async function runStage(options) {
|
|
|
184
186
|
outcome = await runStageYieldLoop({
|
|
185
187
|
handle,
|
|
186
188
|
runId,
|
|
187
|
-
stageId
|
|
189
|
+
stageId,
|
|
188
190
|
hitl,
|
|
189
191
|
workerMode,
|
|
190
192
|
store: workerMode ? store : undefined,
|
|
@@ -195,15 +197,15 @@ export async function runStage(options) {
|
|
|
195
197
|
catch (err) {
|
|
196
198
|
const reason = err instanceof Error ? err.message : String(err);
|
|
197
199
|
await activityChain;
|
|
198
|
-
hitl?.clearLiveWait(runId,
|
|
200
|
+
hitl?.clearLiveWait(runId, stageId);
|
|
199
201
|
await appendLifecycleEventAndPatchExecution({
|
|
200
202
|
store,
|
|
201
203
|
runId,
|
|
202
|
-
stageId
|
|
204
|
+
stageId,
|
|
203
205
|
event: { event: "failed", reason },
|
|
204
206
|
attemptCtx,
|
|
205
207
|
});
|
|
206
|
-
console.error(`Stage ${
|
|
208
|
+
console.error(`Stage ${stageId} failed: ${reason}`);
|
|
207
209
|
await handle.close().catch(() => undefined);
|
|
208
210
|
return { ok: false, reason };
|
|
209
211
|
}
|
|
@@ -216,7 +218,7 @@ export async function runStage(options) {
|
|
|
216
218
|
return await finalizeStageResult({
|
|
217
219
|
store,
|
|
218
220
|
runId,
|
|
219
|
-
stageId
|
|
221
|
+
stageId,
|
|
220
222
|
result: outcome,
|
|
221
223
|
activityChain,
|
|
222
224
|
attemptCtx,
|