dsh-context 0.31.0 → 0.32.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.
Files changed (3) hide show
  1. package/README.md +24 -9
  2. package/lib/client.js +373 -91
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  **The best [DeepSeek Harness plugin](https://www.deepseek.com/harness/) for Agent's context insights and management.**
10
10
 
11
11
  `dsh-context` provides full context lifecycle management features.
12
- - **Context tab** — an UI context dashboard for DeepSeek Harness’s context stats, composition, history, events, and messages.
12
+ - **Context tab** — an UI context dashboard for DeepSeek Harness’s context stats, composition, trend, events, and messages.
13
13
  - **`/context` command** — the slash command shows the context model for current context composition and recent context evolution.
14
14
 
15
15
  ## Install / Update
@@ -46,7 +46,7 @@ Type `/context` (or pick it from the `/` menu) and press Enter: a centered dialo
46
46
 
47
47
  ### ⚙️ Settings — per-user preferences
48
48
 
49
- In **Settings → Plugins → Plugin configuration**, the **Context / 上下文** card holds this plugin's per-user preferences — currently the **default trend granularity** (Step/Turn) the Context tab opens with. In-chart toggling stays per-view and never overwrites the stored preference. The card appears only when the Host half is installed and the settings document is writable (a remote browser keeps settings process-local and shows no card).
49
+ In **Settings → Plugins → Plugin configuration**, the **Context / 上下文** card holds this plugin's per-user preferences — the **default trend granularity** (Step/Turn) and the **default trend mode** (Total/Delta) the Context tab opens with. In-chart toggling stays per-view and never overwrites the stored preference. The card appears only when the Host half is installed and the settings document is writable (a remote browser keeps settings process-local and shows no card).
50
50
 
51
51
  ## What you'll see
52
52
 
@@ -60,17 +60,27 @@ A six-color stacked bar scaled against the model's full context window (the gray
60
60
 
61
61
  The headline occupancy and the composition counts read the **same official token-meter projections the chat composer's context ring reads** (`contextPressure` / `contextBreakdown`), so the legend's `≈` figures and proportions match the ring's click-open panel exactly; the message bucket is subdivided into the four surface categories by the fold's per-category ratios.
62
62
 
63
- ### 📈 Historywatch the window grow (and get compacted)
63
+ ### 📈 Context Trend every request's size *and* its story
64
64
 
65
- One stacked bar per model request, finer than per-message. Toggle between **Turn** and **Step** granularity, scroll sideways through the session, hover any bar for a quick tooltip, and click to pin the full breakdown — including provider-reported actual prompt/output tokens next to the estimate. **Hovering a bar also drives the Context browser beside it** — the browser previews that step's assembled context in real time as you scrub across the history. **✂ marks where compaction or pruning happened** — watch the bars drop:
65
+ One stacked bar per model request finer than per-message so you watch the window grow turn by turn, and drop in one when compaction hits:
66
66
 
67
- ![History chart with a pinned request](https://raw.githubusercontent.com/bowenliang123/dsh-context/main/docs/history-detail.png)
67
+ ![Context Trend card with the step brief](https://raw.githubusercontent.com/bowenliang123/dsh-context/main/docs/context-trend.png)
68
+
69
+ - **✨ Step brief — what a step *was*, not just how big.** Three plain-language rows under the chart: **User** recalls the message that opened the turn (on any of its steps), **In** lists what newly entered the context — usually the previous tool calls' results, failures flagged — and **Response** shows what the model returned: its reply text and/or the tools it called. Hover a row's tag to learn what the row means; click any row to open that exact message in the Context browser.
70
+ - **Read it your way** — **Step** or **Turn** granularity, **Total** (cumulative makeup) or **Delta** (each request's signed change), and sideways scroll through the whole session.
71
+ - **Hover & pin** — scrub for an instant tooltip (turn/step, time, tokens, a one-line reply preview); click to pin the full category breakdown, with provider-reported actual prompt/output/cache figures next to the estimates.
72
+ - **✂ marks the events** — compactions and prunes land exactly where they happened, so the bars' drops explain themselves.
73
+ - **Live linkage** — hovering a bar previews that step's assembled context in the Context browser beside the chart; leave the chart and it returns to your own pick.
68
74
 
69
- Above: a real session that grew to ~563k tokens across 48 turns, then compaction (✂) recycled −535.5k in one step, and the conversation continued from a fresh, small window.
75
+ Above: Turn 1 · Step 15 of a real session the brief recalls the turn's opening message, the files just read in, and the reply that called `read` next.
70
76
 
71
- In **Step** granularity, hovering any bar shows that single step's context info instantly its turn/step, timestamp, and estimated vs. provider-reported token counts:
77
+ A longer session tells the dramatic version ~563k tokens across 48 turns, then compaction (✂) recycled −535.5k in one step, and the conversation continued from a fresh, small window:
78
+
79
+ ![History chart with a pinned request](https://raw.githubusercontent.com/bowenliang123/dsh-context/main/docs/history-detail.png)
72
80
 
73
- ![History chart with a step hover tooltip](https://raw.githubusercontent.com/bowenliang123/dsh-context/main/docs/history-step-hover.png)
81
+ Switch the chart from **Total** to **Delta** and each bar becomes the *change* that request made to the window instead of its cumulative size: diverging stacks pile up from the solid zero baseline when the window grew and hang below it when it shrank, tooltips read `Δ ±Nk`, and the pinned detail card re-prices every category as a signed delta — so you can tell exactly which part of a request added (or reclaimed) tokens. Below, Turn 5's first step grew the window by **+1.6k**: injected context **+803**, the user message **+649**, the assistant reply **+178** — and nothing else moved:
82
+
83
+ ![History chart in Delta mode](https://raw.githubusercontent.com/bowenliang123/dsh-context/main/docs/history-delta.png)
74
84
 
75
85
  ### ⚡ Context events — when and why the window changed
76
86
 
@@ -90,8 +100,13 @@ Pick **Live (next request)** or any retained step from the picker, and browse wh
90
100
 
91
101
  Six collapsible category sections (system prompt, tool schemas, user messages, injected context, assistant replies, tool results) expand into one row per element — each with its token price — and every element expands again into its **actual content**: the full system prompt, each tool's description and JSON schema, message text, reasoning, tool-call arguments, and tool outputs.
92
102
 
93
- - **Linked with the history chart** — hover any bar in the History card and the browser previews that step instantly; leave the chart and it returns to your own pick. Keep a category open while scrubbing to compare one category across steps.
103
+ - **Linked with the trend chart** — hover any bar in the Context trend card and the browser previews that step instantly; leave the chart and it returns to your own pick. Keep a category open while scrubbing to compare one category across steps. Clicking a step-brief row (**User** / **In** / **Response**) opens that exact message here, expanded and scrolled into view.
94
104
  - **Honest about coverage** — steps before a compaction are reconstructed from the removed-message archive, and the card says so when a step's makeup is only approximate. Elements older than the loaded chat window page older history in automatically when you expand them, and live injections (AGENTS.md, session-start context, …) are always listed — never a token sum without its items.
105
+ - **Diff against the previous turn** — switch the picker to **vs previous turn** and every category gets signed delta badges (`+N` items, `+Nk` tokens), so one glance tells you what the conversation added since the end of the last turn.
106
+
107
+ Tool results open into the full call and response: the tool's name and arguments with its **OK/error** status on top, the result body with its line count and a **Raw / Markdown** display toggle, and any image payload (e.g. `read_image` output) rendered as a thumbnail card with its name, dimensions, stored size, and estimated token cost — instead of a flattened blob of text:
108
+
109
+ ![Context browser showing a tool result with Raw/Markdown toggle and an image payload](https://raw.githubusercontent.com/bowenliang123/dsh-context/main/docs/context-browser-tool-result.png)
95
110
 
96
111
  ### 🖼 Multimodal — image attachments in full view (DeepSeek Harness 0.1.1+)
97
112
 
package/lib/client.js CHANGED
@@ -13,7 +13,7 @@ window.__ModuleLoader__.load({
13
13
  "cat.inject": "注入内容",
14
14
  "cat.assistant": "助手消息",
15
15
  "cat.tool": "工具结果",
16
- "overview.title": "当前构成",
16
+ "overview.title": "当前上下文",
17
17
  "overview.estimate": "tokens(估算)",
18
18
  "overview.free": "剩余窗口",
19
19
  "overview.used": "上下文已用",
@@ -41,7 +41,7 @@ window.__ModuleLoader__.load({
41
41
  "plugin.github": "GitHub",
42
42
  "tools.top": "工具定义 Top:",
43
43
  "tools.more": "等 {n} 个",
44
- "trend.title": "历史趋势",
44
+ "trend.title": "上下文趋势",
45
45
  "gran.step": "步骤",
46
46
  "gran.turn": "轮次",
47
47
  "settings.title": "上下文",
@@ -63,6 +63,14 @@ window.__ModuleLoader__.load({
63
63
  "detail.actual": "实际 prompt {n}",
64
64
  "detail.output": "输出 {n}",
65
65
  "detail.cache": "缓存 {n}%",
66
+ "brief.turn": "本轮",
67
+ "brief.input": "输入",
68
+ "brief.reply": "回复",
69
+ "brief.more": "+{n}",
70
+ "brief.locate": "在上下文浏览器中查看",
71
+ "brief.turnTip": "这一轮开场时用户发送的消息",
72
+ "brief.inputTip": "这一步新进入上下文的内容(通常是上一步工具调用的结果)",
73
+ "brief.replyTip": "这一步模型返回的内容(文本回复或工具调用)",
66
74
  "events.title": "上下文事件",
67
75
  "events.empty": "暂无上下文事件(压缩、注入、模型切换会出现在这里)",
68
76
  "events.at": "第 {t} 轮 · 第 {s} 步",
@@ -188,7 +196,7 @@ window.__ModuleLoader__.load({
188
196
  "plugin.github": "GitHub",
189
197
  "tools.top": "Top Tool Schemas:",
190
198
  "tools.more": "of {n}",
191
- "trend.title": "Context History",
199
+ "trend.title": "Context Trend",
192
200
  "gran.step": "Step",
193
201
  "gran.turn": "Turn",
194
202
  "settings.title": "Context",
@@ -210,6 +218,14 @@ window.__ModuleLoader__.load({
210
218
  "detail.actual": "Actual Prompt {n}",
211
219
  "detail.output": "Output {n}",
212
220
  "detail.cache": "Cache {n}%",
221
+ "brief.turn": "User",
222
+ "brief.input": "In",
223
+ "brief.reply": "Response",
224
+ "brief.more": "+{n}",
225
+ "brief.locate": "Reveal in Context Browser",
226
+ "brief.turnTip": "The user message that opened this turn",
227
+ "brief.inputTip": "What newly entered the context for this step (usually results of the previous tool calls)",
228
+ "brief.replyTip": "What the model returned on this step (a text reply or tool calls)",
213
229
  "events.title": "Context Events",
214
230
  "events.empty": "No context events yet (compaction, injections, model switches appear here)",
215
231
  "events.at": "Turn {t} · Step {s}",
@@ -419,6 +435,8 @@ window.__ModuleLoader__.load({
419
435
  "assistant",
420
436
  "tool"
421
437
  ];
438
+ /** Category key → chart color, built once from CATS. */
439
+ const CAT_COLORS = Object.fromEntries(CATS.map((c) => [c.key, c.color]));
422
440
  function partsOf(breakdown) {
423
441
  return CATS.map((c) => {
424
442
  return {
@@ -686,6 +704,56 @@ window.__ModuleLoader__.load({
686
704
  const h = React.createElement;
687
705
  const ReactDOM = require("react-dom");
688
706
  //#endregion
707
+ //#region src/client/callSummary.ts
708
+ function parseCallArgs(raw) {
709
+ if (typeof raw !== "string" || raw === "") return null;
710
+ try {
711
+ const parsed = JSON.parse(raw);
712
+ return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
713
+ } catch {
714
+ return null;
715
+ }
716
+ }
717
+ function summaryInArgs(args) {
718
+ if (args === null) return null;
719
+ for (const k of [
720
+ "description",
721
+ "file_path",
722
+ "path",
723
+ "filePath"
724
+ ]) {
725
+ const v = args[k];
726
+ if (typeof v === "string" && v !== "") return v;
727
+ }
728
+ return null;
729
+ }
730
+ function callSummaryOf(conv) {
731
+ return summaryInArgs(parseCallArgs(conv?.call?.argsRaw));
732
+ }
733
+ function blockSummaryOf(conv) {
734
+ if (conv === void 0 || !Array.isArray(conv.blocks)) return null;
735
+ for (const b of conv.blocks) {
736
+ const blk = b !== null && typeof b === "object" ? b : null;
737
+ if (blk === null || blk.kind !== "tool-call") continue;
738
+ const s = summaryInArgs(parseCallArgs(blk.argsRaw));
739
+ if (s !== null) return s;
740
+ }
741
+ return null;
742
+ }
743
+ /**
744
+ * All tool-call names in an assistant conversation node, in order. The fold's surface node keeps `calls` only for TEXT-LESS replies,
745
+ * so a reply carrying both text and calls recovers its call breadcrumb here through the conversation join.
746
+ */
747
+ function callNamesOf(conv) {
748
+ if (conv === void 0 || !Array.isArray(conv.blocks)) return [];
749
+ const names = [];
750
+ for (const b of conv.blocks) {
751
+ const blk = b !== null && typeof b === "object" ? b : null;
752
+ if (blk !== null && blk.kind === "tool-call" && typeof blk.name === "string") names.push(blk.name);
753
+ }
754
+ return names;
755
+ }
756
+ //#endregion
689
757
  //#region src/client/components/nodes.tsx
690
758
  function makeNodeText(kit) {
691
759
  const { t } = kit;
@@ -704,15 +772,13 @@ window.__ModuleLoader__.load({
704
772
  const nodeText = makeNodeText(kit);
705
773
  return function NodeList(props) {
706
774
  if (props.nodes.length === 0) return /* @__PURE__ */ React.createElement("div", { className: "lc-empty" }, t("nodes.empty"));
707
- const catColor = {};
708
- for (const c of CATS) catColor[c.key] = c.color;
709
775
  const rows = props.nodes.slice().reverse();
710
776
  return /* @__PURE__ */ React.createElement("div", { className: "lc-nodes" }, props.dropped > 0 ? /* @__PURE__ */ React.createElement("div", { className: "lc-nodes-more" }, t("nodes.more", { n: props.dropped })) : null, rows.map((n) => {
711
777
  const text = nodeText(n);
712
778
  return /* @__PURE__ */ React.createElement("div", {
713
779
  key: n.seq,
714
780
  className: "lc-node"
715
- }, /* @__PURE__ */ React.createElement("i", { style: { background: catColor[n.cat] || "#999" } }), /* @__PURE__ */ React.createElement("span", {
781
+ }, /* @__PURE__ */ React.createElement("i", { style: { background: CAT_COLORS[n.cat] || "#999" } }), /* @__PURE__ */ React.createElement("span", {
716
782
  className: "lc-node-preview",
717
783
  title: text
718
784
  }, text), typeof n.time === "number" ? /* @__PURE__ */ React.createElement("span", { className: "lc-node-time" }, fmtTime(n.time)) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-node-tokens" }, fmt(n.tokens)));
@@ -1261,62 +1327,79 @@ window.__ModuleLoader__.load({
1261
1327
  flushImages();
1262
1328
  return /* @__PURE__ */ React.createElement(React.Fragment, null, out);
1263
1329
  }
1264
- function parseArgs(raw) {
1265
- if (typeof raw !== "string" || raw === "") return null;
1266
- try {
1267
- const parsed = JSON.parse(raw);
1268
- return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
1269
- } catch {
1270
- return null;
1271
- }
1272
- }
1273
1330
  /**
1274
- * A call's preview: bash-style `description`, or the target path (`file_path`/`path`/`filePath`) for edit/read/write tools; null when the
1275
- * arguments hold neither.
1331
+ * The trailing status markers dsh shell tools append at the END of a result's text while `isError` stays false
1332
+ * (the status is result data, per tool-bash's render: "non-zero exits are reported, not errored"):
1333
+ * - one-shot bash/pwsh: `[exit code: N]` (non-zero only), `[killed by signal: X]`
1334
+ * - persistent shells: `[shell killed by signal: X]`, `[shell exited: code N]` — riding LAST, after the
1335
+ * `[exit code: N]` of the command whose failure killed the shell, so the command marker is re-checked
1336
+ * on the preceding text
1337
+ * - job_output: `[status: killed]` / `[status: failed, detail]` — the tool-jobs status line always terminates
1338
+ * the read; a killed/failed background job settles with `isError` false, so only the line flags the loss
1339
+ * End-anchored like dsh's own parseExitStatus, so marker text quoted inside the output (e.g. a cat'ed log)
1340
+ * is not a failure. A clean shell exit (code 0 or code-less) or a live/completed job status is a notice,
1341
+ * not a failure.
1342
+ * The parsed exit code feeds the FAILED run-state pill.
1276
1343
  */
1277
- function summaryIn(args) {
1278
- if (args === null) return null;
1279
- for (const k of [
1280
- "description",
1281
- "file_path",
1282
- "path",
1283
- "filePath"
1284
- ]) {
1285
- const v = args[k];
1286
- if (typeof v === "string" && v !== "") return v;
1344
+ function tailStatusOf(conv) {
1345
+ if (conv === void 0 || !Array.isArray(conv.content)) return {
1346
+ fail: false,
1347
+ exit: null
1348
+ };
1349
+ for (const b of conv.content) {
1350
+ const text = b?.text;
1351
+ if (typeof text !== "string") continue;
1352
+ const tail = text.trimEnd();
1353
+ const shell = /\[(shell killed by signal: [^\]\n]+|shell exited(?:: code \d+)?)\]$/.exec(tail);
1354
+ if (shell !== null) {
1355
+ const cmdExit = /\[exit code:\s*(\d+)\]\s*$/.exec(tail.slice(0, shell.index));
1356
+ if (cmdExit !== null) return {
1357
+ fail: true,
1358
+ exit: Number(cmdExit[1])
1359
+ };
1360
+ const code = /: code (\d+)$/.exec(shell[1]);
1361
+ if (code !== null) return {
1362
+ fail: code[1] !== "0",
1363
+ exit: code[1] === "0" ? null : Number(code[1])
1364
+ };
1365
+ return {
1366
+ fail: shell[1].startsWith("shell killed"),
1367
+ exit: null
1368
+ };
1369
+ }
1370
+ const exit = /\[exit code:\s*(\d+)\]$/.exec(tail);
1371
+ if (exit !== null) return {
1372
+ fail: true,
1373
+ exit: Number(exit[1])
1374
+ };
1375
+ if (/\[killed by signal: [^\]\n]+\]$/.test(tail)) return {
1376
+ fail: true,
1377
+ exit: null
1378
+ };
1379
+ if (/\[status: (?:killed|failed)(?:, [^\]\n]*)?\]$/.test(tail)) return {
1380
+ fail: true,
1381
+ exit: null
1382
+ };
1287
1383
  }
1288
- return null;
1289
- }
1290
- function callSummaryOf(conv) {
1291
- return summaryIn(parseArgs(conv?.call?.argsRaw));
1384
+ return {
1385
+ fail: false,
1386
+ exit: null
1387
+ };
1292
1388
  }
1293
1389
  /**
1294
- * The dsh `[exit code: N]` marker across the payload's direct text blockssurfaced only on the FAILED run-state pill, the one place the
1295
- * number matters.
1390
+ * A tool result's failure: the fold-stamped `err` or the snapshot's `isError` (infrastructure failuresdsh stamps
1391
+ * those) OR a trailing status marker (see tailStatusOf). dsh settles a failing COMMAND as a completed call, so the
1392
+ * marker is the only failure signal — mirroring the chat row's terminalFailed. A timeout stays a notice, as in the chat.
1296
1393
  */
1297
- function exitCodeOf(conv) {
1298
- if (conv === void 0 || !Array.isArray(conv.content)) return null;
1299
- for (const b of conv.content) {
1300
- if (b === null || typeof b !== "object") continue;
1301
- const blk = b;
1302
- if (typeof blk.text !== "string") continue;
1303
- const m = blk.text.match(/\[exit code:\s*(\d+)\]/);
1304
- if (m !== null) return Number(m[1]);
1305
- }
1306
- return null;
1307
- }
1308
- function blockSummaryOf(conv) {
1309
- if (conv === void 0 || !Array.isArray(conv.blocks)) return null;
1310
- for (const b of conv.blocks) {
1311
- const blk = b !== null && typeof b === "object" ? b : null;
1312
- if (blk === null || blk.kind !== "tool-call") continue;
1313
- const s = summaryIn(parseArgs(blk.argsRaw));
1314
- if (s !== null) return s;
1315
- }
1316
- return null;
1394
+ function toolErrOf(node, conv) {
1395
+ const tail = tailStatusOf(conv);
1396
+ return {
1397
+ err: node.err === true || conv?.isError === true || tail.fail,
1398
+ exit: tail.exit
1399
+ };
1317
1400
  }
1318
1401
  function ToolCallCard(props) {
1319
- const args = React.useMemo(() => parseArgs(props.argsRaw), [props.argsRaw]);
1402
+ const args = React.useMemo(() => parseCallArgs(props.argsRaw), [props.argsRaw]);
1320
1403
  return /* @__PURE__ */ React.createElement(Section, {
1321
1404
  label: (props.arrow ?? "→") + " " + props.name,
1322
1405
  labelClass: "lc-ts-call-name",
@@ -1351,12 +1434,12 @@ window.__ModuleLoader__.load({
1351
1434
  labels
1352
1435
  });
1353
1436
  if (conv.kind === "tool-result") {
1354
- const err = node.err === true || conv.isError === true;
1437
+ const { err, exit } = toolErrOf(node, conv);
1355
1438
  return /* @__PURE__ */ React.createElement(React.Fragment, null, conv.call != null ? /* @__PURE__ */ React.createElement(ToolCallCard, {
1356
1439
  arrow: "←",
1357
1440
  name: conv.call.name,
1358
1441
  argsRaw: conv.call.argsRaw,
1359
- status: labels.callState(err, err ? exitCodeOf(conv) : null)
1442
+ status: labels.callState(err, exit)
1360
1443
  }) : null, Array.isArray(conv.content) ? /* @__PURE__ */ React.createElement(BlocksBody, {
1361
1444
  blocks: conv.content,
1362
1445
  richable: false,
@@ -1386,10 +1469,10 @@ window.__ModuleLoader__.load({
1386
1469
  for (const n of asm.nodes) (m[n.cat] ??= []).push(n);
1387
1470
  return m;
1388
1471
  }
1389
- function countOf(asm, c) {
1472
+ function countOf(asm, byCat, c) {
1390
1473
  if (c === "system") return asm.header !== null && asm.header.system !== void 0 ? 1 : 0;
1391
1474
  if (c === "tools") return asm.header !== null ? asm.header.tools.length : 0;
1392
- return byCatOf(asm)[c]?.length ?? 0;
1475
+ return byCat[c]?.length ?? 0;
1393
1476
  }
1394
1477
  function lastOfTurn(requests, turn) {
1395
1478
  for (let i = requests.length - 1; i >= 0; i--) if ((requests[i].turn ?? 0) === turn) return requests[i];
@@ -1400,8 +1483,6 @@ window.__ModuleLoader__.load({
1400
1483
  const nodeText = makeNodeText(kit);
1401
1484
  const rich = makeRichText(kit);
1402
1485
  const ImageCard = makeImageCard(kit);
1403
- const catColor = {};
1404
- for (const c of CATS) catColor[c.key] = c.color;
1405
1486
  const MAX_AUTO_PAGES = 20;
1406
1487
  return function ContextBrowser(props) {
1407
1488
  const { data, headers } = props;
@@ -1463,6 +1544,22 @@ window.__ModuleLoader__.load({
1463
1544
  setOpenElem(toolFocus.tool !== void 0 ? "tool:" + toolFocus.tool : null);
1464
1545
  if (props.onToolFocusHandled !== void 0) props.onToolFocusHandled();
1465
1546
  }, [toolFocus, props.onToolFocusHandled]);
1547
+ const rootRef = React.useRef(null);
1548
+ const focusScrollRef = React.useRef(false);
1549
+ const nodeFocus = props.nodeFocus;
1550
+ React.useEffect(() => {
1551
+ if (nodeFocus === null || nodeFocus === void 0) return;
1552
+ setSel(nodeFocus.step);
1553
+ setOpenCat(nodeFocus.cat);
1554
+ setOpenElem("n" + String(nodeFocus.seq));
1555
+ focusScrollRef.current = true;
1556
+ if (props.onNodeFocusHandled !== void 0) props.onNodeFocusHandled();
1557
+ }, [nodeFocus, props.onNodeFocusHandled]);
1558
+ React.useLayoutEffect(() => {
1559
+ if (!focusScrollRef.current) return;
1560
+ focusScrollRef.current = false;
1561
+ rootRef.current?.querySelector(".lc-br-elem-on")?.scrollIntoView({ block: "nearest" });
1562
+ });
1466
1563
  const awaiting = missingSeq !== null && !exhausted && loadOlderHistory !== void 0 && hasMore;
1467
1564
  const requests = data.requests;
1468
1565
  const hoverReq = props.previewSeq !== null && props.previewSeq !== void 0 ? requests.find((r) => r.seq === props.previewSeq) ?? null : null;
@@ -1481,8 +1578,9 @@ window.__ModuleLoader__.load({
1481
1578
  };
1482
1579
  const refReq = req === null ? requests.length > 0 ? requests[requests.length - 1] : null : lastOfTurn(requests, (req.turn ?? 0) - 1);
1483
1580
  const prevView = refReq !== null ? assemble(data, headers, refReq.seq) : null;
1581
+ const prevByCat = prevView !== null ? byCatOf(prevView) : null;
1484
1582
  const byCat = byCatOf(view);
1485
- const toolCount = (c) => countOf(view, c);
1583
+ const toolCount = (c) => countOf(view, byCat, c);
1486
1584
  const toggleCat = (c) => {
1487
1585
  if (!(toolCount(c) > 0 || (c === "system" || c === "tools") && view.header === null)) return;
1488
1586
  setOpenCat(openCat === c ? null : c);
@@ -1542,7 +1640,7 @@ window.__ModuleLoader__.load({
1542
1640
  }
1543
1641
  return (byCat[c] ?? []).slice().reverse().map((n) => {
1544
1642
  const conv = bySeq.get(n.seq);
1545
- const rowErr = n.cat === "tool" && (n.err === true || conv !== void 0 && conv.isError === true);
1643
+ const rowErr = n.cat === "tool" && toolErrOf(n, conv).err;
1546
1644
  let tag = null;
1547
1645
  let preview = nodeText(n);
1548
1646
  if (n.cat === "tool") {
@@ -1582,7 +1680,10 @@ window.__ModuleLoader__.load({
1582
1680
  }), rowErr);
1583
1681
  });
1584
1682
  };
1585
- return /* @__PURE__ */ React.createElement("div", { className: "lc-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, /* @__PURE__ */ React.createElement("span", { className: "lc-card-title-text" }, t("browser.title")), /* @__PURE__ */ React.createElement("span", { className: "lc-br-hint" }, t("browser.deltaHint")), /* @__PURE__ */ React.createElement("select", {
1683
+ return /* @__PURE__ */ React.createElement("div", {
1684
+ className: "lc-card",
1685
+ ref: rootRef
1686
+ }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, /* @__PURE__ */ React.createElement("span", { className: "lc-card-title-text" }, t("browser.title")), /* @__PURE__ */ React.createElement("span", { className: "lc-br-hint" }, t("browser.deltaHint")), /* @__PURE__ */ React.createElement("select", {
1586
1687
  className: "lc-br-pick",
1587
1688
  value: seq === null ? "live" : String(seq),
1588
1689
  onChange: (e) => {
@@ -1606,7 +1707,7 @@ window.__ModuleLoader__.load({
1606
1707
  })), view.missingLive > 0 ? /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, t("browser.missingLive", { n: view.missingLive })) : null, view.approximate ? /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, t("browser.approx")) : null, /* @__PURE__ */ React.createElement("div", { className: "lc-br-cats" }, CATS.map((c) => {
1607
1708
  const count = toolCount(c.key);
1608
1709
  const v = breakdown[c.key] || 0;
1609
- const prevCount = prevView !== null ? countOf(prevView, c.key) : null;
1710
+ const prevCount = prevView !== null && prevByCat !== null ? countOf(prevView, prevByCat, c.key) : null;
1610
1711
  const countDelta = prevCount !== null ? count - prevCount : null;
1611
1712
  const prevTokens = refReq !== null ? refReq[c.key] || 0 : null;
1612
1713
  const tokenDelta = prevTokens !== null ? v - prevTokens : null;
@@ -2045,6 +2146,73 @@ window.__ModuleLoader__.load({
2045
2146
  };
2046
2147
  }
2047
2148
  //#endregion
2149
+ //#region src/client/brief.ts
2150
+ /** Every served node (live tail + removed archive copies), seq-sorted. */
2151
+ function briefNodes(data) {
2152
+ return [...data.nodes, ...data.archive].sort((a, b) => a.seq - b.seq);
2153
+ }
2154
+ /** First index whose node seq is >= `seq` (lower bound over the sorted list). */
2155
+ function lowerBound(nodes, seq) {
2156
+ let lo = 0;
2157
+ let hi = nodes.length;
2158
+ while (lo < hi) {
2159
+ const mid = lo + hi >> 1;
2160
+ if (nodes[mid].seq < seq) lo = mid + 1;
2161
+ else hi = mid;
2162
+ }
2163
+ return lo;
2164
+ }
2165
+ /**
2166
+ * Derive the brief for `requests[idx]` (the DISPLAY list — step records or
2167
+ * turn aggregates; a turn aggregate is always a turn start, so its inputs row
2168
+ * stays hidden and the opener/response carry the narrative).
2169
+ */
2170
+ function briefOf(nodes, requests, idx) {
2171
+ if (idx < 0 || idx >= requests.length) return null;
2172
+ const req = requests[idx];
2173
+ const ri = lowerBound(nodes, req.seq);
2174
+ const hit = ri < nodes.length && nodes[ri].seq === req.seq ? nodes[ri] : void 0;
2175
+ const response = hit !== void 0 && hit.cat === "assistant" ? hit : void 0;
2176
+ const turnStart = idx === 0 || (requests[idx - 1].turn ?? 0) !== (req.turn ?? 0);
2177
+ let firstIdx = idx;
2178
+ while (firstIdx > 0 && (requests[firstIdx - 1].turn ?? 0) === (req.turn ?? 0)) firstIdx--;
2179
+ const upper = requests[firstIdx].seq;
2180
+ const lower = firstIdx > 0 ? requests[firstIdx - 1].seq : -1;
2181
+ let opener;
2182
+ for (let i = lowerBound(nodes, upper) - 1; i >= 0; i--) {
2183
+ const n = nodes[i];
2184
+ if (n.seq <= lower) break;
2185
+ if (n.cat === "user") {
2186
+ opener = n;
2187
+ break;
2188
+ }
2189
+ }
2190
+ const inputs = [];
2191
+ if (!turnStart) {
2192
+ const prevSeq = requests[idx - 1].seq;
2193
+ for (let i = lowerBound(nodes, prevSeq + 1); i < nodes.length && nodes[i].seq < req.seq; i++) inputs.push(nodes[i]);
2194
+ }
2195
+ return {
2196
+ opener,
2197
+ inputs,
2198
+ response
2199
+ };
2200
+ }
2201
+ /**
2202
+ * seq → one-line reply preview for the chart tooltip: the response node's
2203
+ * text, else its tool-call breadcrumb. Absent for usage-only replies and
2204
+ * steps outside retention.
2205
+ */
2206
+ function replyTipsOf(nodes) {
2207
+ const m = /* @__PURE__ */ new Map();
2208
+ for (const n of nodes) {
2209
+ if (n.cat !== "assistant") continue;
2210
+ const s = n.text ?? (n.calls !== void 0 ? n.calls.join(" › ") : "");
2211
+ if (s !== "") m.set(n.seq, s);
2212
+ }
2213
+ return m;
2214
+ }
2215
+ //#endregion
2048
2216
  //#region src/client/components/events.tsx
2049
2217
  const EVENT_ICONS = {
2050
2218
  compaction: "✂",
@@ -2181,7 +2349,7 @@ window.__ModuleLoader__.load({
2181
2349
  return function PluginInfo() {
2182
2350
  const [latest, setLatest] = React.useState(null);
2183
2351
  React.useEffect(() => {
2184
- if ("0.31.0".includes("-dev")) return;
2352
+ if ("0.32.0".includes("-dev")) return;
2185
2353
  let on = true;
2186
2354
  fetchLatestVersion().then((v) => {
2187
2355
  if (on && v) setLatest(v);
@@ -2190,8 +2358,8 @@ window.__ModuleLoader__.load({
2190
2358
  on = false;
2191
2359
  };
2192
2360
  }, []);
2193
- const update = latest !== null && isNewerVersion(latest, "0.31.0") ? latest : null;
2194
- const nameValue = ["dsh-context (v0.31.0)"];
2361
+ const update = latest !== null && isNewerVersion(latest, "0.32.0") ? latest : null;
2362
+ const nameValue = ["dsh-context (v0.32.0)"];
2195
2363
  if (update) nameValue.push(/* @__PURE__ */ React.createElement("span", {
2196
2364
  key: "update",
2197
2365
  className: "lc-pi-update"
@@ -2203,6 +2371,92 @@ window.__ModuleLoader__.load({
2203
2371
  //#region src/client/components/requestDetail.tsx
2204
2372
  function makeRequestDetail(kit, StackedBar) {
2205
2373
  const { t, fmt, fmtTime, catLabel, eventLabel, eventAt } = kit;
2374
+ /**
2375
+ * One brief row: a fixed-width kind tag plus one glanceable line. The tag carries a styled, instant explanation bubble (the
2376
+ * `.lc-stat-tip` pattern); the content span keeps the native title (preview + locate hint), so the two never stack.
2377
+ * Clickable when the browser linkage is wired.
2378
+ */
2379
+ function BriefRow(props) {
2380
+ const cls = "lc-brief-row" + (props.onLocate !== void 0 ? " lc-brief-row-link" : "");
2381
+ const inner = /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", { className: "lc-brief-tag" }, props.tag, /* @__PURE__ */ React.createElement("span", {
2382
+ className: "lc-brief-tip",
2383
+ role: "tooltip"
2384
+ }, props.tagTip)), props.children);
2385
+ if (props.onLocate === void 0) return /* @__PURE__ */ React.createElement("div", { className: cls }, inner);
2386
+ const locate = () => {
2387
+ props.onLocate?.(props.node, props.isResponse);
2388
+ };
2389
+ return /* @__PURE__ */ React.createElement("button", {
2390
+ type: "button",
2391
+ className: cls,
2392
+ onClick: locate
2393
+ }, inner);
2394
+ }
2395
+ /** One-line identity of a surface node: text preview, call breadcrumb, tool name, or a localized placeholder. */
2396
+ function nodeLine(n, conv) {
2397
+ if (n.cat === "tool") return callSummaryOf(conv) ?? n.tool ?? t("node.toolResult");
2398
+ if (n.text !== void 0 && n.text !== "") return n.text;
2399
+ if (n.skill !== void 0) return t("node.skillTag", { name: n.skill });
2400
+ if (n.calls !== void 0 && n.calls.length > 0) {
2401
+ const summary = blockSummaryOf(conv);
2402
+ return n.calls.join(" › ") + (summary !== null ? " · " + summary : "");
2403
+ }
2404
+ if (n.cat === "assistant") return t("node.empty");
2405
+ if (n.cat === "inject") return t("form." + (n.form ?? "context"));
2406
+ return t("node.nonText");
2407
+ }
2408
+ function BriefSection(props) {
2409
+ const { opener, inputs, response } = props.brief;
2410
+ if (opener === void 0 && inputs.length === 0 && response === void 0) return null;
2411
+ const convOf = props.convOf ?? (() => void 0);
2412
+ const hint = props.onLocate !== void 0 ? " — " + t("brief.locate") : "";
2413
+ const locateChip = props.onLocate === void 0 ? void 0 : (n) => (e) => {
2414
+ e?.stopPropagation();
2415
+ props.onLocate?.(n, false);
2416
+ };
2417
+ const MAX_CHIPS = 3;
2418
+ let replyText = "";
2419
+ let replyArrow = false;
2420
+ if (response !== void 0) {
2421
+ const conv = convOf(response.seq);
2422
+ replyText = nodeLine(response, conv);
2423
+ if (response.calls !== void 0 && response.calls.length > 0) replyArrow = true;
2424
+ else {
2425
+ const joined = callNamesOf(conv);
2426
+ if (joined.length > 0) replyText += " → " + joined.join(" › ");
2427
+ }
2428
+ }
2429
+ return /* @__PURE__ */ React.createElement("div", { className: "lc-brief" }, opener !== void 0 ? /* @__PURE__ */ React.createElement(BriefRow, {
2430
+ tag: t("brief.turn"),
2431
+ tagTip: t("brief.turnTip"),
2432
+ node: opener,
2433
+ isResponse: false,
2434
+ onLocate: props.onLocate
2435
+ }, /* @__PURE__ */ React.createElement("span", {
2436
+ className: "lc-brief-text",
2437
+ title: nodeLine(opener, convOf(opener.seq)) + hint
2438
+ }, nodeLine(opener, convOf(opener.seq)))) : null, inputs.length > 0 ? /* @__PURE__ */ React.createElement(BriefRow, {
2439
+ tag: t("brief.input"),
2440
+ tagTip: t("brief.inputTip"),
2441
+ node: inputs[0],
2442
+ isResponse: false,
2443
+ onLocate: props.onLocate
2444
+ }, inputs.slice(0, MAX_CHIPS).map((n) => /* @__PURE__ */ React.createElement("span", {
2445
+ key: n.seq,
2446
+ className: "lc-brief-chip" + (props.onLocate !== void 0 ? " lc-brief-chip-link" : ""),
2447
+ title: nodeLine(n, convOf(n.seq)) + hint,
2448
+ onClick: locateChip !== void 0 ? locateChip(n) : void 0
2449
+ }, n.err === true ? /* @__PURE__ */ React.createElement("span", { className: "lc-br-err-dot" }) : null, nodeLine(n, convOf(n.seq)))), inputs.length > MAX_CHIPS ? /* @__PURE__ */ React.createElement("span", { className: "lc-brief-more" }, t("brief.more", { n: inputs.length - MAX_CHIPS })) : null) : null, response !== void 0 ? /* @__PURE__ */ React.createElement(BriefRow, {
2450
+ tag: t("brief.reply"),
2451
+ tagTip: t("brief.replyTip"),
2452
+ node: response,
2453
+ isResponse: true,
2454
+ onLocate: props.onLocate
2455
+ }, /* @__PURE__ */ React.createElement("span", {
2456
+ className: "lc-brief-text",
2457
+ title: replyText + hint
2458
+ }, replyArrow ? "→ " : "", replyText)) : null);
2459
+ }
2206
2460
  return function RequestDetail(props) {
2207
2461
  const req = props.request;
2208
2462
  if (!req) return null;
@@ -2233,7 +2487,11 @@ window.__ModuleLoader__.load({
2233
2487
  return /* @__PURE__ */ React.createElement("div", { className: "lc-detail" }, /* @__PURE__ */ React.createElement("div", { className: "lc-detail-head" }, /* @__PURE__ */ React.createElement("b", null, head), marker !== null && markerAt !== null ? /* @__PURE__ */ React.createElement("span", {
2234
2488
  className: "lc-detail-marker",
2235
2489
  title: eventLabel(marker)
2236
- }, "✂ " + markerAt) : null, isTurn ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-tag" }, t("detail.lastStep")) : null, delta ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-tag" }, t("gran.delta")) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-detail-time" }, fmtTime(req.time)), delta ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-metric" + (net > 0 ? " lc-detail-metric-up" : net < 0 ? " lc-detail-metric-down" : "") }, t("tip.delta", { n: (net > 0 ? "+" : "") + fmt(net) })) : null, !delta && req.prompt !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-metric" }, t("detail.actual", { n: fmt(req.prompt) })) : null, !delta && req.output !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-metric" }, t("detail.output", { n: fmt(req.output) })) : null, !delta && req.prompt !== void 0 && req.cacheRead !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-metric" }, t("detail.cache", { n: cacheHitPercent$1(req.cacheRead, req.prompt) ?? "—" })) : null), /* @__PURE__ */ React.createElement(StackedBar, {
2490
+ }, "✂ " + markerAt) : null, isTurn ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-tag" }, t("detail.lastStep")) : null, delta ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-tag" }, t("gran.delta")) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-detail-time" }, fmtTime(req.time)), delta ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-metric" + (net > 0 ? " lc-detail-metric-up" : net < 0 ? " lc-detail-metric-down" : "") }, t("tip.delta", { n: (net > 0 ? "+" : "") + fmt(net) })) : null, !delta && req.prompt !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-metric" }, t("detail.actual", { n: fmt(req.prompt) })) : null, !delta && req.output !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-metric" }, t("detail.output", { n: fmt(req.output) })) : null, !delta && req.prompt !== void 0 && req.cacheRead !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-metric" }, t("detail.cache", { n: cacheHitPercent$1(req.cacheRead, req.prompt) ?? "—" })) : null), props.brief !== null && props.brief !== void 0 ? /* @__PURE__ */ React.createElement(BriefSection, {
2491
+ brief: props.brief,
2492
+ convOf: props.convOf,
2493
+ onLocate: props.onLocate
2494
+ }) : null, /* @__PURE__ */ React.createElement(StackedBar, {
2237
2495
  parts,
2238
2496
  height: 10
2239
2497
  }), /* @__PURE__ */ React.createElement("div", { className: "lc-detail-rows" }, CATS.map((c, i) => {
@@ -2371,6 +2629,15 @@ window.__ModuleLoader__.load({
2371
2629
  const writes = numOf(usage.cacheWriteTokens);
2372
2630
  return cacheHitPercent$1(reads, uncached + reads + writes);
2373
2631
  }
2632
+ function cell(label, value, tip) {
2633
+ return /* @__PURE__ */ React.createElement("div", { className: "lc-stat" + (tip === void 0 ? "" : " lc-stat-tipped") }, /* @__PURE__ */ React.createElement("span", { className: "lc-stat-label" }, label, tip !== void 0 && /* @__PURE__ */ React.createElement("i", {
2634
+ className: "lc-stat-q",
2635
+ "aria-hidden": "true"
2636
+ }, "?")), /* @__PURE__ */ React.createElement("b", { className: "lc-stat-value" }, value), tip !== void 0 && /* @__PURE__ */ React.createElement("span", {
2637
+ className: "lc-stat-tip",
2638
+ role: "tooltip"
2639
+ }, tip));
2640
+ }
2374
2641
  function makeStatsBoard(kit) {
2375
2642
  const { t, fmt } = kit;
2376
2643
  return function StatsBoard(props) {
@@ -2394,13 +2661,6 @@ window.__ModuleLoader__.load({
2394
2661
  key: r.family,
2395
2662
  className: "lc-stat-tip-row"
2396
2663
  }, /* @__PURE__ */ React.createElement("b", { className: "lc-stat-tip-model" }, r.family), " ", t("stats.costHit"), " ", fmtRate(r.peak.hit), "/", fmtRate(r.off.hit), " · ", t("stats.costMiss"), " ", fmtRate(r.peak.miss), "/", fmtRate(r.off.miss), " · ", t("stats.costOut"), " ", fmtRate(r.peak.out), "/", fmtRate(r.off.out))))];
2397
- const cell = (label, value, tip) => /* @__PURE__ */ React.createElement("div", { className: "lc-stat" + (tip === void 0 ? "" : " lc-stat-tipped") }, /* @__PURE__ */ React.createElement("span", { className: "lc-stat-label" }, label, tip !== void 0 && /* @__PURE__ */ React.createElement("i", {
2398
- className: "lc-stat-q",
2399
- "aria-hidden": "true"
2400
- }, "?")), /* @__PURE__ */ React.createElement("b", { className: "lc-stat-value" }, value), tip !== void 0 && /* @__PURE__ */ React.createElement("span", {
2401
- className: "lc-stat-tip",
2402
- role: "tooltip"
2403
- }, tip));
2404
2664
  return /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col lc-col-stats" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, /* @__PURE__ */ React.createElement("span", { className: "lc-card-title-text" }, t("stats.title")), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("stats.hint"))), /* @__PURE__ */ React.createElement("div", { className: "lc-stats" }, cell(t("stats.turns"), fmt(turns.size)), cell(t("stats.steps"), fmt(steps)), cell(t("stats.injects"), fmt(injects)), cell(t("stats.compactions"), fmt(compactions)), cell(t("stats.prunes"), fmt(prunes)), cell(t("stats.toolCalls"), fmt(props.toolCalls ?? 0)), cell(t("stats.images"), fmt(props.images ?? 0)), cell(t("stats.cacheHit"), hit === null ? "—" : hit + "%"), cell(t("stats.cost"), cost === null ? "—" : formatCost(cost, currency), costTip)));
2405
2665
  };
2406
2666
  }
@@ -2461,7 +2721,7 @@ window.__ModuleLoader__.load({
2461
2721
  * provider prompt/output are dropped (they are not deltas).
2462
2722
  */
2463
2723
  const deltaOf = (req, prev) => {
2464
- const out = { ...req };
2724
+ const { prompt: _prompt, output: _output, ...out } = req;
2465
2725
  let churn = 0;
2466
2726
  let net = 0;
2467
2727
  for (const c of CATS) {
@@ -2472,8 +2732,6 @@ window.__ModuleLoader__.load({
2472
2732
  }
2473
2733
  out.total = churn;
2474
2734
  out.net = net;
2475
- delete out.prompt;
2476
- delete out.output;
2477
2735
  return out;
2478
2736
  };
2479
2737
  const ChartBar = React.memo(function ChartBar(props) {
@@ -2664,11 +2922,13 @@ window.__ModuleLoader__.load({
2664
2922
  t: req.turn ?? 0,
2665
2923
  s: req.step ?? 0
2666
2924
  });
2925
+ const reply = props.replyTips?.get(req.seq);
2926
+ const tail = reply !== void 0 ? " · “" + (reply.length > 48 ? reply.slice(0, 48) + "…" : reply) + "”" : "";
2667
2927
  if (delta) {
2668
2928
  const n = req.net ?? 0;
2669
- return head + " · " + fmtTime(req.time) + " · " + t("tip.delta", { n: (n > 0 ? "+" : "") + fmt(n) });
2929
+ return head + " · " + fmtTime(req.time) + " · " + t("tip.delta", { n: (n > 0 ? "+" : "") + fmt(n) }) + tail;
2670
2930
  }
2671
- return head + " · " + fmtTime(req.time) + " · " + t("tip.total", { n: fmt(req.total) }) + (req.prompt !== void 0 ? " · " + t("tip.actual", { n: fmt(req.prompt) }) : "");
2931
+ return head + " · " + fmtTime(req.time) + " · " + t("tip.total", { n: fmt(req.total) }) + (req.prompt !== void 0 ? " · " + t("tip.actual", { n: fmt(req.prompt) }) : "") + tail;
2672
2932
  };
2673
2933
  const hoveredIdx = props.hoveredSeq !== null ? requests.findIndex((r) => r.seq === props.hoveredSeq) : -1;
2674
2934
  const hoveredReq = hoveredIdx >= 0 ? requests[hoveredIdx] : null;
@@ -2763,7 +3023,6 @@ window.__ModuleLoader__.load({
2763
3023
  const [selectedSeq, setSelectedSeq] = React.useState(null);
2764
3024
  const [hoveredSeq, setHoveredSeq] = React.useState(null);
2765
3025
  const [hoverTurn, setHoverTurn] = React.useState(null);
2766
- const [tick, setTick] = React.useState(0);
2767
3026
  const [granularity, setGranularity] = React.useState(() => settings.defaultGranularity());
2768
3027
  const [trendMode, setTrendMode] = React.useState(() => settings.defaultTrendMode());
2769
3028
  const [focusTurn, setFocusTurn] = React.useState(null);
@@ -2780,6 +3039,10 @@ window.__ModuleLoader__.load({
2780
3039
  const clearToolFocus = React.useCallback(() => {
2781
3040
  setToolFocus(null);
2782
3041
  }, []);
3042
+ const [nodeFocus, setNodeFocus] = React.useState(null);
3043
+ const clearNodeFocus = React.useCallback(() => {
3044
+ setNodeFocus(null);
3045
+ }, []);
2783
3046
  const loadImage = React.useMemo(() => {
2784
3047
  if (typeof sessionId !== "string" || sessionId === "") return void 0;
2785
3048
  const conversation = ctx.get("conversation");
@@ -2806,19 +3069,20 @@ window.__ModuleLoader__.load({
2806
3069
  viewScroll.set(sessionId, scroller.scrollTop);
2807
3070
  };
2808
3071
  }, [sessionId]);
2809
- React.useEffect(() => {
2810
- const localeSvc = ctx.get("locale");
2811
- if (!localeSvc) return void 0;
2812
- return localeSvc.subscribe(() => {
2813
- setTick((x) => x + 1);
2814
- });
2815
- }, []);
2816
3072
  const requests = data ? data.requests : [];
2817
3073
  const events = data ? data.events : [];
2818
3074
  const shownEvents = pickedKinds.length === EVENT_KINDS.length ? events : events.filter((e) => pickedKinds.includes(e.kind));
2819
3075
  const nodes = data ? data.nodes : [];
2820
3076
  const displayRequests = React.useMemo(() => granularity === "turn" ? aggregateByTurn(requests) : requests, [requests, granularity]);
2821
3077
  const markers = React.useMemo(() => attachMarkers(displayRequests, events), [displayRequests, events]);
3078
+ const briefList = React.useMemo(() => data ? briefNodes(data) : [], [data]);
3079
+ const replyTips = React.useMemo(() => replyTipsOf(briefList), [briefList]);
3080
+ const convNodes = typeof props.useSession === "function" ? props.useSession((s) => s.nodes) : void 0;
3081
+ const bySeq = React.useMemo(() => {
3082
+ const m = /* @__PURE__ */ new Map();
3083
+ for (const n of convNodes ?? []) m.set(n.seq, n);
3084
+ return m;
3085
+ }, [convNodes]);
2822
3086
  if (!data) return /* @__PURE__ */ React.createElement("div", {
2823
3087
  className: "lc-root",
2824
3088
  ref: rootRef
@@ -2840,6 +3104,18 @@ window.__ModuleLoader__.load({
2840
3104
  if (activeIdx < 0) activeIdx = pinnedIdx;
2841
3105
  if (activeIdx < 0 && displayRequests.length > 0) activeIdx = displayRequests.length - 1;
2842
3106
  const activeReq = activeIdx >= 0 ? displayRequests[activeIdx] : null;
3107
+ const brief = activeReq !== null ? briefOf(briefList, displayRequests, activeIdx) : null;
3108
+ const convOf = (seq) => bySeq.get(seq);
3109
+ const locateNode = (node, isResponse) => {
3110
+ if (activeReq === null) return;
3111
+ const next = isResponse && activeIdx + 1 < displayRequests.length ? displayRequests[activeIdx + 1] : null;
3112
+ const step = isResponse ? next !== null ? next.seq : "live" : activeReq.seq;
3113
+ setNodeFocus({
3114
+ step,
3115
+ seq: node.seq,
3116
+ cat: node.cat
3117
+ });
3118
+ };
2843
3119
  let activeTurn = hoverTurn;
2844
3120
  if (activeTurn === null && hoveredSeq !== null) {
2845
3121
  for (const req of displayRequests) if (req.seq === hoveredSeq) {
@@ -2910,11 +3186,15 @@ window.__ModuleLoader__.load({
2910
3186
  },
2911
3187
  onFocusTurnHandled: () => {
2912
3188
  setFocusTurn(null);
2913
- }
3189
+ },
3190
+ replyTips
2914
3191
  }), /* @__PURE__ */ React.createElement(RequestDetail, {
2915
3192
  request: activeReq,
2916
3193
  prev: trendMode === "delta" && activeIdx >= 0 ? activeIdx > 0 ? displayRequests[activeIdx - 1] : null : void 0,
2917
- marker: activeReq !== null ? markerOf(activeReq) : void 0
3194
+ marker: activeReq !== null ? markerOf(activeReq) : void 0,
3195
+ brief,
3196
+ convOf,
3197
+ onLocate: locateNode
2918
3198
  })))), /* @__PURE__ */ React.createElement("div", { className: "lc-col lc-col-browser" }, /* @__PURE__ */ React.createElement(ContextBrowser, {
2919
3199
  data,
2920
3200
  headers,
@@ -2926,6 +3206,8 @@ window.__ModuleLoader__.load({
2926
3206
  onHoverKey: setHoverCat,
2927
3207
  toolFocus,
2928
3208
  onToolFocusHandled: clearToolFocus,
3209
+ nodeFocus,
3210
+ onNodeFocusHandled: clearNodeFocus,
2929
3211
  loadImage
2930
3212
  }))), /* @__PURE__ */ React.createElement("div", { className: "lc-cols" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, /* @__PURE__ */ React.createElement("span", { className: "lc-card-title-text" }, t("events.title")), /* @__PURE__ */ React.createElement("div", { className: "lc-kinds" }, EVENT_KINDS.map((k) => /* @__PURE__ */ React.createElement("button", {
2931
3213
  key: k,
@@ -2957,7 +3239,7 @@ window.__ModuleLoader__.load({
2957
3239
  }
2958
3240
  //#endregion
2959
3241
  //#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles.css.mjs
2960
- const css = ".lc-root{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-primary);padding:16px 20px 32px;font-size:13px;overflow-y:auto}.lc-card{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;margin-bottom:14px;padding:14px 16px}.lc-card-title{align-items:baseline;gap:8px;margin-bottom:10px;font-weight:600;display:flex}.lc-card-title-text{white-space:nowrap;flex:none}.lc-stats{grid-template-columns:repeat(auto-fit,minmax(62px,1fr));gap:6px;display:grid}.lc-stat{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex-direction:column;gap:2px;min-width:0;padding:6px;display:flex}.lc-stat-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;font-weight:600;overflow:hidden}.lc-stat-value{color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;text-align:center;font-size:14px;font-weight:600;overflow:hidden}.lc-stat-sub{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;overflow:hidden}.lc-stat-tipped{position:relative}.lc-stat-q{text-align:center;width:11px;height:11px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);cursor:help;border-radius:50%;margin-left:4px;font-size:9px;font-style:normal;font-weight:700;line-height:11px;display:inline-block}.lc-stat-tipped:hover .lc-stat-q{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary)}.lc-stat-tip{z-index:6;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;max-width:280px;color:var(--dsw-alias-label-primary);pointer-events:none;opacity:0;border-radius:6px;padding:6px 10px;font-size:12px;font-weight:400;line-height:1.5;transition:opacity .12s;position:absolute;top:calc(100% + 6px);left:0;box-shadow:0 2px 8px #0000002e}.lc-stat-tipped:hover .lc-stat-tip{opacity:1}.lc-stat-tip-prices{border-top:1px dashed var(--dsw-alias-border-l1);margin-top:5px;padding-top:5px;display:block}.lc-stat-tip-head{font-weight:600;display:block}.lc-stat-tip-row{margin-top:2px;display:block}.lc-stat-tip-model{color:var(--dsw-alias-label-primary)}.lc-card-sub{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:400}.lc-gran,.lc-kinds{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;gap:2px;margin-left:auto;padding:1px;display:flex}.lc-trend-ctl{align-items:center;gap:6px;margin-left:auto;display:flex}.lc-trend-ctl .lc-gran{margin-left:0}.lc-gran-btn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:5px;padding:3px 8px;font-family:inherit;font-size:11px;line-height:1}.lc-gran-btn:hover{color:var(--dsw-alias-label-primary)}.lc-gran-on,.lc-gran-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.lc-settings-card{background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;transition:border-color .16s,background .16s}.lc-settings-card:hover{border-color:var(--dsw-alias-label-dimmed)}.lc-settings-open,.lc-settings-open:hover{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.lc-settings-head{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.lc-settings-headtext{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.lc-settings-name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.lc-settings-desc{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.lc-settings-chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.lc-settings-open .lc-settings-chevron{transform:rotate(180deg)}.lc-settings-body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding:4px 0 12px}.lc-settings-row{align-items:center;gap:8px;padding:8px 0;display:flex}.lc-settings-label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:14px}.lc-settings-select{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.lc-settings-select:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.lc-settings-select:disabled{opacity:.5;cursor:default}.lc-settings-note{color:var(--dsw-alias-label-tertiary);margin:12px 0 4px;font-size:12px;line-height:1.5}.lc-overview-num{align-items:baseline;gap:6px;margin-bottom:8px;display:flex}.lc-overview-num>b{font-size:20px}.lc-overview-num span{color:var(--dsw-alias-label-secondary)}.lc-overview-pct{margin-left:auto;font-size:11px}.lc-overview-pct b{color:var(--dsw-alias-label-primary);margin-right:4px;font-size:20px}.lc-stacked-wrap{width:100%;position:relative}.lc-stacked{background:#8080802e;border-radius:5px;width:100%;display:flex;position:relative;overflow:hidden}.lc-occupied-box{border:2px solid var(--dsw-alias-label-tertiary);box-sizing:border-box;pointer-events:none;opacity:0;box-shadow:0 0 0 1px var(--dsw-alias-bg-layer-2);border-radius:5px;transition:opacity .12s;position:absolute;top:0;bottom:0;left:0}.lc-occupied-box-on{opacity:1}.lc-bar-tip{z-index:5;white-space:nowrap;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);pointer-events:none;opacity:0;border-radius:6px;padding:3px 8px;font-size:12px;transition:opacity .12s;position:absolute;bottom:calc(100% + 6px);transform:translate(-50%);box-shadow:0 2px 8px #0000002e}.lc-bar-tip-on{opacity:1}.lc-stacked>div{height:100%}.lc-stacked-seg{transition:filter .12s,opacity .12s}.lc-stacked-free{box-sizing:border-box;transition:box-shadow .12s,opacity .12s}.lc-stacked-seg-on{filter:brightness(1.18)}.lc-reserve{z-index:1;pointer-events:auto;cursor:help;background:repeating-linear-gradient(45deg, color-mix(in srgb, var(--dsw-alias-state-warn-primary) 24%, transparent) 0 5px, transparent 5px 10px);position:absolute;top:0;bottom:0}.lc-stacked-free-on{border:2px dashed var(--dsw-alias-label-secondary);border-radius:3px}.lc-stacked-dim .lc-stacked-seg{opacity:.35}.lc-stacked-dim .lc-stacked-seg-on{opacity:1}.lc-stacked-dim .lc-stacked-free{opacity:.35}.lc-stacked-dim .lc-stacked-free-on{opacity:1}.lc-legend{grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:6px 14px;margin-top:10px;display:grid}.lc-chip{min-width:0;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:5px;padding:1px 6px;transition:background-color .12s;display:flex}.lc-chip-label{white-space:nowrap;text-overflow:ellipsis;min-width:0;font-weight:600;overflow:hidden}.lc-chip-nums{white-space:nowrap;flex:none;align-items:baseline;gap:6px;margin-left:auto;display:inline-flex}.lc-chip i,.lc-detail-row i,.lc-node i{border-radius:2px;width:8px;height:8px;display:inline-block}.lc-chip i{transition:box-shadow .12s}.lc-chip em{color:var(--dsw-alias-label-secondary);font-style:normal}.lc-chip-on{background:var(--dsw-alias-interactive-bg-hover);font-weight:600}.lc-chip-on i{box-shadow:0 0 0 1px var(--dsw-alias-brand-primary)}.lc-tools{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;align-items:center;gap:6px;margin-top:10px;display:flex}.lc-tools-label,.lc-tools-more{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;padding:0;font-family:inherit;font-size:12px}.lc-tools-label:hover,.lc-tools-more:hover{text-decoration:underline}.lc-tool-chip{background:var(--dsw-alias-bg-layer-2);font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:0;border-radius:4px;padding:1px 7px;font-size:12px}.lc-tool-chip:hover{text-decoration:underline}.lc-chartrow{align-items:stretch;gap:6px;display:flex}.lc-axis{box-sizing:border-box;width:40px;height:150px;color:var(--dsw-alias-label-secondary);padding-top:18px;font-size:11px;position:relative}.lc-axis span{line-height:1;position:absolute;right:0}.lc-axis-top{top:13px}.lc-axis-mid{top:69px}.lc-axis-bot{top:125px}.lc-chart-scroll{scrollbar-width:thin;flex:1;min-width:0;padding-bottom:8px;position:relative;overflow:auto hidden}.lc-chart-fade{pointer-events:none;z-index:2;width:26px;position:absolute;top:0;bottom:0}.lc-chart-fade-l{background:linear-gradient(to right, var(--dsw-alias-bg-layer-1), transparent);left:0}.lc-chart-fade-r{background:linear-gradient(to left, var(--dsw-alias-bg-layer-1), transparent);right:0}.lc-chart{box-sizing:border-box;align-items:flex-end;gap:2px;width:max-content;min-width:100%;height:130px;padding-top:18px;display:flex;position:relative}.lc-grid{border-top:1px dashed var(--dsw-alias-border-l1);pointer-events:none;position:absolute;left:0;right:0}.lc-grid-top{top:18px}.lc-grid-mid{top:74px}.lc-grid-zero{border-top-style:solid;border-top-color:#80808080}.lc-bar{cursor:pointer;border-radius:2px;flex:none;align-items:flex-end;width:14px;height:100%;transition:opacity .12s,background-color .12s;display:flex;position:relative}.lc-chart-dim .lc-bar{opacity:.35}.lc-chart-dim .lc-bar-in-turn{opacity:1}.lc-chart-dim .lc-turn{opacity:.35}.lc-chart-dim .lc-turn-on{opacity:1}.lc-chart-tip{z-index:5;white-space:nowrap;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;padding:3px 8px;font-size:12px;position:absolute;top:0;transform:translate(-50%);box-shadow:0 2px 8px #0000002e}.lc-bar:hover{background:var(--dsw-alias-bg-layer-2)}.lc-bar-hovered{outline:1px dashed var(--dsw-alias-brand-primary);outline-offset:1px}.lc-bar-selected{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.lc-bar-in-turn{background:#80808024}.lc-bar-stack{flex-direction:column-reverse;width:100%;display:flex}.lc-bar-stack>div{width:100%}.lc-bar-up,.lc-bar-down{width:100%;display:flex;position:absolute;left:0}.lc-bar-up{flex-direction:column-reverse}.lc-bar-down{flex-direction:column}.lc-bar-up>div,.lc-bar-down>div{width:100%}.lc-bar-marker{color:var(--dsw-alias-state-warn-primary);font-size:11px;position:absolute;top:-16px;left:50%;transform:translate(-50%)}.lc-turns{gap:2px;width:max-content;min-width:100%;margin-top:4px;display:flex}.lc-turn{box-sizing:border-box;text-align:center;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;cursor:pointer;border-radius:3px;flex:none;height:14px;font-size:10px;font-weight:600;line-height:14px;transition:filter .12s,opacity .12s;overflow:hidden}.lc-turn-on{filter:brightness(1.35);color:var(--dsw-alias-label-primary)}.lc-turn-label{text-overflow:ellipsis;max-width:100%;display:inline-block;overflow:hidden}.lc-detail{border-top:1px solid var(--dsw-alias-border-l1);margin-top:12px;padding-top:12px}.lc-detail-head{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;align-items:center;gap:6px 8px;margin-bottom:10px;display:flex}.lc-detail-head b{color:var(--dsw-alias-label-primary);font-size:13px}.lc-detail-time{font-variant-numeric:tabular-nums;white-space:nowrap;margin-left:auto;font-size:12px}.lc-detail-marker{color:var(--dsw-alias-state-warn-primary);background:color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);border-radius:6px;padding:1px 7px;font-size:11px}.lc-detail-tag{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:4px;padding:0 6px;font-size:11px}.lc-detail-metric{font-variant-numeric:tabular-nums;white-space:nowrap;color:var(--dsw-alias-label-primary);background:color-mix(in srgb, var(--dsw-alias-label-secondary) 14%, transparent);border-radius:6px;padding:2px 8px;font-size:12px;font-weight:600}.lc-detail-metric-up{color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 15%, transparent)}.lc-detail-metric-down{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 15%, transparent)}.lc-detail-rows{grid-template-columns:1fr 1fr;gap:4px 24px;margin-top:10px;display:grid}.lc-detail-row{align-items:center;gap:8px;display:flex}.lc-detail-label{white-space:nowrap;min-width:70px;color:var(--dsw-alias-label-secondary)}.lc-bar-track{background:#8080802e;border-radius:3px;flex:1;height:5px;display:block;position:relative;overflow:hidden}.lc-bar-fill{border-radius:3px;height:100%;display:block}.lc-bar-zero{border-left:1px solid #80808073;position:absolute;top:0;bottom:0;left:50%}.lc-bar-fill-up,.lc-bar-fill-down{height:100%;display:block;position:absolute;top:0}.lc-bar-fill-up{border-radius:0 3px 3px 0;left:50%}.lc-bar-fill-down{border-radius:3px 0 0 3px;right:50%}.lc-detail-num{text-align:right;width:44px}.lc-detail-num-up,.lc-detail-num-down{font-variant-numeric:tabular-nums;width:52px}.lc-detail-num-up{color:var(--dsw-alias-state-success-primary)}.lc-detail-num-down{color:var(--dsw-alias-state-error-primary)}.lc-detail-pct{text-align:right;width:34px;color:var(--dsw-alias-label-secondary)}.lc-cols{flex-wrap:wrap;gap:14px;margin-bottom:14px;display:flex}.lc-col{flex:1;min-width:280px}.lc-cols>.lc-card,.lc-col>.lc-card:last-child{margin-bottom:0}.lc-col-browser{flex-direction:column;display:flex}.lc-col-browser>.lc-card{flex:1}.lc-head>.lc-card:first-child{flex:7 1 0;min-width:360px}.lc-head>.lc-card:last-child{flex:3 1 0;min-width:220px}.lc-pi-grid{grid-template-columns:1fr;gap:8px;display:grid}.lc-pi-row{min-width:0;color:inherit;flex-direction:row;justify-content:space-between;align-items:baseline;gap:12px;text-decoration:none;display:flex}.lc-pi-row:hover .lc-pi-value{text-decoration:underline}.lc-pi-update{color:var(--dsw-alias-state-warn-primary);white-space:nowrap;margin-left:6px;font-size:11px}.lc-pi-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;flex:none;font-size:11px;font-weight:600;overflow:hidden}.lc-pi-value{min-width:0;color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;text-align:right;font-size:13px;font-weight:600;overflow:hidden}.lc-events,.lc-nodes{flex-direction:column;gap:2px;max-height:320px;display:flex;overflow-y:auto}.lc-event{align-items:center;gap:8px;padding:3px 0;display:flex}.lc-event-icon{text-align:center;width:18px;color:var(--dsw-alias-state-warn-primary)}.lc-event-icon.lc-event-inject{color:#a855f7}.lc-event-icon.lc-event-model{color:var(--dsw-alias-brand-primary)}.lc-event-icon.lc-event-mode{color:var(--dsw-alias-label-secondary)}.lc-kind{white-space:nowrap;border-radius:4px;flex:none;padding:1px 6px;font-size:10px;font-weight:600}.lc-kind-inject{background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 15%, transparent);color:var(--dsw-alias-state-success-primary)}.lc-kind-compaction{background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 15%, transparent);color:var(--dsw-alias-state-error-primary)}.lc-kind-prune{color:#8b5cf6;background:#8b5cf626}.lc-kind-model{background:color-mix(in srgb, var(--dsw-alias-brand-primary) 15%, transparent);color:var(--dsw-alias-brand-primary)}.lc-kind-mode{background:color-mix(in srgb, var(--dsw-alias-label-secondary) 15%, transparent);color:var(--dsw-alias-label-secondary)}.lc-event-label{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.lc-event-at{color:var(--dsw-alias-label-secondary);white-space:nowrap;flex:none;font-size:11px}.lc-event-tokens{color:var(--dsw-alias-state-success-primary);white-space:nowrap;font-weight:600}.lc-event-tokens.lc-up{color:var(--dsw-alias-state-warn-primary)}.lc-event-time{color:var(--dsw-alias-label-secondary);font-size:12px}.lc-node{align-items:center;gap:8px;padding:3px 0;display:flex}.lc-node-preview{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);flex:1;overflow:hidden}.lc-node-time{color:var(--dsw-alias-label-secondary);text-align:right;min-width:54px;font-size:12px}.lc-node-tokens{color:var(--dsw-alias-label-secondary)}.lc-nodes-more{color:var(--dsw-alias-label-secondary);padding:3px 0}.lc-empty{color:var(--dsw-alias-label-secondary);text-align:center;padding:18px 0}.lc-error{flex-direction:column;align-items:center;gap:8px;padding:40px 16px;display:flex}.lc-error-msg{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);overflow-wrap:anywhere;border-radius:6px;max-width:100%;padding:4px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.lc-error-retry{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:6px;padding:4px 14px;font-size:12px}.lc-error-retry:hover{border-color:var(--dsw-alias-label-primary)}.lc-foot{color:var(--dsw-alias-label-secondary);margin-top:4px;font-size:12px}.lc-modal-backdrop{z-index:200;background:#00000073;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.lc-modal-card{box-sizing:border-box;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);width:min(720px,100vw - 48px);max-height:min(82vh,760px);box-shadow:var(--dsw-shadow-lv3,0 12px 32px #0006);color:var(--dsw-alias-label-primary);border-radius:12px;padding:16px 18px 18px;font-size:13px;overflow-y:auto}.lc-modal-head{align-items:baseline;gap:8px;margin-bottom:12px;display:flex}.lc-modal-title{font-size:14px;font-weight:600}.lc-modal-close{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:6px;margin-left:auto;padding:2px 6px;font-family:inherit;font-size:18px;line-height:1}.lc-modal-close:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.lc-br-hint{color:var(--dsw-alias-label-secondary);white-space:nowrap;margin-left:auto;font-size:11px;font-weight:400}.lc-br-pick{font:inherit;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;max-width:240px;padding:3px 6px;font-size:12px}.lc-br-meta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:6px 16px;margin-bottom:8px;display:flex}.lc-br-meta b{color:var(--dsw-alias-label-primary)}.lc-br-meta .lc-actual{color:var(--dsw-alias-state-success-primary)}.lc-br-note{color:var(--dsw-alias-label-secondary);margin-top:8px;font-size:12px}.lc-br-cats{flex-direction:column;gap:4px;margin-top:10px;display:flex}.lc-br-cat{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);border-radius:8px;overflow:hidden}.lc-br-cat-empty{opacity:.55}.lc-br-cat-row{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:0;align-items:center;gap:8px;padding:7px 10px;transition:background-color .12s;display:flex}.lc-br-cat-row:hover,.lc-br-cat-on{background:var(--dsw-alias-interactive-bg-hover)}.lc-br-cat-on i{box-shadow:0 0 0 1px var(--dsw-alias-brand-primary)}.lc-br-cat-row i{border-radius:2px;flex:none;width:8px;height:8px;transition:box-shadow .12s;display:inline-block}.lc-br-cat-label{font-weight:600}.lc-br-cat-count{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:12px}.lc-br-count-grp{flex:1;align-items:center;gap:4px;min-width:0;display:inline-flex}.lc-br-chev{width:12px;color:var(--dsw-alias-label-secondary);flex:none;transition:transform .12s}.lc-br-chev-on{transform:rotate(90deg)}.lc-br-tokens{color:var(--dsw-alias-label-secondary);flex:none;font-size:12px}.lc-br-delta,.lc-br-tdelta{white-space:nowrap;border-radius:4px;flex:none;padding:0 5px;font-size:11px;font-weight:600}.lc-br-delta-up,.lc-br-tdelta-up{color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 15%, transparent)}.lc-br-delta-down,.lc-br-tdelta-down{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 15%, transparent)}.lc-br-tokens-grp{flex:none;align-items:center;gap:4px;min-width:0;display:inline-flex}.lc-br-pct{text-align:right;width:36px;color:var(--dsw-alias-label-secondary);flex:none;font-size:12px}.lc-br-body{border-top:1px solid var(--dsw-alias-border-l1);flex-direction:column;gap:2px;padding:4px 6px;display:flex}.lc-br-elem{border-radius:6px}.lc-br-elem-on{background:var(--dsw-alias-interactive-bg-active)}.lc-br-elem-row{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:0;border-radius:6px;align-items:center;gap:8px;padding:5px 6px;font-size:12px;transition:background-color .12s;display:flex}.lc-br-elem-row:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-br-err-dot{background:var(--dsw-alias-state-error-primary);width:6px;height:6px;box-shadow:0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);border-radius:50%;flex:none}.lc-br-tag{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);text-overflow:ellipsis;white-space:nowrap;border-radius:4px;flex:none;max-width:220px;padding:0 6px;font-size:11px;overflow:hidden}.lc-br-preview{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.lc-br-time{color:var(--dsw-alias-label-secondary);flex:none;font-size:11px}.lc-br-content{flex-direction:column;gap:6px;padding:2px 6px 8px 26px;display:flex}.lc-br-dim{color:var(--dsw-alias-label-secondary)}.lc-ts-card{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;min-width:0;overflow:hidden}.lc-ts-card-head{color:var(--dsw-alias-label-secondary);border-bottom:1px solid var(--dsw-alias-border-l1);align-items:center;gap:8px;padding:6px 10px;font-size:11px;font-weight:600;display:flex}.lc-ts-card-head b{color:var(--dsw-alias-label-primary)}.lc-ts-call-name{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px}.lc-ts-card-count{margin-left:auto}.lc-ts-card-right{align-items:center;gap:8px;margin-left:auto;display:inline-flex}.lc-ts-card-meta{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-variant-numeric:tabular-nums;font-size:11px;font-weight:400}.lc-ts-call-state{white-space:nowrap;border-radius:999px;flex:none;align-items:center;gap:4px;padding:2px 7px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;font-weight:600;line-height:1;display:inline-flex}.lc-ts-call-state i{background:currentColor;border-radius:50%;flex:none;width:6px;height:6px}.lc-ts-call-ok{color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 12%, transparent)}.lc-ts-call-err{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.lc-ts-desc-body{color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;scrollbar-width:thin;max-height:320px;margin:0;padding:8px 10px;font-size:12px;line-height:1.55;overflow-y:auto}.lc-ts-param-row{border-top:1px solid var(--dsw-alias-border-l1);grid-template-columns:140px 90px 56px 1fr;align-items:baseline;gap:2px 10px;padding:6px 10px;font-size:12px;display:grid}.lc-ts-param-row:first-of-type{border-top:0}.lc-ts-param-name{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-weight:600;overflow:hidden}.lc-ts-param-type{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;overflow:hidden}.lc-ts-param-req{color:var(--dsw-alias-state-warn-primary);font-size:11px;font-weight:600}.lc-ts-param-req-off{color:var(--dsw-alias-label-secondary);font-size:11px}.lc-ts-param-desc{color:var(--dsw-alias-label-secondary);grid-column:1/-1;line-height:1.5}.lc-ts-params-empty{color:var(--dsw-alias-label-secondary);padding:8px 10px;font-size:12px}.lc-ts-arg-row{border-top:1px solid var(--dsw-alias-border-l1);grid-template-columns:minmax(0,96px) 1fr;align-items:start;column-gap:12px;padding:6px 10px;font-size:12px;display:grid}.lc-ts-arg-row:first-of-type{border-top:0}.lc-ts-arg-row .lc-ts-param-name{text-overflow:unset;white-space:normal;overflow-wrap:anywhere;overflow:visible}.lc-ts-arg-val{color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;scrollbar-width:thin;max-height:200px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.55;overflow-y:auto}.lc-ts-json{flex-direction:column;gap:4px;display:flex}.lc-ts-json-toggle{color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border:0;align-self:flex-start;padding:0;font-size:11px}.lc-ts-json-toggle:hover{color:var(--dsw-alias-label-primary);text-decoration:underline}.lc-rich-seg{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;gap:2px;margin-left:auto;padding:1px;display:flex}.lc-rich-seg-btn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:5px;padding:3px 8px;font-family:inherit;font-size:11px;line-height:1}.lc-rich-seg-btn:hover{color:var(--dsw-alias-label-primary)}.lc-rich-seg-on,.lc-rich-seg-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.lc-ts-desc-md{color:var(--dsw-alias-label-primary);word-break:break-word;overflow-wrap:anywhere;white-space:pre-line;scrollbar-width:thin;min-width:0;max-height:320px;padding:4px 10px;font-size:12px;line-height:1.55;overflow:hidden auto}.lc-ts-desc-md>div{font-size:13px;line-height:1.55}.lc-ts-desc-md div :is(h1,h2,h3,h4,h5,h6){margin:10px 0 4px;font-size:13px;font-weight:600}.lc-ts-desc-md div p{margin:6px 0}.lc-ts-desc-md div pre{white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word;margin:6px 0}.lc-ts-desc-md div :not(pre)>code{box-decoration-break:clone;padding:1px 5px;line-height:1.3;font-size:1em!important}.lc-ts-desc-md div table code{font-size:inherit}.lc-att-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;padding:8px 10px;display:grid}.lc-att-item{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l1);width:100%;min-width:0;font:inherit;text-align:left;cursor:pointer;background:0 0;border-radius:8px;align-items:center;gap:8px;padding:6px;display:flex}.lc-att-item:hover{border-color:var(--dsw-alias-border-l2,var(--dsw-alias-border-l1));background:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-2))}.lc-att-thumb{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:6px;flex:none;justify-content:center;align-items:center;width:64px;height:64px;padding:0;display:flex;overflow:hidden}.lc-att-thumb img{object-fit:cover;width:100%;height:100%;display:block}.lc-att-ph,.lc-att-err{color:var(--dsw-alias-label-secondary);text-align:center;padding:2px;font-size:10px}.lc-att-meta{flex-direction:column;gap:2px;min-width:0;display:flex}.lc-att-name{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;word-break:break-word;font-size:12px;line-height:1.3}.lc-att-row{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;font-size:11px}.lc-att-row-label{min-width:3.2em;font-weight:400;display:inline-block}.lc-att-lightbox{z-index:1000;place-items:center;padding:40px;display:grid;position:fixed;inset:0}.lc-att-lightbox-mask{background:var(--dsw-alias-bg-mask-1,#00000073);backdrop-filter:var(--dsw-mask-blur,blur(2px));position:absolute;inset:0}.lc-att-lightbox-img{object-fit:contain;background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-1));max-width:min(100%,1600px);max-height:calc(100vh - 80px);box-shadow:var(--dsw-shadow-lv3,0 12px 32px #0006);border-radius:12px;position:relative}.lc-att-lightbox-close{z-index:1;border:1px solid var(--dsw-alias-border-l2-darkmode-thin,var(--dsw-alias-border-l1));background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-1));width:36px;height:36px;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:999px;place-items:center;padding:0;display:grid;position:fixed;top:20px;right:20px}[data-conversation-scroll]:has(.lc-root)>[data-composer-seat]:not(:has([data-approval-key],[data-question-key],[data-plan-review-key])){display:none}";
3242
+ const css = ".lc-root{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-primary);padding:16px 20px 32px;font-size:13px;overflow-y:auto}.lc-card{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;margin-bottom:14px;padding:14px 16px}.lc-card-title{align-items:baseline;gap:8px;margin-bottom:10px;font-weight:600;display:flex}.lc-card-title-text{white-space:nowrap;flex:none}.lc-stats{grid-template-columns:repeat(auto-fit,minmax(62px,1fr));gap:6px;display:grid}.lc-stat{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex-direction:column;gap:2px;min-width:0;padding:6px;display:flex}.lc-stat-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;font-weight:600;overflow:hidden}.lc-stat-value{color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;text-align:center;font-size:14px;font-weight:600;overflow:hidden}.lc-stat-sub{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;overflow:hidden}.lc-stat-tipped{position:relative}.lc-stat-q{text-align:center;width:11px;height:11px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);cursor:help;border-radius:50%;margin-left:4px;font-size:9px;font-style:normal;font-weight:700;line-height:11px;display:inline-block}.lc-stat-tipped:hover .lc-stat-q{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary)}.lc-stat-tip{z-index:6;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;max-width:280px;color:var(--dsw-alias-label-primary);pointer-events:none;opacity:0;border-radius:6px;padding:6px 10px;font-size:12px;font-weight:400;line-height:1.5;transition:opacity .12s;position:absolute;top:calc(100% + 6px);left:0;box-shadow:0 2px 8px #0000002e}.lc-stat-tipped:hover .lc-stat-tip{opacity:1}.lc-stat-tip-prices{border-top:1px dashed var(--dsw-alias-border-l1);margin-top:5px;padding-top:5px;display:block}.lc-stat-tip-head{font-weight:600;display:block}.lc-stat-tip-row{margin-top:2px;display:block}.lc-stat-tip-model{color:var(--dsw-alias-label-primary)}.lc-card-sub{color:var(--dsw-alias-label-secondary);margin-left:auto;font-size:12px;font-weight:400}.lc-gran,.lc-kinds{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;gap:2px;margin-left:auto;padding:1px;display:flex}.lc-trend-ctl{align-items:center;gap:6px;margin-left:auto;display:flex}.lc-trend-ctl .lc-gran{margin-left:0}.lc-gran-btn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:5px;padding:3px 8px;font-family:inherit;font-size:11px;line-height:1}.lc-gran-btn:hover{color:var(--dsw-alias-label-primary)}.lc-gran-on,.lc-gran-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.lc-settings-card{background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;transition:border-color .16s,background .16s}.lc-settings-card:hover{border-color:var(--dsw-alias-label-dimmed)}.lc-settings-open,.lc-settings-open:hover{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.lc-settings-head{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.lc-settings-headtext{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.lc-settings-name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.lc-settings-desc{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.lc-settings-chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.lc-settings-open .lc-settings-chevron{transform:rotate(180deg)}.lc-settings-body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding:4px 0 12px}.lc-settings-row{align-items:center;gap:8px;padding:8px 0;display:flex}.lc-settings-label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:14px}.lc-settings-select{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.lc-settings-select:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.lc-settings-select:disabled{opacity:.5;cursor:default}.lc-settings-note{color:var(--dsw-alias-label-tertiary);margin:12px 0 4px;font-size:12px;line-height:1.5}.lc-overview-num{align-items:baseline;gap:6px;margin-bottom:8px;display:flex}.lc-overview-num>b{font-size:20px}.lc-overview-num span{color:var(--dsw-alias-label-secondary)}.lc-overview-pct{margin-left:auto;font-size:11px}.lc-overview-pct b{color:var(--dsw-alias-label-primary);margin-right:4px;font-size:20px}.lc-stacked-wrap{width:100%;position:relative}.lc-stacked{background:#8080802e;border-radius:5px;width:100%;display:flex;position:relative;overflow:hidden}.lc-occupied-box{border:2px solid var(--dsw-alias-label-tertiary);box-sizing:border-box;pointer-events:none;opacity:0;box-shadow:0 0 0 1px var(--dsw-alias-bg-layer-2);border-radius:5px;transition:opacity .12s;position:absolute;top:0;bottom:0;left:0}.lc-occupied-box-on{opacity:1}.lc-bar-tip{z-index:5;white-space:nowrap;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);pointer-events:none;opacity:0;border-radius:6px;padding:3px 8px;font-size:12px;transition:opacity .12s;position:absolute;bottom:calc(100% + 6px);transform:translate(-50%);box-shadow:0 2px 8px #0000002e}.lc-bar-tip-on{opacity:1}.lc-stacked>div{height:100%}.lc-stacked-seg{transition:filter .12s,opacity .12s}.lc-stacked-free{box-sizing:border-box;transition:box-shadow .12s,opacity .12s}.lc-stacked-seg-on{filter:brightness(1.18)}.lc-reserve{z-index:1;pointer-events:auto;cursor:help;background:repeating-linear-gradient(45deg, color-mix(in srgb, var(--dsw-alias-state-warn-primary) 24%, transparent) 0 5px, transparent 5px 10px);position:absolute;top:0;bottom:0}.lc-stacked-free-on{border:2px dashed var(--dsw-alias-label-secondary);border-radius:3px}.lc-stacked-dim .lc-stacked-seg{opacity:.35}.lc-stacked-dim .lc-stacked-seg-on{opacity:1}.lc-stacked-dim .lc-stacked-free{opacity:.35}.lc-stacked-dim .lc-stacked-free-on{opacity:1}.lc-legend{grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:6px 14px;margin-top:10px;display:grid}.lc-chip{min-width:0;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:5px;padding:1px 6px;transition:background-color .12s;display:flex}.lc-chip-label{white-space:nowrap;text-overflow:ellipsis;min-width:0;font-weight:600;overflow:hidden}.lc-chip-nums{white-space:nowrap;flex:none;align-items:baseline;gap:6px;margin-left:auto;display:inline-flex}.lc-chip i,.lc-detail-row i,.lc-node i{border-radius:2px;width:8px;height:8px;display:inline-block}.lc-chip i{transition:box-shadow .12s}.lc-chip em{color:var(--dsw-alias-label-secondary);font-style:normal}.lc-chip-on{background:var(--dsw-alias-interactive-bg-hover);font-weight:600}.lc-chip-on i{box-shadow:0 0 0 1px var(--dsw-alias-brand-primary)}.lc-tools{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;align-items:center;gap:6px;margin-top:10px;display:flex}.lc-tools-label,.lc-tools-more{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;padding:0;font-family:inherit;font-size:12px}.lc-tools-label:hover,.lc-tools-more:hover{text-decoration:underline}.lc-tool-chip{background:var(--dsw-alias-bg-layer-2);font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:0;border-radius:4px;padding:1px 7px;font-size:12px}.lc-tool-chip:hover{text-decoration:underline}.lc-chartrow{align-items:stretch;gap:6px;display:flex}.lc-axis{box-sizing:border-box;width:40px;height:150px;color:var(--dsw-alias-label-secondary);padding-top:18px;font-size:11px;position:relative}.lc-axis span{line-height:1;position:absolute;right:0}.lc-axis-top{top:13px}.lc-axis-mid{top:69px}.lc-axis-bot{top:125px}.lc-chart-scroll{scrollbar-width:thin;scrollbar-gutter:stable;flex:1;min-width:0;padding-bottom:8px;position:relative;overflow:auto hidden}.lc-chart-fade{pointer-events:none;z-index:2;width:26px;position:absolute;top:0;bottom:0}.lc-chart-fade-l{background:linear-gradient(to right, var(--dsw-alias-bg-layer-1), transparent);left:0}.lc-chart-fade-r{background:linear-gradient(to left, var(--dsw-alias-bg-layer-1), transparent);right:0}.lc-chart{box-sizing:border-box;align-items:flex-end;gap:2px;width:max-content;min-width:100%;height:130px;padding-top:18px;display:flex;position:relative}.lc-grid{border-top:1px dashed var(--dsw-alias-border-l1);pointer-events:none;position:absolute;left:0;right:0}.lc-grid-top{top:18px}.lc-grid-mid{top:74px}.lc-grid-zero{border-top-style:solid;border-top-color:#80808080}.lc-bar{cursor:pointer;border-radius:2px;flex:none;align-items:flex-end;width:14px;height:100%;transition:opacity .12s,background-color .12s;display:flex;position:relative}.lc-chart-dim .lc-bar{opacity:.35}.lc-chart-dim .lc-bar-in-turn{opacity:1}.lc-chart-dim .lc-turn{opacity:.35}.lc-chart-dim .lc-turn-on{opacity:1}.lc-chart-tip{z-index:5;white-space:nowrap;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;padding:3px 8px;font-size:12px;position:absolute;top:0;transform:translate(-50%);box-shadow:0 2px 8px #0000002e}.lc-bar:hover{background:var(--dsw-alias-bg-layer-2)}.lc-bar-hovered{outline:1px dashed var(--dsw-alias-brand-primary);outline-offset:1px}.lc-bar-selected{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.lc-bar-in-turn{background:#80808024}.lc-bar-stack{flex-direction:column-reverse;width:100%;display:flex}.lc-bar-stack>div{width:100%}.lc-bar-up,.lc-bar-down{width:100%;display:flex;position:absolute;left:0}.lc-bar-up{flex-direction:column-reverse}.lc-bar-down{flex-direction:column}.lc-bar-up>div,.lc-bar-down>div{width:100%}.lc-bar-marker{color:var(--dsw-alias-state-warn-primary);font-size:11px;position:absolute;top:-16px;left:50%;transform:translate(-50%)}.lc-turns{gap:2px;width:max-content;min-width:100%;margin-top:4px;display:flex}.lc-turn{box-sizing:border-box;text-align:center;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;cursor:pointer;border-radius:3px;flex:none;height:14px;font-size:10px;font-weight:600;line-height:14px;transition:filter .12s,opacity .12s;overflow:hidden}.lc-turn-on{filter:brightness(1.35);color:var(--dsw-alias-label-primary)}.lc-turn-label{text-overflow:ellipsis;max-width:100%;display:inline-block;overflow:hidden}.lc-detail{border-top:1px solid var(--dsw-alias-border-l1);margin-top:12px;padding-top:12px}.lc-detail-head{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;align-items:center;gap:6px 8px;margin-bottom:10px;display:flex}.lc-detail-head b{color:var(--dsw-alias-label-primary);font-size:13px}.lc-detail-time{font-variant-numeric:tabular-nums;white-space:nowrap;margin-left:auto;font-size:12px}.lc-detail-marker{color:var(--dsw-alias-state-warn-primary);background:color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);border-radius:6px;padding:1px 7px;font-size:11px}.lc-detail-tag{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:4px;padding:0 6px;font-size:11px}.lc-detail-metric{font-variant-numeric:tabular-nums;white-space:nowrap;color:var(--dsw-alias-label-primary);background:color-mix(in srgb, var(--dsw-alias-label-secondary) 14%, transparent);border-radius:6px;padding:2px 8px;font-size:12px;font-weight:600}.lc-detail-metric-up{color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 15%, transparent)}.lc-detail-metric-down{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 15%, transparent)}.lc-detail-rows{grid-template-columns:1fr 1fr;gap:4px 24px;margin-top:10px;display:grid}.lc-brief{flex-direction:column;gap:2px;margin:-4px 0 10px;display:flex}.lc-brief-row{min-width:0;color:var(--dsw-alias-label-primary);text-align:left;background:0 0;border:0;border-radius:6px;align-items:center;gap:8px;margin-left:-6px;margin-right:-6px;padding:3px 6px;font-family:inherit;font-size:12px;line-height:1.5;transition:background-color .12s;display:flex}.lc-brief-row-link:hover{background:var(--dsw-alias-interactive-bg-hover)}button.lc-brief-row-link{cursor:pointer}.lc-brief-tag{box-sizing:border-box;text-align:center;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);min-width:56px;color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;padding:0 6px;font-size:11px;position:relative}.lc-brief-tip{z-index:6;white-space:normal;text-align:left;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;max-width:240px;color:var(--dsw-alias-label-primary);pointer-events:none;opacity:0;border-radius:6px;padding:6px 10px;font-size:12px;font-weight:400;line-height:1.5;transition:opacity .12s;position:absolute;bottom:calc(100% + 6px);left:0;box-shadow:0 2px 8px #0000002e}.lc-brief-tag:hover .lc-brief-tip{opacity:1}.lc-brief-text{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.lc-brief-chip{text-overflow:ellipsis;white-space:nowrap;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);max-width:220px;color:var(--dsw-alias-label-primary);border-radius:5px;align-items:center;gap:5px;padding:0 7px;font-size:12px;transition:background-color .12s;display:inline-flex;overflow:hidden}.lc-brief-chip-link{cursor:pointer}.lc-brief-chip-link:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-brief-more{color:var(--dsw-alias-label-secondary);flex:none;font-size:11px}.lc-detail-row{align-items:center;gap:8px;display:flex}.lc-detail-label{white-space:nowrap;min-width:70px;color:var(--dsw-alias-label-secondary)}.lc-bar-track{background:#8080802e;border-radius:3px;flex:1;height:5px;display:block;position:relative;overflow:hidden}.lc-bar-fill{border-radius:3px;height:100%;display:block}.lc-bar-zero{border-left:1px solid #80808073;position:absolute;top:0;bottom:0;left:50%}.lc-bar-fill-up,.lc-bar-fill-down{height:100%;display:block;position:absolute;top:0}.lc-bar-fill-up{border-radius:0 3px 3px 0;left:50%}.lc-bar-fill-down{border-radius:3px 0 0 3px;right:50%}.lc-detail-num{text-align:right;font-variant-numeric:tabular-nums;width:52px}.lc-detail-num-up{color:var(--dsw-alias-state-success-primary)}.lc-detail-num-down{color:var(--dsw-alias-state-error-primary)}.lc-detail-pct{text-align:right;width:34px;color:var(--dsw-alias-label-secondary)}.lc-cols{flex-wrap:wrap;gap:14px;margin-bottom:14px;display:flex}.lc-col{flex:1;min-width:280px}.lc-cols>.lc-card,.lc-col>.lc-card:last-child{margin-bottom:0}.lc-col-browser{flex-direction:column;display:flex}.lc-col-browser>.lc-card{flex:1}.lc-head>.lc-card:first-child{flex:7 1 0;min-width:360px}.lc-head>.lc-card:last-child{flex:3 1 0;min-width:220px}.lc-pi-grid{grid-template-columns:1fr;gap:8px;display:grid}.lc-pi-row{min-width:0;color:inherit;flex-direction:row;justify-content:space-between;align-items:baseline;gap:12px;text-decoration:none;display:flex}.lc-pi-row:hover .lc-pi-value{text-decoration:underline}.lc-pi-update{color:var(--dsw-alias-state-warn-primary);white-space:nowrap;margin-left:6px;font-size:11px}.lc-pi-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;flex:none;font-size:11px;font-weight:600;overflow:hidden}.lc-pi-value{min-width:0;color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;text-align:right;font-size:13px;font-weight:600;overflow:hidden}.lc-events,.lc-nodes{flex-direction:column;gap:2px;max-height:320px;display:flex;overflow-y:auto}.lc-event{align-items:center;gap:8px;padding:3px 0;display:flex}.lc-event-icon{text-align:center;width:18px;color:var(--dsw-alias-state-warn-primary)}.lc-event-icon.lc-event-inject{color:#a855f7}.lc-event-icon.lc-event-model{color:var(--dsw-alias-brand-primary)}.lc-event-icon.lc-event-mode{color:var(--dsw-alias-label-secondary)}.lc-kind{white-space:nowrap;border-radius:4px;flex:none;padding:1px 6px;font-size:10px;font-weight:600}.lc-kind-inject{background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 15%, transparent);color:var(--dsw-alias-state-success-primary)}.lc-kind-compaction{background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 15%, transparent);color:var(--dsw-alias-state-error-primary)}.lc-kind-prune{color:#8b5cf6;background:#8b5cf626}.lc-kind-model{background:color-mix(in srgb, var(--dsw-alias-brand-primary) 15%, transparent);color:var(--dsw-alias-brand-primary)}.lc-kind-mode{background:color-mix(in srgb, var(--dsw-alias-label-secondary) 15%, transparent);color:var(--dsw-alias-label-secondary)}.lc-event-label{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.lc-event-at{color:var(--dsw-alias-label-secondary);white-space:nowrap;flex:none;font-size:11px}.lc-event-tokens{color:var(--dsw-alias-state-success-primary);white-space:nowrap;font-weight:600}.lc-event-tokens.lc-up{color:var(--dsw-alias-state-warn-primary)}.lc-event-time{color:var(--dsw-alias-label-secondary);font-size:12px}.lc-node{align-items:center;gap:8px;padding:3px 0;display:flex}.lc-node-preview{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);flex:1;overflow:hidden}.lc-node-time{color:var(--dsw-alias-label-secondary);text-align:right;min-width:54px;font-size:12px}.lc-node-tokens{color:var(--dsw-alias-label-secondary)}.lc-nodes-more{color:var(--dsw-alias-label-secondary);padding:3px 0}.lc-empty{color:var(--dsw-alias-label-secondary);text-align:center;padding:18px 0}.lc-error{flex-direction:column;align-items:center;gap:8px;padding:40px 16px;display:flex}.lc-error-msg{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);overflow-wrap:anywhere;border-radius:6px;max-width:100%;padding:4px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.lc-error-retry{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:6px;padding:4px 14px;font-size:12px}.lc-error-retry:hover{border-color:var(--dsw-alias-label-primary)}.lc-foot{color:var(--dsw-alias-label-secondary);margin-top:4px;font-size:12px}.lc-modal-backdrop{z-index:200;background:#00000073;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.lc-modal-card{box-sizing:border-box;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);width:min(720px,100vw - 48px);max-height:min(82vh,760px);box-shadow:var(--dsw-shadow-lv3,0 12px 32px #0006);color:var(--dsw-alias-label-primary);border-radius:12px;padding:16px 18px 18px;font-size:13px;overflow-y:auto}.lc-modal-head{align-items:baseline;gap:8px;margin-bottom:12px;display:flex}.lc-modal-title{font-size:14px;font-weight:600}.lc-modal-close{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:6px;margin-left:auto;padding:2px 6px;font-family:inherit;font-size:18px;line-height:1}.lc-modal-close:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.lc-br-hint{color:var(--dsw-alias-label-secondary);white-space:nowrap;margin-left:auto;font-size:11px;font-weight:400}.lc-br-pick{font:inherit;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;max-width:240px;padding:3px 6px;font-size:12px}.lc-br-meta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:6px 16px;margin-bottom:8px;display:flex}.lc-br-meta b{color:var(--dsw-alias-label-primary)}.lc-br-meta .lc-actual{color:var(--dsw-alias-state-success-primary)}.lc-br-note{color:var(--dsw-alias-label-secondary);margin-top:8px;font-size:12px}.lc-br-cats{flex-direction:column;gap:4px;margin-top:10px;display:flex}.lc-br-cat{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);border-radius:8px;overflow:hidden}.lc-br-cat-empty{opacity:.55}.lc-br-cat-row{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:0;align-items:center;gap:8px;padding:7px 10px;transition:background-color .12s;display:flex}.lc-br-cat-row:hover,.lc-br-cat-on{background:var(--dsw-alias-interactive-bg-hover)}.lc-br-cat-on i{box-shadow:0 0 0 1px var(--dsw-alias-brand-primary)}.lc-br-cat-row i{border-radius:2px;flex:none;width:8px;height:8px;transition:box-shadow .12s;display:inline-block}.lc-br-cat-label{font-weight:600}.lc-br-cat-count{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:12px}.lc-br-count-grp{flex:1;align-items:center;gap:4px;min-width:0;display:inline-flex}.lc-br-chev{width:12px;color:var(--dsw-alias-label-secondary);flex:none;transition:transform .12s}.lc-br-chev-on{transform:rotate(90deg)}.lc-br-tokens{color:var(--dsw-alias-label-secondary);flex:none;font-size:12px}.lc-br-delta,.lc-br-tdelta{white-space:nowrap;border-radius:4px;flex:none;padding:0 5px;font-size:11px;font-weight:600}.lc-br-delta-up,.lc-br-tdelta-up{color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 15%, transparent)}.lc-br-delta-down,.lc-br-tdelta-down{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 15%, transparent)}.lc-br-tokens-grp{flex:none;align-items:center;gap:4px;min-width:0;display:inline-flex}.lc-br-pct{text-align:right;width:36px;color:var(--dsw-alias-label-secondary);flex:none;font-size:12px}.lc-br-body{border-top:1px solid var(--dsw-alias-border-l1);flex-direction:column;gap:2px;padding:4px 6px;display:flex}.lc-br-elem{border-radius:6px}.lc-br-elem-on{background:var(--dsw-alias-interactive-bg-active)}.lc-br-elem-row{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:0;border-radius:6px;align-items:center;gap:8px;padding:5px 6px;font-size:12px;transition:background-color .12s;display:flex}.lc-br-elem-row:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-br-err-dot{background:var(--dsw-alias-state-error-primary);width:6px;height:6px;box-shadow:0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);border-radius:50%;flex:none}.lc-br-tag{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);text-overflow:ellipsis;white-space:nowrap;border-radius:4px;flex:none;max-width:220px;padding:0 6px;font-size:11px;overflow:hidden}.lc-br-preview{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.lc-br-time{color:var(--dsw-alias-label-secondary);flex:none;font-size:11px}.lc-br-content{flex-direction:column;gap:6px;padding:2px 6px 8px 26px;display:flex}.lc-br-dim{color:var(--dsw-alias-label-secondary)}.lc-ts-card{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;min-width:0;overflow:hidden}.lc-ts-card-head{color:var(--dsw-alias-label-secondary);border-bottom:1px solid var(--dsw-alias-border-l1);align-items:center;gap:8px;padding:6px 10px;font-size:11px;font-weight:600;display:flex}.lc-ts-card-head b{color:var(--dsw-alias-label-primary)}.lc-ts-call-name{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px}.lc-ts-card-count{margin-left:auto}.lc-ts-card-right{align-items:center;gap:8px;margin-left:auto;display:inline-flex}.lc-ts-card-meta{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-variant-numeric:tabular-nums;font-size:11px;font-weight:400}.lc-ts-call-state{white-space:nowrap;border-radius:999px;flex:none;align-items:center;gap:4px;padding:2px 7px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;font-weight:600;line-height:1;display:inline-flex}.lc-ts-call-state i{background:currentColor;border-radius:50%;flex:none;width:6px;height:6px}.lc-ts-call-ok{color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 12%, transparent)}.lc-ts-call-err{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.lc-ts-desc-body{color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;scrollbar-width:thin;max-height:320px;margin:0;padding:8px 10px;font-size:12px;line-height:1.55;overflow-y:auto}.lc-ts-param-row{border-top:1px solid var(--dsw-alias-border-l1);grid-template-columns:140px 90px 56px 1fr;align-items:baseline;gap:2px 10px;padding:6px 10px;font-size:12px;display:grid}.lc-ts-param-row:first-of-type{border-top:0}.lc-ts-param-name{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-weight:600;overflow:hidden}.lc-ts-param-type{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;overflow:hidden}.lc-ts-param-req{color:var(--dsw-alias-state-warn-primary);font-size:11px;font-weight:600}.lc-ts-param-req-off{color:var(--dsw-alias-label-secondary);font-size:11px}.lc-ts-param-desc{color:var(--dsw-alias-label-secondary);grid-column:1/-1;line-height:1.5}.lc-ts-params-empty{color:var(--dsw-alias-label-secondary);padding:8px 10px;font-size:12px}.lc-ts-arg-row{border-top:1px solid var(--dsw-alias-border-l1);grid-template-columns:minmax(0,96px) 1fr;align-items:start;column-gap:12px;padding:6px 10px;font-size:12px;display:grid}.lc-ts-arg-row:first-of-type{border-top:0}.lc-ts-arg-row .lc-ts-param-name{text-overflow:unset;white-space:normal;overflow-wrap:anywhere;overflow:visible}.lc-ts-arg-val{color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;scrollbar-width:thin;max-height:200px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.55;overflow-y:auto}.lc-ts-json{flex-direction:column;gap:4px;display:flex}.lc-ts-json-toggle{color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border:0;align-self:flex-start;padding:0;font-size:11px}.lc-ts-json-toggle:hover{color:var(--dsw-alias-label-primary);text-decoration:underline}.lc-rich-seg{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;gap:2px;margin-left:auto;padding:1px;display:flex}.lc-rich-seg-btn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:5px;padding:3px 8px;font-family:inherit;font-size:11px;line-height:1}.lc-rich-seg-btn:hover{color:var(--dsw-alias-label-primary)}.lc-rich-seg-on,.lc-rich-seg-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.lc-ts-desc-md{color:var(--dsw-alias-label-primary);word-break:break-word;overflow-wrap:anywhere;white-space:pre-line;scrollbar-width:thin;min-width:0;max-height:320px;padding:4px 10px;font-size:12px;line-height:1.55;overflow:hidden auto}.lc-ts-desc-md>div{font-size:13px;line-height:1.55}.lc-ts-desc-md div :is(h1,h2,h3,h4,h5,h6){margin:10px 0 4px;font-size:13px;font-weight:600}.lc-ts-desc-md div p{margin:6px 0}.lc-ts-desc-md div pre{white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word;margin:6px 0}.lc-ts-desc-md div :not(pre)>code{box-decoration-break:clone;padding:1px 5px;line-height:1.3;font-size:1em!important}.lc-ts-desc-md div table code{font-size:inherit}.lc-att-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;padding:8px 10px;display:grid}.lc-att-item{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l1);width:100%;min-width:0;font:inherit;text-align:left;cursor:pointer;background:0 0;border-radius:8px;align-items:center;gap:8px;padding:6px;display:flex}.lc-att-item:hover{border-color:var(--dsw-alias-border-l2,var(--dsw-alias-border-l1));background:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-2))}.lc-att-thumb{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:6px;flex:none;justify-content:center;align-items:center;width:64px;height:64px;padding:0;display:flex;overflow:hidden}.lc-att-thumb img{object-fit:cover;width:100%;height:100%;display:block}.lc-att-ph,.lc-att-err{color:var(--dsw-alias-label-secondary);text-align:center;padding:2px;font-size:10px}.lc-att-meta{flex-direction:column;gap:2px;min-width:0;display:flex}.lc-att-name{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;word-break:break-word;font-size:12px;line-height:1.3}.lc-att-row{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;font-size:11px}.lc-att-row-label{min-width:3.2em;font-weight:400;display:inline-block}.lc-att-lightbox{z-index:1000;place-items:center;padding:40px;display:grid;position:fixed;inset:0}.lc-att-lightbox-mask{background:var(--dsw-alias-bg-mask-1,#00000073);backdrop-filter:var(--dsw-mask-blur,blur(2px));position:absolute;inset:0}.lc-att-lightbox-img{object-fit:contain;background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-1));max-width:min(100%,1600px);max-height:calc(100vh - 80px);box-shadow:var(--dsw-shadow-lv3,0 12px 32px #0006);border-radius:12px;position:relative}.lc-att-lightbox-close{z-index:1;border:1px solid var(--dsw-alias-border-l2-darkmode-thin,var(--dsw-alias-border-l1));background:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-1));width:36px;height:36px;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:999px;place-items:center;padding:0;display:grid;position:fixed;top:20px;right:20px}[data-conversation-scroll]:has(.lc-root)>[data-composer-seat]:not(:has([data-approval-key],[data-question-key],[data-plan-review-key])){display:none}";
2961
3243
  const tagId = "dsh-context/styles.css";
2962
3244
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
2963
3245
  const tag = document.createElement("style");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-context",
3
- "version": "0.31.0",
3
+ "version": "0.32.0",
4
4
  "description": "A DeepSeek Harness plugin for context insight and management, with context dashboard and context command, for understanding how the context is made of, and how it evolves.",
5
5
  "author": "bowenliang123",
6
6
  "repository": {