dsh-vscode-mode 0.1.42 → 0.1.44

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/index.js CHANGED
@@ -128,18 +128,9 @@ const FILE_OPEN_SETTINGS_NS = "dsh-vscode-mode";
128
128
  const FILE_OPEN_DEFAULT = "auto";
129
129
  let depsPromise;
130
130
  /**
131
- * 按命令目录构建 keybindings 显式键形状(每键独立默认值)。
132
- * @author ddj 2026年08月26号
133
- * @param z schemastery 命名空间
134
- * @returns keybindings 字段形状
135
- */
136
- function keybindingsShape(z) {
137
- const shape = {};
138
- for (const [id, chord] of Object.entries(KEYBINDING_DEFAULTS)) shape[id] = z.string().default(chord);
139
- return shape;
140
- }
141
- /**
142
- * 动态加载设置依赖(模块级缓存;任一缺失返回 null 而非抛错)。
131
+ * 动态加载设置依赖(模块级缓存;任一缺失/失败返回 null 而非抛错)。
132
+ * installSettingsSection 仅在 rc 线 dsh-settings 中存在时提供(alpha 起移除,
133
+ * 属性探测得到 undefined,不抛错)。
143
134
  * @author ddj 2026年08月24号
144
135
  * @returns 设置依赖或 null
145
136
  */
@@ -150,6 +141,101 @@ function loadSettingsDeps() {
150
141
  })).catch(() => null);
151
142
  return depsPromise;
152
143
  }
