dsh-toolfold 0.1.9 → 0.1.10

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/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  所有显著变更将记录于此。版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
4
4
 
5
+ ## [0.1.10] - 2026-09-10
6
+
7
+ > ⚠️ **版本支持**:自 `0.1.10` 起支持 DSH `>= 0.1.2-rc.1 < 0.1.3 || >= 0.1.5-rc.1 < 0.1.6`
8
+ >(以 `package.json engines.dsh` 为准)。
9
+
10
+ ### 功能变更
11
+ - **新增支持 DSH 0.1.5 系列**:`0.1.5-rc.1` 上的版本不匹配警告消除。
12
+
13
+ ### 缺陷修复
14
+ - **版本校验不再硬编码**:支持区间以 `package.json engines.dsh` 为唯一真相源(构建期注入产物);旧的写死单区间是 `0.1.5-rc.1` 误报感叹号的根因。console 警告与卡片 hover 提示改为直接引用 live 区间。
15
+ - **设置卡箭头换成官方图标**:header 的 `▾` 文字段落(字体相关、比官方粗)换成产品自己的 `IconChevronDownOutline14`,取不到时回落为像素一致的内联 SVG。
16
+
5
17
  ## [0.1.9] - 2026-09-05
6
18
 
7
19
  > ⚠️ **版本支持**:本节改动将随 `0.1.9` 发布;自 `0.1.9` 起,本插件仅支持 DSH `>= 0.1.2-rc.1` 且 `< 0.1.3`(安装节有同样提示)。
package/README.en.md CHANGED
@@ -58,7 +58,7 @@ dsh plugin --profile web remove dsh-toolfold
58
58
 
59
59
  After restart, the interface returns to its original state.
60
60
 
61
- > ⚠️ **Version support**: starting from `0.1.9`, this plugin only supports DSH `>= 0.1.2-rc.1` and `< 0.1.3`. On DSH versions outside this range, the settings card shows a version-mismatch warning and folding may not work correctly.
61
+ > ⚠️ **Version support**: the supported DSH range is whatever `engines.dsh` in `package.json` declares. On DSH versions outside this range, the settings card shows a version-mismatch warning (hover for the live range) and folding may not work correctly.
62
62
 
63
63
  ---
64
64
 
package/README.md CHANGED
@@ -57,7 +57,7 @@ dsh plugin --profile web remove dsh-toolfold
57
57
 
58
58
  重启后界面完全恢复原样。
59
59
 
60
- > ⚠️ **版本支持**:自 `0.1.9` 起,本插件仅支持 DSH `>= 0.1.2-rc.1` 且 `< 0.1.3`。在此范围之外的 DSH 上,设置卡片会显示版本不匹配警告,折叠功能可能无法正常工作。
60
+ > ⚠️ **版本支持**:本插件支持的 DSH 区间以 `package.json` 中 `engines.dsh` 声明为准。在此范围之外的 DSH 上,设置卡片会显示版本不匹配警告(hover 提示 live 区间),折叠功能可能无法正常工作。
61
61
 
62
62
  ---
63
63
 
