footprint-explainable-ui 0.14.11 → 0.16.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 CHANGED
@@ -20,9 +20,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
+ CompactTimeline: () => CompactTimeline,
24
+ DataTracePanel: () => DataTracePanel,
23
25
  ExplainableShell: () => ExplainableShell,
24
26
  FootprintTheme: () => FootprintTheme,
25
27
  GanttTimeline: () => GanttTimeline,
28
+ InsightPanel: () => InsightPanel,
29
+ InspectorPanel: () => InspectorPanel,
26
30
  MemoryInspector: () => MemoryInspector,
27
31
  MemoryPanel: () => MemoryPanel,
28
32
  NarrativeLog: () => NarrativeLog,
@@ -2257,7 +2261,7 @@ function TimeTravelControls({
2257
2261
  }
2258
2262
 
2259
2263
  // src/components/ExplainableShell/ExplainableShell.tsx
2260
- var import_react20 = require("react");
2264
+ var import_react24 = require("react");
2261
2265
 
2262
2266
  // src/utils/narrativeSync.ts
2263
2267
  function buildEntryRangeIndex(entries) {
@@ -3997,22 +4001,520 @@ function TracedFlowchartView({
3997
4001
  );
3998
4002
  }
3999
4003
 
4000
- // src/components/ExplainableShell/ExplainableShell.tsx
4004
+ // src/components/InspectorPanel/InspectorPanel.tsx
4005
+ var import_react21 = require("react");
4006
+
4007
+ // src/components/DataTracePanel/DataTracePanel.tsx
4008
+ var import_react20 = require("react");
4001
4009
  var import_jsx_runtime18 = require("react/jsx-runtime");
4002
- var HLinePill = (0, import_react20.memo)(function HLinePill2({
4010
+ var DataTracePanel = (0, import_react20.memo)(function DataTracePanel2({
4011
+ frames,
4012
+ selectedStageId,
4013
+ onFrameClick,
4014
+ fromStageName
4015
+ }) {
4016
+ if (frames.length === 0) {
4017
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { padding: "14px 14px 12px", fontSize: 13, lineHeight: 1.55 }, children: [
4018
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4019
+ "div",
4020
+ {
4021
+ style: {
4022
+ fontSize: 11,
4023
+ color: theme.textMuted,
4024
+ textTransform: "uppercase",
4025
+ letterSpacing: "0.5px",
4026
+ fontWeight: 600,
4027
+ marginBottom: 6
4028
+ },
4029
+ children: "Backward causal chain"
4030
+ }
4031
+ ),
4032
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { color: theme.textSecondary, marginBottom: 10 }, children: "Trace any value back to the stage that created it \u2014 and everything upstream that influenced it." }),
4033
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { color: theme.textMuted, fontSize: 12 }, children: "Select a stage above to see its dependency chain." })
4034
+ ] });
4035
+ }
4036
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { padding: "8px 0", fontSize: 13 }, children: [
4037
+ fromStageName && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { padding: "4px 12px 8px" }, children: [
4038
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4039
+ "div",
4040
+ {
4041
+ style: {
4042
+ fontSize: 11,
4043
+ color: theme.textMuted,
4044
+ textTransform: "uppercase",
4045
+ letterSpacing: "0.5px",
4046
+ fontWeight: 600
4047
+ },
4048
+ children: [
4049
+ "Data trace from ",
4050
+ fromStageName
4051
+ ]
4052
+ }
4053
+ ),
4054
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4055
+ "div",
4056
+ {
4057
+ style: {
4058
+ fontSize: 11,
4059
+ color: theme.textMuted,
4060
+ fontStyle: "italic",
4061
+ marginTop: 3
4062
+ },
4063
+ children: "Every value here was derived from the stages below."
4064
+ }
4065
+ )
4066
+ ] }),
4067
+ frames.map((frame, i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4068
+ DataTraceFrame,
4069
+ {
4070
+ frame,
4071
+ isFirst: i === 0,
4072
+ isLast: i === frames.length - 1,
4073
+ isSelected: frame.runtimeStageId === selectedStageId,
4074
+ onClick: onFrameClick
4075
+ },
4076
+ frame.runtimeStageId
4077
+ ))
4078
+ ] });
4079
+ });
4080
+ var DataTraceFrame = (0, import_react20.memo)(function DataTraceFrame2({
4081
+ frame,
4082
+ isFirst,
4083
+ isLast,
4084
+ isSelected,
4085
+ onClick
4086
+ }) {
4087
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4088
+ "button",
4089
+ {
4090
+ onClick: () => onClick?.(frame.runtimeStageId),
4091
+ style: {
4092
+ display: "block",
4093
+ width: "100%",
4094
+ textAlign: "left",
4095
+ border: "none",
4096
+ background: isSelected ? "var(--fp-accent-bg, rgba(99,102,241,0.12))" : "transparent",
4097
+ padding: "6px 12px 6px 16px",
4098
+ cursor: onClick ? "pointer" : "default",
4099
+ borderLeft: isSelected ? "3px solid var(--fp-accent, #6366f1)" : "3px solid transparent",
4100
+ color: "inherit",
4101
+ fontSize: 13
4102
+ },
4103
+ children: [
4104
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
4105
+ !isFirst && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { color: theme.textMuted, fontSize: 11 }, children: "\u2191" }),
4106
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4107
+ "span",
4108
+ {
4109
+ style: {
4110
+ fontWeight: isFirst ? 600 : 400,
4111
+ color: isFirst ? "var(--fp-accent, #6366f1)" : theme.textPrimary
4112
+ },
4113
+ children: frame.stageName
4114
+ }
4115
+ ),
4116
+ isLast && !isFirst && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4117
+ "span",
4118
+ {
4119
+ style: {
4120
+ fontSize: 10,
4121
+ color: theme.textMuted,
4122
+ fontStyle: "italic"
4123
+ },
4124
+ children: "(origin)"
4125
+ }
4126
+ )
4127
+ ] }),
4128
+ frame.keysWritten.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4129
+ "div",
4130
+ {
4131
+ style: {
4132
+ fontSize: 11,
4133
+ color: theme.textMuted,
4134
+ paddingLeft: isFirst ? 0 : 18,
4135
+ marginTop: 2
4136
+ },
4137
+ children: [
4138
+ "wrote:",
4139
+ " ",
4140
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { color: theme.textSecondary }, children: frame.keysWritten.join(", ") })
4141
+ ]
4142
+ }
4143
+ ),
4144
+ frame.linkedBy && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4145
+ "div",
4146
+ {
4147
+ style: {
4148
+ fontSize: 11,
4149
+ color: "var(--fp-accent, #6366f1)",
4150
+ paddingLeft: 18,
4151
+ marginTop: 1
4152
+ },
4153
+ children: [
4154
+ "\u2190 via ",
4155
+ frame.linkedBy
4156
+ ]
4157
+ }
4158
+ )
4159
+ ]
4160
+ }
4161
+ );
4162
+ });
4163
+
4164
+ // src/components/InspectorPanel/InspectorPanel.tsx
4165
+ var import_jsx_runtime19 = require("react/jsx-runtime");
4166
+ var InspectorPanel = (0, import_react21.memo)(function InspectorPanel2({
4167
+ snapshots,
4168
+ selectedIndex,
4169
+ dataTraceFrames,
4170
+ selectedStageId,
4171
+ onNavigateToStage
4172
+ }) {
4173
+ const [tab, setTab] = (0, import_react21.useState)("state");
4174
+ const currentSnapshot = snapshots[selectedIndex];
4175
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4176
+ "div",
4177
+ {
4178
+ style: {
4179
+ display: "flex",
4180
+ flexDirection: "column",
4181
+ height: "100%",
4182
+ overflow: "hidden"
4183
+ },
4184
+ children: [
4185
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4186
+ "div",
4187
+ {
4188
+ style: {
4189
+ display: "flex",
4190
+ borderBottom: `1px solid ${theme.border}`,
4191
+ flexShrink: 0
4192
+ },
4193
+ children: [
4194
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4195
+ TabButton,
4196
+ {
4197
+ active: tab === "state",
4198
+ onClick: () => setTab("state"),
4199
+ label: "State"
4200
+ }
4201
+ ),
4202
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4203
+ TabButton,
4204
+ {
4205
+ active: tab === "trace",
4206
+ onClick: () => setTab("trace"),
4207
+ label: "Data Trace",
4208
+ badge: dataTraceFrames.length > 0 ? String(dataTraceFrames.length) : void 0
4209
+ }
4210
+ )
4211
+ ]
4212
+ }
4213
+ ),
4214
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { flex: 1, overflow: "auto" }, children: [
4215
+ tab === "state" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4216
+ MemoryPanel,
4217
+ {
4218
+ snapshots,
4219
+ selectedIndex
4220
+ }
4221
+ ),
4222
+ tab === "trace" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4223
+ DataTracePanel,
4224
+ {
4225
+ frames: dataTraceFrames,
4226
+ selectedStageId,
4227
+ onFrameClick: onNavigateToStage,
4228
+ fromStageName: currentSnapshot?.stageName
4229
+ }
4230
+ )
4231
+ ] })
4232
+ ]
4233
+ }
4234
+ );
4235
+ });
4236
+ function TabButton({
4237
+ active,
4238
+ onClick,
4239
+ label,
4240
+ badge
4241
+ }) {
4242
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4243
+ "button",
4244
+ {
4245
+ onClick,
4246
+ style: {
4247
+ padding: "8px 14px",
4248
+ border: "none",
4249
+ borderBottom: active ? "2px solid var(--fp-accent, #6366f1)" : "2px solid transparent",
4250
+ background: "transparent",
4251
+ color: active ? "var(--fp-accent, #6366f1)" : theme.textMuted,
4252
+ fontWeight: active ? 600 : 400,
4253
+ fontSize: 12,
4254
+ cursor: "pointer",
4255
+ display: "flex",
4256
+ alignItems: "center",
4257
+ gap: 4
4258
+ },
4259
+ children: [
4260
+ label,
4261
+ badge && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4262
+ "span",
4263
+ {
4264
+ style: {
4265
+ fontSize: 10,
4266
+ background: active ? "var(--fp-accent, #6366f1)" : theme.textMuted,
4267
+ color: "#fff",
4268
+ borderRadius: 8,
4269
+ padding: "1px 5px",
4270
+ fontWeight: 600
4271
+ },
4272
+ children: badge
4273
+ }
4274
+ )
4275
+ ]
4276
+ }
4277
+ );
4278
+ }
4279
+
4280
+ // src/components/InsightPanel/InsightPanel.tsx
4281
+ var import_react22 = require("react");
4282
+ var import_jsx_runtime20 = require("react/jsx-runtime");
4283
+ var InsightPanel = (0, import_react22.memo)(function InsightPanel2({
4284
+ insights,
4285
+ expandedId,
4286
+ mode
4287
+ }) {
4288
+ if (insights.length === 0) {
4289
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { padding: 12, color: theme.textMuted, fontSize: 13 }, children: "No insights available. Attach recorders to see data." });
4290
+ }
4291
+ if (mode === "grid") {
4292
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(InsightGrid, { insights });
4293
+ }
4294
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(InsightTabs, { insights, defaultId: expandedId });
4295
+ });
4296
+ var InsightTabs = (0, import_react22.memo)(function InsightTabs2({
4297
+ insights,
4298
+ defaultId
4299
+ }) {
4300
+ const [activeId, setActiveId] = (0, import_react22.useState)(defaultId ?? insights[0]?.id);
4301
+ const active = insights.find((i) => i.id === activeId) ?? insights[0];
4302
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
4303
+ "div",
4304
+ {
4305
+ style: {
4306
+ display: "flex",
4307
+ flexDirection: "column",
4308
+ height: "100%",
4309
+ overflow: "hidden"
4310
+ },
4311
+ children: [
4312
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
4313
+ "div",
4314
+ {
4315
+ style: {
4316
+ display: "flex",
4317
+ borderBottom: `1px solid ${theme.border}`,
4318
+ flexShrink: 0,
4319
+ overflowX: "auto"
4320
+ },
4321
+ children: insights.map((insight) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
4322
+ "button",
4323
+ {
4324
+ onClick: () => setActiveId(insight.id),
4325
+ style: {
4326
+ padding: "8px 12px",
4327
+ border: "none",
4328
+ borderBottom: activeId === insight.id ? "2px solid var(--fp-accent, #6366f1)" : "2px solid transparent",
4329
+ background: "transparent",
4330
+ color: activeId === insight.id ? "var(--fp-accent, #6366f1)" : theme.textMuted,
4331
+ fontWeight: activeId === insight.id ? 600 : 400,
4332
+ fontSize: 12,
4333
+ cursor: "pointer",
4334
+ whiteSpace: "nowrap"
4335
+ },
4336
+ children: insight.name
4337
+ },
4338
+ insight.id
4339
+ ))
4340
+ }
4341
+ ),
4342
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: active?.render() })
4343
+ ]
4344
+ }
4345
+ );
4346
+ });
4347
+ var InsightGrid = (0, import_react22.memo)(function InsightGrid2({
4348
+ insights
4349
+ }) {
4350
+ const cols = insights.length <= 2 ? 1 : 2;
4351
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
4352
+ "div",
4353
+ {
4354
+ style: {
4355
+ display: "grid",
4356
+ gridTemplateColumns: `repeat(${cols}, 1fr)`,
4357
+ height: "100%",
4358
+ overflow: "auto",
4359
+ gap: 1,
4360
+ background: theme.border
4361
+ },
4362
+ children: insights.map((insight) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
4363
+ "div",
4364
+ {
4365
+ style: {
4366
+ background: "var(--fp-bg, #1a1b26)",
4367
+ display: "flex",
4368
+ flexDirection: "column",
4369
+ overflow: "hidden"
4370
+ },
4371
+ children: [
4372
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
4373
+ "div",
4374
+ {
4375
+ style: {
4376
+ padding: "6px 10px",
4377
+ fontSize: 11,
4378
+ fontWeight: 600,
4379
+ color: theme.textMuted,
4380
+ textTransform: "uppercase",
4381
+ letterSpacing: "0.5px",
4382
+ borderBottom: `1px solid ${theme.border}`,
4383
+ flexShrink: 0
4384
+ },
4385
+ children: [
4386
+ insight.name,
4387
+ insight.summary && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
4388
+ "span",
4389
+ {
4390
+ style: {
4391
+ marginLeft: 8,
4392
+ fontWeight: 400,
4393
+ fontSize: 10,
4394
+ color: theme.textMuted
4395
+ },
4396
+ children: insight.summary
4397
+ }
4398
+ )
4399
+ ]
4400
+ }
4401
+ ),
4402
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: insight.render() })
4403
+ ]
4404
+ },
4405
+ insight.id
4406
+ ))
4407
+ }
4408
+ );
4409
+ });
4410
+
4411
+ // src/components/CompactTimeline/CompactTimeline.tsx
4412
+ var import_react23 = require("react");
4413
+ var import_jsx_runtime21 = require("react/jsx-runtime");
4414
+ var CompactTimeline = (0, import_react23.memo)(function CompactTimeline2({
4415
+ snapshots,
4416
+ selectedIndex,
4417
+ defaultExpanded = false
4418
+ }) {
4419
+ const [expanded, setExpanded] = (0, import_react23.useState)(defaultExpanded);
4420
+ if (snapshots.length === 0) return null;
4421
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { borderTop: `1px solid ${theme.border}` }, children: [
4422
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4423
+ "button",
4424
+ {
4425
+ onClick: () => setExpanded((e) => !e),
4426
+ style: {
4427
+ width: "100%",
4428
+ display: "flex",
4429
+ alignItems: "center",
4430
+ gap: 8,
4431
+ padding: "6px 12px",
4432
+ border: "none",
4433
+ background: "transparent",
4434
+ cursor: "pointer",
4435
+ fontSize: 11,
4436
+ color: theme.textMuted,
4437
+ fontWeight: 600,
4438
+ textTransform: "uppercase",
4439
+ letterSpacing: "0.5px"
4440
+ },
4441
+ children: [
4442
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { fontSize: 10 }, children: expanded ? "\u25BC" : "\u25B8" }),
4443
+ "Timeline",
4444
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { style: { fontWeight: 400, fontSize: 10 }, children: [
4445
+ snapshots.length,
4446
+ " stages"
4447
+ ] }),
4448
+ !expanded && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4449
+ "div",
4450
+ {
4451
+ style: {
4452
+ flex: 1,
4453
+ display: "flex",
4454
+ alignItems: "center",
4455
+ gap: 2,
4456
+ marginLeft: 8
4457
+ },
4458
+ children: [
4459
+ snapshots.map((snap, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4460
+ "div",
4461
+ {
4462
+ style: {
4463
+ width: i === selectedIndex ? 8 : 5,
4464
+ height: i === selectedIndex ? 8 : 5,
4465
+ borderRadius: "50%",
4466
+ background: i < selectedIndex ? "var(--fp-success, #22c55e)" : i === selectedIndex ? "var(--fp-accent, #6366f1)" : theme.textMuted + "40",
4467
+ transition: "all 0.15s",
4468
+ flexShrink: 0
4469
+ },
4470
+ title: snap.stageName
4471
+ },
4472
+ i
4473
+ )),
4474
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4475
+ "div",
4476
+ {
4477
+ style: {
4478
+ flex: 1,
4479
+ height: 1,
4480
+ background: theme.textMuted + "30",
4481
+ marginLeft: -2,
4482
+ marginRight: 4
4483
+ }
4484
+ }
4485
+ )
4486
+ ]
4487
+ }
4488
+ )
4489
+ ]
4490
+ }
4491
+ ),
4492
+ expanded && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { padding: "0 12px 8px" }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4493
+ GanttTimeline,
4494
+ {
4495
+ snapshots,
4496
+ selectedIndex
4497
+ }
4498
+ ) })
4499
+ ] });
4500
+ });
4501
+
4502
+ // src/components/ExplainableShell/ExplainableShell.tsx
4503
+ var import_jsx_runtime22 = require("react/jsx-runtime");
4504
+ var HLinePill = (0, import_react24.memo)(function HLinePill2({
4003
4505
  label,
4004
4506
  detail,
4005
4507
  expanded,
4006
4508
  onClick
4007
4509
  }) {
4008
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: {
4510
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: {
4009
4511
  display: "flex",
4010
4512
  alignItems: "center",
4011
4513
  gap: 0,
4012
4514
  padding: "0"
4013
4515
  }, children: [
4014
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flex: 1, height: 1, background: theme.border } }),
4015
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4516
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { flex: 1, height: 1, background: theme.border } }),
4517
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
4016
4518
  "button",