144
+ const INSTALL_UNMOUNTED = "设置 section 尚未装配";
145
+ const INSTALL_LEGACY = "rc 线:dsh-settings.installSettingsSection";
146
+ const INSTALL_SERVICE = "0.1.2-alpha 线:settings 服务 installSection";
147
+ const INSTALL_NONE = "两路均不可用:设置持久化降级为配置值";
148
+ let observedInstall = {
149
+ strategy: "unknown",
150
+ note: INSTALL_UNMOUNTED
151
+ };
152
+ /** 记录最近一次安装策略(供兼容报告展示;失败路径也记录,便于诊断)。 */
153
+ function recordInstall(strategy, note) {
154
+ observedInstall = {
155
+ strategy,
156
+ note
157
+ };
158
+ return strategy;
159
+ }
160
+ /** 读取观测到的安装策略(供报告;测试可用 reset 复位)。 */
161
+ function settingsInstallStrategy() {
162
+ return observedInstall.strategy;
163
+ }
164
+ /** 读取观测到的安装策略说明文案。 */
165
+ function settingsInstallNote() {
166
+ return observedInstall.note;
167
+ }
168
+ /**
169
+ * 设置 section 版本自适应安装(核心策略分派)。
170
+ * legacy:dsh-settings 仍导出 installSettingsSection(rc 线)→ 原样调用,行为与旧版一致。
171
+ * service:该导出已移除(0.1.2-alpha 起)→ 经 ctx.inject(['settings']) 走服务方法
172
+ * provider.installSection(owner, ns, schema, entry, hooks)(等义封装,含
173
+ * base 层与 fiber 卸载回退)。回调内方法缺失再降级记录 none。
174
+ * none:两条路由都不存在 → 仅记录并告警,调用方按配置值运行。
175
+ * 全程不抛错、不产生未捕获 rejection。
176
+ * @author ddj 2026年09月02号
177
+ * @param ctx DSH host 上下文(inject 可选探测)
178
+ * @param ns 设置命名空间
179
+ * @param schema schemastery schema
180
+ * @param entry 初始设置值(作为 base 层)
181
+ * @param hooks 设置源绑定与变更回调
182
+ * @param loader 依赖装载器(测试注入)
183
+ * @returns 采用/观测到的策略
184
+ */
185
+ async function runSettingsInstall(ctx, ns, schema, entry, hooks, loader = loadSettingsDeps) {
186
+ let deps = null;
187
+ try {
188
+ deps = await loader();
189
+ } catch {}
190
+ if (!deps) {
191
+ console.warn("[dsh-vscode-mode] 设置依赖不可用,section " + ns + " 未安装(配置回退)");
192
+ return recordInstall("none", INSTALL_NONE);
193
+ }
194
+ const legacy = deps.installSettingsSection;
195
+ if (typeof legacy === "function") try {
196
+ legacy(ctx, ns, schema, entry, hooks);
197
+ return recordInstall("legacy", INSTALL_LEGACY);
198
+ } catch (error) {
199
+ console.warn("[dsh-vscode-mode] legacy 设置安装失败,尝试服务路由:" + String(error));
200
+ }
201
+ const ctxInject = ctx.inject;
202
+ if (typeof ctxInject !== "function") return recordInstall("none", INSTALL_NONE);
203
+ try {
204
+ ctxInject(["settings"], (sctx) => {
205
+ const sc = sctx;
206
+ const provider = typeof sc.get === "function" ? sc.get("settings") : sc.settings;
207
+ const install = provider?.installSection;
208
+ if (typeof install !== "function") {
209
+ console.warn("[dsh-vscode-mode] settings 服务无 installSection(DSH 版本 API 变化),section " + ns + " 降级为配置值");
210
+ recordInstall("none", INSTALL_NONE);
211
+ return;
212
+ }
213
+ try {
214
+ install.call(provider, ctx, ns, schema, entry, hooks);
215
+ recordInstall("service", INSTALL_SERVICE);
216
+ } catch (error) {
217
+ console.warn("[dsh-vscode-mode] settings.installSection 安装失败(" + String(error) + "),section " + ns + " 降级为配置值");
218
+ recordInstall("none", INSTALL_NONE);
219
+ }
220
+ });
221
+ } catch (error) {
222
+ console.warn("[dsh-vscode-mode] settings 服务路由不可用(" + String(error) + ")");
223
+ return recordInstall("none", INSTALL_NONE);
224
+ }
225
+ if (observedInstall.strategy !== "unknown") return observedInstall.strategy;
226
+ return recordInstall("service", "已调度 settings 服务 installSection(等待 settings 就绪)");
227
+ }
228
+ /**
229
+ * 按命令目录构建 keybindings 显式键形状(每键独立默认值)。
230
+ * @author ddj 2026年08月26号
231
+ * @param z schemastery 命名空间
232
+ * @returns keybindings 字段形状
233
+ */
234
+ function keybindingsShape(z) {
235
+ const shape = {};
236
+ for (const [id, chord] of Object.entries(KEYBINDING_DEFAULTS)) shape[id] = z.string().default(chord);
237
+ return shape;
238
+ }
153
239
  function normalizeValue(value) {
154
240
  if (typeof value !== "string" || value.trim() === "") return FILE_OPEN_DEFAULT;
155
241
  return value.trim();
@@ -158,8 +244,8 @@ function configValue(config) {
158
244
  return normalizeValue(config?.fileOpenTool);
159
245
  }
160
246
  /**
161
- * 安装设置 section(动态依赖;缺失返回 false 不抛错)。
162
- * @author ddj 2026年08月24号
247
+ * 安装设置 section(版本自适应;任一策略不可用返回 false 不抛错)。
248
+ * @author ddj 2026年08月24号 / 2026年09月02号
163
249
  * @param ctx DSH host 上下文
164
250
  * @param ns 设置命名空间
165
251
  * @param entry 初始设置值
@@ -168,14 +254,19 @@ function configValue(config) {
168
254
  * @returns 是否成功安装
169
255
  */
170
256
  async function installOpenSettingsSection(ctx, ns, entry, hooks, loader = loadSettingsDeps) {
171
- const deps = await loader();
257
+ let deps = null;
258
+ try {
259
+ deps = await loader();
260
+ } catch {}
172
261
  if (!deps) return false;
173
- const schema = deps.z.object({
262
+ const strategy = await runSettingsInstall(ctx, ns, deps.z.object({
174
263
  fileOpenTool: deps.z.string().default(FILE_OPEN_DEFAULT),
175
264
  keybindings: deps.z.object(keybindingsShape(deps.z)).default({ ...KEYBINDING_DEFAULTS })
176
- });
177
- deps.installSettingsSection(ctx, ns, schema, entry, hooks);
178
- return true;
265
+ }), entry, {
266
+ setSource: (source) => hooks.setSource(source),
267
+ onChange: hooks.onChange
268
+ }, loader);
269
+ return strategy === "legacy" || strategy === "service";
179
270
  }
180
271
  /**
181
272
  * 注册设置命名空间,并提供 host 侧的读取与更新状态。
@@ -370,6 +461,101 @@ async function runPnpmInstall(ctx, profileDir) {
370
461
  }
371
462
  }
372
463
  //#endregion
464
+ //#region src/dshVersion.ts
465
+ /**
466
+ * dsh-vscode-mode host — DSH 核心版本探测与区间匹配(版本适配机制的地基)。
467
+ * 约定:以运行时可解析的 @deepseek-ai/dsh-settings 包版本代表 DSH 核心版本——
468
+ * 核心包发布锁步同版(rc.2 / alpha.2 全树同版实证),且该包是插件动态依赖面、
469
+ * exports 已放行 ./package.json。解析失败按候选降级(dsh-web-app / dsh-base / dsh),
470
+ * 全部失败返回空串(报告显示"未探测",功能按能力探测运行)。
471
+ * 纯函数(parse / compare / inRange / familyLabel)可在 node 环境单测。
472
+ * 作者 ddj 2026-09-02
473
+ */
474
+ const VERSION_RE = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
475
+ /** 解析版本串;非法返回 null(不抛错)。 */
476
+ function parseDshVersion(input) {
477
+ const match = VERSION_RE.exec(input.trim());
478
+ if (!match) return null;
479
+ return {
480
+ major: Number(match[1]),
481
+ minor: Number(match[2]),
482
+ patch: Number(match[3]),
483
+ pre: match[4] ? match[4].split(".") : []
484
+ };
485
+ }
486
+ /** 预发布标识比较:纯数字按值;数字段 < 字母段;字母按字典序(semver 规则)。 */
487
+ function comparePreId(a, b) {
488
+ const numericA = /^\d+$/.test(a);
489
+ const numericB = /^\d+$/.test(b);
490
+ if (numericA && numericB) return Number(a) - Number(b);
491
+ if (numericA !== numericB) return numericA ? -1 : 1;
492
+ return a < b ? -1 : a > b ? 1 : 0;
493
+ }
494
+ /** 比较两个已解析版本:a<b → -1;相等 → 0;a>b → 1。 */
495
+ function compareDshVersions(a, b) {
496
+ for (const key of [
497
+ "major",
498
+ "minor",
499
+ "patch"
500
+ ]) if (a[key] !== b[key]) return a[key] < b[key] ? -1 : 1;
501
+ if (a.pre.length === b.pre.length && a.pre.every((part, index) => part === b.pre[index])) return 0;
502
+ if (a.pre.length === 0) return 1;
503
+ if (b.pre.length === 0) return -1;
504
+ const length = Math.max(a.pre.length, b.pre.length);
505
+ for (let i = 0; i < length; i++) {
506
+ const left = a.pre[i];
507
+ const right = b.pre[i];
508
+ if (left === void 0) return -1;
509
+ if (right === void 0) return 1;
510
+ const cmp = comparePreId(left, right);
511
+ if (cmp !== 0) return cmp;
512
+ }
513
+ return 0;
514
+ }
515
+ /** 版本是否落在区间内(入参解析失败一律不命中)。 */
516
+ function inDshRange(version, range) {
517
+ if (!version) return false;
518
+ if (range.from) {
519
+ const lower = parseDshVersion(range.from);
520
+ if (!lower || compareDshVersions(version, lower) < 0) return false;
521
+ }
522
+ if (range.to) {
523
+ const upper = parseDshVersion(range.to);
524
+ if (!upper || compareDshVersions(version, upper) > 0) return false;
525
+ }
526
+ return true;
527
+ }
528
+ /** 版本线标签:报告与文档展示版本归属;不可解析返回 '未知'。 */
529
+ function familyLabel(input) {
530
+ const version = parseDshVersion(input);
531
+ if (!version) return "未知";
532
+ if (inDshRange(version, { from: "0.1.2-alpha.1" })) return "0.1.2-alpha 及更新(设置 API=settings.installSection)";
533
+ return "0.1.0/0.1.1 rc 线(设置 API=installSettingsSection)";
534
+ }
535
+ /** 探测候选:按与插件运行环境相关性排序,逐个尝试解析 package.json。 */
536
+ const VERSION_CANDIDATES = [
537
+ "@deepseek-ai/dsh-settings/package.json",
538
+ "@deepseek-ai/dsh-web-app/package.json",
539
+ "@deepseek-ai/dsh-base/package.json",
540
+ "@deepseek-ai/dsh/package.json"
541
+ ];
542
+ let detectedVersion;
543
+ /** 探测运行中 DSH 核心版本(模块级缓存;失败空串,不抛错)。 */
544
+ function detectDshVersion() {
545
+ if (detectedVersion !== void 0) return detectedVersion;
546
+ detectedVersion = "";
547
+ const require = createRequire(import.meta.url);
548
+ for (const specifier of VERSION_CANDIDATES) try {
549
+ const file = require.resolve(specifier);
550
+ const pkg = JSON.parse(readFileSync(file, "utf8"));
551
+ if (typeof pkg.version === "string" && parseDshVersion(pkg.version) !== null) {
552
+ detectedVersion = pkg.version;
553
+ break;
554
+ }
555
+ } catch {}
556
+ return detectedVersion;
557
+ }
558
+ //#endregion
373
559
  //#region src/shared/rpc.ts
374
560
  /** webServer 精确路由。 */
375
561
  const RPC_PATH = "/edrv/rpc";
@@ -745,26 +931,63 @@ function detectGuards(ctx) {
745
931
  note: duplicates[0] ?? "唯一装配"
746
932
  }];
