agentfootprint-lens 0.63.0 → 0.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -78,7 +78,7 @@ changes.
78
78
  |---|---|
79
79
  | `agentfootprint-lens/why` | Replay a recording as the agent's own milestones. `<WhyLens recording={...} />` takes the recording straight (`recordRun()`'s `{ snapshot, events, structure }`, or the `persistRecording` envelope), validates it at mount, and mounts the shipped `<Lens>` shell on the milestone axis — plus the axis helpers (`scrubAxisFor`, `stepForCommitIdx`, `stepForRuntimeStageId`, `resolveNavigation`) for hosts holding one cursor across views. |
80
80
  | `agentfootprint-lens/skillgraph` | Debug how a run routed through its skills. `<SkillGraphDebugger recorder={...} />` plus its headless selectors (`selectSkillRoute`, `selectSkillBeats`, `selectSkillTopology`, `selectSkillFrameContext`, `stepForRuntimeStageId`, `resolveNavigation`). |
81
- | `agentfootprint-lens/context` | What the model HAD at a stop — the served document of that epoch on top (the Served tab itself: pieces, messages, tools, verdicts, delta since the previous call) — and what it was BUILT from beneath: the record key by key, who wrote each, what moved; a long value opens in place (0.54.0). `<ContextView runner={...} />` walks the milestone axis on its own; hand it `cursor` and it follows the ONE cursor (0.53.1). Under the record, the **Findings** band (0.61.0): on an armed run (`.findings()`, agentfootprint 9.101) the model's own ledger at the stop, folded for reading — facts, conflicts as first seen (each witness with its current standing, no verdict), open, ruled out, noise, undeclared — every string off the record, absent on an unarmed run. Beside it, the **Reasoning** lens (0.62.0): `<ReasoningLens runner={...} shared={shared} />` — the same ledger read BY CALL, one card per tool call at the cursor (basis before, result, current standing after, the model's words quoted) and an answer card; absent on an unarmed run. Its `exchange` view (0.63.0) lays the same beats out as the transcript between model and tools — the call with its `_findings` JSON, the result, the ticket served instead, the findings piece, the answer — only what crossed the wire. |
81
+ | `agentfootprint-lens/context` | What the model HAD at a stop — the served document of that epoch on top (the Served tab itself: pieces, messages, tools, verdicts, delta since the previous call) — and what it was BUILT from beneath: the record key by key, who wrote each, what moved; a long value opens in place (0.54.0). `<ContextView runner={...} />` walks the milestone axis on its own; hand it `cursor` and it follows the ONE cursor (0.53.1). Under the record, the **Findings** band (0.61.0): on an armed run (`.findings()`, agentfootprint 9.101) the model's own ledger at the stop, folded for reading — facts, conflicts as first seen (each witness with its current standing, no verdict), open, ruled out, noise, undeclared — every string off the record, absent on an unarmed run. Beside it, the **Reasoning** lens (0.62.0): `<ReasoningLens runner={...} shared={shared} />` — the same ledger read BY CALL, one card per tool call at the cursor (basis before, result, current standing after, the model's words quoted) and an answer card; absent on an unarmed run. Its `exchange` view (0.63.0) lays the same beats out as the transcript between model and tools — the call with its `_findings` JSON, the result, the ticket served instead, the findings piece, the answer — only what crossed the wire. Beside both, the **Ontology** view (0.64.0): `<OntologyView runner={...} shared={shared} />` — the map an agent declared (`.ontology(...)`, agentfootprint 9.106.0) drawn from the run constant on the record: sources, the terms they hold and via which tool, the terms no source holds under `known, not held here`, relations in the author's words — a chart and the same data as a list; absent on an agent that declared no map. |
82
82
 
83
83
  The axis model in three sentences: one run leaves one causal trace, and each
84
84
  lens replays one AXIS of it — the Why reading scrubs the milestones, the Flow
@@ -903,6 +903,7 @@ function ReasoningLens(props) {
903
903
  llmLatestToolCalls: keyValue(context, "llmLatestToolCalls")
904
904
  });
905
905
  }, [context, rows]);
906
+ const mover = props.cursor === void 0 && shared !== void 0 && cursor.total > 0 && cursor.at.step >= 0;
906
907
  if (exchange === void 0) return null;
907
908
  const fold = exchange.reasoning;
908
909
  return /* @__PURE__ */ jsxs3(
@@ -924,6 +925,16 @@ function ReasoningLens(props) {
924
925
  ] }),
925
926
  /* @__PURE__ */ jsx3(ViewToggle, { view, onView: setView })
