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
|
@@ -1,8 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizeForkChoice } from "../envelope/forkChoice.js";
|
|
2
|
+
import { buildPipelineDagSnapshotFromLoaded } from "../runstore/pipelineDagSnapshot.js";
|
|
3
|
+
import { definitionIdForInstance } from "../runstore/stageInstanceId.js";
|
|
4
|
+
import { applyCloneForksFromEnvelopes, applyCloneForksToSchedule, cloneFailureContinuesSchedule, cloneFanoutConflict, cloneRetryDownstream, cloneFailFastSkipIds, cloneScheduleAllowsRun, isCloneInstance, protectedClonableChildIds, sequentialLaterCloneIds, } from "./cloneSchedule.js";
|
|
5
|
+
import { collectDownstreamStageIds } from "./dagTraversal.js";
|
|
2
6
|
import { buildCompletedEnvelopesFromRun, buildStageConfigById, } from "./envelopeRouting.js";
|
|
3
7
|
import { WAIT_WITHOUT_WORKER_DISPATCH } from "./answerResume.js";
|
|
4
8
|
import { runStage, isRunStageWaiting } from "./stageRunner.js";
|
|
5
9
|
import { attemptContext } from "./stageAttemptContext.js";
|
|
10
|
+
function asDagSnapshot(dag) {
|
|
11
|
+
const snapshot = dag;
|
|
12
|
+
if (Array.isArray(snapshot.stage_ids))
|
|
13
|
+
return snapshot;
|
|
14
|
+
return {
|
|
15
|
+
...dag,
|
|
16
|
+
stage_ids: dag.nodes.map((n) => n.id),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export { applyCloneForksFromEnvelopes, applyCloneForksToSchedule, };
|
|
20
|
+
function synthesizedFailureEnvelope(reason) {
|
|
21
|
+
return { status: "failure", summary: reason, artifacts: [] };
|
|
22
|
+
}
|
|
6
23
|
export function snapshotToScheduleState(snap, overrides, stageId, executionMode) {
|
|
7
24
|
const override = overrides.get(stageId);
|
|
8
25
|
if (override !== undefined)
|
|
@@ -16,23 +33,28 @@ export function snapshotToScheduleState(snap, overrides, stageId, executionMode)
|
|
|
16
33
|
return "active";
|
|
17
34
|
case "waiting_for_input":
|
|
18
35
|
return executionMode === "process" ? "waiting" : "active";
|
|
36
|
+
case "skipped":
|
|
37
|
+
return "skipped";
|
|
19
38
|
default:
|
|
20
39
|
return "pending";
|
|
21
40
|
}
|
|
22
41
|
}
|
|
23
42
|
export async function hydrateScheduleFromStore(store, runId, dag, executionMode = "process") {
|
|
43
|
+
const runDetail = await store.readRun(runId);
|
|
44
|
+
const meta = await store.readRunMeta(runId);
|
|
45
|
+
const resolvedDag = meta.pipeline_dag ?? asDagSnapshot(dag);
|
|
24
46
|
const states = new Map();
|
|
25
|
-
for (const node of
|
|
47
|
+
for (const node of resolvedDag.nodes) {
|
|
26
48
|
states.set(node.id, "pending");
|
|
27
49
|
}
|
|
28
|
-
const
|
|
29
|
-
const completedEnvelopes = await buildCompletedEnvelopesFromRun(store, runId, runDetail.stages);
|
|
50
|
+
const completedEnvelopes = await buildCompletedEnvelopesFromRun(store, runId, runDetail.stages, resolvedDag);
|
|
30
51
|
let schedulingHalted = false;
|
|
31
52
|
const overrides = new Map();
|
|
32
53
|
for (const snap of runDetail.stages) {
|
|
33
54
|
const state = snapshotToScheduleState(snap, overrides, snap.stage_id, executionMode);
|
|
34
55
|
states.set(snap.stage_id, state);
|
|
35
|
-
if (state === "failed"
|
|
56
|
+
if (state === "failed" &&
|
|
57
|
+
!cloneFailureContinuesSchedule(resolvedDag, snap.stage_id, completedEnvelopes)) {
|
|
36
58
|
schedulingHalted = true;
|
|
37
59
|
}
|
|
38
60
|
}
|
|
@@ -41,15 +63,23 @@ export async function hydrateScheduleFromStore(store, runId, dag, executionMode
|
|
|
41
63
|
completedEnvelopes,
|
|
42
64
|
schedulingHalted,
|
|
43
65
|
firstFailureReason: undefined,
|
|
66
|
+
dag: resolvedDag,
|
|
44
67
|
};
|
|
45
68
|
}
|
|
46
69
|
export async function hydrateScheduleForRetryRoots(store, runId, dag, retryStageIds) {
|
|
47
70
|
const runDetail = await store.readRun(runId);
|
|
48
|
-
const
|
|
71
|
+
const meta = await store.readRunMeta(runId);
|
|
72
|
+
const resolvedDag = meta.pipeline_dag ?? asDagSnapshot(dag);
|
|
73
|
+
const completedEnvelopes = await buildCompletedEnvelopesFromRun(store, runId, runDetail.stages, resolvedDag);
|
|
74
|
+
const downstream = cloneRetryDownstream(resolvedDag, retryStageIds);
|
|
75
|
+
for (const rootId of retryStageIds) {
|
|
76
|
+
for (const id of sequentialLaterCloneIds(resolvedDag, rootId, completedEnvelopes)) {
|
|
77
|
+
downstream.add(id);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
49
80
|
const retryRootSet = new Set(retryStageIds);
|
|
50
|
-
const completedEnvelopes = await buildCompletedEnvelopesFromRun(store, runId, runDetail.stages);
|
|
51
81
|
const states = new Map();
|
|
52
|
-
for (const node of
|
|
82
|
+
for (const node of resolvedDag.nodes) {
|
|
53
83
|
states.set(node.id, "pending");
|
|
54
84
|
}
|
|
55
85
|
const overrides = new Map();
|
|
@@ -72,6 +102,7 @@ export async function hydrateScheduleForRetryRoots(store, runId, dag, retryStage
|
|
|
72
102
|
completedEnvelopes,
|
|
73
103
|
schedulingHalted: false,
|
|
74
104
|
firstFailureReason: undefined,
|
|
105
|
+
dag: resolvedDag,
|
|
75
106
|
};
|
|
76
107
|
}
|
|
77
108
|
export async function hydrateScheduleForRetry(store, runId, dag, retryStageId) {
|
|
@@ -79,7 +110,8 @@ export async function hydrateScheduleForRetry(store, runId, dag, retryStageId) {
|
|
|
79
110
|
}
|
|
80
111
|
export async function resumeRun(options) {
|
|
81
112
|
const { prepared, resumeFromStageId, initialPrior } = options;
|
|
82
|
-
const
|
|
113
|
+
const meta = await prepared.store.readRunMeta(prepared.run.runId);
|
|
114
|
+
const dag = meta.pipeline_dag ?? buildPipelineDagSnapshotFromLoaded(prepared.loaded);
|
|
83
115
|
const downstream = dag.childrenOf[resumeFromStageId];
|
|
84
116
|
if (downstream?.length) {
|
|
85
117
|
return runPipelineDag(options);
|
|
@@ -104,7 +136,10 @@ export async function resumeRun(options) {
|
|
|
104
136
|
return state !== undefined && terminalState(state);
|
|
105
137
|
});
|
|
106
138
|
if (allTerminal) {
|
|
107
|
-
const allSucceeded = dag.nodes.every((node) =>
|
|
139
|
+
const allSucceeded = dag.nodes.every((node) => {
|
|
140
|
+
const s = hydrated.states.get(node.id);
|
|
141
|
+
return s === "succeeded" || s === "skipped";
|
|
142
|
+
});
|
|
108
143
|
await prepared.store.updateRunStatus(prepared.run.runId, allSucceeded ? "succeeded" : "failed");
|
|
109
144
|
return {
|
|
110
145
|
ok: allSucceeded,
|
|
@@ -120,7 +155,7 @@ export async function resumeRun(options) {
|
|
|
120
155
|
}
|
|
121
156
|
export async function retryRun(options) {
|
|
122
157
|
const { prepared, retryRoots } = options;
|
|
123
|
-
const hydrated = await hydrateScheduleForRetryRoots(prepared.store, prepared.run.runId, prepared.loaded
|
|
158
|
+
const hydrated = await hydrateScheduleForRetryRoots(prepared.store, prepared.run.runId, buildPipelineDagSnapshotFromLoaded(prepared.loaded), [...retryRoots.keys()]);
|
|
124
159
|
return runPipelineDag({
|
|
125
160
|
prepared: options.prepared,
|
|
126
161
|
maxActiveStagesPerRun: options.maxActiveStagesPerRun,
|
|
@@ -133,10 +168,42 @@ export async function retryRun(options) {
|
|
|
133
168
|
onRetryRootTerminal: options.onRetryRootTerminal,
|
|
134
169
|
});
|
|
135
170
|
}
|
|
171
|
+
function applyForkChoiceToSchedule(dag, forkStageId, chosen, states, options) {
|
|
172
|
+
const skipPending = (stageId) => {
|
|
173
|
+
if (states.get(stageId) === "pending") {
|
|
174
|
+
states.set(stageId, "skipped");
|
|
175
|
+
options?.onSkip?.(stageId);
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
for (const childId of dag.childrenOf[forkStageId] ?? []) {
|
|
179
|
+
if (options?.protectedIds?.has(childId))
|
|
180
|
+
continue;
|
|
181
|
+
if (!chosen.has(childId)) {
|
|
182
|
+
skipPending(childId);
|
|
183
|
+
for (const desc of collectDownstreamStageIds(dag, childId)) {
|
|
184
|
+
skipPending(desc);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
export function applyForkSkipsFromEnvelopes(dag, states, completedEnvelopes) {
|
|
190
|
+
for (const node of dag.nodes) {
|
|
191
|
+
if (!node.fork)
|
|
192
|
+
continue;
|
|
193
|
+
const envelope = completedEnvelopes.get(node.id);
|
|
194
|
+
if (!envelope)
|
|
195
|
+
continue;
|
|
196
|
+
const chosen = normalizeForkChoice(envelope.fork_choice, "stored");
|
|
197
|
+
applyForkChoiceToSchedule(dag, node.id, chosen, states);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
136
200
|
export function applyRetryRootDelta(dag, states, completedEnvelopes, retryRoots, stageId, attempt, clearSchedulingHalt) {
|
|
137
201
|
retryRoots.set(stageId, attempt);
|
|
138
|
-
const downstream =
|
|
202
|
+
const downstream = cloneRetryDownstream(dag, [stageId]);
|
|
139
203
|
const resetIds = new Set([stageId, ...downstream]);
|
|
204
|
+
for (const id of sequentialLaterCloneIds(dag, stageId, completedEnvelopes)) {
|
|
205
|
+
resetIds.add(id);
|
|
206
|
+
}
|
|
140
207
|
for (const id of resetIds) {
|
|
141
208
|
const state = states.get(id);
|
|
142
209
|
if (state === "active" || state === "succeeded") {
|
|
@@ -190,27 +257,28 @@ function sortRunnableIds(dag, ids) {
|
|
|
190
257
|
const indexById = new Map(dag.nodes.map((node) => [node.id, node.stageIndex]));
|
|
191
258
|
return ids.slice().sort((a, b) => (indexById.get(a) ?? 0) - (indexById.get(b) ?? 0));
|
|
192
259
|
}
|
|
193
|
-
function isRunnable(dag, stageId, states, schedulingHalted) {
|
|
260
|
+
function isRunnable(dag, stageId, states, schedulingHalted, completedEnvelopes) {
|
|
194
261
|
if (schedulingHalted)
|
|
195
262
|
return false;
|
|
196
263
|
const state = states.get(stageId);
|
|
197
264
|
if (state !== "pending")
|
|
198
265
|
return false;
|
|
199
|
-
|
|
200
|
-
if (!node)
|
|
201
|
-
return false;
|
|
202
|
-
if (node.needs === null)
|
|
203
|
-
return true;
|
|
204
|
-
return states.get(node.needs) === "succeeded";
|
|
266
|
+
return cloneScheduleAllowsRun(dag, stageId, states, completedEnvelopes);
|
|
205
267
|
}
|
|
206
268
|
export async function runPipelineDag(options) {
|
|
207
269
|
const { prepared, maxActiveStagesPerRun } = options;
|
|
208
270
|
const executionMode = options.executionMode ?? "process";
|
|
209
|
-
const { agent, task, loaded, run, store, checkoutRoot, hitl, cwd, } = prepared;
|
|
210
|
-
const
|
|
271
|
+
const { agent, task, loaded, run, store, checkoutRoot, hitl, cwd, projectRoot, } = prepared;
|
|
272
|
+
const factoryCwd = projectRoot ?? cwd ?? process.cwd();
|
|
273
|
+
const fallbackDag = buildPipelineDagSnapshotFromLoaded(loaded);
|
|
274
|
+
let { states, completedEnvelopes, schedulingHalted, firstFailureReason, dag: hydratedDag, } = options.initialSchedule ??
|
|
275
|
+
(await hydrateScheduleFromStore(store, run.runId, fallbackDag, executionMode));
|
|
276
|
+
let dag = hydratedDag ?? fallbackDag;
|
|
277
|
+
if (hydratedDag === undefined) {
|
|
278
|
+
const meta = await store.readRunMeta(run.runId);
|
|
279
|
+
dag = meta.pipeline_dag ?? fallbackDag;
|
|
280
|
+
}
|
|
211
281
|
const stageById = buildStageConfigById(loaded);
|
|
212
|
-
let { states, completedEnvelopes, schedulingHalted, firstFailureReason } = options.initialSchedule ??
|
|
213
|
-
(await hydrateScheduleFromStore(store, run.runId, dag, executionMode));
|
|
214
282
|
const retryContext = options.retryContext;
|
|
215
283
|
const resolveLaunchAttempt = async (stageId) => {
|
|
216
284
|
if (retryContext) {
|
|
@@ -260,6 +328,14 @@ export async function runPipelineDag(options) {
|
|
|
260
328
|
}
|
|
261
329
|
}
|
|
262
330
|
}
|
|
331
|
+
applyForkSkipsFromEnvelopes(dag, states, completedEnvelopes);
|
|
332
|
+
{
|
|
333
|
+
const applied = applyCloneForksFromEnvelopes(dag, states, completedEnvelopes);
|
|
334
|
+
if (applied.dag !== dag) {
|
|
335
|
+
await store.updatePipelineDag(run.runId, applied.dag);
|
|
336
|
+
}
|
|
337
|
+
dag = applied.dag;
|
|
338
|
+
}
|
|
263
339
|
let activeCount = 0;
|
|
264
340
|
const inFlight = new Set();
|
|
265
341
|
const notifyRetryRootTerminal = (stageId, outcome) => {
|
|
@@ -270,6 +346,20 @@ export async function runPipelineDag(options) {
|
|
|
270
346
|
return;
|
|
271
347
|
options.onRetryRootTerminal?.(stageId, attempt, outcome);
|
|
272
348
|
};
|
|
349
|
+
const persistSkipPending = async (id) => {
|
|
350
|
+
if (states.get(id) !== "pending")
|
|
351
|
+
return;
|
|
352
|
+
states.set(id, "skipped");
|
|
353
|
+
notifyRetryRootTerminal(id, "skipped");
|
|
354
|
+
await store.appendStageEvent(run.runId, id, { event: "skipped" });
|
|
355
|
+
};
|
|
356
|
+
for (const [stageId, state] of states) {
|
|
357
|
+
if (state !== "failed")
|
|
358
|
+
continue;
|
|
359
|
+
for (const id of cloneFailFastSkipIds(dag, stageId, completedEnvelopes)) {
|
|
360
|
+
await persistSkipPending(id);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
273
363
|
const markSkippedPending = () => {
|
|
274
364
|
for (const node of dag.nodes) {
|
|
275
365
|
if (states.get(node.id) === "pending") {
|
|
@@ -300,9 +390,41 @@ export async function runPipelineDag(options) {
|
|
|
300
390
|
});
|
|
301
391
|
});
|
|
302
392
|
};
|
|
303
|
-
const
|
|
393
|
+
const recordCloneFailureEnvelope = async (stageId, reason, envelope) => {
|
|
394
|
+
if (!isCloneInstance(dag, stageId)) {
|
|
395
|
+
if (envelope !== undefined) {
|
|
396
|
+
completedEnvelopes.set(stageId, envelope);
|
|
397
|
+
}
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
const failureEnvelope = envelope ??
|
|
401
|
+
completedEnvelopes.get(stageId) ??
|
|
402
|
+
synthesizedFailureEnvelope(reason);
|
|
403
|
+
completedEnvelopes.set(stageId, failureEnvelope);
|
|
404
|
+
if (envelope === undefined) {
|
|
405
|
+
try {
|
|
406
|
+
await store.writeEnvelope(run.runId, stageId, failureEnvelope);
|
|
407
|
+
}
|
|
408
|
+
catch {
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
const onStageFailure = async (stageId, reason, envelope) => {
|
|
304
413
|
states.set(stageId, "failed");
|
|
305
414
|
notifyRetryRootTerminal(stageId, "failed");
|
|
415
|
+
await recordCloneFailureEnvelope(stageId, reason, envelope);
|
|
416
|
+
if (cloneFailureContinuesSchedule(dag, stageId, completedEnvelopes)) {
|
|
417
|
+
if (firstFailureReason === undefined) {
|
|
418
|
+
firstFailureReason = reason;
|
|
419
|
+
}
|
|
420
|
+
for (const id of cloneFailFastSkipIds(dag, stageId, completedEnvelopes)) {
|
|
421
|
+
await persistSkipPending(id);
|
|
422
|
+
}
|
|
423
|
+
if (retryContext) {
|
|
424
|
+
drainRetryMutations();
|
|
425
|
+
}
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
306
428
|
if (retryContext) {
|
|
307
429
|
markBranchDownstreamSkipped(stageId);
|
|
308
430
|
drainRetryMutations();
|
|
@@ -319,13 +441,59 @@ export async function runPipelineDag(options) {
|
|
|
319
441
|
firstFailureReason = reason;
|
|
320
442
|
}
|
|
321
443
|
};
|
|
322
|
-
const onStageSuccess = (stageId, envelope) => {
|
|
444
|
+
const onStageSuccess = async (stageId, envelope) => {
|
|
445
|
+
const conflict = cloneFanoutConflict(dag, envelope);
|
|
446
|
+
if (conflict !== undefined) {
|
|
447
|
+
await store.appendStageEvent(run.runId, stageId, {
|
|
448
|
+
event: "failed",
|
|
449
|
+
reason: conflict,
|
|
450
|
+
});
|
|
451
|
+
await onStageFailure(stageId, conflict);
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
323
454
|
states.set(stageId, "succeeded");
|
|
324
455
|
completedEnvelopes.set(stageId, envelope);
|
|
325
456
|
notifyRetryRootTerminal(stageId, "succeeded");
|
|
457
|
+
const node = dag.nodes.find((n) => n.id === stageId);
|
|
458
|
+
const protectedIds = protectedClonableChildIds(dag, stageId, envelope);
|
|
459
|
+
if (node?.fork) {
|
|
460
|
+
const chosen = normalizeForkChoice(envelope.fork_choice, "stored");
|
|
461
|
+
const skippedIds = [];
|
|
462
|
+
applyForkChoiceToSchedule(dag, stageId, chosen, states, {
|
|
463
|
+
protectedIds,
|
|
464
|
+
onSkip: (id) => {
|
|
465
|
+
notifyRetryRootTerminal(id, "skipped");
|
|
466
|
+
skippedIds.push(id);
|
|
467
|
+
},
|
|
468
|
+
});
|
|
469
|
+
for (const id of skippedIds) {
|
|
470
|
+
await store.appendStageEvent(run.runId, id, { event: "skipped" });
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
const applied = applyCloneForksToSchedule(dag, stageId, envelope, states);
|
|
474
|
+
const dagChanged = applied.dag !== dag;
|
|
475
|
+
dag = applied.dag;
|
|
476
|
+
if (dagChanged) {
|
|
477
|
+
await store.updatePipelineDag(run.runId, dag);
|
|
478
|
+
}
|
|
479
|
+
for (const id of applied.skippedIds) {
|
|
480
|
+
notifyRetryRootTerminal(id, "skipped");
|
|
481
|
+
await store.appendStageEvent(run.runId, id, { event: "skipped" });
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
const handlePostSuccessError = async (stageId, reason) => {
|
|
485
|
+
if (states.get(stageId) === "succeeded") {
|
|
486
|
+
completedEnvelopes.delete(stageId);
|
|
487
|
+
await store.appendStageEvent(run.runId, stageId, {
|
|
488
|
+
event: "failed",
|
|
489
|
+
reason,
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
await onStageFailure(stageId, reason);
|
|
326
493
|
};
|
|
327
494
|
const launchStage = async (stageId) => {
|
|
328
|
-
const
|
|
495
|
+
const definitionId = definitionIdForInstance(dag, stageId);
|
|
496
|
+
const stage = stageById.get(definitionId);
|
|
329
497
|
if (!stage) {
|
|
330
498
|
await onStageFailure(stageId, `stage config missing for "${stageId}"`);
|
|
331
499
|
return;
|
|
@@ -341,7 +509,7 @@ export async function runPipelineDag(options) {
|
|
|
341
509
|
const launchResult = await launcher.launch({
|
|
342
510
|
runId: run.runId,
|
|
343
511
|
stageId,
|
|
344
|
-
rootDir:
|
|
512
|
+
rootDir: factoryCwd,
|
|
345
513
|
attempt,
|
|
346
514
|
...(prepared.operatorCatalog !== undefined
|
|
347
515
|
? { operatorCatalog: prepared.operatorCatalog }
|
|
@@ -351,11 +519,11 @@ export async function runPipelineDag(options) {
|
|
|
351
519
|
if (launchResult.type === "succeeded") {
|
|
352
520
|
try {
|
|
353
521
|
const envelope = await store.readEnvelope(run.runId, stageId);
|
|
354
|
-
onStageSuccess(stageId, envelope);
|
|
522
|
+
await onStageSuccess(stageId, envelope);
|
|
355
523
|
}
|
|
356
|
-
catch {
|
|
357
|
-
|
|
358
|
-
|
|
524
|
+
catch (err) {
|
|
525
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
526
|
+
await handlePostSuccessError(stageId, reason);
|
|
359
527
|
}
|
|
360
528
|
return;
|
|
361
529
|
}
|
|
@@ -371,13 +539,14 @@ export async function runPipelineDag(options) {
|
|
|
371
539
|
store,
|
|
372
540
|
runId: run.runId,
|
|
373
541
|
stage,
|
|
542
|
+
stageId,
|
|
374
543
|
task,
|
|
375
544
|
dag,
|
|
376
545
|
checkoutRoot,
|
|
377
546
|
workspaceDir: run.workspaceDir,
|
|
378
547
|
hitl,
|
|
379
548
|
attemptCtx,
|
|
380
|
-
factoryCwd
|
|
549
|
+
factoryCwd,
|
|
381
550
|
operatorCatalog: prepared.operatorCatalog,
|
|
382
551
|
completedEnvelopes,
|
|
383
552
|
skipGates: prepared.skipGates,
|
|
@@ -387,11 +556,17 @@ export async function runPipelineDag(options) {
|
|
|
387
556
|
return;
|
|
388
557
|
}
|
|
389
558
|
if (!result.ok) {
|
|
390
|
-
await onStageFailure(stageId, result.reason ?? "stage failed");
|
|
559
|
+
await onStageFailure(stageId, result.reason ?? "stage failed", result.envelope);
|
|
391
560
|
return;
|
|
392
561
|
}
|
|
393
562
|
if (result.envelope) {
|
|
394
|
-
|
|
563
|
+
try {
|
|
564
|
+
await onStageSuccess(stageId, result.envelope);
|
|
565
|
+
}
|
|
566
|
+
catch (err) {
|
|
567
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
568
|
+
await handlePostSuccessError(stageId, reason);
|
|
569
|
+
}
|
|
395
570
|
}
|
|
396
571
|
else {
|
|
397
572
|
states.set(stageId, "succeeded");
|
|
@@ -412,7 +587,7 @@ export async function runPipelineDag(options) {
|
|
|
412
587
|
const pickRunnable = () => {
|
|
413
588
|
const ids = [];
|
|
414
589
|
for (const node of dag.nodes) {
|
|
415
|
-
if (isRunnable(dag, node.id, states, schedulingHalted)) {
|
|
590
|
+
if (isRunnable(dag, node.id, states, schedulingHalted, completedEnvelopes)) {
|
|
416
591
|
ids.push(node.id);
|
|
417
592
|
}
|
|
418
593
|
}
|
|
@@ -485,7 +660,10 @@ export async function runPipelineDag(options) {
|
|
|
485
660
|
reason: firstFailureReason,
|
|
486
661
|
};
|
|
487
662
|
}
|
|
488
|
-
const allSucceeded = dag.nodes.every((node) =>
|
|
663
|
+
const allSucceeded = dag.nodes.every((node) => {
|
|
664
|
+
const s = states.get(node.id);
|
|
665
|
+
return s === "succeeded" || s === "skipped";
|
|
666
|
+
});
|
|
489
667
|
if (!allSucceeded) {
|
|
490
668
|
if (retryContext === undefined) {
|
|
491
669
|
await store.updateRunStatus(run.runId, "failed");
|
|
@@ -498,9 +676,7 @@ export async function runPipelineDag(options) {
|
|
|
498
676
|
reason: firstFailureReason ?? "pipeline incomplete",
|
|
499
677
|
};
|
|
500
678
|
}
|
|
501
|
-
|
|
502
|
-
await store.updateRunStatus(run.runId, "succeeded");
|
|
503
|
-
}
|
|
679
|
+
await store.updateRunStatus(run.runId, "succeeded");
|
|
504
680
|
return {
|
|
505
681
|
ok: true,
|
|
506
682
|
outcome: "succeeded",
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { RunMeta } from "../runstore/port.js";
|
|
2
|
+
import type { LoadedPipeline } from "../types/pipeline.js";
|
|
3
|
+
import type { TaskFile } from "../types/task.js";
|
|
4
|
+
export declare function reloadPipelineForRun(meta: RunMeta): Promise<LoadedPipeline>;
|
|
5
|
+
export declare function reloadTaskForRun(meta: RunMeta): Promise<TaskFile>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
import { loadPipeline } from "../config/loadPipeline.js";
|
|
3
|
+
import { loadTask } from "../config/loadTask.js";
|
|
4
|
+
import { normalizeCatalogPath } from "../runstore/normalizeCatalogPath.js";
|
|
5
|
+
function missingLocator(field, runId) {
|
|
6
|
+
throw new Error(`Run ${runId} is missing ${field}; reload requires stored catalog locators.`);
|
|
7
|
+
}
|
|
8
|
+
function requireProjectRoot(meta) {
|
|
9
|
+
if (!meta.project_root) {
|
|
10
|
+
missingLocator("project_root", meta.run_id);
|
|
11
|
+
}
|
|
12
|
+
return normalizeCatalogPath(meta.project_root);
|
|
13
|
+
}
|
|
14
|
+
function requirePipelinePath(meta) {
|
|
15
|
+
if (!meta.pipeline_path) {
|
|
16
|
+
missingLocator("pipeline_path", meta.run_id);
|
|
17
|
+
}
|
|
18
|
+
return normalizeCatalogPath(meta.pipeline_path);
|
|
19
|
+
}
|
|
20
|
+
function requireTaskPath(meta) {
|
|
21
|
+
if (!meta.task_path) {
|
|
22
|
+
missingLocator("task_path", meta.run_id);
|
|
23
|
+
}
|
|
24
|
+
return normalizeCatalogPath(meta.task_path);
|
|
25
|
+
}
|
|
26
|
+
async function assertCatalogFileExists(filePath, label) {
|
|
27
|
+
try {
|
|
28
|
+
await access(filePath);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
throw new Error(`${label} not found at stored path: ${filePath}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export async function reloadPipelineForRun(meta) {
|
|
35
|
+
const projectRoot = requireProjectRoot(meta);
|
|
36
|
+
const pipelinePath = requirePipelinePath(meta);
|
|
37
|
+
await assertCatalogFileExists(pipelinePath, "Pipeline");
|
|
38
|
+
return loadPipeline(pipelinePath, { cwd: projectRoot });
|
|
39
|
+
}
|
|
40
|
+
export async function reloadTaskForRun(meta) {
|
|
41
|
+
const taskPath = requireTaskPath(meta);
|
|
42
|
+
await assertCatalogFileExists(taskPath, "Task");
|
|
43
|
+
return loadTask(taskPath);
|
|
44
|
+
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
2
3
|
import { fakeHitlResumePath } from "../agent/fakeAgent.js";
|
|
3
|
-
import { loadPipeline } from "../config/loadPipeline.js";
|
|
4
4
|
import { loadTaskFromYaml } from "../config/loadTask.js";
|
|
5
|
+
import { normalizeCatalogPath } from "../runstore/normalizeCatalogPath.js";
|
|
6
|
+
import { reloadPipelineForRun, reloadTaskForRun, } from "./reloadRunCatalog.js";
|
|
7
|
+
import { definitionIdForInstance } from "../runstore/stageInstanceId.js";
|
|
5
8
|
import { WAIT_WITHOUT_WORKER_DISPATCH } from "./answerResume.js";
|
|
6
9
|
import { resumeRun } from "./pipelineScheduler.js";
|
|
7
10
|
import { buildStageRoots, withResolvedAuthPath } from "./stageRoots.js";
|
|
@@ -10,20 +13,34 @@ import { attemptContext } from "./stageAttemptContext.js";
|
|
|
10
13
|
import { openStageAttempt, } from "./stageAttemptBootstrap.js";
|
|
11
14
|
export async function loadRunContext(store, runId, cwd) {
|
|
12
15
|
const meta = await store.readRunMeta(runId);
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
const reloadMeta = {
|
|
17
|
+
...meta,
|
|
18
|
+
project_root: meta.project_root ?? normalizeCatalogPath(cwd),
|
|
19
|
+
};
|
|
20
|
+
const loaded = await reloadPipelineForRun(reloadMeta);
|
|
21
|
+
let taskYaml;
|
|
22
|
+
let task;
|
|
23
|
+
if (meta.task_path) {
|
|
24
|
+
task = await reloadTaskForRun(meta);
|
|
25
|
+
taskYaml = await readFile(normalizeCatalogPath(meta.task_path), "utf8");
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
taskYaml = await store.readTaskYaml(runId);
|
|
29
|
+
task = loadTaskFromYaml(taskYaml, `run ${runId} task`);
|
|
30
|
+
}
|
|
16
31
|
const workspaceDir = store.getWorkspaceDir(runId);
|
|
17
32
|
return { meta, taskYaml, task, loaded, workspaceDir };
|
|
18
33
|
}
|
|
19
34
|
export async function reconstructAndContinue(ctx) {
|
|
20
35
|
const { runId, stageId, opaqueAnswer, agent, store, cwd } = ctx;
|
|
36
|
+
const factoryCwd = ctx.factoryCwd ?? cwd;
|
|
21
37
|
try {
|
|
22
38
|
const latestExecution = await store.getLatestStageExecution(runId, stageId);
|
|
23
39
|
const attemptCtx = attemptContext(latestExecution?.attempt ?? 1);
|
|
24
40
|
const attemptOpt = attemptCtx.eventOptions();
|
|
25
41
|
const { meta, task, loaded } = await loadRunContext(store, runId, cwd);
|
|
26
|
-
const
|
|
42
|
+
const definitionId = definitionIdForInstance(meta.pipeline_dag, stageId);
|
|
43
|
+
const stageIndex = loaded.stages.findIndex((s) => s.id === definitionId);
|
|
27
44
|
if (stageIndex < 0) {
|
|
28
45
|
const reason = `Stage ${stageId} not in pipeline ${meta.pipeline_id}`;
|
|
29
46
|
await store.appendStageEvent(runId, stageId, {
|
|
@@ -34,9 +51,10 @@ export async function reconstructAndContinue(ctx) {
|
|
|
34
51
|
return { ok: false, reason };
|
|
35
52
|
}
|
|
36
53
|
const stage = loaded.stages[stageIndex];
|
|
54
|
+
const dag = meta.pipeline_dag ?? loaded.dag;
|
|
37
55
|
const workspaceDir = store.getWorkspaceDir(runId);
|
|
38
56
|
const checkoutRoot = meta.checkout_root;
|
|
39
|
-
const roots = withResolvedAuthPath(buildStageRoots(workspaceDir, stageId, checkoutRoot, attemptCtx),
|
|
57
|
+
const roots = withResolvedAuthPath(buildStageRoots(workspaceDir, stageId, checkoutRoot, attemptCtx), factoryCwd);
|
|
40
58
|
const fakeResume = fakeHitlResumePath(roots, stageId);
|
|
41
59
|
const piSession = attemptCtx.sessionPath(workspaceDir, stageId);
|
|
42
60
|
if (!existsSync(fakeResume) && !existsSync(piSession)) {
|
|
@@ -53,11 +71,12 @@ export async function reconstructAndContinue(ctx) {
|
|
|
53
71
|
store,
|
|
54
72
|
runId,
|
|
55
73
|
stage,
|
|
74
|
+
stageId,
|
|
56
75
|
task,
|
|
57
|
-
dag
|
|
76
|
+
dag,
|
|
58
77
|
checkoutRoot,
|
|
59
78
|
workspaceDir,
|
|
60
|
-
factoryCwd
|
|
79
|
+
factoryCwd,
|
|
61
80
|
attemptCtx,
|
|
62
81
|
operatorCatalog: ctx.operatorCatalog,
|
|
63
82
|
onActivity: (event) => {
|
|
@@ -78,15 +97,16 @@ export async function reconstructAndContinue(ctx) {
|
|
|
78
97
|
store,
|
|
79
98
|
runId,
|
|
80
99
|
stage,
|
|
100
|
+
stageId,
|
|
81
101
|
task,
|
|
82
|
-
dag
|
|
102
|
+
dag,
|
|
83
103
|
checkoutRoot,
|
|
84
104
|
workspaceDir,
|
|
85
105
|
hitl: ctx.hitl,
|
|
86
106
|
skipStarted: true,
|
|
87
107
|
existingHandle: opened.handle,
|
|
88
108
|
attemptCtx,
|
|
89
|
-
factoryCwd
|
|
109
|
+
factoryCwd,
|
|
90
110
|
operatorCatalog: ctx.operatorCatalog,
|
|
91
111
|
});
|
|
92
112
|
if (isRunStageWaiting(result)) {
|
|
@@ -108,6 +128,7 @@ export async function reconstructAndContinue(ctx) {
|
|
|
108
128
|
agent,
|
|
109
129
|
store,
|
|
110
130
|
cwd,
|
|
131
|
+
projectRoot: factoryCwd,
|
|
111
132
|
checkoutRoot,
|
|
112
133
|
hitl: ctx.hitl,
|
|
113
134
|
operatorCatalog: ctx.operatorCatalog,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { RunStore } from "../runstore/port.js";
|
|
2
|
+
export type RunChangeKind = "created" | "status" | "waiting";
|
|
3
|
+
export type RunChangeEvent = {
|
|
4
|
+
runId: string;
|
|
5
|
+
kind: RunChangeKind;
|
|
6
|
+
};
|
|
7
|
+
type RunChangeListener = (event: RunChangeEvent) => void;
|
|
8
|
+
export declare class RunChangeBus {
|
|
9
|
+
private readonly listeners;
|
|
10
|
+
on(listener: RunChangeListener): () => void;
|
|
11
|
+
off(listener: RunChangeListener): void;
|
|
12
|
+
emit(event: RunChangeEvent): void;
|
|
13
|
+
}
|
|
14
|
+
export declare function createRunChangeBus(): RunChangeBus;
|
|
15
|
+
export declare function isRunStoreWrapped(store: RunStore): boolean;
|
|
16
|
+
export declare function getRunChangeBusFromWrappedStore(store: RunStore): RunChangeBus | undefined;
|
|
17
|
+
export declare function wrapRunStoreWithChangeBus(store: RunStore, bus: RunChangeBus): RunStore;
|
|
18
|
+
export {};
|