stageflow 0.16.0 → 0.19.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 (124) hide show
  1. package/README.md +2 -4
  2. package/dist/agent/activity.d.ts +4 -0
  3. package/dist/agent/claudeAdapter.js +38 -0
  4. package/dist/agent/claudeTools.d.ts +1 -4
  5. package/dist/agent/claudeTools.js +1 -6
  6. package/dist/agent/fakeAgent.js +7 -6
  7. package/dist/agent/piAdapter.js +34 -15
  8. package/dist/agent/port.d.ts +1 -1
  9. package/dist/agent/stageTimeout.d.ts +9 -0
  10. package/dist/agent/stageTimeout.js +24 -0
  11. package/dist/cli/graphCommand.d.ts +15 -0
  12. package/dist/cli/graphCommand.js +79 -0
  13. package/dist/cli/graphRender.d.ts +2 -0
  14. package/dist/cli/graphRender.js +85 -0
  15. package/dist/cli/runsCommand.d.ts +1 -1
  16. package/dist/cli/runsCommand.js +37 -0
  17. package/dist/cli.js +12 -0
  18. package/dist/config/cloneChain.d.ts +12 -0
  19. package/dist/config/cloneChain.js +322 -0
  20. package/dist/config/createPipeline.js +101 -21
  21. package/dist/config/createStage.js +7 -0
  22. package/dist/config/loadOutcome.d.ts +1 -0
  23. package/dist/config/loadPipeline.d.ts +2 -0
  24. package/dist/config/loadPipeline.js +34 -22
  25. package/dist/config/loadStage.d.ts +2 -0
  26. package/dist/config/loadStage.js +135 -125
  27. package/dist/config/migrateYaml.js +14 -3
  28. package/dist/config/normalizePipelineStageEntry.d.ts +5 -9
  29. package/dist/config/normalizePipelineStageEntry.js +133 -60
  30. package/dist/config/parsePreEmitChecks.js +2 -2
  31. package/dist/config/pipelineNeeds.d.ts +15 -2
  32. package/dist/config/pipelineNeeds.js +86 -4
  33. package/dist/config/pipelineRoute.d.ts +46 -0
  34. package/dist/config/pipelineRoute.js +215 -0
  35. package/dist/config/pipelineStageKeys.d.ts +2 -0
  36. package/dist/config/pipelineStageKeys.js +15 -4
  37. package/dist/config/printTargetYaml.js +18 -12
  38. package/dist/config/resolveForkEmitContext.d.ts +1 -1
  39. package/dist/config/resolveForkEmitContext.js +3 -26
  40. package/dist/config/resolvePipelineDag.d.ts +1 -3
  41. package/dist/config/resolvePipelineDag.js +143 -186
  42. package/dist/config/routeIf.d.ts +24 -0
  43. package/dist/config/routeIf.js +247 -0
  44. package/dist/config/validateCatalog.d.ts +1 -1
  45. package/dist/config/validateCatalog.js +5 -3
  46. package/dist/config/yamlDialect.d.ts +5 -8
  47. package/dist/config/yamlDialect.js +37 -29
  48. package/dist/envelope/check.d.ts +0 -2
  49. package/dist/envelope/check.js +1 -57
  50. package/dist/envelope/feedbackLoop.js +0 -3
  51. package/dist/envelope/forkChoice.js +1 -1
  52. package/dist/envelope/payloadSchema.d.ts +14 -0
  53. package/dist/envelope/payloadSchema.js +87 -2
  54. package/dist/mcp/catalogTools.js +1 -2
  55. package/dist/mcp/controlTools.js +17 -0
  56. package/dist/package-meta.d.ts +1 -1
  57. package/dist/package-meta.js +1 -1
  58. package/dist/projection/projectRun.d.ts +0 -2
  59. package/dist/projection/projectRun.js +0 -3
  60. package/dist/prompt/priorEnvelope.js +1 -1
  61. package/dist/runstore/port.js +2 -0
  62. package/dist/runstore/stageInstanceId.d.ts +1 -0
  63. package/dist/runstore/stageInstanceId.js +9 -0
  64. package/dist/runtime/cloneSchedule.d.ts +16 -33
  65. package/dist/runtime/cloneSchedule.js +155 -236
  66. package/dist/runtime/envelopeRouting.js +43 -94
  67. package/dist/runtime/forkGeneration.d.ts +6 -2
  68. package/dist/runtime/forkGeneration.js +45 -15
  69. package/dist/runtime/joinReadiness.d.ts +16 -0
  70. package/dist/runtime/joinReadiness.js +156 -0
  71. package/dist/runtime/pipelineScheduler.d.ts +0 -3
  72. package/dist/runtime/pipelineScheduler.js +103 -65
  73. package/dist/runtime/reopenSkipped.d.ts +13 -0
  74. package/dist/runtime/reopenSkipped.js +56 -0
  75. package/dist/runtime/resumeTimedOut.d.ts +33 -0
  76. package/dist/runtime/resumeTimedOut.js +165 -0
  77. package/dist/runtime/routeIfEval.d.ts +3 -0
  78. package/dist/runtime/routeIfEval.js +94 -0
  79. package/dist/runtime/runManager.d.ts +1 -0
  80. package/dist/runtime/runManager.js +76 -0
  81. package/dist/runtime/runRetryCoordinator.js +0 -4
  82. package/dist/runtime/stageAttemptBootstrap.js +60 -11
  83. package/dist/runtime/stageRecovery.js +2 -2
  84. package/dist/runtime/stageRunner.js +6 -2
  85. package/dist/runtime/taskInput.js +1 -13
  86. package/dist/server/http.js +18 -0
  87. package/dist/tools/askOperator.d.ts +1 -0
  88. package/dist/tools/askOperator.js +14 -11
  89. package/dist/tools/emitStageEnvelope.d.ts +3 -3
  90. package/dist/tools/emitStageEnvelope.js +4 -66
  91. package/dist/tools/prepareToolArguments.d.ts +4 -0
  92. package/dist/tools/prepareToolArguments.js +79 -0
  93. package/dist/types/envelope.d.ts +0 -2
  94. package/dist/types/forkChoice.d.ts +0 -16
  95. package/dist/types/pipeline.d.ts +86 -27
  96. package/dist/types/stage.d.ts +11 -7
  97. package/dist/ui/assets/{index-D2Wt8hwH.css → index-CSsDued1.css} +1 -1
  98. package/dist/ui/assets/index-DMVdl1qB.js +119 -0
  99. package/dist/ui/index.html +2 -2
  100. package/package.json +2 -1
  101. package/skills/stageflow-author/SKILL.md +4 -4
  102. package/skills/stageflow-author/assets/examples/branch-decision/hotfix.yaml +10 -2
  103. package/skills/stageflow-author/assets/examples/branch-decision/release-gate.pipeline.yaml +12 -4
  104. package/skills/stageflow-author/assets/examples/branch-decision/run-tests.yaml +6 -4
  105. package/skills/stageflow-author/assets/examples/branch-decision/ship.yaml +9 -1
  106. package/skills/stageflow-author/assets/examples/linear-review/draft.yaml +3 -0
  107. package/skills/stageflow-author/assets/examples/linear-review/publish.yaml +8 -0
  108. package/skills/stageflow-author/assets/examples/linear-review/review-loop.pipeline.yaml +5 -2
  109. package/skills/stageflow-author/assets/examples/linear-review/review.yaml +8 -0
  110. package/skills/stageflow-author/assets/examples/non-sdlc-digest/gather.yaml +3 -0
  111. package/skills/stageflow-author/assets/examples/non-sdlc-digest/research-digest.pipeline.yaml +5 -2
  112. package/skills/stageflow-author/assets/examples/non-sdlc-digest/send.yaml +8 -0
  113. package/skills/stageflow-author/assets/examples/non-sdlc-digest/summarize.yaml +8 -0
  114. package/skills/stageflow-author/references/catalog-mapping.md +159 -50
  115. package/skills/stageflow-author/references/catalog-write-conventions.md +3 -3
  116. package/skills/stageflow-author/references/stage-prompt-template.md +57 -17
  117. package/skills/stageflow-session-capture/SKILL.md +2 -2
  118. package/skills/stageflow-session-capture/assets/example-pipeline/example.pipeline.yaml +3 -1
  119. package/skills/stageflow-session-capture/assets/example-pipeline/implement.yaml +15 -0
  120. package/skills/stageflow-session-capture/assets/example-pipeline/research.yaml +3 -0
  121. package/skills/stageflow-session-capture/references/catalog-authoring.md +4 -2
  122. package/dist/envelope/cloneForks.d.ts +0 -2
  123. package/dist/envelope/cloneForks.js +0 -77
  124. package/dist/ui/assets/index-XWJovnp7.js +0 -118