747
933
  }
934
+ /** 已实测覆盖的最高 DSH 版本(适配矩阵上界,超过则提示,见 buildReport)。 */
935
+ const TESTED_DSH_MAX = "0.1.2-alpha.4";
936
+ /** 版本适配机制状态行:DSH 版本探测 + 设置 section 安装策略。 */
937
+ function versionAdapters(dshVersion) {
938
+ const adapters = [];
939
+ const parsed = parseDshVersion(dshVersion);
940
+ if (dshVersion === "") adapters.push({
941
+ name: "DSH 版本",
942
+ active: false,
943
+ note: "未探测到版本号(能力探测模式运行)"
944
+ });
945
+ else if (!parsed) adapters.push({
946
+ name: "DSH 版本",
947
+ active: false,
948
+ note: "无法解析版本号 " + dshVersion + "(能力探测模式运行)"
949
+ });
950
+ else adapters.push({
951
+ name: "DSH 版本",
952
+ active: true,
953
+ note: dshVersion + " · " + familyLabel(dshVersion)
954
+ });
955
+ const strategy = settingsInstallStrategy();
956
+ adapters.push({
957
+ name: "设置 section 安装(版本适配)",
958
+ active: strategy === "legacy" || strategy === "service",
959
+ note: settingsInstallNote()
960
+ });
961
+ return adapters;
962
+ }
748
963
  /**
749
964
  * 构建完整兼容性报告(RPC 与启动日志共用)。
750
- * @author ddj 2026年08月24号
965
+ * @author ddj 2026年08月24号 / 2026年09月02号
751
966
  * @param ctx DSH host 上下文
752
- * @param options 测试注入:depsAvailable 跳过动态导入、version 固定版本号
967
+ * @param options 测试注入:depsAvailable 跳过动态导入、version 固定插件版本、dshVersion 固定 DSH 版本
753
968
  * @returns 兼容性报告
754
969
  */
