@michengai/dsh-codex-ui 0.2.92 → 0.2.94

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
@@ -4,6 +4,28 @@
4
4
 
5
5
  This changelog records recent releases of DSH Codex UI and its one-click installer. Earlier changes remain available in the [Git history](https://github.com/MichengAI/dsh-codex-ui/commits/main).
6
6
 
7
+ ## 0.2.94 — 2026-08-30
8
+
9
+ Companion release: `@michengai/dsh-codex-suite-installer@0.1.11`.
10
+
11
+ ### Safety
12
+
13
+ - Completed symmetric validation of the public Desktop services: if either `desktopProfiles` or `desktopPnpm` is exposed without the other, dependency management now fails safely instead of falling back to an ambient CLI that could mutate another profile.
14
+
15
+ ## 0.2.93 — 2026-08-30
16
+
17
+ ### Compatibility
18
+
19
+ - Resolved the active DSH Desktop profile through the public `desktopProfiles` service and delegated installs and updates to the public `desktopPnpm` package manager instead of hard-coding the `web` profile.
20
+ - Preserved the ordinary Web/CLI profile fallback while recognizing Desktop-provided runtime and companion-package state across restarts.
21
+ - Routed new-session actions through Archive Manager's optional `uiWorkspace.startSession()` service, with the standard workspace service retained as the fallback.
22
+
23
+ ### Safety
24
+
25
+ - Removed the dependency on the launcher-private `desktopPnpmBootstrap` implementation detail.
26
+ - Failed safely when a Desktop generation exposes incomplete public services instead of falling back to an ambient CLI that could mutate another profile.
27
+ - Reported the running Desktop DSH runtime as installed without fabricating a version or update when the Host exposes no supported runtime path.
28
+
7
29
  ## 0.2.92 — 2026-08-28
8
30
 
9
31
  Companion release: `@michengai/dsh-codex-suite-installer@0.1.9`.
@@ -4,6 +4,28 @@
4
4
 
5
5
  本日志记录 DSH Codex UI 及其一键安装器的最近发布;更早的变更可查看 [Git 提交历史](https://github.com/MichengAI/dsh-codex-ui/commits/main)。
6
6
 
7
+ ## 0.2.94 — 2026-08-30
8
+
9
+ 配套版本:`@michengai/dsh-codex-suite-installer@0.1.11`。
10
+
11
+ ### 安全性
12
+
13
+ - 完成 Desktop 公开服务的双向完整性校验:`desktopProfiles` 与 `desktopPnpm` 任意一项单独存在时,依赖管理都会安全失败,不再回退到可能修改其他 Profile 的环境 CLI。
14
+
15
+ ## 0.2.93 — 2026-08-30
16
+
17
+ ### 兼容性
18
+
19
+ - 通过公开的 `desktopProfiles` service 读取 DSH Desktop 当前 Profile,并把安装与更新交给公开的 `desktopPnpm` 包管理服务,不再硬编码 `web` Profile。
20
+ - 保留普通 Web/CLI 的 Profile 回退,同时在 Desktop 重启前后正确识别宿主 Runtime 与配套插件状态。
21
+ - 新建会话优先调用 Archive Manager 可选提供的 `uiWorkspace.startSession()` service,缺失时继续使用标准工作区服务。
22
+
23
+ ### 安全性
24
+
25
+ - 移除对 Launcher 私有实现细节 `desktopPnpmBootstrap` 的依赖。
26
+ - Desktop generation 的公开服务不完整时安全失败,不再回退到可能修改其他 Profile 的环境 CLI。
27
+ - 宿主没有通过受支持路径暴露 Runtime 目录时,只确认正在运行的 Desktop DSH Runtime 已安装,不伪造版本或升级状态。
28
+
7
29
  ## 0.2.92 — 2026-08-28
8
30
 
9
31
  配套版本:`@michengai/dsh-codex-suite-installer@0.1.9`。
package/dist/client.js CHANGED
@@ -5445,6 +5445,18 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5445
5445
  function hasDeleteSession(value) {
5446
5446
  return value !== null && typeof value === "object" && "deleteSession" in value && typeof value.deleteSession === "function";
5447
5447
  }
5448
+ function hasStartSession(value) {
5449
+ return value !== null && typeof value === "object" && "startSession" in value && typeof value.startSession === "function";
5450
+ }
5451
+ /** Archive Manager replaces the official ui-workspace row with this optional service. */
5452
+ function startWorkspaceSession(ctx, workspaceId) {
5453
+ const uiWorkspace = ctx.get("uiWorkspace");
5454
+ if (hasStartSession(uiWorkspace)) {
5455
+ uiWorkspace.startSession(workspaceId);
5456
+ return;
5457
+ }
5458
+ ctx.workspaces.startSession(workspaceId);
5459
+ }
5448
5460
  /** 替换 DSH 的官方 sidebar 插槽,不修改 DSH 源码或会话数据。 */
5449
5461
  function apply(ctx) {
5450
5462
  ctx.effect(() => ctx.locale.register(NS, {
@@ -5490,7 +5502,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5490
5502
  ctx.sessions.open(sessionId);
5491
5503
  },
5492
5504
  startSession: (workspaceId) => {
5493
- ctx.workspaces.startSession(workspaceId);
5505
+ startWorkspaceSession(ctx, workspaceId);
5494
5506
  },
5495
5507
  toggleSidebar: () => {
5496
5508
  ctx.layout.toggleSidebar();
@@ -5561,7 +5573,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5561
5573
  insertWorkspaceBefore: (workspaceId, beforeWorkspaceId) => ctx.workspaces.insertBefore(workspaceId, beforeWorkspaceId),
5562
5574
  insertSessionBefore: (workspaceId, sessionId, beforeSessionId) => ctx.workspaces.insertSessionBefore(workspaceId, sessionId, beforeSessionId),
5563
5575
  startSession: (workspaceId) => {
5564
- ctx.workspaces.startSession(workspaceId);
5576
+ startWorkspaceSession(ctx, workspaceId);
5565
5577
  }
5566
5578
  })
5567
5579
  }, CodexWorkspaceBrowser));
@@ -5601,6 +5613,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5601
5613
  //#endregion
5602
5614
  exports.apply = apply;
5603
5615
  exports.inject = inject;
5616
+ exports.startWorkspaceSession = startWorkspaceSession;
5604
5617
  return module.exports;
5605
5618
  }
