@agent-inspect/tui 6.14.0 → 6.14.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.
package/dist/index.cjs CHANGED
@@ -60,9 +60,32 @@ function buildTuiTraceModel(events) {
60
60
  }
61
61
  const roots = [];
62
62
  const sortByStarted = (a, b) => a.startedAt - b.startedAt;
63
+ const parentOf = /* @__PURE__ */ new Map();
64
+ const candidates = [...nodes.values()].filter(
65
+ (n) => n.parentId !== void 0 && n.parentId !== n.id && nodes.has(n.parentId)
66
+ ).sort(sortByStarted);
67
+ for (const n of candidates) {
68
+ const parentId = n.parentId;
69
+ parentOf.set(n.id, parentId);
70
+ let cursor = parentId;
71
+ const seen = /* @__PURE__ */ new Set([n.id]);
72
+ let cyclic = false;
73
+ while (cursor) {
74
+ if (seen.has(cursor)) {
75
+ cyclic = true;
76
+ break;
77
+ }
78
+ seen.add(cursor);
79
+ cursor = parentOf.get(cursor);
80
+ }
81
+ if (cyclic) {
82
+ parentOf.delete(n.id);
83
+ }
84
+ }
63
85
  for (const n of nodes.values()) {
64
- if (n.parentId !== void 0 && nodes.has(n.parentId)) {
65
- nodes.get(n.parentId).children.push(n);
86
+ const parentId = parentOf.get(n.id);
87
+ if (parentId) {
88
+ nodes.get(parentId).children.push(n);
66
89
  } else {
67
90
  roots.push(n);
68
91
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tree-model.ts","../src/trace-loader.ts","../src/keymap.ts","../src/expand.ts","../src/index-cjs.ts"],"names":["resolveTraceDir","readTraceEvents"],"mappings":"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","file":"index.cjs","sourcesContent":["import type {\n RunCompletedEvent,\n RunStartedEvent,\n StepCompletedEvent,\n StepStartedEvent,\n TraceEvent,\n} from \"agent-inspect/advanced\";\n\nimport type { TuiTraceModel, TuiTraceNode } from \"./types.js\";\n\ntype StepBuild = {\n id: string;\n parentId?: string;\n name: string;\n type: string;\n status: string;\n durationMs?: number;\n startedAt: number;\n error?: string;\n metadata?: Record<string, unknown>;\n children: StepBuild[];\n};\n\nfunction dfsFlat(roots: TuiTraceNode[], out: TuiTraceNode[]): void {\n for (const n of roots) {\n out.push(n);\n if (n.children.length > 0) dfsFlat(n.children, out);\n }\n}\n\nfunction toTuiNodes(builds: StepBuild[], depth: number): TuiTraceNode[] {\n return builds.map((b) => ({\n id: b.id,\n name: b.name,\n type: b.type,\n status: b.status,\n durationMs: b.durationMs,\n depth,\n parentId: b.parentId,\n error: b.error,\n metadata: b.metadata,\n children: toTuiNodes(b.children, depth + 1),\n }));\n}\n\n/**\n * Build a navigable tree model from v0.1 JSONL trace events.\n * Does not mutate the input array or event objects.\n */\nexport function buildTuiTraceModel(events: TraceEvent[]): TuiTraceModel {\n const started = events.find((e): e is RunStartedEvent => e.event === \"run_started\");\n if (!started) {\n throw new Error(\"Invalid trace: missing run_started\");\n }\n\n const runId = started.runId;\n const runName = started.name;\n\n const completedAll = events.filter((e): e is RunCompletedEvent => e.event === \"run_completed\");\n const lastCompleted = completedAll[completedAll.length - 1];\n const runStatus = lastCompleted ? lastCompleted.status : \"running\";\n const runDurationMs =\n lastCompleted !== undefined && Number.isFinite(lastCompleted.durationMs)\n ? lastCompleted.durationMs\n : undefined;\n\n const nodes = new Map<string, StepBuild>();\n\n for (const e of events) {\n if (e.event !== \"step_started\") continue;\n const s = e as StepStartedEvent;\n nodes.set(s.stepId, {\n id: s.stepId,\n parentId: s.parentId,\n name: s.name,\n type: s.type,\n status: \"running\",\n startedAt: s.startTime,\n metadata: s.metadata as Record<string, unknown> | undefined,\n children: [],\n });\n }\n\n for (const e of events) {\n if (e.event !== \"step_completed\") continue;\n const c = e as StepCompletedEvent;\n const node = nodes.get(c.stepId);\n if (!node) continue;\n node.status = c.status;\n node.durationMs = c.durationMs;\n node.error =\n c.error !== undefined && typeof c.error.message === \"string\"\n ? c.error.message\n : undefined;\n }\n\n const roots: StepBuild[] = [];\n const sortByStarted = (a: StepBuild, b: StepBuild) => a.startedAt - b.startedAt;\n\n for (const n of nodes.values()) {\n if (n.parentId !== undefined && nodes.has(n.parentId)) {\n nodes.get(n.parentId)!.children.push(n);\n } else {\n roots.push(n);\n }\n }\n\n roots.sort(sortByStarted);\n for (const n of nodes.values()) {\n n.children.sort(sortByStarted);\n }\n\n const treeRoots = toTuiNodes(roots, 0);\n const flatNodes: TuiTraceNode[] = [];\n dfsFlat(treeRoots, flatNodes);\n\n return {\n runId,\n name: runName,\n status: runStatus,\n durationMs: runDurationMs,\n nodes: treeRoots,\n flatNodes,\n };\n}\n\n/** Total step count in tree (for default expand policy). Exported for tests. */\nexport function countTreeSteps(roots: TuiTraceNode[]): number {\n let n = 0;\n for (const r of roots) {\n n += 1 + countSubtree(r.children);\n }\n return n;\n}\n\nfunction countSubtree(children: TuiTraceNode[]): number {\n let n = 0;\n for (const c of children) {\n n += 1 + countSubtree(c.children);\n }\n return n;\n}\n","import { readTraceEvents, resolveTraceDir } from \"agent-inspect/advanced\";\n\nimport { buildTuiTraceModel } from \"./tree-model.js\";\nimport type { TuiTraceModel } from \"./types.js\";\n\nexport interface LoadTraceForTuiOptions {\n runId: string;\n dir?: string;\n}\n\n/**\n * Load JSONL trace events and build a TUI model. Does not write or mutate trace files.\n */\nexport async function loadTraceForTui(options: LoadTraceForTuiOptions): Promise<TuiTraceModel> {\n const traceDir = resolveTraceDir({ dir: options.dir });\n const events = await readTraceEvents(options.runId, traceDir);\n\n if (events.length === 0) {\n throw new Error(\n `Run not found or trace is empty: ${options.runId} (directory: ${traceDir})`,\n );\n }\n\n return buildTuiTraceModel(events);\n}\n","export type TuiAction =\n | \"up\"\n | \"down\"\n | \"expand\"\n | \"collapse\"\n | \"toggle\"\n | \"details\"\n | \"help\"\n | \"quit\"\n | \"unknown\";\n\n/** Map Ink `useInput` args to a semantic action. Pure helper for tests. */\nexport function mapInputToAction(\n input: string,\n key: Partial<{\n name: string;\n ctrl: boolean;\n meta: boolean;\n shift: boolean;\n return: boolean;\n escape: boolean;\n upArrow: boolean;\n downArrow: boolean;\n leftArrow: boolean;\n rightArrow: boolean;\n }> = {},\n): TuiAction {\n if (key.escape === true) return \"quit\";\n if (key.ctrl === true && input === \"c\") return \"quit\";\n\n if (input === \"q\" || input === \"Q\") return \"quit\";\n\n if (input === \"?\") return \"help\";\n\n if (input === \"d\" || input === \"D\") return \"details\";\n\n if (key.return === true) return \"expand\";\n\n if (input === \" \") return \"toggle\";\n\n if (key.upArrow === true || input === \"k\") return \"up\";\n if (key.downArrow === true || input === \"j\") return \"down\";\n if (key.rightArrow === true || input === \"l\") return \"expand\";\n if (key.leftArrow === true || input === \"h\") return \"collapse\";\n\n return \"unknown\";\n}\n","import type { TuiTraceModel } from \"./types.js\";\n\n/** Small traces: expand all branches. Larger traces: only root rows expanded (show first nesting level). */\nexport function initialExpandedSet(model: TuiTraceModel): Set<string> {\n const s = new Set<string>();\n const small = model.flatNodes.length <= 15;\n if (small) {\n for (const n of model.flatNodes) {\n if (n.children.length > 0) s.add(n.id);\n }\n return s;\n }\n for (const r of model.nodes) {\n if (r.children.length > 0) s.add(r.id);\n }\n return s;\n}\n","/**\n * @experimental Optional TUI package CommonJS entry.\n *\n * Keep this entry free of eager Ink imports so `require(\"@agent-inspect/tui\")`\n * can load pure helpers even though Ink is ESM with top-level await.\n */\nexport type { TuiTraceModel, TuiTraceNode } from \"./types.js\";\nexport { buildTuiTraceModel, countTreeSteps } from \"./tree-model.js\";\nexport type { LoadTraceForTuiOptions } from \"./trace-loader.js\";\nexport { loadTraceForTui } from \"./trace-loader.js\";\nexport type { TuiAction } from \"./keymap.js\";\nexport { mapInputToAction } from \"./keymap.js\";\nexport type { TraceViewerAppProps } from \"./app.js\";\nexport { initialExpandedSet } from \"./expand.js\";\nexport type { RunTraceViewerOptions } from \"./run-viewer.js\";\n\nimport type { RunTraceViewerOptions } from \"./run-viewer.js\";\n\nexport async function runTraceViewer(options: RunTraceViewerOptions): Promise<void> {\n const esmEntry = \"./index.mjs\";\n const mod = await import(esmEntry) as {\n runTraceViewer(options: RunTraceViewerOptions): Promise<void>;\n };\n return mod.runTraceViewer(options);\n}\n"]}
1
+ {"version":3,"sources":["../src/tree-model.ts","../src/trace-loader.ts","../src/keymap.ts","../src/expand.ts","../src/index-cjs.ts"],"names":["resolveTraceDir","readTraceEvents"],"mappings":";;;;;AAuBA,SAAS,OAAA,CAAQ,OAAuB,GAAA,EAA2B;AACjE,EAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,IAAA,GAAA,CAAI,KAAK,CAAC,CAAA;AACV,IAAA,IAAI,EAAE,QAAA,CAAS,MAAA,GAAS,GAAG,OAAA,CAAQ,CAAA,CAAE,UAAU,GAAG,CAAA;AAAA,EACpD;AACF;AAEA,SAAS,UAAA,CAAW,QAAqB,KAAA,EAA+B;AACtE,EAAA,OAAO,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,IACxB,IAAI,CAAA,CAAE,EAAA;AAAA,IACN,MAAM,CAAA,CAAE,IAAA;AAAA,IACR,MAAM,CAAA,CAAE,IAAA;AAAA,IACR,QAAQ,CAAA,CAAE,MAAA;AAAA,IACV,YAAY,CAAA,CAAE,UAAA;AAAA,IACd,KAAA;AAAA,IACA,UAAU,CAAA,CAAE,QAAA;AAAA,IACZ,OAAO,CAAA,CAAE,KAAA;AAAA,IACT,UAAU,CAAA,CAAE,QAAA;AAAA,IACZ,QAAA,EAAU,UAAA,CAAW,CAAA,CAAE,QAAA,EAAU,QAAQ,CAAC;AAAA,GAC5C,CAAE,CAAA;AACJ;AAMO,SAAS,mBAAmB,MAAA,EAAqC;AACtE,EAAA,MAAM,UAAU,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAA4B,CAAA,CAAE,UAAU,aAAa,CAAA;AAClF,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,MAAM,oCAAoC,CAAA;AAAA,EACtD;AAEA,EAAA,MAAM,QAAQ,OAAA,CAAQ,KAAA;AACtB,EAAA,MAAM,UAAU,OAAA,CAAQ,IAAA;AAExB,EAAA,MAAM,eAAe,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,KAA8B,CAAA,CAAE,UAAU,eAAe,CAAA;AAC7F,EAAA,MAAM,aAAA,GAAgB,YAAA,CAAa,YAAA,CAAa,MAAA,GAAS,CAAC,CAAA;AAC1D,EAAA,MAAM,SAAA,GAAY,aAAA,GAAgB,aAAA,CAAc,MAAA,GAAS,SAAA;AACzD,EAAA,MAAM,aAAA,GACJ,kBAAkB,MAAA,IAAa,MAAA,CAAO,SAAS,aAAA,CAAc,UAAU,CAAA,GACnE,aAAA,CAAc,UAAA,GACd,MAAA;AAEN,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAuB;AAEzC,EAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACtB,IAAA,IAAI,CAAA,CAAE,UAAU,cAAA,EAAgB;AAChC,IAAA,MAAM,CAAA,GAAI,CAAA;AACV,IAAA,KAAA,CAAM,GAAA,CAAI,EAAE,MAAA,EAAQ;AAAA,MAClB,IAAI,CAAA,CAAE,MAAA;AAAA,MACN,UAAU,CAAA,CAAE,QAAA;AAAA,MACZ,MAAM,CAAA,CAAE,IAAA;AAAA,MACR,MAAM,CAAA,CAAE,IAAA;AAAA,MACR,MAAA,EAAQ,SAAA;AAAA,MACR,WAAW,CAAA,CAAE,SAAA;AAAA,MACb,UAAU,CAAA,CAAE,QAAA;AAAA,MACZ,UAAU;AAAC,KACZ,CAAA;AAAA,EACH;AAEA,EAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACtB,IAAA,IAAI,CAAA,CAAE,UAAU,gBAAA,EAAkB;AAClC,IAAA,MAAM,CAAA,GAAI,CAAA;AACV,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,GAAA,CAAI,CAAA,CAAE,MAAM,CAAA;AAC/B,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,IAAA,CAAK,SAAS,CAAA,CAAE,MAAA;AAChB,IAAA,IAAA,CAAK,aAAa,CAAA,CAAE,UAAA;AACpB,IAAA,IAAA,CAAK,KAAA,GACH,CAAA,CAAE,KAAA,KAAU,MAAA,IAAa,OAAO,CAAA,CAAE,KAAA,CAAM,OAAA,KAAY,QAAA,GAChD,CAAA,CAAE,KAAA,CAAM,OAAA,GACR,MAAA;AAAA,EACR;AAEA,EAAA,MAAM,QAAqB,EAAC;AAC5B,EAAA,MAAM,gBAAgB,CAAC,CAAA,EAAc,CAAA,KAAiB,CAAA,CAAE,YAAY,CAAA,CAAE,SAAA;AACtE,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAoB;AAIzC,EAAA,MAAM,aAAa,CAAC,GAAG,KAAA,CAAM,MAAA,EAAQ,CAAA,CAClC,MAAA;AAAA,IACC,CAAC,CAAA,KACC,CAAA,CAAE,QAAA,KAAa,MAAA,IACf,CAAA,CAAE,QAAA,KAAa,CAAA,CAAE,EAAA,IACjB,KAAA,CAAM,GAAA,CAAI,CAAA,CAAE,QAAQ;AAAA,GACxB,CACC,KAAK,aAAa,CAAA;AAErB,EAAA,KAAA,MAAW,KAAK,UAAA,EAAY;AAC1B,IAAA,MAAM,WAAW,CAAA,CAAE,QAAA;AACnB,IAAA,QAAA,CAAS,GAAA,CAAI,CAAA,CAAE,EAAA,EAAI,QAAQ,CAAA;AAC3B,IAAA,IAAI,MAAA,GAA6B,QAAA;AACjC,IAAA,MAAM,uBAAO,IAAI,GAAA,CAAY,CAAC,CAAA,CAAE,EAAE,CAAC,CAAA;AACnC,IAAA,IAAI,MAAA,GAAS,KAAA;AACb,IAAA,OAAO,MAAA,EAAQ;AACb,MAAA,IAAI,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,EAAG;AACpB,QAAA,MAAA,GAAS,IAAA;AACT,QAAA;AAAA,MACF;AACA,MAAA,IAAA,CAAK,IAAI,MAAM,CAAA;AACf,MAAA,MAAA,GAAS,QAAA,CAAS,IAAI,MAAM,CAAA;AAAA,IAC9B;AACA,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,QAAA,CAAS,MAAA,CAAO,EAAE,EAAE,CAAA;AAAA,IACtB;AAAA,EACF;AAEA,EAAA,KAAA,MAAW,CAAA,IAAK,KAAA,CAAM,MAAA,EAAO,EAAG;AAC9B,IAAA,MAAM,QAAA,GAAW,QAAA,CAAS,GAAA,CAAI,CAAA,CAAE,EAAE,CAAA;AAClC,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,KAAA,CAAM,GAAA,CAAI,QAAQ,CAAA,CAAG,QAAA,CAAS,KAAK,CAAC,CAAA;AAAA,IACtC,CAAA,MAAO;AACL,MAAA,KAAA,CAAM,KAAK,CAAC,CAAA;AAAA,IACd;AAAA,EACF;AAEA,EAAA,KAAA,CAAM,KAAK,aAAa,CAAA;AACxB,EAAA,KAAA,MAAW,CAAA,IAAK,KAAA,CAAM,MAAA,EAAO,EAAG;AAC9B,IAAA,CAAA,CAAE,QAAA,CAAS,KAAK,aAAa,CAAA;AAAA,EAC/B;AAEA,EAAA,MAAM,SAAA,GAAY,UAAA,CAAW,KAAA,EAAO,CAAC,CAAA;AACrC,EAAA,MAAM,YAA4B,EAAC;AACnC,EAAA,OAAA,CAAQ,WAAW,SAAS,CAAA;AAE5B,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,IAAA,EAAM,OAAA;AAAA,IACN,MAAA,EAAQ,SAAA;AAAA,IACR,UAAA,EAAY,aAAA;AAAA,IACZ,KAAA,EAAO,SAAA;AAAA,IACP;AAAA,GACF;AACF;AAGO,SAAS,eAAe,KAAA,EAA+B;AAC5D,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,IAAA,CAAA,IAAK,CAAA,GAAI,YAAA,CAAa,CAAA,CAAE,QAAQ,CAAA;AAAA,EAClC;AACA,EAAA,OAAO,CAAA;AACT;AAEA,SAAS,aAAa,QAAA,EAAkC;AACtD,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACxB,IAAA,CAAA,IAAK,CAAA,GAAI,YAAA,CAAa,CAAA,CAAE,QAAQ,CAAA;AAAA,EAClC;AACA,EAAA,OAAO,CAAA;AACT;AChKA,eAAsB,gBAAgB,OAAA,EAAyD;AAC7F,EAAA,MAAM,WAAWA,wBAAA,CAAgB,EAAE,GAAA,EAAK,OAAA,CAAQ,KAAK,CAAA;AACrD,EAAA,MAAM,MAAA,GAAS,MAAMC,wBAAA,CAAgB,OAAA,CAAQ,OAAO,QAAQ,CAAA;AAE5D,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,iCAAA,EAAoC,OAAA,CAAQ,KAAK,CAAA,aAAA,EAAgB,QAAQ,CAAA,CAAA;AAAA,KAC3E;AAAA,EACF;AAEA,EAAA,OAAO,mBAAmB,MAAM,CAAA;AAClC;;;ACZO,SAAS,gBAAA,CACd,KAAA,EACA,GAAA,GAWK,EAAC,EACK;AACX,EAAA,IAAI,GAAA,CAAI,MAAA,KAAW,IAAA,EAAM,OAAO,MAAA;AAChC,EAAA,IAAI,GAAA,CAAI,IAAA,KAAS,IAAA,IAAQ,KAAA,KAAU,KAAK,OAAO,MAAA;AAE/C,EAAA,IAAI,KAAA,KAAU,GAAA,IAAO,KAAA,KAAU,GAAA,EAAK,OAAO,MAAA;AAE3C,EAAA,IAAI,KAAA,KAAU,KAAK,OAAO,MAAA;AAE1B,EAAA,IAAI,KAAA,KAAU,GAAA,IAAO,KAAA,KAAU,GAAA,EAAK,OAAO,SAAA;AAE3C,EAAA,IAAI,GAAA,CAAI,MAAA,KAAW,IAAA,EAAM,OAAO,QAAA;AAEhC,EAAA,IAAI,KAAA,KAAU,KAAK,OAAO,QAAA;AAE1B,EAAA,IAAI,GAAA,CAAI,OAAA,KAAY,IAAA,IAAQ,KAAA,KAAU,KAAK,OAAO,IAAA;AAClD,EAAA,IAAI,GAAA,CAAI,SAAA,KAAc,IAAA,IAAQ,KAAA,KAAU,KAAK,OAAO,MAAA;AACpD,EAAA,IAAI,GAAA,CAAI,UAAA,KAAe,IAAA,IAAQ,KAAA,KAAU,KAAK,OAAO,QAAA;AACrD,EAAA,IAAI,GAAA,CAAI,SAAA,KAAc,IAAA,IAAQ,KAAA,KAAU,KAAK,OAAO,UAAA;AAEpD,EAAA,OAAO,SAAA;AACT;;;AC3CO,SAAS,mBAAmB,KAAA,EAAmC;AACpE,EAAA,MAAM,CAAA,uBAAQ,GAAA,EAAY;AAC1B,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,SAAA,CAAU,MAAA,IAAU,EAAA;AACxC,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,KAAA,MAAW,CAAA,IAAK,MAAM,SAAA,EAAW;AAC/B,MAAA,IAAI,EAAE,QAAA,CAAS,MAAA,GAAS,GAAG,CAAA,CAAE,GAAA,CAAI,EAAE,EAAE,CAAA;AAAA,IACvC;AACA,IAAA,OAAO,CAAA;AAAA,EACT;AACA,EAAA,KAAA,MAAW,CAAA,IAAK,MAAM,KAAA,EAAO;AAC3B,IAAA,IAAI,EAAE,QAAA,CAAS,MAAA,GAAS,GAAG,CAAA,CAAE,GAAA,CAAI,EAAE,EAAE,CAAA;AAAA,EACvC;AACA,EAAA,OAAO,CAAA;AACT;;;ACEA,eAAsB,eAAe,OAAA,EAA+C;AAClF,EAAA,MAAM,QAAA,GAAW,aAAA;AACjB,EAAA,MAAM,GAAA,GAAM,MAAM,OAAO,QAAA,CAAA;AAGzB,EAAA,OAAO,GAAA,CAAI,eAAe,OAAO,CAAA;AACnC","file":"index.cjs","sourcesContent":["import type {\n RunCompletedEvent,\n RunStartedEvent,\n StepCompletedEvent,\n StepStartedEvent,\n TraceEvent,\n} from \"agent-inspect/advanced\";\n\nimport type { TuiTraceModel, TuiTraceNode } from \"./types.js\";\n\ntype StepBuild = {\n id: string;\n parentId?: string;\n name: string;\n type: string;\n status: string;\n durationMs?: number;\n startedAt: number;\n error?: string;\n metadata?: Record<string, unknown>;\n children: StepBuild[];\n};\n\nfunction dfsFlat(roots: TuiTraceNode[], out: TuiTraceNode[]): void {\n for (const n of roots) {\n out.push(n);\n if (n.children.length > 0) dfsFlat(n.children, out);\n }\n}\n\nfunction toTuiNodes(builds: StepBuild[], depth: number): TuiTraceNode[] {\n return builds.map((b) => ({\n id: b.id,\n name: b.name,\n type: b.type,\n status: b.status,\n durationMs: b.durationMs,\n depth,\n parentId: b.parentId,\n error: b.error,\n metadata: b.metadata,\n children: toTuiNodes(b.children, depth + 1),\n }));\n}\n\n/**\n * Build a navigable tree model from v0.1 JSONL trace events.\n * Does not mutate the input array or event objects.\n */\nexport function buildTuiTraceModel(events: TraceEvent[]): TuiTraceModel {\n const started = events.find((e): e is RunStartedEvent => e.event === \"run_started\");\n if (!started) {\n throw new Error(\"Invalid trace: missing run_started\");\n }\n\n const runId = started.runId;\n const runName = started.name;\n\n const completedAll = events.filter((e): e is RunCompletedEvent => e.event === \"run_completed\");\n const lastCompleted = completedAll[completedAll.length - 1];\n const runStatus = lastCompleted ? lastCompleted.status : \"running\";\n const runDurationMs =\n lastCompleted !== undefined && Number.isFinite(lastCompleted.durationMs)\n ? lastCompleted.durationMs\n : undefined;\n\n const nodes = new Map<string, StepBuild>();\n\n for (const e of events) {\n if (e.event !== \"step_started\") continue;\n const s = e as StepStartedEvent;\n nodes.set(s.stepId, {\n id: s.stepId,\n parentId: s.parentId,\n name: s.name,\n type: s.type,\n status: \"running\",\n startedAt: s.startTime,\n metadata: s.metadata as Record<string, unknown> | undefined,\n children: [],\n });\n }\n\n for (const e of events) {\n if (e.event !== \"step_completed\") continue;\n const c = e as StepCompletedEvent;\n const node = nodes.get(c.stepId);\n if (!node) continue;\n node.status = c.status;\n node.durationMs = c.durationMs;\n node.error =\n c.error !== undefined && typeof c.error.message === \"string\"\n ? c.error.message\n : undefined;\n }\n\n const roots: StepBuild[] = [];\n const sortByStarted = (a: StepBuild, b: StepBuild) => a.startedAt - b.startedAt;\n const parentOf = new Map<string, string>();\n\n // Visibility-first: skip self-parents; accept edges in start-time order and\n // drop any edge that would close a cycle so every node stays reachable.\n const candidates = [...nodes.values()]\n .filter(\n (n) =>\n n.parentId !== undefined &&\n n.parentId !== n.id &&\n nodes.has(n.parentId),\n )\n .sort(sortByStarted);\n\n for (const n of candidates) {\n const parentId = n.parentId!;\n parentOf.set(n.id, parentId);\n let cursor: string | undefined = parentId;\n const seen = new Set<string>([n.id]);\n let cyclic = false;\n while (cursor) {\n if (seen.has(cursor)) {\n cyclic = true;\n break;\n }\n seen.add(cursor);\n cursor = parentOf.get(cursor);\n }\n if (cyclic) {\n parentOf.delete(n.id);\n }\n }\n\n for (const n of nodes.values()) {\n const parentId = parentOf.get(n.id);\n if (parentId) {\n nodes.get(parentId)!.children.push(n);\n } else {\n roots.push(n);\n }\n }\n\n roots.sort(sortByStarted);\n for (const n of nodes.values()) {\n n.children.sort(sortByStarted);\n }\n\n const treeRoots = toTuiNodes(roots, 0);\n const flatNodes: TuiTraceNode[] = [];\n dfsFlat(treeRoots, flatNodes);\n\n return {\n runId,\n name: runName,\n status: runStatus,\n durationMs: runDurationMs,\n nodes: treeRoots,\n flatNodes,\n };\n}\n\n/** Total step count in tree (for default expand policy). Exported for tests. */\nexport function countTreeSteps(roots: TuiTraceNode[]): number {\n let n = 0;\n for (const r of roots) {\n n += 1 + countSubtree(r.children);\n }\n return n;\n}\n\nfunction countSubtree(children: TuiTraceNode[]): number {\n let n = 0;\n for (const c of children) {\n n += 1 + countSubtree(c.children);\n }\n return n;\n}\n","import { readTraceEvents, resolveTraceDir } from \"agent-inspect/advanced\";\n\nimport { buildTuiTraceModel } from \"./tree-model.js\";\nimport type { TuiTraceModel } from \"./types.js\";\n\nexport interface LoadTraceForTuiOptions {\n runId: string;\n dir?: string;\n}\n\n/**\n * Load JSONL trace events and build a TUI model. Does not write or mutate trace files.\n */\nexport async function loadTraceForTui(options: LoadTraceForTuiOptions): Promise<TuiTraceModel> {\n const traceDir = resolveTraceDir({ dir: options.dir });\n const events = await readTraceEvents(options.runId, traceDir);\n\n if (events.length === 0) {\n throw new Error(\n `Run not found or trace is empty: ${options.runId} (directory: ${traceDir})`,\n );\n }\n\n return buildTuiTraceModel(events);\n}\n","export type TuiAction =\n | \"up\"\n | \"down\"\n | \"expand\"\n | \"collapse\"\n | \"toggle\"\n | \"details\"\n | \"help\"\n | \"quit\"\n | \"unknown\";\n\n/** Map Ink `useInput` args to a semantic action. Pure helper for tests. */\nexport function mapInputToAction(\n input: string,\n key: Partial<{\n name: string;\n ctrl: boolean;\n meta: boolean;\n shift: boolean;\n return: boolean;\n escape: boolean;\n upArrow: boolean;\n downArrow: boolean;\n leftArrow: boolean;\n rightArrow: boolean;\n }> = {},\n): TuiAction {\n if (key.escape === true) return \"quit\";\n if (key.ctrl === true && input === \"c\") return \"quit\";\n\n if (input === \"q\" || input === \"Q\") return \"quit\";\n\n if (input === \"?\") return \"help\";\n\n if (input === \"d\" || input === \"D\") return \"details\";\n\n if (key.return === true) return \"expand\";\n\n if (input === \" \") return \"toggle\";\n\n if (key.upArrow === true || input === \"k\") return \"up\";\n if (key.downArrow === true || input === \"j\") return \"down\";\n if (key.rightArrow === true || input === \"l\") return \"expand\";\n if (key.leftArrow === true || input === \"h\") return \"collapse\";\n\n return \"unknown\";\n}\n","import type { TuiTraceModel } from \"./types.js\";\n\n/** Small traces: expand all branches. Larger traces: only root rows expanded (show first nesting level). */\nexport function initialExpandedSet(model: TuiTraceModel): Set<string> {\n const s = new Set<string>();\n const small = model.flatNodes.length <= 15;\n if (small) {\n for (const n of model.flatNodes) {\n if (n.children.length > 0) s.add(n.id);\n }\n return s;\n }\n for (const r of model.nodes) {\n if (r.children.length > 0) s.add(r.id);\n }\n return s;\n}\n","/**\n * @experimental Optional TUI package CommonJS entry.\n *\n * Keep this entry free of eager Ink imports so `require(\"@agent-inspect/tui\")`\n * can load pure helpers even though Ink is ESM with top-level await.\n */\nexport type { TuiTraceModel, TuiTraceNode } from \"./types.js\";\nexport { buildTuiTraceModel, countTreeSteps } from \"./tree-model.js\";\nexport type { LoadTraceForTuiOptions } from \"./trace-loader.js\";\nexport { loadTraceForTui } from \"./trace-loader.js\";\nexport type { TuiAction } from \"./keymap.js\";\nexport { mapInputToAction } from \"./keymap.js\";\nexport type { TraceViewerAppProps } from \"./app.js\";\nexport { initialExpandedSet } from \"./expand.js\";\nexport type { RunTraceViewerOptions } from \"./run-viewer.js\";\n\nimport type { RunTraceViewerOptions } from \"./run-viewer.js\";\n\nexport async function runTraceViewer(options: RunTraceViewerOptions): Promise<void> {\n const esmEntry = \"./index.mjs\";\n const mod = await import(esmEntry) as {\n runTraceViewer(options: RunTraceViewerOptions): Promise<void>;\n };\n return mod.runTraceViewer(options);\n}\n"]}
package/dist/index.mjs CHANGED
@@ -59,9 +59,32 @@ function buildTuiTraceModel(events) {
59
59
  }
60
60
  const roots = [];
61
61
  const sortByStarted = (a, b) => a.startedAt - b.startedAt;
62
+ const parentOf = /* @__PURE__ */ new Map();
63
+ const candidates = [...nodes.values()].filter(
64
+ (n) => n.parentId !== void 0 && n.parentId !== n.id && nodes.has(n.parentId)
65
+ ).sort(sortByStarted);
66
+ for (const n of candidates) {
67
+ const parentId = n.parentId;
68
+ parentOf.set(n.id, parentId);
69
+ let cursor = parentId;
70
+ const seen = /* @__PURE__ */ new Set([n.id]);
71
+ let cyclic = false;
72
+ while (cursor) {
73
+ if (seen.has(cursor)) {
74
+ cyclic = true;
75
+ break;
76
+ }
77
+ seen.add(cursor);
78
+ cursor = parentOf.get(cursor);
79
+ }
80
+ if (cyclic) {
81
+ parentOf.delete(n.id);
82
+ }
83
+ }
62
84
  for (const n of nodes.values()) {
63
- if (n.parentId !== void 0 && nodes.has(n.parentId)) {
64
- nodes.get(n.parentId).children.push(n);
85
+ const parentId = parentOf.get(n.id);
86
+ if (parentId) {
87
+ nodes.get(parentId).children.push(n);
65
88
  } else {
66
89
  roots.push(n);
67
90
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tree-model.ts","../src/trace-loader.ts","../src/run-viewer.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type {\n RunCompletedEvent,\n RunStartedEvent,\n StepCompletedEvent,\n StepStartedEvent,\n TraceEvent,\n} from \"agent-inspect/advanced\";\n\nimport type { TuiTraceModel, TuiTraceNode } from \"./types.js\";\n\ntype StepBuild = {\n id: string;\n parentId?: string;\n name: string;\n type: string;\n status: string;\n durationMs?: number;\n startedAt: number;\n error?: string;\n metadata?: Record<string, unknown>;\n children: StepBuild[];\n};\n\nfunction dfsFlat(roots: TuiTraceNode[], out: TuiTraceNode[]): void {\n for (const n of roots) {\n out.push(n);\n if (n.children.length > 0) dfsFlat(n.children, out);\n }\n}\n\nfunction toTuiNodes(builds: StepBuild[], depth: number): TuiTraceNode[] {\n return builds.map((b) => ({\n id: b.id,\n name: b.name,\n type: b.type,\n status: b.status,\n durationMs: b.durationMs,\n depth,\n parentId: b.parentId,\n error: b.error,\n metadata: b.metadata,\n children: toTuiNodes(b.children, depth + 1),\n }));\n}\n\n/**\n * Build a navigable tree model from v0.1 JSONL trace events.\n * Does not mutate the input array or event objects.\n */\nexport function buildTuiTraceModel(events: TraceEvent[]): TuiTraceModel {\n const started = events.find((e): e is RunStartedEvent => e.event === \"run_started\");\n if (!started) {\n throw new Error(\"Invalid trace: missing run_started\");\n }\n\n const runId = started.runId;\n const runName = started.name;\n\n const completedAll = events.filter((e): e is RunCompletedEvent => e.event === \"run_completed\");\n const lastCompleted = completedAll[completedAll.length - 1];\n const runStatus = lastCompleted ? lastCompleted.status : \"running\";\n const runDurationMs =\n lastCompleted !== undefined && Number.isFinite(lastCompleted.durationMs)\n ? lastCompleted.durationMs\n : undefined;\n\n const nodes = new Map<string, StepBuild>();\n\n for (const e of events) {\n if (e.event !== \"step_started\") continue;\n const s = e as StepStartedEvent;\n nodes.set(s.stepId, {\n id: s.stepId,\n parentId: s.parentId,\n name: s.name,\n type: s.type,\n status: \"running\",\n startedAt: s.startTime,\n metadata: s.metadata as Record<string, unknown> | undefined,\n children: [],\n });\n }\n\n for (const e of events) {\n if (e.event !== \"step_completed\") continue;\n const c = e as StepCompletedEvent;\n const node = nodes.get(c.stepId);\n if (!node) continue;\n node.status = c.status;\n node.durationMs = c.durationMs;\n node.error =\n c.error !== undefined && typeof c.error.message === \"string\"\n ? c.error.message\n : undefined;\n }\n\n const roots: StepBuild[] = [];\n const sortByStarted = (a: StepBuild, b: StepBuild) => a.startedAt - b.startedAt;\n\n for (const n of nodes.values()) {\n if (n.parentId !== undefined && nodes.has(n.parentId)) {\n nodes.get(n.parentId)!.children.push(n);\n } else {\n roots.push(n);\n }\n }\n\n roots.sort(sortByStarted);\n for (const n of nodes.values()) {\n n.children.sort(sortByStarted);\n }\n\n const treeRoots = toTuiNodes(roots, 0);\n const flatNodes: TuiTraceNode[] = [];\n dfsFlat(treeRoots, flatNodes);\n\n return {\n runId,\n name: runName,\n status: runStatus,\n durationMs: runDurationMs,\n nodes: treeRoots,\n flatNodes,\n };\n}\n\n/** Total step count in tree (for default expand policy). Exported for tests. */\nexport function countTreeSteps(roots: TuiTraceNode[]): number {\n let n = 0;\n for (const r of roots) {\n n += 1 + countSubtree(r.children);\n }\n return n;\n}\n\nfunction countSubtree(children: TuiTraceNode[]): number {\n let n = 0;\n for (const c of children) {\n n += 1 + countSubtree(c.children);\n }\n return n;\n}\n","import { readTraceEvents, resolveTraceDir } from \"agent-inspect/advanced\";\n\nimport { buildTuiTraceModel } from \"./tree-model.js\";\nimport type { TuiTraceModel } from \"./types.js\";\n\nexport interface LoadTraceForTuiOptions {\n runId: string;\n dir?: string;\n}\n\n/**\n * Load JSONL trace events and build a TUI model. Does not write or mutate trace files.\n */\nexport async function loadTraceForTui(options: LoadTraceForTuiOptions): Promise<TuiTraceModel> {\n const traceDir = resolveTraceDir({ dir: options.dir });\n const events = await readTraceEvents(options.runId, traceDir);\n\n if (events.length === 0) {\n throw new Error(\n `Run not found or trace is empty: ${options.runId} (directory: ${traceDir})`,\n );\n }\n\n return buildTuiTraceModel(events);\n}\n","import { loadTraceForTui } from \"./trace-loader.js\";\n\nexport interface RunTraceViewerOptions {\n runId: string;\n dir?: string;\n}\n\nconst TTY_MSG =\n \"TUI requires an interactive terminal. Use agent-inspect view without --tui for plain output.\";\n\nexport async function runTraceViewer(options: RunTraceViewerOptions): Promise<void> {\n if (!process.stdout.isTTY || !process.stdin.isTTY) {\n throw new Error(TTY_MSG);\n }\n\n const model = await loadTraceForTui({\n runId: options.runId,\n dir: options.dir,\n });\n const [{ default: React }, { render }, { TraceViewerApp }] = await Promise.all([\n import(\"react\"),\n import(\"ink\"),\n import(\"./app.js\"),\n ]);\n\n const { waitUntilExit } = render(\n React.createElement(TraceViewerApp, { model }),\n );\n await waitUntilExit();\n}\n"]}
1
+ {"version":3,"sources":["../src/tree-model.ts","../src/trace-loader.ts","../src/run-viewer.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type {\n RunCompletedEvent,\n RunStartedEvent,\n StepCompletedEvent,\n StepStartedEvent,\n TraceEvent,\n} from \"agent-inspect/advanced\";\n\nimport type { TuiTraceModel, TuiTraceNode } from \"./types.js\";\n\ntype StepBuild = {\n id: string;\n parentId?: string;\n name: string;\n type: string;\n status: string;\n durationMs?: number;\n startedAt: number;\n error?: string;\n metadata?: Record<string, unknown>;\n children: StepBuild[];\n};\n\nfunction dfsFlat(roots: TuiTraceNode[], out: TuiTraceNode[]): void {\n for (const n of roots) {\n out.push(n);\n if (n.children.length > 0) dfsFlat(n.children, out);\n }\n}\n\nfunction toTuiNodes(builds: StepBuild[], depth: number): TuiTraceNode[] {\n return builds.map((b) => ({\n id: b.id,\n name: b.name,\n type: b.type,\n status: b.status,\n durationMs: b.durationMs,\n depth,\n parentId: b.parentId,\n error: b.error,\n metadata: b.metadata,\n children: toTuiNodes(b.children, depth + 1),\n }));\n}\n\n/**\n * Build a navigable tree model from v0.1 JSONL trace events.\n * Does not mutate the input array or event objects.\n */\nexport function buildTuiTraceModel(events: TraceEvent[]): TuiTraceModel {\n const started = events.find((e): e is RunStartedEvent => e.event === \"run_started\");\n if (!started) {\n throw new Error(\"Invalid trace: missing run_started\");\n }\n\n const runId = started.runId;\n const runName = started.name;\n\n const completedAll = events.filter((e): e is RunCompletedEvent => e.event === \"run_completed\");\n const lastCompleted = completedAll[completedAll.length - 1];\n const runStatus = lastCompleted ? lastCompleted.status : \"running\";\n const runDurationMs =\n lastCompleted !== undefined && Number.isFinite(lastCompleted.durationMs)\n ? lastCompleted.durationMs\n : undefined;\n\n const nodes = new Map<string, StepBuild>();\n\n for (const e of events) {\n if (e.event !== \"step_started\") continue;\n const s = e as StepStartedEvent;\n nodes.set(s.stepId, {\n id: s.stepId,\n parentId: s.parentId,\n name: s.name,\n type: s.type,\n status: \"running\",\n startedAt: s.startTime,\n metadata: s.metadata as Record<string, unknown> | undefined,\n children: [],\n });\n }\n\n for (const e of events) {\n if (e.event !== \"step_completed\") continue;\n const c = e as StepCompletedEvent;\n const node = nodes.get(c.stepId);\n if (!node) continue;\n node.status = c.status;\n node.durationMs = c.durationMs;\n node.error =\n c.error !== undefined && typeof c.error.message === \"string\"\n ? c.error.message\n : undefined;\n }\n\n const roots: StepBuild[] = [];\n const sortByStarted = (a: StepBuild, b: StepBuild) => a.startedAt - b.startedAt;\n const parentOf = new Map<string, string>();\n\n // Visibility-first: skip self-parents; accept edges in start-time order and\n // drop any edge that would close a cycle so every node stays reachable.\n const candidates = [...nodes.values()]\n .filter(\n (n) =>\n n.parentId !== undefined &&\n n.parentId !== n.id &&\n nodes.has(n.parentId),\n )\n .sort(sortByStarted);\n\n for (const n of candidates) {\n const parentId = n.parentId!;\n parentOf.set(n.id, parentId);\n let cursor: string | undefined = parentId;\n const seen = new Set<string>([n.id]);\n let cyclic = false;\n while (cursor) {\n if (seen.has(cursor)) {\n cyclic = true;\n break;\n }\n seen.add(cursor);\n cursor = parentOf.get(cursor);\n }\n if (cyclic) {\n parentOf.delete(n.id);\n }\n }\n\n for (const n of nodes.values()) {\n const parentId = parentOf.get(n.id);\n if (parentId) {\n nodes.get(parentId)!.children.push(n);\n } else {\n roots.push(n);\n }\n }\n\n roots.sort(sortByStarted);\n for (const n of nodes.values()) {\n n.children.sort(sortByStarted);\n }\n\n const treeRoots = toTuiNodes(roots, 0);\n const flatNodes: TuiTraceNode[] = [];\n dfsFlat(treeRoots, flatNodes);\n\n return {\n runId,\n name: runName,\n status: runStatus,\n durationMs: runDurationMs,\n nodes: treeRoots,\n flatNodes,\n };\n}\n\n/** Total step count in tree (for default expand policy). Exported for tests. */\nexport function countTreeSteps(roots: TuiTraceNode[]): number {\n let n = 0;\n for (const r of roots) {\n n += 1 + countSubtree(r.children);\n }\n return n;\n}\n\nfunction countSubtree(children: TuiTraceNode[]): number {\n let n = 0;\n for (const c of children) {\n n += 1 + countSubtree(c.children);\n }\n return n;\n}\n","import { readTraceEvents, resolveTraceDir } from \"agent-inspect/advanced\";\n\nimport { buildTuiTraceModel } from \"./tree-model.js\";\nimport type { TuiTraceModel } from \"./types.js\";\n\nexport interface LoadTraceForTuiOptions {\n runId: string;\n dir?: string;\n}\n\n/**\n * Load JSONL trace events and build a TUI model. Does not write or mutate trace files.\n */\nexport async function loadTraceForTui(options: LoadTraceForTuiOptions): Promise<TuiTraceModel> {\n const traceDir = resolveTraceDir({ dir: options.dir });\n const events = await readTraceEvents(options.runId, traceDir);\n\n if (events.length === 0) {\n throw new Error(\n `Run not found or trace is empty: ${options.runId} (directory: ${traceDir})`,\n );\n }\n\n return buildTuiTraceModel(events);\n}\n","import { loadTraceForTui } from \"./trace-loader.js\";\n\nexport interface RunTraceViewerOptions {\n runId: string;\n dir?: string;\n}\n\nconst TTY_MSG =\n \"TUI requires an interactive terminal. Use agent-inspect view without --tui for plain output.\";\n\nexport async function runTraceViewer(options: RunTraceViewerOptions): Promise<void> {\n if (!process.stdout.isTTY || !process.stdin.isTTY) {\n throw new Error(TTY_MSG);\n }\n\n const model = await loadTraceForTui({\n runId: options.runId,\n dir: options.dir,\n });\n const [{ default: React }, { render }, { TraceViewerApp }] = await Promise.all([\n import(\"react\"),\n import(\"ink\"),\n import(\"./app.js\"),\n ]);\n\n const { waitUntilExit } = render(\n React.createElement(TraceViewerApp, { model }),\n );\n await waitUntilExit();\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-inspect/tui",
3
- "version": "6.14.0",
3
+ "version": "6.14.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "private": false,
@@ -37,7 +37,7 @@
37
37
  "dependencies": {
38
38
  "ink": "^5.0.1",
39
39
  "react": "^18.3.1",
40
- "agent-inspect": "6.14.0"
40
+ "agent-inspect": "6.14.2"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/react": "^18.3.18"
@@ -45,6 +45,12 @@
45
45
  "publishConfig": {
46
46
  "access": "public"
47
47
  },
48
+ "keywords": [
49
+ "tui",
50
+ "agent-inspect",
51
+ "terminal",
52
+ "typescript"
53
+ ],
48
54
  "scripts": {
49
55
  "build": "pnpm --workspace-root exec tsup --config tsup.tui.config.ts",
50
56
  "test": "vitest run -c ../../vitest.config.ts"