755
970
  async function buildReport(ctx, options) {
756
971
  const deps = options?.depsAvailable ?? await loadSettingsDeps() !== null;
972
+ const dshVersion = options?.dshVersion ?? detectDshVersion();
757
973
  const external = detectExternal(ctx, deps);
758
974
  const guards = detectGuards(ctx);
975
+ const adapters = versionAdapters(dshVersion);
759
976
  const warnings = [];
760
977
  if (!deps) warnings.push("未安装 @deepseek-ai/dsh-settings:文件打开工具设置持久化不可用(降级为配置值)");
978
+ if (settingsInstallStrategy() === "none") warnings.push("设置 section 安装不可用:" + settingsInstallNote());
979
+ const parsed = parseDshVersion(dshVersion);
980
+ const testedMax = parseDshVersion(TESTED_DSH_MAX);
981
+ if (parsed && testedMax && compareDshVersions(parsed, testedMax) > 0) warnings.push("DSH " + dshVersion + " 高于已实测版本(0.1.2-alpha.4):设置 API 按能力探测运行,异常时请回报适配矩阵");
761
982
  for (const guard of guards) if (!guard.active && guard.note) warnings.push(guard.note);
762
983
  return {
763
984
  pluginVersion: options?.version ?? pluginVersionOf(),
764
985
  external,
765
986
  guards,
987
+ adapters,
766
988
  warnings,
767
- devForm: readDevForm()
989
+ devForm: readDevForm(),
990
+ dshVersion
768
991
  };
769
992
  }