@@ -179,10 +179,21 @@ function compileNode(node, path, ctx) {
179
179
  schema.minItems < 0)) {
180
180
  throw new Error(`${path}: minItems must be a non-negative integer when present`);
181
181
  }
182
+ if (schema.maxItems !== undefined &&
183
+ (typeof schema.maxItems !== "number" ||
184
+ !Number.isInteger(schema.maxItems) ||
185
+ schema.maxItems < 0)) {
186
+ throw new Error(`${path}: maxItems must be a non-negative integer when present`);
187
+ }
182
188
  const items = compileNode(schema.items, `${path}.items`, childCtx);
189
+ const arrayOpts = {};
190
+ if (schema.minItems !== undefined)
191
+ arrayOpts.minItems = schema.minItems;
192
+ if (schema.maxItems !== undefined)
193
+ arrayOpts.maxItems = schema.maxItems;
183
194
  base =
184
- schema.minItems !== undefined
185
- ? Type.Array(items, { minItems: schema.minItems })
195
+ Object.keys(arrayOpts).length > 0
196
+ ? Type.Array(items, arrayOpts)
186
197
  : Type.Array(items);
187
198
  break;
188
199
  }
@@ -420,6 +431,61 @@ export function expandPayloadSchemaRefs(raw, options) {
420
431
  stack: [],
421
432
  });
422
433
  }
434
+ const INDEX_SEGMENT = /^\d+$/;
435
+ function schemaNodeType(schema) {
436
+ return typeof schema?.type === "string" ? schema.type : undefined;
437
+ }
438
+ function tryExpandSchema(node, options) {
439
+ try {
440
+ return expandPayloadSchemaRefs(node, options);
441
+ }
442
+ catch {
443
+ return node;
444
+ }
445
+ }
446
+ export function resolvePayloadSchemaFieldPath(schema, field, options) {
447
+ const segments = field.split(".");
448
+ if (segments.length === 0 || segments.some((segment) => segment === "")) {
449
+ return { ok: false, issue: "empty_segment" };
450
+ }
451
+ if (segments.some((segment) => INDEX_SEGMENT.test(segment))) {
452
+ return { ok: false, issue: "array_index" };
453
+ }
454
+ let current = tryExpandSchema(schema, options);
455
+ for (const segment of segments) {
456
+ if (!isPlainSchemaObject(current)) {
457
+ return { ok: false, issue: "missing" };
458
+ }
459
+ const node = current;
460
+ if (node.$ref !== undefined && node.properties === undefined) {
461
+ return { ok: false, issue: "missing" };
462
+ }
463
+ const typeName = schemaNodeType(node);
464
+ if (typeName === "array" ||
465
+ (node.items !== undefined && typeName !== "object")) {
466
+ return { ok: false, issue: "array_index" };
467
+ }
468
+ const properties = readProperties(node);
469
+ if (!Object.prototype.hasOwnProperty.call(properties, segment)) {
470
+ return { ok: false, issue: "missing" };
471
+ }
472
+ if (!readRequiredKeys(node).includes(segment)) {
473
+ return { ok: false, issue: "optional" };
474
+ }
475
+ current = properties[segment];
476
+ }
477
+ const leaf = isPlainSchemaObject(current)
478
+ ? tryExpandSchema(current, options)
479
+ : undefined;
480
+ if (leaf?.$ref !== undefined && leaf.properties === undefined) {
481
+ return { ok: false, issue: "untyped" };
482
+ }
483
+ const fieldType = schemaNodeType(leaf);
484
+ if (fieldType === undefined) {
485
+ return { ok: false, issue: "untyped" };
486
+ }
487
+ return { ok: true, type: fieldType };
488
+ }
423
489
  function expandSchemaNode(node, path, ctx) {
424
490
  const { schema, stack } = derefSchemaNode(node, path, ctx);
425
491
  const childCtx = { schemas: ctx.schemas, stack };
@@ -496,3 +562,22 @@ export function assertCloneAssignmentPayload(envelope, cloneInputSchema, success
496
562
  : `${pathLead}clone assignment payload does not match io.input.schema for ${successorId}`);
497
563
  }
498
564
  }