4017
4519
  {
4018
4520
  onClick,
@@ -4036,31 +4538,31 @@ var HLinePill = (0, import_react20.memo)(function HLinePill2({
4036
4538
  transition: "color 0.15s ease"
4037
4539
  },
4038
4540
  children: [
4039
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { fontSize: 7 }, children: expanded ? "\u25BC" : "\u25B6" }),
4541
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { fontSize: 7 }, children: expanded ? "\u25BC" : "\u25B6" }),
4040
4542
  label,
4041
- detail && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { fontWeight: 400, opacity: 0.5, fontSize: 9 }, children: detail })
4543
+ detail && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { fontWeight: 400, opacity: 0.5, fontSize: 9 }, children: detail })
4042
4544
  ]
4043
4545
  }
4044
4546
  ),
4045
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flex: 1, height: 1, background: theme.border } })
4547
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { flex: 1, height: 1, background: theme.border } })
4046
4548
  ] });
4047
4549
  });
4048
- var VLinePill = (0, import_react20.memo)(function VLinePill2({
4550
+ var VLinePill = (0, import_react24.memo)(function VLinePill2({
4049
4551
  label,
4050
4552
  expanded,
4051
4553
  side = "right",
4052
4554
  onClick
4053
4555
  }) {
4054
4556
  const arrow = side === "right" ? expanded ? "\u25B6" : "\u25C0" : expanded ? "\u25C0" : "\u25B6";
4055
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: {
4557
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: {
4056
4558
  display: "flex",
4057
4559
  flexDirection: "column",
4058
4560
  alignItems: "center",
4059
4561
  gap: 0,
4060
4562
  padding: "0"
4061
4563
  }, children: [
4062
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flex: 1, width: 1, background: theme.border } }),
4063
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4564
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { flex: 1, width: 1, background: theme.border } }),
4565
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
4064
4566
  "button",
4065
4567
  {
4066
4568
  onClick,
@@ -4085,12 +4587,12 @@ var VLinePill = (0, import_react20.memo)(function VLinePill2({
4085
4587
  transition: "color 0.15s ease"
4086
4588
  },
4087
4589
  children: [
4088
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { fontSize: 7, writingMode: "horizontal-tb" }, children: arrow }),
4590
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { fontSize: 7, writingMode: "horizontal-tb" }, children: arrow }),
4089
4591
  label
4090
4592
  ]
4091
4593
  }
