@dsh-workbench/adapter-probe 1.1.14-beta.1 → 1.1.14
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/dist/bootstrap-run.d.ts +31 -0
- package/dist/bootstrap-run.js +59 -0
- package/dist/browser-wake.d.ts +2 -2
- package/dist/browser-wake.js +11 -15
- package/dist/desktop-runtime.d.ts +14 -0
- package/dist/desktop-runtime.js +59 -0
- package/dist/diy-preset-health.js +3 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/platform.d.ts +3 -1
- package/dist/platform.js +5 -2
- package/dist/preflight-route.d.ts +3 -2
- package/dist/preflight-route.js +20 -14
- package/dist/preflight.d.ts +3 -2
- package/dist/preflight.js +13 -11
- package/dist/probe-cache.js +3 -2
- package/dist/probe-libs.d.ts +2 -3
- package/dist/probe-libs.js +2 -2
- package/dist/probe-units.d.ts +3 -4
- package/dist/probe-units.js +21 -14
- package/dist/release-port.d.ts +3 -3
- package/dist/release-port.js +2 -2
- package/dist/runtime-seed.d.ts +4 -6
- package/dist/runtime-seed.js +31 -61
- package/dist/self-update.d.ts +3 -3
- package/dist/self-update.js +10 -13
- package/dist/supply-port.d.ts +5 -2
- package/dist/supply-port.js +3 -2
- package/dist/toolchain-probe.d.ts +4 -2
- package/dist/toolchain-probe.js +80 -14
- package/dist/toolchain.d.ts +7 -19
- package/dist/toolchain.js +19 -63
- package/package.json +5 -8
package/dist/probe-units.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { commandNamesMatch } from './command-name.js';
|
|
2
|
-
import { OPENCLI_TIMEOUT_MS, PROBE_TTL_MS, buildSupplyIndex, NEED_KIND_SPECS, needIdOf, npmSourceOf, parseJsonLoose,
|
|
2
|
+
import { OPENCLI_TIMEOUT_MS, PROBE_TTL_MS, buildSupplyIndex, NEED_KIND_SPECS, needIdOf, noWrite, npmSourceOf, parseJsonLoose, productWrite, quoteShellArg, } from '@dsh-workbench/shared/host';
|
|
3
3
|
import { npmRegistryOf } from '@dsh-workbench/adapter-supply';
|
|
4
4
|
import { probeRelease } from './release-port.js';
|
|
5
5
|
import { createTimedMemo } from './probe-cache.js';
|
|
@@ -13,17 +13,24 @@ export function parsePluginList(stdout) {
|
|
|
13
13
|
return parsed;
|
|
14
14
|
return /no plugins? installed/i.test(stdout) ? [] : undefined;
|
|
15
15
|
}
|
|
16
|
-
async function probeBinary(
|
|
16
|
+
async function probeBinary(seam, name) {
|
|
17
17
|
const line = process.platform === 'win32' ? `where ${quoteShellArg(name)}` : `command -v ${quoteShellArg(name)}`;
|
|
18
|
-
const result = await
|
|
18
|
+
const result = await seam
|
|
19
|
+
.run({ command: line, intent: noWrite(), retry: 'safe', timeoutMs: BINARY_PROBE_TIMEOUT_MS, bestEffort: true })
|
|
20
|
+
.catch(() => undefined);
|
|
19
21
|
return result?.exitCode === 0;
|
|
20
22
|
}
|
|
21
23
|
async function runtimeList(options) {
|
|
22
24
|
if (!options.needsPlugins)
|
|
23
25
|
return {};
|
|
24
|
-
const result = await
|
|
26
|
+
const result = await options.seam
|
|
27
|
+
.run({
|
|
28
|
+
command: `${options.command} plugin list -f json`,
|
|
29
|
+
intent: productWrite(),
|
|
30
|
+
retry: 'safe',
|
|
25
31
|
timeoutMs: OPENCLI_TIMEOUT_MS,
|
|
26
|
-
})
|
|
32
|
+
})
|
|
33
|
+
.then((value) => ({ ok: true, stdout: value.exitCode === 0 ? value.stdout : '', stderr: value.stderr }), (error) => ({ ok: false, stdout: '', stderr: String(error) }));
|
|
27
34
|
if (!result.ok)
|
|
28
35
|
return { failure: result.stderr };
|
|
29
36
|
const list = parsePluginList(result.stdout);
|
|
@@ -46,7 +53,7 @@ async function releasesOf(index, options) {
|
|
|
46
53
|
continue;
|
|
47
54
|
const registry = npmRegistryOf(source, process.env);
|
|
48
55
|
const signal = await probeRelease({
|
|
49
|
-
|
|
56
|
+
seam: options.seam,
|
|
50
57
|
package: entry.package,
|
|
51
58
|
...(registry.ok ? { registry: registry.value } : {}),
|
|
52
59
|
force: options.force,
|
|
@@ -70,7 +77,7 @@ function runtimeCommandOf(need, runtimeCommands) {
|
|
|
70
77
|
return KNOWN_RUNTIMES.includes(need.runtime) ? need.runtime : undefined;
|
|
71
78
|
}
|
|
72
79
|
export async function probeUnits(options) {
|
|
73
|
-
const {
|
|
80
|
+
const { seam, runtimeCommands, units, force = false } = options;
|
|
74
81
|
const commandKey = Object.values(runtimeCommands).sort().join('|');
|
|
75
82
|
const hits = units.map((unit) => unitCache.get(cacheKeyOf(commandKey, units, unit.unit)));
|
|
76
83
|
if (!force && hits.every((hit) => hit !== undefined)) {
|
|
@@ -82,7 +89,7 @@ export async function probeUnits(options) {
|
|
|
82
89
|
if (shared !== undefined)
|
|
83
90
|
return shared;
|
|
84
91
|
}
|
|
85
|
-
const task = loadCapabilities({
|
|
92
|
+
const task = loadCapabilities({ seam, runtimeCommands, units, force });
|
|
86
93
|
pendingProbes.set(key, task);
|
|
87
94
|
try {
|
|
88
95
|
return await task;
|
|
@@ -93,7 +100,7 @@ export async function probeUnits(options) {
|
|
|
93
100
|
}
|
|
94
101
|
}
|
|
95
102
|
async function loadCapabilities(options) {
|
|
96
|
-
const {
|
|
103
|
+
const { seam, runtimeCommands, units, force } = options;
|
|
97
104
|
const index = buildSupplyIndex(units.map((unit) => ({ id: unit.unit, needs: unit.needs })), {
|
|
98
105
|
env: process.env,
|
|
99
106
|
packagePrefix: 'opencli-plugin-',
|
|
@@ -105,7 +112,7 @@ async function loadCapabilities(options) {
|
|
|
105
112
|
const runtimeNames = Object.values(runtimeCommands);
|
|
106
113
|
await Promise.all(binNames.map(async (name) => {
|
|
107
114
|
const known = runtimeNames.some((command) => commandNamesMatch(name, command));
|
|
108
|
-
binaries.set(name, known ? true : await probeBinary(
|
|
115
|
+
binaries.set(name, known ? true : await probeBinary(seam, name));
|
|
109
116
|
}));
|
|
110
117
|
const extensionNeeds = units.flatMap((unit) => unit.needs.filter((need) => need.kind === 'extension'));
|
|
111
118
|
const runtimes = [...new Set(extensionNeeds.map((need) => need.runtime))];
|
|
@@ -117,11 +124,11 @@ async function loadCapabilities(options) {
|
|
|
117
124
|
return;
|
|
118
125
|
}
|
|
119
126
|
const needsPlugins = extensionNeeds.some((need) => need.runtime === runtime && conflictOf(index, need) === undefined);
|
|
120
|
-
lists.set(runtime, await runtimeList({
|
|
127
|
+
lists.set(runtime, await runtimeList({ seam, command, needsPlugins }));
|
|
121
128
|
}));
|
|
122
129
|
const libNeeds = units.flatMap((unit) => unit.needs.filter((need) => need.kind === 'lib'));
|
|
123
|
-
const libStates = await probeLibs({ needs: libNeeds,
|
|
124
|
-
const releases = await releasesOf(index, {
|
|
130
|
+
const libStates = await probeLibs({ needs: libNeeds, seam, force, index });
|
|
131
|
+
const releases = await releasesOf(index, { seam, force });
|
|
125
132
|
const statesOfUnit = (unit) => unit.needs.map((need) => {
|
|
126
133
|
const conflict = need.kind === 'extension' || need.kind === 'lib' ? conflictOf(index, need) : undefined;
|
|
127
134
|
if (conflict !== undefined) {
|
|
@@ -179,7 +186,7 @@ async function loadCapabilities(options) {
|
|
|
179
186
|
export async function probeUnitCommands(options) {
|
|
180
187
|
const units = options.catalog === undefined ? [options.unit] : options.catalog;
|
|
181
188
|
const all = await probeUnits({
|
|
182
|
-
|
|
189
|
+
seam: options.seam,
|
|
183
190
|
runtimeCommands: options.runtimeCommands ?? {},
|
|
184
191
|
units,
|
|
185
192
|
...(options.force === undefined ? {} : { force: options.force }),
|
package/dist/release-port.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
export declare const latestVersion: (options: {
|
|
2
|
-
readonly
|
|
2
|
+
readonly seam: import("@dsh-workbench/shared/host").Seam;
|
|
3
3
|
readonly name: string;
|
|
4
4
|
readonly registry: string;
|
|
5
5
|
readonly force?: boolean;
|
|
6
6
|
}) => Promise<string | undefined>;
|
|
7
7
|
export declare const missingReleaseParts: (options: {
|
|
8
|
-
readonly
|
|
8
|
+
readonly seam: import("@dsh-workbench/shared/host").Seam;
|
|
9
9
|
readonly name: string;
|
|
10
10
|
readonly registry: string;
|
|
11
11
|
readonly version: string;
|
|
12
12
|
readonly force?: boolean;
|
|
13
13
|
}) => Promise<readonly string[]>;
|
|
14
14
|
export declare const probeRelease: (options: {
|
|
15
|
-
readonly
|
|
15
|
+
readonly seam: import("@dsh-workbench/shared/host").Seam;
|
|
16
16
|
readonly package: string;
|
|
17
17
|
readonly registry?: string | undefined;
|
|
18
18
|
readonly force?: boolean;
|
package/dist/release-port.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createReleasePort } from '@dsh-workbench/adapter-profile';
|
|
2
|
-
import {
|
|
3
|
-
const port = createReleasePort({
|
|
2
|
+
import { vendorPrefix } from '@dsh-workbench/adapter-runtime';
|
|
3
|
+
const port = createReleasePort({ prefix: vendorPrefix() });
|
|
4
4
|
export const latestVersion = port.latestVersion;
|
|
5
5
|
export const missingReleaseParts = port.missingReleaseParts;
|
|
6
6
|
export const probeRelease = port.probeRelease;
|
package/dist/runtime-seed.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { spawn } from 'node:child_process';
|
|
2
1
|
import type { DshHostContext } from '@dsh-workbench/shared';
|
|
2
|
+
import type { Seam } from '@dsh-workbench/shared/host';
|
|
3
3
|
export type SeedLog = (message: string) => void;
|
|
4
4
|
export interface RuntimeSeedPaths {
|
|
5
5
|
readonly root: string;
|
|
@@ -21,9 +21,7 @@ export interface RuntimeSeedOptions {
|
|
|
21
21
|
}
|
|
22
22
|
export declare function opencliBinName(platform?: NodeJS.Platform): string;
|
|
23
23
|
export declare function runtimeSeedPaths(root: string, platform?: NodeJS.Platform): RuntimeSeedPaths;
|
|
24
|
-
export declare function runtimeSeedRootOf(
|
|
25
|
-
export declare function coversWritableRoot(workspaceRoot: string, root: string): boolean;
|
|
26
|
-
export declare function warnUnwritableRoot(ctx: DshHostContext): void;
|
|
24
|
+
export declare function runtimeSeedRootOf(_ctx: DshHostContext): string | null;
|
|
27
25
|
export declare function wrapperRootOf(fallbackRoot: string): string;
|
|
28
26
|
export declare function isInstalledCopy(packageRoot: string): boolean;
|
|
29
27
|
export declare function opencliWrapperScript(packageRoot: string, home: string, platform?: NodeJS.Platform): string;
|
|
@@ -38,7 +36,7 @@ export declare function workshopSeedPlan(packageRoot: string, home: string, root
|
|
|
38
36
|
readonly entry: SeedCommand;
|
|
39
37
|
readonly full: SeedCommand;
|
|
40
38
|
};
|
|
41
|
-
export declare function runDetached(command: SeedCommand, onError: SeedLog,
|
|
39
|
+
export declare function runDetached(command: SeedCommand, onError: SeedLog, seam?: Seam | undefined): void;
|
|
42
40
|
export declare function prependPath(entryDir: string, env?: NodeJS.ProcessEnv): boolean;
|
|
43
|
-
export declare function seedWorkbenchToolchain(root: string, log: SeedLog): void
|
|
41
|
+
export declare function seedWorkbenchToolchain(root: string, log: SeedLog, seam?: Seam | undefined): Promise<void>;
|
|
44
42
|
export declare function seedRuntimeFiles(options: RuntimeSeedOptions): readonly string[];
|
package/dist/runtime-seed.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { execa } from 'execa';
|
|
2
1
|
import { toolchainManifestOf } from '@dsh-workbench/adapter-runtime';
|
|
3
2
|
import { createRequire } from 'node:module';
|
|
4
|
-
import
|
|
5
|
-
import { chmodSync, closeSync, mkdirSync, openSync, readFileSync, rmSync, } from 'node:fs';
|
|
3
|
+
import { mkdirSync, readFileSync, rmSync } from 'node:fs';
|
|
6
4
|
import { delimiter, dirname, join, sep } from 'node:path';
|
|
7
|
-
import { quoteShellArg, quoteShellArgFor } from '@dsh-workbench/shared/host';
|
|
8
|
-
import { desktopPnpmPath, desktopPnpmVersion, ensureToolchain, localNpmCache, localPnpmCommand,
|
|
5
|
+
import { pathWithBinsOf, quoteShellArg, quoteShellArgFor, workbenchRoot, writeTextFile } from '@dsh-workbench/shared/host';
|
|
6
|
+
import { desktopBundledBins, desktopNodeExecutable, desktopPnpmPath, desktopPnpmVersion, ensureToolchain, localNpmCache, localPnpmCommand, provisionLocalPnpm, } from './toolchain.js';
|
|
9
7
|
export function opencliBinName(platform = process.platform) {
|
|
10
8
|
return platform === 'win32' ? 'opencli.cmd' : 'opencli';
|
|
11
9
|
}
|
|
@@ -25,32 +23,8 @@ export function runtimeSeedPaths(root, platform = process.platform) {
|
|
|
25
23
|
workshopManifest: join(workshop, 'package.json'),
|
|
26
24
|
};
|
|
27
25
|
}
|
|
28
|
-
export function runtimeSeedRootOf(
|
|
29
|
-
|
|
30
|
-
if (configured !== undefined && configured !== '')
|
|
31
|
-
return configured;
|
|
32
|
-
const homePath = ctx.get('dshHomePath');
|
|
33
|
-
if (typeof homePath !== 'function')
|
|
34
|
-
return null;
|
|
35
|
-
try {
|
|
36
|
-
return homePath('workbench');
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
export function coversWritableRoot(workspaceRoot, root) {
|
|
43
|
-
const prefix = workspaceRoot.endsWith(sep) ? workspaceRoot : `${workspaceRoot}${sep}`;
|
|
44
|
-
return root === workspaceRoot || root.startsWith(prefix);
|
|
45
|
-
}
|
|
46
|
-
export function warnUnwritableRoot(ctx) {
|
|
47
|
-
const root = runtimeSeedRootOf(ctx);
|
|
48
|
-
if (root === null)
|
|
49
|
-
return;
|
|
50
|
-
const workspaceRoot = ctx.get('sandboxPolicy')?.workspaceRoot;
|
|
51
|
-
if (workspaceRoot === undefined || coversWritableRoot(workspaceRoot, root))
|
|
52
|
-
return;
|
|
53
|
-
ctx.logger?.warn?.(`[dsh-workbench] 可写根 ${workspaceRoot} 盖不住 ${root}:市场装插件、自举命令可能被沙箱挡(把 profile/sandbox.patch.yml 那一行写进这个 profile 的 cordis.patch.yml 再重启)`);
|
|
26
|
+
export function runtimeSeedRootOf(_ctx) {
|
|
27
|
+
return workbenchRoot();
|
|
54
28
|
}
|
|
55
29
|
export function wrapperRootOf(fallbackRoot) {
|
|
56
30
|
try {
|
|
@@ -88,49 +62,46 @@ export function workshopSeedPlan(packageRoot, home, root, platform = process.pla
|
|
|
88
62
|
full: { file: 'bash', args: [script], env, log },
|
|
89
63
|
};
|
|
90
64
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
65
|
+
export function runDetached(command, onError, seam) {
|
|
66
|
+
if (seam === undefined) {
|
|
67
|
+
onError(`自举脚本没跑起来(${command.file}):宿主没给执行缝`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
94
70
|
try {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
71
|
+
const handle = seam.spawn({
|
|
72
|
+
target: { argv: [command.file, ...command.args] },
|
|
73
|
+
intent: { kind: 'host' },
|
|
74
|
+
lifetime: 'host',
|
|
75
|
+
logFile: command.log,
|
|
76
|
+
env: command.env,
|
|
77
|
+
label: 'seed',
|
|
100
78
|
});
|
|
101
|
-
|
|
102
|
-
child.unref();
|
|
79
|
+
handle.onError((error) => onError(`自举脚本没跑起来(${command.file}):${String(error)}`));
|
|
103
80
|
}
|
|
104
81
|
catch (error) {
|
|
105
82
|
onError(`自举脚本没跑起来(${command.file}):${String(error)}`);
|
|
106
83
|
}
|
|
107
|
-
finally {
|
|
108
|
-
if (fd !== null)
|
|
109
|
-
closeQuietly(fd);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
function closeQuietly(fd) {
|
|
113
|
-
try {
|
|
114
|
-
closeSync(fd);
|
|
115
|
-
}
|
|
116
|
-
catch {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
84
|
}
|
|
120
85
|
export function prependPath(entryDir, env = process.env) {
|
|
121
86
|
const parts = (env.PATH ?? '').split(delimiter).filter((part) => part !== '');
|
|
122
87
|
if (parts.includes(entryDir))
|
|
123
88
|
return false;
|
|
124
|
-
env.PATH = [entryDir
|
|
89
|
+
env.PATH = pathWithBinsOf(env.PATH, [entryDir]);
|
|
125
90
|
return true;
|
|
126
91
|
}
|
|
127
|
-
export function seedWorkbenchToolchain(root, log) {
|
|
92
|
+
export async function seedWorkbenchToolchain(root, log, seam) {
|
|
93
|
+
for (const dir of desktopBundledBins()) {
|
|
94
|
+
if (prependPath(dir))
|
|
95
|
+
log(`PATH 前插 Desktop 自带 ${dir}`);
|
|
96
|
+
}
|
|
128
97
|
const bundledPnpm = desktopPnpmPath();
|
|
129
98
|
const bundledMajor = Number(desktopPnpmVersion()?.split('.')[0] ?? '0');
|
|
130
99
|
const bundledUsable = bundledPnpm !== undefined && bundledMajor >= 10;
|
|
131
100
|
if (bundledPnpm !== undefined && bundledUsable) {
|
|
132
|
-
|
|
133
|
-
|
|
101
|
+
const bundledNode = desktopNodeExecutable();
|
|
102
|
+
const nodePrefix = bundledNode === undefined ? 'node' : quoteShellArgFor(bundledNode, process.platform);
|
|
103
|
+
process.env.DSH_WB_PNPM = `${nodePrefix} ${quoteShellArgFor(bundledPnpm, process.platform)}`;
|
|
104
|
+
log(`pnpm 用 Desktop 自带的:${bundledPnpm}(node: ${nodePrefix})`);
|
|
134
105
|
}
|
|
135
106
|
else if (bundledPnpm !== undefined) {
|
|
136
107
|
log(`Desktop 自带 pnpm 版本低于 10,优先用 PATH 上的 pnpm`);
|
|
@@ -155,7 +126,7 @@ export function seedWorkbenchToolchain(root, log) {
|
|
|
155
126
|
process.env.DSH_WB_PNPM = localPnpmCommand(root);
|
|
156
127
|
}
|
|
157
128
|
else if (!bundledUsable && toolchain.pathDir !== undefined) {
|
|
158
|
-
const installed =
|
|
129
|
+
const installed = await provisionLocalPnpm({ root, seam });
|
|
159
130
|
if (installed.ok && installed.binDir !== undefined) {
|
|
160
131
|
if (prependPath(installed.binDir))
|
|
161
132
|
log(`PATH 前插 ${installed.binDir}`);
|
|
@@ -178,15 +149,14 @@ export function seedRuntimeFiles(options) {
|
|
|
178
149
|
const manifest = join(paths.opencliRoot, 'toolchain', 'package.json');
|
|
179
150
|
mkdirSync(dirname(manifest), { recursive: true });
|
|
180
151
|
if (readText(manifest) !== toolchainManifestOf()) {
|
|
181
|
-
|
|
152
|
+
writeTextFile(manifest, toolchainManifestOf());
|
|
182
153
|
done.push(manifest);
|
|
183
154
|
}
|
|
184
155
|
rmSync(join(paths.opencliRoot, 'toolchain', 'pnpm-workspace.yaml'), { force: true });
|
|
185
156
|
const wanted = opencliWrapperScript(options.packageRoot, options.home, platform);
|
|
186
157
|
if (readText(paths.opencliBin) !== wanted) {
|
|
187
158
|
rmSync(paths.opencliBin, { force: true });
|
|
188
|
-
|
|
189
|
-
chmodSync(paths.opencliBin, 0o755);
|
|
159
|
+
writeTextFile(paths.opencliBin, wanted, { mode: 0o755 });
|
|
190
160
|
done.push(paths.opencliBin);
|
|
191
161
|
}
|
|
192
162
|
}
|
package/dist/self-update.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Seam } from '@dsh-workbench/shared/host';
|
|
2
2
|
import { type SeedCommand } from './runtime-seed.js';
|
|
3
3
|
import { SELF_UPDATE_STATES, type SelfUpdateState, type WorkbenchSelfUpdate } from '@dsh-workbench/shared/contract/protocol/bundle-install';
|
|
4
4
|
export { SELF_UPDATE_STATES, type SelfUpdateState };
|
|
@@ -47,7 +47,7 @@ export interface SelfUpdateStart {
|
|
|
47
47
|
readonly paths: SelfUpdatePaths;
|
|
48
48
|
readonly forward: string;
|
|
49
49
|
}
|
|
50
|
-
export declare function selfUpdatePaths(
|
|
50
|
+
export declare function selfUpdatePaths(_dshHome: string, platform?: NodeJS.Platform): SelfUpdatePaths;
|
|
51
51
|
export declare function recoveryCommand(input: {
|
|
52
52
|
readonly profile: string;
|
|
53
53
|
readonly pkg: string;
|
|
@@ -58,6 +58,6 @@ export declare function selfUpdateMarker(request: SelfUpdateRequest, state: Self
|
|
|
58
58
|
export declare function selfUpdateScript(request: SelfUpdateRequest, paths: SelfUpdatePaths, cli?: SelfUpdateCli): string;
|
|
59
59
|
export declare function selfUpdateNodeScript(request: SelfUpdateRequest, paths: SelfUpdatePaths, cli?: SelfUpdateCli): string;
|
|
60
60
|
export declare function planSelfUpdate(request: SelfUpdateRequest, now?: Date, cli?: SelfUpdateCli, platform?: NodeJS.Platform): SelfUpdatePlan;
|
|
61
|
-
export declare function startSelfUpdate(request: SelfUpdateRequest, onError: (message: string) => void,
|
|
61
|
+
export declare function startSelfUpdate(request: SelfUpdateRequest, onError: (message: string) => void, seam?: Seam | undefined, cli?: SelfUpdateCli): SelfUpdateStart;
|
|
62
62
|
export declare function readSelfUpdateView(home: string, profile?: string): WorkbenchSelfUpdate | undefined;
|
|
63
63
|
export { runningVersionOf } from '@dsh-workbench/shared/host';
|
package/dist/self-update.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { quoteShellArg } from '@dsh-workbench/shared/host';
|
|
1
|
+
import { now as clockNow, quoteShellArg, workbenchRoot, writeJsonFile, writeTextFile } from '@dsh-workbench/shared/host';
|
|
3
2
|
import { hostSurface } from './platform.js';
|
|
4
|
-
import {
|
|
3
|
+
import { closeSync, existsSync, mkdirSync, openSync, readFileSync, readSync, statSync, } from 'node:fs';
|
|
5
4
|
import { dirname, join } from 'node:path';
|
|
6
5
|
import { runDetached } from './runtime-seed.js';
|
|
7
6
|
import { SELF_UPDATE_STATES, } from '@dsh-workbench/shared/contract/protocol/bundle-install';
|
|
@@ -41,9 +40,8 @@ export function selfUpdateCliFor(profile, proc = process, exists = existsSync) {
|
|
|
41
40
|
return PATH_DSH;
|
|
42
41
|
return desktopSelfUpdateCli(proc, exists) ?? PATH_DSH;
|
|
43
42
|
}
|
|
44
|
-
export function selfUpdatePaths(
|
|
45
|
-
const
|
|
46
|
-
const dir = configured === undefined || configured === '' ? join(dshHome, 'workbench') : configured;
|
|
43
|
+
export function selfUpdatePaths(_dshHome, platform = process.platform) {
|
|
44
|
+
const dir = workbenchRoot();
|
|
47
45
|
return {
|
|
48
46
|
dir,
|
|
49
47
|
script: join(dir, platform === 'win32' ? 'self-update.mjs' : 'self-update.sh'),
|
|
@@ -178,7 +176,7 @@ export function selfUpdateNodeScript(request, paths, cli = selfUpdateCliFor(requ
|
|
|
178
176
|
'',
|
|
179
177
|
].join('\n');
|
|
180
178
|
}
|
|
181
|
-
export function planSelfUpdate(request, now = new Date(), cli = selfUpdateCliFor(request.profile), platform = process.platform) {
|
|
179
|
+
export function planSelfUpdate(request, now = new Date(clockNow()), cli = selfUpdateCliFor(request.profile), platform = process.platform) {
|
|
182
180
|
const paths = selfUpdatePaths(request.dshHome, platform);
|
|
183
181
|
const windows = platform === 'win32';
|
|
184
182
|
return {
|
|
@@ -195,13 +193,12 @@ export function planSelfUpdate(request, now = new Date(), cli = selfUpdateCliFor
|
|
|
195
193
|
: { file: 'bash', args: [paths.script], env: {}, log: paths.log },
|
|
196
194
|
};
|
|
197
195
|
}
|
|
198
|
-
export function startSelfUpdate(request, onError,
|
|
199
|
-
const plan = planSelfUpdate(request, new Date(), cli);
|
|
196
|
+
export function startSelfUpdate(request, onError, seam, cli = selfUpdateCliFor(request.profile)) {
|
|
197
|
+
const plan = planSelfUpdate(request, new Date(clockNow()), cli);
|
|
200
198
|
mkdirSync(plan.paths.dir, { recursive: true });
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
runDetached(plan.command, onError, spawnImpl);
|
|
199
|
+
writeTextFile(plan.paths.script, plan.script, { mode: 0o755 });
|
|
200
|
+
writeJsonFile(plan.paths.marker, plan.marker);
|
|
201
|
+
runDetached(plan.command, onError, seam);
|
|
205
202
|
const forward = recoveryCommand({
|
|
206
203
|
profile: request.profile,
|
|
207
204
|
pkg: request.pkg,
|
package/dist/supply-port.d.ts
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
import type { SupplyPort } from '@dsh-workbench/shared/host';
|
|
2
|
-
export
|
|
1
|
+
import type { Seam, SupplyPort } from '@dsh-workbench/shared/host';
|
|
2
|
+
export interface ProbeSupplyOptions {
|
|
3
|
+
readonly seam?: Seam | undefined;
|
|
4
|
+
}
|
|
5
|
+
export declare function createSupplyPort(options?: ProbeSupplyOptions): SupplyPort;
|
package/dist/supply-port.js
CHANGED
|
@@ -7,7 +7,8 @@ import { startSelfUpdate } from './self-update.js';
|
|
|
7
7
|
import { declarationGaps, declarationRefusalOf, moduleDeclarationOf, packageRouteOf, pathDeclarationOf, pluginInstallPlan, profileDirOf, profileModules, readInstalledModule, readProfilePackage, registryDeclarationOf, resolvePluginSource, splitNpmSpec, } from '@dsh-workbench/adapter-supply';
|
|
8
8
|
import { readBundleManager, refusalReason } from '@dsh-workbench/shared/host';
|
|
9
9
|
import { OPENCLI_MANIFEST_FILE } from '@dsh-workbench/adapter-runtime';
|
|
10
|
-
export function createSupplyPort() {
|
|
10
|
+
export function createSupplyPort(options = {}) {
|
|
11
|
+
const seam = options.seam;
|
|
11
12
|
const port = {
|
|
12
13
|
isolatedRoot,
|
|
13
14
|
isolatedHome,
|
|
@@ -42,7 +43,7 @@ export function createSupplyPort() {
|
|
|
42
43
|
splitNpmSpec,
|
|
43
44
|
libInstallCommand,
|
|
44
45
|
libUninstallCommand,
|
|
45
|
-
startSelfUpdate,
|
|
46
|
+
startSelfUpdate: (request, onError) => startSelfUpdate(request, onError, seam),
|
|
46
47
|
};
|
|
47
48
|
return { ...port, env: port, modules: port };
|
|
48
49
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Seam } from '@dsh-workbench/shared/host';
|
|
2
2
|
export interface ToolchainReport {
|
|
3
3
|
readonly ok: boolean;
|
|
4
4
|
readonly detail: string;
|
|
@@ -6,5 +6,7 @@ export interface ToolchainReport {
|
|
|
6
6
|
readonly npmMissing: boolean;
|
|
7
7
|
readonly pnpmProblem: boolean;
|
|
8
8
|
readonly stalled?: boolean | undefined;
|
|
9
|
+
readonly diagnostics?: readonly string[] | undefined;
|
|
10
|
+
readonly hostBroken?: boolean | undefined;
|
|
9
11
|
}
|
|
10
|
-
export declare function probeDesktopToolchain(
|
|
12
|
+
export declare function probeDesktopToolchain(seam: Seam): Promise<ToolchainReport>;
|
package/dist/toolchain-probe.js
CHANGED
|
@@ -1,28 +1,49 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { productWrite, quoteShellArg } from '@dsh-workbench/shared/host';
|
|
2
|
+
import { delimiter } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { desktopBundledBins, desktopNodeExecutable, desktopPnpmPath, desktopPnpmVersion, desktopResourcesDir, desktopRuntimeEnv, } from './desktop-runtime.js';
|
|
4
5
|
import { hostSurface } from './platform.js';
|
|
5
|
-
async function toolVersion(
|
|
6
|
+
async function toolVersion(seam, line, extra) {
|
|
6
7
|
try {
|
|
7
|
-
const result = await
|
|
8
|
+
const result = await seam.run({
|
|
9
|
+
command: line,
|
|
10
|
+
intent: productWrite(),
|
|
11
|
+
retry: 'safe',
|
|
12
|
+
timeoutMs: 10_000,
|
|
13
|
+
...(extra?.workdir === undefined ? {} : { workdir: extra.workdir }),
|
|
14
|
+
});
|
|
8
15
|
const text = (result.stdout || result.stderr).trim().split('\n')[0] ?? '';
|
|
9
|
-
|
|
16
|
+
const fact = seam.facts().filter((entry) => entry.command === line).at(-1);
|
|
17
|
+
const sandbox = fact === undefined
|
|
18
|
+
? '(无)'
|
|
19
|
+
: `mode=${fact.mode} root=${fact.workspaceRoot}${fact.denial === undefined ? '' : ` denial=${fact.denial.scope}`}`;
|
|
20
|
+
return {
|
|
21
|
+
ok: result.exitCode === 0 && !result.timedOut,
|
|
22
|
+
text,
|
|
23
|
+
stalled: result.stalled,
|
|
24
|
+
code: result.exitCode,
|
|
25
|
+
raw: `${result.stdout ?? ''}${result.stderr ?? ''}`.trim().split('\n').slice(0, 2).join(' / '),
|
|
26
|
+
sandbox,
|
|
27
|
+
};
|
|
10
28
|
}
|
|
11
|
-
catch {
|
|
12
|
-
return { ok: false, text: '', stalled: false };
|
|
29
|
+
catch (error) {
|
|
30
|
+
return { ok: false, text: '', stalled: false, code: null, raw: String(error), sandbox: '(抛错)' };
|
|
13
31
|
}
|
|
14
32
|
}
|
|
15
|
-
export async function probeDesktopToolchain(
|
|
33
|
+
export async function probeDesktopToolchain(seam) {
|
|
34
|
+
const bundledNode = desktopNodeExecutable();
|
|
16
35
|
const bundledPnpm = desktopPnpmPath();
|
|
17
36
|
const bundledMajor = desktopPnpmVersion()?.split('.')[0];
|
|
18
37
|
const preferBundled = bundledPnpm !== undefined && Number(bundledMajor ?? '0') >= 10;
|
|
38
|
+
const nodeCommand = bundledNode === undefined ? 'node' : quoteShellArg(bundledNode);
|
|
19
39
|
const pnpmLine = preferBundled
|
|
20
|
-
?
|
|
40
|
+
? `${nodeCommand} ${quoteShellArg(bundledPnpm ?? '')} --version`
|
|
21
41
|
: 'pnpm --version';
|
|
42
|
+
const path = desktopRuntimeEnv().PATH;
|
|
22
43
|
const [node, npm, pnpm] = await Promise.all([
|
|
23
|
-
toolVersion(
|
|
24
|
-
toolVersion(
|
|
25
|
-
toolVersion(
|
|
44
|
+
toolVersion(seam, `${nodeCommand} --version`),
|
|
45
|
+
toolVersion(seam, 'npm --version'),
|
|
46
|
+
toolVersion(seam, pnpmLine),
|
|
26
47
|
]);
|
|
27
48
|
if (node.stalled || npm.stalled || pnpm.stalled) {
|
|
28
49
|
return {
|
|
@@ -56,5 +77,50 @@ export async function probeDesktopToolchain(shell) {
|
|
|
56
77
|
? `pnpm ${pnpm.text}(Desktop 自带)`
|
|
57
78
|
: `pnpm ${pnpm.text}`,
|
|
58
79
|
];
|
|
59
|
-
|
|
80
|
+
const control = [];
|
|
81
|
+
if (nodeMissing) {
|
|
82
|
+
for (const [label, file] of [
|
|
83
|
+
['direct bundled node', desktopNodeExecutable()],
|
|
84
|
+
['direct host node', process.execPath],
|
|
85
|
+
]) {
|
|
86
|
+
if (file === undefined) {
|
|
87
|
+
control.push(`control ${label}: (没有可执行文件)`);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const out = await seam.run({
|
|
92
|
+
argv: [file, '--version'],
|
|
93
|
+
intent: { kind: 'host' },
|
|
94
|
+
timeoutMs: 10_000,
|
|
95
|
+
});
|
|
96
|
+
control.push(`control ${label}: exit=${String(out.exitCode)} out=${(out.stdout || out.stderr).slice(0, 80)}`);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
control.push(`control ${label}: 起不来 ${String(error).slice(0, 120)}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
for (const [label, workdir] of [
|
|
103
|
+
['default', undefined],
|
|
104
|
+
['home', homedir()],
|
|
105
|
+
['cwd', process.cwd()],
|
|
106
|
+
]) {
|
|
107
|
+
const probe = await toolVersion(seam, 'echo workbench-probe', { workdir });
|
|
108
|
+
control.push(`control ${label}: exit=${String(probe.code)} out=${probe.raw.slice(0, 80) || '(空)'}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const hostBroken = control.some((line) => line.includes('exit=3221225794'));
|
|
112
|
+
const diagnostics = [
|
|
113
|
+
`deployment=${desktop ? 'desktop' : 'host'} · resources=${desktopResourcesDir() ?? '(无)'} · execPath=${process.execPath}`,
|
|
114
|
+
`bundled node=${bundledNode ?? '(找不到)'} · bundled pnpm=${bundledPnpm ?? '(找不到)'} · bins=${desktopBundledBins().join('|') || '(无)'}`,
|
|
115
|
+
`PATH 前两段=${(path ?? '').split(delimiter).slice(0, 2).join('|') || '(空)'}`,
|
|
116
|
+
`node: exit=${String(node.code)} sandbox=${node.sandbox} out=${node.raw.slice(0, 160) || '(空)'} cmd=${nodeCommand}`,
|
|
117
|
+
`pnpm: exit=${String(pnpm.code)} sandbox=${pnpm.sandbox} out=${pnpm.raw.slice(0, 160) || '(空)'} cmd=${pnpmLine}`,
|
|
118
|
+
`npm: exit=${String(npm.code)} sandbox=${npm.sandbox} out=${npm.raw.slice(0, 120) || '(空)'}`,
|
|
119
|
+
...control,
|
|
120
|
+
];
|
|
121
|
+
const base = parts.join(' · ');
|
|
122
|
+
const detail = hostBroken
|
|
123
|
+
? `宿主执行通道起不了子进程(0xC0000142 · DLL 初始化失败)——不是没装 node:${base}`
|
|
124
|
+
: base;
|
|
125
|
+
return { ok: !nodeMissing, detail, nodeMissing, npmMissing, pnpmProblem, diagnostics, hostBroken };
|
|
60
126
|
}
|
package/dist/toolchain.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import type { Seam } from '@dsh-workbench/shared/host';
|
|
2
|
+
import type { PnpmProcess } from './desktop-runtime.js';
|
|
3
|
+
export { desktopBundledBins, desktopNodeExecutable, desktopPnpmPath, desktopPnpmVersion, desktopResourcesDir, desktopRuntimeEnv, desktopRuntimeEnvPath } from './desktop-runtime.js';
|
|
4
|
+
export type { PnpmProcess } from './desktop-runtime.js';
|
|
1
5
|
export interface ToolchainProcess {
|
|
2
6
|
readonly versions: {
|
|
3
7
|
readonly electron?: string | undefined;
|
|
@@ -6,15 +10,6 @@ export interface ToolchainProcess {
|
|
|
6
10
|
readonly execPath: string;
|
|
7
11
|
readonly resourcesPath?: string | undefined;
|
|
8
12
|
}
|
|
9
|
-
export interface PnpmProcess {
|
|
10
|
-
readonly versions: {
|
|
11
|
-
readonly electron?: string | undefined;
|
|
12
|
-
readonly node?: string | undefined;
|
|
13
|
-
};
|
|
14
|
-
readonly resourcesPath?: string | undefined;
|
|
15
|
-
}
|
|
16
|
-
export declare function desktopPnpmPath(proc?: PnpmProcess, exists?: (path: string) => boolean): string | undefined;
|
|
17
|
-
export declare function desktopPnpmVersion(proc?: PnpmProcess, exists?: (path: string) => boolean): string | undefined;
|
|
18
13
|
export interface ToolchainOptions {
|
|
19
14
|
readonly root: string;
|
|
20
15
|
readonly proc?: ToolchainProcess | undefined;
|
|
@@ -61,10 +56,11 @@ export interface LocalPnpmProvision {
|
|
|
61
56
|
}
|
|
62
57
|
export declare function provisionLocalPnpm(options: {
|
|
63
58
|
readonly root: string;
|
|
64
|
-
readonly
|
|
59
|
+
readonly seam?: Seam | undefined;
|
|
60
|
+
readonly run?: ((command: string) => Promise<{
|
|
65
61
|
ok: boolean;
|
|
66
62
|
detail: string;
|
|
67
|
-
}
|
|
63
|
+
}>) | undefined;
|
|
68
64
|
readonly installed?: (() => boolean) | undefined;
|
|
69
65
|
readonly platform?: NodeJS.Platform | undefined;
|
|
70
66
|
readonly proc?: PnpmProcess | undefined;
|
|
@@ -72,14 +68,6 @@ export declare function provisionLocalPnpm(options: {
|
|
|
72
68
|
readonly pnpm?: string | undefined;
|
|
73
69
|
readonly npm?: string | undefined;
|
|
74
70
|
}): Promise<LocalPnpmProvision>;
|
|
75
|
-
export declare function provisionLocalPnpmSync(options: {
|
|
76
|
-
readonly root: string;
|
|
77
|
-
readonly run?: ((command: string) => void) | undefined;
|
|
78
|
-
readonly installed?: (() => boolean) | undefined;
|
|
79
|
-
readonly platform?: NodeJS.Platform | undefined;
|
|
80
|
-
readonly proc?: PnpmProcess | undefined;
|
|
81
|
-
readonly exists?: ((path: string) => boolean) | undefined;
|
|
82
|
-
}): LocalPnpmProvision;
|
|
83
71
|
export declare function desktopNodeBinary(proc?: ToolchainProcess, platform?: NodeJS.Platform, exists?: (path: string) => boolean): string | undefined;
|
|
84
72
|
export declare function desktopNodeShim(proc?: ToolchainProcess, platform?: NodeJS.Platform, exists?: (path: string) => boolean): string | undefined;
|
|
85
73
|
export declare function toolchainBinDir(root: string): string;
|