926
927
  ] }),
928
+ mover && /* @__PURE__ */ jsx3("div", { "data-testid": "reasoning-transport", children: /* @__PURE__ */ jsx3(
929
+ TimeTravel,
930
+ {
931
+ total: cursor.total,
932
+ focusSeq: Math.max(0, cursor.at.step),
933
+ onFocusChange: (n) => cursor.moveTo(n),
934
+ isLive: false,
935
+ compact: true
936
+ }
937
+ ) }),
927
938
  view === "cards" && /* @__PURE__ */ jsxs3("div", { style: column, "data-testid": "reasoning-cards", children: [
928
939
  fold.cards.map((card) => /* @__PURE__ */ jsx3(Card, { card }, card.toolCallId)),
929
940
  fold.answer !== void 0 && /* @__PURE__ */ jsx3(Answer, { answer: fold.answer })
@@ -1280,9 +1291,9 @@ function Chip({
1280
1291
  children,
1281
1292
  color,
1282
1293
  testId,
1283
- title: title3
1294
+ title: title4
1284
1295
  }) {
1285
- return /* @__PURE__ */ jsx3("span", { style: { ...chip, borderColor: color, color }, "data-testid": testId, ...title3 !== void 0 ? { title: title3 } : {}, children });
1296
+ return /* @__PURE__ */ jsx3("span", { style: { ...chip, borderColor: color, color }, "data-testid": testId, ...title4 !== void 0 ? { title: title4 } : {}, children });
1286
1297
  }
1287
1298
  var panel2 = {
1288
1299
  display: "flex",
@@ -1339,6 +1350,476 @@ var summaryStyle = { cursor: "pointer", color: T.textMuted };
1339
1350
  var detailsBody = { display: "flex", flexDirection: "column", gap: 2, paddingTop: 4 };
1340
1351
  var list3 = { margin: "2px 0 0", paddingLeft: 18 };
1341
1352
 
1353
+ // src/react/components/OntologyView.tsx
1354
+ import { useMemo as useMemo4 } from "react";
1355
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1356
+ var LABELS4 = Object.freeze({
1357
+ view: "Ontology",
1358
+ version: "version",
1359
+ hash: "hash",
1360
+ nodes: "nodes",
1361
+ sources: "sources",
1362
+ edges: "edges",
1363
+ /** The declaration's own heading for a term with no source (the served piece's line). */
1364
+ unheld: "known, not held here",
1365
+ heldBy: "held by",
1366
+ relations: "relations",
1367
+ via: "via",
1368
+ unit: "unit",
1369
+ aliases: "aliases",
1370
+ coverage: "coverage",
1371
+ configured: "configured",
1372
+ chart: "chart",
1373
+ list: "list"
1374
+ });
1375
+ var isRecord3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
1376
+ var isStringArray = (v) => Array.isArray(v) && v.every((s) => typeof s === "string");
1377
+ function ontologyRecordOf(value) {
1378
+ if (!isRecord3(value)) return void 0;
1379
+ const { id, version, hash, spec } = value;
1380
+ if (typeof id !== "string" || typeof version !== "string" || typeof hash !== "string" || !isRecord3(spec)) return void 0;
1381
+ if (!isRecord3(spec.nodes) || !isRecord3(spec.sources)) return void 0;
1382
+ return {
1383
+ id,
1384
+ version,
1385
+ hash,
1386
+ nodes: spec.nodes,
1387
+ sources: spec.sources,
1388
+ edges: Array.isArray(spec.edges) ? spec.edges : []
1389
+ };
1390
+ }
1391
+ function heldOf(node, value, sources) {
1392
+ if (!isRecord3(value) || typeof value.source !== "string" || !(value.source in sources)) return void 0;
1393
+ return {
1394
+ node,
1395
+ source: value.source,
1396
+ via: isStringArray(value.via) ? value.via : [],
1397
+ ...typeof value.coverage === "string" ? { coverage: value.coverage } : {}
1398
+ };
1399
+ }
1400
+ function termOf(id, value, sources) {
1401
+ if (!isRecord3(value) || typeof value.meaning !== "string") return void 0;
1402
+ const held = Array.isArray(value.sources) ? value.sources.map((s) => heldOf(id, s, sources)).filter((h) => h !== void 0) : [];
1403
+ return {
1404
+ id,
1405
+ meaning: value.meaning,
1406
+ ...typeof value.unit === "string" ? { unit: value.unit } : {},
1407
+ aliases: isStringArray(value.aliases) ? value.aliases : [],
1408
+ held
1409
+ };
1410
+ }
1411
+ function sourceOf(id, value) {
1412
+ if (!isRecord3(value) || typeof value.meaning !== "string") return void 0;
1413
+ return {
1414
+ id,
1415
+ meaning: value.meaning,
1416
+ ...typeof value.coverage === "string" ? { coverage: value.coverage } : {},
1417
+ ...typeof value.configured === "boolean" ? { configured: value.configured } : {}
1418
+ };
1419
+ }
1420
+ function relationOf(value) {
1421
+ if (!isRecord3(value) || typeof value.from !== "string" || typeof value.to !== "string" || typeof value.relation !== "string") return void 0;
1422
+ return {
1423
+ from: value.from,
1424
+ to: value.to,
1425
+ relation: value.relation,
1426
+ ...typeof value.meaning === "string" ? { meaning: value.meaning } : {}
1427
+ };
1428
+ }
1429
+ var byId = (a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
1430
+ function foldOntology(record) {
1431
+ const terms = Object.entries(record.nodes).map(([id, v]) => termOf(id, v, record.sources)).filter((t) => t !== void 0).sort(byId);
1432
+ const sources = Object.entries(record.sources).map(([id, v]) => sourceOf(id, v)).filter((s) => s !== void 0).sort(byId);
1433
+ const relations = record.edges.map(relationOf).filter((r) => r !== void 0);
1434
+ return Object.freeze({
1435
+ id: record.id,
1436
+ version: record.version,
1437
+ hash: record.hash,
1438
+ terms: Object.freeze(terms),
1439
+ sources: Object.freeze(sources),
1440
+ held: Object.freeze(terms.flatMap((t) => t.held)),
1441
+ relations: Object.freeze(relations),
1442
+ unheld: Object.freeze(terms.filter((t) => t.held.length === 0).map((t) => t.id))
1443
+ });
1444
+ }
1445
+ var GEOMETRY = Object.freeze({
1446
+ nodeWidth: 168,
1447
+ nodeHeight: 44,
1448
+ rowGap: 18,
1449
+ columnGap: 96,
1450
+ /** The lane each relation elbow takes to the right of the term columns, per edge. */
1451
+ laneGap: 14,
1452
+ padding: 12,
1453
+ labelOffset: 4
1454
+ });
1455
+ var columnX = (column2) => GEOMETRY.padding + column2 * (GEOMETRY.nodeWidth + GEOMETRY.columnGap);
1456
+ var rowY = (row2) => GEOMETRY.padding + GEOMETRY.nodeHeight + row2 * (GEOMETRY.nodeHeight + GEOMETRY.rowGap);
1457
+ var centreY = (n) => n.y + GEOMETRY.nodeHeight / 2;
1458
+ function layoutOntology(fold) {
1459
+ const heldTerms = fold.terms.filter((t) => t.held.length > 0);
1460
+ const unheldTerms = fold.terms.filter((t) => t.held.length === 0);
1461
+ const nodes = [
1462
+ ...fold.sources.map((s, i) => ({ id: s.id, kind: "source", column: 0, x: columnX(0), y: rowY(i) })),
1463
+ ...heldTerms.map((t, i) => ({ id: t.id, kind: "term", column: 1, x: columnX(1), y: rowY(i) })),
1464
+ ...unheldTerms.map((t, i) => ({ id: t.id, kind: "term", column: 2, x: columnX(2), y: rowY(i) }))
1465
+ ];
1466
+ const at = new Map(nodes.map((n) => [`${n.kind}:${n.id}`, n]));
1467
+ const columns = unheldTerms.length > 0 ? 3 : heldTerms.length > 0 ? 2 : 1;
1468
+ const rightEdge = columnX(columns - 1) + GEOMETRY.nodeWidth;
1469
+ const edges = [];
1470
+ for (const h of fold.held) {
1471
+ const from = at.get(`source:${h.source}`);
1472
+ const to = at.get(`term:${h.node}`);
1473
+ if (from === void 0 || to === void 0) continue;
1474
+ const x1 = from.x + GEOMETRY.nodeWidth;
1475
+ const y1 = centreY(from);
1476
+ const x2 = to.x;
1477
+ const y2 = centreY(to);
1478
+ edges.push({
1479
+ kind: "held",
1480
+ from: h.source,
1481
+ to: h.node,
1482
+ path: `M ${x1} ${y1} L ${x2} ${y2}`,
1483
+ labelX: (x1 + x2) / 2,
1484
+ labelY: (y1 + y2) / 2 - GEOMETRY.labelOffset,
1485
+ label: h.via.join(", ")
1486
+ });
1487
+ }
1488
+ fold.relations.forEach((r, i) => {
1489
+ const from = at.get(`term:${r.from}`);
1490
+ const to = at.get(`term:${r.to}`);
1491
+ if (from === void 0 || to === void 0) return;
1492
+ const lane = rightEdge + GEOMETRY.laneGap * (i + 1);
1493
+ const x1 = from.x + GEOMETRY.nodeWidth;
1494
+ const y1 = centreY(from);
1495
+ const x2 = to.x + GEOMETRY.nodeWidth;
1496
+ const y2 = centreY(to);
1497
+ edges.push({
1498
+ kind: "relation",
1499
+ from: r.from,
1500
+ to: r.to,
1501
+ path: `M ${x1} ${y1} H ${lane} V ${y2} H ${x2}`,
1502
+ labelX: lane + GEOMETRY.labelOffset,
1503
+ labelY: (y1 + y2) / 2,
1504
+ label: r.relation,
1505
+ relation: r.relation
1506
+ });
1507
+ });
1508
+ const rows = Math.max(fold.sources.length, heldTerms.length, unheldTerms.length, 1);
1509
+ const lanes = fold.relations.length;
1510
+ return Object.freeze({
1511
+ width: rightEdge + GEOMETRY.laneGap * (lanes + 1) + GEOMETRY.padding + 120,
1512
+ height: rowY(rows) + GEOMETRY.padding,
1513
+ nodes: Object.freeze(nodes),
1514
+ edges: Object.freeze(edges),
1515
+ ...unheldTerms.length > 0 ? { unheldX: columnX(2) } : {}
1516
+ });
1517
+ }
1518
+ function positionsOf3(snapshot) {
1519
+ return tagAxisPositions(snapshot, MILESTONE_AXIS, []) ?? [];
1520
+ }
1521
+ var noMove2 = () => void 0;
1522
+ function keyValue2(context, path) {
1523
+ return context.keys.find((k) => k.path === path)?.value;
1524
+ }
1525
+ function OntologyView(props) {
1526
+ const { runner, events, shared, recorder } = props;
1527
+ const fresh = snapshotOfRunner(runner);
1528
+ const logKey = snapshotLogKey(fresh);
1529
+ const snapshot = useMemo4(() => fresh, [runner, logKey]);
1530
+ const ownPositions = useMemo4(
1531
+ () => props.cursor !== void 0 ? void 0 : recorder !== void 0 ? scrubAxisFor(recorder, "group") : positionsOf3(snapshot),
1532
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- the recorder's axis moves with the log key
1533
+ [snapshot, props.cursor, recorder, logKey]
1534
+ );
1535
+ const positions = ownPositions ?? [];
1536
+ const cursor = props.cursor ?? (shared !== void 0 ? shared.over(positions) : lensCursorFrom(positions, Math.max(0, positions.length - 1), noMove2));
1537
+ const context = useMemo4(
1538
+ () => contextAt(snapshot, { runtimeStageId: cursor.at.runtimeStageId, commitIdx: cursor.at.commitIdx }, { events }),
1539
+ [snapshot, cursor.at.runtimeStageId, cursor.at.commitIdx, events]
1540
+ );
1541
+ const record = ontologyRecordOf(keyValue2(context, "ontology"));
1542
+ const fold = useMemo4(() => record === void 0 ? void 0 : foldOntology(record), [record]);
1543
+ const layout = useMemo4(() => fold === void 0 ? void 0 : layoutOntology(fold), [fold]);
1544
+ const mover = props.cursor === void 0 && shared !== void 0 && cursor.total > 0 && cursor.at.step >= 0;
1545
+ if (fold === void 0 || layout === void 0) return null;
1546
+ return /* @__PURE__ */ jsxs4(
1547
+ "div",
1548
+ {
1549
+ style: panel3,
1550
+ "data-testid": "ontology-view",
1551
+ "data-id": fold.id,
1552
+ "data-version": fold.version,
1553
+ "data-hash": fold.hash,
1554
+ "data-step": cursor.at.step,
1555
+ "data-commit": cursor.at.commitIdx,
1556
+ children: [
1557
+ /* @__PURE__ */ jsx4(Header, { fold }),
1558
+ mover && /* @__PURE__ */ jsx4("div", { "data-testid": "ontology-transport", children: /* @__PURE__ */ jsx4(
1559
+ TimeTravel,
1560
+ {
1561
+ total: cursor.total,
1562
+ focusSeq: Math.max(0, cursor.at.step),
1563
+ onFocusChange: (n) => cursor.moveTo(n),
1564
+ isLive: false,
1565
+ compact: true
1566
+ }
1567
+ ) }),
1568
+ /* @__PURE__ */ jsxs4("div", { style: body, children: [
1569
+ /* @__PURE__ */ jsx4(Chart, { fold, layout }),
1570
+ /* @__PURE__ */ jsx4(List, { fold })
1571
+ ] })
1572
+ ]
1573
+ }
1574
+ );
1575
+ }
1576
+ var SHORT_HASH = 12;
1577
+ function Header({ fold }) {
1578
+ return /* @__PURE__ */ jsxs4("div", { style: header3, "data-testid": "ontology-header", children: [
1579
+ /* @__PURE__ */ jsx4("span", { style: title3, children: LABELS4.view }),
1580
+ /* @__PURE__ */ jsx4("code", { style: mono4, "data-testid": "ontology-id", children: fold.id }),
1581
+ /* @__PURE__ */ jsxs4("span", { style: dim4, children: [
1582
+ LABELS4.version,
1583
+ " ",
1584
+ /* @__PURE__ */ jsx4("code", { style: mono4, children: fold.version })
1585
+ ] }),
1586
+ /* @__PURE__ */ jsxs4("span", { style: dim4, children: [
1587
+ LABELS4.hash,
1588
+ " ",
1589
+ /* @__PURE__ */ jsx4("code", { style: mono4, title: fold.hash, "data-testid": "ontology-hash", children: fold.hash.length > SHORT_HASH ? `${fold.hash.slice(0, SHORT_HASH)}\u2026` : fold.hash })
1590
+ ] }),
1591
+ /* @__PURE__ */ jsxs4("span", { style: dim4, "data-testid": "ontology-counts", children: [
1592
+ fold.terms.length,
1593
+ " ",
1594
+ LABELS4.nodes,
1595
+ " \xB7 ",
1596
+ fold.sources.length,
1597
+ " ",
1598
+ LABELS4.sources,
1599
+ " \xB7 ",
1600
+ fold.held.length + fold.relations.length,
1601
+ " ",
1602
+ LABELS4.edges
1603
+ ] })
1604
+ ] });
1605
+ }
1606
+ var CLIP = 28;
1607
+ var ARROW = [
1608
+ [0, 0],
1609
+ [8, 4],
1610
+ [0, 8]
1611
+ ];
1612
+ function arrowPoints() {
1613
+ return ARROW.map((p) => p.join(",")).join(" ");
1614
+ }
1615
+ function clip(text, max = CLIP) {
1616
+ return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
1617
+ }
1618
+ function Chart({ fold, layout }) {
1619
+ const terms = new Map(fold.terms.map((t) => [t.id, t]));
1620
+ const sources = new Map(fold.sources.map((s) => [s.id, s]));
1621
+ const arrow = `ontology-arrow-${fold.hash.slice(0, SHORT_HASH)}`;
1622
+ const { nodeWidth, nodeHeight } = GEOMETRY;
1623
+ return /* @__PURE__ */ jsxs4(
1624
+ "svg",
1625
+ {
1626
+ role: "img",
1627
+ "aria-label": LABELS4.chart,
1628
+ width: layout.width,
1629
+ height: layout.height,
1630
+ viewBox: `0 0 ${layout.width} ${layout.height}`,
1631
+ style: chartStyle,
1632
+ "data-testid": "ontology-chart",
1633
+ children: [
1634
+ /* @__PURE__ */ jsx4("defs", { children: /* @__PURE__ */ jsx4("marker", { id: arrow, viewBox: "0 0 8 8", refX: "7", refY: "4", markerWidth: "7", markerHeight: "7", orient: "auto", children: /* @__PURE__ */ jsx4("polygon", { points: arrowPoints(), fill: T.textMuted }) }) }),
1635
+ /* @__PURE__ */ jsx4("text", { x: columnX(0), y: GEOMETRY.padding + 14, style: headingText, fill: T.textMuted, children: LABELS4.sources }),
1636
+ layout.nodes.some((n) => n.column === 1) && /* @__PURE__ */ jsx4("text", { x: columnX(1), y: GEOMETRY.padding + 14, style: headingText, fill: T.textMuted, children: LABELS4.nodes }),
1637
+ layout.unheldX !== void 0 && /* @__PURE__ */ jsx4("text", { x: layout.unheldX, y: GEOMETRY.padding + 14, style: headingText, fill: T.textMuted, "data-testid": "ontology-chart-unheld", children: LABELS4.unheld }),
1638
+ layout.edges.map((e, i) => /* @__PURE__ */ jsxs4(
1639
+ "g",
1640
+ {
1641
+ "data-testid": "ontology-chart-edge",
1642
+ "data-kind": e.kind,
1643
+ "data-from": e.from,
1644
+ "data-to": e.to,
1645
+ ...e.relation !== void 0 ? { "data-relation": e.relation } : {},
1646
+ children: [
1647
+ /* @__PURE__ */ jsx4(
1648
+ "path",
1649
+ {
1650
+ d: e.path,
1651
+ fill: "none",
1652
+ stroke: e.kind === "held" ? T.srcTool : T.primary,
1653
+ strokeWidth: 1.25,
1654
+ strokeDasharray: e.kind === "held" ? void 0 : "4 3",
1655
+ markerEnd: `url(#${arrow})`
1656
+ }
1657
+ ),
1658
+ e.label.length > 0 && /* @__PURE__ */ jsx4("text", { x: e.labelX, y: e.labelY, style: edgeText, fill: e.kind === "held" ? T.srcTool : T.primary, textAnchor: e.kind === "held" ? "middle" : "start", children: e.label })
1659
+ ]
1660
+ },
1661
+ `${e.kind}:${e.from}:${e.to}:${i}`
1662
+ )),
1663
+ layout.nodes.map((n) => {
1664
+ const term = terms.get(n.id);
1665
+ const source = sources.get(n.id);
1666
+ const shape = n.kind === "source" ? source : term;
1667
+ const meaning = shape?.meaning ?? "";
1668
+ const held = n.kind === "term" && term !== void 0 && term.held.length > 0;
1669
+ return /* @__PURE__ */ jsxs4(
1670
+ "g",
1671
+ {
1672
+ transform: `translate(${n.x} ${n.y})`,
1673
+ "data-testid": "ontology-chart-node",
1674
+ "data-kind": n.kind,
1675
+ "data-node": n.id,
1676
+ ...n.kind === "term" ? { "data-held": String(held) } : {},
1677
+ children: [
1678
+ /* @__PURE__ */ jsx4("title", { children: n.kind === "source" && source?.coverage !== void 0 ? `${meaning} \xB7 ${source.coverage}` : meaning }),
1679
+ /* @__PURE__ */ jsx4(
1680
+ "rect",
1681
+ {
1682
+ width: nodeWidth,
1683
+ height: nodeHeight,
1684
+ rx: n.kind === "source" ? 2 : 8,
1685
+ fill: T.bgSecondary,
1686
+ stroke: n.kind === "source" ? T.srcTool : held ? T.primary : T.textMuted,
1687
+ strokeWidth: n.kind === "source" ? 2 : 1.25,
1688
+ strokeDasharray: n.kind === "term" && !held ? "4 3" : void 0
1689
+ }
1690
+ ),
1691
+ /* @__PURE__ */ jsx4("text", { x: 8, y: 17, style: nodeIdText, fill: T.textPrimary, children: clip(n.id, 20) }),
1692
+ n.kind === "term" && term?.unit !== void 0 && /* @__PURE__ */ jsx4("text", { x: nodeWidth - 8, y: 17, style: chipText, fill: T.warning, textAnchor: "end", children: clip(term.unit, 12) }),
1693
+ n.kind === "source" && source?.configured !== void 0 && /* @__PURE__ */ jsx4("text", { x: nodeWidth - 8, y: 17, style: chipText, fill: source.configured ? T.success : T.warning, textAnchor: "end", children: LABELS4.configured }),
1694
+ /* @__PURE__ */ jsx4("text", { x: 8, y: 34, style: nodeMeaningText, fill: T.textSecondary, children: clip(n.kind === "source" && source?.coverage !== void 0 ? `${meaning} \xB7 ${source.coverage}` : meaning) })
1695
+ ]
1696
+ },
1697
+ `${n.kind}:${n.id}`
1698
+ );
1699
+ })
1700
+ ]
1701
+ }
1702
+ );
1703
+ }
1704
+ function List({ fold }) {
1705
+ return /* @__PURE__ */ jsxs4("div", { style: listStyle, "data-testid": "ontology-list", "aria-label": LABELS4.list, children: [
1706
+ /* @__PURE__ */ jsx4(Group2, { label: LABELS4.nodes, count: fold.terms.length, testId: "ontology-nodes", children: fold.terms.map((t) => /* @__PURE__ */ jsxs4("li", { "data-testid": "ontology-node", "data-node": t.id, "data-held": String(t.held.length > 0), children: [
1707
+ /* @__PURE__ */ jsx4("code", { style: strong2, children: t.id }),
1708
+ " ",
1709
+ /* @__PURE__ */ jsx4("span", { children: t.meaning }),
1710
+ t.unit !== void 0 && /* @__PURE__ */ jsxs4(Chip2, { color: T.warning, testId: "ontology-unit", children: [
1711
+ LABELS4.unit,
1712
+ " ",
1713
+ t.unit
1714
+ ] }),
1715
+ t.aliases.length > 0 && /* @__PURE__ */ jsxs4("span", { style: dim4, "data-testid": "ontology-aliases", children: [
1716
+ " ",
1717
+ LABELS4.aliases,
1718
+ " ",
1719
+ t.aliases.join(", ")
1720
+ ] })
1721
+ ] }, t.id)) }),
1722
+ /* @__PURE__ */ jsx4(Group2, { label: LABELS4.sources, count: fold.sources.length, testId: "ontology-sources", children: fold.sources.map((s) => /* @__PURE__ */ jsxs4("li", { "data-testid": "ontology-source", "data-source": s.id, ...s.configured !== void 0 ? { "data-configured": String(s.configured) } : {}, children: [
1723
+ /* @__PURE__ */ jsx4("code", { style: strong2, children: s.id }),
1724
+ " ",
1725
+ /* @__PURE__ */ jsx4("span", { children: s.meaning }),
1726
+ s.configured !== void 0 && /* @__PURE__ */ jsxs4(Chip2, { color: s.configured ? T.success : T.warning, testId: "ontology-configured", children: [
1727
+ LABELS4.configured,
1728
+ " ",
1729
+ String(s.configured)
1730
+ ] }),
1731
+ s.coverage !== void 0 && /* @__PURE__ */ jsxs4("span", { style: dim4, "data-testid": "ontology-source-coverage", children: [
1732
+ " ",
1733
+ LABELS4.coverage,
1734
+ " ",
1735
+ /* @__PURE__ */ jsx4("q", { children: s.coverage })
1736
+ ] })
1737
+ ] }, s.id)) }),
1738
+ fold.held.length > 0 && /* @__PURE__ */ jsx4(Group2, { label: LABELS4.heldBy, count: fold.held.length, testId: "ontology-held-by", children: fold.held.map((h, i) => /* @__PURE__ */ jsxs4("li", { "data-testid": "ontology-held", "data-node": h.node, "data-source": h.source, children: [
1739
+ /* @__PURE__ */ jsx4("code", { style: strong2, children: h.node }),
1740
+ " ",
1741
+ /* @__PURE__ */ jsx4("span", { style: dim4, children: "\u2190" }),
1742
+ " ",
1743
+ /* @__PURE__ */ jsx4("code", { style: strong2, children: h.source }),
1744
+ h.via.length > 0 && /* @__PURE__ */ jsxs4("span", { style: dim4, "data-testid": "ontology-via", children: [
1745
+ " ",
1746
+ LABELS4.via,
1747
+ " ",
1748
+ /* @__PURE__ */ jsx4("code", { style: mono4, children: h.via.join(", ") })
1749
+ ] }),
1750
+ h.coverage !== void 0 && /* @__PURE__ */ jsxs4("span", { style: dim4, "data-testid": "ontology-held-coverage", children: [
1751
+ " ",
1752
+ LABELS4.coverage,
1753
+ " ",
1754
+ /* @__PURE__ */ jsx4("q", { children: h.coverage })
1755
+ ] })
1756
+ ] }, `${h.node}:${h.source}:${i}`)) }),
1757
+ fold.relations.length > 0 && /* @__PURE__ */ jsx4(Group2, { label: LABELS4.relations, count: fold.relations.length, testId: "ontology-relations", children: fold.relations.map((r, i) => /* @__PURE__ */ jsxs4("li", { "data-testid": "ontology-edge", "data-from": r.from, "data-to": r.to, "data-relation": r.relation, children: [
1758
+ /* @__PURE__ */ jsx4("code", { style: strong2, children: r.from }),
1759
+ " ",
1760
+ /* @__PURE__ */ jsx4("code", { style: relationWord, children: r.relation }),
1761
+ " ",
1762
+ /* @__PURE__ */ jsx4("code", { style: strong2, children: r.to }),
1763
+ r.meaning !== void 0 && /* @__PURE__ */ jsxs4("span", { style: dim4, "data-testid": "ontology-edge-meaning", children: [
1764
+ " ",
1765
+ /* @__PURE__ */ jsx4("q", { children: r.meaning })
1766
+ ] })
1767
+ ] }, `${r.from}:${r.relation}:${r.to}:${i}`)) }),
1768
+ fold.unheld.length > 0 && /* @__PURE__ */ jsx4(Group2, { label: LABELS4.unheld, count: fold.unheld.length, testId: "ontology-unheld-group", children: fold.unheld.map((id) => /* @__PURE__ */ jsx4("li", { "data-testid": "ontology-unheld", "data-node": id, children: /* @__PURE__ */ jsx4("code", { style: strong2, children: id }) }, id)) })
1769
+ ] });
1770
+ }
1771
+ function Group2({
1772
+ label,
1773
+ count,
1774
+ testId,
1775
+ children
1776
+ }) {
1777
+ return /* @__PURE__ */ jsxs4("div", { "data-testid": testId, "data-count": count, children: [
1778
+ /* @__PURE__ */ jsxs4("div", { style: groupHeading, children: [
1779
+ label,
1780
+ " \xB7 ",
1781
+ count
1782
+ ] }),
1783
+ /* @__PURE__ */ jsx4("ul", { style: list4, children })
1784
+ ] });
1785
+ }
1786
+ function Chip2({ children, color, testId }) {
1787
+ return /* @__PURE__ */ jsx4("span", { style: { ...chip2, borderColor: color, color }, "data-testid": testId, children });
1788
+ }
1789
+ var panel3 = {
1790
+ display: "flex",
1791
+ flexDirection: "column",
1792
+ gap: 8,
1793
+ padding: 10,
1794
+ fontSize: 13,
1795
+ fontFamily: T.fontSans,
1796
+ color: T.textPrimary
1797
+ };
1798
+ var header3 = { display: "flex", alignItems: "center", flexWrap: "wrap", gap: 10 };
1799
+ var title3 = { fontWeight: 600 };
1800
+ var strong2 = { fontWeight: 600, fontFamily: T.fontMono, fontSize: 12 };
1801
+ var dim4 = { color: T.textMuted };
1802
+ var mono4 = { fontFamily: T.fontMono, fontSize: 12, wordBreak: "break-word" };
1803
+ var relationWord = { fontFamily: T.fontMono, fontSize: 12, color: T.primary };
1804
+ var body = { display: "flex", flexWrap: "wrap", alignItems: "flex-start", gap: 16 };
1805
+ var chartStyle = { maxWidth: "100%", height: "auto", fontFamily: T.fontSans, background: T.bgPrimary, borderRadius: 6 };
1806
+ var headingText = { fontSize: 11, fontWeight: 600 };
1807
+ var edgeText = { fontSize: 10, fontFamily: T.fontMono };
1808
+ var nodeIdText = { fontSize: 12, fontWeight: 600, fontFamily: T.fontMono };
1809
+ var nodeMeaningText = { fontSize: 10 };
1810
+ var chipText = { fontSize: 9, fontFamily: T.fontMono };
1811
+ var listStyle = { display: "flex", flexDirection: "column", gap: 8, minWidth: 240, flex: 1 };
1812
+ var groupHeading = { fontWeight: 600, color: T.textSecondary, fontSize: 12 };
1813
+ var list4 = { margin: "2px 0 0", paddingLeft: 18, display: "flex", flexDirection: "column", gap: 2 };
1814
+ var chip2 = {
1815
+ marginLeft: 6,
1816
+ padding: "0 6px",
1817
+ borderRadius: 8,
1818
+ fontSize: 11,
1819
+ border: "1px solid",
1820
+ whiteSpace: "nowrap"
1821
+ };
1822
+
1342
1823
  export {
1343
1824
  LABELS2 as LABELS,
1344
1825
  MILESTONE_AXIS,
@@ -1346,6 +1827,12 @@ export {
1346
1827
  LABELS3 as LABELS2,
1347
1828
  foldReasoning,
1348
1829
  foldExchange,
1349
- ReasoningLens
1830
+ ReasoningLens,
1831
+ LABELS4 as LABELS3,
1832
+ ontologyRecordOf,
1833
+ foldOntology,
1834
+ GEOMETRY,
1835
+ layoutOntology,
1836
+ OntologyView
1350
1837
  };
1351
- //# sourceMappingURL=chunk-Y5ZHXZRE.js.map
1838
+ //# sourceMappingURL=chunk-RHXCHNS6.js.map