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