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.
Files changed (113) hide show
  1. package/README.md +158 -14
  2. package/dist/agent/activity.d.ts +10 -1
  3. package/dist/agent/activity.js +37 -2
  4. package/dist/agent/activityObserver.d.ts +5 -1
  5. package/dist/agent/activityObserver.js +174 -11
  6. package/dist/agent/fakeAgent.js +4 -0
  7. package/dist/agent/piAdapter.d.ts +16 -0
  8. package/dist/agent/piAdapter.js +88 -21
  9. package/dist/agent/port.d.ts +2 -0
  10. package/dist/agent/providerAuth.js +12 -7
  11. package/dist/catalog/displayCatalogPath.d.ts +12 -0
  12. package/dist/catalog/displayCatalogPath.js +28 -0
  13. package/dist/cli/initCommand.d.ts +9 -0
  14. package/dist/cli/initCommand.js +71 -0
  15. package/dist/cli/initTemplates.d.ts +3 -0
  16. package/dist/cli/initTemplates.js +19 -0
  17. package/dist/cli/operatorCatalog.d.ts +10 -0
  18. package/dist/cli/operatorCatalog.js +16 -0
  19. package/dist/cli/runCommand.d.ts +3 -1
  20. package/dist/cli/runCommand.js +48 -7
  21. package/dist/cli/validateCommand.d.ts +1 -1
  22. package/dist/cli/validateCommand.js +20 -3
  23. package/dist/cli.d.ts +1 -0
  24. package/dist/cli.js +52 -19
  25. package/dist/config/browseCatalog.d.ts +45 -0
  26. package/dist/config/browseCatalog.js +170 -0
  27. package/dist/config/createPipeline.d.ts +12 -3
  28. package/dist/config/createPipeline.js +292 -100
  29. package/dist/config/createStage.d.ts +10 -4
  30. package/dist/config/createStage.js +44 -14
  31. package/dist/config/listConfig.d.ts +14 -19
  32. package/dist/config/listConfig.js +26 -191
  33. package/dist/config/listModelsFromManifest.d.ts +2 -0
  34. package/dist/config/listModelsFromManifest.js +4 -0
  35. package/dist/config/loadOutcome.d.ts +4 -0
  36. package/dist/config/loadPipeline.d.ts +1 -15
  37. package/dist/config/loadPipeline.js +84 -142
  38. package/dist/config/loadStage.d.ts +4 -0
  39. package/dist/config/loadStage.js +60 -32
  40. package/dist/config/loadStageflowManifest.d.ts +5 -0
  41. package/dist/config/loadStageflowManifest.js +157 -0
  42. package/dist/config/mergePipelineIncludes.d.ts +9 -0
  43. package/dist/config/mergePipelineIncludes.js +141 -0
  44. package/dist/config/normalizePipelineStageEntry.d.ts +16 -0
  45. package/dist/config/normalizePipelineStageEntry.js +186 -0
  46. package/dist/config/pipelineStageKeys.d.ts +4 -0
  47. package/dist/config/pipelineStageKeys.js +14 -0
  48. package/dist/config/resolveCatalogContext.d.ts +13 -0
  49. package/dist/config/resolveCatalogContext.js +13 -0
  50. package/dist/config/resolveForkEmitContext.d.ts +3 -0
  51. package/dist/config/resolveForkEmitContext.js +12 -0
  52. package/dist/config/resolvePipelineDag.d.ts +5 -1
  53. package/dist/config/resolvePipelineDag.js +54 -36
  54. package/dist/config/scanCatalogPaths.d.ts +4 -0
  55. package/dist/config/scanCatalogPaths.js +83 -0
  56. package/dist/config/validateCatalog.d.ts +22 -4
  57. package/dist/config/validateCatalog.js +169 -132
  58. package/dist/envelope/check.js +7 -0
  59. package/dist/envelope/forkChoice.d.ts +3 -0
  60. package/dist/envelope/forkChoice.js +47 -0
  61. package/dist/index.d.ts +4 -0
  62. package/dist/index.js +4 -0
  63. package/dist/mcp/projectRun.d.ts +3 -0
  64. package/dist/mcp/projectRun.js +7 -0
  65. package/dist/mcp/tools.js +28 -11
  66. package/dist/project/findProjectRoot.d.ts +2 -0
  67. package/dist/project/findProjectRoot.js +51 -0
  68. package/dist/project/globalHome.d.ts +2 -0
  69. package/dist/project/globalHome.js +19 -0
  70. package/dist/project/resolveProjectContext.d.ts +9 -0
  71. package/dist/project/resolveProjectContext.js +38 -0
  72. package/dist/project/resolveStageflowContext.d.ts +11 -0
  73. package/dist/project/resolveStageflowContext.js +66 -0
  74. package/dist/runstore/normalizeCatalogPath.d.ts +1 -0
  75. package/dist/runstore/normalizeCatalogPath.js +4 -0
  76. package/dist/runstore/port.d.ts +9 -0
  77. package/dist/runstore/runProjection.js +11 -1
  78. package/dist/runstore/sqlite/SqliteRunStore.js +30 -4
  79. package/dist/runstore/sqlite/schema.d.ts +1 -1
  80. package/dist/runstore/sqlite/schema.js +4 -1
  81. package/dist/runtime/credentialBinding.d.ts +8 -6
  82. package/dist/runtime/credentialBinding.js +18 -24
  83. package/dist/runtime/pipelineRunner.d.ts +3 -0
  84. package/dist/runtime/pipelineRunner.js +15 -1
  85. package/dist/runtime/pipelineScheduler.d.ts +2 -0
  86. package/dist/runtime/pipelineScheduler.js +51 -11
  87. package/dist/runtime/reloadRunCatalog.d.ts +5 -0
  88. package/dist/runtime/reloadRunCatalog.js +44 -0
  89. package/dist/runtime/resumeReconstruct.d.ts +1 -0
  90. package/dist/runtime/resumeReconstruct.js +23 -7
  91. package/dist/runtime/runManager.d.ts +4 -0
  92. package/dist/runtime/runManager.js +36 -16
  93. package/dist/runtime/settingsFile.d.ts +12 -0
  94. package/dist/runtime/settingsFile.js +87 -6
  95. package/dist/runtime/stageAttemptBootstrap.js +3 -0
  96. package/dist/runtime/stageProcessLauncher.js +3 -0
  97. package/dist/runtime/stageRecovery.js +3 -1
  98. package/dist/runtime/stageWorker.js +2 -6
  99. package/dist/server/http.js +33 -9
  100. package/dist/tools/emitStageEnvelope.d.ts +3 -1
  101. package/dist/tools/emitStageEnvelope.js +11 -1
  102. package/dist/types/envelope.d.ts +1 -0
  103. package/dist/types/forkChoice.d.ts +8 -0
  104. package/dist/types/forkChoice.js +1 -0
  105. package/dist/types/pipeline.d.ts +51 -2
  106. package/dist/types/stageflowManifest.d.ts +23 -0
  107. package/dist/types/stageflowManifest.js +1 -0
  108. package/dist/ui/assets/index-CFSzDZje.js +118 -0
  109. package/dist/ui/assets/{index-DCsDopak.css → index-DefBlEvN.css} +1 -1
  110. package/dist/ui/index.html +3 -2
  111. package/dist/ui/stageflow-icon.svg +12 -0
  112. package/package.json +7 -5
  113. package/dist/ui/assets/index-Cry0Tpfx.js +0 -118
