agentfootprint-lens 0.58.1 → 0.58.2

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.
@@ -23,7 +23,12 @@ function buildStepGraphFromSnapshot(snapshot) {
23
23
  visit(snapshot.executionTree, [], ctx);
24
24
  return { nodes: ctx.nodes, edges: ctx.edges };
25
25
  }
26
- function visit(stage, parentPath, ctx) {
26
+ function visit(first, parentPath, ctx) {
27
+ for (let stage = first; stage !== void 0; stage = stage.next) {
28
+ visitOne(stage, parentPath, ctx);
29
+ }
30
+ }
31
+ function visitOne(stage, parentPath, ctx) {
27
32
  const primitiveKind = parsePrimitiveKind(stage.description);
28
33
  const isPrimitive = primitiveKind !== void 0;
29
34
  const subflowPath = stage.subflowId ? [...parentPath, stage.subflowId] : parentPath;
@@ -93,7 +98,6 @@ function visit(stage, parentPath, ctx) {
93
98
  });
94
99
  }
95
100
  }
96
- visit(stage.next, parentPath, ctx);
97
101
  }
98
102
  }
99
103
  function findFirstPrimitive(stage) {
@@ -1232,4 +1236,4 @@ export {
1232
1236
  decisionSentence,
1233
1237
  isConsentDecision
1234
1238
  };
1235
- //# sourceMappingURL=chunk-PDBBBAB4.js.map
1239
+ //# sourceMappingURL=chunk-JH5SK5E3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/buildStepGraphFromSnapshot.ts","../src/core/buildSpecTreeFromBoundary.ts","../src/core/cursor/sharedCursor.ts","../src/core/translate/helpers/makeNodeId.ts","../src/core/translate/perKind/translateAgent.ts","../src/core/translate/helpers/exitNodeId.ts","../src/core/translate/helpers/makeEdge.ts","../src/core/translate/helpers/mergeOutputs.ts","../src/core/translate/perKind/translateConditional.ts","../src/core/translate/perKind/translateLLMCall.ts","../src/core/translate/perKind/translateLoop.ts","../src/core/translate/helpers/pinUnderParent.ts","../src/core/translate/perKind/translateParallel.ts","../src/core/translate/perKind/translateSequence.ts","../src/core/translate/lensGroupTranslator.ts","../src/core/explainableShellProps.ts","../src/core/render/toReactFlow.ts","../src/react/layout/dagreLayout.ts","../src/core/render/layoutLensGraph.ts","../src/core/bugReport/issueBody.ts","../src/core/bugReport/github.ts","../src/core/artifacts/resolvers.ts","../src/core/artifacts/presented.ts","../src/core/hitl/decision.ts"],"sourcesContent":["/**\n * @deprecated FOR LIVE USE — use `LensSnapshotRecorder` instead, which\n * builds the StepGraph incrementally as the engine traverses (O(1) per\n * event, NO post-walk). This function walks the snapshot tree once\n * per call, which becomes O(N²) when invoked from a render loop.\n *\n * STILL VALID for offline / replay scenarios where you have a\n * snapshot from a completed run but no live event stream — e.g.,\n * loading a saved RuntimeSnapshot from disk to render.\n *\n * See `docs/design/lens-snapshot-recorder.md` for the full rationale\n * (the \"Law 1\" section explicitly forbids post-walking on the live path).\n *\n * `buildStepGraphFromSnapshot` — derives a Lens StepGraph from\n * footprintjs's canonical RuntimeSnapshot. Pure function, no state.\n *\n * Inputs:\n * - footprintjs RuntimeSnapshot (`runner.getLastSnapshot()`)\n *\n * Outputs:\n * - Lens StepGraph (nodes + edges) — same shape FlowchartRecorder\n * produces today, but with structural info sourced from the\n * canonical snapshot, not from typed events.\n *\n * What this function does NOT do:\n * - Decorate nodes with payload (LLM tokens, tool args, context\n * injections). That's a separate join step against typed events.\n *\n * Algorithm (recursive walk over `executionTree.next`):\n * 1. Each StageSnapshot represents one stage. Inspect its\n * `description` for composition kind:\n * - \"LLMCall: …\" → subflow node, primitiveKind=LLMCall\n * - \"Agent: …\" → subflow node, primitiveKind=Agent\n * - \"Sequence: …\" → subflow node, primitiveKind=Sequence\n * - \"Parallel: N-way fanout\" → fork node + N fork-branch nodes\n * - \"Conditional: …\" → decision node + chosen branch\n * - \"Loop: …\" → subflow node + iteration edges\n * 2. Walk `flowMessages` for control-flow transitions (next, fork\n * with `targetStage[]`, decision with chosen branch, loop).\n * 3. Recurse into `next` chain.\n */\n\nimport type { StepGraph, StepNode, StepEdge } from 'agentfootprint/observe';\n\n/** Footprintjs StageSnapshot — the runtime tree node shape. We only\n * read fields the snapshot reliably populates; `unknown` for the rest.\n * All fields optional so this matches footprintjs's RuntimeSnapshot\n * even when fields are partially populated mid-traversal. */\ninterface StageSnapshot {\n id?: string;\n runtimeStageId?: string;\n name?: string;\n description?: string;\n subflowId?: string;\n flowMessages?: ReadonlyArray<FlowMessage>;\n next?: StageSnapshot;\n}\n\ninterface FlowMessage {\n type: 'next' | 'children' | 'subflow' | 'decision' | 'loop' | string;\n description?: string;\n timestamp?: number;\n targetStage?: string | readonly string[];\n count?: number;\n}\n\ninterface RuntimeSnapshotLike {\n executionTree?: StageSnapshot;\n}\n\n/**\n * Build a StepGraph from a footprintjs snapshot. Returns an empty\n * graph (no nodes, no edges) if the snapshot is undefined or has no\n * executionTree (run hasn't started).\n */\nexport function buildStepGraphFromSnapshot(\n snapshot: RuntimeSnapshotLike | undefined,\n): StepGraph {\n if (!snapshot?.executionTree) {\n return { nodes: [], edges: [] };\n }\n const ctx: BuilderContext = {\n nodes: [],\n edges: [],\n runStartMs: snapshot.executionTree.flowMessages?.[0]?.timestamp ?? 0,\n };\n visit(snapshot.executionTree, [], ctx);\n return { nodes: ctx.nodes, edges: ctx.edges };\n}\n\ninterface BuilderContext {\n nodes: StepNode[];\n edges: StepEdge[];\n runStartMs: number;\n}\n\n/**\n * Walk one `next` chain — a LOOP, not a recursion (0.58.2). A long linear run\n * links stages by `next` one level per stage; a recursive visit hit the\n * engine's call-stack limit at ~10 000 stages in the browser, the same wall\n * `JSON.stringify` hits on the record (footprintjs 9.26.0). `parentPath` is\n * constant along the chain, so the loop is the recursion, exactly.\n */\nfunction visit(first: StageSnapshot, parentPath: readonly string[], ctx: BuilderContext): void {\n for (let stage: StageSnapshot | undefined = first; stage !== undefined; stage = stage.next) {\n visitOne(stage, parentPath, ctx);\n }\n}\n\nfunction visitOne(stage: StageSnapshot, parentPath: readonly string[], ctx: BuilderContext): void {\n const primitiveKind = parsePrimitiveKind(stage.description);\n const isPrimitive = primitiveKind !== undefined;\n const subflowPath = stage.subflowId ? [...parentPath, stage.subflowId] : parentPath;\n const startOffsetMs = relTime(stage.flowMessages?.[0]?.timestamp, ctx.runStartMs);\n const stageRid = stage.runtimeStageId ?? stage.id ?? '';\n\n // Emit one subflow node per primitive-bearing stage. Plain\n // routing/wrapper stages (no description) don't get nodes — they're\n // structural plumbing.\n if (isPrimitive) {\n const node: StepNode = {\n id: stageRid,\n kind: 'subflow',\n label: stage.name ?? stage.id ?? 'unnamed',\n startOffsetMs,\n subflowPath: subflowPath.length > 0 ? subflowPath : ['__root__'],\n primitiveKind,\n isPrimitiveBoundary: true,\n ...(primitiveKind === 'Agent' ? { isAgentBoundary: true } : {}),\n runtimeStageId: stageRid,\n };\n ctx.nodes.push(node);\n }\n\n // Walk flowMessages for control-flow transitions originating at this\n // stage. The MOST IMPORTANT one for Parallel/fork detection: the\n // `children` message carries `targetStage: [branch1, branch2, ...]`.\n if (stage.flowMessages) {\n for (const msg of stage.flowMessages) {\n if (msg.type === 'children' && Array.isArray(msg.targetStage)) {\n // Parallel fork — synthesize one fork-branch node per child.\n for (const childId of msg.targetStage) {\n const childRid = `${childId}#${stageRid}`;\n ctx.nodes.push({\n id: childRid,\n kind: 'fork-branch',\n label: childId,\n startOffsetMs: relTime(msg.timestamp, ctx.runStartMs),\n subflowPath: [...subflowPath, childId],\n runtimeStageId: childRid,\n });\n ctx.edges.push({\n id: `${stageRid}->${childRid}`,\n from: stageRid,\n to: childRid,\n kind: 'fork-branch',\n });\n }\n } else if (msg.type === 'decision' && typeof msg.targetStage === 'string') {\n // Conditional — emit a decision-branch edge to the chosen target.\n ctx.edges.push({\n id: `${stageRid}->${msg.targetStage}`,\n from: stageRid,\n to: msg.targetStage,\n kind: 'decision-branch',\n });\n } else if (msg.type === 'loop' && typeof msg.targetStage === 'string') {\n ctx.edges.push({\n id: `${stageRid}->${msg.targetStage}#loop`,\n from: stageRid,\n to: msg.targetStage,\n kind: 'loop-iteration',\n });\n }\n }\n }\n\n // Recurse into the next stage in the linear chain. The chain ends\n // when `next` is undefined (terminal stage).\n if (stage.next) {\n if (isPrimitive) {\n // Emit a `next` edge from THIS stage to the NEXT primitive node\n // we'll see (resolved when the recursion reaches it).\n const nextPrimitive = findFirstPrimitive(stage.next);\n if (nextPrimitive) {\n const nextRid = nextPrimitive.runtimeStageId ?? nextPrimitive.id ?? '';\n ctx.edges.push({\n id: `${stageRid}->${nextRid}`,\n from: stageRid,\n to: nextRid,\n kind: 'next',\n });\n }\n }\n }\n}\n\n/** Walk the next chain to find the first stage with a primitive\n * description — i.e., the next StepNode that will be emitted. */\nfunction findFirstPrimitive(stage: StageSnapshot): StageSnapshot | undefined {\n let cur: StageSnapshot | undefined = stage;\n while (cur) {\n if (parsePrimitiveKind(cur.description) !== undefined) return cur;\n cur = cur.next;\n }\n return undefined;\n}\n\nconst KNOWN_PRIMITIVES = new Set([\n 'Agent',\n 'LLMCall',\n 'Sequence',\n 'Parallel',\n 'Conditional',\n 'Loop',\n]);\n\nfunction parsePrimitiveKind(description: string | undefined): string | undefined {\n if (!description) return undefined;\n const colon = description.indexOf(':');\n if (colon < 0) return undefined;\n const prefix = description.slice(0, colon).trim();\n return KNOWN_PRIMITIVES.has(prefix) ? prefix : undefined;\n}\n\nfunction relTime(absMs: number | undefined, runStartMs: number): number {\n if (absMs === undefined) return 0;\n return Math.max(0, absMs - runStartMs);\n}\n","/**\n * buildSpecTreeFromBoundary — Phase 5 Layer 4 adapter from\n * BoundaryRecorder's commit-range index to explainable-ui's\n * `SpecNode` tree shape.\n *\n * Why this exists: footprint-explainable-ui's `specToLayout` walks a\n * tree (children-as-array → horizontal fanout; next chain → vertical\n * stack). BoundaryRecorder owns a FLAT range index. This helper\n * bridges the two — building the tree from boundary parent/child\n * relationships derived from `subflowPath`.\n *\n * Pure function. No framework imports. No React. Called from the\n * `<RunTreeFlow>` component (or any non-React adapter) on every\n * change-notify; memoized at the call site.\n *\n * See `docs/design/lens-layout-unification.md` for the full contract.\n */\n\nimport type { BoundaryRecorder, BoundaryRangeLabel } from 'agentfootprint/observe';\n\n/**\n * SpecNode — Lens-local subflow tree shape.\n *\n * Historically imported from `footprint-explainable-ui/flowchart`, but\n * v0.20+ no longer exports the type (the legacy spec-walk path was\n * removed — explainable-ui now consumes `TraceGraph` via recorders\n * instead). Lens still uses this shape internally to walk the\n * BoundaryRecorder-derived composition tree (children/next/subflow\n * structure), so we define it locally as the single source of truth.\n *\n * The `icon` field is a Lens addition — `buildSpecTreeFromBoundary`\n * stamps it from the primitive kind ('agent' / 'llm' / 'fork' / etc.)\n * so downstream renderers (`useAgentLegend`, `useCompareBranches`) can\n * dispatch on it without re-parsing the description.\n */\nexport interface SpecNode {\n name: string;\n id?: string;\n description?: string;\n icon?: string;\n children?: SpecNode[];\n next?: SpecNode;\n isSubflowRoot?: boolean;\n subflowId?: string;\n subflowName?: string;\n subflowStructure?: SpecNode;\n}\n\n/**\n * Map a BoundaryRangeLabel's primitiveKind to an explainable-ui\n * icon name. Conservative fallbacks: unknown kinds → no icon.\n * The icons are rendered by explainable-ui's StageNode component.\n */\nconst PRIMITIVE_ICON: Record<string, string> = {\n Agent: 'agent',\n LLMCall: 'llm',\n Sequence: 'sequence',\n Parallel: 'fork',\n Conditional: 'guard',\n Loop: 'loop',\n};\n\n/** Composition primitives whose children render as a horizontal fanout\n * (siblings under the same parent). When the parent has `kind:Parallel`\n * or `kind:Conditional`, its descendants go into `children[]`. */\nconst FANOUT_KINDS = new Set(['Parallel', 'Conditional']);\n\n/**\n * Build a `SpecNode` tree from the BoundaryRecorder's commit-range\n * index. The tree is rooted at a synthetic `__root__` node so\n * `specToLayout` has a single entry point.\n *\n * Algorithm:\n * 1. Get all ranges from the index (open + closed).\n * 2. Sort by depth ascending — parents always processed before children.\n * 3. Build a `byPath` index keyed by the FULL subflowPath (joined) so\n * parent lookup is O(1) and immune to sibling-name collisions\n * (two `legal` branches under different parents stay distinct).\n * 4. Attach each label to its parent's `children[]` (parent is a\n * fanout kind — Parallel / Conditional) OR to its `next` chain\n * (Sequence-like). Fanout-vs-sequence is read from the parent's\n * OWN `primitiveKind`, not re-parsed from `description`.\n * 5. Return the root.\n *\n * Returns a tree with `children` only if any ranges exist. Empty index\n * → tree with no children (renders as a single `__root__` node).\n */\nexport function buildSpecTreeFromBoundary(boundary: BoundaryRecorder): SpecNode {\n // The boundary index intentionally captures EVERY subflow — domain\n // primitives (Agent / LLMCall / Parallel / Sequence / Conditional /\n // Loop) AND internal plumbing (slot subflows that compose LLM context:\n // sf-system-prompt / sf-messages / sf-tools; routing subflows like\n // sf-injection-engine, sf-tool-calls, sf-cache-decision). The slider's\n // time-travel queries need them all.\n //\n // The user-facing flowchart should show ONLY domain boundaries.\n // Filter rule:\n // - `primitiveKind` set → domain boundary → keep\n // - `slotKind` set → slot internal → drop\n // - `isAgentInternal` → routing plumbing → drop\n // - everything else → not a domain step → drop\n const all = boundary.boundaryIndex\n .overlapping(0, Number.MAX_SAFE_INTEGER)\n .filter((entry) => {\n const label = entry.label as {\n primitiveKind?: string;\n slotKind?: string;\n isAgentInternal?: boolean;\n };\n if (!label.primitiveKind) return false;\n if (label.slotKind) return false;\n if (label.isAgentInternal) return false;\n return true;\n });\n\n const root: MutableSpecNode = {\n name: 'Run',\n id: '__root__',\n children: [],\n };\n // Path-keyed index. Keys are the joined subflowPath, e.g.\n // `'__root__'`, `'__root__/committee'`, `'__root__/committee/legal'`.\n // Two siblings with the SAME display name (`'legal'`) sit under\n // different parents → different joined paths → no collision.\n // Lookup is O(1) regardless of tree size or depth.\n const byPath = new Map<string, MutableSpecNode>();\n byPath.set('__root__', root);\n // runtimeStageId dedup — same boundary may appear twice (open + closed\n // snapshots from `overlapping(0, MAX)`). Keep the first one.\n const seenRid = new Set<string>(['__root__#0']);\n\n // Sort by depth ascending so parents always exist when we attach\n // children. Stable sort preserves insertion order within same depth,\n // which matters for fanout siblings — they render left-to-right in\n // the order they entered the recorder.\n const sorted = [...all].sort((a, b) => labelDepth(a.label) - labelDepth(b.label));\n\n for (const entry of sorted) {\n const label = entry.label;\n const rid = label.runtimeStageId;\n if (seenRid.has(rid)) continue;\n // Defensive: skip labels with an empty/missing subflowPath — they\n // cannot be placed in the tree and must not corrupt the byPath\n // index. (BoundaryRecorder normalizes to a non-empty array today,\n // but the helper guards against future contract drift.)\n if (!label.subflowPath || label.subflowPath.length === 0) continue;\n\n seenRid.add(rid);\n const node: MutableSpecNode = toSpecNode(label);\n\n // The LEAF of the path is THIS node. Its parent's path is the\n // prefix without the last segment.\n const pathKey = label.subflowPath.join('/');\n const parentKey = label.subflowPath.slice(0, -1).join('/');\n byPath.set(pathKey, node);\n\n // Single-element subflowPath (depth 0, e.g. the root) means no\n // parent; everything else falls back to root if the named parent\n // isn't registered (out-of-order arrival under a non-buggy\n // engine shouldn't happen — sort guarantees parent first).\n const parent = parentKey ? (byPath.get(parentKey) ?? root) : root;\n\n if (isFanoutKind(parent.__kind)) {\n // Fanout parent → append to children[] for horizontal layout.\n if (!parent.children) parent.children = [];\n parent.children.push(node);\n } else {\n // Sequence-like parent → chain via `next` so layout stacks vertically.\n attachToNextChain(parent, node);\n }\n }\n\n return root;\n}\n\n// ─── Internals ────────────────────────────────────────────────────\n\n/** Internal — mutable shadow of SpecNode for the construction phase.\n * Carries `__kind` so we can decide fanout-vs-sequence from the\n * PARENT's own primitiveKind (read directly off its label) instead of\n * re-parsing `description`. `__kind` is intentionally private to this\n * module — it does not appear on the wire SpecNode shape. */\ninterface MutableSpecNode extends SpecNode {\n children?: MutableSpecNode[];\n next?: MutableSpecNode;\n __kind?: string;\n}\n\nfunction labelDepth(label: BoundaryRangeLabel): number {\n return label.depth ?? 0;\n}\n\nfunction isFanoutKind(kind: string | undefined): boolean {\n return kind !== undefined && FANOUT_KINDS.has(kind);\n}\n\nfunction toSpecNode(label: BoundaryRangeLabel): MutableSpecNode {\n const primitiveKind = (label as { primitiveKind?: string }).primitiveKind;\n const subflowName = (label as { subflowName?: string }).subflowName;\n const node: MutableSpecNode = {\n name: subflowName ?? label.runtimeStageId,\n id: label.runtimeStageId,\n };\n if (primitiveKind && PRIMITIVE_ICON[primitiveKind]) {\n node.icon = PRIMITIVE_ICON[primitiveKind];\n }\n if (primitiveKind) {\n // Keep `description` for the visible \"Kind: Name\" subtitle.\n node.description = `${primitiveKind}: ${node.name}`;\n // Internal field — drives fanout-vs-sequence decisions in\n // `buildSpecTreeFromBoundary`. Reading it from the label directly\n // (vs re-parsing the description string) means the layout decision\n // does not depend on description formatting and survives custom\n // descriptions / localized strings unchanged.\n node.__kind = primitiveKind;\n }\n const subflowId = (label as { subflowId?: string }).subflowId;\n if (subflowId) {\n node.subflowId = subflowId;\n }\n return node;\n}\n\n/** Walk to the end of a Sequence-like chain and append `node` via\n * the `next` pointer. Builds the linear-chain layout. */\nfunction attachToNextChain(parent: MutableSpecNode, node: MutableSpecNode): void {\n // Root uses children[] always (the run is a container, not a step).\n if (parent.id === '__root__') {\n if (!parent.children) parent.children = [];\n parent.children.push(node);\n return;\n }\n let cur: MutableSpecNode = parent;\n while (cur.next) cur = cur.next;\n cur.next = node;\n}\n","/**\n * sharedCursor — ONE address, every axis.\n *\n * A host that mounts several lenses over one recording keeps ONE cursor. The\n * lenses draw different axes — the commit axis (every executed stage) and\n * the milestone axis (the agent's own moments) — so what the host holds must\n * be an ADDRESS on the record, never a step on an axis: a step is a fact\n * about one axis, an address is a fact about the run.\n *\n * The law, in three sentences. A tab DERIVES its step from the address\n * (`stepForAddress`). Only a MOVER changes the address (`moveTo` hands the\n * landed position's address back). A visit to a coarser axis and back lands\n * on the same commit, because the address was never rewritten by the visit.\n *\n * The step an axis derives is the library's own ladder: the exact stage when\n * the axis has it (`stepForRuntimeStageId`), else the stop that CONTAINS the\n * commit — the last stop at or before it (`stepForCommitIdx`) — else `-1`,\n * which `lensCursorFrom` reads as \"no position on this axis\" (an empty\n * reading that says so; nothing is nudged onto a neighbour).\n *\n * Headless: no React, no state. `useSharedCursor` (react/) holds the address\n * and hands this out per axis. See src/core/cursor/README.md.\n */\nimport type { CursorPosition } from '../group/cursorPositionsAtDrill.js';\nimport { stepForCommitIdx } from '../group/stepForCommitIdx.js';\nimport { stepForRuntimeStageId } from '../group/stepForRuntimeStageId.js';\nimport { lensCursorFrom, type LensCursor } from './lensCursor.js';\n\n/** Where THE cursor stands — on the record, not on an axis. */\nexport interface CursorAddress {\n readonly runtimeStageId: string;\n readonly commitIdx: number;\n /**\n * The subflow the address is read inside — `scrubAxisFor`'s `drillPath`.\n * Absent = the root log. Part of the address because a subflow keeps its\n * own log: the same commit index names a different stage inside a mount.\n */\n readonly drillPath?: readonly string[];\n}\n\n/** The address a position stands at, carrying the drill path it was read under. */\nexport function addressOf(position: CursorPosition, drillPath?: readonly string[]): CursorAddress {\n return Object.freeze({\n runtimeStageId: position.runtimeStageId,\n commitIdx: position.commitIdx,\n ...(drillPath !== undefined && drillPath.length > 0 ? { drillPath } : {}),\n });\n}\n\n/**\n * The step `positions` derives for `address`: the stop standing at BOTH the\n * stage and the commit, else the exact stage (the library's own ladder),\n * else the stop that contains the commit, else `-1`.\n *\n * Why the first rung: an axis can hold several stops on ONE stage — a\n * milestone axis stops at a route decision and at the answer the same\n * stage produced, one commit apart — so the stage name alone is ambiguous\n * and the commit index is what tells them apart.\n */\nexport function stepForAddress(positions: readonly CursorPosition[], address: CursorAddress): number {\n if (address.runtimeStageId !== '') {\n const both = positions.findIndex(\n (p) => p.runtimeStageId === address.runtimeStageId && p.commitIdx === address.commitIdx,\n );\n if (both >= 0) return both;\n const exact = stepForRuntimeStageId(positions, address.runtimeStageId);\n if (exact >= 0) return exact;\n }\n return stepForCommitIdx(positions, address.commitIdx);\n}\n\nconst ROOT: readonly string[] = Object.freeze([]);\n\nfunction sameDrill(a: readonly string[] | undefined, b: readonly string[]): boolean {\n const x = a ?? ROOT;\n return x.length === b.length && x.every((seg, i) => seg === b[i]);\n}\n\n/**\n * A `LensCursor` over `positions` — the axis read under `axisDrillPath` —\n * whose reading is DERIVED from `address` and whose `moveTo` hands the landed\n * position's address (under that same drill path) to `onMove` — the one\n * funnel. It holds nothing: call it again with the new address.\n *\n * ACROSS MOUNTS: a subflow keeps its own log, so a commit index from one\n * drill path names a different stage under another. When the address was\n * read under a different drill path than this axis, only the exact stage\n * lookup applies (stage ids are unique across the whole run); there is no\n * commit fallback, and an address the axis cannot hold reads as no position.\n */\nexport function cursorForAddress(\n positions: readonly CursorPosition[],\n address: CursorAddress,\n onMove: (next: CursorAddress) => void,\n axisDrillPath: readonly string[] = ROOT,\n): LensCursor {\n const step = sameDrill(address.drillPath, axisDrillPath)\n ? stepForAddress(positions, address)\n : address.runtimeStageId === ''\n ? -1\n : stepForRuntimeStageId(positions, address.runtimeStageId);\n return lensCursorFrom(positions, step, (n: number) => {\n if (positions.length === 0) return;\n const landed = positions[Math.min(Math.max(Math.trunc(n), 0), positions.length - 1)];\n if (landed !== undefined) onMove(addressOf(landed, axisDrillPath));\n });\n}\n","/**\n * makeNodeId — stable, collision-free node id derivation for\n * `LensNode.id`.\n *\n * Layer 1 (helpers, pure) / Lens v0.1 translator pipeline.\n *\n * Why a dedicated helper\n * ──────────────────────\n * Per-kind translators need deterministic ids that survive across\n * re-builds AND don't collide when the same `GroupMetadata.id`\n * string appears at different composition levels (e.g., two\n * sub-Parallels both named `'committee'` under different parents).\n * Centralising the rule keeps the per-kind translators free of\n * \"did I get the prefix right\" mistakes and gives one canonical\n * shape for tests to assert against.\n *\n * Convention\n * ──────────\n * Top-level node: `<kindLowerCase>:<id>` e.g., `parallel:committee`\n * Member of a parent: `<parentNodeId>/<memberId>` e.g., `parallel:committee/legal`\n *\n * The `<parentNodeId>` form is what a caller passes when stamping\n * children — it already includes its own prefix, so collisions\n * across composition trees are impossible.\n *\n * Pure function — no closures, no module state.\n */\n\nimport type { GroupKind } from 'agentfootprint';\n\n/** Build a top-level node id from the composition kind + id. */\nexport function makeRootNodeId(kind: GroupKind, id: string): string {\n return `${kind.toLowerCase()}:${id}`;\n}\n\n/**\n * Build a child node id rooted under a parent node. The parent's id is\n * passed verbatim — it already contains its own kind prefix so the\n * resulting id is collision-free across composition trees.\n */\nexport function makeChildNodeId(parentNodeId: string, memberId: string): string {\n return `${parentNodeId}/${memberId}`;\n}\n","/**\n * translateAgent — `Agent` GroupMetadata → `LensGroupOutput`.\n *\n * Layer 2 (per-kind translator, pure) / Lens v0.1 translator pipeline.\n *\n * What it emits\n * ─────────────\n * ONE `stage` node carrying the Agent's `extra` (slots, toolNames,\n * maxIterations) as `metadata`. No edges. `rootNodeId` points at\n * the single node so a parent composition can attach control-flow\n * edges to it.\n *\n * Why a leaf node (not a compound group)\n * ──────────────────────────────────────\n * Agent's slots (SystemPrompt / Messages / Tools) and tool list\n * render INSIDE the Agent card itself in Lens v0.1 — the\n * slot/tool UI is a per-card concern, not a compound-graph\n * concern. The Agent's iteration loop is a runtime artifact\n * (visualised via timeline / step recorder), not a graph\n * topology element here.\n *\n * The whole point of Lens's three render boxes (Parallel / Agent /\n * LLMCall) is that an Agent card opens to its detail view on drill-\n * in; the card itself stays as one graph node.\n *\n * Pure function — no closures, no module state. Member array is\n * always empty for Agent (`buildUIGroupMetadata` returns\n * `members: []`); the translator does not iterate it.\n */\n\nimport type { GroupMetadata } from 'agentfootprint';\nimport { makeRootNodeId } from '../helpers/makeNodeId.js';\nimport type { LensGroupOutput, LensNode } from '../types.js';\n\nexport function translateAgent(metadata: GroupMetadata): LensGroupOutput {\n if (metadata.kind !== 'Agent') {\n throw new TypeError(\n `translateAgent: expected GroupMetadata.kind = 'Agent', got '${metadata.kind}'`,\n );\n }\n const id = makeRootNodeId('Agent', metadata.id);\n const node: LensNode = {\n id,\n kind: 'stage',\n label: metadata.name,\n primitiveKind: 'Agent',\n ...(metadata.extra !== undefined && { metadata: metadata.extra }),\n };\n return {\n nodes: [node],\n edges: [],\n rootNodeId: id,\n exitNodeId: id,\n };\n}\n","/**\n * exitNodeIdOf — resolve the effective exit node id of a\n * `LensGroupOutput`. Returns `exitNodeId` when set, otherwise\n * `rootNodeId` (the default for leaves and entry-only compositions).\n *\n * Layer 1 (helpers, pure) / Lens v0.1 translator pipeline.\n *\n * Used by chain-style translators (Sequence, Loop) when wiring\n * `next` edges so they target the inner composition's true exit\n * instead of its entry. Centralising the resolution keeps every\n * per-kind translator using the same default rule and frees them\n * from re-asserting the null-coalesce pattern.\n *\n * Pure function — no closures, no module state.\n */\n\nimport type { LensGroupOutput } from '../types.js';\n\nexport function exitNodeIdOf(output: LensGroupOutput): string {\n return output.exitNodeId ?? output.rootNodeId;\n}\n","/**\n * makeEdge — factory for `LensEdge` with deterministic id derivation.\n *\n * Layer 1 (helpers, pure) / Lens v0.1 translator pipeline.\n *\n * Why a dedicated factory\n * ───────────────────────\n * Edge ids must be globally unique within a `LensGroupOutput` (xyflow\n * keys edges by `id` for diff). Per-kind translators previously had to\n * roll their own id strings, leaking the \"did I encode kind + source\n * + target consistently\" responsibility across the codebase. This\n * helper centralises the rule so every edge id is predictable and\n * collision-free.\n *\n * Convention\n * ──────────\n * `<kind>:<source>->\\<target>` e.g., `next:seed->merge`\n * `<kind>:<source>->\\<target>#<n>` when N edges share endpoints\n *\n * The optional `#N` disambiguator handles cases where the same logical\n * edge appears twice (rare; e.g., loop-iteration self-edges across\n * two iteration contexts). Callers pass `n` explicitly — the helper\n * does NOT track state.\n *\n * Pure function — no closures, no module state.\n */\n\nimport type { LensEdge } from '../types.js';\n\n/**\n * Build a `LensEdge` with a deterministic id from kind + endpoints.\n * Optional `n` disambiguates collisions when the same logical edge\n * appears more than once.\n */\nexport function makeEdge(\n kind: LensEdge['kind'],\n source: string,\n target: string,\n options: { label?: string; n?: number } = {},\n): LensEdge {\n const idCore = `${kind}:${source}->${target}`;\n const id = options.n !== undefined ? `${idCore}#${options.n}` : idCore;\n return {\n id,\n source,\n target,\n kind,\n ...(options.label !== undefined && { label: options.label }),\n };\n}\n","/**\n * mergeOutputs — fold N `LensGroupOutput`s into one.\n *\n * Layer 1 (helpers, pure) / Lens v0.1 translator pipeline.\n *\n * Why a dedicated fold\n * ────────────────────\n * Compositions with multiple members (Parallel, Sequence,\n * Conditional) each produce one `LensGroupOutput` per member. The\n * parent composition merges them — concatenating nodes + edges and\n * preserving order. Centralising the fold means every per-kind\n * translator follows the same merge semantics (concat, no dedup, no\n * reorder) so consumers can reason about the final graph from any\n * translator output without surprise.\n *\n * Identity\n * ────────\n * `mergeOutputs([])` returns the EMPTY output (no nodes, no edges,\n * empty rootNodeId). Callers must NOT rely on this empty form for\n * semantic meaning — they own picking a real `rootNodeId` AFTER the\n * fold (e.g., the parent container's id). The empty `rootNodeId`\n * is a sentinel: any caller producing a 0-member parent is\n * probably mis-modeling its composition.\n *\n * Order preservation (locked)\n * ───────────────────────────\n * Nodes appear in the order they're encountered (depth-first by\n * caller). xyflow renders nodes in array order — preserving the\n * composition's natural ordering means Lens defaults to \"left-to-\n * right by declaration\" which matches developer mental models.\n *\n * Dev-mode collision guard\n * ────────────────────────\n * When footprintjs `isDevMode()` is on, the fold asserts that node\n * ids and edge ids are globally unique across the merged subgraphs.\n * Duplicate ids would silently produce a malformed xyflow graph\n * (xyflow keys both nodes and edges by id; duplicates cause\n * rendering and diff surprises that are hard to debug). The check\n * is gated on dev mode so production paths pay zero overhead, in\n * line with the footprintjs convention (CLAUDE.md → \"Dev Mode\").\n * Collision sources we have seen in practice:\n *\n * - two sibling compositions sharing the same caller-supplied id\n * - a nested Loop emitting a duplicate `loop-iteration` self-edge\n * whose endpoints alias an outer loop's body root\n * - a Sequence whose first member's `rootNodeId` collides with\n * another sibling's leading node\n *\n * Production callers can opt in to the guard via `enableDevMode()`.\n *\n * Pure function — no closures, no module state.\n */\n\nimport { isDevMode } from 'footprintjs';\nimport type { LensGroupOutput, LensEdge, LensNode } from '../types.js';\n\n/**\n * Concatenate N outputs' nodes + edges into a single output. The\n * caller supplies the `rootNodeId` AFTER the fold (typically the\n * parent composition's container id; for a flat fold with no\n * container, the lead member's `rootNodeId`).\n */\nexport function mergeOutputs(\n outputs: readonly LensGroupOutput[],\n rootNodeId: string,\n): LensGroupOutput {\n const nodes: LensNode[] = [];\n const edges: LensEdge[] = [];\n for (const o of outputs) {\n for (const n of o.nodes) nodes.push(n);\n for (const e of o.edges) edges.push(e);\n }\n if (isDevMode()) assertNoCollisions(nodes, edges);\n return { nodes, edges, rootNodeId };\n}\n\nfunction assertNoCollisions(\n nodes: readonly LensNode[],\n edges: readonly LensEdge[],\n): void {\n const nodeIds = new Set<string>();\n for (const n of nodes) {\n if (nodeIds.has(n.id)) {\n throw new Error(\n `mergeOutputs: duplicate node id '${n.id}' detected during fold. ` +\n `Cause: two sibling compositions share the same caller-supplied id, ` +\n `or a nested composition aliases its parent's rootNodeId. Disambiguate ` +\n `the upstream composition ids.`,\n );\n }\n nodeIds.add(n.id);\n }\n const edgeIds = new Set<string>();\n for (const e of edges) {\n if (edgeIds.has(e.id)) {\n throw new Error(\n `mergeOutputs: duplicate edge id '${e.id}' detected during fold. ` +\n `Cause: nested compositions emit the same control-flow edge (commonly ` +\n `a self-edge in nested loops). Use makeEdge's 'n' disambiguator at the ` +\n `inner level.`,\n );\n }\n edgeIds.add(e.id);\n }\n}\n","/**\n * translateConditional — `Conditional` GroupMetadata → `LensGroupOutput`.\n *\n * Layer 2 (per-kind translator, pure) / Lens v0.1 translator pipeline.\n *\n * What it emits\n * ─────────────\n * ONE synthetic `stage` node (the decision point) carrying the\n * conditional's `extra` (`fallbackId`) as `metadata`, plus each\n * branch's subgraph, plus N `decision-branch` edges from the\n * decision point to each branch's `rootNodeId`. The decision\n * point's id is `conditional:<id>`. The edge for the fallback\n * branch is labelled `'<memberId> (default)'` so the renderer\n * can highlight it without reading the metadata bag.\n *\n * Why a synthetic decision node\n * ─────────────────────────────\n * xyflow needs a concrete source for every edge. Conditional has\n * no caller-supplied node to serve as that source (the runtime\n * decision is data, not a node) — so we synthesise one. It\n * renders as a small diamond / \"?\" stage in the default theme,\n * matching the convention readers expect from BPMN-style\n * flowcharts.\n *\n * The decision node is NOT a compound box: only Parallel / Agent /\n * LLMCall get those (locked Lens v0.1 architecture). Conditional's\n * visual presence is the decision point + the fanout edges.\n *\n * Pure function — no closures, no module state.\n */\n\nimport type { GroupMetadata } from 'agentfootprint';\nimport { exitNodeIdOf } from '../helpers/exitNodeId.js';\nimport { makeEdge } from '../helpers/makeEdge.js';\nimport { makeRootNodeId } from '../helpers/makeNodeId.js';\nimport { mergeOutputs } from '../helpers/mergeOutputs.js';\nimport type { LensEdge, LensGroupOutput, LensNode } from '../types.js';\nimport type { MemberResolver } from './MemberResolver.js';\n\nexport function translateConditional(\n metadata: GroupMetadata,\n resolve: MemberResolver,\n): LensGroupOutput {\n if (metadata.kind !== 'Conditional') {\n throw new TypeError(\n `translateConditional: expected GroupMetadata.kind = 'Conditional', got '${metadata.kind}'`,\n );\n }\n if (metadata.members.length === 0) {\n throw new RangeError(\n `translateConditional: Conditional '${metadata.id}' has zero branches — caller bug.`,\n );\n }\n\n const decisionId = makeRootNodeId('Conditional', metadata.id);\n // Suffix synthetic ids with `/converge` so they're guaranteed\n // distinct from any caller-supplied composition id.\n const convergeId = `${decisionId}/converge`;\n const fallbackId =\n metadata.extra !== undefined && typeof metadata.extra['fallbackId'] === 'string'\n ? (metadata.extra['fallbackId'] as string)\n : undefined;\n\n const decisionNode: LensNode = {\n id: decisionId,\n kind: 'stage',\n label: metadata.name,\n primitiveKind: 'Conditional',\n ...(metadata.extra !== undefined && { metadata: metadata.extra }),\n };\n\n // Synthetic Converge tail node — represents the join after the\n // chosen branch completes. Mirrors the engine's runtime semantics:\n // exactly one branch runs, and execution converges to a single\n // point before continuing.\n const convergeNode: LensNode = {\n id: convergeId,\n kind: 'stage',\n label: 'converge',\n primitiveKind: 'Conditional',\n metadata: { synthetic: 'converge' },\n };\n\n const branchOutputs = metadata.members.map(resolve);\n const merged = mergeOutputs(branchOutputs, decisionId);\n\n const fanoutEdges: LensEdge[] = metadata.members.map((m, i) => {\n const branchOut = branchOutputs[i]!;\n const isFallback = fallbackId !== undefined && m.memberId === fallbackId;\n const label = isFallback ? `${m.memberId} (default)` : m.memberId;\n return makeEdge('decision-branch', decisionId, branchOut.rootNodeId, {\n label,\n });\n });\n\n // Each branch's exit → converge. `next` kind (not decision-branch)\n // because the fan-IN side is purely sequential — the decision\n // already happened at the decision node.\n const joinEdges: LensEdge[] = branchOutputs.map((b) =>\n makeEdge('next', exitNodeIdOf(b), convergeId),\n );\n\n return {\n nodes: [decisionNode, ...merged.nodes, convergeNode],\n edges: [...merged.edges, ...fanoutEdges, ...joinEdges],\n rootNodeId: decisionId,\n exitNodeId: convergeId,\n };\n}\n","/**\n * translateLLMCall — `LLMCall` GroupMetadata → `LensGroupOutput`.\n *\n * Layer 2 (per-kind translator, pure) / Lens v0.1 translator pipeline.\n *\n * What it emits\n * ─────────────\n * ONE `stage` node carrying the LLMCall's slot list as `metadata`.\n * No edges (leaves are terminal). The output's `rootNodeId` points\n * at this single node so a parent composition can attach control-\n * flow edges to it.\n *\n * Why a leaf node (not a compound group)\n * ──────────────────────────────────────\n * LLMCall's slots (SystemPrompt / Messages / Tools) render INSIDE\n * the stage card itself in Lens v0.1 — the slot UI is a per-card\n * concern, not a compound-graph concern. Translating slots into\n * xyflow child nodes would scatter them across the graph and break\n * the locked \"three boxes only\" rendering rule (Parallel / Agent /\n * LLMCall).\n *\n * Pure function — no closures, no module state. Member array is\n * always empty for LLMCall (`buildUIGroupMetadata` returns\n * `members: []`); the translator does not iterate it.\n */\n\nimport type { GroupMetadata } from 'agentfootprint';\nimport { makeRootNodeId } from '../helpers/makeNodeId.js';\nimport type { LensGroupOutput, LensNode } from '../types.js';\n\nexport function translateLLMCall(metadata: GroupMetadata): LensGroupOutput {\n if (metadata.kind !== 'LLMCall') {\n throw new TypeError(\n `translateLLMCall: expected GroupMetadata.kind = 'LLMCall', got '${metadata.kind}'`,\n );\n }\n const id = makeRootNodeId('LLMCall', metadata.id);\n const node: LensNode = {\n id,\n kind: 'stage',\n label: metadata.name,\n primitiveKind: 'LLMCall',\n ...(metadata.extra !== undefined && { metadata: metadata.extra }),\n };\n return {\n nodes: [node],\n edges: [],\n rootNodeId: id,\n exitNodeId: id,\n };\n}\n","/**\n * translateLoop — `Loop` GroupMetadata → `LensGroupOutput`.\n *\n * Layer 2 (per-kind translator, pure) / Lens v0.1 translator pipeline.\n *\n * What it emits\n * ─────────────\n * The body's subgraph unchanged, plus ONE self-edge of kind\n * `loop-iteration` from the body's `rootNodeId` back to itself.\n * The self-edge label encodes the loop's iteration budget (and\n * optional wallclock budget) so the renderer can show \"max N\" /\n * \"max N · 30s\" without having to read the edge's metadata bag.\n *\n * Why no own container\n * ────────────────────\n * Loop is a control-flow decoration on its body, not a visual\n * cluster. Wrapping the body in a \"Loop box\" would force the\n * renderer to draw an extra frame on every loop, which the locked\n * Lens v0.1 architecture (`memory/lens_v0_1_one_cursor_architecture.md`)\n * rejects — only Parallel / Agent / LLMCall get boxes.\n *\n * Why label-encode, not separate-edge-metadata\n * ────────────────────────────────────────────\n * v0.1 doesn't need programmatic access to a Loop's iteration\n * budget from the rendered graph — the budget is already\n * visible in the agentfootprint runner's snapshot. The label\n * keeps the visualisation self-contained without inflating\n * `LensEdge` with a metadata bag we'd only fill for this one\n * kind. YAGNI applies until a renderer requires it.\n *\n * Pure function — no closures, no module state.\n */\n\nimport type { GroupMetadata } from 'agentfootprint';\nimport { exitNodeIdOf } from '../helpers/exitNodeId.js';\nimport { makeEdge } from '../helpers/makeEdge.js';\nimport type { LensGroupOutput } from '../types.js';\nimport type { MemberResolver } from './MemberResolver.js';\n\nfunction buildLoopLabel(extra: Readonly<Record<string, unknown>> | undefined): string {\n if (extra === undefined) return 'iterate';\n const maxIterations = extra['maxIterations'];\n const maxWallclockMs = extra['maxWallclockMs'];\n const parts: string[] = [];\n if (typeof maxIterations === 'number') parts.push(`max ${maxIterations}`);\n if (typeof maxWallclockMs === 'number') parts.push(`${Math.round(maxWallclockMs / 1000)}s`);\n return parts.length > 0 ? parts.join(' · ') : 'iterate';\n}\n\nexport function translateLoop(\n metadata: GroupMetadata,\n resolve: MemberResolver,\n): LensGroupOutput {\n if (metadata.kind !== 'Loop') {\n throw new TypeError(\n `translateLoop: expected GroupMetadata.kind = 'Loop', got '${metadata.kind}'`,\n );\n }\n if (metadata.members.length !== 1) {\n throw new RangeError(\n `translateLoop: Loop '${metadata.id}' must have exactly 1 member (the body), got ${metadata.members.length}.`,\n );\n }\n\n const body = resolve(metadata.members[0]!);\n // The loop-iteration self-edge goes from body's EXIT back to body's\n // root — capturing \"after the body finishes, run it again\". For\n // single-stage bodies exit == root and the edge degenerates into a\n // self-loop; for chain bodies (Loop of Sequence) the back-edge\n // points from the last step's exit to the first step's root, which\n // is the correct visual semantic.\n const selfEdge = makeEdge(\n 'loop-iteration',\n exitNodeIdOf(body),\n body.rootNodeId,\n { label: buildLoopLabel(metadata.extra) },\n );\n\n return {\n nodes: body.nodes,\n edges: [...body.edges, selfEdge],\n rootNodeId: body.rootNodeId,\n exitNodeId: exitNodeIdOf(body),\n };\n}\n","/**\n * pinUnderParent — set `parentId` on every TOP-LEVEL node of a child\n * output so xyflow renders the child inside the parent's compound\n * container.\n *\n * Layer 1 (helpers, pure) / Lens v0.1 translator pipeline.\n *\n * Why \"all top-level nodes\" (not just the root)\n * ─────────────────────────────────────────────\n * Top-level = \"no `parentId` set in the child output\". That nicely\n * subsumes both compositional shapes:\n *\n * 1. Child has its OWN container (Parallel / Agent / LLMCall)\n * ─ the container is the only top-level node; the container's\n * internal members already carry `parentId: container`.\n * Result: only the container is re-pinned under the new\n * parent, preserving the inner compound structure.\n *\n * 2. Child has NO own container (Sequence / Loop / Conditional)\n * ─ all of the child's nodes are top-level. xyflow needs each\n * one to live INSIDE the parent's compound box, so every\n * top-level node gets the new `parentId`.\n *\n * This matches xyflow's compound model: `parentId` is single-level,\n * and a node renders inside whichever container its `parentId`\n * points to. We never overwrite an already-set `parentId`, which\n * would otherwise re-parent grandchildren away from their proper\n * compound box.\n *\n * Why a new output (not in-place mutation)\n * ────────────────────────────────────────\n * `LensGroupOutput` is documented as reference-stable. Mutating an\n * input output would silently change a value the runner has memoised\n * in its `uiGroupCache`. Returning a new output preserves the\n * runner-side memoisation invariant.\n *\n * Pure function — no closures, no module state.\n */\n\nimport type { LensGroupOutput, LensNode } from '../types.js';\n\n/**\n * Return a new `LensGroupOutput` identical to `child` except every\n * TOP-LEVEL node (no `parentId`) now carries `parentId: parentNodeId`.\n * Nodes that already carry a `parentId` pass through unchanged so\n * grandchildren stay pinned inside their proper inner container.\n *\n * `child.rootNodeId` is preserved verbatim — it remains the semantic\n * entry point for parent compositions wiring control-flow edges.\n */\nexport function pinUnderParent(\n child: LensGroupOutput,\n parentNodeId: string,\n): LensGroupOutput {\n const nodes: LensNode[] = child.nodes.map((n) =>\n n.parentId === undefined ? { ...n, parentId: parentNodeId } : n,\n );\n return {\n nodes,\n edges: child.edges,\n rootNodeId: child.rootNodeId,\n };\n}\n","/**\n * translateParallel — `Parallel` GroupMetadata → `LensGroupOutput`.\n *\n * Layer 2 (per-kind translator, pure) / Lens v0.1 translator pipeline.\n *\n * What it emits\n * ─────────────\n * ONE compound `group` node (the Parallel container) carrying\n * `extra.mergeStrategy` as `metadata`, plus each branch's\n * subgraph PINNED inside the container via `pinUnderParent`,\n * plus N `fork-branch` edges from the container to each branch's\n * `rootNodeId`. Container node id is `parallel:<id>`. Container\n * appears FIRST in the nodes array so xyflow sees the parent\n * before its children (xyflow renders in array order).\n *\n * Why a compound container\n * ────────────────────────\n * Parallel is one of the THREE rendering boxes in Lens v0.1\n * (Parallel / Agent / LLMCall) — see\n * `memory/lens_v0_1_one_cursor_architecture.md`. The container\n * visually groups the branches so a reader instantly sees \"these\n * N things run concurrently.\" Without the box, parallel branches\n * look identical to a fan-out from a decision point.\n *\n * Why fork-branch edges in ADDITION to compound containment\n * ─────────────────────────────────────────────────────────\n * The container expresses \"which branches belong together\"; the\n * `fork-branch` edges express \"the parent fans out to each\n * branch's entry point.\" Some renderers theme fork-branch edges\n * differently (dotted, dashed) to distinguish from sequential\n * `next` edges — keeping them explicit lets every renderer\n * theme consistently without inferring intent from the\n * parent-child relationship alone.\n *\n * Pure function — no closures, no module state. The branches'\n * subgraphs arrive resolved via the `resolve` callback; this\n * translator does not call other translators directly.\n */\n\nimport type { GroupMetadata } from 'agentfootprint';\nimport { exitNodeIdOf } from '../helpers/exitNodeId.js';\nimport { makeEdge } from '../helpers/makeEdge.js';\nimport { makeRootNodeId } from '../helpers/makeNodeId.js';\nimport { mergeOutputs } from '../helpers/mergeOutputs.js';\nimport { pinUnderParent } from '../helpers/pinUnderParent.js';\nimport type { LensEdge, LensGroupOutput, LensNode } from '../types.js';\nimport type { MemberResolver } from './MemberResolver.js';\n\nexport function translateParallel(\n metadata: GroupMetadata,\n resolve: MemberResolver,\n): LensGroupOutput {\n if (metadata.kind !== 'Parallel') {\n throw new TypeError(\n `translateParallel: expected GroupMetadata.kind = 'Parallel', got '${metadata.kind}'`,\n );\n }\n if (metadata.members.length === 0) {\n throw new RangeError(\n `translateParallel: Parallel '${metadata.id}' has zero branches — caller bug.`,\n );\n }\n\n const containerId = makeRootNodeId('Parallel', metadata.id);\n // Synthetic Merge tail node — represents the engine's merge stage\n // that collects results from every branch. Lives OUTSIDE the\n // container (a sibling, not a child) so layout positions it after\n // the container. Suffix `/merge` keeps it disjoint from any\n // caller-supplied composition id.\n const mergeId = `${containerId}/merge`;\n\n const container: LensNode = {\n id: containerId,\n kind: 'group',\n label: metadata.name,\n primitiveKind: 'Parallel',\n ...(metadata.extra !== undefined && { metadata: metadata.extra }),\n };\n\n const mergeNode: LensNode = {\n id: mergeId,\n kind: 'stage',\n label: 'merge',\n primitiveKind: 'Parallel',\n metadata: { synthetic: 'merge' },\n };\n\n const branchOutputs = metadata.members.map(resolve);\n const pinnedBranches = branchOutputs.map((out) =>\n pinUnderParent(out, containerId),\n );\n\n const merged = mergeOutputs(pinnedBranches, containerId);\n\n const forkEdges: LensEdge[] = metadata.members.map((m, i) => {\n const branchOut = branchOutputs[i]!;\n return makeEdge('fork-branch', containerId, branchOut.rootNodeId, {\n label: m.memberId,\n });\n });\n\n // Each branch's exit → Merge. `next` kind (not fork-branch) because\n // the fan-IN side is sequential — the fork already happened at the\n // container.\n const joinEdges: LensEdge[] = branchOutputs.map((b) =>\n makeEdge('next', exitNodeIdOf(b), mergeId),\n );\n\n return {\n // Order: container first (so xyflow sees parent before children),\n // then pinned children, then Merge synthetic sibling.\n nodes: [container, ...merged.nodes, mergeNode],\n edges: [...merged.edges, ...forkEdges, ...joinEdges],\n rootNodeId: containerId,\n exitNodeId: mergeId,\n };\n}\n","/**\n * translateSequence — `Sequence` GroupMetadata → `LensGroupOutput`.\n *\n * Layer 2 (per-kind translator, pure) / Lens v0.1 translator pipeline.\n *\n * What it emits\n * ─────────────\n * The concatenation of each member's subgraph, plus N-1 `next`\n * edges chaining consecutive members through their `rootNodeId`s.\n * Sequence has NO own container node — the locked Lens v0.1\n * architecture renders only Parallel / Agent / LLMCall as compound\n * boxes. Sequence is a control-flow pattern, not a visual cluster.\n *\n * Why no own container\n * ────────────────────\n * A \"Sequence box\" would force the renderer to draw two visually\n * redundant frames (the Sequence's container + each member's own\n * card), which clutters multi-agent flowcharts. The chain of\n * `next` edges between members carries all the semantic weight\n * the user needs to read the sequence. Layout engines (dagre,\n * ELK) handle this naturally as a horizontal chain.\n *\n * rootNodeId convention\n * ─────────────────────\n * The first member's `rootNodeId` becomes the Sequence's\n * `rootNodeId` — that's the entry point a parent composition\n * wires control-flow edges to. Empty Sequence (zero members) is\n * a caller bug; the translator throws so the bug surfaces loudly\n * at translation time, not as a silent empty graph.\n *\n * Pure function — no closures, no module state. Member subgraphs\n * arrive resolved via the `resolve` callback supplied by the\n * dispatcher; this translator does not call back into other\n * translators directly.\n */\n\nimport type { GroupMetadata } from 'agentfootprint';\nimport { exitNodeIdOf } from '../helpers/exitNodeId.js';\nimport { makeEdge } from '../helpers/makeEdge.js';\nimport { mergeOutputs } from '../helpers/mergeOutputs.js';\nimport type { LensEdge, LensGroupOutput } from '../types.js';\nimport type { MemberResolver } from './MemberResolver.js';\n\nexport function translateSequence(\n metadata: GroupMetadata,\n resolve: MemberResolver,\n): LensGroupOutput {\n if (metadata.kind !== 'Sequence') {\n throw new TypeError(\n `translateSequence: expected GroupMetadata.kind = 'Sequence', got '${metadata.kind}'`,\n );\n }\n if (metadata.members.length === 0) {\n throw new RangeError(\n `translateSequence: Sequence '${metadata.id}' has zero members — caller bug (a Sequence must declare at least one step).`,\n );\n }\n\n const memberOutputs = metadata.members.map(resolve);\n const rootNodeId = memberOutputs[0]!.rootNodeId;\n const exitNodeId = exitNodeIdOf(memberOutputs[memberOutputs.length - 1]!);\n const merged = mergeOutputs(memberOutputs, rootNodeId);\n\n // Chain edges connect each member's EXIT to the next member's ROOT\n // so chains-of-chains (Sequence of Parallel of LLMCall) wire from\n // the inner Parallel's Merge node, not its container entry.\n const chainEdges: LensEdge[] = [];\n for (let i = 0; i < memberOutputs.length - 1; i++) {\n chainEdges.push(\n makeEdge(\n 'next',\n exitNodeIdOf(memberOutputs[i]!),\n memberOutputs[i + 1]!.rootNodeId,\n ),\n );\n }\n\n return {\n nodes: merged.nodes,\n edges: [...merged.edges, ...chainEdges],\n rootNodeId,\n exitNodeId,\n };\n}\n","/**\n * lensGroupTranslator — kind-discriminated dispatcher composing the\n * six per-kind translators into a single `GroupTranslator` ready to\n * pass to any agentfootprint composition's `groupTranslator`\n * constructor option (or `getUIGroupWith(...)` per-method override).\n *\n * Layer 2.4 (dispatcher) / Lens v0.1 translator pipeline.\n *\n * Recursion strategy\n * ──────────────────\n * The per-kind translators are PURE — they don't import the\n * dispatcher and don't recurse on their own. Instead, each\n * compound translator (Parallel / Sequence / Loop / Conditional)\n * takes a `MemberResolver` callback. The dispatcher constructs a\n * resolver that:\n *\n * 1. If `member.uiGroup` is already populated (because the\n * consumer wired a `groupTranslator` at that level), trust\n * it and cast to `LensGroupOutput`.\n * 2. Otherwise call `member.runner.getUIGroupWith(lensGroupTranslator)`\n * to recurse with the same dispatcher. This means the\n * consumer only needs to wire `lensGroupTranslator` ONCE\n * at the top of the tree.\n * 3. If both paths yield undefined, throw — the member's\n * runner doesn't expose any UI group shape, which is a\n * consumer bug (or a footprintjs bug if a built-in runner\n * forgot to implement `buildUIGroupMetadata`).\n *\n * Why a single dispatcher, not a Map of translators\n * ──────────────────────────────────────────────────\n * A `switch` on the discriminator keeps the dispatcher\n * well-typed without `as` casts: the compiler narrows\n * `metadata.kind` inside each branch so the per-kind translator\n * call type-checks. A `Record<GroupKind, GroupTranslator>` would\n * widen the `metadata` argument and lose narrowing.\n *\n * Pure function — no closures over module state. The dispatcher is\n * its own resolver: the `getUIGroupWith` call passes a reference to\n * the same exported function, closing the recursion cleanly.\n */\n\nimport type { GroupMember, GroupMetadata, GroupTranslator } from 'agentfootprint';\nimport { translateAgent } from './perKind/translateAgent.js';\nimport { translateConditional } from './perKind/translateConditional.js';\nimport { translateLLMCall } from './perKind/translateLLMCall.js';\nimport { translateLoop } from './perKind/translateLoop.js';\nimport { translateParallel } from './perKind/translateParallel.js';\nimport { translateSequence } from './perKind/translateSequence.js';\nimport type { MemberResolver } from './perKind/MemberResolver.js';\nimport type { LensGroupOutput } from './types.js';\n\nfunction isLensGroupOutput(value: unknown): value is LensGroupOutput {\n if (typeof value !== 'object' || value === null) return false;\n const v = value as { nodes?: unknown; edges?: unknown; rootNodeId?: unknown };\n return (\n Array.isArray(v.nodes) &&\n Array.isArray(v.edges) &&\n typeof v.rootNodeId === 'string'\n );\n}\n\nconst resolve: MemberResolver = (member: GroupMember): LensGroupOutput => {\n if (member.uiGroup !== undefined) {\n if (!isLensGroupOutput(member.uiGroup)) {\n throw new TypeError(\n `lensGroupTranslator: member '${member.memberId}' has a uiGroup but it is not a LensGroupOutput. ` +\n `A consumer wired a different GroupTranslator at that level — Lens cannot consume the result.`,\n );\n }\n return member.uiGroup;\n }\n const fromRunner = member.runner.getUIGroupWith<LensGroupOutput>(\n lensGroupTranslator,\n );\n if (fromRunner === undefined) {\n throw new Error(\n `lensGroupTranslator: member '${member.memberId}' has no translatable UI group shape — its runner returned undefined from getUIGroupWith.`,\n );\n }\n return fromRunner;\n};\n\n/**\n * Translate one `GroupMetadata` into a `LensGroupOutput`. Dispatches\n * to the appropriate per-kind translator based on `metadata.kind`.\n * Throws `TypeError` on unknown kinds — keeps the union closed at\n * runtime, not just at compile time.\n */\nexport const lensGroupTranslator: GroupTranslator<LensGroupOutput> = (\n metadata: GroupMetadata,\n): LensGroupOutput => {\n switch (metadata.kind) {\n case 'LLMCall':\n return translateLLMCall(metadata);\n case 'Agent':\n return translateAgent(metadata);\n case 'Sequence':\n return translateSequence(metadata, resolve);\n case 'Loop':\n return translateLoop(metadata, resolve);\n case 'Conditional':\n return translateConditional(metadata, resolve);\n case 'Parallel':\n return translateParallel(metadata, resolve);\n default: {\n const exhaustive: never = metadata.kind;\n throw new TypeError(\n `lensGroupTranslator: unknown GroupMetadata.kind '${exhaustive as string}'`,\n );\n }\n }\n};\n","/**\n * explainableShellPropsFromRunner — the ONE typed call a consumer makes to\n * drive eui's `<ExplainableShell>` from an agentfootprint `Runner` + a\n * `LensRecorder`.\n *\n * WHY this exists: consumers used to hand-wire FIVE values from five lib\n * accessors into `<ExplainableShell>` — and because each was threaded through\n * an `any` (or an `as never` cast), the compiler protected none of them. That\n * is how a footprintjs `FlowChart` blob slipped into eui's `spec` prop (which\n * wants a `SpecNode`) and silently blanked the chart on subflow drill.\n *\n * Lens is the bridge that already owns BOTH vocabularies (agentfootprint\n * `Runner` and eui's prop/overlay types), so the contract is enforced HERE,\n * once. The consumer just spreads the result:\n *\n * ```tsx\n * const props = explainableShellPropsFromRunner(agent, recorder);\n * <ExplainableShell {...props} />\n * ```\n *\n * Note: NO `spec`. The chart renders from `traceGraph` + `runtimeOverlay`\n * (both eui-owned types). The legacy spec tree is not needed for rendering and\n * was the source of the silent-blank type mismatch — leaving it out means a\n * consumer using this helper cannot pass it wrong.\n */\nimport type { Agent } from 'agentfootprint';\nimport type { ExplainableShellProps } from 'footprint-explainable-ui';\nimport type { CombinedNarrativeEntry } from 'footprintjs';\n\nimport type { LensRecorder } from './LensRecorder.js';\nimport { structureGraphFromRunner } from './collapser/structureGraphFromRunner.js';\n\n/**\n * The exact subset of `ExplainableShellProps` this helper provides. Spread it\n * into `<ExplainableShell {...props} />`. Pulled from eui's own prop type, so\n * if eui changes the contract this helper fails to typecheck — not the\n * consumer at runtime.\n */\nexport type ExplainableShellInputs = Pick<\n ExplainableShellProps,\n 'runtimeSnapshot' | 'narrativeEntries' | 'traceGraph' | 'runtimeOverlay'\n>;\n\n/** One narrative entry in the vocabulary `<ExplainableShell>` declares.\n * Derived from eui's own prop type — never re-typed here. */\ntype ShellNarrativeEntry = NonNullable<\n ExplainableShellInputs['narrativeEntries']\n>[number];\n\n/**\n * The entry types `<ExplainableShell>` knows how to render, as a runtime\n * lookup. Typed as a total `Record` over eui's union, so BOTH directions are\n * compiler-checked: drop a key (or eui adds one) and this fails to build.\n *\n * That trap is not decoration — it fired for real when eui learned `'retry'`,\n * with exactly the message it should have:\n *\n * TS2741: Property 'retry' is missing ... but required in Record<... | \"retry\", true>\n *\n * It only fires if lens actually BUILDS against a current eui, which is why the\n * `footprint-explainable-ui` devDependency is a floor-and-major range rather\n * than a caret: a caret pinned lens to one eui minor, so eui widened its union\n * three releases running and this file never heard about it.\n *\n * footprintjs's own narrative vocabulary is still the SUPERSET and still grows\n * on its own cadence, so `toShellNarrativeEntries` keeps a fallback for the\n * NEXT type eui has not learned yet. `'retry'` is no longer that case — eui\n * renders it natively now, so it passes straight through.\n */\nconst SHELL_ENTRY_TYPES: Record<ShellNarrativeEntry['type'], true> = {\n stage: true,\n step: true,\n condition: true,\n fork: true,\n selector: true,\n subflow: true,\n loop: true,\n break: true,\n error: true,\n pause: true,\n resume: true,\n emit: true,\n // eui >= 0.32.0 renders retry with its own icon, label and warning-weight\n // colour. Listing it here IS the passthrough — there is no separate branch.\n retry: true,\n};\n\n/** Where an entry type eui does not know is rendered: the generic step line —\n * a plain, indented sub-item at the entry's own depth, which is where\n * footprintjs places its nested per-stage entries. The entry's own `text` is\n * what shows, verbatim. This is the bridge for the NEXT variant footprintjs\n * adds, not for any type in `SHELL_ENTRY_TYPES` above. */\nconst GENERIC_ENTRY_TYPE = 'step' satisfies ShellNarrativeEntry['type'];\n\nfunction isShellEntryType(\n type: CombinedNarrativeEntry['type'],\n): type is ShellNarrativeEntry['type'] {\n return Object.prototype.hasOwnProperty.call(SHELL_ENTRY_TYPES, type);\n}\n\n/**\n * Translate footprintjs narrative entries into the vocabulary\n * `<ExplainableShell>` declares. Entry types eui knows pass through untouched —\n * `'retry'` among them, as of eui 0.32.0, so the badge reads \"retry\" and the\n * line carries retry's own icon instead of a generic step dot.\n *\n * A type eui has NOT learned yet is still rendered as a generic step line\n * keeping its own text — displayed honestly, never dropped, and never silently\n * typed as something eui would style differently (a heading, an error). Folding\n * costs the badge its real name, which is why folding is the fallback and never\n * the destination: the fix for a folded type is always upstream, eui teaching\n * its union the new variant, exactly as it just did for retry.\n */\nexport function toShellNarrativeEntries(\n entries: readonly CombinedNarrativeEntry[],\n): ShellNarrativeEntry[] {\n return entries.map((entry) => {\n const { type } = entry;\n return isShellEntryType(type)\n ? { ...entry, type }\n : { ...entry, type: GENERIC_ENTRY_TYPE };\n });\n}\n\n/**\n * Assemble the full, typed `<ExplainableShell>` input bundle from a finished\n * (or paused) run. Call AFTER `recorder.observe(runner)` + `runner.run(...)`,\n * so the runtime overlay has been captured.\n *\n * The `traceGraph` is ALWAYS the plain, undecorated view. This is not a knob:\n * `<ExplainableShell>` IS the footprintjs-level renderer — plain stages/subflows\n * lit purely by the runtime overlay (visited + current). The agent-semantic\n * (decorated) rendering is a DIFFERENT renderer, `<Lens>`, whose whole job is\n * the decorated view. Baking plain-vs-decorated into which renderer you pick —\n * rather than a hidden default on this helper — keeps the boundary enforceable:\n * the shell can never accidentally carry agent decoration.\n *\n * Escape hatch: if you deliberately want a decorated graph inside the shell,\n * build it explicitly with `structureGraphFromRunner(agent, { decorate: true })`\n * and pass it as `traceGraph` yourself — a visible, non-default choice.\n */\nexport function explainableShellPropsFromRunner(\n agent: Agent,\n recorder: LensRecorder,\n): ExplainableShellInputs {\n return {\n runtimeSnapshot: agent.getLastSnapshot() ?? null,\n narrativeEntries: toShellNarrativeEntries(agent.getLastNarrativeEntries()),\n traceGraph: structureGraphFromRunner(agent, { decorate: false }),\n runtimeOverlay: recorder.runtime.getOverlay(),\n };\n}\n","/**\n * toReactFlow — pure mapper `LensGroupOutput` → xyflow `Node[]` + `Edge[]`.\n *\n * Layer 3.1 (pure render mapper) / Lens v0.1 translator pipeline.\n *\n * Why a pure mapper (no layout, no React, no DOM)\n * ───────────────────────────────────────────────\n * The translate pipeline (L2) produces a UI-framework-agnostic\n * `LensGroupOutput`. The xyflow mapping is the FIRST place a\n * framework dependency enters — keep it isolated in this one file\n * so a Vue / D3 consumer can swap in their own mapper without\n * touching the data layer or the React hook above.\n *\n * Positions are NOT set here: dagre (or any layout engine) runs\n * downstream over the result. Keeping layout out of the mapper\n * means the mapper is trivially testable against fixed outputs.\n *\n * Node mapping\n * ────────────\n * LensNode.kind = 'group' → xyflow Node with `type: 'group'`,\n * `style: { width, height }` placeholders\n * (final dims come from layout).\n * LensNode.kind = 'stage' → xyflow Node with `type: 'lensStage'`\n * (consumer registers a renderer for that\n * type — Lens does NOT bake in JSX here).\n * parentId → xyflow parentId + `extent: 'parent'` so the child is\n * clipped to its compound container.\n * data → { label, primitiveKind, metadata } — exactly what a\n * renderer needs to theme by kind without re-importing\n * LensNode.\n *\n * Edge mapping\n * ────────────\n * LensEdge maps 1:1 to xyflow Edge. `data` carries the LensEdge\n * `kind` so consumers can theme:\n *\n * next → solid arrow (default)\n * fork-branch → dashed / fanned\n * decision-branch → conditional / dashed\n * loop-iteration → curved back-edge\n *\n * `label` passes through verbatim. `type` defaults to 'default'\n * (xyflow's straight-line) so the consumer-supplied edgeTypes map\n * can pick a custom edge component per kind without bezier/straight\n * conflicts.\n *\n * Pure function — no closures, no module state.\n */\n\nimport type { Edge, Node } from '@xyflow/react';\nimport type { LensEdge, LensGroupOutput, LensNode } from '../../core/translate/types.js';\n\n/** Default size box for a stage node. Layout overrides via dagre. */\nconst DEFAULT_STAGE_SIZE = { width: 180, height: 56 } as const;\n/** Default placeholder size for a group container — dagre overrides. */\nconst DEFAULT_GROUP_SIZE = { width: 260, height: 120 } as const;\n\n/**\n * Data payload xyflow renderers receive on each node. Closed enough\n * that a consumer renderer can switch on `primitiveKind` and consume\n * `metadata` safely.\n *\n * `userActor` is set ONLY on the synthetic user-frame nodes\n * (`__lens_user_in` / `__lens_user_out`) added by `layoutLensGraph`\n * when `withUserFrame` is on. Real composition nodes leave it\n * undefined. Renderers theme accordingly: a circular actor pill for\n * `'in' | 'out'`, the standard stage card otherwise.\n */\nexport interface LensReactFlowNodeData {\n readonly label: string;\n readonly primitiveKind: LensNode['primitiveKind'];\n readonly metadata?: Readonly<Record<string, unknown>>;\n readonly userActor?: 'in' | 'out';\n readonly [key: string]: unknown;\n}\n\n/**\n * Data payload xyflow renderers receive on each edge. Carries the\n * LensEdge `kind` so the consumer can switch on it without re-deriving.\n */\nexport interface LensReactFlowEdgeData {\n readonly kind: LensEdge['kind'];\n readonly [key: string]: unknown;\n}\n\nexport interface ToReactFlowResult {\n readonly nodes: Node<LensReactFlowNodeData>[];\n readonly edges: Edge<LensReactFlowEdgeData>[];\n}\n\nexport function toReactFlow(output: LensGroupOutput): ToReactFlowResult {\n const nodes: Node<LensReactFlowNodeData>[] = output.nodes.map((n) =>\n nodeToXyflow(n),\n );\n const edges: Edge<LensReactFlowEdgeData>[] = output.edges.map((e) =>\n edgeToXyflow(e),\n );\n return { nodes, edges };\n}\n\nfunction nodeToXyflow(n: LensNode): Node<LensReactFlowNodeData> {\n const data: LensReactFlowNodeData = {\n label: n.label,\n primitiveKind: n.primitiveKind,\n ...(n.metadata !== undefined && { metadata: n.metadata }),\n };\n const base: Node<LensReactFlowNodeData> = {\n id: n.id,\n position: { x: 0, y: 0 },\n data,\n ...(n.kind === 'group'\n ? { type: 'group', style: { ...DEFAULT_GROUP_SIZE } }\n : { type: 'lensStage' }),\n ...(n.parentId !== undefined && {\n parentId: n.parentId,\n extent: 'parent' as const,\n }),\n };\n return base;\n}\n\nfunction edgeToXyflow(e: LensEdge): Edge<LensReactFlowEdgeData> {\n return {\n id: e.id,\n source: e.source,\n target: e.target,\n type: 'default',\n data: { kind: e.kind },\n ...(e.label !== undefined && { label: e.label }),\n };\n}\n\n/**\n * Default size hint per LensNode kind — exported so the layout step\n * can sit alongside the mapper and consumers can override at one\n * boundary instead of inferring sizes from CSS during layout.\n */\nexport function defaultSize(node: LensNode): { width: number; height: number } {\n return node.kind === 'group'\n ? { ...DEFAULT_GROUP_SIZE }\n : { ...DEFAULT_STAGE_SIZE };\n}\n","/**\n * dagreLayout — pure fn `(nodes, edges) → positioned nodes`.\n *\n * Pattern: thin wrapper around dagre's `graphlib` layout. Lens hands\n * over its node-set (User actor + agent containers + LLM /\n * Tool / ContextBin children) and edge-set (asks / forwards /\n * answers / loop-back / fork-branch); dagre returns one\n * coordinate per node, computed top-to-bottom.\n * Role: Replaces the hand-tuned position constants that previously\n * lived in `RunTreeFlow.buildFlow`. One layout path now\n * handles Sequence (vertical chain), Parallel (auto fan-out),\n * Loop (self-edge + back-edge), Conditional (single chosen\n * branch), and arbitrary nesting — anything we feed dagre,\n * dagre lays out.\n *\n * Why dagre and not elk: dagre is ~12kb gzipped, layered-tree is the\n * shape we always want, and xyflow has well-trodden integration docs\n * for it. ELK is more powerful but ~10× the bundle and overkill for\n * the patterns Lens actually renders.\n *\n * The function is pure: same input → same output, no side effects.\n * That keeps it testable in isolation and — crucially — keeps the\n * step-slider sync logic unchanged. Selection / focus ring uses node\n * IDs and ViewModel state; coordinates are purely visual.\n */\n\nimport dagre from 'dagre';\nimport type { Edge, Node } from '@xyflow/react';\n\n/** Per-node size hint. Without these dagre uses 0×0 boxes and arrows\n * collapse to a point. We supply the same dimensions xyflow uses for\n * rendering so the layout matches the painted result. */\nexport interface SizedNode<T extends Node = Node> {\n readonly node: T;\n readonly width: number;\n readonly height: number;\n}\n\nexport interface DagreLayoutOptions {\n /** Layout direction. `'TB'` (top-to-bottom) is the Lens default —\n * matches \"User asks → pipeline → User answers\" reading order.\n * Use `'LR'` for left-to-right when displaying very long chains\n * side-by-side. */\n readonly direction?: 'TB' | 'BT' | 'LR' | 'RL';\n /** Vertical spacing between rank layers (px). */\n readonly rankSep?: number;\n /** Horizontal spacing between siblings within a rank (px). */\n readonly nodeSep?: number;\n /** Spacing between edges (px). */\n readonly edgeSep?: number;\n}\n\n/**\n * Lay out the given nodes + edges and return new nodes with computed\n * `position` (top-left). Edges pass through unchanged — xyflow handles\n * routing once nodes are placed.\n *\n * @param sized nodes paired with their rendered width/height\n * @param edges edges (only `.source` / `.target` are read)\n * @param options layout tuning\n */\nexport function dagreLayout(\n sized: readonly SizedNode[],\n edges: readonly Edge[],\n options: DagreLayoutOptions = {},\n): Node[] {\n const direction = options.direction ?? 'TB';\n const rankSep = options.rankSep ?? 80;\n const nodeSep = options.nodeSep ?? 60;\n const edgeSep = options.edgeSep ?? 20;\n\n const g = new dagre.graphlib.Graph({ compound: true });\n g.setGraph({ rankdir: direction, ranksep: rankSep, nodesep: nodeSep, edgesep: edgeSep });\n g.setDefaultEdgeLabel(() => ({}));\n\n // Register nodes WITH dimensions — dagre needs both to compute valid\n // coordinates. xyflow Parent/child wiring (parentId) is preserved as\n // dagre compound parent links so children stay inside their parent's\n // bounding box (single-agent triangle layout uses this).\n for (const { node, width, height } of sized) {\n g.setNode(node.id, { width, height });\n if (node.parentId) {\n g.setParent(node.id, node.parentId);\n }\n }\n\n // Register edges. dagre ignores edges whose endpoints aren't both\n // present in the graph (defensive — xyflow filters orphans elsewhere).\n for (const e of edges) {\n if (g.hasNode(e.source) && g.hasNode(e.target)) {\n g.setEdge(e.source, e.target);\n }\n }\n\n dagre.layout(g);\n\n // dagre returns center coordinates; xyflow wants top-left. Convert by\n // subtracting half the width/height. Children with `parentId` get\n // coordinates relative to the parent (xyflow convention) — dagre\n // produces absolute coords, so we subtract the parent's top-left.\n const out: Node[] = [];\n for (const { node, width, height } of sized) {\n const laidOut = g.node(node.id);\n if (!laidOut) {\n // Node wasn't laid out (rare edge case — orphaned node). Keep\n // its original position so we don't drop it.\n out.push(node);\n continue;\n }\n let x = laidOut.x - width / 2;\n let y = laidOut.y - height / 2;\n if (node.parentId) {\n const parent = g.node(node.parentId);\n const parentSized = sized.find((s) => s.node.id === node.parentId);\n if (parent && parentSized) {\n x -= parent.x - parentSized.width / 2;\n y -= parent.y - parentSized.height / 2;\n }\n }\n out.push({ ...node, position: { x, y } });\n }\n return out;\n}\n","/**\n * layoutLensGraph — pure orchestrator: LensGroupOutput → laid-out xyflow.\n *\n * Layer 3.2 (pure layout orchestrator) / Lens v0.1 translator pipeline.\n *\n * Pipeline\n * ────────\n *\n * LensGroupOutput\n * │\n * ▼ toReactFlow (L3.1)\n * Node[] + Edge[] (xyflow shape, no positions)\n * │\n * ▼ defaultSize (L3.1)\n * SizedNode[] (per-node width/height hints)\n * │\n * ▼ dagreLayout (existing pure layout)\n * Positioned Node[] + Edge[] (ready for <ReactFlow>)\n *\n * Why orchestrate here and not in the hook\n * ────────────────────────────────────────\n * The hook is a thin React shim that subscribes to the runner and\n * calls this function. Keeping the data pipeline OUTSIDE the hook\n * makes it framework-agnostic: a Vue / D3 consumer running on the\n * same upstream `LensGroupOutput` can call `layoutLensGraph` to\n * get a positioned graph without dragging in any React deps. The\n * `@xyflow/react` import is the only React-adjacent piece, and\n * it's a pure data type (`Node` / `Edge`) — no DOM, no JSX.\n *\n * Pure function — no closures, no module state.\n */\n\nimport type { Edge, Node } from '@xyflow/react';\nimport { dagreLayout, type DagreLayoutOptions } from '../../react/layout/dagreLayout.js';\nimport type { LensGroupOutput, LensNode } from '../translate/types.js';\nimport {\n defaultSize,\n toReactFlow,\n type LensReactFlowEdgeData,\n type LensReactFlowNodeData,\n} from './toReactFlow.js';\n\nexport interface LayoutLensGraphOptions {\n readonly direction?: DagreLayoutOptions['direction'];\n readonly rankSep?: DagreLayoutOptions['rankSep'];\n readonly nodeSep?: DagreLayoutOptions['nodeSep'];\n readonly edgeSep?: DagreLayoutOptions['edgeSep'];\n /**\n * Per-node size override. Receives the source `LensNode` so the\n * consumer can theme by `primitiveKind` or `kind`. Falls back to\n * `defaultSize` when the override returns `undefined` — lets\n * consumers tweak ONE kind without re-implementing all six.\n */\n readonly sizeOverride?: (\n node: LensNode,\n ) => { width: number; height: number } | undefined;\n /**\n * When true, augment the laid-out graph with two synthetic \"user\"\n * nodes — one above the root, one below the exit — connected to\n * the composition by plain `next` edges. Reflects the Lens v0.1\n * mental model: every run is \"user asks → composition runs → user\n * gets answer back\".\n *\n * Default is `false` because the orchestrator is a general-purpose\n * layout tool — headless / preview / non-Lens consumers should NOT\n * receive synthetic user actors by surprise. The `<LensFlow>`\n * component flips it on as its UX convention.\n *\n * The synthetic nodes use xyflow `type: 'lensUser'`; consumers\n * registering custom `nodeTypes` should include a renderer for\n * that type (the default `<LensFlow>` ships one).\n */\n readonly withUserFrame?: boolean;\n}\n\n/** Sentinel node IDs for the optional user frame. */\nexport const USER_IN_NODE_ID = '__lens_user_in';\nexport const USER_OUT_NODE_ID = '__lens_user_out';\n\nexport interface LayoutLensGraphResult {\n readonly nodes: Node<LensReactFlowNodeData>[];\n readonly edges: Edge<LensReactFlowEdgeData>[];\n}\n\n/** Layout size for synthetic user actor nodes in the user frame. */\nconst USER_NODE_SIZE = { width: 100, height: 44 } as const;\n\nexport function layoutLensGraph(\n output: LensGroupOutput,\n options: LayoutLensGraphOptions = {},\n): LayoutLensGraphResult {\n const { nodes: unpositionedNodes, edges } = toReactFlow(output);\n const withUserFrame = options.withUserFrame ?? false;\n\n const sized = unpositionedNodes.map((node, i) => {\n const sourceLensNode = output.nodes[i]!;\n const size =\n options.sizeOverride?.(sourceLensNode) ?? defaultSize(sourceLensNode);\n return { node, width: size.width, height: size.height };\n });\n\n // The user-frame nodes are added AFTER layout — dagre cannot rank\n // an edge whose endpoint is a compound parent (the Parallel\n // container), so handing it `user-in → container` crashes the\n // ranker. Position user-in above the laid-out bounding box and\n // user-out below; xyflow handles edges to/from compound parents\n // at render time without complaint.\n\n // dagre cannot rank edges whose endpoints are in a compound parent/\n // child relationship — it throws \"Cannot set properties of undefined\n // (setting 'rank')\" because the compound parent is not a leaf in the\n // ranking graph. The data layer keeps these edges (consumers may\n // theme them as decorative fork/decision arrows); the layout step\n // routes them around dagre. The compound containment itself supplies\n // the visual \"parent contains child\" cue, so dagre layout for the\n // remaining edges is sufficient to position the children.\n const parentIdByNodeId = new Map<string, string>();\n for (const n of unpositionedNodes) {\n if (n.parentId !== undefined) parentIdByNodeId.set(n.id, n.parentId);\n }\n const layoutEdges = edges.filter(\n (e) =>\n parentIdByNodeId.get(e.target) !== e.source &&\n parentIdByNodeId.get(e.source) !== e.target,\n );\n\n const positionedNodes = dagreLayout(sized, layoutEdges, {\n ...(options.direction !== undefined && { direction: options.direction }),\n ...(options.rankSep !== undefined && { rankSep: options.rankSep }),\n ...(options.nodeSep !== undefined && { nodeSep: options.nodeSep }),\n ...(options.edgeSep !== undefined && { edgeSep: options.edgeSep }),\n }) as Node<LensReactFlowNodeData>[];\n\n // dagre lays out children at positions RELATIVE to their parent group,\n // but the parent's `style.width/height` defaults from `defaultSize`\n // don't account for the actual child bounding box — so xyflow may\n // render the compound container too small to hold its children. Walk\n // each group, compute the bounding box of its (now-positioned)\n // children, and resize the container's style to fit. Padding gives\n // breathing room for borders and label chrome.\n const PADDING = { top: 36, right: 24, bottom: 24, left: 24 };\n const sizedById = new Map(sized.map((s) => [s.node.id, s]));\n const resizedNodes = positionedNodes.map((node) => {\n if (node.type !== 'group') return node;\n const children = positionedNodes.filter((c) => c.parentId === node.id);\n if (children.length === 0) return node;\n let maxRight = 0;\n let maxBottom = 0;\n for (const child of children) {\n const childSized = sizedById.get(child.id);\n if (!childSized) continue;\n const right = child.position.x + childSized.width;\n const bottom = child.position.y + childSized.height;\n if (right > maxRight) maxRight = right;\n if (bottom > maxBottom) maxBottom = bottom;\n }\n return {\n ...node,\n style: {\n ...(node.style ?? {}),\n width: maxRight + PADDING.right + PADDING.left,\n height: maxBottom + PADDING.bottom + PADDING.top,\n },\n };\n });\n\n if (!withUserFrame) {\n return { nodes: resizedNodes, edges };\n }\n\n // Post-layout user-frame positioning. Compute the bounding box of\n // top-level (no parentId) nodes, then place user-in centered above\n // and user-out centered below, with vertical gap = USER_GAP.\n const USER_GAP = 60;\n let minX = Infinity;\n let maxX = -Infinity;\n let minY = Infinity;\n let maxY = -Infinity;\n for (const n of resizedNodes) {\n if (n.parentId !== undefined) continue;\n const sizedEntry = sizedById.get(n.id);\n const w = (n.style as { width?: number } | undefined)?.width\n ?? sizedEntry?.width\n ?? 180;\n const h = (n.style as { height?: number } | undefined)?.height\n ?? sizedEntry?.height\n ?? 56;\n if (n.position.x < minX) minX = n.position.x;\n if (n.position.y < minY) minY = n.position.y;\n if (n.position.x + w > maxX) maxX = n.position.x + w;\n if (n.position.y + h > maxY) maxY = n.position.y + h;\n }\n const centerX = (minX + maxX) / 2 - USER_NODE_SIZE.width / 2;\n const userIn: Node<LensReactFlowNodeData> = {\n id: USER_IN_NODE_ID,\n type: 'lensUser',\n position: { x: centerX, y: minY - USER_GAP - USER_NODE_SIZE.height },\n data: { label: 'user', primitiveKind: 'Agent', userActor: 'in' },\n };\n const userOut: Node<LensReactFlowNodeData> = {\n id: USER_OUT_NODE_ID,\n type: 'lensUser',\n position: { x: centerX, y: maxY + USER_GAP },\n data: { label: 'user', primitiveKind: 'Agent', userActor: 'out' },\n };\n // user-out attaches to the composition's EXIT node (Parallel's\n // Merge, Conditional's Converge, or the inner exit for chains) so\n // the \"user back\" arrow originates from the right place visually.\n // Falls back to rootNodeId for leaves where entry == exit.\n const exitNodeId = output.exitNodeId ?? output.rootNodeId;\n const userEdges = [\n {\n id: '__lens_edge_user_in',\n source: USER_IN_NODE_ID,\n target: output.rootNodeId,\n type: 'default' as const,\n data: { kind: 'next' as const },\n },\n {\n id: '__lens_edge_user_out',\n source: exitNodeId,\n target: USER_OUT_NODE_ID,\n type: 'default' as const,\n data: { kind: 'next' as const },\n },\n ];\n return {\n nodes: [userIn, ...resizedNodes, userOut],\n edges: [...edges, ...userEdges],\n };\n}\n","/**\n * The issue body — the prose the reporter typed, plus the manifest as a table.\n *\n * One builder, three submit modes. Whether the report is pasted into GitHub's\n * new-issue form by hand, filed by the reporter's own token, or relayed through\n * the app's server, the maintainer reads the SAME text: what was tried, what\n * was expected, what happened, and then — in a table nobody has to take on\n * trust — exactly which units of evidence came along, which were left out, and\n * which state keys were already scrubbed before any of it was recorded.\n *\n * What is never in here: a token, a zip byte, a redacted VALUE. The manifest\n * carries redacted key NAMES only (footprintjs scrubbed the values upstream at\n * commit time), and this builder copies names, never values.\n */\n\nimport { formatBytes } from './selection.js';\nimport type { BugReportFieldsView, BugReportManifestView } from './types.js';\n\n/** Where the evidence zip ended up — stated in the issue, never implied. */\nexport interface EvidenceNote {\n readonly filename: string;\n readonly bytes: number;\n /**\n * `'by-hand'` the reporter has the file and must attach it.\n * `'relayed'` the app's server received it and files it with the issue.\n */\n readonly delivery: 'by-hand' | 'relayed';\n}\n\nexport interface IssueBodyArgs {\n readonly fields: BugReportFieldsView;\n /** The manifest of what is actually being sent (the export's, when there is one). */\n readonly manifest: BugReportManifestView;\n /** The ticked unit ids, when the manifest's own `selected` is not the truth yet. */\n readonly selected?: readonly string[];\n readonly evidence?: EvidenceNote;\n}\n\n/** Build the markdown body. Deterministic — same inputs, same bytes. */\nexport function buildIssueBody(args: IssueBodyArgs): string {\n const { fields, manifest, evidence } = args;\n const selected = new Set(args.selected ?? manifest.selected ?? manifest.units.map((u) => u.id));\n const lines: string[] = [];\n\n lines.push('### Steps to reproduce', '', textOr(fields.stepsToReproduce), '');\n lines.push('### Expected', '', textOr(fields.expected), '');\n lines.push('### Actual', '', textOr(fields.actual), '');\n\n lines.push('### Evidence in this report', '');\n lines.push('| unit | kind | size | events | turns |');\n lines.push('| --- | --- | --- | --- | --- |');\n for (const unit of manifest.units) {\n if (!selected.has(unit.id)) continue;\n lines.push(\n `| \\`${unit.id}\\` | ${unit.kind} | ${formatBytes(unit.bytes || 0)} | ` +\n `${unit.eventCount ?? '—'} | ${unit.turnCount ?? '—'} |`,\n );\n }\n lines.push('');\n\n const left = manifest.units.filter((unit) => !selected.has(unit.id));\n if (left.length > 0) {\n lines.push(\n `The reporter left out ${left.length} unit${left.length === 1 ? '' : 's'}: ` +\n `${left.map((unit) => `\\`${unit.id}\\``).join(', ')}. ` +\n 'A turn that refers to something not here is referring to one of those.',\n '',\n );\n }\n\n const redacted = manifest.redactedKeys ?? [];\n if (redacted.length > 0) {\n lines.push(\n `**Redacted before recording** (names only — the values never left the reporter's ` +\n `machine): ${redacted.map((key) => `\\`${key}\\``).join(', ')}`,\n '',\n );\n }\n\n for (const warning of manifest.warnings ?? []) lines.push(`> ⚠ ${warning}`, '');\n for (const note of manifest.notes ?? []) lines.push(`> ${note}`, '');\n\n if (evidence) {\n lines.push(\n evidence.delivery === 'by-hand'\n ? `**Evidence bundle:** \\`${evidence.filename}\\` (${formatBytes(evidence.bytes)}) — ` +\n 'downloaded to the reporter\\'s machine and attached to this issue by hand. If it is ' +\n 'not attached above, ask them for it: nothing was uploaded automatically.'\n : `**Evidence bundle:** \\`${evidence.filename}\\` (${formatBytes(evidence.bytes)}) — ` +\n 'sent to the application\\'s bug-report endpoint, which files it with this issue.',\n '',\n );\n }\n\n lines.push('### Environment', '');\n const env = manifest.environment ?? {};\n for (const [label, value] of [\n ['agentfootprint', env.agentfootprint],\n ['footprintjs', env.footprintjs],\n ['node', env.node],\n ['platform', joinPlatform(env.platform, env.arch)],\n ['app', env.appVersion ?? fields.appVersion],\n ] as const) {\n if (value) lines.push(`- ${label}: \\`${value}\\``);\n }\n lines.push('');\n lines.push('<sub>Filed from Why Lens — the manifest above is the library\\'s own.</sub>');\n\n return `${lines.join('\\n').replace(/\\n{3,}/g, '\\n\\n').trimEnd()}\\n`;\n}\n\nconst textOr = (value: string | undefined): string =>\n value && value.trim() !== '' ? value.trim() : '_(not given)_';\n\nfunction joinPlatform(platform?: string, arch?: string): string | undefined {\n if (!platform && !arch) return undefined;\n return [platform, arch].filter(Boolean).join('/');\n}\n","/**\n * Talking to GitHub: where the issue goes, and what a URL can carry.\n *\n * The button never asks for an owner or a repo. It asks for the ISSUES URL a\n * maintainer would paste into a README —\n * `https://github.com/footprintjs/agentfootprint/issues` — and takes the rest\n * from it, including the API root, so the same prop works on GitHub Enterprise\n * Server (`https://github.acme.com/…` → `https://github.acme.com/api/v3`).\n */\n\n/** Owner, repo, and the API root that serves them. */\nexport interface GithubTarget {\n readonly owner: string;\n readonly repo: string;\n /** `https://api.github.com`, or `<origin>/api/v3` on GitHub Enterprise Server. */\n readonly apiBase: string;\n /** The new-issue form, without a query. */\n readonly newIssueUrl: string;\n}\n\n/**\n * Parse `https://host/OWNER/REPO[/issues[/…]]`.\n *\n * Returns `undefined` for anything that is not one — a missing repo is a fact\n * the caller states (\"this button cannot open an issue form\"), never a guess.\n */\nexport function parseGithubRepo(issuesUrl: string): GithubTarget | undefined {\n let url: URL;\n try {\n url = new URL(issuesUrl);\n } catch {\n return undefined;\n }\n if (url.protocol !== 'https:' && url.protocol !== 'http:') return undefined;\n const [owner, repo] = url.pathname.split('/').filter(Boolean);\n if (!owner || !repo) return undefined;\n const isDotCom = url.hostname === 'github.com' || url.hostname === 'www.github.com';\n return {\n owner,\n repo: repo.replace(/\\.git$/, ''),\n apiBase: isDotCom ? 'https://api.github.com' : `${url.origin}/api/v3`,\n newIssueUrl: `${url.origin}/${owner}/${repo}/issues/new`,\n };\n}\n\n/**\n * GitHub's new-issue form is a GET, and a GET has a ceiling.\n *\n * The documented practical limit is around 8 KB of URL; browsers and proxies\n * differ below that. 8000 leaves room for the title, the labels and the scheme\n * without pretending to know one exact number.\n */\nexport const MAX_ISSUE_URL_BYTES = 8000;\n\n/** The prefilled form URL, and whether the body had to be cut to fit. */\nexport interface PrefilledIssueUrl {\n readonly url: string;\n readonly truncated: boolean;\n}\n\n/** What a truncated body ends with — the reason the full one is not lost. */\nexport const TRUNCATION_NOTICE =\n '\\n\\n…truncated to fit a URL — the full report is on the clipboard, paste it over this.\\n';\n\n/**\n * Build `…/issues/new?title=&body=&labels=`, cutting the BODY (never the title,\n * never the labels) until the whole URL fits.\n *\n * A body that does not fit is not dropped and not silently shortened: it is cut\n * at a line boundary and told to be replaced from the clipboard, which is where\n * this flow always puts it first.\n */\nexport function buildNewIssueUrl(args: {\n readonly target: GithubTarget;\n readonly title: string;\n readonly body: string;\n readonly labels?: readonly string[];\n readonly maxBytes?: number;\n}): PrefilledIssueUrl {\n const limit = args.maxBytes ?? MAX_ISSUE_URL_BYTES;\n const compose = (body: string): string => {\n const params = new URLSearchParams();\n params.set('title', args.title);\n params.set('body', body);\n if (args.labels && args.labels.length > 0) params.set('labels', args.labels.join(','));\n return `${args.target.newIssueUrl}?${params.toString()}`;\n };\n\n const full = compose(args.body);\n if (full.length <= limit) return { url: full, truncated: false };\n\n // Shrink the body until the composed URL fits. Percent-encoding means the\n // relationship between characters cut and bytes saved is not 1:1, so this\n // converges by measuring rather than by arithmetic.\n let keep = args.body.length;\n let url = full;\n while (keep > 0 && url.length > limit) {\n keep = Math.floor(keep * (limit / url.length) * 0.95);\n url = compose(cutAtLine(args.body, keep) + TRUNCATION_NOTICE);\n }\n return { url, truncated: true };\n}\n\n/** Cut to at most `keep` characters, preferring the last line break. */\nfunction cutAtLine(body: string, keep: number): string {\n const head = body.slice(0, Math.max(0, keep));\n const lastBreak = head.lastIndexOf('\\n');\n return lastBreak > keep * 0.5 ? head.slice(0, lastBreak) : head;\n}\n\n/**\n * The body Lens POSTs to an application's relay endpoint.\n *\n * The BROWSER builds the bundle (it is where the recording is) and the relay\n * holds the token (it is the only place a token belongs). So the payload is the\n * finished bundle plus the reporter's prose, and the server's whole job is:\n *\n * ```ts\n * app.post('/bug-report', async (req, res) => {\n * const { fields, manifest, filename, zipBase64 } = req.body;\n * const zip = Buffer.from(zipBase64, 'base64');\n * res.json(await reporter.file({ manifest, files: [], zip, filename }));\n * });\n * ```\n *\n * `kind` and `version` are there so a relay can refuse a payload it does not\n * recognise instead of half-reading it.\n */\nexport interface RelayPayload {\n readonly kind: 'agentfootprint-lens.bug-report';\n readonly version: 1;\n readonly fields: {\n readonly title: string;\n readonly stepsToReproduce: string;\n readonly expected: string;\n readonly actual: string;\n readonly appVersion?: string;\n };\n /** The unit ids the reporter consented to. */\n readonly include: readonly string[];\n readonly labels?: readonly string[];\n /** The export's manifest — the same one `manifest.json` carries in the zip. */\n readonly manifest: unknown;\n /** The issue body Lens composed, so the relay files the text the reporter saw. */\n readonly body: string;\n readonly filename: string;\n /** The zip, base64. The size ceiling is what keeps this a reasonable POST. */\n readonly zipBase64: string;\n}\n\n/** What a relay is expected to answer with. Anything else is reported verbatim. */\nexport interface RelayResult {\n readonly issueUrl?: string;\n readonly zipUrl?: string;\n readonly error?: string;\n readonly message?: string;\n}\n\n/**\n * Base64 for a zip, without assuming a runtime.\n *\n * `btoa` in a browser, `Buffer` in Node (a relay flow tested under jsdom or\n * rendered on a server hits the second). Chunked so a multi-megabyte bundle\n * does not blow the argument limit of `String.fromCharCode`.\n */\nexport function encodeBase64(bytes: Uint8Array): string {\n const maybeBuffer = (globalThis as { Buffer?: { from(b: Uint8Array): { toString(e: string): string } } })\n .Buffer;\n if (typeof maybeBuffer?.from === 'function') return maybeBuffer.from(bytes).toString('base64');\n let binary = '';\n const chunk = 0x8000;\n for (let i = 0; i < bytes.length; i += chunk) {\n binary += String.fromCharCode(...bytes.subarray(i, i + chunk));\n }\n return btoa(binary);\n}\n","/**\n * The two shipped ArtifactResolvers.\n *\n * `httpArtifactResolver` speaks the hosting wire's published grammar (9.23.0):\n *\n * POST <url> { op: 'artifact-head', ref, sessionId }\n * → 200 { artifact: { ref, meta } }\n * POST <url> { op: 'artifact-get', ref, sessionId }\n * → 200 { artifact: { ref, meta, data } }\n * failure { error, code } (managed-runtime dialect adds status:'error')\n *\n * The grammar is spoken here BY VALUE, not imported from\n * `agentfootprint/hosting`: that subpath exists only on 9.2x, and the lens\n * peers back to ^7 — a named import would be a module-link crash on older\n * installs, and the hosting barrel drags `node:http` into a browser bundle.\n * The protocol is the contract; these strings are it.\n *\n * The governing law both resolvers uphold: **an id in a response is safe —\n * the RESOLUTION is governed.** Every HTTP redemption carries the session's\n * identity exactly as every other request on that wire does (body `sessionId`,\n * plus `userId` on wires that carry one); the serving agent enforces scope and\n * redaction at its boundary. `404 ERR_ARTIFACT_NOT_FOUND` is the ONE\n * indistinguishable answer for missing, expired and another-session's ref —\n * these resolvers surface it as `absent` and deliberately carry nothing else,\n * so no UI can accidentally say more than the store chose to.\n */\n\nimport type { ArtifactMetaView, ArtifactResolution, ArtifactResolver } from './types.js';\n\n/** The wire spelling of `head` — metadata only, the render-by-ref decision. */\nconst ARTIFACT_HEAD_OP = 'artifact-head';\n/** The wire spelling of `get` — metadata + payload. */\nconst ARTIFACT_GET_OP = 'artifact-get';\n/** The one failure code that means \"no data\" rather than \"the door failed\". */\nconst NOT_FOUND_CODE = 'ERR_ARTIFACT_NOT_FOUND';\n\nexport interface HttpArtifactResolverOptions {\n /** The served agent's invoke URL — the SAME path conversation turns POST to\n * (e.g. `'https://host/invoke'` or a relative `'/invoke'`). */\n readonly url: string;\n /** The session whose runs minted the refs. Redemption is governed by it:\n * a ref from another session answers the same not-found a missing ref\n * does. Omit only for a host that binds the session another way (a session\n * cookie); a wire that requires one will answer its own teaching refusal,\n * which the resolver surfaces verbatim. */\n readonly sessionId?: string;\n /** The caller's user id, on wires that carry one. */\n readonly userId?: string;\n /** Extra headers (an auth token, a tenant header). `content-type` is set\n * by the resolver. */\n readonly headers?: Readonly<Record<string, string>>;\n /** The fetch to use. Default: the global `fetch`. Injectable for tests and\n * for hosts that need credentialed fetch (`credentials: 'include'` — wrap\n * and forward). */\n readonly fetch?: typeof fetch;\n}\n\n/**\n * Redeem refs over a served agent's wire — `standingAgent` + `httpHost` /\n * `nodeHost`, or the managed-runtime dialect (both answer the same\n * `{ artifact: … }` body; the managed one adds `status` beside it, which is\n * read past).\n *\n * Never throws for wire answers: outcomes come back as\n * {@link ArtifactResolution} arms so a pane can branch. A fetch that cannot\n * reach the host at all resolves to `failed` with the network error named.\n */\nexport function httpArtifactResolver(options: HttpArtifactResolverOptions): ArtifactResolver {\n if (typeof options?.url !== 'string' || options.url.trim().length === 0) {\n throw new Error(\n \"httpArtifactResolver needs `url` — the served agent's invoke path, the same one \" +\n \"conversation turns POST to (e.g. '/invoke' or 'https://host/invoke').\",\n );\n }\n const doFetch = options.fetch ?? globalThis.fetch;\n if (typeof doFetch !== 'function') {\n throw new Error(\n 'httpArtifactResolver found no fetch: this runtime has no global fetch and none was ' +\n 'passed. Pass one via { fetch } (Node < 18 needs a polyfill).',\n );\n }\n\n const redeem = async (op: string, ref: string): Promise<ArtifactResolution> => {\n let response: Response;\n try {\n response = await doFetch(options.url, {\n method: 'POST',\n headers: { 'content-type': 'application/json', ...options.headers },\n body: JSON.stringify({\n op,\n ref,\n ...(options.sessionId !== undefined && { sessionId: options.sessionId }),\n ...(options.userId !== undefined && { userId: options.userId }),\n }),\n });\n } catch (err) {\n return {\n status: 'failed',\n message: `Could not reach ${options.url} to redeem '${ref}' (${\n err instanceof Error ? err.name || 'network error' : 'network error'\n }).`,\n };\n }\n let body: Record<string, unknown>;\n try {\n body = (await response.json()) as Record<string, unknown>;\n } catch {\n return {\n status: 'failed',\n message: `${options.url} answered ${response.status} with a body that is not JSON — not an artifact wire reply.`,\n };\n }\n const artifact = body?.artifact;\n if (artifact !== null && typeof artifact === 'object') {\n const parcel = artifact as Record<string, unknown>;\n const meta = parcel.meta;\n if (meta === null || typeof meta !== 'object' || typeof (meta as ArtifactMetaView).kind !== 'string') {\n return {\n status: 'failed',\n message: `${options.url} answered with an artifact body carrying no readable meta — not the published wire shape.`,\n };\n }\n return {\n status: 'live',\n meta: meta as ArtifactMetaView,\n ...(op === ARTIFACT_GET_OP && 'data' in parcel && { data: parcel.data }),\n };\n }\n const code = typeof body?.code === 'string' ? body.code : undefined;\n if (code === NOT_FOUND_CODE) return { status: 'absent' };\n // The door refused or errored. Surface ITS sentence — refusals teach.\n const message =\n typeof body?.error === 'string'\n ? body.error\n : `${options.url} answered ${response.status} with no error message.`;\n return { status: 'failed', message, ...(code !== undefined && { code }) };\n };\n\n return {\n head: (ref) => redeem(ARTIFACT_HEAD_OP, ref),\n get: (ref) => redeem(ARTIFACT_GET_OP, ref),\n };\n}\n\n/**\n * The store half of `storeArtifactResolver` — duck-typed against\n * agentfootprint's five-verb `ArtifactStore` port (only the two read verbs\n * are used; a hand-rolled test double needs nothing else).\n */\nexport interface ArtifactStoreLike {\n head(scope: unknown, ref: string): Promise<ArtifactMetaView | null>;\n get(scope: unknown, ref: string): Promise<{ meta: ArtifactMetaView; data: unknown } | null>;\n}\n\nexport interface StoreArtifactResolverOptions {\n /** The store itself — `inMemoryArtifacts()`, `sqliteArtifacts(...)`, or any\n * object with the two read verbs. */\n readonly store: ArtifactStoreLike;\n /**\n * The isolation scope the run's tools minted under — the same\n * tenant/principal/conversation tuple memory scopes on. REQUIRED, not\n * defaulted: a defaulted scope would silently resolve nothing for scoped\n * refs (wrong scope IS \"no data\"), which is the accepted-and-silently-wrong\n * failure. State the scope; an anonymous run's is `{ conversationId: runId }`.\n */\n readonly scope: unknown;\n}\n\n/**\n * Redeem refs against a directly passed store — the same-process door for\n * demos, tests and apps that run the agent in the page's own process. The\n * store's `null` (missing-or-expired, deliberately ambiguous) becomes\n * `absent`; a store that THROWS (an integrity digest mismatch refusing to\n * deliver corrupt bytes) becomes `failed` with the store's own sentence.\n */\nexport function storeArtifactResolver(options: StoreArtifactResolverOptions): ArtifactResolver {\n const store = options?.store;\n if (\n store === null ||\n typeof store !== 'object' ||\n typeof store.head !== 'function' ||\n typeof store.get !== 'function'\n ) {\n throw new Error(\n 'storeArtifactResolver needs `store` — an object with the artifact read verbs ' +\n '`head(scope, ref)` and `get(scope, ref)` (any agentfootprint artifact store qualifies).',\n );\n }\n if (!('scope' in (options as object))) {\n throw new Error(\n 'storeArtifactResolver needs `scope` — the isolation tuple the refs were minted under. ' +\n 'A wrong scope resolves to \"no data\" by design, so it must be stated, never guessed.',\n );\n }\n\n const failed = (ref: string, err: unknown): ArtifactResolution => ({\n status: 'failed',\n message:\n err instanceof Error && err.message\n ? err.message\n : `The store threw while redeeming '${ref}'.`,\n });\n\n return {\n async head(ref) {\n try {\n const meta = await store.head(options.scope, ref);\n return meta === null ? { status: 'absent' } : { status: 'live', meta };\n } catch (err) {\n return failed(ref, err);\n }\n },\n async get(ref) {\n try {\n const record = await store.get(options.scope, ref);\n return record === null\n ? { status: 'absent' }\n : { status: 'live', meta: record.meta, data: record.data };\n } catch (err) {\n return failed(ref, err);\n }\n },\n };\n}\n","/**\n * Reading `present` calls back out of history — and the placeholder copy.\n *\n * The ref the model handed to the screen lives INSIDE the `present` tool\n * result (`{ presented: true, ref, as, snapshot }`) — the one thing provider\n * message history keeps typed and durable — and, when the run was recorded,\n * on the `agentfootprint.artifacts.presented` event. No parsing refs out of\n * prose: a regex over assistant text is the exact string-convention bug the\n * ecosystem spent releases killing.\n *\n * The placeholder is the load-bearing detail: when an artifact has expired,\n * the store can no longer describe what's gone, so the snapshot carried at\n * speak time is the pane's WHOLE diet —\n *\n * Chart — \"Q3 sales by region\" (bar-chart, 41.0 KB) — expired; re-run to regenerate.\n *\n * Never a blank pane, never a stale copy pretending to be live. This is\n * `#REF!`, taught manners.\n */\n\nimport { formatBytes } from '../bugReport/selection.js';\nimport type { PresentedCallView, PresentSnapshotView } from './types.js';\n\n/** The event a wire-recorded `present` rides. Matched by raw type string —\n * the lens compiles against an older event union (humanizeRouting precedent). */\nconst PRESENTED_EVENT_TYPE = 'agentfootprint.artifacts.presented';\n\n/** Validate the snapshot half of a presented shape. */\nfunction readSnapshot(value: unknown): PresentSnapshotView | undefined {\n if (value === null || typeof value !== 'object') return undefined;\n const s = value as Record<string, unknown>;\n if (typeof s.kind !== 'string' || typeof s.mediaType !== 'string' || typeof s.bytes !== 'number')\n return undefined;\n return {\n kind: s.kind,\n mediaType: s.mediaType,\n bytes: s.bytes,\n ...(typeof s.label === 'string' && { label: s.label }),\n };\n}\n\n/** ref + as + snapshot — the common trunk of the tool result and the event. */\nfunction readPresentedShape(\n value: Record<string, unknown>,\n): Omit<PresentedCallView, 'toolCallId' | 'iteration'> | undefined {\n if (typeof value.ref !== 'string' || typeof value.as !== 'string') return undefined;\n const snapshot = readSnapshot(value.snapshot);\n if (!snapshot) return undefined;\n return { ref: value.ref, as: value.as, snapshot };\n}\n\n/**\n * Read one tool RESULT as a `present` result, if it is one.\n *\n * Accepts the value as history stores it — the JSON string on the\n * `role: 'tool'` message — or the already-parsed object. Branches on\n * `presented: true` (the field the result carries for exactly this walk).\n * Returns `undefined` for anything else: this is a filter over arbitrary tool\n * results, and \"not a present call\" is a legitimate answer, not a swallowed\n * error.\n */\nexport function readPresentedResult(value: unknown): PresentedCallView | undefined {\n let parsed: unknown = value;\n if (typeof value === 'string') {\n try {\n parsed = JSON.parse(value);\n } catch {\n return undefined;\n }\n }\n if (parsed === null || typeof parsed !== 'object') return undefined;\n const record = parsed as Record<string, unknown>;\n if (record.presented !== true) return undefined;\n const trunk = readPresentedShape(record);\n if (!trunk) return undefined;\n return {\n ...trunk,\n ...(typeof record.toolCallId === 'string' && { toolCallId: record.toolCallId }),\n };\n}\n\n/**\n * Collect every presented artifact from an event log — a `Recording.events`\n * array or a `LensRecorder` event log (entries carrying `{ event }` are\n * unwrapped). Tolerant of `null` holes and foreign shapes: recordings from\n * other eras walk cleanly, and a malformed presented payload is skipped, not\n * invented.\n */\nexport function presentedFromEvents(\n events: ReadonlyArray<unknown> | null | undefined,\n): PresentedCallView[] {\n if (!events) return [];\n const found: PresentedCallView[] = [];\n for (const item of events) {\n if (item === null || typeof item !== 'object') continue;\n const wrapper = item as Record<string, unknown>;\n const event =\n typeof wrapper.type === 'string'\n ? wrapper\n : wrapper.event !== null && typeof wrapper.event === 'object'\n ? (wrapper.event as Record<string, unknown>)\n : undefined;\n if (!event || event.type !== PRESENTED_EVENT_TYPE) continue;\n const payload = event.payload;\n if (payload === null || typeof payload !== 'object') continue;\n const record = payload as Record<string, unknown>;\n const trunk = readPresentedShape(record);\n if (!trunk) continue;\n found.push({\n ...trunk,\n ...(typeof record.toolCallId === 'string' && { toolCallId: record.toolCallId }),\n ...(typeof record.iteration === 'number' && { iteration: record.iteration }),\n });\n }\n return found;\n}\n\n/** `'chart/spec'` → `'Chart'`; `'dataset/rows'` → `'Dataset'`; `''` → `'Artifact'`. */\nfunction kindNoun(kind: string): string {\n const head = kind.split('/')[0]?.trim() ?? '';\n if (head.length === 0) return 'Artifact';\n return head[0]!.toUpperCase() + head.slice(1);\n}\n\n/**\n * The descriptive head every pane state shares —\n * `Chart — \"Q3 sales by region\" (bar-chart, 41.0 KB)` — built from the\n * snapshot alone. A snapshot with no label names the ref instead: a fact the\n * call always carries, never an invented title.\n */\nexport function describePresented(presented: PresentedCallView): string {\n const { snapshot } = presented;\n const name = snapshot.label !== undefined ? `\"${snapshot.label}\"` : presented.ref;\n return `${kindNoun(snapshot.kind)} — ${name} (${presented.as}, ${formatBytes(snapshot.bytes)})`;\n}\n\n/**\n * The stated absence, rendered from the snapshot alone — no store round-trip\n * beyond the failed head. Missing, expired and another-session's ref all\n * answer one indistinguishable not-found by design, and this one line covers\n * them all:\n *\n * Chart — \"Q3 sales by region\" (bar-chart, 41.0 KB) — expired; re-run to regenerate.\n */\nexport function artifactPlaceholder(presented: PresentedCallView): string {\n return `${describePresented(presented)} — expired; re-run to regenerate.`;\n}\n","/**\n * The headless half of typed HITL: reading the component out of an awaiting\n * payload, building the structured decision, and rendering it as words.\n *\n * The governing law, stated once and honored everywhere here: **decisions\n * land as STRUCTURED facts on the record; natural language is a rendering of\n * the decision, never the record.** `decisionSentence` exists so a screen can\n * say \"Approved by alice@ops\" after the click — the sentence is display; the\n * `{ approved, by, at }` object that posted is the fact.\n */\n\nimport type {\n AskComponentView,\n ConsentDecisionView,\n DecisionRequestBody,\n PendingAskView,\n} from './types.js';\n\n/**\n * The ONE reader of \"the component of this awaiting payload\" — era-robust.\n *\n * agentfootprint 9.24 lifts the component onto `PendingAsk.component`, one\n * place for every pause kind. This reader checks that place first, then walks\n * the three homes inside `pauseData` (top-level `component` for a plain\n * `askHuman`, `checkIn.component` for a consent gate, `ask.component` for a\n * middleware ask) — the same walk agentfootprint's own `readAskComponent`\n * does — so a hand-rolled host that forwards `pauseData` without the lift\n * still shows its person the typed question.\n *\n * Duck-shaped on purpose: a value that is not a plausible component is\n * reported absent, never guessed at — the pane then renders the prose\n * `question` exactly as every pre-9.24 screen did.\n */\nexport function readAwaitingComponent(awaiting: unknown): AskComponentView | undefined {\n if (typeof awaiting !== 'object' || awaiting === null) return undefined;\n const pending = awaiting as PendingAskView;\n const direct = asComponent(pending.component);\n if (direct) return direct;\n const bag = pending.pauseData;\n if (typeof bag !== 'object' || bag === null) return undefined;\n const homes = bag as {\n component?: unknown;\n checkIn?: { component?: unknown };\n ask?: { component?: unknown };\n };\n return (\n asComponent(homes.component) ??\n asComponent(\n typeof homes.checkIn === 'object' && homes.checkIn !== null\n ? homes.checkIn.component\n : undefined,\n ) ??\n asComponent(\n typeof homes.ask === 'object' && homes.ask !== null ? homes.ask.component : undefined,\n )\n );\n}\n\n/** A plausible AskComponent, or nothing — never a guess. */\nfunction asComponent(value: unknown): AskComponentView | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const c = value as { componentId?: unknown };\n if (typeof c.componentId !== 'string' || c.componentId.length === 0) return undefined;\n return value as AskComponentView;\n}\n\n/**\n * Is this awaiting payload a CONSENT gate — a tool `checkIn` or a middleware\n * `ask`? Those are answered with the approve/decline vocabulary\n * ({@link approveDecision} / {@link declineDecision}); a plain `askHuman`\n * pause is answered with whatever value the tool's author documented.\n * agentfootprint's wire REFUSES a consent gate answered with a bare value, so\n * a screen that gets this wrong is told loudly — this predicate is how a\n * screen gets it right the first time.\n */\nexport function isConsentAsk(awaiting: unknown): boolean {\n if (typeof awaiting !== 'object' || awaiting === null) return false;\n const pending = awaiting as PendingAskView;\n return (\n (typeof pending.checkIn === 'object' && pending.checkIn !== null) ||\n (typeof pending.ask === 'object' && pending.ask !== null)\n );\n}\n\n/** Options for {@link approveDecision} / {@link declineDecision}. */\nexport interface ConsentDecisionInput {\n /** Who decided — an operator id, an email. REQUIRED: an audit row with no\n * actor is the accepted-and-silently-wrong record these gates exist to\n * prevent. */\n readonly by: string;\n /** Optional free-text note. On decline it is surfaced to the model. */\n readonly note?: string;\n}\n\n/**\n * Approve a pending consent gate — the paused tool executes on resume.\n * Byte-compatible with agentfootprint's `checkInApproved()` (mirrored by\n * value; the lens never imports agentfootprint — peer-era law).\n */\nexport function approveDecision(input: ConsentDecisionInput): ConsentDecisionView {\n return buildConsent(true, input, 'approveDecision');\n}\n\n/** Decline a pending consent gate — the tool is NOT executed; the model\n * receives the decline (and the note) and adapts in-loop. */\nexport function declineDecision(input: ConsentDecisionInput): ConsentDecisionView {\n return buildConsent(false, input, 'declineDecision');\n}\n\nfunction buildConsent(\n approved: boolean,\n input: ConsentDecisionInput,\n door: string,\n): ConsentDecisionView {\n if (typeof input?.by !== 'string' || input.by.trim().length === 0) {\n throw new Error(\n `${door} needs \\`by\\` — who is deciding (an operator id, an email). The decision is ` +\n `an audit record, and a record with no actor names nobody; it cannot be defaulted.`,\n );\n }\n return {\n approved,\n by: input.by,\n at: Date.now(),\n ...(input.note !== undefined && input.note.length > 0 && { note: input.note }),\n };\n}\n\n/** Options for {@link decisionRequestBody}. */\nexport interface DecisionRequestInput {\n /** The structured decision — the record. For consent gates, the object\n * {@link approveDecision} / {@link declineDecision} built; for a plain\n * `askHuman`, whatever value the tool's author documented. */\n readonly decision: unknown;\n /** The session holding the paused run — `awaiting.sessionId`. */\n readonly sessionId?: string;\n /** A new message to ride along; almost always omitted (`''`). */\n readonly input?: string;\n}\n\n/**\n * The request body that posts a decision back — agentfootprint's JSON wire\n * shape `{ input, sessionId?, decision }`, where the PRESENCE of `decision`\n * is what makes the request a resume instead of a new message.\n *\n * The lens does not own the POST — the host app does (its URL, its auth, its\n * fetch). This helper only guarantees the body says what the person decided:\n * `JSON.stringify(decisionRequestBody({ decision, sessionId }))` is the whole\n * payload.\n *\n * An `undefined` decision is refused rather than serialized away: JSON drops\n * the key, the wire would read the request as a NEW MESSAGE, and the pause\n * would sit unanswered while the screen believed it had answered — the exact\n * silently-wrong outcome this helper exists to make impossible. (`null` is a\n * fine decision; absence is not.)\n */\nexport function decisionRequestBody(args: DecisionRequestInput): DecisionRequestBody {\n if (args === null || typeof args !== 'object' || !('decision' in args)) {\n throw new Error(\n 'decisionRequestBody needs `decision` — the structured answer to the pending ask. ' +\n 'Its presence is what distinguishes a resume from a new message on the wire.',\n );\n }\n if (args.decision === undefined) {\n throw new Error(\n 'decisionRequestBody refused `decision: undefined` — JSON drops the key, the wire ' +\n 'would read a NEW MESSAGE, and the pause would sit unanswered while the screen ' +\n 'believed it answered. Post the actual decision (`null` is allowed; absence is not).',\n );\n }\n return {\n input: args.input ?? '',\n decision: args.decision,\n ...(args.sessionId !== undefined && { sessionId: args.sessionId }),\n };\n}\n\n/** How many characters of a structured decision's JSON the sentence quotes\n * before eliding — the sentence is display, not the record. */\nconst SENTENCE_JSON_CAP = 120;\n\n/**\n * \"Interact-to-NL\": render a decision as one plain sentence — **display\n * only**. The record is the structured decision that posted; this sentence is\n * a rendering of it, never a substitute for it, and nothing ever parses it\n * back.\n *\n * approve/decline → `Approved by alice@ops — \"verified with customer\".`\n * a string → `Answered: \"option-42\".`\n * anything else → `Answered with a structured decision: {...}.`\n */\nexport function decisionSentence(decision: unknown): string {\n if (isConsentDecision(decision)) {\n const verb = decision.approved ? 'Approved' : 'Declined';\n const note = decision.note !== undefined ? ` — \"${decision.note}\"` : '';\n return `${verb} by ${decision.by}${note}.`;\n }\n if (typeof decision === 'string') return `Answered: \"${decision}\".`;\n if (decision === null || typeof decision !== 'object')\n return `Answered: ${String(decision)}.`;\n let json: string;\n try {\n json = JSON.stringify(decision) ?? String(decision);\n } catch {\n json = '[unserializable]';\n }\n if (json.length > SENTENCE_JSON_CAP) json = `${json.slice(0, SENTENCE_JSON_CAP)}…`;\n return `Answered with a structured decision: ${json}.`;\n}\n\n/** Is this decision the consent vocabulary? Mirrors `isCheckInDecision`. */\nexport function isConsentDecision(value: unknown): value is ConsentDecisionView {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as ConsentDecisionView).approved === 'boolean' &&\n typeof (value as ConsentDecisionView).by === 'string'\n );\n}\n"],"mappings":"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","names":["resolve","resolve","resolve","resolve"]}
package/dist/core.cjs CHANGED
@@ -1546,7 +1546,12 @@ function buildStepGraphFromSnapshot(snapshot) {
1546
1546
  visit(snapshot.executionTree, [], ctx);
1547
1547
  return { nodes: ctx.nodes, edges: ctx.edges };
1548
1548
  }
1549
- function visit(stage, parentPath, ctx) {
1549
+ function visit(first, parentPath, ctx) {
1550
+ for (let stage = first; stage !== void 0; stage = stage.next) {
1551
+ visitOne(stage, parentPath, ctx);
1552
+ }
1553
+ }
1554
+ function visitOne(stage, parentPath, ctx) {
1550
1555
  const primitiveKind = parsePrimitiveKind2(stage.description);
1551
1556
  const isPrimitive = primitiveKind !== void 0;
1552
1557
  const subflowPath = stage.subflowId ? [...parentPath, stage.subflowId] : parentPath;
@@ -1616,7 +1621,6 @@ function visit(stage, parentPath, ctx) {
1616
1621
  });
1617
1622
  }
1618
1623
  }
1619
- visit(stage.next, parentPath, ctx);
1620
1624
  }
1621
1625
  }
1622
1626
  function findFirstPrimitive(stage) {