stageflow 0.19.0 → 0.25.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.
Files changed (120) hide show
  1. package/README.md +16 -3
  2. package/dist/a2a/configDiscovery.d.ts +9 -0
  3. package/dist/a2a/configDiscovery.js +18 -0
  4. package/dist/a2a/contracts.d.ts +93 -0
  5. package/dist/a2a/contracts.js +163 -0
  6. package/dist/a2a/limits.d.ts +14 -0
  7. package/dist/a2a/limits.js +29 -0
  8. package/dist/a2a/registry.d.ts +44 -0
  9. package/dist/a2a/registry.js +159 -0
  10. package/dist/a2a/server.d.ts +29 -0
  11. package/dist/a2a/server.js +341 -0
  12. package/dist/a2a/service.d.ts +97 -0
  13. package/dist/a2a/service.js +496 -0
  14. package/dist/a2a/store.d.ts +106 -0
  15. package/dist/a2a/store.js +245 -0
  16. package/dist/agent/activity.d.ts +5 -0
  17. package/dist/agent/activityObserver.d.ts +3 -0
  18. package/dist/agent/activityObserver.js +6 -1
  19. package/dist/agent/piAdapter.js +7 -3
  20. package/dist/agent/port.d.ts +2 -0
  21. package/dist/agent/providerInspect.d.ts +19 -0
  22. package/dist/agent/providerInspect.js +35 -0
  23. package/dist/agent/streamLogRedact.d.ts +2 -0
  24. package/dist/agent/streamLogRedact.js +13 -0
  25. package/dist/cli/a2aCommand.d.ts +8 -0
  26. package/dist/cli/a2aCommand.js +131 -0
  27. package/dist/cli/artifactCommand.js +2 -2
  28. package/dist/cli/envelopeCommand.js +2 -2
  29. package/dist/cli/exportRunCommand.js +2 -2
  30. package/dist/cli/hostClient.d.ts +43 -0
  31. package/dist/cli/hostClient.js +182 -0
  32. package/dist/cli/providersCommand.js +5 -3
  33. package/dist/cli/runCommand.d.ts +6 -5
  34. package/dist/cli/runCommand.js +23 -31
  35. package/dist/cli/runOutput.d.ts +1 -1
  36. package/dist/cli/runStageCommand.d.ts +33 -0
  37. package/dist/cli/runStageCommand.js +407 -0
  38. package/dist/cli/runsCommand.d.ts +3 -7
  39. package/dist/cli/runsCommand.js +33 -94
  40. package/dist/cli.js +20 -5
  41. package/dist/config/describePipeline.d.ts +26 -0
  42. package/dist/config/describePipeline.js +37 -0
  43. package/dist/config/loadPipeline.d.ts +13 -1
  44. package/dist/config/loadPipeline.js +34 -4
  45. package/dist/config/mergePipelineIncludes.d.ts +11 -0
  46. package/dist/config/mergePipelineIncludes.js +75 -0
  47. package/dist/config/validateCatalog.d.ts +2 -2
  48. package/dist/config/validateCatalog.js +24 -17
  49. package/dist/mcp/catalogTools.js +285 -52
  50. package/dist/mcp/controlTools.js +77 -19
  51. package/dist/mcp/deps.d.ts +3 -0
  52. package/dist/mcp/projectMcpTools.d.ts +3 -0
  53. package/dist/mcp/projectMcpTools.js +25 -0
  54. package/dist/mcp/providerTools.d.ts +3 -0
  55. package/dist/mcp/providerTools.js +17 -0
  56. package/dist/mcp/readArtifact.d.ts +9 -0
  57. package/dist/mcp/readArtifact.js +11 -0
  58. package/dist/mcp/server.js +9 -1
  59. package/dist/mcp/tailStreamLog.d.ts +8 -0
  60. package/dist/mcp/tailStreamLog.js +28 -0
  61. package/dist/mcp/toolResults.d.ts +17 -0
  62. package/dist/mcp/toolResults.js +15 -0
  63. package/dist/mcp/tools.js +4 -0
  64. package/dist/mcp/waitRun.js +4 -4
  65. package/dist/mcp/waitingGates.d.ts +1 -0
  66. package/dist/mcp/waitingGates.js +3 -2
  67. package/dist/package-meta.d.ts +1 -1
  68. package/dist/package-meta.js +1 -1
  69. package/dist/projection/projectRun.d.ts +3 -0
  70. package/dist/projection/projectRun.js +7 -0
  71. package/dist/runstore/createStore.d.ts +10 -0
  72. package/dist/runstore/createStore.js +13 -4
  73. package/dist/runstore/port.d.ts +17 -2
  74. package/dist/runstore/sqlite/SqliteRunStore.d.ts +11 -1
  75. package/dist/runstore/sqlite/SqliteRunStore.js +81 -26
  76. package/dist/runstore/sqlite/schema.d.ts +1 -1
  77. package/dist/runstore/sqlite/schema.js +6 -0
  78. package/dist/runstore/submission.d.ts +11 -0
  79. package/dist/runstore/submission.js +7 -0
  80. package/dist/runstore/workspaceLayout.d.ts +1 -0
  81. package/dist/runstore/workspaceLayout.js +3 -0
  82. package/dist/runtime/feedbackLoopCoordinator.d.ts +9 -1
  83. package/dist/runtime/feedbackLoopCoordinator.js +50 -20
  84. package/dist/runtime/feedbackLoopDecision.js +33 -1
  85. package/dist/runtime/pipelineRunner.d.ts +5 -3
  86. package/dist/runtime/pipelineRunner.js +6 -1
  87. package/dist/runtime/pipelineScheduler.js +32 -15
  88. package/dist/runtime/reloadRunCatalog.js +7 -1
  89. package/dist/runtime/resolveEnvelopeRef.d.ts +30 -0
  90. package/dist/runtime/resolveEnvelopeRef.js +79 -0
  91. package/dist/runtime/resumeReconstruct.js +2 -2
  92. package/dist/runtime/runManager.d.ts +24 -2
  93. package/dist/runtime/runManager.js +83 -19
  94. package/dist/runtime/settingsFile.d.ts +2 -0
  95. package/dist/runtime/settingsFile.js +19 -0
  96. package/dist/runtime/stageAttemptBootstrap.d.ts +3 -0
  97. package/dist/runtime/stageAttemptBootstrap.js +8 -2
  98. package/dist/runtime/stageStreamLog.d.ts +17 -0
  99. package/dist/runtime/stageStreamLog.js +89 -0
  100. package/dist/runtime/stageWorker.js +2 -1
  101. package/dist/server/bootstrap.d.ts +2 -0
  102. package/dist/server/bootstrap.js +22 -4
  103. package/dist/server/createHttpHost.js +6 -0
  104. package/dist/server/ensureGlobalService.d.ts +35 -0
  105. package/dist/server/ensureGlobalService.js +138 -0
  106. package/dist/server/http.d.ts +20 -1
  107. package/dist/server/http.js +450 -402
  108. package/dist/server/mcpHost.js +7 -8
  109. package/dist/server/operatorResults.d.ts +10 -0
  110. package/dist/server/operatorResults.js +24 -0
  111. package/dist/server/providerRoutes.d.ts +0 -6
  112. package/dist/server/providerRoutes.js +10 -18
  113. package/dist/types/pipeline.d.ts +8 -0
  114. package/dist/ui/assets/{index-DMVdl1qB.js → index-Da5EHU6M.js} +5 -5
  115. package/dist/ui/index.html +1 -1
  116. package/package.json +2 -1
  117. package/skills/stageflow/references/control-surface.md +2 -2
  118. package/skills/stageflow-run/SKILL.md +27 -9
  119. package/skills/stageflow-run/references/mcp-call.md +1 -1
  120. package/skills/stageflow-run/scripts/mcp-call.mjs +9 -0
