dsh-context 0.29.0 → 0.30.1
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 +1 -0
- package/cordis.patch.yml +3 -7
- package/lib/client.js +173 -204
- package/lib/index.d.ts +21 -54
- package/lib/index.js +17 -34
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -62,6 +62,7 @@ window.__ModuleLoader__.load({
|
|
|
62
62
|
"detail.estTotal": "估算合计 ≈ {n}",
|
|
63
63
|
"detail.actual": "实际 prompt {n}",
|
|
64
64
|
"detail.output": "输出 {n}",
|
|
65
|
+
"detail.cache": "缓存 {n}%",
|
|
65
66
|
"events.title": "上下文事件",
|
|
66
67
|
"events.empty": "暂无上下文事件(压缩、注入、模型切换会出现在这里)",
|
|
67
68
|
"events.at": "第 {t} 轮 · 第 {s} 步",
|
|
@@ -132,6 +133,12 @@ window.__ModuleLoader__.load({
|
|
|
132
133
|
"block.content": "内容",
|
|
133
134
|
"block.result": "结果",
|
|
134
135
|
"block.summary": "摘要",
|
|
136
|
+
"block.line": "{n} 行",
|
|
137
|
+
"block.lines": "{n} 行",
|
|
138
|
+
"call.ok": "正常",
|
|
139
|
+
"call.fail": "失败",
|
|
140
|
+
"call.exit": "exit {n}",
|
|
141
|
+
"node.failed": "工具执行失败",
|
|
135
142
|
"attach.images": "图片附件",
|
|
136
143
|
"attach.other": "其他内容",
|
|
137
144
|
"attach.image": "图片",
|
|
@@ -202,6 +209,7 @@ window.__ModuleLoader__.load({
|
|
|
202
209
|
"detail.estTotal": "Estimated ≈ {n}",
|
|
203
210
|
"detail.actual": "Actual Prompt {n}",
|
|
204
211
|
"detail.output": "Output {n}",
|
|
212
|
+
"detail.cache": "Cache {n}%",
|
|
205
213
|
"events.title": "Context Events",
|
|
206
214
|
"events.empty": "No context events yet (compaction, injections, model switches appear here)",
|
|
207
215
|
"events.at": "Turn {t} · Step {s}",
|
|
@@ -272,6 +280,12 @@ window.__ModuleLoader__.load({
|
|
|
272
280
|
"block.content": "Content",
|
|
273
281
|
"block.result": "Result",
|
|
274
282
|
"block.summary": "Summary",
|
|
283
|
+
"block.line": "1 line",
|
|
284
|
+
"block.lines": "{n} lines",
|
|
285
|
+
"call.ok": "OK",
|
|
286
|
+
"call.fail": "Failed",
|
|
287
|
+
"call.exit": "exit {n}",
|
|
288
|
+
"node.failed": "Tool execution failed",
|
|
275
289
|
"attach.images": "Images",
|
|
276
290
|
"attach.other": "Other content",
|
|
277
291
|
"attach.image": "Image",
|
|
@@ -314,7 +328,6 @@ window.__ModuleLoader__.load({
|
|
|
314
328
|
function setPendingConsume(sessionId, guard) {
|
|
315
329
|
pendingConsume.set(sessionId, guard);
|
|
316
330
|
}
|
|
317
|
-
/** Take (and clear) the guard recorded by the open path, if any. */
|
|
318
331
|
function takePendingConsume(sessionId) {
|
|
319
332
|
const guard = pendingConsume.get(sessionId);
|
|
320
333
|
if (guard !== void 0) pendingConsume.delete(sessionId);
|
|
@@ -514,7 +527,6 @@ window.__ModuleLoader__.load({
|
|
|
514
527
|
function numOf(value) {
|
|
515
528
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
516
529
|
}
|
|
517
|
-
/** The usable (non-null object) entries of a delivered list; [] when the field is not a list. */
|
|
518
530
|
function objectsOf(value) {
|
|
519
531
|
if (!Array.isArray(value)) return [];
|
|
520
532
|
return value.filter((v) => v !== null && typeof v === "object");
|
|
@@ -644,10 +656,6 @@ window.__ModuleLoader__.load({
|
|
|
644
656
|
for (let i = headers.headers.length - 1; i >= 0; i--) if (headers.headers[i].seq < seq) return headers.headers[i];
|
|
645
657
|
return null;
|
|
646
658
|
}
|
|
647
|
-
/**
|
|
648
|
-
* Reconstruct the assembled surface for one step (`seq` = the request
|
|
649
|
-
* record's seq) or the live surface (`seq` = null).
|
|
650
|
-
*/
|
|
651
659
|
function assemble(data, headers, seq) {
|
|
652
660
|
const live = seq === null;
|
|
653
661
|
let nodes;
|
|
@@ -679,7 +687,6 @@ window.__ModuleLoader__.load({
|
|
|
679
687
|
const ReactDOM = require("react-dom");
|
|
680
688
|
//#endregion
|
|
681
689
|
//#region src/client/components/nodes.tsx
|
|
682
|
-
/** One-line preview of a surface node (shared by the node list and the Context browser's element rows). */
|
|
683
690
|
function makeNodeText(kit) {
|
|
684
691
|
const { t } = kit;
|
|
685
692
|
return function nodeText(n) {
|
|
@@ -714,10 +721,7 @@ window.__ModuleLoader__.load({
|
|
|
714
721
|
}
|
|
715
722
|
//#endregion
|
|
716
723
|
//#region src/client/format.ts
|
|
717
|
-
/**
|
|
718
|
-
* Number/time formatting for the UI. `fmt` uses the same k/M suffix style
|
|
719
|
-
* everywhere (bars, details, stats); `fmtTime` renders a local HH:MM:SS.
|
|
720
|
-
*/
|
|
724
|
+
/** `fmt`: the k/M suffix style shared by bars/details/stats; `fmtTime`: local HH:MM:SS. */
|
|
721
725
|
function fmt(n) {
|
|
722
726
|
if (n === void 0 || n === null || isNaN(n)) return "—";
|
|
723
727
|
const sign = n < 0 ? "-" : "";
|
|
@@ -733,6 +737,18 @@ window.__ModuleLoader__.load({
|
|
|
733
737
|
if (n >= 1e3) return (n / 1e3).toFixed(1) + " kB";
|
|
734
738
|
return String(Math.round(n)) + " B";
|
|
735
739
|
}
|
|
740
|
+
/**
|
|
741
|
+
* Cache-hit share of billed prompt-side input (`reads` over `billed`),
|
|
742
|
+
* TRUNCATED to two decimals (cut, not round) — same formula as the harness
|
|
743
|
+
* chat stats line's '缓存命中' figure and the stats board's cell. Null when
|
|
744
|
+
* nothing was billed. The 1e-9 epsilon absorbs only float noise (integer
|
|
745
|
+
* token counts never sit that close to a boundary).
|
|
746
|
+
*/
|
|
747
|
+
function cacheHitPercent$1(reads, billed) {
|
|
748
|
+
if (!(billed > 0)) return null;
|
|
749
|
+
const hundredths = Math.trunc(reads / billed * 1e4 + 1e-9);
|
|
750
|
+
return `${Math.floor(hundredths / 100)}.${String(hundredths % 100).padStart(2, "0")}`;
|
|
751
|
+
}
|
|
736
752
|
function fmtTime(t) {
|
|
737
753
|
const d = new Date(t);
|
|
738
754
|
if (isNaN(d.getTime())) return "—";
|
|
@@ -767,7 +783,6 @@ window.__ModuleLoader__.load({
|
|
|
767
783
|
const MIN_PIXELS = 147456;
|
|
768
784
|
const floorDiv = (a, b) => Math.floor(a / b);
|
|
769
785
|
const ceilDiv = (a, b) => Math.floor((a + b - 1) / b);
|
|
770
|
-
/** Token count of one patch grid (rows×cols) under the v4 layout rule. */
|
|
771
786
|
function gridTokens(rows, cols) {
|
|
772
787
|
let n = rows * (cols + 1) + 2;
|
|
773
788
|
if (rows % 2 === 1) n += cols + 1;
|
|
@@ -849,10 +864,8 @@ window.__ModuleLoader__.load({
|
|
|
849
864
|
return safeResize(h, w, paddedHeight, paddedWidth);
|
|
850
865
|
}
|
|
851
866
|
/**
|
|
852
|
-
* Estimate the tokens one image consumes in a DeepSeek vision request
|
|
853
|
-
*
|
|
854
|
-
* or when the official iteration fails to converge — callers fall back to
|
|
855
|
-
* the generic structural price.
|
|
867
|
+
* Estimate the tokens one image consumes in a DeepSeek vision request from its pixel dimensions. Returns null for non-positive/non-finite
|
|
868
|
+
* dimensions or when the official iteration fails to converge — callers fall back to the generic structural price.
|
|
856
869
|
*/
|
|
857
870
|
function estimateImageTokens(width, height) {
|
|
858
871
|
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return null;
|
|
@@ -871,11 +884,9 @@ window.__ModuleLoader__.load({
|
|
|
871
884
|
//#endregion
|
|
872
885
|
//#region src/client/components/images.tsx
|
|
873
886
|
/**
|
|
874
|
-
* Narrow an unknown content block to a durable image
|
|
875
|
-
*
|
|
876
|
-
*
|
|
877
|
-
* else returns null. Lenient on the ref's optional facts (name/bytes/dims) —
|
|
878
|
-
* `resolveImage` reads only `attachmentId`.
|
|
887
|
+
* Narrow an unknown content block to a durable image ref: accepts both raw message blocks (`{ type: 'image', attachment }`) and the
|
|
888
|
+
* snapshot's assistant blocks (`{ kind: 'image', attachment }`); everything else null. Lenient on the optional facts — resolveImage reads
|
|
889
|
+
* only attachmentId.
|
|
879
890
|
*/
|
|
880
891
|
function imageRefOf(block) {
|
|
881
892
|
if (block === null || typeof block !== "object") return null;
|
|
@@ -901,12 +912,9 @@ window.__ModuleLoader__.load({
|
|
|
901
912
|
};
|
|
902
913
|
}
|
|
903
914
|
/**
|
|
904
|
-
* Document-level original-image preview — the chat history's ImageLightbox
|
|
905
|
-
*
|
|
906
|
-
*
|
|
907
|
-
* filtered ancestor cannot trap the fixed backdrop, blurred mask layer,
|
|
908
|
-
* contain-fit image, circular close control, Escape/mask close, and focus
|
|
909
|
-
* restored to the opener on unmount.
|
|
915
|
+
* Document-level original-image preview — the chat history's ImageLightbox recipe (dsh ui-attachment, which the browser module table does
|
|
916
|
+
* not seed) ported onto the plugin's lc-* classes: body portal (a transformed/filtered ancestor cannot trap the fixed backdrop), blurred
|
|
917
|
+
* mask, contain-fit image, circular close, Escape/mask close, focus restored to the opener.
|
|
910
918
|
*/
|
|
911
919
|
function AttachmentLightbox(props) {
|
|
912
920
|
const { src, alt, labels, onClose } = props;
|
|
@@ -946,13 +954,9 @@ window.__ModuleLoader__.load({
|
|
|
946
954
|
}, /* @__PURE__ */ React.createElement(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 16 }))), document.body);
|
|
947
955
|
}
|
|
948
956
|
/**
|
|
949
|
-
* One attachment card
|
|
950
|
-
*
|
|
951
|
-
*
|
|
952
|
-
* normalization reduced the image; Sent, the normalized raster the model
|
|
953
|
-
* receives, with its stored byte size; and the estimated provider-billed
|
|
954
|
-
* tokens). Clicking opens the chat-style lightbox preview (load failures
|
|
955
|
-
* retry on click instead). Unknown facts leave no row behind.
|
|
957
|
+
* One attachment card, the WHOLE card the click target: 64px cover tile + metadata column — Raw (the pre-normalization raster dsh records
|
|
958
|
+
* when normalization reduced the image), Sent (the normalized raster the model receives, with byte size), estimated provider-billed tokens.
|
|
959
|
+
* Click opens the chat-style lightbox; load failures retry on click; unknown facts leave no row.
|
|
956
960
|
*/
|
|
957
961
|
function makeImageCard(kit) {
|
|
958
962
|
const { t, fmt } = kit;
|
|
@@ -1066,7 +1070,6 @@ window.__ModuleLoader__.load({
|
|
|
1066
1070
|
}
|
|
1067
1071
|
//#endregion
|
|
1068
1072
|
//#region src/client/components/browser.tsx
|
|
1069
|
-
/** Flatten the `anyOf` / `oneOf` alternation into one displayable string. */
|
|
1070
1073
|
function unionTypesOf(p) {
|
|
1071
1074
|
const branches = [];
|
|
1072
1075
|
if (Array.isArray(p.anyOf)) branches.push(...p.anyOf);
|
|
@@ -1076,12 +1079,6 @@ window.__ModuleLoader__.load({
|
|
|
1076
1079
|
for (const b of branches) if (b !== null && typeof b === "object") parts.push(typeOf(b));
|
|
1077
1080
|
return parts.length > 0 ? parts.join(" | ") : null;
|
|
1078
1081
|
}
|
|
1079
|
-
/**
|
|
1080
|
-
* Derive a short, human-readable type label from a JSON Schema fragment.
|
|
1081
|
-
* Arrays show their element type (`array<number>`); unions fold into
|
|
1082
|
-
* `a | b`; enums collapse into `(enum)`. Returns `unknown` when the schema
|
|
1083
|
-
* carries no usable signal — the row falls back to its description then.
|
|
1084
|
-
*/
|
|
1085
1082
|
function typeOf(p) {
|
|
1086
1083
|
const u = unionTypesOf(p);
|
|
1087
1084
|
if (u !== null) return u;
|
|
@@ -1103,9 +1100,8 @@ window.__ModuleLoader__.load({
|
|
|
1103
1100
|
return "unknown";
|
|
1104
1101
|
}
|
|
1105
1102
|
/**
|
|
1106
|
-
*
|
|
1107
|
-
*
|
|
1108
|
-
* the schema as the bare JSON Schema (when `type === 'object'`).
|
|
1103
|
+
* Tool schemas nest parameters under `parameters`, `input_schema`, or `inputSchema` (producer-dependent), or bare when `type === 'object'`
|
|
1104
|
+
* — `{type:'object', properties}` at the root is itself the parameter object.
|
|
1109
1105
|
*/
|
|
1110
1106
|
function paramsOf(schema) {
|
|
1111
1107
|
if (schema === null || typeof schema !== "object") return null;
|
|
@@ -1116,33 +1112,19 @@ window.__ModuleLoader__.load({
|
|
|
1116
1112
|
if (s.type === "object" && s.properties !== void 0 && typeof s.properties === "object") return s;
|
|
1117
1113
|
return null;
|
|
1118
1114
|
}
|
|
1119
|
-
/**
|
|
1120
|
-
* One row of the parsed parameter table — name (mono-styled, with a
|
|
1121
|
-
* required chip), short type label, and the description on its own line
|
|
1122
|
-
* (so a long blurb never breaks the name/type rhythm).
|
|
1123
|
-
*/
|
|
1124
1115
|
function ParamRow(props) {
|
|
1125
1116
|
const typeLabel = typeOf(props.schema);
|
|
1126
1117
|
const desc = props.schema.description;
|
|
1127
1118
|
return /* @__PURE__ */ React.createElement("div", { className: "lc-ts-param-row" }, /* @__PURE__ */ React.createElement("span", { className: "lc-ts-param-name" }, props.name), /* @__PURE__ */ React.createElement("span", { className: "lc-ts-param-type" }, typeLabel), /* @__PURE__ */ React.createElement("span", { className: props.required ? "lc-ts-param-req" : "lc-ts-param-req-off" }, props.required ? "✓" : "·"), typeof desc === "string" && desc !== "" ? /* @__PURE__ */ React.createElement("span", { className: "lc-ts-param-desc" }, desc) : null);
|
|
1128
1119
|
}
|
|
1129
1120
|
/**
|
|
1130
|
-
* Section — the ONE detail chrome of the
|
|
1131
|
-
*
|
|
1132
|
-
* extras on the right (a count badge and/or the Raw/MD switch), with the
|
|
1133
|
-
* body below. Every expanded element renders as a stack of these — prose,
|
|
1134
|
-
* tool calls, parameter rows, image grids, and raw JSON all share the same
|
|
1135
|
-
* frame, so the reader scans one repeating anatomy instead of a different
|
|
1136
|
-
* layout per content kind.
|
|
1121
|
+
* Section — the ONE detail chrome of the browser: every expanded element is a stack of these (labeled head + body), so the reader scans one
|
|
1122
|
+
* repeating anatomy per content kind.
|
|
1137
1123
|
*/
|
|
1138
1124
|
function Section(props) {
|
|
1139
|
-
|
|
1125
|
+
const right = props.actions !== void 0 || props.meta !== void 0;
|
|
1126
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-ts-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-ts-card-head" }, /* @__PURE__ */ React.createElement("b", { className: props.labelClass }, props.label), right ? /* @__PURE__ */ React.createElement("span", { className: "lc-ts-card-right" }, props.meta ?? null, props.actions ?? null) : null, props.count !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-ts-card-count" }, props.count) : null), props.children);
|
|
1140
1127
|
}
|
|
1141
|
-
/**
|
|
1142
|
-
* TextSection — a prose Section (system prompt, message/injection/summary
|
|
1143
|
-
* body, thinking, answer, tool description): the head's right edge carries
|
|
1144
|
-
* the Raw/MD switch and the body follows the per-card mode.
|
|
1145
|
-
*/
|
|
1146
1128
|
function TextSection(props) {
|
|
1147
1129
|
const { rich } = props;
|
|
1148
1130
|
const [mode, setMode] = rich.useRichMode();
|
|
@@ -1151,21 +1133,19 @@ window.__ModuleLoader__.load({
|
|
|
1151
1133
|
actions: /* @__PURE__ */ React.createElement(rich.RichSwitch, {
|
|
1152
1134
|
mode,
|
|
1153
1135
|
onPick: setMode
|
|
1154
|
-
})
|
|
1136
|
+
}),
|
|
1137
|
+
meta: props.meta
|
|
1155
1138
|
}, /* @__PURE__ */ React.createElement(rich.RichText, {
|
|
1156
1139
|
text: props.text,
|
|
1157
1140
|
mode
|
|
1158
1141
|
}));
|
|
1159
1142
|
}
|
|
1160
|
-
/** RawSection — a dimmed text Section without a view switch (structured payloads: tool results, raw JSON). */
|
|
1161
1143
|
function RawSection(props) {
|
|
1162
1144
|
return /* @__PURE__ */ React.createElement(Section, { label: props.label }, /* @__PURE__ */ React.createElement("pre", { className: "lc-ts-desc-body lc-br-dim" }, props.text));
|
|
1163
1145
|
}
|
|
1164
1146
|
/**
|
|
1165
|
-
*
|
|
1166
|
-
*
|
|
1167
|
-
* Owns its own open/closed state for the JSON so two expanded tools stay
|
|
1168
|
-
* independent.
|
|
1147
|
+
* Full tool-row body: description, parsed parameter table (when the schema carries one), raw JSON behind a per-row toggle — the JSON open
|
|
1148
|
+
* state is per-row so two expanded tools stay independent.
|
|
1169
1149
|
*/
|
|
1170
1150
|
function ToolSchema(props) {
|
|
1171
1151
|
const { rich } = props;
|
|
@@ -1210,14 +1190,9 @@ window.__ModuleLoader__.load({
|
|
|
1210
1190
|
}, (jsonOpen ? "▾ " : "▸ ") + (jsonOpen ? props.labels.hide : props.labels.show)), jsonOpen ? /* @__PURE__ */ React.createElement("pre", { className: "lc-ts-desc-body lc-br-dim" }, schemaJson) : null) : null);
|
|
1211
1191
|
}
|
|
1212
1192
|
/**
|
|
1213
|
-
*
|
|
1214
|
-
*
|
|
1215
|
-
*
|
|
1216
|
-
* conversation snapshot's assistant blocks (`kind`: text / reasoning /
|
|
1217
|
-
* tool-call / image, argsRaw). Consecutive images group into one grid
|
|
1218
|
-
* section; `richable` bodies (messages, injections) carry the Raw/MD
|
|
1219
|
-
* switch while tool-result payloads stay raw (structured data, not prose)
|
|
1220
|
-
* and dim; nested tool-result blocks flatten into the same flow.
|
|
1193
|
+
* Both block vocabularies normalize here — raw durable blocks (`type`: text/reasoning/tool-call/tool-result/image) and snapshot assistant
|
|
1194
|
+
* blocks (`kind`: text/reasoning/tool-call/image, argsRaw). Consecutive images group into one grid; tool-result payloads carry the Raw/MD
|
|
1195
|
+
* switch + line count; nested tool-result blocks flatten into the same flow.
|
|
1221
1196
|
*/
|
|
1222
1197
|
function BlocksBody(props) {
|
|
1223
1198
|
const { rich, img, labels } = props;
|
|
@@ -1248,15 +1223,12 @@ window.__ModuleLoader__.load({
|
|
|
1248
1223
|
const blockKind = blk !== null ? typeof blk.type === "string" ? blk.type : typeof blk.kind === "string" ? blk.kind : "" : "";
|
|
1249
1224
|
if ((blockKind === "text" || blockKind === "reasoning") && typeof blk?.text === "string") {
|
|
1250
1225
|
const label = blockKind === "reasoning" ? labels.thinking : props.textLabel;
|
|
1251
|
-
out.push(
|
|
1226
|
+
out.push(/* @__PURE__ */ React.createElement(TextSection, {
|
|
1252
1227
|
key: out.length,
|
|
1253
1228
|
label,
|
|
1254
1229
|
text: blk.text,
|
|
1255
|
-
rich
|
|
1256
|
-
|
|
1257
|
-
key: out.length,
|
|
1258
|
-
label,
|
|
1259
|
-
text: blk.text
|
|
1230
|
+
rich,
|
|
1231
|
+
meta: props.textLabel === labels.result ? /* @__PURE__ */ React.createElement("span", { className: "lc-ts-card-meta" }, labels.lines(blk.text.split("\n").length)) : void 0
|
|
1260
1232
|
}));
|
|
1261
1233
|
continue;
|
|
1262
1234
|
}
|
|
@@ -1289,11 +1261,6 @@ window.__ModuleLoader__.load({
|
|
|
1289
1261
|
flushImages();
|
|
1290
1262
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, out);
|
|
1291
1263
|
}
|
|
1292
|
-
/**
|
|
1293
|
-
* Parse a call's raw argument payload into an object; null when the payload
|
|
1294
|
-
* is missing, malformed, or not a JSON object (callers fall back to the raw
|
|
1295
|
-
* text).
|
|
1296
|
-
*/
|
|
1297
1264
|
function parseArgs(raw) {
|
|
1298
1265
|
if (typeof raw !== "string" || raw === "") return null;
|
|
1299
1266
|
try {
|
|
@@ -1304,11 +1271,8 @@ window.__ModuleLoader__.load({
|
|
|
1304
1271
|
}
|
|
1305
1272
|
}
|
|
1306
1273
|
/**
|
|
1307
|
-
*
|
|
1308
|
-
*
|
|
1309
|
-
* read / write) name their target via `file_path`/`path`/`filePath`. Null
|
|
1310
|
-
* when the arguments hold neither — the row then falls back to the generic
|
|
1311
|
-
* label.
|
|
1274
|
+
* A call's preview: bash-style `description`, or the target path (`file_path`/`path`/`filePath`) for edit/read/write tools; null when the
|
|
1275
|
+
* arguments hold neither.
|
|
1312
1276
|
*/
|
|
1313
1277
|
function summaryIn(args) {
|
|
1314
1278
|
if (args === null) return null;
|
|
@@ -1323,18 +1287,24 @@ window.__ModuleLoader__.load({
|
|
|
1323
1287
|
}
|
|
1324
1288
|
return null;
|
|
1325
1289
|
}
|
|
1326
|
-
/**
|
|
1327
|
-
* The summary of a tool result's own call — the collapsed row's preview.
|
|
1328
|
-
* Null when the call summarizes to nothing.
|
|
1329
|
-
*/
|
|
1330
1290
|
function callSummaryOf(conv) {
|
|
1331
1291
|
return summaryIn(parseArgs(conv?.call?.argsRaw));
|
|
1332
1292
|
}
|
|
1333
1293
|
/**
|
|
1334
|
-
* The
|
|
1335
|
-
*
|
|
1336
|
-
* block summarizes.
|
|
1294
|
+
* The dsh `[exit code: N]` marker across the payload's direct text blocks — surfaced only on the FAILED run-state pill, the one place the
|
|
1295
|
+
* number matters.
|
|
1337
1296
|
*/
|
|
1297
|
+
function exitCodeOf(conv) {
|
|
1298
|
+
if (conv === void 0 || !Array.isArray(conv.content)) return null;
|
|
1299
|
+
for (const b of conv.content) {
|
|
1300
|
+
if (b === null || typeof b !== "object") continue;
|
|
1301
|
+
const blk = b;
|
|
1302
|
+
if (typeof blk.text !== "string") continue;
|
|
1303
|
+
const m = blk.text.match(/\[exit code:\s*(\d+)\]/);
|
|
1304
|
+
if (m !== null) return Number(m[1]);
|
|
1305
|
+
}
|
|
1306
|
+
return null;
|
|
1307
|
+
}
|
|
1338
1308
|
function blockSummaryOf(conv) {
|
|
1339
1309
|
if (conv === void 0 || !Array.isArray(conv.blocks)) return null;
|
|
1340
1310
|
for (const b of conv.blocks) {
|
|
@@ -1345,37 +1315,23 @@ window.__ModuleLoader__.load({
|
|
|
1345
1315
|
}
|
|
1346
1316
|
return null;
|
|
1347
1317
|
}
|
|
1348
|
-
/**
|
|
1349
|
-
* One tool call as a Section, mirroring the tool-definition parameter
|
|
1350
|
-
* card: the head names the call target (mono, with the parsed argument
|
|
1351
|
-
* count), the body lists the arguments as name/value rows. Arguments that
|
|
1352
|
-
* are not a parseable JSON object fall back to the raw payload inside the
|
|
1353
|
-
* same card. Shared by assistant tool-call blocks (`→`) and the call half
|
|
1354
|
-
* of a tool result (`←`).
|
|
1355
|
-
*/
|
|
1356
1318
|
function ToolCallCard(props) {
|
|
1357
1319
|
const args = React.useMemo(() => parseArgs(props.argsRaw), [props.argsRaw]);
|
|
1358
1320
|
return /* @__PURE__ */ React.createElement(Section, {
|
|
1359
1321
|
label: (props.arrow ?? "→") + " " + props.name,
|
|
1360
1322
|
labelClass: "lc-ts-call-name",
|
|
1361
|
-
|
|
1323
|
+
meta: props.status
|
|
1362
1324
|
}, args !== null ? Object.keys(args).map((k) => /* @__PURE__ */ React.createElement(CallArgRow, {
|
|
1363
1325
|
key: k,
|
|
1364
1326
|
name: k,
|
|
1365
1327
|
value: args[k]
|
|
1366
1328
|
})) : typeof props.argsRaw === "string" && props.argsRaw !== "" ? /* @__PURE__ */ React.createElement("pre", { className: "lc-ts-desc-body lc-br-dim" }, props.argsRaw) : null);
|
|
1367
1329
|
}
|
|
1368
|
-
/** One parsed call argument: the name on the left, the value on the right. */
|
|
1369
1330
|
function CallArgRow(props) {
|
|
1370
1331
|
const v = props.value;
|
|
1371
1332
|
const text = typeof v === "string" ? v : v === void 0 ? "" : JSON.stringify(v);
|
|
1372
1333
|
return /* @__PURE__ */ React.createElement("div", { className: "lc-ts-arg-row" }, /* @__PURE__ */ React.createElement("span", { className: "lc-ts-param-name" }, props.name), /* @__PURE__ */ React.createElement("span", { className: "lc-ts-arg-val" }, text));
|
|
1373
1334
|
}
|
|
1374
|
-
/**
|
|
1375
|
-
* The actual content of one surface element, joined from the conversation
|
|
1376
|
-
* snapshot — rendered as a uniform Section stack (see BlocksBody); the
|
|
1377
|
-
* element row's open body wraps the stack in `lc-br-content`.
|
|
1378
|
-
*/
|
|
1379
1335
|
function NodeContent(props) {
|
|
1380
1336
|
const { node, conv, rich, img, labels } = props;
|
|
1381
1337
|
if (conv === void 0) {
|
|
@@ -1394,18 +1350,22 @@ window.__ModuleLoader__.load({
|
|
|
1394
1350
|
img,
|
|
1395
1351
|
labels
|
|
1396
1352
|
});
|
|
1397
|
-
if (conv.kind === "tool-result")
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1353
|
+
if (conv.kind === "tool-result") {
|
|
1354
|
+
const err = node.err === true || conv.isError === true;
|
|
1355
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, conv.call != null ? /* @__PURE__ */ React.createElement(ToolCallCard, {
|
|
1356
|
+
arrow: "←",
|
|
1357
|
+
name: conv.call.name,
|
|
1358
|
+
argsRaw: conv.call.argsRaw,
|
|
1359
|
+
status: labels.callState(err, err ? exitCodeOf(conv) : null)
|
|
1360
|
+
}) : null, Array.isArray(conv.content) ? /* @__PURE__ */ React.createElement(BlocksBody, {
|
|
1361
|
+
blocks: conv.content,
|
|
1362
|
+
richable: false,
|
|
1363
|
+
textLabel: labels.result,
|
|
1364
|
+
rich,
|
|
1365
|
+
img,
|
|
1366
|
+
labels
|
|
1367
|
+
}) : null);
|
|
1368
|
+
}
|
|
1409
1369
|
if (conv.kind === "compaction") return typeof conv.summary === "string" && conv.summary !== "" ? /* @__PURE__ */ React.createElement(TextSection, {
|
|
1410
1370
|
label: labels.summary,
|
|
1411
1371
|
text: conv.summary,
|
|
@@ -1421,19 +1381,16 @@ window.__ModuleLoader__.load({
|
|
|
1421
1381
|
});
|
|
1422
1382
|
return /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, props.hint);
|
|
1423
1383
|
}
|
|
1424
|
-
/** Group an assembled surface's nodes by category (for per-category counts). */
|
|
1425
1384
|
function byCatOf(asm) {
|
|
1426
1385
|
const m = {};
|
|
1427
1386
|
for (const n of asm.nodes) (m[n.cat] ??= []).push(n);
|
|
1428
1387
|
return m;
|
|
1429
1388
|
}
|
|
1430
|
-
/** Count one category's elements in an assembled surface (header cats included). */
|
|
1431
1389
|
function countOf(asm, c) {
|
|
1432
1390
|
if (c === "system") return asm.header !== null && asm.header.system !== void 0 ? 1 : 0;
|
|
1433
1391
|
if (c === "tools") return asm.header !== null ? asm.header.tools.length : 0;
|
|
1434
1392
|
return byCatOf(asm)[c]?.length ?? 0;
|
|
1435
1393
|
}
|
|
1436
|
-
/** The last request of `turn` in a seq-ordered timeline, or null. */
|
|
1437
1394
|
function lastOfTurn(requests, turn) {
|
|
1438
1395
|
for (let i = requests.length - 1; i >= 0; i--) if ((requests[i].turn ?? 0) === turn) return requests[i];
|
|
1439
1396
|
return null;
|
|
@@ -1534,9 +1491,11 @@ window.__ModuleLoader__.load({
|
|
|
1534
1491
|
const toggleElem = (key) => {
|
|
1535
1492
|
setOpenElem(openElem === key ? null : key);
|
|
1536
1493
|
};
|
|
1537
|
-
/**
|
|
1538
|
-
*
|
|
1539
|
-
|
|
1494
|
+
/**
|
|
1495
|
+
* Expandable element row; `err` rows carry the red run-state dot right after the chevron (the chat's failed-tool marker) so a failed
|
|
1496
|
+
* result scans while collapsed.
|
|
1497
|
+
*/
|
|
1498
|
+
const elemRow = (key, tag, preview, tokens, time, body, err = false) => {
|
|
1540
1499
|
const open = openElem === key;
|
|
1541
1500
|
return /* @__PURE__ */ React.createElement("div", {
|
|
1542
1501
|
key,
|
|
@@ -1547,7 +1506,10 @@ window.__ModuleLoader__.load({
|
|
|
1547
1506
|
onClick: () => {
|
|
1548
1507
|
toggleElem(key);
|
|
1549
1508
|
}
|
|
1550
|
-
}, /* @__PURE__ */ React.createElement("span", { className: "lc-br-chev" + (open ? " lc-br-chev-on" : "") }, "▸"),
|
|
1509
|
+
}, /* @__PURE__ */ React.createElement("span", { className: "lc-br-chev" + (open ? " lc-br-chev-on" : "") }, "▸"), err ? /* @__PURE__ */ React.createElement("span", {
|
|
1510
|
+
className: "lc-br-err-dot",
|
|
1511
|
+
title: t("node.failed")
|
|
1512
|
+
}) : null, tag !== null ? /* @__PURE__ */ React.createElement("span", { className: "lc-br-tag" }, tag) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-br-preview" }, preview), time !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-br-time" }, fmtTime(time)) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-br-tokens" }, "≈" + fmt(tokens))), open ? /* @__PURE__ */ React.createElement("div", { className: "lc-br-content" }, body) : null);
|
|
1551
1513
|
};
|
|
1552
1514
|
const catBody = (c) => {
|
|
1553
1515
|
if (c === "system") {
|
|
@@ -1579,17 +1541,18 @@ window.__ModuleLoader__.load({
|
|
|
1579
1541
|
});
|
|
1580
1542
|
}
|
|
1581
1543
|
return (byCat[c] ?? []).slice().reverse().map((n) => {
|
|
1544
|
+
const conv = bySeq.get(n.seq);
|
|
1545
|
+
const rowErr = n.cat === "tool" && (n.err === true || conv !== void 0 && conv.isError === true);
|
|
1582
1546
|
let tag = null;
|
|
1583
1547
|
let preview = nodeText(n);
|
|
1584
1548
|
if (n.cat === "tool") {
|
|
1585
|
-
tag = n.skill ? t("node.skillTag", { name: n.skill }) :
|
|
1586
|
-
preview = callSummaryOf(
|
|
1549
|
+
tag = n.skill ? t("node.skillTag", { name: n.skill }) : n.tool ?? "?";
|
|
1550
|
+
preview = callSummaryOf(conv) ?? t("node.toolResult");
|
|
1587
1551
|
} else if (n.cat === "assistant" && Array.isArray(n.calls) && n.calls.length > 0) {
|
|
1588
1552
|
tag = n.calls.join(" › ");
|
|
1589
|
-
preview = (n.text !== void 0 && n.text !== "" ? n.text : null) ?? blockSummaryOf(
|
|
1590
|
-
} else if (n.cat === "assistant" && (n.text === void 0 || n.text === "")) preview = blockSummaryOf(
|
|
1553
|
+
preview = (n.text !== void 0 && n.text !== "" ? n.text : null) ?? blockSummaryOf(conv) ?? t("node.empty");
|
|
1554
|
+
} else if (n.cat === "assistant" && (n.text === void 0 || n.text === "")) preview = blockSummaryOf(conv) ?? preview;
|
|
1591
1555
|
else if (n.cat === "user") {
|
|
1592
|
-
const conv = bySeq.get(n.seq);
|
|
1593
1556
|
const imgCount = conv !== void 0 && Array.isArray(conv.content) ? conv.content.filter((b) => imageRefOf(b) !== null).length : 0;
|
|
1594
1557
|
if (imgCount > 0 && openElem !== `n${n.seq}`) tag = t("attach.image") + (imgCount > 1 ? " ×" + String(imgCount) : "");
|
|
1595
1558
|
} else if (n.cat === "inject" && !n.skill) {
|
|
@@ -1598,7 +1561,7 @@ window.__ModuleLoader__.load({
|
|
|
1598
1561
|
}
|
|
1599
1562
|
return elemRow(`n${n.seq}`, tag, preview, n.tokens, n.time, /* @__PURE__ */ React.createElement(NodeContent, {
|
|
1600
1563
|
node: n,
|
|
1601
|
-
conv
|
|
1564
|
+
conv,
|
|
1602
1565
|
rich,
|
|
1603
1566
|
img: {
|
|
1604
1567
|
Card: ImageCard,
|
|
@@ -1611,10 +1574,12 @@ window.__ModuleLoader__.load({
|
|
|
1611
1574
|
result: t("block.result"),
|
|
1612
1575
|
summary: t("block.summary"),
|
|
1613
1576
|
images: t("attach.images"),
|
|
1614
|
-
other: t("attach.other")
|
|
1577
|
+
other: t("attach.other"),
|
|
1578
|
+
lines: (n) => t(n === 1 ? "block.line" : "block.lines", { n }),
|
|
1579
|
+
callState: (err, exit) => /* @__PURE__ */ React.createElement("span", { className: "lc-ts-call-state " + (err ? "lc-ts-call-err" : "lc-ts-call-ok") }, /* @__PURE__ */ React.createElement("i", null), err ? t("call.fail") + (exit !== null ? " · " + t("call.exit", { n: exit }) : "") : t("call.ok"))
|
|
1615
1580
|
},
|
|
1616
|
-
hint:
|
|
1617
|
-
}));
|
|
1581
|
+
hint: conv === void 0 && awaiting ? t("browser.loading") : t("browser.noContent")
|
|
1582
|
+
}), rowErr);
|
|
1618
1583
|
});
|
|
1619
1584
|
};
|
|
1620
1585
|
return /* @__PURE__ */ React.createElement("div", { className: "lc-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, /* @__PURE__ */ React.createElement("span", { className: "lc-card-title-text" }, t("browser.title")), /* @__PURE__ */ React.createElement("span", { className: "lc-br-hint" }, t("browser.deltaHint")), /* @__PURE__ */ React.createElement("select", {
|
|
@@ -1669,12 +1634,9 @@ window.__ModuleLoader__.load({
|
|
|
1669
1634
|
//#endregion
|
|
1670
1635
|
//#region src/client/components/stackedBar.tsx
|
|
1671
1636
|
/**
|
|
1672
|
-
*
|
|
1673
|
-
*
|
|
1674
|
-
*
|
|
1675
|
-
* reached). DSH does not publish the configured ratio to plugins or clients,
|
|
1676
|
-
* so the UI mirrors the default here; deployments that tune `thresholdRatio`
|
|
1677
|
-
* / `modelPolicies` can adjust it if they want the reserve band to match.
|
|
1637
|
+
* Mirror of dsh-compaction-basic's default `thresholdRatio` (0.8): it compacts at step boundaries once `floor(contextWindow × ratio)` is
|
|
1638
|
+
* reached; DSH does not publish the configured ratio to plugins/clients, so the reserve band mirrors the default — deployments tuning
|
|
1639
|
+
* `thresholdRatio`/`modelPolicies` should adjust it to match.
|
|
1678
1640
|
*/
|
|
1679
1641
|
const AUTO_COMPACT_RATIO = .8;
|
|
1680
1642
|
function makeStackedBar(kit) {
|
|
@@ -1945,7 +1907,6 @@ window.__ModuleLoader__.load({
|
|
|
1945
1907
|
}
|
|
1946
1908
|
//#endregion
|
|
1947
1909
|
//#region src/client/components/settingsCard.tsx
|
|
1948
|
-
/** One preference row: label + selector pill opening the framework Menu. */
|
|
1949
1910
|
function PrefRow(props) {
|
|
1950
1911
|
const [open, setOpen] = React.useState(false);
|
|
1951
1912
|
const active = props.options.find((o) => o.id === props.value)?.label ?? props.value;
|
|
@@ -2025,7 +1986,6 @@ window.__ModuleLoader__.load({
|
|
|
2025
1986
|
}
|
|
2026
1987
|
//#endregion
|
|
2027
1988
|
//#region src/client/settings.ts
|
|
2028
|
-
/** Read the known preferences out of a raw section; unknown/absent fields drop out. */
|
|
2029
1989
|
function prefsOf(value) {
|
|
2030
1990
|
if (value === null || typeof value !== "object") return {};
|
|
2031
1991
|
const v = value;
|
|
@@ -2093,7 +2053,6 @@ window.__ModuleLoader__.load({
|
|
|
2093
2053
|
model: "⇄",
|
|
2094
2054
|
mode: "⇄"
|
|
2095
2055
|
};
|
|
2096
|
-
/** Build the event text helpers bound to the translate function. */
|
|
2097
2056
|
function makeEventText(t) {
|
|
2098
2057
|
function eventLabel(ev) {
|
|
2099
2058
|
if (ev.kind === "compaction") return t("ev.compaction", { n: ev.count || 0 });
|
|
@@ -2110,11 +2069,8 @@ window.__ModuleLoader__.load({
|
|
|
2110
2069
|
return label;
|
|
2111
2070
|
}
|
|
2112
2071
|
/**
|
|
2113
|
-
* Where this event sits in the
|
|
2114
|
-
*
|
|
2115
|
-
* "Step 2→3", cross-turn "Turn 50 · Step 8 → Turn 51 · Step 1". Injections
|
|
2116
|
-
* and model switches belong to one request and keep the single point.
|
|
2117
|
-
* Events with no following request (in flight) stay unlabeled.
|
|
2072
|
+
* Where this event sits in the timeline: boundary events (compaction/prune) label the GAP they sit in — same-turn 'Turn 2 · Step 3→4',
|
|
2073
|
+
* cross-turn 'Turn 50 · Step 8 → Turn 51 · Step 1'; other kinds keep their single point; no turn/step (in flight) → null.
|
|
2118
2074
|
*/
|
|
2119
2075
|
function eventAt(ev) {
|
|
2120
2076
|
if (ev.kind === "compaction" || ev.kind === "prune") {
|
|
@@ -2183,20 +2139,14 @@ window.__ModuleLoader__.load({
|
|
|
2183
2139
|
};
|
|
2184
2140
|
}
|
|
2185
2141
|
const PLUGIN_REPO = "https://github.com/bowenliang123/dsh-context";
|
|
2186
|
-
/** Short `owner/repo` form of the GitHub URL, for display only. */
|
|
2187
2142
|
const PLUGIN_REPO_SHORT = PLUGIN_REPO.replace(/^https?:\/\/github\.com\//, "");
|
|
2188
2143
|
//#endregion
|
|
2189
2144
|
//#region src/client/latestVersion.ts
|
|
2190
2145
|
/**
|
|
2191
|
-
*
|
|
2192
|
-
*
|
|
2193
|
-
* card mount and cached with a 1-hour TTL, so the registry is hit at most
|
|
2194
|
-
* once per hour per page. Every failure mode (offline, CSP-blocked,
|
|
2195
|
-
* non-200, malformed body) narrows to null = no upgrade hint, so the card
|
|
2196
|
-
* silently keeps its static version.
|
|
2146
|
+
* One live check for the Plugin-info card: lazy with 1h TTL; every failure
|
|
2147
|
+
* mode narrows to null so the card silently keeps its static version.
|
|
2197
2148
|
*/
|
|
2198
2149
|
const REGISTRY_URL = "https://registry.npmjs.org/dsh-context/latest";
|
|
2199
|
-
/** How long a registry result stays fresh before the next check refetches. */
|
|
2200
2150
|
const TTL_MS = 36e5;
|
|
2201
2151
|
let cached = null;
|
|
2202
2152
|
function fetchLatestVersion() {
|
|
@@ -2231,7 +2181,7 @@ window.__ModuleLoader__.load({
|
|
|
2231
2181
|
return function PluginInfo() {
|
|
2232
2182
|
const [latest, setLatest] = React.useState(null);
|
|
2233
2183
|
React.useEffect(() => {
|
|
2234
|
-
if ("0.
|
|
2184
|
+
if ("0.30.1".includes("-dev")) return;
|
|
2235
2185
|
let on = true;
|
|
2236
2186
|
fetchLatestVersion().then((v) => {
|
|
2237
2187
|
if (on && v) setLatest(v);
|
|
@@ -2240,8 +2190,8 @@ window.__ModuleLoader__.load({
|
|
|
2240
2190
|
on = false;
|
|
2241
2191
|
};
|
|
2242
2192
|
}, []);
|
|
2243
|
-
const update = latest !== null && isNewerVersion(latest, "0.
|
|
2244
|
-
const nameValue = ["dsh-context (v0.
|
|
2193
|
+
const update = latest !== null && isNewerVersion(latest, "0.30.1") ? latest : null;
|
|
2194
|
+
const nameValue = ["dsh-context (v0.30.1)"];
|
|
2245
2195
|
if (update) nameValue.push(/* @__PURE__ */ React.createElement("span", {
|
|
2246
2196
|
key: "update",
|
|
2247
2197
|
className: "lc-pi-update"
|
|
@@ -2269,7 +2219,7 @@ window.__ModuleLoader__.load({
|
|
|
2269
2219
|
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", {
|
|
2270
2220
|
className: "lc-detail-marker",
|
|
2271
2221
|
title: eventLabel(marker)
|
|
2272
|
-
}, "✂ " + markerAt) : null, isTurn ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-tag" }, t("detail.lastStep")) : null, /* @__PURE__ */ React.createElement("span", null, fmtTime(req.time)), /* @__PURE__ */ React.createElement("span",
|
|
2222
|
+
}, "✂ " + markerAt) : null, isTurn ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-tag" }, t("detail.lastStep")) : null, /* @__PURE__ */ React.createElement("span", null, fmtTime(req.time)), req.prompt !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-actual" }, t("detail.actual", { n: fmt(req.prompt) })) : null, req.output !== void 0 ? /* @__PURE__ */ React.createElement("span", null, t("detail.output", { n: fmt(req.output) })) : null, req.prompt !== void 0 && req.cacheRead !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-cache" }, t("detail.cache", { n: cacheHitPercent$1(req.cacheRead, req.prompt) ?? "—" })) : null), /* @__PURE__ */ React.createElement(StackedBar, {
|
|
2273
2223
|
parts: partsOf(req),
|
|
2274
2224
|
height: 10
|
|
2275
2225
|
}), /* @__PURE__ */ React.createElement("div", { className: "lc-detail-rows" }, CATS.map((c) => {
|
|
@@ -2366,7 +2316,6 @@ window.__ModuleLoader__.load({
|
|
|
2366
2316
|
}
|
|
2367
2317
|
return any ? total : null;
|
|
2368
2318
|
}
|
|
2369
|
-
/** Short money format: two decimals at and above one unit, two significant digits below. */
|
|
2370
2319
|
function formatCost(amount, currency) {
|
|
2371
2320
|
return (currency === "cny" ? "¥" : "$") + (amount >= 1 ? amount.toFixed(2) : amount.toPrecision(2));
|
|
2372
2321
|
}
|
|
@@ -2391,24 +2340,15 @@ window.__ModuleLoader__.load({
|
|
|
2391
2340
|
//#endregion
|
|
2392
2341
|
//#region src/client/components/statsBoard.tsx
|
|
2393
2342
|
/**
|
|
2394
|
-
* Cache-hit share of billed prompt-side input — same
|
|
2395
|
-
*
|
|
2396
|
-
*
|
|
2397
|
-
* whole-percent rounding, this one TRUNCATES to two decimal places (cut, not
|
|
2398
|
-
* round). Null when no input was billed. A tiny epsilon keeps a double stored
|
|
2399
|
-
* a hair below a cent boundary (e.g. 80.00 as 79.9999999999…) from losing its
|
|
2400
|
-
* last digit — with integer token counts no genuine value ever sits that close
|
|
2401
|
-
* to a boundary, so the epsilon can only absorb float noise. Bucket reads go
|
|
2402
|
-
* through numOf so a malformed payload degrades to a dash instead of NaN text.
|
|
2343
|
+
* Cache-hit share of billed prompt-side input — same three disjoint buckets
|
|
2344
|
+
* as the harness chat line (`cacheReadTokens` over uncached + reads + writes)
|
|
2345
|
+
* and the step line's 缓存 figure; null when nothing was billed.
|
|
2403
2346
|
*/
|
|
2404
2347
|
function cacheHitPercent(usage) {
|
|
2405
2348
|
const uncached = numOf(usage.uncachedInputTokens);
|
|
2406
2349
|
const reads = numOf(usage.cacheReadTokens);
|
|
2407
2350
|
const writes = numOf(usage.cacheWriteTokens);
|
|
2408
|
-
|
|
2409
|
-
if (billed === 0) return null;
|
|
2410
|
-
const hundredths = Math.trunc(reads / billed * 1e4 + 1e-9);
|
|
2411
|
-
return `${Math.floor(hundredths / 100)}.${String(hundredths % 100).padStart(2, "0")}`;
|
|
2351
|
+
return cacheHitPercent$1(reads, uncached + reads + writes);
|
|
2412
2352
|
}
|
|
2413
2353
|
function makeStatsBoard(kit) {
|
|
2414
2354
|
const { t, fmt } = kit;
|
|
@@ -2446,12 +2386,8 @@ window.__ModuleLoader__.load({
|
|
|
2446
2386
|
//#endregion
|
|
2447
2387
|
//#region src/client/components/trendChart.tsx
|
|
2448
2388
|
/**
|
|
2449
|
-
* Collapse
|
|
2450
|
-
*
|
|
2451
|
-
* finished), tagged with the number of steps the turn spans so the bar can
|
|
2452
|
-
* keep the turn's column width and the detail can label it. Requests of one
|
|
2453
|
-
* turn are consecutive in the log, so a run of equal turns is replaced by
|
|
2454
|
-
* its final record.
|
|
2389
|
+
* Collapse per-step requests into one bar per turn — each turn is represented by its LAST step's record, tagged `stepCount` for the bar's
|
|
2390
|
+
* column width; the log keeps one turn's requests consecutive, so a run of equal turns collapses to its final record.
|
|
2455
2391
|
*/
|
|
2456
2392
|
function aggregateByTurn(requests) {
|
|
2457
2393
|
const out = [];
|
|
@@ -2475,10 +2411,8 @@ window.__ModuleLoader__.load({
|
|
|
2475
2411
|
return out;
|
|
2476
2412
|
}
|
|
2477
2413
|
/**
|
|
2478
|
-
* Attach each boundary event (compaction/prune) to the first request
|
|
2479
|
-
*
|
|
2480
|
-
* the bar and the range chip in the detail header. Shared by TrendChart
|
|
2481
|
-
* and the detail panel so both show the SAME event for a request.
|
|
2414
|
+
* Attach each boundary event (compaction/prune) to the first request logged after it — one entry per index, for the ✂ marker and the detail
|
|
2415
|
+
* chip; shared with the detail panel so both show the SAME event.
|
|
2482
2416
|
*/
|
|
2483
2417
|
function attachMarkers(requests, events) {
|
|
2484
2418
|
const markers = new Array(requests.length);
|
|
@@ -2500,14 +2434,8 @@ window.__ModuleLoader__.load({
|
|
|
2500
2434
|
const anchorOf = (req) => typeof req.prompt === "number" && req.prompt > 0 && req.total > 0 ? req.prompt / req.total : 1;
|
|
2501
2435
|
const barTotalOf = (req) => typeof req.prompt === "number" && req.prompt > 0 ? req.prompt : req.total;
|
|
2502
2436
|
/**
|
|
2503
|
-
*
|
|
2504
|
-
*
|
|
2505
|
-
* change, stacked like the cumulative bars), `total` becomes the summed
|
|
2506
|
-
* magnitude, and `net` keeps the signed change for the tooltip. The first
|
|
2507
|
-
* request (no previous) diff from empty is zero, so the diff mode's scale
|
|
2508
|
-
* is driven purely by inter-request changes rather than the initial
|
|
2509
|
-
* cumulative baseline. Provider prompt/output are dropped: they are
|
|
2510
|
-
* per-request values, not diffs.
|
|
2437
|
+
* Diff mode: each category becomes |current − previous|, `total` the summed magnitude, `net` the signed change for the tooltip; the first
|
|
2438
|
+
* request diffs from zero so the scale is change-driven, and per-request provider prompt/output are dropped (they are not diffs).
|
|
2511
2439
|
*/
|
|
2512
2440
|
const diffOf = (req, prev) => {
|
|
2513
2441
|
const out = { ...req };
|
|
@@ -2577,6 +2505,17 @@ window.__ModuleLoader__.load({
|
|
|
2577
2505
|
grp.count++;
|
|
2578
2506
|
grp.span += req.stepCount ?? 1;
|
|
2579
2507
|
}
|
|
2508
|
+
const turnOffsets = [];
|
|
2509
|
+
const turnWidths = [];
|
|
2510
|
+
{
|
|
2511
|
+
let x = 0;
|
|
2512
|
+
for (const grp of groups) {
|
|
2513
|
+
const w = grp.agg ? BAR_W : grp.span * 16 - BAR_GAP;
|
|
2514
|
+
turnOffsets.push(x);
|
|
2515
|
+
turnWidths.push(w);
|
|
2516
|
+
x += w + BAR_GAP;
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2580
2519
|
const scrollRef = React.useRef(null);
|
|
2581
2520
|
const scrolledOnce = React.useRef(false);
|
|
2582
2521
|
const lastGranRef = React.useRef(props.granularity);
|
|
@@ -2599,6 +2538,35 @@ window.__ModuleLoader__.load({
|
|
|
2599
2538
|
right
|
|
2600
2539
|
});
|
|
2601
2540
|
};
|
|
2541
|
+
/**
|
|
2542
|
+
* Keep each turn label centered within its block's VISIBLE slice so it never scrolls out while any part of the block is on screen
|
|
2543
|
+
* (narrower-than-label blocks stay put); reads (offsetWidth) batch before writes (transform) to avoid layout thrash — out-of-view
|
|
2544
|
+
* blocks need no measurement.
|
|
2545
|
+
*/
|
|
2546
|
+
const updateTurnLabels = (el) => {
|
|
2547
|
+
const labels = el.querySelectorAll(".lc-turn-label");
|
|
2548
|
+
const n = Math.min(labels.length, turnOffsets.length);
|
|
2549
|
+
const sl = el.scrollLeft;
|
|
2550
|
+
const vr = sl + el.clientWidth;
|
|
2551
|
+
const writes = [];
|
|
2552
|
+
for (let i = 0; i < n; i++) {
|
|
2553
|
+
const off = turnOffsets[i];
|
|
2554
|
+
const w = turnWidths[i];
|
|
2555
|
+
const visL = Math.max(off, sl);
|
|
2556
|
+
const visR = Math.min(off + w, vr);
|
|
2557
|
+
let dx = 0;
|
|
2558
|
+
if (visR > visL) {
|
|
2559
|
+
const lw = labels[i].offsetWidth;
|
|
2560
|
+
if (lw < w) {
|
|
2561
|
+
const center = (visL + visR) / 2 - off;
|
|
2562
|
+
dx = Math.min(Math.max(center, lw / 2), w - lw / 2) - w / 2;
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
const next = dx !== 0 ? `translateX(${dx}px)` : "";
|
|
2566
|
+
if (labels[i].style.transform !== next) writes.push([labels[i], next]);
|
|
2567
|
+
}
|
|
2568
|
+
for (const [label, next] of writes) label.style.transform = next;
|
|
2569
|
+
};
|
|
2602
2570
|
React.useLayoutEffect(() => {
|
|
2603
2571
|
const el = scrollRef.current;
|
|
2604
2572
|
if (el === null) return;
|
|
@@ -2619,6 +2587,7 @@ window.__ModuleLoader__.load({
|
|
|
2619
2587
|
el.scrollLeft = el.scrollWidth;
|
|
2620
2588
|
} else if (el.scrollLeft + el.clientWidth >= el.scrollWidth - 24) el.scrollLeft = el.scrollWidth;
|
|
2621
2589
|
updateEdges(el);
|
|
2590
|
+
updateTurnLabels(el);
|
|
2622
2591
|
});
|
|
2623
2592
|
const tipOf = (req) => {
|
|
2624
2593
|
const head = req.stepCount !== void 0 && req.stepCount > 1 ? t("tip.turn", {
|
|
@@ -2641,6 +2610,7 @@ window.__ModuleLoader__.load({
|
|
|
2641
2610
|
ref: scrollRef,
|
|
2642
2611
|
onScroll: (e) => {
|
|
2643
2612
|
updateEdges(e.currentTarget);
|
|
2613
|
+
updateTurnLabels(e.currentTarget);
|
|
2644
2614
|
}
|
|
2645
2615
|
}, edges.left ? /* @__PURE__ */ React.createElement("div", { className: "lc-chart-fade lc-chart-fade-l" }) : null, /* @__PURE__ */ React.createElement("div", {
|
|
2646
2616
|
className: "lc-chart",
|
|
@@ -2667,12 +2637,11 @@ window.__ModuleLoader__.load({
|
|
|
2667
2637
|
}
|
|
2668
2638
|
}, groups.map((grp, gi) => {
|
|
2669
2639
|
const on = props.activeTurn === grp.turn;
|
|
2670
|
-
const blockW = grp.agg ? BAR_W : grp.span * 16 - BAR_GAP;
|
|
2671
2640
|
return /* @__PURE__ */ React.createElement("span", {
|
|
2672
2641
|
key: `turn-${gi}`,
|
|
2673
2642
|
className: "lc-turn" + (on ? " lc-turn-on" : ""),
|
|
2674
2643
|
style: {
|
|
2675
|
-
width: `${
|
|
2644
|
+
width: `${turnWidths[gi]}px`,
|
|
2676
2645
|
background: TURN_FILLS[gi % TURN_FILLS.length]
|
|
2677
2646
|
},
|
|
2678
2647
|
title: `T${grp.turn}`,
|
|
@@ -2682,7 +2651,7 @@ window.__ModuleLoader__.load({
|
|
|
2682
2651
|
onClick: () => {
|
|
2683
2652
|
props.onPickTurn(grp.turn);
|
|
2684
2653
|
}
|
|
2685
|
-
}, `T${grp.turn}`);
|
|
2654
|
+
}, /* @__PURE__ */ React.createElement("span", { className: "lc-turn-label" }, `T${grp.turn}`));
|
|
2686
2655
|
}))), edges.right ? /* @__PURE__ */ React.createElement("div", { className: "lc-chart-fade lc-chart-fade-r" }) : null);
|
|
2687
2656
|
};
|
|
2688
2657
|
}
|
|
@@ -2906,7 +2875,7 @@ window.__ModuleLoader__.load({
|
|
|
2906
2875
|
}
|
|
2907
2876
|
//#endregion
|
|
2908
2877
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles.css.mjs
|
|
2909
|
-
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-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-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-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;gap:6px 16px;margin-bottom:8px;display:flex}.lc-detail-head b{color:var(--dsw-alias-label-primary)}.lc-detail-marker{color:var(--dsw-alias-state-warn-primary);background:var(--dsw-alias-bg-layer-2);border-radius:6px;padding:1px 7px;font-size:11px}.lc-detail-head .lc-actual{color:var(--dsw-alias-state-success-primary)}.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-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;overflow:hidden}.lc-bar-fill{border-radius:3px;height:100%;display:block}.lc-detail-num{text-align:right;width:44px}.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-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;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-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;scrollbar-width:thin;max-height:320px;padding:4px 10px;font-size:12px;line-height:1.55;overflow-y: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,.lc-ts-desc-md div pre{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}";
|
|
2878
|
+
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-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-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;gap:6px 16px;margin-bottom:8px;display:flex}.lc-detail-head b{color:var(--dsw-alias-label-primary)}.lc-detail-marker{color:var(--dsw-alias-state-warn-primary);background:var(--dsw-alias-bg-layer-2);border-radius:6px;padding:1px 7px;font-size:11px}.lc-detail-head .lc-actual,.lc-detail-head .lc-cache{color:var(--dsw-alias-state-success-primary)}.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-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;overflow:hidden}.lc-bar-fill{border-radius:3px;height:100%;display:block}.lc-detail-num{text-align:right;width:44px}.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}";
|
|
2910
2879
|
const tagId = "dsh-context/styles.css";
|
|
2911
2880
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
2912
2881
|
const tag = document.createElement("style");
|