770
993
  //#endregion
@@ -7498,7 +7721,10 @@ function createLspRpc(deps) {
7498
7721
  * @returns 是否成功安装
7499
7722
  */
7500
7723
  async function installLspSettingsSection(ctx, entry) {
7501
- const deps = await loadSettingsDeps();
7724
+ let deps = null;
7725
+ try {
7726
+ deps = await loadSettingsDeps();
7727
+ } catch {}
7502
7728
  if (!deps) return false;
7503
7729
  try {
7504
7730
  const z = deps.z;
@@ -7509,11 +7735,11 @@ async function installLspSettingsSection(ctx, entry) {
7509
7735
  path: z.string()
7510
7736
  }).default({});
7511
7737
  const schema = z.object(langShape).default({});
7512
- deps.installSettingsSection(ctx, LSP_SETTINGS_NS, schema, entry, {
7738
+ const strategy = await runSettingsInstall(ctx, LSP_SETTINGS_NS, schema, entry, {
7513
7739
  setSource: () => {},
7514
7740
  onChange: () => {}
7515
7741
  });
7516
- return true;
7742
+ return strategy === "legacy" || strategy === "service";
7517
7743
  } catch (error) {
7518
7744
  console.error("[dsh-vscode-mode] LSP 设置 section 安装失败:" + String(error));
7519
7745
  return false;
@@ -7599,7 +7825,7 @@ async function logCompatSummary(ctx, warnings) {
7599
7825
  for (const warning of warnings) report.warnings.push(warning);
7600
7826
  const logger = ctx.logger;
7601
7827
  if (!logger?.info) return;
7602
- const head = "[dsh-vscode-mode] 兼容性:" + report.external.length + " 项外部适配 / " + report.guards.length + " 项护栏";
7828
+ const head = "[dsh-vscode-mode] 兼容性:" + (report.dshVersion ? "DSH " + report.dshVersion : "DSH 未探测") + " · " + report.external.length + " 项外部适配 / " + report.guards.length + " 项护栏 / " + (report.adapters?.length ?? 0) + " 项版本适配";
7603
7829
  if (report.warnings.length) logger.warn?.(head + ",警告 " + report.warnings.length + " 条:" + report.warnings.join(";"));
7604
7830
  else logger.info?.(head + ",无警告");
7605
7831
  } catch (error) {