stageflow 0.2.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 +158 -14
- 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/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 +3 -1
- package/dist/cli/runCommand.js +48 -7
- 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 +52 -19
- 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/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 +9 -0
- package/dist/runstore/runProjection.js +11 -1
- package/dist/runstore/sqlite/SqliteRunStore.js +30 -4
- package/dist/runstore/sqlite/schema.d.ts +1 -1
- package/dist/runstore/sqlite/schema.js +4 -1
- package/dist/runtime/credentialBinding.d.ts +8 -6
- package/dist/runtime/credentialBinding.js +18 -24
- package/dist/runtime/pipelineRunner.d.ts +3 -0
- package/dist/runtime/pipelineRunner.js +15 -1
- package/dist/runtime/pipelineScheduler.d.ts +2 -0
- package/dist/runtime/pipelineScheduler.js +51 -11
- 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 +23 -7
- 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.js +3 -0
- package/dist/runtime/stageProcessLauncher.js +3 -0
- package/dist/runtime/stageRecovery.js +3 -1
- package/dist/runtime/stageWorker.js +2 -6
- 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/ui/assets/index-Cry0Tpfx.js +0 -118
package/dist/cli.js
CHANGED
|
@@ -4,16 +4,20 @@ import { realpathSync } from "node:fs";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { PiAgentAdapter } from "./agent/piAdapter.js";
|
|
7
|
+
import { INIT_USAGE, runInitCommand } from "./cli/initCommand.js";
|
|
7
8
|
import { PROVIDERS_USAGE, runProvidersCommand } from "./cli/providersCommand.js";
|
|
8
9
|
import { RUN_USAGE, runRunCommand } from "./cli/runCommand.js";
|
|
10
|
+
import { resolveOperatorCatalog } from "./cli/operatorCatalog.js";
|
|
9
11
|
import { VALIDATE_USAGE, runValidateCommand } from "./cli/validateCommand.js";
|
|
10
12
|
import { createRunStore } from "./runstore/createStore.js";
|
|
13
|
+
import { resolveStageflowContext } from "./project/resolveStageflowContext.js";
|
|
11
14
|
import { exitForOutcome, runStageWorker } from "./runtime/stageWorker.js";
|
|
12
15
|
import { SF_STAGE_WORKER } from "./runtime/stageWorkerProtocol.js";
|
|
13
16
|
import { DEFAULT_PORT, startUiServer } from "./server/http.js";
|
|
14
17
|
const USAGE = `Usage:
|
|
15
|
-
sf
|
|
16
|
-
sf
|
|
18
|
+
sf init
|
|
19
|
+
sf run --task <path> --pipeline <path> [--checkout <path>] [--json] [--skip-gates] [--git-sha <sha>] [--ci-pr-url <url>] [--ci-job-url <url>] [--operator-cwd <path>] [--operator-agent-dir <path>]
|
|
20
|
+
sf validate [--pipeline <path>] [--task <path>] [--strict] [--json]
|
|
17
21
|
sf ui [--port ${DEFAULT_PORT}]
|
|
18
22
|
sf providers list
|
|
19
23
|
sf providers status [--provider <id>]
|
|
@@ -27,6 +31,8 @@ Stageflow (sf) runs YAML-defined automatic stage pipelines.
|
|
|
27
31
|
|
|
28
32
|
Store backend: SF_STORE=sqlite only. SF_STORE=disk is rejected; disk-era .stageflow/runs trees import when the SQLite store is empty. Data under .stageflow/.
|
|
29
33
|
|
|
34
|
+
${INIT_USAGE}
|
|
35
|
+
|
|
30
36
|
${RUN_USAGE}
|
|
31
37
|
|
|
32
38
|
${VALIDATE_USAGE}
|
|
@@ -44,7 +50,8 @@ function parseArgs(argv) {
|
|
|
44
50
|
const command = args[0];
|
|
45
51
|
if (command === "providers" ||
|
|
46
52
|
command === "validate" ||
|
|
47
|
-
command === "run"
|
|
53
|
+
command === "run" ||
|
|
54
|
+
command === "init") {
|
|
48
55
|
return { help: false, command };
|
|
49
56
|
}
|
|
50
57
|
if (args.includes("--help") || args.includes("-h")) {
|
|
@@ -85,6 +92,7 @@ export function parseRunStageArgs(argv) {
|
|
|
85
92
|
let resumeAnswer;
|
|
86
93
|
let attempt;
|
|
87
94
|
let sessionFilePath;
|
|
95
|
+
let operatorCwd;
|
|
88
96
|
let operatorAgentDir;
|
|
89
97
|
let skipGates = false;
|
|
90
98
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -130,6 +138,12 @@ export function parseRunStageArgs(argv) {
|
|
|
130
138
|
throw new Error("Missing value for --session-file");
|
|
131
139
|
}
|
|
132
140
|
}
|
|
141
|
+
else if (argv[i] === "--operator-cwd") {
|
|
142
|
+
operatorCwd = argv[++i];
|
|
143
|
+
if (operatorCwd === undefined) {
|
|
144
|
+
throw new Error("Missing value for --operator-cwd");
|
|
145
|
+
}
|
|
146
|
+
}
|
|
133
147
|
else if (argv[i] === "--operator-agent-dir") {
|
|
134
148
|
operatorAgentDir = argv[++i];
|
|
135
149
|
if (operatorAgentDir === undefined) {
|
|
@@ -143,6 +157,11 @@ export function parseRunStageArgs(argv) {
|
|
|
143
157
|
if (!runId || !stageId) {
|
|
144
158
|
throw new Error("Missing --run-id and/or --stage-id");
|
|
145
159
|
}
|
|
160
|
+
const operatorCatalog = resolveOperatorCatalog({
|
|
161
|
+
flags: { operatorCwd, operatorAgentDir },
|
|
162
|
+
env: process.env,
|
|
163
|
+
defaultCwd: process.cwd(),
|
|
164
|
+
});
|
|
146
165
|
return {
|
|
147
166
|
runId,
|
|
148
167
|
stageId,
|
|
@@ -151,9 +170,7 @@ export function parseRunStageArgs(argv) {
|
|
|
151
170
|
attempt,
|
|
152
171
|
sessionFilePath,
|
|
153
172
|
skipGates,
|
|
154
|
-
|
|
155
|
-
? { operatorCatalog: { cwd: process.cwd(), agentDir: operatorAgentDir } }
|
|
156
|
-
: {}),
|
|
173
|
+
operatorCatalog,
|
|
157
174
|
};
|
|
158
175
|
}
|
|
159
176
|
async function handleInternalRunStage(argv) {
|
|
@@ -194,21 +211,30 @@ async function main(argv) {
|
|
|
194
211
|
console.log(USAGE);
|
|
195
212
|
return argv.slice(2).length === 0 ? 1 : 0;
|
|
196
213
|
}
|
|
197
|
-
const
|
|
214
|
+
const ctx = await resolveStageflowContext(process.cwd());
|
|
215
|
+
if (parsed.command === "init") {
|
|
216
|
+
return runInitCommand(argv.slice(3), { cwd: ctx.invocationCwd });
|
|
217
|
+
}
|
|
198
218
|
if (parsed.command === "validate") {
|
|
199
|
-
return runValidateCommand(argv.slice(3), { cwd:
|
|
219
|
+
return runValidateCommand(argv.slice(3), { cwd: ctx.invocationCwd });
|
|
200
220
|
}
|
|
201
221
|
if (parsed.command === "run") {
|
|
202
|
-
return runRunCommand(argv.slice(3), {
|
|
222
|
+
return runRunCommand(argv.slice(3), {
|
|
223
|
+
cwd: ctx.invocationCwd,
|
|
224
|
+
projectRoot: ctx.projectRoot,
|
|
225
|
+
isGitProject: ctx.isGitProject,
|
|
226
|
+
});
|
|
203
227
|
}
|
|
204
228
|
if (parsed.command === "providers") {
|
|
205
|
-
return runProvidersCommand(argv.slice(3),
|
|
229
|
+
return runProvidersCommand(argv.slice(3), ctx.invocationCwd);
|
|
206
230
|
}
|
|
207
|
-
const store = createRunStore({ rootDir });
|
|
231
|
+
const store = createRunStore({ rootDir: ctx.projectRoot });
|
|
208
232
|
if (parsed.command === "ui") {
|
|
209
233
|
const { url, mcpUrl } = await startUiServer({
|
|
210
234
|
agent: new PiAgentAdapter(),
|
|
211
235
|
store,
|
|
236
|
+
cwd: ctx.invocationCwd,
|
|
237
|
+
rootDir: ctx.projectRoot,
|
|
212
238
|
port: parsed.port,
|
|
213
239
|
});
|
|
214
240
|
console.log(`Operator console: ${url}`);
|
|
@@ -235,16 +261,23 @@ async function main(argv) {
|
|
|
235
261
|
return 1;
|
|
236
262
|
}
|
|
237
263
|
}
|
|
264
|
+
function normalizeCliEntry(filePath) {
|
|
265
|
+
const resolved = path.resolve(filePath);
|
|
266
|
+
let canonical;
|
|
267
|
+
try {
|
|
268
|
+
canonical = realpathSync(resolved);
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
canonical = resolved;
|
|
272
|
+
}
|
|
273
|
+
return canonical.replace(/\.(?:[cm]?[jt]s)$/i, "");
|
|
274
|
+
}
|
|
275
|
+
export function sameCliEntry(a, b) {
|
|
276
|
+
return normalizeCliEntry(a) === normalizeCliEntry(b);
|
|
277
|
+
}
|
|
238
278
|
function isDirectCliInvocation() {
|
|
239
279
|
const self = fileURLToPath(import.meta.url);
|
|
240
|
-
return process.argv.slice(1).some((arg) =>
|
|
241
|
-
try {
|
|
242
|
-
return realpathSync(path.resolve(arg)) === realpathSync(self);
|
|
243
|
-
}
|
|
244
|
-
catch {
|
|
245
|
-
return false;
|
|
246
|
-
}
|
|
247
|
-
});
|
|
280
|
+
return process.argv.slice(1).some((arg) => sameCliEntry(arg, self));
|
|
248
281
|
}
|
|
249
282
|
if (isDirectCliInvocation()) {
|
|
250
283
|
main(process.argv)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { StageGateKind } from "../types/stage.js";
|
|
2
|
+
import type { LoadedManifest } from "../types/stageflowManifest.js";
|
|
3
|
+
import type { LoadIssue } from "./loadOutcome.js";
|
|
4
|
+
import type { CatalogContext } from "./resolveCatalogContext.js";
|
|
5
|
+
import { type CatalogManifestStatus, type StageflowContext } from "../project/resolveStageflowContext.js";
|
|
6
|
+
export type TaskListing = {
|
|
7
|
+
path: string;
|
|
8
|
+
id: string;
|
|
9
|
+
goal: string;
|
|
10
|
+
};
|
|
11
|
+
export type PipelineStageListing = {
|
|
12
|
+
id: string;
|
|
13
|
+
gate_kinds?: StageGateKind[];
|
|
14
|
+
uses_path?: string;
|
|
15
|
+
inline?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export type PipelineListing = {
|
|
18
|
+
path: string;
|
|
19
|
+
id: string;
|
|
20
|
+
stages: PipelineStageListing[];
|
|
21
|
+
};
|
|
22
|
+
export type CatalogBrowseWarning = {
|
|
23
|
+
path: string;
|
|
24
|
+
kind: "pipeline" | "task";
|
|
25
|
+
error: string;
|
|
26
|
+
};
|
|
27
|
+
export type CatalogBrowseResult = {
|
|
28
|
+
projectRoot: string | null;
|
|
29
|
+
manifest: LoadedManifest | null;
|
|
30
|
+
manifestStatus: CatalogManifestStatus;
|
|
31
|
+
issues: LoadIssue[];
|
|
32
|
+
pipelines: PipelineListing[];
|
|
33
|
+
tasks: TaskListing[];
|
|
34
|
+
models: string[];
|
|
35
|
+
warnings: CatalogBrowseWarning[];
|
|
36
|
+
};
|
|
37
|
+
export type CatalogScanPaths = {
|
|
38
|
+
pipelinePaths: string[];
|
|
39
|
+
taskPaths: string[];
|
|
40
|
+
};
|
|
41
|
+
export declare function getCatalogScanPaths(ctx: CatalogContext): Promise<CatalogScanPaths | null>;
|
|
42
|
+
export declare function browseCatalog(invocationCwd: string | StageflowContext): Promise<CatalogBrowseResult>;
|
|
43
|
+
export declare function listPipelinesForContext(ctx: CatalogContext): Promise<PipelineListing[]>;
|
|
44
|
+
export declare function listTasksForContext(ctx: CatalogContext): Promise<TaskListing[]>;
|
|
45
|
+
export declare function listModelsForContext(ctx: CatalogContext): Promise<string[]>;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { loadPipeline } from "./loadPipeline.js";
|
|
3
|
+
import { loadTask } from "./loadTask.js";
|
|
4
|
+
import { resolveStageflowContext, } from "../project/resolveStageflowContext.js";
|
|
5
|
+
import { scanCatalogPaths } from "./scanCatalogPaths.js";
|
|
6
|
+
const BAKED_MODEL_IDS = [
|
|
7
|
+
"anthropic/claude-sonnet-4-5",
|
|
8
|
+
"cursor/auto",
|
|
9
|
+
"cursor/composer-2-5",
|
|
10
|
+
];
|
|
11
|
+
function repoRelPath(projectRoot, absPath) {
|
|
12
|
+
return path.relative(projectRoot, absPath).replace(/\\/g, "/");
|
|
13
|
+
}
|
|
14
|
+
function mapStageListing(stage, source, projectRoot) {
|
|
15
|
+
const listing = {
|
|
16
|
+
id: stage.id,
|
|
17
|
+
...(stage.gate_kinds ? { gate_kinds: stage.gate_kinds } : {}),
|
|
18
|
+
};
|
|
19
|
+
if (source?.kind === "inline") {
|
|
20
|
+
listing.inline = true;
|
|
21
|
+
}
|
|
22
|
+
else if (source?.kind === "file") {
|
|
23
|
+
listing.uses_path = repoRelPath(projectRoot, source.path);
|
|
24
|
+
}
|
|
25
|
+
return listing;
|
|
26
|
+
}
|
|
27
|
+
function bakedModels() {
|
|
28
|
+
return [...BAKED_MODEL_IDS].sort((a, b) => a.localeCompare(b));
|
|
29
|
+
}
|
|
30
|
+
function catalogReadyFromStageflow(ctx) {
|
|
31
|
+
return ctx.isGitProject && ctx.manifestStatus === "ok" && ctx.manifest !== null;
|
|
32
|
+
}
|
|
33
|
+
function catalogReady(ctx) {
|
|
34
|
+
return ctx.manifestStatus === "ok" && ctx.projectRoot !== null && ctx.manifest !== null;
|
|
35
|
+
}
|
|
36
|
+
export async function getCatalogScanPaths(ctx) {
|
|
37
|
+
if (!catalogReady(ctx)) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const [pipelinePaths, taskPaths] = await Promise.all([
|
|
41
|
+
scanCatalogPaths(ctx.manifest, "pipeline"),
|
|
42
|
+
scanCatalogPaths(ctx.manifest, "task"),
|
|
43
|
+
]);
|
|
44
|
+
return { pipelinePaths, taskPaths };
|
|
45
|
+
}
|
|
46
|
+
async function listTasksFromManifest(projectRoot, manifest, warnings) {
|
|
47
|
+
const filePaths = await scanCatalogPaths(manifest, "task");
|
|
48
|
+
const listings = [];
|
|
49
|
+
for (const filePath of filePaths) {
|
|
50
|
+
try {
|
|
51
|
+
const task = await loadTask(filePath);
|
|
52
|
+
listings.push({
|
|
53
|
+
path: repoRelPath(projectRoot, filePath),
|
|
54
|
+
id: task.id,
|
|
55
|
+
goal: task.goal,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
warnings.push({
|
|
60
|
+
path: repoRelPath(projectRoot, filePath),
|
|
61
|
+
kind: "task",
|
|
62
|
+
error: err instanceof Error ? err.message : String(err),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
listings.sort((a, b) => {
|
|
67
|
+
const pathCmp = a.path.localeCompare(b.path);
|
|
68
|
+
if (pathCmp !== 0)
|
|
69
|
+
return pathCmp;
|
|
70
|
+
return a.id.localeCompare(b.id);
|
|
71
|
+
});
|
|
72
|
+
return listings;
|
|
73
|
+
}
|
|
74
|
+
async function listPipelinesFromManifest(projectRoot, manifest, warnings) {
|
|
75
|
+
const filePaths = await scanCatalogPaths(manifest, "pipeline");
|
|
76
|
+
const listings = [];
|
|
77
|
+
for (const filePath of filePaths) {
|
|
78
|
+
try {
|
|
79
|
+
const loaded = await loadPipeline(filePath, { cwd: projectRoot });
|
|
80
|
+
listings.push({
|
|
81
|
+
path: repoRelPath(projectRoot, filePath),
|
|
82
|
+
id: loaded.pipeline.id,
|
|
83
|
+
stages: loaded.stages.map((stage) => mapStageListing(stage, loaded.stageSources?.[stage.id], projectRoot)),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
warnings.push({
|
|
88
|
+
path: repoRelPath(projectRoot, filePath),
|
|
89
|
+
kind: "pipeline",
|
|
90
|
+
error: err instanceof Error ? err.message : String(err),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
listings.sort((a, b) => {
|
|
95
|
+
const pathCmp = a.path.localeCompare(b.path);
|
|
96
|
+
if (pathCmp !== 0)
|
|
97
|
+
return pathCmp;
|
|
98
|
+
return a.id.localeCompare(b.id);
|
|
99
|
+
});
|
|
100
|
+
return listings;
|
|
101
|
+
}
|
|
102
|
+
async function listModelsFromManifest(projectRoot, manifest) {
|
|
103
|
+
const models = new Set(BAKED_MODEL_IDS);
|
|
104
|
+
const filePaths = await scanCatalogPaths(manifest, "pipeline");
|
|
105
|
+
for (const filePath of filePaths) {
|
|
106
|
+
try {
|
|
107
|
+
const loaded = await loadPipeline(filePath, { cwd: projectRoot });
|
|
108
|
+
for (const stage of loaded.stages) {
|
|
109
|
+
if (stage.model.trim()) {
|
|
110
|
+
models.add(stage.model);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// skip invalid pipelines
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return [...models].sort((a, b) => a.localeCompare(b));
|
|
119
|
+
}
|
|
120
|
+
export async function browseCatalog(invocationCwd) {
|
|
121
|
+
const ctx = typeof invocationCwd === "string"
|
|
122
|
+
? await resolveStageflowContext(invocationCwd)
|
|
123
|
+
: invocationCwd;
|
|
124
|
+
const base = {
|
|
125
|
+
projectRoot: ctx.isGitProject ? ctx.projectRoot : null,
|
|
126
|
+
manifest: ctx.manifest,
|
|
127
|
+
manifestStatus: ctx.manifestStatus,
|
|
128
|
+
issues: ctx.manifestIssues,
|
|
129
|
+
};
|
|
130
|
+
if (!catalogReadyFromStageflow(ctx)) {
|
|
131
|
+
return {
|
|
132
|
+
...base,
|
|
133
|
+
pipelines: [],
|
|
134
|
+
tasks: [],
|
|
135
|
+
models: bakedModels(),
|
|
136
|
+
warnings: [],
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const warnings = [];
|
|
140
|
+
const [pipelines, tasks, models] = await Promise.all([
|
|
141
|
+
listPipelinesFromManifest(ctx.projectRoot, ctx.manifest, warnings),
|
|
142
|
+
listTasksFromManifest(ctx.projectRoot, ctx.manifest, warnings),
|
|
143
|
+
listModelsFromManifest(ctx.projectRoot, ctx.manifest),
|
|
144
|
+
]);
|
|
145
|
+
return {
|
|
146
|
+
...base,
|
|
147
|
+
pipelines,
|
|
148
|
+
tasks,
|
|
149
|
+
models,
|
|
150
|
+
warnings,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
export async function listPipelinesForContext(ctx) {
|
|
154
|
+
if (!catalogReady(ctx)) {
|
|
155
|
+
return [];
|
|
156
|
+
}
|
|
157
|
+
return listPipelinesFromManifest(ctx.projectRoot, ctx.manifest, []);
|
|
158
|
+
}
|
|
159
|
+
export async function listTasksForContext(ctx) {
|
|
160
|
+
if (!catalogReady(ctx)) {
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
163
|
+
return listTasksFromManifest(ctx.projectRoot, ctx.manifest, []);
|
|
164
|
+
}
|
|
165
|
+
export async function listModelsForContext(ctx) {
|
|
166
|
+
if (!catalogReady(ctx)) {
|
|
167
|
+
return bakedModels();
|
|
168
|
+
}
|
|
169
|
+
return listModelsFromManifest(ctx.projectRoot, ctx.manifest);
|
|
170
|
+
}
|
|
@@ -1,11 +1,20 @@
|
|
|
1
|
+
import type { StageGateKind } from "../types/stage.js";
|
|
1
2
|
import type { PipelineListing } from "./listConfig.js";
|
|
3
|
+
export type CreatePipelineStageInline = {
|
|
4
|
+
system_prompt: string;
|
|
5
|
+
model: string;
|
|
6
|
+
gate_kinds?: StageGateKind[];
|
|
7
|
+
};
|
|
2
8
|
export type CreatePipelineStageRef = {
|
|
3
9
|
id: string;
|
|
4
10
|
needs?: string;
|
|
11
|
+
uses?: string;
|
|
12
|
+
inline?: CreatePipelineStageInline;
|
|
5
13
|
};
|
|
6
14
|
export type CreatePipelineInput = {
|
|
15
|
+
directory: string;
|
|
7
16
|
id: string;
|
|
8
|
-
stages: CreatePipelineStageRef[]
|
|
17
|
+
stages: CreatePipelineStageRef[];
|
|
9
18
|
};
|
|
10
19
|
export type CreatePipelineParseError = {
|
|
11
20
|
ok: false;
|
|
@@ -20,7 +29,7 @@ export type CreatePipelineResult = {
|
|
|
20
29
|
status: 400 | 409 | 422 | 500;
|
|
21
30
|
error: string;
|
|
22
31
|
};
|
|
23
|
-
export declare function normalizeCreatePipelineStages(stages: CreatePipelineStageRef[]
|
|
32
|
+
export declare function normalizeCreatePipelineStages(stages: CreatePipelineStageRef[]): CreatePipelineStageRef[];
|
|
24
33
|
export declare function parseCreatePipelineBody(body: unknown): CreatePipelineInput | CreatePipelineParseError;
|
|
25
34
|
export declare function pipelineConfigToYaml(pipeline: {
|
|
26
35
|
id: string;
|
|
@@ -28,4 +37,4 @@ export declare function pipelineConfigToYaml(pipeline: {
|
|
|
28
37
|
}, options: {
|
|
29
38
|
format: "linear" | "dag";
|
|
30
39
|
}): string;
|
|
31
|
-
export declare function createPipeline(
|
|
40
|
+
export declare function createPipeline(projectRoot: string, input: CreatePipelineInput): Promise<CreatePipelineResult>;
|