dsh-context 0.53.1 → 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 +325 -342
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -3400,11 +3400,12 @@ window.__ModuleLoader__.load({
|
|
|
3400
3400
|
}
|
|
3401
3401
|
//#endregion
|
|
3402
3402
|
//#region src/client/format.ts
|
|
3403
|
-
/** `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. */
|
|
3404
3404
|
function fmt(n) {
|
|
3405
3405
|
if (n === void 0 || n === null || isNaN(n)) return "—";
|
|
3406
3406
|
const sign = n < 0 ? "-" : "";
|
|
3407
3407
|
const a = Math.abs(n);
|
|
3408
|
+
if (a >= 1e9) return sign + (a / 1e9).toFixed(1) + "B";
|
|
3408
3409
|
if (a >= 1e6) return sign + (a / 1e6).toFixed(1) + "M";
|
|
3409
3410
|
if (a >= 1e3) return sign + (a / 1e3).toFixed(1) + "k";
|
|
3410
3411
|
return sign + String(Math.round(a));
|
|
@@ -5293,77 +5294,67 @@ window.__ModuleLoader__.load({
|
|
|
5293
5294
|
};
|
|
5294
5295
|
}
|
|
5295
5296
|
//#endregion
|
|
5296
|
-
//#region
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
* Build the address of a file read through one Session.
|
|
5315
|
-
* @param sessionId - the Session whose Host workspace resolves the path.
|
|
5316
|
-
* @param path - absolute or workspace-relative path; backslashes are normalized to `/`, and leading `./` prefixes are dropped.
|
|
5317
|
-
* @returns the `dsh-resource://file/session/<sessionId>/<path>` address.
|
|
5318
|
-
*/
|
|
5319
|
-
function sessionFileAddress(sessionId, path) {
|
|
5320
|
-
const normalized = path.replace(/\\/g, "/").replace(/^(?:\.\/)+/, "");
|
|
5321
|
-
return `${FILE_ADDRESS_PREFIX}session/${encodeSegment(sessionId)}/${encodePath(normalized)}`;
|
|
5322
|
-
}
|
|
5323
|
-
/**
|
|
5324
|
-
* Browser-safe Workspace path and display helpers.
|
|
5325
|
-
* @module @deepseek-ai/dsh-util-workspace-path
|
|
5326
|
-
*/
|
|
5327
|
-
/** Whether a path uses a Windows drive or UNC prefix. */
|
|
5328
|
-
function isWindowsStylePath(value) {
|
|
5329
|
-
return /^[A-Za-z]:[/\\]/.test(value) || value.startsWith("\\\\");
|
|
5330
|
-
}
|
|
5331
|
-
/**
|
|
5332
|
-
* Whether a path is absolute in either spelling the Host accepts: POSIX (`/a/b`) or Windows drive or UNC.
|
|
5333
|
-
* @param path - the path to classify.
|
|
5334
|
-
* @returns `true` for an absolute path; `false` for a Workspace-relative one.
|
|
5335
|
-
*/
|
|
5336
|
-
function isAbsoluteWorkspacePath(path) {
|
|
5337
|
-
return path.startsWith("/") || isWindowsStylePath(path);
|
|
5338
|
-
}
|
|
5339
|
-
/**
|
|
5340
|
-
* Read the final non-empty segment of a Workspace path for display.
|
|
5341
|
-
* Workspace-label surfaces use this helper instead of deriving another basename.
|
|
5342
|
-
* @param path - Workspace directory path using POSIX or Windows separators.
|
|
5343
|
-
* @returns the final segment, or an empty string for a separator-only path.
|
|
5344
|
-
*/
|
|
5345
|
-
function workspaceTitleOf(path) {
|
|
5346
|
-
const trimmed = path.replace(/[/\\]+$/, "");
|
|
5347
|
-
const separator = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
|
|
5348
|
-
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
|
+
};
|
|
5349
5315
|
}
|
|
5316
|
+
const overviewStore = createStore();
|
|
5317
|
+
//#endregion
|
|
5318
|
+
//#region src/client/components/overviewButton.tsx
|
|
5350
5319
|
/**
|
|
5351
|
-
* The
|
|
5352
|
-
*
|
|
5353
|
-
*
|
|
5354
|
-
*
|
|
5355
|
-
*
|
|
5356
|
-
*
|
|
5357
|
-
*
|
|
5358
|
-
*
|
|
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.
|
|
5359
5331
|
*/
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
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
|
+
};
|
|
5367
5358
|
}
|
|
5368
5359
|
//#endregion
|
|
5369
5360
|
//#region src/shared/providers.ts
|
|
@@ -5543,6 +5534,258 @@ window.__ModuleLoader__.load({
|
|
|
5543
5534
|
return formatCost(amount, currency).replace(/0+$/, "").replace(/\.$/, "");
|
|
5544
5535
|
}
|
|
5545
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
|
|
5546
5789
|
//#region src/client/overview.ts
|
|
5547
5790
|
/**
|
|
5548
5791
|
* The Context Dashboard's data layer: everything the panel renders is derived
|
|
@@ -5576,21 +5819,6 @@ window.__ModuleLoader__.load({
|
|
|
5576
5819
|
return null;
|
|
5577
5820
|
}
|
|
5578
5821
|
}
|
|
5579
|
-
/** The running-session tally for the footer entry's badge (0 on any shape failure). */
|
|
5580
|
-
function runningCountOf(snapshot) {
|
|
5581
|
-
const state = asRecord(snapshot);
|
|
5582
|
-
if (state === null) return 0;
|
|
5583
|
-
const byId = asRecord(state.byId);
|
|
5584
|
-
if (byId === null) return 0;
|
|
5585
|
-
let count = 0;
|
|
5586
|
-
try {
|
|
5587
|
-
for (const id of Object.keys(byId)) {
|
|
5588
|
-
const row = asRecord(byId[id]);
|
|
5589
|
-
if (row !== null && row.running === true) count++;
|
|
5590
|
-
}
|
|
5591
|
-
} catch {}
|
|
5592
|
-
return count;
|
|
5593
|
-
}
|
|
5594
5822
|
/**
|
|
5595
5823
|
* The `useWorkspaces` standard prop read — same guarded-hook contract as
|
|
5596
5824
|
* {@link sessionsSnapshotOf}. The overview joins its session → workspace
|
|
@@ -5857,7 +6085,12 @@ window.__ModuleLoader__.load({
|
|
|
5857
6085
|
let toolsMs = 0;
|
|
5858
6086
|
let calls = 0;
|
|
5859
6087
|
let wallMs = 0;
|
|
6088
|
+
let costSessions = 0;
|
|
6089
|
+
let usageSessions = 0;
|
|
5860
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++;
|
|
5861
6094
|
turns += turnsOf(row.timeline);
|
|
5862
6095
|
const timing = row.timeline?.timing;
|
|
5863
6096
|
toolCalls += timing?.toolCalls ?? 0;
|
|
@@ -5871,7 +6104,9 @@ window.__ModuleLoader__.load({
|
|
|
5871
6104
|
tokens: totals?.total ?? 0,
|
|
5872
6105
|
turns,
|
|
5873
6106
|
cost: estimateSessionCost(usage, prices, currency),
|
|
6107
|
+
costSessions,
|
|
5874
6108
|
cacheHit: totals === null ? null : cacheHitPercent(totals.cacheRead, totals.input + totals.cacheRead + totals.cacheWrite),
|
|
6109
|
+
usageSessions,
|
|
5875
6110
|
toolCalls,
|
|
5876
6111
|
toolsMs,
|
|
5877
6112
|
calls,
|
|
@@ -5948,258 +6183,6 @@ window.__ModuleLoader__.load({
|
|
|
5948
6183
|
return t("ov.time.d", { n: Math.floor(hours / 24) });
|
|
5949
6184
|
}
|
|
5950
6185
|
//#endregion
|
|
5951
|
-
//#region src/client/overviewStore.ts
|
|
5952
|
-
function createStore() {
|
|
5953
|
-
let open = false;
|
|
5954
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
5955
|
-
return {
|
|
5956
|
-
subscribe: (listener) => {
|
|
5957
|
-
listeners.add(listener);
|
|
5958
|
-
return () => {
|
|
5959
|
-
listeners.delete(listener);
|
|
5960
|
-
};
|
|
5961
|
-
},
|
|
5962
|
-
getSnapshot: () => open,
|
|
5963
|
-
set: (next) => {
|
|
5964
|
-
if (next === open) return;
|
|
5965
|
-
open = next;
|
|
5966
|
-
for (const listener of listeners) listener();
|
|
5967
|
-
}
|
|
5968
|
-
};
|
|
5969
|
-
}
|
|
5970
|
-
const overviewStore = createStore();
|
|
5971
|
-
//#endregion
|
|
5972
|
-
//#region src/client/components/overviewButton.tsx
|
|
5973
|
-
/**
|
|
5974
|
-
* The Context Dashboard's sidebar entry: a footer action stacked directly
|
|
5975
|
-
* above Settings (the harness's own foot layout: footer actions, then the
|
|
5976
|
-
* settings row), mirroring the Settings trigger's geometry in both column
|
|
5977
|
-
* widths. The button carries the plugin emblem and, on the wide
|
|
5978
|
-
* column, its label; a badge counts the sessions currently running (the one
|
|
5979
|
-
* glanceable live fact a footer can carry). Clicking opens the overview
|
|
5980
|
-
* overlay through the shared module store (overviewStore.ts).
|
|
5981
|
-
*
|
|
5982
|
-
* The per-user `insightsEntry` preference takes the entry down (renders
|
|
5983
|
-
* null) without unregistering the seat. The subscription fails open: an
|
|
5984
|
-
* absent settings store, an unserved namespace, or a value the plugin
|
|
5985
|
-
* cannot understand all leave the entry visible.
|
|
5986
|
-
*/
|
|
5987
|
-
/** Stable subscription faces for the settings-less degrade (no re-subscribes). */
|
|
5988
|
-
const subscribeNever = () => () => {};
|
|
5989
|
-
const entryShown = () => "show";
|
|
5990
|
-
function makeOverviewButton(kit, settings) {
|
|
5991
|
-
const { t } = kit;
|
|
5992
|
-
const subscribeEntry = settings === void 0 ? subscribeNever : (listener) => settings.store.subscribe(listener);
|
|
5993
|
-
const getEntry = settings === void 0 ? entryShown : () => settings.insightsEntry();
|
|
5994
|
-
return function OverviewButton(props) {
|
|
5995
|
-
const running = runningCountOf(sessionsSnapshotOf(props));
|
|
5996
|
-
if ((0, react.useSyncExternalStore)(subscribeEntry, getEntry) === "hide") return null;
|
|
5997
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
5998
|
-
type: "button",
|
|
5999
|
-
className: props.wide === true ? "lc-ov-entry" : "lc-ov-entry lc-ov-entry-rail",
|
|
6000
|
-
title: t("ov.entry"),
|
|
6001
|
-
"aria-label": t("ov.entry"),
|
|
6002
|
-
onClick: () => {
|
|
6003
|
-
overviewStore.set(true);
|
|
6004
|
-
},
|
|
6005
|
-
children: [
|
|
6006
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContextIcon, {
|
|
6007
|
-
size: props.wide === true ? 16 : 18,
|
|
6008
|
-
className: "lc-ov-entry-icon"
|
|
6009
|
-
}),
|
|
6010
|
-
props.wide === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6011
|
-
className: "lc-ov-entry-label",
|
|
6012
|
-
children: t("ov.entry")
|
|
6013
|
-
}),
|
|
6014
|
-
running > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6015
|
-
className: "lc-ov-badge",
|
|
6016
|
-
"aria-hidden": "true",
|
|
6017
|
-
children: running
|
|
6018
|
-
})
|
|
6019
|
-
]
|
|
6020
|
-
});
|
|
6021
|
-
};
|
|
6022
|
-
}
|
|
6023
|
-
//#endregion
|
|
6024
|
-
//#region node_modules/.pnpm/@opencode-ai+models@0.0.72/node_modules/@opencode-ai/models/dist/error.js
|
|
6025
|
-
/**
|
|
6026
|
-
* The only error thrown by the models.dev client.
|
|
6027
|
-
*
|
|
6028
|
-
* - `Transport` — the fetch itself failed (network, DNS, abort). `cause` is the underlying error.
|
|
6029
|
-
* - `UnexpectedStatus` — non-2xx response. `cause` is `{ status: number }`.
|
|
6030
|
-
* - `MalformedResponse` — the body was empty or not valid JSON. `cause` is the parse error, if any.
|
|
6031
|
-
*/
|
|
6032
|
-
var ModelsDevError = class extends Error {
|
|
6033
|
-
reason;
|
|
6034
|
-
name = "ModelsDevError";
|
|
6035
|
-
constructor(reason, options) {
|
|
6036
|
-
super(reason, options);
|
|
6037
|
-
this.reason = reason;
|
|
6038
|
-
}
|
|
6039
|
-
};
|
|
6040
|
-
//#endregion
|
|
6041
|
-
//#region node_modules/.pnpm/@opencode-ai+models@0.0.72/node_modules/@opencode-ai/models/dist/client.js
|
|
6042
|
-
/**
|
|
6043
|
-
* Creates a stateless models.dev client. Every method performs exactly one
|
|
6044
|
-
* `GET` and nothing is ever cached — callers who want caching should wrap
|
|
6045
|
-
* calls with their own policy. For a no-network alternative, see the
|
|
6046
|
-
* `@opencode-ai/models/snapshot` entrypoint.
|
|
6047
|
-
*/
|
|
6048
|
-
function make(options = {}) {
|
|
6049
|
-
const baseUrl = options.baseUrl ?? "https://models.dev";
|
|
6050
|
-
const base = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/";
|
|
6051
|
-
const request = async (path, requestOptions) => {
|
|
6052
|
-
const fetch = options.fetch ?? globalThis.fetch;
|
|
6053
|
-
const headers = new Headers();
|
|
6054
|
-
for (const [key, value] of new Headers(options.headers)) headers.set(key, value);
|
|
6055
|
-
for (const [key, value] of new Headers(requestOptions?.headers)) headers.set(key, value);
|
|
6056
|
-
let response;
|
|
6057
|
-
try {
|
|
6058
|
-
response = await fetch(new URL(path, base), {
|
|
6059
|
-
method: "GET",
|
|
6060
|
-
headers,
|
|
6061
|
-
signal: requestOptions?.signal
|
|
6062
|
-
});
|
|
6063
|
-
} catch (cause) {
|
|
6064
|
-
throw new ModelsDevError("Transport", { cause });
|
|
6065
|
-
}
|
|
6066
|
-
if (!response.ok) {
|
|
6067
|
-
try {
|
|
6068
|
-
await response.body?.cancel();
|
|
6069
|
-
} catch {}
|
|
6070
|
-
throw new ModelsDevError("UnexpectedStatus", { cause: { status: response.status } });
|
|
6071
|
-
}
|
|
6072
|
-
let text;
|
|
6073
|
-
try {
|
|
6074
|
-
text = await response.text();
|
|
6075
|
-
} catch (cause) {
|
|
6076
|
-
throw new ModelsDevError("Transport", { cause });
|
|
6077
|
-
}
|
|
6078
|
-
if (text === "") throw new ModelsDevError("MalformedResponse");
|
|
6079
|
-
try {
|
|
6080
|
-
return JSON.parse(text);
|
|
6081
|
-
} catch (cause) {
|
|
6082
|
-
throw new ModelsDevError("MalformedResponse", { cause });
|
|
6083
|
-
}
|
|
6084
|
-
};
|
|
6085
|
-
return {
|
|
6086
|
-
/** All providers with their models, pricing, and limits (`/api.json`). */
|
|
6087
|
-
providers: (requestOptions) => request("api.json", requestOptions),
|
|
6088
|
-
/** Provider-agnostic model metadata (`/models.json`). */
|
|
6089
|
-
models: (requestOptions) => request("models.json", requestOptions),
|
|
6090
|
-
/** Providers and model metadata in a single request (`/catalog.json`). */
|
|
6091
|
-
catalog: (requestOptions) => request("catalog.json", requestOptions)
|
|
6092
|
-
};
|
|
6093
|
-
}
|
|
6094
|
-
//#endregion
|
|
6095
|
-
//#region src/client/modelPrices.ts
|
|
6096
|
-
/**
|
|
6097
|
-
* The client's model-price book (client/cost.ts prices from it): the
|
|
6098
|
-
* models.dev registry, fetched through the official @opencode-ai/models
|
|
6099
|
-
* SDK. The registry payload is untrusted wire input, so `pricesBookOf`
|
|
6100
|
-
* re-proves every field at the boundary — a non-conforming provider/model/
|
|
6101
|
-
* cost entry drops whole. The book keeps EVERY provider that prices (keyed
|
|
6102
|
-
* by the registry's own provider id), so a dsh provider id outside the
|
|
6103
|
-
* rename table still prices by direct passthrough. One fetch per page load,
|
|
6104
|
-
* kicked on first subscribe; a failure degrades to a visible state the cost
|
|
6105
|
-
* cell notes, with a backed-off automatic retry — never a spinner, and
|
|
6106
|
-
* never an unhandled rejection.
|
|
6107
|
-
*/
|
|
6108
|
-
/** One finite non-negative registry figure, or null. */
|
|
6109
|
-
function rateOf(value) {
|
|
6110
|
-
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
6111
|
-
}
|
|
6112
|
-
/**
|
|
6113
|
-
* Extract the whole registry's per-model USD rates from a delivered
|
|
6114
|
-
* providers payload (`/api.json`), keyed by the registry's provider ids.
|
|
6115
|
-
* Any shape failure skips just that entry; a payload that is not a record
|
|
6116
|
-
* at all returns null (the store treats it as a failed fetch and retries).
|
|
6117
|
-
*/
|
|
6118
|
-
function pricesBookOf(value) {
|
|
6119
|
-
const data = asRecord(value);
|
|
6120
|
-
if (data === null || Array.isArray(data)) return null;
|
|
6121
|
-
const book = {};
|
|
6122
|
-
for (const providerId of Object.keys(data)) {
|
|
6123
|
-
const provider = asRecord(data[providerId]);
|
|
6124
|
-
const modelList = provider !== null ? asRecord(provider.models) : null;
|
|
6125
|
-
if (modelList === null) continue;
|
|
6126
|
-
const models = {};
|
|
6127
|
-
for (const id of Object.keys(modelList)) {
|
|
6128
|
-
const model = asRecord(modelList[id]);
|
|
6129
|
-
const cost = model !== null ? asRecord(model.cost) : null;
|
|
6130
|
-
if (cost === null) continue;
|
|
6131
|
-
const miss = rateOf(cost.input);
|
|
6132
|
-
const out = rateOf(cost.output);
|
|
6133
|
-
if (miss === null || out === null) continue;
|
|
6134
|
-
models[id] = {
|
|
6135
|
-
hit: rateOf(cost.cache_read) ?? miss,
|
|
6136
|
-
miss,
|
|
6137
|
-
write: rateOf(cost.cache_write) ?? miss,
|
|
6138
|
-
out
|
|
6139
|
-
};
|
|
6140
|
-
}
|
|
6141
|
-
if (Object.keys(models).length > 0) book[providerId] = models;
|
|
6142
|
-
}
|
|
6143
|
-
return book;
|
|
6144
|
-
}
|
|
6145
|
-
const defaultLoader = () => make().providers();
|
|
6146
|
-
/** The retry backoff base; each consecutive failure doubles the wait, capped at 3 doublings. */
|
|
6147
|
-
const RETRY_BASE_MS = 3e4;
|
|
6148
|
-
let loader = defaultLoader;
|
|
6149
|
-
let snap = {
|
|
6150
|
-
prices: null,
|
|
6151
|
-
failed: false
|
|
6152
|
-
};
|
|
6153
|
-
let inFlight = false;
|
|
6154
|
-
let failures = 0;
|
|
6155
|
-
let timer = null;
|
|
6156
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
6157
|
-
function fail() {
|
|
6158
|
-
snap = {
|
|
6159
|
-
...snap,
|
|
6160
|
-
failed: true
|
|
6161
|
-
};
|
|
6162
|
-
failures++;
|
|
6163
|
-
timer = setTimeout(() => {
|
|
6164
|
-
timer = null;
|
|
6165
|
-
fire();
|
|
6166
|
-
}, RETRY_BASE_MS * 2 ** Math.min(failures - 1, 3));
|
|
6167
|
-
}
|
|
6168
|
-
async function fire() {
|
|
6169
|
-
inFlight = true;
|
|
6170
|
-
try {
|
|
6171
|
-
const book = pricesBookOf(await loader());
|
|
6172
|
-
if (book !== null) {
|
|
6173
|
-
snap = {
|
|
6174
|
-
prices: book,
|
|
6175
|
-
failed: false
|
|
6176
|
-
};
|
|
6177
|
-
failures = 0;
|
|
6178
|
-
} else fail();
|
|
6179
|
-
} catch {
|
|
6180
|
-
fail();
|
|
6181
|
-
}
|
|
6182
|
-
inFlight = false;
|
|
6183
|
-
for (const fn of listeners) fn();
|
|
6184
|
-
}
|
|
6185
|
-
function kick() {
|
|
6186
|
-
if (snap.prices !== null || inFlight || timer !== null) return;
|
|
6187
|
-
fire();
|
|
6188
|
-
}
|
|
6189
|
-
/** The useSyncExternalStore seam: subscribing also kicks the first fetch. */
|
|
6190
|
-
const subscribeModelPrices = (fn) => {
|
|
6191
|
-
listeners.add(fn);
|
|
6192
|
-
kick();
|
|
6193
|
-
return () => {
|
|
6194
|
-
listeners.delete(fn);
|
|
6195
|
-
};
|
|
6196
|
-
};
|
|
6197
|
-
const getModelPricesSnap = () => snap;
|
|
6198
|
-
/** The stats board's read of the price book (null until the fetch lands). */
|
|
6199
|
-
function useModelPrices() {
|
|
6200
|
-
return (0, react.useSyncExternalStore)(subscribeModelPrices, getModelPricesSnap);
|
|
6201
|
-
}
|
|
6202
|
-
//#endregion
|
|
6203
6186
|
//#region src/shared/days.ts
|
|
6204
6187
|
/**
|
|
6205
6188
|
* The local-day key (`YYYY-MM-DD`) shared by the activity fold (host) and the
|
|
@@ -6824,7 +6807,7 @@ window.__ModuleLoader__.load({
|
|
|
6824
6807
|
}),
|
|
6825
6808
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6826
6809
|
className: "lc-stat-sub",
|
|
6827
|
-
children: t("ov.kpi.sessionsSub", { n: kpi.
|
|
6810
|
+
children: t("ov.kpi.sessionsSub", { n: kpi.costSessions })
|
|
6828
6811
|
})
|
|
6829
6812
|
]
|
|
6830
6813
|
}),
|
|
@@ -6841,7 +6824,7 @@ window.__ModuleLoader__.load({
|
|
|
6841
6824
|
}),
|
|
6842
6825
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6843
6826
|
className: "lc-stat-sub",
|
|
6844
|
-
children: t("ov.kpi.sessionsSub", { n: kpi.
|
|
6827
|
+
children: t("ov.kpi.sessionsSub", { n: kpi.usageSessions })
|
|
6845
6828
|
})
|
|
6846
6829
|
]
|
|
6847
6830
|
}),
|
|
@@ -9492,7 +9475,7 @@ window.__ModuleLoader__.load({
|
|
|
9492
9475
|
return function PluginInfo() {
|
|
9493
9476
|
const [latest, setLatest] = (0, react.useState)(null);
|
|
9494
9477
|
(0, react.useEffect)(() => {
|
|
9495
|
-
if ("0.53.
|
|
9478
|
+
if ("0.53.2".includes("-dev")) return;
|
|
9496
9479
|
let on = true;
|
|
9497
9480
|
fetchLatestVersion().then((v) => {
|
|
9498
9481
|
if (on && v) setLatest(v);
|
|
@@ -9501,8 +9484,8 @@ window.__ModuleLoader__.load({
|
|
|
9501
9484
|
on = false;
|
|
9502
9485
|
};
|
|
9503
9486
|
}, []);
|
|
9504
|
-
const update = latest !== null && isNewerVersion(latest, "0.53.
|
|
9505
|
-
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)";
|
|
9506
9489
|
const nameValue = [nameText];
|
|
9507
9490
|
if (update) nameValue.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9508
9491
|
className: "lc-pi-update",
|
|
@@ -11348,7 +11331,7 @@ window.__ModuleLoader__.load({
|
|
|
11348
11331
|
}
|
|
11349
11332
|
//#endregion
|
|
11350
11333
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/overview.css.mjs
|
|
11351
|
-
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;position:relative;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-badge{box-sizing:border-box;background:var(--color-green-500);color:#fff;pointer-events:none;border-radius:999px;justify-content:center;align-items:center;min-width:15px;height:15px;padding:0 4px;font-size:9px;font-weight:700;line-height:1;display:flex;position:absolute;top:1px;right:4px}.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}";
|
|
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}";
|
|
11352
11335
|
const tagId = "dsh-context/overview.css";
|
|
11353
11336
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
11354
11337
|
const tag = document.createElement("style");
|
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": {
|