package/dist/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawn } from "node:child_process";
3
+ import { A2A_USAGE, runA2aCommand } from "./cli/a2aCommand.js";
3
4
  import { realpathSync } from "node:fs";
4
5
  import path from "node:path";
5
6
  import { fileURLToPath } from "node:url";
@@ -10,6 +11,7 @@ import { EXPORT_RUN_USAGE, runExportRunCommand, } from "./cli/exportRunCommand.j
10
11
  import { INIT_USAGE, runInitCommand } from "./cli/initCommand.js";
11
12
  import { PROVIDERS_USAGE, runProvidersCommand } from "./cli/providersCommand.js";
12
13
  import { RUN_USAGE, runRunCommand } from "./cli/runCommand.js";
14
+ import { RUN_STAGE_USAGE, runRunStageCommand } from "./cli/runStageCommand.js";
13
15
  import { RUNS_USAGE, runRunsCommand } from "./cli/runsCommand.js";
14
16
  import { resolveOperatorCatalog } from "./cli/operatorCatalog.js";
15
17
  import { SKILLS_USAGE, runSkillsCommand } from "./cli/skillsCommand.js";
@@ -27,6 +29,7 @@ import { PACKAGE_VERSION } from "./package-meta.js";
27
29
  const USAGE = `Usage:
28
30
  sf init
29
31
  sf run --task <path> --pipeline <path> [--checkout <path>] [--json] [--include stages] [--skip-gates] [--git-sha <sha>] [--ci-pr-url <url>] [--ci-job-url <url>] [--operator-cwd <path>] [--operator-agent-dir <path>]
32
+ sf run-stage (--stage <path> | --stage-inline '<json>') (--task <path> | --task-inline '<json>' | --envelope-ref <runId>:<stageId>[:<attempt>]) [--checkout <path>] [--model <id>] [--blocking] [--timeout-ms <n>] [--json]
30
33
  sf validate [--pipeline <path>] [--task <path>] [--strict] [--json]
31
34
  sf graph --pipeline <path> [--json]
32
35
  sf migrate-yaml [path] [--root <path>] [--write] [--json] [--force]
@@ -58,6 +61,8 @@ const USAGE = `Usage:
58
61
  sf --version
