dsh-usage-state 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +8 -3
- package/README.md +8 -3
- package/cordis.patch.yml +12 -1
- package/lib/client.js +50 -5
- package/lib/index.js +72 -27
- package/package.json +13 -8
package/README.en.md
CHANGED
|
@@ -22,7 +22,8 @@ hover any segment: Source DeepSeek · Mode API balance · Granted 0 ·
|
|
|
22
22
|
|
|
23
23
|
## Install
|
|
24
24
|
|
|
25
|
-
**Requirements**: DSH `0.
|
|
25
|
+
**Requirements**: DSH `0.2.0-rc.2` or a later 0.2 release, Node ≥ 20, installed into the `web` profile. The package **ships the prebuilt `lib/`**, so installation has no build step.
|
|
26
|
+
**On the 0.1 line install `0.3.2` instead**: DSH 0.2 replaced the whole settings API (`settingsScope` / `settings.register` → `configForms` / the plugin's own `Config`), and the two share no surface, so `0.4.0` and up support the 0.2 line only (see revision 17 of [`docs/design-consensus.md`](docs/design-consensus.md)).
|
|
26
27
|
|
|
27
28
|
```bash
|
|
28
29
|
# 1) install (npm package)
|
|
@@ -46,6 +47,8 @@ For development, a local path works too (host-side changes still need a DSH rest
|
|
|
46
47
|
dsh plugin --profile web add /path/to/dsh-usage-state
|
|
47
48
|
```
|
|
48
49
|
|
|
50
|
+
It is also listed in [dsh-market](https://github.com/dsh-market/dsh-market): search for `usage state` (or `takboo`) and install it in one click — the plugin is on the [awesome-dsh-plugin](https://awesome-dsh-plugin.com) curated list under Usage & Billing.
|
|
51
|
+
|
|
49
52
|
Nothing showing up after installing? See the troubleshooting table at the end of [`docs/adapters.md`](docs/adapters.md).
|
|
50
53
|
|
|
51
54
|
## Quick start
|
|
@@ -96,9 +99,11 @@ Expanding **Advanced** lets you override the source and endpoint, name a credent
|
|
|
96
99
|
|
|
97
100
|
## Compatibility
|
|
98
101
|
|
|
99
|
-
-
|
|
102
|
+
- **0.2 line only**: `engines.dsh` = `>=0.2.0-rc.2 <0.3.0-0` (this is what dsh-market's badge and install gate read). On an earlier host, install `0.3.2`.
|
|
103
|
+
- `peerDependencies` carry `@deepseek-ai/dsh-settings` (`^0.2.0-rc.2`) and `@deepseek-ai/schemastery` (`^3.18.2`). The first one is deliberate: the runtime install gate only reads `@deepseek-ai/dsh*` peers, so declaring it makes a 0.1.x host **refuse the install** instead of accepting it and then failing to boot. Both are platform-provided; pnpm may print a `missing peer` warning for them, which is expected.
|
|
104
|
+
- Version `0.4.0` migrates to the 0.2 settings model (`Config` + `configForms`, with cross-entry config read through `configEditor`). Verification and results: [`docs/implementation.md`](docs/implementation.md) §10; rationale: [`docs/design-consensus.md`](docs/design-consensus.md) revision 17.
|
|
105
|
+
- Version `0.3.2` (last of the 0.1 line) only widened `engines.dsh`; **its claimed 0.2 compatibility was wrong** — on `0.2.0-rc.2` it fails the entire web boot because `settingsScope` does not exist there.
|
|
100
106
|
- Published to npm as [`dsh-usage-state`](https://www.npmjs.com/package/dsh-usage-state); GitHub installs work too.
|
|
101
|
-
- Version `0.3.1`: DeepSeek, z.ai and OpenCode Zen Go are verified against live accounts; see the limitations below.
|
|
102
107
|
|
|
103
108
|
## Limitations
|
|
104
109
|
|
package/README.md
CHANGED
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
|
|
25
25
|
## 安装
|
|
26
26
|
|
|
27
|
-
**前置条件**:DSH `0.
|
|
27
|
+
**前置条件**:DSH `0.2.0-rc.2` 或更新的 0.2 线、Node ≥ 20,装进 `web` profile。包内**自带预构建的 `lib/`**,安装时没有构建步骤。
|
|
28
|
+
**用 0.1 线请装 `0.3.2`**:DSH 0.2 换掉了整套设置 API(`settingsScope` / `settings.register` → `configForms` / 插件自带 `Config`),两套 API 没有重叠,所以 `0.4.0` 起只支持 0.2 线(原因见 [`docs/design-consensus.md`](docs/design-consensus.md) 修订 17)。
|
|
28
29
|
|
|
29
30
|
```bash
|
|
30
31
|
# 1) 安装(npm 包)
|
|
@@ -48,6 +49,8 @@ dsh plugin --profile web add github:takboo/dsh-usage-state
|
|
|
48
49
|
dsh plugin --profile web add /path/to/dsh-usage-state
|
|
49
50
|
```
|
|
50
51
|
|
|
52
|
+
也可以在 [dsh-market](https://github.com/dsh-market/dsh-market) 里搜索 `usage state`(或 `takboo`)一键安装——本插件已收录在精选列表 [awesome-dsh-plugin](https://awesome-dsh-plugin.com) 的「用量与计费」分类。
|
|
53
|
+
|
|
51
54
|
装好后界面没有出现?见 [`docs/adapters.md`](docs/adapters.md) 末尾的排查表。
|
|
52
55
|
|
|
53
56
|
## 快速开始
|
|
@@ -120,9 +123,11 @@ dsh plugin --profile web add /path/to/dsh-usage-state
|
|
|
120
123
|
|
|
121
124
|
## 兼容性
|
|
122
125
|
|
|
123
|
-
-
|
|
126
|
+
- **只支持 DSH 0.2 线**:`engines.dsh` = `>=0.2.0-rc.2 <0.3.0-0`(市场读它做徽标与"可安装"判定)。0.2 之前的宿主请装 `0.3.2`。
|
|
127
|
+
- `peerDependencies` 里有 `@deepseek-ai/dsh-settings`(`^0.2.0-rc.2`)与 `@deepseek-ai/schemastery`(`^3.18.2`):前者是**故意的**——平台的运行时安装闸门只读 `@deepseek-ai/dsh*` 的 peer,声明它可以让 0.1.x 宿主在**安装时**就拒绝,而不是装上之后把启动搞崩;两者都由平台提供,pnpm 可能为此打一行 `missing peer` 警告,属预期。
|
|
128
|
+
- 版本 `0.4.0`:迁到 0.2 原生设置模型(`Config` + `configForms`,宿主侧 `configEditor` 读跨条目配置)。验证方式与结论见 [`docs/implementation.md`](docs/implementation.md) §10、决策见 [`docs/design-consensus.md`](docs/design-consensus.md) 修订 17。
|
|
129
|
+
- 版本 `0.3.2`(0.1 线末版):仅放宽 `engines.dsh`;**它声称的 0.2 兼容是错的**(0.3.2 在 0.2.0-rc.2 上会因 `settingsScope` 不存在而让整个 web 启动失败)。
|
|
124
130
|
- 同名发布在 npm([`dsh-usage-state`](https://www.npmjs.com/package/dsh-usage-state)),也可从 GitHub 直接安装。
|
|
125
|
-
- 版本 `0.3.1`:DeepSeek、z.ai 与 OpenCode Zen Go 已在真机验证,其余见下。
|
|
126
131
|
|
|
127
132
|
## 已知限制
|
|
128
133
|
|
package/cordis.patch.yml
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
# Mount layer contributed by this plugin.
|
|
2
2
|
#
|
|
3
3
|
# `dsh plugin add` appends this package to the profile's `dsh.profile.bundles`,
|
|
4
|
-
# which applies this patch on boot
|
|
4
|
+
# which applies this patch on boot.
|
|
5
|
+
#
|
|
6
|
+
# The row id **is the settings namespace** on DSH 0.2 (`configForms.get(id)` on the
|
|
7
|
+
# client, `entry.options.id` on the host), so it has to keep matching
|
|
8
|
+
# `USAGE_STATE_NS` in `src/host/settings.ts`.
|
|
9
|
+
#
|
|
10
|
+
# `config: {}` gives every install a section to resolve: without it the entry has
|
|
11
|
+
# no config at all, the settings projection answers `undefined`, and the status
|
|
12
|
+
# line stays silent until the user saves something. A user's own
|
|
13
|
+
# `- id: usage-state, config: { … }` row still replaces this whole value, because
|
|
14
|
+
# the profile patch layer applies after every bundle layer.
|
|
5
15
|
- insert:
|
|
6
16
|
- id: usage-state
|
|
7
17
|
name: dsh-usage-state
|
|
18
|
+
config: {}
|
package/lib/client.js
CHANGED
|
@@ -1524,6 +1524,54 @@ window.__ModuleLoader__.load({
|
|
|
1524
1524
|
}
|
|
1525
1525
|
}
|
|
1526
1526
|
//#endregion
|
|
1527
|
+
//#region src/client/settings-form.ts
|
|
1528
|
+
/**
|
|
1529
|
+
* Present one `configForms` entry as the settings scope the components consume.
|
|
1530
|
+
*
|
|
1531
|
+
* Two things the platform form does not do for us:
|
|
1532
|
+
*
|
|
1533
|
+
* - **Decoding.** The host hands the stored section through unchanged, because this
|
|
1534
|
+
* plugin's schema declares no fields on purpose (see `host/settings.ts`). So
|
|
1535
|
+
* `normalizeConfig` runs here, keeping the single lenient decoder the plugin has
|
|
1536
|
+
* always had. A namespace the platform has not answered yet keeps `value`
|
|
1537
|
+
* undefined, which is what makes the status line stay silent instead of drawing
|
|
1538
|
+
* defaults the host never accepted.
|
|
1539
|
+
* - **Snapshot identity.** `useSettingsValue` stores whatever `getSnapshot()`
|
|
1540
|
+
* returns, so a fresh object per call would re-render forever. The decoded
|
|
1541
|
+
* snapshot is cached against the platform snapshot it came from.
|
|
1542
|
+
*/
|
|
1543
|
+
function usageStateSettings(form) {
|
|
1544
|
+
let source;
|
|
1545
|
+
let decoded;
|
|
1546
|
+
const snapshot = () => {
|
|
1547
|
+
const next = form.getSnapshot();
|
|
1548
|
+
if (decoded === void 0 || next !== source) {
|
|
1549
|
+
source = next;
|
|
1550
|
+
decoded = {
|
|
1551
|
+
status: next.status,
|
|
1552
|
+
value: next.value === void 0 ? void 0 : normalizeConfig(next.value),
|
|
1553
|
+
revision: next.revision,
|
|
1554
|
+
writable: next.writable,
|
|
1555
|
+
mode: next.mode
|
|
1556
|
+
};
|
|
1557
|
+
}
|
|
1558
|
+
return decoded;
|
|
1559
|
+
};
|
|
1560
|
+
return {
|
|
1561
|
+
getSnapshot: snapshot,
|
|
1562
|
+
subscribe: (listener) => form.subscribe(listener),
|
|
1563
|
+
set: async (field, value) => {
|
|
1564
|
+
await form.set(field, value);
|
|
1565
|
+
},
|
|
1566
|
+
unset: async (field) => {
|
|
1567
|
+
await form.unset(field);
|
|
1568
|
+
},
|
|
1569
|
+
mutate: async (ops, expectedRevision) => {
|
|
1570
|
+
await form.mutate(ops, expectedRevision);
|
|
1571
|
+
}
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
//#endregion
|
|
1527
1575
|
//#region src/client/slots.ts
|
|
1528
1576
|
const STATUS_LINE_SLOTS = [{
|
|
1529
1577
|
name: "conversation.composer.dock",
|
|
@@ -1680,7 +1728,7 @@ window.__ModuleLoader__.load({
|
|
|
1680
1728
|
const inject = [
|
|
1681
1729
|
"slots",
|
|
1682
1730
|
"locale",
|
|
1683
|
-
"
|
|
1731
|
+
"configForms",
|
|
1684
1732
|
"remote",
|
|
1685
1733
|
"remote.session",
|
|
1686
1734
|
"remote.credentials"
|
|
@@ -1727,10 +1775,7 @@ window.__ModuleLoader__.load({
|
|
|
1727
1775
|
en
|
|
1728
1776
|
}), "dsh-usage-state: dictionaries");
|
|
1729
1777
|
const t = ctx.locale.bind(LOCALE_NS);
|
|
1730
|
-
const settings = ctx.
|
|
1731
|
-
namespace: USAGE_STATE_NS,
|
|
1732
|
-
decode: (section) => normalizeConfig(section)
|
|
1733
|
-
});
|
|
1778
|
+
const settings = usageStateSettings(ctx.configForms.get(USAGE_STATE_NS));
|
|
1734
1779
|
const usageStateRemote = () => remoteService(ctx, "remote.usageState");
|
|
1735
1780
|
const store = new UsageStateClientStore({
|
|
1736
1781
|
getState: async (force) => {
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
+
import z from "@deepseek-ai/schemastery";
|
|
4
5
|
//#region src/shared/config.ts
|
|
5
6
|
const DEFAULT_CONFIG = {
|
|
6
7
|
models: [],
|
|
@@ -1410,29 +1411,42 @@ var UsageStateService = class {
|
|
|
1410
1411
|
};
|
|
1411
1412
|
//#endregion
|
|
1412
1413
|
//#region src/host/settings.ts
|
|
1413
|
-
/** Settings namespace owned by this plugin; must match `/^[a-z][a-z0-9-]*$/`. */
|
|
1414
|
-
const USAGE_STATE_NS = "usage-state";
|
|
1415
|
-
const usageStateSchema = Object.assign((section) => normalizeConfig(section), { toJSON: () => ({
|
|
1416
|
-
uid: 1,
|
|
1417
|
-
refs: { 1: {
|
|
1418
|
-
type: "object",
|
|
1419
|
-
meta: {},
|
|
1420
|
-
dict: {}
|
|
1421
|
-
} }
|
|
1422
|
-
}) });
|
|
1423
1414
|
/**
|
|
1424
|
-
*
|
|
1415
|
+
* The plugin's `Config`, which the 0.2 loader resolves from this module export
|
|
1416
|
+
* (`entry.fiber.runtime.Config`), validates with `Config['~standard']`, and hands
|
|
1417
|
+
* to `apply` as its second argument.
|
|
1425
1418
|
*
|
|
1426
|
-
*
|
|
1427
|
-
*
|
|
1428
|
-
*
|
|
1429
|
-
*
|
|
1419
|
+
* Two deliberate choices, both about staying compatible with documents this
|
|
1420
|
+
* plugin does not fully control:
|
|
1421
|
+
*
|
|
1422
|
+
* - **A volatile root.** The loader hands a volatile schema's value over as a live
|
|
1423
|
+
* reference, commits edits into it in place, and announces them as
|
|
1424
|
+
* `loader/volatile-update`. A non-volatile schema would instead find the config
|
|
1425
|
+
* "changed" on every settings write and remount the plugin.
|
|
1426
|
+
* - **`any`, not a field-by-field object.** The settings service projects form
|
|
1427
|
+
* values *through* the schema, so a declared object schema silently drops every
|
|
1428
|
+
* field it does not declare — including keys a hand-edited document carries, and
|
|
1429
|
+
* including keys a future version adds. Validation stays where it has always
|
|
1430
|
+
* been: `normalizeConfig`, which is deliberately lenient, so a dirty document
|
|
1431
|
+
* still loads instead of failing the entry.
|
|
1432
|
+
*/
|
|
1433
|
+
const Config = z.any().volatile();
|
|
1434
|
+
/**
|
|
1435
|
+
* Keep a live snapshot of the plugin's own config.
|
|
1436
|
+
*
|
|
1437
|
+
* `reference` is `apply`'s second argument. On a host that does not model volatile
|
|
1438
|
+
* config (or when the entry carries no schema) the loader passes nothing, and the
|
|
1439
|
+
* plugin keeps its own defaults — the same graceful degradation the 0.1 path got
|
|
1440
|
+
* from `ctx.inject(['settings'], …)`, which 0.2 no longer offers.
|
|
1430
1441
|
*/
|
|
1431
|
-
function installUsageStateSettings(ctx, onConfig) {
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
onConfig(normalizeConfig(
|
|
1435
|
-
|
|
1442
|
+
function installUsageStateSettings(ctx, reference, onConfig) {
|
|
1443
|
+
if (reference === void 0) return;
|
|
1444
|
+
const publish = () => {
|
|
1445
|
+
onConfig(normalizeConfig(reference.get()));
|
|
1446
|
+
};
|
|
1447
|
+
publish();
|
|
1448
|
+
ctx.on("loader/volatile-update", () => {
|
|
1449
|
+
publish();
|
|
1436
1450
|
});
|
|
1437
1451
|
}
|
|
1438
1452
|
//#endregion
|
|
@@ -1598,11 +1612,38 @@ function resolveTargets(config, options = {}) {
|
|
|
1598
1612
|
const name = "usage-state";
|
|
1599
1613
|
/** `timer` is what provides `ctx.timeout` / `ctx.interval`. */
|
|
1600
1614
|
const inject = ["timer"];
|
|
1615
|
+
/** The shared volatile-reference protocol (`cosmokit.volatile.write`). */
|
|
1616
|
+
const VOLATILE_WRITE = Symbol.for("cosmokit.volatile.write");
|
|
1617
|
+
/** Whether a loader config value is a live volatile reference rather than data. */
|
|
1618
|
+
function isVolatileRef(value) {
|
|
1619
|
+
return typeof value === "object" && value !== null && VOLATILE_WRITE in value && typeof value.get === "function";
|
|
1620
|
+
}
|
|
1621
|
+
/**
|
|
1622
|
+
* Detach a loader config: volatile fields are live references, and a snapshot is
|
|
1623
|
+
* only useful once they are read out. Mirrors the platform's own `plainConfig`,
|
|
1624
|
+
* including its refusal to guard against cycles (config cannot contain one).
|
|
1625
|
+
*/
|
|
1626
|
+
function plainConfig(value) {
|
|
1627
|
+
if (isVolatileRef(value)) return plainConfig(value.get());
|
|
1628
|
+
if (Array.isArray(value)) return value.map((item) => plainConfig(item));
|
|
1629
|
+
if (value !== null && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, plainConfig(item)]));
|
|
1630
|
+
return value;
|
|
1631
|
+
}
|
|
1632
|
+
/**
|
|
1633
|
+
* Another plugin's resolved config, by profile entry id.
|
|
1634
|
+
*
|
|
1635
|
+
* DSH 0.1 answered this from `settings.get(namespace)`; 0.2 derives every
|
|
1636
|
+
* namespace from the entry that owns it, so the resolved value lives on that
|
|
1637
|
+
* entry's fiber (the same place the platform's settings service reads it).
|
|
1638
|
+
* A host without a config editor degrades to `undefined`, which is what this
|
|
1639
|
+
* plugin's provider refinement has always done when a namespace was absent.
|
|
1640
|
+
*/
|
|
1601
1641
|
function readNamespace(ctx, namespace) {
|
|
1602
|
-
const
|
|
1603
|
-
if (
|
|
1642
|
+
const editor = ctx.get("configEditor");
|
|
1643
|
+
if (typeof editor?.entries !== "function") return void 0;
|
|
1604
1644
|
try {
|
|
1605
|
-
|
|
1645
|
+
const entry = editor.entries().find((candidate) => candidate.options?.id === namespace);
|
|
1646
|
+
return entry?.fiber?.config === void 0 ? void 0 : plainConfig(entry.fiber.config);
|
|
1606
1647
|
} catch {
|
|
1607
1648
|
return;
|
|
1608
1649
|
}
|
|
@@ -1675,7 +1716,7 @@ function createUsageState(ctx, deps = {}) {
|
|
|
1675
1716
|
const catalog = toSourceCatalog(ALL_SOURCES);
|
|
1676
1717
|
const lookup = createCredentialLookup(ctx, deps.credentialFallback ?? {});
|
|
1677
1718
|
let config = DEFAULT_CONFIG;
|
|
1678
|
-
installUsageStateSettings(ctx, (next) => {
|
|
1719
|
+
installUsageStateSettings(ctx, deps.config, (next) => {
|
|
1679
1720
|
config = next;
|
|
1680
1721
|
});
|
|
1681
1722
|
/**
|
|
@@ -1757,8 +1798,12 @@ function createUsageState(ctx, deps = {}) {
|
|
|
1757
1798
|
store.start();
|
|
1758
1799
|
return provideUsageState(ctx, service);
|
|
1759
1800
|
}
|
|
1760
|
-
|
|
1761
|
-
|
|
1801
|
+
/**
|
|
1802
|
+
* Cordis entry point. The second argument is the loader's resolved config for this
|
|
1803
|
+
* entry — a live reference, because the exported schema is a volatile root.
|
|
1804
|
+
*/
|
|
1805
|
+
function apply(ctx, config) {
|
|
1806
|
+
createUsageState(ctx, { config });
|
|
1762
1807
|
}
|
|
1763
1808
|
//#endregion
|
|
1764
|
-
export { apply, createCredentialLookup, createUsageState, inject, name, provideUsageState };
|
|
1809
|
+
export { Config, apply, createCredentialLookup, createUsageState, inject, isVolatileRef, name, plainConfig, provideUsageState };
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-usage-state",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "DSH plugin: show account balance (API mode) or coding-plan quota (5h/7d/30d) for the model in use",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"engines": {
|
|
8
8
|
"node": ">=20",
|
|
9
|
-
"dsh": ">=0.
|
|
9
|
+
"dsh": ">=0.2.0-rc.2 <0.3.0-0"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
12
|
"test": "node --import ./tests/support/client-render-hook.mjs --test",
|
|
@@ -28,12 +28,13 @@
|
|
|
28
28
|
"./package.json": "./package.json"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@deepseek-ai/dsh-client-locale": "^0.
|
|
32
|
-
"@deepseek-ai/dsh-client-store": "^0.
|
|
33
|
-
"@deepseek-ai/dsh-client-ui-conversation": "^0.
|
|
34
|
-
"@deepseek-ai/dsh-client-ui-primitives": "^0.
|
|
35
|
-
"@deepseek-ai/dsh-client-ui-slots": "^0.
|
|
36
|
-
"@deepseek-ai/dsh-typert-loader": "^0.
|
|
31
|
+
"@deepseek-ai/dsh-client-locale": "^0.2.0-rc.2",
|
|
32
|
+
"@deepseek-ai/dsh-client-store": "^0.2.0-rc.2",
|
|
33
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.2.0-rc.2",
|
|
34
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.2.0-rc.2",
|
|
35
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.2.0-rc.2",
|
|
36
|
+
"@deepseek-ai/dsh-typert-loader": "^0.2.0-rc.2",
|
|
37
|
+
"@deepseek-ai/schemastery": "^3.18.2",
|
|
37
38
|
"@types/node": "^24.0.0",
|
|
38
39
|
"@types/react": "~18.3.1",
|
|
39
40
|
"@types/react-dom": "~18.3.1",
|
|
@@ -43,6 +44,10 @@
|
|
|
43
44
|
"typescript": "^5.9.2",
|
|
44
45
|
"unrun": "^0.2.39"
|
|
45
46
|
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"@deepseek-ai/dsh-settings": "^0.2.0-rc.2",
|
|
49
|
+
"@deepseek-ai/schemastery": "^3.18.2"
|
|
50
|
+
},
|
|
46
51
|
"dependencies": {
|
|
47
52
|
"zod": "4.5.1"
|
|
48
53
|
},
|