package/lib/client.js CHANGED
@@ -150,15 +150,18 @@ window.__ModuleLoader__.load({
150
150
  var disposers = [];
151
151
  var compatState = "unknown";
152
152
  var compatVersion = null;
153
+ var compatRange = null;
153
154
  var compatWarned = false;
154
155
  function setCompat(info) {
155
156
  var state = info && (info.state === "ok" || info.state === "old" || info.state === "new") ? info.state : "unknown";
156
157
  var version = info && typeof info.version === "string" ? info.version : null;
158
+ var range = info && typeof info.range === "string" && info.range !== "" ? info.range : null;
157
159
  compatState = state;
158
160
  compatVersion = version;
161
+ compatRange = range;
159
162
  if (state !== "ok" && !compatWarned && typeof console !== "undefined" && typeof console.warn === "function") {
160
163
  compatWarned = true;
161
- console.warn("[dsh-toolfold] DSH 版本不匹配(当前 " + (version === null ? "未知" : version) + "):本插件支持 DSH >=0.1.2-rc.1 <0.1.3," + (state === "old" ? "当前版本过旧,请升级 DSH" : "当前版本过新,请等待插件更新") + "。");
164
+ console.warn("[dsh-toolfold] DSH 版本不匹配(当前 " + (version === null ? "未知" : version) + "):本插件支持 DSH " + (range === null ? "见 package.json engines.dsh 声明的区间" : range) + "," + (state === "old" ? "当前版本过旧,请升级 DSH" : "当前版本过新,请等待插件更新") + "。");
162
165
  }
163
166
  store.update({});
164
167
  }
@@ -249,11 +252,12 @@ window.__ModuleLoader__.load({
249
252
  status: function() {
250
253
  return scopeReady || routeOk ? "dsh" : "local";
251
254
  },
252
- /** Last host-reported DSH compatibility: { state, version }. */
255
+ /** Last host-reported DSH compatibility: { state, version, range }. */
253
256
  compat: function() {
254
257
  return {
255
258
  state: compatState,
256
- version: compatVersion
259
+ version: compatVersion,
260
+ range: compatRange
257
261
  };
258
262
  },
259
263
  load: routeLoad,
@@ -297,7 +301,7 @@ window.__ModuleLoader__.load({
297
301
  ".ccxHeadText{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}",
298
302
  ".ccxName{font-size:15px;font-weight:600;line-height:1.4;color:var(--dsw-alias-label-primary,#222)}",
299
303
  ".ccxDescription{font-size:13px;line-height:1.5;color:var(--dsw-alias-label-tertiary,#888)}",
300
- ".ccxChevron{flex:none;font-size:14px;line-height:1;color:var(--dsw-alias-label-tertiary,#888);transition:transform .16s}",
304
+ ".ccxChevron{flex:none;color:var(--dsw-alias-label-tertiary,#888);transition:transform .16s}",
301
305
  ".ccxChevronOpen{transform:rotate(180deg)}",
302
306
  ".ccxBody{border-top:1px solid var(--dsw-alias-border-l2,#e4e4e7);margin:0 16px;padding:4px 0 8px}",
303
307
  ".ccxField{display:flex;flex-direction:column;gap:6px;padding:12px 0}",
@@ -1657,9 +1661,76 @@ window.__ModuleLoader__.load({
1657
1661
  module.exports = { acquireReact };
1658
1662
  }));
1659
1663
  //#endregion
1664
+ //#region src/client/primitives.js
1665
+ var require_primitives = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1666
+ /**
1667
+ * Product icon bridge (chevron-down 14).
1668
+ *
1669
+ * The web shell seeds every client bundle's `require` with a frozen module
1670
+ * table that includes `@deepseek-ai/dsh-client-ui-primitives` — the same
1671
+ * `IconChevronDownOutline14` the product's own plugin cards render. That
1672
+ * table is a runtime surface, not a build dependency, so this module never
1673
+ * imports it statically (tsdown keeps the specifier external via
1674
+ * `deps.neverBundle`): `acquireChevronDown` tries the live component and
1675
+ * falls back to a pixel-identical inline SVG carrying the official path
1676
+ * data. Either way the settings card's chevron is the official artwork,
1677
+ * never a font-dependent text glyph.
1678
+ *
1679
+ * Resolution is lazy AND cached: the harness's throwing `require`, the
1680
+ * dynamic-runner body (no `require` at all), and headless tests all land
1681
+ * on the fallback without ever breaking module load.
1682
+ */
1683
+ var CHEVRON_DOWN_PATH = "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z";
1684
+ var cachedChevron = null;
1685
+ function tryOfficialChevron() {
1686
+ try {
1687
+ if (typeof require !== "function") return null;
1688
+ var prim = require("@deepseek-ai/dsh-client-ui-primitives");
1689
+ if (prim !== null && typeof prim === "object" && typeof prim.IconChevronDownOutline14 === "function") return prim.IconChevronDownOutline14;
1690
+ } catch (err) {}
1691
+ return null;
1692
+ }
1693
+ /**
1694
+ * Resolve the chevron-down component for the given React instance:
1695
+ * the product's own icon when the channel provides it, else the inline
1696
+ * fallback. Never throws; safe to call at card-render time only (module
1697
+ * load must stay side-effect free for the harness).
1698
+ */
1699
+ function acquireChevronDown(React) {
1700
+ if (cachedChevron !== null) return cachedChevron;
1701
+ var Official = tryOfficialChevron();
1702
+ if (Official !== null) {
1703
+ cachedChevron = Official;
1704
+ return cachedChevron;
1705
+ }
1706
+ cachedChevron = function FallbackChevronDown(props) {
1707
+ var p = props !== null && typeof props === "object" ? props : {};
1708
+ var size = p.size === void 0 ? 14 : p.size;
1709
+ return React.createElement("svg", {
1710
+ width: size,
1711
+ height: size,
1712
+ viewBox: "0 0 14 14",
1713
+ fill: "none",
1714
+ xmlns: "http://www.w3.org/2000/svg",
1715
+ "aria-hidden": true,
1716
+ className: p.className
1717
+ }, React.createElement("path", {
1718
+ d: CHEVRON_DOWN_PATH,
1719
+ fill: "currentColor"
1720
+ }));
1721
+ };
1722
+ return cachedChevron;
1723
+ }
1724
+ module.exports = {
1725
+ acquireChevronDown,
1726
+ CHEVRON_DOWN_PATH
1727
+ };
1728
+ }));
1729
+ //#endregion
1660
1730
  //#region src/client/card.js
1661
1731
  var require_card = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1662
1732
  const { acquireReact } = require_react_env();
1733
+ const { acquireChevronDown } = require_primitives();
1663
1734
  /**
1664
1735
  * One plugin card under Settings → 插件, owning the folding preferences.
1665
1736
  * @param props - injected face: useCcxSettings snapshot hook, setDur,
@@ -1686,13 +1757,17 @@ window.__ModuleLoader__.load({
1686
1757
  }, [state.stats]);
1687
1758
  var cardClass = isOpen ? "ccxCard ccxCardOpen" : "ccxCard";
1688
1759
  var compat = props.compat();
1760
+ var ChevronDown = acquireChevronDown(React);
1689
1761
  var warnEl = null;
1690
- if (compat.state === "old" || compat.state === "new") warnEl = React.createElement("span", {
1691
- className: "ccxWarn",
1692
- "data-tip": compat.state === "old" ? "版本不匹配:当前 DSH 版本落后。\n本插件需要 DSH >= 0.1.2-rc.1,请升级 DSH。" : "版本不匹配:当前 DSH 版本过新。\n本插件尚未适配,请等待插件更新。",
1693
- "aria-label": "版本不匹配",
1694
- role: "img"
1695
- }, "⚠");
1762
+ if (compat.state === "old" || compat.state === "new") {
1763
+ var rangeText = compat.range || "package.json engines.dsh 声明的区间";
1764
+ warnEl = React.createElement("span", {
1765
+ className: "ccxWarn",
1766
+ "data-tip": compat.state === "old" ? "版本不匹配:当前 DSH 版本落后。\n本插件需要 DSH " + rangeText + ",请升级 DSH。" : "版本不匹配:当前 DSH 版本过新。\n本插件支持 DSH " + rangeText + ",请等待插件更新。",
1767
+ "aria-label": "版本不匹配",
1768
+ role: "img"
1769
+ }, "⚠");
1770
+ }
1696
1771
  var header = React.createElement("button", {
1697
1772
  type: "button",
1698
1773
  className: "ccxHeader",
@@ -1701,7 +1776,7 @@ window.__ModuleLoader__.load({
1701
1776
  onClick: function() {
1702
1777
  setOpen(!isOpen);
1703
1778
  }
1704
- }, React.createElement("span", { className: "ccxHeadText" }, React.createElement("span", { className: "ccxName" }, "工具折叠"), React.createElement("span", { className: "ccxDescription" }, "折叠工具调用与思考的显示设置")), warnEl, React.createElement("span", { className: isOpen ? "ccxChevron ccxChevronOpen" : "ccxChevron" }, "▾"));
1779
+ }, React.createElement("span", { className: "ccxHeadText" }, React.createElement("span", { className: "ccxName" }, "工具折叠"), React.createElement("span", { className: "ccxDescription" }, "折叠工具调用与思考的显示设置")), warnEl, React.createElement(ChevronDown, { className: isOpen ? "ccxChevron ccxChevronOpen" : "ccxChevron" }));
1705
1780
  if (!isOpen) return React.createElement("li", { className: cardClass }, header);
1706
1781
  var enabledField = React.createElement("div", { className: "ccxField" }, React.createElement("div", { className: "ccxFieldHead" }, React.createElement("label", {
1707
1782
  className: "ccxFieldLabel",
package/lib/index.js CHANGED
@@ -2,6 +2,164 @@ import { createRequire } from "node:module";
2
2
  import z from "schemastery";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { resolve } from "node:path";
5
+ //#region src/host/version.js
6
+ /**
7
+ * dsh-toolfold — version-range helpers (host side, zero dependencies).
8
+ *
9
+ * The single source of truth for the supported DSH product range is this
10
+ * package's own `engines.dsh` field (an npm-style range such as
11
+ * ">=0.1.2-rc.1 <0.1.3 || >=0.1.5-rc.1 <0.1.6"). The build stamps that
12
+ * field into the host artifact via tsdown `define` (__DSH_ENGINES__, see
13
+ * tsdown.config.mjs) and the host half judges the running DSH with the
14
+ * matcher below — no range is hardcoded anywhere, so widening support is
15
+ * a one-line package.json edit + rebuild.
16
+ *
17
+ * Supported range grammar (the subset npm engines ranges actually use):
18
+ * range := branch ("||" branch)*
19
+ * branch := comparator ((" " | ",") comparator)*
20
+ * comparator := (">=" | "<=" | ">" | "<" | "=" | "==")? version
21
+ * A bare version means "=". Anything else (caret/tilde/x-ranges, hyphen
22
+ * ranges, junk) invalidates its branch; a range with no valid branch
23
+ * matches nothing and the caller reports 'unknown' instead of crying wolf.
24
+ *
25
+ * Prerelease gating follows npm semver: a prerelease running version only
26
+ * satisfies a branch that names a prerelease on the same
27
+ * [major, minor, patch] tuple (e.g. 0.1.5-rc.1 satisfies
28
+ * ">=0.1.5-rc.1 <0.1.6", but 0.1.3-rc.1 does NOT satisfy
29
+ * ">=0.1.2-rc.1 <0.1.3").
30
+ */
31
+ /** Parse "v1.2.3-rc.4+build" into comparable parts; null on junk. */
32
+ function parseVersion(value) {
33
+ const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(String(value));
34
+ if (!match) return null;
35
+ return {
36
+ core: [
37
+ Number(match[1]),
38
+ Number(match[2]),
39
+ Number(match[3])
40
+ ],
41
+ pre: match[4] === void 0 ? null : match[4].split(".")
42
+ };
43
+ }
44
+ /** Compare two parsed versions (semver precedence, prerelease-aware): -1/0/1. */
45
+ function compareParsed(a, b) {
46
+ for (let i = 0; i < 3; i++) if (a.core[i] !== b.core[i]) return a.core[i] < b.core[i] ? -1 : 1;
47
+ if (a.pre === null && b.pre === null) return 0;
48
+ if (a.pre === null) return 1;
49
+ if (b.pre === null) return -1;
50
+ const len = Math.max(a.pre.length, b.pre.length);
51
+ for (let i = 0; i < len; i++) {
52
+ const x = a.pre[i];
53
+ const y = b.pre[i];
54
+ if (x === void 0) return -1;
55
+ if (y === void 0) return 1;
56
+ const xn = /^\d+$/.test(x);
57
+ const yn = /^\d+$/.test(y);
58
+ if (xn && yn) {
59
+ const dx = Number(x);
60
+ const dy = Number(y);
61
+ if (dx !== dy) return dx < dy ? -1 : 1;
62
+ } else if (xn !== yn) return xn ? -1 : 1;
63
+ else if (x !== y) return x < y ? -1 : 1;
64
+ }
65
+ return 0;
66
+ }
67
+ /**
68
+ * Parse one "||" branch into comparators; null when the branch is unusable.
69
+ * The operator may be separated from its version by whitespace (npm
70
+ * semver tolerates ">= 1.2.3"), so comparators are matched globally and
71
+ * the gaps between matches must contain only whitespace/commas — anything
72
+ * else invalidates the branch.
73
+ */
74
+ function parseBranch(text) {
75
+ const src = String(text).trim();
76
+ if (src === "") return null;
77
+ const re = /(>=|<=|>|<|==|=)?\s*(v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)/g;
78
+ const comps = [];
79
+ let pos = 0;
80
+ let m;
81
+ while ((m = re.exec(src)) !== null) {
82
+ if (m[0] === "") {
83
+ re.lastIndex++;
84
+ continue;
85
+ }
86
+ if (!/^[\s,]*$/.test(src.slice(pos, m.index))) return null;
87
+ const v = parseVersion(m[2]);
88
+ if (v === null) return null;
89
+ comps.push({
90
+ op: m[1] === void 0 || m[1] === "==" ? "=" : m[1],
91
+ v
92
+ });
93
+ pos = m.index + m[0].length;
94
+ }
95
+ if (!/^[\s,]*$/.test(src.slice(pos))) return null;
96
+ return comps.length === 0 ? null : comps;
97
+ }
98
+ /** Parse a full range string into its valid branches; [] when unusable. */
99
+ function parseEnginesRange(rangeStr) {
100
+ if (typeof rangeStr !== "string") return [];
101
+ const branches = [];
102
+ for (const part of rangeStr.split("||")) {
103
+ const comps = parseBranch(part.trim());
104
+ if (comps !== null) branches.push(comps);
105
+ }
106
+ return branches;
107
+ }
108
+ function testComp(op, cmp) {
109
+ switch (op) {
110
+ case ">=": return cmp >= 0;
111
+ case "<=": return cmp <= 0;
112
+ case ">": return cmp > 0;
113
+ case "<": return cmp < 0;
114
+ default: return cmp === 0;
115
+ }
116
+ }
117
+ function sameCore(a, b) {
118
+ return a.core[0] === b.core[0] && a.core[1] === b.core[1] && a.core[2] === b.core[2];
119
+ }
120
+ /** npm semver prerelease gate for one branch. */
121
+ function gateOk(comps, ver) {
122
+ if (ver.pre === null) return true;
123
+ return comps.some((c) => c.v.pre !== null && sameCore(c.v, ver));
124
+ }
125
+ /** True when the parsed version satisfies at least one branch. */
126
+ function satisfiesEngines(parsed, branches) {
127
+ for (const comps of branches) {
128
+ let ok = true;
129
+ for (const c of comps) if (!testComp(c.op, compareParsed(parsed, c.v))) {
130
+ ok = false;
131
+ break;
132
+ }
133
+ if (ok && gateOk(comps, parsed)) return true;
134
+ }
135
+ return false;
136
+ }
137
+ /** Lowest lower bound across all branches (>=, >, =); null when unbounded. */
138
+ function lowestFloor(branches) {
139
+ let floor = null;
140
+ for (const comps of branches) for (const c of comps) if (c.op === ">=" || c.op === ">" || c.op === "=") {
141
+ if (floor === null || compareParsed(c.v, floor) < 0) floor = c.v;
142
+ }
143
+ return floor;
144
+ }
145
+ /**
146
+ * Judge a running version against a raw engines range string:
147
+ * 'ok' | 'old' | 'new' | 'unknown'. Never throws. Below every supported
148
+ * floor → 'old'; outside anywhere else (including between "||" gaps) →
149
+ * 'new'; unusable input on either side → 'unknown' (fail silent, never
150
+ * false-alarm).
151
+ */
152
+ function compatFor(version, rangeStr) {
153
+ const parsed = parseVersion(version);
154
+ if (parsed === null) return "unknown";
155
+ const branches = parseEnginesRange(rangeStr);
156
+ if (branches.length === 0) return "unknown";
157
+ if (satisfiesEngines(parsed, branches)) return "ok";
158
+ const floor = lowestFloor(branches);
159
+ if (floor !== null && compareParsed(parsed, floor) < 0) return "old";
160
+ return "new";
161
+ }
162
+ //#endregion
5
163
  //#region src/host/index.js
6
164
  /**
7
165
  * dsh-toolfold — HOST half.
@@ -16,11 +174,13 @@ import { resolve } from "node:path";
16
174
  * expectedRevision? }
17
175
  * → { ok, value: { value, revision, writable } }
18
176
  *
19
- * Every success response additionally carries `dsh: { version, state }` — the
20
- * running DSH product version and its compatibility with the supported range
21
- * ('ok' | 'old' | 'new' | 'unknown'). DSH does not enforce `engines.dsh`
22
- * anywhere, so the host half reports the mismatch itself and the settings
23
- * card warns the user (once-only console warning + hover-tip icon).
177
+ * Every success response additionally carries `dsh: { version, state, range }` —
178
+ * the running DSH product version, its compatibility with the supported
179
+ * range ('ok' | 'old' | 'new' | 'unknown'), and the raw `engines.dsh`
180
+ * requirement the verdict was judged against. DSH does not enforce
181
+ * `engines.dsh` anywhere, so the host half reports the mismatch itself
182
+ * and the settings card warns the user (once-only console warning +
183
+ * hover-tip icon quoting the live range).
24
184
  *
25
185
  * The browser half prefers the official `settingsScope` transport when the
26
186
  * deployment exposes this namespace, then this route, then browser
@@ -70,44 +230,7 @@ function resolveThinkMode(section) {
70
230
  if (section !== void 0 && section !== null && section.thinkAuto === false) return section.keepThink === true ? "keep" : "hide";
71
231
  return "auto";
72
232
  }
73
- const DSH_MIN = "0.1.2-rc.1";
74
- const DSH_MAX = "0.1.3";
75
- /** Parse "v1.2.3-rc.4+build" into comparable parts; null on junk. */
76
- function parseVersion(value) {
77
- const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(String(value));
78
- if (!match) return null;
79
- return {
80
- core: [
81
- Number(match[1]),
82
- Number(match[2]),
83
- Number(match[3])
84
- ],
85
- pre: match[4] === void 0 ? null : match[4].split(".")
86
- };
87
- }
88
- /** Compare two parsed versions (semver precedence, prerelease-aware): -1/0/1. */
89
- function compareParsed(a, b) {
90
- for (let i = 0; i < 3; i++) if (a.core[i] !== b.core[i]) return a.core[i] < b.core[i] ? -1 : 1;
91
- if (a.pre === null && b.pre === null) return 0;
92
- if (a.pre === null) return 1;
93
- if (b.pre === null) return -1;
94
- const len = Math.max(a.pre.length, b.pre.length);
95
- for (let i = 0; i < len; i++) {
96
- const x = a.pre[i];
97
- const y = b.pre[i];
98
- if (x === void 0) return -1;
99
- if (y === void 0) return 1;
100
- const xn = /^\d+$/.test(x);
101
- const yn = /^\d+$/.test(y);
102
- if (xn && yn) {
103
- const dx = Number(x);
104
- const dy = Number(y);
105
- if (dx !== dy) return dx < dy ? -1 : 1;
106
- } else if (xn !== yn) return xn ? -1 : 1;
107
- else if (x !== y) return x < y ? -1 : 1;
108
- }
109
- return 0;
110
- }
233
+ const ENGINES_RANGE = ">=0.1.2-rc.1 <0.1.3 || >=0.1.5-rc.1 <0.1.6";
111
234
  /**
112
235
  * The @deepseek-ai/dsh version this process was launched from: process.argv[1]
113
236
  * is the CLI's entry, and module resolution from that file reaches the
@@ -127,26 +250,24 @@ function dshVersion() {
127
250
  } catch (error) {}
128
251
  return cachedDshVersion;
129
252
  }
130
- /** Running DSH vs the supported range: 'ok' | 'old' | 'new' | 'unknown'. */
253
+ /**
254
+ * Running DSH vs the supported range (see ./version.js): the report the
255
+ * settings card renders its warning icon from. `range` is the raw
256
+ * `engines.dsh` string so the card can quote the live requirement instead
257
+ * of hardcoding it: { version, state: 'ok'|'old'|'new'|'unknown', range }.
258
+ */
131
259
  function dshCompat() {
132
260
  const version = dshVersion();
133
- if (version === null) return {
134
- version: null,
135
- state: "unknown"
136
- };
137
- const parsed = parseVersion(version);
138
- if (parsed === null) return {
261
+ const range = ENGINES_RANGE;
262
+ if (version === null || false) return {
139
263
  version,
140
- state: "unknown"
264
+ state: "unknown",
265
+ range
141
266
  };
142
- const min = parseVersion(DSH_MIN);
143
- const max = parseVersion(DSH_MAX);
144
- let state = "ok";
145
- if (compareParsed(parsed, min) < 0) state = "old";
146
- else if (compareParsed(parsed, max) >= 0) state = "new";
147
267
  return {
148
268
  version,
149
- state
269
+ state: compatFor(version, range),
270
+ range
150
271
  };
151
272
  }
152
273
  /** Write one JSON response. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-toolfold",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "工具调用与思考的折叠显示:连续工具调用折叠为最后一个调用(可展开),已完成的思考随组折叠(可保留、展开时按原顺序显示),进行中的思考保持独立显示。",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,7 +36,7 @@
36
36
  "CHANGELOG.md"
37
37
  ],
38
38
  "engines": {
39
- "dsh": ">=0.1.2-rc.1 <0.1.3"
39
+ "dsh": ">=0.1.2-rc.1 <0.1.3 || >=0.1.5-rc.1 <0.1.6"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "schemastery": "^3.18.0"
@@ -51,6 +51,7 @@
51
51
  "build": "tsdown",
52
52
  "build:watch": "tsdown --watch",
53
53
  "test:engine": "node tools/engine-smoke.mjs",
54
+ "test:version": "node tools/version-smoke.mjs",
54
55
  "probe:live": "node tools/live-probe.mjs",
55
56
  "install:dsh": "node scripts/install-dsh.cjs",
56
57
  "uninstall:dsh": "node scripts/install-dsh.cjs uninstall"