footprint-explainable-ui 0.29.0 → 0.30.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 +12 -0
- package/dist/index.cjs +224 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +224 -68
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -163,6 +163,18 @@ have. One cursor, no new axis.
|
|
|
163
163
|
- **[Copy story]** emits the same text an LLM backtrack tool returns — the
|
|
164
164
|
human's board and the agent's answer are one artifact.
|
|
165
165
|
- Tracing lives on the root rail: drilling into a subflow exits it honestly.
|
|
166
|
+
- **Trace anything**: below the current step's chips, a search box lists
|
|
167
|
+
*every* variable the run ever wrote — trace any of them from wherever you
|
|
168
|
+
stand.
|
|
169
|
+
- **Forks ask, never assume**: at a value made from two or more ingredients
|
|
170
|
+
the walk-back button becomes **⑂ choose cause…** and asks which ingredient
|
|
171
|
+
to follow (or "visit all, in time order"). Nothing is ever silently picked.
|
|
172
|
+
|
|
173
|
+

|
|
174
|
+
|
|
175
|
+
- **Unmistakable mode**: the whole tracing rail wears its own color
|
|
176
|
+
(`--fp-tracing`, teal by default — themeable) so tracing can never be
|
|
177
|
+
confused with normal time-travel.
|
|
166
178
|
|
|
167
179
|
### Panel Labels
|
|
168
180
|
|
package/dist/index.cjs
CHANGED
|
@@ -2089,14 +2089,19 @@ function TimeTravelControls({
|
|
|
2089
2089
|
if (!tracing) return null;
|
|
2090
2090
|
return tracing.stopIndices.find((i) => i > selectedIndex) ?? null;
|
|
2091
2091
|
}, [tracing, selectedIndex]);
|
|
2092
|
-
const
|
|
2092
|
+
const forkPrompt = isTracing && (tracing.forkCount ?? 0) >= 2 && !!tracing.onForkPrompt;
|
|
2093
|
+
const canPrev = isTracing ? forkPrompt || earlierStop !== null : selectedIndex > 0;
|
|
2093
2094
|
const canNext = isTracing ? laterStop !== null : selectedIndex < total - 1;
|
|
2094
2095
|
const goPrev = (0, import_react10.useCallback)(() => {
|
|
2095
2096
|
setPlaying(false);
|
|
2096
2097
|
if (isTracing) {
|
|
2098
|
+
if (forkPrompt) {
|
|
2099
|
+
tracing.onForkPrompt();
|
|
2100
|
+
return;
|
|
2101
|
+
}
|
|
2097
2102
|
if (earlierStop !== null) onIndexChange(earlierStop);
|
|
2098
2103
|
} else if (selectedIndex > 0) onIndexChange(selectedIndex - 1);
|
|
2099
|
-
}, [isTracing, earlierStop, selectedIndex, onIndexChange]);
|
|
2104
|
+
}, [isTracing, forkPrompt, tracing, earlierStop, selectedIndex, onIndexChange]);
|
|
2100
2105
|
const goNext = (0, import_react10.useCallback)(() => {
|
|
2101
2106
|
setPlaying(false);
|
|
2102
2107
|
if (isTracing) {
|
|
@@ -2148,7 +2153,7 @@ function TimeTravelControls({
|
|
|
2148
2153
|
[canPrev, canNext, playing, goPrev, goNext, autoPlayable, togglePlay, isTracing, tracing]
|
|
2149
2154
|
);
|
|
2150
2155
|
const fs = fontSize[size];
|
|
2151
|
-
const
|
|
2156
|
+
const tracingColor = "var(--fp-tracing, #0d9488)";
|
|
2152
2157
|
if (unstyled) {
|
|
2153
2158
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
2154
2159
|
"div",
|
|
@@ -2185,8 +2190,8 @@ function TimeTravelControls({
|
|
|
2185
2190
|
"data-fp": "tt-prev",
|
|
2186
2191
|
disabled: !canPrev || playing,
|
|
2187
2192
|
onClick: goPrev,
|
|
2188
|
-
"aria-label": isTracing ? "Earlier cause" : "Previous stage",
|
|
2189
|
-
children: isTracing ? "Earlier cause" : "Prev"
|
|
2193
|
+
"aria-label": isTracing ? forkPrompt ? "Choose cause" : "Earlier cause" : "Previous stage",
|
|
2194
|
+
children: isTracing ? forkPrompt ? "Choose cause\u2026" : "Earlier cause" : "Prev"
|
|
2190
2195
|
}
|
|
2191
2196
|
),
|
|
2192
2197
|
autoPlayable && !isTracing && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { "data-fp": "tt-play", onClick: togglePlay, "aria-label": playing ? "Pause" : "Play", children: playing ? "Pause" : "Play" }),
|
|
@@ -2225,8 +2230,8 @@ function TimeTravelControls({
|
|
|
2225
2230
|
}
|
|
2226
2231
|
const btnStyle = (disabled) => ({
|
|
2227
2232
|
background: theme.bgTertiary,
|
|
2228
|
-
border: `1px solid ${theme.border}`,
|
|
2229
|
-
color: disabled ? theme.textMuted : theme.textPrimary,
|
|
2233
|
+
border: `1px solid ${isTracing ? tracingColor : theme.border}`,
|
|
2234
|
+
color: disabled ? theme.textMuted : isTracing ? tracingColor : theme.textPrimary,
|
|
2230
2235
|
borderRadius: "6px",
|
|
2231
2236
|
padding: "4px 12px",
|
|
2232
2237
|
fontSize: fs.body,
|
|
@@ -2242,7 +2247,7 @@ function TimeTravelControls({
|
|
|
2242
2247
|
style: {
|
|
2243
2248
|
padding: "6px 12px",
|
|
2244
2249
|
background: theme.bgSecondary,
|
|
2245
|
-
borderBottom: isTracing ? `2px solid ${
|
|
2250
|
+
borderBottom: isTracing ? `2px solid ${tracingColor}` : `1px solid ${theme.border}`,
|
|
2246
2251
|
display: "flex",
|
|
2247
2252
|
alignItems: "center",
|
|
2248
2253
|
gap: 6,
|
|
@@ -2277,14 +2282,14 @@ function TimeTravelControls({
|
|
|
2277
2282
|
letterSpacing: "0.06em",
|
|
2278
2283
|
textTransform: "uppercase",
|
|
2279
2284
|
color: "#fff",
|
|
2280
|
-
background:
|
|
2285
|
+
background: tracingColor,
|
|
2281
2286
|
borderRadius: 4,
|
|
2282
2287
|
padding: "2px 7px"
|
|
2283
2288
|
},
|
|
2284
2289
|
children: "Tracing"
|
|
2285
2290
|
}
|
|
2286
2291
|
),
|
|
2287
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { fontFamily: "monospace", fontWeight: 600, color:
|
|
2292
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { fontFamily: "monospace", fontWeight: 600, color: tracingColor }, children: tracing.tracedKey }),
|
|
2288
2293
|
tracing.viaKey && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { style: { color: theme.textMuted }, children: [
|
|
2289
2294
|
"\u25B8 via",
|
|
2290
2295
|
" ",
|
|
@@ -2298,7 +2303,7 @@ function TimeTravelControls({
|
|
|
2298
2303
|
style: {
|
|
2299
2304
|
border: "none",
|
|
2300
2305
|
background: "transparent",
|
|
2301
|
-
color:
|
|
2306
|
+
color: tracingColor,
|
|
2302
2307
|
cursor: "pointer",
|
|
2303
2308
|
fontSize: fs.body,
|
|
2304
2309
|
textDecoration: "underline",
|
|
@@ -2323,10 +2328,10 @@ function TimeTravelControls({
|
|
|
2323
2328
|
style: btnStyle(!canPrev || playing),
|
|
2324
2329
|
disabled: !canPrev || playing,
|
|
2325
2330
|
onClick: goPrev,
|
|
2326
|
-
"aria-label": isTracing ? "Earlier cause" : "Previous stage",
|
|
2327
|
-
title: isTracing ? "Earlier cause" : "Previous stage",
|
|
2331
|
+
"aria-label": isTracing ? forkPrompt ? "Choose cause" : "Earlier cause" : "Previous stage",
|
|
2332
|
+
title: isTracing ? forkPrompt ? "This stop is a fork \u2014 choose which cause to follow" : "Earlier cause" : "Previous stage",
|
|
2328
2333
|
"data-fp": "tt-prev",
|
|
2329
|
-
children: isTracing ? "\u25C0 earlier cause" : "\u25C0"
|
|
2334
|
+
children: isTracing ? forkPrompt ? "\u2442 choose cause\u2026" : "\u25C0 earlier cause" : "\u25C0"
|
|
2330
2335
|
}
|
|
2331
2336
|
),
|
|
2332
2337
|
autoPlayable && !isTracing && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
@@ -2397,7 +2402,7 @@ function TimeTravelControls({
|
|
|
2397
2402
|
borderRadius: 3,
|
|
2398
2403
|
border: "none",
|
|
2399
2404
|
cursor: unlandable ? "default" : "pointer",
|
|
2400
|
-
background: isTracing ? isActive ?
|
|
2405
|
+
background: isTracing ? isActive ? tracingColor : isStop ? "color-mix(in srgb, " + tracingColor + " 55%, transparent)" : theme.bgTertiary : isActive ? theme.primary : isDone ? theme.success : theme.bgTertiary,
|
|
2401
2406
|
opacity: unlandable ? 0.3 : isTracing || isDone || isActive ? 1 : 0.4,
|
|
2402
2407
|
transition: "all 0.15s ease"
|
|
2403
2408
|
}
|
|
@@ -2648,16 +2653,22 @@ var TraceWalkCard = (0, import_react11.memo)(function TraceWalkCard2({
|
|
|
2648
2653
|
onFollowIngredient,
|
|
2649
2654
|
onJumpToStop,
|
|
2650
2655
|
onShowAll,
|
|
2651
|
-
onExit
|
|
2656
|
+
onExit,
|
|
2657
|
+
forkChooserOpen,
|
|
2658
|
+
onContinueTimeOrder,
|
|
2659
|
+
canContinueTimeOrder = true
|
|
2652
2660
|
}) {
|
|
2653
2661
|
const [copied, setCopied] = (0, import_react11.useState)(false);
|
|
2654
2662
|
const accent = "var(--fp-accent, #6366f1)";
|
|
2663
|
+
const tracingColor = "var(--fp-tracing, #0d9488)";
|
|
2655
2664
|
const currentIdx = (0, import_react11.useMemo)(() => {
|
|
2656
2665
|
if (!cursorRuntimeStageId) return 0;
|
|
2657
2666
|
const i = walk.stops.findIndex((s) => s.runtimeStageId === cursorRuntimeStageId);
|
|
2658
2667
|
return i >= 0 ? i : 0;
|
|
2659
2668
|
}, [walk, cursorRuntimeStageId]);
|
|
2660
2669
|
const current = walk.stops[currentIdx];
|
|
2670
|
+
const followableCount = current ? current.ingredients.filter((ing) => ing.writerRuntimeStageId !== null).length : 0;
|
|
2671
|
+
const chooserVisible = !!forkChooserOpen && followableCount >= 2;
|
|
2661
2672
|
const copyStory = () => {
|
|
2662
2673
|
const text = formatTraceWalk(walk, stepNumberOf);
|
|
2663
2674
|
void navigator.clipboard?.writeText(text).then(() => {
|
|
@@ -2743,7 +2754,60 @@ var TraceWalkCard = (0, import_react11.memo)(function TraceWalkCard2({
|
|
|
2743
2754
|
preview
|
|
2744
2755
|
] })
|
|
2745
2756
|
] }),
|
|
2746
|
-
|
|
2757
|
+
chooserVisible && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
2758
|
+
"div",
|
|
2759
|
+
{
|
|
2760
|
+
"data-fp": "twc-fork-chooser",
|
|
2761
|
+
style: {
|
|
2762
|
+
marginTop: 10,
|
|
2763
|
+
padding: "10px 12px",
|
|
2764
|
+
border: `1.5px solid ${tracingColor}`,
|
|
2765
|
+
borderRadius: 8,
|
|
2766
|
+
background: `color-mix(in srgb, ${tracingColor} 8%, transparent)`
|
|
2767
|
+
},
|
|
2768
|
+
children: [
|
|
2769
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { fontWeight: 600, fontSize: 12, color: theme.textPrimary }, children: [
|
|
2770
|
+
"This value was made from ",
|
|
2771
|
+
current.ingredients.length,
|
|
2772
|
+
" ingredients \u2014 which one should the walk follow?"
|
|
2773
|
+
] }),
|
|
2774
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, marginTop: 8 }, children: current.ingredients.map((ing, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2775
|
+
IngredientChip,
|
|
2776
|
+
{
|
|
2777
|
+
ing,
|
|
2778
|
+
color: i < CHIP_COLORS.length ? CHIP_COLORS[i] : theme.textMuted,
|
|
2779
|
+
step: ing.writerRuntimeStageId ? stepNumberOf(ing.writerRuntimeStageId) : null,
|
|
2780
|
+
onFollow: onFollowIngredient
|
|
2781
|
+
},
|
|
2782
|
+
ing.key
|
|
2783
|
+
)) }),
|
|
2784
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2785
|
+
"button",
|
|
2786
|
+
{
|
|
2787
|
+
"data-fp": "twc-continue-time",
|
|
2788
|
+
onClick: canContinueTimeOrder ? onContinueTimeOrder : void 0,
|
|
2789
|
+
disabled: !canContinueTimeOrder,
|
|
2790
|
+
title: canContinueTimeOrder ? void 0 : "This is the walk's earliest stop \u2014 there is nothing earlier to visit",
|
|
2791
|
+
style: {
|
|
2792
|
+
display: "block",
|
|
2793
|
+
width: "100%",
|
|
2794
|
+
marginTop: 8,
|
|
2795
|
+
border: `1px solid ${theme.border}`,
|
|
2796
|
+
background: theme.bgTertiary,
|
|
2797
|
+
color: theme.textPrimary,
|
|
2798
|
+
borderRadius: 6,
|
|
2799
|
+
padding: "5px 10px",
|
|
2800
|
+
fontSize: 11,
|
|
2801
|
+
fontWeight: 600,
|
|
2802
|
+
cursor: "pointer"
|
|
2803
|
+
},
|
|
2804
|
+
children: "visit all, oldest cause last (time order)"
|
|
2805
|
+
}
|
|
2806
|
+
)
|
|
2807
|
+
]
|
|
2808
|
+
}
|
|
2809
|
+
),
|
|
2810
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { marginTop: 10 }, children: chooserVisible ? null : current.ingredients.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
2747
2811
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { fontSize: 11, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.5px", fontWeight: 600 }, children: [
|
|
2748
2812
|
"Made from ",
|
|
2749
2813
|
current.ingredients.length,
|
|
@@ -6875,6 +6939,11 @@ function ExplainableShell({
|
|
|
6875
6939
|
const [rightPanelMode, setRightPanelMode] = (0, import_react32.useState)("insights");
|
|
6876
6940
|
const [inspectorTab, setInspectorTab] = (0, import_react32.useState)("state");
|
|
6877
6941
|
const [tracing, setTracing] = (0, import_react32.useState)(null);
|
|
6942
|
+
const [forkChooserOpen, setForkChooserOpen] = (0, import_react32.useState)(false);
|
|
6943
|
+
const [traceSearch, setTraceSearch] = (0, import_react32.useState)("");
|
|
6944
|
+
(0, import_react32.useEffect)(() => {
|
|
6945
|
+
setForkChooserOpen(false);
|
|
6946
|
+
}, [snapshotIdx]);
|
|
6878
6947
|
const [leftExpanded, setLeftExpanded] = (0, import_react32.useState)(defaultExpanded?.topology ?? false);
|
|
6879
6948
|
const [timelineExpanded, setTimelineExpanded] = (0, import_react32.useState)(defaultExpanded?.timeline ?? false);
|
|
6880
6949
|
(0, import_react32.useEffect)(() => {
|
|
@@ -6914,6 +6983,21 @@ function ExplainableShell({
|
|
|
6914
6983
|
() => runtimeSnapshot?.commitLog ? buildDataTrace(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, activeSnapshots[safeIdx]?.runtimeStageId ?? "") : { frames: [], readsAvailable: true },
|
|
6915
6984
|
[runtimeSnapshot, activeSnapshots, safeIdx]
|
|
6916
6985
|
);
|
|
6986
|
+
const allTracedKeys = (0, import_react32.useMemo)(() => {
|
|
6987
|
+
const log = runtimeSnapshot?.commitLog;
|
|
6988
|
+
if (!log?.length) return [];
|
|
6989
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6990
|
+
const keys = [];
|
|
6991
|
+
for (const c of log) {
|
|
6992
|
+
for (const t of c.trace ?? []) {
|
|
6993
|
+
if (!seen.has(t.path)) {
|
|
6994
|
+
seen.add(t.path);
|
|
6995
|
+
keys.push(t.path);
|
|
6996
|
+
}
|
|
6997
|
+
}
|
|
6998
|
+
}
|
|
6999
|
+
return keys;
|
|
7000
|
+
}, [runtimeSnapshot]);
|
|
6917
7001
|
const traceWalk = (0, import_react32.useMemo)(() => {
|
|
6918
7002
|
if (!tracing || !runtimeSnapshot?.commitLog) return null;
|
|
6919
7003
|
const scope = tracing.via.length > 0 ? tracing.via[tracing.via.length - 1] : tracing;
|
|
@@ -6987,6 +7071,8 @@ function ExplainableShell({
|
|
|
6987
7071
|
const cursorCommitIdx = log.findIndex((c) => c.runtimeStageId === cursorRsid);
|
|
6988
7072
|
const beforeCommitIdx = cursorCommitIdx >= 0 ? cursorCommitIdx + 1 : void 0;
|
|
6989
7073
|
setTracing({ key, beforeCommitIdx, via: [] });
|
|
7074
|
+
setForkChooserOpen(false);
|
|
7075
|
+
setTraceSearch("");
|
|
6990
7076
|
setRightPanelMode("what");
|
|
6991
7077
|
setInspectorTab("trace");
|
|
6992
7078
|
jumpToAnchor(
|
|
@@ -7000,6 +7086,7 @@ function ExplainableShell({
|
|
|
7000
7086
|
if (!tracing || !runtimeSnapshot?.commitLog || ing.writerCommitIdx === null) return;
|
|
7001
7087
|
const scope = { key: ing.key, beforeCommitIdx: ing.writerCommitIdx + 1 };
|
|
7002
7088
|
setTracing({ ...tracing, via: [...tracing.via, scope] });
|
|
7089
|
+
setForkChooserOpen(false);
|
|
7003
7090
|
jumpToAnchor(
|
|
7004
7091
|
buildTraceWalk(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, scope.key, {
|
|
7005
7092
|
beforeCommitIdx: scope.beforeCommitIdx
|
|
@@ -7011,18 +7098,29 @@ function ExplainableShell({
|
|
|
7011
7098
|
const handleShowAllIngredients = (0, import_react32.useCallback)(() => {
|
|
7012
7099
|
if (!tracing || !runtimeSnapshot?.commitLog) return;
|
|
7013
7100
|
setTracing({ ...tracing, via: [] });
|
|
7101
|
+
setForkChooserOpen(false);
|
|
7014
7102
|
jumpToAnchor(
|
|
7015
7103
|
buildTraceWalk(runtimeSnapshot.commitLog, runtimeSnapshot.executionTree, tracing.key, {
|
|
7016
7104
|
beforeCommitIdx: tracing.beforeCommitIdx
|
|
7017
7105
|
})
|
|
7018
7106
|
);
|
|
7019
7107
|
}, [tracing, runtimeSnapshot, jumpToAnchor]);
|
|
7020
|
-
const handleExitTracing = (0, import_react32.useCallback)(() =>
|
|
7108
|
+
const handleExitTracing = (0, import_react32.useCallback)(() => {
|
|
7109
|
+
setTracing(null);
|
|
7110
|
+
setForkChooserOpen(false);
|
|
7111
|
+
}, []);
|
|
7112
|
+
const handleForkPrompt = (0, import_react32.useCallback)(() => setForkChooserOpen(true), []);
|
|
7113
|
+
const handleContinueTimeOrder = (0, import_react32.useCallback)(() => {
|
|
7114
|
+
const earlier = traceStopIndices.filter((i) => i < safeIdx);
|
|
7115
|
+
if (earlier.length > 0) setSnapshotIdx(earlier[earlier.length - 1]);
|
|
7116
|
+
setForkChooserOpen(false);
|
|
7117
|
+
}, [traceStopIndices, safeIdx]);
|
|
7021
7118
|
const handleDrillDown = (0, import_react32.useCallback)(
|
|
7022
7119
|
(nodeName) => {
|
|
7023
7120
|
const entry = resolveSubflowFromRuntime(activeSnapshots, nodeName, narrativeEntries);
|
|
7024
7121
|
if (entry) {
|
|
7025
7122
|
setTracing(null);
|
|
7123
|
+
setForkChooserOpen(false);
|
|
7026
7124
|
setDrillDownStack((prev) => [...prev, { ...entry, parentSnapshotIdx: snapshotIdx }]);
|
|
7027
7125
|
setSnapshotIdx(0);
|
|
7028
7126
|
}
|
|
@@ -7088,6 +7186,7 @@ function ExplainableShell({
|
|
|
7088
7186
|
if (!tracing || !traceWalk || traceWalk.missing || traceStopIndices.length === 0) return null;
|
|
7089
7187
|
const cursorRsid = activeSnapshots[safeIdx]?.runtimeStageId;
|
|
7090
7188
|
const walkIdx = traceWalk.stops.findIndex((st) => st.runtimeStageId === cursorRsid);
|
|
7189
|
+
const currentStop = traceWalk.stops[walkIdx >= 0 ? walkIdx : 0];
|
|
7091
7190
|
return {
|
|
7092
7191
|
tracedKey: tracing.key,
|
|
7093
7192
|
viaKey: activeViaKey,
|
|
@@ -7095,59 +7194,116 @@ function ExplainableShell({
|
|
|
7095
7194
|
stopOrdinal: walkIdx >= 0 ? walkIdx + 1 : 1,
|
|
7096
7195
|
totalStops: traceWalk.stops.length,
|
|
7097
7196
|
onExit: handleExitTracing,
|
|
7098
|
-
onShowAll: activeViaKey ? handleShowAllIngredients : void 0
|
|
7099
|
-
};
|
|
7100
|
-
}, [tracing, traceWalk, traceStopIndices, activeSnapshots, safeIdx, activeViaKey, handleExitTracing, handleShowAllIngredients]);
|
|
7101
|
-
const traceTabContent = (0, import_react32.useMemo)(() => tracing && traceWalk ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
7102
|
-
TraceWalkCard,
|
|
7103
|
-
{
|
|
7104
|
-
walk: traceWalk,
|
|
7105
|
-
cursorRuntimeStageId: activeSnapshots[safeIdx]?.runtimeStageId ?? null,
|
|
7106
|
-
viaKey: activeViaKey,
|
|
7107
|
-
stepNumberOf,
|
|
7108
|
-
previewValueOf: (k) => activeSnapshots[safeIdx]?.memory?.[k],
|
|
7109
|
-
onFollowIngredient: handleFollowIngredient,
|
|
7110
|
-
onJumpToStop: navigateToStage,
|
|
7111
7197
|
onShowAll: activeViaKey ? handleShowAllIngredients : void 0,
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7198
|
+
// Followable ingredients only — termini can't be chosen, so a stop of
|
|
7199
|
+
// run-inputs must not prompt (matches the card's chooser gate).
|
|
7200
|
+
forkCount: currentStop?.ingredients.filter((ing) => ing.writerRuntimeStageId !== null).length ?? 0,
|
|
7201
|
+
onForkPrompt: handleForkPrompt
|
|
7202
|
+
};
|
|
7203
|
+
}, [tracing, traceWalk, traceStopIndices, activeSnapshots, safeIdx, activeViaKey, handleExitTracing, handleShowAllIngredients, handleForkPrompt]);
|
|
7204
|
+
const traceTabContent = (0, import_react32.useMemo)(() => {
|
|
7205
|
+
if (tracing && traceWalk) {
|
|
7206
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
7207
|
+
TraceWalkCard,
|
|
7119
7208
|
{
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
7209
|
+
walk: traceWalk,
|
|
7210
|
+
cursorRuntimeStageId: activeSnapshots[safeIdx]?.runtimeStageId ?? null,
|
|
7211
|
+
viaKey: activeViaKey,
|
|
7212
|
+
stepNumberOf,
|
|
7213
|
+
previewValueOf: (k) => activeSnapshots[safeIdx]?.memory?.[k],
|
|
7214
|
+
onFollowIngredient: handleFollowIngredient,
|
|
7215
|
+
onJumpToStop: navigateToStage,
|
|
7216
|
+
onShowAll: activeViaKey ? handleShowAllIngredients : void 0,
|
|
7217
|
+
onExit: handleExitTracing,
|
|
7218
|
+
forkChooserOpen,
|
|
7219
|
+
onContinueTimeOrder: handleContinueTimeOrder,
|
|
7220
|
+
canContinueTimeOrder: traceStopIndices.some((i) => i < safeIdx)
|
|
7221
|
+
}
|
|
7222
|
+
);
|
|
7223
|
+
}
|
|
7224
|
+
const chipStyle = {
|
|
7225
|
+
border: "1px solid var(--fp-accent, #6366f1)",
|
|
7226
|
+
background: "transparent",
|
|
7227
|
+
color: "var(--fp-accent, #6366f1)",
|
|
7228
|
+
borderRadius: 12,
|
|
7229
|
+
padding: "2px 10px",
|
|
7230
|
+
margin: "0 6px 6px 0",
|
|
7231
|
+
fontSize: 11,
|
|
7232
|
+
fontWeight: 600,
|
|
7233
|
+
fontFamily: "monospace",
|
|
7234
|
+
cursor: "pointer"
|
|
7235
|
+
};
|
|
7236
|
+
const query = traceSearch.trim().toLowerCase();
|
|
7237
|
+
const matchedKeys = query ? allTracedKeys.filter((k) => k.toLowerCase().includes(query)) : allTracedKeys;
|
|
7238
|
+
const shownKeys = matchedKeys.slice(0, 12);
|
|
7239
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
7240
|
+
!isInSubflow && (shellDataTrace.frames[0]?.keysWritten?.length ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { "data-fp": "trace-entry", style: { padding: "10px 14px 0", fontSize: 12 }, children: [
|
|
7241
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { style: { color: theme.textMuted, marginRight: 6 }, children: "This step wrote:" }),
|
|
7242
|
+
shellDataTrace.frames[0].keysWritten.map((k) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
7243
|
+
"button",
|
|
7244
|
+
{
|
|
7245
|
+
"data-fp": "trace-entry-chip",
|
|
7246
|
+
onClick: () => handleStartTracing(k),
|
|
7247
|
+
title: "Where did " + k + " come from? Walk its causes on the timeline.",
|
|
7248
|
+
style: chipStyle,
|
|
7249
|
+
children: k
|
|
7134
7250
|
},
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
)
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7251
|
+
k
|
|
7252
|
+
))
|
|
7253
|
+
] }),
|
|
7254
|
+
!isInSubflow && allTracedKeys.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { "data-fp": "trace-any", style: { padding: "6px 14px 0", fontSize: 12 }, children: [
|
|
7255
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { color: theme.textMuted, marginBottom: 4 }, children: "Trace any variable:" }),
|
|
7256
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
7257
|
+
"input",
|
|
7258
|
+
{
|
|
7259
|
+
"data-fp": "trace-search",
|
|
7260
|
+
value: traceSearch,
|
|
7261
|
+
onChange: (e) => setTraceSearch(e.target.value),
|
|
7262
|
+
placeholder: "search any variable...",
|
|
7263
|
+
style: {
|
|
7264
|
+
display: "block",
|
|
7265
|
+
width: "100%",
|
|
7266
|
+
boxSizing: "border-box",
|
|
7267
|
+
background: theme.bgTertiary,
|
|
7268
|
+
border: `1px solid ${theme.border}`,
|
|
7269
|
+
borderRadius: 6,
|
|
7270
|
+
color: theme.textPrimary,
|
|
7271
|
+
fontSize: 11,
|
|
7272
|
+
fontFamily: "monospace",
|
|
7273
|
+
padding: "4px 8px",
|
|
7274
|
+
marginBottom: 6
|
|
7275
|
+
}
|
|
7276
|
+
}
|
|
7277
|
+
),
|
|
7278
|
+
shownKeys.map((k) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
7279
|
+
"button",
|
|
7280
|
+
{
|
|
7281
|
+
"data-fp": "trace-any-chip",
|
|
7282
|
+
onClick: () => handleStartTracing(k),
|
|
7283
|
+
title: "Where did " + k + " come from? Walk its causes on the timeline.",
|
|
7284
|
+
style: chipStyle,
|
|
7285
|
+
children: k
|
|
7286
|
+
},
|
|
7287
|
+
k
|
|
7288
|
+
)),
|
|
7289
|
+
query === "" && matchedKeys.length > shownKeys.length && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { style: { color: theme.textMuted, fontSize: 11 }, children: [
|
|
7290
|
+
"+",
|
|
7291
|
+
matchedKeys.length - shownKeys.length,
|
|
7292
|
+
" more \u2014 type to search"
|
|
7293
|
+
] })
|
|
7294
|
+
] }),
|
|
7295
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
7296
|
+
DataTracePanel,
|
|
7297
|
+
{
|
|
7298
|
+
frames: shellDataTrace.frames,
|
|
7299
|
+
note: shellDataTrace.readsAvailable ? void 0 : "\u26A0 reads were not recorded (readTracking off) \u2014 dependencies are unknowable, not absent.",
|
|
7300
|
+
selectedStageId: activeSnapshots[safeIdx]?.runtimeStageId,
|
|
7301
|
+
onFrameClick: navigateToStage,
|
|
7302
|
+
fromStageName: activeSnapshots[safeIdx]?.stageName
|
|
7303
|
+
}
|
|
7304
|
+
)
|
|
7305
|
+
] });
|
|
7306
|
+
}, [tracing, traceWalk, activeSnapshots, safeIdx, activeViaKey, stepNumberOf, handleFollowIngredient, navigateToStage, handleShowAllIngredients, handleExitTracing, handleStartTracing, isInSubflow, shellDataTrace, forkChooserOpen, handleContinueTimeOrder, traceStopIndices, traceSearch, allTracedKeys]);
|
|
7151
7307
|
const tabLabels = new Map(allTabs.map((t) => [t.id, t.name]));
|
|
7152
7308
|
if (unstyled) {
|
|
7153
7309
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className, style, "data-fp": "explainable-shell", children: [
|