stageflow 0.13.0 → 0.15.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 (97) hide show
  1. package/dist/agent/piAdapter.js +5 -2
  2. package/dist/agent/port.d.ts +2 -2
  3. package/dist/cli/initTemplates.d.ts +1 -1
  4. package/dist/cli/initTemplates.js +1 -1
  5. package/dist/cli/migrateYamlCommand.d.ts +18 -0
  6. package/dist/cli/migrateYamlCommand.js +180 -0
  7. package/dist/cli/runOutput.js +26 -18
  8. package/dist/cli/validateCommand.d.ts +1 -0
  9. package/dist/cli/validateCommand.js +2 -0
  10. package/dist/cli.js +15 -1
  11. package/dist/config/browseCatalog.js +1 -1
  12. package/dist/config/createPipeline.d.ts +1 -1
  13. package/dist/config/createPipeline.js +23 -11
  14. package/dist/config/createStage.d.ts +1 -1
  15. package/dist/config/createStage.js +10 -5
  16. package/dist/config/legacyYaml.d.ts +28 -0
  17. package/dist/config/legacyYaml.js +98 -0
  18. package/dist/config/loadOutcome.d.ts +2 -1
  19. package/dist/config/loadOutcome.js +4 -1
  20. package/dist/config/loadPipeline.d.ts +2 -0
  21. package/dist/config/loadPipeline.js +150 -8
  22. package/dist/config/loadStage.d.ts +8 -1
  23. package/dist/config/loadStage.js +138 -29
  24. package/dist/config/loadStageflowManifest.js +10 -0
  25. package/dist/config/loadTask.js +14 -0
  26. package/dist/config/materializeStageModels.d.ts +7 -0
  27. package/dist/config/materializeStageModels.js +35 -0
  28. package/dist/config/mergePipelineIncludes.d.ts +5 -1
  29. package/dist/config/mergePipelineIncludes.js +82 -4
  30. package/dist/config/migrateYaml.d.ts +19 -0
  31. package/dist/config/migrateYaml.js +627 -0
  32. package/dist/config/modelField.d.ts +13 -0
  33. package/dist/config/modelField.js +16 -0
  34. package/dist/config/normalizePipelineStageEntry.js +41 -2
  35. package/dist/config/parseCompletionContract.d.ts +5 -2
  36. package/dist/config/parseCompletionContract.js +16 -3
  37. package/dist/config/parsePreEmitChecks.js +4 -0
  38. package/dist/config/pipelineNeeds.js +3 -3
  39. package/dist/config/pipelineStageKeys.d.ts +11 -0
  40. package/dist/config/pipelineStageKeys.js +14 -0
  41. package/dist/config/printTargetYaml.d.ts +28 -0
  42. package/dist/config/printTargetYaml.js +243 -0
  43. package/dist/config/resolveModel.d.ts +20 -0
  44. package/dist/config/resolveModel.js +35 -0
  45. package/dist/config/validateCatalog.d.ts +5 -1
  46. package/dist/config/validateCatalog.js +36 -6
  47. package/dist/config/validateCompletionContract.js +5 -0
  48. package/dist/config/yamlDialect.d.ts +29 -0
  49. package/dist/config/yamlDialect.js +327 -0
  50. package/dist/envelope/payloadSchema.d.ts +37 -5
  51. package/dist/envelope/payloadSchema.js +272 -22
  52. package/dist/mcp/catalogTools.js +1 -0
  53. package/dist/package-meta.d.ts +1 -1
  54. package/dist/package-meta.js +1 -1
  55. package/dist/runstore/pipelineDagSnapshot.js +2 -0
  56. package/dist/runstore/port.d.ts +1 -0
  57. package/dist/runtime/completionCheckRunner.d.ts +3 -2
  58. package/dist/runtime/completionCheckRunner.js +3 -2
  59. package/dist/runtime/envelopeRouting.d.ts +2 -2
  60. package/dist/runtime/pipelineRunner.d.ts +3 -0
  61. package/dist/runtime/pipelineRunner.js +23 -3
  62. package/dist/runtime/runManager.js +3 -2
  63. package/dist/runtime/stageAttemptBootstrap.d.ts +2 -2
  64. package/dist/runtime/stageRunner.d.ts +2 -2
  65. package/dist/runtime/taskInput.d.ts +7 -0
  66. package/dist/runtime/taskInput.js +60 -0
  67. package/dist/runtime/verifiedStageExecution.js +3 -0
  68. package/dist/types/completion.d.ts +6 -0
  69. package/dist/types/pipeline.d.ts +21 -2
  70. package/dist/types/preEmitCheck.d.ts +4 -6
  71. package/dist/types/stage.d.ts +22 -3
  72. package/dist/types/stageflowManifest.d.ts +2 -0
  73. package/dist/types/task.d.ts +1 -0
  74. package/dist/ui/assets/{index-Yzh42vhf.js → index-GtyiWiZg.js} +1 -1
  75. package/dist/ui/index.html +1 -1
  76. package/package.json +1 -1
  77. package/skills/stageflow-author/SKILL.md +7 -7
  78. package/skills/stageflow-author/assets/examples/branch-decision/hotfix.yaml +9 -1
  79. package/skills/stageflow-author/assets/examples/branch-decision/release-gate.pipeline.yaml +6 -2
  80. package/skills/stageflow-author/assets/examples/branch-decision/run-tests.yaml +9 -1
  81. package/skills/stageflow-author/assets/examples/branch-decision/ship.yaml +16 -1
  82. package/skills/stageflow-author/assets/examples/linear-review/draft.yaml +12 -2
  83. package/skills/stageflow-author/assets/examples/linear-review/publish.yaml +16 -1
  84. package/skills/stageflow-author/assets/examples/linear-review/review-loop.pipeline.yaml +11 -2
  85. package/skills/stageflow-author/assets/examples/linear-review/review.yaml +19 -1
  86. package/skills/stageflow-author/assets/examples/non-sdlc-digest/gather.yaml +9 -1
  87. package/skills/stageflow-author/assets/examples/non-sdlc-digest/research-digest.pipeline.yaml +6 -2
  88. package/skills/stageflow-author/assets/examples/non-sdlc-digest/send.yaml +16 -1
  89. package/skills/stageflow-author/assets/examples/non-sdlc-digest/summarize.yaml +9 -1
  90. package/skills/stageflow-author/references/catalog-mapping.md +30 -28
  91. package/skills/stageflow-author/references/catalog-write-conventions.md +2 -2
  92. package/skills/stageflow-author/references/stage-prompt-template.md +5 -5
  93. package/skills/stageflow-session-capture/SKILL.md +1 -1
  94. package/skills/stageflow-session-capture/assets/example-pipeline/example.pipeline.yaml +2 -1
  95. package/skills/stageflow-session-capture/assets/example-pipeline/implement.yaml +13 -2
  96. package/skills/stageflow-session-capture/assets/example-pipeline/research.yaml +18 -2
  97. package/skills/stageflow-session-capture/references/catalog-authoring.md +2 -2
