dsh-context 0.46.0 → 0.47.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 -4
- package/lib/client.js +490 -285
- package/lib/index.d.ts +48 -3
- package/lib/index.js +243 -32
- package/package.json +6 -3
package/lib/client.js
CHANGED
|
@@ -10,6 +10,7 @@ window.__ModuleLoader__.load({
|
|
|
10
10
|
//#region src/client/i18n.ts
|
|
11
11
|
const DICT_ZH = {
|
|
12
12
|
"tab": "上下文",
|
|
13
|
+
"sidebar.guideDescription": "查看这个会话的上下文构成、每步变化与消息列表。",
|
|
13
14
|
"cat.system": "系统提示词",
|
|
14
15
|
"cat.tools": "工具定义",
|
|
15
16
|
"cat.user": "用户消息",
|
|
@@ -72,8 +73,9 @@ window.__ModuleLoader__.load({
|
|
|
72
73
|
"gran.total": "全量",
|
|
73
74
|
"gran.delta": "增量",
|
|
74
75
|
"gran.modeHint": "全量:累计构成;增量:相对上一条请求的变化量",
|
|
75
|
-
"trend.hint": "✂ 表示压缩/剪枝,步骤/轮次 切换粒度",
|
|
76
76
|
"trend.focus": "仅展示 {cat}",
|
|
77
|
+
"trend.adaptive": "自适应",
|
|
78
|
+
"trend.adaptiveHint": "按当前可视范围内的柱子重新缩放高度,滚动时随之变化",
|
|
77
79
|
"trend.empty": "发起一轮对话后,这里会展示每次模型请求的上下文构成",
|
|
78
80
|
"detail.step": "第 {t} 轮 · 第 {s} 步",
|
|
79
81
|
"detail.turn": "第 {t} 轮 · 共 {n} 步",
|
|
@@ -89,7 +91,6 @@ window.__ModuleLoader__.load({
|
|
|
89
91
|
"brief.noInputs": "(无新增)",
|
|
90
92
|
"brief.locate": "在上下文浏览器中查看",
|
|
91
93
|
"jump.title": "在上下文标签页中查看此轮",
|
|
92
|
-
"jump.statsLine": "在上下文标签页中查看上下文构成",
|
|
93
94
|
"brief.turnTip": "这一轮开场时用户发送的消息;回合内的每一步都会回显同一条",
|
|
94
95
|
"brief.inputTip": "上一步回复之后、本次请求发出前新进入上下文的内容——通常是上一步所调工具的结果;每轮的第一步无新增",
|
|
95
96
|
"brief.replyTip": "这一步模型返回的内容(文本回复或工具调用);此步发起的调用,其结果会出现在下一柱的「输入」行",
|
|
@@ -296,6 +297,7 @@ window.__ModuleLoader__.load({
|
|
|
296
297
|
};
|
|
297
298
|
const DICT_EN = {
|
|
298
299
|
"tab": "Context",
|
|
300
|
+
"sidebar.guideDescription": "Inspect this session's context composition, per-step history, and messages.",
|
|
299
301
|
"cat.system": "System Prompt",
|
|
300
302
|
"cat.tools": "Tool Schemas",
|
|
301
303
|
"cat.user": "User Messages",
|
|
@@ -358,8 +360,9 @@ window.__ModuleLoader__.load({
|
|
|
358
360
|
"gran.total": "Total",
|
|
359
361
|
"gran.delta": "Delta",
|
|
360
362
|
"gran.modeHint": "Total: cumulative makeup; Delta: change vs the previous request",
|
|
361
|
-
"trend.hint": "✂ marks compaction/prune, Step/Turn switches granularity",
|
|
362
363
|
"trend.focus": "Showing {cat} only",
|
|
364
|
+
"trend.adaptive": "Adaptive",
|
|
365
|
+
"trend.adaptiveHint": "Rescale bar heights to the visible range, following the scroll",
|
|
363
366
|
"trend.empty": "Send a message and each model request’s context makeup shows up here",
|
|
364
367
|
"detail.step": "Turn {t} · Step {s}",
|
|
365
368
|
"detail.turn": "Turn {t} · {n} steps",
|
|
@@ -375,7 +378,6 @@ window.__ModuleLoader__.load({
|
|
|
375
378
|
"brief.noInputs": "(nothing new)",
|
|
376
379
|
"brief.locate": "Reveal in Context Browser",
|
|
377
380
|
"jump.title": "View this turn in the Context tab",
|
|
378
|
-
"jump.statsLine": "View the context composition in the Context tab",
|
|
379
381
|
"brief.turnTip": "The user message that opened this turn — every step of the turn recalls it",
|
|
380
382
|
"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",
|
|
381
383
|
"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",
|
|
@@ -954,7 +956,7 @@ window.__ModuleLoader__.load({
|
|
|
954
956
|
"assistant",
|
|
955
957
|
"tool",
|
|
956
958
|
"total"
|
|
957
|
-
].every((k) => typeof current[k] === "number") && recordsOnly(data.requests) && recordsOnly(data.events) && recordsOnly(data.nodes) && recordsOnly(data.archive) && timingFastOk(data.timing)) return data;
|
|
959
|
+
].every((k) => typeof current[k] === "number") && recordsOnly(data.requests) && recordsOnly(data.events) && recordsOnly(data.nodes) && recordsOnly(data.archive) && systemsFastOk(data.systems) && timingFastOk(data.timing)) return data;
|
|
958
960
|
const safeCurrent = current !== null && typeof current === "object" ? current : {};
|
|
959
961
|
const cost = typeof data.cost === "object" && data.cost !== null && !Array.isArray(data.cost) ? data.cost : void 0;
|
|
960
962
|
const timing = timingOf(data.timing);
|
|
@@ -988,6 +990,7 @@ window.__ModuleLoader__.load({
|
|
|
988
990
|
...typeof data.detailRev === "number" && Number.isFinite(data.detailRev) ? { detailRev: data.detailRev } : {},
|
|
989
991
|
...cost !== void 0 ? { cost } : {},
|
|
990
992
|
...timing !== null ? { timing } : {},
|
|
993
|
+
...data.systems !== void 0 ? { systems: systemsOf(data.systems) } : {},
|
|
991
994
|
...typeof data.surfaceFloor === "number" ? { surfaceFloor: data.surfaceFloor } : {},
|
|
992
995
|
...typeof data.archiveFloor === "number" ? { archiveFloor: data.archiveFloor } : {},
|
|
993
996
|
...data.fileOps !== void 0 ? { fileOps: objectsOf(data.fileOps) } : {},
|
|
@@ -995,6 +998,45 @@ window.__ModuleLoader__.load({
|
|
|
995
998
|
};
|
|
996
999
|
}
|
|
997
1000
|
/**
|
|
1001
|
+
* The live system-prompt nodes, re-proved per entry and sorted by seq: an
|
|
1002
|
+
* entry missing a finite seq/time/tokens drops out (the browser then falls
|
|
1003
|
+
* back to the header epoch), so a hostile collection can never produce a NaN
|
|
1004
|
+
* prompt figure or an unfetchable seq. Absent or empty stays absent.
|
|
1005
|
+
*/
|
|
1006
|
+
function systemsOf(value) {
|
|
1007
|
+
const list = objectsOf(value);
|
|
1008
|
+
const out = [];
|
|
1009
|
+
for (const entry of list) {
|
|
1010
|
+
const { seq, time, tokens } = entry;
|
|
1011
|
+
if (typeof seq !== "number" || !Number.isFinite(seq)) continue;
|
|
1012
|
+
if (typeof time !== "number" || !Number.isFinite(time)) continue;
|
|
1013
|
+
if (typeof tokens !== "number" || !Number.isFinite(tokens)) continue;
|
|
1014
|
+
out.push({
|
|
1015
|
+
seq,
|
|
1016
|
+
time,
|
|
1017
|
+
tokens
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
return out.sort((a, b) => a.seq - b.seq);
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* The fast path's check for the live system-prompt nodes: every entry must
|
|
1024
|
+
* carry the three finite numbers the browser reads — `seq` for the per-step
|
|
1025
|
+
* resolution, `time` for the DNA band, `tokens` for its width. A primitive
|
|
1026
|
+
* entry, or one whose fields are not numbers, sends the payload down the
|
|
1027
|
+
* sanitizing slow path (`systemsOf` drops it) instead of leaking `undefined`
|
|
1028
|
+
* into the bar math. An absent list is fine.
|
|
1029
|
+
*/
|
|
1030
|
+
function systemsFastOk(value) {
|
|
1031
|
+
if (value === void 0) return true;
|
|
1032
|
+
if (!Array.isArray(value)) return false;
|
|
1033
|
+
return value.every((entry) => {
|
|
1034
|
+
if (entry === null || typeof entry !== "object") return false;
|
|
1035
|
+
const { seq, time, tokens } = entry;
|
|
1036
|
+
return typeof seq === "number" && Number.isFinite(seq) && typeof time === "number" && Number.isFinite(time) && typeof tokens === "number" && Number.isFinite(tokens);
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
998
1040
|
* The split head's count figures, re-proved field by field: a present-but-
|
|
999
1041
|
* partial record zeroes its unreadable fields (the stats board's no-NaN
|
|
1000
1042
|
* guarantee), an absent or non-record value stays absent (legacy generation
|
|
@@ -1323,6 +1365,25 @@ window.__ModuleLoader__.load({
|
|
|
1323
1365
|
return out.trim() === "" ? null : out;
|
|
1324
1366
|
}
|
|
1325
1367
|
/**
|
|
1368
|
+
* The system prompt's exact rendered text — every text block joined with NO
|
|
1369
|
+
* normalization: a whitespace-only prompt is still the prompt the model
|
|
1370
|
+
* received (the host prices it as text), so it must render rather than read
|
|
1371
|
+
* as absent. Null when the content carries no text block at all.
|
|
1372
|
+
*/
|
|
1373
|
+
function systemTextOf(blocks) {
|
|
1374
|
+
if (!Array.isArray(blocks)) return null;
|
|
1375
|
+
let out = "";
|
|
1376
|
+
let seen = false;
|
|
1377
|
+
for (const b of blocks) {
|
|
1378
|
+
const text = b !== null && typeof b === "object" ? b.text : void 0;
|
|
1379
|
+
if (typeof text === "string") {
|
|
1380
|
+
out += text;
|
|
1381
|
+
seen = true;
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
return seen ? out : null;
|
|
1385
|
+
}
|
|
1386
|
+
/**
|
|
1326
1387
|
* One assistant content block → the snapshot block vocabulary the browser
|
|
1327
1388
|
* already renders (`kind`: text/reasoning/image/tool-call); unmappable
|
|
1328
1389
|
* blocks pass through raw and degrade to the generic JSON section.
|
|
@@ -1548,13 +1609,23 @@ window.__ModuleLoader__.load({
|
|
|
1548
1609
|
};
|
|
1549
1610
|
}
|
|
1550
1611
|
/**
|
|
1551
|
-
* Map one raw
|
|
1552
|
-
*
|
|
1553
|
-
* description and raw schema
|
|
1554
|
-
*
|
|
1555
|
-
*
|
|
1612
|
+
* Map one raw durable event into the epoch content the browser renders. A
|
|
1613
|
+
* `request/header` yields the full system prompt text (V0/V2 envelope) plus
|
|
1614
|
+
* each tool's producer description and raw schema; a V3 `system/message`
|
|
1615
|
+
* yields the prompt text alone (its tools live in the request header). Both
|
|
1616
|
+
* mirror the host fold's per-entry guards — a null or primitive tool entry
|
|
1617
|
+
* degrades to an unnamed row instead of throwing the read. Null when the
|
|
1618
|
+
* envelope carries neither.
|
|
1556
1619
|
*/
|
|
1557
|
-
function headerContentOf(
|
|
1620
|
+
function headerContentOf(event) {
|
|
1621
|
+
const { type, data } = event;
|
|
1622
|
+
if (type === "system/message") {
|
|
1623
|
+
const system = systemTextOf((data.message !== null && typeof data.message === "object" ? data.message : null)?.content);
|
|
1624
|
+
return system === null ? null : {
|
|
1625
|
+
system,
|
|
1626
|
+
tools: []
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1558
1629
|
const rawHeader = data.header !== null && typeof data.header === "object" ? data.header : null;
|
|
1559
1630
|
if (rawHeader === null) return null;
|
|
1560
1631
|
const toolsRaw = Array.isArray(rawHeader.tools) ? rawHeader.tools : [];
|
|
@@ -1573,15 +1644,15 @@ window.__ModuleLoader__.load({
|
|
|
1573
1644
|
};
|
|
1574
1645
|
}
|
|
1575
1646
|
/**
|
|
1576
|
-
* The on-demand CONTENT fetch for
|
|
1577
|
-
* counterpart of the node fetcher above. One seq-anchored history
|
|
1578
|
-
* the
|
|
1579
|
-
*
|
|
1580
|
-
*
|
|
1581
|
-
* (history is immutable), and OLDER
|
|
1582
|
-
*
|
|
1583
|
-
* history face exists — the browser keeps a
|
|
1584
|
-
* instead.
|
|
1647
|
+
* The on-demand CONTENT fetch for the browser's System and Tools sections —
|
|
1648
|
+
* the lazy counterpart of the node fetcher above. One seq-anchored history
|
|
1649
|
+
* read off the requested seq returns the page holding that event (non-message
|
|
1650
|
+
* events ride the page verbatim); a `request/header` maps to the epoch's
|
|
1651
|
+
* tools (and its V0/V2 system text), a `system/message` to a V3 prompt's
|
|
1652
|
+
* text. Landed content caches per seq (history is immutable), and OLDER
|
|
1653
|
+
* epochs sharing the page cache for free — stepping back through epochs walks
|
|
1654
|
+
* the same pages. Undefined when no history face exists — the browser keeps a
|
|
1655
|
+
* metadata-only degradation instead.
|
|
1585
1656
|
*/
|
|
1586
1657
|
function makeHeaderFetcher(sessionId) {
|
|
1587
1658
|
const read = pageReaderOf(sessionId);
|
|
@@ -1594,8 +1665,8 @@ window.__ModuleLoader__.load({
|
|
|
1594
1665
|
let picked = null;
|
|
1595
1666
|
for (const entry of rows) {
|
|
1596
1667
|
const ev = eventOf(entry);
|
|
1597
|
-
if (ev === null || ev.type !== "request/header") continue;
|
|
1598
|
-
const content = headerContentOf(ev
|
|
1668
|
+
if (ev === null || ev.type !== "request/header" && ev.type !== "system/message") continue;
|
|
1669
|
+
const content = headerContentOf(ev);
|
|
1599
1670
|
if (content === null) continue;
|
|
1600
1671
|
cache.set(ev.seq, content);
|
|
1601
1672
|
if (ev.seq === seq) picked = content;
|
|
@@ -1872,6 +1943,30 @@ window.__ModuleLoader__.load({
|
|
|
1872
1943
|
for (let i = headers.headers.length - 1; i >= 0; i--) if (headers.headers[i].seq < seq) return headers.headers[i];
|
|
1873
1944
|
return null;
|
|
1874
1945
|
}
|
|
1946
|
+
/**
|
|
1947
|
+
* The system prompt in force at `seq` (null = none) — the LAST live system
|
|
1948
|
+
* node at or before it carrying tokens, which is exactly the host fold's
|
|
1949
|
+
* "last nonempty surviving system" rule and therefore agrees with the
|
|
1950
|
+
* per-step `system` figure the fold recorded. Rows folded before `systems`
|
|
1951
|
+
* existed carry none; the header epoch's envelope figure stands in for them
|
|
1952
|
+
* (the pre-V3 wire shape).
|
|
1953
|
+
*/
|
|
1954
|
+
function systemAt(data, header, seq) {
|
|
1955
|
+
const systems = data.systems;
|
|
1956
|
+
if (systems !== void 0 && systems.length > 0) {
|
|
1957
|
+
for (let i = systems.length - 1; i >= 0; i--) {
|
|
1958
|
+
const node = systems[i];
|
|
1959
|
+
if (node.tokens <= 0) continue;
|
|
1960
|
+
if (seq === null || node.seq < seq) return node;
|
|
1961
|
+
}
|
|
1962
|
+
return null;
|
|
1963
|
+
}
|
|
1964
|
+
return header !== null && header.systemTokens !== void 0 ? {
|
|
1965
|
+
seq: header.seq,
|
|
1966
|
+
time: header.time,
|
|
1967
|
+
tokens: header.systemTokens
|
|
1968
|
+
} : null;
|
|
1969
|
+
}
|
|
1875
1970
|
function assemble(data, headers, seq) {
|
|
1876
1971
|
const live = seq === null;
|
|
1877
1972
|
let nodes;
|
|
@@ -1888,9 +1983,11 @@ window.__ModuleLoader__.load({
|
|
|
1888
1983
|
if (live || data.surfaceFloor !== void 0 && seq > data.surfaceFloor) missingLive = data.droppedNodes;
|
|
1889
1984
|
}
|
|
1890
1985
|
const approximate = !live && data.archiveFloor !== void 0 && seq < data.archiveFloor;
|
|
1986
|
+
const header = headerAt(headers, seq);
|
|
1891
1987
|
return {
|
|
1892
1988
|
live,
|
|
1893
|
-
header
|
|
1989
|
+
header,
|
|
1990
|
+
system: systemAt(data, header, seq),
|
|
1894
1991
|
nodes,
|
|
1895
1992
|
missingLive,
|
|
1896
1993
|
approximate
|
|
@@ -1900,19 +1997,17 @@ window.__ModuleLoader__.load({
|
|
|
1900
1997
|
//#region src/client/dna.ts
|
|
1901
1998
|
function dnaOf(view) {
|
|
1902
1999
|
const items = [];
|
|
1903
|
-
if (view.
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
});
|
|
1915
|
-
}
|
|
2000
|
+
if (view.system !== null) items.push({
|
|
2001
|
+
key: "sys",
|
|
2002
|
+
cat: "system",
|
|
2003
|
+
tokens: view.system.tokens,
|
|
2004
|
+
time: view.system.time
|
|
2005
|
+
});
|
|
2006
|
+
if (view.header !== null) for (const tool of view.header.tools) items.push({
|
|
2007
|
+
key: "tool:" + tool.name,
|
|
2008
|
+
cat: "tools",
|
|
2009
|
+
tokens: tool.tokens
|
|
2010
|
+
});
|
|
1916
2011
|
for (const n of view.nodes) items.push({
|
|
1917
2012
|
key: "n" + String(n.seq),
|
|
1918
2013
|
cat: n.cat,
|
|
@@ -3217,7 +3312,7 @@ window.__ModuleLoader__.load({
|
|
|
3217
3312
|
return m;
|
|
3218
3313
|
}
|
|
3219
3314
|
function countOf(asm, byCat, c) {
|
|
3220
|
-
if (c === "system") return asm.
|
|
3315
|
+
if (c === "system") return asm.system !== null ? 1 : 0;
|
|
3221
3316
|
if (c === "tools") return asm.header !== null ? asm.header.tools.length : 0;
|
|
3222
3317
|
return byCat[c]?.length ?? 0;
|
|
3223
3318
|
}
|
|
@@ -3302,7 +3397,8 @@ window.__ModuleLoader__.load({
|
|
|
3302
3397
|
const view = assemble(data, headers, seq);
|
|
3303
3398
|
const fetchHeader = props.fetchHeader;
|
|
3304
3399
|
const headerSeq = view.header !== null ? view.header.seq : null;
|
|
3305
|
-
const
|
|
3400
|
+
const systemSeq = view.system !== null ? view.system.seq : null;
|
|
3401
|
+
const epoch = useFetchOnMiss(openCat === "system" ? systemSeq : openCat === "tools" ? headerSeq : null, fetchHeader, "dsh-context: header content fetch failed");
|
|
3306
3402
|
const headerContent = epoch.values;
|
|
3307
3403
|
const headerNote = fetchMissNote(t, fetchHeader, epoch.state, epoch.retry, "browser.headerMetaOnly");
|
|
3308
3404
|
const breakdown = req !== null ? req : data.current;
|
|
@@ -3336,6 +3432,7 @@ window.__ModuleLoader__.load({
|
|
|
3336
3432
|
label: dnaLabel(it),
|
|
3337
3433
|
group: it.cat
|
|
3338
3434
|
})) ?? null;
|
|
3435
|
+
const liveDnaKey = dnaKey !== null && dnaByKey.has(dnaKey) ? dnaKey : null;
|
|
3339
3436
|
const pickDna = (key) => {
|
|
3340
3437
|
const it = dnaByKey.get(key);
|
|
3341
3438
|
/* v8 ignore next 1 -- the bar only reports keys of the parts it was handed; defensive. */
|
|
@@ -3347,7 +3444,7 @@ window.__ModuleLoader__.load({
|
|
|
3347
3444
|
};
|
|
3348
3445
|
const toolCount = (c) => countOf(view, byCat, c);
|
|
3349
3446
|
const singleKeyOf = (c) => {
|
|
3350
|
-
if (c === "system") return view.
|
|
3447
|
+
if (c === "system") return view.system !== null ? "sys" : null;
|
|
3351
3448
|
if (c === "tools") {
|
|
3352
3449
|
const tools = view.header?.tools;
|
|
3353
3450
|
return tools !== void 0 && tools.length === 1 ? "tool:" + tools[0].name : null;
|
|
@@ -3417,11 +3514,12 @@ window.__ModuleLoader__.load({
|
|
|
3417
3514
|
};
|
|
3418
3515
|
const catBody = (c) => {
|
|
3419
3516
|
if (c === "system") {
|
|
3420
|
-
|
|
3517
|
+
const sys = view.system;
|
|
3518
|
+
if (sys === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3421
3519
|
className: "lc-br-note",
|
|
3422
3520
|
children: t(headers === null ? "browser.noHeader" : "browser.noEpoch")
|
|
3423
3521
|
});
|
|
3424
|
-
const content = headerContent.get(
|
|
3522
|
+
const content = headerContent.get(sys.seq);
|
|
3425
3523
|
if (content === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3426
3524
|
className: "lc-br-note",
|
|
3427
3525
|
children: headerNote
|
|
@@ -3638,7 +3736,7 @@ window.__ModuleLoader__.load({
|
|
|
3638
3736
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StackedBar, {
|
|
3639
3737
|
parts: dnaParts ?? parts,
|
|
3640
3738
|
height: 10,
|
|
3641
|
-
hoverKey: dna ?
|
|
3739
|
+
hoverKey: dna ? liveDnaKey ?? linkKey ?? pinKey : linkKey ?? pinKey,
|
|
3642
3740
|
onHoverKey: dna ? setDnaKey : linked ? props.onHoverKey : void 0,
|
|
3643
3741
|
tip: dna,
|
|
3644
3742
|
onPickKey: dna ? pickDna : void 0,
|
|
@@ -5158,6 +5256,35 @@ window.__ModuleLoader__.load({
|
|
|
5158
5256
|
for (const r of requests) if (r.seq > seq && (gone === void 0 || gone > r.seq)) return r.seq;
|
|
5159
5257
|
return gone === void 0 ? "live" : null;
|
|
5160
5258
|
}
|
|
5259
|
+
//#endregion
|
|
5260
|
+
//#region src/client/overscroll.ts
|
|
5261
|
+
/**
|
|
5262
|
+
* Stop a horizontal scroller's overscroll from reaching the browser's history navigation — the trackpad
|
|
5263
|
+
* swipe-back (left edge) and swipe-forward (right edge) gestures. The spec answer is `overscroll-behavior-x:
|
|
5264
|
+
* contain`, the harness's own idiom for its horizontal scrollers and what the sheets beside this module's
|
|
5265
|
+
* callers already set; it covers Chromium and Firefox, but WebKit still navigates on horizontal overscroll with
|
|
5266
|
+
* the property set (bug 240183), where a canceled wheel is the only lever. Without either, one swipe past the
|
|
5267
|
+
* edge of the trend chart or the agent graph leaves the whole app for another page in the tab's history.
|
|
5268
|
+
*/
|
|
5269
|
+
/**
|
|
5270
|
+
* Cancel the horizontal-dominant wheel gestures a scroller cannot consume — the ones the browser would
|
|
5271
|
+
* otherwise read as a history swipe. Vertical-dominant gestures are left alone: they belong to the page's own
|
|
5272
|
+
* scrolling, and the scrollers this guards only overflow horizontally.
|
|
5273
|
+
* @param el - the horizontal scroll container (the listener must be non-passive, so it cannot ride React's passive wheel seat).
|
|
5274
|
+
* @returns the disposer removing the listener.
|
|
5275
|
+
*/
|
|
5276
|
+
function containHorizontalOverscroll(el) {
|
|
5277
|
+
const onWheel = (e) => {
|
|
5278
|
+
if (Math.abs(e.deltaX) <= Math.abs(e.deltaY)) return;
|
|
5279
|
+
const atStart = e.deltaX < 0 && el.scrollLeft <= 0;
|
|
5280
|
+
const atEnd = e.deltaX > 0 && el.scrollLeft + el.clientWidth >= el.scrollWidth - 1;
|
|
5281
|
+
if (atStart || atEnd) e.preventDefault();
|
|
5282
|
+
};
|
|
5283
|
+
el.addEventListener("wheel", onWheel, { passive: false });
|
|
5284
|
+
return () => {
|
|
5285
|
+
el.removeEventListener("wheel", onWheel);
|
|
5286
|
+
};
|
|
5287
|
+
}
|
|
5161
5288
|
const SLOT_MAX = 184;
|
|
5162
5289
|
const SLOT_MIN = 112;
|
|
5163
5290
|
const CAPTION_GUTTER = 8;
|
|
@@ -5605,6 +5732,13 @@ window.__ModuleLoader__.load({
|
|
|
5605
5732
|
};
|
|
5606
5733
|
/* v8 ignore stop */
|
|
5607
5734
|
}, []);
|
|
5735
|
+
(0, react.useEffect)(() => {
|
|
5736
|
+
const el = stageRef.current;
|
|
5737
|
+
/* v8 ignore next 1 -- the stage renders whenever the card does, and React
|
|
5738
|
+
attaches refs before effects run; el is never null here. */
|
|
5739
|
+
if (el === null) return;
|
|
5740
|
+
return containHorizontalOverscroll(el);
|
|
5741
|
+
}, []);
|
|
5608
5742
|
(0, react.useEffect)(() => {
|
|
5609
5743
|
if (face === null || typeof sessionId !== "string" || sessionId === "") return;
|
|
5610
5744
|
if (typeof face.refreshSubagents !== "function") return;
|
|
@@ -6445,7 +6579,7 @@ window.__ModuleLoader__.load({
|
|
|
6445
6579
|
return function PluginInfo() {
|
|
6446
6580
|
const [latest, setLatest] = (0, react.useState)(null);
|
|
6447
6581
|
(0, react.useEffect)(() => {
|
|
6448
|
-
if ("0.
|
|
6582
|
+
if ("0.47.0".includes("-dev")) return;
|
|
6449
6583
|
let on = true;
|
|
6450
6584
|
fetchLatestVersion().then((v) => {
|
|
6451
6585
|
if (on && v) setLatest(v);
|
|
@@ -6454,8 +6588,8 @@ window.__ModuleLoader__.load({
|
|
|
6454
6588
|
on = false;
|
|
6455
6589
|
};
|
|
6456
6590
|
}, []);
|
|
6457
|
-
const update = latest !== null && isNewerVersion(latest, "0.
|
|
6458
|
-
const nameText = "dsh-context (v0.
|
|
6591
|
+
const update = latest !== null && isNewerVersion(latest, "0.47.0") ? latest : null;
|
|
6592
|
+
const nameText = "dsh-context (v0.47.0)";
|
|
6459
6593
|
const nameValue = [nameText];
|
|
6460
6594
|
if (update) nameValue.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6461
6595
|
className: "lc-pi-update",
|
|
@@ -7576,6 +7710,42 @@ window.__ModuleLoader__.load({
|
|
|
7576
7710
|
focus
|
|
7577
7711
|
]);
|
|
7578
7712
|
const markers = props.markers;
|
|
7713
|
+
const adaptive = props.adaptive === true;
|
|
7714
|
+
const [visMax, setVisMax] = (0, react.useState)(null);
|
|
7715
|
+
const measureVisible = (el) => {
|
|
7716
|
+
if (!adaptive) return;
|
|
7717
|
+
const n = requests.length;
|
|
7718
|
+
if (n === 0 || el.clientWidth <= 0) return;
|
|
7719
|
+
const pitch = 16;
|
|
7720
|
+
const sl = el.scrollLeft;
|
|
7721
|
+
const vr = sl + el.clientWidth;
|
|
7722
|
+
let total = 0;
|
|
7723
|
+
let up = 0;
|
|
7724
|
+
let down = 0;
|
|
7725
|
+
const from = Math.max(0, Math.floor(sl / pitch));
|
|
7726
|
+
const to = Math.min(n - 1, Math.max(from, Math.floor((vr - 1) / pitch)));
|
|
7727
|
+
for (let i = from; i <= to; i++) {
|
|
7728
|
+
const col = i * pitch;
|
|
7729
|
+
if (col >= vr || col + BAR_W <= sl) continue;
|
|
7730
|
+
const req = requests[i];
|
|
7731
|
+
if (delta) {
|
|
7732
|
+
let bu = 0;
|
|
7733
|
+
let bd = 0;
|
|
7734
|
+
for (const c of CATS) {
|
|
7735
|
+
const d = req[c.key] || 0;
|
|
7736
|
+
if (d > 0) bu += d;
|
|
7737
|
+
else bd -= d;
|
|
7738
|
+
}
|
|
7739
|
+
if (bu > up) up = bu;
|
|
7740
|
+
if (bd > down) down = bd;
|
|
7741
|
+
} else if (req.total > total) total = req.total;
|
|
7742
|
+
}
|
|
7743
|
+
setVisMax((prev) => prev !== null && prev.total === total && prev.up === up && prev.down === down ? prev : {
|
|
7744
|
+
total,
|
|
7745
|
+
up,
|
|
7746
|
+
down
|
|
7747
|
+
});
|
|
7748
|
+
};
|
|
7579
7749
|
let maxTotal = 1;
|
|
7580
7750
|
let maxUp = 0;
|
|
7581
7751
|
let maxDown = 0;
|
|
@@ -7591,6 +7761,14 @@ window.__ModuleLoader__.load({
|
|
|
7591
7761
|
if (down > maxDown) maxDown = down;
|
|
7592
7762
|
}
|
|
7593
7763
|
else for (const req of requests) if (req.total > maxTotal) maxTotal = req.total;
|
|
7764
|
+
if (adaptive && visMax !== null) {
|
|
7765
|
+
if (delta) {
|
|
7766
|
+
if (visMax.up + visMax.down > 0) {
|
|
7767
|
+
maxUp = visMax.up;
|
|
7768
|
+
maxDown = visMax.down;
|
|
7769
|
+
}
|
|
7770
|
+
} else maxTotal = Math.max(1, visMax.total);
|
|
7771
|
+
}
|
|
7594
7772
|
const span = Math.max(1, maxUp + maxDown);
|
|
7595
7773
|
const deltaScale = CHART_H / span;
|
|
7596
7774
|
const upPx = Math.round(maxUp * deltaScale);
|
|
@@ -7710,11 +7888,38 @@ window.__ModuleLoader__.load({
|
|
|
7710
7888
|
prevScrollWidthRef.current = el.scrollWidth;
|
|
7711
7889
|
updateTurnLabels(el);
|
|
7712
7890
|
syncTip(el);
|
|
7891
|
+
measureVisible(el);
|
|
7713
7892
|
}, [
|
|
7714
7893
|
props.granularity,
|
|
7715
7894
|
props.focusTurn,
|
|
7716
|
-
requests
|
|
7895
|
+
requests,
|
|
7896
|
+
adaptive
|
|
7717
7897
|
]);
|
|
7898
|
+
const measureRef = (0, react.useRef)(measureVisible);
|
|
7899
|
+
(0, react.useLayoutEffect)(() => {
|
|
7900
|
+
measureRef.current = measureVisible;
|
|
7901
|
+
});
|
|
7902
|
+
(0, react.useLayoutEffect)(() => {
|
|
7903
|
+
const el = scrollRef.current;
|
|
7904
|
+
/* v8 ignore next 1 -- the scroll div renders unconditionally and React
|
|
7905
|
+
attaches refs before layout effects run; el is never null here. */
|
|
7906
|
+
if (el === null) return;
|
|
7907
|
+
if (typeof ResizeObserver !== "function") return;
|
|
7908
|
+
const observer = new ResizeObserver(() => {
|
|
7909
|
+
measureRef.current(el);
|
|
7910
|
+
});
|
|
7911
|
+
observer.observe(el);
|
|
7912
|
+
return () => {
|
|
7913
|
+
observer.disconnect();
|
|
7914
|
+
};
|
|
7915
|
+
}, []);
|
|
7916
|
+
(0, react.useLayoutEffect)(() => {
|
|
7917
|
+
const el = scrollRef.current;
|
|
7918
|
+
/* v8 ignore next 1 -- the scroll div renders unconditionally and React
|
|
7919
|
+
attaches refs before layout effects run; el is never null here. */
|
|
7920
|
+
if (el === null) return;
|
|
7921
|
+
return containHorizontalOverscroll(el);
|
|
7922
|
+
}, []);
|
|
7718
7923
|
const tipRowsOf = (req) => {
|
|
7719
7924
|
const n = req.stepCount ?? 1;
|
|
7720
7925
|
const head = props.granularity === "turn" ? n > 1 ? t("tip.turn", {
|
|
@@ -7819,6 +8024,7 @@ window.__ModuleLoader__.load({
|
|
|
7819
8024
|
onScroll: (e) => {
|
|
7820
8025
|
updateTurnLabels(e.currentTarget);
|
|
7821
8026
|
syncTip(e.currentTarget);
|
|
8027
|
+
measureVisible(e.currentTarget);
|
|
7822
8028
|
},
|
|
7823
8029
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7824
8030
|
className: "lc-chart",
|
|
@@ -7958,6 +8164,7 @@ window.__ModuleLoader__.load({
|
|
|
7958
8164
|
const ErrorBoundary = makeErrorBoundary(t);
|
|
7959
8165
|
function ContextViewBody(props) {
|
|
7960
8166
|
const sessionId = props.sessionId;
|
|
8167
|
+
const inSidebar = props.host === "sidebar";
|
|
7961
8168
|
const source = useTimelineSource(ctx, props);
|
|
7962
8169
|
const data = source.data;
|
|
7963
8170
|
const pressure = projectionOf(props, "contextPressure", contextPressureOf);
|
|
@@ -7969,6 +8176,7 @@ window.__ModuleLoader__.load({
|
|
|
7969
8176
|
const [hoverTurn, setHoverTurn] = (0, react.useState)(null);
|
|
7970
8177
|
const [granularity, setGranularity] = (0, react.useState)(() => settings.defaultGranularity());
|
|
7971
8178
|
const [trendMode, setTrendMode] = (0, react.useState)(() => settings.defaultTrendMode());
|
|
8179
|
+
const [adaptive, setAdaptive] = (0, react.useState)(false);
|
|
7972
8180
|
const [focusTurn, setFocusTurn] = (0, react.useState)(null);
|
|
7973
8181
|
const [jumpSeq, setJumpSeq] = (0, react.useState)(null);
|
|
7974
8182
|
const [hoverCat, setHoverCat] = (0, react.useState)(null);
|
|
@@ -8151,6 +8359,132 @@ window.__ModuleLoader__.load({
|
|
|
8151
8359
|
const activeLocale = localeSvc !== void 0 && typeof localeSvc.getLocale === "function" ? localeSvc.getLocale().active : "en";
|
|
8152
8360
|
const subtitle = (data.model ?? "") + (data.provider ? " · " + data.provider : "");
|
|
8153
8361
|
const gate = unsupportedOf(data.unsupported);
|
|
8362
|
+
const compositionCard = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CurrentComposition, {
|
|
8363
|
+
head,
|
|
8364
|
+
subtitle,
|
|
8365
|
+
hoverKey: hoverCat,
|
|
8366
|
+
onHoverKey: setHoverCat
|
|
8367
|
+
});
|
|
8368
|
+
const trendCard = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8369
|
+
className: "lc-card",
|
|
8370
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8371
|
+
className: "lc-card-title",
|
|
8372
|
+
children: [
|
|
8373
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8374
|
+
className: "lc-card-title-text",
|
|
8375
|
+
children: t("trend.title")
|
|
8376
|
+
}),
|
|
8377
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8378
|
+
className: "lc-gran lc-trend-adaptive",
|
|
8379
|
+
role: "group",
|
|
8380
|
+
title: t("trend.adaptiveHint"),
|
|
8381
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8382
|
+
type: "button",
|
|
8383
|
+
className: "lc-gran-btn" + (adaptive ? " lc-gran-on" : ""),
|
|
8384
|
+
onClick: () => {
|
|
8385
|
+
setAdaptive((on) => !on);
|
|
8386
|
+
},
|
|
8387
|
+
children: t("trend.adaptive")
|
|
8388
|
+
})
|
|
8389
|
+
}),
|
|
8390
|
+
focusCat !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8391
|
+
className: "lc-card-sub",
|
|
8392
|
+
children: t("trend.focus", { cat: kit.catLabel(focusCat) })
|
|
8393
|
+
}) : null,
|
|
8394
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8395
|
+
className: "lc-trend-ctl",
|
|
8396
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8397
|
+
className: "lc-gran",
|
|
8398
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8399
|
+
className: "lc-gran-btn" + (granularity === "step" ? " lc-gran-on" : ""),
|
|
8400
|
+
onClick: () => {
|
|
8401
|
+
setGranularity("step");
|
|
8402
|
+
},
|
|
8403
|
+
children: t("gran.step")
|
|
8404
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8405
|
+
className: "lc-gran-btn" + (granularity === "turn" ? " lc-gran-on" : ""),
|
|
8406
|
+
onClick: () => {
|
|
8407
|
+
setGranularity("turn");
|
|
8408
|
+
},
|
|
8409
|
+
children: t("gran.turn")
|
|
8410
|
+
})]
|
|
8411
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8412
|
+
className: "lc-gran",
|
|
8413
|
+
title: t("gran.modeHint"),
|
|
8414
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8415
|
+
className: "lc-gran-btn" + (trendMode === "total" ? " lc-gran-on" : ""),
|
|
8416
|
+
onClick: () => {
|
|
8417
|
+
setTrendMode("total");
|
|
8418
|
+
},
|
|
8419
|
+
children: t("gran.total")
|
|
8420
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8421
|
+
className: "lc-gran-btn" + (trendMode === "delta" ? " lc-gran-on" : ""),
|
|
8422
|
+
onClick: () => {
|
|
8423
|
+
setTrendMode("delta");
|
|
8424
|
+
},
|
|
8425
|
+
children: t("gran.delta")
|
|
8426
|
+
})]
|
|
8427
|
+
})]
|
|
8428
|
+
})
|
|
8429
|
+
]
|
|
8430
|
+
}), displayRequests.length === 0 ? detailReady ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8431
|
+
className: "lc-empty",
|
|
8432
|
+
children: t("trend.empty")
|
|
8433
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailNote, {
|
|
8434
|
+
state: source.detailState === "failed" ? "failed" : "loading",
|
|
8435
|
+
onRetry: source.retryDetail
|
|
8436
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrendChart, {
|
|
8437
|
+
requests: displayRequests,
|
|
8438
|
+
markers,
|
|
8439
|
+
selectedSeq: pinnedReq ? pinnedReq.seq : null,
|
|
8440
|
+
hoveredSeq,
|
|
8441
|
+
activeTurn,
|
|
8442
|
+
granularity,
|
|
8443
|
+
mode: trendMode,
|
|
8444
|
+
focusTurn,
|
|
8445
|
+
hoverCat: trendHoverCat,
|
|
8446
|
+
focusCat,
|
|
8447
|
+
adaptive,
|
|
8448
|
+
onSelect: setSelectedSeq,
|
|
8449
|
+
onHover: setHoveredSeq,
|
|
8450
|
+
onHoverTurn: setHoverTurn,
|
|
8451
|
+
onPickTurn: (turn) => {
|
|
8452
|
+
setGranularity("turn");
|
|
8453
|
+
setFocusTurn(turn);
|
|
8454
|
+
},
|
|
8455
|
+
onFocusTurnHandled: () => {
|
|
8456
|
+
setFocusTurn(null);
|
|
8457
|
+
}
|
|
8458
|
+
}, sessionId), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RequestDetail, {
|
|
8459
|
+
request: activeReq,
|
|
8460
|
+
prev: trendMode === "delta" && activeIdx >= 0 ? activeIdx > 0 ? displayRequests[activeIdx - 1] : null : void 0,
|
|
8461
|
+
/* v8 ignore next 1 -- RequestDetail renders only when
|
|
8462
|
+
displayRequests.length > 0, which forces activeReq
|
|
8463
|
+
non-null via the activeIdx fallback above. */
|
|
8464
|
+
marker: activeReq !== null ? markerOf(activeReq) : void 0,
|
|
8465
|
+
brief,
|
|
8466
|
+
convOf,
|
|
8467
|
+
onLocate: locateNode,
|
|
8468
|
+
hoverKey: trendHoverCat
|
|
8469
|
+
})] })]
|
|
8470
|
+
});
|
|
8471
|
+
const browserCard = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContextBrowser, {
|
|
8472
|
+
data,
|
|
8473
|
+
headers,
|
|
8474
|
+
convNodes,
|
|
8475
|
+
fetchContent,
|
|
8476
|
+
fetchHeader,
|
|
8477
|
+
previewSeq: hoveredSeq,
|
|
8478
|
+
pinSeq: pinnedReq !== null ? pinnedReq.seq : null,
|
|
8479
|
+
hoverKey: hoverCat,
|
|
8480
|
+
onHoverKey: setHoverCat,
|
|
8481
|
+
onOpenCat: setFocusCat,
|
|
8482
|
+
nodeFocus,
|
|
8483
|
+
onNodeFocusHandled: clearNodeFocus,
|
|
8484
|
+
loadImage,
|
|
8485
|
+
detailState: source.detailState,
|
|
8486
|
+
onDetailRetry: source.retryDetail
|
|
8487
|
+
});
|
|
8154
8488
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8155
8489
|
className: "lc-root",
|
|
8156
8490
|
ref: rootRef,
|
|
@@ -8158,7 +8492,7 @@ window.__ModuleLoader__.load({
|
|
|
8158
8492
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8159
8493
|
className: "lc-cols lc-head",
|
|
8160
8494
|
children: [
|
|
8161
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatsContext, {
|
|
8495
|
+
inSidebar ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatsContext, {
|
|
8162
8496
|
counts: data.counts ?? countsOfRecords(requests, events),
|
|
8163
8497
|
toolCalls: data.toolCalls,
|
|
8164
8498
|
images: data.images,
|
|
@@ -8170,127 +8504,31 @@ window.__ModuleLoader__.load({
|
|
|
8170
8504
|
timing: data.timing ?? null,
|
|
8171
8505
|
locale: activeLocale
|
|
8172
8506
|
}),
|
|
8173
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PluginInfo, {})
|
|
8507
|
+
inSidebar ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PluginInfo, {})
|
|
8174
8508
|
]
|
|
8175
8509
|
}),
|
|
8176
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
8177
|
-
className: "lc-cols",
|
|
8178
|
-
children:
|
|
8510
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8511
|
+
className: "lc-cols lc-cols-main",
|
|
8512
|
+
children: inSidebar ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
8513
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8514
|
+
className: "lc-col",
|
|
8515
|
+
children: compositionCard
|
|
8516
|
+
}),
|
|
8517
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8518
|
+
className: "lc-col lc-col-browser",
|
|
8519
|
+
children: browserCard
|
|
8520
|
+
}),
|
|
8521
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8522
|
+
className: "lc-col",
|
|
8523
|
+
children: trendCard
|
|
8524
|
+
})
|
|
8525
|
+
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8179
8526
|
className: "lc-col",
|
|
8180
|
-
children: [
|
|
8181
|
-
head,
|
|
8182
|
-
subtitle,
|
|
8183
|
-
hoverKey: hoverCat,
|
|
8184
|
-
onHoverKey: setHoverCat
|
|
8185
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8186
|
-
className: "lc-card",
|
|
8187
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8188
|
-
className: "lc-card-title",
|
|
8189
|
-
children: [
|
|
8190
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8191
|
-
className: "lc-card-title-text",
|
|
8192
|
-
children: t("trend.title")
|
|
8193
|
-
}),
|
|
8194
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8195
|
-
className: "lc-card-sub",
|
|
8196
|
-
children: focusCat !== null ? t("trend.focus", { cat: kit.catLabel(focusCat) }) : t("trend.hint")
|
|
8197
|
-
}),
|
|
8198
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8199
|
-
className: "lc-trend-ctl",
|
|
8200
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8201
|
-
className: "lc-gran",
|
|
8202
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8203
|
-
className: "lc-gran-btn" + (granularity === "step" ? " lc-gran-on" : ""),
|
|
8204
|
-
onClick: () => {
|
|
8205
|
-
setGranularity("step");
|
|
8206
|
-
},
|
|
8207
|
-
children: t("gran.step")
|
|
8208
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8209
|
-
className: "lc-gran-btn" + (granularity === "turn" ? " lc-gran-on" : ""),
|
|
8210
|
-
onClick: () => {
|
|
8211
|
-
setGranularity("turn");
|
|
8212
|
-
},
|
|
8213
|
-
children: t("gran.turn")
|
|
8214
|
-
})]
|
|
8215
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8216
|
-
className: "lc-gran",
|
|
8217
|
-
title: t("gran.modeHint"),
|
|
8218
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8219
|
-
className: "lc-gran-btn" + (trendMode === "total" ? " lc-gran-on" : ""),
|
|
8220
|
-
onClick: () => {
|
|
8221
|
-
setTrendMode("total");
|
|
8222
|
-
},
|
|
8223
|
-
children: t("gran.total")
|
|
8224
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8225
|
-
className: "lc-gran-btn" + (trendMode === "delta" ? " lc-gran-on" : ""),
|
|
8226
|
-
onClick: () => {
|
|
8227
|
-
setTrendMode("delta");
|
|
8228
|
-
},
|
|
8229
|
-
children: t("gran.delta")
|
|
8230
|
-
})]
|
|
8231
|
-
})]
|
|
8232
|
-
})
|
|
8233
|
-
]
|
|
8234
|
-
}), displayRequests.length === 0 ? detailReady ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8235
|
-
className: "lc-empty",
|
|
8236
|
-
children: t("trend.empty")
|
|
8237
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DetailNote, {
|
|
8238
|
-
state: source.detailState === "failed" ? "failed" : "loading",
|
|
8239
|
-
onRetry: source.retryDetail
|
|
8240
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrendChart, {
|
|
8241
|
-
requests: displayRequests,
|
|
8242
|
-
markers,
|
|
8243
|
-
selectedSeq: pinnedReq ? pinnedReq.seq : null,
|
|
8244
|
-
hoveredSeq,
|
|
8245
|
-
activeTurn,
|
|
8246
|
-
granularity,
|
|
8247
|
-
mode: trendMode,
|
|
8248
|
-
focusTurn,
|
|
8249
|
-
hoverCat: trendHoverCat,
|
|
8250
|
-
focusCat,
|
|
8251
|
-
onSelect: setSelectedSeq,
|
|
8252
|
-
onHover: setHoveredSeq,
|
|
8253
|
-
onHoverTurn: setHoverTurn,
|
|
8254
|
-
onPickTurn: (turn) => {
|
|
8255
|
-
setGranularity("turn");
|
|
8256
|
-
setFocusTurn(turn);
|
|
8257
|
-
},
|
|
8258
|
-
onFocusTurnHandled: () => {
|
|
8259
|
-
setFocusTurn(null);
|
|
8260
|
-
}
|
|
8261
|
-
}, sessionId), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RequestDetail, {
|
|
8262
|
-
request: activeReq,
|
|
8263
|
-
prev: trendMode === "delta" && activeIdx >= 0 ? activeIdx > 0 ? displayRequests[activeIdx - 1] : null : void 0,
|
|
8264
|
-
/* v8 ignore next 1 -- RequestDetail renders only when
|
|
8265
|
-
displayRequests.length > 0, which forces activeReq
|
|
8266
|
-
non-null via the activeIdx fallback above. */
|
|
8267
|
-
marker: activeReq !== null ? markerOf(activeReq) : void 0,
|
|
8268
|
-
brief,
|
|
8269
|
-
convOf,
|
|
8270
|
-
onLocate: locateNode,
|
|
8271
|
-
hoverKey: trendHoverCat
|
|
8272
|
-
})] })]
|
|
8273
|
-
})]
|
|
8527
|
+
children: [compositionCard, trendCard]
|
|
8274
8528
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8275
8529
|
className: "lc-col lc-col-browser",
|
|
8276
|
-
children:
|
|
8277
|
-
|
|
8278
|
-
headers,
|
|
8279
|
-
convNodes,
|
|
8280
|
-
fetchContent,
|
|
8281
|
-
fetchHeader,
|
|
8282
|
-
previewSeq: hoveredSeq,
|
|
8283
|
-
pinSeq: pinnedReq !== null ? pinnedReq.seq : null,
|
|
8284
|
-
hoverKey: hoverCat,
|
|
8285
|
-
onHoverKey: setHoverCat,
|
|
8286
|
-
onOpenCat: setFocusCat,
|
|
8287
|
-
nodeFocus,
|
|
8288
|
-
onNodeFocusHandled: clearNodeFocus,
|
|
8289
|
-
loadImage,
|
|
8290
|
-
detailState: source.detailState,
|
|
8291
|
-
onDetailRetry: source.retryDetail
|
|
8292
|
-
})
|
|
8293
|
-
})]
|
|
8530
|
+
children: browserCard
|
|
8531
|
+
})] })
|
|
8294
8532
|
}),
|
|
8295
8533
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8296
8534
|
className: "lc-cols",
|
|
@@ -8436,122 +8674,97 @@ window.__ModuleLoader__.load({
|
|
|
8436
8674
|
};
|
|
8437
8675
|
}
|
|
8438
8676
|
//#endregion
|
|
8439
|
-
//#region src/client/
|
|
8440
|
-
/**
|
|
8441
|
-
* The
|
|
8442
|
-
* `conversation.composer.dock` seat — becomes a jump affordance: hovering
|
|
8443
|
-
* underlines it, a click (or Enter/Space) opens the Context tab. The plugin
|
|
8444
|
-
* wires this from a sibling dock entry that renders no UI of its own: an
|
|
8445
|
-
* invisible anchor mounts inside the slot's `[data-slot]` wrapper and spots
|
|
8446
|
-
* the stats row beside it, and a MutationObserver re-spots it on dock churn
|
|
8447
|
-
* (the row mounts only once the first stats exist, tooltip bubbles come and
|
|
8448
|
-
* go beside it, and switching conversations remounts the pair together).
|
|
8677
|
+
//#region src/client/sidebar.ts
|
|
8678
|
+
/**
|
|
8679
|
+
* The right Sidebar's Context tab (dsh 0.1.5-alpha.1+).
|
|
8449
8680
|
*
|
|
8450
|
-
*
|
|
8451
|
-
*
|
|
8452
|
-
*
|
|
8453
|
-
*
|
|
8454
|
-
*
|
|
8455
|
-
* page
|
|
8456
|
-
|
|
8457
|
-
|
|
8458
|
-
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
*
|
|
8462
|
-
*
|
|
8463
|
-
*
|
|
8464
|
-
*
|
|
8465
|
-
*
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
|
|
8681
|
+
* The tab reuses the Context conversation-view component VERBATIM: the
|
|
8682
|
+
* `sidebar.right.pane.tab` seat is session-scoped and delivers the same
|
|
8683
|
+
* framework standard kit (`sessionId`, `useProjection`, `useChat`, the locale
|
|
8684
|
+
* `t` seat) the `conversation.view` seat does, so the panel and the tab are
|
|
8685
|
+
* one component with one data path. The tab type contributes a guide entry, so
|
|
8686
|
+
* the sidebar's guide page offers "Context" and picking it opens the panel —
|
|
8687
|
+
* the product's own path, exactly as the shipped Files type does.
|
|
8688
|
+
*
|
|
8689
|
+
* OPTIONAL BY CONTRACT. `ctx.sidebarRightTabs` and the seat exist only from
|
|
8690
|
+
* dsh 0.1.5-alpha.1; the registration therefore rides a DEFERRED inject (the
|
|
8691
|
+
* plugin's hard injects stay `slots` + `locale`), so on every older supported
|
|
8692
|
+
* line the callback never fires, the plugin fiber never pends, and nothing is
|
|
8693
|
+
* registered. The registry is re-proved structurally and the whole
|
|
8694
|
+
* registration is guarded: a foreign or hostile registry (a throwing
|
|
8695
|
+
* `register`, a taken id/kind) leaves the sidebar without the tab instead of
|
|
8696
|
+
* taking the browser down.
|
|
8697
|
+
*
|
|
8698
|
+
* @module dsh-context/client/sidebar
|
|
8699
|
+
*/
|
|
8700
|
+
/** The tab type's identity in the sidebar's tab system (also its body-seat key). */
|
|
8701
|
+
const SIDEBAR_CONTEXT_ID = "dsh-context";
|
|
8702
|
+
/**
|
|
8703
|
+
* The kind `openTab` names. Namespaced rather than the bare `context`: the
|
|
8704
|
+
* registry THROWS when a kind collides with another registration in a
|
|
8705
|
+
* non-coexisting band, and a foreign plugin may well own `context`.
|
|
8706
|
+
*/
|
|
8707
|
+
const SIDEBAR_CONTEXT_KIND = "dsh-context";
|
|
8708
|
+
/** The guide box's position: after the shipped Files entry (order 10). */
|
|
8709
|
+
const GUIDE_ORDER = 20;
|
|
8710
|
+
/**
|
|
8711
|
+
* The guide box's glyph, read defensively: the icon is OPTIONAL in the entry,
|
|
8712
|
+
* and a primitives module that does not serve it — or whose namespace THROWS
|
|
8713
|
+
* on the read (an interop/mock shape does exactly that) — must cost the glyph,
|
|
8714
|
+
* never the whole tab.
|
|
8715
|
+
* @returns the icon component, or undefined to register the tab without one.
|
|
8716
|
+
*/
|
|
8717
|
+
function guideIcon() {
|
|
8718
|
+
try {
|
|
8719
|
+
return _deepseek_ai_dsh_client_ui_primitives.IconContextInjectionOutline16;
|
|
8720
|
+
} catch {
|
|
8721
|
+
return;
|
|
8479
8722
|
}
|
|
8480
|
-
return row;
|
|
8481
8723
|
}
|
|
8482
8724
|
/**
|
|
8483
|
-
*
|
|
8484
|
-
*
|
|
8485
|
-
*
|
|
8725
|
+
* Register the Context tab type and its body on the right Sidebar, if — and
|
|
8726
|
+
* only if — this harness serves the sidebar tab registry.
|
|
8727
|
+
* @param ctx - client root context carrying `slots` and the locale service.
|
|
8728
|
+
* @param view - the Context view component factory result (the same one the
|
|
8729
|
+
* conversation tab mounts).
|
|
8730
|
+
* @param t - the plugin-namespace translate; the label thunks read the active
|
|
8731
|
+
* locale at call time, so a language switch relabels the guide entry.
|
|
8732
|
+
* @param ns - the plugin's locale namespace, put on the body registration so
|
|
8733
|
+
* the framework synthesizes the `t` seat for the panel too.
|
|
8486
8734
|
*/
|
|
8487
|
-
function
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
const unwire = () => {
|
|
8491
|
-
wired?.off();
|
|
8492
|
-
wired = null;
|
|
8493
|
-
};
|
|
8494
|
-
const scan = () => {
|
|
8735
|
+
function watchSidebarContextTab(ctx, view, t, ns) {
|
|
8736
|
+
ctx.inject(["sidebarRightTabs"], (raw) => {
|
|
8737
|
+
const injected = raw;
|
|
8495
8738
|
try {
|
|
8496
|
-
const
|
|
8497
|
-
if (
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
};
|
|
8509
|
-
const
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
}
|
|
8514
|
-
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
8518
|
-
|
|
8519
|
-
|
|
8520
|
-
row.removeEventListener("keydown", onKey);
|
|
8521
|
-
row.classList.remove(ROW_CLASS);
|
|
8522
|
-
row.removeAttribute("role");
|
|
8523
|
-
row.removeAttribute("tabindex");
|
|
8524
|
-
row.removeAttribute("aria-label");
|
|
8525
|
-
}
|
|
8739
|
+
const tabs = injected.sidebarRightTabs;
|
|
8740
|
+
if (tabs === void 0 || typeof tabs.register !== "function") return;
|
|
8741
|
+
const disposeType = tabs.register({
|
|
8742
|
+
id: SIDEBAR_CONTEXT_ID,
|
|
8743
|
+
kind: SIDEBAR_CONTEXT_KIND,
|
|
8744
|
+
title: () => t("tab"),
|
|
8745
|
+
guide: [{
|
|
8746
|
+
order: GUIDE_ORDER,
|
|
8747
|
+
title: () => t("tab"),
|
|
8748
|
+
description: () => t("sidebar.guideDescription"),
|
|
8749
|
+
icon: guideIcon()
|
|
8750
|
+
}]
|
|
8751
|
+
});
|
|
8752
|
+
const disposeBody = injected.slots.inject("sidebar.right.pane.tab", () => injected.slots.register({
|
|
8753
|
+
name: "sidebar.right.pane.tab",
|
|
8754
|
+
key: SIDEBAR_CONTEXT_ID,
|
|
8755
|
+
locale: ns
|
|
8756
|
+
}, (props) => view({
|
|
8757
|
+
...props,
|
|
8758
|
+
host: "sidebar"
|
|
8759
|
+
})));
|
|
8760
|
+
return () => {
|
|
8761
|
+
disposeType();
|
|
8762
|
+
if (typeof disposeBody === "function") disposeBody();
|
|
8526
8763
|
};
|
|
8527
|
-
} catch {
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
if (parent === null) return unwire;
|
|
8532
|
-
const observer = new MutationObserver(scan);
|
|
8533
|
-
observer.observe(parent, { childList: true });
|
|
8534
|
-
return () => {
|
|
8535
|
-
observer.disconnect();
|
|
8536
|
-
unwire();
|
|
8537
|
-
};
|
|
8538
|
-
}
|
|
8539
|
-
/** The dock entry component: the invisible anchor plus the wiring around it. */
|
|
8540
|
-
function makeStatsJump(kit) {
|
|
8541
|
-
const { t } = kit;
|
|
8542
|
-
return function StatsJump() {
|
|
8543
|
-
const anchorRef = (0, react.useRef)(null);
|
|
8544
|
-
const label = t("jump.statsLine");
|
|
8545
|
-
(0, react.useEffect)(() => wireDock(anchorRef.current, label, () => {
|
|
8546
|
-
activateContextTab(t("tab"));
|
|
8547
|
-
}), [label]);
|
|
8548
|
-
return (0, react.createElement)("span", {
|
|
8549
|
-
ref: anchorRef,
|
|
8550
|
-
className: ANCHOR_CLASS,
|
|
8551
|
-
hidden: true,
|
|
8552
|
-
"aria-hidden": "true"
|
|
8553
|
-
});
|
|
8554
|
-
};
|
|
8764
|
+
} catch {
|
|
8765
|
+
return;
|
|
8766
|
+
}
|
|
8767
|
+
});
|
|
8555
8768
|
}
|
|
8556
8769
|
//#endregion
|
|
8557
8770
|
//#region src/client/viewkit.ts
|
|
@@ -8570,7 +8783,7 @@ window.__ModuleLoader__.load({
|
|
|
8570
8783
|
}
|
|
8571
8784
|
//#endregion
|
|
8572
8785
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/base.css.mjs
|
|
8573
|
-
const css$13 = ".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-root .lc-card{margin-bottom:7px;padding:7px 8px;container:lc-card/inline-size}.lc-root .lc-cols{gap:7px;margin-bottom:7px}.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-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;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);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-tip{z-index:6;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-shadow-lv3,0 2px 8px #0000002e);pointer-events:none;opacity:0;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;padding:6px 10px;font-size:12px;position:absolute}.lc-events,.lc-fa-list{flex-direction:column;gap:2px;height:320px;display:flex;overflow-y:auto}.lc-cols{flex-wrap:wrap;gap:14px;margin-bottom:14px;display:flex}.lc-col{flex:1;min-width:min(
|
|
8786
|
+
const css$13 = ".lc-root{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-primary);padding:16px 20px 32px;font-size:13px;overflow-y:auto}[data-sidebar-right-open] .lc-root,[data-sidebar-right-float-host] .lc-root{height:auto;padding:0;overflow:visible}.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-root .lc-card{margin-bottom:7px;padding:7px 8px;container:lc-card/inline-size}.lc-root .lc-cols{gap:7px;margin-bottom:7px}.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-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-trend-adaptive{flex:none;margin-left:0}.lc-gran-btn{color:var(--dsw-alias-label-secondary);cursor:pointer;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);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-tip{z-index:6;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-shadow-lv3,0 2px 8px #0000002e);pointer-events:none;opacity:0;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;padding:6px 10px;font-size:12px;position:absolute}.lc-events,.lc-fa-list{flex-direction:column;gap:2px;height:320px;display:flex;overflow-y:auto}.lc-cols{flex-wrap:wrap;gap:14px;margin-bottom:14px;display:flex}.lc-col{flex:1;min-width:min(360px,100%)}.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{container:lc-head-row/inline-size}.lc-head>.lc-card{flex:1 1 0;min-width:0}@container lc-head-row (width<=1045px){.lc-head>.lc-card{flex-basis:40%}}@container lc-head-row (width<=480px){.lc-head>.lc-card{flex-basis:100%}}.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-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{font-family:var(--ds-font-family-code,ui-monospace, SFMono-Regular, Menlo, monospace);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-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;transition:border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);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}[data-conversation-scroll]:has(.lc-root)>[data-composer-seat]:not(:has([data-approval-key],[data-question-key],[data-plan-review-key])),[data-conversation-scroll]:has(.lc-root,.lc-modal-backdrop)~[data-width-handle]{display:none}";
|
|
8574
8787
|
const tagId$13 = "dsh-context/base.css";
|
|
8575
8788
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$13) + "]") === null) {
|
|
8576
8789
|
const tag = document.createElement("style");
|
|
@@ -8592,7 +8805,7 @@ window.__ModuleLoader__.load({
|
|
|
8592
8805
|
}
|
|
8593
8806
|
//#endregion
|
|
8594
8807
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/jump.css.mjs
|
|
8595
|
-
const css$11 = ".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;transition:background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);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)}
|
|
8808
|
+
const css$11 = ".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;transition:background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);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)}";
|
|
8596
8809
|
const tagId$11 = "dsh-context/jump.css";
|
|
8597
8810
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$11) + "]") === null) {
|
|
8598
8811
|
const tag = document.createElement("style");
|
|
@@ -8625,7 +8838,7 @@ window.__ModuleLoader__.load({
|
|
|
8625
8838
|
}
|
|
8626
8839
|
//#endregion
|
|
8627
8840
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/trendChart.css.mjs
|
|
8628
|
-
const css$8 = ".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-q3{top:41px}.lc-axis-mid{top:69px}.lc-axis-q1{top:97px}.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-l2);pointer-events:none;position:absolute;left:0;right:0}.lc-grid-top{top:18px}.lc-grid-q3{top:46px}.lc-grid-mid{top:74px}.lc-grid-q1{top:102px}.lc-grid-zero{border-top-style:solid;border-top-color:#80808080;top:130px}.lc-bar{cursor:pointer;outline-offset:1px;width:14px;height:100%;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), outline-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:2px;outline:1px dashed #0000;flex:none;align-items:flex-end;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;box-sizing:border-box;overflow-wrap:break-word;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);max-width:100%;color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;flex-direction:column;gap:2px;padding:3px 8px;font-size:12px;display:flex;position:absolute;bottom:calc(100% + 4px);left:0;box-shadow:0 2px 8px #0000002e}.lc-bar:hover{background:var(--dsw-alias-bg-layer-2)}.lc-bar-hovered{outline-color:var(--dsw-alias-brand-primary)}.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 var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.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;overflow:hidden}.lc-turn{box-sizing:border-box;text-align:center;color:var(--dsw-alias-label-secondary);white-space:nowrap;cursor:pointer;height:14px;transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:3px;flex:none;font-size:10px;font-weight:600;line-height:14px}.lc-turn-on{filter:brightness(1.35);color:var(--dsw-alias-label-primary)}.lc-turn-label{display:inline-block}";
|
|
8841
|
+
const css$8 = ".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-q3{top:41px}.lc-axis-mid{top:69px}.lc-axis-q1{top:97px}.lc-axis-bot{top:125px}.lc-chart-wrap{flex:1;min-width:0;position:relative}.lc-chart-scroll{overscroll-behavior-x:contain;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-l2);pointer-events:none;position:absolute;left:0;right:0}.lc-grid-top{top:18px}.lc-grid-q3{top:46px}.lc-grid-mid{top:74px}.lc-grid-q1{top:102px}.lc-grid-zero{border-top-style:solid;border-top-color:#80808080;top:130px}.lc-bar{cursor:pointer;outline-offset:1px;width:14px;height:100%;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), outline-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:2px;outline:1px dashed #0000;flex:none;align-items:flex-end;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;box-sizing:border-box;overflow-wrap:break-word;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);max-width:100%;color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;flex-direction:column;gap:2px;padding:3px 8px;font-size:12px;display:flex;position:absolute;bottom:calc(100% + 4px);left:0;box-shadow:0 2px 8px #0000002e}.lc-bar:hover{background:var(--dsw-alias-bg-layer-2)}.lc-bar-hovered{outline-color:var(--dsw-alias-brand-primary)}.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 var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.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;overflow:hidden}.lc-turn{box-sizing:border-box;text-align:center;color:var(--dsw-alias-label-secondary);white-space:nowrap;cursor:pointer;height:14px;transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:3px;flex:none;font-size:10px;font-weight:600;line-height:14px}.lc-turn-on{filter:brightness(1.35);color:var(--dsw-alias-label-primary)}.lc-turn-label{display:inline-block}";
|
|
8629
8842
|
const tagId$8 = "dsh-context/trendChart.css";
|
|
8630
8843
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$8) + "]") === null) {
|
|
8631
8844
|
const tag = document.createElement("style");
|
|
@@ -8713,7 +8926,7 @@ window.__ModuleLoader__.load({
|
|
|
8713
8926
|
}
|
|
8714
8927
|
//#endregion
|
|
8715
8928
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/agentGraph.css.mjs
|
|
8716
|
-
const css = ".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 var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.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}";
|
|
8929
|
+
const css = ".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{overscroll-behavior-x:contain;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 var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.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}";
|
|
8717
8930
|
const tagId = "dsh-context/agentGraph.css";
|
|
8718
8931
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
8719
8932
|
const tag = document.createElement("style");
|
|
@@ -8769,6 +8982,7 @@ window.__ModuleLoader__.load({
|
|
|
8769
8982
|
label: () => t("tab")
|
|
8770
8983
|
}, (props) => (0, react.createElement)(ContextView, props));
|
|
8771
8984
|
});
|
|
8985
|
+
watchSidebarContextTab(ctx, ContextView, t, NS);
|
|
8772
8986
|
const ContextJump = makeContextJumpButton(kit);
|
|
8773
8987
|
ctx.slots.inject("conversation.chat.assistant-actions", () => {
|
|
8774
8988
|
return ctx.slots.register({
|
|
@@ -8778,15 +8992,6 @@ window.__ModuleLoader__.load({
|
|
|
8778
8992
|
locale: NS
|
|
8779
8993
|
}, (props) => (0, react.createElement)(ContextJump, props));
|
|
8780
8994
|
});
|
|
8781
|
-
const StatsJump = makeStatsJump(kit);
|
|
8782
|
-
ctx.slots.inject("conversation.composer.dock", () => {
|
|
8783
|
-
return ctx.slots.register({
|
|
8784
|
-
name: "conversation.composer.dock",
|
|
8785
|
-
id: "stats-jump",
|
|
8786
|
-
order: 10,
|
|
8787
|
-
locale: NS
|
|
8788
|
-
}, (props) => (0, react.createElement)(StatsJump, props));
|
|
8789
|
-
});
|
|
8790
8995
|
registerContextCommand(ctx, kit);
|
|
8791
8996
|
const ContextModal = makeContextModal(ctx, kit);
|
|
8792
8997
|
ctx.slots.inject("conversation.input.overlay", () => {
|