@jagreehal/workflow 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +664 -350
- package/dist/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +179 -1
- package/dist/core.d.ts +179 -1
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +5 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/visualize.cjs +6 -6
- package/dist/visualize.cjs.map +1 -1
- package/dist/visualize.js +6 -6
- package/dist/visualize.js.map +1 -1
- package/dist/workflow.cjs +1 -1
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.js +1 -1
- package/dist/workflow.js.map +1 -1
- package/docs/coming-from-neverthrow.md +920 -0
- package/docs/visualize-examples.md +330 -0
- package/package.json +2 -1
package/dist/visualize.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/visualize/utils/timing.ts","../src/visualize/parallel-detector.ts","../src/visualize/ir-builder.ts","../src/visualize/types.ts","../src/visualize/renderers/colors.ts","../src/visualize/renderers/ascii.ts","../src/visualize/renderers/mermaid.ts","../src/visualize/live-visualizer.ts","../src/visualize/decision-tracker.ts","../src/visualize/index.ts"],"sourcesContent":["/**\n * Timing utilities for workflow visualization.\n */\n\n/**\n * Format duration in milliseconds to a human-readable string.\n *\n * @example\n * formatDuration(23) // \"23ms\"\n * formatDuration(1500) // \"1.5s\"\n * formatDuration(65000) // \"1m 5s\"\n */\nexport function formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${Math.round(ms)}ms`;\n }\n\n if (ms < 60000) {\n const seconds = ms / 1000;\n // Show one decimal for seconds\n return `${seconds.toFixed(1).replace(/\\.0$/, \"\")}s`;\n }\n\n const minutes = Math.floor(ms / 60000);\n const seconds = Math.round((ms % 60000) / 1000);\n\n if (seconds === 0) {\n return `${minutes}m`;\n }\n\n return `${minutes}m ${seconds}s`;\n}\n\n/**\n * Generate a unique ID for nodes.\n */\nexport function generateId(): string {\n return `node_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n}\n","/**\n * Parallel Detection - Heuristic detection of parallel execution from timing.\n *\n * When steps overlap in time (one starts before another ends), they are\n * likely running in parallel. This module detects such patterns and\n * groups overlapping steps into ParallelNode structures.\n */\n\nimport type { FlowNode, ParallelNode, StepNode } from \"./types\";\n\n/**\n * Options for parallel detection.\n */\nexport interface ParallelDetectorOptions {\n /**\n * Minimum overlap in milliseconds to consider steps parallel.\n * Default: 0 (any overlap counts)\n */\n minOverlapMs?: number;\n\n /**\n * Maximum gap in milliseconds to still consider steps as part of same parallel group.\n * Default: 5 (steps starting within 5ms are grouped)\n */\n maxGapMs?: number;\n}\n\n/**\n * Step timing information for overlap detection.\n */\ninterface StepTiming {\n node: StepNode;\n startTs: number;\n endTs: number;\n}\n\n/**\n * Check if nodes contain real scope nodes (from scope_start/scope_end events).\n * When real scope nodes exist, heuristic detection should be skipped to avoid\n * duplicating or conflicting with the explicit structure.\n */\nfunction hasRealScopeNodes(nodes: FlowNode[]): boolean {\n for (const node of nodes) {\n // Real scope nodes are parallel/race/sequence that came from scope events\n // (not from heuristic detection, which uses ids starting with \"detected_\")\n if (\n (node.type === \"parallel\" || node.type === \"race\" || node.type === \"sequence\") &&\n !node.id.startsWith(\"detected_\")\n ) {\n return true;\n }\n // Also check for decision nodes if present\n if (\"decisionId\" in node) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Group overlapping steps into parallel nodes.\n *\n * Algorithm:\n * 1. Sort steps by start time\n * 2. For each step, check if it overlaps with existing parallel groups\n * 3. If it overlaps, add to group; otherwise start new sequence\n * 4. Merge overlapping groups when step bridges them\n *\n * Note: If real scope nodes (from scope_start/scope_end) are present,\n * heuristic detection is skipped to avoid conflicts.\n */\nexport function detectParallelGroups(\n nodes: FlowNode[],\n options: ParallelDetectorOptions = {}\n): FlowNode[] {\n // If real scope nodes exist, skip heuristic detection\n // The explicit scope events provide accurate structure\n if (hasRealScopeNodes(nodes)) {\n return nodes;\n }\n\n const { maxGapMs = 5 } = options;\n\n // Extract step nodes with timing info, preserving indices for position restoration\n const stepsWithTiming: (StepTiming & { originalIndex: number })[] = [];\n const nonStepNodes: { node: FlowNode; originalIndex: number }[] = [];\n\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i];\n if (node.type === \"step\" && node.startTs !== undefined) {\n stepsWithTiming.push({\n node,\n startTs: node.startTs,\n endTs: node.endTs ?? node.startTs + (node.durationMs ?? 0),\n originalIndex: i,\n });\n } else {\n // Keep non-step nodes with their original position\n nonStepNodes.push({ node, originalIndex: i });\n }\n }\n\n if (stepsWithTiming.length <= 1) {\n return nodes; // Nothing to group\n }\n\n // Sort by start time\n stepsWithTiming.sort((a, b) => a.startTs - b.startTs);\n\n // Group overlapping steps\n type StepTimingWithIndex = StepTiming & { originalIndex: number };\n const groups: StepTimingWithIndex[][] = [];\n let currentGroup: StepTimingWithIndex[] = [stepsWithTiming[0]];\n\n for (let i = 1; i < stepsWithTiming.length; i++) {\n const step = stepsWithTiming[i];\n const groupEnd = Math.max(...currentGroup.map((s) => s.endTs));\n\n // Check if this step overlaps with current group\n if (step.startTs <= groupEnd + maxGapMs) {\n currentGroup.push(step);\n } else {\n // No overlap - finalize current group and start new one\n groups.push(currentGroup);\n currentGroup = [step];\n }\n }\n groups.push(currentGroup);\n\n // Convert groups to nodes with position tracking\n const groupedNodes: { node: FlowNode; position: number }[] = [];\n\n for (const group of groups) {\n // Use the minimum original index as the position for the group\n const position = Math.min(...group.map((s) => s.originalIndex));\n\n if (group.length === 1) {\n // Single step - no parallel grouping needed\n groupedNodes.push({ node: group[0].node, position });\n } else {\n // Multiple overlapping steps - create parallel node\n const children = group.map((s) => s.node);\n const startTs = Math.min(...group.map((s) => s.startTs));\n const endTs = Math.max(...group.map((s) => s.endTs));\n\n const parallelNode: ParallelNode = {\n type: \"parallel\",\n id: `detected_parallel_${startTs}`,\n name: `${children.length} parallel steps`,\n state: deriveGroupState(children),\n mode: \"all\",\n children,\n startTs,\n endTs,\n durationMs: endTs - startTs,\n };\n\n groupedNodes.push({ node: parallelNode, position });\n }\n }\n\n // Add non-step nodes with their original positions\n for (const { node, originalIndex } of nonStepNodes) {\n groupedNodes.push({ node, position: originalIndex });\n }\n\n // Sort by original position to preserve ordering\n groupedNodes.sort((a, b) => a.position - b.position);\n\n return groupedNodes.map((g) => g.node);\n}\n\n/**\n * Derive the state of a group from its children.\n */\nfunction deriveGroupState(\n children: FlowNode[]\n): \"pending\" | \"running\" | \"success\" | \"error\" | \"aborted\" | \"cached\" {\n const hasError = children.some((c) => c.state === \"error\");\n if (hasError) return \"error\";\n\n const hasRunning = children.some((c) => c.state === \"running\");\n if (hasRunning) return \"running\";\n\n const hasPending = children.some((c) => c.state === \"pending\");\n if (hasPending) return \"pending\";\n\n const allSuccess = children.every(\n (c) => c.state === \"success\" || c.state === \"cached\"\n );\n if (allSuccess) return \"success\";\n\n return \"success\";\n}\n\n/**\n * Create a parallel detector that processes nodes.\n */\nexport function createParallelDetector(options: ParallelDetectorOptions = {}) {\n return {\n /**\n * Process nodes and group overlapping ones into parallel nodes.\n */\n detect: (nodes: FlowNode[]) => detectParallelGroups(nodes, options),\n };\n}\n","/**\n * IR Builder - Converts workflow events to Intermediate Representation.\n *\n * The builder maintains state as events arrive, constructing a tree\n * representation of the workflow execution that can be rendered.\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type {\n FlowNode,\n ScopeEndEvent,\n ScopeStartEvent,\n ScopeType,\n StepNode,\n StepState,\n WorkflowIR,\n WorkflowNode,\n ParallelNode,\n RaceNode,\n DecisionNode,\n DecisionStartEvent,\n DecisionBranchEvent,\n DecisionEndEvent,\n DecisionBranch,\n} from \"./types\";\nimport { generateId } from \"./utils/timing\";\nimport { detectParallelGroups, type ParallelDetectorOptions } from \"./parallel-detector\";\n\n// =============================================================================\n// Builder Options\n// =============================================================================\n\n/**\n * Options for the IR builder.\n */\nexport interface IRBuilderOptions {\n /**\n * Enable heuristic parallel detection based on timing.\n * When true, overlapping steps are grouped into ParallelNodes.\n * Default: true\n */\n detectParallel?: boolean;\n\n /**\n * Options for parallel detection.\n */\n parallelDetection?: ParallelDetectorOptions;\n}\n\n// =============================================================================\n// Builder State\n// =============================================================================\n\ninterface ActiveStep {\n id: string;\n name?: string;\n key?: string;\n startTs: number;\n retryCount: number;\n timedOut: boolean;\n timeoutMs?: number;\n}\n\ninterface ActiveScope {\n id: string;\n name?: string;\n type: ScopeType;\n startTs: number;\n children: FlowNode[];\n}\n\ninterface ActiveDecision {\n id: string;\n name?: string;\n condition?: string;\n decisionValue?: unknown;\n startTs: number;\n branches: Map<string, DecisionBranch>;\n branchTaken?: string | boolean;\n}\n\n// =============================================================================\n// IR Builder\n// =============================================================================\n\n/**\n * Creates an IR builder that processes workflow events.\n */\nexport function createIRBuilder(options: IRBuilderOptions = {}) {\n const { detectParallel = true, parallelDetection } = options;\n\n // Current workflow state\n let workflowId: string | undefined;\n let workflowStartTs: number | undefined;\n let workflowState: StepState = \"pending\";\n let workflowError: unknown;\n let workflowDurationMs: number | undefined;\n\n // Active steps (currently running)\n const activeSteps = new Map<string, ActiveStep>();\n\n // Active scopes (parallel/race blocks)\n const scopeStack: ActiveScope[] = [];\n\n // Active decisions (conditional branches)\n const decisionStack: ActiveDecision[] = [];\n\n // Completed nodes at the current scope level\n let currentNodes: FlowNode[] = [];\n\n // Metadata\n let createdAt = Date.now();\n let lastUpdatedAt = createdAt;\n\n /**\n * Get the step ID from an event.\n * Uses stepId if available (new events), then falls back to stepKey or name,\n * and finally generates a random ID for backwards compatibility.\n */\n function getStepId(event: { stepId?: string; stepKey?: string; name?: string }): string {\n return event.stepId ?? event.stepKey ?? event.name ?? generateId();\n }\n\n /**\n * Add a completed node to the current scope or decision branch.\n */\n function addNode(node: FlowNode): void {\n // If we're in a decision, add to the taken branch\n if (decisionStack.length > 0) {\n const decision = decisionStack[decisionStack.length - 1];\n // Find the taken branch\n for (const branch of decision.branches.values()) {\n if (branch.taken) {\n branch.children.push(node);\n lastUpdatedAt = Date.now();\n return;\n }\n }\n // If no branch is marked as taken yet, add to the first branch\n // (this handles cases where steps execute before branch is marked)\n const firstBranch = Array.from(decision.branches.values())[0];\n if (firstBranch) {\n firstBranch.children.push(node);\n lastUpdatedAt = Date.now();\n return;\n }\n }\n\n // If we're in a scope, add to the scope\n if (scopeStack.length > 0) {\n // Add to the innermost scope\n scopeStack[scopeStack.length - 1].children.push(node);\n } else {\n // Add to the root level\n currentNodes.push(node);\n }\n lastUpdatedAt = Date.now();\n }\n\n /**\n * Handle a workflow event and update the IR.\n */\n function handleEvent(event: WorkflowEvent<unknown>): void {\n switch (event.type) {\n case \"workflow_start\":\n workflowId = event.workflowId;\n workflowStartTs = event.ts;\n workflowState = \"running\";\n createdAt = Date.now();\n lastUpdatedAt = createdAt;\n break;\n\n case \"workflow_success\":\n workflowState = \"success\";\n workflowDurationMs = event.durationMs;\n lastUpdatedAt = Date.now();\n break;\n\n case \"workflow_error\":\n workflowState = \"error\";\n workflowError = event.error;\n workflowDurationMs = event.durationMs;\n lastUpdatedAt = Date.now();\n break;\n\n case \"step_start\": {\n const id = getStepId(event);\n activeSteps.set(id, {\n id,\n name: event.name,\n key: event.stepKey,\n startTs: event.ts,\n retryCount: 0,\n timedOut: false,\n });\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"step_success\": {\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n const node: StepNode = {\n type: \"step\",\n id: active.id,\n name: active.name,\n key: active.key,\n state: \"success\",\n startTs: active.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n ...(active.retryCount > 0 && { retryCount: active.retryCount }),\n ...(active.timedOut && { timedOut: true, timeoutMs: active.timeoutMs }),\n };\n addNode(node);\n activeSteps.delete(id);\n }\n break;\n }\n\n case \"step_error\": {\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n const node: StepNode = {\n type: \"step\",\n id: active.id,\n name: active.name,\n key: active.key,\n state: \"error\",\n startTs: active.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n error: event.error,\n ...(active.retryCount > 0 && { retryCount: active.retryCount }),\n ...(active.timedOut && { timedOut: true, timeoutMs: active.timeoutMs }),\n };\n addNode(node);\n activeSteps.delete(id);\n }\n break;\n }\n\n case \"step_aborted\": {\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n const node: StepNode = {\n type: \"step\",\n id: active.id,\n name: active.name,\n key: active.key,\n state: \"aborted\",\n startTs: active.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n ...(active.retryCount > 0 && { retryCount: active.retryCount }),\n ...(active.timedOut && { timedOut: true, timeoutMs: active.timeoutMs }),\n };\n addNode(node);\n activeSteps.delete(id);\n }\n break;\n }\n\n case \"step_cache_hit\": {\n const id = getStepId(event);\n const node: StepNode = {\n type: \"step\",\n id,\n name: event.name,\n key: event.stepKey,\n state: \"cached\",\n startTs: event.ts,\n endTs: event.ts,\n durationMs: 0,\n };\n addNode(node);\n break;\n }\n\n case \"step_cache_miss\":\n // Cache miss just means the step will execute normally\n // We'll get a step_start event next\n break;\n\n case \"step_complete\":\n // step_complete is for state persistence, not visualization\n // We already handled the step via step_success/step_error\n break;\n\n case \"step_timeout\": {\n // Timeout is an intermediate event - step may retry or will get step_error\n // Track timeout info on the active step\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n active.timedOut = true;\n active.timeoutMs = event.timeoutMs;\n }\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"step_retry\": {\n // Retry is an intermediate event - increment retry counter\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n active.retryCount = (event.attempt ?? 1) - 1; // attempt is 1-indexed, retryCount is 0-indexed\n }\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"step_retries_exhausted\":\n // All retries exhausted - step_error will follow\n // The error state will be set by step_error handler\n lastUpdatedAt = Date.now();\n break;\n\n case \"step_skipped\": {\n const id = getStepId(event);\n const node: StepNode = {\n type: \"step\",\n id,\n name: event.name,\n key: event.stepKey,\n state: \"skipped\",\n startTs: event.ts,\n endTs: event.ts,\n durationMs: 0,\n };\n addNode(node);\n break;\n }\n }\n }\n\n /**\n * Handle a scope event (parallel/race start/end).\n */\n function handleScopeEvent(event: ScopeStartEvent | ScopeEndEvent): void {\n if (event.type === \"scope_start\") {\n scopeStack.push({\n id: event.scopeId,\n name: event.name,\n type: event.scopeType,\n startTs: event.ts,\n children: [],\n });\n lastUpdatedAt = Date.now();\n } else if (event.type === \"scope_end\") {\n const scope = scopeStack.pop();\n if (scope) {\n const node: ParallelNode | RaceNode =\n scope.type === \"race\"\n ? {\n type: \"race\",\n id: scope.id,\n name: scope.name,\n state: deriveState(scope.children),\n startTs: scope.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n children: scope.children,\n winnerId: event.winnerId,\n }\n : {\n type: \"parallel\",\n id: scope.id,\n name: scope.name,\n state: deriveState(scope.children),\n startTs: scope.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n children: scope.children,\n mode: scope.type === \"allSettled\" ? \"allSettled\" : \"all\",\n };\n addNode(node);\n }\n }\n }\n\n /**\n * Handle a decision event (conditional branch start/branch/end).\n */\n function handleDecisionEvent(\n event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent\n ): void {\n if (event.type === \"decision_start\") {\n decisionStack.push({\n id: event.decisionId,\n name: event.name,\n condition: event.condition,\n decisionValue: event.decisionValue,\n startTs: event.ts,\n branches: new Map(),\n });\n lastUpdatedAt = Date.now();\n } else if (event.type === \"decision_branch\") {\n const decision = decisionStack[decisionStack.length - 1];\n if (decision && decision.id === event.decisionId) {\n // Find or create branch\n const branchKey = event.branchLabel;\n const existing = decision.branches.get(branchKey);\n if (existing) {\n // Update existing branch\n existing.taken = event.taken;\n } else {\n // Create new branch\n decision.branches.set(branchKey, {\n label: event.branchLabel,\n condition: event.condition,\n taken: event.taken,\n children: [],\n });\n }\n lastUpdatedAt = Date.now();\n }\n } else if (event.type === \"decision_end\") {\n const decision = decisionStack.pop();\n if (decision && decision.id === event.decisionId) {\n // Convert branches map to array\n const branches: DecisionBranch[] = Array.from(decision.branches.values());\n\n const node: DecisionNode = {\n type: \"decision\",\n id: decision.id,\n name: decision.name,\n state: deriveState(\n branches.flatMap((b) => (b.taken ? b.children : []))\n ),\n startTs: decision.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n condition: decision.condition,\n decisionValue: decision.decisionValue,\n branchTaken: event.branchTaken ?? decision.branchTaken,\n branches,\n };\n addNode(node);\n }\n }\n }\n\n /**\n * Derive the state of a parent node from its children.\n */\n function deriveState(children: FlowNode[]): StepState {\n if (children.length === 0) return \"success\";\n\n const hasError = children.some((c) => c.state === \"error\");\n if (hasError) return \"error\";\n\n const allSuccess = children.every(\n (c) => c.state === \"success\" || c.state === \"cached\"\n );\n if (allSuccess) return \"success\";\n\n const hasRunning = children.some((c) => c.state === \"running\");\n if (hasRunning) return \"running\";\n\n return \"pending\";\n }\n\n /**\n * Get the current nodes including any active (running) steps.\n */\n function getCurrentNodes(): FlowNode[] {\n const nodes = [...currentNodes];\n\n // Add active steps as running nodes\n for (const [, active] of activeSteps) {\n nodes.push({\n type: \"step\",\n id: active.id,\n name: active.name,\n key: active.key,\n state: \"running\",\n startTs: active.startTs,\n ...(active.retryCount > 0 && { retryCount: active.retryCount }),\n ...(active.timedOut && { timedOut: true, timeoutMs: active.timeoutMs }),\n });\n }\n\n return nodes;\n }\n\n /**\n * Build and return the current IR state.\n */\n function getIR(): WorkflowIR {\n let children = getCurrentNodes();\n\n // Apply parallel detection if enabled\n if (detectParallel) {\n children = detectParallelGroups(children, parallelDetection);\n }\n\n const root: WorkflowNode = {\n type: \"workflow\",\n id: workflowId ?? generateId(),\n workflowId: workflowId ?? \"unknown\",\n state: workflowState,\n startTs: workflowStartTs,\n durationMs: workflowDurationMs,\n children,\n error: workflowError,\n };\n\n return {\n root,\n metadata: {\n createdAt,\n lastUpdatedAt,\n },\n };\n }\n\n /**\n * Reset the builder state.\n */\n function reset(): void {\n workflowId = undefined;\n workflowStartTs = undefined;\n workflowState = \"pending\";\n workflowError = undefined;\n workflowDurationMs = undefined;\n activeSteps.clear();\n scopeStack.length = 0;\n decisionStack.length = 0;\n currentNodes = [];\n createdAt = Date.now();\n lastUpdatedAt = createdAt;\n }\n\n return {\n handleEvent,\n handleScopeEvent,\n handleDecisionEvent,\n getIR,\n reset,\n /** Check if there are active (running) steps */\n get hasActiveSteps() {\n return activeSteps.size > 0;\n },\n /** Get the current workflow state */\n get state() {\n return workflowState;\n },\n };\n}\n\n/**\n * Type for the IR builder instance.\n */\nexport type IRBuilder = ReturnType<typeof createIRBuilder>;\n","/**\n * Workflow Visualization - Intermediate Representation Types\n *\n * The IR (Intermediate Representation) is a DSL that represents workflow\n * execution structure. Events are converted to IR, which can then be\n * rendered to various output formats (ASCII, Mermaid, JSON, etc.).\n */\n\n// =============================================================================\n// Step States\n// =============================================================================\n\n/**\n * Execution state of a step with semantic meaning for visualization.\n *\n * Color mapping:\n * - pending → white/clear (not started)\n * - running → yellow (currently executing)\n * - success → green (completed successfully)\n * - error → red (failed with error)\n * - aborted → gray (cancelled, e.g., in race)\n * - cached → blue (served from cache)\n * - skipped → dim gray (not executed due to conditional logic)\n */\nexport type StepState =\n | \"pending\"\n | \"running\"\n | \"success\"\n | \"error\"\n | \"aborted\"\n | \"cached\"\n | \"skipped\";\n\n// =============================================================================\n// Node Types\n// =============================================================================\n\n/**\n * Base properties shared by all IR nodes.\n */\nexport interface BaseNode {\n /** Unique identifier for this node */\n id: string;\n /** Human-readable name (from step options or inferred) */\n name?: string;\n /** Cache key if this is a keyed step */\n key?: string;\n /** Current execution state */\n state: StepState;\n /** Timestamp when execution started */\n startTs?: number;\n /** Timestamp when execution ended */\n endTs?: number;\n /** Duration in milliseconds */\n durationMs?: number;\n /** Error value if state is 'error' */\n error?: unknown;\n /** Input value that triggered this step (for decision understanding) */\n input?: unknown;\n /** Output value from this step (for decision understanding) */\n output?: unknown;\n /** Number of retry attempts made (0 = no retries, 1 = one retry, etc.) */\n retryCount?: number;\n /** Whether this step experienced a timeout (may have retried after) */\n timedOut?: boolean;\n /** Timeout duration in ms (if timed out) */\n timeoutMs?: number;\n}\n\n/**\n * A single step execution node.\n */\nexport interface StepNode extends BaseNode {\n type: \"step\";\n}\n\n/**\n * Sequential execution - steps run one after another.\n * This is the implicit structure when steps are awaited in sequence.\n */\nexport interface SequenceNode extends BaseNode {\n type: \"sequence\";\n children: FlowNode[];\n}\n\n/**\n * Parallel execution - all branches run simultaneously.\n * Created by allAsync() or allSettledAsync().\n */\nexport interface ParallelNode extends BaseNode {\n type: \"parallel\";\n children: FlowNode[];\n /**\n * Execution mode:\n * - 'all': Fails on first error (allAsync)\n * - 'allSettled': Collects all results (allSettledAsync)\n */\n mode: \"all\" | \"allSettled\";\n}\n\n/**\n * Race execution - first to complete wins.\n * Created by anyAsync().\n */\nexport interface RaceNode extends BaseNode {\n type: \"race\";\n children: FlowNode[];\n /** ID of the winning branch (first to succeed) */\n winnerId?: string;\n}\n\n/**\n * Decision point - conditional branch (if/switch).\n * Shows which branch was taken and why.\n */\nexport interface DecisionNode extends BaseNode {\n type: \"decision\";\n /** Condition that was evaluated (e.g., \"user.role === 'admin'\") */\n condition?: string;\n /** Value that was evaluated (the input to the decision) */\n decisionValue?: unknown;\n /** Which branch was taken (true/false, or the matched case) */\n branchTaken?: string | boolean;\n /** All possible branches (including skipped ones) */\n branches: DecisionBranch[];\n}\n\n/**\n * A branch in a decision node.\n */\nexport interface DecisionBranch {\n /** Label for this branch (e.g., \"if\", \"else\", \"case 'admin'\") */\n label: string;\n /** Condition that would trigger this branch */\n condition?: string;\n /** Whether this branch was taken */\n taken: boolean;\n /** Steps in this branch */\n children: FlowNode[];\n}\n\n/**\n * Union of all flow node types.\n */\nexport type FlowNode = StepNode | SequenceNode | ParallelNode | RaceNode | DecisionNode;\n\n/**\n * Root node representing the entire workflow.\n */\nexport interface WorkflowNode extends BaseNode {\n type: \"workflow\";\n /** Correlation ID from the workflow execution */\n workflowId: string;\n /** Child nodes (steps, parallel blocks, etc.) */\n children: FlowNode[];\n}\n\n// =============================================================================\n// Workflow IR\n// =============================================================================\n\n/**\n * Complete workflow intermediate representation.\n * This is the main data structure produced by the IR builder.\n */\nexport interface WorkflowIR {\n /** Root workflow node */\n root: WorkflowNode;\n /** Metadata about the IR */\n metadata: {\n /** When the IR was first created */\n createdAt: number;\n /** When the IR was last updated */\n lastUpdatedAt: number;\n };\n}\n\n// =============================================================================\n// Scope Events (for parallel/race detection)\n// =============================================================================\n\n// Re-export ScopeType from core for consistency\nexport type { ScopeType } from \"../core\";\nimport type { ScopeType } from \"../core\";\n\n/**\n * Event emitted when entering a parallel/race scope.\n * This matches the scope_start event in WorkflowEvent.\n */\nexport interface ScopeStartEvent {\n type: \"scope_start\";\n workflowId: string;\n scopeId: string;\n scopeType: ScopeType;\n name?: string;\n ts: number;\n}\n\n/**\n * Event emitted when exiting a parallel/race scope.\n */\nexport interface ScopeEndEvent {\n type: \"scope_end\";\n workflowId: string;\n scopeId: string;\n ts: number;\n durationMs: number;\n /** For race scopes, the ID of the winning branch */\n winnerId?: string;\n}\n\n/**\n * Event emitted when a decision point is encountered.\n * Use this to track conditional logic (if/switch).\n */\nexport interface DecisionStartEvent {\n type: \"decision_start\";\n workflowId: string;\n decisionId: string;\n /** Condition being evaluated (e.g., \"user.role === 'admin'\") */\n condition?: string;\n /** Value being evaluated */\n decisionValue?: unknown;\n /** Name/label for this decision point */\n name?: string;\n ts: number;\n}\n\n/**\n * Event emitted when a decision branch is taken.\n */\nexport interface DecisionBranchEvent {\n type: \"decision_branch\";\n workflowId: string;\n decisionId: string;\n /** Label for this branch (e.g., \"if\", \"else\", \"case 'admin'\") */\n branchLabel: string;\n /** Condition for this branch */\n condition?: string;\n /** Whether this branch was taken */\n taken: boolean;\n ts: number;\n}\n\n/**\n * Event emitted when a decision point completes.\n */\nexport interface DecisionEndEvent {\n type: \"decision_end\";\n workflowId: string;\n decisionId: string;\n /** Which branch was taken */\n branchTaken?: string | boolean;\n ts: number;\n durationMs: number;\n}\n\n/**\n * Event emitted when a step is skipped due to conditional logic.\n */\nexport interface StepSkippedEvent {\n type: \"step_skipped\";\n workflowId: string;\n stepKey?: string;\n name?: string;\n /** Reason why this step was skipped (e.g., \"condition was false\") */\n reason?: string;\n /** The decision that caused this skip */\n decisionId?: string;\n ts: number;\n}\n\n/**\n * Union of scope-related events.\n */\nexport type ScopeEvent = ScopeStartEvent | ScopeEndEvent;\n\n/**\n * Union of decision-related events.\n */\nexport type DecisionEvent = DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent;\n\n// =============================================================================\n// Renderer Types\n// =============================================================================\n\n/**\n * Color scheme for rendering step states.\n */\nexport interface ColorScheme {\n pending: string;\n running: string;\n success: string;\n error: string;\n aborted: string;\n cached: string;\n skipped: string;\n}\n\n/**\n * Options passed to renderers.\n */\nexport interface RenderOptions {\n /** Show timing information (duration) */\n showTimings: boolean;\n /** Show step cache keys */\n showKeys: boolean;\n /** Terminal width for ASCII renderer */\n terminalWidth?: number;\n /** Color scheme */\n colors: ColorScheme;\n}\n\n/**\n * Renderer interface - transforms IR to output format.\n */\nexport interface Renderer {\n /** Unique identifier for this renderer */\n readonly name: string;\n /** Render IR to string output */\n render(ir: WorkflowIR, options: RenderOptions): string;\n /** Whether this renderer supports live (incremental) updates */\n supportsLive?: boolean;\n /** Render incremental update (optional) */\n renderUpdate?(\n ir: WorkflowIR,\n changedNodes: FlowNode[],\n options: RenderOptions\n ): string;\n}\n\n// =============================================================================\n// Visualizer Types\n// =============================================================================\n\n/**\n * Output format for rendering.\n */\nexport type OutputFormat = \"ascii\" | \"mermaid\" | \"json\";\n\n/**\n * Options for creating a visualizer.\n */\nexport interface VisualizerOptions {\n /** Name for the workflow in visualizations */\n workflowName?: string;\n /** Enable parallel detection heuristics (default: true) */\n detectParallel?: boolean;\n /** Show timing information (default: true) */\n showTimings?: boolean;\n /** Show step keys (default: false) */\n showKeys?: boolean;\n /** Custom color scheme */\n colors?: Partial<ColorScheme>;\n}\n\n/**\n * Options for live visualization.\n */\nexport interface LiveVisualizerOptions extends VisualizerOptions {\n /** Output stream (default: process.stdout) */\n stream?: NodeJS.WriteStream;\n /** Update interval in ms (default: 100) */\n updateInterval?: number;\n}\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\n/**\n * Check if a node is a StepNode.\n */\nexport function isStepNode(node: FlowNode): node is StepNode {\n return node.type === \"step\";\n}\n\n/**\n * Check if a node is a SequenceNode.\n */\nexport function isSequenceNode(node: FlowNode): node is SequenceNode {\n return node.type === \"sequence\";\n}\n\n/**\n * Check if a node is a ParallelNode.\n */\nexport function isParallelNode(node: FlowNode): node is ParallelNode {\n return node.type === \"parallel\";\n}\n\n/**\n * Check if a node is a RaceNode.\n */\nexport function isRaceNode(node: FlowNode): node is RaceNode {\n return node.type === \"race\";\n}\n\n/**\n * Check if a node is a DecisionNode.\n */\nexport function isDecisionNode(node: FlowNode): node is DecisionNode {\n return node.type === \"decision\";\n}\n\n/**\n * Check if a node has children.\n */\nexport function hasChildren(\n node: FlowNode\n): node is SequenceNode | ParallelNode | RaceNode | DecisionNode {\n return \"children\" in node || (node.type === \"decision\" && \"branches\" in node);\n}\n","/**\n * ANSI color utilities for terminal output.\n */\n\nimport type { ColorScheme, StepState } from \"../types\";\n\n// =============================================================================\n// ANSI Escape Codes\n// =============================================================================\n\nconst RESET = \"\\x1b[0m\";\nconst BOLD = \"\\x1b[1m\";\nconst DIM = \"\\x1b[2m\";\n\n// Foreground colors\nconst FG_RED = \"\\x1b[31m\";\nconst FG_GREEN = \"\\x1b[32m\";\nconst FG_YELLOW = \"\\x1b[33m\";\nconst FG_BLUE = \"\\x1b[34m\";\nconst FG_GRAY = \"\\x1b[90m\";\nconst FG_WHITE = \"\\x1b[37m\";\n\n// =============================================================================\n// Color Functions\n// =============================================================================\n\n/**\n * Apply ANSI color to text.\n */\nexport function colorize(text: string, color: string): string {\n if (!color) return text;\n return `${color}${text}${RESET}`;\n}\n\n/**\n * Make text bold.\n */\nexport function bold(text: string): string {\n return `${BOLD}${text}${RESET}`;\n}\n\n/**\n * Make text dim.\n */\nexport function dim(text: string): string {\n return `${DIM}${text}${RESET}`;\n}\n\n// =============================================================================\n// Default Color Scheme\n// =============================================================================\n\n/**\n * Default ANSI color scheme for step states.\n */\nexport const defaultColorScheme: ColorScheme = {\n pending: FG_WHITE,\n running: FG_YELLOW,\n success: FG_GREEN,\n error: FG_RED,\n aborted: FG_GRAY,\n cached: FG_BLUE,\n skipped: DIM + FG_GRAY, // Dim gray for skipped steps\n};\n\n// =============================================================================\n// State Symbols\n// =============================================================================\n\n/**\n * Get the symbol for a step state.\n */\nexport function getStateSymbol(state: StepState): string {\n switch (state) {\n case \"pending\":\n return \"○\"; // Empty circle\n case \"running\":\n return \"⟳\"; // Rotating arrows\n case \"success\":\n return \"✓\"; // Check mark\n case \"error\":\n return \"✗\"; // X mark\n case \"aborted\":\n return \"⊘\"; // Circled slash\n case \"cached\":\n return \"↺\"; // Cached/replay\n case \"skipped\":\n return \"⊘\"; // Circled slash (same as aborted, but different color)\n }\n}\n\n/**\n * Get the colored symbol for a step state.\n */\nexport function getColoredSymbol(state: StepState, colors: ColorScheme): string {\n const symbol = getStateSymbol(state);\n return colorize(symbol, colors[state]);\n}\n\n/**\n * Get colored text based on step state.\n */\nexport function colorByState(\n text: string,\n state: StepState,\n colors: ColorScheme\n): string {\n return colorize(text, colors[state]);\n}\n\n// =============================================================================\n// Strip ANSI\n// =============================================================================\n\n/**\n * Strip ANSI escape codes from a string.\n * Useful for calculating visible string length.\n */\nexport function stripAnsi(str: string): string {\n // eslint-disable-next-line no-control-regex\n return str.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n}\n\n/**\n * Get the visible length of a string (without ANSI codes).\n */\nexport function visibleLength(str: string): string {\n return stripAnsi(str);\n}\n","/**\n * ASCII Terminal Renderer\n *\n * Renders the workflow IR as ASCII art with box-drawing characters\n * and ANSI colors for terminal display.\n */\n\nimport type {\n FlowNode,\n ParallelNode,\n RaceNode,\n DecisionNode,\n Renderer,\n RenderOptions,\n StepNode,\n WorkflowIR,\n} from \"../types\";\nimport { isParallelNode, isRaceNode, isStepNode, isDecisionNode } from \"../types\";\nimport { formatDuration } from \"../utils/timing\";\nimport {\n bold,\n colorByState,\n colorize,\n defaultColorScheme,\n dim,\n getColoredSymbol,\n stripAnsi,\n} from \"./colors\";\n\n// =============================================================================\n// Box Drawing Characters\n// =============================================================================\n\nconst BOX = {\n topLeft: \"┌\",\n topRight: \"┐\",\n bottomLeft: \"└\",\n bottomRight: \"┘\",\n horizontal: \"─\",\n vertical: \"│\",\n teeRight: \"├\",\n teeLeft: \"┤\",\n teeDown: \"┬\",\n teeUp: \"┴\",\n cross: \"┼\",\n} as const;\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Pad a string to a fixed width, accounting for ANSI codes.\n */\nfunction padEnd(str: string, width: number): string {\n const visibleLen = stripAnsi(str).length;\n const padding = Math.max(0, width - visibleLen);\n return str + \" \".repeat(padding);\n}\n\n/**\n * Create a horizontal line with optional title.\n */\nfunction horizontalLine(width: number, title?: string): string {\n if (!title) {\n return BOX.horizontal.repeat(width);\n }\n\n const titleText = ` ${title} `;\n const remainingWidth = width - titleText.length;\n if (remainingWidth < 4) {\n return BOX.horizontal.repeat(width);\n }\n\n const leftPad = 2;\n const rightPad = remainingWidth - leftPad;\n\n return (\n BOX.horizontal.repeat(leftPad) + titleText + BOX.horizontal.repeat(rightPad)\n );\n}\n\n// =============================================================================\n// ASCII Renderer\n// =============================================================================\n\n/**\n * Create the ASCII terminal renderer.\n */\nexport function asciiRenderer(): Renderer {\n return {\n name: \"ascii\",\n supportsLive: true,\n\n render(ir: WorkflowIR, options: RenderOptions): string {\n const colors = { ...defaultColorScheme, ...options.colors };\n const width = options.terminalWidth ?? 60;\n const innerWidth = width - 4; // Account for borders\n\n const lines: string[] = [];\n\n // Header\n const workflowName = ir.root.name ?? \"workflow\";\n const headerTitle = bold(workflowName);\n lines.push(\n `${BOX.topLeft}${horizontalLine(width - 2, headerTitle)}${BOX.topRight}`\n );\n lines.push(`${BOX.vertical}${\" \".repeat(width - 2)}${BOX.vertical}`);\n\n // Render children\n const childLines = renderNodes(ir.root.children, options, colors, 0);\n for (const line of childLines) {\n lines.push(\n `${BOX.vertical} ${padEnd(line, innerWidth)}${BOX.vertical}`\n );\n }\n\n // Footer with timing\n lines.push(`${BOX.vertical}${\" \".repeat(width - 2)}${BOX.vertical}`);\n\n if (ir.root.durationMs !== undefined && options.showTimings) {\n const status = ir.root.state === \"success\" ? \"Completed\" : \"Failed\";\n const statusColored = colorByState(status, ir.root.state, colors);\n const footer = `${statusColored} in ${formatDuration(ir.root.durationMs)}`;\n lines.push(\n `${BOX.vertical} ${padEnd(footer, innerWidth)}${BOX.vertical}`\n );\n lines.push(`${BOX.vertical}${\" \".repeat(width - 2)}${BOX.vertical}`);\n }\n\n lines.push(\n `${BOX.bottomLeft}${BOX.horizontal.repeat(width - 2)}${BOX.bottomRight}`\n );\n\n return lines.join(\"\\n\");\n },\n };\n}\n\n/**\n * Render a list of nodes.\n */\nfunction renderNodes(\n nodes: FlowNode[],\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n depth: number\n): string[] {\n const lines: string[] = [];\n\n for (const node of nodes) {\n if (isStepNode(node)) {\n lines.push(renderStepNode(node, options, colors));\n } else if (isParallelNode(node)) {\n lines.push(...renderParallelNode(node, options, colors, depth));\n } else if (isRaceNode(node)) {\n lines.push(...renderRaceNode(node, options, colors, depth));\n } else if (isDecisionNode(node)) {\n lines.push(...renderDecisionNode(node, options, colors, depth));\n }\n }\n\n return lines;\n}\n\n/**\n * Render a single step node.\n */\nfunction renderStepNode(\n node: StepNode,\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>\n): string {\n const symbol = getColoredSymbol(node.state, colors);\n const name = node.name ?? node.key ?? \"step\";\n const nameColored = colorByState(name, node.state, colors);\n\n let line = `${symbol} ${nameColored}`;\n\n // Add key if requested\n if (options.showKeys && node.key) {\n line += dim(` [key: ${node.key}]`);\n }\n\n // Add input/output if available (for decision understanding)\n if (node.input !== undefined) {\n const inputStr = typeof node.input === \"string\" \n ? node.input \n : JSON.stringify(node.input).slice(0, 30);\n line += dim(` [in: ${inputStr}${inputStr.length >= 30 ? \"...\" : \"\"}]`);\n }\n if (node.output !== undefined && node.state === \"success\") {\n const outputStr = typeof node.output === \"string\"\n ? node.output\n : JSON.stringify(node.output).slice(0, 30);\n line += dim(` [out: ${outputStr}${outputStr.length >= 30 ? \"...\" : \"\"}]`);\n }\n\n // Add timing if available and requested\n if (options.showTimings && node.durationMs !== undefined) {\n line += dim(` [${formatDuration(node.durationMs)}]`);\n }\n\n // Add retry indicator if retries occurred\n if (node.retryCount !== undefined && node.retryCount > 0) {\n line += dim(` [${node.retryCount} ${node.retryCount === 1 ? \"retry\" : \"retries\"}]`);\n }\n\n // Add timeout indicator if step timed out\n if (node.timedOut) {\n const timeoutInfo = node.timeoutMs !== undefined ? ` ${node.timeoutMs}ms` : \"\";\n line += dim(` [timeout${timeoutInfo}]`);\n }\n\n return line;\n}\n\n/**\n * Render a parallel node (allAsync).\n */\nfunction renderParallelNode(\n node: ParallelNode,\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n depth: number\n): string[] {\n const lines: string[] = [];\n const indent = \" \".repeat(depth);\n\n // Header\n const symbol = getColoredSymbol(node.state, colors);\n const name = node.name ?? \"parallel\";\n const mode = node.mode === \"allSettled\" ? \" (allSettled)\" : \"\";\n lines.push(`${indent}${BOX.teeRight}${BOX.teeDown}${BOX.horizontal} ${symbol} ${bold(name)}${mode}`);\n\n // Children\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n const isLast = i === node.children.length - 1;\n const prefix = isLast ? `${indent}${BOX.vertical} ${BOX.bottomLeft}` : `${indent}${BOX.vertical} ${BOX.teeRight}`;\n\n if (isStepNode(child)) {\n lines.push(`${prefix} ${renderStepNode(child, options, colors)}`);\n } else {\n // Nested structure - recurse\n const nestedLines = renderNodes([child], options, colors, depth + 1);\n for (const line of nestedLines) {\n lines.push(`${indent}${BOX.vertical} ${line}`);\n }\n }\n }\n\n // Timing footer\n if (options.showTimings && node.durationMs !== undefined) {\n lines.push(`${indent}${BOX.bottomLeft}${BOX.horizontal}${BOX.horizontal} ${dim(`[${formatDuration(node.durationMs)}]`)}`);\n }\n\n return lines;\n}\n\n/**\n * Render a race node (anyAsync).\n */\nfunction renderRaceNode(\n node: RaceNode,\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n depth: number\n): string[] {\n const lines: string[] = [];\n const indent = \" \".repeat(depth);\n\n // Header with lightning bolt for race\n const symbol = getColoredSymbol(node.state, colors);\n const name = node.name ?? \"race\";\n lines.push(`${indent}${BOX.teeRight}⚡ ${symbol} ${bold(name)}`);\n\n // Children\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n const isLast = i === node.children.length - 1;\n const prefix = isLast ? `${indent}${BOX.vertical} ${BOX.bottomLeft}` : `${indent}${BOX.vertical} ${BOX.teeRight}`;\n\n // Mark winner\n const isWinner = node.winnerId && child.id === node.winnerId;\n const winnerSuffix = isWinner ? dim(\" (winner)\") : \"\";\n\n if (isStepNode(child)) {\n lines.push(`${prefix} ${renderStepNode(child, options, colors)}${winnerSuffix}`);\n } else {\n const nestedLines = renderNodes([child], options, colors, depth + 1);\n for (const line of nestedLines) {\n lines.push(`${indent}${BOX.vertical} ${line}`);\n }\n }\n }\n\n // Timing footer\n if (options.showTimings && node.durationMs !== undefined) {\n lines.push(`${indent}${BOX.bottomLeft}${BOX.horizontal}${BOX.horizontal} ${dim(`[${formatDuration(node.durationMs)}]`)}`);\n }\n\n return lines;\n}\n\n/**\n * Render a decision node (conditional branch).\n */\nfunction renderDecisionNode(\n node: DecisionNode,\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n depth: number\n): string[] {\n const lines: string[] = [];\n const indent = \" \".repeat(depth);\n\n // Header with decision info\n const symbol = getColoredSymbol(node.state, colors);\n const name = node.name ?? \"decision\";\n const condition = node.condition \n ? dim(` (${node.condition})`)\n : \"\";\n const decisionValue = node.decisionValue !== undefined\n ? dim(` = ${String(node.decisionValue)}`)\n : \"\";\n const branchTaken = node.branchTaken !== undefined\n ? dim(` → ${String(node.branchTaken)}`)\n : \"\";\n\n lines.push(\n `${indent}${BOX.teeRight}${BOX.teeDown}${BOX.horizontal} ${symbol} ${bold(name)}${condition}${decisionValue}${branchTaken}`\n );\n\n // Render branches\n for (let i = 0; i < node.branches.length; i++) {\n const branch = node.branches[i];\n const isLast = i === node.branches.length - 1;\n const prefix = isLast \n ? `${indent}${BOX.vertical} ${BOX.bottomLeft}` \n : `${indent}${BOX.vertical} ${BOX.teeRight}`;\n\n // Branch label with taken/skipped indicator\n const branchSymbol = branch.taken ? \"✓\" : \"⊘\";\n const branchColor = branch.taken ? colors.success : colors.skipped;\n const branchLabel = colorize(\n `${branchSymbol} ${branch.label}`,\n branchColor\n );\n const branchCondition = branch.condition\n ? dim(` (${branch.condition})`)\n : \"\";\n\n lines.push(`${prefix} ${branchLabel}${branchCondition}`);\n\n // Render children of this branch\n if (branch.children.length > 0) {\n const childLines = renderNodes(branch.children, options, colors, depth + 1);\n for (const line of childLines) {\n lines.push(`${indent}${BOX.vertical} ${line}`);\n }\n } else if (!branch.taken) {\n // Show that this branch was skipped\n lines.push(\n `${indent}${BOX.vertical} ${dim(\"(skipped)\")}`\n );\n }\n }\n\n // Timing footer\n if (options.showTimings && node.durationMs !== undefined) {\n lines.push(\n `${indent}${BOX.bottomLeft}${BOX.horizontal}${BOX.horizontal} ${dim(`[${formatDuration(node.durationMs)}]`)}`\n );\n }\n\n return lines;\n}\n\nexport { defaultColorScheme };\n","/**\n * Mermaid Diagram Renderer\n *\n * Renders the workflow IR as a Mermaid flowchart diagram.\n * Supports sequential flows, parallel (subgraph), and race patterns.\n */\n\nimport type {\n FlowNode,\n ParallelNode,\n RaceNode,\n DecisionNode,\n Renderer,\n RenderOptions,\n StepNode,\n StepState,\n WorkflowIR,\n} from \"../types\";\nimport { isParallelNode, isRaceNode, isStepNode, isDecisionNode } from \"../types\";\nimport { formatDuration } from \"../utils/timing\";\n\n// =============================================================================\n// Mermaid Style Definitions\n// =============================================================================\n\n/**\n * Get Mermaid class definition for step states.\n */\nfunction getStyleDefinitions(): string[] {\n return [\n \" classDef pending fill:#e5e7eb,stroke:#9ca3af,color:#374151\",\n \" classDef running fill:#fef3c7,stroke:#f59e0b,color:#92400e\",\n \" classDef success fill:#d1fae5,stroke:#10b981,color:#065f46\",\n \" classDef error fill:#fee2e2,stroke:#ef4444,color:#991b1b\",\n \" classDef aborted fill:#f3f4f6,stroke:#6b7280,color:#4b5563\",\n \" classDef cached fill:#dbeafe,stroke:#3b82f6,color:#1e40af\",\n // Note: Use a lighter fill color to distinguish skipped steps visually\n // Mermaid classDef only supports: fill, stroke, color, stroke-width (without px unit)\n \" classDef skipped fill:#f9fafb,stroke:#d1d5db,color:#6b7280\",\n ];\n}\n\n/**\n * Get the Mermaid class name for a step state.\n */\nfunction getStateClass(state: StepState): string {\n return state;\n}\n\n// =============================================================================\n// Node ID Generation\n// =============================================================================\n\nlet nodeCounter = 0;\n\nfunction generateNodeId(prefix: string = \"node\"): string {\n return `${prefix}_${++nodeCounter}`;\n}\n\nfunction resetNodeCounter(): void {\n nodeCounter = 0;\n}\n\n// =============================================================================\n// Mermaid Text Escaping\n// =============================================================================\n\n/**\n * Escape text for use in Mermaid diagrams.\n * Removes characters that break Mermaid parsing.\n * \n * Characters removed:\n * - {}[]() - Brackets and parentheses break parsing in labels\n * - <> - Angle brackets can cause issues\n * - \" - Double quotes replaced with single quotes\n * \n * @param text - Text to escape\n * @returns Escaped text safe for Mermaid\n */\nfunction escapeMermaidText(text: string): string {\n return text\n .replace(/[{}[\\]()]/g, \"\") // Remove brackets and parentheses (they break parsing)\n .replace(/[<>]/g, \"\") // Remove angle brackets\n .replace(/\"/g, \"'\") // Replace double quotes with single\n .trim();\n}\n\n/**\n * Escape text for use in Mermaid subgraph names.\n * Subgraph names in brackets need special handling.\n * \n * @param text - Text to escape for subgraph name\n * @returns Escaped text safe for subgraph names\n */\nfunction escapeSubgraphName(text: string): string {\n return escapeMermaidText(text)\n .replace(/[[\\]]/g, \"\"); // Also remove brackets from subgraph names\n}\n\n// =============================================================================\n// Mermaid Renderer\n// =============================================================================\n\n/**\n * Create the Mermaid diagram renderer.\n */\nexport function mermaidRenderer(): Renderer {\n return {\n name: \"mermaid\",\n supportsLive: false,\n\n render(ir: WorkflowIR, options: RenderOptions): string {\n resetNodeCounter();\n const lines: string[] = [];\n\n // Diagram header\n lines.push(\"flowchart TD\");\n\n // Start node\n const startId = \"start\";\n lines.push(` ${startId}((Start))`);\n\n // Track the last node for connections\n let prevNodeId = startId;\n\n // Render children\n for (const child of ir.root.children) {\n const result = renderNode(child, options, lines);\n lines.push(` ${prevNodeId} --> ${result.entryId}`);\n prevNodeId = result.exitId;\n }\n\n // End node (if workflow completed)\n if (ir.root.state === \"success\" || ir.root.state === \"error\") {\n const endId = \"finish\";\n const endShape =\n ir.root.state === \"success\" ? `((Done))` : `((Failed))`;\n const endClass =\n ir.root.state === \"success\" ? \":::success\" : \":::error\";\n lines.push(` ${endId}${endShape}${endClass}`);\n lines.push(` ${prevNodeId} --> ${endId}`);\n }\n\n // Add style definitions\n lines.push(\"\");\n lines.push(...getStyleDefinitions());\n\n return lines.join(\"\\n\");\n },\n };\n}\n\n/**\n * Render result with entry and exit node IDs.\n */\ninterface RenderResult {\n entryId: string;\n exitId: string;\n}\n\n/**\n * Render a node and return its entry/exit IDs.\n */\nfunction renderNode(\n node: FlowNode,\n options: RenderOptions,\n lines: string[]\n): RenderResult {\n if (isStepNode(node)) {\n return renderStepNode(node, options, lines);\n } else if (isParallelNode(node)) {\n return renderParallelNode(node, options, lines);\n } else if (isRaceNode(node)) {\n return renderRaceNode(node, options, lines);\n } else if (isDecisionNode(node)) {\n return renderDecisionNode(node, options, lines);\n }\n\n // Fallback for sequence or unknown nodes\n const id = generateNodeId(\"unknown\");\n lines.push(` ${id}[Unknown Node]`);\n return { entryId: id, exitId: id };\n}\n\n/**\n * Render a step node.\n */\nfunction renderStepNode(\n node: StepNode,\n options: RenderOptions,\n lines: string[]\n): RenderResult {\n const id = node.key\n ? `step_${node.key.replace(/[^a-zA-Z0-9]/g, \"_\")}`\n : generateNodeId(\"step\");\n\n const label = escapeMermaidText(node.name ?? node.key ?? \"Step\");\n \n // Format timing - use space instead of parentheses to avoid Mermaid parse errors\n const timing =\n options.showTimings && node.durationMs !== undefined\n ? ` ${formatDuration(node.durationMs)}`\n : \"\";\n\n // Add input/output info if available\n // Use newlines for multi-line labels, but escape special characters\n let ioInfo = \"\";\n if (node.input !== undefined) {\n const inputStr = typeof node.input === \"string\"\n ? escapeMermaidText(node.input)\n : escapeMermaidText(JSON.stringify(node.input).slice(0, 20));\n ioInfo += `\\\\nin: ${inputStr}`;\n }\n if (node.output !== undefined && node.state === \"success\") {\n const outputStr = typeof node.output === \"string\"\n ? escapeMermaidText(node.output)\n : escapeMermaidText(JSON.stringify(node.output).slice(0, 20));\n ioInfo += `\\\\nout: ${outputStr}`;\n }\n\n // Add retry/timeout indicators\n let retryInfo = \"\";\n if (node.retryCount !== undefined && node.retryCount > 0) {\n retryInfo += `\\\\n↻${node.retryCount}`;\n }\n if (node.timedOut) {\n const timeoutStr = node.timeoutMs !== undefined ? `${node.timeoutMs}ms` : \"\";\n retryInfo += `\\\\n⏱${timeoutStr}`;\n }\n\n // Combine all label parts\n const escapedLabel = (label + ioInfo + retryInfo + timing).trim();\n\n const stateClass = getStateClass(node.state);\n\n // Use different shapes based on state\n let shape: string;\n switch (node.state) {\n case \"error\":\n shape = `{{${escapedLabel}}}`;\n break;\n case \"cached\":\n shape = `[(${escapedLabel})]`;\n break;\n case \"skipped\":\n shape = `[${escapedLabel}]:::skipped`;\n break;\n default:\n shape = `[${escapedLabel}]`;\n }\n\n lines.push(` ${id}${shape}:::${stateClass}`);\n\n return { entryId: id, exitId: id };\n}\n\n/**\n * Render a parallel node as a subgraph with fork/join.\n */\nfunction renderParallelNode(\n node: ParallelNode,\n options: RenderOptions,\n lines: string[]\n): RenderResult {\n const subgraphId = generateNodeId(\"parallel\");\n const forkId = `${subgraphId}_fork`;\n const joinId = `${subgraphId}_join`;\n const name = escapeSubgraphName(node.name ?? \"Parallel\");\n\n // Subgraph for parallel block\n lines.push(` subgraph ${subgraphId}[${name}]`);\n lines.push(` direction TB`);\n\n // Fork node (diamond)\n lines.push(` ${forkId}{Fork}`);\n\n // Child branches\n const childExitIds: string[] = [];\n for (const child of node.children) {\n const result = renderNode(child, options, lines);\n lines.push(` ${forkId} --> ${result.entryId}`);\n childExitIds.push(result.exitId);\n }\n\n // Join node (diamond)\n lines.push(` ${joinId}{Join}`);\n for (const exitId of childExitIds) {\n lines.push(` ${exitId} --> ${joinId}`);\n }\n\n lines.push(` end`);\n\n // Apply state styling to subgraph via a connecting node\n const stateClass = getStateClass(node.state);\n lines.push(` class ${subgraphId} ${stateClass}`);\n\n return { entryId: forkId, exitId: joinId };\n}\n\n/**\n * Render a race node as a subgraph with racing indicator.\n */\nfunction renderRaceNode(\n node: RaceNode,\n options: RenderOptions,\n lines: string[]\n): RenderResult {\n const subgraphId = generateNodeId(\"race\");\n const startId = `${subgraphId}_start`;\n const endId = `${subgraphId}_end`;\n const name = escapeSubgraphName(node.name ?? \"Race\");\n\n // Subgraph for race block - escape name and emoji is safe in quoted strings\n lines.push(` subgraph ${subgraphId}[\"⚡ ${name}\"]`);\n lines.push(` direction TB`);\n\n // Start node\n lines.push(` ${startId}((Race))`);\n\n // Child branches\n const childExitIds: string[] = [];\n for (const child of node.children) {\n const result = renderNode(child, options, lines);\n lines.push(` ${startId} --> ${result.entryId}`);\n childExitIds.push(result.exitId);\n\n // Mark winner\n if (isStepNode(child) && node.winnerId === child.id) {\n lines.push(` ${result.exitId} -. winner .-> ${endId}`);\n }\n }\n\n // End node\n lines.push(` ${endId}((First))`);\n for (const exitId of childExitIds) {\n if (\n !node.winnerId ||\n !node.children.some((c) => isStepNode(c) && c.id === node.winnerId)\n ) {\n lines.push(` ${exitId} --> ${endId}`);\n }\n }\n\n lines.push(` end`);\n\n const stateClass = getStateClass(node.state);\n lines.push(` class ${subgraphId} ${stateClass}`);\n\n return { entryId: startId, exitId: endId };\n}\n\n/**\n * Render a decision node as a diamond with branches.\n */\nfunction renderDecisionNode(\n node: DecisionNode,\n options: RenderOptions,\n lines: string[]\n): RenderResult {\n const decisionId = node.key\n ? `decision_${node.key.replace(/[^a-zA-Z0-9]/g, \"_\")}`\n : generateNodeId(\"decision\");\n\n // Escape condition and decision value - remove characters that break Mermaid\n const condition = escapeMermaidText(node.condition ?? \"condition\");\n const decisionValue = node.decisionValue !== undefined\n ? ` = ${escapeMermaidText(String(node.decisionValue)).slice(0, 30)}`\n : \"\";\n\n // Decision diamond - ensure no invalid characters\n const decisionLabel = `${condition}${decisionValue}`.trim();\n lines.push(` ${decisionId}{${decisionLabel}}`);\n\n // Render branches\n const branchExitIds: string[] = [];\n let takenBranchExitId: string | undefined;\n\n for (const branch of node.branches) {\n const branchId = `${decisionId}_${branch.label.replace(/[^a-zA-Z0-9]/g, \"_\")}`;\n // Escape branch label - remove parentheses and other special chars\n const branchLabelText = escapeMermaidText(branch.label);\n const branchLabel = branch.taken\n ? `${branchLabelText} ✓`\n : `${branchLabelText} skipped`;\n const branchClass = branch.taken ? \":::success\" : \":::skipped\";\n\n // Branch label node\n lines.push(` ${branchId}[${branchLabel}]${branchClass}`);\n\n // Connect decision to branch\n // Mermaid edge labels must be simple text - escape special characters\n // Also remove pipe character as it's used for edge label syntax\n const edgeLabel = branch.condition \n ? `|${escapeMermaidText(branch.condition).replace(/\\|/g, \"\")}|` \n : \"\";\n lines.push(` ${decisionId} -->${edgeLabel} ${branchId}`);\n\n // Render children of this branch\n if (branch.children.length > 0) {\n let prevId = branchId;\n for (const child of branch.children) {\n const result = renderNode(child, options, lines);\n lines.push(` ${prevId} --> ${result.entryId}`);\n prevId = result.exitId;\n }\n branchExitIds.push(prevId);\n if (branch.taken) {\n takenBranchExitId = prevId;\n }\n } else {\n branchExitIds.push(branchId);\n if (branch.taken) {\n takenBranchExitId = branchId;\n }\n }\n }\n\n // Join point (if we have a taken branch)\n if (takenBranchExitId) {\n return { entryId: decisionId, exitId: takenBranchExitId };\n }\n\n // If no branch was taken, return decision as exit\n return { entryId: decisionId, exitId: decisionId };\n}\n\nexport { mermaidRenderer as default };\n","/**\n * Live Visualizer - Real-time terminal updates during workflow execution.\n *\n * Uses ANSI escape codes to update the terminal in-place, showing\n * workflow progress as it happens.\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type {\n LiveVisualizerOptions,\n RenderOptions,\n ScopeEndEvent,\n ScopeStartEvent,\n DecisionStartEvent,\n DecisionBranchEvent,\n DecisionEndEvent,\n WorkflowIR,\n} from \"./types\";\nimport { createIRBuilder } from \"./ir-builder\";\nimport { asciiRenderer, defaultColorScheme } from \"./renderers\";\n\n// =============================================================================\n// ANSI Escape Codes\n// =============================================================================\n\nconst ANSI = {\n /** Clear from cursor to end of screen */\n clearToEnd: \"\\x1b[J\",\n /** Move cursor up N lines */\n cursorUp: (n: number) => `\\x1b[${n}A`,\n /** Move cursor to beginning of line */\n cursorToStart: \"\\x1b[G\",\n /** Hide cursor */\n hideCursor: \"\\x1b[?25l\",\n /** Show cursor */\n showCursor: \"\\x1b[?25h\",\n /** Save cursor position */\n saveCursor: \"\\x1b[s\",\n /** Restore cursor position */\n restoreCursor: \"\\x1b[u\",\n};\n\n// =============================================================================\n// Live Visualizer Interface\n// =============================================================================\n\n/**\n * Live visualizer with real-time terminal updates.\n */\nexport interface LiveVisualizer {\n /** Process a workflow event */\n handleEvent: (event: WorkflowEvent<unknown>) => void;\n /** Process a scope event */\n handleScopeEvent: (event: ScopeStartEvent | ScopeEndEvent) => void;\n /** Process a decision event */\n handleDecisionEvent: (event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent) => void;\n /** Get current IR state */\n getIR: () => WorkflowIR;\n /** Render current state to string (without terminal output) */\n render: () => string;\n /** Start live rendering to terminal */\n start: () => void;\n /** Stop live rendering */\n stop: () => void;\n /** Force an immediate redraw */\n refresh: () => void;\n /** Reset state for a new workflow */\n reset: () => void;\n}\n\n// =============================================================================\n// Create Live Visualizer\n// =============================================================================\n\n/**\n * Create a live visualizer for real-time terminal updates.\n *\n * @example\n * ```typescript\n * const live = createLiveVisualizer({ workflowName: 'my-workflow' });\n * const workflow = createWorkflow(deps, { onEvent: live.handleEvent });\n *\n * live.start();\n * await workflow(async (step) => { ... });\n * live.stop();\n * ```\n */\nexport function createLiveVisualizer(\n options: LiveVisualizerOptions = {}\n): LiveVisualizer {\n const {\n workflowName,\n detectParallel = true,\n showTimings = true,\n showKeys = false,\n colors: customColors,\n stream = process.stdout,\n updateInterval = 100,\n } = options;\n\n const builder = createIRBuilder({ detectParallel });\n const renderer = asciiRenderer();\n\n // Render options\n const renderOptions: RenderOptions = {\n showTimings,\n showKeys,\n terminalWidth: stream.columns ?? 80,\n colors: { ...defaultColorScheme, ...customColors },\n };\n\n // State\n let isRunning = false;\n let lastOutput = \"\";\n let lastLineCount = 0;\n let throttleTimeout: ReturnType<typeof setTimeout> | null = null;\n let pendingUpdate = false;\n\n /**\n * Write to the output stream.\n */\n function write(text: string): void {\n if (stream.writable) {\n stream.write(text);\n }\n }\n\n /**\n * Clear the previous output and write new content.\n */\n function redraw(): void {\n if (!isRunning) return;\n\n const ir = getIR();\n const output = renderer.render(ir, renderOptions);\n\n // If output hasn't changed, skip redraw\n if (output === lastOutput) return;\n\n // Clear previous output\n if (lastLineCount > 0) {\n // Move cursor up and clear\n write(ANSI.cursorUp(lastLineCount));\n write(ANSI.cursorToStart);\n write(ANSI.clearToEnd);\n }\n\n // Write new output\n write(output);\n write(\"\\n\");\n\n // Track line count for next clear\n lastOutput = output;\n lastLineCount = output.split(\"\\n\").length;\n }\n\n /**\n * Schedule a throttled redraw.\n */\n function scheduleRedraw(): void {\n if (!isRunning) return;\n\n pendingUpdate = true;\n\n if (throttleTimeout === null) {\n throttleTimeout = setTimeout(() => {\n throttleTimeout = null;\n if (pendingUpdate) {\n pendingUpdate = false;\n redraw();\n }\n }, updateInterval);\n }\n }\n\n /**\n * Handle a workflow event.\n */\n function handleEvent(event: WorkflowEvent<unknown>): void {\n // Route scope events to handleScopeEvent for proper IR building\n if (event.type === \"scope_start\" || event.type === \"scope_end\") {\n handleScopeEvent(event as ScopeStartEvent | ScopeEndEvent);\n return;\n }\n\n builder.handleEvent(event);\n\n if (isRunning) {\n // Immediate redraw for start/end events, throttled for others\n if (\n event.type === \"workflow_start\" ||\n event.type === \"workflow_success\" ||\n event.type === \"workflow_error\"\n ) {\n redraw();\n } else {\n scheduleRedraw();\n }\n }\n }\n\n /**\n * Handle a scope event.\n */\n function handleScopeEvent(event: ScopeStartEvent | ScopeEndEvent): void {\n builder.handleScopeEvent(event);\n if (isRunning) {\n scheduleRedraw();\n }\n }\n\n /**\n * Handle a decision event.\n */\n function handleDecisionEvent(\n event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent\n ): void {\n builder.handleDecisionEvent(event);\n if (isRunning) {\n scheduleRedraw();\n }\n }\n\n /**\n * Get the current IR state.\n */\n function getIR(): WorkflowIR {\n const ir = builder.getIR();\n if (workflowName && !ir.root.name) {\n ir.root.name = workflowName;\n }\n return ir;\n }\n\n /**\n * Render current state to string.\n */\n function render(): string {\n return renderer.render(getIR(), renderOptions);\n }\n\n /**\n * Start live rendering.\n */\n function start(): void {\n if (isRunning) return;\n\n isRunning = true;\n lastOutput = \"\";\n lastLineCount = 0;\n\n // Hide cursor during updates\n write(ANSI.hideCursor);\n\n // Initial render\n redraw();\n }\n\n /**\n * Stop live rendering.\n */\n function stop(): void {\n if (!isRunning) return;\n\n isRunning = false;\n\n // Clear any pending throttle\n if (throttleTimeout !== null) {\n clearTimeout(throttleTimeout);\n throttleTimeout = null;\n }\n\n // Final redraw to show completed state\n const ir = getIR();\n const output = renderer.render(ir, renderOptions);\n\n if (lastLineCount > 0) {\n write(ANSI.cursorUp(lastLineCount));\n write(ANSI.cursorToStart);\n write(ANSI.clearToEnd);\n }\n\n write(output);\n write(\"\\n\");\n\n // Show cursor again\n write(ANSI.showCursor);\n }\n\n /**\n * Force an immediate redraw.\n */\n function refresh(): void {\n if (throttleTimeout !== null) {\n clearTimeout(throttleTimeout);\n throttleTimeout = null;\n }\n pendingUpdate = false;\n redraw();\n }\n\n /**\n * Reset state for a new workflow.\n */\n function reset(): void {\n builder.reset();\n lastOutput = \"\";\n lastLineCount = 0;\n }\n\n return {\n handleEvent,\n handleScopeEvent,\n handleDecisionEvent,\n getIR,\n render,\n start,\n stop,\n refresh,\n reset,\n };\n}\n","/**\n * Decision Tracker - Helper for tracking conditional logic in workflows.\n *\n * This module provides utilities to track decision points (if/switch statements)\n * so they can be visualized in workflow diagrams.\n *\n * @example\n * ```typescript\n * import { trackDecision } from '@jagreehal/workflow/visualize';\n *\n * const workflow = createWorkflow(deps, {\n * onEvent: (event) => {\n * // Pass events to visualizer\n * viz.handleEvent(event);\n * }\n * });\n *\n * await workflow(async (step) => {\n * const user = await step(fetchUser(id));\n *\n * // Track a decision point\n * const decision = trackDecision('user-role-check', {\n * condition: 'user.role === \"admin\"',\n * value: user.role\n * });\n *\n * if (user.role === 'admin') {\n * decision.takeBranch('admin', true);\n * await step(processAdminAction(user));\n * } else {\n * decision.takeBranch('user', false);\n * await step(processUserAction(user));\n * }\n *\n * decision.end();\n * });\n * ```\n */\n\nimport type {\n DecisionStartEvent,\n DecisionBranchEvent,\n DecisionEndEvent,\n} from \"./types\";\n\n// =============================================================================\n// Decision Tracker\n// =============================================================================\n\n/**\n * Options for creating a decision tracker.\n */\nexport interface DecisionTrackerOptions {\n /** Condition being evaluated (e.g., \"user.role === 'admin'\") */\n condition?: string;\n /** Value being evaluated */\n value?: unknown;\n /** Name/label for this decision point */\n name?: string;\n /** Workflow ID (auto-generated if not provided) */\n workflowId?: string;\n /** Event emitter function */\n emit?: (event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent) => void;\n}\n\n/**\n * Track a decision point in your workflow.\n *\n * Use this to annotate conditional logic (if/switch) so it appears\n * in workflow visualizations.\n *\n * @param decisionId - Unique identifier for this decision\n * @param options - Decision tracking options\n * @returns A tracker object with methods to track branches\n *\n * @example\n * ```typescript\n * const decision = trackDecision('check-role', {\n * condition: 'user.role === \"admin\"',\n * value: user.role,\n * emit: (event) => viz.handleDecisionEvent(event)\n * });\n *\n * if (user.role === 'admin') {\n * decision.takeBranch('admin', true);\n * // ... admin logic\n * } else {\n * decision.takeBranch('user', false);\n * // ... user logic\n * }\n *\n * decision.end();\n * ```\n */\nexport function trackDecision(\n decisionId: string,\n options: DecisionTrackerOptions = {}\n): DecisionTracker {\n const {\n condition,\n value,\n name,\n workflowId = crypto.randomUUID(),\n emit,\n } = options;\n\n const startTs = Date.now();\n let branchTaken: string | boolean | undefined;\n const branches: Array<{ label: string; condition?: string; taken: boolean }> = [];\n\n function takeBranch(\n label: string,\n taken: boolean,\n branchCondition?: string\n ): void {\n branches.push({ label, condition: branchCondition, taken });\n if (taken) {\n branchTaken = label;\n }\n\n emit?.({\n type: \"decision_branch\",\n workflowId,\n decisionId,\n branchLabel: label,\n condition: branchCondition,\n taken,\n ts: Date.now(),\n });\n }\n\n function end(): void {\n const durationMs = Date.now() - startTs;\n emit?.({\n type: \"decision_end\",\n workflowId,\n decisionId,\n branchTaken,\n ts: Date.now(),\n durationMs,\n });\n }\n\n // Emit start event immediately\n emit?.({\n type: \"decision_start\",\n workflowId,\n decisionId,\n condition,\n decisionValue: value,\n name,\n ts: startTs,\n });\n\n return {\n takeBranch,\n end,\n getBranchTaken: () => branchTaken,\n getBranches: () => [...branches],\n };\n}\n\n/**\n * Decision tracker instance.\n */\nexport interface DecisionTracker {\n /**\n * Mark that a branch was taken or skipped.\n * @param label - Label for this branch (e.g., \"if\", \"else\", \"case 'admin'\")\n * @param taken - Whether this branch was executed\n * @param branchCondition - Optional condition for this specific branch\n */\n takeBranch(label: string, taken: boolean, branchCondition?: string): void;\n\n /**\n * End the decision tracking.\n * Call this after all branches have been evaluated.\n */\n end(): void;\n\n /**\n * Get which branch was taken.\n */\n getBranchTaken(): string | boolean | undefined;\n\n /**\n * Get all branches (taken and skipped).\n */\n getBranches(): Array<{ label: string; condition?: string; taken: boolean }>;\n}\n\n// =============================================================================\n// Convenience Helpers\n// =============================================================================\n\n/**\n * Track a simple if/else decision.\n *\n * @example\n * ```typescript\n * const decision = trackIf('check-admin', user.role === 'admin', {\n * condition: 'user.role === \"admin\"',\n * value: user.role,\n * emit: (e) => viz.handleDecisionEvent(e)\n * });\n *\n * if (decision.condition) {\n * decision.then();\n * // admin logic\n * } else {\n * decision.else();\n * // user logic\n * }\n *\n * decision.end();\n * ```\n */\nexport function trackIf(\n decisionId: string,\n condition: boolean,\n options: Omit<DecisionTrackerOptions, \"value\"> & { value?: unknown } = {}\n): IfTracker {\n const tracker = trackDecision(decisionId, {\n ...options,\n condition: options.condition ?? String(condition),\n value: options.value ?? condition,\n });\n\n return {\n ...tracker,\n condition,\n then: () => {\n tracker.takeBranch(\"if\", true);\n },\n else: () => {\n // Mark else branch as taken (true) when the else block executes\n tracker.takeBranch(\"else\", true);\n },\n };\n}\n\n/**\n * If tracker with convenience methods.\n */\nexport interface IfTracker extends DecisionTracker {\n /** The condition value */\n condition: boolean;\n /** Mark the \"if\" branch as taken */\n then(): void;\n /** Mark the \"else\" branch as taken */\n else(): void;\n}\n\n/**\n * Track a switch statement decision.\n *\n * @example\n * ```typescript\n * const decision = trackSwitch('process-type', user.type, {\n * emit: (e) => viz.handleDecisionEvent(e)\n * });\n *\n * switch (user.type) {\n * case 'admin':\n * decision.case('admin', true);\n * // admin logic\n * break;\n * case 'user':\n * decision.case('user', true);\n * // user logic\n * break;\n * default:\n * decision.default(true);\n * // default logic\n * }\n *\n * decision.end();\n * ```\n */\nexport function trackSwitch(\n decisionId: string,\n value: unknown,\n options: Omit<DecisionTrackerOptions, \"value\"> = {}\n): SwitchTracker {\n const tracker = trackDecision(decisionId, {\n ...options,\n condition: options.condition ?? `switch(${String(value)})`,\n value,\n });\n\n return {\n ...tracker,\n value,\n case: (caseValue: string | number, taken: boolean) => {\n tracker.takeBranch(`case '${caseValue}'`, taken, `value === '${caseValue}'`);\n },\n default: (taken: boolean) => {\n tracker.takeBranch(\"default\", taken);\n },\n };\n}\n\n/**\n * Switch tracker with convenience methods.\n */\nexport interface SwitchTracker extends DecisionTracker {\n /** The value being switched on */\n value: unknown;\n /** Mark a case branch */\n case(caseValue: string | number, taken: boolean): void;\n /** Mark the default branch */\n default(taken: boolean): void;\n}\n","/**\n * Workflow Visualization Module\n *\n * Provides tools for visualizing workflow execution with color-coded\n * step states and support for parallel/race operations.\n *\n * @example\n * ```typescript\n * import { createVisualizer } from '@jagreehal/workflow/visualize';\n *\n * const viz = createVisualizer({ workflowName: 'checkout' });\n * const workflow = createWorkflow(deps, { onEvent: viz.handleEvent });\n *\n * await workflow(async (step) => {\n * await step(() => validateCart(cart), 'Validate cart');\n * await step(() => processPayment(payment), 'Process payment');\n * });\n *\n * console.log(viz.render());\n * ```\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type {\n OutputFormat,\n RenderOptions,\n ScopeEndEvent,\n ScopeStartEvent,\n DecisionStartEvent,\n DecisionBranchEvent,\n DecisionEndEvent,\n VisualizerOptions,\n WorkflowIR,\n} from \"./types\";\nimport { createIRBuilder } from \"./ir-builder\";\nimport { asciiRenderer, mermaidRenderer, defaultColorScheme } from \"./renderers\";\n\n// =============================================================================\n// Re-exports\n// =============================================================================\n\nexport * from \"./types\";\nexport { createIRBuilder, type IRBuilderOptions } from \"./ir-builder\";\nexport { asciiRenderer, mermaidRenderer, defaultColorScheme } from \"./renderers\";\nexport { detectParallelGroups, createParallelDetector, type ParallelDetectorOptions } from \"./parallel-detector\";\nexport { createLiveVisualizer, type LiveVisualizer } from \"./live-visualizer\";\nexport { trackDecision, trackIf, trackSwitch, type DecisionTracker, type IfTracker, type SwitchTracker } from \"./decision-tracker\";\n\n// =============================================================================\n// Visualizer Interface\n// =============================================================================\n\n/**\n * Workflow visualizer that processes events and renders output.\n */\nexport interface WorkflowVisualizer {\n /** Process a workflow event */\n handleEvent: (event: WorkflowEvent<unknown>) => void;\n\n /** Process a scope event (parallel/race) */\n handleScopeEvent: (event: ScopeStartEvent | ScopeEndEvent) => void;\n\n /** Process a decision event (conditional branches) */\n handleDecisionEvent: (event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent) => void;\n\n /** Get current IR state */\n getIR: () => WorkflowIR;\n\n /** Render current state using the default renderer */\n render: () => string;\n\n /** Render to a specific format */\n renderAs: (format: OutputFormat) => string;\n\n /** Reset state for a new workflow */\n reset: () => void;\n\n /** Subscribe to IR updates (for live visualization) */\n onUpdate: (callback: (ir: WorkflowIR) => void) => () => void;\n}\n\n// =============================================================================\n// Create Visualizer\n// =============================================================================\n\n/**\n * Create a workflow visualizer.\n *\n * @example\n * ```typescript\n * const viz = createVisualizer({ workflowName: 'my-workflow' });\n *\n * const workflow = createWorkflow(deps, {\n * onEvent: viz.handleEvent,\n * });\n *\n * await workflow(async (step) => { ... });\n *\n * console.log(viz.render());\n * ```\n */\nexport function createVisualizer(\n options: VisualizerOptions = {}\n): WorkflowVisualizer {\n const {\n workflowName,\n detectParallel = true,\n showTimings = true,\n showKeys = false,\n colors: customColors,\n } = options;\n\n const builder = createIRBuilder({ detectParallel });\n const updateCallbacks: Set<(ir: WorkflowIR) => void> = new Set();\n\n // Renderers\n const ascii = asciiRenderer();\n const mermaid = mermaidRenderer();\n\n // Build render options\n const renderOptions: RenderOptions = {\n showTimings,\n showKeys,\n terminalWidth: process.stdout?.columns ?? 80,\n colors: { ...defaultColorScheme, ...customColors },\n };\n\n function notifyUpdate(): void {\n if (updateCallbacks.size > 0) {\n const ir = builder.getIR();\n for (const callback of updateCallbacks) {\n callback(ir);\n }\n }\n }\n\n function handleEvent(event: WorkflowEvent<unknown>): void {\n // Route scope events to handleScopeEvent for proper IR building\n if (event.type === \"scope_start\" || event.type === \"scope_end\") {\n handleScopeEvent(event as ScopeStartEvent | ScopeEndEvent);\n return;\n }\n\n builder.handleEvent(event);\n\n // Set workflow name if provided\n if (event.type === \"workflow_start\" && workflowName) {\n // Note: We'd need to extend the builder to support setting name\n // For now, the name is passed in render options\n }\n\n notifyUpdate();\n }\n\n function handleScopeEvent(event: ScopeStartEvent | ScopeEndEvent): void {\n builder.handleScopeEvent(event);\n notifyUpdate();\n }\n\n function handleDecisionEvent(\n event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent\n ): void {\n builder.handleDecisionEvent(event);\n notifyUpdate();\n }\n\n function getIR(): WorkflowIR {\n const ir = builder.getIR();\n // Apply workflow name if provided\n if (workflowName && !ir.root.name) {\n ir.root.name = workflowName;\n }\n return ir;\n }\n\n function render(): string {\n const ir = getIR();\n return ascii.render(ir, renderOptions);\n }\n\n function renderAs(format: OutputFormat): string {\n const ir = getIR();\n\n switch (format) {\n case \"ascii\":\n return ascii.render(ir, renderOptions);\n\n case \"mermaid\":\n return mermaid.render(ir, renderOptions);\n\n case \"json\":\n return JSON.stringify(ir, null, 2);\n\n default:\n throw new Error(`Unknown format: ${format}`);\n }\n }\n\n function reset(): void {\n builder.reset();\n notifyUpdate();\n }\n\n function onUpdate(callback: (ir: WorkflowIR) => void): () => void {\n updateCallbacks.add(callback);\n return () => updateCallbacks.delete(callback);\n }\n\n return {\n handleEvent,\n handleScopeEvent,\n handleDecisionEvent,\n getIR,\n render,\n renderAs,\n reset,\n onUpdate,\n };\n}\n\n// =============================================================================\n// Convenience Functions\n// =============================================================================\n\n/**\n * Union type for all collectable/visualizable events (workflow + decision).\n */\nexport type CollectableEvent =\n | WorkflowEvent<unknown>\n | DecisionStartEvent\n | DecisionBranchEvent\n | DecisionEndEvent;\n\n/**\n * Visualize collected events (post-execution).\n *\n * Supports both workflow events (from onEvent) and decision events\n * (from trackDecision/trackIf/trackSwitch).\n *\n * @example\n * ```typescript\n * const events: CollectableEvent[] = [];\n * const workflow = createWorkflow(deps, {\n * onEvent: (e) => events.push(e),\n * });\n *\n * await workflow(async (step) => {\n * const decision = trackIf('check', condition, {\n * emit: (e) => events.push(e),\n * });\n * // ...\n * });\n *\n * console.log(visualizeEvents(events));\n * ```\n */\nexport function visualizeEvents(\n events: CollectableEvent[],\n options: VisualizerOptions = {}\n): string {\n const viz = createVisualizer(options);\n\n for (const event of events) {\n if (event.type.startsWith(\"decision_\")) {\n viz.handleDecisionEvent(event as DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent);\n } else {\n viz.handleEvent(event as WorkflowEvent<unknown>);\n }\n }\n\n return viz.render();\n}\n\n/**\n * Create an event collector for later visualization.\n *\n * Supports both workflow events (from onEvent) and decision events\n * (from trackDecision/trackIf/trackSwitch).\n *\n * @example\n * ```typescript\n * const collector = createEventCollector();\n *\n * const workflow = createWorkflow(deps, {\n * onEvent: collector.handleEvent,\n * });\n *\n * await workflow(async (step) => {\n * // Decision events can also be collected\n * const decision = trackIf('check', condition, {\n * emit: collector.handleDecisionEvent,\n * });\n * // ...\n * });\n *\n * console.log(collector.visualize());\n * ```\n */\nexport function createEventCollector(options: VisualizerOptions = {}) {\n const events: CollectableEvent[] = [];\n\n return {\n /** Handle a workflow event */\n handleEvent: (event: WorkflowEvent<unknown>) => {\n events.push(event);\n },\n\n /** Handle a decision event */\n handleDecisionEvent: (event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent) => {\n events.push(event);\n },\n\n /** Get all collected events */\n getEvents: () => [...events],\n\n /** Get workflow events only */\n getWorkflowEvents: () => events.filter((e): e is WorkflowEvent<unknown> =>\n !e.type.startsWith(\"decision_\")\n ),\n\n /** Get decision events only */\n getDecisionEvents: () => events.filter((e): e is DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent =>\n e.type.startsWith(\"decision_\")\n ),\n\n /** Clear collected events */\n clear: () => {\n events.length = 0;\n },\n\n /** Visualize collected events */\n visualize: () => {\n const viz = createVisualizer(options);\n for (const event of events) {\n if (event.type.startsWith(\"decision_\")) {\n viz.handleDecisionEvent(event as DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent);\n } else {\n viz.handleEvent(event as WorkflowEvent<unknown>);\n }\n }\n return viz.render();\n },\n\n /** Visualize in a specific format */\n visualizeAs: (format: OutputFormat) => {\n const viz = createVisualizer(options);\n for (const event of events) {\n if (event.type.startsWith(\"decision_\")) {\n viz.handleDecisionEvent(event as DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent);\n } else {\n viz.handleEvent(event as WorkflowEvent<unknown>);\n }\n }\n return viz.renderAs(format);\n },\n };\n}\n\n"],"mappings":"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","names":["formatDuration","ms","minutes","seconds","generateId","hasRealScopeNodes","nodes","node","detectParallelGroups","options","maxGapMs","stepsWithTiming","nonStepNodes","i","b","groups","currentGroup","step","groupEnd","s","groupedNodes","group","position","children","startTs","endTs","parallelNode","deriveGroupState","originalIndex","g","c","createParallelDetector","createIRBuilder","options","detectParallel","parallelDetection","workflowId","workflowStartTs","workflowState","workflowError","workflowDurationMs","activeSteps","scopeStack","decisionStack","currentNodes","createdAt","lastUpdatedAt","getStepId","event","generateId","addNode","node","decision","branch","firstBranch","handleEvent","id","active","handleScopeEvent","scope","deriveState","handleDecisionEvent","branchKey","existing","branches","b","children","c","getCurrentNodes","nodes","getIR","detectParallelGroups","reset","isStepNode","node","isSequenceNode","isParallelNode","isRaceNode","isDecisionNode","hasChildren","RESET","BOLD","DIM","FG_RED","FG_GREEN","FG_YELLOW","FG_BLUE","FG_GRAY","FG_WHITE","colorize","text","color","bold","dim","defaultColorScheme","getStateSymbol","state","getColoredSymbol","colors","symbol","colorByState","stripAnsi","str","BOX","padEnd","str","width","visibleLen","stripAnsi","padding","horizontalLine","title","titleText","remainingWidth","leftPad","rightPad","asciiRenderer","ir","options","colors","defaultColorScheme","innerWidth","lines","workflowName","headerTitle","bold","childLines","renderNodes","line","status","footer","colorByState","formatDuration","nodes","depth","node","isStepNode","renderStepNode","isParallelNode","renderParallelNode","isRaceNode","renderRaceNode","isDecisionNode","renderDecisionNode","symbol","getColoredSymbol","name","nameColored","dim","inputStr","outputStr","timeoutInfo","indent","mode","i","child","prefix","nestedLines","winnerSuffix","condition","decisionValue","branchTaken","branch","branchSymbol","branchColor","branchLabel","colorize","branchCondition","getStyleDefinitions","nodeCounter","generateNodeId","prefix","resetNodeCounter","escapeMermaidText","text","escapeSubgraphName","mermaidRenderer","ir","options","lines","startId","prevNodeId","child","result","renderNode","endId","endShape","endClass","getStyleDefinitions","node","isStepNode","renderStepNode","isParallelNode","renderParallelNode","isRaceNode","renderRaceNode","isDecisionNode","renderDecisionNode","id","label","timing","formatDuration","ioInfo","inputStr","outputStr","retryInfo","timeoutStr","escapedLabel","stateClass","shape","subgraphId","forkId","joinId","name","childExitIds","exitId","c","decisionId","condition","decisionValue","decisionLabel","branchExitIds","takenBranchExitId","branch","branchId","branchLabelText","branchLabel","branchClass","edgeLabel","prevId","ANSI","n","createLiveVisualizer","options","workflowName","detectParallel","showTimings","showKeys","customColors","stream","updateInterval","builder","createIRBuilder","renderer","asciiRenderer","renderOptions","defaultColorScheme","isRunning","lastOutput","lastLineCount","throttleTimeout","pendingUpdate","write","text","redraw","ir","getIR","output","scheduleRedraw","handleEvent","event","handleScopeEvent","handleDecisionEvent","render","start","stop","refresh","reset","trackDecision","decisionId","options","condition","value","name","workflowId","emit","startTs","branchTaken","branches","takeBranch","label","taken","branchCondition","end","durationMs","trackIf","tracker","trackSwitch","caseValue","createVisualizer","options","workflowName","detectParallel","showTimings","showKeys","customColors","builder","createIRBuilder","updateCallbacks","ascii","asciiRenderer","mermaid","mermaidRenderer","renderOptions","defaultColorScheme","notifyUpdate","ir","callback","handleEvent","event","handleScopeEvent","handleDecisionEvent","getIR","render","renderAs","format","reset","onUpdate","visualizeEvents","events","viz","createEventCollector","e"]}
|
|
1
|
+
{"version":3,"sources":["../src/visualize/utils/timing.ts","../src/visualize/parallel-detector.ts","../src/visualize/ir-builder.ts","../src/visualize/types.ts","../src/visualize/renderers/colors.ts","../src/visualize/renderers/ascii.ts","../src/visualize/renderers/mermaid.ts","../src/visualize/live-visualizer.ts","../src/visualize/decision-tracker.ts","../src/visualize/index.ts"],"sourcesContent":["/**\n * Timing utilities for workflow visualization.\n */\n\n/**\n * Format duration in milliseconds to a human-readable string.\n *\n * @example\n * formatDuration(23) // \"23ms\"\n * formatDuration(1500) // \"1.5s\"\n * formatDuration(65000) // \"1m 5s\"\n */\nexport function formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${Math.round(ms)}ms`;\n }\n\n if (ms < 60000) {\n const seconds = ms / 1000;\n // Show one decimal for seconds\n return `${seconds.toFixed(1).replace(/\\.0$/, \"\")}s`;\n }\n\n const minutes = Math.floor(ms / 60000);\n const seconds = Math.round((ms % 60000) / 1000);\n\n if (seconds === 0) {\n return `${minutes}m`;\n }\n\n return `${minutes}m ${seconds}s`;\n}\n\n/**\n * Generate a unique ID for nodes.\n */\nexport function generateId(): string {\n return `node_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n}\n","/**\n * Parallel Detection - Heuristic detection of parallel execution from timing.\n *\n * When steps overlap in time (one starts before another ends), they are\n * likely running in parallel. This module detects such patterns and\n * groups overlapping steps into ParallelNode structures.\n */\n\nimport type { FlowNode, ParallelNode, StepNode } from \"./types\";\n\n/**\n * Options for parallel detection.\n */\nexport interface ParallelDetectorOptions {\n /**\n * Minimum overlap in milliseconds to consider steps parallel.\n * Default: 0 (any overlap counts)\n */\n minOverlapMs?: number;\n\n /**\n * Maximum gap in milliseconds to still consider steps as part of same parallel group.\n * Default: 5 (steps starting within 5ms are grouped)\n */\n maxGapMs?: number;\n}\n\n/**\n * Step timing information for overlap detection.\n */\ninterface StepTiming {\n node: StepNode;\n startTs: number;\n endTs: number;\n}\n\n/**\n * Check if nodes contain real scope nodes (from scope_start/scope_end events).\n * When real scope nodes exist, heuristic detection should be skipped to avoid\n * duplicating or conflicting with the explicit structure.\n */\nfunction hasRealScopeNodes(nodes: FlowNode[]): boolean {\n for (const node of nodes) {\n // Real scope nodes are parallel/race/sequence that came from scope events\n // (not from heuristic detection, which uses ids starting with \"detected_\")\n if (\n (node.type === \"parallel\" || node.type === \"race\" || node.type === \"sequence\") &&\n !node.id.startsWith(\"detected_\")\n ) {\n return true;\n }\n // Also check for decision nodes if present\n if (\"decisionId\" in node) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Group overlapping steps into parallel nodes.\n *\n * Algorithm:\n * 1. Sort steps by start time\n * 2. For each step, check if it overlaps with existing parallel groups\n * 3. If it overlaps, add to group; otherwise start new sequence\n * 4. Merge overlapping groups when step bridges them\n *\n * Note: If real scope nodes (from scope_start/scope_end) are present,\n * heuristic detection is skipped to avoid conflicts.\n */\nexport function detectParallelGroups(\n nodes: FlowNode[],\n options: ParallelDetectorOptions = {}\n): FlowNode[] {\n // If real scope nodes exist, skip heuristic detection\n // The explicit scope events provide accurate structure\n if (hasRealScopeNodes(nodes)) {\n return nodes;\n }\n\n const { minOverlapMs = 0, maxGapMs = 5 } = options;\n\n // Extract step nodes with timing info, preserving indices for position restoration\n const stepsWithTiming: (StepTiming & { originalIndex: number })[] = [];\n const nonStepNodes: { node: FlowNode; originalIndex: number }[] = [];\n\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i];\n if (node.type === \"step\" && node.startTs !== undefined) {\n stepsWithTiming.push({\n node,\n startTs: node.startTs,\n endTs: node.endTs ?? node.startTs + (node.durationMs ?? 0),\n originalIndex: i,\n });\n } else {\n // Keep non-step nodes with their original position\n nonStepNodes.push({ node, originalIndex: i });\n }\n }\n\n if (stepsWithTiming.length <= 1) {\n return nodes; // Nothing to group\n }\n\n // Sort by start time\n stepsWithTiming.sort((a, b) => a.startTs - b.startTs);\n\n // Group overlapping steps\n type StepTimingWithIndex = StepTiming & { originalIndex: number };\n const groups: StepTimingWithIndex[][] = [];\n let currentGroup: StepTimingWithIndex[] = [stepsWithTiming[0]];\n\n for (let i = 1; i < stepsWithTiming.length; i++) {\n const step = stepsWithTiming[i];\n const groupStart = Math.min(...currentGroup.map((s) => s.startTs));\n const groupEnd = Math.max(...currentGroup.map((s) => s.endTs));\n\n // Two ways steps can be parallel:\n // 1. They started together (within maxGapMs) - handles timing jitter\n // 2. They genuinely overlap (step starts before group ends)\n const startedTogether = step.startTs <= groupStart + maxGapMs;\n const hasTrueOverlap = step.startTs < groupEnd;\n\n if (!startedTogether && !hasTrueOverlap) {\n // Sequential: step started after group ended AND not with the group\n groups.push(currentGroup);\n currentGroup = [step];\n continue;\n }\n\n // Check minOverlapMs threshold for overlap duration\n // For steps that started together, overlap is measured from step start to group end\n // For steps with true overlap, it's from step start to min(step end, group end)\n const overlapDuration = hasTrueOverlap\n ? Math.min(step.endTs, groupEnd) - step.startTs\n : 0;\n\n // Started together bypasses minOverlapMs (they're parallel by definition)\n // True overlap must meet the minOverlapMs threshold\n if (startedTogether || overlapDuration >= minOverlapMs) {\n currentGroup.push(step);\n } else {\n // Overlap too small - treat as sequential\n groups.push(currentGroup);\n currentGroup = [step];\n }\n }\n groups.push(currentGroup);\n\n // Convert groups to nodes with position tracking\n const groupedNodes: { node: FlowNode; position: number }[] = [];\n\n for (const group of groups) {\n // Use the minimum original index as the position for the group\n const position = Math.min(...group.map((s) => s.originalIndex));\n\n if (group.length === 1) {\n // Single step - no parallel grouping needed\n groupedNodes.push({ node: group[0].node, position });\n } else {\n // Multiple overlapping steps - create parallel node\n const children = group.map((s) => s.node);\n const startTs = Math.min(...group.map((s) => s.startTs));\n const endTs = Math.max(...group.map((s) => s.endTs));\n\n const parallelNode: ParallelNode = {\n type: \"parallel\",\n id: `detected_parallel_${startTs}`,\n name: `${children.length} parallel steps`,\n state: deriveGroupState(children),\n mode: \"all\",\n children,\n startTs,\n endTs,\n durationMs: endTs - startTs,\n };\n\n groupedNodes.push({ node: parallelNode, position });\n }\n }\n\n // Add non-step nodes with their original positions\n for (const { node, originalIndex } of nonStepNodes) {\n groupedNodes.push({ node, position: originalIndex });\n }\n\n // Sort by original position to preserve ordering\n groupedNodes.sort((a, b) => a.position - b.position);\n\n return groupedNodes.map((g) => g.node);\n}\n\n/**\n * Derive the state of a group from its children.\n */\nfunction deriveGroupState(\n children: FlowNode[]\n): \"pending\" | \"running\" | \"success\" | \"error\" | \"aborted\" | \"cached\" {\n const hasError = children.some((c) => c.state === \"error\");\n if (hasError) return \"error\";\n\n const hasRunning = children.some((c) => c.state === \"running\");\n if (hasRunning) return \"running\";\n\n const hasPending = children.some((c) => c.state === \"pending\");\n if (hasPending) return \"pending\";\n\n const allSuccess = children.every(\n (c) => c.state === \"success\" || c.state === \"cached\"\n );\n if (allSuccess) return \"success\";\n\n return \"success\";\n}\n\n/**\n * Create a parallel detector that processes nodes.\n */\nexport function createParallelDetector(options: ParallelDetectorOptions = {}) {\n return {\n /**\n * Process nodes and group overlapping ones into parallel nodes.\n */\n detect: (nodes: FlowNode[]) => detectParallelGroups(nodes, options),\n };\n}\n","/**\n * IR Builder - Converts workflow events to Intermediate Representation.\n *\n * The builder maintains state as events arrive, constructing a tree\n * representation of the workflow execution that can be rendered.\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type {\n FlowNode,\n ScopeEndEvent,\n ScopeStartEvent,\n ScopeType,\n StepNode,\n StepState,\n WorkflowIR,\n WorkflowNode,\n ParallelNode,\n RaceNode,\n DecisionNode,\n DecisionStartEvent,\n DecisionBranchEvent,\n DecisionEndEvent,\n DecisionBranch,\n} from \"./types\";\nimport { generateId } from \"./utils/timing\";\nimport { detectParallelGroups, type ParallelDetectorOptions } from \"./parallel-detector\";\n\n// =============================================================================\n// Builder Options\n// =============================================================================\n\n/**\n * Options for the IR builder.\n */\nexport interface IRBuilderOptions {\n /**\n * Enable heuristic parallel detection based on timing.\n * When true, overlapping steps are grouped into ParallelNodes.\n * Default: true\n */\n detectParallel?: boolean;\n\n /**\n * Options for parallel detection.\n */\n parallelDetection?: ParallelDetectorOptions;\n}\n\n// =============================================================================\n// Builder State\n// =============================================================================\n\ninterface ActiveStep {\n id: string;\n name?: string;\n key?: string;\n startTs: number;\n retryCount: number;\n timedOut: boolean;\n timeoutMs?: number;\n}\n\ninterface ActiveScope {\n id: string;\n name?: string;\n type: ScopeType;\n startTs: number;\n children: FlowNode[];\n}\n\ninterface ActiveDecision {\n id: string;\n name?: string;\n condition?: string;\n decisionValue?: unknown;\n startTs: number;\n branches: Map<string, DecisionBranch>;\n branchTaken?: string | boolean;\n}\n\n// =============================================================================\n// IR Builder\n// =============================================================================\n\n/**\n * Creates an IR builder that processes workflow events.\n */\nexport function createIRBuilder(options: IRBuilderOptions = {}) {\n const { detectParallel = true, parallelDetection } = options;\n\n // Current workflow state\n let workflowId: string | undefined;\n let workflowStartTs: number | undefined;\n let workflowState: StepState = \"pending\";\n let workflowError: unknown;\n let workflowDurationMs: number | undefined;\n\n // Active steps (currently running)\n const activeSteps = new Map<string, ActiveStep>();\n\n // Active scopes (parallel/race blocks)\n const scopeStack: ActiveScope[] = [];\n\n // Active decisions (conditional branches)\n const decisionStack: ActiveDecision[] = [];\n\n // Completed nodes at the current scope level\n let currentNodes: FlowNode[] = [];\n\n // Metadata\n let createdAt = Date.now();\n let lastUpdatedAt = createdAt;\n\n /**\n * Get the step ID from an event.\n * Uses stepId if available (new events), then falls back to stepKey or name,\n * and finally generates a random ID for backwards compatibility.\n */\n function getStepId(event: { stepId?: string; stepKey?: string; name?: string }): string {\n return event.stepId ?? event.stepKey ?? event.name ?? generateId();\n }\n\n /**\n * Add a completed node to the current scope or decision branch.\n */\n function addNode(node: FlowNode): void {\n // If we're in a decision, add to the taken branch\n if (decisionStack.length > 0) {\n const decision = decisionStack[decisionStack.length - 1];\n // Find the taken branch\n for (const branch of decision.branches.values()) {\n if (branch.taken) {\n branch.children.push(node);\n lastUpdatedAt = Date.now();\n return;\n }\n }\n // If no branch is marked as taken yet, add to the first branch\n // (this handles cases where steps execute before branch is marked)\n const firstBranch = Array.from(decision.branches.values())[0];\n if (firstBranch) {\n firstBranch.children.push(node);\n lastUpdatedAt = Date.now();\n return;\n }\n }\n\n // If we're in a scope, add to the scope\n if (scopeStack.length > 0) {\n // Add to the innermost scope\n scopeStack[scopeStack.length - 1].children.push(node);\n } else {\n // Add to the root level\n currentNodes.push(node);\n }\n lastUpdatedAt = Date.now();\n }\n\n /**\n * Handle a workflow event and update the IR.\n */\n function handleEvent(event: WorkflowEvent<unknown>): void {\n switch (event.type) {\n case \"workflow_start\":\n workflowId = event.workflowId;\n workflowStartTs = event.ts;\n workflowState = \"running\";\n createdAt = Date.now();\n lastUpdatedAt = createdAt;\n break;\n\n case \"workflow_success\":\n workflowState = \"success\";\n workflowDurationMs = event.durationMs;\n lastUpdatedAt = Date.now();\n break;\n\n case \"workflow_error\":\n workflowState = \"error\";\n workflowError = event.error;\n workflowDurationMs = event.durationMs;\n lastUpdatedAt = Date.now();\n break;\n\n case \"step_start\": {\n const id = getStepId(event);\n activeSteps.set(id, {\n id,\n name: event.name,\n key: event.stepKey,\n startTs: event.ts,\n retryCount: 0,\n timedOut: false,\n });\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"step_success\": {\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n const node: StepNode = {\n type: \"step\",\n id: active.id,\n name: active.name,\n key: active.key,\n state: \"success\",\n startTs: active.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n ...(active.retryCount > 0 && { retryCount: active.retryCount }),\n ...(active.timedOut && { timedOut: true, timeoutMs: active.timeoutMs }),\n };\n addNode(node);\n activeSteps.delete(id);\n }\n break;\n }\n\n case \"step_error\": {\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n const node: StepNode = {\n type: \"step\",\n id: active.id,\n name: active.name,\n key: active.key,\n state: \"error\",\n startTs: active.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n error: event.error,\n ...(active.retryCount > 0 && { retryCount: active.retryCount }),\n ...(active.timedOut && { timedOut: true, timeoutMs: active.timeoutMs }),\n };\n addNode(node);\n activeSteps.delete(id);\n }\n break;\n }\n\n case \"step_aborted\": {\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n const node: StepNode = {\n type: \"step\",\n id: active.id,\n name: active.name,\n key: active.key,\n state: \"aborted\",\n startTs: active.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n ...(active.retryCount > 0 && { retryCount: active.retryCount }),\n ...(active.timedOut && { timedOut: true, timeoutMs: active.timeoutMs }),\n };\n addNode(node);\n activeSteps.delete(id);\n }\n break;\n }\n\n case \"step_cache_hit\": {\n const id = getStepId(event);\n const node: StepNode = {\n type: \"step\",\n id,\n name: event.name,\n key: event.stepKey,\n state: \"cached\",\n startTs: event.ts,\n endTs: event.ts,\n durationMs: 0,\n };\n addNode(node);\n break;\n }\n\n case \"step_cache_miss\":\n // Cache miss just means the step will execute normally\n // We'll get a step_start event next\n break;\n\n case \"step_complete\":\n // step_complete is for state persistence, not visualization\n // We already handled the step via step_success/step_error\n break;\n\n case \"step_timeout\": {\n // Timeout is an intermediate event - step may retry or will get step_error\n // Track timeout info on the active step\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n active.timedOut = true;\n active.timeoutMs = event.timeoutMs;\n }\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"step_retry\": {\n // Retry is an intermediate event - increment retry counter\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n active.retryCount = (event.attempt ?? 1) - 1; // attempt is 1-indexed, retryCount is 0-indexed\n }\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"step_retries_exhausted\":\n // All retries exhausted - step_error will follow\n // The error state will be set by step_error handler\n lastUpdatedAt = Date.now();\n break;\n\n case \"step_skipped\": {\n const id = getStepId(event);\n const node: StepNode = {\n type: \"step\",\n id,\n name: event.name,\n key: event.stepKey,\n state: \"skipped\",\n startTs: event.ts,\n endTs: event.ts,\n durationMs: 0,\n };\n addNode(node);\n break;\n }\n }\n }\n\n /**\n * Handle a scope event (parallel/race start/end).\n */\n function handleScopeEvent(event: ScopeStartEvent | ScopeEndEvent): void {\n if (event.type === \"scope_start\") {\n scopeStack.push({\n id: event.scopeId,\n name: event.name,\n type: event.scopeType,\n startTs: event.ts,\n children: [],\n });\n lastUpdatedAt = Date.now();\n } else if (event.type === \"scope_end\") {\n const scope = scopeStack.pop();\n if (scope) {\n const node: ParallelNode | RaceNode =\n scope.type === \"race\"\n ? {\n type: \"race\",\n id: scope.id,\n name: scope.name,\n state: deriveState(scope.children),\n startTs: scope.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n children: scope.children,\n winnerId: event.winnerId,\n }\n : {\n type: \"parallel\",\n id: scope.id,\n name: scope.name,\n state: deriveState(scope.children),\n startTs: scope.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n children: scope.children,\n mode: scope.type === \"allSettled\" ? \"allSettled\" : \"all\",\n };\n addNode(node);\n }\n }\n }\n\n /**\n * Handle a decision event (conditional branch start/branch/end).\n */\n function handleDecisionEvent(\n event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent\n ): void {\n if (event.type === \"decision_start\") {\n decisionStack.push({\n id: event.decisionId,\n name: event.name,\n condition: event.condition,\n decisionValue: event.decisionValue,\n startTs: event.ts,\n branches: new Map(),\n });\n lastUpdatedAt = Date.now();\n } else if (event.type === \"decision_branch\") {\n const decision = decisionStack[decisionStack.length - 1];\n if (decision && decision.id === event.decisionId) {\n // Find or create branch\n const branchKey = event.branchLabel;\n const existing = decision.branches.get(branchKey);\n if (existing) {\n // Update existing branch\n existing.taken = event.taken;\n } else {\n // Create new branch\n decision.branches.set(branchKey, {\n label: event.branchLabel,\n condition: event.condition,\n taken: event.taken,\n children: [],\n });\n }\n lastUpdatedAt = Date.now();\n }\n } else if (event.type === \"decision_end\") {\n const decision = decisionStack.pop();\n if (decision && decision.id === event.decisionId) {\n // Convert branches map to array\n const branches: DecisionBranch[] = Array.from(decision.branches.values());\n\n const node: DecisionNode = {\n type: \"decision\",\n id: decision.id,\n name: decision.name,\n state: deriveState(\n branches.flatMap((b) => (b.taken ? b.children : []))\n ),\n startTs: decision.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n condition: decision.condition,\n decisionValue: decision.decisionValue,\n branchTaken: event.branchTaken ?? decision.branchTaken,\n branches,\n };\n addNode(node);\n }\n }\n }\n\n /**\n * Derive the state of a parent node from its children.\n */\n function deriveState(children: FlowNode[]): StepState {\n if (children.length === 0) return \"success\";\n\n const hasError = children.some((c) => c.state === \"error\");\n if (hasError) return \"error\";\n\n const allSuccess = children.every(\n (c) => c.state === \"success\" || c.state === \"cached\"\n );\n if (allSuccess) return \"success\";\n\n const hasRunning = children.some((c) => c.state === \"running\");\n if (hasRunning) return \"running\";\n\n return \"pending\";\n }\n\n /**\n * Get the current nodes including any active (running) steps.\n */\n function getCurrentNodes(): FlowNode[] {\n const nodes = [...currentNodes];\n\n // Add active steps as running nodes\n for (const [, active] of activeSteps) {\n nodes.push({\n type: \"step\",\n id: active.id,\n name: active.name,\n key: active.key,\n state: \"running\",\n startTs: active.startTs,\n ...(active.retryCount > 0 && { retryCount: active.retryCount }),\n ...(active.timedOut && { timedOut: true, timeoutMs: active.timeoutMs }),\n });\n }\n\n return nodes;\n }\n\n /**\n * Build and return the current IR state.\n */\n function getIR(): WorkflowIR {\n let children = getCurrentNodes();\n\n // Apply parallel detection if enabled\n if (detectParallel) {\n children = detectParallelGroups(children, parallelDetection);\n }\n\n const root: WorkflowNode = {\n type: \"workflow\",\n id: workflowId ?? generateId(),\n workflowId: workflowId ?? \"unknown\",\n state: workflowState,\n startTs: workflowStartTs,\n durationMs: workflowDurationMs,\n children,\n error: workflowError,\n };\n\n return {\n root,\n metadata: {\n createdAt,\n lastUpdatedAt,\n },\n };\n }\n\n /**\n * Reset the builder state.\n */\n function reset(): void {\n workflowId = undefined;\n workflowStartTs = undefined;\n workflowState = \"pending\";\n workflowError = undefined;\n workflowDurationMs = undefined;\n activeSteps.clear();\n scopeStack.length = 0;\n decisionStack.length = 0;\n currentNodes = [];\n createdAt = Date.now();\n lastUpdatedAt = createdAt;\n }\n\n return {\n handleEvent,\n handleScopeEvent,\n handleDecisionEvent,\n getIR,\n reset,\n /** Check if there are active (running) steps */\n get hasActiveSteps() {\n return activeSteps.size > 0;\n },\n /** Get the current workflow state */\n get state() {\n return workflowState;\n },\n };\n}\n\n/**\n * Type for the IR builder instance.\n */\nexport type IRBuilder = ReturnType<typeof createIRBuilder>;\n","/**\n * Workflow Visualization - Intermediate Representation Types\n *\n * The IR (Intermediate Representation) is a DSL that represents workflow\n * execution structure. Events are converted to IR, which can then be\n * rendered to various output formats (ASCII, Mermaid, JSON, etc.).\n */\n\n// =============================================================================\n// Step States\n// =============================================================================\n\n/**\n * Execution state of a step with semantic meaning for visualization.\n *\n * Color mapping:\n * - pending → white/clear (not started)\n * - running → yellow (currently executing)\n * - success → green (completed successfully)\n * - error → red (failed with error)\n * - aborted → gray (cancelled, e.g., in race)\n * - cached → blue (served from cache)\n * - skipped → dim gray (not executed due to conditional logic)\n */\nexport type StepState =\n | \"pending\"\n | \"running\"\n | \"success\"\n | \"error\"\n | \"aborted\"\n | \"cached\"\n | \"skipped\";\n\n// =============================================================================\n// Node Types\n// =============================================================================\n\n/**\n * Base properties shared by all IR nodes.\n */\nexport interface BaseNode {\n /** Unique identifier for this node */\n id: string;\n /** Human-readable name (from step options or inferred) */\n name?: string;\n /** Cache key if this is a keyed step */\n key?: string;\n /** Current execution state */\n state: StepState;\n /** Timestamp when execution started */\n startTs?: number;\n /** Timestamp when execution ended */\n endTs?: number;\n /** Duration in milliseconds */\n durationMs?: number;\n /** Error value if state is 'error' */\n error?: unknown;\n /** Input value that triggered this step (for decision understanding) */\n input?: unknown;\n /** Output value from this step (for decision understanding) */\n output?: unknown;\n /** Number of retry attempts made (0 = no retries, 1 = one retry, etc.) */\n retryCount?: number;\n /** Whether this step experienced a timeout (may have retried after) */\n timedOut?: boolean;\n /** Timeout duration in ms (if timed out) */\n timeoutMs?: number;\n}\n\n/**\n * A single step execution node.\n */\nexport interface StepNode extends BaseNode {\n type: \"step\";\n}\n\n/**\n * Sequential execution - steps run one after another.\n * This is the implicit structure when steps are awaited in sequence.\n */\nexport interface SequenceNode extends BaseNode {\n type: \"sequence\";\n children: FlowNode[];\n}\n\n/**\n * Parallel execution - all branches run simultaneously.\n * Created by allAsync() or allSettledAsync().\n */\nexport interface ParallelNode extends BaseNode {\n type: \"parallel\";\n children: FlowNode[];\n /**\n * Execution mode:\n * - 'all': Fails on first error (allAsync)\n * - 'allSettled': Collects all results (allSettledAsync)\n */\n mode: \"all\" | \"allSettled\";\n}\n\n/**\n * Race execution - first to complete wins.\n * Created by anyAsync().\n */\nexport interface RaceNode extends BaseNode {\n type: \"race\";\n children: FlowNode[];\n /** ID of the winning branch (first to succeed) */\n winnerId?: string;\n}\n\n/**\n * Decision point - conditional branch (if/switch).\n * Shows which branch was taken and why.\n */\nexport interface DecisionNode extends BaseNode {\n type: \"decision\";\n /** Condition that was evaluated (e.g., \"user.role === 'admin'\") */\n condition?: string;\n /** Value that was evaluated (the input to the decision) */\n decisionValue?: unknown;\n /** Which branch was taken (true/false, or the matched case) */\n branchTaken?: string | boolean;\n /** All possible branches (including skipped ones) */\n branches: DecisionBranch[];\n}\n\n/**\n * A branch in a decision node.\n */\nexport interface DecisionBranch {\n /** Label for this branch (e.g., \"if\", \"else\", \"case 'admin'\") */\n label: string;\n /** Condition that would trigger this branch */\n condition?: string;\n /** Whether this branch was taken */\n taken: boolean;\n /** Steps in this branch */\n children: FlowNode[];\n}\n\n/**\n * Union of all flow node types.\n */\nexport type FlowNode = StepNode | SequenceNode | ParallelNode | RaceNode | DecisionNode;\n\n/**\n * Root node representing the entire workflow.\n */\nexport interface WorkflowNode extends BaseNode {\n type: \"workflow\";\n /** Correlation ID from the workflow execution */\n workflowId: string;\n /** Child nodes (steps, parallel blocks, etc.) */\n children: FlowNode[];\n}\n\n// =============================================================================\n// Workflow IR\n// =============================================================================\n\n/**\n * Complete workflow intermediate representation.\n * This is the main data structure produced by the IR builder.\n */\nexport interface WorkflowIR {\n /** Root workflow node */\n root: WorkflowNode;\n /** Metadata about the IR */\n metadata: {\n /** When the IR was first created */\n createdAt: number;\n /** When the IR was last updated */\n lastUpdatedAt: number;\n };\n}\n\n// =============================================================================\n// Scope Events (for parallel/race detection)\n// =============================================================================\n\n// Re-export ScopeType from core for consistency\nexport type { ScopeType } from \"../core\";\nimport type { ScopeType } from \"../core\";\n\n/**\n * Event emitted when entering a parallel/race scope.\n * This matches the scope_start event in WorkflowEvent.\n */\nexport interface ScopeStartEvent {\n type: \"scope_start\";\n workflowId: string;\n scopeId: string;\n scopeType: ScopeType;\n name?: string;\n ts: number;\n}\n\n/**\n * Event emitted when exiting a parallel/race scope.\n */\nexport interface ScopeEndEvent {\n type: \"scope_end\";\n workflowId: string;\n scopeId: string;\n ts: number;\n durationMs: number;\n /** For race scopes, the ID of the winning branch */\n winnerId?: string;\n}\n\n/**\n * Event emitted when a decision point is encountered.\n * Use this to track conditional logic (if/switch).\n */\nexport interface DecisionStartEvent {\n type: \"decision_start\";\n workflowId: string;\n decisionId: string;\n /** Condition being evaluated (e.g., \"user.role === 'admin'\") */\n condition?: string;\n /** Value being evaluated */\n decisionValue?: unknown;\n /** Name/label for this decision point */\n name?: string;\n ts: number;\n}\n\n/**\n * Event emitted when a decision branch is taken.\n */\nexport interface DecisionBranchEvent {\n type: \"decision_branch\";\n workflowId: string;\n decisionId: string;\n /** Label for this branch (e.g., \"if\", \"else\", \"case 'admin'\") */\n branchLabel: string;\n /** Condition for this branch */\n condition?: string;\n /** Whether this branch was taken */\n taken: boolean;\n ts: number;\n}\n\n/**\n * Event emitted when a decision point completes.\n */\nexport interface DecisionEndEvent {\n type: \"decision_end\";\n workflowId: string;\n decisionId: string;\n /** Which branch was taken */\n branchTaken?: string | boolean;\n ts: number;\n durationMs: number;\n}\n\n/**\n * Event emitted when a step is skipped due to conditional logic.\n */\nexport interface StepSkippedEvent {\n type: \"step_skipped\";\n workflowId: string;\n stepKey?: string;\n name?: string;\n /** Reason why this step was skipped (e.g., \"condition was false\") */\n reason?: string;\n /** The decision that caused this skip */\n decisionId?: string;\n ts: number;\n}\n\n/**\n * Union of scope-related events.\n */\nexport type ScopeEvent = ScopeStartEvent | ScopeEndEvent;\n\n/**\n * Union of decision-related events.\n */\nexport type DecisionEvent = DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent;\n\n// =============================================================================\n// Renderer Types\n// =============================================================================\n\n/**\n * Color scheme for rendering step states.\n */\nexport interface ColorScheme {\n pending: string;\n running: string;\n success: string;\n error: string;\n aborted: string;\n cached: string;\n skipped: string;\n}\n\n/**\n * Options passed to renderers.\n */\nexport interface RenderOptions {\n /** Show timing information (duration) */\n showTimings: boolean;\n /** Show step cache keys */\n showKeys: boolean;\n /** Terminal width for ASCII renderer */\n terminalWidth?: number;\n /** Color scheme */\n colors: ColorScheme;\n}\n\n/**\n * Renderer interface - transforms IR to output format.\n */\nexport interface Renderer {\n /** Unique identifier for this renderer */\n readonly name: string;\n /** Render IR to string output */\n render(ir: WorkflowIR, options: RenderOptions): string;\n /** Whether this renderer supports live (incremental) updates */\n supportsLive?: boolean;\n /** Render incremental update (optional) */\n renderUpdate?(\n ir: WorkflowIR,\n changedNodes: FlowNode[],\n options: RenderOptions\n ): string;\n}\n\n// =============================================================================\n// Visualizer Types\n// =============================================================================\n\n/**\n * Output format for rendering.\n */\nexport type OutputFormat = \"ascii\" | \"mermaid\" | \"json\";\n\n/**\n * Options for creating a visualizer.\n */\nexport interface VisualizerOptions {\n /** Name for the workflow in visualizations */\n workflowName?: string;\n /** Enable parallel detection heuristics (default: true) */\n detectParallel?: boolean;\n /** Show timing information (default: true) */\n showTimings?: boolean;\n /** Show step keys (default: false) */\n showKeys?: boolean;\n /** Custom color scheme */\n colors?: Partial<ColorScheme>;\n}\n\n/**\n * Options for live visualization.\n */\nexport interface LiveVisualizerOptions extends VisualizerOptions {\n /** Output stream (default: process.stdout) */\n stream?: NodeJS.WriteStream;\n /** Update interval in ms (default: 100) */\n updateInterval?: number;\n}\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\n/**\n * Check if a node is a StepNode.\n */\nexport function isStepNode(node: FlowNode): node is StepNode {\n return node.type === \"step\";\n}\n\n/**\n * Check if a node is a SequenceNode.\n */\nexport function isSequenceNode(node: FlowNode): node is SequenceNode {\n return node.type === \"sequence\";\n}\n\n/**\n * Check if a node is a ParallelNode.\n */\nexport function isParallelNode(node: FlowNode): node is ParallelNode {\n return node.type === \"parallel\";\n}\n\n/**\n * Check if a node is a RaceNode.\n */\nexport function isRaceNode(node: FlowNode): node is RaceNode {\n return node.type === \"race\";\n}\n\n/**\n * Check if a node is a DecisionNode.\n */\nexport function isDecisionNode(node: FlowNode): node is DecisionNode {\n return node.type === \"decision\";\n}\n\n/**\n * Check if a node has children.\n */\nexport function hasChildren(\n node: FlowNode\n): node is SequenceNode | ParallelNode | RaceNode | DecisionNode {\n return \"children\" in node || (node.type === \"decision\" && \"branches\" in node);\n}\n","/**\n * ANSI color utilities for terminal output.\n */\n\nimport type { ColorScheme, StepState } from \"../types\";\n\n// =============================================================================\n// ANSI Escape Codes\n// =============================================================================\n\nconst RESET = \"\\x1b[0m\";\nconst BOLD = \"\\x1b[1m\";\nconst DIM = \"\\x1b[2m\";\n\n// Foreground colors\nconst FG_RED = \"\\x1b[31m\";\nconst FG_GREEN = \"\\x1b[32m\";\nconst FG_YELLOW = \"\\x1b[33m\";\nconst FG_BLUE = \"\\x1b[34m\";\nconst FG_GRAY = \"\\x1b[90m\";\nconst FG_WHITE = \"\\x1b[37m\";\n\n// =============================================================================\n// Color Functions\n// =============================================================================\n\n/**\n * Apply ANSI color to text.\n */\nexport function colorize(text: string, color: string): string {\n if (!color) return text;\n return `${color}${text}${RESET}`;\n}\n\n/**\n * Make text bold.\n */\nexport function bold(text: string): string {\n return `${BOLD}${text}${RESET}`;\n}\n\n/**\n * Make text dim.\n */\nexport function dim(text: string): string {\n return `${DIM}${text}${RESET}`;\n}\n\n// =============================================================================\n// Default Color Scheme\n// =============================================================================\n\n/**\n * Default ANSI color scheme for step states.\n */\nexport const defaultColorScheme: ColorScheme = {\n pending: FG_WHITE,\n running: FG_YELLOW,\n success: FG_GREEN,\n error: FG_RED,\n aborted: FG_GRAY,\n cached: FG_BLUE,\n skipped: DIM + FG_GRAY, // Dim gray for skipped steps\n};\n\n// =============================================================================\n// State Symbols\n// =============================================================================\n\n/**\n * Get the symbol for a step state.\n */\nexport function getStateSymbol(state: StepState): string {\n switch (state) {\n case \"pending\":\n return \"○\"; // Empty circle\n case \"running\":\n return \"⟳\"; // Rotating arrows\n case \"success\":\n return \"✓\"; // Check mark\n case \"error\":\n return \"✗\"; // X mark\n case \"aborted\":\n return \"⊘\"; // Circled slash\n case \"cached\":\n return \"↺\"; // Cached/replay\n case \"skipped\":\n return \"⊘\"; // Circled slash (same as aborted, but different color)\n }\n}\n\n/**\n * Get the colored symbol for a step state.\n */\nexport function getColoredSymbol(state: StepState, colors: ColorScheme): string {\n const symbol = getStateSymbol(state);\n return colorize(symbol, colors[state]);\n}\n\n/**\n * Get colored text based on step state.\n */\nexport function colorByState(\n text: string,\n state: StepState,\n colors: ColorScheme\n): string {\n return colorize(text, colors[state]);\n}\n\n// =============================================================================\n// Strip ANSI\n// =============================================================================\n\n/**\n * Strip ANSI escape codes from a string.\n * Useful for calculating visible string length.\n */\nexport function stripAnsi(str: string): string {\n // eslint-disable-next-line no-control-regex\n return str.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n}\n\n/**\n * Get the visible length of a string (without ANSI codes).\n */\nexport function visibleLength(str: string): string {\n return stripAnsi(str);\n}\n","/**\n * ASCII Terminal Renderer\n *\n * Renders the workflow IR as ASCII art with box-drawing characters\n * and ANSI colors for terminal display.\n */\n\nimport type {\n FlowNode,\n ParallelNode,\n RaceNode,\n DecisionNode,\n Renderer,\n RenderOptions,\n StepNode,\n WorkflowIR,\n} from \"../types\";\nimport { isParallelNode, isRaceNode, isStepNode, isDecisionNode } from \"../types\";\nimport { formatDuration } from \"../utils/timing\";\nimport {\n bold,\n colorByState,\n colorize,\n defaultColorScheme,\n dim,\n getColoredSymbol,\n stripAnsi,\n} from \"./colors\";\n\n// =============================================================================\n// Box Drawing Characters\n// =============================================================================\n\nconst BOX = {\n topLeft: \"┌\",\n topRight: \"┐\",\n bottomLeft: \"└\",\n bottomRight: \"┘\",\n horizontal: \"─\",\n vertical: \"│\",\n teeRight: \"├\",\n teeLeft: \"┤\",\n teeDown: \"┬\",\n teeUp: \"┴\",\n cross: \"┼\",\n} as const;\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Pad a string to a fixed width, accounting for ANSI codes.\n */\nfunction padEnd(str: string, width: number): string {\n const visibleLen = stripAnsi(str).length;\n const padding = Math.max(0, width - visibleLen);\n return str + \" \".repeat(padding);\n}\n\n/**\n * Create a horizontal line with optional title.\n */\nfunction horizontalLine(width: number, title?: string): string {\n if (!title) {\n return BOX.horizontal.repeat(width);\n }\n\n const titleText = ` ${title} `;\n const remainingWidth = width - titleText.length;\n if (remainingWidth < 4) {\n return BOX.horizontal.repeat(width);\n }\n\n const leftPad = 2;\n const rightPad = remainingWidth - leftPad;\n\n return (\n BOX.horizontal.repeat(leftPad) + titleText + BOX.horizontal.repeat(rightPad)\n );\n}\n\n// =============================================================================\n// ASCII Renderer\n// =============================================================================\n\n/**\n * Create the ASCII terminal renderer.\n */\nexport function asciiRenderer(): Renderer {\n return {\n name: \"ascii\",\n supportsLive: true,\n\n render(ir: WorkflowIR, options: RenderOptions): string {\n const colors = { ...defaultColorScheme, ...options.colors };\n const width = options.terminalWidth ?? 60;\n const innerWidth = width - 4; // Account for borders\n\n const lines: string[] = [];\n\n // Header\n const workflowName = ir.root.name ?? \"workflow\";\n const headerTitle = bold(workflowName);\n lines.push(\n `${BOX.topLeft}${horizontalLine(width - 2, headerTitle)}${BOX.topRight}`\n );\n lines.push(`${BOX.vertical}${\" \".repeat(width - 2)}${BOX.vertical}`);\n\n // Render children\n const childLines = renderNodes(ir.root.children, options, colors, 0);\n for (const line of childLines) {\n lines.push(\n `${BOX.vertical} ${padEnd(line, innerWidth)}${BOX.vertical}`\n );\n }\n\n // Footer with timing\n lines.push(`${BOX.vertical}${\" \".repeat(width - 2)}${BOX.vertical}`);\n\n if (ir.root.durationMs !== undefined && options.showTimings) {\n const status = ir.root.state === \"success\" ? \"Completed\" : \"Failed\";\n const statusColored = colorByState(status, ir.root.state, colors);\n const footer = `${statusColored} in ${formatDuration(ir.root.durationMs)}`;\n lines.push(\n `${BOX.vertical} ${padEnd(footer, innerWidth)}${BOX.vertical}`\n );\n lines.push(`${BOX.vertical}${\" \".repeat(width - 2)}${BOX.vertical}`);\n }\n\n lines.push(\n `${BOX.bottomLeft}${BOX.horizontal.repeat(width - 2)}${BOX.bottomRight}`\n );\n\n return lines.join(\"\\n\");\n },\n };\n}\n\n/**\n * Render a list of nodes.\n */\nfunction renderNodes(\n nodes: FlowNode[],\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n depth: number\n): string[] {\n const lines: string[] = [];\n\n for (const node of nodes) {\n if (isStepNode(node)) {\n lines.push(renderStepNode(node, options, colors));\n } else if (isParallelNode(node)) {\n lines.push(...renderParallelNode(node, options, colors, depth));\n } else if (isRaceNode(node)) {\n lines.push(...renderRaceNode(node, options, colors, depth));\n } else if (isDecisionNode(node)) {\n lines.push(...renderDecisionNode(node, options, colors, depth));\n }\n }\n\n return lines;\n}\n\n/**\n * Render a single step node.\n */\nfunction renderStepNode(\n node: StepNode,\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>\n): string {\n const symbol = getColoredSymbol(node.state, colors);\n const name = node.name ?? node.key ?? \"step\";\n const nameColored = colorByState(name, node.state, colors);\n\n let line = `${symbol} ${nameColored}`;\n\n // Add key if requested\n if (options.showKeys && node.key) {\n line += dim(` [key: ${node.key}]`);\n }\n\n // Add input/output if available (for decision understanding)\n if (node.input !== undefined) {\n const inputStr = typeof node.input === \"string\" \n ? node.input \n : JSON.stringify(node.input).slice(0, 30);\n line += dim(` [in: ${inputStr}${inputStr.length >= 30 ? \"...\" : \"\"}]`);\n }\n if (node.output !== undefined && node.state === \"success\") {\n const outputStr = typeof node.output === \"string\"\n ? node.output\n : JSON.stringify(node.output).slice(0, 30);\n line += dim(` [out: ${outputStr}${outputStr.length >= 30 ? \"...\" : \"\"}]`);\n }\n\n // Add timing if available and requested\n if (options.showTimings && node.durationMs !== undefined) {\n line += dim(` [${formatDuration(node.durationMs)}]`);\n }\n\n // Add retry indicator if retries occurred\n if (node.retryCount !== undefined && node.retryCount > 0) {\n line += dim(` [${node.retryCount} ${node.retryCount === 1 ? \"retry\" : \"retries\"}]`);\n }\n\n // Add timeout indicator if step timed out\n if (node.timedOut) {\n const timeoutInfo = node.timeoutMs !== undefined ? ` ${node.timeoutMs}ms` : \"\";\n line += dim(` [timeout${timeoutInfo}]`);\n }\n\n return line;\n}\n\n/**\n * Render a parallel node (allAsync).\n */\nfunction renderParallelNode(\n node: ParallelNode,\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n depth: number\n): string[] {\n const lines: string[] = [];\n const indent = \" \".repeat(depth);\n\n // Header\n const symbol = getColoredSymbol(node.state, colors);\n const name = node.name ?? \"parallel\";\n const mode = node.mode === \"allSettled\" ? \" (allSettled)\" : \"\";\n lines.push(`${indent}${BOX.teeRight}${BOX.teeDown}${BOX.horizontal} ${symbol} ${bold(name)}${mode}`);\n\n // Children\n if (node.children.length === 0) {\n // Empty parallel scope - operations inside allAsync/anyAsync weren't tracked as steps\n lines.push(`${indent}${BOX.vertical} ${dim(\"(operations not individually tracked)\")}`);\n lines.push(`${indent}${BOX.vertical} ${dim(\"(wrap each operation with step() to see individual steps)\")}`);\n } else {\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n const isLast = i === node.children.length - 1;\n const prefix = isLast ? `${indent}${BOX.vertical} ${BOX.bottomLeft}` : `${indent}${BOX.vertical} ${BOX.teeRight}`;\n\n if (isStepNode(child)) {\n lines.push(`${prefix} ${renderStepNode(child, options, colors)}`);\n } else {\n // Nested structure - recurse\n const nestedLines = renderNodes([child], options, colors, depth + 1);\n for (const line of nestedLines) {\n lines.push(`${indent}${BOX.vertical} ${line}`);\n }\n }\n }\n }\n\n // Timing footer\n if (options.showTimings && node.durationMs !== undefined) {\n lines.push(`${indent}${BOX.bottomLeft}${BOX.horizontal}${BOX.horizontal} ${dim(`[${formatDuration(node.durationMs)}]`)}`);\n }\n\n return lines;\n}\n\n/**\n * Render a race node (anyAsync).\n */\nfunction renderRaceNode(\n node: RaceNode,\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n depth: number\n): string[] {\n const lines: string[] = [];\n const indent = \" \".repeat(depth);\n\n // Header with lightning bolt for race\n const symbol = getColoredSymbol(node.state, colors);\n const name = node.name ?? \"race\";\n lines.push(`${indent}${BOX.teeRight}⚡ ${symbol} ${bold(name)}`);\n\n // Children\n if (node.children.length === 0) {\n // Empty race scope - operations inside anyAsync weren't tracked as steps\n lines.push(`${indent}${BOX.vertical} ${dim(\"(operations not individually tracked)\")}`);\n lines.push(`${indent}${BOX.vertical} ${dim(\"(wrap each operation with step() to see individual steps)\")}`);\n } else {\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n const isLast = i === node.children.length - 1;\n const prefix = isLast ? `${indent}${BOX.vertical} ${BOX.bottomLeft}` : `${indent}${BOX.vertical} ${BOX.teeRight}`;\n\n // Mark winner\n const isWinner = node.winnerId && child.id === node.winnerId;\n const winnerSuffix = isWinner ? dim(\" (winner)\") : \"\";\n\n if (isStepNode(child)) {\n lines.push(`${prefix} ${renderStepNode(child, options, colors)}${winnerSuffix}`);\n } else {\n const nestedLines = renderNodes([child], options, colors, depth + 1);\n for (const line of nestedLines) {\n lines.push(`${indent}${BOX.vertical} ${line}`);\n }\n }\n }\n }\n\n // Timing footer\n if (options.showTimings && node.durationMs !== undefined) {\n lines.push(`${indent}${BOX.bottomLeft}${BOX.horizontal}${BOX.horizontal} ${dim(`[${formatDuration(node.durationMs)}]`)}`);\n }\n\n return lines;\n}\n\n/**\n * Render a decision node (conditional branch).\n */\nfunction renderDecisionNode(\n node: DecisionNode,\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n depth: number\n): string[] {\n const lines: string[] = [];\n const indent = \" \".repeat(depth);\n\n // Header with decision info\n const symbol = getColoredSymbol(node.state, colors);\n const name = node.name ?? \"decision\";\n const condition = node.condition \n ? dim(` (${node.condition})`)\n : \"\";\n const decisionValue = node.decisionValue !== undefined\n ? dim(` = ${String(node.decisionValue)}`)\n : \"\";\n const branchTaken = node.branchTaken !== undefined\n ? dim(` → ${String(node.branchTaken)}`)\n : \"\";\n\n lines.push(\n `${indent}${BOX.teeRight}${BOX.teeDown}${BOX.horizontal} ${symbol} ${bold(name)}${condition}${decisionValue}${branchTaken}`\n );\n\n // Render branches\n for (let i = 0; i < node.branches.length; i++) {\n const branch = node.branches[i];\n const isLast = i === node.branches.length - 1;\n const prefix = isLast \n ? `${indent}${BOX.vertical} ${BOX.bottomLeft}` \n : `${indent}${BOX.vertical} ${BOX.teeRight}`;\n\n // Branch label with taken/skipped indicator\n const branchSymbol = branch.taken ? \"✓\" : \"⊘\";\n const branchColor = branch.taken ? colors.success : colors.skipped;\n const branchLabel = colorize(\n `${branchSymbol} ${branch.label}`,\n branchColor\n );\n const branchCondition = branch.condition\n ? dim(` (${branch.condition})`)\n : \"\";\n\n lines.push(`${prefix} ${branchLabel}${branchCondition}`);\n\n // Render children of this branch\n if (branch.children.length > 0) {\n const childLines = renderNodes(branch.children, options, colors, depth + 1);\n for (const line of childLines) {\n lines.push(`${indent}${BOX.vertical} ${line}`);\n }\n } else if (!branch.taken) {\n // Show that this branch was skipped\n lines.push(\n `${indent}${BOX.vertical} ${dim(\"(skipped)\")}`\n );\n }\n }\n\n // Timing footer\n if (options.showTimings && node.durationMs !== undefined) {\n lines.push(\n `${indent}${BOX.bottomLeft}${BOX.horizontal}${BOX.horizontal} ${dim(`[${formatDuration(node.durationMs)}]`)}`\n );\n }\n\n return lines;\n}\n\nexport { defaultColorScheme };\n","/**\n * Mermaid Diagram Renderer\n *\n * Renders the workflow IR as a Mermaid flowchart diagram.\n * Supports sequential flows, parallel (subgraph), and race patterns.\n */\n\nimport type {\n FlowNode,\n ParallelNode,\n RaceNode,\n DecisionNode,\n Renderer,\n RenderOptions,\n StepNode,\n StepState,\n WorkflowIR,\n} from \"../types\";\nimport { isParallelNode, isRaceNode, isStepNode, isDecisionNode } from \"../types\";\nimport { formatDuration } from \"../utils/timing\";\n\n// =============================================================================\n// Mermaid Style Definitions\n// =============================================================================\n\n/**\n * Get Mermaid class definition for step states.\n * Colors inspired by AWS Step Functions and XState visualizers for professional appearance.\n */\nfunction getStyleDefinitions(): string[] {\n return [\n // Pending - light gray, subtle\n \" classDef pending fill:#f3f4f6,stroke:#9ca3af,stroke-width:2px,color:#374151\",\n // Running - amber/yellow, indicates active execution\n \" classDef running fill:#fef3c7,stroke:#f59e0b,stroke-width:3px,color:#92400e\",\n // Success - green, clear positive indicator\n \" classDef success fill:#d1fae5,stroke:#10b981,stroke-width:3px,color:#065f46\",\n // Error - red, clear negative indicator\n \" classDef error fill:#fee2e2,stroke:#ef4444,stroke-width:3px,color:#991b1b\",\n // Aborted - gray, indicates cancellation\n \" classDef aborted fill:#f3f4f6,stroke:#6b7280,stroke-width:2px,color:#4b5563,stroke-dasharray: 5 5\",\n // Cached - blue, indicates cache hit\n \" classDef cached fill:#dbeafe,stroke:#3b82f6,stroke-width:3px,color:#1e40af\",\n // Skipped - light gray with dashed border\n \" classDef skipped fill:#f9fafb,stroke:#d1d5db,stroke-width:2px,color:#6b7280,stroke-dasharray: 5 5\",\n ];\n}\n\n/**\n * Get the Mermaid class name for a step state.\n */\nfunction getStateClass(state: StepState): string {\n return state;\n}\n\n// =============================================================================\n// Node ID Generation\n// =============================================================================\n\nlet nodeCounter = 0;\n\nfunction generateNodeId(prefix: string = \"node\"): string {\n return `${prefix}_${++nodeCounter}`;\n}\n\nfunction resetNodeCounter(): void {\n nodeCounter = 0;\n}\n\n// =============================================================================\n// Mermaid Text Escaping\n// =============================================================================\n\n/**\n * Escape text for use in Mermaid diagrams.\n * Removes characters that break Mermaid parsing.\n * \n * Characters removed:\n * - {}[]() - Brackets and parentheses break parsing in labels\n * - <> - Angle brackets can cause issues\n * - \" - Double quotes replaced with single quotes\n * \n * @param text - Text to escape\n * @returns Escaped text safe for Mermaid\n */\nfunction escapeMermaidText(text: string): string {\n return text\n .replace(/[{}[\\]()]/g, \"\") // Remove brackets and parentheses (they break parsing)\n .replace(/[<>]/g, \"\") // Remove angle brackets\n .replace(/\"/g, \"'\") // Replace double quotes with single\n .trim();\n}\n\n/**\n * Escape text for use in Mermaid subgraph names.\n * Subgraph names in brackets need special handling.\n * \n * @param text - Text to escape for subgraph name\n * @returns Escaped text safe for subgraph names\n */\nfunction escapeSubgraphName(text: string): string {\n return escapeMermaidText(text)\n .replace(/[[\\]]/g, \"\"); // Also remove brackets from subgraph names\n}\n\n// =============================================================================\n// Mermaid Renderer\n// =============================================================================\n\n/**\n * Create the Mermaid diagram renderer.\n */\nexport function mermaidRenderer(): Renderer {\n return {\n name: \"mermaid\",\n supportsLive: false,\n\n render(ir: WorkflowIR, options: RenderOptions): string {\n resetNodeCounter();\n const lines: string[] = [];\n\n // Diagram header\n lines.push(\"flowchart TD\");\n\n // Start node - more visually distinctive\n const startId = \"start\";\n lines.push(` ${startId}((\"▶ Start\"))`);\n\n // Track the last node for connections\n let prevNodeId = startId;\n\n // Render children\n for (const child of ir.root.children) {\n const result = renderNode(child, options, lines);\n lines.push(` ${prevNodeId} --> ${result.entryId}`);\n prevNodeId = result.exitId;\n }\n\n // End node (if workflow completed) - more visually distinctive\n if (ir.root.state === \"success\" || ir.root.state === \"error\") {\n const endId = \"finish\";\n const endIcon = ir.root.state === \"success\" ? \"✓\" : \"✗\";\n const endLabel = ir.root.state === \"success\" ? \"Done\" : \"Failed\";\n const endShape = `((\"${endIcon} ${endLabel}\"))`;\n const endClass =\n ir.root.state === \"success\" ? \":::success\" : \":::error\";\n lines.push(` ${endId}${endShape}${endClass}`);\n lines.push(` ${prevNodeId} --> ${endId}`);\n }\n\n // Add style definitions\n lines.push(\"\");\n lines.push(...getStyleDefinitions());\n\n return lines.join(\"\\n\");\n },\n };\n}\n\n/**\n * Render result with entry and exit node IDs.\n */\ninterface RenderResult {\n entryId: string;\n exitId: string;\n}\n\n/**\n * Render a node and return its entry/exit IDs.\n */\nfunction renderNode(\n node: FlowNode,\n options: RenderOptions,\n lines: string[]\n): RenderResult {\n if (isStepNode(node)) {\n return renderStepNode(node, options, lines);\n } else if (isParallelNode(node)) {\n return renderParallelNode(node, options, lines);\n } else if (isRaceNode(node)) {\n return renderRaceNode(node, options, lines);\n } else if (isDecisionNode(node)) {\n return renderDecisionNode(node, options, lines);\n }\n\n // Fallback for sequence or unknown nodes\n const id = generateNodeId(\"unknown\");\n lines.push(` ${id}[Unknown Node]`);\n return { entryId: id, exitId: id };\n}\n\n/**\n * Render a step node.\n */\nfunction renderStepNode(\n node: StepNode,\n options: RenderOptions,\n lines: string[]\n): RenderResult {\n const id = node.key\n ? `step_${node.key.replace(/[^a-zA-Z0-9]/g, \"_\")}`\n : generateNodeId(\"step\");\n\n const label = escapeMermaidText(node.name ?? node.key ?? \"Step\");\n \n // Format timing - use space instead of parentheses to avoid Mermaid parse errors\n const timing =\n options.showTimings && node.durationMs !== undefined\n ? ` ${formatDuration(node.durationMs)}`\n : \"\";\n\n // Add visual indicators based on state (like XState/AWS Step Functions)\n let stateIcon = \"\";\n switch (node.state) {\n case \"success\":\n stateIcon = \"✓ \";\n break;\n case \"error\":\n stateIcon = \"✗ \";\n break;\n case \"cached\":\n stateIcon = \"💾 \";\n break;\n case \"running\":\n stateIcon = \"⏳ \";\n break;\n case \"skipped\":\n stateIcon = \"⊘ \";\n break;\n }\n\n // Add input/output info if available\n // Use newlines for multi-line labels, but escape special characters\n let ioInfo = \"\";\n if (node.input !== undefined) {\n const inputStr = typeof node.input === \"string\"\n ? escapeMermaidText(node.input)\n : escapeMermaidText(JSON.stringify(node.input).slice(0, 20));\n ioInfo += `\\\\nin: ${inputStr}`;\n }\n if (node.output !== undefined && node.state === \"success\") {\n const outputStr = typeof node.output === \"string\"\n ? escapeMermaidText(node.output)\n : escapeMermaidText(JSON.stringify(node.output).slice(0, 20));\n ioInfo += `\\\\nout: ${outputStr}`;\n }\n\n // Add retry/timeout indicators with icons\n let retryInfo = \"\";\n if (node.retryCount !== undefined && node.retryCount > 0) {\n retryInfo += `\\\\n↻ ${node.retryCount} retr${node.retryCount === 1 ? \"y\" : \"ies\"}`;\n }\n if (node.timedOut) {\n const timeoutStr = node.timeoutMs !== undefined ? `${node.timeoutMs}ms` : \"\";\n retryInfo += `\\\\n⏱ timeout ${timeoutStr}`;\n }\n\n // Combine all label parts with icon\n const escapedLabel = (stateIcon + label + ioInfo + retryInfo + timing).trim();\n\n const stateClass = getStateClass(node.state);\n\n // Use different shapes based on state (like AWS Step Functions)\n let shape: string;\n switch (node.state) {\n case \"error\":\n // Hexagon for errors (more distinctive)\n shape = `{{${escapedLabel}}}`;\n break;\n case \"cached\":\n // Rounded rectangle with double border for cached\n shape = `[(${escapedLabel})]`;\n break;\n case \"skipped\":\n // Dashed border for skipped\n shape = `[${escapedLabel}]:::skipped`;\n break;\n default:\n // Standard rectangle for normal steps\n shape = `[${escapedLabel}]`;\n }\n\n lines.push(` ${id}${shape}:::${stateClass}`);\n\n return { entryId: id, exitId: id };\n}\n\n/**\n * Render a parallel node as a subgraph with fork/join.\n */\nfunction renderParallelNode(\n node: ParallelNode,\n options: RenderOptions,\n lines: string[]\n): RenderResult {\n const subgraphId = generateNodeId(\"parallel\");\n const forkId = `${subgraphId}_fork`;\n const joinId = `${subgraphId}_join`;\n const name = escapeSubgraphName(node.name ?? \"Parallel\");\n const modeLabel = node.mode === \"allSettled\" ? \" (allSettled)\" : \"\";\n\n // If no children, render as a simple step-like node with note\n if (node.children.length === 0) {\n const id = subgraphId;\n const label = escapeMermaidText(`${name}${modeLabel}`);\n const note = \"operations not individually tracked\";\n const timing = options.showTimings && node.durationMs !== undefined\n ? ` ${formatDuration(node.durationMs)}`\n : \"\";\n \n // Use a rounded rectangle to indicate it's a parallel operation\n lines.push(` ${id}[${label}${timing}\\\\n${note}]:::${getStateClass(node.state)}`);\n return { entryId: id, exitId: id };\n }\n\n // Subgraph for parallel block with proper visual hierarchy\n lines.push(` subgraph ${subgraphId}[\"${name}${modeLabel}\"]`);\n lines.push(` direction TB`);\n\n // Fork node (diamond) - more visually distinct\n lines.push(` ${forkId}{\"⚡ Fork\"}`);\n\n // Child branches - render in parallel columns\n const childExitIds: string[] = [];\n for (const child of node.children) {\n const result = renderNode(child, options, lines);\n lines.push(` ${forkId} --> ${result.entryId}`);\n childExitIds.push(result.exitId);\n }\n\n // Join node (diamond) - visually distinct\n lines.push(` ${joinId}{\"✓ Join\"}`);\n for (const exitId of childExitIds) {\n lines.push(` ${exitId} --> ${joinId}`);\n }\n\n lines.push(` end`);\n\n // Apply state styling to subgraph\n const stateClass = getStateClass(node.state);\n lines.push(` class ${subgraphId} ${stateClass}`);\n\n return { entryId: forkId, exitId: joinId };\n}\n\n/**\n * Render a race node as a subgraph with racing indicator.\n */\nfunction renderRaceNode(\n node: RaceNode,\n options: RenderOptions,\n lines: string[]\n): RenderResult {\n const subgraphId = generateNodeId(\"race\");\n const startId = `${subgraphId}_start`;\n const endId = `${subgraphId}_end`;\n const name = escapeSubgraphName(node.name ?? \"Race\");\n\n // If no children, render as a simple step-like node with note\n if (node.children.length === 0) {\n const id = subgraphId;\n const label = escapeMermaidText(name);\n const note = \"operations not individually tracked\";\n const timing = options.showTimings && node.durationMs !== undefined\n ? ` ${formatDuration(node.durationMs)}`\n : \"\";\n \n lines.push(` ${id}[⚡ ${label}${timing}\\\\n${note}]:::${getStateClass(node.state)}`);\n return { entryId: id, exitId: id };\n }\n\n // Subgraph for race block - escape name and emoji is safe in quoted strings\n lines.push(` subgraph ${subgraphId}[\"⚡ ${name}\"]`);\n lines.push(` direction TB`);\n\n // Start node - use a more distinctive shape\n lines.push(` ${startId}((\"🏁 Start\"))`);\n\n // Child branches\n const childExitIds: Array<{ exitId: string; isWinner: boolean }> = [];\n let winnerExitId: string | undefined;\n \n for (const child of node.children) {\n const result = renderNode(child, options, lines);\n const isWinner = isStepNode(child) && node.winnerId === child.id;\n lines.push(` ${startId} --> ${result.entryId}`);\n \n if (isWinner) {\n winnerExitId = result.exitId;\n }\n childExitIds.push({ exitId: result.exitId, isWinner });\n }\n\n // End node - more distinctive\n lines.push(` ${endId}((\"✓ First\"))`);\n \n // Connect winner with thick line, others with dashed (cancelled)\n for (const { exitId, isWinner } of childExitIds) {\n if (isWinner && winnerExitId) {\n lines.push(` ${exitId} ==>|🏆 Winner| ${endId}`);\n } else if (node.winnerId) {\n // Non-winner: show as cancelled\n lines.push(` ${exitId} -. cancelled .-> ${endId}`);\n } else {\n // No winner determined, normal connection\n lines.push(` ${exitId} --> ${endId}`);\n }\n }\n\n lines.push(` end`);\n\n const stateClass = getStateClass(node.state);\n lines.push(` class ${subgraphId} ${stateClass}`);\n\n return { entryId: startId, exitId: endId };\n}\n\n/**\n * Render a decision node as a diamond with branches.\n */\nfunction renderDecisionNode(\n node: DecisionNode,\n options: RenderOptions,\n lines: string[]\n): RenderResult {\n const decisionId = node.key\n ? `decision_${node.key.replace(/[^a-zA-Z0-9]/g, \"_\")}`\n : generateNodeId(\"decision\");\n\n // Escape condition and decision value - remove characters that break Mermaid\n const condition = escapeMermaidText(node.condition ?? \"condition\");\n const decisionValue = node.decisionValue !== undefined\n ? ` = ${escapeMermaidText(String(node.decisionValue)).slice(0, 30)}`\n : \"\";\n\n // Decision diamond - ensure no invalid characters\n const decisionLabel = `${condition}${decisionValue}`.trim();\n lines.push(` ${decisionId}{${decisionLabel}}`);\n\n // Render branches\n const branchExitIds: string[] = [];\n let takenBranchExitId: string | undefined;\n\n for (const branch of node.branches) {\n const branchId = `${decisionId}_${branch.label.replace(/[^a-zA-Z0-9]/g, \"_\")}`;\n // Escape branch label - remove parentheses and other special chars\n const branchLabelText = escapeMermaidText(branch.label);\n const branchLabel = branch.taken\n ? `${branchLabelText} ✓`\n : `${branchLabelText} skipped`;\n const branchClass = branch.taken ? \":::success\" : \":::skipped\";\n\n // Branch label node\n lines.push(` ${branchId}[${branchLabel}]${branchClass}`);\n\n // Connect decision to branch\n // Mermaid edge labels must be simple text - escape special characters\n // Also remove pipe character as it's used for edge label syntax\n const edgeLabel = branch.condition \n ? `|${escapeMermaidText(branch.condition).replace(/\\|/g, \"\")}|` \n : \"\";\n lines.push(` ${decisionId} -->${edgeLabel} ${branchId}`);\n\n // Render children of this branch\n if (branch.children.length > 0) {\n let prevId = branchId;\n for (const child of branch.children) {\n const result = renderNode(child, options, lines);\n lines.push(` ${prevId} --> ${result.entryId}`);\n prevId = result.exitId;\n }\n branchExitIds.push(prevId);\n if (branch.taken) {\n takenBranchExitId = prevId;\n }\n } else {\n branchExitIds.push(branchId);\n if (branch.taken) {\n takenBranchExitId = branchId;\n }\n }\n }\n\n // Join point (if we have a taken branch)\n if (takenBranchExitId) {\n return { entryId: decisionId, exitId: takenBranchExitId };\n }\n\n // If no branch was taken, return decision as exit\n return { entryId: decisionId, exitId: decisionId };\n}\n\nexport { mermaidRenderer as default };\n","/**\n * Live Visualizer - Real-time terminal updates during workflow execution.\n *\n * Uses ANSI escape codes to update the terminal in-place, showing\n * workflow progress as it happens.\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type {\n LiveVisualizerOptions,\n RenderOptions,\n ScopeEndEvent,\n ScopeStartEvent,\n DecisionStartEvent,\n DecisionBranchEvent,\n DecisionEndEvent,\n WorkflowIR,\n} from \"./types\";\nimport { createIRBuilder } from \"./ir-builder\";\nimport { asciiRenderer, defaultColorScheme } from \"./renderers\";\n\n// =============================================================================\n// ANSI Escape Codes\n// =============================================================================\n\nconst ANSI = {\n /** Clear from cursor to end of screen */\n clearToEnd: \"\\x1b[J\",\n /** Move cursor up N lines */\n cursorUp: (n: number) => `\\x1b[${n}A`,\n /** Move cursor to beginning of line */\n cursorToStart: \"\\x1b[G\",\n /** Hide cursor */\n hideCursor: \"\\x1b[?25l\",\n /** Show cursor */\n showCursor: \"\\x1b[?25h\",\n /** Save cursor position */\n saveCursor: \"\\x1b[s\",\n /** Restore cursor position */\n restoreCursor: \"\\x1b[u\",\n};\n\n// =============================================================================\n// Live Visualizer Interface\n// =============================================================================\n\n/**\n * Live visualizer with real-time terminal updates.\n */\nexport interface LiveVisualizer {\n /** Process a workflow event */\n handleEvent: (event: WorkflowEvent<unknown>) => void;\n /** Process a scope event */\n handleScopeEvent: (event: ScopeStartEvent | ScopeEndEvent) => void;\n /** Process a decision event */\n handleDecisionEvent: (event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent) => void;\n /** Get current IR state */\n getIR: () => WorkflowIR;\n /** Render current state to string (without terminal output) */\n render: () => string;\n /** Start live rendering to terminal */\n start: () => void;\n /** Stop live rendering */\n stop: () => void;\n /** Force an immediate redraw */\n refresh: () => void;\n /** Reset state for a new workflow */\n reset: () => void;\n}\n\n// =============================================================================\n// Create Live Visualizer\n// =============================================================================\n\n/**\n * Create a live visualizer for real-time terminal updates.\n *\n * @example\n * ```typescript\n * const live = createLiveVisualizer({ workflowName: 'my-workflow' });\n * const workflow = createWorkflow(deps, { onEvent: live.handleEvent });\n *\n * live.start();\n * await workflow(async (step) => { ... });\n * live.stop();\n * ```\n */\nexport function createLiveVisualizer(\n options: LiveVisualizerOptions = {}\n): LiveVisualizer {\n const {\n workflowName,\n detectParallel = true,\n showTimings = true,\n showKeys = false,\n colors: customColors,\n stream = process.stdout,\n updateInterval = 100,\n } = options;\n\n const builder = createIRBuilder({ detectParallel });\n const renderer = asciiRenderer();\n\n // Render options\n const renderOptions: RenderOptions = {\n showTimings,\n showKeys,\n terminalWidth: stream.columns ?? 80,\n colors: { ...defaultColorScheme, ...customColors },\n };\n\n // State\n let isRunning = false;\n let lastOutput = \"\";\n let lastLineCount = 0;\n let throttleTimeout: ReturnType<typeof setTimeout> | null = null;\n let pendingUpdate = false;\n\n /**\n * Write to the output stream.\n */\n function write(text: string): void {\n if (stream.writable) {\n stream.write(text);\n }\n }\n\n /**\n * Clear the previous output and write new content.\n */\n function redraw(): void {\n if (!isRunning) return;\n\n const ir = getIR();\n const output = renderer.render(ir, renderOptions);\n\n // If output hasn't changed, skip redraw\n if (output === lastOutput) return;\n\n // Clear previous output\n if (lastLineCount > 0) {\n // Move cursor up and clear\n write(ANSI.cursorUp(lastLineCount));\n write(ANSI.cursorToStart);\n write(ANSI.clearToEnd);\n }\n\n // Write new output\n write(output);\n write(\"\\n\");\n\n // Track line count for next clear\n lastOutput = output;\n lastLineCount = output.split(\"\\n\").length;\n }\n\n /**\n * Schedule a throttled redraw.\n */\n function scheduleRedraw(): void {\n if (!isRunning) return;\n\n pendingUpdate = true;\n\n if (throttleTimeout === null) {\n throttleTimeout = setTimeout(() => {\n throttleTimeout = null;\n if (pendingUpdate) {\n pendingUpdate = false;\n redraw();\n }\n }, updateInterval);\n }\n }\n\n /**\n * Handle a workflow event.\n */\n function handleEvent(event: WorkflowEvent<unknown>): void {\n // Route scope events to handleScopeEvent for proper IR building\n if (event.type === \"scope_start\" || event.type === \"scope_end\") {\n handleScopeEvent(event as ScopeStartEvent | ScopeEndEvent);\n return;\n }\n\n builder.handleEvent(event);\n\n if (isRunning) {\n // Immediate redraw for start/end events, throttled for others\n if (\n event.type === \"workflow_start\" ||\n event.type === \"workflow_success\" ||\n event.type === \"workflow_error\"\n ) {\n redraw();\n } else {\n scheduleRedraw();\n }\n }\n }\n\n /**\n * Handle a scope event.\n */\n function handleScopeEvent(event: ScopeStartEvent | ScopeEndEvent): void {\n builder.handleScopeEvent(event);\n if (isRunning) {\n scheduleRedraw();\n }\n }\n\n /**\n * Handle a decision event.\n */\n function handleDecisionEvent(\n event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent\n ): void {\n builder.handleDecisionEvent(event);\n if (isRunning) {\n scheduleRedraw();\n }\n }\n\n /**\n * Get the current IR state.\n */\n function getIR(): WorkflowIR {\n const ir = builder.getIR();\n if (workflowName && !ir.root.name) {\n ir.root.name = workflowName;\n }\n return ir;\n }\n\n /**\n * Render current state to string.\n */\n function render(): string {\n return renderer.render(getIR(), renderOptions);\n }\n\n /**\n * Start live rendering.\n */\n function start(): void {\n if (isRunning) return;\n\n isRunning = true;\n lastOutput = \"\";\n lastLineCount = 0;\n\n // Hide cursor during updates\n write(ANSI.hideCursor);\n\n // Initial render\n redraw();\n }\n\n /**\n * Stop live rendering.\n */\n function stop(): void {\n if (!isRunning) return;\n\n isRunning = false;\n\n // Clear any pending throttle\n if (throttleTimeout !== null) {\n clearTimeout(throttleTimeout);\n throttleTimeout = null;\n }\n\n // Final redraw to show completed state\n const ir = getIR();\n const output = renderer.render(ir, renderOptions);\n\n if (lastLineCount > 0) {\n write(ANSI.cursorUp(lastLineCount));\n write(ANSI.cursorToStart);\n write(ANSI.clearToEnd);\n }\n\n write(output);\n write(\"\\n\");\n\n // Show cursor again\n write(ANSI.showCursor);\n }\n\n /**\n * Force an immediate redraw.\n */\n function refresh(): void {\n if (throttleTimeout !== null) {\n clearTimeout(throttleTimeout);\n throttleTimeout = null;\n }\n pendingUpdate = false;\n redraw();\n }\n\n /**\n * Reset state for a new workflow.\n */\n function reset(): void {\n builder.reset();\n lastOutput = \"\";\n lastLineCount = 0;\n }\n\n return {\n handleEvent,\n handleScopeEvent,\n handleDecisionEvent,\n getIR,\n render,\n start,\n stop,\n refresh,\n reset,\n };\n}\n","/**\n * Decision Tracker - Helper for tracking conditional logic in workflows.\n *\n * This module provides utilities to track decision points (if/switch statements)\n * so they can be visualized in workflow diagrams.\n *\n * @example\n * ```typescript\n * import { trackDecision } from '@jagreehal/workflow/visualize';\n *\n * const workflow = createWorkflow(deps, {\n * onEvent: (event) => {\n * // Pass events to visualizer\n * viz.handleEvent(event);\n * }\n * });\n *\n * await workflow(async (step) => {\n * const user = await step(fetchUser(id));\n *\n * // Track a decision point\n * const decision = trackDecision('user-role-check', {\n * condition: 'user.role === \"admin\"',\n * value: user.role\n * });\n *\n * if (user.role === 'admin') {\n * decision.takeBranch('admin', true);\n * await step(processAdminAction(user));\n * } else {\n * decision.takeBranch('user', false);\n * await step(processUserAction(user));\n * }\n *\n * decision.end();\n * });\n * ```\n */\n\nimport type {\n DecisionStartEvent,\n DecisionBranchEvent,\n DecisionEndEvent,\n} from \"./types\";\n\n// =============================================================================\n// Decision Tracker\n// =============================================================================\n\n/**\n * Options for creating a decision tracker.\n */\nexport interface DecisionTrackerOptions {\n /** Condition being evaluated (e.g., \"user.role === 'admin'\") */\n condition?: string;\n /** Value being evaluated */\n value?: unknown;\n /** Name/label for this decision point */\n name?: string;\n /** Workflow ID (auto-generated if not provided) */\n workflowId?: string;\n /** Event emitter function */\n emit?: (event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent) => void;\n}\n\n/**\n * Track a decision point in your workflow.\n *\n * Use this to annotate conditional logic (if/switch) so it appears\n * in workflow visualizations.\n *\n * @param decisionId - Unique identifier for this decision\n * @param options - Decision tracking options\n * @returns A tracker object with methods to track branches\n *\n * @example\n * ```typescript\n * const decision = trackDecision('check-role', {\n * condition: 'user.role === \"admin\"',\n * value: user.role,\n * emit: (event) => viz.handleDecisionEvent(event)\n * });\n *\n * if (user.role === 'admin') {\n * decision.takeBranch('admin', true);\n * // ... admin logic\n * } else {\n * decision.takeBranch('user', false);\n * // ... user logic\n * }\n *\n * decision.end();\n * ```\n */\nexport function trackDecision(\n decisionId: string,\n options: DecisionTrackerOptions = {}\n): DecisionTracker {\n const {\n condition,\n value,\n name,\n workflowId = crypto.randomUUID(),\n emit,\n } = options;\n\n const startTs = Date.now();\n let branchTaken: string | boolean | undefined;\n const branches: Array<{ label: string; condition?: string; taken: boolean }> = [];\n\n function takeBranch(\n label: string,\n taken: boolean,\n branchCondition?: string\n ): void {\n branches.push({ label, condition: branchCondition, taken });\n if (taken) {\n branchTaken = label;\n }\n\n emit?.({\n type: \"decision_branch\",\n workflowId,\n decisionId,\n branchLabel: label,\n condition: branchCondition,\n taken,\n ts: Date.now(),\n });\n }\n\n function end(): void {\n const durationMs = Date.now() - startTs;\n emit?.({\n type: \"decision_end\",\n workflowId,\n decisionId,\n branchTaken,\n ts: Date.now(),\n durationMs,\n });\n }\n\n // Emit start event immediately\n emit?.({\n type: \"decision_start\",\n workflowId,\n decisionId,\n condition,\n decisionValue: value,\n name,\n ts: startTs,\n });\n\n return {\n takeBranch,\n end,\n getBranchTaken: () => branchTaken,\n getBranches: () => [...branches],\n };\n}\n\n/**\n * Decision tracker instance.\n */\nexport interface DecisionTracker {\n /**\n * Mark that a branch was taken or skipped.\n * @param label - Label for this branch (e.g., \"if\", \"else\", \"case 'admin'\")\n * @param taken - Whether this branch was executed\n * @param branchCondition - Optional condition for this specific branch\n */\n takeBranch(label: string, taken: boolean, branchCondition?: string): void;\n\n /**\n * End the decision tracking.\n * Call this after all branches have been evaluated.\n */\n end(): void;\n\n /**\n * Get which branch was taken.\n */\n getBranchTaken(): string | boolean | undefined;\n\n /**\n * Get all branches (taken and skipped).\n */\n getBranches(): Array<{ label: string; condition?: string; taken: boolean }>;\n}\n\n// =============================================================================\n// Convenience Helpers\n// =============================================================================\n\n/**\n * Track a simple if/else decision.\n *\n * @example\n * ```typescript\n * const decision = trackIf('check-admin', user.role === 'admin', {\n * condition: 'user.role === \"admin\"',\n * value: user.role,\n * emit: (e) => viz.handleDecisionEvent(e)\n * });\n *\n * if (decision.condition) {\n * decision.then();\n * // admin logic\n * } else {\n * decision.else();\n * // user logic\n * }\n *\n * decision.end();\n * ```\n */\nexport function trackIf(\n decisionId: string,\n condition: boolean,\n options: Omit<DecisionTrackerOptions, \"value\"> & { value?: unknown } = {}\n): IfTracker {\n const tracker = trackDecision(decisionId, {\n ...options,\n condition: options.condition ?? String(condition),\n value: options.value ?? condition,\n });\n\n return {\n ...tracker,\n condition,\n then: () => {\n tracker.takeBranch(\"if\", true);\n },\n else: () => {\n // Mark else branch as taken (true) when the else block executes\n tracker.takeBranch(\"else\", true);\n },\n };\n}\n\n/**\n * If tracker with convenience methods.\n */\nexport interface IfTracker extends DecisionTracker {\n /** The condition value */\n condition: boolean;\n /** Mark the \"if\" branch as taken */\n then(): void;\n /** Mark the \"else\" branch as taken */\n else(): void;\n}\n\n/**\n * Track a switch statement decision.\n *\n * @example\n * ```typescript\n * const decision = trackSwitch('process-type', user.type, {\n * emit: (e) => viz.handleDecisionEvent(e)\n * });\n *\n * switch (user.type) {\n * case 'admin':\n * decision.case('admin', true);\n * // admin logic\n * break;\n * case 'user':\n * decision.case('user', true);\n * // user logic\n * break;\n * default:\n * decision.default(true);\n * // default logic\n * }\n *\n * decision.end();\n * ```\n */\nexport function trackSwitch(\n decisionId: string,\n value: unknown,\n options: Omit<DecisionTrackerOptions, \"value\"> = {}\n): SwitchTracker {\n const tracker = trackDecision(decisionId, {\n ...options,\n condition: options.condition ?? `switch(${String(value)})`,\n value,\n });\n\n return {\n ...tracker,\n value,\n case: (caseValue: string | number, taken: boolean) => {\n tracker.takeBranch(`case '${caseValue}'`, taken, `value === '${caseValue}'`);\n },\n default: (taken: boolean) => {\n tracker.takeBranch(\"default\", taken);\n },\n };\n}\n\n/**\n * Switch tracker with convenience methods.\n */\nexport interface SwitchTracker extends DecisionTracker {\n /** The value being switched on */\n value: unknown;\n /** Mark a case branch */\n case(caseValue: string | number, taken: boolean): void;\n /** Mark the default branch */\n default(taken: boolean): void;\n}\n","/**\n * Workflow Visualization Module\n *\n * Provides tools for visualizing workflow execution with color-coded\n * step states and support for parallel/race operations.\n *\n * @example\n * ```typescript\n * import { createVisualizer } from '@jagreehal/workflow/visualize';\n *\n * const viz = createVisualizer({ workflowName: 'checkout' });\n * const workflow = createWorkflow(deps, { onEvent: viz.handleEvent });\n *\n * await workflow(async (step) => {\n * await step(() => validateCart(cart), 'Validate cart');\n * await step(() => processPayment(payment), 'Process payment');\n * });\n *\n * console.log(viz.render());\n * ```\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type {\n OutputFormat,\n RenderOptions,\n ScopeEndEvent,\n ScopeStartEvent,\n DecisionStartEvent,\n DecisionBranchEvent,\n DecisionEndEvent,\n VisualizerOptions,\n WorkflowIR,\n} from \"./types\";\nimport { createIRBuilder } from \"./ir-builder\";\nimport { asciiRenderer, mermaidRenderer, defaultColorScheme } from \"./renderers\";\n\n// =============================================================================\n// Re-exports\n// =============================================================================\n\nexport * from \"./types\";\nexport { createIRBuilder, type IRBuilderOptions } from \"./ir-builder\";\nexport { asciiRenderer, mermaidRenderer, defaultColorScheme } from \"./renderers\";\nexport { detectParallelGroups, createParallelDetector, type ParallelDetectorOptions } from \"./parallel-detector\";\nexport { createLiveVisualizer, type LiveVisualizer } from \"./live-visualizer\";\nexport { trackDecision, trackIf, trackSwitch, type DecisionTracker, type IfTracker, type SwitchTracker } from \"./decision-tracker\";\n\n// =============================================================================\n// Visualizer Interface\n// =============================================================================\n\n/**\n * Workflow visualizer that processes events and renders output.\n */\nexport interface WorkflowVisualizer {\n /** Process a workflow event */\n handleEvent: (event: WorkflowEvent<unknown>) => void;\n\n /** Process a scope event (parallel/race) */\n handleScopeEvent: (event: ScopeStartEvent | ScopeEndEvent) => void;\n\n /** Process a decision event (conditional branches) */\n handleDecisionEvent: (event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent) => void;\n\n /** Get current IR state */\n getIR: () => WorkflowIR;\n\n /** Render current state using the default renderer */\n render: () => string;\n\n /** Render to a specific format */\n renderAs: (format: OutputFormat) => string;\n\n /** Reset state for a new workflow */\n reset: () => void;\n\n /** Subscribe to IR updates (for live visualization) */\n onUpdate: (callback: (ir: WorkflowIR) => void) => () => void;\n}\n\n// =============================================================================\n// Create Visualizer\n// =============================================================================\n\n/**\n * Create a workflow visualizer.\n *\n * @example\n * ```typescript\n * const viz = createVisualizer({ workflowName: 'my-workflow' });\n *\n * const workflow = createWorkflow(deps, {\n * onEvent: viz.handleEvent,\n * });\n *\n * await workflow(async (step) => { ... });\n *\n * console.log(viz.render());\n * ```\n */\nexport function createVisualizer(\n options: VisualizerOptions = {}\n): WorkflowVisualizer {\n const {\n workflowName,\n detectParallel = true,\n showTimings = true,\n showKeys = false,\n colors: customColors,\n } = options;\n\n const builder = createIRBuilder({ detectParallel });\n const updateCallbacks: Set<(ir: WorkflowIR) => void> = new Set();\n\n // Renderers\n const ascii = asciiRenderer();\n const mermaid = mermaidRenderer();\n\n // Build render options\n const renderOptions: RenderOptions = {\n showTimings,\n showKeys,\n terminalWidth: process.stdout?.columns ?? 80,\n colors: { ...defaultColorScheme, ...customColors },\n };\n\n function notifyUpdate(): void {\n if (updateCallbacks.size > 0) {\n const ir = builder.getIR();\n for (const callback of updateCallbacks) {\n callback(ir);\n }\n }\n }\n\n function handleEvent(event: WorkflowEvent<unknown>): void {\n // Route scope events to handleScopeEvent for proper IR building\n if (event.type === \"scope_start\" || event.type === \"scope_end\") {\n handleScopeEvent(event as ScopeStartEvent | ScopeEndEvent);\n return;\n }\n\n builder.handleEvent(event);\n\n // Set workflow name if provided\n if (event.type === \"workflow_start\" && workflowName) {\n // Note: We'd need to extend the builder to support setting name\n // For now, the name is passed in render options\n }\n\n notifyUpdate();\n }\n\n function handleScopeEvent(event: ScopeStartEvent | ScopeEndEvent): void {\n builder.handleScopeEvent(event);\n notifyUpdate();\n }\n\n function handleDecisionEvent(\n event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent\n ): void {\n builder.handleDecisionEvent(event);\n notifyUpdate();\n }\n\n function getIR(): WorkflowIR {\n const ir = builder.getIR();\n // Apply workflow name if provided\n if (workflowName && !ir.root.name) {\n ir.root.name = workflowName;\n }\n return ir;\n }\n\n function render(): string {\n const ir = getIR();\n return ascii.render(ir, renderOptions);\n }\n\n function renderAs(format: OutputFormat): string {\n const ir = getIR();\n\n switch (format) {\n case \"ascii\":\n return ascii.render(ir, renderOptions);\n\n case \"mermaid\":\n return mermaid.render(ir, renderOptions);\n\n case \"json\":\n return JSON.stringify(ir, null, 2);\n\n default:\n throw new Error(`Unknown format: ${format}`);\n }\n }\n\n function reset(): void {\n builder.reset();\n notifyUpdate();\n }\n\n function onUpdate(callback: (ir: WorkflowIR) => void): () => void {\n updateCallbacks.add(callback);\n return () => updateCallbacks.delete(callback);\n }\n\n return {\n handleEvent,\n handleScopeEvent,\n handleDecisionEvent,\n getIR,\n render,\n renderAs,\n reset,\n onUpdate,\n };\n}\n\n// =============================================================================\n// Convenience Functions\n// =============================================================================\n\n/**\n * Union type for all collectable/visualizable events (workflow + decision).\n */\nexport type CollectableEvent =\n | WorkflowEvent<unknown>\n | DecisionStartEvent\n | DecisionBranchEvent\n | DecisionEndEvent;\n\n/**\n * Visualize collected events (post-execution).\n *\n * Supports both workflow events (from onEvent) and decision events\n * (from trackDecision/trackIf/trackSwitch).\n *\n * @example\n * ```typescript\n * const events: CollectableEvent[] = [];\n * const workflow = createWorkflow(deps, {\n * onEvent: (e) => events.push(e),\n * });\n *\n * await workflow(async (step) => {\n * const decision = trackIf('check', condition, {\n * emit: (e) => events.push(e),\n * });\n * // ...\n * });\n *\n * console.log(visualizeEvents(events));\n * ```\n */\nexport function visualizeEvents(\n events: CollectableEvent[],\n options: VisualizerOptions = {}\n): string {\n const viz = createVisualizer(options);\n\n for (const event of events) {\n if (event.type.startsWith(\"decision_\")) {\n viz.handleDecisionEvent(event as DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent);\n } else {\n viz.handleEvent(event as WorkflowEvent<unknown>);\n }\n }\n\n return viz.render();\n}\n\n/**\n * Create an event collector for later visualization.\n *\n * Supports both workflow events (from onEvent) and decision events\n * (from trackDecision/trackIf/trackSwitch).\n *\n * @example\n * ```typescript\n * const collector = createEventCollector();\n *\n * const workflow = createWorkflow(deps, {\n * onEvent: collector.handleEvent,\n * });\n *\n * await workflow(async (step) => {\n * // Decision events can also be collected\n * const decision = trackIf('check', condition, {\n * emit: collector.handleDecisionEvent,\n * });\n * // ...\n * });\n *\n * console.log(collector.visualize());\n * ```\n */\nexport function createEventCollector(options: VisualizerOptions = {}) {\n const events: CollectableEvent[] = [];\n\n return {\n /** Handle a workflow event */\n handleEvent: (event: WorkflowEvent<unknown>) => {\n events.push(event);\n },\n\n /** Handle a decision event */\n handleDecisionEvent: (event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent) => {\n events.push(event);\n },\n\n /** Get all collected events */\n getEvents: () => [...events],\n\n /** Get workflow events only */\n getWorkflowEvents: () => events.filter((e): e is WorkflowEvent<unknown> =>\n !e.type.startsWith(\"decision_\")\n ),\n\n /** Get decision events only */\n getDecisionEvents: () => events.filter((e): e is DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent =>\n e.type.startsWith(\"decision_\")\n ),\n\n /** Clear collected events */\n clear: () => {\n events.length = 0;\n },\n\n /** Visualize collected events */\n visualize: () => {\n const viz = createVisualizer(options);\n for (const event of events) {\n if (event.type.startsWith(\"decision_\")) {\n viz.handleDecisionEvent(event as DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent);\n } else {\n viz.handleEvent(event as WorkflowEvent<unknown>);\n }\n }\n return viz.render();\n },\n\n /** Visualize in a specific format */\n visualizeAs: (format: OutputFormat) => {\n const viz = createVisualizer(options);\n for (const event of events) {\n if (event.type.startsWith(\"decision_\")) {\n viz.handleDecisionEvent(event as DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent);\n } else {\n viz.handleEvent(event as WorkflowEvent<unknown>);\n }\n }\n return viz.renderAs(format);\n },\n };\n}\n\n"],"mappings":"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","names":["formatDuration","ms","minutes","seconds","generateId","hasRealScopeNodes","nodes","node","detectParallelGroups","options","minOverlapMs","maxGapMs","stepsWithTiming","nonStepNodes","i","a","b","groups","currentGroup","step","groupStart","s","groupEnd","startedTogether","hasTrueOverlap","overlapDuration","groupedNodes","group","position","children","startTs","endTs","parallelNode","deriveGroupState","originalIndex","g","c","createParallelDetector","createIRBuilder","options","detectParallel","parallelDetection","workflowId","workflowStartTs","workflowState","workflowError","workflowDurationMs","activeSteps","scopeStack","decisionStack","currentNodes","createdAt","lastUpdatedAt","getStepId","event","generateId","addNode","node","decision","branch","firstBranch","handleEvent","id","active","handleScopeEvent","scope","deriveState","handleDecisionEvent","branchKey","existing","branches","b","children","c","getCurrentNodes","nodes","getIR","detectParallelGroups","reset","isStepNode","node","isSequenceNode","isParallelNode","isRaceNode","isDecisionNode","hasChildren","RESET","BOLD","DIM","FG_RED","FG_GREEN","FG_YELLOW","FG_BLUE","FG_GRAY","FG_WHITE","colorize","text","color","bold","dim","defaultColorScheme","getStateSymbol","state","getColoredSymbol","colors","symbol","colorByState","stripAnsi","str","BOX","padEnd","str","width","visibleLen","stripAnsi","padding","horizontalLine","title","titleText","remainingWidth","leftPad","rightPad","asciiRenderer","ir","options","colors","defaultColorScheme","innerWidth","lines","workflowName","headerTitle","bold","childLines","renderNodes","line","status","footer","colorByState","formatDuration","nodes","depth","node","isStepNode","renderStepNode","isParallelNode","renderParallelNode","isRaceNode","renderRaceNode","isDecisionNode","renderDecisionNode","symbol","getColoredSymbol","name","nameColored","dim","inputStr","outputStr","timeoutInfo","indent","mode","i","child","prefix","nestedLines","winnerSuffix","condition","decisionValue","branchTaken","branch","branchSymbol","branchColor","branchLabel","colorize","branchCondition","getStyleDefinitions","nodeCounter","generateNodeId","prefix","resetNodeCounter","escapeMermaidText","text","escapeSubgraphName","mermaidRenderer","ir","options","lines","startId","prevNodeId","child","result","renderNode","endId","endIcon","endLabel","endShape","endClass","getStyleDefinitions","node","isStepNode","renderStepNode","isParallelNode","renderParallelNode","isRaceNode","renderRaceNode","isDecisionNode","renderDecisionNode","id","label","timing","formatDuration","stateIcon","ioInfo","inputStr","outputStr","retryInfo","timeoutStr","escapedLabel","stateClass","shape","subgraphId","forkId","joinId","name","modeLabel","note","childExitIds","exitId","winnerExitId","isWinner","decisionId","condition","decisionValue","decisionLabel","branchExitIds","takenBranchExitId","branch","branchId","branchLabelText","branchLabel","branchClass","edgeLabel","prevId","ANSI","n","createLiveVisualizer","options","workflowName","detectParallel","showTimings","showKeys","customColors","stream","updateInterval","builder","createIRBuilder","renderer","asciiRenderer","renderOptions","defaultColorScheme","isRunning","lastOutput","lastLineCount","throttleTimeout","pendingUpdate","write","text","redraw","ir","getIR","output","scheduleRedraw","handleEvent","event","handleScopeEvent","handleDecisionEvent","render","start","stop","refresh","reset","trackDecision","decisionId","options","condition","value","name","workflowId","emit","startTs","branchTaken","branches","takeBranch","label","taken","branchCondition","end","durationMs","trackIf","tracker","trackSwitch","caseValue","createVisualizer","options","workflowName","detectParallel","showTimings","showKeys","customColors","builder","createIRBuilder","updateCallbacks","ascii","asciiRenderer","mermaid","mermaidRenderer","renderOptions","defaultColorScheme","notifyUpdate","ir","callback","handleEvent","event","handleScopeEvent","handleDecisionEvent","getIR","render","renderAs","format","reset","onUpdate","visualizeEvents","events","viz","createEventCollector","e"]}
|