stageflow 0.1.0 → 0.3.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 +190 -13
- package/dist/agent/activity.d.ts +10 -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/fakeAgent.js +4 -0
- package/dist/agent/piAdapter.d.ts +16 -0
- package/dist/agent/piAdapter.js +88 -21
- package/dist/agent/port.d.ts +2 -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/ciIdentity.d.ts +14 -0
- package/dist/cli/ciIdentity.js +52 -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 +26 -0
- package/dist/cli/runCommand.js +209 -0
- package/dist/cli/runOutput.d.ts +19 -0
- package/dist/cli/runOutput.js +125 -0
- package/dist/cli/validateCommand.d.ts +1 -1
- package/dist/cli/validateCommand.js +20 -3
- package/dist/cli.d.ts +12 -1
- package/dist/cli.js +82 -66
- 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 +84 -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 +16 -0
- package/dist/config/normalizePipelineStageEntry.js +186 -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 +3 -0
- package/dist/config/resolveForkEmitContext.js +12 -0
- package/dist/config/resolvePipelineDag.d.ts +5 -1
- package/dist/config/resolvePipelineDag.js +54 -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.js +7 -0
- package/dist/envelope/forkChoice.d.ts +3 -0
- package/dist/envelope/forkChoice.js +47 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/mcp/projectRun.d.ts +3 -0
- package/dist/mcp/projectRun.js +7 -0
- package/dist/mcp/server.js +1 -1
- package/dist/mcp/tools.js +28 -11
- 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/runstore/normalizeCatalogPath.d.ts +1 -0
- package/dist/runstore/normalizeCatalogPath.js +4 -0
- package/dist/runstore/port.d.ts +15 -0
- package/dist/runstore/runProjection.js +11 -1
- package/dist/runstore/sqlite/SqliteRunStore.js +46 -4
- package/dist/runstore/sqlite/schema.d.ts +1 -1
- package/dist/runstore/sqlite/schema.js +7 -1
- package/dist/runtime/credentialBinding.d.ts +8 -6
- package/dist/runtime/credentialBinding.js +18 -24
- package/dist/runtime/pipelineRunner.d.ts +11 -0
- package/dist/runtime/pipelineRunner.js +25 -1
- package/dist/runtime/pipelineScheduler.d.ts +3 -0
- package/dist/runtime/pipelineScheduler.js +70 -14
- 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 +27 -10
- package/dist/runtime/runManager.d.ts +8 -0
- package/dist/runtime/runManager.js +49 -18
- package/dist/runtime/settingsFile.d.ts +12 -0
- package/dist/runtime/settingsFile.js +87 -6
- package/dist/runtime/stageAttemptBootstrap.js +3 -0
- package/dist/runtime/stageProcessLauncher.d.ts +1 -0
- package/dist/runtime/stageProcessLauncher.js +6 -0
- package/dist/runtime/stageRecovery.js +3 -1
- package/dist/runtime/stageRunner.d.ts +2 -0
- package/dist/runtime/stageRunner.js +9 -2
- package/dist/runtime/stageWorker.js +4 -6
- package/dist/runtime/stageWorkerProtocol.d.ts +1 -0
- package/dist/server/http.js +33 -9
- package/dist/tools/emitStageEnvelope.d.ts +3 -1
- package/dist/tools/emitStageEnvelope.js +11 -1
- package/dist/types/envelope.d.ts +1 -0
- package/dist/types/forkChoice.d.ts +8 -0
- package/dist/types/forkChoice.js +1 -0
- package/dist/types/pipeline.d.ts +51 -2
- package/dist/types/stageflowManifest.d.ts +23 -0
- package/dist/types/stageflowManifest.js +1 -0
- package/dist/ui/assets/index-CFSzDZje.js +118 -0
- package/dist/ui/assets/{index-DCsDopak.css → index-DefBlEvN.css} +1 -1
- package/dist/ui/index.html +3 -2
- package/dist/ui/stageflow-icon.svg +12 -0
- package/package.json +7 -5
- package/dist/agent/cursorExtension.d.ts +0 -12
- package/dist/agent/cursorExtension.js +0 -88
- package/dist/runstore/catalog.d.ts +0 -8
- package/dist/runstore/catalog.js +0 -16
- package/dist/runstore/disk/DiskRunStore.d.ts +0 -30
- package/dist/runstore/disk/DiskRunStore.js +0 -238
- package/dist/runstore/layout.d.ts +0 -22
- package/dist/runstore/layout.js +0 -58
- package/dist/runtime/hitlSeams.d.ts +0 -38
- package/dist/runtime/hitlSeams.js +0 -2
- package/dist/ui/assets/index-Cry0Tpfx.js +0 -118
|
@@ -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 { 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";
|
|
@@ -63,6 +64,7 @@ export async function openStageAttempt(input) {
|
|
|
63
64
|
const attempt = input.attemptCtx?.attempt ?? 1;
|
|
64
65
|
const resumeToken = input.resumeToken ??
|
|
65
66
|
resumeSessionFilePath(input.workspaceDir, input.stage.id, attempt);
|
|
67
|
+
const forkEmitContext = resolveForkEmitContext(input.dag, input.stage.id);
|
|
66
68
|
const opened = await openStageWithOperatorCatalog(input.agent, {
|
|
67
69
|
roots,
|
|
68
70
|
stage: input.stage,
|
|
@@ -70,6 +72,7 @@ export async function openStageAttempt(input) {
|
|
|
70
72
|
priorEnvelope: priorResult.prior,
|
|
71
73
|
resumeToken,
|
|
72
74
|
onActivity: input.onActivity,
|
|
75
|
+
forkEmitContext,
|
|
73
76
|
}, input.operatorCatalog);
|
|
74
77
|
if (!opened.ok)
|
|
75
78
|
return opened;
|
|
@@ -132,9 +132,15 @@ 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
|
}
|
|
141
|
+
if (input.skipGates) {
|
|
142
|
+
args.push("--skip-gates");
|
|
143
|
+
}
|
|
138
144
|
const child = fork(this.cliEntry, args, {
|
|
139
145
|
cwd: input.rootDir,
|
|
140
146
|
env: { ...process.env, ...this.env, [SF_STAGE_WORKER]: "1" },
|
|
@@ -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
|
}
|
|
@@ -43,6 +43,7 @@ export type RunStageOptions = {
|
|
|
43
43
|
factoryCwd?: string;
|
|
44
44
|
operatorCatalog?: OperatorCatalog;
|
|
45
45
|
completedEnvelopes?: Map<string, StageEnvelope>;
|
|
46
|
+
skipGates?: boolean;
|
|
46
47
|
};
|
|
47
48
|
/**
|
|
48
49
|
* Yield loop: next() until completed; on wait, coordinator enterWait (KTD6).
|
|
@@ -55,5 +56,6 @@ export declare function runStageYieldLoop(options: {
|
|
|
55
56
|
workerMode?: boolean;
|
|
56
57
|
store?: RunStore;
|
|
57
58
|
attemptCtx?: StageAttemptContext;
|
|
59
|
+
skipGates?: boolean;
|
|
58
60
|
}): Promise<RunStageYieldLoopResult>;
|
|
59
61
|
export declare function runStage(options: RunStageOptions): Promise<RunStageOutcome>;
|
|
@@ -73,10 +73,16 @@ async function finalizeStageResult(options) {
|
|
|
73
73
|
* Yield loop: next() until completed; on wait, coordinator enterWait (KTD6).
|
|
74
74
|
*/
|
|
75
75
|
export async function runStageYieldLoop(options) {
|
|
76
|
-
const { handle, runId, stageId, hitl, workerMode, store, attemptCtx } = options;
|
|
76
|
+
const { handle, runId, stageId, hitl, workerMode, store, attemptCtx, skipGates } = options;
|
|
77
77
|
while (true) {
|
|
78
78
|
const event = await handle.next();
|
|
79
79
|
if (event.status === "waiting_for_input") {
|
|
80
|
+
if (skipGates) {
|
|
81
|
+
return {
|
|
82
|
+
ok: false,
|
|
83
|
+
reason: "skip-gates: stage requested wait",
|
|
84
|
+
};
|
|
85
|
+
}
|
|
80
86
|
if (workerMode) {
|
|
81
87
|
if (!store) {
|
|
82
88
|
return {
|
|
@@ -107,7 +113,7 @@ export async function runStageYieldLoop(options) {
|
|
|
107
113
|
}
|
|
108
114
|
}
|
|
109
115
|
export async function runStage(options) {
|
|
110
|
-
const { agent, store, runId, stage, task, dag, checkoutRoot, workspaceDir, hitl, skipStarted, existingHandle, workerMode, roots: rootsOverride, attemptCtx, factoryCwd, operatorCatalog, completedEnvelopes, } = options;
|
|
116
|
+
const { agent, store, runId, stage, task, dag, checkoutRoot, workspaceDir, hitl, skipStarted, existingHandle, workerMode, roots: rootsOverride, attemptCtx, factoryCwd, operatorCatalog, completedEnvelopes, skipGates, } = options;
|
|
111
117
|
const attemptOpt = attemptCtx?.eventOptions();
|
|
112
118
|
const baseRoots = rootsOverride ??
|
|
113
119
|
buildStageRoots(workspaceDir ?? store.getWorkspaceDir(runId), stage.id, checkoutRoot, attemptCtx);
|
|
@@ -183,6 +189,7 @@ export async function runStage(options) {
|
|
|
183
189
|
workerMode,
|
|
184
190
|
store: workerMode ? store : undefined,
|
|
185
191
|
attemptCtx,
|
|
192
|
+
skipGates,
|
|
186
193
|
});
|
|
187
194
|
}
|
|
188
195
|
catch (err) {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { PiAgentAdapter } from "../agent/piAdapter.js";
|
|
2
|
-
import { loadPipeline } from "../config/loadPipeline.js";
|
|
3
|
-
import { loadTaskFromYaml } from "../config/loadTask.js";
|
|
4
2
|
import { createRunStore } from "../runstore/createStore.js";
|
|
3
|
+
import { loadRunContext } from "./resumeReconstruct.js";
|
|
5
4
|
import { bindPiAgentDirEnv, rootsForStageWorker, withResolvedAuthPath, } from "./stageRoots.js";
|
|
6
5
|
import { runStage, isRunStageWaiting, } from "./stageRunner.js";
|
|
7
6
|
import { openStageAttempt } from "./stageAttemptBootstrap.js";
|
|
@@ -9,10 +8,7 @@ import { attemptContext } from "./stageAttemptContext.js";
|
|
|
9
8
|
import { outcomeToWorkerResult, STAGE_WORKER_EXIT, } from "./stageWorkerProtocol.js";
|
|
10
9
|
export async function runStageWorker(input) {
|
|
11
10
|
const store = createRunStore({ rootDir: input.rootDir });
|
|
12
|
-
const meta = await store.
|
|
13
|
-
const taskYaml = await store.readTaskYaml(input.runId);
|
|
14
|
-
const task = loadTaskFromYaml(taskYaml, `run ${input.runId} task`);
|
|
15
|
-
const loaded = await loadPipeline(meta.pipeline_id, { cwd: input.rootDir });
|
|
11
|
+
const { meta, task, loaded } = await loadRunContext(store, input.runId, input.rootDir);
|
|
16
12
|
const stage = loaded.stages.find((s) => s.id === input.stageId);
|
|
17
13
|
if (!stage) {
|
|
18
14
|
return {
|
|
@@ -68,6 +64,7 @@ export async function runStageWorker(input) {
|
|
|
68
64
|
attemptCtx,
|
|
69
65
|
factoryCwd: input.rootDir,
|
|
70
66
|
operatorCatalog: input.operatorCatalog,
|
|
67
|
+
skipGates: input.skipGates,
|
|
71
68
|
});
|
|
72
69
|
return outcome;
|
|
73
70
|
}
|
|
@@ -85,6 +82,7 @@ export async function runStageWorker(input) {
|
|
|
85
82
|
attemptCtx,
|
|
86
83
|
factoryCwd: input.rootDir,
|
|
87
84
|
operatorCatalog: input.operatorCatalog,
|
|
85
|
+
skipGates: input.skipGates,
|
|
88
86
|
});
|
|
89
87
|
}
|
|
90
88
|
finally {
|
package/dist/server/http.js
CHANGED
|
@@ -8,12 +8,14 @@ import { getCredentialSourceSettings, setCredentialSource, } from "../agent/prov
|
|
|
8
8
|
import { handleProviderRoutes, providerAuthErrorBody, } from "./providerRoutes.js";
|
|
9
9
|
import { createPipeline, parseCreatePipelineBody } from "../config/createPipeline.js";
|
|
10
10
|
import { createStage, parseCreateStageBody } from "../config/createStage.js";
|
|
11
|
-
import {
|
|
11
|
+
import { browseCatalog } from "../config/browseCatalog.js";
|
|
12
12
|
import { listExtensions } from "../config/listExtensions.js";
|
|
13
13
|
import { listSkills } from "../config/listSkills.js";
|
|
14
14
|
import { readRunArtifact } from "../mcp/readArtifact.js";
|
|
15
15
|
import { handleMcpHttpRequest } from "../mcp/server.js";
|
|
16
16
|
import { createRunStore } from "../runstore/createStore.js";
|
|
17
|
+
import { resolveStageflowContext } from "../project/resolveStageflowContext.js";
|
|
18
|
+
import { findProjectRoot } from "../project/findProjectRoot.js";
|
|
17
19
|
import { RunManager, } from "../runtime/runManager.js";
|
|
18
20
|
import { INVALID_SLOT_COUNT_MESSAGE, parseSlotCount, } from "../runtime/settingsFile.js";
|
|
19
21
|
import { isTaskFile } from "../runtime/taskInput.js";
|
|
@@ -202,9 +204,14 @@ export function defaultUiDistDir() {
|
|
|
202
204
|
return path.resolve(here, "../ui");
|
|
203
205
|
}
|
|
204
206
|
export async function startUiServer(options) {
|
|
205
|
-
const
|
|
207
|
+
const invocationCwd = options.cwd ?? process.cwd();
|
|
208
|
+
const ctx = await resolveStageflowContext(invocationCwd);
|
|
209
|
+
const cwd = ctx.invocationCwd;
|
|
206
210
|
const agentDir = options.agentDir ?? getAgentDir();
|
|
207
|
-
const rootDir = options.rootDir ??
|
|
211
|
+
const rootDir = options.rootDir ?? ctx.projectRoot;
|
|
212
|
+
const isGitProject = options.rootDir !== undefined
|
|
213
|
+
? findProjectRoot(rootDir) !== null
|
|
214
|
+
: ctx.isGitProject;
|
|
208
215
|
const host = options.host ?? "127.0.0.1";
|
|
209
216
|
const port = options.port ?? DEFAULT_PORT;
|
|
210
217
|
const providerAuthContext = options.providerAuthContext;
|
|
@@ -214,6 +221,8 @@ export async function startUiServer(options) {
|
|
|
214
221
|
const manager = new RunManager({
|
|
215
222
|
agent: options.agent,
|
|
216
223
|
cwd,
|
|
224
|
+
projectRoot: rootDir,
|
|
225
|
+
isGitProject,
|
|
217
226
|
store,
|
|
218
227
|
maxConcurrent: options.maxConcurrent,
|
|
219
228
|
operatorCatalog: { cwd, agentDir },
|
|
@@ -388,15 +397,19 @@ export async function startUiServer(options) {
|
|
|
388
397
|
return;
|
|
389
398
|
}
|
|
390
399
|
if (method === "GET" && pathname === "/api/tasks") {
|
|
391
|
-
|
|
400
|
+
const catalog = await browseCatalog(cwd);
|
|
401
|
+
json(res, 200, { tasks: catalog.tasks });
|
|
392
402
|
return;
|
|
393
403
|
}
|
|
394
404
|
if (method === "GET" && pathname === "/api/pipelines") {
|
|
395
|
-
|
|
405
|
+
const catalog = await browseCatalog(cwd);
|
|
406
|
+
json(res, 200, { pipelines: catalog.pipelines });
|
|
396
407
|
return;
|
|
397
408
|
}
|
|
398
409
|
if (method === "GET" && pathname === "/api/stages") {
|
|
399
|
-
json(res,
|
|
410
|
+
json(res, 404, {
|
|
411
|
+
error: "Global stage library removed; stages are pipeline-scoped",
|
|
412
|
+
});
|
|
400
413
|
return;
|
|
401
414
|
}
|
|
402
415
|
if (method === "POST" && pathname === "/api/stages") {
|
|
@@ -413,7 +426,12 @@ export async function startUiServer(options) {
|
|
|
413
426
|
json(res, parsed.status, { error: parsed.error });
|
|
414
427
|
return;
|
|
415
428
|
}
|
|
416
|
-
const
|
|
429
|
+
const ctx = await resolveStageflowContext(cwd);
|
|
430
|
+
if (!ctx.isGitProject) {
|
|
431
|
+
json(res, 400, { error: "Project root not found; initialize stageflow.yaml in a git repo" });
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
const result = await createStage(ctx.projectRoot, parsed);
|
|
417
435
|
if (!result.ok) {
|
|
418
436
|
json(res, result.status, { error: result.error });
|
|
419
437
|
return;
|
|
@@ -435,7 +453,12 @@ export async function startUiServer(options) {
|
|
|
435
453
|
json(res, parsed.status, { error: parsed.error });
|
|
436
454
|
return;
|
|
437
455
|
}
|
|
438
|
-
const
|
|
456
|
+
const ctx = await resolveStageflowContext(cwd);
|
|
457
|
+
if (!ctx.isGitProject) {
|
|
458
|
+
json(res, 400, { error: "Project root not found; initialize stageflow.yaml in a git repo" });
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
const result = await createPipeline(ctx.projectRoot, parsed);
|
|
439
462
|
if (!result.ok) {
|
|
440
463
|
json(res, result.status, { error: result.error });
|
|
441
464
|
return;
|
|
@@ -444,7 +467,8 @@ export async function startUiServer(options) {
|
|
|
444
467
|
return;
|
|
445
468
|
}
|
|
446
469
|
if (method === "GET" && pathname === "/api/models") {
|
|
447
|
-
|
|
470
|
+
const catalog = await browseCatalog(cwd);
|
|
471
|
+
json(res, 200, { models: catalog.models });
|
|
448
472
|
return;
|
|
449
473
|
}
|
|
450
474
|
if (await handleProviderRoutes(req, res, {
|
|
@@ -11,11 +11,12 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { Type } from "typebox";
|
|
13
13
|
import type { StageEnvelope } from "../types/envelope.js";
|
|
14
|
+
import type { ForkEmitContext } from "../types/forkChoice.js";
|
|
14
15
|
export type EmitCapture = {
|
|
15
16
|
envelope?: StageEnvelope;
|
|
16
17
|
error?: string;
|
|
17
18
|
};
|
|
18
|
-
export declare function createEmitStageEnvelopeTool(capture: EmitCapture, payloadSchema?: unknown): {
|
|
19
|
+
export declare function createEmitStageEnvelopeTool(capture: EmitCapture, payloadSchema?: unknown, forkEmitContext?: ForkEmitContext): {
|
|
19
20
|
name: string;
|
|
20
21
|
label: string;
|
|
21
22
|
description: string;
|
|
@@ -24,6 +25,7 @@ export declare function createEmitStageEnvelopeTool(capture: EmitCapture, payloa
|
|
|
24
25
|
summary: Type.TString;
|
|
25
26
|
artifacts: Type.TArray<Type.TString>;
|
|
26
27
|
payload: Type.TSchema;
|
|
28
|
+
fork_choice: Type.TArray<Type.TString>;
|
|
27
29
|
stage_id: Type.TOptional<Type.TString>;
|
|
28
30
|
notes: Type.TOptional<Type.TString>;
|
|
29
31
|
}>;
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { Type } from "typebox";
|
|
13
13
|
import { assertRequiredEnvelope, isAdvancingEnvelope, } from "../envelope/check.js";
|
|
14
|
+
import { normalizeForkChoice } from "../envelope/forkChoice.js";
|
|
14
15
|
import { assertEnvelopePayload, compilePayloadSchema, } from "../envelope/payloadSchema.js";
|
|
15
16
|
function toolResult(text, details, options) {
|
|
16
17
|
return {
|
|
@@ -20,7 +21,7 @@ function toolResult(text, details, options) {
|
|
|
20
21
|
...(options?.terminate ? { terminate: true } : {}),
|
|
21
22
|
};
|
|
22
23
|
}
|
|
23
|
-
export function createEmitStageEnvelopeTool(capture, payloadSchema) {
|
|
24
|
+
export function createEmitStageEnvelopeTool(capture, payloadSchema, forkEmitContext) {
|
|
24
25
|
const compiledPayload = payloadSchema !== undefined
|
|
25
26
|
? compilePayloadSchema(payloadSchema)
|
|
26
27
|
: undefined;
|
|
@@ -35,6 +36,9 @@ export function createEmitStageEnvelopeTool(capture, payloadSchema) {
|
|
|
35
36
|
payload: compiledPayload !== undefined
|
|
36
37
|
? compiledPayload
|
|
37
38
|
: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
|
|
39
|
+
fork_choice: forkEmitContext !== undefined
|
|
40
|
+
? Type.Array(Type.String())
|
|
41
|
+
: Type.Optional(Type.Array(Type.String())),
|
|
38
42
|
stage_id: Type.Optional(Type.String()),
|
|
39
43
|
notes: Type.Optional(Type.String()),
|
|
40
44
|
}),
|
|
@@ -43,6 +47,12 @@ export function createEmitStageEnvelopeTool(capture, payloadSchema) {
|
|
|
43
47
|
return toolResult("Envelope already accepted; later emits are ignored.", { advancing: isAdvancingEnvelope(capture.envelope), error: "" }, { terminate: true });
|
|
44
48
|
}
|
|
45
49
|
try {
|
|
50
|
+
if (forkEmitContext !== undefined) {
|
|
51
|
+
const record = params;
|
|
52
|
+
if (record.status !== "failure") {
|
|
53
|
+
normalizeForkChoice(record.fork_choice, "emit", forkEmitContext);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
46
56
|
const envelope = assertRequiredEnvelope(params);
|
|
47
57
|
assertEnvelopePayload(envelope, payloadSchema);
|
|
48
58
|
capture.envelope = envelope;
|
package/dist/types/envelope.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/types/pipeline.d.ts
CHANGED
|
@@ -1,17 +1,64 @@
|
|
|
1
|
+
import type { StageConfig, StageGateKind } from "./stage.js";
|
|
1
2
|
export type PipelineConfig = {
|
|
2
3
|
id: string;
|
|
3
4
|
stages: string[];
|
|
4
5
|
};
|
|
6
|
+
export type PipelineForkConfig = {
|
|
7
|
+
select: "one" | "subset";
|
|
8
|
+
allow_none: boolean;
|
|
9
|
+
};
|
|
5
10
|
export type PipelineStageRef = {
|
|
6
11
|
id: string;
|
|
7
12
|
needs?: string;
|
|
13
|
+
fork?: {
|
|
14
|
+
select: "one" | "subset";
|
|
15
|
+
allow_none?: boolean;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export type PipelineStageYamlEntry = PipelineStageRef & {
|
|
19
|
+
uses?: string;
|
|
20
|
+
system_prompt?: string;
|
|
21
|
+
model?: string;
|
|
22
|
+
payload_schema?: unknown;
|
|
23
|
+
gate_kinds?: StageGateKind[];
|
|
24
|
+
skill?: string;
|
|
25
|
+
};
|
|
26
|
+
export type PipelineIncludeEntry = {
|
|
27
|
+
local: string;
|
|
28
|
+
};
|
|
29
|
+
export type PipelineFragmentConfig = {
|
|
30
|
+
include?: PipelineIncludeEntry[];
|
|
31
|
+
stages?: PipelineStageYamlEntry[];
|
|
32
|
+
};
|
|
33
|
+
export type NormalizedPipelineStageEntry = {
|
|
34
|
+
id: string;
|
|
35
|
+
needs?: string;
|
|
36
|
+
fork?: {
|
|
37
|
+
select: "one" | "subset";
|
|
38
|
+
allow_none?: boolean;
|
|
39
|
+
};
|
|
40
|
+
body: {
|
|
41
|
+
kind: "inline";
|
|
42
|
+
raw: Record<string, unknown>;
|
|
43
|
+
} | {
|
|
44
|
+
kind: "uses";
|
|
45
|
+
path: string;
|
|
46
|
+
absolutePath: string;
|
|
47
|
+
};
|
|
48
|
+
declaringPath: string;
|
|
49
|
+
};
|
|
50
|
+
export type PipelineStageSource = {
|
|
51
|
+
kind: "inline";
|
|
52
|
+
} | {
|
|
53
|
+
kind: "file";
|
|
54
|
+
path: string;
|
|
8
55
|
};
|
|
9
|
-
export type PipelineStageYamlEntry = string | PipelineStageRef;
|
|
10
56
|
export type ResolvedPipelineStageNode = {
|
|
11
57
|
id: string;
|
|
12
58
|
needs: string | null;
|
|
13
59
|
ancestors: string[];
|
|
14
60
|
stageIndex: number;
|
|
61
|
+
fork?: PipelineForkConfig;
|
|
15
62
|
};
|
|
16
63
|
export type ResolvedPipelineDag = {
|
|
17
64
|
nodes: ResolvedPipelineStageNode[];
|
|
@@ -20,6 +67,8 @@ export type ResolvedPipelineDag = {
|
|
|
20
67
|
};
|
|
21
68
|
export type LoadedPipeline = {
|
|
22
69
|
pipeline: PipelineConfig;
|
|
23
|
-
stages:
|
|
70
|
+
stages: StageConfig[];
|
|
24
71
|
dag: ResolvedPipelineDag;
|
|
72
|
+
pipelinePath: string;
|
|
73
|
+
stageSources?: Record<string, PipelineStageSource>;
|
|
25
74
|
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type StageflowManifestVersion = 1;
|
|
2
|
+
export type StageflowManifestCatalog = {
|
|
3
|
+
pipelines: string[];
|
|
4
|
+
tasks: string[];
|
|
5
|
+
patterns?: {
|
|
6
|
+
pipeline?: string;
|
|
7
|
+
task?: string;
|
|
8
|
+
};
|
|
9
|
+
exclude?: string[];
|
|
10
|
+
};
|
|
11
|
+
export type StageflowManifest = {
|
|
12
|
+
version: StageflowManifestVersion;
|
|
13
|
+
catalog: StageflowManifestCatalog;
|
|
14
|
+
};
|
|
15
|
+
export type LoadedManifest = {
|
|
16
|
+
path: string;
|
|
17
|
+
projectRoot: string;
|
|
18
|
+
manifest: StageflowManifest;
|
|
19
|
+
patterns: {
|
|
20
|
+
pipeline: string;
|
|
21
|
+
task: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|