4092
4594
  ),
4093
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flex: 1, width: 1, background: theme.border } })
4595
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { flex: 1, width: 1, background: theme.border } })
4094
4596
  ] });
4095
4597
  });
4096
4598
  function detectKeyedSteps(data) {
@@ -4127,9 +4629,9 @@ function KeyedRecorderView({
4127
4629
  snapshots,
4128
4630
  selectedIndex
4129
4631
  }) {
4130
- const [showAggregate, setShowAggregate] = (0, import_react20.useState)(false);
4131
- const detected = (0, import_react20.useMemo)(() => detectKeyedSteps(data), [data]);
4132
- const visibleKeys = (0, import_react20.useMemo)(() => {
4632
+ const [showAggregate, setShowAggregate] = (0, import_react24.useState)(false);
4633
+ const detected = (0, import_react24.useMemo)(() => detectKeyedSteps(data), [data]);
4634
+ const visibleKeys = (0, import_react24.useMemo)(() => {
4133
4635
  const keys = /* @__PURE__ */ new Set();
4134
4636
  for (let i = 0; i <= selectedIndex && i < snapshots.length; i++) {
4135
4637
  const snap = snapshots[i];
@@ -4144,7 +4646,7 @@ function KeyedRecorderView({
4144
4646
  }, [snapshots, selectedIndex, detected?.keyType]);
4145
4647
  const isAtEnd = selectedIndex >= snapshots.length - 1;
4146
4648
  if (!detected) {
4147
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { padding: 12, fontFamily: theme.fontMono, fontSize: 11, whiteSpace: "pre-wrap", overflow: "auto", height: "100%" }, children: typeof data === "string" ? data : JSON.stringify(data, null, 2) });
4649
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { padding: 12, fontFamily: theme.fontMono, fontSize: 11, whiteSpace: "pre-wrap", overflow: "auto", height: "100%" }, children: typeof data === "string" ? data : JSON.stringify(data, null, 2) });
4148
4650
  }
4149
4651
  const steps = detected.steps;
4150
4652
  const hints = extractRenderHints(data);
@@ -4158,13 +4660,13 @@ function KeyedRecorderView({
4158
4660
  }
4159
4661
  }
4160
4662
  const grandTotal = hints?.grandTotal ?? 0;
4161
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { overflow: "auto", height: "100%", display: "flex", flexDirection: "column" }, children: [
4162
- description && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { padding: "6px 12px", fontSize: 11, color: theme.textMuted, fontStyle: "italic", borderBottom: `1px solid ${theme.border}`, flexShrink: 0 }, children: description }),
4163
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { padding: 12, flex: 1, overflow: "auto" }, children: [
4663
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { overflow: "auto", height: "100%", display: "flex", flexDirection: "column" }, children: [
4664
+ description && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { padding: "6px 12px", fontSize: 11, color: theme.textMuted, fontStyle: "italic", borderBottom: `1px solid ${theme.border}`, flexShrink: 0 }, children: description }),
4665
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { padding: 12, flex: 1, overflow: "auto" }, children: [
4164
4666
  preferredOperation === "aggregate" ? (
4165
4667
  /* AGGREGATE: collect silently during scrub, button at end to reveal total */
4166
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4167
- isAtEnd ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { marginBottom: 16 }, children: !showAggregate ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4668
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
4669
+ isAtEnd ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { marginBottom: 16 }, children: !showAggregate ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4168
4670
  "button",
4169
4671
  {
4170
4672
  onClick: () => setShowAggregate(true),
@@ -4182,35 +4684,35 @@ function KeyedRecorderView({
4182
4684
  },
4183
4685
  children: "Aggregate \u2014 Show Grand Total"
4184
4686
  }
4185
- ) : /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { padding: "14px 16px", background: `color-mix(in srgb, ${theme.success} 12%, transparent)`, borderRadius: 8, border: `1px solid ${theme.success}44` }, children: [
4186
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Aggregate \u2014 grand total" }),
4187
- numFieldKey && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { fontSize: 26, fontWeight: 700, color: theme.success }, children: [
4687
+ ) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { padding: "14px 16px", background: `color-mix(in srgb, ${theme.success} 12%, transparent)`, borderRadius: 8, border: `1px solid ${theme.success}44` }, children: [
4688
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Aggregate \u2014 grand total" }),
4689
+ numFieldKey && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { fontSize: 26, fontWeight: 700, color: theme.success }, children: [
4188
4690
  grandTotal < 1 ? grandTotal.toFixed(3) : grandTotal.toFixed(1),
4189
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { style: { fontSize: 11, color: theme.textMuted, fontWeight: 400, marginLeft: 8 }, children: [
4691
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { style: { fontSize: 11, color: theme.textMuted, fontWeight: 400, marginLeft: 8 }, children: [
4190
4692
  numFieldKey,
4191
4693
  " \xB7 ",
4192
4694
  allKeys.length,
4193
4695
  " steps"
4194
4696
  ] })
4195
4697
  ] })
4196
- ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { padding: "10px 14px", background: `color-mix(in srgb, ${theme.textMuted} 6%, transparent)`, borderRadius: 6, marginBottom: 16, border: `1px dashed ${theme.border}` }, children: [
4197
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", fontWeight: 600 }, children: "Collecting data..." }),
4198
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { fontSize: 11, color: theme.textMuted, marginTop: 4 }, children: [
4698
+ ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { padding: "10px 14px", background: `color-mix(in srgb, ${theme.textMuted} 6%, transparent)`, borderRadius: 6, marginBottom: 16, border: `1px dashed ${theme.border}` }, children: [
4699
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", fontWeight: 600 }, children: "Collecting data..." }),
4700
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { fontSize: 11, color: theme.textMuted, marginTop: 4 }, children: [
4199
4701
  visibleEntries.length,
4200
4702
  " of ",
4201
4703
  allKeys.length,
4202
4704
  " steps collected. Scrub to end to aggregate."
4203
4705
  ] })
4204
4706
  ] }),
4205
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Per-step detail" })
4707
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Per-step detail" })
4206
4708
  ] })
