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.
- package/README.md +24 -9
- package/lib/client.js +373 -91
- 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,
|
|
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 —
|
|
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
|
-
### 📈
|
|
63
|
+
### 📈 Context Trend — every request's size *and* its story
|
|
64
64
|
|
|
65
|
-
One stacked bar per model request
|
|
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
|
-

|
|
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
|
|
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
|
-
|
|
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
|
+

|
|
72
80
|
|
|
73
|
-
|
|
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
|
+

|
|
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
|
|
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
|
+

|
|
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
|
|
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:
|
|
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
|
-
*
|
|
1275
|
-
*
|
|
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
|
|
1278
|
-
if (
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
const
|
|
1286
|
-
|
|
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
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1384
|
+
return {
|
|
1385
|
+
fail: false,
|
|
1386
|
+
exit: null
|
|
1387
|
+
};
|
|
1292
1388
|
}
|
|
1293
1389
|
/**
|
|
1294
|
-
*
|
|
1295
|
-
*
|
|
1390
|
+
* A tool result's failure: the fold-stamped `err` or the snapshot's `isError` (infrastructure failures — dsh 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
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
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(() =>
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
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", {
|
|
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.
|
|
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.
|
|
2194
|
-
const nameValue = ["dsh-context (v0.
|
|
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(
|
|
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
|
|
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.
|
|
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": {
|