dsh-context 0.28.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/cordis.patch.yml +3 -7
- package/lib/client.js +336 -201
- package/lib/index.d.ts +15 -54
- package/lib/index.js +32 -33
- package/package.json +7 -2
package/lib/client.js
CHANGED
|
@@ -44,6 +44,13 @@ window.__ModuleLoader__.load({
|
|
|
44
44
|
"trend.title": "历史趋势",
|
|
45
45
|
"gran.step": "步骤",
|
|
46
46
|
"gran.turn": "轮次",
|
|
47
|
+
"settings.title": "上下文",
|
|
48
|
+
"settings.desc": "上下文面板的展示偏好",
|
|
49
|
+
"settings.gran": "趋势图默认粒度",
|
|
50
|
+
"settings.mode": "趋势图默认展示",
|
|
51
|
+
"settings.expand": "展开",
|
|
52
|
+
"settings.collapse": "收起",
|
|
53
|
+
"settings.readOnly": "当前环境的设置为只读",
|
|
47
54
|
"gran.total": "全量",
|
|
48
55
|
"gran.diff": "增量",
|
|
49
56
|
"gran.modeHint": "全量:累计构成;增量:相对上一条请求的变化量",
|
|
@@ -125,6 +132,12 @@ window.__ModuleLoader__.load({
|
|
|
125
132
|
"block.content": "内容",
|
|
126
133
|
"block.result": "结果",
|
|
127
134
|
"block.summary": "摘要",
|
|
135
|
+
"block.line": "{n} 行",
|
|
136
|
+
"block.lines": "{n} 行",
|
|
137
|
+
"call.ok": "正常",
|
|
138
|
+
"call.fail": "失败",
|
|
139
|
+
"call.exit": "exit {n}",
|
|
140
|
+
"node.failed": "工具执行失败",
|
|
128
141
|
"attach.images": "图片附件",
|
|
129
142
|
"attach.other": "其他内容",
|
|
130
143
|
"attach.image": "图片",
|
|
@@ -177,6 +190,13 @@ window.__ModuleLoader__.load({
|
|
|
177
190
|
"trend.title": "Context History",
|
|
178
191
|
"gran.step": "Step",
|
|
179
192
|
"gran.turn": "Turn",
|
|
193
|
+
"settings.title": "Context",
|
|
194
|
+
"settings.desc": "Display preferences for the Context panel",
|
|
195
|
+
"settings.gran": "Default trend granularity",
|
|
196
|
+
"settings.mode": "Default trend display",
|
|
197
|
+
"settings.expand": "Expand",
|
|
198
|
+
"settings.collapse": "Collapse",
|
|
199
|
+
"settings.readOnly": "Settings are read-only in this environment",
|
|
180
200
|
"gran.total": "Total",
|
|
181
201
|
"gran.diff": "Diff",
|
|
182
202
|
"gran.modeHint": "Total: cumulative makeup; Diff: change vs the previous request",
|
|
@@ -258,6 +278,12 @@ window.__ModuleLoader__.load({
|
|
|
258
278
|
"block.content": "Content",
|
|
259
279
|
"block.result": "Result",
|
|
260
280
|
"block.summary": "Summary",
|
|
281
|
+
"block.line": "1 line",
|
|
282
|
+
"block.lines": "{n} lines",
|
|
283
|
+
"call.ok": "OK",
|
|
284
|
+
"call.fail": "Failed",
|
|
285
|
+
"call.exit": "exit {n}",
|
|
286
|
+
"node.failed": "Tool execution failed",
|
|
261
287
|
"attach.images": "Images",
|
|
262
288
|
"attach.other": "Other content",
|
|
263
289
|
"attach.image": "Image",
|
|
@@ -300,7 +326,6 @@ window.__ModuleLoader__.load({
|
|
|
300
326
|
function setPendingConsume(sessionId, guard) {
|
|
301
327
|
pendingConsume.set(sessionId, guard);
|
|
302
328
|
}
|
|
303
|
-
/** Take (and clear) the guard recorded by the open path, if any. */
|
|
304
329
|
function takePendingConsume(sessionId) {
|
|
305
330
|
const guard = pendingConsume.get(sessionId);
|
|
306
331
|
if (guard !== void 0) pendingConsume.delete(sessionId);
|
|
@@ -500,7 +525,6 @@ window.__ModuleLoader__.load({
|
|
|
500
525
|
function numOf(value) {
|
|
501
526
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
502
527
|
}
|
|
503
|
-
/** The usable (non-null object) entries of a delivered list; [] when the field is not a list. */
|
|
504
528
|
function objectsOf(value) {
|
|
505
529
|
if (!Array.isArray(value)) return [];
|
|
506
530
|
return value.filter((v) => v !== null && typeof v === "object");
|
|
@@ -630,10 +654,6 @@ window.__ModuleLoader__.load({
|
|
|
630
654
|
for (let i = headers.headers.length - 1; i >= 0; i--) if (headers.headers[i].seq < seq) return headers.headers[i];
|
|
631
655
|
return null;
|
|
632
656
|
}
|
|
633
|
-
/**
|
|
634
|
-
* Reconstruct the assembled surface for one step (`seq` = the request
|
|
635
|
-
* record's seq) or the live surface (`seq` = null).
|
|
636
|
-
*/
|
|
637
657
|
function assemble(data, headers, seq) {
|
|
638
658
|
const live = seq === null;
|
|
639
659
|
let nodes;
|
|
@@ -665,7 +685,6 @@ window.__ModuleLoader__.load({
|
|
|
665
685
|
const ReactDOM = require("react-dom");
|
|
666
686
|
//#endregion
|
|
667
687
|
//#region src/client/components/nodes.tsx
|
|
668
|
-
/** One-line preview of a surface node (shared by the node list and the Context browser's element rows). */
|
|
669
688
|
function makeNodeText(kit) {
|
|
670
689
|
const { t } = kit;
|
|
671
690
|
return function nodeText(n) {
|
|
@@ -700,10 +719,7 @@ window.__ModuleLoader__.load({
|
|
|
700
719
|
}
|
|
701
720
|
//#endregion
|
|
702
721
|
//#region src/client/format.ts
|
|
703
|
-
/**
|
|
704
|
-
* Number/time formatting for the UI. `fmt` uses the same k/M suffix style
|
|
705
|
-
* everywhere (bars, details, stats); `fmtTime` renders a local HH:MM:SS.
|
|
706
|
-
*/
|
|
722
|
+
/** `fmt`: the k/M suffix style shared by bars/details/stats; `fmtTime`: local HH:MM:SS. */
|
|
707
723
|
function fmt(n) {
|
|
708
724
|
if (n === void 0 || n === null || isNaN(n)) return "—";
|
|
709
725
|
const sign = n < 0 ? "-" : "";
|
|
@@ -753,7 +769,6 @@ window.__ModuleLoader__.load({
|
|
|
753
769
|
const MIN_PIXELS = 147456;
|
|
754
770
|
const floorDiv = (a, b) => Math.floor(a / b);
|
|
755
771
|
const ceilDiv = (a, b) => Math.floor((a + b - 1) / b);
|
|
756
|
-
/** Token count of one patch grid (rows×cols) under the v4 layout rule. */
|
|
757
772
|
function gridTokens(rows, cols) {
|
|
758
773
|
let n = rows * (cols + 1) + 2;
|
|
759
774
|
if (rows % 2 === 1) n += cols + 1;
|
|
@@ -835,10 +850,8 @@ window.__ModuleLoader__.load({
|
|
|
835
850
|
return safeResize(h, w, paddedHeight, paddedWidth);
|
|
836
851
|
}
|
|
837
852
|
/**
|
|
838
|
-
* Estimate the tokens one image consumes in a DeepSeek vision request
|
|
839
|
-
*
|
|
840
|
-
* or when the official iteration fails to converge — callers fall back to
|
|
841
|
-
* the generic structural price.
|
|
853
|
+
* Estimate the tokens one image consumes in a DeepSeek vision request from its pixel dimensions. Returns null for non-positive/non-finite
|
|
854
|
+
* dimensions or when the official iteration fails to converge — callers fall back to the generic structural price.
|
|
842
855
|
*/
|
|
843
856
|
function estimateImageTokens(width, height) {
|
|
844
857
|
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return null;
|
|
@@ -857,11 +870,9 @@ window.__ModuleLoader__.load({
|
|
|
857
870
|
//#endregion
|
|
858
871
|
//#region src/client/components/images.tsx
|
|
859
872
|
/**
|
|
860
|
-
* Narrow an unknown content block to a durable image
|
|
861
|
-
*
|
|
862
|
-
*
|
|
863
|
-
* else returns null. Lenient on the ref's optional facts (name/bytes/dims) —
|
|
864
|
-
* `resolveImage` reads only `attachmentId`.
|
|
873
|
+
* Narrow an unknown content block to a durable image ref: accepts both raw message blocks (`{ type: 'image', attachment }`) and the
|
|
874
|
+
* snapshot's assistant blocks (`{ kind: 'image', attachment }`); everything else null. Lenient on the optional facts — resolveImage reads
|
|
875
|
+
* only attachmentId.
|
|
865
876
|
*/
|
|
866
877
|
function imageRefOf(block) {
|
|
867
878
|
if (block === null || typeof block !== "object") return null;
|
|
@@ -887,12 +898,9 @@ window.__ModuleLoader__.load({
|
|
|
887
898
|
};
|
|
888
899
|
}
|
|
889
900
|
/**
|
|
890
|
-
* Document-level original-image preview — the chat history's ImageLightbox
|
|
891
|
-
*
|
|
892
|
-
*
|
|
893
|
-
* filtered ancestor cannot trap the fixed backdrop, blurred mask layer,
|
|
894
|
-
* contain-fit image, circular close control, Escape/mask close, and focus
|
|
895
|
-
* restored to the opener on unmount.
|
|
901
|
+
* Document-level original-image preview — the chat history's ImageLightbox recipe (dsh ui-attachment, which the browser module table does
|
|
902
|
+
* not seed) ported onto the plugin's lc-* classes: body portal (a transformed/filtered ancestor cannot trap the fixed backdrop), blurred
|
|
903
|
+
* mask, contain-fit image, circular close, Escape/mask close, focus restored to the opener.
|
|
896
904
|
*/
|
|
897
905
|
function AttachmentLightbox(props) {
|
|
898
906
|
const { src, alt, labels, onClose } = props;
|
|
@@ -932,13 +940,9 @@ window.__ModuleLoader__.load({
|
|
|
932
940
|
}, /* @__PURE__ */ React.createElement(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 16 }))), document.body);
|
|
933
941
|
}
|
|
934
942
|
/**
|
|
935
|
-
* One attachment card
|
|
936
|
-
*
|
|
937
|
-
*
|
|
938
|
-
* normalization reduced the image; Sent, the normalized raster the model
|
|
939
|
-
* receives, with its stored byte size; and the estimated provider-billed
|
|
940
|
-
* tokens). Clicking opens the chat-style lightbox preview (load failures
|
|
941
|
-
* retry on click instead). Unknown facts leave no row behind.
|
|
943
|
+
* One attachment card, the WHOLE card the click target: 64px cover tile + metadata column — Raw (the pre-normalization raster dsh records
|
|
944
|
+
* when normalization reduced the image), Sent (the normalized raster the model receives, with byte size), estimated provider-billed tokens.
|
|
945
|
+
* Click opens the chat-style lightbox; load failures retry on click; unknown facts leave no row.
|
|
942
946
|
*/
|
|
943
947
|
function makeImageCard(kit) {
|
|
944
948
|
const { t, fmt } = kit;
|
|
@@ -1052,7 +1056,6 @@ window.__ModuleLoader__.load({
|
|
|
1052
1056
|
}
|
|
1053
1057
|
//#endregion
|
|
1054
1058
|
//#region src/client/components/browser.tsx
|
|
1055
|
-
/** Flatten the `anyOf` / `oneOf` alternation into one displayable string. */
|
|
1056
1059
|
function unionTypesOf(p) {
|
|
1057
1060
|
const branches = [];
|
|
1058
1061
|
if (Array.isArray(p.anyOf)) branches.push(...p.anyOf);
|
|
@@ -1062,12 +1065,6 @@ window.__ModuleLoader__.load({
|
|
|
1062
1065
|
for (const b of branches) if (b !== null && typeof b === "object") parts.push(typeOf(b));
|
|
1063
1066
|
return parts.length > 0 ? parts.join(" | ") : null;
|
|
1064
1067
|
}
|
|
1065
|
-
/**
|
|
1066
|
-
* Derive a short, human-readable type label from a JSON Schema fragment.
|
|
1067
|
-
* Arrays show their element type (`array<number>`); unions fold into
|
|
1068
|
-
* `a | b`; enums collapse into `(enum)`. Returns `unknown` when the schema
|
|
1069
|
-
* carries no usable signal — the row falls back to its description then.
|
|
1070
|
-
*/
|
|
1071
1068
|
function typeOf(p) {
|
|
1072
1069
|
const u = unionTypesOf(p);
|
|
1073
1070
|
if (u !== null) return u;
|
|
@@ -1089,9 +1086,8 @@ window.__ModuleLoader__.load({
|
|
|
1089
1086
|
return "unknown";
|
|
1090
1087
|
}
|
|
1091
1088
|
/**
|
|
1092
|
-
*
|
|
1093
|
-
*
|
|
1094
|
-
* the schema as the bare JSON Schema (when `type === 'object'`).
|
|
1089
|
+
* Tool schemas nest parameters under `parameters`, `input_schema`, or `inputSchema` (producer-dependent), or bare when `type === 'object'`
|
|
1090
|
+
* — `{type:'object', properties}` at the root is itself the parameter object.
|
|
1095
1091
|
*/
|
|
1096
1092
|
function paramsOf(schema) {
|
|
1097
1093
|
if (schema === null || typeof schema !== "object") return null;
|
|
@@ -1102,33 +1098,19 @@ window.__ModuleLoader__.load({
|
|
|
1102
1098
|
if (s.type === "object" && s.properties !== void 0 && typeof s.properties === "object") return s;
|
|
1103
1099
|
return null;
|
|
1104
1100
|
}
|
|
1105
|
-
/**
|
|
1106
|
-
* One row of the parsed parameter table — name (mono-styled, with a
|
|
1107
|
-
* required chip), short type label, and the description on its own line
|
|
1108
|
-
* (so a long blurb never breaks the name/type rhythm).
|
|
1109
|
-
*/
|
|
1110
1101
|
function ParamRow(props) {
|
|
1111
1102
|
const typeLabel = typeOf(props.schema);
|
|
1112
1103
|
const desc = props.schema.description;
|
|
1113
1104
|
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);
|
|
1114
1105
|
}
|
|
1115
1106
|
/**
|
|
1116
|
-
* Section — the ONE detail chrome of the
|
|
1117
|
-
*
|
|
1118
|
-
* extras on the right (a count badge and/or the Raw/MD switch), with the
|
|
1119
|
-
* body below. Every expanded element renders as a stack of these — prose,
|
|
1120
|
-
* tool calls, parameter rows, image grids, and raw JSON all share the same
|
|
1121
|
-
* frame, so the reader scans one repeating anatomy instead of a different
|
|
1122
|
-
* layout per content kind.
|
|
1107
|
+
* Section — the ONE detail chrome of the browser: every expanded element is a stack of these (labeled head + body), so the reader scans one
|
|
1108
|
+
* repeating anatomy per content kind.
|
|
1123
1109
|
*/
|
|
1124
1110
|
function Section(props) {
|
|
1125
|
-
|
|
1111
|
+
const right = props.actions !== void 0 || props.meta !== void 0;
|
|
1112
|
+
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);
|
|
1126
1113
|
}
|
|
1127
|
-
/**
|
|
1128
|
-
* TextSection — a prose Section (system prompt, message/injection/summary
|
|
1129
|
-
* body, thinking, answer, tool description): the head's right edge carries
|
|
1130
|
-
* the Raw/MD switch and the body follows the per-card mode.
|
|
1131
|
-
*/
|
|
1132
1114
|
function TextSection(props) {
|
|
1133
1115
|
const { rich } = props;
|
|
1134
1116
|
const [mode, setMode] = rich.useRichMode();
|
|
@@ -1137,21 +1119,19 @@ window.__ModuleLoader__.load({
|
|
|
1137
1119
|
actions: /* @__PURE__ */ React.createElement(rich.RichSwitch, {
|
|
1138
1120
|
mode,
|
|
1139
1121
|
onPick: setMode
|
|
1140
|
-
})
|
|
1122
|
+
}),
|
|
1123
|
+
meta: props.meta
|
|
1141
1124
|
}, /* @__PURE__ */ React.createElement(rich.RichText, {
|
|
1142
1125
|
text: props.text,
|
|
1143
1126
|
mode
|
|
1144
1127
|
}));
|
|
1145
1128
|
}
|
|
1146
|
-
/** RawSection — a dimmed text Section without a view switch (structured payloads: tool results, raw JSON). */
|
|
1147
1129
|
function RawSection(props) {
|
|
1148
1130
|
return /* @__PURE__ */ React.createElement(Section, { label: props.label }, /* @__PURE__ */ React.createElement("pre", { className: "lc-ts-desc-body lc-br-dim" }, props.text));
|
|
1149
1131
|
}
|
|
1150
1132
|
/**
|
|
1151
|
-
*
|
|
1152
|
-
*
|
|
1153
|
-
* Owns its own open/closed state for the JSON so two expanded tools stay
|
|
1154
|
-
* independent.
|
|
1133
|
+
* Full tool-row body: description, parsed parameter table (when the schema carries one), raw JSON behind a per-row toggle — the JSON open
|
|
1134
|
+
* state is per-row so two expanded tools stay independent.
|
|
1155
1135
|
*/
|
|
1156
1136
|
function ToolSchema(props) {
|
|
1157
1137
|
const { rich } = props;
|
|
@@ -1196,14 +1176,9 @@ window.__ModuleLoader__.load({
|
|
|
1196
1176
|
}, (jsonOpen ? "▾ " : "▸ ") + (jsonOpen ? props.labels.hide : props.labels.show)), jsonOpen ? /* @__PURE__ */ React.createElement("pre", { className: "lc-ts-desc-body lc-br-dim" }, schemaJson) : null) : null);
|
|
1197
1177
|
}
|
|
1198
1178
|
/**
|
|
1199
|
-
*
|
|
1200
|
-
*
|
|
1201
|
-
*
|
|
1202
|
-
* conversation snapshot's assistant blocks (`kind`: text / reasoning /
|
|
1203
|
-
* tool-call / image, argsRaw). Consecutive images group into one grid
|
|
1204
|
-
* section; `richable` bodies (messages, injections) carry the Raw/MD
|
|
1205
|
-
* switch while tool-result payloads stay raw (structured data, not prose)
|
|
1206
|
-
* and dim; nested tool-result blocks flatten into the same flow.
|
|
1179
|
+
* Both block vocabularies normalize here — raw durable blocks (`type`: text/reasoning/tool-call/tool-result/image) and snapshot assistant
|
|
1180
|
+
* blocks (`kind`: text/reasoning/tool-call/image, argsRaw). Consecutive images group into one grid; tool-result payloads carry the Raw/MD
|
|
1181
|
+
* switch + line count; nested tool-result blocks flatten into the same flow.
|
|
1207
1182
|
*/
|
|
1208
1183
|
function BlocksBody(props) {
|
|
1209
1184
|
const { rich, img, labels } = props;
|
|
@@ -1234,15 +1209,12 @@ window.__ModuleLoader__.load({
|
|
|
1234
1209
|
const blockKind = blk !== null ? typeof blk.type === "string" ? blk.type : typeof blk.kind === "string" ? blk.kind : "" : "";
|
|
1235
1210
|
if ((blockKind === "text" || blockKind === "reasoning") && typeof blk?.text === "string") {
|
|
1236
1211
|
const label = blockKind === "reasoning" ? labels.thinking : props.textLabel;
|
|
1237
|
-
out.push(
|
|
1212
|
+
out.push(/* @__PURE__ */ React.createElement(TextSection, {
|
|
1238
1213
|
key: out.length,
|
|
1239
1214
|
label,
|
|
1240
1215
|
text: blk.text,
|
|
1241
|
-
rich
|
|
1242
|
-
|
|
1243
|
-
key: out.length,
|
|
1244
|
-
label,
|
|
1245
|
-
text: blk.text
|
|
1216
|
+
rich,
|
|
1217
|
+
meta: props.textLabel === labels.result ? /* @__PURE__ */ React.createElement("span", { className: "lc-ts-card-meta" }, labels.lines(blk.text.split("\n").length)) : void 0
|
|
1246
1218
|
}));
|
|
1247
1219
|
continue;
|
|
1248
1220
|
}
|
|
@@ -1275,11 +1247,6 @@ window.__ModuleLoader__.load({
|
|
|
1275
1247
|
flushImages();
|
|
1276
1248
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, out);
|
|
1277
1249
|
}
|
|
1278
|
-
/**
|
|
1279
|
-
* Parse a call's raw argument payload into an object; null when the payload
|
|
1280
|
-
* is missing, malformed, or not a JSON object (callers fall back to the raw
|
|
1281
|
-
* text).
|
|
1282
|
-
*/
|
|
1283
1250
|
function parseArgs(raw) {
|
|
1284
1251
|
if (typeof raw !== "string" || raw === "") return null;
|
|
1285
1252
|
try {
|
|
@@ -1290,11 +1257,8 @@ window.__ModuleLoader__.load({
|
|
|
1290
1257
|
}
|
|
1291
1258
|
}
|
|
1292
1259
|
/**
|
|
1293
|
-
*
|
|
1294
|
-
*
|
|
1295
|
-
* read / write) name their target via `file_path`/`path`/`filePath`. Null
|
|
1296
|
-
* when the arguments hold neither — the row then falls back to the generic
|
|
1297
|
-
* label.
|
|
1260
|
+
* A call's preview: bash-style `description`, or the target path (`file_path`/`path`/`filePath`) for edit/read/write tools; null when the
|
|
1261
|
+
* arguments hold neither.
|
|
1298
1262
|
*/
|
|
1299
1263
|
function summaryIn(args) {
|
|
1300
1264
|
if (args === null) return null;
|
|
@@ -1309,18 +1273,24 @@ window.__ModuleLoader__.load({
|
|
|
1309
1273
|
}
|
|
1310
1274
|
return null;
|
|
1311
1275
|
}
|
|
1312
|
-
/**
|
|
1313
|
-
* The summary of a tool result's own call — the collapsed row's preview.
|
|
1314
|
-
* Null when the call summarizes to nothing.
|
|
1315
|
-
*/
|
|
1316
1276
|
function callSummaryOf(conv) {
|
|
1317
1277
|
return summaryIn(parseArgs(conv?.call?.argsRaw));
|
|
1318
1278
|
}
|
|
1319
1279
|
/**
|
|
1320
|
-
* The
|
|
1321
|
-
*
|
|
1322
|
-
* block summarizes.
|
|
1280
|
+
* 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
|
|
1281
|
+
* number matters.
|
|
1323
1282
|
*/
|
|
1283
|
+
function exitCodeOf(conv) {
|
|
1284
|
+
if (conv === void 0 || !Array.isArray(conv.content)) return null;
|
|
1285
|
+
for (const b of conv.content) {
|
|
1286
|
+
if (b === null || typeof b !== "object") continue;
|
|
1287
|
+
const blk = b;
|
|
1288
|
+
if (typeof blk.text !== "string") continue;
|
|
1289
|
+
const m = blk.text.match(/\[exit code:\s*(\d+)\]/);
|
|
1290
|
+
if (m !== null) return Number(m[1]);
|
|
1291
|
+
}
|
|
1292
|
+
return null;
|
|
1293
|
+
}
|
|
1324
1294
|
function blockSummaryOf(conv) {
|
|
1325
1295
|
if (conv === void 0 || !Array.isArray(conv.blocks)) return null;
|
|
1326
1296
|
for (const b of conv.blocks) {
|
|
@@ -1331,37 +1301,23 @@ window.__ModuleLoader__.load({
|
|
|
1331
1301
|
}
|
|
1332
1302
|
return null;
|
|
1333
1303
|
}
|
|
1334
|
-
/**
|
|
1335
|
-
* One tool call as a Section, mirroring the tool-definition parameter
|
|
1336
|
-
* card: the head names the call target (mono, with the parsed argument
|
|
1337
|
-
* count), the body lists the arguments as name/value rows. Arguments that
|
|
1338
|
-
* are not a parseable JSON object fall back to the raw payload inside the
|
|
1339
|
-
* same card. Shared by assistant tool-call blocks (`→`) and the call half
|
|
1340
|
-
* of a tool result (`←`).
|
|
1341
|
-
*/
|
|
1342
1304
|
function ToolCallCard(props) {
|
|
1343
1305
|
const args = React.useMemo(() => parseArgs(props.argsRaw), [props.argsRaw]);
|
|
1344
1306
|
return /* @__PURE__ */ React.createElement(Section, {
|
|
1345
1307
|
label: (props.arrow ?? "→") + " " + props.name,
|
|
1346
1308
|
labelClass: "lc-ts-call-name",
|
|
1347
|
-
|
|
1309
|
+
meta: props.status
|
|
1348
1310
|
}, args !== null ? Object.keys(args).map((k) => /* @__PURE__ */ React.createElement(CallArgRow, {
|
|
1349
1311
|
key: k,
|
|
1350
1312
|
name: k,
|
|
1351
1313
|
value: args[k]
|
|
1352
1314
|
})) : typeof props.argsRaw === "string" && props.argsRaw !== "" ? /* @__PURE__ */ React.createElement("pre", { className: "lc-ts-desc-body lc-br-dim" }, props.argsRaw) : null);
|
|
1353
1315
|
}
|
|
1354
|
-
/** One parsed call argument: the name on the left, the value on the right. */
|
|
1355
1316
|
function CallArgRow(props) {
|
|
1356
1317
|
const v = props.value;
|
|
1357
1318
|
const text = typeof v === "string" ? v : v === void 0 ? "" : JSON.stringify(v);
|
|
1358
1319
|
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));
|
|
1359
1320
|
}
|
|
1360
|
-
/**
|
|
1361
|
-
* The actual content of one surface element, joined from the conversation
|
|
1362
|
-
* snapshot — rendered as a uniform Section stack (see BlocksBody); the
|
|
1363
|
-
* element row's open body wraps the stack in `lc-br-content`.
|
|
1364
|
-
*/
|
|
1365
1321
|
function NodeContent(props) {
|
|
1366
1322
|
const { node, conv, rich, img, labels } = props;
|
|
1367
1323
|
if (conv === void 0) {
|
|
@@ -1380,18 +1336,22 @@ window.__ModuleLoader__.load({
|
|
|
1380
1336
|
img,
|
|
1381
1337
|
labels
|
|
1382
1338
|
});
|
|
1383
|
-
if (conv.kind === "tool-result")
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1339
|
+
if (conv.kind === "tool-result") {
|
|
1340
|
+
const err = node.err === true || conv.isError === true;
|
|
1341
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, conv.call != null ? /* @__PURE__ */ React.createElement(ToolCallCard, {
|
|
1342
|
+
arrow: "←",
|
|
1343
|
+
name: conv.call.name,
|
|
1344
|
+
argsRaw: conv.call.argsRaw,
|
|
1345
|
+
status: labels.callState(err, err ? exitCodeOf(conv) : null)
|
|
1346
|
+
}) : null, Array.isArray(conv.content) ? /* @__PURE__ */ React.createElement(BlocksBody, {
|
|
1347
|
+
blocks: conv.content,
|
|
1348
|
+
richable: false,
|
|
1349
|
+
textLabel: labels.result,
|
|
1350
|
+
rich,
|
|
1351
|
+
img,
|
|
1352
|
+
labels
|
|
1353
|
+
}) : null);
|
|
1354
|
+
}
|
|
1395
1355
|
if (conv.kind === "compaction") return typeof conv.summary === "string" && conv.summary !== "" ? /* @__PURE__ */ React.createElement(TextSection, {
|
|
1396
1356
|
label: labels.summary,
|
|
1397
1357
|
text: conv.summary,
|
|
@@ -1407,19 +1367,16 @@ window.__ModuleLoader__.load({
|
|
|
1407
1367
|
});
|
|
1408
1368
|
return /* @__PURE__ */ React.createElement("div", { className: "lc-br-note" }, props.hint);
|
|
1409
1369
|
}
|
|
1410
|
-
/** Group an assembled surface's nodes by category (for per-category counts). */
|
|
1411
1370
|
function byCatOf(asm) {
|
|
1412
1371
|
const m = {};
|
|
1413
1372
|
for (const n of asm.nodes) (m[n.cat] ??= []).push(n);
|
|
1414
1373
|
return m;
|
|
1415
1374
|
}
|
|
1416
|
-
/** Count one category's elements in an assembled surface (header cats included). */
|
|
1417
1375
|
function countOf(asm, c) {
|
|
1418
1376
|
if (c === "system") return asm.header !== null && asm.header.system !== void 0 ? 1 : 0;
|
|
1419
1377
|
if (c === "tools") return asm.header !== null ? asm.header.tools.length : 0;
|
|
1420
1378
|
return byCatOf(asm)[c]?.length ?? 0;
|
|
1421
1379
|
}
|
|
1422
|
-
/** The last request of `turn` in a seq-ordered timeline, or null. */
|
|
1423
1380
|
function lastOfTurn(requests, turn) {
|
|
1424
1381
|
for (let i = requests.length - 1; i >= 0; i--) if ((requests[i].turn ?? 0) === turn) return requests[i];
|
|
1425
1382
|
return null;
|
|
@@ -1520,9 +1477,11 @@ window.__ModuleLoader__.load({
|
|
|
1520
1477
|
const toggleElem = (key) => {
|
|
1521
1478
|
setOpenElem(openElem === key ? null : key);
|
|
1522
1479
|
};
|
|
1523
|
-
/**
|
|
1524
|
-
*
|
|
1525
|
-
|
|
1480
|
+
/**
|
|
1481
|
+
* Expandable element row; `err` rows carry the red run-state dot right after the chevron (the chat's failed-tool marker) so a failed
|
|
1482
|
+
* result scans while collapsed.
|
|
1483
|
+
*/
|
|
1484
|
+
const elemRow = (key, tag, preview, tokens, time, body, err = false) => {
|
|
1526
1485
|
const open = openElem === key;
|
|
1527
1486
|
return /* @__PURE__ */ React.createElement("div", {
|
|
1528
1487
|
key,
|
|
@@ -1533,7 +1492,10 @@ window.__ModuleLoader__.load({
|
|
|
1533
1492
|
onClick: () => {
|
|
1534
1493
|
toggleElem(key);
|
|
1535
1494
|
}
|
|
1536
|
-
}, /* @__PURE__ */ React.createElement("span", { className: "lc-br-chev" + (open ? " lc-br-chev-on" : "") }, "▸"),
|
|
1495
|
+
}, /* @__PURE__ */ React.createElement("span", { className: "lc-br-chev" + (open ? " lc-br-chev-on" : "") }, "▸"), err ? /* @__PURE__ */ React.createElement("span", {
|
|
1496
|
+
className: "lc-br-err-dot",
|
|
1497
|
+
title: t("node.failed")
|
|
1498
|
+
}) : 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);
|
|
1537
1499
|
};
|
|
1538
1500
|
const catBody = (c) => {
|
|
1539
1501
|
if (c === "system") {
|
|
@@ -1565,17 +1527,18 @@ window.__ModuleLoader__.load({
|
|
|
1565
1527
|
});
|
|
1566
1528
|
}
|
|
1567
1529
|
return (byCat[c] ?? []).slice().reverse().map((n) => {
|
|
1530
|
+
const conv = bySeq.get(n.seq);
|
|
1531
|
+
const rowErr = n.cat === "tool" && (n.err === true || conv !== void 0 && conv.isError === true);
|
|
1568
1532
|
let tag = null;
|
|
1569
1533
|
let preview = nodeText(n);
|
|
1570
1534
|
if (n.cat === "tool") {
|
|
1571
|
-
tag = n.skill ? t("node.skillTag", { name: n.skill }) :
|
|
1572
|
-
preview = callSummaryOf(
|
|
1535
|
+
tag = n.skill ? t("node.skillTag", { name: n.skill }) : n.tool ?? "?";
|
|
1536
|
+
preview = callSummaryOf(conv) ?? t("node.toolResult");
|
|
1573
1537
|
} else if (n.cat === "assistant" && Array.isArray(n.calls) && n.calls.length > 0) {
|
|
1574
1538
|
tag = n.calls.join(" › ");
|
|
1575
|
-
preview = (n.text !== void 0 && n.text !== "" ? n.text : null) ?? blockSummaryOf(
|
|
1576
|
-
} else if (n.cat === "assistant" && (n.text === void 0 || n.text === "")) preview = blockSummaryOf(
|
|
1539
|
+
preview = (n.text !== void 0 && n.text !== "" ? n.text : null) ?? blockSummaryOf(conv) ?? t("node.empty");
|
|
1540
|
+
} else if (n.cat === "assistant" && (n.text === void 0 || n.text === "")) preview = blockSummaryOf(conv) ?? preview;
|
|
1577
1541
|
else if (n.cat === "user") {
|
|
1578
|
-
const conv = bySeq.get(n.seq);
|
|
1579
1542
|
const imgCount = conv !== void 0 && Array.isArray(conv.content) ? conv.content.filter((b) => imageRefOf(b) !== null).length : 0;
|
|
1580
1543
|
if (imgCount > 0 && openElem !== `n${n.seq}`) tag = t("attach.image") + (imgCount > 1 ? " ×" + String(imgCount) : "");
|
|
1581
1544
|
} else if (n.cat === "inject" && !n.skill) {
|
|
@@ -1584,7 +1547,7 @@ window.__ModuleLoader__.load({
|
|
|
1584
1547
|
}
|
|
1585
1548
|
return elemRow(`n${n.seq}`, tag, preview, n.tokens, n.time, /* @__PURE__ */ React.createElement(NodeContent, {
|
|
1586
1549
|
node: n,
|
|
1587
|
-
conv
|
|
1550
|
+
conv,
|
|
1588
1551
|
rich,
|
|
1589
1552
|
img: {
|
|
1590
1553
|
Card: ImageCard,
|
|
@@ -1597,10 +1560,12 @@ window.__ModuleLoader__.load({
|
|
|
1597
1560
|
result: t("block.result"),
|
|
1598
1561
|
summary: t("block.summary"),
|
|
1599
1562
|
images: t("attach.images"),
|
|
1600
|
-
other: t("attach.other")
|
|
1563
|
+
other: t("attach.other"),
|
|
1564
|
+
lines: (n) => t(n === 1 ? "block.line" : "block.lines", { n }),
|
|
1565
|
+
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"))
|
|
1601
1566
|
},
|
|
1602
|
-
hint:
|
|
1603
|
-
}));
|
|
1567
|
+
hint: conv === void 0 && awaiting ? t("browser.loading") : t("browser.noContent")
|
|
1568
|
+
}), rowErr);
|
|
1604
1569
|
});
|
|
1605
1570
|
};
|
|
1606
1571
|
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", {
|
|
@@ -1655,12 +1620,9 @@ window.__ModuleLoader__.load({
|
|
|
1655
1620
|
//#endregion
|
|
1656
1621
|
//#region src/client/components/stackedBar.tsx
|
|
1657
1622
|
/**
|
|
1658
|
-
*
|
|
1659
|
-
*
|
|
1660
|
-
*
|
|
1661
|
-
* reached). DSH does not publish the configured ratio to plugins or clients,
|
|
1662
|
-
* so the UI mirrors the default here; deployments that tune `thresholdRatio`
|
|
1663
|
-
* / `modelPolicies` can adjust it if they want the reserve band to match.
|
|
1623
|
+
* Mirror of dsh-compaction-basic's default `thresholdRatio` (0.8): it compacts at step boundaries once `floor(contextWindow × ratio)` is
|
|
1624
|
+
* reached; DSH does not publish the configured ratio to plugins/clients, so the reserve band mirrors the default — deployments tuning
|
|
1625
|
+
* `thresholdRatio`/`modelPolicies` should adjust it to match.
|
|
1664
1626
|
*/
|
|
1665
1627
|
const AUTO_COMPACT_RATIO = .8;
|
|
1666
1628
|
function makeStackedBar(kit) {
|
|
@@ -1930,6 +1892,145 @@ window.__ModuleLoader__.load({
|
|
|
1930
1892
|
};
|
|
1931
1893
|
}
|
|
1932
1894
|
//#endregion
|
|
1895
|
+
//#region src/client/components/settingsCard.tsx
|
|
1896
|
+
function PrefRow(props) {
|
|
1897
|
+
const [open, setOpen] = React.useState(false);
|
|
1898
|
+
const active = props.options.find((o) => o.id === props.value)?.label ?? props.value;
|
|
1899
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-settings-row" }, /* @__PURE__ */ React.createElement("span", { className: "lc-settings-label" }, props.label), /* @__PURE__ */ React.createElement(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
1900
|
+
open,
|
|
1901
|
+
onClose: () => {
|
|
1902
|
+
setOpen(false);
|
|
1903
|
+
},
|
|
1904
|
+
items: props.options,
|
|
1905
|
+
selectedId: props.value,
|
|
1906
|
+
onSelect: (id) => {
|
|
1907
|
+
setOpen(false);
|
|
1908
|
+
props.onPick(id);
|
|
1909
|
+
},
|
|
1910
|
+
align: "end",
|
|
1911
|
+
portal: true,
|
|
1912
|
+
anchor: /* @__PURE__ */ React.createElement("button", {
|
|
1913
|
+
type: "button",
|
|
1914
|
+
className: "lc-settings-select",
|
|
1915
|
+
disabled: props.disabled,
|
|
1916
|
+
"aria-haspopup": "menu",
|
|
1917
|
+
"aria-expanded": open,
|
|
1918
|
+
onClick: () => {
|
|
1919
|
+
setOpen((v) => !v);
|
|
1920
|
+
}
|
|
1921
|
+
}, active, /* @__PURE__ */ React.createElement(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, null))
|
|
1922
|
+
}));
|
|
1923
|
+
}
|
|
1924
|
+
function makeSettingsCard(kit) {
|
|
1925
|
+
const { t } = kit;
|
|
1926
|
+
return function SettingsCard(props) {
|
|
1927
|
+
const [open, setOpen] = React.useState(false);
|
|
1928
|
+
const state = typeof props.useContextSettings === "function" ? props.useContextSettings((s) => s) : void 0;
|
|
1929
|
+
if (state === void 0 || state.status === "unavailable") return null;
|
|
1930
|
+
const disabled = state.status !== "ready" || !state.writable;
|
|
1931
|
+
return /* @__PURE__ */ React.createElement("li", { className: "lc-settings-card" + (open ? " lc-settings-open" : "") }, /* @__PURE__ */ React.createElement("button", {
|
|
1932
|
+
type: "button",
|
|
1933
|
+
className: "lc-settings-head",
|
|
1934
|
+
"aria-expanded": open,
|
|
1935
|
+
"aria-label": `${t(open ? "settings.collapse" : "settings.expand")}: ${t("settings.title")}`,
|
|
1936
|
+
onClick: () => {
|
|
1937
|
+
setOpen(!open);
|
|
1938
|
+
}
|
|
1939
|
+
}, /* @__PURE__ */ React.createElement("span", { className: "lc-settings-headtext" }, /* @__PURE__ */ React.createElement("span", { className: "lc-settings-name" }, t("settings.title")), /* @__PURE__ */ React.createElement("span", { className: "lc-settings-desc" }, t("settings.desc"))), /* @__PURE__ */ React.createElement(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: "lc-settings-chevron" })), open ? /* @__PURE__ */ React.createElement("div", { className: "lc-settings-body" }, !state.writable && state.status === "ready" ? /* @__PURE__ */ React.createElement("p", {
|
|
1940
|
+
className: "lc-settings-note",
|
|
1941
|
+
role: "status"
|
|
1942
|
+
}, t("settings.readOnly")) : null, /* @__PURE__ */ React.createElement(PrefRow, {
|
|
1943
|
+
label: t("settings.gran"),
|
|
1944
|
+
value: state.granularity,
|
|
1945
|
+
disabled,
|
|
1946
|
+
options: [{
|
|
1947
|
+
id: "step",
|
|
1948
|
+
label: t("gran.step")
|
|
1949
|
+
}, {
|
|
1950
|
+
id: "turn",
|
|
1951
|
+
label: t("gran.turn")
|
|
1952
|
+
}],
|
|
1953
|
+
onPick: (id) => {
|
|
1954
|
+
props.set?.("defaultGranularity", id);
|
|
1955
|
+
}
|
|
1956
|
+
}), /* @__PURE__ */ React.createElement(PrefRow, {
|
|
1957
|
+
label: t("settings.mode"),
|
|
1958
|
+
value: state.mode,
|
|
1959
|
+
disabled,
|
|
1960
|
+
options: [{
|
|
1961
|
+
id: "total",
|
|
1962
|
+
label: t("gran.total")
|
|
1963
|
+
}, {
|
|
1964
|
+
id: "diff",
|
|
1965
|
+
label: t("gran.diff")
|
|
1966
|
+
}],
|
|
1967
|
+
onPick: (id) => {
|
|
1968
|
+
props.set?.("defaultTrendMode", id);
|
|
1969
|
+
}
|
|
1970
|
+
})) : null);
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1973
|
+
//#endregion
|
|
1974
|
+
//#region src/client/settings.ts
|
|
1975
|
+
function prefsOf(value) {
|
|
1976
|
+
if (value === null || typeof value !== "object") return {};
|
|
1977
|
+
const v = value;
|
|
1978
|
+
return {
|
|
1979
|
+
...v.defaultGranularity === "step" || v.defaultGranularity === "turn" ? { granularity: v.defaultGranularity } : {},
|
|
1980
|
+
...v.defaultTrendMode === "total" || v.defaultTrendMode === "diff" ? { mode: v.defaultTrendMode } : {}
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
function createContextSettings() {
|
|
1984
|
+
let state = {
|
|
1985
|
+
status: "loading",
|
|
1986
|
+
granularity: "step",
|
|
1987
|
+
mode: "total",
|
|
1988
|
+
writable: false
|
|
1989
|
+
};
|
|
1990
|
+
let scope;
|
|
1991
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1992
|
+
const publish = (next) => {
|
|
1993
|
+
if (next.status === state.status && next.granularity === state.granularity && next.mode === state.mode && next.writable === state.writable) return;
|
|
1994
|
+
state = next;
|
|
1995
|
+
for (const listener of listeners) listener();
|
|
1996
|
+
};
|
|
1997
|
+
return {
|
|
1998
|
+
store: {
|
|
1999
|
+
subscribe(listener) {
|
|
2000
|
+
listeners.add(listener);
|
|
2001
|
+
return () => {
|
|
2002
|
+
listeners.delete(listener);
|
|
2003
|
+
};
|
|
2004
|
+
},
|
|
2005
|
+
getSnapshot: () => state
|
|
2006
|
+
},
|
|
2007
|
+
defaultGranularity: () => state.granularity,
|
|
2008
|
+
defaultTrendMode: () => state.mode,
|
|
2009
|
+
attach(bound) {
|
|
2010
|
+
scope = bound;
|
|
2011
|
+
const sync = () => {
|
|
2012
|
+
const snap = bound.getSnapshot();
|
|
2013
|
+
const prefs = prefsOf(snap.value);
|
|
2014
|
+
publish({
|
|
2015
|
+
status: snap.status === "ready" || snap.status === "unavailable" ? snap.status : "loading",
|
|
2016
|
+
granularity: prefs.granularity ?? state.granularity,
|
|
2017
|
+
mode: prefs.mode ?? state.mode,
|
|
2018
|
+
writable: snap.writable
|
|
2019
|
+
});
|
|
2020
|
+
};
|
|
2021
|
+
sync();
|
|
2022
|
+
return bound.subscribe(sync);
|
|
2023
|
+
},
|
|
2024
|
+
set(field, value) {
|
|
2025
|
+
publish({
|
|
2026
|
+
...state,
|
|
2027
|
+
...prefsOf({ [field]: value })
|
|
2028
|
+
});
|
|
2029
|
+
scope?.set(field, value);
|
|
2030
|
+
}
|
|
2031
|
+
};
|
|
2032
|
+
}
|
|
2033
|
+
//#endregion
|
|
1933
2034
|
//#region src/client/components/events.tsx
|
|
1934
2035
|
const EVENT_ICONS = {
|
|
1935
2036
|
compaction: "✂",
|
|
@@ -1938,7 +2039,6 @@ window.__ModuleLoader__.load({
|
|
|
1938
2039
|
model: "⇄",
|
|
1939
2040
|
mode: "⇄"
|
|
1940
2041
|
};
|
|
1941
|
-
/** Build the event text helpers bound to the translate function. */
|
|
1942
2042
|
function makeEventText(t) {
|
|
1943
2043
|
function eventLabel(ev) {
|
|
1944
2044
|
if (ev.kind === "compaction") return t("ev.compaction", { n: ev.count || 0 });
|
|
@@ -1955,11 +2055,8 @@ window.__ModuleLoader__.load({
|
|
|
1955
2055
|
return label;
|
|
1956
2056
|
}
|
|
1957
2057
|
/**
|
|
1958
|
-
* Where this event sits in the
|
|
1959
|
-
*
|
|
1960
|
-
* "Step 2→3", cross-turn "Turn 50 · Step 8 → Turn 51 · Step 1". Injections
|
|
1961
|
-
* and model switches belong to one request and keep the single point.
|
|
1962
|
-
* Events with no following request (in flight) stay unlabeled.
|
|
2058
|
+
* Where this event sits in the timeline: boundary events (compaction/prune) label the GAP they sit in — same-turn 'Turn 2 · Step 3→4',
|
|
2059
|
+
* cross-turn 'Turn 50 · Step 8 → Turn 51 · Step 1'; other kinds keep their single point; no turn/step (in flight) → null.
|
|
1963
2060
|
*/
|
|
1964
2061
|
function eventAt(ev) {
|
|
1965
2062
|
if (ev.kind === "compaction" || ev.kind === "prune") {
|
|
@@ -2028,20 +2125,14 @@ window.__ModuleLoader__.load({
|
|
|
2028
2125
|
};
|
|
2029
2126
|
}
|
|
2030
2127
|
const PLUGIN_REPO = "https://github.com/bowenliang123/dsh-context";
|
|
2031
|
-
/** Short `owner/repo` form of the GitHub URL, for display only. */
|
|
2032
2128
|
const PLUGIN_REPO_SHORT = PLUGIN_REPO.replace(/^https?:\/\/github\.com\//, "");
|
|
2033
2129
|
//#endregion
|
|
2034
2130
|
//#region src/client/latestVersion.ts
|
|
2035
2131
|
/**
|
|
2036
|
-
*
|
|
2037
|
-
*
|
|
2038
|
-
* card mount and cached with a 1-hour TTL, so the registry is hit at most
|
|
2039
|
-
* once per hour per page. Every failure mode (offline, CSP-blocked,
|
|
2040
|
-
* non-200, malformed body) narrows to null = no upgrade hint, so the card
|
|
2041
|
-
* silently keeps its static version.
|
|
2132
|
+
* One live check for the Plugin-info card: lazy with 1h TTL; every failure
|
|
2133
|
+
* mode narrows to null so the card silently keeps its static version.
|
|
2042
2134
|
*/
|
|
2043
2135
|
const REGISTRY_URL = "https://registry.npmjs.org/dsh-context/latest";
|
|
2044
|
-
/** How long a registry result stays fresh before the next check refetches. */
|
|
2045
2136
|
const TTL_MS = 36e5;
|
|
2046
2137
|
let cached = null;
|
|
2047
2138
|
function fetchLatestVersion() {
|
|
@@ -2076,7 +2167,7 @@ window.__ModuleLoader__.load({
|
|
|
2076
2167
|
return function PluginInfo() {
|
|
2077
2168
|
const [latest, setLatest] = React.useState(null);
|
|
2078
2169
|
React.useEffect(() => {
|
|
2079
|
-
if ("0.
|
|
2170
|
+
if ("0.30.0".includes("-dev")) return;
|
|
2080
2171
|
let on = true;
|
|
2081
2172
|
fetchLatestVersion().then((v) => {
|
|
2082
2173
|
if (on && v) setLatest(v);
|
|
@@ -2085,8 +2176,8 @@ window.__ModuleLoader__.load({
|
|
|
2085
2176
|
on = false;
|
|
2086
2177
|
};
|
|
2087
2178
|
}, []);
|
|
2088
|
-
const update = latest !== null && isNewerVersion(latest, "0.
|
|
2089
|
-
const nameValue = ["dsh-context (v0.
|
|
2179
|
+
const update = latest !== null && isNewerVersion(latest, "0.30.0") ? latest : null;
|
|
2180
|
+
const nameValue = ["dsh-context (v0.30.0)"];
|
|
2090
2181
|
if (update) nameValue.push(/* @__PURE__ */ React.createElement("span", {
|
|
2091
2182
|
key: "update",
|
|
2092
2183
|
className: "lc-pi-update"
|
|
@@ -2211,7 +2302,6 @@ window.__ModuleLoader__.load({
|
|
|
2211
2302
|
}
|
|
2212
2303
|
return any ? total : null;
|
|
2213
2304
|
}
|
|
2214
|
-
/** Short money format: two decimals at and above one unit, two significant digits below. */
|
|
2215
2305
|
function formatCost(amount, currency) {
|
|
2216
2306
|
return (currency === "cny" ? "¥" : "$") + (amount >= 1 ? amount.toFixed(2) : amount.toPrecision(2));
|
|
2217
2307
|
}
|
|
@@ -2236,15 +2326,10 @@ window.__ModuleLoader__.load({
|
|
|
2236
2326
|
//#endregion
|
|
2237
2327
|
//#region src/client/components/statsBoard.tsx
|
|
2238
2328
|
/**
|
|
2239
|
-
* Cache-hit share of billed prompt-side input — same buckets as the harness
|
|
2240
|
-
*
|
|
2241
|
-
*
|
|
2242
|
-
*
|
|
2243
|
-
* round). Null when no input was billed. A tiny epsilon keeps a double stored
|
|
2244
|
-
* a hair below a cent boundary (e.g. 80.00 as 79.9999999999…) from losing its
|
|
2245
|
-
* last digit — with integer token counts no genuine value ever sits that close
|
|
2246
|
-
* to a boundary, so the epsilon can only absorb float noise. Bucket reads go
|
|
2247
|
-
* through numOf so a malformed payload degrades to a dash instead of NaN text.
|
|
2329
|
+
* Cache-hit share of billed prompt-side input — same three disjoint buckets as the harness chat line (`cacheReadTokens` over uncached +
|
|
2330
|
+
* reads + writes), but deliberately TRUNCATES to two decimals (cut, not round), unlike that line's integer rounding; null when nothing was
|
|
2331
|
+
* billed. The 1e-9 epsilon absorbs only float noise (integer token counts never sit that close to a boundary); `numOf` keeps malformed
|
|
2332
|
+
* payloads at a dash.
|
|
2248
2333
|
*/
|
|
2249
2334
|
function cacheHitPercent(usage) {
|
|
2250
2335
|
const uncached = numOf(usage.uncachedInputTokens);
|
|
@@ -2291,12 +2376,8 @@ window.__ModuleLoader__.load({
|
|
|
2291
2376
|
//#endregion
|
|
2292
2377
|
//#region src/client/components/trendChart.tsx
|
|
2293
2378
|
/**
|
|
2294
|
-
* Collapse
|
|
2295
|
-
*
|
|
2296
|
-
* finished), tagged with the number of steps the turn spans so the bar can
|
|
2297
|
-
* keep the turn's column width and the detail can label it. Requests of one
|
|
2298
|
-
* turn are consecutive in the log, so a run of equal turns is replaced by
|
|
2299
|
-
* its final record.
|
|
2379
|
+
* 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
|
|
2380
|
+
* column width; the log keeps one turn's requests consecutive, so a run of equal turns collapses to its final record.
|
|
2300
2381
|
*/
|
|
2301
2382
|
function aggregateByTurn(requests) {
|
|
2302
2383
|
const out = [];
|
|
@@ -2320,10 +2401,8 @@ window.__ModuleLoader__.load({
|
|
|
2320
2401
|
return out;
|
|
2321
2402
|
}
|
|
2322
2403
|
/**
|
|
2323
|
-
* Attach each boundary event (compaction/prune) to the first request
|
|
2324
|
-
*
|
|
2325
|
-
* the bar and the range chip in the detail header. Shared by TrendChart
|
|
2326
|
-
* and the detail panel so both show the SAME event for a request.
|
|
2404
|
+
* Attach each boundary event (compaction/prune) to the first request logged after it — one entry per index, for the ✂ marker and the detail
|
|
2405
|
+
* chip; shared with the detail panel so both show the SAME event.
|
|
2327
2406
|
*/
|
|
2328
2407
|
function attachMarkers(requests, events) {
|
|
2329
2408
|
const markers = new Array(requests.length);
|
|
@@ -2345,14 +2424,8 @@ window.__ModuleLoader__.load({
|
|
|
2345
2424
|
const anchorOf = (req) => typeof req.prompt === "number" && req.prompt > 0 && req.total > 0 ? req.prompt / req.total : 1;
|
|
2346
2425
|
const barTotalOf = (req) => typeof req.prompt === "number" && req.prompt > 0 ? req.prompt : req.total;
|
|
2347
2426
|
/**
|
|
2348
|
-
*
|
|
2349
|
-
*
|
|
2350
|
-
* change, stacked like the cumulative bars), `total` becomes the summed
|
|
2351
|
-
* magnitude, and `net` keeps the signed change for the tooltip. The first
|
|
2352
|
-
* request (no previous) diff from empty is zero, so the diff mode's scale
|
|
2353
|
-
* is driven purely by inter-request changes rather than the initial
|
|
2354
|
-
* cumulative baseline. Provider prompt/output are dropped: they are
|
|
2355
|
-
* per-request values, not diffs.
|
|
2427
|
+
* Diff mode: each category becomes |current − previous|, `total` the summed magnitude, `net` the signed change for the tooltip; the first
|
|
2428
|
+
* request diffs from zero so the scale is change-driven, and per-request provider prompt/output are dropped (they are not diffs).
|
|
2356
2429
|
*/
|
|
2357
2430
|
const diffOf = (req, prev) => {
|
|
2358
2431
|
const out = { ...req };
|
|
@@ -2422,6 +2495,17 @@ window.__ModuleLoader__.load({
|
|
|
2422
2495
|
grp.count++;
|
|
2423
2496
|
grp.span += req.stepCount ?? 1;
|
|
2424
2497
|
}
|
|
2498
|
+
const turnOffsets = [];
|
|
2499
|
+
const turnWidths = [];
|
|
2500
|
+
{
|
|
2501
|
+
let x = 0;
|
|
2502
|
+
for (const grp of groups) {
|
|
2503
|
+
const w = grp.agg ? BAR_W : grp.span * 16 - BAR_GAP;
|
|
2504
|
+
turnOffsets.push(x);
|
|
2505
|
+
turnWidths.push(w);
|
|
2506
|
+
x += w + BAR_GAP;
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2425
2509
|
const scrollRef = React.useRef(null);
|
|
2426
2510
|
const scrolledOnce = React.useRef(false);
|
|
2427
2511
|
const lastGranRef = React.useRef(props.granularity);
|
|
@@ -2444,6 +2528,35 @@ window.__ModuleLoader__.load({
|
|
|
2444
2528
|
right
|
|
2445
2529
|
});
|
|
2446
2530
|
};
|
|
2531
|
+
/**
|
|
2532
|
+
* 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
|
|
2533
|
+
* (narrower-than-label blocks stay put); reads (offsetWidth) batch before writes (transform) to avoid layout thrash — out-of-view
|
|
2534
|
+
* blocks need no measurement.
|
|
2535
|
+
*/
|
|
2536
|
+
const updateTurnLabels = (el) => {
|
|
2537
|
+
const labels = el.querySelectorAll(".lc-turn-label");
|
|
2538
|
+
const n = Math.min(labels.length, turnOffsets.length);
|
|
2539
|
+
const sl = el.scrollLeft;
|
|
2540
|
+
const vr = sl + el.clientWidth;
|
|
2541
|
+
const writes = [];
|
|
2542
|
+
for (let i = 0; i < n; i++) {
|
|
2543
|
+
const off = turnOffsets[i];
|
|
2544
|
+
const w = turnWidths[i];
|
|
2545
|
+
const visL = Math.max(off, sl);
|
|
2546
|
+
const visR = Math.min(off + w, vr);
|
|
2547
|
+
let dx = 0;
|
|
2548
|
+
if (visR > visL) {
|
|
2549
|
+
const lw = labels[i].offsetWidth;
|
|
2550
|
+
if (lw < w) {
|
|
2551
|
+
const center = (visL + visR) / 2 - off;
|
|
2552
|
+
dx = Math.min(Math.max(center, lw / 2), w - lw / 2) - w / 2;
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
const next = dx !== 0 ? `translateX(${dx}px)` : "";
|
|
2556
|
+
if (labels[i].style.transform !== next) writes.push([labels[i], next]);
|
|
2557
|
+
}
|
|
2558
|
+
for (const [label, next] of writes) label.style.transform = next;
|
|
2559
|
+
};
|
|
2447
2560
|
React.useLayoutEffect(() => {
|
|
2448
2561
|
const el = scrollRef.current;
|
|
2449
2562
|
if (el === null) return;
|
|
@@ -2464,6 +2577,7 @@ window.__ModuleLoader__.load({
|
|
|
2464
2577
|
el.scrollLeft = el.scrollWidth;
|
|
2465
2578
|
} else if (el.scrollLeft + el.clientWidth >= el.scrollWidth - 24) el.scrollLeft = el.scrollWidth;
|
|
2466
2579
|
updateEdges(el);
|
|
2580
|
+
updateTurnLabels(el);
|
|
2467
2581
|
});
|
|
2468
2582
|
const tipOf = (req) => {
|
|
2469
2583
|
const head = req.stepCount !== void 0 && req.stepCount > 1 ? t("tip.turn", {
|
|
@@ -2486,6 +2600,7 @@ window.__ModuleLoader__.load({
|
|
|
2486
2600
|
ref: scrollRef,
|
|
2487
2601
|
onScroll: (e) => {
|
|
2488
2602
|
updateEdges(e.currentTarget);
|
|
2603
|
+
updateTurnLabels(e.currentTarget);
|
|
2489
2604
|
}
|
|
2490
2605
|
}, edges.left ? /* @__PURE__ */ React.createElement("div", { className: "lc-chart-fade lc-chart-fade-l" }) : null, /* @__PURE__ */ React.createElement("div", {
|
|
2491
2606
|
className: "lc-chart",
|
|
@@ -2512,12 +2627,11 @@ window.__ModuleLoader__.load({
|
|
|
2512
2627
|
}
|
|
2513
2628
|
}, groups.map((grp, gi) => {
|
|
2514
2629
|
const on = props.activeTurn === grp.turn;
|
|
2515
|
-
const blockW = grp.agg ? BAR_W : grp.span * 16 - BAR_GAP;
|
|
2516
2630
|
return /* @__PURE__ */ React.createElement("span", {
|
|
2517
2631
|
key: `turn-${gi}`,
|
|
2518
2632
|
className: "lc-turn" + (on ? " lc-turn-on" : ""),
|
|
2519
2633
|
style: {
|
|
2520
|
-
width: `${
|
|
2634
|
+
width: `${turnWidths[gi]}px`,
|
|
2521
2635
|
background: TURN_FILLS[gi % TURN_FILLS.length]
|
|
2522
2636
|
},
|
|
2523
2637
|
title: `T${grp.turn}`,
|
|
@@ -2527,7 +2641,7 @@ window.__ModuleLoader__.load({
|
|
|
2527
2641
|
onClick: () => {
|
|
2528
2642
|
props.onPickTurn(grp.turn);
|
|
2529
2643
|
}
|
|
2530
|
-
}, `T${grp.turn}`);
|
|
2644
|
+
}, /* @__PURE__ */ React.createElement("span", { className: "lc-turn-label" }, `T${grp.turn}`));
|
|
2531
2645
|
}))), edges.right ? /* @__PURE__ */ React.createElement("div", { className: "lc-chart-fade lc-chart-fade-r" }) : null);
|
|
2532
2646
|
};
|
|
2533
2647
|
}
|
|
@@ -2541,7 +2655,7 @@ window.__ModuleLoader__.load({
|
|
|
2541
2655
|
"model",
|
|
2542
2656
|
"mode"
|
|
2543
2657
|
];
|
|
2544
|
-
function makeContextView(ctx, kit) {
|
|
2658
|
+
function makeContextView(ctx, kit, settings) {
|
|
2545
2659
|
const { t } = kit;
|
|
2546
2660
|
const StackedBar = makeStackedBar(kit);
|
|
2547
2661
|
const CurrentComposition = makeCurrentComposition(kit, StackedBar, makeLegend(kit));
|
|
@@ -2564,8 +2678,8 @@ window.__ModuleLoader__.load({
|
|
|
2564
2678
|
const [hoveredSeq, setHoveredSeq] = React.useState(null);
|
|
2565
2679
|
const [hoverTurn, setHoverTurn] = React.useState(null);
|
|
2566
2680
|
const [tick, setTick] = React.useState(0);
|
|
2567
|
-
const [granularity, setGranularity] = React.useState(
|
|
2568
|
-
const [trendMode, setTrendMode] = React.useState(
|
|
2681
|
+
const [granularity, setGranularity] = React.useState(() => settings.defaultGranularity());
|
|
2682
|
+
const [trendMode, setTrendMode] = React.useState(() => settings.defaultTrendMode());
|
|
2569
2683
|
const [focusTurn, setFocusTurn] = React.useState(null);
|
|
2570
2684
|
const [hoverCat, setHoverCat] = React.useState(null);
|
|
2571
2685
|
const [pickedKinds, setPickedKinds] = React.useState([...EVENT_KINDS]);
|
|
@@ -2751,7 +2865,7 @@ window.__ModuleLoader__.load({
|
|
|
2751
2865
|
}
|
|
2752
2866
|
//#endregion
|
|
2753
2867
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles.css.mjs
|
|
2754
|
-
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-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}";
|
|
2868
|
+
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{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}";
|
|
2755
2869
|
const tagId = "dsh-context/styles.css";
|
|
2756
2870
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
2757
2871
|
const tag = document.createElement("style");
|
|
@@ -2794,7 +2908,8 @@ window.__ModuleLoader__.load({
|
|
|
2794
2908
|
}, "dsh-context: dictionaries");
|
|
2795
2909
|
const t = ctx.locale.bind(NS);
|
|
2796
2910
|
const kit = makeViewKit(t);
|
|
2797
|
-
const
|
|
2911
|
+
const settings = createContextSettings();
|
|
2912
|
+
const ContextView = makeContextView(ctx, kit, settings);
|
|
2798
2913
|
ctx.effect(() => {
|
|
2799
2914
|
const noop = () => {};
|
|
2800
2915
|
const sessions = ctx.get("sessions");
|
|
@@ -2828,6 +2943,26 @@ window.__ModuleLoader__.load({
|
|
|
2828
2943
|
inject: (sessionId) => ({ hooks: { contextModal: modalStoreOf(sessionId) } })
|
|
2829
2944
|
}, (props) => h(ContextModal, props));
|
|
2830
2945
|
});
|
|
2946
|
+
ctx.inject(["settingsScope"], (raw) => {
|
|
2947
|
+
const c = raw;
|
|
2948
|
+
const binder = c.settingsScope;
|
|
2949
|
+
if (binder === void 0) return;
|
|
2950
|
+
c.effect(() => settings.attach(binder.bind({ namespace: NS })), "dsh-context: settings scope");
|
|
2951
|
+
const SettingsCard = makeSettingsCard(kit);
|
|
2952
|
+
c.slots.inject("settings.plugin.item", () => {
|
|
2953
|
+
return c.slots.register({
|
|
2954
|
+
name: "settings.plugin.item",
|
|
2955
|
+
key: NS,
|
|
2956
|
+
locale: NS,
|
|
2957
|
+
inject: () => ({
|
|
2958
|
+
hooks: { contextSettings: settings.store },
|
|
2959
|
+
set: (field, value) => {
|
|
2960
|
+
settings.set(field, value);
|
|
2961
|
+
}
|
|
2962
|
+
})
|
|
2963
|
+
}, (props) => h(SettingsCard, props));
|
|
2964
|
+
});
|
|
2965
|
+
});
|
|
2831
2966
|
}
|
|
2832
2967
|
module.exports = {
|
|
2833
2968
|
name: "dsh-context",
|