@@ -1,5 +1,8 @@
1
+ import path from "node:path";
1
2
  import { stringify as stringifyYaml } from "yaml";
2
3
  import { parseTaskFile } from "../config/loadTask.js";
4
+ import { relPath } from "../config/validateCatalog.js";
5
+ import { payloadInstanceMismatch } from "../envelope/payloadSchema.js";
3
6
  import { resolveTaskPath } from "./pipelineRunner.js";
4
7
  export function isTaskFile(value) {
5
8
  return parseTaskFile(value, "task").ok;
@@ -15,8 +18,65 @@ export function taskFileToYaml(task) {
15
18
  doc.constraints = task.constraints;
16
19
  if (task.checkout !== undefined)
17
20
  doc.checkout = task.checkout;
21
+ if (task.input !== undefined)
22
+ doc.input = task.input;
18
23
  return stringifyYaml(doc);
19
24
  }
25
+ /** Validate optional `task.input` against entry-stage IR `clone_input_schema` (YAML: `io.input.schema`). */
26
+ export function checkTaskEntryInput(task, loaded, options) {
27
+ const absPath = options.taskPath
28
+ ? path.resolve(options.cwd, options.taskPath)
29
+ : path.resolve(options.cwd, "task.yaml");
30
+ const findingPath = relPath(options.cwd, absPath);
31
+ const stageById = new Map(loaded.stages.map((stage) => [stage.id, stage]));
32
+ const findings = [];
33
+ for (const rootId of loaded.dag.roots) {
34
+ const stage = stageById.get(rootId);
35
+ if (stage?.clone_input_schema === undefined)
36
+ continue;
37
+ if (task.input === undefined) {
38
+ findings.push({
39
+ severity: "warning",
40
+ code: "task.entry_input_unmet",
41
+ path: findingPath,
42
+ message: `Task has no input; entry stage "${rootId}" requires io.input`,
43
+ category: "task",
44
+ pipelineId: loaded.pipeline.id,
45
+ stageId: rootId,
46
+ });
47
+ continue;
48
+ }
49
+ let details;
50
+ try {
51
+ details = payloadInstanceMismatch(task.input, stage.clone_input_schema);
52
+ }
53
+ catch (err) {
54
+ const message = err instanceof Error ? err.message : String(err);
55
+ findings.push({
56
+ severity: "error",
57
+ code: "task.invalid_shape",
58
+ path: findingPath,
59
+ message: `Task input does not match entry stage "${rootId}" io.input: ${message}`,
60
+ category: "task",
61
+ pipelineId: loaded.pipeline.id,
62
+ stageId: rootId,
63
+ });
64
+ continue;
65
+ }
66
+ if (details !== undefined) {
67
+ findings.push({
68
+ severity: "error",
69
+ code: "task.invalid_shape",
70
+ path: findingPath,
71
+ message: `Task input does not match entry stage "${rootId}" io.input: ${details}`,
72
+ category: "task",
73
+ pipelineId: loaded.pipeline.id,
74
+ stageId: rootId,
75
+ });
76
+ }
77
+ }
78
+ return findings;
79
+ }
20
80
  export function resolveStartTaskInput(input, cwd) {
21
81
  if (typeof input.taskYaml === "string") {
22
82
  if (input.taskYaml.trim().length === 0) {
@@ -1,3 +1,6 @@
1
+ /**
2
+ * After-phase VSE. Runs IR `CompletionContract` (YAML: `verify` when after).
3
+ */
1
4
  import { mkdir, writeFile } from "node:fs/promises";
2
5
  import path from "node:path";
3
6
  import { listQaExchanges } from "../hitl/qaTrail.js";
@@ -1,5 +1,10 @@
1
1
  import type { StageGateKind } from "./stage.js";
2
2
  export declare const COMPLETION_VERIFICATION_FAILURE_PREFIX = "Completion verification failed:";
3
+ /**
4
+ * After-phase check IR (`DAG node.completion`). YAML: `verify` items whose
5
+ * `when` includes `after`. `type: payload_schema` here is a check kind (re-check
6
+ * the success payload after emit), not the old YAML authoring key.
7
+ */
3
8
  export type CompletionCheck = {
4
9
  id: string;
5
10
  type: "command";
@@ -31,6 +36,7 @@ export type CompletionContract = {
31
36
  mode: "all";
32
37
  checks: CompletionCheck[];
33
38
  };
39
+ /** IR recovery on the DAG node. YAML: `on_verify_fail`. */
34
40
  export type RecoveryPolicy = {
35
41
  mode: "repair";
36
42
  max_attempts: number;
@@ -1,11 +1,15 @@
1
1
  import type { CloneAction } from "./forkChoice.js";
2
- import type { StageConfig, StageGateKind } from "./stage.js";
2
+ import type { LoadedStageConfig, StageGateKind, StageIoYaml } from "./stage.js";
3
3
  import type { CompletionContract, RecoveryPolicy } from "./completion.js";
4
4
  export type PipelineConfig = {
5
5
  id: string;
6
6
  stages: string[];
7
7
  /** Selects the AgentPort backend for every stage in this pipeline; overrides the global default. */
8
8
  agent?: string;
9
+ /** Default LLM model id for every stage in this pipeline; overrides the global default. */
10
+ model?: string;
11
+ /** Pipeline-file `$ref` root (`#/schemas/<name>`). */
12
+ schemas?: Record<string, unknown>;
9
13
  };
10
14
  export type PipelineForkConfig = {
11
15
  select: "one" | "subset";
@@ -37,12 +41,20 @@ export type PipelineStageRef = {
37
41
  };
38
42
  clonable?: boolean;
39
43
  clone_cap?: number;
44
+ /** IR: after-phase checks. YAML: `verify` items whose `when` includes `after`. */
40
45
  completion?: CompletionContract;
46
+ /** IR: after-phase failure policy. YAML: `on_verify_fail`. */
41
47
  recovery?: RecoveryPolicy;
42
48
  feedback_loop?: FeedbackLoopConfig;
43
49
  /** Omitted means this stage is safe to include in a feedback replay. */
44
50
  replay_safe?: boolean;
45
51
  };
52
+ /**
53
+ * Pipeline YAML stage entry (both dialects). Target authoring is `io` / `verify`
54
+ * / `on_verify_fail`. The payload_schema / pre_emit_checks / completion /
55
+ * recovery keys are the legacy YAML dialect (and also the IR names after compile).
56
+ * New catalog fields: add target YAML keys here and compile them in yamlDialect.ts.
57
+ */
46
58
  export type PipelineStageYamlEntry = PipelineStageRef & {
47
59
  uses?: string;
48
60
  system_prompt?: string;
@@ -53,6 +65,10 @@ export type PipelineStageYamlEntry = PipelineStageRef & {
53
65
  clone_actions?: CloneAction[];
54
66
  skill?: string;
55
67
  mcp?: string[];
68
+ io?: StageIoYaml;
69
+ verify?: unknown;
70
+ on_verify_fail?: RecoveryPolicy;
71
+ pre_emit_checks?: unknown;
56
72
  };
57
73
  export type PipelineIncludeEntry = {
58
74
  local: string;
@@ -70,6 +86,7 @@ export type NormalizedPipelineStageEntry = {
70
86
  };
71
87
  clonable?: boolean;
72
88
  clone_cap?: number;
89
+ /** IR after compile. YAML `verify` after-phase / `on_verify_fail`. */
73
90
  completion?: CompletionContract;
74
91
  recovery?: RecoveryPolicy;
75
92
  feedback_loop?: FeedbackLoopConfig;
@@ -102,7 +119,9 @@ export type ResolvedPipelineStageNode = {
102
119
  clonable?: boolean;
103
120
  clone_cap?: number;
104
121
  definition_id?: string;
122
+ /** Persisted on pipeline_dag. YAML `verify` after-phase. */
105
123
  completion?: CompletionContract;
124
+ /** Persisted on pipeline_dag. YAML `on_verify_fail`. */
106
125
  recovery?: RecoveryPolicy;
107
126
  feedback_loop?: FeedbackLoopConfig;
108
127
  replay_safe?: boolean;
@@ -114,7 +133,7 @@ export type ResolvedPipelineDag = {
114
133
  };
115
134
  export type LoadedPipeline = {
116
135
  pipeline: PipelineConfig;
117
- stages: StageConfig[];
136
+ stages: LoadedStageConfig[];
118
137
  dag: ResolvedPipelineDag;
119
138
  pipelinePath: string;
120
139
  stageSources?: Record<string, PipelineStageSource>;
@@ -1,11 +1,9 @@
1
1
  import type { StageGateKind } from "./stage.js";
2
2
  /**
3
- * In-session checks `emit_stage_envelope` must satisfy this attempt before a
4
- * success emit is accepted. Distinct from `CompletionCheck`/`CompletionContract`
5
- * (`src/types/completion.ts`): those run post-hoc, after a candidate envelope
6
- * has already been captured, driven by the pipeline-wiring `completion` field.
7
- * `PreEmitCheck` runs synchronously inside the agent's own `emit_stage_envelope`
8
- * tool call, driven by the stage-body `pre_emit_checks` field.
3
+ * Emit-phase check IR (`StageConfig.pre_emit_checks`). YAML: `verify` items
4
+ * whose `when` includes `emit`. Distinct from after-phase `CompletionCheck`
5
+ * (`src/types/completion.ts`), which runs after a candidate envelope is captured.
6
+ * This runs inside `emit_stage_envelope` before success is accepted.
9
7
  */
10
8
  export type PreEmitCheck = {
11
9
  id: string;
@@ -2,16 +2,32 @@ import type { PreEmitCheck } from "./preEmitCheck.js";
2
2
  import type { CloneAction } from "./forkChoice.js";
3
3
  export declare const STAGE_GATE_KINDS: readonly ["free_text", "confirm", "multi_question", "artifact_backed"];
4
4
  export type StageGateKind = (typeof STAGE_GATE_KINDS)[number];
5
+ /** Target YAML `io:` block. Compiles onto StageConfig.payload_schema / clone_input_schema. */
6
+ export type StageIoYaml = {
7
+ input?: {
8
+ schema?: unknown;
9
+ };
10
+ output?: {
11
+ schema?: unknown;
12
+ };
13
+ };
14
+ /**
15
+ * Loaded stage IR. Field names are the runtime contract (emit, VSE, snapshots),
16
+ * not the catalog YAML spelling. Target YAML `io` / `verify` compile onto these
17
+ * in `src/config/yamlDialect.ts`. Do not add new catalog keys here — add them on
18
+ * the YAML dialect and map them in compileTargetContract.
19
+ */
5
20
  export type StageConfig = {
6
21
  id: string;
7
22
  system_prompt: string;
8
- model: string;
9
- /** Optional JSON Schema (subset) for envelope.payload on success. */
23
+ model?: string;
24
+ /** IR: success envelope.payload schema. YAML: `io.output.schema`. */
10
25
  payload_schema?: unknown;
11
26
  /** Declared ask_operator kinds this stage is expected to stop on. */
12
27
  gate_kinds?: StageGateKind[];
13
- /** In-session checks emit must satisfy this attempt before success is accepted. */
28
+ /** IR: emit-phase checks. YAML: `verify` items whose `when` includes `emit`. */
14
29
  pre_emit_checks?: PreEmitCheck[];
30
+ /** IR: clone/fan-out assignment schema. YAML: `io.input.schema`. */
15
31
  clone_input_schema?: unknown;
16
32
  clone_actions?: CloneAction[];
17
33
  /** Optional stage wall-clock timeout in milliseconds (default 60 minutes). */
@@ -24,3 +40,6 @@ export type StageConfig = {
24
40
  */
25
41
  agent?: string;
26
42
  };
43
+ export type LoadedStageConfig = StageConfig & {
44
+ model: string;
45
+ };
@@ -13,6 +13,8 @@ export type StageflowManifest = {
13
13
  catalog: StageflowManifestCatalog;
14
14
  /** Default AgentPort backend for every pipeline/stage that doesn't override it. */
15
15
  agent?: string;
16
+ /** Default LLM model id for every stage that doesn't override it at pipeline or stage level. */
17
+ model?: string;
16
18
  };
17
19
  export type LoadedManifest = {
18
20
  path: string;
@@ -4,4 +4,5 @@ export type TaskFile = {
4
4
  context?: string;
5
5
  constraints?: string;
6
6
  checkout?: string;
7
+ input?: Record<string, unknown>;
7
8
  };