5606
5619
  });
package/dist/index.mjs CHANGED
@@ -56,13 +56,64 @@ function managedDependency(id) {
56
56
  const PROFILE_PENDING_UPDATES_FILE = ".dsh-pending-updates.json";
57
57
  const APPLY_PLUGIN_UPDATES_IPC = "apply-plugin-updates";
58
58
  const PLUGIN_INSTALL_TIMEOUT_MS = 6e5;
59
- function profileDirectory() {
60
- if (process.env.DSH_PROFILE_DIR !== void 0) return process.env.DSH_PROFILE_DIR;
61
- return resolve(homedir(), ".dsh", "profiles", "web");
59
+ function optionalService(ctx, name) {
60
+ if (ctx === void 0) return void 0;
61
+ return typeof ctx.get === "function" ? ctx.get(name) : ctx[name];
62
62
  }
63
- async function declaredPluginNames() {
63
+ function validProfileName(value) {
64
+ return typeof value === "string" && value !== "" && value !== "." && value !== ".." && value !== "node_modules" && !value.includes("/") && !value.includes("\\") && !/[\0-\x1f\x7f]/.test(value);
65
+ }
66
+ function profileNameFromArgv(argv) {
67
+ for (let index = 2; index < argv.length; index += 1) {
68
+ const argument = argv[index];
69
+ if (argument === "--profile") return argv[index + 1];
70
+ if (argument?.startsWith("--profile=")) return argument.slice(10);
71
+ }
72
+ return argv[2] === "web" ? "web" : void 0;
73
+ }
74
+ /**
75
+ * Desktop 通过可选 Host service 暴露当前 profile;普通 Web/CLI 继续使用
76
+ * DSH_PROFILE_DIR、命令行 profile 与默认 web profile。
77
+ */
78
+ function resolveDependencyRuntime(ctx, options = {}) {
79
+ const env = options.env ?? process.env;
80
+ const argv = options.argv ?? process.argv;
81
+ const cwd = options.cwd ?? process.cwd();
82
+ const home = options.homeDir ?? homedir();
83
+ const profiles = optionalService(ctx, "desktopProfiles");
84
+ const desktopPnpm = optionalService(ctx, "desktopPnpm");
85
+ if (profiles === void 0 && desktopPnpm !== void 0) throw new Error("DSH Desktop Profile 服务尚未就绪,请重启 Desktop 后重试。");
86
+ if (profiles !== void 0) {
87
+ const current = profiles.current;
88
+ if (!validProfileName(current?.name) || typeof current.dir !== "string" || !isAbsolute(current.dir)) throw new Error("DSH Desktop 当前 Profile 信息无效,请重启 Desktop 后重试。");
89
+ if (typeof desktopPnpm?.runPlugin !== "function") throw new Error("DSH Desktop 包管理服务尚未就绪,请重启 Desktop 后重试。");
90
+ const profileDir = resolve(current.dir);
91
+ const runtimeRoots = typeof env.DSH_RUNTIME_DIR === "string" && isAbsolute(env.DSH_RUNTIME_DIR) ? [resolve(env.DSH_RUNTIME_DIR)] : [];
92
+ return {
93
+ environmentKind: "desktop",
94
+ profileName: current.name,
95
+ profileDir,
96
+ runtimeRoots,
97
+ desktopPnpm
98
+ };
99
+ }
100
+ const profileDir = resolve(env.DSH_PROFILE_DIR ?? resolve(home, ".dsh", "profiles", "web"));
101
+ const selected = profileNameFromArgv(argv);
102
+ const profileName = validProfileName(selected) ? selected : validProfileName(basename(profileDir)) ? basename(profileDir) : "web";
103
+ const cliRuntimeRoot = argv[1] === void 0 ? void 0 : resolveDshRuntimeRoot(argv[1], cwd);
104
+ return {
105
+ environmentKind: "cli",
106
+ profileName,
107
+ profileDir,
108
+ runtimeRoots: [env.DSH_RUNTIME_DIR, cliRuntimeRoot].filter((root) => root !== void 0 && root !== "")
109
+ };
110
+ }
111
+ function profileDirectory(runtime) {
112
+ return runtime.profileDir;
113
+ }
114
+ async function declaredPluginNames(runtime) {
64
115
  try {
65
- const manifest = JSON.parse(await readFile(resolve(profileDirectory(), "package.json"), "utf8"));
116
+ const manifest = JSON.parse(await readFile(resolve(profileDirectory(runtime), "package.json"), "utf8"));
66
117
  return [.../* @__PURE__ */ new Set([...Object.keys({
67
118
  ...manifest.devDependencies,
68
119
  ...manifest.dependencies
@@ -101,17 +152,12 @@ function resolveDshRuntimeRoot(entry = process.argv[1], cwd = process.cwd()) {
101
152
  const root = cliEntry.slice(0, index);
102
153
  return root.endsWith(sep) ? root.slice(0, -1) : root;
103
154
  }
104
- function packageLookupRoots(packageName) {
105
- if (!isOfficialRuntimePackage(packageName)) return [profileDirectory()];
106
- const runtimeDir = process.env.DSH_RUNTIME_DIR;
107
- return [...new Set([
108
- runtimeDir,
109
- resolveDshRuntimeRoot(),
110
- profileDirectory()
111
- ].filter((root) => root !== void 0 && root !== ""))];
155
+ function packageLookupRoots(packageName, runtime) {
156
+ if (!isOfficialRuntimePackage(packageName)) return [profileDirectory(runtime)];
157
+ return [.../* @__PURE__ */ new Set([...runtime.runtimeRoots, profileDirectory(runtime)])];
112
158
  }
113
- async function installedPackageVersion(packageName) {
114
- for (const root of packageLookupRoots(packageName)) try {
159
+ async function installedPackageVersion(packageName, runtime) {
160
+ for (const root of packageLookupRoots(packageName, runtime)) try {
115
161
  const manifest = JSON.parse(await readFile(resolve(root, "node_modules", ...packageName.split("/"), "package.json"), "utf8"));
116
162
  if (typeof manifest.version === "string" && manifest.version !== "") return manifest.version;
117
163
  } catch (error) {
@@ -183,9 +229,9 @@ function applyReleaseExclude(source, packageName, version) {
183
229
  return `${source}${source === "" || source.endsWith("\n") ? "" : eol}minimumReleaseAgeExclude:${eol}${entry}${eol}`;
184
230
  }
185
231
  /** 将用户本次确认的精确版本加入 Profile 的 pnpm 发布时间保护例外。 */
186
- async function ensureLatestReleaseAllowed(packageName, version) {
232
+ async function ensureLatestReleaseAllowed(packageName, version, runtime) {
187
233
  if (parseSemver(version) === void 0) throw new Error("npm 返回了无法识别的最新版本。");
188
- const path = resolve(profileDirectory(), "pnpm-workspace.yaml");
234
+ const path = resolve(profileDirectory(runtime), "pnpm-workspace.yaml");
189
235
  let source;
190
236
  try {
191
237
  source = await readFile(path, "utf8");
@@ -231,11 +277,16 @@ function newerVersion(installed, latest) {
231
277
  for (let index = 0; index < current.core.length; index += 1) if (candidate.core[index] !== current.core[index]) return candidate.core[index] > current.core[index];
232
278
  return comparePrerelease(candidate.prerelease, current.prerelease) > 0;
233
279
  }
234
- /** 返回 Web profile 中固定管理插件的实际安装版本与 npm latest 状态。 */
235
- async function dependencyStatuses() {
236
- const declaredNames = await declaredPluginNames();
280
+ /** 返回当前 profile 中固定管理插件的实际安装版本与 npm latest 状态。 */
281
+ async function dependencyStatuses(runtime = resolveDependencyRuntime()) {
282
+ const declaredNames = await declaredPluginNames(runtime);
237
283
  return Promise.all(MANAGED_DEPENDENCIES.map(async (dependency) => {
238
- const version = await installedPackageVersion(dependency.packageName);
284
+ const version = await installedPackageVersion(dependency.packageName, runtime);
285
+ if (version === void 0 && runtime.environmentKind === "desktop" && isOfficialRuntimePackage(dependency.packageName)) return {
286
+ ...dependency,
287
+ installed: true,
288
+ updateAvailable: false
289
+ };
239
290
  const declared = isOfficialRuntimePackage(dependency.packageName) || isManagedPackageDeclared(dependency.packageName, declaredNames);
240
291
  if (version === void 0 || !isManagedPackageInstalled({
241
292
  installedVersion: version,
@@ -273,8 +324,8 @@ function isRestartableInstallError(error) {
273
324
  const message = error instanceof Error ? error.message : String(error);
274
325
  return /完全退出桌面端|正在运行的插件|pnpm 仓库不一致/.test(message);
275
326
  }
276
- async function recordPendingUpdate(packageName, version) {
277
- const pendingPath = resolve(profileDirectory(), PROFILE_PENDING_UPDATES_FILE);
327
+ async function recordPendingUpdate(packageName, version, runtime) {
328
+ const pendingPath = resolve(profileDirectory(runtime), PROFILE_PENDING_UPDATES_FILE);
278
329
  let packages = [];
279
330
  try {
280
331
  const parsed = JSON.parse(await readFile(pendingPath, "utf8"));
@@ -297,8 +348,8 @@ async function recordPendingUpdate(packageName, version) {
297
348
  });
298
349
  await writeFile(pendingPath, `${JSON.stringify({ packages }, void 0, 2)}\n`, "utf8");
299
350
  }
300
- async function removePendingUpdate(packageName) {
301
- const pendingPath = resolve(profileDirectory(), PROFILE_PENDING_UPDATES_FILE);
351
+ async function removePendingUpdate(packageName, runtime) {
352
+ const pendingPath = resolve(profileDirectory(runtime), PROFILE_PENDING_UPDATES_FILE);
302
353
  try {
303
354
  const parsed = JSON.parse(await readFile(pendingPath, "utf8"));
304
355
  if (!Array.isArray(parsed.packages)) return;
@@ -313,8 +364,8 @@ async function removePendingUpdate(packageName) {
313
364
  if (error.code !== "ENOENT") throw error;
314
365
  }
315
366
  }
316
- async function recordDeclaredVersion(packageName, version) {
317
- const manifestPath = resolve(profileDirectory(), "package.json");
367
+ async function recordDeclaredVersion(packageName, version, runtime) {
368
+ const manifestPath = resolve(profileDirectory(runtime), "package.json");
318
369
  let manifest;
319
370
  try {
320
371
  manifest = JSON.parse(await readFile(manifestPath, "utf8"));
@@ -344,6 +395,7 @@ function pluginExecArgv(args = process.execArgv) {
344
395
  return args.filter((arg) => !/^--(?:inspect|inspect-brk|debug|debug-brk)(?:=|$)/.test(arg));
345
396
  }
346
397
  const activePluginChildren = /* @__PURE__ */ new Set();
398
+ const activeDesktopPluginHandles = /* @__PURE__ */ new Set();
347
399
  function terminatePluginChild(child) {
348
400
  if (child.exitCode !== null || child.killed) return;
349
401
  if (process.platform === "win32" && child.pid !== void 0) {
@@ -367,6 +419,7 @@ function terminatePluginChild(child) {
367
419
  /** 插件停用时终止仍在运行的安装进程,避免热更新后遗留 pnpm。 */
368
420
  function disposeDependencyInstaller() {
369
421
  for (const child of activePluginChildren) terminatePluginChild(child);
422
+ for (const handle of activeDesktopPluginHandles) handle.cancel();
370
423
  }
371
424
  function monitorPluginChild(child, timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS) {
372
425
  return new Promise((resolvePromise, reject) => {
@@ -398,14 +451,52 @@ function monitorPluginChild(child, timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS) {
398
451
  timeout.unref?.();
399
452
  });
400
453
  }
401
- function runDshPlugin(args, timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS) {
454
+ function monitorDesktopPlugin(handle, timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS) {
455
+ return new Promise((resolvePromise, reject) => {
456
+ activeDesktopPluginHandles.add(handle);
457
+ let output = "";
458
+ let settled = false;
459
+ const collect = (chunk) => {
460
+ output = `${output}${String(chunk)}`.slice(-65536);
461
+ };
462
+ const finish = (error) => {
463
+ if (settled) return;
464
+ settled = true;
465
+ clearTimeout(timeout);
466
+ activeDesktopPluginHandles.delete(handle);
467
+ error === void 0 ? resolvePromise() : reject(error);
468
+ };
469
+ handle.stdout?.on("data", collect);
470
+ handle.stderr?.on("data", collect);
471
+ handle.stdout?.once("error", () => {
472
+ handle.cancel();
473
+ finish(/* @__PURE__ */ new Error("无法读取 DSH Desktop 插件安装输出。"));
474
+ });
475
+ handle.stderr?.once("error", () => {
476
+ handle.cancel();
477
+ finish(/* @__PURE__ */ new Error("无法读取 DSH Desktop 插件安装输出。"));
478
+ });
479
+ handle.done.then((outcome) => {
480
+ finish(outcome.exitCode === 0 && outcome.signal === null ? void 0 : pluginCommandError(output));
481
+ }, () => {
482
+ finish(pluginCommandError(output));
483
+ });
484
+ const timeout = setTimeout(() => {
485
+ handle.cancel();
486
+ finish(/* @__PURE__ */ new Error("插件安装超时,已终止安装进程。请检查网络后重试。"));
487
+ }, timeoutMs);
488
+ timeout.unref?.();
489
+ });
490
+ }
491
+ function runDshPlugin(args, runtime = resolveDependencyRuntime(), timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS) {
492
+ if (runtime.desktopPnpm !== void 0) return monitorDesktopPlugin(runtime.desktopPnpm.runPlugin(args, runtime.profileDir), timeoutMs);
402
493
  const entry = resolveDshCliEntry();
403
494
  return monitorPluginChild(spawn(process.execPath, [
404
495
  ...pluginExecArgv(),
405
496
  entry,
406
497
  "plugin",
407
498
  "--profile",
408
- "web",
499
+ runtime.profileName,
409
500
  ...args
410
501
  ], {
411
502
  cwd: process.cwd(),
@@ -424,11 +515,11 @@ function runDshPlugin(args, timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS) {
424
515
  /** 并发安装互斥:pnpm 锁文件竞争会触发 EPERM/EBUSY,同一时间只允许一个安装进程。 */
425
516
  let installing = false;
426
517
  /** 仅允许安装固定依赖,避免把浏览器输入转成任意命令。 */
427
- async function installDependency(id, requestHotUpdate = requestDesktopHotUpdate) {
518
+ async function installDependency(id, requestHotUpdate = requestDesktopHotUpdate, runtime = resolveDependencyRuntime()) {
428
519
  if (installing) throw new Error("已有依赖安装正在进行,请等待完成后再试。");
429
520
  installing = true;
430
521
  try {
431
- return await installDependenciesLocked([id], requestHotUpdate);
522
+ return await installDependenciesLocked([id], requestHotUpdate, runtime);
432
523
  } finally {
433
524
  installing = false;
434
525
  }
@@ -438,31 +529,31 @@ function updatableDependencyIds(statuses) {
438
529
  return statuses.filter((status) => status.installed && status.updateAvailable).map((status) => status.id);
439
530
  }
440
531
  /** 把所有待更新版本一次写入清单,最后只请求一次桌面热更新。 */
441
- async function updateAllDependencies(requestHotUpdate = requestDesktopHotUpdate) {
532
+ async function updateAllDependencies(requestHotUpdate = requestDesktopHotUpdate, runtime = resolveDependencyRuntime()) {
442
533
  if (installing) throw new Error("已有依赖安装正在进行,请等待完成后再试。");
443
534
  installing = true;
444
535
  try {
445
- const current = await dependencyStatuses();
536
+ const current = await dependencyStatuses(runtime);
446
537
  const ids = updatableDependencyIds(current);
447
538
  if (ids.length === 0) return {
448
539
  dependencies: current,
449
540
  updatedCount: 0
450
541
  };
451
542
  return {
452
- dependencies: await installDependenciesLocked(ids, requestHotUpdate),
543
+ dependencies: await installDependenciesLocked(ids, requestHotUpdate, runtime),
453
544
  updatedCount: ids.length
454
545
  };
455
546
  } finally {
456
547
  installing = false;
457
548
  }
458
549
  }
459
- async function installDependenciesLocked(ids, requestHotUpdate) {
550
+ async function installDependenciesLocked(ids, requestHotUpdate, runtime) {
460
551
  const dependencies = [...new Set(ids)].map((id) => {
461
552
  const dependency = managedDependency(id);
462
553
  if (dependency === void 0) throw new Error("不支持安装该依赖。");
463
554
  return dependency;
464
555
  });
465
- const declared = await declaredPluginNames();
556
+ const declared = await declaredPluginNames(runtime);
466
557
  const requestedTargets = await Promise.all(dependencies.map(async (dependency) => {
467
558
  const latestVersion = await npmLatestVersion(dependency.packageName);
468
559
  if (latestVersion === void 0) throw new Error("无法获取 npm 最新版本,请检查网络或 npm registry 后重试。");
@@ -482,7 +573,7 @@ async function installDependenciesLocked(ids, requestHotUpdate) {
482
573
  packageName,
483
574
  version: requestedVersion
484
575
  };
485
- const version = await installedPackageVersion(packageName) ?? await npmLatestVersion(packageName);
576
+ const version = await installedPackageVersion(packageName, runtime) ?? await npmLatestVersion(packageName);
486
577
  if (version === void 0) throw new Error("无法读取 Suite 成员版本,请检查 npm 安装后重试。");
487
578
  return {
488
579
  packageName,
@@ -491,27 +582,27 @@ async function installDependenciesLocked(ids, requestHotUpdate) {
491
582
  }));
492
583
  const remove = [...new Set(targets.flatMap((target) => pluginsToRemoveBeforeInstall(declared, target.packageName)))];
493
584
  for (const target of targets) {
494
- await ensureLatestReleaseAllowed(target.packageName, target.version);
495
- if (!isOfficialRuntimePackage(target.packageName)) await recordDeclaredVersion(target.packageName, target.version);
496
- await recordPendingUpdate(target.packageName, target.version);
585
+ await ensureLatestReleaseAllowed(target.packageName, target.version, runtime);
586
+ if (!isOfficialRuntimePackage(target.packageName)) await recordDeclaredVersion(target.packageName, target.version, runtime);
587
+ await recordPendingUpdate(target.packageName, target.version, runtime);
497
588
  }
498
- if (remove.length > 0) await runDshPlugin(["remove", ...remove]);
499
- if (requestHotUpdate()) return dependencyStatuses();
589
+ if (remove.length > 0) await runDshPlugin(["remove", ...remove], runtime);
590
+ if (runtime.desktopPnpm === void 0 && requestHotUpdate()) return dependencyStatuses(runtime);
500
591
  for (const target of targets) {
501
592
  try {
502
593
  await runDshPlugin([
503
594
  "add",
504
595
  `${target.packageName}@${target.version}`,
505
596
  "--registry=https://registry.npmjs.org/"
506
- ]);
597
+ ], runtime);
507
598
  } catch (error) {
508
- if (isRestartableInstallError(error)) return dependencyStatuses();
599
+ if (isRestartableInstallError(error)) return dependencyStatuses(runtime);
509
600
  throw error;
510
601
  }
511
- if (await installedPackageVersion(target.packageName) !== target.version) return dependencyStatuses();
512
- await removePendingUpdate(target.packageName);
602
+ if (await installedPackageVersion(target.packageName, runtime) !== target.version) return dependencyStatuses(runtime);
603
+ await removePendingUpdate(target.packageName, runtime);
513
604
  }
514
- return dependencyStatuses();
605
+ return dependencyStatuses(runtime);
515
606
  }
516
607
  //#endregion
517
608
  //#region src/explorer-path-policy.ts
@@ -950,7 +1041,7 @@ function apply(ctx) {
950
1041
  const url = new URL(request.url ?? "/", "http://localhost");
951
1042
  try {
952
1043
  if (request.method === "GET") {
953
- const dependencies = await dependencyStatuses();
1044
+ const dependencies = await dependencyStatuses(resolveDependencyRuntime(ctx));
954
1045
  response.writeHead(200, {
955
1046
  "content-type": "application/json; charset=utf-8",
956
1047
  "cache-control": "no-store"
@@ -972,7 +1063,7 @@ function apply(ctx) {
972
1063
  const { dependencies, updatedCount } = await updateAllDependencies(() => {
973
1064
  restartAfterResponse = typeof process.send === "function";
974
1065
  return restartAfterResponse;
975
- });
1066
+ }, resolveDependencyRuntime(ctx));
976
1067
  response.writeHead(200, {
977
1068
  "content-type": "application/json; charset=utf-8",
978
1069
  "cache-control": "no-store"
@@ -990,7 +1081,7 @@ function apply(ctx) {
990
1081
  const dependencies = await installDependency(url.searchParams.get("dependency"), () => {
991
1082
  restartAfterResponse = typeof process.send === "function";
992
1083
  return restartAfterResponse;
993
- });
1084
+ }, resolveDependencyRuntime(ctx));
994
1085
  response.writeHead(200, {
995
1086
  "content-type": "application/json; charset=utf-8",
996
1087
  "cache-control": "no-store"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@michengai/dsh-codex-ui",
3
- "version": "0.2.92",
3
+ "version": "0.2.94",
4
4
  "description": "以 Codex 风格重构 DSH Web 侧栏的独立客户端插件",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {