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 +12 -0
- package/README.en.md +1 -1
- package/README.md +1 -1
- package/lib/client.js +86 -11
- package/lib/index.js +178 -57
- package/package.json +3 -2
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**:
|
|
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
|
-
> ⚠️
|
|
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
|
|
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;
|
|
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")
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
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(
|
|
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 }` —
|
|
20
|
-
* running DSH product version
|
|
21
|
-
* ('ok' | 'old' | 'new' | 'unknown')
|
|
22
|
-
*
|
|
23
|
-
*
|
|
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
|
|
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
|
-
/**
|
|
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
|
-
|
|
134
|
-
|
|
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.
|
|
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"
|