@@ -0,0 +1,14 @@
1
+ export const WIRING_KEYS = new Set(["id", "needs", "fork", "uses"]);
2
+ export const BODY_KEYS = new Set([
3
+ "system_prompt",
4
+ "model",
5
+ "payload_schema",
6
+ "gate_kinds",
7
+ "skill",
8
+ ]);
9
+ export function isPipelineStageBodyKey(key) {
10
+ return BODY_KEYS.has(key);
11
+ }
12
+ export function isAllowedPipelineStageEntryKey(key) {
13
+ return WIRING_KEYS.has(key) || BODY_KEYS.has(key);
14
+ }
@@ -0,0 +1,13 @@
1
+ import type { LoadedManifest } from "../types/stageflowManifest.js";
2
+ import type { LoadIssue } from "./loadOutcome.js";
3
+ import { type CatalogManifestStatus, type StageflowContext } from "../project/resolveStageflowContext.js";
4
+ export type { CatalogManifestStatus };
5
+ export type CatalogContext = {
6
+ projectRoot: string | null;
7
+ manifest: LoadedManifest | null;
8
+ manifestStatus: CatalogManifestStatus;
9
+ issues: LoadIssue[];
10
+ };
11
+ export declare function catalogContextFromStageflow(ctx: StageflowContext): CatalogContext;
12
+ /** @deprecated Prefer resolveStageflowContext */
13
+ export declare function resolveCatalogContext(invocationCwd: string): Promise<CatalogContext>;
@@ -0,0 +1,13 @@
1
+ import { resolveStageflowContext, } from "../project/resolveStageflowContext.js";
2
+ export function catalogContextFromStageflow(ctx) {
3
+ return {
4
+ projectRoot: ctx.isGitProject ? ctx.projectRoot : null,
5
+ manifest: ctx.manifest,
6
+ manifestStatus: ctx.manifestStatus,
7
+ issues: ctx.manifestIssues,
8
+ };
9
+ }
10
+ /** @deprecated Prefer resolveStageflowContext */
11
+ export async function resolveCatalogContext(invocationCwd) {
12
+ return catalogContextFromStageflow(await resolveStageflowContext(invocationCwd));
13
+ }
@@ -0,0 +1,3 @@
1
+ import type { ForkEmitContext } from "../types/forkChoice.js";
2
+ import type { ResolvedPipelineDag } from "../types/pipeline.js";
3
+ export declare function resolveForkEmitContext(dag: ResolvedPipelineDag, stageId: string): ForkEmitContext | undefined;
@@ -0,0 +1,12 @@
1
+ export function resolveForkEmitContext(dag, stageId) {
2
+ const dagNode = dag.nodes.find((n) => n.id === stageId);
3
+ if (!dagNode?.fork)
4
+ return undefined;
5
+ return {
6
+ immediateSuccessorIds: dag.childrenOf[stageId] ?? [],
7
+ forkShape: {
8
+ cardinality: dagNode.fork.select,
9
+ allowNone: dagNode.fork.allow_none,
10
+ },
11
+ };
12
+ }
@@ -1,9 +1,13 @@
1
- import type { PipelineStageYamlEntry, ResolvedPipelineDag } from "../types/pipeline.js";
1
+ import type { PipelineStageRef, PipelineStageYamlEntry, ResolvedPipelineDag } from "../types/pipeline.js";
2
2
  export type ResolvePipelineDagContext = {
3
3
  pipelineId: string;
4
4
  path: string;
5
5
  };
