@crewx/cli 0.9.0-rc.111 → 0.9.0-rc.112

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.
@@ -293,6 +293,9 @@ function runnerCommand(command) {
293
293
  function buildRunnerEnvironment(taskId) {
294
294
  const env = { ...process.env };
295
295
  delete env[INTERNAL_TOKEN_ENV];
296
+ if (process.versions.electron) {
297
+ env.ELECTRON_RUN_AS_NODE = '1';
298
+ }
296
299
  env.CREWX_DETACHED_RUNNER = '1';
297
300
  env.CREWX_ASSIGNED_TASK_ID = taskId;
298
301
  return env;
@@ -328,6 +331,9 @@ function readAssignedTaskActor(taskRepo, taskId) {
328
331
  }
329
332
  function buildMiddleEnvironment(token) {
330
333
  const env = { ...process.env };
334
+ if (process.versions.electron) {
335
+ env.ELECTRON_RUN_AS_NODE = '1';
336
+ }
331
337
  env[INTERNAL_TOKEN_ENV] = token;
332
338
  return env;
333
339
  }
@@ -6,6 +6,7 @@
6
6
  * crewx doctor Run full diagnosis
7
7
  * crewx doctor --config <path> Use specific config file
8
8
  */
9
+ import type { CrewxExecutableResolution, CrewxExecutableStage } from '@crewx/sdk';
9
10
  interface DiagnosticResult {
10
11
  name: string;
11
12
  status: 'success' | 'warning' | 'error';
@@ -44,6 +45,25 @@ export interface CrewxShimReport {
44
45
  fingerprint: string;
45
46
  }>;
46
47
  }
48
+ export interface CrewxExecutableReport {
49
+ platform: NodeJS.Platform;
50
+ pathCandidates: string[];
51
+ stage?: CrewxExecutableStage;
52
+ argv?: string[];
53
+ electron: boolean;
54
+ requiredEnvKeys: string[];
55
+ binResolution: 'global_first' | 'local_first';
56
+ adoptedPath?: string;
57
+ resolutionError?: string;
58
+ }
59
+ export interface CrewxExecutableInspectionOptions {
60
+ platform?: NodeJS.Platform;
61
+ cwd?: string;
62
+ env?: NodeJS.ProcessEnv;
63
+ binResolution?: 'global_first' | 'local_first';
64
+ pathCandidates?: readonly string[];
65
+ resolution?: CrewxExecutableResolution;
66
+ }
47
67
  /** CLI diagnostics keyed by the bare provider name used in PROVIDER_ORDER. */
48
68
  export declare const CLI_PROVIDER_INFO: Record<string, CliProviderInfo>;
49
69
  /** Format a byte count for diagnostic output. */
@@ -52,6 +72,10 @@ export declare function formatBytes(bytes: number): string;
52
72
  export declare function inspectNpxCache(cacheRoot?: string): NpxCacheReport;
53
73
  /** Inspect installed CrewX hooks without rewriting provider settings. */
54
74
  export declare function inspectHookCommands(projectRoot: string): HookCommandReport;
75
+ /** Inspect the SDK-selected CrewX executable without printing environment values. */
76
+ export declare function inspectCrewxExecutable(options?: CrewxExecutableInspectionOptions & {
77
+ configPath?: string;
78
+ }): CrewxExecutableReport;
55
79
  /** Inspect orphaned CrewX PATH shim directories without modifying them. */
56
80
  export declare function inspectCrewxShims(crewxHome?: string, resolvedFingerprint?: string | undefined): CrewxShimReport;
57
81
  /**
@@ -12,10 +12,10 @@ exports.CLI_PROVIDER_INFO = void 0;
12
12
  exports.formatBytes = formatBytes;
13
13
  exports.inspectNpxCache = inspectNpxCache;
14
14
  exports.inspectHookCommands = inspectHookCommands;
15
+ exports.inspectCrewxExecutable = inspectCrewxExecutable;
15
16
  exports.inspectCrewxShims = inspectCrewxShims;
16
17
  exports.checkCliProviders = checkCliProviders;
17
18
  exports.handleDoctor = handleDoctor;
18
- const node_crypto_1 = require("node:crypto");
19
19
  const node_child_process_1 = require("node:child_process");
20
20
  const node_fs_1 = require("node:fs");
21
21
  const node_os_1 = require("node:os");
@@ -255,17 +255,98 @@ function inspectHookCommands(projectRoot) {
255
255
  }
256
256
  return { inspectedFiles, issues };
257
257
  }
258
- function currentShimFingerprint() {
259
- const resolution = (0, sdk_1.resolveCrewxExecutable)();
260
- if (!resolution.ok)
261
- return undefined;
262
- return (0, node_crypto_1.createHash)('sha256')
263
- .update(JSON.stringify(resolution.argv))
264
- .digest('hex')
265
- .slice(0, 16);
258
+ function configuredBinResolution(configPath, fallback = 'global_first') {
259
+ try {
260
+ const config = (0, sdk_1.loadYamlFile)(configPath);
261
+ const value = config.settings?.bin_resolution;
262
+ return value === 'local_first' || value === 'global_first' ? value : fallback;
263
+ }
264
+ catch {
265
+ return fallback;
266
+ }
267
+ }
268
+ function readWindowsCrewxPathCandidates(cwd, env, platform) {
269
+ if (platform !== 'win32')
270
+ return [];
271
+ try {
272
+ (0, sdk_1.primeWindowsConsoleCodePage)();
273
+ const output = (0, node_child_process_1.execFileSync)('where.exe', ['crewx'], {
274
+ cwd,
275
+ env,
276
+ encoding: null,
277
+ stdio: ['ignore', 'pipe', 'ignore'],
278
+ });
279
+ return (0, sdk_1.decodeConsoleBuffer)(output, { platform })
280
+ .split(/\r?\n/)
281
+ .map((line) => line.trim())
282
+ .filter((line) => line.length > 0);
283
+ }
284
+ catch {
285
+ return [];
286
+ }
287
+ }
288
+ /** Inspect the SDK-selected CrewX executable without printing environment values. */
289
+ function inspectCrewxExecutable(options = {}) {
290
+ const platform = options.platform ?? process.platform;
291
+ const cwd = (0, node_path_1.resolve)(options.cwd ?? process.cwd());
292
+ const env = options.env ?? process.env;
293
+ const configPath = options.configPath ?? (0, node_path_1.join)(cwd, 'crewx.yaml');
294
+ const resolution = options.resolution ?? (0, sdk_1.resolveCrewxExecutable)({ env, cwd, platform });
295
+ const pathCandidates = options.pathCandidates
296
+ ? [...options.pathCandidates]
297
+ : readWindowsCrewxPathCandidates(cwd, env, platform);
298
+ const requiredEnvKeys = resolution.ok
299
+ ? Object.keys(resolution.requiredEnv ?? {})
300
+ .filter((key) => key === 'ELECTRON_RUN_AS_NODE')
301
+ : [];
302
+ return {
303
+ platform,
304
+ pathCandidates,
305
+ ...(resolution.ok
306
+ ? {
307
+ stage: resolution.stage,
308
+ argv: [...resolution.argv],
309
+ adoptedPath: resolution.argv[0],
310
+ }
311
+ : { resolutionError: resolution.reason }),
312
+ electron: requiredEnvKeys.includes('ELECTRON_RUN_AS_NODE'),
313
+ requiredEnvKeys,
314
+ binResolution: options.binResolution ?? configuredBinResolution(configPath),
315
+ };
316
+ }
317
+ function checkCrewxExecutable(report) {
318
+ const details = [
319
+ `platform: ${report.platform}`,
320
+ `stage: ${report.stage ?? '(unresolved)'}`,
321
+ `argv: ${report.argv ? (0, sdk_1.formatCrewxExecutableArgv)(report.argv) : '(unresolved)'}`,
322
+ `adopted path: ${report.adoptedPath ?? '(none)'}`,
323
+ `Electron runtime: ${report.electron ? 'yes' : 'no'}`,
324
+ `required environment keys: ${report.requiredEnvKeys.length > 0 ? report.requiredEnvKeys.join(', ') : '(none)'}`,
325
+ `bin_resolution setting: ${report.binResolution}`,
326
+ ...(report.platform === 'win32'
327
+ ? [`where.exe crewx candidates: ${report.pathCandidates.length > 0 ? report.pathCandidates.join(', ') : '(none)'}`]
328
+ : []),
329
+ ];
330
+ if (report.resolutionError) {
331
+ return {
332
+ name: 'CrewX Executable',
333
+ status: 'warning',
334
+ message: 'Could not resolve the CrewX executable',
335
+ details: `${details.join('\n')}\nResolution failed; no environment values were printed.`,
336
+ };
337
+ }
338
+ return {
339
+ name: 'CrewX Executable',
340
+ status: 'success',
341
+ message: 'SDK child executable contract is available',
342
+ details: details.join('\n'),
343
+ };
266
344
  }
267
345
  /** Inspect orphaned CrewX PATH shim directories without modifying them. */
268
- function inspectCrewxShims(crewxHome = (0, sdk_1.getCrewxHome)(), resolvedFingerprint = currentShimFingerprint()) {
346
+ function inspectCrewxShims(crewxHome = (0, sdk_1.getCrewxHome)(), resolvedFingerprint = (() => {
347
+ const resolution = (0, sdk_1.resolveCrewxExecutable)();
348
+ return resolution.ok ? (0, sdk_1.crewxCliShimFingerprint)(resolution) : undefined;
349
+ })()) {
269
350
  const shimRoot = (0, node_path_1.join)((0, node_path_1.resolve)(crewxHome), 'bin-shim');
270
351
  const staleDirectories = [];
271
352
  if (resolvedFingerprint) {
@@ -526,6 +607,7 @@ async function handleDoctor(args) {
526
607
  let shims = inspectCrewxShims();
527
608
  const projectRoot = (0, node_path_1.dirname)((0, node_path_1.resolve)(configPath));
528
609
  const hooks = inspectHookCommands(projectRoot);
610
+ const executable = inspectCrewxExecutable({ configPath, cwd: process.cwd() });
529
611
  if (cleanNpxCache) {
530
612
  cleanDoctorArtifacts(npxCache, shims);
531
613
  npxCache = inspectNpxCache();
@@ -535,6 +617,7 @@ async function handleDoctor(args) {
535
617
  checkConfig(configPath),
536
618
  checkLogsDir(),
537
619
  checkEnvVars(),
620
+ checkCrewxExecutable(executable),
538
621
  ...checkCliProviders(),
539
622
  checkNpxCache(npxCache),
540
623
  checkHookCommands(hooks),
@@ -32,9 +32,26 @@ function resolveCrewxBinary() {
32
32
  if (!resolution.ok) {
33
33
  throw new Error((0, sdk_1.formatCrewxExecutableFailure)(resolution));
34
34
  }
35
- const stableEntrypoint = (0, sdk_1.materializeCrewxStableEntrypoint)(resolution);
36
- const useStable = stableEntrypoint && resolution.argv.some(sdk_1.isRotatingInstallPath);
37
- return (0, sdk_1.formatCrewxExecutableArgv)(useStable ? [stableEntrypoint] : resolution.argv);
35
+ let stableEntrypoint;
36
+ try {
37
+ stableEntrypoint = (0, sdk_1.materializeCrewxStableEntrypoint)(resolution, { allowEnvStage: true });
38
+ }
39
+ catch (error) {
40
+ if (resolution.requiredEnv && Object.keys(resolution.requiredEnv).length > 0) {
41
+ throw new Error(`CrewX hook entrypoint could not preserve required environment: ${error instanceof Error ? error.message : String(error)}`);
42
+ }
43
+ throw error;
44
+ }
45
+ if (stableEntrypoint) {
46
+ return (0, sdk_1.formatCrewxExecutableArgv)([stableEntrypoint]);
47
+ }
48
+ // A required runtime environment cannot be represented by a raw argv string,
49
+ // and the fingerprint shim directory is doctor-GC managed. Refuse to write
50
+ // either representation when the stable hook path was not eligible.
51
+ if (resolution.requiredEnv && Object.keys(resolution.requiredEnv).length > 0) {
52
+ throw new Error('CrewX hook entrypoint could not preserve required environment: stable entrypoint is not eligible for this executable');
53
+ }
54
+ return (0, sdk_1.formatCrewxExecutableArgv)(resolution.argv);
38
55
  }
39
56
  function readSettingsTyped(settingsPath) {
40
57
  return (0, paths_1.readSettings)(settingsPath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crewx/cli",
3
- "version": "0.9.0-rc.111",
3
+ "version": "0.9.0-rc.112",
4
4
  "license": "UNLICENSED",
5
5
  "engines": {
6
6
  "node": ">=20.19.0"
@@ -25,19 +25,19 @@
25
25
  "better-sqlite3": "*",
26
26
  "dotenv": "17.2.3",
27
27
  "isomorphic-git": "1.37.1",
28
- "@crewx/knowledge-core": "0.1.17-rc.121",
29
- "@crewx/sdk": "0.9.0-rc.111",
30
- "@crewx/memory": "0.1.23-rc.128",
31
- "@crewx/doc": "0.1.9-rc.104",
32
- "@crewx/cron": "0.1.10-rc.146",
33
- "@crewx/search": "0.1.10-rc.107",
34
- "@crewx/skill": "0.1.20-rc.5",
35
- "@crewx/workflow": "0.3.22-rc.157",
36
- "@crewx/chromex": "0.1.0-rc.144",
37
- "@crewx/wbs": "0.1.10-rc.137",
38
- "@crewx/notify": "0.1.0-rc.82",
39
- "@crewx/shared": "0.0.6-rc.26",
40
- "@crewx/wi": "0.1.10-rc.131"
28
+ "@crewx/knowledge-core": "0.1.17-rc.122",
29
+ "@crewx/sdk": "0.9.0-rc.112",
30
+ "@crewx/memory": "0.1.23-rc.129",
31
+ "@crewx/cron": "0.1.10-rc.147",
32
+ "@crewx/search": "0.1.10-rc.108",
33
+ "@crewx/doc": "0.1.9-rc.105",
34
+ "@crewx/wbs": "0.1.10-rc.138",
35
+ "@crewx/workflow": "0.3.22-rc.158",
36
+ "@crewx/skill": "0.1.20-rc.6",
37
+ "@crewx/notify": "0.1.0-rc.83",
38
+ "@crewx/chromex": "0.1.0-rc.145",
39
+ "@crewx/shared": "0.0.6-rc.27",
40
+ "@crewx/wi": "0.1.10-rc.132"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/better-sqlite3": "*",