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