@cascade-flow/worker 0.2.25 → 0.2.27

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.
@@ -1,6 +1,11 @@
1
1
  import type { Backend, StepEvent } from "@cascade-flow/backend-interface";
2
2
  import { type LoadedStep } from "@cascade-flow/runner";
3
3
  import { RetryableError } from "@cascade-flow/workflow";
4
+ /**
5
+ * Event types needed for state projection. Excludes high-volume types
6
+ * that don't affect step state (LogEntry, StepRetrying, StepCheckpoint, StepCheckpointFailed).
7
+ */
8
+ export declare const STATE_PROJECTION_TYPES: string[];
4
9
  /**
5
10
  * Thrown when a dependency's projected state is unexpectedly non-terminal while
6
11
  * attempting to load dependency outputs.
@@ -1 +1 @@
1
- {"version":3,"file":"dependency-resolver.d.ts","sourceRoot":"","sources":["../../src/execution/dependency-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAE1E,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGxD;;;;;;;;GAQG;AACH,qBAAa,uBAAwB,SAAQ,cAAc;IACzD,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;gBAEtB,kBAAkB,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,OAAO,GAAE,MAAY;CAUxF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,GAC5C,OAAO,CAAC,OAAO,CAAC,CAmClB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAwC9B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,UAAU,EAAE,EACtB,YAAY,GAAE,OAAe,GAC5B,UAAU,EAAE,CAed"}
1
+ {"version":3,"file":"dependency-resolver.d.ts","sourceRoot":"","sources":["../../src/execution/dependency-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAE1E,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGxD;;;GAGG;AACH,eAAO,MAAM,sBAAsB,UAGlC,CAAC;AAEF;;;;;;;;GAQG;AACH,qBAAa,uBAAwB,SAAQ,cAAc;IACzD,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;gBAEtB,kBAAkB,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,OAAO,GAAE,MAAY;CAUxF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,GAC5C,OAAO,CAAC,OAAO,CAAC,CAoClB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAyC9B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,UAAU,EAAE,EACtB,YAAY,GAAE,OAAe,GAC5B,UAAU,EAAE,CAed"}
package/dist/index.js CHANGED
@@ -81,6 +81,15 @@ import {
81
81
  import { projectStepState } from "@cascade-flow/backend-interface";
82
82
  import { RetryableError as RetryableError2 } from "@cascade-flow/workflow";
83
83
  import { isOptional } from "@cascade-flow/workflow";
84
+ var STATE_PROJECTION_TYPES = [
85
+ "StepScheduled",
86
+ "StepStarted",
87
+ "StepCompleted",
88
+ "StepFailed",
89
+ "StepSkipped",
90
+ "StepReclaimed",
91
+ "StepHeartbeat"
92
+ ];
84
93
 
85
94
  class DependencyNotReadyError extends RetryableError2 {
86
95
  dependencyStepName;
@@ -96,7 +105,8 @@ async function checkDependenciesSatisfied(step, backend, workflowSlug, runId, st
96
105
  for (const [depKey, dep] of Object.entries(step.dependencies)) {
97
106
  const depEvents = stepEventsByStepId?.get(dep.id) ?? await backend.loadEvents(workflowSlug, runId, {
98
107
  category: "step",
99
- stepId: dep.id
108
+ stepId: dep.id,
109
+ types: STATE_PROJECTION_TYPES
100
110
  });
101
111
  if (depEvents.length === 0) {
102
112
  return false;
@@ -122,7 +132,8 @@ async function loadDependencyOutputs(step, backend, workflowSlug, runId) {
122
132
  for (const [depKey, depStep] of Object.entries(step.dependencies)) {
123
133
  const depEvents = await backend.loadEvents(workflowSlug, runId, {
124
134
  category: "step",
125
- stepId: depStep.id
135
+ stepId: depStep.id,
136
+ types: STATE_PROJECTION_TYPES
126
137
  });
127
138
  if (depEvents.length === 0) {
128
139
  throw new Error(`Dependency ${depStep.name} has no events - step was scheduled prematurely`);
@@ -419,7 +430,139 @@ function parseWorkflowInput(workflowEvents) {
419
430
  return;
420
431
  }
421
432
 
433
+ // src/utils/log-batcher.ts
434
+ class LogBatcher {
435
+ backend;
436
+ flushIntervalMs;
437
+ buffer = [];
438
+ timer = null;
439
+ flushing = null;
440
+ constructor(backend, flushIntervalMs = 500) {
441
+ this.backend = backend;
442
+ this.flushIntervalMs = flushIntervalMs;
443
+ }
444
+ add(workflowSlug, runId, event) {
445
+ this.buffer.push({ workflowSlug, runId, event });
446
+ this.scheduleFlush();
447
+ }
448
+ scheduleFlush() {
449
+ if (this.timer || this.flushing)
450
+ return;
451
+ this.timer = setTimeout(() => {
452
+ this.timer = null;
453
+ this.doFlush();
454
+ }, this.flushIntervalMs);
455
+ }
456
+ doFlush() {
457
+ if (this.flushing || this.buffer.length === 0)
458
+ return;
459
+ const batch = this.buffer;
460
+ this.buffer = [];
461
+ this.flushing = this.backend.batchAppendEvents(batch).catch(() => {
462
+ this.buffer = batch.concat(this.buffer);
463
+ }).finally(() => {
464
+ this.flushing = null;
465
+ if (this.buffer.length > 0) {
466
+ this.scheduleFlush();
467
+ }
468
+ });
469
+ }
470
+ async drain() {
471
+ if (this.timer) {
472
+ clearTimeout(this.timer);
473
+ this.timer = null;
474
+ }
475
+ if (this.flushing) {
476
+ await this.flushing;
477
+ }
478
+ if (this.buffer.length > 0) {
479
+ const batch = this.buffer;
480
+ this.buffer = [];
481
+ await this.backend.batchAppendEvents(batch);
482
+ }
483
+ }
484
+ }
485
+
422
486
  // src/step-worker.ts
487
+ var IS_LINUX = process.platform === "linux";
488
+ var procConstantsPromise = null;
489
+ function getProcConstants() {
490
+ if (!procConstantsPromise) {
491
+ procConstantsPromise = (async () => {
492
+ let pageSize = 4096;
493
+ let clkTck = 100;
494
+ try {
495
+ const ps = Bun.spawn(["getconf", "PAGESIZE"], { stdout: "pipe", stderr: "ignore" });
496
+ const out = await new Response(ps.stdout).text();
497
+ await ps.exited;
498
+ const parsed = parseInt(out.trim(), 10);
499
+ if (!isNaN(parsed) && parsed > 0)
500
+ pageSize = parsed;
501
+ } catch {}
502
+ try {
503
+ const cs = Bun.spawn(["getconf", "CLK_TCK"], { stdout: "pipe", stderr: "ignore" });
504
+ const out = await new Response(cs.stdout).text();
505
+ await cs.exited;
506
+ const parsed = parseInt(out.trim(), 10);
507
+ if (!isNaN(parsed) && parsed > 0)
508
+ clkTck = parsed;
509
+ } catch {}
510
+ return { pageSize, clkTck };
511
+ })();
512
+ }
513
+ return procConstantsPromise;
514
+ }
515
+ async function readProcStats(pid) {
516
+ try {
517
+ const { pageSize, clkTck } = await getProcConstants();
518
+ const stat = await Bun.file(`/proc/${pid}/stat`).text();
519
+ const closeParen = stat.lastIndexOf(")");
520
+ if (closeParen === -1)
521
+ return;
522
+ const fields = stat.substring(closeParen + 2).split(" ");
523
+ if (fields.length < 22)
524
+ return;
525
+ const utime = parseInt(fields[11], 10);
526
+ const stime = parseInt(fields[12], 10);
527
+ const rss = parseInt(fields[21], 10);
528
+ if (isNaN(rss) || rss <= 0)
529
+ return;
530
+ const memoryBytes = rss * pageSize;
531
+ const cpuTimeUs = Math.round((utime + stime) / clkTck * 1e6);
532
+ return { memoryBytes, cpuTimeUs };
533
+ } catch {
534
+ return;
535
+ }
536
+ }
537
+ async function readPsStats(pid) {
538
+ try {
539
+ const ps = Bun.spawn(["ps", "-o", "rss=,cputime=", "-p", String(pid)], {
540
+ stdout: "pipe",
541
+ stderr: "ignore"
542
+ });
543
+ const output = await new Response(ps.stdout).text();
544
+ await ps.exited;
545
+ const parts = output.trim().split(/\s+/);
546
+ if (parts.length === 0)
547
+ return;
548
+ const rssKB = parseInt(parts[0], 10);
549
+ if (isNaN(rssKB) || rssKB <= 0)
550
+ return;
551
+ const result = { memoryBytes: rssKB * 1024 };
552
+ if (parts[1]) {
553
+ const cpuTimeUs = parseCpuTime(parts[1]);
554
+ if (cpuTimeUs !== null) {
555
+ result.cpuTimeUs = cpuTimeUs;
556
+ }
557
+ }
558
+ return result;
559
+ } catch {
560
+ return;
561
+ }
562
+ }
563
+ async function readResourceStats(pid) {
564
+ return IS_LINUX ? readProcStats(pid) : readPsStats(pid);
565
+ }
423
566
  function parseCpuTime(raw) {
424
567
  const hms = raw.match(/^(\d+):(\d{2}):(\d{2})$/);
425
568
  if (hms) {
@@ -858,6 +1001,7 @@ class StepWorker {
858
1001
  let attemptNumber = null;
859
1002
  let heartbeatTimer = null;
860
1003
  let slotIndex = null;
1004
+ const logBatcher = new LogBatcher(this.backend);
861
1005
  try {
862
1006
  const workflowData = this.workflowCache.get(workflowSlug);
863
1007
  if (!workflowData) {
@@ -896,25 +1040,7 @@ class StepWorker {
896
1040
  return;
897
1041
  let resourceSnapshot;
898
1042
  if (childPid) {
899
- try {
900
- const ps = Bun.spawn(["ps", "-o", "rss=,cputime=", "-p", String(childPid)], {
901
- stdout: "pipe",
902
- stderr: "ignore"
903
- });
904
- const output2 = await new Response(ps.stdout).text();
905
- await ps.exited;
906
- const parts = output2.trim().split(/\s+/);
907
- const rssKB = parseInt(parts[0], 10);
908
- if (!isNaN(rssKB) && rssKB > 0) {
909
- resourceSnapshot = { memoryBytes: rssKB * 1024 };
910
- if (parts[1]) {
911
- const cpuTimeUs = parseCpuTime(parts[1]);
912
- if (cpuTimeUs !== null) {
913
- resourceSnapshot.cpuTimeUs = cpuTimeUs;
914
- }
915
- }
916
- }
917
- } catch {}
1043
+ resourceSnapshot = await readResourceStats(childPid);
918
1044
  }
919
1045
  const trackedAfter = this.activeSteps.get(stepKey);
920
1046
  if (!trackedAfter || trackedAfter.attemptNumber !== heartbeatAttemptNumber)
@@ -970,7 +1096,7 @@ class StepWorker {
970
1096
  const timeout = step.timeoutMs ?? submissionTimeoutMs ?? 300000;
971
1097
  const existingCheckpoints = await this.loadCheckpointsFromEvents(workflowSlug, runId, stepId);
972
1098
  const abortController = new AbortController;
973
- const executionPromise = executeStepInProcess(stepFile, step.id, dependencyOutputs, ctx, attemptNumber, this.backend, async (log) => {
1099
+ const executionPromise = executeStepInProcess(stepFile, step.id, dependencyOutputs, ctx, attemptNumber, this.backend, (log) => {
974
1100
  const logEvent = {
975
1101
  workflowSlug,
976
1102
  runId,
@@ -982,7 +1108,7 @@ class StepWorker {
982
1108
  attemptNumber,
983
1109
  timestampUs: log.timestamp
984
1110
  };
985
- await this.backend.appendEvent(workflowSlug, runId, logEvent);
1111
+ logBatcher.add(workflowSlug, runId, logEvent);
986
1112
  }, async (checkpoint) => {
987
1113
  let parentCheckpoint;
988
1114
  let label;
@@ -1029,9 +1155,10 @@ class StepWorker {
1029
1155
  const { result: output, resourceUsage } = execResult;
1030
1156
  const endTime = getMicrosecondTimestamp5();
1031
1157
  const duration = endTime - startTime;
1158
+ await logBatcher.drain();
1032
1159
  this.finalizeActiveStep(stepKey, { heartbeatTimer, slotIndex });
1033
1160
  heartbeatTimer = null;
1034
- const currentStepEvents = await this.backend.loadEvents(workflowSlug, runId, { category: "step", stepId });
1161
+ const currentStepEvents = await this.backend.loadEvents(workflowSlug, runId, { category: "step", stepId, types: STATE_PROJECTION_TYPES });
1035
1162
  const currentStepState = projectStepState6(currentStepEvents, workflowSlug);
1036
1163
  if (currentStepState.attemptNumber > attemptNumber) {
1037
1164
  console.warn(`[StepWorker ${this.workerId}] Discarding stale completion for ${step.name} (attempt ${attemptNumber}, current: ${currentStepState.attemptNumber})`);
@@ -1064,6 +1191,7 @@ class StepWorker {
1064
1191
  } catch (error) {
1065
1192
  const failureContext = attemptNumber === null ? "Failed to claim" : "Failed";
1066
1193
  console.error(`[StepWorker ${this.workerId}] ${failureContext} ${stepKey}:`, error);
1194
+ await logBatcher.drain().catch(() => {});
1067
1195
  this.finalizeActiveStep(stepKey, { heartbeatTimer, slotIndex });
1068
1196
  heartbeatTimer = null;
1069
1197
  if (attemptNumber === null) {
@@ -1199,4 +1327,4 @@ export {
1199
1327
  StepWorker
1200
1328
  };
1201
1329
 
1202
- //# debugId=0C8D0652261AD70364756E2164756E21
1330
+ //# debugId=14E4D7C2C231256D64756E2164756E21
package/dist/index.js.map CHANGED
@@ -1,18 +1,19 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/step-worker.ts", "../src/retry/policy-resolver.ts", "../src/retry/index.ts", "../src/execution/dependency-resolver.ts", "../src/scheduling/skip-handler.ts", "../src/scheduling/step-scheduler.ts", "../src/utils/step-key.ts", "../src/scheduling/workflow-lifecycle.ts", "../src/utils/event-helpers.ts"],
3
+ "sources": ["../src/step-worker.ts", "../src/retry/policy-resolver.ts", "../src/retry/index.ts", "../src/execution/dependency-resolver.ts", "../src/scheduling/skip-handler.ts", "../src/scheduling/step-scheduler.ts", "../src/utils/step-key.ts", "../src/scheduling/workflow-lifecycle.ts", "../src/utils/event-helpers.ts", "../src/utils/log-batcher.ts"],
4
4
  "sourcesContent": [
5
- "import { FileSystemBackend } from \"@cascade-flow/backend-filesystem\";\nimport type { Backend } from \"@cascade-flow/backend-interface\";\nimport { getMicrosecondTimestamp, MICROSECONDS_PER_MILLISECOND, convertZodToJSONSchema, projectStepState, serializeError } from \"@cascade-flow/backend-interface\";\nimport { hostname } from \"node:os\";\nimport { join } from \"node:path\";\nimport { discoverSteps, discoverWorkflows, executeStepInProcess, calculateWorkflowHash, getGitInfo, StepExecutionError, type LoadedStep, type CheckpointData, type CheckpointFailedData } from \"@cascade-flow/runner\";\nimport { Skip } from \"@cascade-flow/workflow\";\nimport {\n getCurrentPolicy,\n computeDelay,\n resolveRetryPolicies,\n getTotalAttempts,\n isRetryableError,\n isNonRetryableError,\n} from \"./retry\";\nimport type { ZodSchema } from \"zod\";\nimport { checkDependenciesSatisfied, loadDependencyOutputs } from \"./execution/dependency-resolver.ts\";\nimport { cascadeSkip, handleStepSkip } from \"./scheduling/skip-handler.ts\";\nimport { scheduleDownstreamSteps, scheduleStep } from \"./scheduling/step-scheduler.ts\";\nimport { createStepKey, extractStepId } from \"./utils/step-key.ts\";\nimport {\n handleWorkflowCompletion,\n handleWorkflowFailure,\n handleWorkflowStart,\n parseWorkflowInput,\n validateWorkflowInput,\n} from \"./scheduling/workflow-lifecycle.ts\";\nimport type { StepWorkerOptions, StepWorkerStats } from \"./types.ts\";\nimport {\n getRunSubmittedEvent,\n getWorkflowInputValidationEvent,\n getWorkflowTerminalState,\n hasWorkflowStarted,\n hasWorkflowSubmitted,\n hasWorkflowValidatedInput,\n loadWorkflowEvents\n} from \"./utils/event-helpers.ts\";\n\n/**\n * Parse a `ps` cputime string (\"MM:SS.ff\" or \"H:MM:SS\") into microseconds.\n * Returns null if the format is unrecognised.\n */\nfunction parseCpuTime(raw: string): number | null {\n // Try \"H:MM:SS\" or \"HH:MM:SS\" (no fractional)\n const hms = raw.match(/^(\\d+):(\\d{2}):(\\d{2})$/);\n if (hms) {\n const h = parseInt(hms[1], 10);\n const m = parseInt(hms[2], 10);\n const s = parseInt(hms[3], 10);\n return (h * 3600 + m * 60 + s) * 1_000_000;\n }\n // Try \"MM:SS.ff\" (fractional seconds)\n const msf = raw.match(/^(\\d+):(\\d{2})\\.(\\d+)$/);\n if (msf) {\n const m = parseInt(msf[1], 10);\n const s = parseInt(msf[2], 10);\n const frac = parseFloat(`0.${msf[3]}`);\n return Math.round((m * 60 + s + frac) * 1_000_000);\n }\n // Try \"MM:SS\" (no fractional)\n const ms = raw.match(/^(\\d+):(\\d{2})$/);\n if (ms) {\n const m = parseInt(ms[1], 10);\n const s = parseInt(ms[2], 10);\n return (m * 60 + s) * 1_000_000;\n }\n // Try \"DD-HH:MM:SS\" (day-prefixed, long-running processes)\n const dhms = raw.match(/^(\\d+)-(\\d{2}):(\\d{2}):(\\d{2})$/);\n if (dhms) {\n const d = parseInt(dhms[1], 10);\n const h = parseInt(dhms[2], 10);\n const m = parseInt(dhms[3], 10);\n const s = parseInt(dhms[4], 10);\n return (d * 86400 + h * 3600 + m * 60 + s) * 1_000_000;\n }\n return null;\n}\n\n/**\n * StepWorker - long-running process for step-level distributed workflow execution\n *\n * Architecture:\n * - Workers claim and execute individual steps (not entire workflows)\n * - Steps are scheduled when their dependencies complete\n * - Multiple workers can collaboratively execute steps from the same workflow\n * - Enables finer-grained parallelization and better resource utilization\n *\n * Features:\n * - Executor loop: Claims and executes scheduled steps\n * - Scheduler loop: Finds ready steps and schedules them\n * - Heartbeat loop: Sends heartbeats for running steps\n * - Reclamation loop: Detects and reclaims stale steps from crashed workers\n * - Retry support: Automatic retries with configurable delay\n * - Timeout enforcement: Abort-controlled cancellation of hung subprocesses\n * - Graceful shutdown: Waits for active steps to complete\n */\nexport class StepWorker {\n private workerId: string;\n private backend: Backend;\n private options: Required<StepWorkerOptions>;\n private running: boolean = false;\n private activeSteps: Map<string, {\n workflowSlug: string;\n runId: string;\n stepId: string;\n attemptNumber: number;\n heartbeatTimer: Timer;\n slotIndex: number;\n }> = new Map();\n private stats: StepWorkerStats;\n private workflowCache: Map<string, { metadata: any; steps: LoadedStep[]; inputSchema?: ZodSchema }> = new Map();\n private freeSlots: Set<number> = new Set();\n\n /**\n * Stop heartbeats and clear local running-step bookkeeping.\n *\n * This is intentionally idempotent and safe to call multiple times.\n * It is used before writing terminal step events to prevent a heartbeat\n * from being appended after StepCompleted/StepFailed/StepSkipped.\n */\n private finalizeActiveStep(\n stepKey: string,\n fallback?: { heartbeatTimer?: Timer | null; slotIndex?: number | null }\n ): void {\n const activeStep = this.activeSteps.get(stepKey);\n if (activeStep) {\n clearInterval(activeStep.heartbeatTimer);\n this.freeSlots.add(activeStep.slotIndex);\n this.activeSteps.delete(stepKey);\n this.stats.currentlyRunning--;\n return;\n }\n\n if (fallback?.heartbeatTimer) {\n clearInterval(fallback.heartbeatTimer);\n }\n if (fallback?.slotIndex !== null && fallback?.slotIndex !== undefined) {\n this.freeSlots.add(fallback.slotIndex);\n }\n }\n\n constructor(backend?: Backend, options: StepWorkerOptions = {}) {\n // Generate worker ID if not provided (using microseconds for consistency)\n this.workerId = options.workerId || `step-worker-${hostname()}-${process.pid}-${getMicrosecondTimestamp()}`;\n\n // Use provided backend or create filesystem backend\n this.backend = backend || new FileSystemBackend(options.baseDir || \"./.runs\");\n\n // Set defaults for all options\n this.options = {\n workerId: this.workerId,\n mode: options.mode ?? \"unified\",\n concurrency: options.concurrency ?? 1,\n pollInterval: options.pollInterval ?? 1000,\n heartbeatInterval: options.heartbeatInterval ?? 5000,\n staleThreshold: options.staleThreshold ?? 30000,\n staleCheckInterval: options.staleCheckInterval ?? 10000,\n schedulerInterval: options.schedulerInterval ?? 5000,\n schedulerRunBatchSize: options.schedulerRunBatchSize ?? 200,\n shutdownTimeout: options.shutdownTimeout ?? 30000,\n workflowsDir: options.workflowsDir || \"./workflows\",\n baseDir: options.baseDir || \"./.runs\",\n };\n\n this.stats = {\n workerId: this.workerId,\n mode: this.options.mode,\n startedAt: getMicrosecondTimestamp(), // Convert to microseconds\n totalStepsProcessed: 0,\n currentlyRunning: 0,\n failedSteps: 0,\n reclaimedSteps: 0,\n };\n\n // Initialize free slots (0 to concurrency-1)\n for (let i = 0; i < this.options.concurrency; i++) {\n this.freeSlots.add(i);\n }\n }\n\n /**\n * Get current worker statistics\n */\n getStats(): StepWorkerStats {\n return { ...this.stats };\n }\n\n /**\n * Start the worker (blocking operation)\n *\n * Starts appropriate loops based on worker mode:\n * - unified: All 4 loops (executor, scheduler, heartbeat, reclamation)\n * - executor: Only executor + heartbeat loops\n * - scheduler: Only scheduler + reclamation loops\n */\n async start(): Promise<void> {\n if (this.running) {\n throw new Error(\"Worker is already running\");\n }\n\n this.running = true;\n console.log(`[StepWorker ${this.workerId}] Starting in ${this.options.mode} mode...`);\n\n // Set up signal handlers for graceful shutdown\n this.setupSignalHandlers();\n\n // Load workflow metadata and cache it\n console.log(`[StepWorker ${this.workerId}] Loading workflows from ${this.options.workflowsDir}...`);\n await this.loadWorkflows();\n\n // Register workflows with backend\n console.log(`[StepWorker ${this.workerId}] Registering workflows with backend...`);\n await this.registerWorkflows();\n\n // Start appropriate loops based on mode\n const loops: Promise<void>[] = [];\n\n if (this.options.mode === \"unified\" || this.options.mode === \"executor\") {\n // Executor loop: Claims and executes scheduled steps\n loops.push(this.executorLoop());\n console.log(`[StepWorker ${this.workerId}] Executor loop started (concurrency: ${this.options.concurrency})`);\n }\n\n if (this.options.mode === \"unified\" || this.options.mode === \"scheduler\") {\n // Scheduler loop: Finds ready steps and schedules them\n loops.push(this.schedulerLoop());\n console.log(`[StepWorker ${this.workerId}] Scheduler loop started (interval: ${this.options.schedulerInterval}ms)`);\n\n // Reclamation loop: Detects and reclaims stale steps\n loops.push(this.reclamationLoop());\n console.log(`[StepWorker ${this.workerId}] Reclamation loop started (threshold: ${this.options.staleThreshold}ms)`);\n }\n\n console.log(`[StepWorker ${this.workerId}] Started successfully`);\n\n // Wait for all loops to complete (on shutdown)\n try {\n await Promise.all(loops);\n } finally {\n clearInterval(this.heartbeatTimer as any);\n console.log(`[StepWorker ${this.workerId}] Stopped`);\n }\n }\n\n /**\n * Gracefully stop the worker\n * Waits for active steps to complete before shutting down\n */\n async stop(): Promise<void> {\n if (!this.running) {\n return;\n }\n\n console.log(`[StepWorker ${this.workerId}] Stopping... (${this.activeSteps.size} active steps)`);\n this.running = false;\n\n // Wait for active steps to complete (with timeout)\n const shutdownStart = Date.now();\n while (this.activeSteps.size > 0 && Date.now() - shutdownStart < this.options.shutdownTimeout) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n\n if (this.activeSteps.size > 0) {\n console.warn(`[StepWorker ${this.workerId}] Forced shutdown with ${this.activeSteps.size} active steps`);\n }\n\n console.log(`[StepWorker ${this.workerId}] Stopped`);\n }\n\n /**\n * Load and cache workflow metadata and steps\n */\n private async loadWorkflows(): Promise<void> {\n try {\n const workflows = await discoverWorkflows(this.options.workflowsDir);\n\n for (const workflow of workflows) {\n const steps = await discoverSteps(workflow.stepsDir);\n this.workflowCache.set(workflow.slug, {\n metadata: workflow,\n steps,\n inputSchema: workflow.inputSchema, // Cache Zod schema for validation\n });\n }\n\n console.log(`[StepWorker ${this.workerId}] Loaded ${workflows.length} workflows`);\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Failed to load workflows:`, error);\n throw error;\n }\n }\n\n /**\n * Register workflows with backend\n * Converts Zod schemas to JSON Schema and stores workflow metadata\n */\n private async registerWorkflows(): Promise<void> {\n try {\n for (const [slug, { metadata, steps, inputSchema }] of this.workflowCache) {\n // Convert Zod schema to JSON Schema if present\n let inputSchemaJSON = undefined;\n if (inputSchema) {\n try {\n inputSchemaJSON = convertZodToJSONSchema(inputSchema);\n } catch (error) {\n console.warn(\n `[StepWorker ${this.workerId}] Failed to convert schema for workflow ${slug}: ${error}`\n );\n }\n }\n\n // Build step definitions array\n const stepDefinitions = steps.map((step) => ({\n id: step.id, // Unique identifier (directory name)\n name: step.name, // Display name\n dependencies: Object.values(step.dependencies).map(dep => dep.id), // Use IDs for references\n exportOutput: step.exportOutput ?? false,\n }));\n\n // Register with backend\n await this.backend.registerWorkflow({\n slug,\n name: metadata.name,\n location: metadata.dir, // Filesystem directory path\n inputSchemaJSON,\n steps: stepDefinitions,\n });\n\n // Create workflow version\n const versionId = await calculateWorkflowHash(metadata);\n const git = await getGitInfo(metadata.dir);\n const stepManifest = steps.map((s) => s.id);\n\n await this.backend.createWorkflowVersion({\n workflowSlug: slug,\n versionId,\n createdAt: getMicrosecondTimestamp(),\n stepManifest,\n totalSteps: steps.length,\n git,\n });\n }\n\n console.log(`[StepWorker ${this.workerId}] Registered ${this.workflowCache.size} workflows`);\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Failed to register workflows:`, error);\n throw error;\n }\n }\n\n /**\n * Executor loop: Claims and executes scheduled steps\n */\n private async executorLoop(): Promise<void> {\n while (this.running) {\n try {\n // Check if we have capacity to execute more steps\n if (this.activeSteps.size >= this.options.concurrency) {\n await new Promise((resolve) => setTimeout(resolve, this.options.pollInterval));\n continue;\n }\n\n // List scheduled steps available for claiming\n const limit = this.options.concurrency - this.activeSteps.size;\n const scheduledSteps = await this.backend.listScheduledSteps({ limit });\n\n if (scheduledSteps.length === 0) {\n // No steps available, wait before polling again\n await new Promise((resolve) => setTimeout(resolve, this.options.pollInterval));\n continue;\n }\n\n // Try to claim and execute each step (up to concurrency limit)\n for (const { workflowSlug, runId, stepId } of scheduledSteps) {\n if (this.activeSteps.size >= this.options.concurrency) {\n break;\n }\n\n // Check if step still exists in current workflow definition\n const workflowData = this.workflowCache.get(workflowSlug);\n const stepExists = workflowData?.steps.some((s) => s.id === stepId);\n if (!stepExists) {\n await this.handleOrphanStep(workflowSlug, runId, stepId);\n continue;\n }\n\n // Execute step (non-blocking - fires and forgets)\n this.executeStep(workflowSlug, runId, stepId).catch((err) => {\n console.error(`[StepWorker ${this.workerId}] Error executing ${createStepKey(workflowSlug, runId, stepId)}:`, err);\n });\n }\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error in executor loop:`, error);\n await new Promise((resolve) => setTimeout(resolve, this.options.pollInterval));\n }\n }\n }\n\n /**\n * Scheduler loop: Finds ready steps and schedules them\n */\n private async schedulerLoop(): Promise<void> {\n while (this.running) {\n try {\n // List active workflows (workflows with incomplete runs)\n const activeWorkflows = await this.backend.listActiveWorkflows();\n\n for (const workflowSlug of activeWorkflows) {\n // Get workflow from cache\n const workflowData = this.workflowCache.get(workflowSlug);\n if (!workflowData) {\n console.warn(`[StepWorker ${this.workerId}] Workflow ${workflowSlug} not in cache, skipping`);\n continue;\n }\n\n let activeRuns: Array<{ runId: string }> = [];\n try {\n const result = await this.backend.listRuns({\n workflowSlug,\n status: [\"pending\", \"running\"],\n });\n activeRuns = result.runs;\n } catch {\n // Failed to list runs for this workflow\n continue;\n }\n\n for (const run of activeRuns) {\n const runId = run.runId;\n try {\n // Load workflow events to check run state\n const workflowEvents = await loadWorkflowEvents(this.backend, workflowSlug, runId);\n if (workflowEvents.length === 0) continue;\n\n // Check if workflow is already in a terminal state\n const { hasCompleted, hasFailed, hasCancelled } = getWorkflowTerminalState(workflowEvents);\n\n if (hasCompleted || hasFailed || hasCancelled) {\n continue; // Skip terminal workflows\n }\n\n // Check if workflow has been submitted but not started yet\n const hasSubmitted = hasWorkflowSubmitted(workflowEvents);\n const hasStarted = hasWorkflowStarted(workflowEvents);\n\n if (!hasSubmitted) {\n continue; // Skip workflows without RunSubmitted (shouldn't happen)\n }\n\n // If submitted but not started, emit WorkflowStarted event\n if (!hasStarted) {\n const runSubmittedEvent = getRunSubmittedEvent(workflowEvents);\n if (!runSubmittedEvent) {\n throw new Error(`No RunSubmitted event found for ${workflowSlug}/${runId}`);\n }\n\n await handleWorkflowStart(this.backend, workflowSlug, runId, {\n versionId: runSubmittedEvent.versionId,\n hasInputSchema: workflowData.inputSchema !== undefined,\n hasInput: !!(runSubmittedEvent && runSubmittedEvent.input !== undefined),\n }, workflowEvents);\n\n console.log(`[StepWorker ${this.workerId}] Started workflow ${workflowSlug}/${runId}`);\n }\n\n // Validate input (if not already validated)\n const hasValidatedInput = hasWorkflowValidatedInput(workflowEvents);\n\n if (!hasValidatedInput) {\n const workflowInput = parseWorkflowInput(workflowEvents);\n const validationResult = await validateWorkflowInput(\n this.backend,\n workflowSlug,\n runId,\n workflowInput,\n workflowData.inputSchema,\n workflowEvents\n );\n\n if (!validationResult.success) {\n console.log(\n `[StepWorker ${this.workerId}] Workflow ${workflowSlug}/${runId} failed (input validation)`\n );\n continue; // Skip to next run, don't schedule any steps\n }\n }\n\n // Track completion state\n let allStepsCompleted = true;\n let anyStepFailed = false;\n let failedStepName: string | undefined;\n\n // Get run priority for step scheduling\n const runSubmittedEventForPriority = getRunSubmittedEvent(workflowEvents);\n const runPriority = runSubmittedEventForPriority?.priority;\n\n // Load step events for state projection in a single batch query (avoids N+1)\n const allStepEvents = await this.backend.loadStepEventsForProjection(workflowSlug, runId);\n\n // For each step in the workflow, check if it should be scheduled\n for (const step of workflowData.steps) {\n // Get step events from batch-loaded map\n const stepEvents = allStepEvents.get(step.id) || [];\n\n // If step has no events yet, it's pending\n if (stepEvents.length === 0) {\n allStepsCompleted = false;\n\n // Check if dependencies are satisfied\n const canSchedule = await checkDependenciesSatisfied(\n step,\n this.backend,\n workflowSlug,\n runId,\n allStepEvents\n );\n\n // If no dependencies (initial step) or all deps completed, schedule it\n if (canSchedule) {\n await scheduleStep(\n this.backend,\n workflowSlug,\n runId,\n step.id,\n Object.keys(step.dependencies).length === 0 ? \"initial\" : \"dependency-satisfied\",\n 1,\n { priority: runPriority }\n );\n\n console.log(`[StepWorker ${this.workerId}] Scheduled ${step.name} in ${workflowSlug}/${runId}`);\n }\n } else {\n // Step has events, check its state\n const state = projectStepState(stepEvents, workflowSlug);\n\n if (state.status === \"pending\") {\n allStepsCompleted = false;\n\n // Check if dependencies are satisfied\n const canSchedule = await checkDependenciesSatisfied(\n step,\n this.backend,\n workflowSlug,\n runId,\n allStepEvents\n );\n\n if (canSchedule) {\n await scheduleStep(\n this.backend,\n workflowSlug,\n runId,\n step.id,\n \"dependency-satisfied\",\n 1,\n { priority: runPriority }\n );\n\n console.log(\n `[StepWorker ${this.workerId}] Scheduled pending step ${step.name} in ${workflowSlug}/${runId}`\n );\n }\n } else if (state.status === \"failed\" && state.terminal) {\n anyStepFailed = true;\n failedStepName = step.name;\n allStepsCompleted = false;\n } else if (state.status !== \"completed\" && state.status !== \"skipped\") {\n allStepsCompleted = false;\n }\n }\n }\n\n // Check for workflow completion\n if (allStepsCompleted) {\n await handleWorkflowCompletion(\n this.backend,\n workflowSlug,\n runId,\n workflowData.steps,\n workflowEvents\n );\n\n console.log(`[StepWorker ${this.workerId}] Workflow ${workflowSlug}/${runId} completed`);\n } else if (anyStepFailed) {\n await handleWorkflowFailure(\n this.backend,\n workflowSlug,\n runId,\n workflowData.steps,\n workflowEvents,\n failedStepName\n );\n\n console.log(\n `[StepWorker ${this.workerId}] Workflow ${workflowSlug}/${runId} failed (step: ${failedStepName})`\n );\n }\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error processing run ${runId}:`, error);\n }\n }\n }\n\n await new Promise((resolve) => setTimeout(resolve, this.options.schedulerInterval));\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error in scheduler loop:`, error);\n await new Promise((resolve) => setTimeout(resolve, this.options.schedulerInterval));\n }\n }\n }\n\n /**\n * Reclamation loop: Detects and reclaims stale steps from crashed workers\n */\n private async reclamationLoop(): Promise<void> {\n while (this.running) {\n try {\n const reclaimed = await this.backend.reclaimStaleSteps(\n this.options.staleThreshold * 1000, // Convert to microseconds\n this.workerId\n );\n\n if (reclaimed.length > 0) {\n console.log(`[StepWorker ${this.workerId}] Reclaimed ${reclaimed.length} stale steps`);\n this.stats.reclaimedSteps += reclaimed.length;\n }\n\n // For each reclaimed step, check retry policy before rescheduling\n for (const { workflowSlug, runId, stepId, attemptNumber } of reclaimed) {\n try {\n const workflowData = this.workflowCache.get(workflowSlug);\n const step = workflowData?.steps.find((s) => s.id === stepId);\n\n if (!step) {\n // Step no longer exists — mark as terminal failure\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, {\n name: \"StepRemovedError\",\n message: `Step \"${stepId}\" no longer exists in workflow \"${workflowSlug}\".`,\n }, {\n duration: 0,\n attemptNumber,\n terminal: true,\n failureReason: \"step-removed\",\n });\n continue;\n }\n\n const policies = resolveRetryPolicies(step);\n const nextAttemptNumber = attemptNumber + 1;\n\n if (!policies || policies.length === 0) {\n // No retry policy — terminal failure\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, {\n name: \"WorkerCrashError\",\n message: `Step reclaimed from stale worker (no retry policy configured)`,\n }, {\n duration: 0,\n attemptNumber,\n terminal: true,\n failureReason: \"worker-crash\",\n });\n\n console.log(`[StepWorker ${this.workerId}] Terminal failure for reclaimed step ${step.name} (no retry policy)`);\n continue;\n }\n\n const policyResult = getCurrentPolicy(nextAttemptNumber, policies);\n\n if (policyResult.exhausted) {\n // Retry limit exhausted — terminal failure\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, {\n name: \"WorkerCrashError\",\n message: `Step reclaimed from stale worker (retry limit exhausted)`,\n }, {\n duration: 0,\n attemptNumber,\n terminal: true,\n failureReason: \"exhausted-retries\",\n });\n\n const totalAttempts = getTotalAttempts(policies);\n console.log(`[StepWorker ${this.workerId}] Terminal failure for reclaimed step ${step.name} (exhausted ${totalAttempts} attempts)`);\n } else {\n // Within retry limits — reschedule\n const now = getMicrosecondTimestamp();\n\n // Get run priority for retry scheduling\n const workflowEvents = await loadWorkflowEvents(this.backend, workflowSlug, runId);\n const runSubmittedEvent = getRunSubmittedEvent(workflowEvents);\n\n await this.backend.saveStepScheduled(workflowSlug, runId, stepId, {\n availableAt: now,\n reason: \"retry\",\n attemptNumber: nextAttemptNumber,\n retryDelayMs: 0,\n priority: runSubmittedEvent?.priority,\n });\n\n const totalAttempts = getTotalAttempts(policies);\n console.log(`[StepWorker ${this.workerId}] Rescheduled reclaimed step ${step.name} (attempt ${nextAttemptNumber}/${totalAttempts})`);\n }\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error handling reclaimed step ${createStepKey(workflowSlug, runId, stepId)}:`, error);\n }\n }\n\n await new Promise((resolve) => setTimeout(resolve, this.options.staleCheckInterval));\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error in reclamation loop:`, error);\n await new Promise((resolve) => setTimeout(resolve, this.options.staleCheckInterval));\n }\n }\n }\n\n /**\n * Load existing checkpoints for a step from events\n *\n * Returns a Map from checkpoint name to array of data (by sequence number)\n */\n private async loadCheckpointsFromEvents(\n workflowSlug: string,\n runId: string,\n stepId: string\n ): Promise<Map<string, string[]>> {\n const events = await this.backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId,\n });\n\n const checkpoints = new Map<string, string[]>();\n for (const event of events) {\n if (event.type === \"StepCheckpoint\") {\n if (!checkpoints.has(event.name)) {\n checkpoints.set(event.name, []);\n }\n const arr = checkpoints.get(event.name)!;\n // Ensure array is large enough for sequence number\n while (arr.length <= event.sequenceNumber) {\n arr.push(\"\");\n }\n arr[event.sequenceNumber] = event.data;\n }\n }\n return checkpoints;\n }\n\n /**\n * Execute a single step\n */\n private async executeStep(workflowSlug: string, runId: string, stepId: string): Promise<void> {\n const stepKey = createStepKey(workflowSlug, runId, stepId);\n let startTime = getMicrosecondTimestamp(); // Microseconds - declare at function scope\n let attemptNumber: number | null = null;\n let heartbeatTimer: Timer | null = null;\n let slotIndex: number | null = null;\n\n try {\n // Get workflow and step metadata\n const workflowData = this.workflowCache.get(workflowSlug);\n if (!workflowData) {\n throw new Error(`Workflow ${workflowSlug} not found in cache`);\n }\n\n const step = workflowData.steps.find((s) => s.id === stepId);\n if (!step) {\n throw new Error(`Step ${stepId} not found in workflow ${workflowSlug}`);\n }\n\n // Acquire a slot for this step\n const slotIterator = this.freeSlots.values().next();\n if (slotIterator.done) {\n throw new Error(`No free slots available`);\n }\n slotIndex = slotIterator.value;\n this.freeSlots.delete(slotIndex);\n\n // Atomically claim the step (using stepId)\n // Note: attemptNumber in metadata is a placeholder - backend will determine actual attempt number from step state\n const claimResult = await this.backend.claimScheduledStep(workflowSlug, runId, stepId, this.workerId, {\n dependencies: Object.keys(step.dependencies),\n timestamp: startTime,\n attemptNumber: 1, // Placeholder - backend determines actual attempt from step events\n slotIndex,\n workerConcurrency: this.options.concurrency,\n });\n\n if (!claimResult) {\n console.log(`[StepWorker ${this.workerId}] Skipped ${stepKey} (already claimed)`);\n // Release slot on failed claim\n this.freeSlots.add(slotIndex);\n return;\n }\n\n attemptNumber = claimResult.attemptNumber;\n startTime = getMicrosecondTimestamp(); // Update startTime closer to actual execution\n\n // Track active step and start heartbeat (using stepId)\n const capturedSlotIndex = slotIndex;\n const heartbeatAttemptNumber = attemptNumber;\n let childPid: number | undefined;\n heartbeatTimer = setInterval(async () => {\n // Guard against late ticks after cleanup and against attempt changes.\n const tracked = this.activeSteps.get(stepKey);\n if (!tracked || tracked.attemptNumber !== heartbeatAttemptNumber) return;\n\n // Sample memory and CPU from child process if PID is available\n let resourceSnapshot: { memoryBytes: number; cpuTimeUs?: number } | undefined;\n if (childPid) {\n try {\n const ps = Bun.spawn([\"ps\", \"-o\", \"rss=,cputime=\", \"-p\", String(childPid)], {\n stdout: \"pipe\",\n stderr: \"ignore\",\n });\n const output = await new Response(ps.stdout).text();\n await ps.exited;\n const parts = output.trim().split(/\\s+/);\n const rssKB = parseInt(parts[0], 10);\n if (!isNaN(rssKB) && rssKB > 0) {\n resourceSnapshot = { memoryBytes: rssKB * 1024 };\n // Parse cputime (format: \"MM:SS.ff\" or \"H:MM:SS\")\n if (parts[1]) {\n const cpuTimeUs = parseCpuTime(parts[1]);\n if (cpuTimeUs !== null) {\n resourceSnapshot.cpuTimeUs = cpuTimeUs;\n }\n }\n }\n } catch {\n // Process may have exited, skip snapshot\n }\n }\n\n // Re-check after async sampling to avoid writing heartbeat after terminal events\n // or for a stale attempt (if the step was reclaimed and a new attempt started)\n const trackedAfter = this.activeSteps.get(stepKey);\n if (!trackedAfter || trackedAfter.attemptNumber !== heartbeatAttemptNumber) return;\n\n this.backend.saveStepHeartbeat(workflowSlug, runId, stepId, this.workerId, heartbeatAttemptNumber, {\n slotIndex: capturedSlotIndex,\n workerConcurrency: this.options.concurrency,\n resourceSnapshot,\n }).catch((err) => {\n console.error(`[StepWorker ${this.workerId}] Error sending heartbeat for ${stepKey}:`, err);\n });\n }, this.options.heartbeatInterval);\n\n const trackedTimer = heartbeatTimer!;\n\n this.activeSteps.set(stepKey, {\n workflowSlug,\n runId,\n stepId,\n attemptNumber,\n heartbeatTimer: trackedTimer,\n slotIndex: capturedSlotIndex,\n });\n\n this.stats.currentlyRunning++;\n\n console.log(`[StepWorker ${this.workerId}] Executing ${step.name} (attempt ${attemptNumber})`);\n\n // Load dependency outputs\n const dependencyOutputs = await loadDependencyOutputs(step, this.backend, workflowSlug, runId);\n\n // Load workflow input from RunSubmitted event (pre-validated by scheduler)\n const workflowEvents = await loadWorkflowEvents(this.backend, workflowSlug, runId);\n const runSubmittedEvent = getRunSubmittedEvent(workflowEvents);\n let workflowInput: unknown = undefined;\n\n if (runSubmittedEvent && runSubmittedEvent.input !== undefined) {\n // Parse input from event\n workflowInput = JSON.parse(runSubmittedEvent.input);\n }\n\n // If workflow has schema and validation succeeded, apply defaults (even when no input provided)\n if (workflowData.inputSchema) {\n const validationEvent = getWorkflowInputValidationEvent(workflowEvents);\n if (validationEvent && validationEvent.success) {\n // Re-parse with schema to get defaults (validation already confirmed this will succeed)\n // Use {} as fallback when no input provided to trigger Zod's default values\n const parseResult = workflowData.inputSchema.safeParse(workflowInput ?? {});\n if (parseResult.success) {\n workflowInput = parseResult.data;\n }\n }\n }\n\n // Build context (use step.name for display name in logs)\n const ctx = {\n runId,\n workflow: {\n slug: workflowSlug,\n name: workflowData.metadata.name,\n },\n input: workflowInput,\n log: (...args: any[]) => {\n console.log(`[${step.name}]`, ...args);\n },\n };\n\n // Execute step in subprocess with timeout\n // Priority: step timeout (most specific) → submission timeout → default 5 minutes\n const stepFile = join(step.dir, \"step.ts\");\n const submissionTimeoutMs = runSubmittedEvent && runSubmittedEvent.timeoutUs\n ? Math.floor(runSubmittedEvent.timeoutUs / 1000)\n : undefined;\n const timeout = step.timeoutMs ?? submissionTimeoutMs ?? 300000;\n\n // Load existing checkpoints for replay (from any previous attempts)\n const existingCheckpoints = await this.loadCheckpointsFromEvents(\n workflowSlug,\n runId,\n stepId\n );\n\n const abortController = new AbortController();\n const executionPromise = executeStepInProcess(\n stepFile,\n step.id, // Pass step ID for stable file paths\n dependencyOutputs,\n ctx,\n attemptNumber!,\n this.backend,\n // Real-time log emission callback\n async (log) => {\n // Create LogEntry event - use log.timestamp to preserve exact ordering\n const logEvent: Omit<import(\"@cascade-flow/backend-interface\").LogEntryEvent, \"eventId\"> = {\n workflowSlug,\n runId,\n category: \"step\",\n type: \"LogEntry\",\n stepId,\n stream: log.stream,\n message: log.message,\n attemptNumber: attemptNumber!,\n timestampUs: log.timestamp, // Use the timestamp captured by subprocess executor\n };\n await this.backend.appendEvent(workflowSlug, runId, logEvent as any);\n },\n // Checkpoint persistence callback\n async (checkpoint: CheckpointData) => {\n // Extract metadata from data and strip from payload\n let parentCheckpoint:\n | { name: string; sequenceNumber: number }\n | undefined;\n let label: string | undefined;\n let cleanedData = checkpoint.data;\n try {\n const parsed = JSON.parse(checkpoint.data);\n if (parsed?._parentCheckpoint) {\n parentCheckpoint = parsed._parentCheckpoint;\n delete parsed._parentCheckpoint;\n }\n if (parsed?._label) {\n label = parsed._label;\n delete parsed._label;\n }\n // Re-serialize without metadata fields\n cleanedData = JSON.stringify(parsed);\n } catch {\n // Ignore parse errors - use original data\n }\n\n await this.backend.saveStepCheckpoint(workflowSlug, runId, stepId, {\n name: checkpoint.name,\n sequenceNumber: checkpoint.sequenceNumber,\n attemptNumber: attemptNumber!,\n data: cleanedData,\n label,\n parentCheckpoint,\n });\n },\n // Checkpoint failure callback\n async (failure: CheckpointFailedData) => {\n await this.backend.saveStepCheckpointFailed(workflowSlug, runId, stepId, {\n name: failure.name,\n sequenceNumber: failure.sequenceNumber,\n attemptNumber: attemptNumber!,\n error: JSON.parse(failure.error),\n });\n },\n existingCheckpoints,\n {\n signal: abortController.signal,\n onPid: (pid) => { childPid = pid; },\n }\n );\n\n const timeoutTimer = setTimeout(() => {\n abortController.abort(new Error(`Step timeout after ${timeout}ms`));\n }, timeout);\n\n const execResult = await executionPromise.finally(() => {\n clearTimeout(timeoutTimer);\n });\n\n const { result: output, resourceUsage } = execResult;\n\n const endTime = getMicrosecondTimestamp(); // Microseconds\n const duration = endTime - startTime;\n\n // Stop heartbeats and release slot BEFORE writing the terminal event.\n // This prevents a StepHeartbeat from being appended after StepCompleted.\n this.finalizeActiveStep(stepKey, { heartbeatTimer, slotIndex });\n heartbeatTimer = null;\n\n // Check if our attempt is still current before saving completion.\n // If the step was reclaimed and a new attempt started, our result is stale.\n const currentStepEvents = await this.backend.loadEvents(workflowSlug, runId, { category: \"step\", stepId });\n const currentStepState = projectStepState(currentStepEvents, workflowSlug);\n\n if (currentStepState.attemptNumber > attemptNumber!) {\n console.warn(\n `[StepWorker ${this.workerId}] Discarding stale completion for ${step.name} (attempt ${attemptNumber}, current: ${currentStepState.attemptNumber})`\n );\n return;\n }\n\n // Logs are already emitted in real-time via the onLog callback\n // No need to emit them again here\n\n // Emit StepCompleted event (using stepId)\n await this.backend.saveStepComplete(\n workflowSlug,\n runId,\n stepId,\n output,\n {\n timestamp: endTime,\n duration,\n attemptNumber: attemptNumber!,\n output,\n resourceUsage,\n },\n step.exportOutput ?? false\n );\n\n if (resourceUsage) {\n const peakMB = (resourceUsage.peakMemoryBytes / (1024 * 1024)).toFixed(1);\n const cpuSec = (resourceUsage.cpuTimeTotalUs / 1_000_000).toFixed(2);\n console.log(`[StepWorker ${this.workerId}] Completed ${step.name} (peak: ${peakMB}MB, cpu: ${cpuSec}s)`);\n } else {\n console.log(`[StepWorker ${this.workerId}] Completed ${step.name}`);\n }\n\n this.stats.totalStepsProcessed++;\n\n // If in unified mode, schedule downstream steps (using stepId)\n if (this.options.mode === \"unified\") {\n const workflowData = this.workflowCache.get(workflowSlug);\n if (workflowData) {\n const scheduled = await scheduleDownstreamSteps(\n this.backend,\n workflowSlug,\n runId,\n stepId,\n workflowData.steps,\n { priority: runSubmittedEvent?.priority }\n );\n if (scheduled.length > 0) {\n console.log(\n `[StepWorker ${this.workerId}] Scheduled downstream steps: ${scheduled.join(\", \")}`\n );\n }\n }\n }\n } catch (error) {\n const failureContext = attemptNumber === null ? \"Failed to claim\" : \"Failed\";\n console.error(`[StepWorker ${this.workerId}] ${failureContext} ${stepKey}:`, error);\n\n // Stop heartbeats and release any allocated slot as early as possible.\n this.finalizeActiveStep(stepKey, { heartbeatTimer, slotIndex });\n heartbeatTimer = null;\n\n if (attemptNumber === null) {\n return;\n }\n\n this.stats.failedSteps++;\n\n // Get workflow and step metadata for retry logic\n const workflowData = this.workflowCache.get(workflowSlug);\n if (!workflowData) {\n console.error(`[StepWorker ${this.workerId}] Workflow ${workflowSlug} not found in cache`);\n return;\n }\n\n // Extract stepId from stepKey (handles nested steps with slashes)\n const stepId = extractStepId(stepKey);\n if (!stepId) {\n console.error(`[StepWorker ${this.workerId}] Invalid stepKey format: ${stepKey}`);\n return;\n }\n const step = workflowData.steps.find((s) => s.id === stepId);\n if (!step) {\n console.error(`[StepWorker ${this.workerId}] Step ${stepId} not found in workflow ${workflowSlug}`);\n return;\n }\n\n // Load step events to get current attempt number (using stepId)\n const events = await this.backend.loadEvents(workflowSlug, runId, { category: \"step\", stepId });\n const state = projectStepState(events, workflowSlug);\n const currentAttemptNumber = state.attemptNumber;\n\n const endTime = getMicrosecondTimestamp(); // Microseconds\n const duration = endTime - (state.startTime || startTime);\n\n // Extract resource usage from error if available (attached by subprocess executor)\n const errorResourceUsage = error instanceof StepExecutionError ? error.resourceUsage : undefined;\n\n // Prepare error object using centralized error serialization\n const stepError = serializeError(error);\n\n // SKIP DETECTION: Check if error is a Skip (don't retry, just mark as skipped)\n if (error instanceof Error && (error.name === \"Skip\" || error instanceof Skip)) {\n const skipError = error as Skip;\n\n await handleStepSkip(this.backend, workflowSlug, runId, stepId, skipError, duration, currentAttemptNumber);\n\n console.log(`[StepWorker ${this.workerId}] Skipped ${step.name}: ${skipError.reason || skipError.message}`);\n\n // If in unified mode, check for cascade skips\n if (this.options.mode === \"unified\") {\n const workflowData = this.workflowCache.get(workflowSlug);\n if (workflowData) {\n await cascadeSkip(this.backend, workflowSlug, runId, stepId, workflowData.steps, this.workerId);\n }\n }\n\n return; // Don't retry, don't mark as failed\n }\n\n // Check for NonRetryableError - immediate terminal failure\n if (isNonRetryableError(error)) {\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, stepError, {\n duration,\n attemptNumber: currentAttemptNumber,\n terminal: true,\n failureReason: \"execution-error\",\n resourceUsage: errorResourceUsage,\n });\n\n console.log(`[StepWorker ${this.workerId}] Terminal failure for ${step.name} (non-retryable error)`);\n return;\n }\n\n // Resolve retry policies (new format or legacy conversion)\n const policies = resolveRetryPolicies(step);\n\n // No retry policies configured - terminal failure\n if (!policies || policies.length === 0) {\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, stepError, {\n duration,\n attemptNumber: currentAttemptNumber,\n terminal: true,\n failureReason: \"execution-error\",\n resourceUsage: errorResourceUsage,\n });\n\n console.log(`[StepWorker ${this.workerId}] Terminal failure for ${step.name} (no retry policy)`);\n return;\n }\n\n // Check if we should retry based on current attempt\n const nextAttemptNumber = currentAttemptNumber + 1;\n const policyResult = getCurrentPolicy(nextAttemptNumber, policies);\n\n if (policyResult.exhausted) {\n // Terminal failure - all retry policies exhausted\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, stepError, {\n duration,\n attemptNumber: currentAttemptNumber,\n terminal: true,\n failureReason: \"exhausted-retries\",\n resourceUsage: errorResourceUsage,\n });\n\n const totalAttempts = getTotalAttempts(policies);\n console.log(`[StepWorker ${this.workerId}] Terminal failure for ${step.name} (exhausted ${totalAttempts} attempts across ${policies.length} policies)`);\n } else {\n // Not terminal - schedule retry\n // Check if RetryableError provides a custom delay override\n let retryDelayMs = computeDelay(policyResult.policy.backoff, policyResult.attemptInPolicy);\n if (isRetryableError(error) && error.delayMs !== undefined) {\n retryDelayMs = error.delayMs;\n }\n\n const nextRetryAt = getMicrosecondTimestamp() + retryDelayMs * MICROSECONDS_PER_MILLISECOND;\n\n // Get run priority for retry scheduling\n const retryWorkflowEvents = await loadWorkflowEvents(this.backend, workflowSlug, runId);\n const retryRunSubmittedEvent = getRunSubmittedEvent(retryWorkflowEvents);\n\n // Use atomic method to ensure both failure and schedule events are written together\n await this.backend.saveStepFailedAndScheduleRetry(\n workflowSlug,\n runId,\n stepId,\n stepError,\n {\n duration,\n attemptNumber: currentAttemptNumber,\n nextRetryAt,\n failureReason: \"execution-error\",\n policyIndex: policyResult.policyIndex,\n attemptInPolicy: policyResult.attemptInPolicy,\n resourceUsage: errorResourceUsage,\n },\n {\n availableAt: nextRetryAt,\n nextAttemptNumber,\n retryDelayMs,\n totalPolicies: policies.length,\n policyIndex: policyResult.policyIndex,\n attemptInPolicy: policyResult.attemptInPolicy,\n priority: retryRunSubmittedEvent?.priority,\n }\n );\n\n const totalAttempts = getTotalAttempts(policies);\n console.log(\n `[StepWorker ${this.workerId}] Scheduled retry for ${step.name} (attempt ${nextAttemptNumber}/${totalAttempts}, policy ${policyResult.policyIndex + 1}/${policies.length}, delay ${retryDelayMs}ms)`\n );\n }\n }\n }\n\n /**\n * Handle an orphan step that no longer exists in the workflow definition\n * Writes a terminal StepFailed event to prevent infinite retry loops\n */\n private async handleOrphanStep(\n workflowSlug: string,\n runId: string,\n stepId: string\n ): Promise<void> {\n const stepKey = createStepKey(workflowSlug, runId, stepId);\n console.warn(\n `[StepWorker ${this.workerId}] Orphan step detected: ${stepKey} (step removed from workflow)`\n );\n\n const error = {\n name: \"StepRemovedError\",\n message: `Step \"${stepId}\" no longer exists in workflow \"${workflowSlug}\". The workflow definition was modified after this run was submitted.`,\n };\n\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, error, {\n duration: 0,\n attemptNumber: 1,\n terminal: true,\n failureReason: \"step-removed\",\n });\n\n this.stats.failedSteps++;\n }\n\n /**\n * Set up signal handlers for graceful shutdown\n */\n private setupSignalHandlers(): void {\n const shutdown = async (signal: string) => {\n console.log(`[StepWorker ${this.workerId}] Received ${signal}, shutting down gracefully...`);\n await this.stop();\n process.exit(0);\n };\n\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n }\n\n private heartbeatTimer?: Timer;\n}\n",
5
+ "import { FileSystemBackend } from \"@cascade-flow/backend-filesystem\";\nimport type { Backend } from \"@cascade-flow/backend-interface\";\nimport { getMicrosecondTimestamp, MICROSECONDS_PER_MILLISECOND, convertZodToJSONSchema, projectStepState, serializeError } from \"@cascade-flow/backend-interface\";\nimport { hostname } from \"node:os\";\nimport { join } from \"node:path\";\nimport { discoverSteps, discoverWorkflows, executeStepInProcess, calculateWorkflowHash, getGitInfo, StepExecutionError, type LoadedStep, type CheckpointData, type CheckpointFailedData } from \"@cascade-flow/runner\";\nimport { Skip } from \"@cascade-flow/workflow\";\nimport {\n getCurrentPolicy,\n computeDelay,\n resolveRetryPolicies,\n getTotalAttempts,\n isRetryableError,\n isNonRetryableError,\n} from \"./retry\";\nimport type { ZodSchema } from \"zod\";\nimport { checkDependenciesSatisfied, loadDependencyOutputs, STATE_PROJECTION_TYPES } from \"./execution/dependency-resolver.ts\";\nimport { cascadeSkip, handleStepSkip } from \"./scheduling/skip-handler.ts\";\nimport { scheduleDownstreamSteps, scheduleStep } from \"./scheduling/step-scheduler.ts\";\nimport { createStepKey, extractStepId } from \"./utils/step-key.ts\";\nimport {\n handleWorkflowCompletion,\n handleWorkflowFailure,\n handleWorkflowStart,\n parseWorkflowInput,\n validateWorkflowInput,\n} from \"./scheduling/workflow-lifecycle.ts\";\nimport type { StepWorkerOptions, StepWorkerStats } from \"./types.ts\";\nimport {\n getRunSubmittedEvent,\n getWorkflowInputValidationEvent,\n getWorkflowTerminalState,\n hasWorkflowStarted,\n hasWorkflowSubmitted,\n hasWorkflowValidatedInput,\n loadWorkflowEvents\n} from \"./utils/event-helpers.ts\";\nimport { LogBatcher } from \"./utils/log-batcher.ts\";\n\nconst IS_LINUX = process.platform === \"linux\";\n\n/**\n * Lazily resolved Linux kernel constants (page size and clock ticks per second).\n * Queried once via `getconf` at first use to avoid hardcoding values that vary\n * across architectures (e.g. aarch64 uses 64 KiB pages).\n */\nlet procConstantsPromise: Promise<{ pageSize: number; clkTck: number }> | null = null;\n\nfunction getProcConstants(): Promise<{ pageSize: number; clkTck: number }> {\n if (!procConstantsPromise) {\n procConstantsPromise = (async () => {\n let pageSize = 4096;\n let clkTck = 100;\n try {\n const ps = Bun.spawn([\"getconf\", \"PAGESIZE\"], { stdout: \"pipe\", stderr: \"ignore\" });\n const out = await new Response(ps.stdout).text();\n await ps.exited;\n const parsed = parseInt(out.trim(), 10);\n if (!isNaN(parsed) && parsed > 0) pageSize = parsed;\n } catch {}\n try {\n const cs = Bun.spawn([\"getconf\", \"CLK_TCK\"], { stdout: \"pipe\", stderr: \"ignore\" });\n const out = await new Response(cs.stdout).text();\n await cs.exited;\n const parsed = parseInt(out.trim(), 10);\n if (!isNaN(parsed) && parsed > 0) clkTck = parsed;\n } catch {}\n return { pageSize, clkTck };\n })();\n }\n return procConstantsPromise;\n}\n\n/**\n * Read resource stats from /proc/{pid}/stat on Linux.\n * Returns memory (RSS in bytes) and CPU time (microseconds) without spawning a subprocess.\n */\nasync function readProcStats(pid: number): Promise<{ memoryBytes: number; cpuTimeUs?: number } | undefined> {\n try {\n const { pageSize, clkTck } = await getProcConstants();\n const stat = await Bun.file(`/proc/${pid}/stat`).text();\n // Fields in /proc/[pid]/stat are space-separated. The comm field (2) may contain spaces\n // and is enclosed in parentheses, so we find the closing ')' and split from there.\n const closeParen = stat.lastIndexOf(\")\");\n if (closeParen === -1) return undefined;\n const fields = stat.substring(closeParen + 2).split(\" \");\n // After comm: field index 0 = state (field 3 in stat), so:\n // utime = field 11 (index 11), stime = field 12 (index 12), rss = field 21 (index 21)\n if (fields.length < 22) return undefined;\n const utime = parseInt(fields[11]!, 10);\n const stime = parseInt(fields[12]!, 10);\n const rss = parseInt(fields[21]!, 10);\n if (isNaN(rss) || rss <= 0) return undefined;\n const memoryBytes = rss * pageSize;\n const cpuTimeUs = Math.round(((utime + stime) / clkTck) * 1_000_000);\n return { memoryBytes, cpuTimeUs };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Read resource stats using `ps` command (macOS / non-Linux fallback).\n */\nasync function readPsStats(pid: number): Promise<{ memoryBytes: number; cpuTimeUs?: number } | undefined> {\n try {\n const ps = Bun.spawn([\"ps\", \"-o\", \"rss=,cputime=\", \"-p\", String(pid)], {\n stdout: \"pipe\",\n stderr: \"ignore\",\n });\n const output = await new Response(ps.stdout).text();\n await ps.exited;\n const parts = output.trim().split(/\\s+/);\n if (parts.length === 0) return undefined;\n const rssKB = parseInt(parts[0]!, 10);\n if (isNaN(rssKB) || rssKB <= 0) return undefined;\n const result: { memoryBytes: number; cpuTimeUs?: number } = { memoryBytes: rssKB * 1024 };\n if (parts[1]) {\n const cpuTimeUs = parseCpuTime(parts[1]);\n if (cpuTimeUs !== null) {\n result.cpuTimeUs = cpuTimeUs;\n }\n }\n return result;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Read resource stats for a child process.\n * Uses /proc on Linux (no subprocess spawn), falls back to `ps` on macOS.\n */\nasync function readResourceStats(pid: number): Promise<{ memoryBytes: number; cpuTimeUs?: number } | undefined> {\n return IS_LINUX ? readProcStats(pid) : readPsStats(pid);\n}\n\n/**\n * Parse a `ps` cputime string (\"MM:SS.ff\" or \"H:MM:SS\") into microseconds.\n * Returns null if the format is unrecognised.\n */\nfunction parseCpuTime(raw: string): number | null {\n // Try \"H:MM:SS\" or \"HH:MM:SS\" (no fractional)\n const hms = raw.match(/^(\\d+):(\\d{2}):(\\d{2})$/);\n if (hms) {\n const h = parseInt(hms[1]!, 10);\n const m = parseInt(hms[2]!, 10);\n const s = parseInt(hms[3]!, 10);\n return (h * 3600 + m * 60 + s) * 1_000_000;\n }\n // Try \"MM:SS.ff\" (fractional seconds)\n const msf = raw.match(/^(\\d+):(\\d{2})\\.(\\d+)$/);\n if (msf) {\n const m = parseInt(msf[1]!, 10);\n const s = parseInt(msf[2]!, 10);\n const frac = parseFloat(`0.${msf[3]!}`);\n return Math.round((m * 60 + s + frac) * 1_000_000);\n }\n // Try \"MM:SS\" (no fractional)\n const ms = raw.match(/^(\\d+):(\\d{2})$/);\n if (ms) {\n const m = parseInt(ms[1]!, 10);\n const s = parseInt(ms[2]!, 10);\n return (m * 60 + s) * 1_000_000;\n }\n // Try \"DD-HH:MM:SS\" (day-prefixed, long-running processes)\n const dhms = raw.match(/^(\\d+)-(\\d{2}):(\\d{2}):(\\d{2})$/);\n if (dhms) {\n const d = parseInt(dhms[1]!, 10);\n const h = parseInt(dhms[2]!, 10);\n const m = parseInt(dhms[3]!, 10);\n const s = parseInt(dhms[4]!, 10);\n return (d * 86400 + h * 3600 + m * 60 + s) * 1_000_000;\n }\n return null;\n}\n\n/**\n * StepWorker - long-running process for step-level distributed workflow execution\n *\n * Architecture:\n * - Workers claim and execute individual steps (not entire workflows)\n * - Steps are scheduled when their dependencies complete\n * - Multiple workers can collaboratively execute steps from the same workflow\n * - Enables finer-grained parallelization and better resource utilization\n *\n * Features:\n * - Executor loop: Claims and executes scheduled steps\n * - Scheduler loop: Finds ready steps and schedules them\n * - Heartbeat loop: Sends heartbeats for running steps\n * - Reclamation loop: Detects and reclaims stale steps from crashed workers\n * - Retry support: Automatic retries with configurable delay\n * - Timeout enforcement: Abort-controlled cancellation of hung subprocesses\n * - Graceful shutdown: Waits for active steps to complete\n */\nexport class StepWorker {\n private workerId: string;\n private backend: Backend;\n private options: Required<StepWorkerOptions>;\n private running: boolean = false;\n private activeSteps: Map<string, {\n workflowSlug: string;\n runId: string;\n stepId: string;\n attemptNumber: number;\n heartbeatTimer: Timer;\n slotIndex: number;\n }> = new Map();\n private stats: StepWorkerStats;\n private workflowCache: Map<string, { metadata: any; steps: LoadedStep[]; inputSchema?: ZodSchema }> = new Map();\n private freeSlots: Set<number> = new Set();\n\n /**\n * Stop heartbeats and clear local running-step bookkeeping.\n *\n * This is intentionally idempotent and safe to call multiple times.\n * It is used before writing terminal step events to prevent a heartbeat\n * from being appended after StepCompleted/StepFailed/StepSkipped.\n */\n private finalizeActiveStep(\n stepKey: string,\n fallback?: { heartbeatTimer?: Timer | null; slotIndex?: number | null }\n ): void {\n const activeStep = this.activeSteps.get(stepKey);\n if (activeStep) {\n clearInterval(activeStep.heartbeatTimer);\n this.freeSlots.add(activeStep.slotIndex);\n this.activeSteps.delete(stepKey);\n this.stats.currentlyRunning--;\n return;\n }\n\n if (fallback?.heartbeatTimer) {\n clearInterval(fallback.heartbeatTimer);\n }\n if (fallback?.slotIndex !== null && fallback?.slotIndex !== undefined) {\n this.freeSlots.add(fallback.slotIndex);\n }\n }\n\n constructor(backend?: Backend, options: StepWorkerOptions = {}) {\n // Generate worker ID if not provided (using microseconds for consistency)\n this.workerId = options.workerId || `step-worker-${hostname()}-${process.pid}-${getMicrosecondTimestamp()}`;\n\n // Use provided backend or create filesystem backend\n this.backend = backend || new FileSystemBackend(options.baseDir || \"./.runs\");\n\n // Set defaults for all options\n this.options = {\n workerId: this.workerId,\n mode: options.mode ?? \"unified\",\n concurrency: options.concurrency ?? 1,\n pollInterval: options.pollInterval ?? 1000,\n heartbeatInterval: options.heartbeatInterval ?? 5000,\n staleThreshold: options.staleThreshold ?? 30000,\n staleCheckInterval: options.staleCheckInterval ?? 10000,\n schedulerInterval: options.schedulerInterval ?? 5000,\n schedulerRunBatchSize: options.schedulerRunBatchSize ?? 200,\n shutdownTimeout: options.shutdownTimeout ?? 30000,\n workflowsDir: options.workflowsDir || \"./workflows\",\n baseDir: options.baseDir || \"./.runs\",\n };\n\n this.stats = {\n workerId: this.workerId,\n mode: this.options.mode,\n startedAt: getMicrosecondTimestamp(), // Convert to microseconds\n totalStepsProcessed: 0,\n currentlyRunning: 0,\n failedSteps: 0,\n reclaimedSteps: 0,\n };\n\n // Initialize free slots (0 to concurrency-1)\n for (let i = 0; i < this.options.concurrency; i++) {\n this.freeSlots.add(i);\n }\n }\n\n /**\n * Get current worker statistics\n */\n getStats(): StepWorkerStats {\n return { ...this.stats };\n }\n\n /**\n * Start the worker (blocking operation)\n *\n * Starts appropriate loops based on worker mode:\n * - unified: All 4 loops (executor, scheduler, heartbeat, reclamation)\n * - executor: Only executor + heartbeat loops\n * - scheduler: Only scheduler + reclamation loops\n */\n async start(): Promise<void> {\n if (this.running) {\n throw new Error(\"Worker is already running\");\n }\n\n this.running = true;\n console.log(`[StepWorker ${this.workerId}] Starting in ${this.options.mode} mode...`);\n\n // Set up signal handlers for graceful shutdown\n this.setupSignalHandlers();\n\n // Load workflow metadata and cache it\n console.log(`[StepWorker ${this.workerId}] Loading workflows from ${this.options.workflowsDir}...`);\n await this.loadWorkflows();\n\n // Register workflows with backend\n console.log(`[StepWorker ${this.workerId}] Registering workflows with backend...`);\n await this.registerWorkflows();\n\n // Start appropriate loops based on mode\n const loops: Promise<void>[] = [];\n\n if (this.options.mode === \"unified\" || this.options.mode === \"executor\") {\n // Executor loop: Claims and executes scheduled steps\n loops.push(this.executorLoop());\n console.log(`[StepWorker ${this.workerId}] Executor loop started (concurrency: ${this.options.concurrency})`);\n }\n\n if (this.options.mode === \"unified\" || this.options.mode === \"scheduler\") {\n // Scheduler loop: Finds ready steps and schedules them\n loops.push(this.schedulerLoop());\n console.log(`[StepWorker ${this.workerId}] Scheduler loop started (interval: ${this.options.schedulerInterval}ms)`);\n\n // Reclamation loop: Detects and reclaims stale steps\n loops.push(this.reclamationLoop());\n console.log(`[StepWorker ${this.workerId}] Reclamation loop started (threshold: ${this.options.staleThreshold}ms)`);\n }\n\n console.log(`[StepWorker ${this.workerId}] Started successfully`);\n\n // Wait for all loops to complete (on shutdown)\n try {\n await Promise.all(loops);\n } finally {\n clearInterval(this.heartbeatTimer as any);\n console.log(`[StepWorker ${this.workerId}] Stopped`);\n }\n }\n\n /**\n * Gracefully stop the worker\n * Waits for active steps to complete before shutting down\n */\n async stop(): Promise<void> {\n if (!this.running) {\n return;\n }\n\n console.log(`[StepWorker ${this.workerId}] Stopping... (${this.activeSteps.size} active steps)`);\n this.running = false;\n\n // Wait for active steps to complete (with timeout)\n const shutdownStart = Date.now();\n while (this.activeSteps.size > 0 && Date.now() - shutdownStart < this.options.shutdownTimeout) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n\n if (this.activeSteps.size > 0) {\n console.warn(`[StepWorker ${this.workerId}] Forced shutdown with ${this.activeSteps.size} active steps`);\n }\n\n console.log(`[StepWorker ${this.workerId}] Stopped`);\n }\n\n /**\n * Load and cache workflow metadata and steps\n */\n private async loadWorkflows(): Promise<void> {\n try {\n const workflows = await discoverWorkflows(this.options.workflowsDir);\n\n for (const workflow of workflows) {\n const steps = await discoverSteps(workflow.stepsDir);\n this.workflowCache.set(workflow.slug, {\n metadata: workflow,\n steps,\n inputSchema: workflow.inputSchema, // Cache Zod schema for validation\n });\n }\n\n console.log(`[StepWorker ${this.workerId}] Loaded ${workflows.length} workflows`);\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Failed to load workflows:`, error);\n throw error;\n }\n }\n\n /**\n * Register workflows with backend\n * Converts Zod schemas to JSON Schema and stores workflow metadata\n */\n private async registerWorkflows(): Promise<void> {\n try {\n for (const [slug, { metadata, steps, inputSchema }] of this.workflowCache) {\n // Convert Zod schema to JSON Schema if present\n let inputSchemaJSON = undefined;\n if (inputSchema) {\n try {\n inputSchemaJSON = convertZodToJSONSchema(inputSchema);\n } catch (error) {\n console.warn(\n `[StepWorker ${this.workerId}] Failed to convert schema for workflow ${slug}: ${error}`\n );\n }\n }\n\n // Build step definitions array\n const stepDefinitions = steps.map((step) => ({\n id: step.id, // Unique identifier (directory name)\n name: step.name, // Display name\n dependencies: Object.values(step.dependencies).map(dep => dep.id), // Use IDs for references\n exportOutput: step.exportOutput ?? false,\n }));\n\n // Register with backend\n await this.backend.registerWorkflow({\n slug,\n name: metadata.name,\n location: metadata.dir, // Filesystem directory path\n inputSchemaJSON,\n steps: stepDefinitions,\n });\n\n // Create workflow version\n const versionId = await calculateWorkflowHash(metadata);\n const git = await getGitInfo(metadata.dir);\n const stepManifest = steps.map((s) => s.id);\n\n await this.backend.createWorkflowVersion({\n workflowSlug: slug,\n versionId,\n createdAt: getMicrosecondTimestamp(),\n stepManifest,\n totalSteps: steps.length,\n git,\n });\n }\n\n console.log(`[StepWorker ${this.workerId}] Registered ${this.workflowCache.size} workflows`);\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Failed to register workflows:`, error);\n throw error;\n }\n }\n\n /**\n * Executor loop: Claims and executes scheduled steps\n */\n private async executorLoop(): Promise<void> {\n while (this.running) {\n try {\n // Check if we have capacity to execute more steps\n if (this.activeSteps.size >= this.options.concurrency) {\n await new Promise((resolve) => setTimeout(resolve, this.options.pollInterval));\n continue;\n }\n\n // List scheduled steps available for claiming\n const limit = this.options.concurrency - this.activeSteps.size;\n const scheduledSteps = await this.backend.listScheduledSteps({ limit });\n\n if (scheduledSteps.length === 0) {\n // No steps available, wait before polling again\n await new Promise((resolve) => setTimeout(resolve, this.options.pollInterval));\n continue;\n }\n\n // Try to claim and execute each step (up to concurrency limit)\n for (const { workflowSlug, runId, stepId } of scheduledSteps) {\n if (this.activeSteps.size >= this.options.concurrency) {\n break;\n }\n\n // Check if step still exists in current workflow definition\n const workflowData = this.workflowCache.get(workflowSlug);\n const stepExists = workflowData?.steps.some((s) => s.id === stepId);\n if (!stepExists) {\n await this.handleOrphanStep(workflowSlug, runId, stepId);\n continue;\n }\n\n // Execute step (non-blocking - fires and forgets)\n this.executeStep(workflowSlug, runId, stepId).catch((err) => {\n console.error(`[StepWorker ${this.workerId}] Error executing ${createStepKey(workflowSlug, runId, stepId)}:`, err);\n });\n }\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error in executor loop:`, error);\n await new Promise((resolve) => setTimeout(resolve, this.options.pollInterval));\n }\n }\n }\n\n /**\n * Scheduler loop: Finds ready steps and schedules them\n */\n private async schedulerLoop(): Promise<void> {\n while (this.running) {\n try {\n // List active workflows (workflows with incomplete runs)\n const activeWorkflows = await this.backend.listActiveWorkflows();\n\n for (const workflowSlug of activeWorkflows) {\n // Get workflow from cache\n const workflowData = this.workflowCache.get(workflowSlug);\n if (!workflowData) {\n console.warn(`[StepWorker ${this.workerId}] Workflow ${workflowSlug} not in cache, skipping`);\n continue;\n }\n\n let activeRuns: Array<{ runId: string }> = [];\n try {\n const result = await this.backend.listRuns({\n workflowSlug,\n status: [\"pending\", \"running\"],\n });\n activeRuns = result.runs;\n } catch {\n // Failed to list runs for this workflow\n continue;\n }\n\n for (const run of activeRuns) {\n const runId = run.runId;\n try {\n // Load workflow events to check run state\n const workflowEvents = await loadWorkflowEvents(this.backend, workflowSlug, runId);\n if (workflowEvents.length === 0) continue;\n\n // Check if workflow is already in a terminal state\n const { hasCompleted, hasFailed, hasCancelled } = getWorkflowTerminalState(workflowEvents);\n\n if (hasCompleted || hasFailed || hasCancelled) {\n continue; // Skip terminal workflows\n }\n\n // Check if workflow has been submitted but not started yet\n const hasSubmitted = hasWorkflowSubmitted(workflowEvents);\n const hasStarted = hasWorkflowStarted(workflowEvents);\n\n if (!hasSubmitted) {\n continue; // Skip workflows without RunSubmitted (shouldn't happen)\n }\n\n // If submitted but not started, emit WorkflowStarted event\n if (!hasStarted) {\n const runSubmittedEvent = getRunSubmittedEvent(workflowEvents);\n if (!runSubmittedEvent) {\n throw new Error(`No RunSubmitted event found for ${workflowSlug}/${runId}`);\n }\n\n await handleWorkflowStart(this.backend, workflowSlug, runId, {\n versionId: runSubmittedEvent.versionId,\n hasInputSchema: workflowData.inputSchema !== undefined,\n hasInput: !!(runSubmittedEvent && runSubmittedEvent.input !== undefined),\n }, workflowEvents);\n\n console.log(`[StepWorker ${this.workerId}] Started workflow ${workflowSlug}/${runId}`);\n }\n\n // Validate input (if not already validated)\n const hasValidatedInput = hasWorkflowValidatedInput(workflowEvents);\n\n if (!hasValidatedInput) {\n const workflowInput = parseWorkflowInput(workflowEvents);\n const validationResult = await validateWorkflowInput(\n this.backend,\n workflowSlug,\n runId,\n workflowInput,\n workflowData.inputSchema,\n workflowEvents\n );\n\n if (!validationResult.success) {\n console.log(\n `[StepWorker ${this.workerId}] Workflow ${workflowSlug}/${runId} failed (input validation)`\n );\n continue; // Skip to next run, don't schedule any steps\n }\n }\n\n // Track completion state\n let allStepsCompleted = true;\n let anyStepFailed = false;\n let failedStepName: string | undefined;\n\n // Get run priority for step scheduling\n const runSubmittedEventForPriority = getRunSubmittedEvent(workflowEvents);\n const runPriority = runSubmittedEventForPriority?.priority;\n\n // Load step events for state projection in a single batch query (avoids N+1)\n const allStepEvents = await this.backend.loadStepEventsForProjection(workflowSlug, runId);\n\n // For each step in the workflow, check if it should be scheduled\n for (const step of workflowData.steps) {\n // Get step events from batch-loaded map\n const stepEvents = allStepEvents.get(step.id) || [];\n\n // If step has no events yet, it's pending\n if (stepEvents.length === 0) {\n allStepsCompleted = false;\n\n // Check if dependencies are satisfied\n const canSchedule = await checkDependenciesSatisfied(\n step,\n this.backend,\n workflowSlug,\n runId,\n allStepEvents\n );\n\n // If no dependencies (initial step) or all deps completed, schedule it\n if (canSchedule) {\n await scheduleStep(\n this.backend,\n workflowSlug,\n runId,\n step.id,\n Object.keys(step.dependencies).length === 0 ? \"initial\" : \"dependency-satisfied\",\n 1,\n { priority: runPriority }\n );\n\n console.log(`[StepWorker ${this.workerId}] Scheduled ${step.name} in ${workflowSlug}/${runId}`);\n }\n } else {\n // Step has events, check its state\n const state = projectStepState(stepEvents, workflowSlug);\n\n if (state.status === \"pending\") {\n allStepsCompleted = false;\n\n // Check if dependencies are satisfied\n const canSchedule = await checkDependenciesSatisfied(\n step,\n this.backend,\n workflowSlug,\n runId,\n allStepEvents\n );\n\n if (canSchedule) {\n await scheduleStep(\n this.backend,\n workflowSlug,\n runId,\n step.id,\n \"dependency-satisfied\",\n 1,\n { priority: runPriority }\n );\n\n console.log(\n `[StepWorker ${this.workerId}] Scheduled pending step ${step.name} in ${workflowSlug}/${runId}`\n );\n }\n } else if (state.status === \"failed\" && state.terminal) {\n anyStepFailed = true;\n failedStepName = step.name;\n allStepsCompleted = false;\n } else if (state.status !== \"completed\" && state.status !== \"skipped\") {\n allStepsCompleted = false;\n }\n }\n }\n\n // Check for workflow completion\n if (allStepsCompleted) {\n await handleWorkflowCompletion(\n this.backend,\n workflowSlug,\n runId,\n workflowData.steps,\n workflowEvents\n );\n\n console.log(`[StepWorker ${this.workerId}] Workflow ${workflowSlug}/${runId} completed`);\n } else if (anyStepFailed) {\n await handleWorkflowFailure(\n this.backend,\n workflowSlug,\n runId,\n workflowData.steps,\n workflowEvents,\n failedStepName\n );\n\n console.log(\n `[StepWorker ${this.workerId}] Workflow ${workflowSlug}/${runId} failed (step: ${failedStepName})`\n );\n }\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error processing run ${runId}:`, error);\n }\n }\n }\n\n await new Promise((resolve) => setTimeout(resolve, this.options.schedulerInterval));\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error in scheduler loop:`, error);\n await new Promise((resolve) => setTimeout(resolve, this.options.schedulerInterval));\n }\n }\n }\n\n /**\n * Reclamation loop: Detects and reclaims stale steps from crashed workers\n */\n private async reclamationLoop(): Promise<void> {\n while (this.running) {\n try {\n const reclaimed = await this.backend.reclaimStaleSteps(\n this.options.staleThreshold * 1000, // Convert to microseconds\n this.workerId\n );\n\n if (reclaimed.length > 0) {\n console.log(`[StepWorker ${this.workerId}] Reclaimed ${reclaimed.length} stale steps`);\n this.stats.reclaimedSteps += reclaimed.length;\n }\n\n // For each reclaimed step, check retry policy before rescheduling\n for (const { workflowSlug, runId, stepId, attemptNumber } of reclaimed) {\n try {\n const workflowData = this.workflowCache.get(workflowSlug);\n const step = workflowData?.steps.find((s) => s.id === stepId);\n\n if (!step) {\n // Step no longer exists — mark as terminal failure\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, {\n name: \"StepRemovedError\",\n message: `Step \"${stepId}\" no longer exists in workflow \"${workflowSlug}\".`,\n }, {\n duration: 0,\n attemptNumber,\n terminal: true,\n failureReason: \"step-removed\",\n });\n continue;\n }\n\n const policies = resolveRetryPolicies(step);\n const nextAttemptNumber = attemptNumber + 1;\n\n if (!policies || policies.length === 0) {\n // No retry policy — terminal failure\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, {\n name: \"WorkerCrashError\",\n message: `Step reclaimed from stale worker (no retry policy configured)`,\n }, {\n duration: 0,\n attemptNumber,\n terminal: true,\n failureReason: \"worker-crash\",\n });\n\n console.log(`[StepWorker ${this.workerId}] Terminal failure for reclaimed step ${step.name} (no retry policy)`);\n continue;\n }\n\n const policyResult = getCurrentPolicy(nextAttemptNumber, policies);\n\n if (policyResult.exhausted) {\n // Retry limit exhausted — terminal failure\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, {\n name: \"WorkerCrashError\",\n message: `Step reclaimed from stale worker (retry limit exhausted)`,\n }, {\n duration: 0,\n attemptNumber,\n terminal: true,\n failureReason: \"exhausted-retries\",\n });\n\n const totalAttempts = getTotalAttempts(policies);\n console.log(`[StepWorker ${this.workerId}] Terminal failure for reclaimed step ${step.name} (exhausted ${totalAttempts} attempts)`);\n } else {\n // Within retry limits — reschedule\n const now = getMicrosecondTimestamp();\n\n // Get run priority for retry scheduling\n const workflowEvents = await loadWorkflowEvents(this.backend, workflowSlug, runId);\n const runSubmittedEvent = getRunSubmittedEvent(workflowEvents);\n\n await this.backend.saveStepScheduled(workflowSlug, runId, stepId, {\n availableAt: now,\n reason: \"retry\",\n attemptNumber: nextAttemptNumber,\n retryDelayMs: 0,\n priority: runSubmittedEvent?.priority,\n });\n\n const totalAttempts = getTotalAttempts(policies);\n console.log(`[StepWorker ${this.workerId}] Rescheduled reclaimed step ${step.name} (attempt ${nextAttemptNumber}/${totalAttempts})`);\n }\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error handling reclaimed step ${createStepKey(workflowSlug, runId, stepId)}:`, error);\n }\n }\n\n await new Promise((resolve) => setTimeout(resolve, this.options.staleCheckInterval));\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error in reclamation loop:`, error);\n await new Promise((resolve) => setTimeout(resolve, this.options.staleCheckInterval));\n }\n }\n }\n\n /**\n * Load existing checkpoints for a step from events\n *\n * Returns a Map from checkpoint name to array of data (by sequence number)\n */\n private async loadCheckpointsFromEvents(\n workflowSlug: string,\n runId: string,\n stepId: string\n ): Promise<Map<string, string[]>> {\n const events = await this.backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId,\n });\n\n const checkpoints = new Map<string, string[]>();\n for (const event of events) {\n if (event.type === \"StepCheckpoint\") {\n if (!checkpoints.has(event.name)) {\n checkpoints.set(event.name, []);\n }\n const arr = checkpoints.get(event.name)!;\n // Ensure array is large enough for sequence number\n while (arr.length <= event.sequenceNumber) {\n arr.push(\"\");\n }\n arr[event.sequenceNumber] = event.data;\n }\n }\n return checkpoints;\n }\n\n /**\n * Execute a single step\n */\n private async executeStep(workflowSlug: string, runId: string, stepId: string): Promise<void> {\n const stepKey = createStepKey(workflowSlug, runId, stepId);\n let startTime = getMicrosecondTimestamp(); // Microseconds - declare at function scope\n let attemptNumber: number | null = null;\n let heartbeatTimer: Timer | null = null;\n let slotIndex: number | null = null;\n const logBatcher = new LogBatcher(this.backend);\n\n try {\n // Get workflow and step metadata\n const workflowData = this.workflowCache.get(workflowSlug);\n if (!workflowData) {\n throw new Error(`Workflow ${workflowSlug} not found in cache`);\n }\n\n const step = workflowData.steps.find((s) => s.id === stepId);\n if (!step) {\n throw new Error(`Step ${stepId} not found in workflow ${workflowSlug}`);\n }\n\n // Acquire a slot for this step\n const slotIterator = this.freeSlots.values().next();\n if (slotIterator.done) {\n throw new Error(`No free slots available`);\n }\n slotIndex = slotIterator.value;\n this.freeSlots.delete(slotIndex);\n\n // Atomically claim the step (using stepId)\n // Note: attemptNumber in metadata is a placeholder - backend will determine actual attempt number from step state\n const claimResult = await this.backend.claimScheduledStep(workflowSlug, runId, stepId, this.workerId, {\n dependencies: Object.keys(step.dependencies),\n timestamp: startTime,\n attemptNumber: 1, // Placeholder - backend determines actual attempt from step events\n slotIndex,\n workerConcurrency: this.options.concurrency,\n });\n\n if (!claimResult) {\n console.log(`[StepWorker ${this.workerId}] Skipped ${stepKey} (already claimed)`);\n // Release slot on failed claim\n this.freeSlots.add(slotIndex);\n return;\n }\n\n attemptNumber = claimResult.attemptNumber;\n startTime = getMicrosecondTimestamp(); // Update startTime closer to actual execution\n\n // Track active step and start heartbeat (using stepId)\n const capturedSlotIndex = slotIndex;\n const heartbeatAttemptNumber = attemptNumber;\n let childPid: number | undefined;\n heartbeatTimer = setInterval(async () => {\n // Guard against late ticks after cleanup and against attempt changes.\n const tracked = this.activeSteps.get(stepKey);\n if (!tracked || tracked.attemptNumber !== heartbeatAttemptNumber) return;\n\n // Sample memory and CPU from child process if PID is available\n // Uses /proc on Linux (no subprocess), falls back to `ps` on macOS\n let resourceSnapshot: { memoryBytes: number; cpuTimeUs?: number } | undefined;\n if (childPid) {\n resourceSnapshot = await readResourceStats(childPid);\n }\n\n // Re-check after async sampling to avoid writing heartbeat after terminal events\n // or for a stale attempt (if the step was reclaimed and a new attempt started)\n const trackedAfter = this.activeSteps.get(stepKey);\n if (!trackedAfter || trackedAfter.attemptNumber !== heartbeatAttemptNumber) return;\n\n this.backend.saveStepHeartbeat(workflowSlug, runId, stepId, this.workerId, heartbeatAttemptNumber, {\n slotIndex: capturedSlotIndex,\n workerConcurrency: this.options.concurrency,\n resourceSnapshot,\n }).catch((err) => {\n console.error(`[StepWorker ${this.workerId}] Error sending heartbeat for ${stepKey}:`, err);\n });\n }, this.options.heartbeatInterval);\n\n const trackedTimer = heartbeatTimer!;\n\n this.activeSteps.set(stepKey, {\n workflowSlug,\n runId,\n stepId,\n attemptNumber,\n heartbeatTimer: trackedTimer,\n slotIndex: capturedSlotIndex,\n });\n\n this.stats.currentlyRunning++;\n\n console.log(`[StepWorker ${this.workerId}] Executing ${step.name} (attempt ${attemptNumber})`);\n\n // Load dependency outputs\n const dependencyOutputs = await loadDependencyOutputs(step, this.backend, workflowSlug, runId);\n\n // Load workflow input from RunSubmitted event (pre-validated by scheduler)\n const workflowEvents = await loadWorkflowEvents(this.backend, workflowSlug, runId);\n const runSubmittedEvent = getRunSubmittedEvent(workflowEvents);\n let workflowInput: unknown = undefined;\n\n if (runSubmittedEvent && runSubmittedEvent.input !== undefined) {\n // Parse input from event\n workflowInput = JSON.parse(runSubmittedEvent.input);\n }\n\n // If workflow has schema and validation succeeded, apply defaults (even when no input provided)\n if (workflowData.inputSchema) {\n const validationEvent = getWorkflowInputValidationEvent(workflowEvents);\n if (validationEvent && validationEvent.success) {\n // Re-parse with schema to get defaults (validation already confirmed this will succeed)\n // Use {} as fallback when no input provided to trigger Zod's default values\n const parseResult = workflowData.inputSchema.safeParse(workflowInput ?? {});\n if (parseResult.success) {\n workflowInput = parseResult.data;\n }\n }\n }\n\n // Build context (use step.name for display name in logs)\n const ctx = {\n runId,\n workflow: {\n slug: workflowSlug,\n name: workflowData.metadata.name,\n },\n input: workflowInput,\n log: (...args: any[]) => {\n console.log(`[${step.name}]`, ...args);\n },\n };\n\n // Execute step in subprocess with timeout\n // Priority: step timeout (most specific) → submission timeout → default 5 minutes\n const stepFile = join(step.dir, \"step.ts\");\n const submissionTimeoutMs = runSubmittedEvent && runSubmittedEvent.timeoutUs\n ? Math.floor(runSubmittedEvent.timeoutUs / 1000)\n : undefined;\n const timeout = step.timeoutMs ?? submissionTimeoutMs ?? 300000;\n\n // Load existing checkpoints for replay (from any previous attempts)\n const existingCheckpoints = await this.loadCheckpointsFromEvents(\n workflowSlug,\n runId,\n stepId\n );\n\n const abortController = new AbortController();\n const executionPromise = executeStepInProcess(\n stepFile,\n step.id, // Pass step ID for stable file paths\n dependencyOutputs,\n ctx,\n attemptNumber!,\n this.backend,\n // Real-time log emission callback — batched to reduce DB writes\n (log) => {\n // Create LogEntry event - use log.timestamp to preserve exact ordering\n const logEvent: Omit<import(\"@cascade-flow/backend-interface\").LogEntryEvent, \"eventId\"> = {\n workflowSlug,\n runId,\n category: \"step\",\n type: \"LogEntry\",\n stepId,\n stream: log.stream,\n message: log.message,\n attemptNumber: attemptNumber!,\n timestampUs: log.timestamp, // Use the timestamp captured by subprocess executor\n };\n logBatcher.add(workflowSlug, runId, logEvent as any);\n },\n // Checkpoint persistence callback\n async (checkpoint: CheckpointData) => {\n // Extract metadata from data and strip from payload\n let parentCheckpoint:\n | { name: string; sequenceNumber: number }\n | undefined;\n let label: string | undefined;\n let cleanedData = checkpoint.data;\n try {\n const parsed = JSON.parse(checkpoint.data);\n if (parsed?._parentCheckpoint) {\n parentCheckpoint = parsed._parentCheckpoint;\n delete parsed._parentCheckpoint;\n }\n if (parsed?._label) {\n label = parsed._label;\n delete parsed._label;\n }\n // Re-serialize without metadata fields\n cleanedData = JSON.stringify(parsed);\n } catch {\n // Ignore parse errors - use original data\n }\n\n await this.backend.saveStepCheckpoint(workflowSlug, runId, stepId, {\n name: checkpoint.name,\n sequenceNumber: checkpoint.sequenceNumber,\n attemptNumber: attemptNumber!,\n data: cleanedData,\n label,\n parentCheckpoint,\n });\n },\n // Checkpoint failure callback\n async (failure: CheckpointFailedData) => {\n await this.backend.saveStepCheckpointFailed(workflowSlug, runId, stepId, {\n name: failure.name,\n sequenceNumber: failure.sequenceNumber,\n attemptNumber: attemptNumber!,\n error: JSON.parse(failure.error),\n });\n },\n existingCheckpoints,\n {\n signal: abortController.signal,\n onPid: (pid) => { childPid = pid; },\n }\n );\n\n const timeoutTimer = setTimeout(() => {\n abortController.abort(new Error(`Step timeout after ${timeout}ms`));\n }, timeout);\n\n const execResult = await executionPromise.finally(() => {\n clearTimeout(timeoutTimer);\n });\n\n const { result: output, resourceUsage } = execResult;\n\n const endTime = getMicrosecondTimestamp(); // Microseconds\n const duration = endTime - startTime;\n\n // Drain buffered log events before writing terminal event\n await logBatcher.drain();\n\n // Stop heartbeats and release slot BEFORE writing the terminal event.\n // This prevents a StepHeartbeat from being appended after StepCompleted.\n this.finalizeActiveStep(stepKey, { heartbeatTimer, slotIndex });\n heartbeatTimer = null;\n\n // Check if our attempt is still current before saving completion.\n // If the step was reclaimed and a new attempt started, our result is stale.\n const currentStepEvents = await this.backend.loadEvents(workflowSlug, runId, { category: \"step\", stepId, types: STATE_PROJECTION_TYPES });\n const currentStepState = projectStepState(currentStepEvents, workflowSlug);\n\n if (currentStepState.attemptNumber > attemptNumber!) {\n console.warn(\n `[StepWorker ${this.workerId}] Discarding stale completion for ${step.name} (attempt ${attemptNumber}, current: ${currentStepState.attemptNumber})`\n );\n return;\n }\n\n // Logs are already emitted in real-time via the onLog callback (batched)\n // No need to emit them again here\n\n // Emit StepCompleted event (using stepId)\n await this.backend.saveStepComplete(\n workflowSlug,\n runId,\n stepId,\n output,\n {\n timestamp: endTime,\n duration,\n attemptNumber: attemptNumber!,\n output,\n resourceUsage,\n },\n step.exportOutput ?? false\n );\n\n if (resourceUsage) {\n const peakMB = (resourceUsage.peakMemoryBytes / (1024 * 1024)).toFixed(1);\n const cpuSec = (resourceUsage.cpuTimeTotalUs / 1_000_000).toFixed(2);\n console.log(`[StepWorker ${this.workerId}] Completed ${step.name} (peak: ${peakMB}MB, cpu: ${cpuSec}s)`);\n } else {\n console.log(`[StepWorker ${this.workerId}] Completed ${step.name}`);\n }\n\n this.stats.totalStepsProcessed++;\n\n // If in unified mode, schedule downstream steps (using stepId)\n if (this.options.mode === \"unified\") {\n const workflowData = this.workflowCache.get(workflowSlug);\n if (workflowData) {\n const scheduled = await scheduleDownstreamSteps(\n this.backend,\n workflowSlug,\n runId,\n stepId,\n workflowData.steps,\n { priority: runSubmittedEvent?.priority }\n );\n if (scheduled.length > 0) {\n console.log(\n `[StepWorker ${this.workerId}] Scheduled downstream steps: ${scheduled.join(\", \")}`\n );\n }\n }\n }\n } catch (error) {\n const failureContext = attemptNumber === null ? \"Failed to claim\" : \"Failed\";\n console.error(`[StepWorker ${this.workerId}] ${failureContext} ${stepKey}:`, error);\n\n // Drain buffered logs before writing failure event\n await logBatcher.drain().catch(() => {});\n\n // Stop heartbeats and release any allocated slot as early as possible.\n this.finalizeActiveStep(stepKey, { heartbeatTimer, slotIndex });\n heartbeatTimer = null;\n\n if (attemptNumber === null) {\n return;\n }\n\n this.stats.failedSteps++;\n\n // Get workflow and step metadata for retry logic\n const workflowData = this.workflowCache.get(workflowSlug);\n if (!workflowData) {\n console.error(`[StepWorker ${this.workerId}] Workflow ${workflowSlug} not found in cache`);\n return;\n }\n\n // Extract stepId from stepKey (handles nested steps with slashes)\n const stepId = extractStepId(stepKey);\n if (!stepId) {\n console.error(`[StepWorker ${this.workerId}] Invalid stepKey format: ${stepKey}`);\n return;\n }\n const step = workflowData.steps.find((s) => s.id === stepId);\n if (!step) {\n console.error(`[StepWorker ${this.workerId}] Step ${stepId} not found in workflow ${workflowSlug}`);\n return;\n }\n\n // Load step events to get current attempt number (using stepId)\n const events = await this.backend.loadEvents(workflowSlug, runId, { category: \"step\", stepId });\n const state = projectStepState(events, workflowSlug);\n const currentAttemptNumber = state.attemptNumber;\n\n const endTime = getMicrosecondTimestamp(); // Microseconds\n const duration = endTime - (state.startTime || startTime);\n\n // Extract resource usage from error if available (attached by subprocess executor)\n const errorResourceUsage = error instanceof StepExecutionError ? error.resourceUsage : undefined;\n\n // Prepare error object using centralized error serialization\n const stepError = serializeError(error);\n\n // SKIP DETECTION: Check if error is a Skip (don't retry, just mark as skipped)\n if (error instanceof Error && (error.name === \"Skip\" || error instanceof Skip)) {\n const skipError = error as Skip;\n\n await handleStepSkip(this.backend, workflowSlug, runId, stepId, skipError, duration, currentAttemptNumber);\n\n console.log(`[StepWorker ${this.workerId}] Skipped ${step.name}: ${skipError.reason || skipError.message}`);\n\n // If in unified mode, check for cascade skips\n if (this.options.mode === \"unified\") {\n const workflowData = this.workflowCache.get(workflowSlug);\n if (workflowData) {\n await cascadeSkip(this.backend, workflowSlug, runId, stepId, workflowData.steps, this.workerId);\n }\n }\n\n return; // Don't retry, don't mark as failed\n }\n\n // Check for NonRetryableError - immediate terminal failure\n if (isNonRetryableError(error)) {\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, stepError, {\n duration,\n attemptNumber: currentAttemptNumber,\n terminal: true,\n failureReason: \"execution-error\",\n resourceUsage: errorResourceUsage,\n });\n\n console.log(`[StepWorker ${this.workerId}] Terminal failure for ${step.name} (non-retryable error)`);\n return;\n }\n\n // Resolve retry policies (new format or legacy conversion)\n const policies = resolveRetryPolicies(step);\n\n // No retry policies configured - terminal failure\n if (!policies || policies.length === 0) {\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, stepError, {\n duration,\n attemptNumber: currentAttemptNumber,\n terminal: true,\n failureReason: \"execution-error\",\n resourceUsage: errorResourceUsage,\n });\n\n console.log(`[StepWorker ${this.workerId}] Terminal failure for ${step.name} (no retry policy)`);\n return;\n }\n\n // Check if we should retry based on current attempt\n const nextAttemptNumber = currentAttemptNumber + 1;\n const policyResult = getCurrentPolicy(nextAttemptNumber, policies);\n\n if (policyResult.exhausted) {\n // Terminal failure - all retry policies exhausted\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, stepError, {\n duration,\n attemptNumber: currentAttemptNumber,\n terminal: true,\n failureReason: \"exhausted-retries\",\n resourceUsage: errorResourceUsage,\n });\n\n const totalAttempts = getTotalAttempts(policies);\n console.log(`[StepWorker ${this.workerId}] Terminal failure for ${step.name} (exhausted ${totalAttempts} attempts across ${policies.length} policies)`);\n } else {\n // Not terminal - schedule retry\n // Check if RetryableError provides a custom delay override\n let retryDelayMs = computeDelay(policyResult.policy.backoff, policyResult.attemptInPolicy);\n if (isRetryableError(error) && error.delayMs !== undefined) {\n retryDelayMs = error.delayMs;\n }\n\n const nextRetryAt = getMicrosecondTimestamp() + retryDelayMs * MICROSECONDS_PER_MILLISECOND;\n\n // Get run priority for retry scheduling\n const retryWorkflowEvents = await loadWorkflowEvents(this.backend, workflowSlug, runId);\n const retryRunSubmittedEvent = getRunSubmittedEvent(retryWorkflowEvents);\n\n // Use atomic method to ensure both failure and schedule events are written together\n await this.backend.saveStepFailedAndScheduleRetry(\n workflowSlug,\n runId,\n stepId,\n stepError,\n {\n duration,\n attemptNumber: currentAttemptNumber,\n nextRetryAt,\n failureReason: \"execution-error\",\n policyIndex: policyResult.policyIndex,\n attemptInPolicy: policyResult.attemptInPolicy,\n resourceUsage: errorResourceUsage,\n },\n {\n availableAt: nextRetryAt,\n nextAttemptNumber,\n retryDelayMs,\n totalPolicies: policies.length,\n policyIndex: policyResult.policyIndex,\n attemptInPolicy: policyResult.attemptInPolicy,\n priority: retryRunSubmittedEvent?.priority,\n }\n );\n\n const totalAttempts = getTotalAttempts(policies);\n console.log(\n `[StepWorker ${this.workerId}] Scheduled retry for ${step.name} (attempt ${nextAttemptNumber}/${totalAttempts}, policy ${policyResult.policyIndex + 1}/${policies.length}, delay ${retryDelayMs}ms)`\n );\n }\n }\n }\n\n /**\n * Handle an orphan step that no longer exists in the workflow definition\n * Writes a terminal StepFailed event to prevent infinite retry loops\n */\n private async handleOrphanStep(\n workflowSlug: string,\n runId: string,\n stepId: string\n ): Promise<void> {\n const stepKey = createStepKey(workflowSlug, runId, stepId);\n console.warn(\n `[StepWorker ${this.workerId}] Orphan step detected: ${stepKey} (step removed from workflow)`\n );\n\n const error = {\n name: \"StepRemovedError\",\n message: `Step \"${stepId}\" no longer exists in workflow \"${workflowSlug}\". The workflow definition was modified after this run was submitted.`,\n };\n\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, error, {\n duration: 0,\n attemptNumber: 1,\n terminal: true,\n failureReason: \"step-removed\",\n });\n\n this.stats.failedSteps++;\n }\n\n /**\n * Set up signal handlers for graceful shutdown\n */\n private setupSignalHandlers(): void {\n const shutdown = async (signal: string) => {\n console.log(`[StepWorker ${this.workerId}] Received ${signal}, shutting down gracefully...`);\n await this.stop();\n process.exit(0);\n };\n\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n }\n\n private heartbeatTimer?: Timer;\n}\n",
6
6
  "/**\n * Retry policy resolution and delay computation\n *\n * This module provides stateless functions for computing retry behavior\n * from attempt numbers and policy configurations.\n */\n\nimport type { RetryPolicy, BackoffConfig } from \"@cascade-flow/workflow\";\n\n/**\n * Result of policy resolution when a policy is found\n */\nexport type PolicyResolutionResult =\n | {\n exhausted: false;\n policy: RetryPolicy;\n policyIndex: number;\n attemptInPolicy: number; // 1-indexed within this policy\n }\n | {\n exhausted: true;\n };\n\n/**\n * Get the current policy for an attempt number\n *\n * @param attemptNumber - 1-indexed attempt number (the attempt we're about to make)\n * @param policies - Array of retry policies\n * @returns Policy resolution result\n *\n * @example\n * ```typescript\n * const policies = [\n * { maxAttempts: 10, backoff: { type: \"exponential\", ... } },\n * { maxAttempts: 10, backoff: { type: \"constant\", delayMs: 3600000 } },\n * ];\n *\n * getCurrentPolicy(1, policies) // → policy 0, attemptInPolicy 1\n * getCurrentPolicy(10, policies) // → policy 0, attemptInPolicy 10\n * getCurrentPolicy(11, policies) // → policy 1, attemptInPolicy 1\n * getCurrentPolicy(21, policies) // → exhausted\n * ```\n */\nexport function getCurrentPolicy(\n attemptNumber: number,\n policies: RetryPolicy[]\n): PolicyResolutionResult {\n if (policies.length === 0) {\n return { exhausted: true };\n }\n\n let accumulated = 0;\n\n for (let i = 0; i < policies.length; i++) {\n const policy = policies[i]!;\n if (attemptNumber <= accumulated + policy.maxAttempts) {\n return {\n exhausted: false,\n policy,\n policyIndex: i,\n attemptInPolicy: attemptNumber - accumulated,\n };\n }\n accumulated += policy.maxAttempts;\n }\n\n return { exhausted: true };\n}\n\n/**\n * Compute the delay for a given policy and attempt within that policy\n *\n * @param backoff - Backoff configuration\n * @param attemptInPolicy - 1-indexed attempt number within the policy\n * @returns Delay in milliseconds\n */\nexport function computeDelay(backoff: BackoffConfig, attemptInPolicy: number): number {\n switch (backoff.type) {\n case \"constant\":\n return backoff.delayMs;\n\n case \"exponential\": {\n const multiplier = backoff.multiplier ?? 2;\n // attemptInPolicy 1 → delay = initialDelayMs * multiplier^0 = initialDelayMs\n // attemptInPolicy 2 → delay = initialDelayMs * multiplier^1\n const delay = backoff.initialDelayMs * Math.pow(multiplier, attemptInPolicy - 1);\n return Math.min(delay, backoff.maxDelayMs);\n }\n\n case \"linear\": {\n // attemptInPolicy 1 → delay = initialDelayMs\n // attemptInPolicy 2 → delay = initialDelayMs + incrementMs\n const delay = backoff.initialDelayMs + (attemptInPolicy - 1) * backoff.incrementMs;\n return Math.min(delay, backoff.maxDelayMs);\n }\n\n default: {\n // Type guard for exhaustive check\n const _exhaustive: never = backoff;\n throw new Error(`Unknown backoff type: ${JSON.stringify(_exhaustive)}`);\n }\n }\n}\n\n/**\n * Convert legacy retry configuration to the new policy format\n *\n * @param maxRetries - Legacy maxRetries value (number of retries, not total attempts)\n * @param retryDelayMs - Legacy retryDelayMs value\n * @returns Array of retry policies, or undefined if no retry config\n *\n * @example\n * ```typescript\n * // maxRetries=3 means 4 total attempts (1 initial + 3 retries)\n * convertLegacyRetryConfig(3, 1000)\n * // → [{ maxAttempts: 4, backoff: { type: \"constant\", delayMs: 1000 } }]\n *\n * convertLegacyRetryConfig(0, 0)\n * // → undefined (no retries)\n * ```\n */\nexport function convertLegacyRetryConfig(\n maxRetries?: number,\n retryDelayMs?: number\n): RetryPolicy[] | undefined {\n // No retry if maxRetries is 0 or undefined\n if (!maxRetries || maxRetries <= 0) {\n return undefined;\n }\n\n // Legacy maxRetries means \"number of retries after initial attempt\"\n // So total attempts = maxRetries + 1\n return [\n {\n maxAttempts: maxRetries + 1,\n backoff: {\n type: \"constant\",\n delayMs: retryDelayMs ?? 0,\n },\n },\n ];\n}\n\n/**\n * Get the total number of attempts across all policies\n */\nexport function getTotalAttempts(policies: RetryPolicy[]): number {\n return policies.reduce((sum, p) => sum + p.maxAttempts, 0);\n}\n\n/**\n * Resolve effective retry policies from step configuration\n * Prefers new `retry` array over legacy `maxRetries`/`retryDelayMs`\n *\n * @param step - Step with retry configuration\n * @returns Resolved retry policies or undefined\n */\nexport function resolveRetryPolicies(step: {\n retry?: RetryPolicy[];\n maxRetries?: number;\n retryDelayMs?: number;\n}): RetryPolicy[] | undefined {\n // New format takes precedence\n if (step.retry && step.retry.length > 0) {\n return step.retry;\n }\n\n // Fall back to legacy format\n return convertLegacyRetryConfig(step.maxRetries, step.retryDelayMs);\n}\n",
7
7
  "/**\n * Retry utilities for the worker package\n */\n\n// Policy resolution and delay computation\nexport {\n getCurrentPolicy,\n computeDelay,\n convertLegacyRetryConfig,\n getTotalAttempts,\n resolveRetryPolicies,\n type PolicyResolutionResult,\n} from \"./policy-resolver\";\n\n// Re-export error classes from workflow package for convenience\nexport {\n RetryableError,\n NonRetryableError,\n isRetryableError,\n isNonRetryableError,\n} from \"@cascade-flow/workflow\";\n",
8
- "import type { Backend, StepEvent } from \"@cascade-flow/backend-interface\";\nimport { projectStepState } from \"@cascade-flow/backend-interface\";\nimport { type LoadedStep } from \"@cascade-flow/runner\";\nimport { RetryableError } from \"@cascade-flow/workflow\";\nimport { isOptional } from \"@cascade-flow/workflow\";\n\n/**\n * Thrown when a dependency's projected state is unexpectedly non-terminal while\n * attempting to load dependency outputs.\n *\n * This most commonly indicates the dependency step was reclaimed/rescheduled\n * after previously completing, or that event ordering/selection is inconsistent.\n *\n * We extend RetryableError to trigger a short retry with an overridden delay.\n */\nexport class DependencyNotReadyError extends RetryableError {\n readonly dependencyStepName: string;\n readonly dependencyStatus: string;\n\n constructor(dependencyStepName: string, dependencyStatus: string, delayMs: number = 500) {\n super(\n `Dependency '${dependencyStepName}' is not ready (status: ${dependencyStatus}). ` +\n `This can happen if the dependency was reclaimed/rescheduled after completing.`,\n { delayMs }\n );\n this.name = \"DependencyNotReadyError\";\n this.dependencyStepName = dependencyStepName;\n this.dependencyStatus = dependencyStatus;\n }\n}\n\n/**\n * Check if all dependencies for a step are satisfied\n * Returns true if the step can be scheduled\n *\n * IMPORTANT: Both required AND optional dependencies must reach a terminal state\n * (completed or skipped) before a step can be scheduled. The distinction between\n * required and optional only affects CASCADE SKIP behavior:\n *\n * - Required dependency skips → dependent step is cascade skipped\n * - Optional dependency skips → dependent step executes with undefined value\n *\n * This means optional dependencies still BLOCK scheduling until they either complete\n * or skip. They only differ in how the dependent step handles the skipped state.\n *\n * @param step - The step to check dependencies for\n * @param backend - Backend interface for loading events\n * @param workflowSlug - Workflow identifier\n * @param runId - Run identifier\n * @returns true if all dependencies are in terminal state and satisfy execution requirements\n */\nexport async function checkDependenciesSatisfied(\n step: LoadedStep,\n backend: Backend,\n workflowSlug: string,\n runId: string,\n stepEventsByStepId?: Map<string, StepEvent[]>\n): Promise<boolean> {\n for (const [depKey, dep] of Object.entries(step.dependencies) as [string, LoadedStep][]) {\n const depEvents = stepEventsByStepId?.get(dep.id) ??\n await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: dep.id,\n });\n\n // If dependency has no events yet, we must wait regardless of optional status\n // Optional deps only skip blocking when they are in \"skipped\" terminal state\n if (depEvents.length === 0) {\n return false; // Dependency not ready - wait for it to complete or skip\n }\n\n const depState = projectStepState(depEvents as any, workflowSlug);\n const isOptionalDep = isOptional(step.dependencies[depKey]);\n\n // Check if dependency is in a terminal state we can accept\n if (depState.status === \"completed\") {\n continue; // Completed - always OK for both required and optional\n }\n\n if (depState.status === \"skipped\") {\n if (isOptionalDep) {\n continue; // Skipped optional dep - OK\n } else {\n return false; // Skipped required dep - blocks execution\n }\n }\n\n // Dependency is not in a terminal state (pending, scheduled, running, failed non-terminal)\n return false;\n }\n\n return true; // All dependencies satisfied\n}\n\n/**\n * Load outputs from all dependencies\n * Returns a map of dependency alias to output value\n *\n * This function should only be called after checkDependenciesSatisfied returns true,\n * ensuring all dependencies are in terminal state.\n *\n * Behavior by dependency state:\n * - Completed: Returns parsed JSON output\n * - Skipped + Optional: Returns undefined\n * - Skipped + Required: Throws error (should never happen - step should be cascade skipped)\n * - Any other state: Throws error (should never happen - checkDependenciesSatisfied should prevent scheduling)\n *\n * @param step - The step to load dependency outputs for\n * @param backend - Backend interface for loading events\n * @param workflowSlug - Workflow identifier\n * @param runId - Run identifier\n * @returns Map of dependency alias to output value (undefined for skipped optional deps)\n * @throws Error if dependency is not in a valid terminal state\n */\nexport async function loadDependencyOutputs(\n step: LoadedStep,\n backend: Backend,\n workflowSlug: string,\n runId: string\n): Promise<Record<string, any>> {\n const dependencyOutputs: Record<string, any> = {};\n\n for (const [depKey, depStep] of Object.entries(step.dependencies) as [string, LoadedStep][]) {\n const depEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: depStep.id,\n });\n\n if (depEvents.length === 0) {\n // This should never happen if checkDependenciesSatisfied was called first\n // Both required and optional deps must have events (completed or skipped)\n throw new Error(`Dependency ${depStep.name} has no events - step was scheduled prematurely`);\n }\n\n const depState = projectStepState(depEvents as any, workflowSlug);\n const isOptionalDep = isOptional(step.dependencies[depKey]);\n\n // Optional deps can be skipped\n if (depState.status === \"skipped\" && isOptionalDep) {\n dependencyOutputs[depKey] = undefined;\n continue;\n }\n\n // At this point, dependency must be completed (not skipped optional which was handled above)\n // Note: output field is guaranteed to exist for completed steps (StepCompletedEvent requires it)\n if (depState.status !== \"completed\") {\n // Dependency state changed after we were scheduled/claimed; retry quickly to self-heal.\n throw new DependencyNotReadyError(depStep.name, depState.status);\n }\n\n if (!depState.output) {\n throw new Error(`Dependency '${depStep.name}' has no output despite being completed`);\n }\n\n // Parse dependency output\n dependencyOutputs[depKey] = JSON.parse(depState.output);\n }\n\n return dependencyOutputs;\n}\n\n/**\n * Find all steps that depend on a given step\n * @param targetStepId - The stepId (unique identifier) to find dependents for\n * @param allSteps - All steps in the workflow\n * @param requiredOnly - If true, only return steps with required dependencies\n */\nexport function findDependentSteps(\n targetStepId: string,\n allSteps: LoadedStep[],\n requiredOnly: boolean = false\n): LoadedStep[] {\n return allSteps.filter((step) => {\n const deps = Object.entries(step.dependencies) as [string, LoadedStep][];\n return deps.some(([alias, dep]) => {\n const dependsOnTarget = dep.id === targetStepId;\n if (!dependsOnTarget) return false;\n\n if (requiredOnly) {\n const isOptionalDep = isOptional(step.dependencies[alias]);\n return !isOptionalDep; // Only include if it's a required dependency\n }\n\n return true; // Include all dependencies\n });\n });\n}\n",
8
+ "import type { Backend, StepEvent } from \"@cascade-flow/backend-interface\";\nimport { projectStepState } from \"@cascade-flow/backend-interface\";\nimport { type LoadedStep } from \"@cascade-flow/runner\";\nimport { RetryableError } from \"@cascade-flow/workflow\";\nimport { isOptional } from \"@cascade-flow/workflow\";\n\n/**\n * Event types needed for state projection. Excludes high-volume types\n * that don't affect step state (LogEntry, StepRetrying, StepCheckpoint, StepCheckpointFailed).\n */\nexport const STATE_PROJECTION_TYPES = [\n \"StepScheduled\", \"StepStarted\", \"StepCompleted\",\n \"StepFailed\", \"StepSkipped\", \"StepReclaimed\", \"StepHeartbeat\",\n];\n\n/**\n * Thrown when a dependency's projected state is unexpectedly non-terminal while\n * attempting to load dependency outputs.\n *\n * This most commonly indicates the dependency step was reclaimed/rescheduled\n * after previously completing, or that event ordering/selection is inconsistent.\n *\n * We extend RetryableError to trigger a short retry with an overridden delay.\n */\nexport class DependencyNotReadyError extends RetryableError {\n readonly dependencyStepName: string;\n readonly dependencyStatus: string;\n\n constructor(dependencyStepName: string, dependencyStatus: string, delayMs: number = 500) {\n super(\n `Dependency '${dependencyStepName}' is not ready (status: ${dependencyStatus}). ` +\n `This can happen if the dependency was reclaimed/rescheduled after completing.`,\n { delayMs }\n );\n this.name = \"DependencyNotReadyError\";\n this.dependencyStepName = dependencyStepName;\n this.dependencyStatus = dependencyStatus;\n }\n}\n\n/**\n * Check if all dependencies for a step are satisfied\n * Returns true if the step can be scheduled\n *\n * IMPORTANT: Both required AND optional dependencies must reach a terminal state\n * (completed or skipped) before a step can be scheduled. The distinction between\n * required and optional only affects CASCADE SKIP behavior:\n *\n * - Required dependency skips → dependent step is cascade skipped\n * - Optional dependency skips → dependent step executes with undefined value\n *\n * This means optional dependencies still BLOCK scheduling until they either complete\n * or skip. They only differ in how the dependent step handles the skipped state.\n *\n * @param step - The step to check dependencies for\n * @param backend - Backend interface for loading events\n * @param workflowSlug - Workflow identifier\n * @param runId - Run identifier\n * @returns true if all dependencies are in terminal state and satisfy execution requirements\n */\nexport async function checkDependenciesSatisfied(\n step: LoadedStep,\n backend: Backend,\n workflowSlug: string,\n runId: string,\n stepEventsByStepId?: Map<string, StepEvent[]>\n): Promise<boolean> {\n for (const [depKey, dep] of Object.entries(step.dependencies) as [string, LoadedStep][]) {\n const depEvents = stepEventsByStepId?.get(dep.id) ??\n await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: dep.id,\n types: STATE_PROJECTION_TYPES,\n });\n\n // If dependency has no events yet, we must wait regardless of optional status\n // Optional deps only skip blocking when they are in \"skipped\" terminal state\n if (depEvents.length === 0) {\n return false; // Dependency not ready - wait for it to complete or skip\n }\n\n const depState = projectStepState(depEvents as any, workflowSlug);\n const isOptionalDep = isOptional(step.dependencies[depKey]);\n\n // Check if dependency is in a terminal state we can accept\n if (depState.status === \"completed\") {\n continue; // Completed - always OK for both required and optional\n }\n\n if (depState.status === \"skipped\") {\n if (isOptionalDep) {\n continue; // Skipped optional dep - OK\n } else {\n return false; // Skipped required dep - blocks execution\n }\n }\n\n // Dependency is not in a terminal state (pending, scheduled, running, failed non-terminal)\n return false;\n }\n\n return true; // All dependencies satisfied\n}\n\n/**\n * Load outputs from all dependencies\n * Returns a map of dependency alias to output value\n *\n * This function should only be called after checkDependenciesSatisfied returns true,\n * ensuring all dependencies are in terminal state.\n *\n * Behavior by dependency state:\n * - Completed: Returns parsed JSON output\n * - Skipped + Optional: Returns undefined\n * - Skipped + Required: Throws error (should never happen - step should be cascade skipped)\n * - Any other state: Throws error (should never happen - checkDependenciesSatisfied should prevent scheduling)\n *\n * @param step - The step to load dependency outputs for\n * @param backend - Backend interface for loading events\n * @param workflowSlug - Workflow identifier\n * @param runId - Run identifier\n * @returns Map of dependency alias to output value (undefined for skipped optional deps)\n * @throws Error if dependency is not in a valid terminal state\n */\nexport async function loadDependencyOutputs(\n step: LoadedStep,\n backend: Backend,\n workflowSlug: string,\n runId: string\n): Promise<Record<string, any>> {\n const dependencyOutputs: Record<string, any> = {};\n\n for (const [depKey, depStep] of Object.entries(step.dependencies) as [string, LoadedStep][]) {\n const depEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: depStep.id,\n types: STATE_PROJECTION_TYPES,\n });\n\n if (depEvents.length === 0) {\n // This should never happen if checkDependenciesSatisfied was called first\n // Both required and optional deps must have events (completed or skipped)\n throw new Error(`Dependency ${depStep.name} has no events - step was scheduled prematurely`);\n }\n\n const depState = projectStepState(depEvents as any, workflowSlug);\n const isOptionalDep = isOptional(step.dependencies[depKey]);\n\n // Optional deps can be skipped\n if (depState.status === \"skipped\" && isOptionalDep) {\n dependencyOutputs[depKey] = undefined;\n continue;\n }\n\n // At this point, dependency must be completed (not skipped optional which was handled above)\n // Note: output field is guaranteed to exist for completed steps (StepCompletedEvent requires it)\n if (depState.status !== \"completed\") {\n // Dependency state changed after we were scheduled/claimed; retry quickly to self-heal.\n throw new DependencyNotReadyError(depStep.name, depState.status);\n }\n\n if (!depState.output) {\n throw new Error(`Dependency '${depStep.name}' has no output despite being completed`);\n }\n\n // Parse dependency output\n dependencyOutputs[depKey] = JSON.parse(depState.output);\n }\n\n return dependencyOutputs;\n}\n\n/**\n * Find all steps that depend on a given step\n * @param targetStepId - The stepId (unique identifier) to find dependents for\n * @param allSteps - All steps in the workflow\n * @param requiredOnly - If true, only return steps with required dependencies\n */\nexport function findDependentSteps(\n targetStepId: string,\n allSteps: LoadedStep[],\n requiredOnly: boolean = false\n): LoadedStep[] {\n return allSteps.filter((step) => {\n const deps = Object.entries(step.dependencies) as [string, LoadedStep][];\n return deps.some(([alias, dep]) => {\n const dependsOnTarget = dep.id === targetStepId;\n if (!dependsOnTarget) return false;\n\n if (requiredOnly) {\n const isOptionalDep = isOptional(step.dependencies[alias]);\n return !isOptionalDep; // Only include if it's a required dependency\n }\n\n return true; // Include all dependencies\n });\n });\n}\n",
9
9
  "import type { Backend } from \"@cascade-flow/backend-interface\";\nimport { getMicrosecondTimestamp, projectStepState } from \"@cascade-flow/backend-interface\";\nimport type { LoadedStep } from \"@cascade-flow/runner\";\nimport { findDependentSteps } from \"../execution/dependency-resolver.ts\";\n\n/**\n * Handle a step skip - emit StepSkipped event\n */\nexport async function handleStepSkip(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n stepId: string,\n skipError: {\n reason?: string;\n message: string;\n metadata?: Record<string, unknown>;\n },\n duration: number,\n attemptNumber: number\n): Promise<void> {\n await backend.saveStepSkipped(workflowSlug, runId, stepId, {\n skipType: \"primary\",\n reason: skipError.reason || skipError.message.replace(\"Step skipped: \", \"\"),\n metadata: skipError.metadata,\n duration,\n attemptNumber,\n });\n}\n\n/**\n * Cascade skip to dependent steps that have the skipped step as a REQUIRED dependency\n * Recursively propagates skip to all dependent steps\n */\nexport async function cascadeSkip(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n skippedStepId: string,\n allSteps: LoadedStep[],\n workerId: string\n): Promise<void> {\n // Find steps that depend on the skipped step as a REQUIRED dependency (using stepId)\n const dependentSteps = findDependentSteps(skippedStepId, allSteps, true);\n\n for (const dependentStep of dependentSteps) {\n // Check current state to avoid double-skipping (using stepId)\n const stepEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: dependentStep.id,\n });\n const hasEvents = stepEvents.length > 0;\n\n // If step has no events yet or is not terminal (not completed/failed/skipped), cascade skip\n if (!hasEvents) {\n const now = getMicrosecondTimestamp(); // Microseconds\n\n // Emit StepStarted to mark as \"running\" briefly (for consistency) - using stepId\n await backend.saveStepStart(workflowSlug, runId, dependentStep.id, workerId, {\n dependencies: Object.keys(dependentStep.dependencies),\n timestamp: now,\n attemptNumber: 1,\n });\n\n // Immediately skip with cascade reason (using stepId)\n await backend.saveStepSkipped(workflowSlug, runId, dependentStep.id, {\n skipType: \"cascade\",\n reason: `Dependency '${skippedStepId}' was skipped`,\n duration: 0, // No actual execution time\n attemptNumber: 1,\n cascadedFrom: skippedStepId,\n });\n\n // Recursively cascade to further dependents (using stepId)\n await cascadeSkip(backend, workflowSlug, runId, dependentStep.id, allSteps, workerId);\n } else {\n const depState = projectStepState(stepEvents as any, workflowSlug);\n if (depState.status !== \"completed\" && depState.status !== \"failed\" && depState.status !== \"skipped\") {\n // Step is in progress or scheduled, still cascade skip (using stepId)\n await backend.saveStepSkipped(workflowSlug, runId, dependentStep.id, {\n skipType: \"cascade\",\n reason: `Dependency '${skippedStepId}' was skipped`,\n duration: getMicrosecondTimestamp() - (depState.startTime || getMicrosecondTimestamp()),\n attemptNumber: depState.attemptNumber,\n cascadedFrom: skippedStepId,\n });\n\n // Recursively cascade to further dependents (using stepId)\n await cascadeSkip(backend, workflowSlug, runId, dependentStep.id, allSteps, workerId);\n }\n }\n }\n}\n",
10
10
  "import type { Backend } from \"@cascade-flow/backend-interface\";\nimport { getMicrosecondTimestamp, projectStepState } from \"@cascade-flow/backend-interface\";\nimport type { LoadedStep } from \"@cascade-flow/runner\";\nimport { checkDependenciesSatisfied, findDependentSteps } from \"../execution/dependency-resolver.ts\";\n\n/**\n * Schedule a single step (emit StepScheduled event)\n */\nexport async function scheduleStep(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n stepId: string,\n reason: \"initial\" | \"dependency-satisfied\" | \"retry\",\n attemptNumber: number,\n options?: {\n availableAt?: number;\n retryDelayMs?: number;\n priority?: number;\n }\n): Promise<void> {\n const now = getMicrosecondTimestamp();\n await backend.saveStepScheduled(workflowSlug, runId, stepId, {\n availableAt: options?.availableAt ?? now,\n reason,\n attemptNumber,\n retryDelayMs: options?.retryDelayMs,\n priority: options?.priority,\n });\n}\n\n/**\n * Schedule initial steps (steps with no dependencies or all optional dependencies)\n */\nexport async function scheduleInitialSteps(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n steps: LoadedStep[]\n): Promise<string[]> {\n const scheduledSteps: string[] = [];\n\n for (const step of steps) {\n // Check if step has no events yet (using stepId)\n const stepEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: step.id,\n });\n\n if (stepEvents.length === 0) {\n // Check if dependencies are satisfied\n const canSchedule = await checkDependenciesSatisfied(step, backend, workflowSlug, runId);\n\n if (canSchedule) {\n await scheduleStep(\n backend,\n workflowSlug,\n runId,\n step.id,\n Object.keys(step.dependencies).length === 0 ? \"initial\" : \"dependency-satisfied\",\n 1\n );\n scheduledSteps.push(step.name);\n }\n }\n }\n\n return scheduledSteps;\n}\n\n/**\n * Schedule ready steps (pending steps whose dependencies are now satisfied)\n */\nexport async function scheduleReadySteps(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n steps: LoadedStep[]\n): Promise<string[]> {\n const scheduledSteps: string[] = [];\n\n for (const step of steps) {\n const stepEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: step.id,\n });\n\n // Skip if no events yet (handled by scheduleInitialSteps)\n if (stepEvents.length === 0) continue;\n\n const state = projectStepState(stepEvents as any, workflowSlug);\n\n // Only schedule if step is pending\n if (state.status === \"pending\") {\n const canSchedule = await checkDependenciesSatisfied(step, backend, workflowSlug, runId);\n\n if (canSchedule) {\n await scheduleStep(backend, workflowSlug, runId, step.id, \"dependency-satisfied\", 1);\n scheduledSteps.push(step.name);\n }\n }\n }\n\n return scheduledSteps;\n}\n\n/**\n * Schedule downstream steps (steps that depend on a newly completed step)\n */\nexport async function scheduleDownstreamSteps(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n completedStepId: string,\n allSteps: LoadedStep[],\n options?: {\n priority?: number;\n }\n): Promise<string[]> {\n const scheduledSteps: string[] = [];\n\n // Find steps that depend on the completed step (using stepId)\n const dependentSteps = findDependentSteps(completedStepId, allSteps, false);\n\n for (const dependentStep of dependentSteps) {\n // Check if all dependencies are completed\n const allDepsCompleted = await checkDependenciesSatisfied(dependentStep, backend, workflowSlug, runId);\n\n if (allDepsCompleted) {\n // Check current state to avoid double-scheduling (using stepId)\n const stepEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: dependentStep.id,\n });\n\n // If step has no events yet, or is still pending, schedule it\n if (stepEvents.length === 0) {\n await scheduleStep(backend, workflowSlug, runId, dependentStep.id, \"dependency-satisfied\", 1, { priority: options?.priority });\n scheduledSteps.push(dependentStep.name);\n } else {\n const state = projectStepState(stepEvents as any, workflowSlug);\n if (state.status === \"pending\") {\n await scheduleStep(backend, workflowSlug, runId, dependentStep.id, \"dependency-satisfied\", 1, { priority: options?.priority });\n scheduledSteps.push(dependentStep.name);\n }\n }\n }\n }\n\n return scheduledSteps;\n}\n",
11
11
  "/**\n * Step key utilities\n *\n * A step key is a unique identifier in the format: `workflowSlug/runId/stepId`\n * where stepId may contain slashes for nested steps (e.g., \"slp/cognitive/extract-discrepancy\")\n */\n\n/**\n * Create a step key from its components\n *\n * @param workflowSlug - The workflow identifier\n * @param runId - The run identifier\n * @param stepId - The step identifier (may contain slashes for nested steps)\n * @returns The step key in format: `workflowSlug/runId/stepId`\n *\n * @example\n * createStepKey(\"pdpm\", \"run_123\", \"step-1\")\n * // => \"pdpm/run_123/step-1\"\n *\n * @example\n * createStepKey(\"pdpm\", \"run_123\", \"slp/cognitive/extract-discrepancy\")\n * // => \"pdpm/run_123/slp/cognitive/extract-discrepancy\"\n */\nexport function createStepKey(workflowSlug: string, runId: string, stepId: string): string {\n return `${workflowSlug}/${runId}/${stepId}`;\n}\n\n/**\n * Extract the stepId component from a step key\n *\n * Handles nested steps that contain slashes in their stepId.\n *\n * @param stepKey - The step key in format: `workflowSlug/runId/stepId`\n * @returns The stepId portion (everything after the first two slashes)\n *\n * @example\n * extractStepId(\"pdpm/run_123/step-1\")\n * // => \"step-1\"\n *\n * @example\n * extractStepId(\"pdpm/run_123/slp/cognitive/extract-discrepancy\")\n * // => \"slp/cognitive/extract-discrepancy\"\n */\nexport function extractStepId(stepKey: string): string {\n const parts = stepKey.split('/');\n return parts.slice(2).join('/');\n}\n\n/**\n * Extract the workflowSlug component from a step key\n *\n * @param stepKey - The step key in format: `workflowSlug/runId/stepId`\n * @returns The workflowSlug portion (first component)\n *\n * @example\n * extractWorkflowSlug(\"pdpm/run_123/step-1\")\n * // => \"pdpm\"\n */\nexport function extractWorkflowSlug(stepKey: string): string {\n return stepKey.split('/')[0]!;\n}\n\n/**\n * Extract the runId component from a step key\n *\n * @param stepKey - The step key in format: `workflowSlug/runId/stepId`\n * @returns The runId portion (second component)\n *\n * @example\n * extractRunId(\"pdpm/run_123/step-1\")\n * // => \"run_123\"\n */\nexport function extractRunId(stepKey: string): string {\n return stepKey.split('/')[1]!;\n}\n",
12
12
  "import type { Backend } from \"@cascade-flow/backend-interface\";\nimport { getMicrosecondTimestamp, projectStepState } from \"@cascade-flow/backend-interface\";\nimport type { ZodIssue, ZodSchema } from \"zod\";\nimport type { LoadedStep } from \"@cascade-flow/runner\";\nimport {\n calculateWorkflowDuration,\n getRunSubmittedEvent,\n getCurrentWorkflowAttemptNumber,\n} from \"../utils/event-helpers.ts\";\nimport type { WorkflowEvent } from \"../utils/event-helpers.ts\";\n\n/**\n * Handle workflow start - emit WorkflowStarted event\n */\nexport async function handleWorkflowStart(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n metadata: {\n versionId: string;\n hasInputSchema: boolean;\n hasInput: boolean;\n },\n workflowEvents: WorkflowEvent[]\n): Promise<void> {\n const workflowAttemptNumber = getCurrentWorkflowAttemptNumber(workflowEvents);\n\n await backend.saveWorkflowStart(workflowSlug, runId, {\n versionId: metadata.versionId,\n workflowAttemptNumber,\n hasInputSchema: metadata.hasInputSchema,\n hasInput: metadata.hasInput,\n });\n}\n\n/**\n * Validate workflow input against schema\n * Returns validation result and emits WorkflowInputValidation event\n */\nexport async function validateWorkflowInput(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n workflowInput: unknown,\n inputSchema: ZodSchema | undefined,\n workflowEvents: WorkflowEvent[]\n): Promise<{\n success: boolean;\n error?: { name: string; message: string };\n validationErrors?: Array<{ path: string; message: string }>;\n}> {\n const workflowAttemptNumber = getCurrentWorkflowAttemptNumber(workflowEvents);\n\n if (!inputSchema) {\n // No schema to validate against - if input provided, mark as success\n if (workflowInput !== undefined) {\n await backend.saveWorkflowInputValidation(workflowSlug, runId, {\n workflowAttemptNumber,\n hasSchema: false,\n success: true,\n });\n }\n return { success: true };\n }\n\n // Validate with schema\n const parseResult = inputSchema.safeParse(workflowInput ?? {});\n\n if (!parseResult.success) {\n const validationErrors = parseResult.error.issues.map((e: ZodIssue) => ({\n path: e.path.join(\".\"),\n message: e.message,\n }));\n\n const errorMessage = validationErrors\n .map((e: { path: string; message: string }) => ` ${e.path}: ${e.message}`)\n .join(\"\\n\");\n\n const error = {\n name: \"ValidationError\",\n message: `Invalid workflow input:\\n${errorMessage}`,\n };\n\n // Emit validation FAILURE event\n await backend.saveWorkflowInputValidation(workflowSlug, runId, {\n workflowAttemptNumber,\n hasSchema: true,\n success: false,\n error,\n validationErrors,\n });\n\n // Emit WorkflowFailed event\n const duration = calculateWorkflowDuration(workflowEvents);\n\n await backend.saveWorkflowFailed(\n workflowSlug,\n runId,\n error,\n {\n workflowAttemptNumber,\n duration,\n completedSteps: 0,\n },\n \"step-failed\" // Using existing failure reason\n );\n\n return { success: false, error, validationErrors };\n }\n\n // Validation succeeded - emit validation SUCCESS event\n await backend.saveWorkflowInputValidation(workflowSlug, runId, {\n workflowAttemptNumber,\n hasSchema: true,\n success: true,\n });\n\n return { success: true };\n}\n\n/**\n * Handle workflow completion - collect exported outputs and emit WorkflowCompleted event\n */\nexport async function handleWorkflowCompletion(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n steps: LoadedStep[],\n workflowEvents: WorkflowEvent[]\n): Promise<void> {\n const workflowAttemptNumber = getCurrentWorkflowAttemptNumber(workflowEvents);\n const duration = calculateWorkflowDuration(workflowEvents);\n const now = getMicrosecondTimestamp();\n\n // Collect exported step outputs\n const output: Record<string, unknown> = {};\n for (const step of steps) {\n const stepEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: step.id,\n });\n const state = projectStepState(stepEvents, workflowSlug);\n\n if (state.exportOutput && state.output) {\n output[step.name] = JSON.parse(state.output);\n }\n }\n\n await backend.saveWorkflowComplete(workflowSlug, runId, output, {\n workflowAttemptNumber,\n timestamp: now,\n duration,\n totalSteps: steps.length,\n });\n}\n\n/**\n * Handle workflow failure - count completed steps and emit WorkflowFailed event\n */\nexport async function handleWorkflowFailure(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n steps: LoadedStep[],\n workflowEvents: WorkflowEvent[],\n failedStepName?: string\n): Promise<void> {\n const workflowAttemptNumber = getCurrentWorkflowAttemptNumber(workflowEvents);\n const duration = calculateWorkflowDuration(workflowEvents);\n\n // Count completed steps\n let completedCount = 0;\n for (const step of steps) {\n const stepEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: step.id,\n });\n if (stepEvents.length > 0) {\n const state = projectStepState(stepEvents, workflowSlug);\n if (state.status === \"completed\") {\n completedCount++;\n }\n }\n }\n\n await backend.saveWorkflowFailed(\n workflowSlug,\n runId,\n {\n message: failedStepName ? `Step ${failedStepName} failed` : \"Workflow failed\",\n name: \"StepFailure\",\n },\n {\n workflowAttemptNumber,\n duration,\n completedSteps: completedCount,\n failedStep: failedStepName,\n },\n \"step-failed\"\n );\n}\n\n/**\n * Parse workflow input from RunSubmitted event\n */\nexport function parseWorkflowInput(workflowEvents: WorkflowEvent[]): unknown {\n const runSubmittedEvent = getRunSubmittedEvent(workflowEvents);\n if (runSubmittedEvent && runSubmittedEvent.input) {\n return JSON.parse(runSubmittedEvent.input);\n }\n return undefined;\n}\n",
13
- "import type { Backend, StepEvent, StepState, WorkflowEvent } from \"@cascade-flow/backend-interface\";\nimport { getMicrosecondTimestamp, projectStepState } from \"@cascade-flow/backend-interface\";\n\n// Re-export types for convenience\nexport type { WorkflowEvent, StepEvent, StepState };\n\n/**\n * Load step events and project to current state\n */\nexport async function loadStepState(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n stepId: string\n): Promise<StepState> {\n const stepEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId,\n });\n\n return projectStepState(stepEvents, workflowSlug);\n}\n\n/**\n * Load all workflow events for a run\n */\nexport async function loadWorkflowEvents(\n backend: Backend,\n workflowSlug: string,\n runId: string\n): Promise<WorkflowEvent[]> {\n return backend.loadEvents(workflowSlug, runId, { category: \"workflow\" });\n}\n\n/**\n * Get the current workflow attempt number from events.\n * Returns 1 if no retry has occurred (initial attempt).\n * Returns the workflowAttemptNumber from the most recent WorkflowRetryStarted event.\n */\nexport function getCurrentWorkflowAttemptNumber(events: WorkflowEvent[]): number {\n const retryEvents = events.filter((e): e is Extract<WorkflowEvent, { type: \"WorkflowRetryStarted\" }> =>\n e.type === \"WorkflowRetryStarted\"\n );\n if (retryEvents.length === 0) return 1; // Initial attempt\n\n // Get the most recent retry (events are chronologically sorted)\n const mostRecentRetry = retryEvents[retryEvents.length - 1];\n if (!mostRecentRetry) return 1; // Extra safety check\n\n return mostRecentRetry.workflowAttemptNumber;\n}\n\n/**\n * Check if workflow is in a terminal state (completed, failed, or cancelled)\n * Only considers events from the current workflow attempt.\n */\nexport function isWorkflowTerminal(events: WorkflowEvent[]): boolean {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n return events.some((e) => {\n if (e.type === \"WorkflowCompleted\" || e.type === \"WorkflowFailed\" || e.type === \"WorkflowCancelled\") {\n return e.workflowAttemptNumber === currentAttempt;\n }\n return false;\n });\n}\n\n/**\n * Check specific terminal states\n * Only considers events from the current workflow attempt.\n */\nexport function getWorkflowTerminalState(events: WorkflowEvent[]): {\n hasCompleted: boolean;\n hasFailed: boolean;\n hasCancelled: boolean;\n} {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n\n return {\n hasCompleted: events.some((e) => e.type === \"WorkflowCompleted\" && e.workflowAttemptNumber === currentAttempt),\n hasFailed: events.some((e) => e.type === \"WorkflowFailed\" && e.workflowAttemptNumber === currentAttempt),\n hasCancelled: events.some((e) => e.type === \"WorkflowCancelled\" && e.workflowAttemptNumber === currentAttempt),\n };\n}\n\n/**\n * Calculate workflow duration from start event to now (in microseconds)\n * Uses the WorkflowStarted event from the current workflow attempt.\n */\nexport function calculateWorkflowDuration(events: WorkflowEvent[]): number {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n\n // Find WorkflowStarted event for current attempt\n const workflowStartEvent = events.find((e): e is Extract<WorkflowEvent, { type: \"WorkflowStarted\" }> =>\n e.type === \"WorkflowStarted\" && e.workflowAttemptNumber === currentAttempt\n );\n\n const startTime = workflowStartEvent ? workflowStartEvent.timestampUs : 0;\n const now = getMicrosecondTimestamp();\n return now - startTime;\n}\n\n/**\n * Check if workflow has been started\n * Only considers WorkflowStarted events from the current workflow attempt.\n */\nexport function hasWorkflowStarted(events: WorkflowEvent[]): boolean {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n return events.some((e) => e.type === \"WorkflowStarted\" && e.workflowAttemptNumber === currentAttempt);\n}\n\n/**\n * Check if workflow has been submitted\n */\nexport function hasWorkflowSubmitted(events: WorkflowEvent[]): boolean {\n return events.some((e) => e.type === \"RunSubmitted\");\n}\n\n/**\n * Check if workflow input has been validated\n * Only considers WorkflowInputValidation events from the current workflow attempt.\n */\nexport function hasWorkflowValidatedInput(events: WorkflowEvent[]): boolean {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n return events.some((e) => e.type === \"WorkflowInputValidation\" && e.workflowAttemptNumber === currentAttempt);\n}\n\n/**\n * Get the RunSubmitted event from workflow events\n */\nexport function getRunSubmittedEvent(events: WorkflowEvent[]): Extract<WorkflowEvent, { type: \"RunSubmitted\" }> | undefined {\n return events.find((e): e is Extract<WorkflowEvent, { type: \"RunSubmitted\" }> =>\n e.type === \"RunSubmitted\"\n );\n}\n\n/**\n * Get the WorkflowStarted event from workflow events\n * Returns the WorkflowStarted event from the current workflow attempt.\n */\nexport function getWorkflowStartedEvent(events: WorkflowEvent[]): Extract<WorkflowEvent, { type: \"WorkflowStarted\" }> | undefined {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n return events.find((e): e is Extract<WorkflowEvent, { type: \"WorkflowStarted\" }> =>\n e.type === \"WorkflowStarted\" && e.workflowAttemptNumber === currentAttempt\n );\n}\n\n/**\n * Get the WorkflowInputValidation event from workflow events\n * Returns the most recent WorkflowInputValidation event.\n *\n * Note: We return the most recent validation event regardless of attempt number because:\n * 1. Workflow input is immutable (stored once in RunSubmitted event)\n * 2. Input validation is idempotent - same input + schema = same result\n * 3. This prevents race conditions where executor claims steps before scheduler emits validation for new attempt\n * 4. Validation result from attempt 1 is valid for all subsequent retry attempts\n */\nexport function getWorkflowInputValidationEvent(events: WorkflowEvent[]): Extract<WorkflowEvent, { type: \"WorkflowInputValidation\" }> | undefined {\n // Get the most recent validation event (input doesn't change across attempts)\n const validationEvents = events.filter((e): e is Extract<WorkflowEvent, { type: \"WorkflowInputValidation\" }> =>\n e.type === \"WorkflowInputValidation\"\n );\n return validationEvents.length > 0 ? validationEvents[validationEvents.length - 1] : undefined;\n}\n"
13
+ "import type { Backend, StepEvent, StepState, WorkflowEvent } from \"@cascade-flow/backend-interface\";\nimport { getMicrosecondTimestamp, projectStepState } from \"@cascade-flow/backend-interface\";\n\n// Re-export types for convenience\nexport type { WorkflowEvent, StepEvent, StepState };\n\n/**\n * Load step events and project to current state\n */\nexport async function loadStepState(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n stepId: string\n): Promise<StepState> {\n const stepEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId,\n });\n\n return projectStepState(stepEvents, workflowSlug);\n}\n\n/**\n * Load all workflow events for a run\n */\nexport async function loadWorkflowEvents(\n backend: Backend,\n workflowSlug: string,\n runId: string\n): Promise<WorkflowEvent[]> {\n return backend.loadEvents(workflowSlug, runId, { category: \"workflow\" });\n}\n\n/**\n * Get the current workflow attempt number from events.\n * Returns 1 if no retry has occurred (initial attempt).\n * Returns the workflowAttemptNumber from the most recent WorkflowRetryStarted event.\n */\nexport function getCurrentWorkflowAttemptNumber(events: WorkflowEvent[]): number {\n const retryEvents = events.filter((e): e is Extract<WorkflowEvent, { type: \"WorkflowRetryStarted\" }> =>\n e.type === \"WorkflowRetryStarted\"\n );\n if (retryEvents.length === 0) return 1; // Initial attempt\n\n // Get the most recent retry (events are chronologically sorted)\n const mostRecentRetry = retryEvents[retryEvents.length - 1];\n if (!mostRecentRetry) return 1; // Extra safety check\n\n return mostRecentRetry.workflowAttemptNumber;\n}\n\n/**\n * Check if workflow is in a terminal state (completed, failed, or cancelled)\n * Only considers events from the current workflow attempt.\n */\nexport function isWorkflowTerminal(events: WorkflowEvent[]): boolean {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n return events.some((e) => {\n if (e.type === \"WorkflowCompleted\" || e.type === \"WorkflowFailed\" || e.type === \"WorkflowCancelled\") {\n return e.workflowAttemptNumber === currentAttempt;\n }\n return false;\n });\n}\n\n/**\n * Check specific terminal states\n * Only considers events from the current workflow attempt.\n */\nexport function getWorkflowTerminalState(events: WorkflowEvent[]): {\n hasCompleted: boolean;\n hasFailed: boolean;\n hasCancelled: boolean;\n} {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n\n return {\n hasCompleted: events.some((e) => e.type === \"WorkflowCompleted\" && e.workflowAttemptNumber === currentAttempt),\n hasFailed: events.some((e) => e.type === \"WorkflowFailed\" && e.workflowAttemptNumber === currentAttempt),\n hasCancelled: events.some((e) => e.type === \"WorkflowCancelled\" && e.workflowAttemptNumber === currentAttempt),\n };\n}\n\n/**\n * Calculate workflow duration from start event to now (in microseconds)\n * Uses the WorkflowStarted event from the current workflow attempt.\n */\nexport function calculateWorkflowDuration(events: WorkflowEvent[]): number {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n\n // Find WorkflowStarted event for current attempt\n const workflowStartEvent = events.find((e): e is Extract<WorkflowEvent, { type: \"WorkflowStarted\" }> =>\n e.type === \"WorkflowStarted\" && e.workflowAttemptNumber === currentAttempt\n );\n\n const startTime = workflowStartEvent ? workflowStartEvent.timestampUs : 0;\n const now = getMicrosecondTimestamp();\n return now - startTime;\n}\n\n/**\n * Check if workflow has been started\n * Only considers WorkflowStarted events from the current workflow attempt.\n */\nexport function hasWorkflowStarted(events: WorkflowEvent[]): boolean {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n return events.some((e) => e.type === \"WorkflowStarted\" && e.workflowAttemptNumber === currentAttempt);\n}\n\n/**\n * Check if workflow has been submitted\n */\nexport function hasWorkflowSubmitted(events: WorkflowEvent[]): boolean {\n return events.some((e) => e.type === \"RunSubmitted\");\n}\n\n/**\n * Check if workflow input has been validated\n * Only considers WorkflowInputValidation events from the current workflow attempt.\n */\nexport function hasWorkflowValidatedInput(events: WorkflowEvent[]): boolean {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n return events.some((e) => e.type === \"WorkflowInputValidation\" && e.workflowAttemptNumber === currentAttempt);\n}\n\n/**\n * Get the RunSubmitted event from workflow events\n */\nexport function getRunSubmittedEvent(events: WorkflowEvent[]): Extract<WorkflowEvent, { type: \"RunSubmitted\" }> | undefined {\n return events.find((e): e is Extract<WorkflowEvent, { type: \"RunSubmitted\" }> =>\n e.type === \"RunSubmitted\"\n );\n}\n\n/**\n * Get the WorkflowStarted event from workflow events\n * Returns the WorkflowStarted event from the current workflow attempt.\n */\nexport function getWorkflowStartedEvent(events: WorkflowEvent[]): Extract<WorkflowEvent, { type: \"WorkflowStarted\" }> | undefined {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n return events.find((e): e is Extract<WorkflowEvent, { type: \"WorkflowStarted\" }> =>\n e.type === \"WorkflowStarted\" && e.workflowAttemptNumber === currentAttempt\n );\n}\n\n/**\n * Get the WorkflowInputValidation event from workflow events\n * Returns the most recent WorkflowInputValidation event.\n *\n * Note: We return the most recent validation event regardless of attempt number because:\n * 1. Workflow input is immutable (stored once in RunSubmitted event)\n * 2. Input validation is idempotent - same input + schema = same result\n * 3. This prevents race conditions where executor claims steps before scheduler emits validation for new attempt\n * 4. Validation result from attempt 1 is valid for all subsequent retry attempts\n */\nexport function getWorkflowInputValidationEvent(events: WorkflowEvent[]): Extract<WorkflowEvent, { type: \"WorkflowInputValidation\" }> | undefined {\n // Get the most recent validation event (input doesn't change across attempts)\n const validationEvents = events.filter((e): e is Extract<WorkflowEvent, { type: \"WorkflowInputValidation\" }> =>\n e.type === \"WorkflowInputValidation\"\n );\n return validationEvents.length > 0 ? validationEvents[validationEvents.length - 1] : undefined;\n}\n",
14
+ "import type { Backend, Event } from \"@cascade-flow/backend-interface\";\n\n/**\n * Batches log events and flushes them periodically to reduce database round-trips.\n *\n * Instead of one INSERT per log line, the batcher accumulates events and\n * writes them in a single batch query every `flushIntervalMs` milliseconds.\n *\n * Flushes are serialized — at most one batchAppendEvents call is in-flight at\n * a time to avoid piling up pool connections when writes are slow.\n *\n * On transient flush failures the failed batch is prepended back to the buffer\n * for retry on the next flush cycle. If logs are still undelivered at drain()\n * time, drain() makes one final attempt and propagates the error.\n */\nexport class LogBatcher {\n private buffer: Array<{ workflowSlug: string; runId: string; event: Event }> = [];\n private timer: Timer | null = null;\n private flushing: Promise<void> | null = null;\n\n constructor(\n private backend: Backend,\n private flushIntervalMs: number = 500\n ) {}\n\n /**\n * Add a log event to the buffer. Starts the flush timer if not already running.\n */\n add(workflowSlug: string, runId: string, event: Event): void {\n this.buffer.push({ workflowSlug, runId, event });\n this.scheduleFlush();\n }\n\n private scheduleFlush(): void {\n if (this.timer || this.flushing) return;\n this.timer = setTimeout(() => {\n this.timer = null;\n this.doFlush();\n }, this.flushIntervalMs);\n }\n\n /**\n * Kick off a flush and, when it finishes, re-flush if more data accumulated.\n * On failure, prepend the batch back to the buffer for retry.\n */\n private doFlush(): void {\n if (this.flushing || this.buffer.length === 0) return;\n const batch = this.buffer;\n this.buffer = [];\n this.flushing = this.backend.batchAppendEvents(batch)\n .catch(() => {\n // Prepend failed batch back so it gets retried\n this.buffer = batch.concat(this.buffer);\n })\n .finally(() => {\n this.flushing = null;\n if (this.buffer.length > 0) {\n this.scheduleFlush();\n }\n });\n }\n\n /**\n * Drain all remaining buffered events and wait for in-flight flush to complete.\n * Must be called before writing terminal step events (StepCompleted/StepFailed).\n */\n async drain(): Promise<void> {\n if (this.timer) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n // Wait for any in-flight flush first\n if (this.flushing) {\n await this.flushing;\n }\n // Flush remaining buffer (includes any retried batches from failed flushes)\n if (this.buffer.length > 0) {\n const batch = this.buffer;\n this.buffer = [];\n await this.backend.batchAppendEvents(batch);\n }\n }\n}\n"
14
15
  ],
15
- "mappings": "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",
16
- "debugId": "0C8D0652261AD70364756E2164756E21",
16
+ "mappings": "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",
17
+ "debugId": "14E4D7C2C231256D64756E2164756E21",
17
18
  "names": []
18
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"step-worker.d.ts","sourceRoot":"","sources":["../src/step-worker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAC;AA0B/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAmDrE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,WAAW,CAOJ;IACf,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,aAAa,CAA2F;IAChH,OAAO,CAAC,SAAS,CAA0B;IAE3C;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;gBAqBd,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,GAAE,iBAAsB;IAuC9D;;OAEG;IACH,QAAQ,IAAI,eAAe;IAI3B;;;;;;;OAOG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAiD5B;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB3B;;OAEG;YACW,aAAa;IAoB3B;;;OAGG;YACW,iBAAiB;IAsD/B;;OAEG;YACW,YAAY;IA6C1B;;OAEG;YACW,aAAa;IAkN3B;;OAEG;YACW,eAAe;IAoG7B;;;;OAIG;YACW,yBAAyB;IA2BvC;;OAEG;YACW,WAAW;IA8dzB;;;OAGG;YACW,gBAAgB;IAyB9B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,cAAc,CAAC,CAAQ;CAChC"}
1
+ {"version":3,"file":"step-worker.d.ts","sourceRoot":"","sources":["../src/step-worker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAC;AA0B/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAsJrE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,WAAW,CAOJ;IACf,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,aAAa,CAA2F;IAChH,OAAO,CAAC,SAAS,CAA0B;IAE3C;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;gBAqBd,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,GAAE,iBAAsB;IAuC9D;;OAEG;IACH,QAAQ,IAAI,eAAe;IAI3B;;;;;;;OAOG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAiD5B;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB3B;;OAEG;YACW,aAAa;IAoB3B;;;OAGG;YACW,iBAAiB;IAsD/B;;OAEG;YACW,YAAY;IA6C1B;;OAEG;YACW,aAAa;IAkN3B;;OAEG;YACW,eAAe;IAoG7B;;;;OAIG;YACW,yBAAyB;IA2BvC;;OAEG;YACW,WAAW;IAidzB;;;OAGG;YACW,gBAAgB;IAyB9B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,cAAc,CAAC,CAAQ;CAChC"}
@@ -0,0 +1,38 @@
1
+ import type { Backend, Event } from "@cascade-flow/backend-interface";
2
+ /**
3
+ * Batches log events and flushes them periodically to reduce database round-trips.
4
+ *
5
+ * Instead of one INSERT per log line, the batcher accumulates events and
6
+ * writes them in a single batch query every `flushIntervalMs` milliseconds.
7
+ *
8
+ * Flushes are serialized — at most one batchAppendEvents call is in-flight at
9
+ * a time to avoid piling up pool connections when writes are slow.
10
+ *
11
+ * On transient flush failures the failed batch is prepended back to the buffer
12
+ * for retry on the next flush cycle. If logs are still undelivered at drain()
13
+ * time, drain() makes one final attempt and propagates the error.
14
+ */
15
+ export declare class LogBatcher {
16
+ private backend;
17
+ private flushIntervalMs;
18
+ private buffer;
19
+ private timer;
20
+ private flushing;
21
+ constructor(backend: Backend, flushIntervalMs?: number);
22
+ /**
23
+ * Add a log event to the buffer. Starts the flush timer if not already running.
24
+ */
25
+ add(workflowSlug: string, runId: string, event: Event): void;
26
+ private scheduleFlush;
27
+ /**
28
+ * Kick off a flush and, when it finishes, re-flush if more data accumulated.
29
+ * On failure, prepend the batch back to the buffer for retry.
30
+ */
31
+ private doFlush;
32
+ /**
33
+ * Drain all remaining buffered events and wait for in-flight flush to complete.
34
+ * Must be called before writing terminal step events (StepCompleted/StepFailed).
35
+ */
36
+ drain(): Promise<void>;
37
+ }
38
+ //# sourceMappingURL=log-batcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-batcher.d.ts","sourceRoot":"","sources":["../../src/utils/log-batcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AAEtE;;;;;;;;;;;;GAYG;AACH,qBAAa,UAAU;IAMnB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,eAAe;IANzB,OAAO,CAAC,MAAM,CAAoE;IAClF,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,QAAQ,CAA8B;gBAGpC,OAAO,EAAE,OAAO,EAChB,eAAe,GAAE,MAAY;IAGvC;;OAEG;IACH,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAK5D,OAAO,CAAC,aAAa;IAQrB;;;OAGG;IACH,OAAO,CAAC,OAAO;IAiBf;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB7B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cascade-flow/worker",
3
- "version": "0.2.25",
3
+ "version": "0.2.27",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",