@ran-sh/dsh-crew 1.0.3 → 1.1.0
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/codex/AGENTS.md +101 -92
- package/docs/ui-surfaces.md +48 -21
- package/lib/client.js +68 -44
- package/official-web-bridge/lib/client.js +368 -4709
- package/official-web-bridge/package.json +1 -2
- package/package.json +130 -67
- package/scripts/build-client.mjs +30 -15
- package/scripts/remove-legacy-official-bridge.ps1 +89 -0
- package/scripts/setup.mjs +152 -140
- package/scripts/verify-npm-install.mjs +311 -310
- package/scripts/verify-official-bridge-e2e.mjs +12 -1
- package/src/client/host-readiness.mjs +62 -59
- package/src/client/index.tsx +35 -30
- package/src/client/quick-entry.tsx +10 -0
- package/src/client/quick-panel.tsx +295 -0
- package/src/client/surface-detection.mjs +43 -30
- package/src/dsh-cli-runtime.mjs +500 -40
- package/src/dsh-cohort.mjs +20 -0
- package/src/hub/index.mjs +1602 -1485
- package/src/install/npx-lifecycle.mjs +1568 -111
- package/src/install/official-web.mjs +36 -73
- package/src/jobs.mjs +20 -24
- package/src/official-web-bridge.mjs +329 -249
- package/src/runtime-identity.mjs +23 -1
- package/src/supervisor/restart-request.mjs +202 -0
- package/windows/start-dsh-crew.ps1 +783 -370
- package/worker.cordis.yml +32 -46
- package/zcode/AGENTS.md +35 -26
package/scripts/setup.mjs
CHANGED
|
@@ -13,67 +13,68 @@ import { homedir } from 'node:os';
|
|
|
13
13
|
import * as realInstaller from '../src/install/install.mjs';
|
|
14
14
|
import { crewDshHome, crewProfileDir, CREW_PROFILE_NAME } from '../src/install/install.mjs';
|
|
15
15
|
import {
|
|
16
|
-
ensureCrewDshRuntime,
|
|
17
|
-
ensureCrewPluginRegistration,
|
|
18
|
-
resolveDshCli,
|
|
16
|
+
ensureCrewDshRuntime,
|
|
17
|
+
ensureCrewPluginRegistration,
|
|
18
|
+
resolveDshCli,
|
|
19
19
|
runResolvedDsh,
|
|
20
20
|
describeDshCli,
|
|
21
21
|
removeCrewPluginRegistration,
|
|
22
|
+
TARGET_DSH_VERSION,
|
|
22
23
|
} from '../src/dsh-cli-runtime.mjs';
|
|
23
24
|
|
|
24
25
|
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
25
26
|
|
|
26
|
-
function commandExists(name) {
|
|
27
|
-
const r = spawnSync(/^win/.test(process.platform) ? 'where' : 'which', [name], {
|
|
27
|
+
function commandExists(name) {
|
|
28
|
+
const r = spawnSync(/^win/.test(process.platform) ? 'where' : 'which', [name], {
|
|
28
29
|
encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'],
|
|
29
30
|
});
|
|
30
|
-
return r.status === 0;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const PACKAGE_MANAGER_COMMAND = /^(?:npm|npx|pnpm|yarn|yarnpkg|bun|bunx)$/i;
|
|
34
|
-
|
|
35
|
-
export function spawnCommand(command, platform = process.platform) {
|
|
36
|
-
if (platform === 'win32' && PACKAGE_MANAGER_COMMAND.test(command)) {
|
|
37
|
-
return `${command}.cmd`;
|
|
38
|
-
}
|
|
39
|
-
return command;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function spawnNeedsShell(command, platform = process.platform) {
|
|
43
|
-
return platform === 'win32' && PACKAGE_MANAGER_COMMAND.test(command);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function spawnInvocation(command, args = [], platform = process.platform, environment = process.env) {
|
|
47
|
-
const executable = spawnCommand(command, platform);
|
|
48
|
-
if (!spawnNeedsShell(command, platform)) return { command: executable, args };
|
|
49
|
-
const unsafe = args.find((arg) => !/^[A-Za-z0-9@._:+/=\-]+$/.test(String(arg)));
|
|
50
|
-
if (unsafe !== undefined) throw new Error(`unsafe package-manager argument: ${unsafe}`);
|
|
51
|
-
return {
|
|
52
|
-
command: environment.ComSpec || 'cmd.exe',
|
|
53
|
-
args: ['/d', '/s', '/c', [executable, ...args].join(' ')],
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function run(cmd, args, opts = {}) {
|
|
58
|
-
let invocation;
|
|
59
|
-
try {
|
|
60
|
-
invocation = spawnInvocation(cmd, args);
|
|
61
|
-
} catch (error) {
|
|
62
|
-
return { ok: false, status: -1, stdout: '', stderr: String(error?.message ?? error), error };
|
|
63
|
-
}
|
|
64
|
-
const r = spawnSync(invocation.command, invocation.args, {
|
|
65
|
-
encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], shell: opts.shell === true, cwd: opts.cwd ?? ROOT,
|
|
66
|
-
env: opts.env ?? process.env,
|
|
67
|
-
});
|
|
68
|
-
const processError = r.error ? `${r.error.name}: ${r.error.message}` : '';
|
|
69
|
-
return {
|
|
70
|
-
ok: r.status === 0,
|
|
71
|
-
status: r.status ?? -1,
|
|
72
|
-
stdout: r.stdout ?? '',
|
|
73
|
-
stderr: r.stderr || processError,
|
|
74
|
-
error: r.error ?? null,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
31
|
+
return r.status === 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const PACKAGE_MANAGER_COMMAND = /^(?:npm|npx|pnpm|yarn|yarnpkg|bun|bunx)$/i;
|
|
35
|
+
|
|
36
|
+
export function spawnCommand(command, platform = process.platform) {
|
|
37
|
+
if (platform === 'win32' && PACKAGE_MANAGER_COMMAND.test(command)) {
|
|
38
|
+
return `${command}.cmd`;
|
|
39
|
+
}
|
|
40
|
+
return command;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function spawnNeedsShell(command, platform = process.platform) {
|
|
44
|
+
return platform === 'win32' && PACKAGE_MANAGER_COMMAND.test(command);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function spawnInvocation(command, args = [], platform = process.platform, environment = process.env) {
|
|
48
|
+
const executable = spawnCommand(command, platform);
|
|
49
|
+
if (!spawnNeedsShell(command, platform)) return { command: executable, args };
|
|
50
|
+
const unsafe = args.find((arg) => !/^[A-Za-z0-9@._:+/=\-]+$/.test(String(arg)));
|
|
51
|
+
if (unsafe !== undefined) throw new Error(`unsafe package-manager argument: ${unsafe}`);
|
|
52
|
+
return {
|
|
53
|
+
command: environment.ComSpec || 'cmd.exe',
|
|
54
|
+
args: ['/d', '/s', '/c', [executable, ...args].join(' ')],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function run(cmd, args, opts = {}) {
|
|
59
|
+
let invocation;
|
|
60
|
+
try {
|
|
61
|
+
invocation = spawnInvocation(cmd, args);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
return { ok: false, status: -1, stdout: '', stderr: String(error?.message ?? error), error };
|
|
64
|
+
}
|
|
65
|
+
const r = spawnSync(invocation.command, invocation.args, {
|
|
66
|
+
encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], shell: opts.shell === true, cwd: opts.cwd ?? ROOT,
|
|
67
|
+
env: opts.env ?? process.env,
|
|
68
|
+
});
|
|
69
|
+
const processError = r.error ? `${r.error.name}: ${r.error.message}` : '';
|
|
70
|
+
return {
|
|
71
|
+
ok: r.status === 0,
|
|
72
|
+
status: r.status ?? -1,
|
|
73
|
+
stdout: r.stdout ?? '',
|
|
74
|
+
stderr: r.stderr || processError,
|
|
75
|
+
error: r.error ?? null,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
77
78
|
|
|
78
79
|
/**
|
|
79
80
|
* Detect the DSH CLI. `allowDownload` is intentionally opt-in: installation
|
|
@@ -143,18 +144,18 @@ export async function setupInstall({
|
|
|
143
144
|
installer = realInstaller,
|
|
144
145
|
depRunner = null,
|
|
145
146
|
} = {}) {
|
|
146
|
-
log('DSH Crew installer');
|
|
147
|
-
if (!checkRoot(root)) return { ok: false, error: `not a dsh-crew checkout: ${root}` };
|
|
148
|
-
const pnpmOk = commandExists('pnpm');
|
|
149
|
-
|
|
150
|
-
if (depRunner) {
|
|
147
|
+
log('DSH Crew installer');
|
|
148
|
+
if (!checkRoot(root)) return { ok: false, error: `not a dsh-crew checkout: ${root}` };
|
|
149
|
+
const pnpmOk = commandExists('pnpm');
|
|
150
|
+
|
|
151
|
+
if (depRunner) {
|
|
151
152
|
const r = depRunner(root);
|
|
152
153
|
if (!r.ok) { mark(log, false, r.text); return { ok: false, error: r.text }; }
|
|
153
154
|
mark(log, true, r.text);
|
|
154
|
-
} else if (!dryRun) {
|
|
155
|
-
const cmd = pnpmOk ? 'pnpm' : 'npx';
|
|
155
|
+
} else if (!dryRun) {
|
|
156
|
+
const cmd = pnpmOk ? 'pnpm' : 'npx';
|
|
156
157
|
const baseArgs = pnpmOk ? [] : ['-y', 'pnpm'];
|
|
157
|
-
const d = run(cmd, [...baseArgs, 'install', '--frozen-lockfile'], { cwd: root });
|
|
158
|
+
const d = run(cmd, [...baseArgs, 'install', '--frozen-lockfile'], { cwd: root });
|
|
158
159
|
if (!d.ok) {
|
|
159
160
|
if (depsPresent(root)) mark(log, true, `dependencies (already present; install skipped — ${(d.stderr || d.stdout || '').trim().split('\n')[0]})`);
|
|
160
161
|
else {
|
|
@@ -163,11 +164,11 @@ export async function setupInstall({
|
|
|
163
164
|
}
|
|
164
165
|
} else mark(log, true, 'dependencies');
|
|
165
166
|
} else mark(log, true, 'dependencies (dry-run)');
|
|
166
|
-
|
|
167
|
-
if (!dryRun) {
|
|
168
|
-
const b = pnpmOk
|
|
169
|
-
? run('pnpm', ['run', 'build:client'], { cwd: root })
|
|
170
|
-
: run('npx', ['-y', 'pnpm', 'run', 'build:client'], { cwd: root });
|
|
167
|
+
|
|
168
|
+
if (!dryRun) {
|
|
169
|
+
const b = pnpmOk
|
|
170
|
+
? run('pnpm', ['run', 'build:client'], { cwd: root })
|
|
171
|
+
: run('npx', ['-y', 'pnpm', 'run', 'build:client'], { cwd: root });
|
|
171
172
|
if (!b.ok) {
|
|
172
173
|
log(`✗ client build failed:\n${(b.stderr || b.stdout || '').slice(0, 600)}`);
|
|
173
174
|
return { ok: false, error: 'client build failed' };
|
|
@@ -181,6 +182,17 @@ export async function setupInstall({
|
|
|
181
182
|
// available, install a reusable copy under Crew state before falling back to
|
|
182
183
|
// the transient download path. Dry-run never provisions or downloads.
|
|
183
184
|
let dsh = detectDsh({ allowDownload: false, home });
|
|
185
|
+
// A reusable Crew runtime pinned to a DIFFERENT cohort than this source
|
|
186
|
+
// tree must never be silently reused (and never upgraded in place by the
|
|
187
|
+
// installer): a stale runtime would boot the wrong @deepseek-ai/dsh. The
|
|
188
|
+
// transactional update path owns cohort migration. Dry-run never mutates
|
|
189
|
+
// and must not be blocked by the machine's current cohort state.
|
|
190
|
+
if (!dryRun && dsh?.kind === 'crew-runtime' && dsh.version && dsh.version !== TARGET_DSH_VERSION) {
|
|
191
|
+
return {
|
|
192
|
+
ok: false,
|
|
193
|
+
error: `Crew runtime ${dsh.version} does not match ${TARGET_DSH_VERSION}; use the transactional update path (dsh-crew update) to migrate the cohort`,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
184
196
|
if (!dryRun && (!dsh || dsh.kind === 'npx-local')) {
|
|
185
197
|
const boot = ensureCrewDshRuntime({ home });
|
|
186
198
|
if (boot.ok) dsh = boot.cli;
|
|
@@ -197,45 +209,45 @@ export async function setupInstall({
|
|
|
197
209
|
// is kept here as an explicit contrast so existing CLI tests/people see the
|
|
198
210
|
// change, never as a command that targets the official web profile.
|
|
199
211
|
mark(log, true, `DSH web profile would be linked (legacy) — now: dedicated dsh-crew profile under the Crew DSH_HOME; the official web profile is never modified (${dsh.description ?? dsh.kind} add "link:${root}")`);
|
|
200
|
-
} else {
|
|
201
|
-
const registration = ensureCrewPluginRegistration({ home, root, name });
|
|
202
|
-
if (!registration.ok) {
|
|
203
|
-
log(`✗ DSH crew profile link failed (${registration.code ?? 'unknown'})`);
|
|
204
|
-
return { ok: false, error: 'DSH profile link failed' };
|
|
205
|
-
}
|
|
206
|
-
mark(log, true, `DSH crew profile linked offline (dedicated Crew DSH_HOME, profile dsh-crew; ${registration.changed ? 'updated' : 'already current'})`);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (dryRun) mark(log, true, 'Codex Desktop integration (dry-run)');
|
|
210
|
-
else {
|
|
212
|
+
} else {
|
|
213
|
+
const registration = ensureCrewPluginRegistration({ home, root, name });
|
|
214
|
+
if (!registration.ok) {
|
|
215
|
+
log(`✗ DSH crew profile link failed (${registration.code ?? 'unknown'})`);
|
|
216
|
+
return { ok: false, error: 'DSH profile link failed' };
|
|
217
|
+
}
|
|
218
|
+
mark(log, true, `DSH crew profile linked offline (dedicated Crew DSH_HOME, profile dsh-crew; ${registration.changed ? 'updated' : 'already current'})`);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (dryRun) mark(log, true, 'Codex Desktop integration (dry-run)');
|
|
222
|
+
else {
|
|
211
223
|
const r = installer.installCodex ? installer.installCodex({ home }) : realInstaller.installCodex({ home });
|
|
212
224
|
mark(log, r.ok !== false, r.ok === false ? `Codex Desktop integration failed: ${(r.actions ?? []).join('; ')}` : 'Codex Desktop integration');
|
|
213
|
-
if (r.ok === false) return { ok: false, error: 'Codex integration failed' };
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (dryRun) mark(log, true, 'ZCode integration (dry-run)');
|
|
217
|
-
else {
|
|
218
|
-
const r = installer.installZCode
|
|
219
|
-
? installer.installZCode({ home, root })
|
|
220
|
-
: realInstaller.installZCode({ home, root });
|
|
221
|
-
if (r.ok === false) {
|
|
222
|
-
mark(log, false, `ZCode integration failed (${r.code ?? 'unknown'})`);
|
|
223
|
-
return { ok: false, error: 'ZCode integration failed' };
|
|
224
|
-
}
|
|
225
|
-
mark(log, true, 'ZCode integration');
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (dryRun) mark(log, true, 'Windows login startup (dry-run)');
|
|
229
|
-
else {
|
|
230
|
-
const r = installer.installWindowsStartup
|
|
231
|
-
? installer.installWindowsStartup({ home, root })
|
|
232
|
-
: realInstaller.installWindowsStartup({ home, root });
|
|
233
|
-
if (r.ok === false) {
|
|
234
|
-
mark(log, false, `Windows login startup failed (${r.code ?? 'unknown'})`);
|
|
235
|
-
return { ok: false, error: 'Windows login startup failed' };
|
|
236
|
-
}
|
|
237
|
-
if (r.supported) mark(log, true, 'Windows login startup');
|
|
238
|
-
}
|
|
225
|
+
if (r.ok === false) return { ok: false, error: 'Codex integration failed' };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (dryRun) mark(log, true, 'ZCode integration (dry-run)');
|
|
229
|
+
else {
|
|
230
|
+
const r = installer.installZCode
|
|
231
|
+
? installer.installZCode({ home, root })
|
|
232
|
+
: realInstaller.installZCode({ home, root });
|
|
233
|
+
if (r.ok === false) {
|
|
234
|
+
mark(log, false, `ZCode integration failed (${r.code ?? 'unknown'})`);
|
|
235
|
+
return { ok: false, error: 'ZCode integration failed' };
|
|
236
|
+
}
|
|
237
|
+
mark(log, true, 'ZCode integration');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (dryRun) mark(log, true, 'Windows login startup (dry-run)');
|
|
241
|
+
else {
|
|
242
|
+
const r = installer.installWindowsStartup
|
|
243
|
+
? installer.installWindowsStartup({ home, root })
|
|
244
|
+
: realInstaller.installWindowsStartup({ home, root });
|
|
245
|
+
if (r.ok === false) {
|
|
246
|
+
mark(log, false, `Windows login startup failed (${r.code ?? 'unknown'})`);
|
|
247
|
+
return { ok: false, error: 'Windows login startup failed' };
|
|
248
|
+
}
|
|
249
|
+
if (r.supported) mark(log, true, 'Windows login startup');
|
|
250
|
+
}
|
|
239
251
|
|
|
240
252
|
if (commandExists('claude')) {
|
|
241
253
|
if (dryRun) mark(log, true, 'Claude Code integration (dry-run)');
|
|
@@ -266,31 +278,31 @@ export async function setupUninstall({
|
|
|
266
278
|
const fail = (name, text) => { mark(log, false, text || `${name} failed`); failures.push(name); };
|
|
267
279
|
|
|
268
280
|
if (dryRun) {
|
|
269
|
-
mark(log, true, 'Codex Desktop integration would be removed');
|
|
270
|
-
mark(log, true, 'ZCode integration would be removed');
|
|
271
|
-
mark(log, true, 'Claude Code integration would be removed');
|
|
272
|
-
mark(log, true, 'Windows login startup would be removed');
|
|
273
|
-
mark(log, true, 'DSH crew profile would be removed');
|
|
281
|
+
mark(log, true, 'Codex Desktop integration would be removed');
|
|
282
|
+
mark(log, true, 'ZCode integration would be removed');
|
|
283
|
+
mark(log, true, 'Claude Code integration would be removed');
|
|
284
|
+
mark(log, true, 'Windows login startup would be removed');
|
|
285
|
+
mark(log, true, 'DSH crew profile would be removed');
|
|
274
286
|
} else {
|
|
275
287
|
const cx = installer.uninstallCodex ? installer.uninstallCodex({ home }) : realInstaller.uninstallCodex({ home });
|
|
276
|
-
if (cx.ok !== false) mark(log, true, 'Codex Desktop integration removed');
|
|
277
|
-
else fail('codex', 'Codex Desktop integration removal failed');
|
|
278
|
-
|
|
279
|
-
const zc = installer.uninstallZCode
|
|
280
|
-
? installer.uninstallZCode({ home, root })
|
|
281
|
-
: realInstaller.uninstallZCode({ home, root });
|
|
282
|
-
if (zc.ok !== false) mark(log, true, 'ZCode integration removed');
|
|
283
|
-
else fail('zcode', 'ZCode integration removal failed');
|
|
284
|
-
|
|
285
|
-
const cl = installer.uninstallClaudeCode ? installer.uninstallClaudeCode({ home }) : realInstaller.uninstallClaudeCode({ home });
|
|
286
|
-
if (cl.ok !== false) mark(log, true, 'Claude Code integration removed');
|
|
287
|
-
else fail('claude', 'Claude Code integration removal failed');
|
|
288
|
-
|
|
289
|
-
const startup = installer.uninstallWindowsStartup
|
|
290
|
-
? installer.uninstallWindowsStartup({ home })
|
|
291
|
-
: realInstaller.uninstallWindowsStartup({ home });
|
|
292
|
-
if (startup.ok === false) fail('startup', 'Windows login startup removal failed');
|
|
293
|
-
else if (startup.supported) mark(log, true, 'Windows login startup removed');
|
|
288
|
+
if (cx.ok !== false) mark(log, true, 'Codex Desktop integration removed');
|
|
289
|
+
else fail('codex', 'Codex Desktop integration removal failed');
|
|
290
|
+
|
|
291
|
+
const zc = installer.uninstallZCode
|
|
292
|
+
? installer.uninstallZCode({ home, root })
|
|
293
|
+
: realInstaller.uninstallZCode({ home, root });
|
|
294
|
+
if (zc.ok !== false) mark(log, true, 'ZCode integration removed');
|
|
295
|
+
else fail('zcode', 'ZCode integration removal failed');
|
|
296
|
+
|
|
297
|
+
const cl = installer.uninstallClaudeCode ? installer.uninstallClaudeCode({ home }) : realInstaller.uninstallClaudeCode({ home });
|
|
298
|
+
if (cl.ok !== false) mark(log, true, 'Claude Code integration removed');
|
|
299
|
+
else fail('claude', 'Claude Code integration removal failed');
|
|
300
|
+
|
|
301
|
+
const startup = installer.uninstallWindowsStartup
|
|
302
|
+
? installer.uninstallWindowsStartup({ home })
|
|
303
|
+
: realInstaller.uninstallWindowsStartup({ home });
|
|
304
|
+
if (startup.ok === false) fail('startup', 'Windows login startup removal failed');
|
|
305
|
+
else if (startup.supported) mark(log, true, 'Windows login startup removed');
|
|
294
306
|
|
|
295
307
|
const name = readPackageName(root);
|
|
296
308
|
if (!name) fail('dsh', 'DSH plugin removal failed: package name missing');
|
|
@@ -320,15 +332,15 @@ export async function setupUninstall({
|
|
|
320
332
|
}
|
|
321
333
|
|
|
322
334
|
export async function setupStatus({ log = console.log, root = ROOT, home = homedir(), installer = realInstaller } = {}) {
|
|
323
|
-
const st = installer.installStatus ? installer.installStatus({ home, root }) : realInstaller.installStatus({ home, root });
|
|
324
|
-
const claude = st?.claude?.installed ? 'installed' : 'not installed';
|
|
325
|
-
const codex = st?.codex?.installed ? 'installed' : 'not installed';
|
|
326
|
-
const zcode = st?.zcode?.installed ? 'installed' : 'not installed';
|
|
327
|
-
const startupState = installer.windowsStartupStatus
|
|
328
|
-
? installer.windowsStartupStatus({ home })
|
|
329
|
-
: realInstaller.windowsStartupStatus({ home });
|
|
330
|
-
const windowsStartup = !startupState.supported ? 'not supported'
|
|
331
|
-
: startupState.ready ? 'installed' : startupState.installed ? 'needs repair' : 'not installed';
|
|
335
|
+
const st = installer.installStatus ? installer.installStatus({ home, root }) : realInstaller.installStatus({ home, root });
|
|
336
|
+
const claude = st?.claude?.installed ? 'installed' : 'not installed';
|
|
337
|
+
const codex = st?.codex?.installed ? 'installed' : 'not installed';
|
|
338
|
+
const zcode = st?.zcode?.installed ? 'installed' : 'not installed';
|
|
339
|
+
const startupState = installer.windowsStartupStatus
|
|
340
|
+
? installer.windowsStartupStatus({ home })
|
|
341
|
+
: realInstaller.windowsStartupStatus({ home });
|
|
342
|
+
const windowsStartup = !startupState.supported ? 'not supported'
|
|
343
|
+
: startupState.ready ? 'installed' : startupState.installed ? 'needs repair' : 'not installed';
|
|
332
344
|
// Crew status reads ONLY the dedicated Crew profile under the Crew DSH_HOME;
|
|
333
345
|
// the official web profile layout under the default DSH home is intentionally
|
|
334
346
|
// never inspected.
|
|
@@ -343,12 +355,12 @@ export async function setupStatus({ log = console.log, root = ROOT, home = homed
|
|
|
343
355
|
} catch { dshPlugin = 'unknown'; }
|
|
344
356
|
}
|
|
345
357
|
log(`DSH plugin: ${dshPlugin} (dedicated dsh-crew profile; official web profile ignored)`);
|
|
346
|
-
log(`Codex Desktop integration: ${codex}`);
|
|
347
|
-
log(`ZCode integration: ${zcode}`);
|
|
348
|
-
log(`Claude Code integration: ${claude}`);
|
|
349
|
-
log(`Windows login startup: ${windowsStartup}`);
|
|
350
|
-
return { ok: true, dshPlugin, codex, zcode, claude, windowsStartup };
|
|
351
|
-
}
|
|
358
|
+
log(`Codex Desktop integration: ${codex}`);
|
|
359
|
+
log(`ZCode integration: ${zcode}`);
|
|
360
|
+
log(`Claude Code integration: ${claude}`);
|
|
361
|
+
log(`Windows login startup: ${windowsStartup}`);
|
|
362
|
+
return { ok: true, dshPlugin, codex, zcode, claude, windowsStartup };
|
|
363
|
+
}
|
|
352
364
|
|
|
353
365
|
export async function runSetupCli({ argv = process.argv.slice(2), run: actions = {}, log = console.log } = {}) {
|
|
354
366
|
const action = argv[0];
|