@dsh-sup/dsh-core-linux-x64 0.1.5-BETA.6 → 0.1.5-BETA.7

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.
Files changed (2) hide show
  1. package/core.cjs +122 -7
  2. package/package.json +1 -1
package/core.cjs CHANGED
@@ -289,7 +289,7 @@ var require_version = __commonJS({
289
289
  var fs2 = require("node:fs");
290
290
  var path2 = require("node:path");
291
291
  function guardVersion() {
292
- if (true) return String("0.1.5-BETA.6");
292
+ if (true) return String("0.1.5-BETA.7");
293
293
  try {
294
294
  return JSON.parse(fs2.readFileSync(path2.join(__dirname, "..", "..", "package.json"), "utf8")).version || "unknown";
295
295
  } catch {
@@ -1099,7 +1099,48 @@ var require_exec_path = __commonJS({
1099
1099
  if (resolved) return resolved;
1100
1100
  return "npm.cmd";
1101
1101
  }
1102
- module2.exports = { resolveExecutable, candidateNames, standardDirs, firstExecutable, npmBin, npxBin };
1102
+ var DSH_PKG = ["@deepseek-ai", "dsh"];
1103
+ function dshJsIn(prefix) {
1104
+ return path2.join(prefix, "node_modules", ...DSH_PKG, "lib", "bin.js");
1105
+ }
1106
+ function resolveDsh(opts) {
1107
+ const o = opts || {};
1108
+ const pl = o.platform || process.platform;
1109
+ const env = o.env || process.env;
1110
+ const isFile = (p) => {
1111
+ try {
1112
+ return fs2.statSync(p).isFile();
1113
+ } catch {
1114
+ return false;
1115
+ }
1116
+ };
1117
+ const asJs = (bin, launcher) => ({ runtime: process.execPath, bin, isJs: true, launcher: launcher || null });
1118
+ if (env.DSH_BIN) {
1119
+ try {
1120
+ const r = fs2.realpathSync(env.DSH_BIN);
1121
+ if (isFile(r)) return asJs(r, env.DSH_BIN);
1122
+ } catch {
1123
+ }
1124
+ }
1125
+ const hit = resolveExecutable("dsh", { platform: pl, env });
1126
+ if (hit) {
1127
+ try {
1128
+ const real = fs2.realpathSync(hit);
1129
+ if (isFile(real) && /\.(js|cjs|mjs)$/i.test(real)) return asJs(real, hit);
1130
+ } catch {
1131
+ }
1132
+ const js = dshJsIn(path2.dirname(hit));
1133
+ if (isFile(js)) return asJs(js, hit);
1134
+ if (isFile(hit) && !/\.(cmd|bat|exe)$/i.test(hit)) return asJs(hit, hit);
1135
+ return { runtime: null, bin: hit, isJs: false, launcher: hit };
1136
+ }
1137
+ if (o.npmRoot) {
1138
+ const js = dshJsIn(o.npmRoot);
1139
+ if (isFile(js)) return asJs(js, null);
1140
+ }
1141
+ return null;
1142
+ }
1143
+ module2.exports = { resolveExecutable, candidateNames, standardDirs, firstExecutable, npmBin, npxBin, resolveDsh, dshJsIn };
1103
1144
  }
1104
1145
  });
1105
1146
 
@@ -4773,6 +4814,8 @@ var require_runtime_contract = __commonJS({
4773
4814
  nodePath: j.nodePath || node.path || null,
4774
4815
  nodeBinDir: j.nodeBinDir || node.binDir || null,
4775
4816
  npmPath: j.npmPath || npm.path || null,
4817
+ // 外壳可只提供包内 JS(npmPath=node,npmArgs=[npm-cli.js])——消费者必须带上 args。
4818
+ npmArgs: Array.isArray(j.npmArgs) ? j.npmArgs : Array.isArray(npm.args) ? npm.args : [],
4776
4819
  minNode: j.minNode || null,
4777
4820
  writtenBy: j.writtenBy || null,
4778
4821
  raw: j
@@ -10549,6 +10592,8 @@ var require_plugins = __commonJS({
10549
10592
  name: "\u539F\u751F\u5B9E\u4F8B",
10550
10593
  kind: "native",
10551
10594
  bin: this.dshBin,
10595
+ // 绑定后的原生入口可能是包内 JS(`.../lib/bin.js`)——必须用 node 承载(Windows 更甚:.js 不可直接执行)。
10596
+ runtime: /\.(js|cjs|mjs)$/i.test(this.dshBin) ? process.execPath : null,
10552
10597
  profileDir: this.profileDir,
10553
10598
  profileName: this.profileName,
10554
10599
  env: { HOME: os2.homedir(), PATH: this._pathExtra() }
@@ -10565,6 +10610,8 @@ var require_plugins = __commonJS({
10565
10610
  name: inst.name || inst.id,
10566
10611
  kind: "sandbox",
10567
10612
  bin: path2.join(installDir, "lib", "node_modules", "@deepseek-ai", "dsh", "lib", "bin.js"),
10613
+ runtime: process.execPath,
10614
+ // 包内 JS 入口:显式 node 承载(跨平台一致)
10568
10615
  installDir,
10569
10616
  profileDir: path2.join(dataDir, ".dsh", "profiles", this.profileName),
10570
10617
  profileName: this.profileName,
@@ -10874,7 +10921,9 @@ var require_plugins = __commonJS({
10874
10921
  try {
10875
10922
  const cliArgs = ["plugin", "--profile", target.profileName];
10876
10923
  if (target.storeDir) cliArgs.push("--store-dir", target.storeDir);
10877
- child = spawn(target.bin, [...cliArgs, ...args], { env, stdio: ["ignore", "pipe", "pipe"], windowsHide: true, detached: true });
10924
+ const argv0 = target.runtime || target.bin;
10925
+ const argvPrefix = target.runtime ? [target.bin] : [];
10926
+ child = spawn(argv0, [...argvPrefix, ...cliArgs, ...args], { env, stdio: ["ignore", "pipe", "pipe"], windowsHide: true, detached: true });
10878
10927
  } catch (e) {
10879
10928
  return settle({ ok: false, error: e.message });
10880
10929
  }
@@ -12432,11 +12481,30 @@ var require_manager2 = __commonJS({
12432
12481
  if (this.installLog.length > 60) this.installLog.splice(0, this.installLog.length - 60);
12433
12482
  }
12434
12483
  /* ═══════ 安装状态探测 ═══════ */
12484
+ /** 原生 DSH 真实安装(**唯一检测入口**,2026-09-16 架构修正):
12485
+ * 此前只读静态 `config.command[1]`(出厂默认裸名 'dsh')→ `fs.existsSync('dsh')` 恒 false →
12486
+ * 「已安装」永远判不出来,与「安装」分支形成两套相反逻辑(系统已装 DSH,守卫却报未安装)。
12487
+ * · 已绑定/用户显式指定且**真实存在**的绝对路径 → 尊重之;
12488
+ * · 否则跨平台解析:PATH/PATHEXT → 标准落点 → 包内 `lib/bin.js`(exec-path.resolveDsh)。 */
12489
+ detected() {
12490
+ const cmd2 = Array.isArray(this.config.command) ? this.config.command : [];
12491
+ const configured = cmd2[1];
12492
+ const isBare = !configured || configured === "dsh" || configured === "dsh.cmd" || !/[\\/]/.test(configured) && !String(configured).startsWith("~");
12493
+ if (!isBare) {
12494
+ return { bin: configured, runtime: cmd2[0] || null, isJs: /\.(js|cjs|mjs)$/i.test(configured) };
12495
+ }
12496
+ try {
12497
+ return execPath.resolveDsh({ npmRoot: this.npmRoot });
12498
+ } catch {
12499
+ return null;
12500
+ }
12501
+ }
12435
12502
  binPath() {
12503
+ const d = this.detected();
12504
+ if (d && d.bin) return d.bin;
12436
12505
  const bin = this.config.command && this.config.command[1];
12437
12506
  if (!bin) return null;
12438
- const p = bin === "~" ? os2.homedir() : bin.startsWith("~/") ? path2.join(os2.homedir(), bin.slice(2)) : bin;
12439
- return p;
12507
+ return bin === "~" ? os2.homedir() : bin.startsWith("~/") ? path2.join(os2.homedir(), bin.slice(2)) : bin;
12440
12508
  }
12441
12509
  /** 已安装版本:优先显式配置(installedPkgJsonPath),否则从 bin 所在目录向上找 package.json。未安装返回 null(唯一探测实现)。 */
12442
12510
  installedVersion() {
@@ -17517,9 +17585,21 @@ var require_env_catalog = __commonJS({
17517
17585
  const min = String(runtimeMeta().minNode || MIN_NODE_DEFAULT);
17518
17586
  return { version: "v" + ver, min, meets: verAtLeast(ver, min) };
17519
17587
  }
17588
+ function probeNpm() {
17589
+ try {
17590
+ const c = require_runtime_contract().read();
17591
+ if (c && c.npmPath) {
17592
+ const args = Array.isArray(c.npmArgs) ? c.npmArgs : [];
17593
+ const v = ex2.runOut(c.npmPath, [...args, "--version"], { timeoutMs: 3e3 });
17594
+ if (v && v.trim()) return v.trim();
17595
+ }
17596
+ } catch {
17597
+ }
17598
+ return cachedWhichVersion("npm");
17599
+ }
17520
17600
  var SYSTEM_ENTRIES = {
17521
17601
  node: { label: "Node.js", required: true, probe: probeNode },
17522
- npm: { label: "npm", required: true, probe: () => cachedWhichVersion("npm") },
17602
+ npm: { label: "npm", required: true, probe: probeNpm },
17523
17603
  git: { label: "git", required: false, probe: () => cachedWhichVersion("git") }
17524
17604
  };
17525
17605
  var EnvCatalog = class {
@@ -19659,6 +19739,7 @@ var require_supervisor = __commonJS({
19659
19739
  } catch (e) {
19660
19740
  this.logger.warn && this.logger.warn("ports pools configure: " + (e && e.message));
19661
19741
  }
19742
+ this._bindNativeDshCommand();
19662
19743
  this.instances = new InstanceManager({
19663
19744
  dir: path2.dirname(this.config.stateFile),
19664
19745
  logger: this.logger,
@@ -19743,7 +19824,7 @@ var require_supervisor = __commonJS({
19743
19824
  logger: this.logger
19744
19825
  });
19745
19826
  this.pluginManager = new PluginManager({
19746
- dshBin: "dsh",
19827
+ dshBin: this.config.command && this.config.command[1] ? this.config.command[1] : "dsh",
19747
19828
  profileName: this.config.pluginsProfileName || "web",
19748
19829
  profileDir: path2.join(os2.homedir(), ".dsh", "profiles", this.config.pluginsProfileName || "web"),
19749
19830
  overlayFile: path2.join(path2.dirname(this.config.stateFile), "plugin-states.patch.yml"),
@@ -19791,6 +19872,40 @@ var require_supervisor = __commonJS({
19791
19872
  });
19792
19873
  this._registerFixedPorts();
19793
19874
  }
19875
+ /** 原生 DSH 检测 → 绑定(2026-09-16 架构修正)。
19876
+ *
19877
+ * 原生 DSH 此前只被静态 `config.command[1]`(出厂默认裸名 'dsh')定义 —— `node dsh` 不做 PATH 解析、
19878
+ * Windows 裸名无扩展名 → 「已安装」永远判 false,与「安装」分支形成两套相反逻辑,
19879
+ * 且会去装第二个 DSH 顶替原生的那个。
19880
+ *
19881
+ * 这里在**任何消费者之前**把无法解析的 command[1] 解析为真实绝对入口:
19882
+ * 包内 JS → `['<node>', '<abs lib/bin.js>', ...rest]`;仅垫片 → `['<abs shim>', ...rest]`。
19883
+ * 用户显式给出且真实存在的路径**原样尊重**(不覆盖)。检测与接管由此同源:
19884
+ * 已装 → 绑定并接管;未装 → 由 NativeManager 安装后重新绑定。 */
19885
+ _bindNativeDshCommand() {
19886
+ try {
19887
+ const cmd2 = Array.isArray(this.config.command) ? this.config.command.slice() : [];
19888
+ const cur = cmd2[1];
19889
+ const isBare = !cur || cur === "dsh" || cur === "dsh.cmd" || !/[\\/]/.test(cur) && !String(cur).startsWith("~");
19890
+ if (!isBare) return;
19891
+ const d = require_exec_path().resolveDsh();
19892
+ if (!d || !d.bin) return;
19893
+ this.config.command = d.isJs ? [d.runtime || process.execPath, d.bin, ...cmd2.slice(2)] : [d.bin, ...cmd2.slice(2)];
19894
+ try {
19895
+ this.events && this.events.append("dsh_command_bound", { from: cur || null, to: this.config.command[1] });
19896
+ } catch {
19897
+ }
19898
+ try {
19899
+ this.logger.info && this.logger.info("\u539F\u751F DSH \u5DF2\u7ED1\u5B9A: " + this.config.command.join(" "));
19900
+ } catch {
19901
+ }
19902
+ } catch (e) {
19903
+ try {
19904
+ this.logger.warn && this.logger.warn("\u539F\u751F DSH \u7ED1\u5B9A\u5931\u8D25: " + (e && e.message));
19905
+ } catch {
19906
+ }
19907
+ }
19908
+ }
19794
19909
  /** 固定端口统一登记:主DSH / 守卫API / 中转服务。冲突即抛错(守卫启动失败,避免带病运行)。
19795
19910
  * 主程序端口动态注册:用户使用场景各异(可能先装 DSH 并自定义端口)——
19796
19911
  * 若配置端口无监听且检测到 DSH 进程,从进程实际参数解析端口并动态覆盖(绝不硬编码 3080)。 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-sup/dsh-core-linux-x64",
3
- "version": "0.1.5-BETA.6",
3
+ "version": "0.1.5-BETA.7",
4
4
  "description": "DSH lifecycle guard core (Node launcher) for linux-x64 — requires Node >=18.",
5
5
  "license": "UNLICENSED",
6
6
  "os": [