6
6
  export declare function parsePipelineStageEntries(raw: unknown, ctx: ResolvePipelineDagContext): PipelineStageYamlEntry[];
7
+ export declare function resolvePipelineDagFromRefs(refs: PipelineStageRef[], ctx: ResolvePipelineDagContext): {
8
+ stages: string[];
9
+ dag: ResolvedPipelineDag;
10
+ };
7
11
  export declare function resolvePipelineDag(rawStages: unknown, ctx: ResolvePipelineDagContext): {
8
12
  stages: string[];
9
13
  dag: ResolvedPipelineDag;
@@ -1,4 +1,5 @@
1
- const ALLOWED_STAGE_REF_KEYS = new Set(["id", "needs"]);
1
+ import { isAllowedPipelineStageEntryKey } from "./pipelineStageKeys.js";
2
+ const ALLOWED_FORK_KEYS = new Set(["select", "allow_none"]);
2
3
  function pipelineLabel(ctx) {
3
4
  return `Pipeline ${ctx.pipelineId} (${ctx.path})`;
4
5
  }
@@ -19,26 +20,37 @@ export function parsePipelineStageEntries(raw, ctx) {
19
20
  for (let index = 0; index < raw.length; index++) {
20
21
  const entry = raw[index];
21
22
  if (typeof entry === "string") {
22
- if (!entry) {
23
- throw new Error(formatError(ctx, `invalid stage entry at index ${index}: stage id must be a non-empty string`));
24
- }
25
- entries.push(entry);
26
- continue;
23
+ const hint = entry
24
+ ? `invalid stage entry at index ${index}: bare string stage refs are not supported; use { id: "${entry}", uses: "./${entry}.yaml" } or inline body`
25
+ : `invalid stage entry at index ${index}: bare string stage refs are not supported; use { id: "…", uses: "./….yaml" } or inline body`;
26
+ throw new Error(formatError(ctx, hint));
27
27
  }
28
28
  if (!isPlainObject(entry)) {
29
29
  throw new Error(formatError(ctx, `invalid stage entry at index ${index}`));
30
30
  }
31
31
  const keys = Object.keys(entry);
32
32
  for (const key of keys) {
33
- if (!ALLOWED_STAGE_REF_KEYS.has(key)) {
33
+ if (!isAllowedPipelineStageEntryKey(key)) {
34
34
  throw new Error(formatError(ctx, `invalid stage entry "${String(entry.id ?? index)}": unknown key "${key}"`));
35
35
  }
36
36
  }
37
37
  if (typeof entry.id !== "string" || !entry.id) {
38
38
  throw new Error(formatError(ctx, `invalid stage entry at index ${index}: id must be a non-empty string`));
39
39
  }
40
+ let forkValue;
41
+ if (entry.fork !== undefined) {
42
+ if (!isPlainObject(entry.fork)) {
43
+ throw new Error(formatError(ctx, `stage "${entry.id}": fork must be an object`));
44
+ }
45
+ for (const fk of Object.keys(entry.fork)) {
46
+ if (!ALLOWED_FORK_KEYS.has(fk)) {
47
+ throw new Error(formatError(ctx, `stage "${entry.id}": fork: unknown key "${fk}"`));
48
+ }
49
+ }
50
+ forkValue = entry.fork;
51
+ }
40
52
  if (entry.needs === undefined) {
41
- entries.push({ id: entry.id });
53
+ entries.push(forkValue !== undefined ? { id: entry.id, fork: forkValue } : { id: entry.id });
42
54
  continue;
43
55
  }
44
56
  if (Array.isArray(entry.needs)) {
@@ -50,29 +62,19 @@ export function parsePipelineStageEntries(raw, ctx) {
50
62
  if (typeof entry.needs !== "string" || !entry.needs) {
51
63
  throw new Error(formatError(ctx, `stage "${entry.id}": needs must be a non-empty string`));
52
64
  }
53
- entries.push({ id: entry.id, needs: entry.needs });
65
+ entries.push(forkValue !== undefined
66
+ ? { id: entry.id, needs: entry.needs, fork: forkValue }
67
+ : { id: entry.id, needs: entry.needs });
54
68
  }
55
69
  return entries;
56
70
  }
57
71
  function normalizeToEdges(entries) {
58
- const edges = [];
59
- for (let index = 0; index < entries.length; index++) {
60
- const entry = entries[index];
61
- if (typeof entry === "string") {
62
- edges.push({
63
- id: entry,
64
- needs: index > 0 ? entries[index - 1] : null,
65
- stageIndex: index,
66
- });
67
- continue;
68
- }
69
- edges.push({
70
- id: entry.id,
71
- needs: entry.needs ?? null,
72
- stageIndex: index,
73
- });
74
- }
75
- return edges;
72
+ return entries.map((entry, index) => ({
73
+ id: entry.id,
74
+ needs: entry.needs ?? null,
75
+ stageIndex: index,
76
+ ...(entry.fork !== undefined ? { fork: entry.fork } : {}),
77
+ }));
76
78
  }
77
79
  function detectDuplicateIds(edges, ctx) {
78
80
  const seen = new Set();
@@ -160,7 +162,7 @@ function topologicalSort(edges) {
160
162
  indegree.set(edge.id, (indegree.get(edge.id) ?? 0) + 1);
161
163
  children.get(edge.needs)?.push(edge.id);
162
164
  }
163
- for (const [parent, childIds] of children) {
165
+ for (const [, childIds] of children) {
164
166
  childIds.sort((a, b) => (byId.get(a)?.stageIndex ?? 0) - (byId.get(b)?.stageIndex ?? 0));
165
167
  }
166
168
  const roots = edges
@@ -208,12 +210,26 @@ function buildResolvedPipelineDag(edges) {
208
210
  needs: edge.needs,
209
211
  ancestors: ancestorsById.get(edge.id) ?? [],
210
212
  stageIndex: edge.stageIndex,
213
+ ...(edge.fork !== undefined
214
+ ? { fork: { select: edge.fork.select, allow_none: edge.fork.allow_none ?? false } }
215
+ : {}),
211
216
  }));
212
217
  return { nodes, roots, childrenOf };
213
218
  }
214
- export function resolvePipelineDag(rawStages, ctx) {
215
- const entries = parsePipelineStageEntries(rawStages, ctx);
216
- const edges = normalizeToEdges(entries);
219
+ function validateForkFields(edges, dag, ctx) {
220
+ for (const edge of edges) {
221
+ if (!edge.fork)
222
+ continue;
223
+ if (edge.fork.select !== "one" && edge.fork.select !== "subset") {
224
+ throw new Error(formatError(ctx, `stage "${edge.id}": fork.select must be "one" or "subset"${edge.fork.select === undefined ? " (missing)" : `, got "${String(edge.fork.select)}"`}`));
225
+ }
226
+ if ((dag.childrenOf[edge.id] ?? []).length === 0) {
227
+ throw new Error(formatError(ctx, `fork on stage "${edge.id}": no children in the DAG`));
228
+ }
229
+ }
230
+ }
231
+ export function resolvePipelineDagFromRefs(refs, ctx) {
232
+ const edges = normalizeToEdges(refs);
217
233
  detectDuplicateIds(edges, ctx);
218
234
  validateNeedsTargets(edges, ctx);
219
235
  detectCycle(edges, ctx);
@@ -222,8 +238,13 @@ export function resolvePipelineDag(rawStages, ctx) {
222
238
  .sort((a, b) => a.stageIndex - b.stageIndex)
223
239
  .map((edge) => edge.id);
224
240
  const dag = buildResolvedPipelineDag(edges);
241
+ validateForkFields(edges, dag, ctx);
225
242
  return { stages, dag };
226
243
  }
244
+ export function resolvePipelineDag(rawStages, ctx) {
245
+ const entries = parsePipelineStageEntries(rawStages, ctx);
246
+ return resolvePipelineDagFromRefs(entries, ctx);
247
+ }
227
248
  export function areResolvedDagsEquivalent(a, b) {
228
249
  const nodeIdsA = new Set(a.nodes.map((node) => node.id));
229
250
  const nodeIdsB = new Set(b.nodes.map((node) => node.id));
@@ -256,16 +277,13 @@ export function extractPipelineStageIds(rawStages) {
256
277
  const stageIds = [];
257
278
  for (const entry of rawStages) {
258
279
  if (typeof entry === "string") {
259
- if (!entry)
260
- return null;
261
- stageIds.push(entry);
262
- continue;
280
+ return null;
263
281
  }
264
282
  if (!isPlainObject(entry))
265
283
  return null;
266
284
  const keys = Object.keys(entry);
267
285
  for (const key of keys) {
268
- if (!ALLOWED_STAGE_REF_KEYS.has(key))
286
+ if (!isAllowedPipelineStageEntryKey(key))
269
287
  return null;
270
288
  }
271
289
  if (typeof entry.id !== "string" || !entry.id)
@@ -0,0 +1,4 @@
1
+ import type { LoadedManifest } from "../types/stageflowManifest.js";
2
+ export type CatalogPathKind = "pipeline" | "task";
3
+ export declare function isExcluded(repoRelPath: string, exclude: string[] | undefined): boolean;
4
+ export declare function scanCatalogPaths(manifest: LoadedManifest, kind: CatalogPathKind): Promise<string[]>;
@@ -0,0 +1,83 @@
1
+ import { readdir, stat } from "node:fs/promises";
2
+ import path from "node:path";
3
+ function normalizeRepoRel(repoRelPath) {
4
+ return repoRelPath.replace(/\\/g, "/").replace(/^\.\/+/, "");
5
+ }
6
+ export function isExcluded(repoRelPath, exclude) {
7
+ if (!exclude || exclude.length === 0) {
8
+ return false;
9
+ }
10
+ const normalized = normalizeRepoRel(repoRelPath);
11
+ for (const entry of exclude) {
12
+ const prefix = normalizeRepoRel(entry);
13
+ if (normalized === prefix || normalized.startsWith(`${prefix}/`)) {
14
+ return true;
15
+ }
16
+ }
17
+ return false;
18
+ }
19
+ function globPatternToRegExp(pattern) {
20
+ const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
21
+ return new RegExp(`^${escaped}$`);
22
+ }
23
+ function matchesPattern(basename, pattern) {
24
+ return globPatternToRegExp(pattern).test(basename);
25
+ }
26
+ async function walkDirectory(absDir) {
27
+ const files = [];
28
+ let entries;
29
+ try {
30
+ entries = await readdir(absDir, { withFileTypes: true, recursive: true });
31
+ }
32
+ catch {
33
+ return files;
34
+ }
35
+ for (const entry of entries) {
36
+ if (!entry.isFile())
37
+ continue;
38
+ const parentDir = entry.parentPath ?? absDir;
39
+ files.push(path.join(parentDir, entry.name));
40
+ }
41
+ return files;
42
+ }
43
+ async function expandCatalogEntry(projectRoot, entry, kind, pattern) {
44
+ const absPath = path.join(projectRoot, entry);
45
+ let entryStat;
46
+ try {
47
+ entryStat = await stat(absPath);
48
+ }
49
+ catch {
50
+ return [];
51
+ }
52
+ if (entryStat.isFile()) {
53
+ return [absPath];
54
+ }
55
+ if (!entryStat.isDirectory()) {
56
+ return [];
57
+ }
58
+ const files = await walkDirectory(absPath);
59
+ return files.filter((filePath) => matchesPattern(path.basename(filePath), pattern));
60
+ }
61
+ export async function scanCatalogPaths(manifest, kind) {
62
+ const { projectRoot, manifest: doc, patterns } = manifest;
63
+ const entries = kind === "pipeline" ? doc.catalog.pipelines : doc.catalog.tasks;
64
+ const pattern = kind === "pipeline" ? patterns.pipeline : patterns.task;
65
+ const exclude = doc.catalog.exclude;
66
+ const seen = new Set();
67
+ const resolved = [];
68
+ for (const entry of entries) {
69
+ const absPaths = await expandCatalogEntry(projectRoot, entry, kind, pattern);
70
+ for (const absPath of absPaths) {
71
+ const normalized = path.resolve(absPath);
72
+ if (seen.has(normalized))
73
+ continue;
74
+ const repoRel = normalizeRepoRel(path.relative(projectRoot, normalized));
75
+ if (isExcluded(repoRel, exclude))
76
+ continue;
77
+ seen.add(normalized);
78
+ resolved.push(normalized);
79
+ }
80
+ }
81
+ resolved.sort((a, b) => a.localeCompare(b));
82
+ return resolved;
83
+ }
@@ -1,7 +1,8 @@
1
+ import type { LoadedPipeline } from "../types/pipeline.js";
1
2
  import type { LoadIssue } from "./loadOutcome.js";
2
3
  export type ValidationSeverity = "error" | "warning";
3
- export type ValidationCategory = "pipeline" | "stage" | "catalog";
4
- export type ValidationFindingCode = "pipeline.invalid_shape" | "pipeline.dag_error" | "pipeline.missing_stage" | "pipeline.load_error" | "stage.invalid_shape" | "stage.invalid_payload_schema" | "stage.invalid_gate_kinds" | "stage.invalid_skill" | "stage.load_error" | "stage.id_filename_mismatch" | "catalog.duplicate_pipeline_id" | "catalog.orphan_stage";
4
+ export type ValidationCategory = "pipeline" | "stage" | "catalog" | "task";
5
+ export type ValidationFindingCode = "pipeline.invalid_shape" | "pipeline.dag_error" | "pipeline.missing_stage" | "pipeline.load_error" | "pipeline.string_stage_ref" | "pipeline.stage_uses_inline_conflict" | "pipeline.stage_missing_body" | "pipeline.stage_id_mismatch" | "pipeline.include_cycle" | "pipeline.include_invalid" | "pipeline.include_duplicate_stage" | "stage.invalid_shape" | "stage.invalid_payload_schema" | "stage.invalid_gate_kinds" | "stage.invalid_skill" | "stage.load_error" | "stage.id_filename_mismatch" | "task.invalid_shape" | "task.load_error" | "catalog.duplicate_pipeline_id" | "catalog.manifest_missing" | "catalog.manifest_invalid" | "catalog.empty_catalog" | "catalog.manifest_load_error";
5
6
  export type ValidationFinding = {
6
7
  severity: ValidationSeverity;
7
8
  code: ValidationFindingCode | string;
@@ -11,12 +12,12 @@ export type ValidationFinding = {
11
12
  pipelineId?: string;
12
13
  stageId?: string;
13
14
  };
14
- export type ValidationScope = "full" | "pipeline";
15
+ export type ValidationScope = "full" | "pipeline" | "task";
15
16
  export type ValidateCatalogOptions = {
16
17
  cwd?: string;
17
- stagesDir?: string;
18
18
  scope: ValidationScope;
19
19
  pipeline?: string;
20
+ task?: string;
20
21
  strict?: boolean;
21
22
  };
22
23
  export type ValidationResult = {
@@ -33,4 +34,21 @@ export declare function effectiveSeverity(finding: ValidationFinding, strict: bo
33
34
  export declare function buildValidationResult(scope: ValidationScope, findings: ValidationFinding[], strict: boolean): ValidationResult;
34
35
  export declare function findingsFromLoadIssues(cwd: string, absPath: string, issues: LoadIssue[]): ValidationFinding[];
35
36
  export declare function findingStageIdFilenameMismatch(cwd: string, absPath: string, fileStem: string, declaredId: string): ValidationFinding;
37
+ export type ValidatePipelineOptions = {
38
+ cwd?: string;
39
+ validateStages?: boolean;
40
+ strict?: boolean;
41
+ };
42
+ export declare function validatePipeline(nameOrPath: string, options?: ValidatePipelineOptions): Promise<ValidationResult>;
43
+ export type LoadPipelineValidatedResult = {
44
+ ok: true;
45
+ loaded: LoadedPipeline;
46
+ } | {
47
+ ok: false;
48
+ findings: ValidationFinding[];
49
+ };
50
+ export declare function loadPipelineValidated(nameOrPath: string, options?: {
51
+ cwd?: string;
52
+ validateStages?: boolean;
53
+ }): Promise<LoadPipelineValidatedResult>;
36
54
  export declare function validateCatalog(options: ValidateCatalogOptions): Promise<ValidationResult>;