dsh-context 0.53.0 → 0.53.2
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 +432 -367
- package/lib/index.js +2 -1
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -75,6 +75,9 @@ window.__ModuleLoader__.load({
|
|
|
75
75
|
"placement.tab": "标签页",
|
|
76
76
|
"placement.sidebar": "侧边栏",
|
|
77
77
|
"placement.all": "全部",
|
|
78
|
+
"settings.insightsEntry": "上下文洞察入口",
|
|
79
|
+
"insightsEntry.show": "显示",
|
|
80
|
+
"insightsEntry.hide": "隐藏",
|
|
78
81
|
"settings.gran": "趋势图 · 默认粒度",
|
|
79
82
|
"settings.mode": "趋势图 · 默认展示方式",
|
|
80
83
|
"settings.toolSort": "工具定义 · 默认排序",
|
|
@@ -323,17 +326,28 @@ window.__ModuleLoader__.load({
|
|
|
323
326
|
"ov.kpi.sessions": "活跃会话",
|
|
324
327
|
"ov.kpi.ofTotal": "共 {n} 个",
|
|
325
328
|
"ov.kpi.tokens": "累计消耗",
|
|
326
|
-
"ov.kpi.
|
|
327
|
-
"ov.kpi.cacheSub": "缓存读取 / 计费输入",
|
|
329
|
+
"ov.kpi.sessionsSub": "含 {n} 个会话",
|
|
328
330
|
"ov.kpi.toolSub": "工具执行 {dur}",
|
|
329
331
|
"ov.kpi.wallSub": "模型调用 {n}",
|
|
330
332
|
"ov.heat.title": "活跃度",
|
|
331
|
-
"ov.heat.sub": "
|
|
333
|
+
"ov.heat.sub": "按日期筛选",
|
|
332
334
|
"ov.heat.empty": "暂无活跃数据 — 会话产生模型请求后,这里会显示每日用量",
|
|
333
335
|
"ov.heat.sessions": "{n} 个活跃会话",
|
|
334
336
|
"ov.heat.wd.1": "一",
|
|
335
337
|
"ov.heat.wd.3": "三",
|
|
336
338
|
"ov.heat.wd.5": "五",
|
|
339
|
+
"ov.heat.mon.01": "1月",
|
|
340
|
+
"ov.heat.mon.02": "2月",
|
|
341
|
+
"ov.heat.mon.03": "3月",
|
|
342
|
+
"ov.heat.mon.04": "4月",
|
|
343
|
+
"ov.heat.mon.05": "5月",
|
|
344
|
+
"ov.heat.mon.06": "6月",
|
|
345
|
+
"ov.heat.mon.07": "7月",
|
|
346
|
+
"ov.heat.mon.08": "8月",
|
|
347
|
+
"ov.heat.mon.09": "9月",
|
|
348
|
+
"ov.heat.mon.10": "10月",
|
|
349
|
+
"ov.heat.mon.11": "11月",
|
|
350
|
+
"ov.heat.mon.12": "12月",
|
|
337
351
|
"ov.list.title": "会话",
|
|
338
352
|
"ov.list.search": "搜索标题或目录…",
|
|
339
353
|
"ov.list.sortLabel": "排序",
|
|
@@ -427,6 +441,9 @@ window.__ModuleLoader__.load({
|
|
|
427
441
|
"placement.tab": "Tab",
|
|
428
442
|
"placement.sidebar": "Sidebar",
|
|
429
443
|
"placement.all": "All",
|
|
444
|
+
"settings.insightsEntry": "Context Insights entry",
|
|
445
|
+
"insightsEntry.show": "Show",
|
|
446
|
+
"insightsEntry.hide": "Hide",
|
|
430
447
|
"settings.gran": "Trend Chart · Default granularity",
|
|
431
448
|
"settings.mode": "Trend Chart · Default display",
|
|
432
449
|
"settings.toolSort": "Tool Schemas · Default sort",
|
|
@@ -675,17 +692,28 @@ window.__ModuleLoader__.load({
|
|
|
675
692
|
"ov.kpi.sessions": "Active Sessions",
|
|
676
693
|
"ov.kpi.ofTotal": "of {n} total",
|
|
677
694
|
"ov.kpi.tokens": "Tokens Used",
|
|
678
|
-
"ov.kpi.
|
|
679
|
-
"ov.kpi.cacheSub": "cache reads of billed input",
|
|
695
|
+
"ov.kpi.sessionsSub": "across {n} sessions",
|
|
680
696
|
"ov.kpi.toolSub": "tool runs {dur}",
|
|
681
697
|
"ov.kpi.wallSub": "{n} model calls",
|
|
682
698
|
"ov.heat.title": "Activity",
|
|
683
|
-
"ov.heat.sub": "
|
|
699
|
+
"ov.heat.sub": "Filter by date",
|
|
684
700
|
"ov.heat.empty": "No activity yet — daily usage appears once sessions make model requests",
|
|
685
701
|
"ov.heat.sessions": "{n} active sessions",
|
|
686
702
|
"ov.heat.wd.1": "M",
|
|
687
703
|
"ov.heat.wd.3": "W",
|
|
688
704
|
"ov.heat.wd.5": "F",
|
|
705
|
+
"ov.heat.mon.01": "Jan",
|
|
706
|
+
"ov.heat.mon.02": "Feb",
|
|
707
|
+
"ov.heat.mon.03": "Mar",
|
|
708
|
+
"ov.heat.mon.04": "Apr",
|
|
709
|
+
"ov.heat.mon.05": "May",
|
|
710
|
+
"ov.heat.mon.06": "Jun",
|
|
711
|
+
"ov.heat.mon.07": "Jul",
|
|
712
|
+
"ov.heat.mon.08": "Aug",
|
|
713
|
+
"ov.heat.mon.09": "Sep",
|
|
714
|
+
"ov.heat.mon.10": "Oct",
|
|
715
|
+
"ov.heat.mon.11": "Nov",
|
|
716
|
+
"ov.heat.mon.12": "Dec",
|
|
689
717
|
"ov.list.title": "Sessions",
|
|
690
718
|
"ov.list.search": "Search title or path…",
|
|
691
719
|
"ov.list.sortLabel": "Sort",
|
|
@@ -3372,11 +3400,12 @@ window.__ModuleLoader__.load({
|
|
|
3372
3400
|
}
|
|
3373
3401
|
//#endregion
|
|
3374
3402
|
//#region src/client/format.ts
|
|
3375
|
-
/** `fmt`: the k/M suffix style shared by bars/details/stats; `fmtTime`: local HH:MM:SS. */
|
|
3403
|
+
/** `fmt`: the k/M/B suffix style shared by bars/details/stats; `fmtTime`: local HH:MM:SS. */
|
|
3376
3404
|
function fmt(n) {
|
|
3377
3405
|
if (n === void 0 || n === null || isNaN(n)) return "—";
|
|
3378
3406
|
const sign = n < 0 ? "-" : "";
|
|
3379
3407
|
const a = Math.abs(n);
|
|
3408
|
+
if (a >= 1e9) return sign + (a / 1e9).toFixed(1) + "B";
|
|
3380
3409
|
if (a >= 1e6) return sign + (a / 1e6).toFixed(1) + "M";
|
|
3381
3410
|
if (a >= 1e3) return sign + (a / 1e3).toFixed(1) + "k";
|
|
3382
3411
|
return sign + String(Math.round(a));
|
|
@@ -5265,77 +5294,67 @@ window.__ModuleLoader__.load({
|
|
|
5265
5294
|
};
|
|
5266
5295
|
}
|
|
5267
5296
|
//#endregion
|
|
5268
|
-
//#region
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
* Build the address of a file read through one Session.
|
|
5287
|
-
* @param sessionId - the Session whose Host workspace resolves the path.
|
|
5288
|
-
* @param path - absolute or workspace-relative path; backslashes are normalized to `/`, and leading `./` prefixes are dropped.
|
|
5289
|
-
* @returns the `dsh-resource://file/session/<sessionId>/<path>` address.
|
|
5290
|
-
*/
|
|
5291
|
-
function sessionFileAddress(sessionId, path) {
|
|
5292
|
-
const normalized = path.replace(/\\/g, "/").replace(/^(?:\.\/)+/, "");
|
|
5293
|
-
return `${FILE_ADDRESS_PREFIX}session/${encodeSegment(sessionId)}/${encodePath(normalized)}`;
|
|
5294
|
-
}
|
|
5295
|
-
/**
|
|
5296
|
-
* Browser-safe Workspace path and display helpers.
|
|
5297
|
-
* @module @deepseek-ai/dsh-util-workspace-path
|
|
5298
|
-
*/
|
|
5299
|
-
/** Whether a path uses a Windows drive or UNC prefix. */
|
|
5300
|
-
function isWindowsStylePath(value) {
|
|
5301
|
-
return /^[A-Za-z]:[/\\]/.test(value) || value.startsWith("\\\\");
|
|
5302
|
-
}
|
|
5303
|
-
/**
|
|
5304
|
-
* Whether a path is absolute in either spelling the Host accepts: POSIX (`/a/b`) or Windows drive or UNC.
|
|
5305
|
-
* @param path - the path to classify.
|
|
5306
|
-
* @returns `true` for an absolute path; `false` for a Workspace-relative one.
|
|
5307
|
-
*/
|
|
5308
|
-
function isAbsoluteWorkspacePath(path) {
|
|
5309
|
-
return path.startsWith("/") || isWindowsStylePath(path);
|
|
5310
|
-
}
|
|
5311
|
-
/**
|
|
5312
|
-
* Read the final non-empty segment of a Workspace path for display.
|
|
5313
|
-
* Workspace-label surfaces use this helper instead of deriving another basename.
|
|
5314
|
-
* @param path - Workspace directory path using POSIX or Windows separators.
|
|
5315
|
-
* @returns the final segment, or an empty string for a separator-only path.
|
|
5316
|
-
*/
|
|
5317
|
-
function workspaceTitleOf(path) {
|
|
5318
|
-
const trimmed = path.replace(/[/\\]+$/, "");
|
|
5319
|
-
const separator = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
|
|
5320
|
-
return trimmed.slice(separator + 1);
|
|
5297
|
+
//#region src/client/overviewStore.ts
|
|
5298
|
+
function createStore() {
|
|
5299
|
+
let open = false;
|
|
5300
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
5301
|
+
return {
|
|
5302
|
+
subscribe: (listener) => {
|
|
5303
|
+
listeners.add(listener);
|
|
5304
|
+
return () => {
|
|
5305
|
+
listeners.delete(listener);
|
|
5306
|
+
};
|
|
5307
|
+
},
|
|
5308
|
+
getSnapshot: () => open,
|
|
5309
|
+
set: (next) => {
|
|
5310
|
+
if (next === open) return;
|
|
5311
|
+
open = next;
|
|
5312
|
+
for (const listener of listeners) listener();
|
|
5313
|
+
}
|
|
5314
|
+
};
|
|
5321
5315
|
}
|
|
5316
|
+
const overviewStore = createStore();
|
|
5317
|
+
//#endregion
|
|
5318
|
+
//#region src/client/components/overviewButton.tsx
|
|
5322
5319
|
/**
|
|
5323
|
-
* The
|
|
5324
|
-
*
|
|
5325
|
-
*
|
|
5326
|
-
*
|
|
5327
|
-
*
|
|
5328
|
-
*
|
|
5329
|
-
*
|
|
5330
|
-
*
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5320
|
+
* The Context Dashboard's sidebar entry: a footer action stacked directly
|
|
5321
|
+
* above Settings (the harness's own foot layout: footer actions, then the
|
|
5322
|
+
* settings row), mirroring the Settings trigger's geometry in both column
|
|
5323
|
+
* widths. The button carries the plugin emblem and, on the wide
|
|
5324
|
+
* column, its label. Clicking opens the overview overlay through the shared
|
|
5325
|
+
* module store (overviewStore.ts).
|
|
5326
|
+
*
|
|
5327
|
+
* The per-user `insightsEntry` preference takes the entry down (renders
|
|
5328
|
+
* null) without unregistering the seat. The subscription fails open: an
|
|
5329
|
+
* absent settings store, an unserved namespace, or a value the plugin
|
|
5330
|
+
* cannot understand all leave the entry visible.
|
|
5331
|
+
*/
|
|
5332
|
+
/** Stable subscription faces for the settings-less degrade (no re-subscribes). */
|
|
5333
|
+
const subscribeNever = () => () => {};
|
|
5334
|
+
const entryShown = () => "show";
|
|
5335
|
+
function makeOverviewButton(kit, settings) {
|
|
5336
|
+
const { t } = kit;
|
|
5337
|
+
const subscribeEntry = settings === void 0 ? subscribeNever : (listener) => settings.store.subscribe(listener);
|
|
5338
|
+
const getEntry = settings === void 0 ? entryShown : () => settings.insightsEntry();
|
|
5339
|
+
return function OverviewButton(props) {
|
|
5340
|
+
if ((0, react.useSyncExternalStore)(subscribeEntry, getEntry) === "hide") return null;
|
|
5341
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
5342
|
+
type: "button",
|
|
5343
|
+
className: props.wide === true ? "lc-ov-entry" : "lc-ov-entry lc-ov-entry-rail",
|
|
5344
|
+
title: t("ov.entry"),
|
|
5345
|
+
"aria-label": t("ov.entry"),
|
|
5346
|
+
onClick: () => {
|
|
5347
|
+
overviewStore.set(true);
|
|
5348
|
+
},
|
|
5349
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContextIcon, {
|
|
5350
|
+
size: props.wide === true ? 16 : 18,
|
|
5351
|
+
className: "lc-ov-entry-icon"
|
|
5352
|
+
}), props.wide === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5353
|
+
className: "lc-ov-entry-label",
|
|
5354
|
+
children: t("ov.entry")
|
|
5355
|
+
})]
|
|
5356
|
+
});
|
|
5357
|
+
};
|
|
5339
5358
|
}
|
|
5340
5359
|
//#endregion
|
|
5341
5360
|
//#region src/shared/providers.ts
|
|
@@ -5515,6 +5534,258 @@ window.__ModuleLoader__.load({
|
|
|
5515
5534
|
return formatCost(amount, currency).replace(/0+$/, "").replace(/\.$/, "");
|
|
5516
5535
|
}
|
|
5517
5536
|
//#endregion
|
|
5537
|
+
//#region node_modules/.pnpm/@opencode-ai+models@0.0.72/node_modules/@opencode-ai/models/dist/error.js
|
|
5538
|
+
/**
|
|
5539
|
+
* The only error thrown by the models.dev client.
|
|
5540
|
+
*
|
|
5541
|
+
* - `Transport` — the fetch itself failed (network, DNS, abort). `cause` is the underlying error.
|
|
5542
|
+
* - `UnexpectedStatus` — non-2xx response. `cause` is `{ status: number }`.
|
|
5543
|
+
* - `MalformedResponse` — the body was empty or not valid JSON. `cause` is the parse error, if any.
|
|
5544
|
+
*/
|
|
5545
|
+
var ModelsDevError = class extends Error {
|
|
5546
|
+
reason;
|
|
5547
|
+
name = "ModelsDevError";
|
|
5548
|
+
constructor(reason, options) {
|
|
5549
|
+
super(reason, options);
|
|
5550
|
+
this.reason = reason;
|
|
5551
|
+
}
|
|
5552
|
+
};
|
|
5553
|
+
//#endregion
|
|
5554
|
+
//#region node_modules/.pnpm/@opencode-ai+models@0.0.72/node_modules/@opencode-ai/models/dist/client.js
|
|
5555
|
+
/**
|
|
5556
|
+
* Creates a stateless models.dev client. Every method performs exactly one
|
|
5557
|
+
* `GET` and nothing is ever cached — callers who want caching should wrap
|
|
5558
|
+
* calls with their own policy. For a no-network alternative, see the
|
|
5559
|
+
* `@opencode-ai/models/snapshot` entrypoint.
|
|
5560
|
+
*/
|
|
5561
|
+
function make(options = {}) {
|
|
5562
|
+
const baseUrl = options.baseUrl ?? "https://models.dev";
|
|
5563
|
+
const base = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/";
|
|
5564
|
+
const request = async (path, requestOptions) => {
|
|
5565
|
+
const fetch = options.fetch ?? globalThis.fetch;
|
|
5566
|
+
const headers = new Headers();
|
|
5567
|
+
for (const [key, value] of new Headers(options.headers)) headers.set(key, value);
|
|
5568
|
+
for (const [key, value] of new Headers(requestOptions?.headers)) headers.set(key, value);
|
|
5569
|
+
let response;
|
|
5570
|
+
try {
|
|
5571
|
+
response = await fetch(new URL(path, base), {
|
|
5572
|
+
method: "GET",
|
|
5573
|
+
headers,
|
|
5574
|
+
signal: requestOptions?.signal
|
|
5575
|
+
});
|
|
5576
|
+
} catch (cause) {
|
|
5577
|
+
throw new ModelsDevError("Transport", { cause });
|
|
5578
|
+
}
|
|
5579
|
+
if (!response.ok) {
|
|
5580
|
+
try {
|
|
5581
|
+
await response.body?.cancel();
|
|
5582
|
+
} catch {}
|
|
5583
|
+
throw new ModelsDevError("UnexpectedStatus", { cause: { status: response.status } });
|
|
5584
|
+
}
|
|
5585
|
+
let text;
|
|
5586
|
+
try {
|
|
5587
|
+
text = await response.text();
|
|
5588
|
+
} catch (cause) {
|
|
5589
|
+
throw new ModelsDevError("Transport", { cause });
|
|
5590
|
+
}
|
|
5591
|
+
if (text === "") throw new ModelsDevError("MalformedResponse");
|
|
5592
|
+
try {
|
|
5593
|
+
return JSON.parse(text);
|
|
5594
|
+
} catch (cause) {
|
|
5595
|
+
throw new ModelsDevError("MalformedResponse", { cause });
|
|
5596
|
+
}
|
|
5597
|
+
};
|
|
5598
|
+
return {
|
|
5599
|
+
/** All providers with their models, pricing, and limits (`/api.json`). */
|
|
5600
|
+
providers: (requestOptions) => request("api.json", requestOptions),
|
|
5601
|
+
/** Provider-agnostic model metadata (`/models.json`). */
|
|
5602
|
+
models: (requestOptions) => request("models.json", requestOptions),
|
|
5603
|
+
/** Providers and model metadata in a single request (`/catalog.json`). */
|
|
5604
|
+
catalog: (requestOptions) => request("catalog.json", requestOptions)
|
|
5605
|
+
};
|
|
5606
|
+
}
|
|
5607
|
+
//#endregion
|
|
5608
|
+
//#region src/client/modelPrices.ts
|
|
5609
|
+
/**
|
|
5610
|
+
* The client's model-price book (client/cost.ts prices from it): the
|
|
5611
|
+
* models.dev registry, fetched through the official @opencode-ai/models
|
|
5612
|
+
* SDK. The registry payload is untrusted wire input, so `pricesBookOf`
|
|
5613
|
+
* re-proves every field at the boundary — a non-conforming provider/model/
|
|
5614
|
+
* cost entry drops whole. The book keeps EVERY provider that prices (keyed
|
|
5615
|
+
* by the registry's own provider id), so a dsh provider id outside the
|
|
5616
|
+
* rename table still prices by direct passthrough. One fetch per page load,
|
|
5617
|
+
* kicked on first subscribe; a failure degrades to a visible state the cost
|
|
5618
|
+
* cell notes, with a backed-off automatic retry — never a spinner, and
|
|
5619
|
+
* never an unhandled rejection.
|
|
5620
|
+
*/
|
|
5621
|
+
/** One finite non-negative registry figure, or null. */
|
|
5622
|
+
function rateOf(value) {
|
|
5623
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
5624
|
+
}
|
|
5625
|
+
/**
|
|
5626
|
+
* Extract the whole registry's per-model USD rates from a delivered
|
|
5627
|
+
* providers payload (`/api.json`), keyed by the registry's provider ids.
|
|
5628
|
+
* Any shape failure skips just that entry; a payload that is not a record
|
|
5629
|
+
* at all returns null (the store treats it as a failed fetch and retries).
|
|
5630
|
+
*/
|
|
5631
|
+
function pricesBookOf(value) {
|
|
5632
|
+
const data = asRecord(value);
|
|
5633
|
+
if (data === null || Array.isArray(data)) return null;
|
|
5634
|
+
const book = {};
|
|
5635
|
+
for (const providerId of Object.keys(data)) {
|
|
5636
|
+
const provider = asRecord(data[providerId]);
|
|
5637
|
+
const modelList = provider !== null ? asRecord(provider.models) : null;
|
|
5638
|
+
if (modelList === null) continue;
|
|
5639
|
+
const models = {};
|
|
5640
|
+
for (const id of Object.keys(modelList)) {
|
|
5641
|
+
const model = asRecord(modelList[id]);
|
|
5642
|
+
const cost = model !== null ? asRecord(model.cost) : null;
|
|
5643
|
+
if (cost === null) continue;
|
|
5644
|
+
const miss = rateOf(cost.input);
|
|
5645
|
+
const out = rateOf(cost.output);
|
|
5646
|
+
if (miss === null || out === null) continue;
|
|
5647
|
+
models[id] = {
|
|
5648
|
+
hit: rateOf(cost.cache_read) ?? miss,
|
|
5649
|
+
miss,
|
|
5650
|
+
write: rateOf(cost.cache_write) ?? miss,
|
|
5651
|
+
out
|
|
5652
|
+
};
|
|
5653
|
+
}
|
|
5654
|
+
if (Object.keys(models).length > 0) book[providerId] = models;
|
|
5655
|
+
}
|
|
5656
|
+
return book;
|
|
5657
|
+
}
|
|
5658
|
+
const defaultLoader = () => make().providers();
|
|
5659
|
+
/** The retry backoff base; each consecutive failure doubles the wait, capped at 3 doublings. */
|
|
5660
|
+
const RETRY_BASE_MS = 3e4;
|
|
5661
|
+
let loader = defaultLoader;
|
|
5662
|
+
let snap = {
|
|
5663
|
+
prices: null,
|
|
5664
|
+
failed: false
|
|
5665
|
+
};
|
|
5666
|
+
let inFlight = false;
|
|
5667
|
+
let failures = 0;
|
|
5668
|
+
let timer = null;
|
|
5669
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
5670
|
+
function fail() {
|
|
5671
|
+
snap = {
|
|
5672
|
+
...snap,
|
|
5673
|
+
failed: true
|
|
5674
|
+
};
|
|
5675
|
+
failures++;
|
|
5676
|
+
timer = setTimeout(() => {
|
|
5677
|
+
timer = null;
|
|
5678
|
+
fire();
|
|
5679
|
+
}, RETRY_BASE_MS * 2 ** Math.min(failures - 1, 3));
|
|
5680
|
+
}
|
|
5681
|
+
async function fire() {
|
|
5682
|
+
inFlight = true;
|
|
5683
|
+
try {
|
|
5684
|
+
const book = pricesBookOf(await loader());
|
|
5685
|
+
if (book !== null) {
|
|
5686
|
+
snap = {
|
|
5687
|
+
prices: book,
|
|
5688
|
+
failed: false
|
|
5689
|
+
};
|
|
5690
|
+
failures = 0;
|
|
5691
|
+
} else fail();
|
|
5692
|
+
} catch {
|
|
5693
|
+
fail();
|
|
5694
|
+
}
|
|
5695
|
+
inFlight = false;
|
|
5696
|
+
for (const fn of listeners) fn();
|
|
5697
|
+
}
|
|
5698
|
+
function kick() {
|
|
5699
|
+
if (snap.prices !== null || inFlight || timer !== null) return;
|
|
5700
|
+
fire();
|
|
5701
|
+
}
|
|
5702
|
+
/** The useSyncExternalStore seam: subscribing also kicks the first fetch. */
|
|
5703
|
+
const subscribeModelPrices = (fn) => {
|
|
5704
|
+
listeners.add(fn);
|
|
5705
|
+
kick();
|
|
5706
|
+
return () => {
|
|
5707
|
+
listeners.delete(fn);
|
|
5708
|
+
};
|
|
5709
|
+
};
|
|
5710
|
+
const getModelPricesSnap = () => snap;
|
|
5711
|
+
/** The stats board's read of the price book (null until the fetch lands). */
|
|
5712
|
+
function useModelPrices() {
|
|
5713
|
+
return (0, react.useSyncExternalStore)(subscribeModelPrices, getModelPricesSnap);
|
|
5714
|
+
}
|
|
5715
|
+
//#endregion
|
|
5716
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-util-workspace-path@0.1.5-rc.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-util-workspace-path/lib/index.js
|
|
5717
|
+
/**
|
|
5718
|
+
* The `dsh-resource://file/…` address grammar: how a file is named across the
|
|
5719
|
+
* Sidebar and the resource model, built and parsed without touching a
|
|
5720
|
+
* filesystem.
|
|
5721
|
+
* @module
|
|
5722
|
+
*/
|
|
5723
|
+
/** The scheme and type every file address opens with. */
|
|
5724
|
+
const FILE_ADDRESS_PREFIX = "dsh-resource://file/";
|
|
5725
|
+
/** Component-encode one id or path segment, keeping `:` literal for drive letters. */
|
|
5726
|
+
function encodeSegment(segment) {
|
|
5727
|
+
return encodeURIComponent(segment).replace(/%3A/gi, ":");
|
|
5728
|
+
}
|
|
5729
|
+
/** Encode a `/`-separated path segment by segment. */
|
|
5730
|
+
function encodePath(path) {
|
|
5731
|
+
return path.split("/").map(encodeSegment).join("/");
|
|
5732
|
+
}
|
|
5733
|
+
/**
|
|
5734
|
+
* Build the address of a file read through one Session.
|
|
5735
|
+
* @param sessionId - the Session whose Host workspace resolves the path.
|
|
5736
|
+
* @param path - absolute or workspace-relative path; backslashes are normalized to `/`, and leading `./` prefixes are dropped.
|
|
5737
|
+
* @returns the `dsh-resource://file/session/<sessionId>/<path>` address.
|
|
5738
|
+
*/
|
|
5739
|
+
function sessionFileAddress(sessionId, path) {
|
|
5740
|
+
const normalized = path.replace(/\\/g, "/").replace(/^(?:\.\/)+/, "");
|
|
5741
|
+
return `${FILE_ADDRESS_PREFIX}session/${encodeSegment(sessionId)}/${encodePath(normalized)}`;
|
|
5742
|
+
}
|
|
5743
|
+
/**
|
|
5744
|
+
* Browser-safe Workspace path and display helpers.
|
|
5745
|
+
* @module @deepseek-ai/dsh-util-workspace-path
|
|
5746
|
+
*/
|
|
5747
|
+
/** Whether a path uses a Windows drive or UNC prefix. */
|
|
5748
|
+
function isWindowsStylePath(value) {
|
|
5749
|
+
return /^[A-Za-z]:[/\\]/.test(value) || value.startsWith("\\\\");
|
|
5750
|
+
}
|
|
5751
|
+
/**
|
|
5752
|
+
* Whether a path is absolute in either spelling the Host accepts: POSIX (`/a/b`) or Windows drive or UNC.
|
|
5753
|
+
* @param path - the path to classify.
|
|
5754
|
+
* @returns `true` for an absolute path; `false` for a Workspace-relative one.
|
|
5755
|
+
*/
|
|
5756
|
+
function isAbsoluteWorkspacePath(path) {
|
|
5757
|
+
return path.startsWith("/") || isWindowsStylePath(path);
|
|
5758
|
+
}
|
|
5759
|
+
/**
|
|
5760
|
+
* Read the final non-empty segment of a Workspace path for display.
|
|
5761
|
+
* Workspace-label surfaces use this helper instead of deriving another basename.
|
|
5762
|
+
* @param path - Workspace directory path using POSIX or Windows separators.
|
|
5763
|
+
* @returns the final segment, or an empty string for a separator-only path.
|
|
5764
|
+
*/
|
|
5765
|
+
function workspaceTitleOf(path) {
|
|
5766
|
+
const trimmed = path.replace(/[/\\]+$/, "");
|
|
5767
|
+
const separator = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
|
|
5768
|
+
return trimmed.slice(separator + 1);
|
|
5769
|
+
}
|
|
5770
|
+
/**
|
|
5771
|
+
* The address for a path as a caller holds it: a relative path, or an absolute
|
|
5772
|
+
* path inside the Session's workspace, becomes a `session`-scoped address; an
|
|
5773
|
+
* absolute path outside it, or one whose workspace root is unknown, keeps its
|
|
5774
|
+
* absolute path in that Session's address.
|
|
5775
|
+
* @param sessionId - the Session the path is read in.
|
|
5776
|
+
* @param cwd - that Session's workspace root, when known.
|
|
5777
|
+
* @param path - absolute or workspace-relative path, in either separator spelling.
|
|
5778
|
+
* @returns the `dsh-resource://file/…` address.
|
|
5779
|
+
*/
|
|
5780
|
+
function fileAddressFor(sessionId, cwd, path) {
|
|
5781
|
+
const normalized = path.replace(/\\/g, "/");
|
|
5782
|
+
if (!isAbsoluteWorkspacePath(normalized)) return sessionFileAddress(sessionId, normalized);
|
|
5783
|
+
const root = cwd === void 0 ? "" : cwd.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
5784
|
+
if (root !== "" && normalized === root) return sessionFileAddress(sessionId, "");
|
|
5785
|
+
if (root !== "" && normalized.startsWith(`${root}/`)) return sessionFileAddress(sessionId, normalized.slice(root.length + 1));
|
|
5786
|
+
return sessionFileAddress(sessionId, normalized);
|
|
5787
|
+
}
|
|
5788
|
+
//#endregion
|
|
5518
5789
|
//#region src/client/overview.ts
|
|
5519
5790
|
/**
|
|
5520
5791
|
* The Context Dashboard's data layer: everything the panel renders is derived
|
|
@@ -5548,21 +5819,6 @@ window.__ModuleLoader__.load({
|
|
|
5548
5819
|
return null;
|
|
5549
5820
|
}
|
|
5550
5821
|
}
|
|
5551
|
-
/** The running-session tally for the footer entry's badge (0 on any shape failure). */
|
|
5552
|
-
function runningCountOf(snapshot) {
|
|
5553
|
-
const state = asRecord(snapshot);
|
|
5554
|
-
if (state === null) return 0;
|
|
5555
|
-
const byId = asRecord(state.byId);
|
|
5556
|
-
if (byId === null) return 0;
|
|
5557
|
-
let count = 0;
|
|
5558
|
-
try {
|
|
5559
|
-
for (const id of Object.keys(byId)) {
|
|
5560
|
-
const row = asRecord(byId[id]);
|
|
5561
|
-
if (row !== null && row.running === true) count++;
|
|
5562
|
-
}
|
|
5563
|
-
} catch {}
|
|
5564
|
-
return count;
|
|
5565
|
-
}
|
|
5566
5822
|
/**
|
|
5567
5823
|
* The `useWorkspaces` standard prop read — same guarded-hook contract as
|
|
5568
5824
|
* {@link sessionsSnapshotOf}. The overview joins its session → workspace
|
|
@@ -5829,7 +6085,12 @@ window.__ModuleLoader__.load({
|
|
|
5829
6085
|
let toolsMs = 0;
|
|
5830
6086
|
let calls = 0;
|
|
5831
6087
|
let wallMs = 0;
|
|
6088
|
+
let costSessions = 0;
|
|
6089
|
+
let usageSessions = 0;
|
|
5832
6090
|
for (const row of rows) {
|
|
6091
|
+
const cost = row.timeline?.cost;
|
|
6092
|
+
if (estimateSessionCost(cost, prices, currency) !== null) costSessions++;
|
|
6093
|
+
if (usageTotalsOf(cost) !== null) usageSessions++;
|
|
5833
6094
|
turns += turnsOf(row.timeline);
|
|
5834
6095
|
const timing = row.timeline?.timing;
|
|
5835
6096
|
toolCalls += timing?.toolCalls ?? 0;
|
|
@@ -5843,7 +6104,9 @@ window.__ModuleLoader__.load({
|
|
|
5843
6104
|
tokens: totals?.total ?? 0,
|
|
5844
6105
|
turns,
|
|
5845
6106
|
cost: estimateSessionCost(usage, prices, currency),
|
|
6107
|
+
costSessions,
|
|
5846
6108
|
cacheHit: totals === null ? null : cacheHitPercent(totals.cacheRead, totals.input + totals.cacheRead + totals.cacheWrite),
|
|
6109
|
+
usageSessions,
|
|
5847
6110
|
toolCalls,
|
|
5848
6111
|
toolsMs,
|
|
5849
6112
|
calls,
|
|
@@ -5920,238 +6183,6 @@ window.__ModuleLoader__.load({
|
|
|
5920
6183
|
return t("ov.time.d", { n: Math.floor(hours / 24) });
|
|
5921
6184
|
}
|
|
5922
6185
|
//#endregion
|
|
5923
|
-
//#region src/client/overviewStore.ts
|
|
5924
|
-
function createStore() {
|
|
5925
|
-
let open = false;
|
|
5926
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
5927
|
-
return {
|
|
5928
|
-
subscribe: (listener) => {
|
|
5929
|
-
listeners.add(listener);
|
|
5930
|
-
return () => {
|
|
5931
|
-
listeners.delete(listener);
|
|
5932
|
-
};
|
|
5933
|
-
},
|
|
5934
|
-
getSnapshot: () => open,
|
|
5935
|
-
set: (next) => {
|
|
5936
|
-
if (next === open) return;
|
|
5937
|
-
open = next;
|
|
5938
|
-
for (const listener of listeners) listener();
|
|
5939
|
-
}
|
|
5940
|
-
};
|
|
5941
|
-
}
|
|
5942
|
-
const overviewStore = createStore();
|
|
5943
|
-
//#endregion
|
|
5944
|
-
//#region src/client/components/overviewButton.tsx
|
|
5945
|
-
function makeOverviewButton(kit) {
|
|
5946
|
-
const { t } = kit;
|
|
5947
|
-
return function OverviewButton(props) {
|
|
5948
|
-
const running = runningCountOf(sessionsSnapshotOf(props));
|
|
5949
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
5950
|
-
type: "button",
|
|
5951
|
-
className: props.wide === true ? "lc-ov-entry" : "lc-ov-entry lc-ov-entry-rail",
|
|
5952
|
-
title: t("ov.entry"),
|
|
5953
|
-
"aria-label": t("ov.entry"),
|
|
5954
|
-
onClick: () => {
|
|
5955
|
-
overviewStore.set(true);
|
|
5956
|
-
},
|
|
5957
|
-
children: [
|
|
5958
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContextIcon, {
|
|
5959
|
-
size: props.wide === true ? 16 : 18,
|
|
5960
|
-
className: "lc-ov-entry-icon"
|
|
5961
|
-
}),
|
|
5962
|
-
props.wide === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5963
|
-
className: "lc-ov-entry-label",
|
|
5964
|
-
children: t("ov.entry")
|
|
5965
|
-
}),
|
|
5966
|
-
running > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5967
|
-
className: "lc-ov-badge",
|
|
5968
|
-
"aria-hidden": "true",
|
|
5969
|
-
children: running
|
|
5970
|
-
})
|
|
5971
|
-
]
|
|
5972
|
-
});
|
|
5973
|
-
};
|
|
5974
|
-
}
|
|
5975
|
-
//#endregion
|
|
5976
|
-
//#region node_modules/.pnpm/@opencode-ai+models@0.0.72/node_modules/@opencode-ai/models/dist/error.js
|
|
5977
|
-
/**
|
|
5978
|
-
* The only error thrown by the models.dev client.
|
|
5979
|
-
*
|
|
5980
|
-
* - `Transport` — the fetch itself failed (network, DNS, abort). `cause` is the underlying error.
|
|
5981
|
-
* - `UnexpectedStatus` — non-2xx response. `cause` is `{ status: number }`.
|
|
5982
|
-
* - `MalformedResponse` — the body was empty or not valid JSON. `cause` is the parse error, if any.
|
|
5983
|
-
*/
|
|
5984
|
-
var ModelsDevError = class extends Error {
|
|
5985
|
-
reason;
|
|
5986
|
-
name = "ModelsDevError";
|
|
5987
|
-
constructor(reason, options) {
|
|
5988
|
-
super(reason, options);
|
|
5989
|
-
this.reason = reason;
|
|
5990
|
-
}
|
|
5991
|
-
};
|
|
5992
|
-
//#endregion
|
|
5993
|
-
//#region node_modules/.pnpm/@opencode-ai+models@0.0.72/node_modules/@opencode-ai/models/dist/client.js
|
|
5994
|
-
/**
|
|
5995
|
-
* Creates a stateless models.dev client. Every method performs exactly one
|
|
5996
|
-
* `GET` and nothing is ever cached — callers who want caching should wrap
|
|
5997
|
-
* calls with their own policy. For a no-network alternative, see the
|
|
5998
|
-
* `@opencode-ai/models/snapshot` entrypoint.
|
|
5999
|
-
*/
|
|
6000
|
-
function make(options = {}) {
|
|
6001
|
-
const baseUrl = options.baseUrl ?? "https://models.dev";
|
|
6002
|
-
const base = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/";
|
|
6003
|
-
const request = async (path, requestOptions) => {
|
|
6004
|
-
const fetch = options.fetch ?? globalThis.fetch;
|
|
6005
|
-
const headers = new Headers();
|
|
6006
|
-
for (const [key, value] of new Headers(options.headers)) headers.set(key, value);
|
|
6007
|
-
for (const [key, value] of new Headers(requestOptions?.headers)) headers.set(key, value);
|
|
6008
|
-
let response;
|
|
6009
|
-
try {
|
|
6010
|
-
response = await fetch(new URL(path, base), {
|
|
6011
|
-
method: "GET",
|
|
6012
|
-
headers,
|
|
6013
|
-
signal: requestOptions?.signal
|
|
6014
|
-
});
|
|
6015
|
-
} catch (cause) {
|
|
6016
|
-
throw new ModelsDevError("Transport", { cause });
|
|
6017
|
-
}
|
|
6018
|
-
if (!response.ok) {
|
|
6019
|
-
try {
|
|
6020
|
-
await response.body?.cancel();
|
|
6021
|
-
} catch {}
|
|
6022
|
-
throw new ModelsDevError("UnexpectedStatus", { cause: { status: response.status } });
|
|
6023
|
-
}
|
|
6024
|
-
let text;
|
|
6025
|
-
try {
|
|
6026
|
-
text = await response.text();
|
|
6027
|
-
} catch (cause) {
|
|
6028
|
-
throw new ModelsDevError("Transport", { cause });
|
|
6029
|
-
}
|
|
6030
|
-
if (text === "") throw new ModelsDevError("MalformedResponse");
|
|
6031
|
-
try {
|
|
6032
|
-
return JSON.parse(text);
|
|
6033
|
-
} catch (cause) {
|
|
6034
|
-
throw new ModelsDevError("MalformedResponse", { cause });
|
|
6035
|
-
}
|
|
6036
|
-
};
|
|
6037
|
-
return {
|
|
6038
|
-
/** All providers with their models, pricing, and limits (`/api.json`). */
|
|
6039
|
-
providers: (requestOptions) => request("api.json", requestOptions),
|
|
6040
|
-
/** Provider-agnostic model metadata (`/models.json`). */
|
|
6041
|
-
models: (requestOptions) => request("models.json", requestOptions),
|
|
6042
|
-
/** Providers and model metadata in a single request (`/catalog.json`). */
|
|
6043
|
-
catalog: (requestOptions) => request("catalog.json", requestOptions)
|
|
6044
|
-
};
|
|
6045
|
-
}
|
|
6046
|
-
//#endregion
|
|
6047
|
-
//#region src/client/modelPrices.ts
|
|
6048
|
-
/**
|
|
6049
|
-
* The client's model-price book (client/cost.ts prices from it): the
|
|
6050
|
-
* models.dev registry, fetched through the official @opencode-ai/models
|
|
6051
|
-
* SDK. The registry payload is untrusted wire input, so `pricesBookOf`
|
|
6052
|
-
* re-proves every field at the boundary — a non-conforming provider/model/
|
|
6053
|
-
* cost entry drops whole. The book keeps EVERY provider that prices (keyed
|
|
6054
|
-
* by the registry's own provider id), so a dsh provider id outside the
|
|
6055
|
-
* rename table still prices by direct passthrough. One fetch per page load,
|
|
6056
|
-
* kicked on first subscribe; a failure degrades to a visible state the cost
|
|
6057
|
-
* cell notes, with a backed-off automatic retry — never a spinner, and
|
|
6058
|
-
* never an unhandled rejection.
|
|
6059
|
-
*/
|
|
6060
|
-
/** One finite non-negative registry figure, or null. */
|
|
6061
|
-
function rateOf(value) {
|
|
6062
|
-
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
6063
|
-
}
|
|
6064
|
-
/**
|
|
6065
|
-
* Extract the whole registry's per-model USD rates from a delivered
|
|
6066
|
-
* providers payload (`/api.json`), keyed by the registry's provider ids.
|
|
6067
|
-
* Any shape failure skips just that entry; a payload that is not a record
|
|
6068
|
-
* at all returns null (the store treats it as a failed fetch and retries).
|
|
6069
|
-
*/
|
|
6070
|
-
function pricesBookOf(value) {
|
|
6071
|
-
const data = asRecord(value);
|
|
6072
|
-
if (data === null || Array.isArray(data)) return null;
|
|
6073
|
-
const book = {};
|
|
6074
|
-
for (const providerId of Object.keys(data)) {
|
|
6075
|
-
const provider = asRecord(data[providerId]);
|
|
6076
|
-
const modelList = provider !== null ? asRecord(provider.models) : null;
|
|
6077
|
-
if (modelList === null) continue;
|
|
6078
|
-
const models = {};
|
|
6079
|
-
for (const id of Object.keys(modelList)) {
|
|
6080
|
-
const model = asRecord(modelList[id]);
|
|
6081
|
-
const cost = model !== null ? asRecord(model.cost) : null;
|
|
6082
|
-
if (cost === null) continue;
|
|
6083
|
-
const miss = rateOf(cost.input);
|
|
6084
|
-
const out = rateOf(cost.output);
|
|
6085
|
-
if (miss === null || out === null) continue;
|
|
6086
|
-
models[id] = {
|
|
6087
|
-
hit: rateOf(cost.cache_read) ?? miss,
|
|
6088
|
-
miss,
|
|
6089
|
-
write: rateOf(cost.cache_write) ?? miss,
|
|
6090
|
-
out
|
|
6091
|
-
};
|
|
6092
|
-
}
|
|
6093
|
-
if (Object.keys(models).length > 0) book[providerId] = models;
|
|
6094
|
-
}
|
|
6095
|
-
return book;
|
|
6096
|
-
}
|
|
6097
|
-
const defaultLoader = () => make().providers();
|
|
6098
|
-
/** The retry backoff base; each consecutive failure doubles the wait, capped at 3 doublings. */
|
|
6099
|
-
const RETRY_BASE_MS = 3e4;
|
|
6100
|
-
let loader = defaultLoader;
|
|
6101
|
-
let snap = {
|
|
6102
|
-
prices: null,
|
|
6103
|
-
failed: false
|
|
6104
|
-
};
|
|
6105
|
-
let inFlight = false;
|
|
6106
|
-
let failures = 0;
|
|
6107
|
-
let timer = null;
|
|
6108
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
6109
|
-
function fail() {
|
|
6110
|
-
snap = {
|
|
6111
|
-
...snap,
|
|
6112
|
-
failed: true
|
|
6113
|
-
};
|
|
6114
|
-
failures++;
|
|
6115
|
-
timer = setTimeout(() => {
|
|
6116
|
-
timer = null;
|
|
6117
|
-
fire();
|
|
6118
|
-
}, RETRY_BASE_MS * 2 ** Math.min(failures - 1, 3));
|
|
6119
|
-
}
|
|
6120
|
-
async function fire() {
|
|
6121
|
-
inFlight = true;
|
|
6122
|
-
try {
|
|
6123
|
-
const book = pricesBookOf(await loader());
|
|
6124
|
-
if (book !== null) {
|
|
6125
|
-
snap = {
|
|
6126
|
-
prices: book,
|
|
6127
|
-
failed: false
|
|
6128
|
-
};
|
|
6129
|
-
failures = 0;
|
|
6130
|
-
} else fail();
|
|
6131
|
-
} catch {
|
|
6132
|
-
fail();
|
|
6133
|
-
}
|
|
6134
|
-
inFlight = false;
|
|
6135
|
-
for (const fn of listeners) fn();
|
|
6136
|
-
}
|
|
6137
|
-
function kick() {
|
|
6138
|
-
if (snap.prices !== null || inFlight || timer !== null) return;
|
|
6139
|
-
fire();
|
|
6140
|
-
}
|
|
6141
|
-
/** The useSyncExternalStore seam: subscribing also kicks the first fetch. */
|
|
6142
|
-
const subscribeModelPrices = (fn) => {
|
|
6143
|
-
listeners.add(fn);
|
|
6144
|
-
kick();
|
|
6145
|
-
return () => {
|
|
6146
|
-
listeners.delete(fn);
|
|
6147
|
-
};
|
|
6148
|
-
};
|
|
6149
|
-
const getModelPricesSnap = () => snap;
|
|
6150
|
-
/** The stats board's read of the price book (null until the fetch lands). */
|
|
6151
|
-
function useModelPrices() {
|
|
6152
|
-
return (0, react.useSyncExternalStore)(subscribeModelPrices, getModelPricesSnap);
|
|
6153
|
-
}
|
|
6154
|
-
//#endregion
|
|
6155
6186
|
//#region src/shared/days.ts
|
|
6156
6187
|
/**
|
|
6157
6188
|
* The local-day key (`YYYY-MM-DD`) shared by the activity fold (host) and the
|
|
@@ -6210,7 +6241,8 @@ window.__ModuleLoader__.load({
|
|
|
6210
6241
|
//#region src/client/components/heatmap.tsx
|
|
6211
6242
|
/**
|
|
6212
6243
|
* The Context Dashboard's activity heatmap: a GitHub-style contribution grid
|
|
6213
|
-
* (weeks as columns, Monday-first weekdays as rows
|
|
6244
|
+
* (weeks as columns, Monday-first weekdays as rows, a month label over the
|
|
6245
|
+
* column where each month begins) over the merged daily
|
|
6214
6246
|
* ledger (overview.ts). Cell depth is the day's billed-token share of the
|
|
6215
6247
|
* window's maximum, in four steps; a day with data is a button whose click
|
|
6216
6248
|
* pins the session list to that day (click again to release). Cells tip
|
|
@@ -6309,36 +6341,43 @@ window.__ModuleLoader__.load({
|
|
|
6309
6341
|
}, row))
|
|
6310
6342
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6311
6343
|
className: "lc-heat-cols",
|
|
6312
|
-
children: columns.map((column, wi) =>
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6344
|
+
children: columns.map((column, wi) => {
|
|
6345
|
+
const opens = column[0].key.slice(0, 7) !== column[6].key.slice(0, 7) || column[0].key.slice(8, 10) === "01";
|
|
6346
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6347
|
+
className: "lc-heat-col",
|
|
6348
|
+
children: [opens && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6349
|
+
className: "lc-heat-mon",
|
|
6350
|
+
"aria-hidden": "true",
|
|
6351
|
+
children: t("ov.heat.mon." + column[6].key.slice(5, 7))
|
|
6352
|
+
}), column.map((cell) => {
|
|
6353
|
+
if (cell.future) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6354
|
+
className: "lc-heat-cell lc-heat-future",
|
|
6355
|
+
"aria-hidden": "true"
|
|
6356
|
+
}, cell.key);
|
|
6357
|
+
const level = cell.entry === void 0 ? 0 : levelOf(cell.entry.tokens, max);
|
|
6358
|
+
if (cell.entry === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
6359
|
+
label: cell.key,
|
|
6360
|
+
side: "top",
|
|
6361
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "lc-heat-cell lc-heat-0" })
|
|
6362
|
+
}, cell.key);
|
|
6363
|
+
const picked = props.selected === cell.key;
|
|
6364
|
+
const label = `${cell.key}\n${t("ov.heat.sessions", { n: cell.entry.sessions })}`;
|
|
6365
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
6366
|
+
label,
|
|
6367
|
+
side: "top",
|
|
6368
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6369
|
+
type: "button",
|
|
6370
|
+
className: `lc-heat-cell lc-heat-${String(level)}${picked ? " lc-heat-on" : ""}`,
|
|
6371
|
+
"aria-label": label,
|
|
6372
|
+
"aria-pressed": picked,
|
|
6373
|
+
onClick: () => {
|
|
6374
|
+
if (props.onSelect !== void 0) props.onSelect(picked ? null : cell.key);
|
|
6375
|
+
}
|
|
6376
|
+
})
|
|
6377
|
+
}, cell.key);
|
|
6378
|
+
})]
|
|
6379
|
+
}, wi);
|
|
6380
|
+
})
|
|
6342
6381
|
})]
|
|
6343
6382
|
});
|
|
6344
6383
|
};
|
|
@@ -6768,7 +6807,7 @@ window.__ModuleLoader__.load({
|
|
|
6768
6807
|
}),
|
|
6769
6808
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6770
6809
|
className: "lc-stat-sub",
|
|
6771
|
-
children: t("ov.kpi.
|
|
6810
|
+
children: t("ov.kpi.sessionsSub", { n: kpi.costSessions })
|
|
6772
6811
|
})
|
|
6773
6812
|
]
|
|
6774
6813
|
}),
|
|
@@ -6785,7 +6824,7 @@ window.__ModuleLoader__.load({
|
|
|
6785
6824
|
}),
|
|
6786
6825
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6787
6826
|
className: "lc-stat-sub",
|
|
6788
|
-
children: t("ov.kpi.
|
|
6827
|
+
children: t("ov.kpi.sessionsSub", { n: kpi.usageSessions })
|
|
6789
6828
|
})
|
|
6790
6829
|
]
|
|
6791
6830
|
}),
|
|
@@ -7146,6 +7185,21 @@ window.__ModuleLoader__.load({
|
|
|
7146
7185
|
props.set?.("defaultPlacement", id);
|
|
7147
7186
|
}
|
|
7148
7187
|
}),
|
|
7188
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PrefRow, {
|
|
7189
|
+
label: t("settings.insightsEntry"),
|
|
7190
|
+
value: state.insightsEntry,
|
|
7191
|
+
disabled,
|
|
7192
|
+
options: [{
|
|
7193
|
+
id: "show",
|
|
7194
|
+
label: t("insightsEntry.show")
|
|
7195
|
+
}, {
|
|
7196
|
+
id: "hide",
|
|
7197
|
+
label: t("insightsEntry.hide")
|
|
7198
|
+
}],
|
|
7199
|
+
onPick: (id) => {
|
|
7200
|
+
props.set?.("insightsEntry", id);
|
|
7201
|
+
}
|
|
7202
|
+
}),
|
|
7149
7203
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PrefRow, {
|
|
7150
7204
|
label: t("settings.gran"),
|
|
7151
7205
|
value: state.granularity,
|
|
@@ -7235,7 +7289,8 @@ window.__ModuleLoader__.load({
|
|
|
7235
7289
|
...v.defaultGranularity === "step" || v.defaultGranularity === "turn" ? { granularity: v.defaultGranularity } : {},
|
|
7236
7290
|
...v.defaultTrendMode === "total" || v.defaultTrendMode === "delta" ? { mode: v.defaultTrendMode } : {},
|
|
7237
7291
|
...v.defaultToolSort === "size" || v.defaultToolSort === "count" || v.defaultToolSort === "name" ? { toolSort: v.defaultToolSort } : {},
|
|
7238
|
-
...v.defaultFileSort === "count" || v.defaultFileSort === "latest" || v.defaultFileSort === "path" ? { fileSort: v.defaultFileSort } : {}
|
|
7292
|
+
...v.defaultFileSort === "count" || v.defaultFileSort === "latest" || v.defaultFileSort === "path" ? { fileSort: v.defaultFileSort } : {},
|
|
7293
|
+
...v.insightsEntry === "show" || v.insightsEntry === "hide" ? { insightsEntry: v.insightsEntry } : {}
|
|
7239
7294
|
};
|
|
7240
7295
|
}
|
|
7241
7296
|
function createContextSettings() {
|
|
@@ -7246,29 +7301,34 @@ window.__ModuleLoader__.load({
|
|
|
7246
7301
|
mode: "total",
|
|
7247
7302
|
toolSort: "count",
|
|
7248
7303
|
fileSort: "count",
|
|
7304
|
+
insightsEntry: "show",
|
|
7249
7305
|
writable: false
|
|
7250
7306
|
};
|
|
7251
7307
|
let scope;
|
|
7252
7308
|
const listeners = /* @__PURE__ */ new Set();
|
|
7253
7309
|
const publish = (next) => {
|
|
7254
|
-
if (next.status === state.status && next.placement === state.placement && next.granularity === state.granularity && next.mode === state.mode && next.toolSort === state.toolSort && next.fileSort === state.fileSort && next.writable === state.writable) return;
|
|
7310
|
+
if (next.status === state.status && next.placement === state.placement && next.granularity === state.granularity && next.mode === state.mode && next.toolSort === state.toolSort && next.fileSort === state.fileSort && next.insightsEntry === state.insightsEntry && next.writable === state.writable) return;
|
|
7255
7311
|
state = next;
|
|
7256
7312
|
for (const listener of listeners) listener();
|
|
7257
7313
|
};
|
|
7258
7314
|
const sync = (bound) => {
|
|
7259
7315
|
const snap = bound.getSnapshot();
|
|
7260
7316
|
const prefs = prefsOf(snap.value);
|
|
7261
|
-
const
|
|
7317
|
+
const raw = snap.value !== null && typeof snap.value === "object" ? snap.value : void 0;
|
|
7262
7318
|
publish({
|
|
7263
7319
|
status: snap.status === "ready" || snap.status === "unavailable" ? snap.status : "loading",
|
|
7264
|
-
placement: prefs.placement ?? (
|
|
7320
|
+
placement: prefs.placement ?? (raw?.defaultPlacement === void 0 ? state.placement : "all"),
|
|
7265
7321
|
granularity: prefs.granularity ?? state.granularity,
|
|
7266
7322
|
mode: prefs.mode ?? state.mode,
|
|
7267
7323
|
toolSort: prefs.toolSort ?? state.toolSort,
|
|
7268
7324
|
fileSort: prefs.fileSort ?? state.fileSort,
|
|
7325
|
+
insightsEntry: prefs.insightsEntry ?? (raw?.insightsEntry === void 0 ? state.insightsEntry : "show"),
|
|
7269
7326
|
writable: snap.writable
|
|
7270
7327
|
});
|
|
7271
|
-
return
|
|
7328
|
+
return {
|
|
7329
|
+
placement: prefs.placement,
|
|
7330
|
+
insightsEntry: prefs.insightsEntry
|
|
7331
|
+
};
|
|
7272
7332
|
};
|
|
7273
7333
|
return {
|
|
7274
7334
|
store: {
|
|
@@ -7285,6 +7345,7 @@ window.__ModuleLoader__.load({
|
|
|
7285
7345
|
defaultTrendMode: () => state.mode,
|
|
7286
7346
|
defaultToolSort: () => state.toolSort,
|
|
7287
7347
|
defaultFileSort: () => state.fileSort,
|
|
7348
|
+
insightsEntry: () => state.insightsEntry,
|
|
7288
7349
|
attach(bound) {
|
|
7289
7350
|
scope = bound;
|
|
7290
7351
|
sync(bound);
|
|
@@ -7301,10 +7362,14 @@ window.__ModuleLoader__.load({
|
|
|
7301
7362
|
if (bound === void 0) return;
|
|
7302
7363
|
bound.set(field, value).catch(() => {
|
|
7303
7364
|
const truth = sync(bound);
|
|
7304
|
-
if (field === "defaultPlacement" && truth === void 0) publish({
|
|
7365
|
+
if (field === "defaultPlacement" && truth.placement === void 0) publish({
|
|
7305
7366
|
...state,
|
|
7306
7367
|
placement: "all"
|
|
7307
7368
|
});
|
|
7369
|
+
if (field === "insightsEntry" && truth.insightsEntry === void 0) publish({
|
|
7370
|
+
...state,
|
|
7371
|
+
insightsEntry: "show"
|
|
7372
|
+
});
|
|
7308
7373
|
});
|
|
7309
7374
|
}
|
|
7310
7375
|
};
|
|
@@ -9410,7 +9475,7 @@ window.__ModuleLoader__.load({
|
|
|
9410
9475
|
return function PluginInfo() {
|
|
9411
9476
|
const [latest, setLatest] = (0, react.useState)(null);
|
|
9412
9477
|
(0, react.useEffect)(() => {
|
|
9413
|
-
if ("0.53.
|
|
9478
|
+
if ("0.53.2".includes("-dev")) return;
|
|
9414
9479
|
let on = true;
|
|
9415
9480
|
fetchLatestVersion().then((v) => {
|
|
9416
9481
|
if (on && v) setLatest(v);
|
|
@@ -9419,8 +9484,8 @@ window.__ModuleLoader__.load({
|
|
|
9419
9484
|
on = false;
|
|
9420
9485
|
};
|
|
9421
9486
|
}, []);
|
|
9422
|
-
const update = latest !== null && isNewerVersion(latest, "0.53.
|
|
9423
|
-
const nameText = "dsh-context (v0.53.
|
|
9487
|
+
const update = latest !== null && isNewerVersion(latest, "0.53.2") ? latest : null;
|
|
9488
|
+
const nameText = "dsh-context (v0.53.2)";
|
|
9424
9489
|
const nameValue = [nameText];
|
|
9425
9490
|
if (update) nameValue.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9426
9491
|
className: "lc-pi-update",
|
|
@@ -11266,7 +11331,7 @@ window.__ModuleLoader__.load({
|
|
|
11266
11331
|
}
|
|
11267
11332
|
//#endregion
|
|
11268
11333
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/overview.css.mjs
|
|
11269
|
-
const css = ".lc-ov-entry{box-sizing:border-box;width:calc(100% + 4px);height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:8px;margin:0 -2px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;
|
|
11334
|
+
const css = ".lc-ov-entry{box-sizing:border-box;width:calc(100% + 4px);height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:8px;margin:0 -2px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.lc-ov-entry:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-ov-entry-rail{border-radius:50%;flex:none;justify-content:center;gap:0;width:36px;height:36px;margin:0;padding:0}.lc-ov-entry-icon{flex:none}.lc-ov-entry-label{text-align:left;white-space:nowrap;text-overflow:ellipsis;flex:auto;min-width:0;overflow:hidden}.lc-ov-backdrop{z-index:200;background:var(--dsw-alias-bg-mask-1,#00000073);justify-content:center;align-items:center;display:flex;position:fixed;inset:0;container:lc-ov/inline-size}.lc-ov-card{box-sizing:border-box;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);width:min(1120px,100vw - 32px);max-height:min(86vh,900px);box-shadow:var(--dsw-shadow-lv3,0 12px 32px #0006);color:var(--dsw-alias-label-primary);border-radius:12px;flex-direction:column;padding:16px 18px 18px;font-size:13px;display:flex;overflow:hidden}.lc-ov-head{flex-wrap:wrap;flex:none;align-items:center;gap:10px;margin-bottom:14px;display:flex}.lc-ov-head-icon{flex:none}.lc-ov-title{white-space:nowrap;font-size:15px;font-weight:600}.lc-ov-head .lc-modal-close{flex:none;margin-left:0}.lc-ov-body{flex:auto;grid-template-columns:minmax(0,3fr) minmax(0,7fr);gap:10px;min-height:0;display:grid}.lc-ov-left{scrollbar-gutter:stable;flex-direction:column;gap:10px;min-height:0;padding-right:8px;display:flex;overflow-y:auto}.lc-ov-right{scrollbar-gutter:stable;min-height:0;padding-right:8px;overflow-y:auto}@container lc-ov (width<=932px){.lc-ov-card{overflow-y:auto}.lc-ov-body{display:block}.lc-ov-left{margin-bottom:12px}.lc-ov-left,.lc-ov-right{min-height:auto;padding-right:0;overflow:visible}.lc-ov-heat-card{flex:none}}.lc-ov-left>.lc-card{box-sizing:border-box;min-width:0;margin-bottom:0}.lc-ov-kpis{flex:none;grid-template-rows:repeat(3,1fr);grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;display:grid}.lc-ov-kpi{align-items:center;padding:10px 8px}.lc-ov-kpi .lc-stat-value{font-size:20px}.lc-ov-heat-card{flex-direction:column;flex:1 0 auto;display:flex}.lc-heat{flex:1;justify-content:center;align-items:center;gap:4px;display:flex}.lc-heat-wds,.lc-heat-col{padding-top:13px}.lc-heat-wds{flex-direction:column;gap:3px;display:flex}.lc-heat-wd{width:10px;height:20px;color:var(--dsw-alias-label-secondary);text-align:center;flex:none;justify-content:center;align-items:center;font-size:9px;display:flex}.lc-heat-cols{gap:3px;display:flex}.lc-heat-col{flex-direction:column;gap:3px;display:flex;position:relative}.lc-heat-mon{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:9px;line-height:13px;position:absolute;top:0;left:0}.lc-heat-cell{box-sizing:border-box;background:var(--dsw-alias-bg-layer-2);cursor:default;border:0;border-radius:20%;width:20px;height:20px;padding:0}button.lc-heat-cell{cursor:pointer}button.lc-heat-cell:hover{box-shadow:0 0 0 1.5px color-mix(in srgb, var(--color-blue-500) 70%, transparent)}.lc-heat-future{background:0 0}.lc-heat-0{background:color-mix(in srgb, var(--dsw-alias-label-secondary) 16%, transparent)}.lc-heat-1{background:color-mix(in srgb, var(--color-blue-500) 28%, transparent)}.lc-heat-2{background:color-mix(in srgb, var(--color-blue-500) 50%, transparent)}.lc-heat-3{background:color-mix(in srgb, var(--color-blue-500) 72%, transparent)}.lc-heat-4{background:color-mix(in srgb, var(--color-blue-500) 92%, transparent)}.lc-heat-on{box-shadow:0 0 0 1.5px var(--color-blue-500)}.lc-ov-list-head{flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:10px;display:flex}.lc-ov-list-title{white-space:nowrap;font-weight:600}.lc-ov-list-count{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;background:var(--dsw-alias-bg-layer-2);border-radius:8px;padding:1px 7px;font-size:11px}.lc-ov-day-chip{border:1px solid color-mix(in srgb, var(--color-blue-500) 45%, transparent);color:var(--color-blue-500);background:color-mix(in srgb, var(--color-blue-500) 10%, transparent);cursor:pointer;white-space:nowrap;border-radius:999px;padding:1px 10px;font-family:inherit;font-size:11px;line-height:1.4}.lc-ov-search{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);min-width:110px;font:inherit;color:var(--dsw-alias-label-primary);transition:border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;outline:none;flex:150px;padding:4px 10px;font-size:12px}.lc-ov-search:focus{border-color:var(--dsw-alias-label-secondary)}.lc-ov-search::placeholder{color:var(--dsw-alias-label-secondary)}.lc-ov-groups{flex-wrap:wrap;gap:6px;margin:-2px 0 10px;display:flex}.lc-ov-chip{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;white-space:nowrap;text-overflow:ellipsis;max-width:220px;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), border-color 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);background:0 0;border-radius:999px;align-items:baseline;gap:5px;padding:2px 10px;font-size:11px;line-height:1.5;display:inline-flex;overflow:hidden}.lc-ov-chip:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-secondary)}.lc-ov-chip-on,.lc-ov-chip-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border-color:#0000}.lc-ov-chip-n{font-variant-numeric:tabular-nums;opacity:.65;font-size:10px}.lc-ov-chip-on .lc-ov-chip-n{opacity:.85}.lc-ov-grid{grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:10px;display:grid}.lc-ov-session{text-align:left;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;font:inherit;color:inherit;transition:border-color 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);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;display:flex}.lc-ov-session:hover{border-color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2)}.lc-ov-session-current{border-color:color-mix(in srgb, var(--color-blue-500) 65%, transparent)}.lc-ov-session-head{align-items:flex-start;gap:6px;min-width:0;display:flex}.lc-ov-running{background:var(--color-green-500);border-radius:50%;flex:none;width:7px;height:7px}.lc-ov-session-title{-webkit-line-clamp:2;overflow-wrap:anywhere;-webkit-box-orient:vertical;flex:auto;min-width:0;font-weight:600;display:-webkit-box;overflow:hidden}.lc-ov-current{color:var(--color-blue-500);border:1px solid color-mix(in srgb, var(--color-blue-500) 45%, transparent);border-radius:4px;flex:none;padding:0 4px;font-size:10px;line-height:1.5}.lc-ov-session-times{flex-direction:column;flex:none;align-items:flex-end;gap:1px;display:flex}.lc-ov-session-time{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:11px}.lc-ov-session-created{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-variant-numeric:tabular-nums;font-size:10px;line-height:1.4}.lc-ov-session-crumb{min-width:0;color:var(--dsw-alias-label-secondary);white-space:nowrap;align-items:center;gap:5px;font-size:11px;display:flex;overflow:hidden}.lc-ov-crumb-group{text-overflow:ellipsis;flex:none;max-width:55%;overflow:hidden}.lc-ov-crumb-sep{opacity:.55;flex:none}.lc-ov-crumb-project{text-overflow:ellipsis;min-width:0;font-family:var(--ds-font-family-code,ui-monospace, SFMono-Regular, Menlo, monospace);color:var(--dsw-alias-label-primary);background:color-mix(in srgb, var(--dsw-alias-label-secondary) 16%, transparent);border-radius:999px;flex:0 auto;padding:0 8px;font-size:10px;line-height:1.6;overflow:hidden}.lc-ov-session-body{align-items:center;gap:14px;min-width:0;display:flex}.lc-ov-mini-stats{flex-direction:column;flex:auto;gap:3px;min-width:0;display:flex}.lc-ov-mini-stat{justify-content:space-between;align-items:baseline;gap:10px;font-size:11px;display:flex}.lc-ov-mini-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;flex:none}.lc-ov-mini-value{font-variant-numeric:tabular-nums;white-space:nowrap;font-weight:600}.lc-ov-session-empty{color:var(--dsw-alias-label-secondary);padding:6px 0;font-size:11px;line-height:1.5}.lc-ov-session-preview{border-top:1px solid color-mix(in srgb, var(--dsw-alias-border-l2) 60%, transparent);align-items:baseline;gap:6px;min-width:0;margin-top:auto;padding-top:6px;display:flex}.lc-ov-session-preview-label{color:var(--dsw-alias-label-secondary);flex:none;font-size:10px}.lc-ov-session-preview-text{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);flex:0 auto;font-size:11px;line-height:1.5;overflow:hidden}.lc-ov-pager{justify-content:center;align-items:center;gap:10px;margin-top:12px;display:flex}.lc-ov-pager-btn{border:1px solid var(--dsw-alias-border-l2);width:26px;height:22px;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);background:0 0;border-radius:6px;flex:none;justify-content:center;align-items:center;line-height:1;display:flex}.lc-ov-pager-btn:hover:enabled{border-color:var(--dsw-alias-label-secondary)}.lc-ov-pager-btn:disabled{opacity:.4;cursor:default}.lc-ov-pager-n{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:11px}";
|
|
11270
11335
|
const tagId = "dsh-context/overview.css";
|
|
11271
11336
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
11272
11337
|
const tag = document.createElement("style");
|
|
@@ -11345,7 +11410,7 @@ window.__ModuleLoader__.load({
|
|
|
11345
11410
|
inject: (sessionId = "") => ({ hooks: { contextModal: modalStoreOf(sessionId) } })
|
|
11346
11411
|
}, (props) => (0, react.createElement)(ContextModal, props));
|
|
11347
11412
|
});
|
|
11348
|
-
const OverviewButton = makeOverviewButton(kit);
|
|
11413
|
+
const OverviewButton = makeOverviewButton(kit, settings);
|
|
11349
11414
|
ctx.slots.inject("sidebar.footer.action", () => {
|
|
11350
11415
|
return ctx.slots.register({
|
|
11351
11416
|
name: "sidebar.footer.action",
|
package/lib/index.js
CHANGED
|
@@ -2943,7 +2943,8 @@ const SettingsSchema = z$1.object({
|
|
|
2943
2943
|
"count",
|
|
2944
2944
|
"latest",
|
|
2945
2945
|
"path"
|
|
2946
|
-
]).default("count").loose()
|
|
2946
|
+
]).default("count").loose(),
|
|
2947
|
+
insightsEntry: z$1.union(["show", "hide"]).default("show").loose()
|
|
2947
2948
|
});
|
|
2948
2949
|
/** Serve the namespace while a settings provider is composed; inert otherwise. */
|
|
2949
2950
|
function installSettings(ctx) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-context",
|
|
3
|
-
"version": "0.53.
|
|
3
|
+
"version": "0.53.2",
|
|
4
4
|
"description": "A DeepSeek Harness plugin for context insight and management, with context dashboard and context command, for understanding how the context is made of, and how it evolves.",
|
|
5
5
|
"author": "bowenliang123",
|
|
6
6
|
"repository": {
|