@dsh-workbench/adapter-probe 1.1.12 → 1.1.13
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/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/preflight-route.js +2 -1
- package/dist/preflight.d.ts +5 -11
- package/dist/preflight.js +43 -48
- package/dist/toolchain-probe.d.ts +10 -0
- package/dist/toolchain-probe.js +48 -0
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from './probe-units.js';
|
|
|
9
9
|
export * from './probe-verdict.js';
|
|
10
10
|
export * from './runtime-seed.js';
|
|
11
11
|
export * from './toolchain.js';
|
|
12
|
+
export * from './toolchain-probe.js';
|
|
12
13
|
export * from './version-range.js';
|
|
13
14
|
export * from './install.js';
|
|
14
15
|
export * from './self-update.js';
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export * from './probe-units.js';
|
|
|
9
9
|
export * from './probe-verdict.js';
|
|
10
10
|
export * from './runtime-seed.js';
|
|
11
11
|
export * from './toolchain.js';
|
|
12
|
+
export * from './toolchain-probe.js';
|
|
12
13
|
export * from './version-range.js';
|
|
13
14
|
export * from './install.js';
|
|
14
15
|
export * from './self-update.js';
|
package/dist/preflight-route.js
CHANGED
|
@@ -3,7 +3,8 @@ import { INSTALL_TIMEOUT_MS, preflightHandler, runShell, tailLines, workbenchRoo
|
|
|
3
3
|
import { WAKE_BROWSER_ROUTE } from '@dsh-workbench/shared/contract/protocol/preflight-wake';
|
|
4
4
|
import { createDiyPresetProbe } from './diy-preset-health.js';
|
|
5
5
|
import { hostSurface } from './platform.js';
|
|
6
|
-
import { createPreflight
|
|
6
|
+
import { createPreflight } from './preflight.js';
|
|
7
|
+
import { probeDesktopToolchain } from './toolchain-probe.js';
|
|
7
8
|
import { createDesktopBrowser } from './browser-wake.js';
|
|
8
9
|
import { profileDirOf } from '@dsh-workbench/adapter-supply';
|
|
9
10
|
import { prependPath, runtimeSeedRootOf } from './runtime-seed.js';
|
package/dist/preflight.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { DshShell, RuntimeCapabilities } from '@dsh-workbench/shared';
|
|
2
2
|
import type { DiyPresetVerdict } from './diy-preset-health.js';
|
|
3
3
|
import { type LocalNpmProvision, type LocalPnpmProvision } from './toolchain.js';
|
|
4
|
+
import type { ToolchainReport } from './toolchain-probe.js';
|
|
4
5
|
import type { DesktopBrowser } from './browser-wake.js';
|
|
6
|
+
export type PreflightFailure = 'permission' | 'network' | 'missing' | 'host' | 'unknown';
|
|
7
|
+
export declare function classifyFailure(text: string): PreflightFailure;
|
|
8
|
+
export type PreflightGuidance = 'install' | 'path' | 'shell' | 'host';
|
|
5
9
|
export type PreflightStepId = 'toolchain' | 'runtime' | 'cli' | 'bridge' | 'diy' | 'warm';
|
|
6
10
|
export type PreflightStepStatus = 'pending' | 'running' | 'ok' | 'warn' | 'failed';
|
|
7
11
|
export interface PreflightStep {
|
|
@@ -11,17 +15,6 @@ export interface PreflightStep {
|
|
|
11
15
|
readonly action?: string;
|
|
12
16
|
readonly command?: string;
|
|
13
17
|
}
|
|
14
|
-
export interface ToolchainReport {
|
|
15
|
-
readonly ok: boolean;
|
|
16
|
-
readonly detail: string;
|
|
17
|
-
readonly nodeMissing: boolean;
|
|
18
|
-
readonly npmMissing: boolean;
|
|
19
|
-
readonly pnpmProblem: boolean;
|
|
20
|
-
}
|
|
21
|
-
export type PreflightFailure = 'permission' | 'network' | 'missing' | 'unknown';
|
|
22
|
-
export declare function classifyFailure(text: string): PreflightFailure;
|
|
23
|
-
export type PreflightGuidance = 'install' | 'path' | 'shell';
|
|
24
|
-
export declare function probeDesktopToolchain(shell: DshShell): Promise<ToolchainReport>;
|
|
25
18
|
export type PreflightBridgeIssue = 'daemon' | 'extension' | 'profile' | 'stale' | 'unknown';
|
|
26
19
|
export declare const BRIDGE_ISSUE_ORDER: readonly PreflightBridgeIssue[];
|
|
27
20
|
export declare function readBridgeReport(stdout: string): {
|
|
@@ -57,6 +50,7 @@ export interface BridgeVerdict {
|
|
|
57
50
|
readonly detail: string;
|
|
58
51
|
readonly issues: readonly PreflightBridgeIssue[];
|
|
59
52
|
readonly command?: string | undefined;
|
|
53
|
+
readonly stalled?: boolean | undefined;
|
|
60
54
|
}
|
|
61
55
|
export declare function canWarm(bridge: {
|
|
62
56
|
ok: boolean;
|
package/dist/preflight.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { INSTALL_TIMEOUT_MS, OPENCLI_TIMEOUT_MS, PREFLIGHT_FRESH_MS, WARM_TIMEOUT_MS } from '@dsh-workbench/shared/host';
|
|
1
|
+
import { INSTALL_TIMEOUT_MS, OPENCLI_TIMEOUT_MS, PREFLIGHT_FRESH_MS, PREFLIGHT_VERSION_TIMEOUT_MS, WARM_TIMEOUT_MS, } from '@dsh-workbench/shared/host';
|
|
2
2
|
import { tailLines } from '@dsh-workbench/shared/host';
|
|
3
3
|
import { opencliCommandLine } from '@dsh-workbench/adapter-runtime';
|
|
4
4
|
import { runShell } from '@dsh-workbench/shared/host';
|
|
5
5
|
import { DIY_UPGRADE_COMMAND } from './diy-preset-health.js';
|
|
6
6
|
import { opencliInstallCommand } from './install.js';
|
|
7
|
-
import {
|
|
7
|
+
import { LOCAL_NPM_VERSION, LOCAL_PNPM_VERSION } from './toolchain.js';
|
|
8
8
|
import { bridgeFixCommand } from './browser-wake.js';
|
|
9
9
|
export function classifyFailure(text) {
|
|
10
10
|
const lower = text.toLowerCase();
|
|
@@ -16,42 +16,6 @@ export function classifyFailure(text) {
|
|
|
16
16
|
return 'missing';
|
|
17
17
|
return 'unknown';
|
|
18
18
|
}
|
|
19
|
-
async function toolVersion(shell, line) {
|
|
20
|
-
try {
|
|
21
|
-
const result = await runShell(shell, line, { timeoutMs: 10_000 });
|
|
22
|
-
const text = (result.stdout || result.stderr).trim().split('\n')[0] ?? '';
|
|
23
|
-
return { ok: result.exitCode === 0 && !result.timedOut, text };
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
return { ok: false, text: '' };
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
export async function probeDesktopToolchain(shell) {
|
|
30
|
-
const [node, npm, pnpm] = await Promise.all([
|
|
31
|
-
toolVersion(shell, 'node --version'),
|
|
32
|
-
toolVersion(shell, 'npm --version'),
|
|
33
|
-
toolVersion(shell, 'pnpm --version'),
|
|
34
|
-
]);
|
|
35
|
-
const nodeMissing = !node.ok;
|
|
36
|
-
const npmMissing = !npm.ok;
|
|
37
|
-
const hasBundledPnpm = desktopPnpmPath() !== undefined;
|
|
38
|
-
const pnpmMajor = /^v?(\d+)/.exec(pnpm.text)?.[1];
|
|
39
|
-
const pnpmProblem = !pnpm.ok || pnpmMajor !== '10';
|
|
40
|
-
const parts = [
|
|
41
|
-
nodeMissing ? 'node 不在 PATH(Desktop 自带 Node 的 shim 没生效)' : `node ${node.text}(Desktop 自带)`,
|
|
42
|
-
npmMissing
|
|
43
|
-
? hasBundledPnpm
|
|
44
|
-
? 'npm 缺(opencli 安装走 pnpm;插件安装/模块库仍需 npm)'
|
|
45
|
-
: 'npm 缺(装不了 opencli:bundled pnpm 也没找到)'
|
|
46
|
-
: `npm ${npm.text}`,
|
|
47
|
-
pnpmProblem
|
|
48
|
-
? pnpm.ok
|
|
49
|
-
? `pnpm ${pnpm.text}(工坊按 10 方言)`
|
|
50
|
-
: 'pnpm 缺(只影响工坊 build/install)'
|
|
51
|
-
: `pnpm ${pnpm.text}`,
|
|
52
|
-
];
|
|
53
|
-
return { ok: !nodeMissing, detail: parts.join(' · '), nodeMissing, npmMissing, pnpmProblem };
|
|
54
|
-
}
|
|
55
19
|
export const BRIDGE_ISSUE_ORDER = ['profile', 'stale', 'daemon', 'extension', 'unknown'];
|
|
56
20
|
export function readBridgeReport(stdout) {
|
|
57
21
|
const text = String(stdout ?? '');
|
|
@@ -115,6 +79,7 @@ export function createPreflight(options) {
|
|
|
115
79
|
...(options.desktopBrowser === undefined ? {} : { canWakeBrowser: true }),
|
|
116
80
|
};
|
|
117
81
|
let running = null;
|
|
82
|
+
let shellStalled = false;
|
|
118
83
|
function set(next) {
|
|
119
84
|
current = { ...current, ...next, at: Date.now() };
|
|
120
85
|
return current;
|
|
@@ -122,9 +87,19 @@ export function createPreflight(options) {
|
|
|
122
87
|
function patchStep(id, patch) {
|
|
123
88
|
return set({ steps: current.steps.map((item) => (item.id === id ? { ...item, ...patch } : item)) });
|
|
124
89
|
}
|
|
90
|
+
function hostFailure(detail) {
|
|
91
|
+
return set({ phase: 'failed', error: detail, failure: 'host', guidance: 'host' });
|
|
92
|
+
}
|
|
125
93
|
async function exec(commandLine, timeoutMs) {
|
|
94
|
+
if (shellStalled) {
|
|
95
|
+
return { kind: 'stalled', detail: `前一条命令就没交回结果,这一步没跑:${commandLine}` };
|
|
96
|
+
}
|
|
126
97
|
try {
|
|
127
98
|
const result = await runShell(shell, commandLine, { timeoutMs });
|
|
99
|
+
if (result.stalled) {
|
|
100
|
+
shellStalled = true;
|
|
101
|
+
return { kind: 'stalled', detail: `没有返回(宿主没把结果交回来):${commandLine}` };
|
|
102
|
+
}
|
|
128
103
|
if (result.timedOut) {
|
|
129
104
|
return { kind: 'error', detail: `超时(${String(timeoutMs)} ms):${commandLine}` };
|
|
130
105
|
}
|
|
@@ -138,13 +113,22 @@ export function createPreflight(options) {
|
|
|
138
113
|
}
|
|
139
114
|
}
|
|
140
115
|
async function probeVersion() {
|
|
141
|
-
const result = await exec(`${command} --version`,
|
|
142
|
-
if (result.kind === 'ok')
|
|
143
|
-
return { ok: true, missing: false, detail: result.stdout.trim().split('\n')[0] ?? '' };
|
|
144
|
-
|
|
116
|
+
const result = await exec(`${command} --version`, PREFLIGHT_VERSION_TIMEOUT_MS);
|
|
117
|
+
if (result.kind === 'ok') {
|
|
118
|
+
return { ok: true, missing: false, detail: result.stdout.trim().split('\n')[0] ?? '', stalled: false };
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
ok: false,
|
|
122
|
+
missing: result.kind === 'nonzero',
|
|
123
|
+
detail: result.detail,
|
|
124
|
+
stalled: result.kind === 'stalled',
|
|
125
|
+
};
|
|
145
126
|
}
|
|
146
127
|
async function probeBridge() {
|
|
147
128
|
const result = await exec(`${command} doctor`, OPENCLI_TIMEOUT_MS);
|
|
129
|
+
if (result.kind === 'stalled') {
|
|
130
|
+
return { ok: false, detail: result.detail, issues: ['unknown'], stalled: true };
|
|
131
|
+
}
|
|
148
132
|
if (result.kind !== 'ok')
|
|
149
133
|
return { ok: false, detail: result.detail, issues: ['unknown'] };
|
|
150
134
|
const report = readBridgeReport(result.stdout);
|
|
@@ -206,6 +190,7 @@ export function createPreflight(options) {
|
|
|
206
190
|
return { rows: verdict.rows, detail: verdict.detail, command: DIY_UPGRADE_COMMAND };
|
|
207
191
|
}
|
|
208
192
|
async function doRun() {
|
|
193
|
+
shellStalled = false;
|
|
209
194
|
set({
|
|
210
195
|
phase: 'checking',
|
|
211
196
|
error: undefined,
|
|
@@ -227,6 +212,7 @@ export function createPreflight(options) {
|
|
|
227
212
|
nodeMissing: true,
|
|
228
213
|
npmMissing: true,
|
|
229
214
|
pnpmProblem: true,
|
|
215
|
+
stalled: false,
|
|
230
216
|
}));
|
|
231
217
|
if (toolchain !== undefined && toolchain.ok && toolchain.npmMissing && options.provisionNpm !== undefined) {
|
|
232
218
|
set({ phase: 'installing' });
|
|
@@ -268,12 +254,9 @@ export function createPreflight(options) {
|
|
|
268
254
|
action: undefined,
|
|
269
255
|
});
|
|
270
256
|
if (!toolchain.ok) {
|
|
271
|
-
return
|
|
272
|
-
|
|
273
|
-
error: toolchain.detail,
|
|
274
|
-
failure: 'missing',
|
|
275
|
-
guidance: 'install',
|
|
276
|
-
});
|
|
257
|
+
return toolchain.stalled === true
|
|
258
|
+
? hostFailure(toolchain.detail)
|
|
259
|
+
: set({ phase: 'failed', error: toolchain.detail, failure: 'missing', guidance: 'install' });
|
|
277
260
|
}
|
|
278
261
|
}
|
|
279
262
|
if (options.runtimeCheck !== undefined) {
|
|
@@ -292,6 +275,10 @@ export function createPreflight(options) {
|
|
|
292
275
|
if (diyStarted !== undefined)
|
|
293
276
|
patchStep('diy', { status: 'running' });
|
|
294
277
|
let version = await probeVersion();
|
|
278
|
+
if (version.stalled) {
|
|
279
|
+
patchStep('cli', { status: 'failed', detail: version.detail, action: undefined });
|
|
280
|
+
return hostFailure(version.detail);
|
|
281
|
+
}
|
|
295
282
|
if (!version.ok && !version.missing) {
|
|
296
283
|
patchStep('cli', { status: 'failed', detail: version.detail, action: undefined });
|
|
297
284
|
return set({
|
|
@@ -329,6 +316,10 @@ export function createPreflight(options) {
|
|
|
329
316
|
}
|
|
330
317
|
patchStep('cli', { status: 'running', action: `${command} --version` });
|
|
331
318
|
version = await probeVersion();
|
|
319
|
+
if (version.stalled) {
|
|
320
|
+
patchStep('cli', { status: 'failed', detail: version.detail, action: undefined });
|
|
321
|
+
return hostFailure(version.detail);
|
|
322
|
+
}
|
|
332
323
|
if (!version.ok) {
|
|
333
324
|
patchStep('cli', { status: 'failed', detail: version.detail, command: installCommand });
|
|
334
325
|
return set({
|
|
@@ -343,6 +334,10 @@ export function createPreflight(options) {
|
|
|
343
334
|
}
|
|
344
335
|
patchStep('bridge', { status: 'running', action: `${command} doctor` });
|
|
345
336
|
const bridge = withBridge ? await probeBridge() : { ok: true, detail: '', issues: [] };
|
|
337
|
+
if (bridge.stalled === true) {
|
|
338
|
+
patchStep('bridge', { status: 'failed', detail: bridge.detail, action: undefined });
|
|
339
|
+
return hostFailure(bridge.detail);
|
|
340
|
+
}
|
|
346
341
|
if (withBridge && options.desktopBrowser !== undefined && bridge.ok) {
|
|
347
342
|
await options.desktopBrowser.observe().catch(() => undefined);
|
|
348
343
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DshShell } from '@dsh-workbench/shared';
|
|
2
|
+
export interface ToolchainReport {
|
|
3
|
+
readonly ok: boolean;
|
|
4
|
+
readonly detail: string;
|
|
5
|
+
readonly nodeMissing: boolean;
|
|
6
|
+
readonly npmMissing: boolean;
|
|
7
|
+
readonly pnpmProblem: boolean;
|
|
8
|
+
readonly stalled?: boolean | undefined;
|
|
9
|
+
}
|
|
10
|
+
export declare function probeDesktopToolchain(shell: DshShell): Promise<ToolchainReport>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { runShell } from '@dsh-workbench/shared/host';
|
|
2
|
+
import { desktopPnpmPath } from './toolchain.js';
|
|
3
|
+
async function toolVersion(shell, line) {
|
|
4
|
+
try {
|
|
5
|
+
const result = await runShell(shell, line, { timeoutMs: 10_000 });
|
|
6
|
+
const text = (result.stdout || result.stderr).trim().split('\n')[0] ?? '';
|
|
7
|
+
return { ok: result.exitCode === 0 && !result.timedOut, text, stalled: result.stalled };
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return { ok: false, text: '', stalled: false };
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export async function probeDesktopToolchain(shell) {
|
|
14
|
+
const [node, npm, pnpm] = await Promise.all([
|
|
15
|
+
toolVersion(shell, 'node --version'),
|
|
16
|
+
toolVersion(shell, 'npm --version'),
|
|
17
|
+
toolVersion(shell, 'pnpm --version'),
|
|
18
|
+
]);
|
|
19
|
+
if (node.stalled || npm.stalled || pnpm.stalled) {
|
|
20
|
+
return {
|
|
21
|
+
ok: false,
|
|
22
|
+
detail: '版本探测没有返回:node / npm / pnpm 的命令都没把结果交回来(不是没装)',
|
|
23
|
+
nodeMissing: false,
|
|
24
|
+
npmMissing: false,
|
|
25
|
+
pnpmProblem: false,
|
|
26
|
+
stalled: true,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const nodeMissing = !node.ok;
|
|
30
|
+
const npmMissing = !npm.ok;
|
|
31
|
+
const hasBundledPnpm = desktopPnpmPath() !== undefined;
|
|
32
|
+
const pnpmMajor = /^v?(\d+)/.exec(pnpm.text)?.[1];
|
|
33
|
+
const pnpmProblem = !pnpm.ok || pnpmMajor !== '10';
|
|
34
|
+
const parts = [
|
|
35
|
+
nodeMissing ? 'node 不在 PATH(Desktop 自带 Node 的 shim 没生效)' : `node ${node.text}(Desktop 自带)`,
|
|
36
|
+
npmMissing
|
|
37
|
+
? hasBundledPnpm
|
|
38
|
+
? 'npm 缺(opencli 安装走 pnpm;插件安装/模块库仍需 npm)'
|
|
39
|
+
: 'npm 缺(装不了 opencli:bundled pnpm 也没找到)'
|
|
40
|
+
: `npm ${npm.text}`,
|
|
41
|
+
pnpmProblem
|
|
42
|
+
? pnpm.ok
|
|
43
|
+
? `pnpm ${pnpm.text}(工坊按 10 方言)`
|
|
44
|
+
: 'pnpm 缺(只影响工坊 build/install)'
|
|
45
|
+
: `pnpm ${pnpm.text}`,
|
|
46
|
+
];
|
|
47
|
+
return { ok: !nodeMissing, detail: parts.join(' · '), nodeMissing, npmMissing, pnpmProblem };
|
|
48
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-workbench/adapter-probe",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.13",
|
|
4
4
|
"description": "Workbench adapter-probe adapter.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
"execa": "^10.2.0",
|
|
17
17
|
"proper-lockfile": "^4.1.2",
|
|
18
18
|
"write-file-atomic": "^8.0.0",
|
|
19
|
-
"@dsh-workbench/shared": "1.1.
|
|
20
|
-
"@dsh-workbench/adapter-runtime": "1.1.
|
|
21
|
-
"@dsh-workbench/adapter-profile": "1.1.
|
|
22
|
-
"@dsh-workbench/adapter-supply": "1.1.
|
|
19
|
+
"@dsh-workbench/shared": "1.1.13",
|
|
20
|
+
"@dsh-workbench/adapter-runtime": "1.1.13",
|
|
21
|
+
"@dsh-workbench/adapter-profile": "1.1.13",
|
|
22
|
+
"@dsh-workbench/adapter-supply": "1.1.13"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "^24.19.0",
|