565
+ /**
566
+ * Validate a predecessor success payload against the child's IR
567
+ * `clone_input_schema` (YAML: `io.input.schema`) on a normal pipeline edge.
568
+ */
569
+ export function assertPriorInputPayload(envelope, cloneInputSchema, childId, options) {
570
+ if (envelope.status !== "success") {
571
+ return;
572
+ }
573
+ const schema = compilePayloadSchema(cloneInputSchema, options);
574
+ if (envelope.payload === undefined) {
575
+ throw new EnvelopeError(`prior payload is required by io.input.schema for ${childId}`);
576
+ }
577
+ if (!Value.Check(schema, envelope.payload)) {
578
+ const details = payloadSchemaMismatchDetails(schema, envelope.payload);
579
+ throw new EnvelopeError(details
580
+ ? `prior payload does not match io.input.schema for ${childId}: ${details}`
581
+ : `prior payload does not match io.input.schema for ${childId}`);
582
+ }
583
+ }
@@ -153,7 +153,7 @@ export function registerCatalogTools(server, deps) {
153
153
  }
154
154
  });
155
155
  server.registerTool("describe_pipeline", {
156
- description: "Describe a pipeline DAG: stages with needs, fork, clonable, clone_cap, and gate_kinds. Input is a filesystem pipeline path (same as start_run).",
156
+ description: "Describe a pipeline DAG: stages with needs, fork, and gate_kinds. Input is a filesystem pipeline path (same as start_run).",
157
157
  inputSchema: z.object({
158
158
  pipeline: z.string(),
159
159
  }),
@@ -170,7 +170,6 @@ export function registerCatalogTools(server, deps) {
170
170
  ? node.needsEdges.map((edge) => ({ id: edge.id, on: [...edge.on] }))
171
171
  : node.needs,
172
172
  ...(node.fork !== undefined ? { fork: node.fork } : {}),
173
- ...(node.clonable !== undefined ? { clonable: node.clonable } : {}),
174
173
  ...(node.clone_cap !== undefined ? { clone_cap: node.clone_cap } : {}),
175
174
  ...(gateById.get(node.id) !== undefined
176
175
  ? { gate_kinds: gateById.get(node.id) }
@@ -183,6 +183,23 @@ export function registerControlTools(server, deps) {
183
183
  attemptIndex: result.attemptIndex,
184
184
  });
185
185
  });
186
+ server.registerTool("resume_stage", {
187
+ description: "Resume a stage that failed because it timed out, continuing the same attempt/session (same as POST .../resume). Does not start a new attempt — use retry_stage to start over.",
188
+ inputSchema: z.object({
189
+ runId: z.string(),
190
+ stageId: z.string(),
191
+ }),
192
+ }, async ({ runId, stageId }) => {
193
+ const result = await manager.resumeTimedOutStage(runId, stageId);
194
+ if (!result.ok) {
195
+ return textResult({ ...mapRetryStageFailure(result), status: result.status }, true);
196
+ }
197
+ return textResult({
198
+ runId: result.runId,
199
+ stageId: result.stageId,
200
+ attemptIndex: result.attemptIndex,
201
+ });
202
+ });
186
203
  server.registerTool("abandon_stage", {
187
204
  description: "Abandon a running stage (marks it failed/interrupted). Does not dismiss HITL — waiting stages return 409; answer them with answer_gate. There is no run-level cancel tool.",
188
205
  inputSchema: z.object({
@@ -1,2 +1,2 @@
1
1
  export declare const PACKAGE_NAME = "stageflow";
2
- export declare const PACKAGE_VERSION = "0.16.0";
2
+ export declare const PACKAGE_VERSION = "0.19.0";
@@ -1,2 +1,2 @@
1
1
  export const PACKAGE_NAME = "stageflow";
2
- export const PACKAGE_VERSION = "0.16.0";
2
+ export const PACKAGE_VERSION = "0.19.0";
@@ -2,7 +2,6 @@ import type { FeedbackLoopHistory, FeedbackLoopRecord, RunDetail, StageSnapshot
2
2
  import type { PipelineTrackProjection, RunSummary } from "../runstore/port.js";
3
3
  import type { AskOperatorPrompt } from "../tools/askOperator.js";
4
4
  import type { StageEnvelope } from "../types/envelope.js";
5
- import type { CloneForkItem } from "../types/forkChoice.js";
6
5
  export type StageProjection = {
7
6
  stage_id: string;
8
7
  status: StageSnapshot["status"];
@@ -12,7 +11,6 @@ export type StageProjection = {
12
11
  artifacts: string[];
13
12
  payload?: Record<string, unknown>;
14
13
  fork_choice?: string[];
15
- clone_forks?: CloneForkItem[];
16
14
  feedback_loop?: StageEnvelope["feedback_loop"];
17
15
  } | null;
18
16
  artifacts: string[];
@@ -59,9 +59,6 @@ export function projectRun(detail) {
59
59
  ...(stage.envelope.fork_choice !== undefined
60
60
  ? { fork_choice: stage.envelope.fork_choice }
61
61
  : {}),
62
- ...(stage.envelope.clone_forks !== undefined
63
- ? { clone_forks: stage.envelope.clone_forks }
64
- : {}),
65
62
  ...(stage.envelope.feedback_loop !== undefined
66
63
  ? { feedback_loop: stage.envelope.feedback_loop }
67
64
  : {}),
@@ -3,7 +3,7 @@ export function formatPriorEnvelope(priorEnvelope, priorEnvelopes, priorEnvelope
3
3
  return `Prior envelopes by stage (declaration order):\n${JSON.stringify(priorEnvelopesByStage, null, 2)}`;
4
4
  }
5
5
  if (priorEnvelopes !== undefined && priorEnvelopes.length > 0) {
6
- return `Prior envelopes (${priorEnvelopes.length} clones, clone-list order):\n${JSON.stringify(priorEnvelopes, null, 2)}`;
6
+ return `Prior envelopes (${priorEnvelopes.length}):\n${JSON.stringify(priorEnvelopes, null, 2)}`;
7
7
  }
8
8
  return priorEnvelope === null
9
9
  ? "No prior envelope (first stage)."
@@ -12,6 +12,8 @@ export function stageStatusFromEvents(events) {
12
12
  status = "failed";
13
13
  if (ev.event === "skipped")
14
14
  status = "skipped";
15
+ if (ev.event === "reopened")
16
+ status = "pending";
15
17
  }
16
18
  return status;
17
19
  }
@@ -1,4 +1,5 @@
1
1
  import type { RunPipelineDagSnapshot } from "./port.js";
2
2
  export declare function mintCloneInstanceId(catalogId: string, n: number): string;
3
3
  export declare function mintCloneInstanceIds(catalogId: string, count: number, startAt?: number): string[];
4
+ export declare function cloneInstanceOrdinal(instanceId: string, catalogId: string): number | undefined;
4
5
  export declare function definitionIdForInstance(snapshot: RunPipelineDagSnapshot | null | undefined, instanceId: string): string;
@@ -16,6 +16,15 @@ export function mintCloneInstanceIds(catalogId, count, startAt = 1) {
16
16
  guardPositiveInteger(startAt, "startAt");
17
17
  return Array.from({ length: count }, (_, i) => mintCloneInstanceId(catalogId, startAt + i));
18
18
  }
19
+ export function cloneInstanceOrdinal(instanceId, catalogId) {
20
+ const prefix = `${catalogId}~`;
21
+ if (!instanceId.startsWith(prefix))
22
+ return undefined;
23
+ const n = Number(instanceId.slice(prefix.length));
24
+ if (!Number.isInteger(n) || n < 1)
25
+ return undefined;
26
+ return n;
27
+ }
19
28
  export function definitionIdForInstance(snapshot, instanceId) {
20
29
  const node = snapshot?.nodes.find((n) => n.id === instanceId);
21
30
  if (!node)
@@ -1,30 +1,26 @@
1
1
  import type { RunPipelineDagSnapshot } from "../runstore/port.js";
2
2
  import type { StageEnvelope } from "../types/envelope.js";
3
3
  import type { NeedTerminalState, ResolvedPipelineDag } from "../types/pipeline.js";
4
- import { type ActiveCohort } from "./forkGeneration.js";
4
+ import type { ResolvePriorEnvelopeResult } from "./envelopeRouting.js";
5
5
  import type { StageScheduleState } from "./pipelineScheduler.js";
6
6
  export declare function isCloneInstance(dag: ResolvedPipelineDag, stageId: string): boolean;
7
7
  export declare function sequentialLaterCloneIds(dag: ResolvedPipelineDag, stageId: string, completedEnvelopes: Map<string, StageEnvelope>): string[];
8
8
  export declare function skipRejectedNeedDependents(dag: ResolvedPipelineDag, parentId: string, states: Map<string, StageScheduleState>, observed: NeedTerminalState, onSkip: (stageId: string) => void): void;
9
9
  export declare function failureIsAccepted(dag: ResolvedPipelineDag, failedId: string, states: Map<string, StageScheduleState>): boolean;
10
- /**
11
- * A fresh clone_forks fanout targeting a catalog id that already has
12
- * instances is only safe when every existing instance was put back to
13
- * `pending` by the current retry cascade (`retryDownstreamIds`) — that means
14
- * an ancestor was legitimately retried and this parent re-emitted the same
15
- * fanout for reactivation. Instances that are still active/terminal, or
16
- * merely `pending` without having gone through a retry reset (e.g. an
17
- * envelope processed twice in one live run), are rejected as before.
18
- *
19
- * Feedback-loop replay is different: the prior cohort was superseded
20
- * (`skipped`) and a new generation must mint fresh `~N` ids, so
21
- * `forceFreshCloneIds` bypasses the conflict.
22
- */
23
- export declare function cloneFanoutConflict(dag: ResolvedPipelineDag, envelope: StageEnvelope, states: Map<string, StageScheduleState>, retryDownstreamIds: ReadonlySet<string>, options?: {
24
- forceFreshCloneIds?: boolean;
25
- }): string | undefined;
26
- export declare function nextFreeCloneSuffix(snapshot: RunPipelineDagSnapshot, catalogId: string): number;
27
- export declare function protectedClonableChildIds(dag: ResolvedPipelineDag, predecessorId: string, envelope: StageEnvelope): Set<string>;
10
+ export type MintResult = {
11
+ kind: "none";
12
+ } | {
13
+ kind: "error";
14
+ reason: string;
15
+ } | {
16
+ kind: "minted";
17
+ dag: RunPipelineDagSnapshot;
18
+ catalogChildId: string;
19
+ instanceIds: string[];
20
+ };
21
+ export declare function mint(dag: ResolvedPipelineDag, emitterId: string, envelope: StageEnvelope): MintResult;
22
+ export declare function assignment(dag: ResolvedPipelineDag, stageId: string, definitionId: string, completedEnvelopes: Map<string, StageEnvelope>): ResolvePriorEnvelopeResult | undefined;
23
+ export declare function protectedClonableChildIds(dag: ResolvedPipelineDag, predecessorId: string, _envelope: StageEnvelope): Set<string>;
28
24
  /**
29
25
  * Downstream closure for a retry, resolved through clone-instance ids and
30
26
  * static multi-parent edges. Catalog-level children (e.g. a join stage) are
@@ -38,17 +34,4 @@ export declare function protectedClonableChildIds(dag: ResolvedPipelineDag, pred
38
34
  export declare function cloneRetryDownstream(dag: ResolvedPipelineDag, stageIds: string[]): Set<string>;
39
35
  export declare function cloneFailureContinuesSchedule(dag: ResolvedPipelineDag, stageId: string, completedEnvelopes: Map<string, StageEnvelope>): boolean;
40
36
  export declare function cloneFailFastSkipIds(dag: ResolvedPipelineDag, stageId: string, completedEnvelopes: Map<string, StageEnvelope>): string[];
41
- export declare function cloneScheduleAllowsRun(dag: ResolvedPipelineDag, stageId: string, states: Map<string, StageScheduleState>, completedEnvelopes: Map<string, StageEnvelope>, options?: {
42
- activeCohortForNeeds?: (needsId: string) => ActiveCohort;
43
- activeCloneIdsForNeeds?: (needsId: string) => Set<string> | null;
44
- }): boolean;
45
- export type ApplyCloneForksResult = {
46
- dag: RunPipelineDagSnapshot;
47
- skippedIds: string[];
48
- /** Freshly minted instance ids keyed by clonable catalog successor id. */
49
- mintedBySuccessor?: Map<string, string[]>;
50
- };
51
- export declare function applyCloneForksToSchedule(dag: ResolvedPipelineDag, predecessorId: string, envelope: StageEnvelope, states: Map<string, StageScheduleState>, options?: {
52
- forceFreshCloneIds?: boolean;
53
- }): ApplyCloneForksResult;
54
- export declare function applyCloneForksFromEnvelopes(dag: ResolvedPipelineDag, states: Map<string, StageScheduleState>, completedEnvelopes: Map<string, StageEnvelope>): ApplyCloneForksResult;
37
+ export declare function cloneScheduleAllowsRun(dag: ResolvedPipelineDag, stageId: string, states: Map<string, StageScheduleState>, completedEnvelopes: Map<string, StageEnvelope>): boolean;