dsh-context 0.8.0 → 0.9.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/lib/client.js +226 -439
- package/lib/index.js +269 -210
- package/package.json +9 -2
package/lib/client.js
CHANGED
|
@@ -20,6 +20,7 @@ var DICT_ZH = {
|
|
|
20
20
|
"overview.estimate": "tokens\uFF08\u4F30\u7B97\uFF09",
|
|
21
21
|
"overview.free": "\u5269\u4F59\u7A97\u53E3",
|
|
22
22
|
"overview.splitEst": "\xB7 \u5206\u7C7B\u6309\u4F30\u7B97\u6BD4\u4F8B\u5206\u914D",
|
|
23
|
+
"overview.ofUsed": "\u5360\u5DF2\u7528\u4E0A\u4E0B\u6587",
|
|
23
24
|
"stats.title": "\u4E0A\u4E0B\u6587\u7EDF\u8BA1",
|
|
24
25
|
"stats.hint": "\u7EDF\u8BA1\u5F53\u524D\u4FDD\u7559\u7684\u5386\u53F2\u7A97\u53E3\uFF08\u4E0E\u8D8B\u52BF\u56FE\u4E00\u81F4\uFF09",
|
|
25
26
|
"stats.turns": "\u8F6E\u6B21",
|
|
@@ -90,6 +91,7 @@ var DICT_EN = {
|
|
|
90
91
|
"overview.estimate": "tokens (estimated)",
|
|
91
92
|
"overview.free": "Free window",
|
|
92
93
|
"overview.splitEst": "\xB7 category split is estimated",
|
|
94
|
+
"overview.ofUsed": "of used context",
|
|
93
95
|
"stats.title": "Context stats",
|
|
94
96
|
"stats.hint": "Over the retained history window (same as the History chart)",
|
|
95
97
|
"stats.turns": "Turns",
|
|
@@ -167,11 +169,25 @@ var STYLES = [
|
|
|
167
169
|
".lc-overview-num b { font-size: 20px; }",
|
|
168
170
|
".lc-overview-num span { color: var(--dsw-alias-label-secondary); }",
|
|
169
171
|
".lc-stacked-wrap { position: relative; width: 100%; }",
|
|
170
|
-
".lc-stacked { display: flex; width: 100%; border-radius: 5px; overflow: hidden; background: rgba(128,128,128,0.18); }",
|
|
172
|
+
".lc-stacked { display: flex; width: 100%; border-radius: 5px; overflow: hidden; background: rgba(128,128,128,0.18); position: relative; }",
|
|
173
|
+
// Hover reference frame around the OCCUPIED region of the composition bar:
|
|
174
|
+
// dashes from the left edge to the used/window boundary, so the legend's
|
|
175
|
+
// "share of used" percentages visibly map to the boxed part (the free track
|
|
176
|
+
// sits outside it). pointer-events: none keeps hover on the segments/free.
|
|
177
|
+
// Deliberately high-contrast (label-primary) and thick so the frame reads at
|
|
178
|
+
// a glance, and the other parts dim underneath it (`.lc-stacked-dim`).
|
|
179
|
+
".lc-occupied-box { position: absolute; top: 0; bottom: 0; left: 0; border: 2px dashed var(--dsw-alias-label-primary); border-radius: 5px; box-sizing: border-box; pointer-events: none; opacity: 1; box-shadow: 0 0 0 1px var(--dsw-alias-bg-layer-2); }",
|
|
171
180
|
".lc-bar-tip { position: absolute; bottom: calc(100% + 6px); transform: translateX(-50%); z-index: 5; white-space: nowrap; background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; padding: 3px 8px; font-size: 12px; color: var(--dsw-alias-label-primary); box-shadow: 0 2px 8px rgba(0,0,0,0.18); pointer-events: none; }",
|
|
172
181
|
".lc-stacked > div { height: 100%; }",
|
|
173
182
|
".lc-stacked-seg-on { filter: brightness(1.18); }",
|
|
174
183
|
".lc-stacked-free-on { box-shadow: inset 0 0 0 1px var(--dsw-alias-label-secondary); border-radius: 3px; }",
|
|
184
|
+
// Hover focus: everything except the hovered part (segment, legend chip, or
|
|
185
|
+
// free track) recedes, so the composition highlight and the occupied-region
|
|
186
|
+
// frame read clearly. The selected segment/free keeps full opacity.
|
|
187
|
+
".lc-stacked-dim .lc-stacked-seg { opacity: 0.35; }",
|
|
188
|
+
".lc-stacked-dim .lc-stacked-seg-on { opacity: 1; }",
|
|
189
|
+
".lc-stacked-dim .lc-stacked-free { opacity: 0.35; }",
|
|
190
|
+
".lc-stacked-dim .lc-stacked-free-on { opacity: 1; }",
|
|
175
191
|
".lc-legend { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 10px; }",
|
|
176
192
|
".lc-chip { display: inline-flex; align-items: center; gap: 5px; color: var(--dsw-alias-label-primary); }",
|
|
177
193
|
".lc-chip i, .lc-detail-row i, .lc-node i { display: inline-block; width: 8px; height: 8px; border-radius: 2px; }",
|
|
@@ -250,20 +266,6 @@ var STYLES = [
|
|
|
250
266
|
".lc-foot { color: var(--dsw-alias-label-secondary); font-size: 12px; margin-top: 4px; }"
|
|
251
267
|
].join("\n");
|
|
252
268
|
|
|
253
|
-
// src/client/cache.ts
|
|
254
|
-
var MAX_CACHED_SESSIONS = 10;
|
|
255
|
-
var sessionCache = /* @__PURE__ */ new Map();
|
|
256
|
-
function cacheGet(sessionId) {
|
|
257
|
-
return sessionCache.get(sessionId);
|
|
258
|
-
}
|
|
259
|
-
function cachePut(sessionId, snapshot) {
|
|
260
|
-
sessionCache.set(sessionId, snapshot);
|
|
261
|
-
if (sessionCache.size > MAX_CACHED_SESSIONS) {
|
|
262
|
-
const oldest = sessionCache.keys().next().value;
|
|
263
|
-
if (oldest !== void 0) sessionCache.delete(oldest);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
269
|
// src/client/categories.ts
|
|
268
270
|
var CATS = [
|
|
269
271
|
{ key: "system", color: "#6366f1" },
|
|
@@ -287,6 +289,15 @@ function anchoredParts(parts, target) {
|
|
|
287
289
|
return parts.map((p) => ({ ...p, value: Math.round(p.value * scale) }));
|
|
288
290
|
}
|
|
289
291
|
|
|
292
|
+
// src/client/services.ts
|
|
293
|
+
function timelineOf(value) {
|
|
294
|
+
if (value === null || value === void 0 || typeof value !== "object") return null;
|
|
295
|
+
return value;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// src/client/components/events.tsx
|
|
299
|
+
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
300
|
+
|
|
290
301
|
// src/client/format.ts
|
|
291
302
|
function fmt(n) {
|
|
292
303
|
if (n === void 0 || n === null || isNaN(n)) return "\u2014";
|
|
@@ -306,7 +317,7 @@ function fmtTime(t) {
|
|
|
306
317
|
var React = require("react");
|
|
307
318
|
var h = React.createElement;
|
|
308
319
|
|
|
309
|
-
// src/client/components/events.
|
|
320
|
+
// src/client/components/events.tsx
|
|
310
321
|
var EVENT_ICONS = { compaction: "\u2702", prune: "\u2702", inject: "\uFF0B", model: "\u21C4" };
|
|
311
322
|
function makeEventText(t, tr) {
|
|
312
323
|
function eventLabel(ev) {
|
|
@@ -342,34 +353,19 @@ function makeEventList(kit) {
|
|
|
342
353
|
const { t, fmt: fmt3, fmtTime: fmtTime2, eventLabel, eventAt } = kit;
|
|
343
354
|
return function EventList(props) {
|
|
344
355
|
if (props.events.length === 0) {
|
|
345
|
-
return
|
|
356
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-empty" }, t("events.empty"));
|
|
346
357
|
}
|
|
347
358
|
const sorted = props.events.slice().reverse();
|
|
348
|
-
return
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
return h(
|
|
355
|
-
"div",
|
|
356
|
-
{ key: ev.seq + "-" + i, className: "lc-event" },
|
|
357
|
-
h("span", { className: "lc-event-icon lc-event-" + ev.kind }, EVENT_ICONS[ev.kind] || "\u2022"),
|
|
358
|
-
h("span", { className: "lc-event-label", title: label }, label),
|
|
359
|
-
at !== null ? h("span", { className: "lc-event-at" }, at) : null,
|
|
360
|
-
ev.tokens ? h(
|
|
361
|
-
"span",
|
|
362
|
-
{ className: "lc-event-tokens" + (ev.kind === "inject" ? " lc-up" : " lc-down") },
|
|
363
|
-
(ev.kind === "inject" ? "+" : "\u2212") + fmt3(ev.tokens)
|
|
364
|
-
) : null,
|
|
365
|
-
h("span", { className: "lc-event-time" }, fmtTime2(ev.time))
|
|
366
|
-
);
|
|
367
|
-
})
|
|
368
|
-
);
|
|
359
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-events" }, sorted.map((ev, i) => {
|
|
360
|
+
const label = eventLabel(ev);
|
|
361
|
+
const at = eventAt(ev);
|
|
362
|
+
const glyph = ev.kind === "inject" ? /* @__PURE__ */ React.createElement(import_dsh_client_ui_primitives.IconPlusOutline16, null) : ev.kind === "model" ? /* @__PURE__ */ React.createElement(import_dsh_client_ui_primitives.IconBranchOutline16, null) : EVENT_ICONS[ev.kind] || "\u2022";
|
|
363
|
+
return /* @__PURE__ */ React.createElement("div", { key: ev.seq + "-" + i, className: "lc-event" }, /* @__PURE__ */ React.createElement("span", { className: "lc-event-icon lc-event-" + ev.kind }, glyph), /* @__PURE__ */ React.createElement("span", { className: "lc-event-label", title: label }, label), at !== null ? /* @__PURE__ */ React.createElement("span", { className: "lc-event-at" }, at) : null, ev.tokens ? /* @__PURE__ */ React.createElement("span", { className: "lc-event-tokens" + (ev.kind === "inject" ? " lc-up" : " lc-down") }, (ev.kind === "inject" ? "+" : "\u2212") + fmt3(ev.tokens)) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-event-time" }, fmtTime2(ev.time)));
|
|
364
|
+
}));
|
|
369
365
|
};
|
|
370
366
|
}
|
|
371
367
|
|
|
372
|
-
// src/client/components/nodes.
|
|
368
|
+
// src/client/components/nodes.tsx
|
|
373
369
|
function makeNodeList(kit) {
|
|
374
370
|
const { t, tr, fmt: fmt3, fmtTime: fmtTime2 } = kit;
|
|
375
371
|
function nodeText(n) {
|
|
@@ -385,32 +381,19 @@ function makeNodeList(kit) {
|
|
|
385
381
|
}
|
|
386
382
|
return function NodeList(props) {
|
|
387
383
|
if (props.nodes.length === 0) {
|
|
388
|
-
return
|
|
384
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-empty" }, t("nodes.empty"));
|
|
389
385
|
}
|
|
390
386
|
const catColor = {};
|
|
391
387
|
for (const c of CATS) catColor[c.key] = c.color;
|
|
392
388
|
const rows = props.nodes.slice().reverse();
|
|
393
|
-
return
|
|
394
|
-
|
|
395
|
-
{ className: "lc-
|
|
396
|
-
|
|
397
|
-
rows.map((n) => {
|
|
398
|
-
const text = nodeText(n);
|
|
399
|
-
return h(
|
|
400
|
-
"div",
|
|
401
|
-
{ key: n.seq, className: "lc-node" },
|
|
402
|
-
h("i", { style: { background: catColor[n.cat] || "#999" } }),
|
|
403
|
-
h("span", { className: "lc-node-preview", title: text }, text),
|
|
404
|
-
// Timestamp when the host event carried one.
|
|
405
|
-
typeof n.time === "number" ? h("span", { className: "lc-node-time" }, fmtTime2(n.time)) : null,
|
|
406
|
-
h("span", { className: "lc-node-tokens" }, fmt3(n.tokens))
|
|
407
|
-
);
|
|
408
|
-
})
|
|
409
|
-
);
|
|
389
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-nodes" }, props.dropped > 0 ? /* @__PURE__ */ React.createElement("div", { className: "lc-nodes-more" }, tr("nodes.more", { n: props.dropped })) : null, rows.map((n) => {
|
|
390
|
+
const text = nodeText(n);
|
|
391
|
+
return /* @__PURE__ */ React.createElement("div", { key: n.seq, className: "lc-node" }, /* @__PURE__ */ React.createElement("i", { style: { background: catColor[n.cat] || "#999" } }), /* @__PURE__ */ React.createElement("span", { className: "lc-node-preview", title: text }, text), typeof n.time === "number" ? /* @__PURE__ */ React.createElement("span", { className: "lc-node-time" }, fmtTime2(n.time)) : null, /* @__PURE__ */ React.createElement("span", { className: "lc-node-tokens" }, fmt3(n.tokens)));
|
|
392
|
+
}));
|
|
410
393
|
};
|
|
411
394
|
}
|
|
412
395
|
|
|
413
|
-
// src/client/components/requestDetail.
|
|
396
|
+
// src/client/components/requestDetail.tsx
|
|
414
397
|
function makeRequestDetail(kit, StackedBar) {
|
|
415
398
|
const { t, tr, fmt: fmt3, fmtTime: fmtTime2, catLabel, eventLabel, eventAt } = kit;
|
|
416
399
|
return function RequestDetail(props) {
|
|
@@ -420,46 +403,14 @@ function makeRequestDetail(kit, StackedBar) {
|
|
|
420
403
|
const head = isTurn ? tr("detail.turn", { t: req.turn ?? 0, n: req.stepCount ?? 0 }) : tr("detail.step", { t: req.turn ?? 0, s: req.step ?? 0 });
|
|
421
404
|
const marker = props.marker ?? null;
|
|
422
405
|
const markerAt = marker !== null ? eventAt(marker) : null;
|
|
423
|
-
return
|
|
424
|
-
|
|
425
|
-
{ className: "lc-detail" },
|
|
426
|
-
|
|
427
|
-
"div",
|
|
428
|
-
{ className: "lc-detail-head" },
|
|
429
|
-
h("b", null, head),
|
|
430
|
-
marker !== null && markerAt !== null ? h("span", { className: "lc-detail-marker", title: eventLabel(marker) }, "\u2702 " + markerAt) : null,
|
|
431
|
-
isTurn ? h("span", { className: "lc-detail-tag" }, t("detail.lastStep")) : null,
|
|
432
|
-
h("span", null, fmtTime2(req.time)),
|
|
433
|
-
h("span", null, tr("detail.estTotal", { n: fmt3(req.total) })),
|
|
434
|
-
req.prompt !== void 0 ? h("span", { className: "lc-actual" }, tr("detail.actual", { n: fmt3(req.prompt) })) : null,
|
|
435
|
-
req.output !== void 0 ? h("span", null, tr("detail.output", { n: fmt3(req.output) })) : null
|
|
436
|
-
),
|
|
437
|
-
h(StackedBar, { parts: partsOf(req), height: 10 }),
|
|
438
|
-
h(
|
|
439
|
-
"div",
|
|
440
|
-
{ className: "lc-detail-rows" },
|
|
441
|
-
CATS.map((c) => {
|
|
442
|
-
const v = req[c.key] || 0;
|
|
443
|
-
return h(
|
|
444
|
-
"div",
|
|
445
|
-
{ key: c.key, className: "lc-detail-row" },
|
|
446
|
-
h("i", { style: { background: c.color } }),
|
|
447
|
-
h("span", { className: "lc-detail-label" }, catLabel(c.key)),
|
|
448
|
-
h(
|
|
449
|
-
"span",
|
|
450
|
-
{ className: "lc-bar-track" },
|
|
451
|
-
h("span", { className: "lc-bar-fill", style: { width: (req.total > 0 ? v / req.total * 100 : 0) + "%", background: c.color } })
|
|
452
|
-
),
|
|
453
|
-
h("span", { className: "lc-detail-num" }, "\u2248" + fmt3(v)),
|
|
454
|
-
h("span", { className: "lc-detail-pct" }, req.total > 0 ? Math.round(v / req.total * 100) + "%" : "")
|
|
455
|
-
);
|
|
456
|
-
})
|
|
457
|
-
)
|
|
458
|
-
);
|
|
406
|
+
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", { className: "lc-detail-marker", title: eventLabel(marker) }, "\u2702 " + markerAt) : null, isTurn ? /* @__PURE__ */ React.createElement("span", { className: "lc-detail-tag" }, t("detail.lastStep")) : null, /* @__PURE__ */ React.createElement("span", null, fmtTime2(req.time)), /* @__PURE__ */ React.createElement("span", null, tr("detail.estTotal", { n: fmt3(req.total) })), req.prompt !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-actual" }, tr("detail.actual", { n: fmt3(req.prompt) })) : null, req.output !== void 0 ? /* @__PURE__ */ React.createElement("span", null, tr("detail.output", { n: fmt3(req.output) })) : null), /* @__PURE__ */ React.createElement(StackedBar, { parts: partsOf(req), height: 10 }), /* @__PURE__ */ React.createElement("div", { className: "lc-detail-rows" }, CATS.map((c) => {
|
|
407
|
+
const v = req[c.key] || 0;
|
|
408
|
+
return /* @__PURE__ */ React.createElement("div", { key: c.key, className: "lc-detail-row" }, /* @__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" }, /* @__PURE__ */ React.createElement("span", { className: "lc-bar-fill", style: { width: (req.total > 0 ? v / req.total * 100 : 0) + "%", background: c.color } })), /* @__PURE__ */ React.createElement("span", { className: "lc-detail-num" }, "\u2248" + fmt3(v)), /* @__PURE__ */ React.createElement("span", { className: "lc-detail-pct" }, req.total > 0 ? Math.round(v / req.total * 100) + "%" : ""));
|
|
409
|
+
})));
|
|
459
410
|
};
|
|
460
411
|
}
|
|
461
412
|
|
|
462
|
-
// src/client/components/statsBoard.
|
|
413
|
+
// src/client/components/statsBoard.tsx
|
|
463
414
|
function makeStatsBoard(kit) {
|
|
464
415
|
const { t, tr, fmt: fmt3 } = kit;
|
|
465
416
|
return function StatsBoard(props) {
|
|
@@ -483,50 +434,26 @@ function makeStatsBoard(kit) {
|
|
|
483
434
|
} else if (ev.kind === "inject") injects++;
|
|
484
435
|
else if (ev.kind === "model") switches++;
|
|
485
436
|
}
|
|
486
|
-
const cell = (label, value, sub) =>
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
);
|
|
493
|
-
return h(
|
|
494
|
-
"div",
|
|
495
|
-
{ className: "lc-card" },
|
|
496
|
-
h(
|
|
497
|
-
"div",
|
|
498
|
-
{ className: "lc-card-title" },
|
|
499
|
-
t("stats.title"),
|
|
500
|
-
h("span", { className: "lc-card-sub" }, t("stats.hint"))
|
|
501
|
-
),
|
|
502
|
-
h(
|
|
503
|
-
"div",
|
|
504
|
-
{ className: "lc-stats" },
|
|
505
|
-
cell(t("stats.turns"), fmt3(turns.size)),
|
|
506
|
-
cell(t("stats.steps"), fmt3(steps)),
|
|
507
|
-
cell(
|
|
508
|
-
t("stats.recycled"),
|
|
509
|
-
recycled > 0 ? "\u2212" + fmt3(recycled) : "0",
|
|
510
|
-
tr("stats.recycleSub", { c: compactions, p: prunes })
|
|
511
|
-
),
|
|
512
|
-
cell(t("stats.injects"), fmt3(injects)),
|
|
513
|
-
cell(t("stats.switches"), fmt3(switches)),
|
|
514
|
-
cell(t("stats.est"), "\u2248 " + fmt3(est)),
|
|
515
|
-
cell(t("stats.actualPrompt"), fmt3(prompt)),
|
|
516
|
-
cell(t("stats.output"), fmt3(output))
|
|
517
|
-
)
|
|
518
|
-
);
|
|
437
|
+
const cell = (label, value, sub) => /* @__PURE__ */ React.createElement("div", { className: "lc-stat" }, /* @__PURE__ */ React.createElement("span", { className: "lc-stat-label" }, label), /* @__PURE__ */ React.createElement("b", { className: "lc-stat-value" }, value), sub !== void 0 ? /* @__PURE__ */ React.createElement("span", { className: "lc-stat-sub" }, sub) : null);
|
|
438
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, 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"), fmt3(turns.size)), cell(t("stats.steps"), fmt3(steps)), cell(
|
|
439
|
+
t("stats.recycled"),
|
|
440
|
+
recycled > 0 ? "\u2212" + fmt3(recycled) : "0",
|
|
441
|
+
tr("stats.recycleSub", { c: compactions, p: prunes })
|
|
442
|
+
), cell(t("stats.injects"), fmt3(injects)), cell(t("stats.switches"), fmt3(switches)), cell(t("stats.est"), "\u2248 " + fmt3(est)), cell(t("stats.actualPrompt"), fmt3(prompt)), cell(t("stats.output"), fmt3(output))));
|
|
519
443
|
};
|
|
520
444
|
}
|
|
521
445
|
|
|
522
|
-
// src/client/components/stackedBar.
|
|
446
|
+
// src/client/components/stackedBar.tsx
|
|
523
447
|
function makeStackedBar(kit) {
|
|
524
|
-
const { t, fmt: fmt3, catLabel } = kit;
|
|
448
|
+
const { t, tr, fmt: fmt3, catLabel } = kit;
|
|
525
449
|
return function StackedBar(props) {
|
|
526
450
|
let total = 0;
|
|
527
451
|
for (const p of props.parts) total += p.value;
|
|
528
452
|
const scale = props.max !== void 0 && props.max > total ? props.max : total;
|
|
529
453
|
const free = props.max !== void 0 && props.max > total ? props.max - total : 0;
|
|
454
|
+
const usedPct = scale > 0 ? total / scale * 100 : 0;
|
|
455
|
+
const hovering = props.hoverKey !== null && props.hoverKey !== void 0;
|
|
456
|
+
const showBox = free > 0 && hovering;
|
|
530
457
|
let tip = null;
|
|
531
458
|
if (props.hoverKey !== null && props.hoverKey !== void 0) {
|
|
532
459
|
if (props.hoverKey === "free" && free > 0) {
|
|
@@ -541,7 +468,9 @@ function makeStackedBar(kit) {
|
|
|
541
468
|
const pct = scale > 0 ? p.value / scale * 100 : 0;
|
|
542
469
|
if (p.key === props.hoverKey && p.value > 0) {
|
|
543
470
|
tip = {
|
|
544
|
-
|
|
471
|
+
// "(pct%)" is a share of the OCCUPIED total — the dashed box
|
|
472
|
+
// that appears on hover frames exactly this reference region.
|
|
473
|
+
text: catLabel(p.key) + " \u2248" + fmt3(p.value) + " (" + Math.round(p.value / total * 100) + "%) " + tr("overview.ofUsed"),
|
|
545
474
|
leftPct: Math.max(12, Math.min(acc + pct / 2, 88))
|
|
546
475
|
};
|
|
547
476
|
break;
|
|
@@ -550,75 +479,74 @@ function makeStackedBar(kit) {
|
|
|
550
479
|
}
|
|
551
480
|
}
|
|
552
481
|
}
|
|
553
|
-
return
|
|
482
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-stacked-wrap" }, /* @__PURE__ */ React.createElement(
|
|
554
483
|
"div",
|
|
555
|
-
{
|
|
556
|
-
|
|
557
|
-
"
|
|
558
|
-
{
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
return h("div", {
|
|
484
|
+
{
|
|
485
|
+
className: "lc-stacked" + (hovering ? " lc-stacked-dim" : ""),
|
|
486
|
+
style: { height: (props.height || 14) + "px" },
|
|
487
|
+
onMouseLeave: () => {
|
|
488
|
+
if (props.onHoverKey !== void 0) props.onHoverKey(null);
|
|
489
|
+
}
|
|
490
|
+
},
|
|
491
|
+
total > 0 ? props.parts.map((p) => {
|
|
492
|
+
if (!p.value) return null;
|
|
493
|
+
const on = props.hoverKey !== void 0 && props.hoverKey === p.key;
|
|
494
|
+
return /* @__PURE__ */ React.createElement(
|
|
495
|
+
"div",
|
|
496
|
+
{
|
|
569
497
|
key: p.key,
|
|
570
498
|
className: "lc-stacked-seg" + (on ? " lc-stacked-seg-on" : ""),
|
|
571
499
|
style: { width: p.value / scale * 100 + "%", background: p.color },
|
|
572
500
|
onMouseEnter: () => {
|
|
573
501
|
if (props.onHoverKey !== void 0) props.onHoverKey(p.key);
|
|
574
502
|
}
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
|
|
503
|
+
}
|
|
504
|
+
);
|
|
505
|
+
}) : null,
|
|
506
|
+
free > 0 ? /* @__PURE__ */ React.createElement(
|
|
507
|
+
"div",
|
|
508
|
+
{
|
|
578
509
|
key: "free",
|
|
579
510
|
className: "lc-stacked-free" + (props.hoverKey === "free" ? " lc-stacked-free-on" : ""),
|
|
580
511
|
style: { width: free / scale * 100 + "%" },
|
|
581
512
|
onMouseEnter: () => {
|
|
582
513
|
if (props.onHoverKey !== void 0) props.onHoverKey("free");
|
|
583
514
|
}
|
|
584
|
-
}
|
|
585
|
-
),
|
|
586
|
-
|
|
587
|
-
);
|
|
515
|
+
}
|
|
516
|
+
) : null,
|
|
517
|
+
showBox ? /* @__PURE__ */ React.createElement("div", { className: "lc-occupied-box", style: { width: usedPct + "%" } }) : null
|
|
518
|
+
), tip ? /* @__PURE__ */ React.createElement("div", { className: "lc-bar-tip", style: { left: tip.leftPct + "%" } }, tip.text) : null);
|
|
588
519
|
};
|
|
589
520
|
}
|
|
590
521
|
function makeLegend(kit) {
|
|
591
|
-
const { fmt: fmt3, catLabel } = kit;
|
|
522
|
+
const { tr, fmt: fmt3, catLabel } = kit;
|
|
592
523
|
return function Legend(props) {
|
|
593
524
|
let total = 0;
|
|
594
525
|
for (const p of props.parts) total += p.value;
|
|
595
|
-
return
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
"
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
onMouseEnter: () => {
|
|
606
|
-
if (props.onHoverKey !== void 0) props.onHoverKey(p.key);
|
|
607
|
-
},
|
|
608
|
-
onMouseLeave: () => {
|
|
609
|
-
if (props.onHoverKey !== void 0) props.onHoverKey(null);
|
|
610
|
-
}
|
|
526
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-legend" }, props.parts.map((p) => {
|
|
527
|
+
const on = props.hoverKey !== void 0 && props.hoverKey === p.key;
|
|
528
|
+
return /* @__PURE__ */ React.createElement(
|
|
529
|
+
"span",
|
|
530
|
+
{
|
|
531
|
+
key: p.key,
|
|
532
|
+
className: "lc-chip" + (on ? " lc-chip-on" : ""),
|
|
533
|
+
title: tr("overview.ofUsed"),
|
|
534
|
+
onMouseEnter: () => {
|
|
535
|
+
if (props.onHoverKey !== void 0) props.onHoverKey(p.key);
|
|
611
536
|
},
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
537
|
+
onMouseLeave: () => {
|
|
538
|
+
if (props.onHoverKey !== void 0) props.onHoverKey(null);
|
|
539
|
+
}
|
|
540
|
+
},
|
|
541
|
+
/* @__PURE__ */ React.createElement("i", { style: { background: p.color } }),
|
|
542
|
+
catLabel(p.key) + " \u2248" + fmt3(p.value),
|
|
543
|
+
total > 0 ? /* @__PURE__ */ React.createElement("em", null, Math.round(p.value / total * 100) + "%") : null
|
|
544
|
+
);
|
|
545
|
+
}));
|
|
618
546
|
};
|
|
619
547
|
}
|
|
620
548
|
|
|
621
|
-
// src/client/components/trendChart.
|
|
549
|
+
// src/client/components/trendChart.tsx
|
|
622
550
|
function aggregateByTurn(requests) {
|
|
623
551
|
const out = [];
|
|
624
552
|
let runSteps = 0;
|
|
@@ -707,121 +635,96 @@ function makeTrendChart(kit) {
|
|
|
707
635
|
};
|
|
708
636
|
const hoveredIdx = props.hoveredSeq !== null ? requests.findIndex((r) => r.seq === props.hoveredSeq) : -1;
|
|
709
637
|
const hoveredReq = hoveredIdx >= 0 ? requests[hoveredIdx] : null;
|
|
710
|
-
return
|
|
638
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-chartrow" }, /* @__PURE__ */ React.createElement("div", { className: "lc-axis" }, /* @__PURE__ */ React.createElement("span", { className: "lc-axis-top" }, fmt3(maxTotal)), /* @__PURE__ */ React.createElement("span", { className: "lc-axis-mid" }, fmt3(Math.round(maxTotal / 2))), /* @__PURE__ */ React.createElement("span", { className: "lc-axis-bot" }, "0")), /* @__PURE__ */ React.createElement(
|
|
711
639
|
"div",
|
|
712
|
-
{
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
),
|
|
720
|
-
|
|
640
|
+
{
|
|
641
|
+
className: "lc-chart-scroll" + (props.activeTurn !== null ? " lc-chart-dim" : ""),
|
|
642
|
+
ref: scrollRef,
|
|
643
|
+
onScroll: (e) => {
|
|
644
|
+
updateEdges(e.currentTarget);
|
|
645
|
+
}
|
|
646
|
+
},
|
|
647
|
+
edges.left ? /* @__PURE__ */ React.createElement("div", { className: "lc-chart-fade lc-chart-fade-l" }) : null,
|
|
648
|
+
/* @__PURE__ */ React.createElement(
|
|
721
649
|
"div",
|
|
722
650
|
{
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
ref: scrollRef,
|
|
727
|
-
onScroll: (e) => {
|
|
728
|
-
updateEdges(e.currentTarget);
|
|
651
|
+
className: "lc-chart",
|
|
652
|
+
onMouseLeave: () => {
|
|
653
|
+
props.onHover(null);
|
|
729
654
|
}
|
|
730
655
|
},
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
const marker = markers[i];
|
|
748
|
-
const markerAt = marker !== void 0 ? eventAt(marker) : null;
|
|
749
|
-
const selected = props.selectedSeq === req.seq;
|
|
750
|
-
const hovered = props.hoveredSeq === req.seq;
|
|
751
|
-
const inTurn = props.activeTurn !== null && (req.turn ?? 0) === props.activeTurn;
|
|
752
|
-
return h(
|
|
753
|
-
"div",
|
|
754
|
-
{
|
|
755
|
-
key: req.seq,
|
|
756
|
-
// Uniform column width in BOTH granularities: turn aggregates
|
|
757
|
-
// keep the same fixed width as step bars.
|
|
758
|
-
className: "lc-bar" + (selected ? " lc-bar-selected" : "") + (hovered ? " lc-bar-hovered" : "") + (inTurn ? " lc-bar-in-turn" : ""),
|
|
759
|
-
style: { width: BAR_W + "px" },
|
|
760
|
-
onClick: () => {
|
|
761
|
-
props.onSelect(selected ? null : req.seq);
|
|
762
|
-
},
|
|
763
|
-
onMouseEnter: () => {
|
|
764
|
-
props.onHover(req.seq);
|
|
765
|
-
}
|
|
656
|
+
/* @__PURE__ */ React.createElement("div", { className: "lc-grid lc-grid-top" }),
|
|
657
|
+
/* @__PURE__ */ React.createElement("div", { className: "lc-grid lc-grid-mid" }),
|
|
658
|
+
requests.map((req, i) => {
|
|
659
|
+
const marker = markers[i];
|
|
660
|
+
const markerAt = marker !== void 0 ? eventAt(marker) : null;
|
|
661
|
+
const selected = props.selectedSeq === req.seq;
|
|
662
|
+
const hovered = props.hoveredSeq === req.seq;
|
|
663
|
+
const inTurn = props.activeTurn !== null && (req.turn ?? 0) === props.activeTurn;
|
|
664
|
+
return /* @__PURE__ */ React.createElement(
|
|
665
|
+
"div",
|
|
666
|
+
{
|
|
667
|
+
key: req.seq,
|
|
668
|
+
className: "lc-bar" + (selected ? " lc-bar-selected" : "") + (hovered ? " lc-bar-hovered" : "") + (inTurn ? " lc-bar-in-turn" : ""),
|
|
669
|
+
style: { width: BAR_W + "px" },
|
|
670
|
+
onClick: () => {
|
|
671
|
+
props.onSelect(selected ? null : req.seq);
|
|
766
672
|
},
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
673
|
+
onMouseEnter: () => {
|
|
674
|
+
props.onHover(req.seq);
|
|
675
|
+
}
|
|
676
|
+
},
|
|
677
|
+
marker !== void 0 ? /* @__PURE__ */ React.createElement(
|
|
678
|
+
"span",
|
|
679
|
+
{
|
|
770
680
|
className: "lc-bar-marker",
|
|
771
681
|
title: "\u2702 " + (markerAt !== null ? markerAt + " \u2014 " : "") + eventLabel(marker)
|
|
772
|
-
}, "\u2702") : null,
|
|
773
|
-
h(
|
|
774
|
-
"div",
|
|
775
|
-
{ className: "lc-bar-stack" },
|
|
776
|
-
CATS.map((c) => {
|
|
777
|
-
const v = (req[c.key] || 0) * anchorOf(req);
|
|
778
|
-
if (!v) return null;
|
|
779
|
-
return h("div", { key: c.key, style: { height: Math.max(1, Math.round(v / maxTotal * CHART_H)) + "px", background: c.color } });
|
|
780
|
-
})
|
|
781
|
-
)
|
|
782
|
-
);
|
|
783
|
-
})
|
|
784
|
-
),
|
|
785
|
-
// Instant hover tooltip, glued to its bar's column (it lives in the
|
|
786
|
-
// scrolling content, so it follows the bar while the chart scrolls).
|
|
787
|
-
hoveredReq !== null ? h("div", {
|
|
788
|
-
className: "lc-chart-tip",
|
|
789
|
-
style: { left: hoveredIdx * (BAR_W + BAR_GAP) + BAR_W / 2 + "px" }
|
|
790
|
-
}, tipOf(hoveredReq)) : null,
|
|
791
|
-
// Turn strip: one COLOR BLOCK per turn, spanning exactly its bars'
|
|
792
|
-
// columns, so the partition reads at a glance and lines up with the
|
|
793
|
-
// steps above. Hovering a block highlights that turn's bars in the
|
|
794
|
-
// chart (and hovering a bar highlights its block — the active turn
|
|
795
|
-
// is shared hover-only state).
|
|
796
|
-
h(
|
|
797
|
-
"div",
|
|
798
|
-
{ className: "lc-turns", onMouseLeave: () => {
|
|
799
|
-
props.onHoverTurn(null);
|
|
800
|
-
} },
|
|
801
|
-
groups.map((grp, gi) => {
|
|
802
|
-
const on = props.activeTurn === grp.turn;
|
|
803
|
-
const blockW = grp.agg ? BAR_W : grp.span * (BAR_W + BAR_GAP) - BAR_GAP;
|
|
804
|
-
return h("span", {
|
|
805
|
-
key: "turn-" + gi,
|
|
806
|
-
className: "lc-turn" + (on ? " lc-turn-on" : ""),
|
|
807
|
-
style: {
|
|
808
|
-
width: blockW + "px",
|
|
809
|
-
background: TURN_COLORS[gi % TURN_COLORS.length]
|
|
810
682
|
},
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
683
|
+
"\u2702"
|
|
684
|
+
) : null,
|
|
685
|
+
/* @__PURE__ */ React.createElement("div", { className: "lc-bar-stack" }, CATS.map((c) => {
|
|
686
|
+
const v = (req[c.key] || 0) * anchorOf(req);
|
|
687
|
+
if (!v) return null;
|
|
688
|
+
return /* @__PURE__ */ React.createElement("div", { key: c.key, style: { height: Math.max(1, Math.round(v / maxTotal * CHART_H)) + "px", background: c.color } });
|
|
689
|
+
}))
|
|
690
|
+
);
|
|
691
|
+
})
|
|
818
692
|
),
|
|
819
|
-
|
|
820
|
-
|
|
693
|
+
hoveredReq !== null ? /* @__PURE__ */ React.createElement(
|
|
694
|
+
"div",
|
|
695
|
+
{
|
|
696
|
+
className: "lc-chart-tip",
|
|
697
|
+
style: { left: hoveredIdx * (BAR_W + BAR_GAP) + BAR_W / 2 + "px" }
|
|
698
|
+
},
|
|
699
|
+
tipOf(hoveredReq)
|
|
700
|
+
) : null,
|
|
701
|
+
/* @__PURE__ */ React.createElement("div", { className: "lc-turns", onMouseLeave: () => {
|
|
702
|
+
props.onHoverTurn(null);
|
|
703
|
+
} }, groups.map((grp, gi) => {
|
|
704
|
+
const on = props.activeTurn === grp.turn;
|
|
705
|
+
const blockW = grp.agg ? BAR_W : grp.span * (BAR_W + BAR_GAP) - BAR_GAP;
|
|
706
|
+
return /* @__PURE__ */ React.createElement(
|
|
707
|
+
"span",
|
|
708
|
+
{
|
|
709
|
+
key: "turn-" + gi,
|
|
710
|
+
className: "lc-turn" + (on ? " lc-turn-on" : ""),
|
|
711
|
+
style: {
|
|
712
|
+
width: blockW + "px",
|
|
713
|
+
background: TURN_COLORS[gi % TURN_COLORS.length]
|
|
714
|
+
},
|
|
715
|
+
title: "T" + grp.turn,
|
|
716
|
+
onMouseEnter: () => {
|
|
717
|
+
props.onHoverTurn(grp.turn);
|
|
718
|
+
}
|
|
719
|
+
},
|
|
720
|
+
"T" + grp.turn
|
|
721
|
+
);
|
|
722
|
+
}))
|
|
723
|
+
), edges.right ? /* @__PURE__ */ React.createElement("div", { className: "lc-chart-fade lc-chart-fade-r" }) : null);
|
|
821
724
|
};
|
|
822
725
|
}
|
|
823
726
|
|
|
824
|
-
// src/client/components/contextView.
|
|
727
|
+
// src/client/components/contextView.tsx
|
|
825
728
|
var viewScroll = /* @__PURE__ */ new Map();
|
|
826
729
|
function makeContextView(ctx, kit) {
|
|
827
730
|
const { t, tr, fmt: fmt3, fmtTime: fmtTime2, catLabel } = kit;
|
|
@@ -834,19 +737,13 @@ function makeContextView(ctx, kit) {
|
|
|
834
737
|
const StatsBoard = makeStatsBoard(kit);
|
|
835
738
|
return function ContextView(props) {
|
|
836
739
|
const sessionId = props.sessionId;
|
|
837
|
-
const
|
|
838
|
-
const [data, setData] = React.useState(initial);
|
|
839
|
-
const [error, setError] = React.useState(null);
|
|
740
|
+
const data = typeof props.useProjection === "function" ? timelineOf(props.useProjection("contextTimeline")) : null;
|
|
840
741
|
const [selectedSeq, setSelectedSeq] = React.useState(null);
|
|
841
742
|
const [hoveredSeq, setHoveredSeq] = React.useState(null);
|
|
842
743
|
const [hoverTurn, setHoverTurn] = React.useState(null);
|
|
843
744
|
const [tick, setTick] = React.useState(0);
|
|
844
745
|
const [granularity, setGranularity] = React.useState("step");
|
|
845
746
|
const [hoverCat, setHoverCat] = React.useState(null);
|
|
846
|
-
const dataRef = React.useRef(initial);
|
|
847
|
-
React.useEffect(() => {
|
|
848
|
-
dataRef.current = data;
|
|
849
|
-
}, [data]);
|
|
850
747
|
const rootRef = React.useRef(null);
|
|
851
748
|
const scrollerRef = React.useRef(null);
|
|
852
749
|
const restoredRef = React.useRef(null);
|
|
@@ -867,51 +764,14 @@ function makeContextView(ctx, kit) {
|
|
|
867
764
|
viewScroll.set(sessionId, scroller.scrollTop);
|
|
868
765
|
};
|
|
869
766
|
}, [sessionId]);
|
|
870
|
-
React.useEffect(() => {
|
|
871
|
-
if (typeof sessionId !== "string" || sessionId === "") return void 0;
|
|
872
|
-
let alive = true;
|
|
873
|
-
const load = () => {
|
|
874
|
-
ctx.connection.rpc.call("/dsh-context", "snapshot", { sessionId }).then((res) => {
|
|
875
|
-
if (!alive) return;
|
|
876
|
-
if (res && res.ok) {
|
|
877
|
-
const snap = res.value;
|
|
878
|
-
cachePut(sessionId, snap);
|
|
879
|
-
setData(snap);
|
|
880
|
-
setError(null);
|
|
881
|
-
} else if (dataRef.current === null) {
|
|
882
|
-
setError(res && res.error ? String(res.error.message || res.error.code) : "failed");
|
|
883
|
-
}
|
|
884
|
-
}, (err) => {
|
|
885
|
-
if (alive && dataRef.current === null) {
|
|
886
|
-
setError(String(err instanceof Error ? err.message : err));
|
|
887
|
-
}
|
|
888
|
-
});
|
|
889
|
-
};
|
|
890
|
-
load();
|
|
891
|
-
const timerId = setInterval(() => {
|
|
892
|
-
if (document.visibilityState !== "hidden") load();
|
|
893
|
-
}, 2e3);
|
|
894
|
-
const onVisible = () => {
|
|
895
|
-
if (document.visibilityState === "visible") load();
|
|
896
|
-
};
|
|
897
|
-
document.addEventListener("visibilitychange", onVisible);
|
|
898
|
-
return () => {
|
|
899
|
-
alive = false;
|
|
900
|
-
clearInterval(timerId);
|
|
901
|
-
document.removeEventListener("visibilitychange", onVisible);
|
|
902
|
-
};
|
|
903
|
-
}, [sessionId]);
|
|
904
767
|
React.useEffect(() => {
|
|
905
768
|
const localeSvc = ctx.get("locale");
|
|
906
769
|
if (!localeSvc) return void 0;
|
|
907
770
|
return localeSvc.subscribe(() => setTick((x) => x + 1));
|
|
908
771
|
}, []);
|
|
909
772
|
void tick;
|
|
910
|
-
if (error) {
|
|
911
|
-
return h("div", { className: "lc-root", ref: rootRef }, h("div", { className: "lc-empty" }, t("error") + error));
|
|
912
|
-
}
|
|
913
773
|
if (!data) {
|
|
914
|
-
return
|
|
774
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-root", ref: rootRef }, /* @__PURE__ */ React.createElement("div", { className: "lc-empty" }, t("loading")));
|
|
915
775
|
}
|
|
916
776
|
const current = data.current;
|
|
917
777
|
const requests = data.requests || [];
|
|
@@ -947,116 +807,41 @@ function makeContextView(ctx, kit) {
|
|
|
947
807
|
const headline = occupancyTokens ?? current.total;
|
|
948
808
|
const headlinePct = occupancyWindow ? Math.min(100, Math.round(headline / occupancyWindow * 100)) : null;
|
|
949
809
|
const parts = anchoredParts(partsOf(current), occupancyTokens !== null && headline > 0 ? headline : null);
|
|
950
|
-
return
|
|
951
|
-
"
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
data.toolList.length > 5 ? h("span", { className: "lc-card-sub" }, " " + tr("tools.more", { n: data.toolList.length })) : null
|
|
986
|
-
) : null
|
|
987
|
-
),
|
|
988
|
-
// ---- trend ----
|
|
989
|
-
h(
|
|
990
|
-
"div",
|
|
991
|
-
{ className: "lc-card" },
|
|
992
|
-
h(
|
|
993
|
-
"div",
|
|
994
|
-
{ className: "lc-card-title" },
|
|
995
|
-
t("trend.title"),
|
|
996
|
-
h("span", { className: "lc-card-sub" }, t("trend.hint")),
|
|
997
|
-
h(
|
|
998
|
-
"div",
|
|
999
|
-
{ className: "lc-gran" },
|
|
1000
|
-
h("button", {
|
|
1001
|
-
className: "lc-gran-btn" + (granularity === "step" ? " lc-gran-on" : ""),
|
|
1002
|
-
onClick: () => {
|
|
1003
|
-
setGranularity("step");
|
|
1004
|
-
}
|
|
1005
|
-
}, t("gran.step")),
|
|
1006
|
-
h("button", {
|
|
1007
|
-
className: "lc-gran-btn" + (granularity === "turn" ? " lc-gran-on" : ""),
|
|
1008
|
-
onClick: () => {
|
|
1009
|
-
setGranularity("turn");
|
|
1010
|
-
}
|
|
1011
|
-
}, t("gran.turn"))
|
|
1012
|
-
)
|
|
1013
|
-
),
|
|
1014
|
-
displayRequests.length === 0 ? h("div", { className: "lc-empty" }, t("trend.empty")) : h(
|
|
1015
|
-
"div",
|
|
1016
|
-
null,
|
|
1017
|
-
h(TrendChart, {
|
|
1018
|
-
// Remount per session: switching sessions re-anchors the chart
|
|
1019
|
-
// at the newest bars instead of inheriting stale scroll state.
|
|
1020
|
-
key: sessionId,
|
|
1021
|
-
// The host caps the log at 160 requests; render them ALL so
|
|
1022
|
-
// earlier turns/steps stay reachable via horizontal scroll.
|
|
1023
|
-
requests: displayRequests,
|
|
1024
|
-
markers,
|
|
1025
|
-
selectedSeq: pinnedReq ? pinnedReq.seq : null,
|
|
1026
|
-
hoveredSeq,
|
|
1027
|
-
activeTurn,
|
|
1028
|
-
granularity,
|
|
1029
|
-
onSelect: setSelectedSeq,
|
|
1030
|
-
onHover: setHoveredSeq,
|
|
1031
|
-
onHoverTurn: setHoverTurn
|
|
1032
|
-
}),
|
|
1033
|
-
h(RequestDetail, { request: activeReq, marker: activeReq !== null ? markerOf(activeReq) : void 0 })
|
|
1034
|
-
)
|
|
1035
|
-
),
|
|
1036
|
-
// ---- events + messages ----
|
|
1037
|
-
h(
|
|
1038
|
-
"div",
|
|
1039
|
-
{ className: "lc-cols" },
|
|
1040
|
-
h(
|
|
1041
|
-
"div",
|
|
1042
|
-
{ className: "lc-card lc-col" },
|
|
1043
|
-
h("div", { className: "lc-card-title" }, t("events.title")),
|
|
1044
|
-
h(EventList, { events })
|
|
1045
|
-
),
|
|
1046
|
-
h(
|
|
1047
|
-
"div",
|
|
1048
|
-
{ className: "lc-card lc-col" },
|
|
1049
|
-
h(
|
|
1050
|
-
"div",
|
|
1051
|
-
{ className: "lc-card-title" },
|
|
1052
|
-
t("nodes.title"),
|
|
1053
|
-
h("span", { className: "lc-card-sub" }, t("nodes.hint"))
|
|
1054
|
-
),
|
|
1055
|
-
h(NodeList, { nodes, dropped: data.droppedNodes || 0 })
|
|
1056
|
-
)
|
|
1057
|
-
),
|
|
1058
|
-
h("div", { className: "lc-foot" }, t("footer"))
|
|
1059
|
-
);
|
|
810
|
+
return /* @__PURE__ */ React.createElement("div", { className: "lc-root", ref: rootRef }, /* @__PURE__ */ React.createElement(StatsBoard, { requests, events }), /* @__PURE__ */ React.createElement("div", { className: "lc-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("overview.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, (data.model ? data.model : "") + (data.provider ? " \xB7 " + data.provider : ""))), /* @__PURE__ */ React.createElement("div", { className: "lc-overview-num" }, /* @__PURE__ */ React.createElement("b", null, fmt3(headline)), /* @__PURE__ */ React.createElement("span", null, occupancyWindow ? " / " + fmt3(occupancyWindow) + " " + tr("overview.ofWindow", { p: headlinePct ?? 0 }) : " " + t("overview.estimate")), occupancyTokens !== null ? /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("overview.splitEst")) : null), /* @__PURE__ */ React.createElement(StackedBar, { parts, height: 16, max: occupancyWindow, hoverKey: hoverCat, onHoverKey: setHoverCat }), /* @__PURE__ */ React.createElement(Legend, { parts, hoverKey: hoverCat, onHoverKey: setHoverCat }), data.toolList && data.toolList.length > 0 ? /* @__PURE__ */ React.createElement("div", { className: "lc-tools" }, t("tools.top"), data.toolList.slice().sort((a, b) => b.tokens - a.tokens).slice(0, 5).map((tool) => {
|
|
811
|
+
return /* @__PURE__ */ React.createElement("span", { key: tool.name, className: "lc-tool-chip" }, tool.name + " " + fmt3(tool.tokens));
|
|
812
|
+
}), data.toolList.length > 5 ? /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, " " + tr("tools.more", { n: data.toolList.length })) : null) : null), /* @__PURE__ */ React.createElement("div", { className: "lc-card" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("trend.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("trend.hint")), /* @__PURE__ */ React.createElement("div", { className: "lc-gran" }, /* @__PURE__ */ React.createElement(
|
|
813
|
+
"button",
|
|
814
|
+
{
|
|
815
|
+
className: "lc-gran-btn" + (granularity === "step" ? " lc-gran-on" : ""),
|
|
816
|
+
onClick: () => {
|
|
817
|
+
setGranularity("step");
|
|
818
|
+
}
|
|
819
|
+
},
|
|
820
|
+
t("gran.step")
|
|
821
|
+
), /* @__PURE__ */ React.createElement(
|
|
822
|
+
"button",
|
|
823
|
+
{
|
|
824
|
+
className: "lc-gran-btn" + (granularity === "turn" ? " lc-gran-on" : ""),
|
|
825
|
+
onClick: () => {
|
|
826
|
+
setGranularity("turn");
|
|
827
|
+
}
|
|
828
|
+
},
|
|
829
|
+
t("gran.turn")
|
|
830
|
+
))), displayRequests.length === 0 ? /* @__PURE__ */ React.createElement("div", { className: "lc-empty" }, t("trend.empty")) : /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
|
|
831
|
+
TrendChart,
|
|
832
|
+
{
|
|
833
|
+
key: sessionId,
|
|
834
|
+
requests: displayRequests,
|
|
835
|
+
markers,
|
|
836
|
+
selectedSeq: pinnedReq ? pinnedReq.seq : null,
|
|
837
|
+
hoveredSeq,
|
|
838
|
+
activeTurn,
|
|
839
|
+
granularity,
|
|
840
|
+
onSelect: setSelectedSeq,
|
|
841
|
+
onHover: setHoveredSeq,
|
|
842
|
+
onHoverTurn: setHoverTurn
|
|
843
|
+
}
|
|
844
|
+
), /* @__PURE__ */ React.createElement(RequestDetail, { request: activeReq, marker: activeReq !== null ? markerOf(activeReq) : void 0 }))), /* @__PURE__ */ React.createElement("div", { className: "lc-cols" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("events.title")), /* @__PURE__ */ React.createElement(EventList, { events })), /* @__PURE__ */ React.createElement("div", { className: "lc-card lc-col" }, /* @__PURE__ */ React.createElement("div", { className: "lc-card-title" }, t("nodes.title"), /* @__PURE__ */ React.createElement("span", { className: "lc-card-sub" }, t("nodes.hint"))), /* @__PURE__ */ React.createElement(NodeList, { nodes, dropped: data.droppedNodes || 0 }))), /* @__PURE__ */ React.createElement("div", { className: "lc-foot" }, t("footer")));
|
|
1060
845
|
};
|
|
1061
846
|
}
|
|
1062
847
|
|
|
@@ -1075,11 +860,12 @@ function makeViewKit(t) {
|
|
|
1075
860
|
}
|
|
1076
861
|
|
|
1077
862
|
// src/client/index.ts
|
|
863
|
+
var NS = "dsh-context";
|
|
1078
864
|
function apply(ctx) {
|
|
1079
865
|
ctx.effect(() => {
|
|
1080
|
-
return ctx.locale.register(
|
|
866
|
+
return ctx.locale.register(NS, { zh: DICT_ZH, en: DICT_EN });
|
|
1081
867
|
}, "dsh-context: dictionaries");
|
|
1082
|
-
const t = ctx.locale.bind(
|
|
868
|
+
const t = ctx.locale.bind(NS);
|
|
1083
869
|
ctx.effect(() => {
|
|
1084
870
|
const tag = document.createElement("style");
|
|
1085
871
|
tag.setAttribute("data-plugin", "dsh-context");
|
|
@@ -1092,15 +878,16 @@ function apply(ctx) {
|
|
|
1092
878
|
const ContextView = makeContextView(ctx, makeViewKit(t));
|
|
1093
879
|
ctx.slots.inject("conversation.view", () => {
|
|
1094
880
|
return ctx.slots.register(
|
|
1095
|
-
// order 20 renders right of Chat (0) and Trajectory (10)
|
|
1096
|
-
|
|
881
|
+
// order 20 renders right of Chat (0) and Trajectory (10); the locale
|
|
882
|
+
// namespace put the framework `t` seat on the component's props too.
|
|
883
|
+
{ name: "conversation.view", id: "context", order: 20, locale: NS, label: () => t("tab") },
|
|
1097
884
|
(props) => h(ContextView, props)
|
|
1098
885
|
);
|
|
1099
886
|
});
|
|
1100
887
|
}
|
|
1101
888
|
module.exports = {
|
|
1102
889
|
name: "dsh-context",
|
|
1103
|
-
inject: ["
|
|
890
|
+
inject: ["slots", "locale"],
|
|
1104
891
|
apply
|
|
1105
892
|
};
|
|
1106
893
|
|