4207
4709
  ) : preferredOperation === "accumulate" ? (
4208
4710
  /* ACCUMULATE: running total grows with slider — IS the total at end, no button */
4209
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4210
- numFieldKey && visibleEntries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { padding: "10px 14px", background: `color-mix(in srgb, ${theme.primary} 8%, transparent)`, borderRadius: 6, marginBottom: 16 }, children: [
4211
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 4, fontWeight: 600 }, children: "Accumulate \u2014 running total up to this step" }),
4212
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { fontWeight: 700, fontSize: 18, color: theme.primary }, children: runningTotal < 1 ? runningTotal.toFixed(3) : runningTotal.toFixed(1) }),
4213
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { style: { color: theme.textMuted, marginLeft: 8, fontSize: 10 }, children: [
4711
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
4712
+ numFieldKey && visibleEntries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { padding: "10px 14px", background: `color-mix(in srgb, ${theme.primary} 8%, transparent)`, borderRadius: 6, marginBottom: 16 }, children: [
4713
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 4, fontWeight: 600 }, children: "Accumulate \u2014 running total up to this step" }),
4714
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { fontWeight: 700, fontSize: 18, color: theme.primary }, children: runningTotal < 1 ? runningTotal.toFixed(3) : runningTotal.toFixed(1) }),
4715
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { style: { color: theme.textMuted, marginLeft: 8, fontSize: 10 }, children: [
4214
4716
  numFieldKey,
4215
4717
  " \xB7 ",
4216
4718
  visibleEntries.length,
@@ -4219,27 +4721,27 @@ function KeyedRecorderView({
4219
4721
  " steps"
4220
4722
  ] })
4221
4723
  ] }),
4222
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Per-step detail" })
4724
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Per-step detail" })
4223
4725
  ] })
4224
4726
  ) : (
4225
4727
  /* TRANSLATE: per-step entries prominent, no totals */
4226
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Translate \u2014 per-step detail" })
4728
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { fontSize: 10, color: theme.textMuted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, fontWeight: 600 }, children: "Translate \u2014 per-step detail" })
4227
4729
  ),
4228
4730
  visibleEntries.map((key) => {
4229
4731
  const entry = steps[key];
4230
4732
  const label = entry.stageName ?? key;
4231
4733
  const numVal = numFieldKey ? entry[numFieldKey] : void 0;
4232
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { display: "flex", alignItems: "center", padding: "4px 0", fontSize: 12, fontFamily: theme.fontMono, borderBottom: `1px solid ${theme.border}22` }, children: [
4233
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { color: theme.textMuted, width: 140, flexShrink: 0, fontSize: 10 }, children: key }),
4234
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { fontWeight: 600, flex: 1 }, children: label }),
4235
- numVal !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { color: theme.primary, fontWeight: 700, marginLeft: 8 }, children: numVal < 1 ? numVal.toFixed(3) : numVal.toFixed(1) })
4734
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", alignItems: "center", padding: "4px 0", fontSize: 12, fontFamily: theme.fontMono, borderBottom: `1px solid ${theme.border}22` }, children: [
4735
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { color: theme.textMuted, width: 140, flexShrink: 0, fontSize: 10 }, children: key }),
4736
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { fontWeight: 600, flex: 1 }, children: label }),
4737
+ numVal !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { color: theme.primary, fontWeight: 700, marginLeft: 8 }, children: numVal < 1 ? numVal.toFixed(3) : numVal.toFixed(1) })
4236
4738
  ] }, key);
4237
4739
  }),
4238
- visibleEntries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { color: theme.textMuted, fontSize: 11, fontStyle: "italic", padding: "8px 0" }, children: "Scrub the slider to reveal entries..." })
4740
+ visibleEntries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: theme.textMuted, fontSize: 11, fontStyle: "italic", padding: "8px 0" }, children: "Scrub the slider to reveal entries..." })
4239
4741
  ] })
4240
4742
  ] });
4241
4743
  }