59
62
  sf -V
60
63
  sf --help
64
+ sf a2a validate|list [--config <path>]
65
+ sf a2a add-caller <id> [--config <path>] [--token-env <NAME>]
61
66
 
62
67
  Stageflow (sf) runs YAML-defined automatic stage pipelines.
63
68
 
@@ -67,10 +72,14 @@ ${INIT_USAGE}
67
72
 
68
73
  ${RUN_USAGE}
69
74
 
75
+ ${RUN_STAGE_USAGE}
76
+
70
77
  ${VALIDATE_USAGE}
71
78
 
72
79
  ${GRAPH_USAGE}
73
80
 
81
+ ${A2A_USAGE}
82
+
74
83
  ${MIGRATE_YAML_USAGE}
75
84
 
76
85
  ${ARTIFACT_USAGE}
@@ -103,8 +112,10 @@ function parseArgs(argv) {
103
112
  if (command === "providers" ||
104
113
  command === "validate" ||
105
114
  command === "graph" ||
115
+ command === "a2a" ||
106
116
  command === "migrate-yaml" ||
107
117
  command === "run" ||
118
+ command === "run-stage" ||
108
119
  command === "init" ||
109
120
  command === "artifact" ||
110
121
  command === "envelope" ||
@@ -282,6 +293,9 @@ async function main(argv) {
282
293
  return 0;
283
294
  }
284
295
  const ctx = await resolveStageflowContext(process.cwd());
296
+ if (parsed.command === "a2a") {
297
+ return runA2aCommand(argv.slice(3), { cwd: ctx.invocationCwd, projectRoot: ctx.projectRoot });
298
+ }
285
299
  if (parsed.command === "init") {
286
300
  return runInitCommand(argv.slice(3), { cwd: ctx.invocationCwd });
287
301
  }
@@ -306,8 +320,11 @@ async function main(argv) {
306
320
  if (parsed.command === "run") {
307
321
  return runRunCommand(argv.slice(3), {
308
322
  cwd: ctx.invocationCwd,
309
- projectRoot: ctx.projectRoot,
310
- isGitProject: ctx.isGitProject,
323
+ });
324
+ }
325
+ if (parsed.command === "run-stage") {
326
+ return runRunStageCommand(argv.slice(3), {
327
+ cwd: ctx.invocationCwd,
311
328
  });
312
329
  }
313
330
  if (parsed.command === "artifact") {
@@ -331,8 +348,6 @@ async function main(argv) {
331
348
  if (parsed.command === "runs") {
332
349
  return runRunsCommand(argv.slice(3), {
333
350
  cwd: ctx.invocationCwd,
334
- projectRoot: ctx.projectRoot,
335
- isGitProject: ctx.isGitProject,
336
351
  });
337
352
  }
338
353
  if (parsed.command === "providers") {
@@ -344,7 +359,7 @@ async function main(argv) {
344
359
  projectRoot: ctx.projectRoot,
345
360
  });
346
361
  }
347
- const store = createRunStore({ rootDir: ctx.projectRoot });
362
+ const store = createRunStore({ rootDir: ctx.globalHome });
348
363
  const globalAgent = globalAgentBackendFromManifest(ctx.manifest);
349
364
  if (parsed.command === "ui") {
350
365
  const mcpStateless = resolveMcpStateless({
@@ -0,0 +1,26 @@
1
+ import type { CloneMode, FeedbackLoopConfig, LoadedPipeline, PipelineForkConfig, PipelineNeedEdge, ResolvedPipelineStageNode, RouteIfPredicate } from "../types/pipeline.js";
2
+ import type { StageGateKind } from "../types/stage.js";
3
+ export type PipelineDescribeNeedEdge = {
4
+ id: string;
5
+ on: PipelineNeedEdge["on"];
6
+ if?: RouteIfPredicate;
7
+ };
8
+ export type PipelineDescribeNeeds = string | null | PipelineDescribeNeedEdge[];
9
+ export type PipelineDescribeStage = {
10
+ id: string;
11
+ needs: PipelineDescribeNeeds;
12
+ fork?: PipelineForkConfig;
13
+ gate_kinds?: StageGateKind[];
14
+ clone_cap?: number;
15
+ clone_mode?: CloneMode;
16
+ feedback_loop?: FeedbackLoopConfig;
17
+ entry?: boolean;
18
+ replay_safe?: boolean;
19
+ };
20
+ export type PipelineDescribe = {
21
+ id: string;
22
+ path: string;
23
+ stages: PipelineDescribeStage[];
24
+ };
25
+ export declare function describePipelineNeeds(node: ResolvedPipelineStageNode): PipelineDescribeNeeds;
26
+ export declare function describePipeline(loaded: LoadedPipeline): PipelineDescribe;
@@ -0,0 +1,37 @@
1
+ import { toPipelineNeeds } from "./pipelineNeeds.js";
2
+ export function describePipelineNeeds(node) {
3
+ if (node.needsEdges.length === 0)
4
+ return node.needs;
5
+ const collapsed = toPipelineNeeds(node.needsEdges);
6
+ if (typeof collapsed === "string")
7
+ return collapsed;
8
+ return collapsed.map((edge) => ({
9
+ id: edge.id,
10
+ on: [...edge.on],
11
+ ...(edge.if !== undefined ? { if: edge.if } : {}),
12
+ }));
13
+ }
14
+ export function describePipeline(loaded) {
15
+ const gateById = new Map(loaded.stages.map((stage) => [stage.id, stage.gate_kinds]));
16
+ const stages = loaded.dag.nodes.map((node) => {
17
+ const gateKinds = gateById.get(node.id);
18
+ return {
19
+ id: node.id,
20
+ needs: describePipelineNeeds(node),
21
+ ...(node.fork !== undefined ? { fork: { ...node.fork } } : {}),
22
+ ...(node.clone_cap !== undefined ? { clone_cap: node.clone_cap } : {}),
23
+ ...(node.clone_mode !== undefined ? { clone_mode: node.clone_mode } : {}),
24
+ ...(node.feedback_loop !== undefined
25
+ ? { feedback_loop: { ...node.feedback_loop } }
26
+ : {}),
27
+ ...(node.entry !== undefined ? { entry: node.entry } : {}),
28
+ ...(node.replay_safe !== undefined ? { replay_safe: node.replay_safe } : {}),
29
+ ...(gateKinds !== undefined ? { gate_kinds: [...gateKinds] } : {}),
30
+ };
31
+ });
32
+ return {
33
+ id: loaded.pipeline.id,
34
+ path: loaded.pipelinePath,
35
+ stages,
36
+ };
37
+ }
@@ -1,8 +1,20 @@
1
- import type { LoadedPipeline } from "../types/pipeline.js";
1
+ import type { InlinePipelineDefinition, LoadedPipeline } from "../types/pipeline.js";
2
2
  import { type LoadOutcome } from "./loadOutcome.js";
3
3
  export type { LoadedPipeline } from "../types/pipeline.js";
4
4
  export type { LoadIssue, LoadOutcome } from "./loadOutcome.js";
5
5
  export declare function resolvePipelinePath(pipelinePath: string, cwd: string): Promise<string>;
6
+ /** Synthetic `pipelinePath` for a `LoadedPipeline` built from an inline object with no backing file. */
7
+ export declare const INLINE_PIPELINE_PATH = "<inline>";
8
+ export declare function loadPipelineFromObjectOutcome(raw: InlinePipelineDefinition, options?: {
9
+ cwd?: string;
10
+ projectRoot?: string;
11
+ requireIo?: boolean;
12
+ }): Promise<LoadOutcome<LoadedPipeline>>;
13
+ export declare function loadPipelineFromObject(raw: InlinePipelineDefinition, options?: {
14
+ cwd?: string;
15
+ projectRoot?: string;
16
+ requireIo?: boolean;
17
+ }): Promise<LoadedPipeline>;
6
18
  export declare function loadPipelineOutcome(nameOrPath: string, options?: {
7
19
  cwd?: string;
8
20
  projectRoot?: string;
@@ -2,7 +2,7 @@ import { access } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { compilePayloadSchema, expandPayloadSchemaRefs, isPayloadSchemaSubset, UnresolvedSchemaRefError, } from "../envelope/payloadSchema.js";
4
4
  import { loadFailure, loadSuccess } from "./loadOutcome.js";
5
- import { mergePipelineStages } from "./mergePipelineIncludes.js";
5
+ import { mergeInlinePipelineStages, mergePipelineStages, } from "./mergePipelineIncludes.js";
6
6
  import { normalizePipelineStageEntries, toWiringRefs, } from "./normalizePipelineStageEntry.js";
7
7
  import { loadStageFromObjectOutcome, loadStageOutcome, afterCompletionForStage } from "./loadStage.js";
8
8
  import { materializeStageModels } from "./materializeStageModels.js";
@@ -92,14 +92,44 @@ export async function resolvePipelinePath(pipelinePath, cwd) {
92
92
  throw new Error(`Pipeline file not found: ${resolved}. Pass a filesystem path to --pipeline (e.g. pipelines/hello.pipeline.yaml), not a bare pipeline id.`);
93
93
  }
94
94
  }
95
+ /** Synthetic `pipelinePath` for a `LoadedPipeline` built from an inline object with no backing file. */
96
+ export const INLINE_PIPELINE_PATH = "<inline>";
95
97
  async function loadPipelineFromPath(pipelinePath, cwd, projectRoot = cwd, requireIo = true) {
96
98
  const normalizedPipelinePath = path.normalize(path.resolve(pipelinePath));
97
99
  const mergeOutcome = await mergePipelineStages(normalizedPipelinePath);
98
100
  if (!mergeOutcome.ok) {
99
101
  return loadFailure(mergeOutcome.issues);
100
102
  }
101
- const { entries: rawEntries, pipelineId, agent: pipelineAgent, model: pipelineModel, schemas: pipelineSchemas, warnings: mergeWarnings, } = mergeOutcome.value;
102
- const ctx = { pipelineId, path: normalizedPipelinePath };
103
+ return buildLoadedPipelineFromMerge(mergeOutcome.value, {
104
+ projectRoot,
105
+ requireIo,
106
+ pipelinePath: normalizedPipelinePath,
107
+ });
108
+ }
109
+ export async function loadPipelineFromObjectOutcome(raw, options = {}) {
110
+ const projectRoot = options.projectRoot ?? options.cwd ?? process.cwd();
111
+ const requireIo = options.requireIo !== false;
112
+ const mergeOutcome = await mergeInlinePipelineStages(raw);
113
+ if (!mergeOutcome.ok) {
114
+ return loadFailure(mergeOutcome.issues);
115
+ }
116
+ return buildLoadedPipelineFromMerge(mergeOutcome.value, {
117
+ projectRoot,
118
+ requireIo,
119
+ pipelinePath: INLINE_PIPELINE_PATH,
120
+ });
121
+ }
122
+ export async function loadPipelineFromObject(raw, options = {}) {
123
+ const outcome = await loadPipelineFromObjectOutcome(raw, options);
124
+ if (!outcome.ok) {
125
+ throw new Error(outcome.issues[0].message);
126
+ }
127
+ return outcome.value;
128
+ }
129
+ async function buildLoadedPipelineFromMerge(merge, options) {
130
+ const { projectRoot, requireIo, pipelinePath } = options;
131
+ const { entries: rawEntries, pipelineId, agent: pipelineAgent, model: pipelineModel, schemas: pipelineSchemas, warnings: mergeWarnings, } = merge;
132
+ const ctx = { pipelineId, path: pipelinePath };
103
133
  const warnings = [...mergeWarnings];
104
134
  const normalizeOutcome = normalizePipelineStageEntries(rawEntries, ctx);
105
135
  if (!normalizeOutcome.ok) {
@@ -274,7 +304,7 @@ async function loadPipelineFromPath(pipelinePath, cwd, projectRoot = cwd, requir
274
304
  pipeline,
275
305
  stages: loadedStages,
276
306
  dag,
277
- pipelinePath: normalizedPipelinePath,
307
+ pipelinePath,
278
308
  stageSources,
279
309
  }, warnings);
280
310
  }
@@ -1,4 +1,5 @@
1
1
  import type { PayloadSchemaMap } from "../envelope/payloadSchema.js";
2
+ import type { InlinePipelineDefinition } from "../types/pipeline.js";
2
3
  import { type LoadIssue, type LoadOutcome } from "./loadOutcome.js";
3
4
  export type RawMergedEntry = {
4
5
  raw: unknown;
@@ -12,3 +13,13 @@ export declare function mergePipelineStages(rootPath: string): Promise<LoadOutco
12
13
  schemas?: PayloadSchemaMap;
13
14
  warnings: LoadIssue[];
14
15
  }>>;
16
+ /** Synthetic `declaringPath` for stage entries with no backing file. */
17
+ export declare const INLINE_DECLARING_PATH = "<inline pipeline>";
18
+ export declare function mergeInlinePipelineStages(raw: InlinePipelineDefinition): Promise<LoadOutcome<{
19
+ entries: RawMergedEntry[];
20
+ pipelineId: string;
21
+ agent?: string;
22
+ model?: string;
23
+ schemas?: PayloadSchemaMap;
24
+ warnings: LoadIssue[];
25
+ }>>;
@@ -201,6 +201,81 @@ export async function mergePipelineStages(rootPath) {
201
201
  warnings,
202
202
  });
203
203
  }
204
+ /** Synthetic `declaringPath` for stage entries with no backing file. */
205
+ export const INLINE_DECLARING_PATH = "<inline pipeline>";
206
+ export async function mergeInlinePipelineStages(raw) {
207
+ if (typeof raw.id !== "string" || !raw.id) {
208
+ return loadFailure([
209
+ {
210
+ code: "pipeline.invalid_shape",
211
+ message: `Invalid inline pipeline: id is required`,
212
+ category: "pipeline",
213
+ },
214
+ ]);
215
+ }
216
+ if (!Array.isArray(raw.stages) || raw.stages.length === 0) {
217
+ return loadFailure([
218
+ {
219
+ code: "pipeline.invalid_shape",
220
+ message: `Invalid inline pipeline ${raw.id}: stages must be non-empty`,
221
+ category: "pipeline",
222
+ pipelineId: raw.id,
223
+ },
224
+ ]);
225
+ }
226
+ const pipelineId = raw.id;
227
+ const agentField = parseAgentField(raw.agent);
228
+ if (!agentField.ok) {
229
+ return loadFailure([
230
+ {
231
+ code: "pipeline.invalid_agent",
232
+ message: `Invalid inline pipeline ${pipelineId}: ${agentField.message}`,
233
+ category: "pipeline",
234
+ pipelineId,
235
+ },
236
+ ]);
237
+ }
238
+ const agent = agentField.value;
239
+ const modelField = parseModelField(raw.model);
240
+ if (!modelField.ok) {
241
+ return loadFailure([
242
+ {
243
+ code: "pipeline.invalid_model",
244
+ message: `Invalid inline pipeline ${pipelineId}: ${modelField.message}`,
245
+ category: "pipeline",
246
+ pipelineId,
247
+ },
248
+ ]);
249
+ }
250
+ const model = modelField.value;
251
+ const schemasOutcome = parsePipelineSchemas(raw.schemas, "<inline pipeline>", pipelineId);
252
+ if (!schemasOutcome.ok)
253
+ return schemasOutcome;
254
+ const schemas = schemasOutcome.value;
255
+ const entries = [];
256
+ for (let index = 0; index < raw.stages.length; index++) {
257
+ const entry = raw.stages[index];
258
+ if (isPlainObject(entry) && typeof entry.uses === "string") {
259
+ return loadFailure([
260
+ {
261
+ code: "pipeline.invalid_shape",
262
+ message: `Invalid inline pipeline ${pipelineId}: stage entry at index ${index} has "uses" — inline pipelines cannot reference external stage files, all stage bodies must be inline`,
263
+ category: "pipeline",
264
+ pipelineId,
265
+ },
266
+ ]);
267
+ }
268
+ entries.push({ raw: entry, declaringPath: INLINE_DECLARING_PATH });
269
+ }
270
+ return loadSuccess({
271
+ entries,
272
+ pipelineId,
273
+ ...(agent !== undefined ? { agent } : {}),
274
+ ...(model !== undefined ? { model } : {}),
275
+ ...(schemas !== undefined ? { schemas } : {}),
276
+ warnings: [],
277
+ });
278
+ }
204
279
  function parsePipelineSchemas(raw, absPath, pipelineId) {
205
280
  if (raw === undefined)
206
281
  return loadSuccess(undefined);
@@ -1,4 +1,4 @@
1
- import type { LoadedPipeline } from "../types/pipeline.js";
1
+ import type { InlinePipelineDefinition, LoadedPipeline } from "../types/pipeline.js";
2
2
  import type { LoadIssue } from "./loadOutcome.js";
3
3
  export type ValidationSeverity = "error" | "warning";
4
4
  export type ValidationCategory = "pipeline" | "stage" | "catalog" | "task";
@@ -50,7 +50,7 @@ export type LoadPipelineValidatedResult = {
50
50
  ok: false;
51
51
  findings: ValidationFinding[];
52
52
  };
53
- export declare function loadPipelineValidated(nameOrPath: string, options?: {
53
+ export declare function loadPipelineValidated(nameOrPath: string | InlinePipelineDefinition, options?: {
54
54
  cwd?: string;
55
55
  projectRoot?: string;
56
56
  validateStages?: boolean;
@@ -1,5 +1,5 @@
1
1
  import path from "node:path";
2
- import { loadPipelineOutcome, resolvePipelinePath } from "./loadPipeline.js";
2
+ import { INLINE_PIPELINE_PATH, loadPipelineFromObjectOutcome, loadPipelineOutcome, resolvePipelinePath, } from "./loadPipeline.js";
3
3
  import { loadStageOutcome } from "./loadStage.js";
4
4
  import { loadTaskOutcome } from "./loadTask.js";
5
5
  import { readYamlObject } from "./readYamlObject.js";
@@ -241,23 +241,30 @@ async function runPipelineValidation(nameOrPath, options) {
241
241
  const { cwd, validateStages } = options;
242
242
  const projectRoot = options.projectRoot ?? cwd;
243
243
  let pipelinePath;
244
- try {
245
- pipelinePath = await resolvePipelinePath(nameOrPath, cwd);
244
+ let outcome;
245
+ if (typeof nameOrPath === "string") {
246
+ try {
247
+ pipelinePath = await resolvePipelinePath(nameOrPath, cwd);
248
+ }
249
+ catch (err) {
250
+ const message = err instanceof Error ? err.message : String(err);
251
+ return {
252
+ ok: false,
253
+ findings: findingsFromLoadIssues(cwd, path.resolve(cwd, nameOrPath), [
254
+ {
255
+ code: "pipeline.load_error",
256
+ message,
257
+ category: "pipeline",
258
+ },
259
+ ]),
260
+ };
261
+ }
262
+ outcome = await loadPipelineOutcome(pipelinePath, { cwd, projectRoot });
263
+ }
264
+ else {
265
+ pipelinePath = path.resolve(cwd, INLINE_PIPELINE_PATH);
266
+ outcome = await loadPipelineFromObjectOutcome(nameOrPath, { cwd, projectRoot });
246
267
  }
247
- catch (err) {
248
- const message = err instanceof Error ? err.message : String(err);
249
- return {
250
- ok: false,
251
- findings: findingsFromLoadIssues(cwd, path.resolve(cwd, nameOrPath), [
252
- {
253
- code: "pipeline.load_error",
254
- message,
255
- category: "pipeline",
256
- },
257
- ]),
258
- };
259
- }
260
- const outcome = await loadPipelineOutcome(pipelinePath, { cwd, projectRoot });
261
268
  const findings = [];
262
269
  if (!outcome.ok) {
263
270
  findings.push(...findingsFromLoadIssues(cwd, pipelinePath, outcome.issues));