agentfootprint-lens 0.17.0 → 0.18.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/dist/index.cjs +448 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +134 -1
- package/dist/index.d.ts +134 -1
- package/dist/index.js +449 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -395,6 +395,8 @@ __export(src_exports, {
|
|
|
395
395
|
LensRecorder: () => LensRecorder,
|
|
396
396
|
LensSnapshotRecorder: () => LensSnapshotRecorder,
|
|
397
397
|
RunTreeView: () => RunTreeView,
|
|
398
|
+
SKILL_GRAPH_START_ID: () => SKILL_GRAPH_START_ID,
|
|
399
|
+
SkillGraphFlow: () => SkillGraphFlow,
|
|
398
400
|
SummaryCard: () => SummaryCard,
|
|
399
401
|
TimeTravel: () => TimeTravel,
|
|
400
402
|
buildLLMText: () => buildLLMText,
|
|
@@ -405,6 +407,7 @@ __export(src_exports, {
|
|
|
405
407
|
humanizeWith: () => humanizeWith,
|
|
406
408
|
isContextEngineering: () => isContextEngineering,
|
|
407
409
|
layoutLensGraph: () => layoutLensGraph,
|
|
410
|
+
layoutSkillGraph: () => layoutSkillGraph,
|
|
408
411
|
lensGroupTranslator: () => lensGroupTranslator,
|
|
409
412
|
lensRecorder: () => lensRecorder,
|
|
410
413
|
lensSnapshotRecorder: () => lensSnapshotRecorder,
|
|
@@ -5811,12 +5814,432 @@ function shortType(type) {
|
|
|
5811
5814
|
return type.replace(/^agentfootprint\./, "");
|
|
5812
5815
|
}
|
|
5813
5816
|
|
|
5814
|
-
// src/react/
|
|
5817
|
+
// src/react/SkillGraphFlow.tsx
|
|
5815
5818
|
var import_react13 = require("react");
|
|
5819
|
+
var import_react14 = require("@xyflow/react");
|
|
5820
|
+
var import_style2 = require("@xyflow/react/dist/style.css");
|
|
5821
|
+
|
|
5822
|
+
// src/react/skillGraphFlowLayout.ts
|
|
5823
|
+
var import_dagre2 = __toESM(require("dagre"), 1);
|
|
5824
|
+
var SKILL_GRAPH_START_ID = "__start__";
|
|
5825
|
+
var SIZES = {
|
|
5826
|
+
start: { width: 104, height: 40 },
|
|
5827
|
+
predicate: { width: 188, height: 96 },
|
|
5828
|
+
skill: { width: 192, height: 56 }
|
|
5829
|
+
};
|
|
5830
|
+
function sizeFor(kind) {
|
|
5831
|
+
return SIZES[kind];
|
|
5832
|
+
}
|
|
5833
|
+
function layoutSkillGraph(graph, opts = {}) {
|
|
5834
|
+
const showStart = opts.showStart ?? true;
|
|
5835
|
+
const g = new import_dagre2.default.graphlib.Graph({ multigraph: true });
|
|
5836
|
+
g.setGraph({
|
|
5837
|
+
rankdir: "TB",
|
|
5838
|
+
ranksep: opts.rankSep ?? 64,
|
|
5839
|
+
nodesep: opts.nodeSep ?? 40,
|
|
5840
|
+
marginx: 8,
|
|
5841
|
+
marginy: 8
|
|
5842
|
+
});
|
|
5843
|
+
g.setDefaultEdgeLabel(() => ({}));
|
|
5844
|
+
const usesStart = showStart && graph.edges.some((e) => e.from === null);
|
|
5845
|
+
if (usesStart) g.setNode(SKILL_GRAPH_START_ID, { ...SIZES.start });
|
|
5846
|
+
for (const n of graph.nodes) g.setNode(n.id, { ...SIZES[n.kind] });
|
|
5847
|
+
const flowEdges = [];
|
|
5848
|
+
let i = 0;
|
|
5849
|
+
for (const e of graph.edges) {
|
|
5850
|
+
if (e.from === null && !usesStart) continue;
|
|
5851
|
+
const source = e.from === null ? SKILL_GRAPH_START_ID : e.from;
|
|
5852
|
+
if (!g.hasNode(source) || !g.hasNode(e.to)) continue;
|
|
5853
|
+
const id = `sge${i++}:${source}->${e.to}`;
|
|
5854
|
+
g.setEdge(source, e.to, {}, id);
|
|
5855
|
+
flowEdges.push({ id, source, target: e.to, label: e.label, dashed: e.kind === "model" });
|
|
5856
|
+
}
|
|
5857
|
+
import_dagre2.default.layout(g);
|
|
5858
|
+
const toFlow = (id, kind, label) => {
|
|
5859
|
+
const p = g.node(id);
|
|
5860
|
+
return {
|
|
5861
|
+
id,
|
|
5862
|
+
kind,
|
|
5863
|
+
label,
|
|
5864
|
+
x: p.x - p.width / 2,
|
|
5865
|
+
// dagre centers; xyflow positions by top-left
|
|
5866
|
+
y: p.y - p.height / 2,
|
|
5867
|
+
width: p.width,
|
|
5868
|
+
height: p.height
|
|
5869
|
+
};
|
|
5870
|
+
};
|
|
5871
|
+
const nodes = [];
|
|
5872
|
+
if (usesStart) nodes.push(toFlow(SKILL_GRAPH_START_ID, "start", "\u25B6 start"));
|
|
5873
|
+
for (const n of graph.nodes) nodes.push(toFlow(n.id, n.kind, n.label ?? n.id));
|
|
5874
|
+
return { nodes, edges: flowEdges };
|
|
5875
|
+
}
|
|
5876
|
+
|
|
5877
|
+
// src/react/SkillGraphFlow.tsx
|
|
5878
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
5879
|
+
var HANDLE_STYLE = {
|
|
5880
|
+
opacity: 0,
|
|
5881
|
+
width: 1,
|
|
5882
|
+
height: 1,
|
|
5883
|
+
border: "none",
|
|
5884
|
+
background: "transparent",
|
|
5885
|
+
pointerEvents: "none"
|
|
5886
|
+
};
|
|
5887
|
+
var StartNode = ({ data }) => {
|
|
5888
|
+
const d = data;
|
|
5889
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
5890
|
+
"div",
|
|
5891
|
+
{
|
|
5892
|
+
style: {
|
|
5893
|
+
...sizeFor("start"),
|
|
5894
|
+
display: "flex",
|
|
5895
|
+
alignItems: "center",
|
|
5896
|
+
justifyContent: "center",
|
|
5897
|
+
borderRadius: 999,
|
|
5898
|
+
background: T.bgTertiary,
|
|
5899
|
+
color: T.textSecondary,
|
|
5900
|
+
border: `1px solid ${T.border}`,
|
|
5901
|
+
fontFamily: T.fontSans,
|
|
5902
|
+
fontSize: 12,
|
|
5903
|
+
fontWeight: 600,
|
|
5904
|
+
boxSizing: "border-box"
|
|
5905
|
+
},
|
|
5906
|
+
children: [
|
|
5907
|
+
d.label,
|
|
5908
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react14.Handle, { type: "source", position: import_react14.Position.Bottom, style: HANDLE_STYLE, isConnectable: false })
|
|
5909
|
+
]
|
|
5910
|
+
}
|
|
5911
|
+
);
|
|
5912
|
+
};
|
|
5913
|
+
var SkillBoxNode = ({ data }) => {
|
|
5914
|
+
const d = data;
|
|
5915
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
5916
|
+
"div",
|
|
5917
|
+
{
|
|
5918
|
+
style: {
|
|
5919
|
+
...sizeFor("skill"),
|
|
5920
|
+
display: "flex",
|
|
5921
|
+
alignItems: "center",
|
|
5922
|
+
gap: 8,
|
|
5923
|
+
padding: "0 12px",
|
|
5924
|
+
borderRadius: 10,
|
|
5925
|
+
background: T.bgSecondary,
|
|
5926
|
+
color: T.textPrimary,
|
|
5927
|
+
border: `${d.isSelected ? 2 : 1}px solid ${d.isSelected ? T.srcSkill : T.border}`,
|
|
5928
|
+
boxShadow: d.isSelected ? `0 0 0 3px ${T.srcSkill}33` : "none",
|
|
5929
|
+
fontFamily: T.fontSans,
|
|
5930
|
+
fontSize: 13,
|
|
5931
|
+
fontWeight: 600,
|
|
5932
|
+
boxSizing: "border-box",
|
|
5933
|
+
cursor: "pointer"
|
|
5934
|
+
},
|
|
5935
|
+
children: [
|
|
5936
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react14.Handle, { type: "target", position: import_react14.Position.Top, style: HANDLE_STYLE, isConnectable: false }),
|
|
5937
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5938
|
+
"span",
|
|
5939
|
+
{
|
|
5940
|
+
"aria-hidden": true,
|
|
5941
|
+
style: {
|
|
5942
|
+
flex: "0 0 auto",
|
|
5943
|
+
width: 8,
|
|
5944
|
+
height: 8,
|
|
5945
|
+
borderRadius: 2,
|
|
5946
|
+
background: T.srcSkill
|
|
5947
|
+
}
|
|
5948
|
+
}
|
|
5949
|
+
),
|
|
5950
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: d.label }),
|
|
5951
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react14.Handle, { type: "source", position: import_react14.Position.Bottom, style: HANDLE_STYLE, isConnectable: false })
|
|
5952
|
+
]
|
|
5953
|
+
}
|
|
5954
|
+
);
|
|
5955
|
+
};
|
|
5956
|
+
var PredicateNode = ({ data }) => {
|
|
5957
|
+
const d = data;
|
|
5958
|
+
const { width, height } = sizeFor("predicate");
|
|
5959
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { width, height, position: "relative", cursor: "pointer" }, children: [
|
|
5960
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react14.Handle, { type: "target", position: import_react14.Position.Top, style: HANDLE_STYLE, isConnectable: false }),
|
|
5961
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5962
|
+
"div",
|
|
5963
|
+
{
|
|
5964
|
+
style: {
|
|
5965
|
+
position: "absolute",
|
|
5966
|
+
inset: 0,
|
|
5967
|
+
background: T.bgSecondary,
|
|
5968
|
+
border: `${d.isSelected ? 2 : 1}px solid ${d.isSelected ? T.edgeDecision : T.border}`,
|
|
5969
|
+
boxShadow: d.isSelected ? `0 0 0 3px ${T.edgeDecision}33` : "none",
|
|
5970
|
+
clipPath: "polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)"
|
|
5971
|
+
}
|
|
5972
|
+
}
|
|
5973
|
+
),
|
|
5974
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5975
|
+
"div",
|
|
5976
|
+
{
|
|
5977
|
+
style: {
|
|
5978
|
+
position: "absolute",
|
|
5979
|
+
inset: 0,
|
|
5980
|
+
display: "flex",
|
|
5981
|
+
alignItems: "center",
|
|
5982
|
+
justifyContent: "center",
|
|
5983
|
+
padding: "0 32px",
|
|
5984
|
+
textAlign: "center",
|
|
5985
|
+
color: T.textPrimary,
|
|
5986
|
+
fontFamily: T.fontSans,
|
|
5987
|
+
fontSize: 12,
|
|
5988
|
+
fontWeight: 600,
|
|
5989
|
+
lineHeight: 1.2,
|
|
5990
|
+
boxSizing: "border-box"
|
|
5991
|
+
},
|
|
5992
|
+
children: d.label
|
|
5993
|
+
}
|
|
5994
|
+
),
|
|
5995
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react14.Handle, { type: "source", position: import_react14.Position.Bottom, style: HANDLE_STYLE, isConnectable: false })
|
|
5996
|
+
] });
|
|
5997
|
+
};
|
|
5998
|
+
var NODE_TYPES = {
|
|
5999
|
+
sgStart: StartNode,
|
|
6000
|
+
sgPredicate: PredicateNode,
|
|
6001
|
+
sgSkill: SkillBoxNode
|
|
6002
|
+
};
|
|
6003
|
+
function DetailPanel({
|
|
6004
|
+
node,
|
|
6005
|
+
detail,
|
|
6006
|
+
width
|
|
6007
|
+
}) {
|
|
6008
|
+
const panel = {
|
|
6009
|
+
width,
|
|
6010
|
+
flex: `0 0 ${width}px`,
|
|
6011
|
+
borderLeft: `1px solid ${T.border}`,
|
|
6012
|
+
background: T.bgPrimary,
|
|
6013
|
+
color: T.textPrimary,
|
|
6014
|
+
fontFamily: T.fontSans,
|
|
6015
|
+
padding: 16,
|
|
6016
|
+
overflow: "auto",
|
|
6017
|
+
boxSizing: "border-box"
|
|
6018
|
+
};
|
|
6019
|
+
if (!node) {
|
|
6020
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("aside", { style: panel, "data-testid": "skill-graph-detail", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: { color: T.textMuted, fontSize: 13, margin: 0 }, children: "Click a node to inspect it. Diamonds are decision predicates; boxes are skills that load just-in-time when their path is chosen." }) });
|
|
6021
|
+
}
|
|
6022
|
+
const isPredicate = node.kind === "predicate";
|
|
6023
|
+
const accent = isPredicate ? T.edgeDecision : T.srcSkill;
|
|
6024
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("aside", { style: panel, "data-testid": "skill-graph-detail", children: [
|
|
6025
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 4 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
6026
|
+
"span",
|
|
6027
|
+
{
|
|
6028
|
+
style: {
|
|
6029
|
+
fontSize: 11,
|
|
6030
|
+
fontWeight: 700,
|
|
6031
|
+
textTransform: "uppercase",
|
|
6032
|
+
letterSpacing: 0.5,
|
|
6033
|
+
color: accent
|
|
6034
|
+
},
|
|
6035
|
+
children: isPredicate ? "\u25C7 Decision" : "\u25A2 Skill"
|
|
6036
|
+
}
|
|
6037
|
+
) }),
|
|
6038
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { style: { margin: "0 0 12px", fontSize: 16 }, children: detail?.title ?? node.label ?? node.id }),
|
|
6039
|
+
isPredicate && !detail && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { style: { color: T.textSecondary, fontSize: 13, margin: 0 }, children: [
|
|
6040
|
+
"Routes to its ",
|
|
6041
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: "yes" }),
|
|
6042
|
+
" / ",
|
|
6043
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: "no" }),
|
|
6044
|
+
" subtree based on this predicate, evaluated every iteration."
|
|
6045
|
+
] }),
|
|
6046
|
+
detail?.description && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: { color: T.textSecondary, fontSize: 13, margin: "0 0 12px" }, children: detail.description }),
|
|
6047
|
+
detail?.meta?.map((row) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { fontSize: 12, marginBottom: 6 }, children: [
|
|
6048
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { style: { color: T.textMuted }, children: [
|
|
6049
|
+
row.label,
|
|
6050
|
+
": "
|
|
6051
|
+
] }),
|
|
6052
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { color: T.textSecondary }, children: row.value })
|
|
6053
|
+
] }, row.label)),
|
|
6054
|
+
detail?.tools && detail.tools.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { marginTop: 12 }, children: [
|
|
6055
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { fontSize: 11, color: T.textMuted, marginBottom: 6 }, children: [
|
|
6056
|
+
"UNLOCKS ",
|
|
6057
|
+
detail.tools.length,
|
|
6058
|
+
" TOOL",
|
|
6059
|
+
detail.tools.length === 1 ? "" : "S"
|
|
6060
|
+
] }),
|
|
6061
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6 }, children: detail.tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
6062
|
+
"span",
|
|
6063
|
+
{
|
|
6064
|
+
style: {
|
|
6065
|
+
fontFamily: T.fontMono,
|
|
6066
|
+
fontSize: 11,
|
|
6067
|
+
padding: "2px 6px",
|
|
6068
|
+
borderRadius: 6,
|
|
6069
|
+
background: T.bgTertiary,
|
|
6070
|
+
color: T.textSecondary
|
|
6071
|
+
},
|
|
6072
|
+
children: tool
|
|
6073
|
+
},
|
|
6074
|
+
tool
|
|
6075
|
+
)) })
|
|
6076
|
+
] }),
|
|
6077
|
+
detail?.body && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
6078
|
+
"pre",
|
|
6079
|
+
{
|
|
6080
|
+
style: {
|
|
6081
|
+
marginTop: 12,
|
|
6082
|
+
padding: 10,
|
|
6083
|
+
borderRadius: 8,
|
|
6084
|
+
background: T.bgSecondary,
|
|
6085
|
+
color: T.textSecondary,
|
|
6086
|
+
fontFamily: T.fontMono,
|
|
6087
|
+
fontSize: 11.5,
|
|
6088
|
+
lineHeight: 1.45,
|
|
6089
|
+
whiteSpace: "pre-wrap",
|
|
6090
|
+
wordBreak: "break-word",
|
|
6091
|
+
overflow: "auto"
|
|
6092
|
+
},
|
|
6093
|
+
children: detail.body
|
|
6094
|
+
}
|
|
6095
|
+
)
|
|
6096
|
+
] });
|
|
6097
|
+
}
|
|
6098
|
+
var SkillGraphFlow = ({
|
|
6099
|
+
graph,
|
|
6100
|
+
detailFor,
|
|
6101
|
+
selectedId: selectedIdProp,
|
|
6102
|
+
defaultSelectedId = null,
|
|
6103
|
+
onSelectNode,
|
|
6104
|
+
showStart = true,
|
|
6105
|
+
hideDetailPanel = false,
|
|
6106
|
+
defaultPanelWidth = 320,
|
|
6107
|
+
height = "100%",
|
|
6108
|
+
className,
|
|
6109
|
+
style
|
|
6110
|
+
}) => {
|
|
6111
|
+
const isControlled = selectedIdProp !== void 0;
|
|
6112
|
+
const [internalSelected, setInternalSelected] = (0, import_react13.useState)(defaultSelectedId);
|
|
6113
|
+
const selectedId = isControlled ? selectedIdProp : internalSelected;
|
|
6114
|
+
const select = (0, import_react13.useCallback)(
|
|
6115
|
+
(id) => {
|
|
6116
|
+
if (!isControlled) setInternalSelected(id);
|
|
6117
|
+
onSelectNode?.(id);
|
|
6118
|
+
},
|
|
6119
|
+
[isControlled, onSelectNode]
|
|
6120
|
+
);
|
|
6121
|
+
const containerRef = (0, import_react13.useRef)(null);
|
|
6122
|
+
const [panelWidth, setPanelWidth] = (0, import_react13.useState)(defaultPanelWidth);
|
|
6123
|
+
const [dragging, setDragging] = (0, import_react13.useState)(false);
|
|
6124
|
+
const startResize = (0, import_react13.useCallback)((e) => {
|
|
6125
|
+
e.preventDefault();
|
|
6126
|
+
setDragging(true);
|
|
6127
|
+
const onMove = (ev) => {
|
|
6128
|
+
const rect = containerRef.current?.getBoundingClientRect();
|
|
6129
|
+
if (!rect) return;
|
|
6130
|
+
const next = rect.right - ev.clientX;
|
|
6131
|
+
const max = Math.max(240, rect.width - 240);
|
|
6132
|
+
setPanelWidth(Math.min(max, Math.max(220, next)));
|
|
6133
|
+
};
|
|
6134
|
+
const onUp = () => {
|
|
6135
|
+
setDragging(false);
|
|
6136
|
+
window.removeEventListener("mousemove", onMove);
|
|
6137
|
+
window.removeEventListener("mouseup", onUp);
|
|
6138
|
+
};
|
|
6139
|
+
window.addEventListener("mousemove", onMove);
|
|
6140
|
+
window.addEventListener("mouseup", onUp);
|
|
6141
|
+
}, []);
|
|
6142
|
+
const { rfNodes, rfEdges } = (0, import_react13.useMemo)(() => {
|
|
6143
|
+
const laid = layoutSkillGraph(graph, { showStart });
|
|
6144
|
+
const rfNodes2 = laid.nodes.map((n) => ({
|
|
6145
|
+
id: n.id,
|
|
6146
|
+
type: n.kind === "start" ? "sgStart" : n.kind === "predicate" ? "sgPredicate" : "sgSkill",
|
|
6147
|
+
position: { x: n.x, y: n.y },
|
|
6148
|
+
width: n.width,
|
|
6149
|
+
height: n.height,
|
|
6150
|
+
draggable: false,
|
|
6151
|
+
selectable: n.kind !== "start",
|
|
6152
|
+
data: { label: n.label, isSelected: n.id === selectedId }
|
|
6153
|
+
}));
|
|
6154
|
+
const rfEdges2 = laid.edges.map((e) => ({
|
|
6155
|
+
id: e.id,
|
|
6156
|
+
source: e.source,
|
|
6157
|
+
target: e.target,
|
|
6158
|
+
label: e.label,
|
|
6159
|
+
style: {
|
|
6160
|
+
stroke: T.edgeDefault,
|
|
6161
|
+
strokeWidth: 1.5,
|
|
6162
|
+
strokeDasharray: e.dashed ? "5 4" : void 0
|
|
6163
|
+
},
|
|
6164
|
+
labelStyle: { fill: T.textMuted, fontFamily: T.fontSans, fontSize: 11 },
|
|
6165
|
+
labelBgStyle: { fill: T.bgPrimary, fillOpacity: 0.85 },
|
|
6166
|
+
markerEnd: { type: import_react14.MarkerType.ArrowClosed, color: T.edgeDefault, width: 16, height: 16 }
|
|
6167
|
+
}));
|
|
6168
|
+
return { rfNodes: rfNodes2, rfEdges: rfEdges2 };
|
|
6169
|
+
}, [graph, showStart, selectedId]);
|
|
6170
|
+
const selectedNode = (0, import_react13.useMemo)(
|
|
6171
|
+
() => selectedId ? graph.nodes.find((n) => n.id === selectedId) ?? null : null,
|
|
6172
|
+
[graph.nodes, selectedId]
|
|
6173
|
+
);
|
|
6174
|
+
const detail = selectedNode && detailFor ? detailFor(selectedNode) : void 0;
|
|
6175
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
6176
|
+
"div",
|
|
6177
|
+
{
|
|
6178
|
+
ref: containerRef,
|
|
6179
|
+
className,
|
|
6180
|
+
style: {
|
|
6181
|
+
display: "flex",
|
|
6182
|
+
height,
|
|
6183
|
+
width: "100%",
|
|
6184
|
+
background: T.bgPrimary,
|
|
6185
|
+
// While dragging, suppress text selection + let the divider own the cursor.
|
|
6186
|
+
userSelect: dragging ? "none" : void 0,
|
|
6187
|
+
cursor: dragging ? "col-resize" : void 0,
|
|
6188
|
+
...style
|
|
6189
|
+
},
|
|
6190
|
+
children: [
|
|
6191
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { flex: 1, minWidth: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react14.ReactFlowProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
6192
|
+
import_react14.ReactFlow,
|
|
6193
|
+
{
|
|
6194
|
+
nodes: rfNodes,
|
|
6195
|
+
edges: rfEdges,
|
|
6196
|
+
nodeTypes: NODE_TYPES,
|
|
6197
|
+
onNodeClick: (_, node) => select(node.id),
|
|
6198
|
+
onPaneClick: () => select(null),
|
|
6199
|
+
nodesDraggable: false,
|
|
6200
|
+
nodesConnectable: false,
|
|
6201
|
+
elementsSelectable: true,
|
|
6202
|
+
fitView: true,
|
|
6203
|
+
fitViewOptions: { padding: 0.2 },
|
|
6204
|
+
minZoom: 0.1,
|
|
6205
|
+
maxZoom: 1.5,
|
|
6206
|
+
proOptions: { hideAttribution: true },
|
|
6207
|
+
children: [
|
|
6208
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react14.Background, { color: T.border, gap: 20 }),
|
|
6209
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react14.Controls, { showInteractive: false })
|
|
6210
|
+
]
|
|
6211
|
+
}
|
|
6212
|
+
) }) }),
|
|
6213
|
+
!hideDetailPanel && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
6214
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
6215
|
+
"div",
|
|
6216
|
+
{
|
|
6217
|
+
role: "separator",
|
|
6218
|
+
"aria-orientation": "vertical",
|
|
6219
|
+
"data-testid": "skill-graph-resizer",
|
|
6220
|
+
onMouseDown: startResize,
|
|
6221
|
+
title: "Drag to resize",
|
|
6222
|
+
style: {
|
|
6223
|
+
flex: "0 0 6px",
|
|
6224
|
+
cursor: "col-resize",
|
|
6225
|
+
background: dragging ? T.srcSkill : T.border,
|
|
6226
|
+
transition: dragging ? void 0 : "background 120ms"
|
|
6227
|
+
}
|
|
6228
|
+
}
|
|
6229
|
+
),
|
|
6230
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DetailPanel, { node: selectedNode, detail, width: panelWidth })
|
|
6231
|
+
] })
|
|
6232
|
+
]
|
|
6233
|
+
}
|
|
6234
|
+
);
|
|
6235
|
+
};
|
|
6236
|
+
|
|
6237
|
+
// src/react/hooks/useStepFocus.ts
|
|
6238
|
+
var import_react15 = require("react");
|
|
5816
6239
|
function useStepFocus(max) {
|
|
5817
|
-
const [focus, setFocus] = (0,
|
|
5818
|
-
const prevMax = (0,
|
|
5819
|
-
(0,
|
|
6240
|
+
const [focus, setFocus] = (0, import_react15.useState)(Math.max(0, max));
|
|
6241
|
+
const prevMax = (0, import_react15.useRef)(max);
|
|
6242
|
+
(0, import_react15.useEffect)(() => {
|
|
5820
6243
|
const wasLiveBefore = focus >= prevMax.current;
|
|
5821
6244
|
if (wasLiveBefore) setFocus(max);
|
|
5822
6245
|
prevMax.current = max;
|
|
@@ -5829,32 +6252,32 @@ function useStepFocus(max) {
|
|
|
5829
6252
|
}
|
|
5830
6253
|
|
|
5831
6254
|
// src/react/hooks/useStepView.ts
|
|
5832
|
-
var
|
|
6255
|
+
var import_react16 = require("react");
|
|
5833
6256
|
function useStepView(graph, log, focusIndex, drillPath) {
|
|
5834
|
-
return (0,
|
|
6257
|
+
return (0, import_react16.useMemo)(
|
|
5835
6258
|
() => selectStepView({ graph, log, focusIndex, drillPath }),
|
|
5836
6259
|
[graph, log, focusIndex, drillPath]
|
|
5837
6260
|
);
|
|
5838
6261
|
}
|
|
5839
6262
|
|
|
5840
6263
|
// src/react/hooks/useCommentarySlider.ts
|
|
5841
|
-
var
|
|
5842
|
-
var
|
|
6264
|
+
var import_react17 = require("react");
|
|
6265
|
+
var import_react18 = require("react");
|
|
5843
6266
|
function useCommentarySlider(recorder, initialMode = "commentary") {
|
|
5844
|
-
const version = (0,
|
|
6267
|
+
const version = (0, import_react18.useSyncExternalStore)(
|
|
5845
6268
|
(listener) => recorder.subscribe(listener),
|
|
5846
6269
|
() => recorder.getVersion(),
|
|
5847
6270
|
() => recorder.getVersion()
|
|
5848
6271
|
);
|
|
5849
|
-
const [commitIdx, setCommitIdxRaw] = (0,
|
|
5850
|
-
const [mode, setMode] = (0,
|
|
5851
|
-
const [drill, setDrill] = (0,
|
|
5852
|
-
const ranges = (0,
|
|
6272
|
+
const [commitIdx, setCommitIdxRaw] = (0, import_react17.useState)(0);
|
|
6273
|
+
const [mode, setMode] = (0, import_react17.useState)(initialMode);
|
|
6274
|
+
const [drill, setDrill] = (0, import_react17.useState)(void 0);
|
|
6275
|
+
const ranges = (0, import_react17.useMemo)(
|
|
5853
6276
|
() => selectCommentaryRanges(recorder.boundary),
|
|
5854
6277
|
// version captured at render time — re-derives on every notify.
|
|
5855
6278
|
[recorder, version]
|
|
5856
6279
|
);
|
|
5857
|
-
const totalCommits = (0,
|
|
6280
|
+
const totalCommits = (0, import_react17.useMemo)(() => {
|
|
5858
6281
|
const live = recorder.getCommitCount();
|
|
5859
6282
|
if (live > 0) return live;
|
|
5860
6283
|
if (ranges.length === 0) return 0;
|
|
@@ -5865,11 +6288,11 @@ function useCommentarySlider(recorder, initialMode = "commentary") {
|
|
|
5865
6288
|
}
|
|
5866
6289
|
return max + 1;
|
|
5867
6290
|
}, [recorder, ranges, version]);
|
|
5868
|
-
const snapPoints = (0,
|
|
6291
|
+
const snapPoints = (0, import_react17.useMemo)(() => {
|
|
5869
6292
|
if (mode === "commit") return [];
|
|
5870
6293
|
return ranges.map((r) => r.startIdx);
|
|
5871
6294
|
}, [mode, ranges]);
|
|
5872
|
-
const setCommitIdx = (0,
|
|
6295
|
+
const setCommitIdx = (0, import_react17.useCallback)(
|
|
5873
6296
|
(idx) => {
|
|
5874
6297
|
if (!Number.isFinite(idx)) return;
|
|
5875
6298
|
const max = Math.max(0, totalCommits - 1);
|
|
@@ -5880,7 +6303,7 @@ function useCommentarySlider(recorder, initialMode = "commentary") {
|
|
|
5880
6303
|
},
|
|
5881
6304
|
[totalCommits, drill]
|
|
5882
6305
|
);
|
|
5883
|
-
const drillInto = (0,
|
|
6306
|
+
const drillInto = (0, import_react17.useCallback)(
|
|
5884
6307
|
(range) => {
|
|
5885
6308
|
if (!Number.isFinite(range.startIdx) || range.startIdx < 0) return;
|
|
5886
6309
|
if (range.endIdx !== void 0 && !Number.isFinite(range.endIdx)) return;
|
|
@@ -5900,16 +6323,16 @@ function useCommentarySlider(recorder, initialMode = "commentary") {
|
|
|
5900
6323
|
},
|
|
5901
6324
|
[totalCommits]
|
|
5902
6325
|
);
|
|
5903
|
-
(0,
|
|
6326
|
+
(0, import_react17.useEffect)(() => {
|
|
5904
6327
|
if (!drill) return;
|
|
5905
6328
|
const inRange = commitIdx >= drill.startIdx && (drill.endIdx === void 0 || commitIdx <= drill.endIdx);
|
|
5906
6329
|
if (!inRange) setDrill(void 0);
|
|
5907
6330
|
}, [commitIdx, drill]);
|
|
5908
|
-
const active = (0,
|
|
6331
|
+
const active = (0, import_react17.useMemo)(
|
|
5909
6332
|
() => selectCommentaryAt(recorder.boundary, commitIdx),
|
|
5910
6333
|
[recorder, commitIdx, version]
|
|
5911
6334
|
);
|
|
5912
|
-
const drillRange = (0,
|
|
6335
|
+
const drillRange = (0, import_react17.useMemo)(() => {
|
|
5913
6336
|
if (!drill) return void 0;
|
|
5914
6337
|
return ranges.find(
|
|
5915
6338
|
(r) => r.label.runtimeStageId === drill.runtimeStageId
|
|
@@ -5930,9 +6353,9 @@ function useCommentarySlider(recorder, initialMode = "commentary") {
|
|
|
5930
6353
|
}
|
|
5931
6354
|
|
|
5932
6355
|
// src/react/hooks/useLensRenderGraph.ts
|
|
5933
|
-
var
|
|
6356
|
+
var import_react19 = require("react");
|
|
5934
6357
|
function useLensRenderGraph(runner, options = {}) {
|
|
5935
|
-
return (0,
|
|
6358
|
+
return (0, import_react19.useMemo)(() => {
|
|
5936
6359
|
const output = runner.getUIGroupWith(lensGroupTranslator);
|
|
5937
6360
|
if (output === void 0) {
|
|
5938
6361
|
throw new Error(
|
|
@@ -5971,6 +6394,8 @@ function assertLensGroupOutput(value) {
|
|
|
5971
6394
|
LensRecorder,
|
|
5972
6395
|
LensSnapshotRecorder,
|
|
5973
6396
|
RunTreeView,
|
|
6397
|
+
SKILL_GRAPH_START_ID,
|
|
6398
|
+
SkillGraphFlow,
|
|
5974
6399
|
SummaryCard,
|
|
5975
6400
|
TimeTravel,
|
|
5976
6401
|
buildLLMText,
|
|
@@ -5981,6 +6406,7 @@ function assertLensGroupOutput(value) {
|
|
|
5981
6406
|
humanizeWith,
|
|
5982
6407
|
isContextEngineering,
|
|
5983
6408
|
layoutLensGraph,
|
|
6409
|
+
layoutSkillGraph,
|
|
5984
6410
|
lensGroupTranslator,
|
|
5985
6411
|
lensRecorder,
|
|
5986
6412
|
lensSnapshotRecorder,
|