4242
- var DetailsContent = (0, import_react20.memo)(function DetailsContent2({
4744
+ var DetailsContent = (0, import_react24.memo)(function DetailsContent2({
4243
4745
  snapshots,
4244
4746
  selectedIndex,
4245
4747
  narrativeEntries,
@@ -4252,27 +4754,27 @@ var DetailsContent = (0, import_react20.memo)(function DetailsContent2({
4252
4754
  {
4253
4755
  id: "memory",
4254
4756
  name: "Memory",
4255
- render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MemoryPanel, { snapshots: snaps, selectedIndex: idx, size, style: fillHeight ? { height: "100%" } : void 0 })
4757
+ render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(MemoryPanel, { snapshots: snaps, selectedIndex: idx, size, style: fillHeight ? { height: "100%" } : void 0 })
4256
4758
  },
4257
4759
  {
4258
4760
  id: "narrative",
4259
4761
  name: "Narrative",
4260
- render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NarrativePanel, { snapshots: snaps, selectedIndex: idx, narrativeEntries, narrative, size, style: fillHeight ? { height: "100%" } : void 0 })
4762
+ render: ({ snapshots: snaps, selectedIndex: idx }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(NarrativePanel, { snapshots: snaps, selectedIndex: idx, narrativeEntries, narrative, size, style: fillHeight ? { height: "100%" } : void 0 })
4261
4763
  }
4262
4764
  ];
4263
4765
  const allViews = [...builtInViews, ...extraViews ?? []];
4264
- const [activeViewId, setActiveViewId] = (0, import_react20.useState)(allViews[0]?.id ?? "memory");
4766
+ const [activeViewId, setActiveViewId] = (0, import_react24.useState)(allViews[0]?.id ?? "memory");
4265
4767
  const viewIds = allViews.map((v2) => v2.id).join(",");
4266
- (0, import_react20.useEffect)(() => {
4768
+ (0, import_react24.useEffect)(() => {
4267
4769
  if (!allViews.find((v2) => v2.id === activeViewId)) {
4268
4770
  setActiveViewId(allViews[0]?.id ?? "memory");
4269
4771
  }
4270
4772
  }, [viewIds]);
4271
4773
  const activeView = allViews.find((v2) => v2.id === activeViewId) ?? allViews[0];
4272
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: [
4273
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { display: "flex", borderBottom: `1px solid ${theme.border}`, flexShrink: 0, overflowX: "auto" }, children: allViews.map((view) => {
4774
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: [
4775
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { display: "flex", borderBottom: `1px solid ${theme.border}`, flexShrink: 0, overflowX: "auto" }, children: allViews.map((view) => {
4274
4776
  const active = view.id === activeViewId;
4275
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4777
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4276
4778
  "button",
4277
4779
  {
4278
4780
  onClick: () => setActiveViewId(view.id),
@@ -4296,7 +4798,7 @@ var DetailsContent = (0, import_react20.memo)(function DetailsContent2({
4296
4798
  view.id
4297
4799
  );
4298
4800
  }) }),
4299
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: activeView?.render({ snapshots, selectedIndex }) })
4801
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: activeView?.render({ snapshots, selectedIndex }) })
4300
4802
  ] });
4301
4803
  });
4302
4804
  function resolveSubflowLevel(parentSpec, parentSnapshots, subflowNodeName, narrativeEntries) {
@@ -4336,8 +4838,125 @@ function hasSubflowNodes(node) {
4336
4838
  if (node.next && hasSubflowNodes(node.next)) return true;
4337
4839
  return false;
4338
4840
  }
4841
+ function buildDataTrace(commitLog, targetRuntimeStageId, maxDepth = 10) {
4842
+ const log = commitLog;
4843
+ if (!log?.length) return [];
4844
+ const idxMap = /* @__PURE__ */ new Map();
4845
+ for (let i = 0; i < log.length; i++) idxMap.set(log[i].runtimeStageId, i);
4846
+ const startIdx = idxMap.get(targetRuntimeStageId);
4847
+ if (startIdx === void 0) return [];
4848
+ const startCommit = log[startIdx];
4849
+ const frames = [];
4850
+ const visited = /* @__PURE__ */ new Set();
4851
+ let current = startCommit;
4852
+ let currentIdx = startIdx;
4853
+ let depth = 0;
4854
+ while (current && depth <= maxDepth) {
4855
+ if (visited.has(current.runtimeStageId)) break;
4856
+ visited.add(current.runtimeStageId);
4857
+ frames.push({
4858
+ runtimeStageId: current.runtimeStageId,
4859
+ stageId: current.stageId,
4860
+ stageName: current.stage,
4861
+ keysWritten: current.trace.map((t) => t.path),
4862
+ linkedBy: depth === 0 ? "" : current.trace[0]?.path ?? "",
4863
+ depth
4864
+ });
4865
+ if (currentIdx > 0) {
4866
+ currentIdx--;
4867
+ current = log[currentIdx];
4868
+ depth++;
4869
+ } else {
4870
+ break;
4871
+ }
4872
+ }
4873
+ return frames;
4874
+ }
4875
+ var RightPanel = (0, import_react24.memo)(function RightPanel2({
4876
+ mode,
4877
+ onModeChange,
4878
+ snapshots,
4879
+ selectedIndex,
4880
+ runtimeSnapshot,
4881
+ activeTab,
4882
+ allTabs,
4883
+ activeNarrativeEntries,
4884
+ activeNarrative,
4885
+ recorderViews,
4886
+ autoRecorderViews,
4887
+ size,
4888
+ onNavigateToStage
4889
+ }) {
4890
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
4891
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: {
4892
+ display: "flex",
4893
+ borderBottom: `1px solid ${theme.border}`,
4894
+ flexShrink: 0,
4895
+ background: theme.bgSecondary
4896
+ }, children: ["insights", "what"].map((m) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4897
+ "button",
4898
+ {
4899
+ onClick: () => onModeChange(m),
4900
+ style: {
4901
+ flex: 1,
4902
+ padding: "7px 12px",
4903
+ fontSize: 11,
4904
+ fontWeight: mode === m ? 700 : 500,
4905
+ textTransform: "uppercase",
4906
+ letterSpacing: "0.06em",
4907
+ color: mode === m ? theme.primary : theme.textMuted,
4908
+ background: "transparent",
4909
+ border: "none",
4910
+ borderBottom: mode === m ? `2px solid ${theme.primary}` : "2px solid transparent",
4911
+ cursor: "pointer",
4912
+ fontFamily: "inherit"
4913
+ },
4914
+ children: m === "insights" ? "Insights" : "Inspector"
4915
+ },
4916
+ m
4917
+ )) }),
4918
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { flex: 1, overflow: "hidden" }, children: mode === "insights" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4919
+ InsightPanel,
4920
+ {
4921
+ mode: "tabs",
4922
+ expandedId: activeTab,
4923
+ insights: allTabs.filter((t) => t.id !== "result" && t.id !== "memory").map((tab) => ({
4924
+ id: tab.id,
4925
+ name: insightName(tab.name),
4926
+ render: () => {
4927
+ if (tab.id === "narrative") return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(NarrativePanel, { snapshots, selectedIndex, narrativeEntries: activeNarrativeEntries, narrative: activeNarrative, size, style: { height: "100%" } });
4928
+ const customView = recorderViews?.find((v2) => v2.id === tab.id);
4929
+ if (customView?.render) return customView.render({ snapshots, selectedIndex });
4930
+ const autoView = autoRecorderViews.find((v2) => v2.id === tab.id);
4931
+ if (autoView) return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(KeyedRecorderView, { data: autoView.data, description: autoView.description, preferredOperation: autoView.preferredOperation, snapshots, selectedIndex });
4932
+ return null;
4933
+ }
4934
+ }))
4935
+ }
4936
+ ) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4937
+ InspectorPanel,
4938
+ {
4939
+ snapshots,
4940
+ selectedIndex,
4941
+ dataTraceFrames: runtimeSnapshot?.commitLog ? buildDataTrace(runtimeSnapshot.commitLog, snapshots[selectedIndex]?.runtimeStageId ?? "") : [],
4942
+ selectedStageId: snapshots[selectedIndex]?.runtimeStageId,
4943
+ onNavigateToStage
4944
+ }
4945
+ ) })
4946
+ ] });
4947
+ });
4948
+ function insightName(name) {
4949
+ const map = {
4950
+ "Narrative": "Story",
4951
+ "Memory": "State",
4952
+ "Metrics": "Performance",
4953
+ "Quality": "Quality",
4954
+ "Cost": "Cost"
4955
+ };
4956
+ return map[name] ?? name;
4957
+ }
4339
4958
  function defaultRenderFlowchart({ spec: s, snapshots: snaps, selectedIndex, onNodeClick }) {
4340
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4959
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4341
4960
  TracedFlowchartView,
4342
4961
  {
4343
4962
  spec: s,
@@ -4369,7 +4988,7 @@ function ExplainableShell({
4369
4988
  className,
4370
4989
  style
4371
4990
  }) {
4372
- const derivedFromRuntime = (0, import_react20.useMemo)(() => {
4991
+ const derivedFromRuntime = (0, import_react24.useMemo)(() => {
4373
4992
  if (!runtimeSnapshot) return null;
4374
4993
  try {
4375
4994
  const snaps = toVisualizationSnapshots(runtimeSnapshot, narrativeEntries);
@@ -4390,26 +5009,29 @@ function ExplainableShell({
4390
5009
  const leftLabel = panelLabels?.topology ?? "Topology";
4391
5010
  const rightLabel = panelLabels?.details ?? "Details";
4392
5011
  const bottomLabel = panelLabels?.timeline ?? "Timeline";
4393
- const shellRef = (0, import_react20.useRef)(null);
4394
- const [isNarrow, setIsNarrow] = (0, import_react20.useState)(false);
4395
- (0, import_react20.useEffect)(() => {
5012
+ const shellRef = (0, import_react24.useRef)(null);
5013
+ const [isNarrow, setIsNarrow] = (0, import_react24.useState)(false);
5014
+ const [isMedium, setIsMedium] = (0, import_react24.useState)(false);
5015
+ (0, import_react24.useEffect)(() => {
4396
5016
  const el = shellRef.current;
4397
5017
  if (!el) return;
4398
5018
  const ro = new ResizeObserver(([entry]) => {
4399
- setIsNarrow(entry.contentRect.width < 640);
5019
+ const w = entry.contentRect.width;
5020
+ setIsNarrow(w < 640);
5021
+ setIsMedium(w >= 640 && w < 960);
4400
5022
  window.dispatchEvent(new Event("resize"));
4401
5023
  });
4402
5024
  ro.observe(el);
4403
5025
  return () => ro.disconnect();
4404
5026
  }, []);
4405
- const autoRecorderViews = (0, import_react20.useMemo)(() => {
5027
+ const autoRecorderViews = (0, import_react24.useMemo)(() => {
4406
5028
  const recorders = runtimeSnapshot?.recorders;
4407
5029
  if (!recorders?.length) return [];
4408
5030
  const explicitIds = new Set((recorderViews ?? []).map((v2) => v2.id));
4409
5031
  return recorders.filter((r) => !explicitIds.has(r.id)).map((r) => ({ id: r.id, name: r.name, description: r.description, preferredOperation: r.preferredOperation, data: r.data }));
4410
5032
  }, [runtimeSnapshot, recorderViews]);
4411
5033
  const hasNarrative = !!(narrative?.length || narrativeEntries?.length);
4412
- const allTabs = (0, import_react20.useMemo)(() => {
5034
+ const allTabs = (0, import_react24.useMemo)(() => {
4413
5035
  const tabs2 = [
4414
5036
  { id: "result", name: "Result", description: "Final output and console logs" },
4415
5037
  { id: "memory", name: "Memory", description: "Accumulator \u2014 progressive shared state at each stage" }
@@ -4428,37 +5050,38 @@ function ExplainableShell({
4428
5050
  }, [hasNarrative, recorderViews, autoRecorderViews, hideTabsProp]);
4429
5051
  const validTabIds = new Set(allTabs.map((t) => t.id));
4430
5052
  const resolvedDefault = defaultTab && validTabIds.has(defaultTab) ? defaultTab : allTabs[0]?.id ?? "result";
4431
- const [activeTab, setActiveTab] = (0, import_react20.useState)(resolvedDefault);
4432
- const [snapshotIdx, setSnapshotIdx] = (0, import_react20.useState)(0);
4433
- const [drillDownStack, setDrillDownStack] = (0, import_react20.useState)([]);
4434
- const [rightExpanded, setRightExpanded] = (0, import_react20.useState)(defaultExpanded?.details ?? true);
4435
- const [leftExpanded, setLeftExpanded] = (0, import_react20.useState)(defaultExpanded?.topology ?? false);
4436
- const [timelineExpanded, setTimelineExpanded] = (0, import_react20.useState)(defaultExpanded?.timeline ?? false);
4437
- (0, import_react20.useEffect)(() => {
5053
+ const [activeTab, setActiveTab] = (0, import_react24.useState)(resolvedDefault);
5054
+ const [snapshotIdx, setSnapshotIdx] = (0, import_react24.useState)(0);
5055
+ const [drillDownStack, setDrillDownStack] = (0, import_react24.useState)([]);
5056
+ const [rightExpanded, setRightExpanded] = (0, import_react24.useState)(defaultExpanded?.details ?? true);
5057
+ const [rightPanelMode, setRightPanelMode] = (0, import_react24.useState)("insights");
5058
+ const [leftExpanded, setLeftExpanded] = (0, import_react24.useState)(defaultExpanded?.topology ?? false);
5059
+ const [timelineExpanded, setTimelineExpanded] = (0, import_react24.useState)(defaultExpanded?.timeline ?? false);
5060
+ (0, import_react24.useEffect)(() => {
4438
5061
  if (isNarrow) {
4439
5062
  setLeftExpanded(false);
4440
5063
  setRightExpanded(false);
4441
5064
  setTimelineExpanded(false);
4442
5065
  }
4443
5066
  }, [isNarrow]);
4444
- const triggerReflow = (0, import_react20.useCallback)(() => {
5067
+ const triggerReflow = (0, import_react24.useCallback)(() => {
4445
5068
  requestAnimationFrame(() => window.dispatchEvent(new Event("resize")));
4446
5069
  setTimeout(() => window.dispatchEvent(new Event("resize")), 320);
4447
5070
  }, []);
4448
- const toggleLeft = (0, import_react20.useCallback)((v2) => {
5071
+ const toggleLeft = (0, import_react24.useCallback)((v2) => {
4449
5072
  setLeftExpanded(v2);
4450
5073
  triggerReflow();
4451
5074
  }, [triggerReflow]);
4452
- const toggleRight = (0, import_react20.useCallback)((v2) => {
5075
+ const toggleRight = (0, import_react24.useCallback)((v2) => {
4453
5076
  setRightExpanded(v2);
4454
5077
  triggerReflow();
4455
5078
  }, [triggerReflow]);
4456
- const toggleTimeline = (0, import_react20.useCallback)(() => {
5079
+ const toggleTimeline = (0, import_react24.useCallback)(() => {
4457
5080
  setTimelineExpanded((p) => !p);
4458
5081
  triggerReflow();
4459
5082
  }, [triggerReflow]);
4460
5083
  const isInSubflow = drillDownStack.length > 0;
4461
- const currentLevel = (0, import_react20.useMemo)(() => {
5084
+ const currentLevel = (0, import_react24.useMemo)(() => {
4462
5085
  if (drillDownStack.length > 0) {
4463
5086
  const top = drillDownStack[drillDownStack.length - 1];
4464
5087
  return { spec: top.spec, snapshots: top.snapshots };
@@ -4468,7 +5091,7 @@ function ExplainableShell({
4468
5091
  const activeSnapshots = currentLevel.snapshots;
4469
5092
  const activeSpec = currentLevel.spec;
4470
5093
  const safeIdx = activeSnapshots.length > 0 ? Math.max(0, Math.min(snapshotIdx, activeSnapshots.length - 1)) : 0;
4471
- const activeNarrative = (0, import_react20.useMemo)(() => {
5094
+ const activeNarrative = (0, import_react24.useMemo)(() => {
4472
5095
  if (!isInSubflow) return narrative;
4473
5096
  const lines = [];
4474
5097
  for (const snap of activeSnapshots) {
@@ -4478,25 +5101,25 @@ function ExplainableShell({
4478
5101
  return lines.length > 0 ? lines : void 0;
4479
5102
  }, [isInSubflow, narrative, activeSnapshots]);
4480
5103
  const activeNarrativeEntries = isInSubflow ? void 0 : narrativeEntries;
4481
- const breadcrumbs = (0, import_react20.useMemo)(() => {
5104
+ const breadcrumbs = (0, import_react24.useMemo)(() => {
4482
5105
  const root = { label: title || "Flowchart", spec, description: spec?.description };
4483
5106
  return [root, ...drillDownStack.map((e) => ({ label: e.label, spec: e.spec, description: void 0 }))];
4484
5107
  }, [spec, title, drillDownStack]);
4485
- const showTreeSidebar = (0, import_react20.useMemo)(() => !!spec && hasSubflowNodes(spec), [spec]);
4486
- const rootOverlay = (0, import_react20.useMemo)(() => {
5108
+ const showTreeSidebar = (0, import_react24.useMemo)(() => !!spec && hasSubflowNodes(spec), [spec]);
5109
+ const rootOverlay = (0, import_react24.useMemo)(() => {
4487
5110
  if (isInSubflow || !snapshots.length) return { activeStage: void 0, doneStages: void 0 };
4488
5111
  const doneStages = new Set(snapshots.slice(0, safeIdx).map((s) => s.stageLabel));
4489
5112
  const activeStage = snapshots[safeIdx]?.stageLabel ?? null;
4490
5113
  return { activeStage, doneStages };
4491
5114
  }, [isInSubflow, snapshots, safeIdx]);
4492
- const handleTabChange = (0, import_react20.useCallback)((tab) => {
5115
+ const handleTabChange = (0, import_react24.useCallback)((tab) => {
4493
5116
  setActiveTab(tab);
4494
5117
  setDrillDownStack([]);
4495
5118
  }, []);
4496
- const handleSnapshotChange = (0, import_react20.useCallback)((idx) => {
5119
+ const handleSnapshotChange = (0, import_react24.useCallback)((idx) => {
4497
5120
  if (typeof idx === "number") setSnapshotIdx(idx);
4498
5121
  }, []);
4499
- const handleDrillDown = (0, import_react20.useCallback)(
5122
+ const handleDrillDown = (0, import_react24.useCallback)(
4500
5123
  (nodeName) => {
4501
5124
  if (!activeSpec) return;
4502
5125
  const entry = resolveSubflowLevel(activeSpec, activeSnapshots, nodeName, narrativeEntries);
@@ -4507,14 +5130,14 @@ function ExplainableShell({
4507
5130
  },
4508
5131
  [activeSpec, activeSnapshots, narrativeEntries, snapshotIdx]
4509
5132
  );
4510
- const handleBreadcrumbNavigate = (0, import_react20.useCallback)((level) => {
5133
+ const handleBreadcrumbNavigate = (0, import_react24.useCallback)((level) => {
4511
5134
  setDrillDownStack((prev) => {
4512
5135
  const popped = level === 0 ? prev[0] : prev[level];
4513
5136
  if (popped) setSnapshotIdx(popped.parentSnapshotIdx);
4514
5137
  return level === 0 ? [] : prev.slice(0, level);
4515
5138
  });
4516
5139
  }, []);
4517
- const handleNodeClick = (0, import_react20.useCallback)(
5140
+ const handleNodeClick = (0, import_react24.useCallback)(
4518
5141
  (indexOrId) => {
4519
5142
  if (typeof indexOrId === "number") {
4520
5143
  setSnapshotIdx(indexOrId);
@@ -4532,7 +5155,7 @@ function ExplainableShell({
4532
5155
  },
4533
5156
  [activeSpec, activeSnapshots, handleDrillDown]
4534
5157
  );
4535
- const handleTreeNodeSelect = (0, import_react20.useCallback)(
5158
+ const handleTreeNodeSelect = (0, import_react24.useCallback)(
4536
5159
  (name, isSubflow) => {
4537
5160
  if (isSubflow && spec) {
4538
5161
  setDrillDownStack([]);
@@ -4551,31 +5174,31 @@ function ExplainableShell({
4551
5174
  );
4552
5175
  const tabLabels = new Map(allTabs.map((t) => [t.id, t.name]));
4553
5176
  if (unstyled) {
4554
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className, style, "data-fp": "explainable-shell", children: [
4555
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { "data-fp": "shell-tabs", children: allTabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { "data-fp": "shell-tab", "data-active": tab.id === activeTab, onClick: () => handleTabChange(tab.id), children: tab.name }, tab.id)) }),
4556
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { "data-fp": "shell-content", "data-tab": activeTab, children: [
4557
- activeTab === "result" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ResultPanel, { data: resultData ?? null, logs, hideConsole, unstyled: true }),
4558
- (activeTab === "explainable" || activeTab === "ai-compatible") && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4559
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TimeTravelControls, { snapshots: activeSnapshots, selectedIndex: safeIdx, onIndexChange: handleSnapshotChange, unstyled: true }),
4560
- isInSubflow && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
5177
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className, style, "data-fp": "explainable-shell", children: [
5178
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { "data-fp": "shell-tabs", children: allTabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { "data-fp": "shell-tab", "data-active": tab.id === activeTab, onClick: () => handleTabChange(tab.id), children: tab.name }, tab.id)) }),
5179
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { "data-fp": "shell-content", "data-tab": activeTab, children: [
5180
+ activeTab === "result" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ResultPanel, { data: resultData ?? null, logs, hideConsole, unstyled: true }),
5181
+ (activeTab === "explainable" || activeTab === "ai-compatible") && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
5182
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TimeTravelControls, { snapshots: activeSnapshots, selectedIndex: safeIdx, onIndexChange: handleSnapshotChange, unstyled: true }),
5183
+ isInSubflow && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
4561
5184
  activeSpec && effectiveRenderFlowchart?.({ spec: activeSpec, snapshots: activeSnapshots, selectedIndex: safeIdx, onNodeClick: handleNodeClick }),
4562
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, unstyled: true }),
4563
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, narrative: activeNarrative, unstyled: true }),
4564
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, unstyled: true })
5185
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, unstyled: true }),
5186
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, narrative: activeNarrative, unstyled: true }),
5187
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, unstyled: true })
4565
5188
  ] })
4566
5189
  ] })
4567
5190
  ] });
4568
5191
  }
4569
5192
  const showTopology = !!effectiveRenderFlowchart && !!activeSpec;
4570
- const detailsContent = (0, import_react20.useMemo)(() => {
5193
+ const detailsContent = (0, import_react24.useMemo)(() => {
4571
5194
  if (activeTab === "result") {
4572
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ResultPanel, { data: resultData ?? null, logs, hideConsole, size });
5195
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ResultPanel, { data: resultData ?? null, logs, hideConsole, size });
4573
5196
  }
4574
5197
  if (activeTab === "memory") {
4575
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, size, style: { height: "100%" } });
5198
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(MemoryPanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, size, style: { height: "100%" } });
4576
5199
  }
4577
5200
  if (activeTab === "narrative") {
4578
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, narrative: activeNarrative, size, style: { height: "100%" } });
5201
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(NarrativePanel, { snapshots: activeSnapshots, selectedIndex: safeIdx, narrativeEntries: activeNarrativeEntries, narrative: activeNarrative, size, style: { height: "100%" } });
4579
5202
  }
4580
5203
  const customView = recorderViews?.find((v2) => v2.id === activeTab);
4581
5204
  if (customView?.render) {
@@ -4583,7 +5206,7 @@ function ExplainableShell({
4583
5206
  }
4584
5207
  const autoView = autoRecorderViews.find((v2) => v2.id === activeTab);
4585
5208
  if (autoView) {
4586
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5209
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4587
5210
  KeyedRecorderView,
4588
5211
  {
4589
5212
  data: autoView.data,
@@ -4596,8 +5219,8 @@ function ExplainableShell({
4596
5219
  }
4597
5220
  return null;
4598
5221
  }, [activeTab, resultData, logs, hideConsole, size, activeSnapshots, safeIdx, activeNarrativeEntries, activeNarrative, recorderViews, autoRecorderViews]);
4599
- const detailsPanel = /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { display: "flex", flexDirection: "column", height: "100%", overflow: "hidden" }, children: [
4600
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: {
5222
+ const detailsPanel = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", flexDirection: "column", height: "100%", overflow: "hidden" }, children: [
5223
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: {
4601
5224
  display: "flex",
4602
5225
  borderBottom: `1px solid ${theme.border}`,
4603
5226
  background: theme.bgSecondary,
@@ -4605,7 +5228,7 @@ function ExplainableShell({
4605
5228
  overflowX: "auto"
4606
5229
  }, children: allTabs.map((tab) => {
4607
5230
  const active = tab.id === activeTab;
4608
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5231
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4609
5232
  "button",
4610
5233
  {
4611
5234
  onClick: () => handleTabChange(tab.id),
@@ -4629,9 +5252,9 @@ function ExplainableShell({
4629
5252
  tab.id
4630
5253
  );
4631
5254
  }) }),
4632
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: detailsContent })
5255
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: detailsContent })
4633
5256
  ] });
4634
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5257
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
4635
5258
  "div",
4636
5259
  {
4637
5260
  ref: shellRef,
@@ -4649,7 +5272,7 @@ function ExplainableShell({
4649
5272
  },
4650
5273
  "data-fp": "explainable-shell",
4651
5274
  children: [
4652
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5275
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4653
5276
  TimeTravelControls,
4654
5277
  {
4655
5278
  snapshots: activeSnapshots,
@@ -4658,19 +5281,19 @@ function ExplainableShell({
4658
5281
  size
4659
5282
  }
4660
5283
  ),
4661
- isInSubflow && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
4662
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flex: 1, overflow: isNarrow ? "auto" : "hidden", display: "flex", flexDirection: "column" }, children: isNarrow ? (
5284
+ isInSubflow && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SubflowBreadcrumb, { breadcrumbs, onNavigate: handleBreadcrumbNavigate }),
5285
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { flex: 1, overflow: isNarrow ? "auto" : "hidden", display: "flex", flexDirection: "column" }, children: isNarrow ? (
4663
5286
  /* ── Mobile: stacked vertical ── */
4664
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4665
- showTopology && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { height: 350, flexShrink: 0, overflow: "hidden" }, children: effectiveRenderFlowchart({
5287
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
5288
+ showTopology && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { height: 350, flexShrink: 0, overflow: "hidden" }, children: effectiveRenderFlowchart({
4666
5289
  spec: activeSpec,
4667
5290
  snapshots: activeSnapshots,
4668
5291
  selectedIndex: safeIdx,
4669
5292
  onNodeClick: handleNodeClick
4670
5293
  }) }),
4671
- showTreeSidebar && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4672
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(HLinePill, { label: leftLabel, expanded: leftExpanded, onClick: () => toggleLeft(!leftExpanded) }),
4673
- leftExpanded && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { maxHeight: 180, overflow: "auto", flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5294
+ showTreeSidebar && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
5295
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(HLinePill, { label: leftLabel, expanded: leftExpanded, onClick: () => toggleLeft(!leftExpanded) }),
5296
+ leftExpanded && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { maxHeight: 180, overflow: "auto", flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4674
5297
  SubflowTree,
4675
5298
  {
4676
5299
  spec,
@@ -4680,17 +5303,17 @@ function ExplainableShell({
4680
5303
  }
4681
5304
  ) })
4682
5305
  ] }),
4683
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(HLinePill, { label: rightLabel, expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
4684
- rightExpanded && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { maxHeight: 350, flexShrink: 0, overflow: "hidden" }, children: detailsPanel }),
4685
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(HLinePill, { label: bottomLabel, detail: `${activeSnapshots.length} stages`, expanded: timelineExpanded, onClick: toggleTimeline }),
4686
- timelineExpanded && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flexShrink: 0, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, size }) })
5306
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(HLinePill, { label: rightLabel, expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
5307
+ rightExpanded && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { maxHeight: 350, flexShrink: 0, overflow: "hidden" }, children: detailsPanel }),
5308
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(HLinePill, { label: bottomLabel, detail: `${activeSnapshots.length} stages`, expanded: timelineExpanded, onClick: toggleTimeline }),
5309
+ timelineExpanded && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { flexShrink: 0, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, size }) })
4687
5310
  ] })
4688
- ) : showTopology ? (
4689
- /* ── Desktop with topology: side-by-side ── */
4690
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4691
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { flex: 1, display: "flex", overflow: "hidden" }, children: [
4692
- showTreeSidebar && (leftExpanded ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { width: 220, flexShrink: 0, display: "flex", flexDirection: "row", overflow: "hidden" }, children: [
4693
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5311
+ ) : (
5312
+ /* ── Desktop: two-column — Flowchart | Right Panel ── */
5313
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
5314
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { flex: 1, display: "flex", overflow: "hidden" }, children: [
5315
+ showTreeSidebar && (leftExpanded ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { width: 180, flexShrink: 0, display: "flex", flexDirection: "row", overflow: "hidden" }, children: [
5316
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { flex: 1, overflow: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4694
5317
  SubflowTree,
4695
5318
  {
4696
5319
  spec,
@@ -4699,28 +5322,45 @@ function ExplainableShell({
4699
5322
  onNodeSelect: handleTreeNodeSelect
4700
5323
  }
4701
5324
  ) }),
4702
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VLinePill, { label: leftLabel, expanded: true, side: "left", onClick: () => toggleLeft(false) })
4703
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VLinePill, { label: leftLabel, expanded: false, side: "left", onClick: () => toggleLeft(true) })),
4704
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flex: 1, overflow: "hidden", minWidth: 0 }, children: effectiveRenderFlowchart({
5325
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VLinePill, { label: "Topology", expanded: true, side: "left", onClick: () => toggleLeft(false) })
5326
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VLinePill, { label: "Topology", expanded: false, side: "left", onClick: () => toggleLeft(true) })),
5327
+ showTopology ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { flex: 1, overflow: "hidden", minWidth: 0 }, children: effectiveRenderFlowchart({
4705
5328
  spec: activeSpec,
4706
5329
  snapshots: activeSnapshots,
4707
5330
  selectedIndex: safeIdx,
4708
5331
  onNodeClick: handleNodeClick
4709
- }) }),
4710
- rightExpanded ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { width: "38%", minWidth: 300, maxWidth: 500, display: "flex", flexDirection: "row", overflow: "hidden" }, children: [
4711
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VLinePill, { label: rightLabel, expanded: true, onClick: () => toggleRight(false) }),
4712
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flex: 1, overflow: "hidden" }, children: detailsPanel })
4713
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(VLinePill, { label: rightLabel, expanded: false, onClick: () => toggleRight(true) })
5332
+ }) }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { flex: 1 } }),
5333
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VLinePill, { label: "Details", expanded: rightExpanded, onClick: () => toggleRight(!rightExpanded) }),
5334
+ rightExpanded && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { width: "42%", minWidth: 320, maxWidth: 550, display: "flex", flexDirection: "column", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5335
+ RightPanel,
5336
+ {
5337
+ mode: rightPanelMode,
5338
+ onModeChange: setRightPanelMode,
5339
+ snapshots: activeSnapshots,
5340
+ selectedIndex: safeIdx,
5341
+ runtimeSnapshot,
5342
+ activeTab,
5343
+ allTabs,
5344
+ activeNarrativeEntries,
5345
+ activeNarrative,
5346
+ recorderViews,
5347
+ autoRecorderViews,
5348
+ size,
5349
+ onNavigateToStage: (id) => {
5350
+ const idx = activeSnapshots.findIndex((s) => s.runtimeStageId === id);
5351
+ if (idx >= 0) setSnapshotIdx(idx);
5352
+ }
5353
+ }
5354
+ ) })
4714
5355
  ] }),
4715
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(HLinePill, { label: bottomLabel, detail: `${activeSnapshots.length} stages`, expanded: timelineExpanded, onClick: toggleTimeline }),
4716
- timelineExpanded && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flexShrink: 0, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, size }) })
4717
- ] })
4718
- ) : (
4719
- /* ── Desktop without topology: details panel takes full width ── */
4720
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4721
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flex: 1, overflow: "hidden" }, children: detailsPanel }),
4722
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(HLinePill, { label: bottomLabel, detail: `${activeSnapshots.length} stages`, expanded: timelineExpanded, onClick: toggleTimeline }),
4723
- timelineExpanded && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { flexShrink: 0, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(GanttTimeline, { snapshots: activeSnapshots, selectedIndex: safeIdx, onSelect: handleSnapshotChange, size }) })
5356
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5357
+ CompactTimeline,
5358
+ {
5359
+ snapshots: activeSnapshots,
5360
+ selectedIndex: safeIdx,
5361
+ defaultExpanded: timelineExpanded
5362
+ }
5363
+ )
4724
5364
  ] })
4725
5365
  ) })
4726
5366
  ]
@@ -4729,9 +5369,13 @@ function ExplainableShell({
4729
5369
  }
4730
5370
  // Annotate the CommonJS export names for ESM import in node:
4731
5371
  0 && (module.exports = {
5372
+ CompactTimeline,
5373
+ DataTracePanel,
4732
5374
  ExplainableShell,
4733
5375
  FootprintTheme,
4734
5376
  GanttTimeline,
5377
+ InsightPanel,
5378
+ InspectorPanel,
4735
5379
  MemoryInspector,
4736
5380
  MemoryPanel,
4737
5381
  NarrativeLog,