dsh-context 0.36.0 → 0.38.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 -1
- package/lib/client.js +718 -83
- package/lib/index.d.ts +149 -317
- package/lib/index.js +125 -10
- package/package.json +9 -10
package/lib/client.js
CHANGED
|
@@ -20,7 +20,7 @@ window.__ModuleLoader__.load({
|
|
|
20
20
|
"overview.ofUsed": "占已用上下文",
|
|
21
21
|
"overview.compactReserve": "自动压缩预留:占用达 {pct}% 窗口时触发压缩,此区域一般不实际占用",
|
|
22
22
|
"stats.title": "上下文统计",
|
|
23
|
-
"stats.hint": "
|
|
23
|
+
"stats.hint": "轮次、步骤与上下文事件",
|
|
24
24
|
"stats.turns": "轮次",
|
|
25
25
|
"stats.steps": "步数",
|
|
26
26
|
"stats.injects": "注入",
|
|
@@ -28,22 +28,38 @@ window.__ModuleLoader__.load({
|
|
|
28
28
|
"stats.prunes": "剪枝",
|
|
29
29
|
"stats.toolCalls": "工具调用",
|
|
30
30
|
"stats.images": "图片",
|
|
31
|
-
"stats.cacheHit": "缓存命中",
|
|
32
31
|
"stats.cost": "预估费用",
|
|
33
32
|
"stats.costTip": "按 DeepSeek 官方刊例价估算整个会话的累计费用:输入区分缓存命中/未命中,输出含思考;按请求时间区分高峰(北京时间工作日 9:00–12:00、14:00–18:00)与空闲时段(半价,周末全天均为空闲时段)。适用于 deepseek-v4-flash / deepseek-v4-pro(不限 provider),价格写死在代码中,仅供参考。",
|
|
34
33
|
"stats.costPriceHead": "每百万 tokens 价格(高峰 | 空闲半价):",
|
|
35
34
|
"stats.costHit": "命中",
|
|
36
35
|
"stats.costMiss": "未命中",
|
|
37
36
|
"stats.costOut": "输出",
|
|
37
|
+
"timing.title": "耗时统计",
|
|
38
|
+
"timing.hint": "整个会话的活跃时长分布",
|
|
39
|
+
"timing.total": "总活跃时长",
|
|
40
|
+
"timing.lm": "模型调用",
|
|
41
|
+
"timing.tools": "工具执行",
|
|
42
|
+
"timing.other": "其他开销",
|
|
43
|
+
"timing.times": "{n}次",
|
|
44
|
+
"timing.empty": "暂无耗时数据 · 对话开始后这里会显示时长分布",
|
|
45
|
+
"tokens.title": "Token 统计",
|
|
46
|
+
"tokens.hint": "供应商上报的累计计费用量",
|
|
47
|
+
"tokens.cacheHit": "缓存命中",
|
|
48
|
+
"tokens.cacheRead": "缓存读取",
|
|
49
|
+
"tokens.cacheWrite": "缓存写入",
|
|
50
|
+
"tokens.uncached": "未命中输入",
|
|
51
|
+
"tokens.output": "输出(含思考)",
|
|
38
52
|
"plugin.title": "插件信息",
|
|
39
53
|
"plugin.hint": "The best DSH context plugin ⭐",
|
|
40
54
|
"plugin.name": "插件",
|
|
41
55
|
"plugin.github": "GitHub",
|
|
56
|
+
"plugin.settings": "设置",
|
|
57
|
+
"plugin.settingsOpen": "打开设置",
|
|
42
58
|
"trend.title": "上下文趋势",
|
|
43
59
|
"gran.step": "步骤",
|
|
44
60
|
"gran.turn": "轮次",
|
|
45
61
|
"settings.title": "上下文",
|
|
46
|
-
"settings.desc": "
|
|
62
|
+
"settings.desc": "dsh-context 插件中上下文面板的偏好设置",
|
|
47
63
|
"settings.gran": "趋势图默认粒度",
|
|
48
64
|
"settings.mode": "趋势图默认展示",
|
|
49
65
|
"settings.fileSort": "文件活动默认排序",
|
|
@@ -68,6 +84,7 @@ window.__ModuleLoader__.load({
|
|
|
68
84
|
"brief.more": "+{n}",
|
|
69
85
|
"brief.noInputs": "(无新增)",
|
|
70
86
|
"brief.locate": "在上下文浏览器中查看",
|
|
87
|
+
"jump.title": "在上下文标签页中查看此轮",
|
|
71
88
|
"brief.turnTip": "这一轮开场时用户发送的消息;回合内的每一步都会回显同一条",
|
|
72
89
|
"brief.inputTip": "上一步回复之后、本次请求发出前新进入上下文的内容——通常是上一步所调工具的结果;每轮的第一步无新增",
|
|
73
90
|
"brief.replyTip": "这一步模型返回的内容(文本回复或工具调用);此步发起的调用,其结果会出现在下一柱的「输入」行",
|
|
@@ -271,7 +288,7 @@ window.__ModuleLoader__.load({
|
|
|
271
288
|
"overview.ofUsed": "of used context",
|
|
272
289
|
"overview.compactReserve": "Auto-compaction reserve: auto-compaction triggers at {pct}% of the window — this area is normally kept as headroom, not actually used",
|
|
273
290
|
"stats.title": "Context Stats",
|
|
274
|
-
"stats.hint": "
|
|
291
|
+
"stats.hint": "Turns, steps, and context events",
|
|
275
292
|
"stats.turns": "Turns",
|
|
276
293
|
"stats.steps": "Steps",
|
|
277
294
|
"stats.injects": "Injections",
|
|
@@ -279,22 +296,38 @@ window.__ModuleLoader__.load({
|
|
|
279
296
|
"stats.prunes": "Prunes",
|
|
280
297
|
"stats.toolCalls": "Tool Calls",
|
|
281
298
|
"stats.images": "Images",
|
|
282
|
-
"stats.cacheHit": "Cache Hit",
|
|
283
299
|
"stats.cost": "Cost",
|
|
284
300
|
"stats.costTip": "Rough cumulative cost of the whole session at DeepSeek’s list prices: input split by cache hit/miss, output includes reasoning; each request is priced at the peak (Beijing Time weekdays 09:00–12:00, 14:00–18:00) or half-price off-peak rate by its time — weekends bill at off-peak all day. Applies to deepseek-v4-flash / deepseek-v4-pro on any provider; prices are hardcoded, for reference only.",
|
|
285
301
|
"stats.costPriceHead": "Per-1M-token rates (peak | off-peak at half price):",
|
|
286
302
|
"stats.costHit": "hit",
|
|
287
303
|
"stats.costMiss": "miss",
|
|
288
304
|
"stats.costOut": "output",
|
|
305
|
+
"timing.title": "Timing Stats",
|
|
306
|
+
"timing.hint": "Whole-session active-time split",
|
|
307
|
+
"timing.total": "active time",
|
|
308
|
+
"timing.lm": "Model calls",
|
|
309
|
+
"timing.tools": "Tool runs",
|
|
310
|
+
"timing.other": "Overhead",
|
|
311
|
+
"timing.times": "{n}×",
|
|
312
|
+
"timing.empty": "No timing data yet — durations appear as the conversation runs",
|
|
313
|
+
"tokens.title": "Token Stats",
|
|
314
|
+
"tokens.hint": "Cumulative provider-reported usage",
|
|
315
|
+
"tokens.cacheHit": "Cache hit",
|
|
316
|
+
"tokens.cacheRead": "Cache read",
|
|
317
|
+
"tokens.cacheWrite": "Cache write",
|
|
318
|
+
"tokens.uncached": "Uncached input",
|
|
319
|
+
"tokens.output": "Output (incl. reasoning)",
|
|
289
320
|
"plugin.title": "Plugin Info",
|
|
290
321
|
"plugin.hint": "The best DSH context plugin ⭐",
|
|
291
322
|
"plugin.name": "Plugin",
|
|
292
323
|
"plugin.github": "GitHub",
|
|
324
|
+
"plugin.settings": "Settings",
|
|
325
|
+
"plugin.settingsOpen": "Open in Settings",
|
|
293
326
|
"trend.title": "Context Trend",
|
|
294
327
|
"gran.step": "Step",
|
|
295
328
|
"gran.turn": "Turn",
|
|
296
329
|
"settings.title": "Context",
|
|
297
|
-
"settings.desc": "
|
|
330
|
+
"settings.desc": "Preferences for Context panel in dsh-context plugin",
|
|
298
331
|
"settings.gran": "Default trend granularity",
|
|
299
332
|
"settings.mode": "Default trend display",
|
|
300
333
|
"settings.fileSort": "File Activity default sort",
|
|
@@ -319,6 +352,7 @@ window.__ModuleLoader__.load({
|
|
|
319
352
|
"brief.more": "+{n}",
|
|
320
353
|
"brief.noInputs": "(nothing new)",
|
|
321
354
|
"brief.locate": "Reveal in Context Browser",
|
|
355
|
+
"jump.title": "View this turn in the Context tab",
|
|
322
356
|
"brief.turnTip": "The user message that opened this turn — every step of the turn recalls it",
|
|
323
357
|
"brief.inputTip": "What entered after the previous reply and before this request went out — usually the previous tool-call results; a turn opener has nothing new",
|
|
324
358
|
"brief.replyTip": "What the model returned on this step (a text reply or tool calls) — results of calls made here appear in the In row of the next bar",
|
|
@@ -557,10 +591,10 @@ window.__ModuleLoader__.load({
|
|
|
557
591
|
const COMMAND = "context";
|
|
558
592
|
const LINE = "/context";
|
|
559
593
|
function registerContextCommand(ctx, kit) {
|
|
560
|
-
ctx.
|
|
561
|
-
const inputTriggers =
|
|
562
|
-
if (inputTriggers === void 0
|
|
563
|
-
|
|
594
|
+
ctx.inject(["inputTriggers"], (ictx) => {
|
|
595
|
+
const inputTriggers = ictx.get("inputTriggers");
|
|
596
|
+
if (inputTriggers === void 0 || typeof inputTriggers.registerSource !== "function") return;
|
|
597
|
+
ictx.effect(() => inputTriggers.registerSource({
|
|
564
598
|
trigger: "/",
|
|
565
599
|
name: COMMAND,
|
|
566
600
|
order: 1,
|
|
@@ -590,8 +624,8 @@ window.__ModuleLoader__.load({
|
|
|
590
624
|
modalStoreOf(session.sessionId).set(true);
|
|
591
625
|
return Promise.resolve("handled");
|
|
592
626
|
}
|
|
593
|
-
});
|
|
594
|
-
}
|
|
627
|
+
}), "dsh-context: /context command");
|
|
628
|
+
});
|
|
595
629
|
}
|
|
596
630
|
//#endregion
|
|
597
631
|
//#region src/client/categories.ts
|
|
@@ -723,6 +757,57 @@ window.__ModuleLoader__.load({
|
|
|
723
757
|
//#endregion
|
|
724
758
|
//#region src/client/services.ts
|
|
725
759
|
/**
|
|
760
|
+
* A session-authorized durable-image loader over whichever conversation
|
|
761
|
+
* face the running harness provides (`resolveImage` pre-0.1.2, `imageUrl`
|
|
762
|
+
* since), or undefined when neither service is composed — the caller
|
|
763
|
+
* degrades to metadata-only cards. Hostile snapshots and throwing service
|
|
764
|
+
* reads are caught: this helper can never take a render down.
|
|
765
|
+
*/
|
|
766
|
+
function imageLoaderOf(ctx, sessionId) {
|
|
767
|
+
if (typeof sessionId !== "string" || sessionId === "") return void 0;
|
|
768
|
+
try {
|
|
769
|
+
const legacy = ctx.get("conversation");
|
|
770
|
+
if (legacy !== void 0 && typeof legacy.resolveImage === "function") {
|
|
771
|
+
const resolveImage = legacy.resolveImage.bind(legacy);
|
|
772
|
+
return (attachment) => resolveImage(sessionId, attachment);
|
|
773
|
+
}
|
|
774
|
+
const modern = ctx.get("uiConversation");
|
|
775
|
+
if (modern !== void 0 && typeof modern.imageUrl === "function") {
|
|
776
|
+
const imageUrl = modern.imageUrl.bind(modern);
|
|
777
|
+
return (attachment) => imageUrl(sessionId, attachment);
|
|
778
|
+
}
|
|
779
|
+
} catch {}
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* The conversation-window nodes this plugin joins on, from whichever seat
|
|
783
|
+
* the running harness provides — `useChat` (`ChatSnapshot.legacy.nodes`) on
|
|
784
|
+
* dsh 0.1.2+, the session snapshot's own `nodes` before that. Returns
|
|
785
|
+
* undefined when neither seat delivers a real array (absent seat, older or
|
|
786
|
+
* foreign harness, hostile snapshot) — callers render without the join,
|
|
787
|
+
* never an error.
|
|
788
|
+
*
|
|
789
|
+
* Hook-order contract: the seats are real React hooks, so BOTH are invoked
|
|
790
|
+
* on every call whenever present (the chat seat first, the session seat
|
|
791
|
+
* second) and only the RESULT is picked conditionally — a stable call order
|
|
792
|
+
* across renders. Selectors return stable slice references so the
|
|
793
|
+
* framework's snapshot equality can gate re-renders.
|
|
794
|
+
*/
|
|
795
|
+
function conversationNodesOf(props) {
|
|
796
|
+
const useChat = props.useChat;
|
|
797
|
+
let chatNodes;
|
|
798
|
+
if (typeof useChat === "function") try {
|
|
799
|
+
const slice = useChat((s) => s !== null && typeof s === "object" ? s.legacy : void 0);
|
|
800
|
+
chatNodes = slice !== null && typeof slice === "object" ? slice.nodes : void 0;
|
|
801
|
+
} catch {}
|
|
802
|
+
const useSession = props.useSession;
|
|
803
|
+
let sessionNodes;
|
|
804
|
+
if (typeof useSession === "function") try {
|
|
805
|
+
sessionNodes = useSession((s) => s.nodes);
|
|
806
|
+
} catch {}
|
|
807
|
+
if (Array.isArray(chatNodes)) return chatNodes;
|
|
808
|
+
if (Array.isArray(sessionNodes)) return sessionNodes;
|
|
809
|
+
}
|
|
810
|
+
/**
|
|
726
811
|
* Narrow an unknown projection value to a string-keyed record, or null when
|
|
727
812
|
* it is not one. The boundary type is Record<string, unknown> on purpose:
|
|
728
813
|
* every field read below must re-prove itself (the no-white-screen
|
|
@@ -768,9 +853,10 @@ window.__ModuleLoader__.load({
|
|
|
768
853
|
"assistant",
|
|
769
854
|
"tool",
|
|
770
855
|
"total"
|
|
771
|
-
].every((k) => typeof current[k] === "number") && Array.isArray(data.requests) && Array.isArray(data.events) && Array.isArray(data.nodes) && Array.isArray(data.archive)) return data;
|
|
856
|
+
].every((k) => typeof current[k] === "number") && Array.isArray(data.requests) && Array.isArray(data.events) && Array.isArray(data.nodes) && Array.isArray(data.archive) && timingFastOk(data.timing)) return data;
|
|
772
857
|
const safeCurrent = current !== null && typeof current === "object" ? current : {};
|
|
773
858
|
const cost = typeof data.cost === "object" && data.cost !== null && !Array.isArray(data.cost) ? data.cost : void 0;
|
|
859
|
+
const timing = timingOf(data.timing);
|
|
774
860
|
return {
|
|
775
861
|
ok: true,
|
|
776
862
|
...typeof data.model === "string" ? { model: data.model } : {},
|
|
@@ -793,6 +879,7 @@ window.__ModuleLoader__.load({
|
|
|
793
879
|
...typeof data.toolCalls === "number" ? { toolCalls: data.toolCalls } : {},
|
|
794
880
|
archive: objectsOf(data.archive),
|
|
795
881
|
...cost !== void 0 ? { cost } : {},
|
|
882
|
+
...timing !== null ? { timing } : {},
|
|
796
883
|
...typeof data.surfaceFloor === "number" ? { surfaceFloor: data.surfaceFloor } : {},
|
|
797
884
|
...typeof data.archiveFloor === "number" ? { archiveFloor: data.archiveFloor } : {}
|
|
798
885
|
};
|
|
@@ -837,6 +924,73 @@ window.__ModuleLoader__.load({
|
|
|
837
924
|
return asRecord$1(value);
|
|
838
925
|
}
|
|
839
926
|
/**
|
|
927
|
+
* A non-negative finite number (the timing totals' every field): NaN or a
|
|
928
|
+
* negative degrades to 0 instead of leaking into donut shares.
|
|
929
|
+
*/
|
|
930
|
+
function msNumOf(value) {
|
|
931
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
|
|
932
|
+
}
|
|
933
|
+
/**
|
|
934
|
+
* Cheap whole-value check for the pass-through path of `timelineOf`: absent
|
|
935
|
+
* timing passes; present timing must already be well-formed (every scalar
|
|
936
|
+
* numeric, every per-name row shaped) — anything else sends the payload down
|
|
937
|
+
* the sanitizing slow path.
|
|
938
|
+
*/
|
|
939
|
+
function timingFastOk(value) {
|
|
940
|
+
if (value === void 0) return true;
|
|
941
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
942
|
+
const t = value;
|
|
943
|
+
for (const k of [
|
|
944
|
+
"wallMs",
|
|
945
|
+
"lmMs",
|
|
946
|
+
"calls",
|
|
947
|
+
"toolsMs",
|
|
948
|
+
"toolCalls"
|
|
949
|
+
]) if (typeof t[k] !== "number") return false;
|
|
950
|
+
const tools = t.tools;
|
|
951
|
+
if (tools === null || typeof tools !== "object" || Array.isArray(tools)) return false;
|
|
952
|
+
for (const k in tools) {
|
|
953
|
+
const row = tools[k];
|
|
954
|
+
if (row === null || typeof row !== "object") return false;
|
|
955
|
+
if (typeof row.calls !== "number") return false;
|
|
956
|
+
if (typeof row.ms !== "number") return false;
|
|
957
|
+
}
|
|
958
|
+
return true;
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* Narrow a delivered timing totals value (see TimingTotals) to a RENDER-SAFE
|
|
962
|
+
* shape — the timing card's no-white-screen guarantee. A value that is not a
|
|
963
|
+
* record stays null (the card renders its empty state); wrong-typed scalars
|
|
964
|
+
* zero out and per-name rows failing the shape drop individually, so one
|
|
965
|
+
* hostile row never blanks the ranking.
|
|
966
|
+
*/
|
|
967
|
+
function timingOf(value) {
|
|
968
|
+
const data = asRecord$1(value);
|
|
969
|
+
if (data === null) return null;
|
|
970
|
+
const tools = {};
|
|
971
|
+
const rawTools = data.tools;
|
|
972
|
+
if (rawTools !== null && typeof rawTools === "object" && !Array.isArray(rawTools)) for (const k in rawTools) {
|
|
973
|
+
if (k === "__proto__" || !Object.hasOwn(rawTools, k)) continue;
|
|
974
|
+
const row = rawTools[k];
|
|
975
|
+
if (row === null || typeof row !== "object") continue;
|
|
976
|
+
const calls = row.calls;
|
|
977
|
+
const ms = row.ms;
|
|
978
|
+
if (typeof calls !== "number" || !(calls >= 0) || typeof ms !== "number" || !(ms >= 0)) continue;
|
|
979
|
+
tools[k] = {
|
|
980
|
+
calls,
|
|
981
|
+
ms
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
return {
|
|
985
|
+
wallMs: msNumOf(data.wallMs),
|
|
986
|
+
lmMs: msNumOf(data.lmMs),
|
|
987
|
+
calls: msNumOf(data.calls),
|
|
988
|
+
toolsMs: msNumOf(data.toolsMs),
|
|
989
|
+
toolCalls: msNumOf(data.toolCalls),
|
|
990
|
+
tools
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
840
994
|
* Narrow a delivered projection value to the plugin's `contextHeaders`
|
|
841
995
|
* (request-header content epochs). Absent key = an older Host half without
|
|
842
996
|
* the companion unit — the Context browser degrades its system/tools
|
|
@@ -908,9 +1062,9 @@ window.__ModuleLoader__.load({
|
|
|
908
1062
|
/** Narrow one served row to a validated durable event envelope, or null. */
|
|
909
1063
|
function eventOf(entry) {
|
|
910
1064
|
if (entry === null || typeof entry !== "object") return null;
|
|
911
|
-
const
|
|
912
|
-
if (
|
|
913
|
-
const e =
|
|
1065
|
+
const inner = entry.event ?? entry;
|
|
1066
|
+
if (typeof inner !== "object") return null;
|
|
1067
|
+
const e = inner;
|
|
914
1068
|
if (typeof e.type !== "string" || typeof e.seq !== "number" || !Number.isFinite(e.seq)) return null;
|
|
915
1069
|
const data = e.data !== null && typeof e.data === "object" ? e.data : {};
|
|
916
1070
|
return {
|
|
@@ -1030,26 +1184,65 @@ window.__ModuleLoader__.load({
|
|
|
1030
1184
|
}
|
|
1031
1185
|
return nodes;
|
|
1032
1186
|
}
|
|
1187
|
+
/** Read a service off the client context without letting an absent/foreign
|
|
1188
|
+
* cordis service (a throwing `ctx.get`) escape: returns undefined instead. */
|
|
1189
|
+
function serviceOf(ctx, name) {
|
|
1190
|
+
try {
|
|
1191
|
+
return ctx.get(name);
|
|
1192
|
+
} catch {
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
/** The rows array of a history/page response, under every served envelope. */
|
|
1197
|
+
function rowsOf(response) {
|
|
1198
|
+
let payload = response;
|
|
1199
|
+
if (payload !== null && typeof payload === "object") {
|
|
1200
|
+
const nested = payload.result;
|
|
1201
|
+
if (nested !== null && typeof nested === "object") payload = nested;
|
|
1202
|
+
}
|
|
1203
|
+
if (payload !== null && typeof payload === "object" && "ok" in payload) {
|
|
1204
|
+
const r = payload;
|
|
1205
|
+
if (r.ok !== true || r.value === null || typeof r.value !== "object") throw new Error("history rpc failed");
|
|
1206
|
+
payload = r.value;
|
|
1207
|
+
}
|
|
1208
|
+
if (payload === null || typeof payload !== "object") throw new Error("history rpc failed");
|
|
1209
|
+
const rows = payload.records ?? payload.events;
|
|
1210
|
+
if (!Array.isArray(rows)) throw new Error("history rpc failed");
|
|
1211
|
+
return rows;
|
|
1212
|
+
}
|
|
1033
1213
|
/**
|
|
1034
|
-
* Build the browser's per-session fetcher over
|
|
1035
|
-
*
|
|
1214
|
+
* Build the browser's per-session fetcher over whichever history face the
|
|
1215
|
+
* running harness serves — the 0.1.2+ gateway remotes (`remote.session.page`)
|
|
1216
|
+
* first, the pre-0.1.2 api client verb (`connection.api.sessions.history`)
|
|
1217
|
+
* beneath it. Both cut message-aligned pages, so `beforeSeq: seq + 1` (with
|
|
1218
|
+
* the inclusive cut pinned to `seq` on the newer face) covers the seq whenever
|
|
1219
|
+
* the durable log still holds it. Undefined when no face exists (older
|
|
1036
1220
|
* hosts) — the caller keeps its static preview-plus-hint degradation. Found
|
|
1037
1221
|
* nodes cache in the closure: one mount re-reading a row never re-fetches.
|
|
1038
1222
|
*/
|
|
1039
1223
|
function makeContentFetcher(ctx, sessionId) {
|
|
1040
|
-
const
|
|
1041
|
-
|
|
1224
|
+
const pageFace = serviceOf(ctx, "remote.session");
|
|
1225
|
+
const page = pageFace !== void 0 && typeof pageFace.page === "function" ? pageFace.page.bind(pageFace) : void 0;
|
|
1226
|
+
const historyFace = serviceOf(ctx, "connection")?.api?.sessions;
|
|
1227
|
+
const history = historyFace !== void 0 && typeof historyFace.history === "function" ? historyFace.history.bind(historyFace) : void 0;
|
|
1228
|
+
if (page === void 0 && history === void 0) return void 0;
|
|
1229
|
+
const pageRequest = (seq) => ({
|
|
1230
|
+
address: {
|
|
1231
|
+
kind: "session",
|
|
1232
|
+
sessionId
|
|
1233
|
+
},
|
|
1234
|
+
throughSeq: seq,
|
|
1235
|
+
beforeSeq: seq + 1
|
|
1236
|
+
});
|
|
1237
|
+
const historyCall = (seq) => history({
|
|
1238
|
+
sessionId,
|
|
1239
|
+
beforeSeq: seq + 1
|
|
1240
|
+
});
|
|
1042
1241
|
const cache = /* @__PURE__ */ new Map();
|
|
1043
1242
|
return async (seq) => {
|
|
1044
1243
|
const hit = cache.get(seq);
|
|
1045
1244
|
if (hit !== void 0) return hit;
|
|
1046
|
-
const
|
|
1047
|
-
sessionId,
|
|
1048
|
-
beforeSeq: seq + 1
|
|
1049
|
-
})).result;
|
|
1050
|
-
if (result === null || typeof result !== "object" || result.ok !== true || result.value === null || typeof result.value !== "object") throw new Error("history rpc failed");
|
|
1051
|
-
const events = result.value.events;
|
|
1052
|
-
const node = pageNodesOf(Array.isArray(events) ? events : []).get(seq) ?? null;
|
|
1245
|
+
const node = pageNodesOf(rowsOf(page !== void 0 ? await page(pageRequest(seq), new AbortController().signal) : await historyCall(seq))).get(seq) ?? null;
|
|
1053
1246
|
if (node !== null) cache.set(seq, node);
|
|
1054
1247
|
return node;
|
|
1055
1248
|
};
|
|
@@ -1181,7 +1374,7 @@ window.__ModuleLoader__.load({
|
|
|
1181
1374
|
* nothing was billed. The 1e-9 epsilon absorbs only float noise (integer
|
|
1182
1375
|
* token counts never sit that close to a boundary).
|
|
1183
1376
|
*/
|
|
1184
|
-
function cacheHitPercent
|
|
1377
|
+
function cacheHitPercent(reads, billed) {
|
|
1185
1378
|
if (!(billed > 0)) return null;
|
|
1186
1379
|
const hundredths = Math.trunc(reads / billed * 1e4 + 1e-9);
|
|
1187
1380
|
return `${Math.floor(hundredths / 100)}.${String(hundredths % 100).padStart(2, "0")}`;
|
|
@@ -1191,6 +1384,37 @@ window.__ModuleLoader__.load({
|
|
|
1191
1384
|
if (isNaN(d.getTime())) return "—";
|
|
1192
1385
|
return d.toLocaleTimeString("en-GB", { hour12: false });
|
|
1193
1386
|
}
|
|
1387
|
+
/**
|
|
1388
|
+
* Share of a whole as a compact leading percentage for the slice rows:
|
|
1389
|
+
* '—' when nothing totals, '0%' for empty slices, '<1%' for non-zero crumbs
|
|
1390
|
+
* a rounded-down integer would erase. Shares cap at 100% (parallel tool time
|
|
1391
|
+
* can over-run the wall it belongs to).
|
|
1392
|
+
*/
|
|
1393
|
+
function fmtShare(part, total) {
|
|
1394
|
+
if (!Number.isFinite(part) || !Number.isFinite(total) || total <= 0) return "—";
|
|
1395
|
+
if (part <= 0) return "0%";
|
|
1396
|
+
const pct = Math.min(1, part / total) * 100;
|
|
1397
|
+
if (pct < 1) return "<1%";
|
|
1398
|
+
return `${Math.round(pct)}%`;
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Whole-session durations for the timing card, in the locale's units: raw ms
|
|
1402
|
+
* under a second, one-decimal seconds under a minute, then m/s and h/m.
|
|
1403
|
+
* Non-finite or non-positive input shows the dash (callers render their empty
|
|
1404
|
+
* state anyway).
|
|
1405
|
+
*/
|
|
1406
|
+
function fmtDuration$1(ms, lang) {
|
|
1407
|
+
if (!Number.isFinite(ms) || ms <= 0) return "—";
|
|
1408
|
+
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
1409
|
+
const zh = lang === "zh";
|
|
1410
|
+
if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}${zh ? "秒" : "s"}`;
|
|
1411
|
+
const totalSec = Math.floor(ms / 1e3);
|
|
1412
|
+
const m = Math.floor(totalSec / 60);
|
|
1413
|
+
const s = totalSec % 60;
|
|
1414
|
+
if (ms < 36e5) return zh ? `${m}分${s}秒` : `${m}m ${s}s`;
|
|
1415
|
+
const h = Math.floor(m / 60);
|
|
1416
|
+
return zh ? `${h}时${m % 60}分` : `${h}h ${m % 60}m`;
|
|
1417
|
+
}
|
|
1194
1418
|
//#endregion
|
|
1195
1419
|
//#region src/shared/imageTokens.ts
|
|
1196
1420
|
/**
|
|
@@ -1499,9 +1723,19 @@ window.__ModuleLoader__.load({
|
|
|
1499
1723
|
}, label);
|
|
1500
1724
|
return /* @__PURE__ */ React.createElement("span", { className: "lc-rich-seg" }, seg("raw", t("rich.raw"), t("rich.toRaw")), seg("md", t("rich.md"), t("rich.toMd")));
|
|
1501
1725
|
}
|
|
1726
|
+
function RawText(props) {
|
|
1727
|
+
const lines = React.useMemo(() => {
|
|
1728
|
+
const parts = props.text.split("\n");
|
|
1729
|
+
return parts.length > 1 && parts[parts.length - 1] === "" ? parts.slice(0, -1) : parts;
|
|
1730
|
+
}, [props.text]);
|
|
1731
|
+
return /* @__PURE__ */ React.createElement("pre", { className: "lc-ts-desc-body lc-ts-lines" }, lines.map((line, index) => /* @__PURE__ */ React.createElement("span", {
|
|
1732
|
+
key: index,
|
|
1733
|
+
className: "lc-ts-line"
|
|
1734
|
+
}, line)));
|
|
1735
|
+
}
|
|
1502
1736
|
function RichText(props) {
|
|
1503
1737
|
if (props.mode === "md") return /* @__PURE__ */ React.createElement("div", { className: "lc-ts-desc-md" }, /* @__PURE__ */ React.createElement(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, { text: props.text }));
|
|
1504
|
-
return /* @__PURE__ */ React.createElement(
|
|
1738
|
+
return /* @__PURE__ */ React.createElement(RawText, { text: props.text });
|
|
1505
1739
|
}
|
|
1506
1740
|
return {
|
|
1507
1741
|
RichText,
|
|
@@ -1906,7 +2140,7 @@ window.__ModuleLoader__.load({
|
|
|
1906
2140
|
const [openElem, setOpenElem] = React.useState(null);
|
|
1907
2141
|
const [rowQuery, setRowQuery] = React.useState("");
|
|
1908
2142
|
const [toolSort, setToolSort] = React.useState("size");
|
|
1909
|
-
const convNodes =
|
|
2143
|
+
const convNodes = props.convNodes;
|
|
1910
2144
|
const [fetched, setFetched] = React.useState(() => /* @__PURE__ */ new Map());
|
|
1911
2145
|
const bySeq = React.useMemo(() => {
|
|
1912
2146
|
const m = /* @__PURE__ */ new Map();
|
|
@@ -1935,7 +2169,8 @@ window.__ModuleLoader__.load({
|
|
|
1935
2169
|
return next;
|
|
1936
2170
|
});
|
|
1937
2171
|
setMissState("idle");
|
|
1938
|
-
}, () => {
|
|
2172
|
+
}, (error) => {
|
|
2173
|
+
console.warn("dsh-context: targeted history read failed", error);
|
|
1939
2174
|
if (live) setMissState("failed");
|
|
1940
2175
|
});
|
|
1941
2176
|
return () => {
|
|
@@ -1995,6 +2230,17 @@ window.__ModuleLoader__.load({
|
|
|
1995
2230
|
const prevByCat = prevView !== null ? byCatOf(prevView) : null;
|
|
1996
2231
|
const byCat = byCatOf(view);
|
|
1997
2232
|
const toolCount = (c) => countOf(view, byCat, c);
|
|
2233
|
+
const singleKeyOf = (c) => {
|
|
2234
|
+
if (c === "system") return view.header?.system !== void 0 ? "sys" : null;
|
|
2235
|
+
if (c === "tools") {
|
|
2236
|
+
const tools = view.header?.tools;
|
|
2237
|
+
return tools !== void 0 && tools.length === 1 ? "tool:" + tools[0].name : null;
|
|
2238
|
+
}
|
|
2239
|
+
/* v8 ignore next 1 -- reached only through toggleCat's openable guard
|
|
2240
|
+
(count > 0 ⟺ byCat[c] exists); the fallback is defensive. */
|
|
2241
|
+
const nodes = byCat[c] ?? [];
|
|
2242
|
+
return nodes.length === 1 ? "n" + String(nodes[0].seq) : null;
|
|
2243
|
+
};
|
|
1998
2244
|
const toggleCat = (c) => {
|
|
1999
2245
|
if (!(toolCount(c) > 0 || (c === "system" || c === "tools") && view.header === null)) return;
|
|
2000
2246
|
if (openCat === c) {
|
|
@@ -2004,7 +2250,7 @@ window.__ModuleLoader__.load({
|
|
|
2004
2250
|
}
|
|
2005
2251
|
setOpenCat(c);
|
|
2006
2252
|
setRowQuery("");
|
|
2007
|
-
setOpenElem(c
|
|
2253
|
+
setOpenElem(singleKeyOf(c));
|
|
2008
2254
|
};
|
|
2009
2255
|
const toggleElem = (key) => {
|
|
2010
2256
|
setOpenElem(openElem === key ? null : key);
|
|
@@ -2373,7 +2619,6 @@ window.__ModuleLoader__.load({
|
|
|
2373
2619
|
//#region src/client/components/contextModal.tsx
|
|
2374
2620
|
function makeContextModal(ctx, kit) {
|
|
2375
2621
|
const { t } = kit;
|
|
2376
|
-
const sessions = ctx.get("sessions");
|
|
2377
2622
|
const StackedBar = makeStackedBar(kit);
|
|
2378
2623
|
const CurrentComposition = makeCurrentComposition(kit, StackedBar, makeLegend(kit));
|
|
2379
2624
|
const ContextBrowser = makeContextBrowser(kit, StackedBar);
|
|
@@ -2385,16 +2630,18 @@ window.__ModuleLoader__.load({
|
|
|
2385
2630
|
const pressure = typeof props.useProjection === "function" ? contextPressureOf(props.useProjection("contextPressure")) : null;
|
|
2386
2631
|
const breakdown = typeof props.useProjection === "function" ? contextBreakdownOf(props.useProjection("contextBreakdown")) : null;
|
|
2387
2632
|
const headers = typeof props.useProjection === "function" ? headersOf(props.useProjection("contextHeaders")) : null;
|
|
2633
|
+
const convNodes = conversationNodesOf(props);
|
|
2388
2634
|
const [hoverCat, setHoverCat] = React.useState(null);
|
|
2389
2635
|
const fetchContent = React.useMemo(() => sessionId !== "" ? makeContentFetcher(ctx, sessionId) : void 0, [ctx, sessionId]);
|
|
2390
2636
|
const close = React.useCallback(() => {
|
|
2391
2637
|
if (sessionId === "") return;
|
|
2392
2638
|
modalStoreOf(sessionId).set(false);
|
|
2393
2639
|
const guard = takePendingConsume(sessionId);
|
|
2640
|
+
const sessions = ctx.get("sessions");
|
|
2394
2641
|
if (guard === void 0 || sessions === void 0) return;
|
|
2395
2642
|
const scope = sessions.scope(sessionId);
|
|
2396
2643
|
if (scope !== void 0) scope.bail(scope, "slash/input-consume-token", { guard });
|
|
2397
|
-
}, [sessionId]);
|
|
2644
|
+
}, [ctx, sessionId]);
|
|
2398
2645
|
React.useEffect(() => {
|
|
2399
2646
|
if (!open) return void 0;
|
|
2400
2647
|
const previous = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
@@ -2433,7 +2680,7 @@ window.__ModuleLoader__.load({
|
|
|
2433
2680
|
}), /* @__PURE__ */ React.createElement(ContextBrowser, {
|
|
2434
2681
|
data,
|
|
2435
2682
|
headers,
|
|
2436
|
-
|
|
2683
|
+
convNodes,
|
|
2437
2684
|
fetchContent,
|
|
2438
2685
|
hoverKey: hoverCat,
|
|
2439
2686
|
onHoverKey: setHoverCat
|
|
@@ -4122,6 +4369,58 @@ window.__ModuleLoader__.load({
|
|
|
4122
4369
|
return /* @__PURE__ */ React.createElement("div", { className: "lc-agents-inspector" }, /* @__PURE__ */ React.createElement("b", { className: "lc-agents-inspector-name" }, node.label), node.isCurrent ? /* @__PURE__ */ React.createElement("span", { className: "lc-agents-badge" }, t("agents.self")) : null, node.running ? /* @__PURE__ */ React.createElement("span", { className: "lc-agents-badge lc-agents-badge-on" }, t("agents.running")) : null, node.identity !== null ? /* @__PURE__ */ React.createElement("span", { className: "lc-agents-badge" }, t(node.identity.mode === "one-shot" ? "agents.oneshot" : "agents.continuable")) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-agents-inspector-stats" }, bits.join(" · ")), !node.isCurrent ? /* @__PURE__ */ React.createElement("span", { className: "lc-agents-inspector-open" }, t("agents.open")) : null);
|
|
4123
4370
|
}
|
|
4124
4371
|
//#endregion
|
|
4372
|
+
//#region src/client/components/donut.tsx
|
|
4373
|
+
function makeDonut(kit) {
|
|
4374
|
+
return function Donut(props) {
|
|
4375
|
+
const size = props.size ?? 118;
|
|
4376
|
+
let total = 0;
|
|
4377
|
+
for (const s of props.segments) if (Number.isFinite(s.value) && s.value > 0) total += s.value;
|
|
4378
|
+
const arcs = [];
|
|
4379
|
+
let acc = 0;
|
|
4380
|
+
if (total > 0) for (const s of props.segments) {
|
|
4381
|
+
const v = Number.isFinite(s.value) && s.value > 0 ? s.value : 0;
|
|
4382
|
+
if (v === 0) continue;
|
|
4383
|
+
const pct = v / total * 100;
|
|
4384
|
+
arcs.push({
|
|
4385
|
+
key: s.key,
|
|
4386
|
+
color: s.color,
|
|
4387
|
+
pct,
|
|
4388
|
+
offset: 100 - acc + 25
|
|
4389
|
+
});
|
|
4390
|
+
acc += pct;
|
|
4391
|
+
}
|
|
4392
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
4393
|
+
className: "lc-donut",
|
|
4394
|
+
style: {
|
|
4395
|
+
width: size,
|
|
4396
|
+
height: size
|
|
4397
|
+
}
|
|
4398
|
+
}, /* @__PURE__ */ React.createElement("svg", {
|
|
4399
|
+
viewBox: "0 0 42 42",
|
|
4400
|
+
width: size,
|
|
4401
|
+
height: size,
|
|
4402
|
+
"aria-hidden": "true"
|
|
4403
|
+
}, arcs.length === 0 ? /* @__PURE__ */ React.createElement("circle", {
|
|
4404
|
+
className: "lc-donut-track",
|
|
4405
|
+
cx: "21",
|
|
4406
|
+
cy: "21",
|
|
4407
|
+
r: "15.9155",
|
|
4408
|
+
fill: "none",
|
|
4409
|
+
strokeWidth: "4"
|
|
4410
|
+
}) : arcs.map((a) => /* @__PURE__ */ React.createElement("circle", {
|
|
4411
|
+
key: a.key,
|
|
4412
|
+
cx: "21",
|
|
4413
|
+
cy: "21",
|
|
4414
|
+
r: "15.9155",
|
|
4415
|
+
fill: "none",
|
|
4416
|
+
stroke: a.color,
|
|
4417
|
+
strokeWidth: "4",
|
|
4418
|
+
strokeDasharray: `${a.pct} ${100 - a.pct}`,
|
|
4419
|
+
strokeDashoffset: a.offset
|
|
4420
|
+
}))), /* @__PURE__ */ React.createElement("div", { className: "lc-donut-center" }, /* @__PURE__ */ React.createElement("b", { style: { fontSize: Math.max(11, Math.round(size * .13)) } }, props.centerTop), props.centerSub !== void 0 ? /* @__PURE__ */ React.createElement("span", { style: { fontSize: Math.max(9, Math.round(size * .105)) } }, props.centerSub) : null));
|
|
4421
|
+
};
|
|
4422
|
+
}
|
|
4423
|
+
//#endregion
|
|
4125
4424
|
//#region src/client/components/events.tsx
|
|
4126
4425
|
const EVENT_ICONS = {
|
|
4127
4426
|
compaction: "✂",
|
|
@@ -4443,6 +4742,46 @@ window.__ModuleLoader__.load({
|
|
|
4443
4742
|
return false;
|
|
4444
4743
|
}
|
|
4445
4744
|
//#endregion
|
|
4745
|
+
//#region src/client/settingsJump.ts
|
|
4746
|
+
/**
|
|
4747
|
+
* Best-effort jump to this plugin's settings page (Settings → Plugins →
|
|
4748
|
+
* Plugin configuration). The harness settings panel keeps its open state
|
|
4749
|
+
* inside the shell component — no plugin-facing open face exists — so the
|
|
4750
|
+
* jump drives the real chrome: click the sidebar's settings trigger, then
|
|
4751
|
+
* the Plugins section nav row, both found by their shipped attributes and
|
|
4752
|
+
* labels. EVERY step is individually guarded: a shell that doesn't match
|
|
4753
|
+
* (older host, different layout, missing sidebar) degrades the whole jump
|
|
4754
|
+
* to a silent no-op — this path must never throw into the caller's render.
|
|
4755
|
+
*/
|
|
4756
|
+
/** The Plugins settings section's shipped nav labels (en/zh locales). */
|
|
4757
|
+
const SECTION_LABELS = /* @__PURE__ */ new Set(["Plugins", "插件"]);
|
|
4758
|
+
/** Buttons the jump may operate on, in document order. */
|
|
4759
|
+
function buttonsOf(doc) {
|
|
4760
|
+
return [...doc.querySelectorAll("button")];
|
|
4761
|
+
}
|
|
4762
|
+
/** The sidebar's settings triggers: dialog semantics plus an expanded flag. */
|
|
4763
|
+
function findTriggers(doc) {
|
|
4764
|
+
return buttonsOf(doc).filter((b) => b.getAttribute("aria-haspopup") === "dialog" && b.hasAttribute("aria-expanded"));
|
|
4765
|
+
}
|
|
4766
|
+
/** The Plugins section's nav row, matched by its shipped label. */
|
|
4767
|
+
function findSectionRow(doc) {
|
|
4768
|
+
return buttonsOf(doc).find((b) => SECTION_LABELS.has(b.textContent.trim()));
|
|
4769
|
+
}
|
|
4770
|
+
function openPluginSettings(doc = document, schedule = (run, ms) => {
|
|
4771
|
+
window.setTimeout(run, ms);
|
|
4772
|
+
}) {
|
|
4773
|
+
try {
|
|
4774
|
+
const triggers = findTriggers(doc);
|
|
4775
|
+
if (triggers.find((b) => b.getAttribute("aria-expanded") === "true") === void 0 && triggers.length === 0) return;
|
|
4776
|
+
triggers.find((b) => b.getAttribute("aria-expanded") !== "true")?.click();
|
|
4777
|
+
schedule(() => {
|
|
4778
|
+
try {
|
|
4779
|
+
findSectionRow(doc)?.click();
|
|
4780
|
+
} catch {}
|
|
4781
|
+
}, 80);
|
|
4782
|
+
} catch {}
|
|
4783
|
+
}
|
|
4784
|
+
//#endregion
|
|
4446
4785
|
//#region src/client/components/pluginInfo.tsx
|
|
4447
4786
|
function makePluginInfo(kit) {
|
|
4448
4787
|
const { t } = kit;
|
|
@@ -4455,7 +4794,7 @@ window.__ModuleLoader__.load({
|
|
|
4455
4794
|
return function PluginInfo() {
|
|
4456
4795
|
const [latest, setLatest] = React.useState(null);
|
|
4457
4796
|
React.useEffect(() => {
|
|
4458
|
-
if ("0.
|
|
4797
|
+
if ("0.38.0".includes("-dev")) return;
|
|
4459
4798
|
let on = true;
|
|
4460
4799
|
fetchLatestVersion().then((v) => {
|
|
4461
4800
|
if (on && v) setLatest(v);
|
|
@@ -4464,8 +4803,8 @@ window.__ModuleLoader__.load({
|
|
|
4464
4803
|
on = false;
|
|
4465
4804
|
};
|
|
4466
4805
|
}, []);
|
|
4467
|
-
const update = latest !== null && isNewerVersion(latest, "0.
|
|
4468
|
-
const nameValue = ["dsh-context (v0.
|
|
4806
|
+
const update = latest !== null && isNewerVersion(latest, "0.38.0") ? latest : null;
|
|
4807
|
+
const nameValue = ["dsh-context (v0.38.0)"];
|
|
4469
4808
|
if (update) nameValue.push(/* @__PURE__ */ React.createElement("span", {
|
|
4470
4809
|
key: "update",
|
|
4471
4810
|
className: "lc-pi-update"
|
|
@@ -4475,7 +4814,13 @@ window.__ModuleLoader__.load({
|
|
|
4475
4814
|
href: PLUGIN_REPO,
|
|
4476
4815
|
target: "_blank",
|
|
4477
4816
|
rel: "noreferrer"
|
|
4478
|
-
}, t("plugin.hint"))), /* @__PURE__ */ React.createElement("div", { className: "lc-pi-grid" }, row(t("plugin.name"), nameValue, PLUGIN_REPO + "/releases"), row(t("plugin.github"), PLUGIN_REPO_SHORT, PLUGIN_REPO)
|
|
4817
|
+
}, t("plugin.hint"))), /* @__PURE__ */ React.createElement("div", { className: "lc-pi-grid" }, row(t("plugin.name"), nameValue, PLUGIN_REPO + "/releases"), row(t("plugin.github"), PLUGIN_REPO_SHORT, PLUGIN_REPO), /* @__PURE__ */ React.createElement("button", {
|
|
4818
|
+
type: "button",
|
|
4819
|
+
className: "lc-pi-row lc-pi-row-btn",
|
|
4820
|
+
onClick: () => {
|
|
4821
|
+
openPluginSettings();
|
|
4822
|
+
}
|
|
4823
|
+
}, /* @__PURE__ */ React.createElement("div", { className: "lc-pi-label" }, t("plugin.settings")), /* @__PURE__ */ React.createElement("div", { className: "lc-pi-value" }, t("plugin.settingsOpen")))));
|
|
4479
4824
|
};
|
|
4480
4825
|
}
|
|
4481
4826
|
//#endregion
|
|
@@ -4657,19 +5002,21 @@ window.__ModuleLoader__.load({
|
|
|
4657
5002
|
return /* @__PURE__ */ React.createElement("div", { className: "lc-detail" }, /* @__PURE__ */ React.createElement("div", { className: "lc-detail-head" }, /* @__PURE__ */ React.createElement("b", null, head), marker !== null && markerAt !== null ? /* @__PURE__ */ React.createElement("span", {
|
|
4658
5003
|
className: "lc-detail-marker",
|
|
4659
5004
|
title: eventLabel(marker)
|
|
4660
|
-
}, "✂ " + markerAt) : null, isTurn ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-tag" }, t("detail.lastStep")) : null, delta ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-tag" }, t("gran.delta")) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-detail-time" }, fmtTime(req.time)), delta ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-metric" + (net > 0 ? " lc-detail-metric-up" : net < 0 ? " lc-detail-metric-down" : "") }, t("tip.delta", { n: (net > 0 ? "+" : "") + fmt(net) })) : null, !delta && req.prompt !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-metric" }, t("detail.actual", { n: fmt(req.prompt) })) : null, !delta && req.output !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-metric" }, t("detail.output", { n: fmt(req.output) })) : null, !delta && req.prompt !== void 0 && req.cacheRead !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-metric" }, t("detail.cache", { n: cacheHitPercent
|
|
5005
|
+
}, "✂ " + markerAt) : null, isTurn ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-tag" }, t("detail.lastStep")) : null, delta ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-tag" }, t("gran.delta")) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-detail-time" }, fmtTime(req.time)), delta ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-metric" + (net > 0 ? " lc-detail-metric-up" : net < 0 ? " lc-detail-metric-down" : "") }, t("tip.delta", { n: (net > 0 ? "+" : "") + fmt(net) })) : null, !delta && req.prompt !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-metric" }, t("detail.actual", { n: fmt(req.prompt) })) : null, !delta && req.output !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-metric" }, t("detail.output", { n: fmt(req.output) })) : null, !delta && req.prompt !== void 0 && req.cacheRead !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-metric" }, t("detail.cache", { n: cacheHitPercent(req.cacheRead, req.prompt) ?? "—" })) : null), /* @__PURE__ */ React.createElement(BriefSection, {
|
|
4661
5006
|
brief: props.brief,
|
|
4662
5007
|
convOf: props.convOf,
|
|
4663
5008
|
onLocate: props.onLocate
|
|
4664
5009
|
}), /* @__PURE__ */ React.createElement(StackedBar, {
|
|
4665
5010
|
parts,
|
|
4666
|
-
height: 10
|
|
5011
|
+
height: 10,
|
|
5012
|
+
hoverKey: props.hoverKey,
|
|
5013
|
+
tip: false
|
|
4667
5014
|
}), /* @__PURE__ */ React.createElement("div", { className: "lc-detail-rows" }, CATS.map((c, i) => {
|
|
4668
5015
|
const v = delta ? deltas[i] : req[c.key] || 0;
|
|
4669
5016
|
const mag = Math.abs(v);
|
|
4670
5017
|
return /* @__PURE__ */ React.createElement("div", {
|
|
4671
5018
|
key: c.key,
|
|
4672
|
-
className: "lc-detail-row"
|
|
5019
|
+
className: "lc-detail-row" + (props.hoverKey === c.key ? " lc-detail-row-on" : "")
|
|
4673
5020
|
}, /* @__PURE__ */ React.createElement("i", { style: { background: c.color } }), /* @__PURE__ */ React.createElement("span", { className: "lc-detail-label" }, catLabel(c.key)), /* @__PURE__ */ React.createElement("span", { className: "lc-bar-track" }, delta ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", { className: "lc-bar-zero" }), v !== 0 ? /* @__PURE__ */ React.createElement("span", {
|
|
4674
5021
|
className: "lc-bar-fill " + (v > 0 ? "lc-bar-fill-up" : "lc-bar-fill-down"),
|
|
4675
5022
|
style: {
|
|
@@ -4787,40 +5134,20 @@ window.__ModuleLoader__.load({
|
|
|
4787
5134
|
return formatCost(amount, currency).replace(/0+$/, "").replace(/\.$/, "");
|
|
4788
5135
|
}
|
|
4789
5136
|
//#endregion
|
|
4790
|
-
//#region src/client/components/
|
|
4791
|
-
|
|
4792
|
-
* Cache-hit share of billed prompt-side input — same three disjoint buckets
|
|
4793
|
-
* as the harness chat line (`cacheReadTokens` over uncached + reads + writes)
|
|
4794
|
-
* and the step line's 缓存 figure; null when nothing was billed.
|
|
4795
|
-
*/
|
|
4796
|
-
function cacheHitPercent(usage) {
|
|
4797
|
-
const uncached = numOf(usage.uncachedInputTokens);
|
|
4798
|
-
const reads = numOf(usage.cacheReadTokens);
|
|
4799
|
-
const writes = numOf(usage.cacheWriteTokens);
|
|
4800
|
-
return cacheHitPercent$1(reads, uncached + reads + writes);
|
|
4801
|
-
}
|
|
4802
|
-
function cell(label, value, tip) {
|
|
4803
|
-
return /* @__PURE__ */ React.createElement("div", { className: "lc-stat" + (tip === void 0 ? "" : " lc-stat-tipped") }, /* @__PURE__ */ React.createElement("span", { className: "lc-stat-label" }, label, tip !== void 0 && /* @__PURE__ */ React.createElement("i", {
|
|
4804
|
-
className: "lc-stat-q",
|
|
4805
|
-
"aria-hidden": "true"
|
|
4806
|
-
}, "?")), /* @__PURE__ */ React.createElement("b", { className: "lc-stat-value" }, value), tip !== void 0 && /* @__PURE__ */ React.createElement("span", {
|
|
4807
|
-
className: "lc-stat-tip",
|
|
4808
|
-
role: "tooltip"
|
|
4809
|
-
}, tip));
|
|
4810
|
-
}
|
|
4811
|
-
function makeStatsBoard(kit) {
|
|
5137
|
+
//#region src/client/components/statsContext.tsx
|
|
5138
|
+
function makeStatsContext(kit) {
|
|
4812
5139
|
const { t, fmt } = kit;
|
|
4813
|
-
return function
|
|
5140
|
+
return function StatsContext(props) {
|
|
4814
5141
|
const turns = /* @__PURE__ */ new Set();
|
|
4815
|
-
let steps = 0
|
|
5142
|
+
let steps = 0;
|
|
4816
5143
|
for (const req of props.requests) {
|
|
4817
5144
|
turns.add(req.turn ?? 0);
|
|
4818
5145
|
steps++;
|
|
4819
5146
|
}
|
|
4820
|
-
|
|
5147
|
+
let injects = 0, compactions = 0, prunes = 0;
|
|
5148
|
+
for (const ev of props.events) if (ev.kind === "inject") injects++;
|
|
5149
|
+
else if (ev.kind === "compaction") compactions++;
|
|
4821
5150
|
else if (ev.kind === "prune") prunes++;
|
|
4822
|
-
else if (ev.kind === "inject") injects++;
|
|
4823
|
-
const hit = props.usage !== null ? cacheHitPercent(props.usage) : null;
|
|
4824
5151
|
const currency = props.locale === "zh" ? "cny" : "usd";
|
|
4825
5152
|
const cost = estimateSessionCost(props.cost, currency);
|
|
4826
5153
|
const fmtRate = (n) => formatPriceRate(n, currency);
|
|
@@ -4831,7 +5158,149 @@ window.__ModuleLoader__.load({
|
|
|
4831
5158
|
key: r.family,
|
|
4832
5159
|
className: "lc-stat-tip-row"
|
|
4833
5160
|
}, /* @__PURE__ */ React.createElement("b", { className: "lc-stat-tip-model" }, r.family), " ", t("stats.costHit"), " ", fmtRate(r.peak.hit), "/", fmtRate(r.off.hit), " · ", t("stats.costMiss"), " ", fmtRate(r.peak.miss), "/", fmtRate(r.off.miss), " · ", t("stats.costOut"), " ", fmtRate(r.peak.out), "/", fmtRate(r.off.out))))];
|
|
4834
|
-
|
|
5161
|
+
const cell = (label, value, tip) => /* @__PURE__ */ React.createElement("div", { className: "lc-stat" + (tip === void 0 ? "" : " lc-stat-tipped") }, /* @__PURE__ */ React.createElement("span", { className: "lc-stat-label" }, label, tip !== void 0 && /* @__PURE__ */ React.createElement("i", {
|
|
5162
|
+
className: "lc-stat-q",
|
|
5163
|
+
"aria-hidden": "true"
|
|
5164
|
+
}, "?")), /* @__PURE__ */ React.createElement("b", { className: "lc-stat-value" }, typeof value === "number" ? fmt(value) : value), tip !== void 0 && /* @__PURE__ */ React.createElement("span", {
|
|
5165
|
+
className: "lc-stat-tip",
|
|
5166
|
+
role: "tooltip"
|
|
5167
|
+
}, tip));
|
|
5168
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col-stats" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, /* @__PURE__ */ React.createElement("span", { className: "lc-card-title-text" }, t("stats.title")), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("stats.hint"))), /* @__PURE__ */ React.createElement("div", { className: "lc-stats" }, cell(t("stats.turns"), turns.size), cell(t("stats.steps"), steps), cell(t("stats.toolCalls"), props.toolCalls ?? 0), cell(t("stats.images"), props.images ?? 0), cell(t("stats.cost"), cost === null ? "—" : formatCost(cost, currency), costTip), cell(t("stats.injects"), injects), cell(t("stats.compactions"), compactions), cell(t("stats.prunes"), prunes)));
|
|
5169
|
+
};
|
|
5170
|
+
}
|
|
5171
|
+
//#endregion
|
|
5172
|
+
//#region src/client/components/sliceList.tsx
|
|
5173
|
+
function makeSliceList(kit) {
|
|
5174
|
+
return function SliceList(props) {
|
|
5175
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-sl" }, props.rows.map((r) => /* @__PURE__ */ React.createElement("div", {
|
|
5176
|
+
key: r.key,
|
|
5177
|
+
className: "lc-sl-row"
|
|
5178
|
+
}, /* @__PURE__ */ React.createElement("i", {
|
|
5179
|
+
className: "lc-sl-dot",
|
|
5180
|
+
style: { background: r.color }
|
|
5181
|
+
}), /* @__PURE__ */ React.createElement("span", { className: "lc-sl-label" }, r.label), r.count !== "" ? /* @__PURE__ */ React.createElement("span", { className: "lc-sl-count" }, r.count) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-sl-pct" }, r.pct))));
|
|
5182
|
+
};
|
|
5183
|
+
}
|
|
5184
|
+
//#endregion
|
|
5185
|
+
//#region src/client/components/statsTiming.tsx
|
|
5186
|
+
function makeStatsTiming(kit, Donut) {
|
|
5187
|
+
const { t, fmt, fmtDuration, fmtShare } = kit;
|
|
5188
|
+
const SliceList = makeSliceList(kit);
|
|
5189
|
+
return function StatsTiming(props) {
|
|
5190
|
+
const lang = props.locale === "zh" ? "zh" : "en";
|
|
5191
|
+
const timing = props.timing;
|
|
5192
|
+
const wall = timing !== null && Number.isFinite(timing.wallMs) && timing.wallMs > 0 ? timing.wallMs : 0;
|
|
5193
|
+
let segments = [];
|
|
5194
|
+
let rows = [];
|
|
5195
|
+
if (timing !== null && (wall > 0 || timing.calls > 0 || timing.toolCalls > 0)) {
|
|
5196
|
+
const lm = Math.min(timing.lmMs, wall);
|
|
5197
|
+
const toolRing = Math.max(0, Math.min(timing.toolsMs, wall - lm));
|
|
5198
|
+
const other = Math.max(0, wall - lm - toolRing);
|
|
5199
|
+
const share = (ms) => wall > 0 ? ms / wall : 0;
|
|
5200
|
+
segments = [
|
|
5201
|
+
{
|
|
5202
|
+
key: "lm",
|
|
5203
|
+
color: "#3b82f6",
|
|
5204
|
+
value: share(lm)
|
|
5205
|
+
},
|
|
5206
|
+
{
|
|
5207
|
+
key: "tools",
|
|
5208
|
+
color: "#14b8a6",
|
|
5209
|
+
value: share(toolRing)
|
|
5210
|
+
},
|
|
5211
|
+
{
|
|
5212
|
+
key: "other",
|
|
5213
|
+
color: "#94a3b8",
|
|
5214
|
+
value: share(other)
|
|
5215
|
+
}
|
|
5216
|
+
];
|
|
5217
|
+
rows = [
|
|
5218
|
+
{
|
|
5219
|
+
key: "lm",
|
|
5220
|
+
color: "#3b82f6",
|
|
5221
|
+
label: `${t("timing.lm")} ${t("timing.times", { n: fmt(timing.calls) })}`,
|
|
5222
|
+
pct: fmtShare(timing.lmMs, wall),
|
|
5223
|
+
count: fmtDuration(timing.lmMs, lang)
|
|
5224
|
+
},
|
|
5225
|
+
{
|
|
5226
|
+
key: "tools",
|
|
5227
|
+
color: "#14b8a6",
|
|
5228
|
+
label: `${t("timing.tools")} ${t("timing.times", { n: fmt(timing.toolCalls) })}`,
|
|
5229
|
+
pct: fmtShare(timing.toolsMs, wall),
|
|
5230
|
+
count: fmtDuration(timing.toolsMs, lang)
|
|
5231
|
+
},
|
|
5232
|
+
{
|
|
5233
|
+
key: "other",
|
|
5234
|
+
color: "#94a3b8",
|
|
5235
|
+
label: t("timing.other"),
|
|
5236
|
+
pct: fmtShare(other, wall),
|
|
5237
|
+
count: fmtDuration(other, lang)
|
|
5238
|
+
}
|
|
5239
|
+
];
|
|
5240
|
+
}
|
|
5241
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col-stats lc-col-donut" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, /* @__PURE__ */ React.createElement("span", { className: "lc-card-title-text" }, t("timing.title")), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("timing.hint"))), rows.length === 0 ? /* @__PURE__ */ React.createElement("div", { className: "lc-empty" }, t("timing.empty")) : /* @__PURE__ */ React.createElement("div", { className: "lc-donut-row" }, /* @__PURE__ */ React.createElement(Donut, {
|
|
5242
|
+
segments,
|
|
5243
|
+
size: 96,
|
|
5244
|
+
centerTop: wall > 0 ? fmtDuration(wall, lang) : "—",
|
|
5245
|
+
centerSub: t("timing.total")
|
|
5246
|
+
}), /* @__PURE__ */ React.createElement(SliceList, { rows })));
|
|
5247
|
+
};
|
|
5248
|
+
}
|
|
5249
|
+
//#endregion
|
|
5250
|
+
//#region src/client/components/statsTokens.tsx
|
|
5251
|
+
function makeStatsTokens(kit, Donut) {
|
|
5252
|
+
const { t, fmt, fmtShare } = kit;
|
|
5253
|
+
const SliceList = makeSliceList(kit);
|
|
5254
|
+
return function StatsTokens(props) {
|
|
5255
|
+
const reads = props.usage !== null ? numOf(props.usage.cacheReadTokens) : 0;
|
|
5256
|
+
const writes = props.usage !== null ? numOf(props.usage.cacheWriteTokens) : 0;
|
|
5257
|
+
const uncached = props.usage !== null ? numOf(props.usage.uncachedInputTokens) : 0;
|
|
5258
|
+
const output = props.usage !== null ? numOf(props.usage.outputTokens) : 0;
|
|
5259
|
+
const billed = reads + writes + uncached + output;
|
|
5260
|
+
const hit = props.usage !== null ? cacheHitPercent(reads, uncached + reads + writes) : null;
|
|
5261
|
+
const buckets = [
|
|
5262
|
+
{
|
|
5263
|
+
key: "read",
|
|
5264
|
+
color: "#22c55e",
|
|
5265
|
+
label: t("tokens.cacheRead"),
|
|
5266
|
+
value: reads
|
|
5267
|
+
},
|
|
5268
|
+
{
|
|
5269
|
+
key: "write",
|
|
5270
|
+
color: "#f59e0b",
|
|
5271
|
+
label: t("tokens.cacheWrite"),
|
|
5272
|
+
value: writes
|
|
5273
|
+
},
|
|
5274
|
+
{
|
|
5275
|
+
key: "uncached",
|
|
5276
|
+
color: "#6366f1",
|
|
5277
|
+
label: t("tokens.uncached"),
|
|
5278
|
+
value: uncached
|
|
5279
|
+
},
|
|
5280
|
+
{
|
|
5281
|
+
key: "output",
|
|
5282
|
+
color: "#3b82f6",
|
|
5283
|
+
label: t("tokens.output"),
|
|
5284
|
+
value: output
|
|
5285
|
+
}
|
|
5286
|
+
];
|
|
5287
|
+
const rows = buckets.map((b) => ({
|
|
5288
|
+
key: b.key,
|
|
5289
|
+
color: b.color,
|
|
5290
|
+
label: b.label,
|
|
5291
|
+
pct: fmtShare(b.value, billed),
|
|
5292
|
+
count: fmt(b.value)
|
|
5293
|
+
}));
|
|
5294
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col-stats lc-col-donut" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, /* @__PURE__ */ React.createElement("span", { className: "lc-card-title-text" }, t("tokens.title")), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("tokens.hint"))), /* @__PURE__ */ React.createElement("div", { className: "lc-donut-row" }, /* @__PURE__ */ React.createElement(Donut, {
|
|
5295
|
+
segments: buckets.map((b) => ({
|
|
5296
|
+
key: b.key,
|
|
5297
|
+
color: b.color,
|
|
5298
|
+
value: b.value
|
|
5299
|
+
})),
|
|
5300
|
+
size: 96,
|
|
5301
|
+
centerTop: hit === null ? "—" : `${hit}%`,
|
|
5302
|
+
centerSub: t("tokens.cacheHit")
|
|
5303
|
+
}), /* @__PURE__ */ React.createElement(SliceList, { rows })));
|
|
4835
5304
|
};
|
|
4836
5305
|
}
|
|
4837
5306
|
//#endregion
|
|
@@ -4876,6 +5345,15 @@ window.__ModuleLoader__.load({
|
|
|
4876
5345
|
}
|
|
4877
5346
|
return markers;
|
|
4878
5347
|
}
|
|
5348
|
+
/**
|
|
5349
|
+
* The chat→Context jump's target: the turn bar whose closing reply the user clicked — the relayed seq is a turn's LAST step, exactly the
|
|
5350
|
+
* aggregate's record — or, when that turn has aged out of the host's retained window, the oldest retained bar. Resolved against turn
|
|
5351
|
+
* aggregates, since the jump pins in turn granularity. Null only on an empty history.
|
|
5352
|
+
*/
|
|
5353
|
+
function jumpTargetOf(requests, seq) {
|
|
5354
|
+
for (const req of requests) if (req.seq === seq) return req;
|
|
5355
|
+
return requests.length > 0 ? requests[0] : null;
|
|
5356
|
+
}
|
|
4879
5357
|
function makeTrendChart(kit) {
|
|
4880
5358
|
const { t, fmt, fmtTime, eventLabel, eventAt } = kit;
|
|
4881
5359
|
const CHART_H = 112;
|
|
@@ -4929,6 +5407,8 @@ window.__ModuleLoader__.load({
|
|
|
4929
5407
|
if (d <= 0) return null;
|
|
4930
5408
|
return /* @__PURE__ */ React.createElement("div", {
|
|
4931
5409
|
key: c.key,
|
|
5410
|
+
"data-cat": c.key,
|
|
5411
|
+
className: "lc-cat-seg",
|
|
4932
5412
|
style: {
|
|
4933
5413
|
height: `${Math.max(1, Math.round(d * props.deltaScale))}px`,
|
|
4934
5414
|
background: c.color
|
|
@@ -4942,6 +5422,8 @@ window.__ModuleLoader__.load({
|
|
|
4942
5422
|
if (d >= 0) return null;
|
|
4943
5423
|
return /* @__PURE__ */ React.createElement("div", {
|
|
4944
5424
|
key: c.key,
|
|
5425
|
+
"data-cat": c.key,
|
|
5426
|
+
className: "lc-cat-seg",
|
|
4945
5427
|
style: {
|
|
4946
5428
|
height: `${Math.max(1, Math.round(-d * props.deltaScale))}px`,
|
|
4947
5429
|
background: c.color
|
|
@@ -4952,6 +5434,8 @@ window.__ModuleLoader__.load({
|
|
|
4952
5434
|
if (!v) return null;
|
|
4953
5435
|
return /* @__PURE__ */ React.createElement("div", {
|
|
4954
5436
|
key: c.key,
|
|
5437
|
+
"data-cat": c.key,
|
|
5438
|
+
className: "lc-cat-seg",
|
|
4955
5439
|
style: {
|
|
4956
5440
|
height: `${Math.max(1, Math.round(v / props.maxTotal * CHART_H))}px`,
|
|
4957
5441
|
background: c.color
|
|
@@ -5135,6 +5619,7 @@ window.__ModuleLoader__.load({
|
|
|
5135
5619
|
}
|
|
5136
5620
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
5137
5621
|
className: "lc-chart",
|
|
5622
|
+
"data-catdim": props.hoverCat ?? void 0,
|
|
5138
5623
|
onMouseLeave: () => {
|
|
5139
5624
|
props.onHover(null);
|
|
5140
5625
|
}
|
|
@@ -5180,6 +5665,43 @@ window.__ModuleLoader__.load({
|
|
|
5180
5665
|
};
|
|
5181
5666
|
}
|
|
5182
5667
|
//#endregion
|
|
5668
|
+
//#region src/client/viewFocus.ts
|
|
5669
|
+
/**
|
|
5670
|
+
* Chat → Context jump relay. The assistant-message action records the clicked
|
|
5671
|
+
* reply's request seq here and activates the Context tab; the Context view
|
|
5672
|
+
* consumes the one-shot focus once its projection data is in. Module-level
|
|
5673
|
+
* per-session map — the same life pattern as the modal open-state stores.
|
|
5674
|
+
*/
|
|
5675
|
+
const pendingFocus = /* @__PURE__ */ new Map();
|
|
5676
|
+
/** Record the Context step (request seq) to reveal for `sessionId` — replaces any unconsumed request. */
|
|
5677
|
+
function requestContextFocus(sessionId, seq) {
|
|
5678
|
+
pendingFocus.set(sessionId, seq);
|
|
5679
|
+
}
|
|
5680
|
+
/** Take the pending focus request, if any — one-shot, the map entry is consumed. */
|
|
5681
|
+
function takeContextFocus(sessionId) {
|
|
5682
|
+
const seq = pendingFocus.get(sessionId);
|
|
5683
|
+
if (seq === void 0) return null;
|
|
5684
|
+
pendingFocus.delete(sessionId);
|
|
5685
|
+
return seq;
|
|
5686
|
+
}
|
|
5687
|
+
/**
|
|
5688
|
+
* Activate the Context tab by clicking its own tab-bar button (the semantic
|
|
5689
|
+
* `button[role="tab"]` chrome the conversation shell renders for every view).
|
|
5690
|
+
* The harness hands `openView` only to the ACTIVE view entry, so a nested
|
|
5691
|
+
* chat action cannot call it — this rides the same button a user click would.
|
|
5692
|
+
* Already-active is a no-op that still reports success; no matching tab (any
|
|
5693
|
+
* dsh layout without the tab bar) reports failure and nothing happens.
|
|
5694
|
+
*/
|
|
5695
|
+
function activateContextTab(label) {
|
|
5696
|
+
const tabs = document.querySelectorAll("button[role=\"tab\"]");
|
|
5697
|
+
for (const tab of tabs) {
|
|
5698
|
+
if (tab.textContent.trim() !== label) continue;
|
|
5699
|
+
if (tab.getAttribute("aria-selected") !== "true") tab.click();
|
|
5700
|
+
return true;
|
|
5701
|
+
}
|
|
5702
|
+
return false;
|
|
5703
|
+
}
|
|
5704
|
+
//#endregion
|
|
5183
5705
|
//#region src/client/components/contextView.tsx
|
|
5184
5706
|
const viewScroll = /* @__PURE__ */ new Map();
|
|
5185
5707
|
const EVENT_KINDS = [
|
|
@@ -5197,7 +5719,10 @@ window.__ModuleLoader__.load({
|
|
|
5197
5719
|
const RequestDetail = makeRequestDetail(kit, StackedBar);
|
|
5198
5720
|
const EventList = makeEventList(kit);
|
|
5199
5721
|
const FileCard = makeFileCard(kit, settings);
|
|
5200
|
-
const
|
|
5722
|
+
const Donut = makeDonut(kit);
|
|
5723
|
+
const StatsContext = makeStatsContext(kit);
|
|
5724
|
+
const StatsTiming = makeStatsTiming(kit, Donut);
|
|
5725
|
+
const StatsTokens = makeStatsTokens(kit, Donut);
|
|
5201
5726
|
const PluginInfo = makePluginInfo(kit);
|
|
5202
5727
|
const ContextBrowser = makeContextBrowser(kit, StackedBar);
|
|
5203
5728
|
const AgentGraph = makeAgentGraph(ctx, kit);
|
|
@@ -5215,6 +5740,7 @@ window.__ModuleLoader__.load({
|
|
|
5215
5740
|
const [granularity, setGranularity] = React.useState(() => settings.defaultGranularity());
|
|
5216
5741
|
const [trendMode, setTrendMode] = React.useState(() => settings.defaultTrendMode());
|
|
5217
5742
|
const [focusTurn, setFocusTurn] = React.useState(null);
|
|
5743
|
+
const [jumpSeq, setJumpSeq] = React.useState(null);
|
|
5218
5744
|
const [hoverCat, setHoverCat] = React.useState(null);
|
|
5219
5745
|
const [pickedKinds, setPickedKinds] = React.useState([...EVENT_KINDS]);
|
|
5220
5746
|
const toggleKind = (k) => {
|
|
@@ -5228,12 +5754,7 @@ window.__ModuleLoader__.load({
|
|
|
5228
5754
|
const clearNodeFocus = React.useCallback(() => {
|
|
5229
5755
|
setNodeFocus(null);
|
|
5230
5756
|
}, []);
|
|
5231
|
-
const loadImage = React.useMemo(() =>
|
|
5232
|
-
if (typeof sessionId !== "string" || sessionId === "") return void 0;
|
|
5233
|
-
const conversation = ctx.get("conversation");
|
|
5234
|
-
if (conversation === void 0 || typeof conversation.resolveImage !== "function") return void 0;
|
|
5235
|
-
return (attachment) => conversation.resolveImage(sessionId, attachment);
|
|
5236
|
-
}, [sessionId]);
|
|
5757
|
+
const loadImage = React.useMemo(() => imageLoaderOf(ctx, typeof sessionId === "string" ? sessionId : void 0), [ctx, sessionId]);
|
|
5237
5758
|
const fetchContent = React.useMemo(() => typeof sessionId === "string" && sessionId !== "" ? makeContentFetcher(ctx, sessionId) : void 0, [ctx, sessionId]);
|
|
5238
5759
|
const rootRef = React.useRef(null);
|
|
5239
5760
|
const scrollerRef = React.useRef(null);
|
|
@@ -5262,9 +5783,28 @@ window.__ModuleLoader__.load({
|
|
|
5262
5783
|
const shownEvents = pickedKinds.length === EVENT_KINDS.length ? events : events.filter((e) => pickedKinds.includes(e.kind));
|
|
5263
5784
|
const displayRequests = React.useMemo(() => granularity === "turn" ? aggregateByTurn(requests) : requests, [requests, granularity]);
|
|
5264
5785
|
const markers = React.useMemo(() => attachMarkers(displayRequests, events), [displayRequests, events]);
|
|
5786
|
+
React.useEffect(() => {
|
|
5787
|
+
if (typeof sessionId !== "string" || sessionId === "") return;
|
|
5788
|
+
const seq = takeContextFocus(sessionId);
|
|
5789
|
+
if (seq !== null) setJumpSeq(seq);
|
|
5790
|
+
}, [sessionId]);
|
|
5791
|
+
React.useEffect(() => {
|
|
5792
|
+
if (jumpSeq === null || data === null) return;
|
|
5793
|
+
setJumpSeq(null);
|
|
5794
|
+
const target = jumpTargetOf(aggregateByTurn(requests), jumpSeq);
|
|
5795
|
+
if (target === null) return;
|
|
5796
|
+
setGranularity("turn");
|
|
5797
|
+
setSelectedSeq(target.seq);
|
|
5798
|
+
setFocusTurn(target.turn ?? 0);
|
|
5799
|
+
if (scrollerRef.current !== null) scrollerRef.current.scrollTop = 0;
|
|
5800
|
+
}, [
|
|
5801
|
+
jumpSeq,
|
|
5802
|
+
data,
|
|
5803
|
+
requests
|
|
5804
|
+
]);
|
|
5265
5805
|
const briefList = React.useMemo(() => data ? briefNodes(data) : [], [data]);
|
|
5266
5806
|
const replyTips = React.useMemo(() => replyTipsOf(briefList), [briefList]);
|
|
5267
|
-
const convNodes =
|
|
5807
|
+
const convNodes = conversationNodesOf(props);
|
|
5268
5808
|
const bySeq = React.useMemo(() => {
|
|
5269
5809
|
const m = /* @__PURE__ */ new Map();
|
|
5270
5810
|
for (const n of convNodes ?? []) m.set(n.seq, n);
|
|
@@ -5354,20 +5894,23 @@ window.__ModuleLoader__.load({
|
|
|
5354
5894
|
break;
|
|
5355
5895
|
}
|
|
5356
5896
|
}
|
|
5897
|
+
const trendHoverCat = hoverCat !== null && hoverCat !== "free" ? hoverCat : null;
|
|
5357
5898
|
const localeSvc = ctx.get("locale");
|
|
5358
5899
|
const activeLocale = localeSvc !== void 0 && typeof localeSvc.getLocale === "function" ? localeSvc.getLocale().active : "en";
|
|
5359
5900
|
const subtitle = (data.model ?? "") + (data.provider ? " · " + data.provider : "");
|
|
5360
5901
|
return /* @__PURE__ */ React.createElement("div", {
|
|
5361
5902
|
className: "lc-root",
|
|
5362
5903
|
ref: rootRef
|
|
5363
|
-
}, /* @__PURE__ */ React.createElement("div", { className: "lc-cols lc-head" }, /* @__PURE__ */ React.createElement(
|
|
5904
|
+
}, /* @__PURE__ */ React.createElement("div", { className: "lc-cols lc-head" }, /* @__PURE__ */ React.createElement(StatsContext, {
|
|
5364
5905
|
requests,
|
|
5365
5906
|
events,
|
|
5366
|
-
usage,
|
|
5367
5907
|
toolCalls: data.toolCalls,
|
|
5368
5908
|
images: data.images,
|
|
5369
5909
|
cost: data.cost,
|
|
5370
5910
|
locale: activeLocale
|
|
5911
|
+
}), /* @__PURE__ */ React.createElement(StatsTokens, { usage }), /* @__PURE__ */ React.createElement(StatsTiming, {
|
|
5912
|
+
timing: data.timing ?? null,
|
|
5913
|
+
locale: activeLocale
|
|
5371
5914
|
}), /* @__PURE__ */ React.createElement(PluginInfo, null)), /* @__PURE__ */ React.createElement("div", { className: "lc-cols" }, /* @__PURE__ */ React.createElement("div", { className: "lc-col" }, /* @__PURE__ */ React.createElement(CurrentComposition, {
|
|
5372
5915
|
head,
|
|
5373
5916
|
subtitle,
|
|
@@ -5406,6 +5949,7 @@ window.__ModuleLoader__.load({
|
|
|
5406
5949
|
granularity,
|
|
5407
5950
|
mode: trendMode,
|
|
5408
5951
|
focusTurn,
|
|
5952
|
+
hoverCat: trendHoverCat,
|
|
5409
5953
|
onSelect: setSelectedSeq,
|
|
5410
5954
|
onHover: setHoveredSeq,
|
|
5411
5955
|
onHoverTurn: setHoverTurn,
|
|
@@ -5426,11 +5970,12 @@ window.__ModuleLoader__.load({
|
|
|
5426
5970
|
marker: activeReq !== null ? markerOf(activeReq) : void 0,
|
|
5427
5971
|
brief,
|
|
5428
5972
|
convOf,
|
|
5429
|
-
onLocate: locateNode
|
|
5973
|
+
onLocate: locateNode,
|
|
5974
|
+
hoverKey: trendHoverCat
|
|
5430
5975
|
})))), /* @__PURE__ */ React.createElement("div", { className: "lc-col lc-col-browser" }, /* @__PURE__ */ React.createElement(ContextBrowser, {
|
|
5431
5976
|
data,
|
|
5432
5977
|
headers,
|
|
5433
|
-
|
|
5978
|
+
convNodes,
|
|
5434
5979
|
fetchContent,
|
|
5435
5980
|
previewSeq: hoveredSeq,
|
|
5436
5981
|
pinSeq: pinnedReq !== null ? pinnedReq.seq : null,
|
|
@@ -5465,6 +6010,85 @@ window.__ModuleLoader__.load({
|
|
|
5465
6010
|
};
|
|
5466
6011
|
}
|
|
5467
6012
|
//#endregion
|
|
6013
|
+
//#region src/client/components/contextJump.tsx
|
|
6014
|
+
/**
|
|
6015
|
+
* The assistant-message action that jumps to the Context tab at this reply's
|
|
6016
|
+
* turn. Registered on the harness `conversation.chat.assistant-actions` seat
|
|
6017
|
+
* (the icon row beside copy/branch), it receives the finalized reply's durable
|
|
6018
|
+
* message id, resolves the matching assistant node's seq off whichever node
|
|
6019
|
+
* seat the running harness serves (`useChat` on 0.1.2+, the session snapshot
|
|
6020
|
+
* before it), records it in the viewFocus relay, and activates the Context
|
|
6021
|
+
* tab — where the jump pins the reply's TURN (see contextView's leg 2). An
|
|
6022
|
+
* unresolvable seq still switches tabs, just without a pin; a message id that
|
|
6023
|
+
* is not a plain string renders nothing at all.
|
|
6024
|
+
*/
|
|
6025
|
+
/**
|
|
6026
|
+
* The reply's request seq by its durable message id, or null when no served node proves the pair. Join/log nodes are untrusted input: each
|
|
6027
|
+
* element is isolated, so one hostile object that throws on property access is skipped — the jump keeps its pin, never its click.
|
|
6028
|
+
*/
|
|
6029
|
+
function seqOfMessageId(nodes, messageId) {
|
|
6030
|
+
for (const node of nodes ?? []) try {
|
|
6031
|
+
if (node.kind !== "assistant" || node.messageId !== messageId) continue;
|
|
6032
|
+
return typeof node.seq === "number" && Number.isFinite(node.seq) ? node.seq : null;
|
|
6033
|
+
} catch {
|
|
6034
|
+
continue;
|
|
6035
|
+
}
|
|
6036
|
+
return null;
|
|
6037
|
+
}
|
|
6038
|
+
/** The jump glyph: the plugin's mini stacked composition bars, same 16px outline family as the shipped row icons. */
|
|
6039
|
+
function JumpIcon() {
|
|
6040
|
+
return /* @__PURE__ */ React.createElement("svg", {
|
|
6041
|
+
width: "16",
|
|
6042
|
+
height: "16",
|
|
6043
|
+
viewBox: "0 0 16 16",
|
|
6044
|
+
fill: "none",
|
|
6045
|
+
"aria-hidden": "true"
|
|
6046
|
+
}, /* @__PURE__ */ React.createElement("rect", {
|
|
6047
|
+
x: "2",
|
|
6048
|
+
y: "3",
|
|
6049
|
+
width: "12",
|
|
6050
|
+
height: "2",
|
|
6051
|
+
rx: "1",
|
|
6052
|
+
fill: "currentColor"
|
|
6053
|
+
}), /* @__PURE__ */ React.createElement("rect", {
|
|
6054
|
+
x: "2",
|
|
6055
|
+
y: "7",
|
|
6056
|
+
width: "8.5",
|
|
6057
|
+
height: "2",
|
|
6058
|
+
rx: "1",
|
|
6059
|
+
fill: "currentColor"
|
|
6060
|
+
}), /* @__PURE__ */ React.createElement("rect", {
|
|
6061
|
+
x: "2",
|
|
6062
|
+
y: "11",
|
|
6063
|
+
width: "5.5",
|
|
6064
|
+
height: "2",
|
|
6065
|
+
rx: "1",
|
|
6066
|
+
fill: "currentColor"
|
|
6067
|
+
}));
|
|
6068
|
+
}
|
|
6069
|
+
function makeContextJumpButton(kit) {
|
|
6070
|
+
const { t } = kit;
|
|
6071
|
+
return function ContextJump(props) {
|
|
6072
|
+
const messageId = props.messageId;
|
|
6073
|
+
if (typeof messageId !== "string" || messageId === "") return null;
|
|
6074
|
+
const jump = () => {
|
|
6075
|
+
const seq = seqOfMessageId(conversationNodesOf(props), messageId);
|
|
6076
|
+
const sessionId = props.sessionId;
|
|
6077
|
+
if (seq !== null && typeof sessionId === "string" && sessionId !== "") requestContextFocus(sessionId, seq);
|
|
6078
|
+
activateContextTab(t("tab"));
|
|
6079
|
+
};
|
|
6080
|
+
return /* @__PURE__ */ React.createElement(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
6081
|
+
label: t("jump.title"),
|
|
6082
|
+
side: "bottom"
|
|
6083
|
+
}, /* @__PURE__ */ React.createElement("button", {
|
|
6084
|
+
type: "button",
|
|
6085
|
+
className: "lc-jump",
|
|
6086
|
+
"aria-label": t("jump.title"),
|
|
6087
|
+
onClick: jump
|
|
6088
|
+
}, /* @__PURE__ */ React.createElement(JumpIcon, null)));
|
|
6089
|
+
};
|
|
6090
|
+
}
|
|
6091
|
+
//#endregion
|
|
5468
6092
|
//#region src/client/viewkit.ts
|
|
5469
6093
|
function makeViewKit(t) {
|
|
5470
6094
|
const { eventLabel, eventAt } = makeEventText(t);
|
|
@@ -5472,6 +6096,8 @@ window.__ModuleLoader__.load({
|
|
|
5472
6096
|
t,
|
|
5473
6097
|
fmt,
|
|
5474
6098
|
fmtTime,
|
|
6099
|
+
fmtDuration: fmtDuration$1,
|
|
6100
|
+
fmtShare,
|
|
5475
6101
|
catLabel: (key) => t("cat." + key),
|
|
5476
6102
|
eventLabel,
|
|
5477
6103
|
eventAt
|
|
@@ -5479,7 +6105,7 @@ window.__ModuleLoader__.load({
|
|
|
5479
6105
|
}
|
|
5480
6106
|
//#endregion
|
|
5481
6107
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles.css.mjs
|
|
5482
|
-
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{flex-wrap:wrap;align-items:baseline;gap:8px;margin-bottom:10px;font-weight:600;display:flex}.lc-card-title-text{white-space:nowrap;flex:none}.lc-stats{grid-template-columns:repeat(auto-fit,minmax(62px,1fr));gap:6px;display:grid}.lc-stat{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex-direction:column;gap:2px;min-width:0;padding:6px;display:flex}.lc-stat-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;font-weight:600;overflow:hidden}.lc-stat-value{color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;text-align:center;font-size:14px;font-weight:600;overflow:hidden}.lc-stat-sub{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;overflow:hidden}.lc-stat-tipped{position:relative}.lc-stat-q{text-align:center;width:11px;height:11px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);cursor:help;border-radius:50%;margin-left:4px;font-size:9px;font-style:normal;font-weight:700;line-height:11px;display:inline-block}.lc-stat-tipped:hover .lc-stat-q{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary)}.lc-stat-tip{z-index:6;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;max-width:280px;color:var(--dsw-alias-label-primary);pointer-events:none;opacity:0;border-radius:6px;padding:6px 10px;font-size:12px;font-weight:400;line-height:1.5;transition:opacity .12s;position:absolute;top:calc(100% + 6px);left:0;box-shadow:0 2px 8px #0000002e}.lc-stat-tipped:hover .lc-stat-tip{opacity:1}.lc-stat-tip-prices{border-top:1px dashed var(--dsw-alias-border-l1);margin-top:5px;padding-top:5px;display:block}.lc-stat-tip-head{font-weight:600;display:block}.lc-stat-tip-row{margin-top:2px;display:block}.lc-stat-tip-model{color:var(--dsw-alias-label-primary)}.lc-card-sub{color:var(--dsw-alias-label-secondary);margin-left:auto;font-size:12px;font-weight:400}.lc-gran,.lc-kinds{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;gap:2px;margin-left:auto;padding:1px;display:flex}.lc-trend-ctl{align-items:center;gap:6px;margin-left:auto;display:flex}.lc-trend-ctl .lc-gran{margin-left:0}.lc-gran-btn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:5px;padding:3px 8px;font-family:inherit;font-size:11px;line-height:1}.lc-gran-btn:hover{color:var(--dsw-alias-label-primary)}.lc-gran-on,.lc-gran-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.lc-settings-card{background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;transition:border-color .16s,background .16s}.lc-settings-card:hover{border-color:var(--dsw-alias-label-dimmed)}.lc-settings-open,.lc-settings-open:hover{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.lc-settings-head{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.lc-settings-headtext{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.lc-settings-name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.lc-settings-desc{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.lc-settings-chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.lc-settings-open .lc-settings-chevron{transform:rotate(180deg)}.lc-settings-body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding:4px 0 12px}.lc-settings-row{align-items:center;gap:8px;padding:8px 0;display:flex}.lc-settings-label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:14px}.lc-settings-select{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.lc-settings-select:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.lc-settings-select:disabled{opacity:.5;cursor:default}.lc-settings-note{color:var(--dsw-alias-label-tertiary);margin:12px 0 4px;font-size:12px;line-height:1.5}.lc-overview-num{align-items:baseline;gap:6px;margin-bottom:8px;display:flex}.lc-overview-num>b{font-size:20px}.lc-overview-num span{color:var(--dsw-alias-label-secondary)}.lc-overview-pct{margin-left:auto;font-size:11px}.lc-overview-pct b{color:var(--dsw-alias-label-primary);margin-right:4px;font-size:20px}.lc-stacked-wrap{width:100%;position:relative}.lc-stacked{background:#8080802e;border-radius:5px;width:100%;display:flex;position:relative;overflow:hidden}.lc-occupied-box{border:2px solid var(--dsw-alias-label-tertiary);box-sizing:border-box;pointer-events:none;opacity:0;box-shadow:0 0 0 1px var(--dsw-alias-bg-layer-2);border-radius:5px;transition:opacity .12s;position:absolute;top:0;bottom:0;left:0}.lc-occupied-box-on{opacity:1}.lc-bar-tip{z-index:5;white-space:nowrap;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);pointer-events:none;opacity:0;border-radius:6px;padding:3px 8px;font-size:12px;transition:opacity .12s;position:absolute;bottom:calc(100% + 6px);transform:translate(-50%);box-shadow:0 2px 8px #0000002e}.lc-bar-tip-on{opacity:1}.lc-stacked>div{height:100%}.lc-stacked-seg{transition:filter .12s,opacity .12s}.lc-stacked-free{box-sizing:border-box;transition:box-shadow .12s,opacity .12s}.lc-stacked-seg-on{filter:brightness(1.18)}.lc-reserve{z-index:1;pointer-events:auto;cursor:help;background:repeating-linear-gradient(45deg, color-mix(in srgb, var(--dsw-alias-state-warn-primary) 24%, transparent) 0 5px, transparent 5px 10px);position:absolute;top:0;bottom:0}.lc-stacked-free-on{border:2px dashed var(--dsw-alias-label-secondary);border-radius:3px}.lc-stacked-dim .lc-stacked-seg{opacity:.35}.lc-stacked-dim .lc-stacked-seg-on{opacity:1}.lc-stacked-dim .lc-stacked-free{opacity:.35}.lc-stacked-dim .lc-stacked-free-on{opacity:1}.lc-legend{grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:6px 14px;margin-top:10px;display:grid}.lc-chip{min-width:0;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:5px;padding:1px 6px;transition:background-color .12s;display:flex}.lc-chip-label{white-space:nowrap;text-overflow:ellipsis;min-width:0;font-weight:600;overflow:hidden}.lc-chip-nums{white-space:nowrap;flex:none;align-items:baseline;gap:6px;margin-left:auto;display:inline-flex}.lc-chip i,.lc-detail-row i{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-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-wrap{flex:1;min-width:0;position:relative}.lc-chart-scroll{scrollbar-gutter:stable;padding-bottom:var(--dsh-scrollbar-width,8px);overflow:auto hidden}.lc-chart{box-sizing:border-box;align-items:flex-end;gap:2px;width:max-content;min-width:100%;height:130px;padding-top:18px;display:flex;position:relative}.lc-grid{border-top:1px dashed var(--dsw-alias-border-l1);pointer-events:none;position:absolute;left:0;right:0}.lc-grid-top{top:18px}.lc-grid-mid{top:74px}.lc-grid-zero{border-top-style:solid;border-top-color:#80808080}.lc-bar{cursor:pointer;border-radius:2px;flex:none;align-items:flex-end;width:14px;height:100%;transition:opacity .12s,background-color .12s;display:flex;position:relative}.lc-chart-dim .lc-bar{opacity:.35}.lc-chart-dim .lc-bar-in-turn{opacity:1}.lc-chart-dim .lc-turn{opacity:.35}.lc-chart-dim .lc-turn-on{opacity:1}.lc-chart-tip{z-index:5;white-space:nowrap;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;padding:3px 8px;font-size:12px;position:absolute;top:0;left:0;box-shadow:0 2px 8px #0000002e}.lc-bar:hover{background:var(--dsw-alias-bg-layer-2)}.lc-bar-hovered{outline:1px dashed var(--dsw-alias-brand-primary);outline-offset:1px}.lc-bar-selected{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.lc-bar-in-turn{background:#80808024}.lc-bar-stack{flex-direction:column-reverse;width:100%;display:flex}.lc-bar-stack>div{width:100%}.lc-bar-up,.lc-bar-down{width:100%;display:flex;position:absolute;left:0}.lc-bar-up{flex-direction:column-reverse}.lc-bar-down{flex-direction:column}.lc-bar-up>div,.lc-bar-down>div{width:100%}.lc-bar-marker{color:var(--dsw-alias-state-warn-primary);font-size:11px;position:absolute;top:-16px;left:50%;transform:translate(-50%)}.lc-turns{gap:2px;width:max-content;min-width:100%;margin-top:4px;display:flex}.lc-turn{box-sizing:border-box;text-align:center;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;cursor:pointer;border-radius:3px;flex:none;height:14px;font-size:10px;font-weight:600;line-height:14px;transition:filter .12s,opacity .12s;overflow:hidden}.lc-turn-on{filter:brightness(1.35);color:var(--dsw-alias-label-primary)}.lc-turn-label{text-overflow:ellipsis;max-width:100%;display:inline-block;overflow:hidden}.lc-detail{border-top:1px solid var(--dsw-alias-border-l1);margin-top:12px;padding-top:12px}.lc-detail-head{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;align-items:center;gap:6px 8px;margin-bottom:10px;display:flex}.lc-detail-head b{color:var(--dsw-alias-label-primary);font-size:13px}.lc-detail-time{font-variant-numeric:tabular-nums;white-space:nowrap;margin-left:auto;font-size:12px}.lc-detail-marker{color:var(--dsw-alias-state-warn-primary);background:color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);border-radius:6px;padding:1px 7px;font-size:11px}.lc-detail-tag{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:4px;padding:0 6px;font-size:11px}.lc-detail-metric{font-variant-numeric:tabular-nums;white-space:nowrap;color:var(--dsw-alias-label-primary);background:color-mix(in srgb, var(--dsw-alias-label-secondary) 14%, transparent);border-radius:6px;padding:2px 8px;font-size:12px;font-weight:600}.lc-detail-metric-up{color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 15%, transparent)}.lc-detail-metric-down{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 15%, transparent)}.lc-detail-rows{grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:4px 24px;margin-top:10px;display:grid}.lc-brief{flex-direction:column;gap:2px;min-height:76px;margin:-4px 0 10px;display:flex}.lc-brief-row{min-width:0;color:var(--dsw-alias-label-primary);text-align:left;background:0 0;border:0;border-radius:6px;align-items:center;gap:8px;margin-left:-6px;margin-right:-6px;padding:3px 6px;font-family:inherit;font-size:12px;line-height:1.5;transition:background-color .12s;display:flex}.lc-brief-row-link:hover{background:var(--dsw-alias-interactive-bg-hover)}button.lc-brief-row-link{cursor:pointer}.lc-brief-tag{box-sizing:border-box;text-align:center;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);min-width:56px;color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;padding:0 6px;font-size:11px;position:relative}.lc-brief-tip{z-index:6;white-space:normal;text-align:left;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;max-width:240px;color:var(--dsw-alias-label-primary);pointer-events:none;opacity:0;border-radius:6px;padding:6px 10px;font-size:12px;font-weight:400;line-height:1.5;transition:opacity .12s;position:absolute;bottom:calc(100% + 6px);left:0;box-shadow:0 2px 8px #0000002e}.lc-brief-tag:hover .lc-brief-tip{opacity:1}.lc-brief-text{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.lc-brief-empty{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-tertiary);flex:1;overflow:hidden}.lc-brief-fact{box-sizing:border-box;text-overflow:ellipsis;white-space:nowrap;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);max-width:160px;color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;padding:0 6px;font-size:11px;overflow:hidden}.lc-brief-chip{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);min-width:0;max-width:260px;color:var(--dsw-alias-label-primary);border-radius:5px;align-items:center;gap:5px;padding:0 7px;font-size:12px;transition:background-color .12s;display:inline-flex;overflow:hidden}.lc-brief-chip-grow{flex:1;max-width:none}.lc-brief-chip-tag{text-overflow:ellipsis;white-space:nowrap;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);max-width:120px;color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;padding:0 6px;font-size:11px;overflow:hidden}.lc-brief-chip-text{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.lc-brief-chip-link{cursor:pointer}.lc-brief-chip-link:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-brief-more{color:var(--dsw-alias-label-secondary);flex:none;font-size:11px}.lc-detail-row{align-items:center;gap:8px;display:flex}.lc-detail-label{white-space:nowrap;min-width:70px;color:var(--dsw-alias-label-secondary)}.lc-bar-track{background:#8080802e;border-radius:3px;flex:1;height:5px;display:block;position:relative;overflow:hidden}.lc-bar-fill{border-radius:3px;height:100%;display:block}.lc-bar-zero{border-left:1px solid #80808073;position:absolute;top:0;bottom:0;left:50%}.lc-bar-fill-up,.lc-bar-fill-down{height:100%;display:block;position:absolute;top:0}.lc-bar-fill-up{border-radius:0 3px 3px 0;left:50%}.lc-bar-fill-down{border-radius:3px 0 0 3px;right:50%}.lc-detail-num{text-align:right;font-variant-numeric:tabular-nums;width:52px}.lc-detail-num-up{color:var(--dsw-alias-state-success-primary)}.lc-detail-num-down{color:var(--dsw-alias-state-error-primary)}.lc-detail-pct{text-align:right;width:34px;color:var(--dsw-alias-label-secondary)}.lc-cols{flex-wrap:wrap;gap:14px;margin-bottom:14px;display:flex}.lc-col{flex:1;min-width:280px}.lc-cols>.lc-card,.lc-col>.lc-card:last-child{margin-bottom:0}.lc-col-browser{flex-direction:column;display:flex}.lc-col-browser>.lc-card{flex:1}.lc-head>.lc-card:first-child{flex:7 1 0;min-width:360px}.lc-head>.lc-card:last-child{flex:3 1 0;min-width:220px}.lc-pi-grid{grid-template-columns:1fr;gap:8px;display:grid}.lc-pi-row{min-width:0;color:inherit;flex-direction:row;justify-content:space-between;align-items:baseline;gap:12px;text-decoration:none;display:flex}.lc-pi-row:hover .lc-pi-value{text-decoration:underline}.lc-pi-hint{text-decoration:none}.lc-pi-hint:hover{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-fa-list{flex-direction:column;gap:2px;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-fa-ctl,.lc-br-toolctl{flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:8px;display:flex}.lc-fa-ctl .lc-gran{margin-left:0}.lc-fa-n{opacity:.75;margin-left:4px;font-weight:700}.lc-fa-search,.lc-br-tool-search{min-width:80px;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;outline:none;flex:1;padding:3px 8px;font-size:12px}.lc-fa-search:focus,.lc-br-tool-search:focus{border-color:var(--dsw-alias-label-dimmed)}.lc-fa-meta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:6px;font-size:12px;display:flex}.lc-fa-meta .lc-fa-sort{flex:none}.lc-fa-meta-delta{position:relative}.lc-fa-meta-tip{z-index:6;white-space:normal;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;max-width:260px;color:var(--dsw-alias-label-primary);pointer-events:none;opacity:0;border-radius:6px;padding:6px 10px;font-size:12px;line-height:1.5;transition:opacity .12s;position:absolute;top:calc(100% + 6px);left:0;box-shadow:0 2px 8px #0000002e}.lc-fa-meta-delta:hover .lc-fa-meta-tip{opacity:1}.lc-fa-item{border:1px solid #0000;border-radius:8px;transition:background-color .12s,border-color .12s}.lc-fa-item-on{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l1)}.lc-fa-row{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:0;border-radius:7px;align-items:center;gap:7px;padding:6px 8px;font-size:12px;transition:background-color .12s;display:flex}.lc-fa-row:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-fa-form{opacity:.85;flex:none;justify-content:center;align-items:center;width:20px;height:14px;font-size:11px;display:flex}.lc-fa-lang{border-radius:4px;justify-content:center;align-items:center;min-width:16px;height:13px;padding:0 2px;font-size:8px;font-weight:700;line-height:1;display:inline-flex}.lc-fa-row .lc-br-chev{margin-right:-2px}.lc-fa-path{word-break:break-all;flex:1;min-width:0}.lc-fa-file{cursor:pointer}.lc-fa-file:hover{text-decoration:underline}.lc-fa-path em{color:var(--dsw-alias-label-secondary);font-style:normal}.lc-fa-badge{font-variant-numeric:tabular-nums;white-space:nowrap;border-radius:999px;flex:none;align-items:center;gap:4px;padding:1px 7px;font-size:11px;font-weight:600;display:inline-flex}.lc-fa-badge i{background:currentColor;border-radius:50%;width:5px;height:5px;display:inline-block}.lc-fa-b-read{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent)}.lc-fa-b-write{color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent)}.lc-fa-b-search{color:var(--dsw-alias-state-warn-primary);background:color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent)}.lc-fa-chip-read,.lc-fa-chip-read:hover{color:var(--dsw-alias-brand-primary)}.lc-fa-chip-write,.lc-fa-chip-write:hover{color:var(--dsw-alias-state-success-primary)}.lc-fa-chip-search,.lc-fa-chip-search:hover{color:var(--dsw-alias-state-warn-primary)}.lc-fa-chip-read.lc-gran-on,.lc-fa-chip-read.lc-gran-on:hover{background:color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent);color:var(--dsw-alias-brand-primary)}.lc-fa-chip-write.lc-gran-on,.lc-fa-chip-write.lc-gran-on:hover{background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent);color:var(--dsw-alias-state-success-primary)}.lc-fa-chip-search.lc-gran-on,.lc-fa-chip-search.lc-gran-on:hover{background:color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);color:var(--dsw-alias-state-warn-primary)}.lc-fa-delta{font-variant-numeric:tabular-nums;white-space:nowrap;flex:none;gap:5px;font-size:11px;font-weight:600;display:inline-flex}.lc-fa-up{color:var(--dsw-alias-state-success-primary)}.lc-fa-down{color:var(--dsw-alias-state-error-primary)}.lc-fa-time{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:11px}.lc-fa-ops{border-left:2px solid var(--dsw-alias-border-l1);flex-direction:column;gap:1px;margin:0 8px 8px 15px;padding:2px 0 2px 10px;display:flex}.lc-fa-op{min-width:0;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;background:0 0;border:0;border-radius:5px;align-items:center;gap:8px;padding:3px 6px;font-size:11px;transition:background-color .12s;display:flex}.lc-fa-op-link{cursor:pointer}.lc-fa-op-link:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-fa-op-time{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;margin-left:auto}.lc-fa-op-tool{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:0 6px;font-size:11px}.lc-fa-op-detail{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-secondary);flex:1;overflow:hidden}.lc-fa-read{color:var(--dsw-alias-brand-primary);font-variant-numeric:tabular-nums;white-space:nowrap;flex:none;font-size:11px;font-weight:600}.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-retry{color:var(--dsw-alias-brand-primary);font:inherit;cursor:pointer;text-underline-offset:2px;background:0 0;border:0;padding:0;font-size:12px;text-decoration:underline}.lc-br-retry:hover{filter:brightness(1.15)}.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;height:14px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:flex}.lc-br-chev:before{content:\"\";border-bottom:1px solid;border-right:1px solid;width:5px;height:5px;transition:transform .12s;transform:rotate(-45deg)}.lc-br-chev-on:before{transform:rotate(45deg)}.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{min-width:0;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;max-width:220px;padding:0 6px;font-size:11px;overflow:hidden}.lc-br-tool-plugin{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent);border-color:#0000;border-radius:6px;font-size:12px}.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:minmax(0,140px) minmax(0,90px) 56px minmax(0,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);overflow-wrap:anywhere;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}.lc-agents-chips{flex-wrap:wrap;gap:6px;margin-bottom:10px;display:flex}.lc-agents-chip{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;border-radius:999px;padding:2px 8px;font-size:11px}.lc-agents-chip-on{color:var(--dsw-alias-state-success-primary);border-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent)}.lc-agents-stage{margin:0 -4px;padding:0 4px;overflow-x:auto}.lc-agents-svg{max-width:none;margin:0 auto;display:block}.lc-agents-link{stroke-width:1.5px;stroke-opacity:.45}.lc-agents-link-live{stroke-opacity:.85}.lc-agents-flow{stroke-width:2px;stroke-linecap:round;stroke-dasharray:2 7;animation:.9s linear infinite lc-agent-flow}@keyframes lc-agent-flow{to{stroke-dashoffset:-9px}}.lc-agent-node{outline:none}.lc-agent-clickable{cursor:pointer}.lc-agent-halo{fill:#0000;transition:fill .12s}.lc-agent-hover .lc-agent-halo,.lc-agent-node:focus-visible .lc-agent-halo{fill:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-2))}.lc-agent-self .lc-agent-halo{fill:var(--dsw-alias-bg-layer-2)}.lc-agent-running .lc-agent-halo{fill:color-mix(in srgb, var(--dsw-alias-state-success-primary) 12%, transparent);animation:1.8s ease-in-out infinite lc-agent-glow}.lc-agent-done .lc-agent-halo{fill:color-mix(in srgb, var(--dsw-alias-state-success-primary) 7%, transparent)}@keyframes lc-agent-glow{0%,to{opacity:1}50%{opacity:.4}}.lc-agent-track{fill:var(--dsw-alias-bg-layer-1);stroke:var(--dsw-alias-border-l1);stroke-width:1.5px}.lc-agent-seg{fill:none;stroke-width:9px;transition:stroke-dasharray .3s,stroke-dashoffset .3s}.lc-agent-free{stroke:color-mix(in srgb, var(--dsw-alias-label-secondary) 18%, transparent)}.lc-agent-pct{fill:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;pointer-events:none;font-size:11px;font-weight:600}.lc-agent-caption{text-align:center;pointer-events:none;width:100%;line-height:1.25}.lc-agent-label{color:var(--dsw-alias-label-primary);overflow-wrap:break-word;-webkit-line-clamp:3;-webkit-box-orient:vertical;font-size:11px;display:-webkit-box;overflow:hidden}.lc-agent-tokens{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;font-size:10px}.lc-agents-solo{padding:4px 0 10px}.lc-agents-inspector{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);border-radius:8px;flex-wrap:wrap;align-items:baseline;gap:4px 8px;min-width:0;margin-top:10px;padding:7px 10px;font-size:12px;display:flex}.lc-agents-inspector-name{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere}.lc-agents-badge{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 6px;font-size:10px}.lc-agent-self-badge{vertical-align:1px;margin-left:5px}.lc-agents-badge-on{color:var(--dsw-alias-state-success-primary);border-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent)}.lc-agents-inspector-stats{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.lc-agents-inspector-open{color:var(--dsw-alias-brand-primary,#3b82f6);flex:none;margin-left:auto}.lc-agents-legend{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:4px 14px;margin-top:8px;font-size:11px;display:flex}.lc-agents-legend-item{align-items:center;gap:5px;display:inline-flex}.lc-agents-legend-item i{border-radius:2px;width:8px;height:8px}.lc-agents-legend-free{background:color-mix(in srgb, var(--dsw-alias-label-secondary) 18%, transparent)}.lc-agents-legend-edge{border-top:2px dashed var(--dsw-alias-label-secondary);border-radius:0!important;width:14px!important;height:0!important}";
|
|
6108
|
+
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-l2);border-radius:10px;margin-bottom:14px;padding:14px 16px}.lc-card-title{flex-wrap:wrap;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(4,minmax(0,1fr));gap:6px;display:grid}.lc-stat{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;flex-direction:column;gap:2px;min-width:0;padding:6px;display:flex}.lc-stats .lc-stat{padding:6px 3px}.lc-stats .lc-stat-q{margin:0;position:absolute;top:3px;right:4px}.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-l2);cursor:help;border-radius:50%;margin-left:4px;font-size:9px;font-style:normal;font-weight:700;line-height:11px;display:inline-block}.lc-stat-tipped:hover .lc-stat-q{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary)}.lc-stat-tip{z-index:6;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;max-width:280px;color:var(--dsw-alias-label-primary);pointer-events:none;opacity:0;border-radius:6px;padding:6px 10px;font-size:12px;font-weight:400;line-height:1.5;transition:opacity .12s;position:absolute;top:calc(100% + 6px);left:0;box-shadow:0 2px 8px #0000002e}.lc-stat-tipped:hover .lc-stat-tip{opacity:1}.lc-stat-tip-prices{border-top:1px dashed var(--dsw-alias-border-l1);margin-top:5px;padding-top:5px;display:block}.lc-stat-tip-head{font-weight:600;display:block}.lc-stat-tip-row{margin-top:2px;display:block}.lc-stat-tip-model{color:var(--dsw-alias-label-primary)}.lc-card-sub{color:var(--dsw-alias-label-secondary);margin-left:auto;font-size:12px;font-weight:400}.lc-gran,.lc-kinds{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);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-jump{width:calc(28px + var(--dsh-content-font-delta,0px));height:calc(28px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:28px;justify-content:center;align-items:center;padding:6px;display:inline-flex}.lc-jump svg{width:calc(16px + var(--dsh-content-font-delta,0px));height:calc(16px + var(--dsh-content-font-delta,0px))}.lc-jump:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.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{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-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-wrap{flex:1;min-width:0;position:relative}.lc-chart-scroll{scrollbar-gutter:stable;padding-bottom:var(--dsh-scrollbar-width,8px);overflow:auto hidden}.lc-chart{box-sizing:border-box;align-items:flex-end;gap:2px;width:max-content;min-width:100%;height:130px;padding-top:18px;display:flex;position:relative}.lc-grid{border-top:1px dashed var(--dsw-alias-border-l1);pointer-events:none;position:absolute;left:0;right:0}.lc-grid-top{top:18px}.lc-grid-mid{top:74px}.lc-grid-zero{border-top-style:solid;border-top-color:#80808080}.lc-bar{cursor:pointer;border-radius:2px;flex:none;align-items:flex-end;width:14px;height:100%;transition:opacity .12s,background-color .12s;display:flex;position:relative}.lc-chart-dim .lc-bar{opacity:.35}.lc-chart-dim .lc-bar-in-turn{opacity:1}.lc-chart-dim .lc-turn{opacity:.35}.lc-chart-dim .lc-turn-on{opacity:1}.lc-chart-tip{z-index:5;white-space:nowrap;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;padding:3px 8px;font-size:12px;position:absolute;top:0;left:0;box-shadow:0 2px 8px #0000002e}.lc-bar:hover{background:var(--dsw-alias-bg-layer-2)}.lc-bar-hovered{outline:1px dashed var(--dsw-alias-brand-primary);outline-offset:1px}.lc-bar-selected{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.lc-bar-in-turn{background:#80808024}.lc-bar-stack{flex-direction:column-reverse;width:100%;display:flex}.lc-bar-stack>div{width:100%}.lc-bar-up,.lc-bar-down{width:100%;display:flex;position:absolute;left:0}.lc-bar-up{flex-direction:column-reverse}.lc-bar-down{flex-direction:column}.lc-bar-up>div,.lc-bar-down>div{width:100%}.lc-cat-seg{transition:filter .12s,opacity .12s}.lc-chart[data-catdim] .lc-cat-seg{opacity:.35}.lc-chart[data-catdim=system] .lc-cat-seg[data-cat=system],.lc-chart[data-catdim=tools] .lc-cat-seg[data-cat=tools],.lc-chart[data-catdim=user] .lc-cat-seg[data-cat=user],.lc-chart[data-catdim=inject] .lc-cat-seg[data-cat=inject],.lc-chart[data-catdim=assistant] .lc-cat-seg[data-cat=assistant],.lc-chart[data-catdim=tool] .lc-cat-seg[data-cat=tool]{opacity:1;filter:brightness(1.18)}.lc-bar-marker{color:var(--dsw-alias-state-warn-primary);font-size:11px;position:absolute;top:-16px;left:50%;transform:translate(-50%)}.lc-turns{gap:2px;width:max-content;min-width:100%;margin-top:4px;display:flex}.lc-turn{box-sizing:border-box;text-align:center;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;cursor:pointer;border-radius:3px;flex:none;height:14px;font-size:10px;font-weight:600;line-height:14px;transition:filter .12s,opacity .12s;overflow:hidden}.lc-turn-on{filter:brightness(1.35);color:var(--dsw-alias-label-primary)}.lc-turn-label{text-overflow:ellipsis;max-width:100%;display:inline-block;overflow:hidden}.lc-detail{border-top:1px solid var(--dsw-alias-border-l1);margin-top:12px;padding-top:12px}.lc-detail-head{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;align-items:center;gap:6px 8px;margin-bottom:10px;display:flex}.lc-detail-head b{color:var(--dsw-alias-label-primary);font-size:13px}.lc-detail-time{font-variant-numeric:tabular-nums;white-space:nowrap;margin-left:auto;font-size:12px}.lc-detail-marker{color:var(--dsw-alias-state-warn-primary);background:color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);border-radius:6px;padding:1px 7px;font-size:11px}.lc-detail-tag{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:4px;padding:0 6px;font-size:11px}.lc-detail-metric{font-variant-numeric:tabular-nums;white-space:nowrap;color:var(--dsw-alias-label-primary);background:color-mix(in srgb, var(--dsw-alias-label-secondary) 14%, transparent);border-radius:6px;padding:2px 8px;font-size:12px;font-weight:600}.lc-detail-metric-up{color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 15%, transparent)}.lc-detail-metric-down{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 15%, transparent)}.lc-detail-rows{grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:4px 24px;margin-top:10px;display:grid}.lc-brief{flex-direction:column;gap:2px;min-height:76px;margin:-4px 0 10px;display:flex}.lc-brief-row{min-width:0;color:var(--dsw-alias-label-primary);text-align:left;background:0 0;border:0;border-radius:6px;align-items:center;gap:8px;margin-left:-6px;margin-right:-6px;padding:3px 6px;font-family:inherit;font-size:12px;line-height:1.5;transition:background-color .12s;display:flex}.lc-brief-row-link:hover{background:var(--dsw-alias-interactive-bg-hover)}button.lc-brief-row-link{cursor:pointer}.lc-brief-tag{box-sizing:border-box;text-align:center;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);min-width:56px;color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;padding:0 6px;font-size:11px;position:relative}.lc-brief-tip{z-index:6;white-space:normal;text-align:left;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;max-width:240px;color:var(--dsw-alias-label-primary);pointer-events:none;opacity:0;border-radius:6px;padding:6px 10px;font-size:12px;font-weight:400;line-height:1.5;transition:opacity .12s;position:absolute;bottom:calc(100% + 6px);left:0;box-shadow:0 2px 8px #0000002e}.lc-brief-tag:hover .lc-brief-tip{opacity:1}.lc-brief-text{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.lc-brief-empty{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-tertiary);flex:1;overflow:hidden}.lc-brief-fact{box-sizing:border-box;text-overflow:ellipsis;white-space:nowrap;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);max-width:160px;color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;padding:0 6px;font-size:11px;overflow:hidden}.lc-brief-chip{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);min-width:0;max-width:260px;color:var(--dsw-alias-label-primary);border-radius:5px;align-items:center;gap:5px;padding:0 7px;font-size:12px;transition:background-color .12s;display:inline-flex;overflow:hidden}.lc-brief-chip-grow{flex:1;max-width:none}.lc-brief-chip-tag{text-overflow:ellipsis;white-space:nowrap;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);max-width:120px;color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;padding:0 6px;font-size:11px;overflow:hidden}.lc-brief-chip-text{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.lc-brief-chip-link{cursor:pointer}.lc-brief-chip-link:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-brief-more{color:var(--dsw-alias-label-secondary);flex:none;font-size:11px}.lc-detail-row{border-radius:4px;align-items:center;gap:8px;margin:-1px -4px;padding:1px 4px;transition:background-color .12s;display:flex}.lc-detail-row i{transition:box-shadow .12s}.lc-detail-row-on{background:var(--dsw-alias-interactive-bg-hover)}.lc-detail-row-on i{box-shadow:0 0 0 1px var(--dsw-alias-brand-primary)}.lc-detail-row-on .lc-detail-label{font-weight:600}.lc-detail-label{white-space:nowrap;min-width:70px;color:var(--dsw-alias-label-secondary)}.lc-bar-track{background:#8080802e;border-radius:3px;flex:1;height:5px;display:block;position:relative;overflow:hidden}.lc-bar-fill{border-radius:3px;height:100%;display:block}.lc-bar-zero{border-left:1px solid #80808073;position:absolute;top:0;bottom:0;left:50%}.lc-bar-fill-up,.lc-bar-fill-down{height:100%;display:block;position:absolute;top:0}.lc-bar-fill-up{border-radius:0 3px 3px 0;left:50%}.lc-bar-fill-down{border-radius:3px 0 0 3px;right:50%}.lc-detail-num{text-align:right;font-variant-numeric:tabular-nums;width:52px}.lc-detail-num-up{color:var(--dsw-alias-state-success-primary)}.lc-detail-num-down{color:var(--dsw-alias-state-error-primary)}.lc-detail-pct{text-align:right;width:34px;color:var(--dsw-alias-label-secondary)}.lc-cols{flex-wrap:wrap;gap:14px;margin-bottom:14px;display:flex}.lc-col{flex:1;min-width:280px}.lc-cols>.lc-card,.lc-col>.lc-card:last-child{margin-bottom:0}.lc-col-browser{flex-direction:column;display:flex}.lc-col-browser>.lc-card{flex:1}.lc-head>.lc-card{flex:1 1 0;min-width:0}.lc-head>.lc-card:first-child{flex-direction:column;display:flex}.lc-head>.lc-card:first-child .lc-stats{flex:1;align-content:stretch}.lc-head>.lc-card:first-child .lc-stat{justify-content:center}.lc-stat-head{color:var(--dsw-alias-label-secondary);margin:12px 0 8px;font-size:11px;font-weight:600}.lc-donut-row{justify-content:flex-start;align-items:center;gap:12px;min-width:0;display:flex}.lc-col-donut{flex-direction:column;display:flex}.lc-col-donut .lc-donut-row{flex:1}.lc-donut-row .lc-sl{flex:auto}.lc-donut{flex:none;position:relative}.lc-donut svg{display:block}.lc-donut-track{stroke:#8080802e}.lc-donut-center{pointer-events:none;text-align:center;box-sizing:border-box;flex-direction:column;justify-content:center;align-items:center;gap:1px;padding:0 7px;display:flex;position:absolute;inset:0}.lc-donut-center b{white-space:nowrap;text-overflow:ellipsis;max-width:100%;line-height:1.15;overflow:hidden}.lc-donut-center span{color:var(--dsw-alias-label-secondary);white-space:nowrap}.lc-sl{flex-direction:column;gap:5px;min-width:0;display:flex}.lc-sl-row{align-items:baseline;gap:6px;min-width:0;font-size:12px;display:flex}.lc-sl-dot{border-radius:2px;flex:none;align-self:flex-start;width:8px;height:8px;margin-top:2px}.lc-sl-label{flex:0 auto;min-width:80px;line-height:1.25;overflow:hidden}.lc-sl-count{text-align:right;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;text-overflow:ellipsis;flex:auto;overflow:hidden}.lc-sl-pct{text-align:right;font-variant-numeric:tabular-nums;flex:none;min-width:30px;font-weight:700}.lc-pi-grid{grid-template-columns:1fr;gap:8px;display:grid}.lc-pi-row-btn{appearance:none;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;width:100%;padding:0}.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-hint{text-decoration:none}.lc-pi-hint:hover{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-pi-row-btn .lc-pi-value{font-weight:400}.lc-events,.lc-fa-list{flex-direction:column;gap:2px;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-fa-ctl,.lc-br-toolctl{flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:8px;display:flex}.lc-fa-ctl .lc-gran{margin-left:0}.lc-fa-n{opacity:.75;margin-left:4px;font-weight:700}.lc-fa-search,.lc-br-tool-search{min-width:80px;font:inherit;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:6px;outline:none;flex:1;padding:3px 8px;font-size:12px}.lc-fa-search:focus,.lc-br-tool-search:focus{border-color:var(--dsw-alias-label-dimmed)}.lc-fa-meta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:6px;font-size:12px;display:flex}.lc-fa-meta .lc-fa-sort{flex:none}.lc-fa-meta-delta{position:relative}.lc-fa-meta-tip{z-index:6;white-space:normal;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;max-width:260px;color:var(--dsw-alias-label-primary);pointer-events:none;opacity:0;border-radius:6px;padding:6px 10px;font-size:12px;line-height:1.5;transition:opacity .12s;position:absolute;top:calc(100% + 6px);left:0;box-shadow:0 2px 8px #0000002e}.lc-fa-meta-delta:hover .lc-fa-meta-tip{opacity:1}.lc-fa-item{border:1px solid #0000;border-radius:8px;transition:background-color .12s,border-color .12s}.lc-fa-item-on{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l2)}.lc-fa-row{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:0;border-radius:7px;align-items:center;gap:7px;padding:6px 8px;font-size:12px;transition:background-color .12s;display:flex}.lc-fa-row:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-fa-form{opacity:.85;flex:none;justify-content:center;align-items:center;width:20px;height:14px;font-size:11px;display:flex}.lc-fa-lang{border-radius:4px;justify-content:center;align-items:center;min-width:16px;height:13px;padding:0 2px;font-size:8px;font-weight:700;line-height:1;display:inline-flex}.lc-fa-row .lc-br-chev{margin-right:-2px}.lc-fa-path{word-break:break-all;flex:1;min-width:0}.lc-fa-file{cursor:pointer}.lc-fa-file:hover{text-decoration:underline}.lc-fa-path em{color:var(--dsw-alias-label-secondary);font-style:normal}.lc-fa-badge{font-variant-numeric:tabular-nums;white-space:nowrap;border-radius:999px;flex:none;align-items:center;gap:4px;padding:1px 7px;font-size:11px;font-weight:600;display:inline-flex}.lc-fa-badge i{background:currentColor;border-radius:50%;width:5px;height:5px;display:inline-block}.lc-fa-b-read{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent)}.lc-fa-b-write{color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent)}.lc-fa-b-search{color:var(--dsw-alias-state-warn-primary);background:color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent)}.lc-fa-chip-read,.lc-fa-chip-read:hover{color:var(--dsw-alias-brand-primary)}.lc-fa-chip-write,.lc-fa-chip-write:hover{color:var(--dsw-alias-state-success-primary)}.lc-fa-chip-search,.lc-fa-chip-search:hover{color:var(--dsw-alias-state-warn-primary)}.lc-fa-chip-read.lc-gran-on,.lc-fa-chip-read.lc-gran-on:hover{background:color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent);color:var(--dsw-alias-brand-primary)}.lc-fa-chip-write.lc-gran-on,.lc-fa-chip-write.lc-gran-on:hover{background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent);color:var(--dsw-alias-state-success-primary)}.lc-fa-chip-search.lc-gran-on,.lc-fa-chip-search.lc-gran-on:hover{background:color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);color:var(--dsw-alias-state-warn-primary)}.lc-fa-delta{font-variant-numeric:tabular-nums;white-space:nowrap;flex:none;gap:5px;font-size:11px;font-weight:600;display:inline-flex}.lc-fa-up{color:var(--dsw-alias-state-success-primary)}.lc-fa-down{color:var(--dsw-alias-state-error-primary)}.lc-fa-time{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:11px}.lc-fa-ops{border-left:2px solid var(--dsw-alias-border-l1);flex-direction:column;gap:1px;margin:0 8px 8px 15px;padding:2px 0 2px 10px;display:flex}.lc-fa-op{min-width:0;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;background:0 0;border:0;border-radius:5px;align-items:center;gap:8px;padding:3px 6px;font-size:11px;transition:background-color .12s;display:flex}.lc-fa-op-link{cursor:pointer}.lc-fa-op-link:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-fa-op-time{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;margin-left:auto}.lc-fa-op-tool{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:0 6px;font-size:11px}.lc-fa-op-detail{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-secondary);flex:1;overflow:hidden}.lc-fa-read{color:var(--dsw-alias-brand-primary);font-variant-numeric:tabular-nums;white-space:nowrap;flex:none;font-size:11px;font-weight:600}.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-l2);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-l2);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-l2);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-retry{color:var(--dsw-alias-brand-primary);font:inherit;cursor:pointer;text-underline-offset:2px;background:0 0;border:0;padding:0;font-size:12px;text-decoration:underline}.lc-br-retry:hover{filter:brightness(1.15)}.lc-br-cats{flex-direction:column;gap:4px;margin-top:10px;display:flex}.lc-br-cat{border:1px solid var(--dsw-alias-border-l2);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;height:14px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:flex}.lc-br-chev:before{content:\"\";border-bottom:1px solid;border-right:1px solid;width:5px;height:5px;transition:transform .12s;transform:rotate(-45deg)}.lc-br-chev-on:before{transform:rotate(45deg)}.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{min-width:0;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;max-width:220px;padding:0 6px;font-size:11px;overflow:hidden}.lc-br-tool-plugin{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent);border-color:#0000;border-radius:6px;font-size:12px}.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-l2);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-lines{counter-reset:lc-line}.lc-ts-line{padding-left:26px;display:block;position:relative}.lc-ts-line:before{content:counter(lc-line);counter-increment:lc-line;text-align:right;width:20px;color:var(--dsw-alias-label-tertiary);user-select:none;padding-right:6px;font-size:11px;position:absolute;left:0}.lc-ts-line:empty:after{content:\"\"}.lc-ts-param-row{border-top:1px solid var(--dsw-alias-border-l1);grid-template-columns:minmax(0,140px) minmax(0,90px) 56px minmax(0,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);overflow-wrap:anywhere;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-l2);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;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{white-space:pre-line;margin:6px 0}.lc-ts-desc-md div p br{display:none}.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-l2);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-label-dimmed);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}.lc-agents-chips{flex-wrap:wrap;gap:6px;margin-bottom:10px;display:flex}.lc-agents-chip{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;border-radius:999px;padding:2px 8px;font-size:11px}.lc-agents-chip-on{color:var(--dsw-alias-state-success-primary);border-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent)}.lc-agents-stage{margin:0 -4px;padding:0 4px;overflow-x:auto}.lc-agents-svg{max-width:none;margin:0 auto;display:block}.lc-agents-link{stroke-width:1.5px;stroke-opacity:.45}.lc-agents-link-live{stroke-opacity:.85}.lc-agents-flow{stroke-width:2px;stroke-linecap:round;stroke-dasharray:2 7;animation:.9s linear infinite lc-agent-flow}@keyframes lc-agent-flow{to{stroke-dashoffset:-9px}}.lc-agent-node{outline:none}.lc-agent-clickable{cursor:pointer}.lc-agent-halo{fill:#0000;transition:fill .12s}.lc-agent-hover .lc-agent-halo,.lc-agent-node:focus-visible .lc-agent-halo{fill:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-2))}.lc-agent-self .lc-agent-halo{fill:var(--dsw-alias-bg-layer-2)}.lc-agent-running .lc-agent-halo{fill:color-mix(in srgb, var(--dsw-alias-state-success-primary) 12%, transparent);animation:1.8s ease-in-out infinite lc-agent-glow}.lc-agent-done .lc-agent-halo{fill:color-mix(in srgb, var(--dsw-alias-state-success-primary) 7%, transparent)}@keyframes lc-agent-glow{0%,to{opacity:1}50%{opacity:.4}}.lc-agent-track{fill:var(--dsw-alias-bg-layer-1);stroke:var(--dsw-alias-border-l1);stroke-width:1.5px}.lc-agent-seg{fill:none;stroke-width:9px;transition:stroke-dasharray .3s,stroke-dashoffset .3s}.lc-agent-free{stroke:color-mix(in srgb, var(--dsw-alias-label-secondary) 18%, transparent)}.lc-agent-pct{fill:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;pointer-events:none;font-size:11px;font-weight:600}.lc-agent-caption{text-align:center;pointer-events:none;width:100%;line-height:1.25}.lc-agent-label{color:var(--dsw-alias-label-primary);overflow-wrap:break-word;-webkit-line-clamp:3;-webkit-box-orient:vertical;font-size:11px;display:-webkit-box;overflow:hidden}.lc-agent-tokens{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;font-size:10px}.lc-agents-solo{padding:4px 0 10px}.lc-agents-inspector{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:8px;flex-wrap:wrap;align-items:baseline;gap:4px 8px;min-width:0;margin-top:10px;padding:7px 10px;font-size:12px;display:flex}.lc-agents-inspector-name{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere}.lc-agents-badge{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 6px;font-size:10px}.lc-agent-self-badge{vertical-align:1px;margin-left:5px}.lc-agents-badge-on{color:var(--dsw-alias-state-success-primary);border-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent)}.lc-agents-inspector-stats{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.lc-agents-inspector-open{color:var(--dsw-alias-brand-primary,#3b82f6);flex:none;margin-left:auto}.lc-agents-legend{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:4px 14px;margin-top:8px;font-size:11px;display:flex}.lc-agents-legend-item{align-items:center;gap:5px;display:inline-flex}.lc-agents-legend-item i{border-radius:2px;width:8px;height:8px}.lc-agents-legend-free{background:color-mix(in srgb, var(--dsw-alias-label-secondary) 18%, transparent)}.lc-agents-legend-edge{border-top:2px dashed var(--dsw-alias-label-secondary);border-radius:0!important;width:14px!important;height:0!important}";
|
|
5483
6109
|
const tagId = "dsh-context/styles.css";
|
|
5484
6110
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
5485
6111
|
const tag = document.createElement("style");
|
|
@@ -5533,6 +6159,15 @@ window.__ModuleLoader__.load({
|
|
|
5533
6159
|
label: () => t("tab")
|
|
5534
6160
|
}, (props) => h(ContextView, props));
|
|
5535
6161
|
});
|
|
6162
|
+
const ContextJump = makeContextJumpButton(kit);
|
|
6163
|
+
ctx.slots.inject("conversation.chat.assistant-actions", () => {
|
|
6164
|
+
return ctx.slots.register({
|
|
6165
|
+
name: "conversation.chat.assistant-actions",
|
|
6166
|
+
id: "context-jump",
|
|
6167
|
+
order: 20,
|
|
6168
|
+
locale: NS
|
|
6169
|
+
}, (props) => h(ContextJump, props));
|
|
6170
|
+
});
|
|
5536
6171
|
registerContextCommand(ctx, kit);
|
|
5537
6172
|
const ContextModal = makeContextModal(ctx, kit);
|
|
5538
6173
|
ctx.slots.inject("conversation.input.overlay", () => {
|