@openagents-org/agent-launcher 0.2.148 → 0.2.149

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/installer.js +51 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openagents-org/agent-launcher",
3
- "version": "0.2.148",
3
+ "version": "0.2.149",
4
4
  "description": "OpenAgents Launcher — install, configure, and run AI coding agents from your terminal",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/installer.js CHANGED
@@ -471,7 +471,7 @@ class Installer {
471
471
  // Prefer the resolved absolute binary path (quoted) over the bare name:
472
472
  // it's unambiguous and lets `--version` succeed for binaries resolved via
473
473
  // the package-bin fallback (which are not on PATH).
474
- const versionCmd = checkCmd || `"${binary}" --version`;
474
+ const versionCmd = checkCmd || this._versionProbeCommand(binary);
475
475
 
476
476
  const version = this._detectVersion(binary, versionCmd);
477
477
  const readiness = this._evaluateReadiness(agentType, entry, binary);
@@ -504,6 +504,56 @@ class Installer {
504
504
  };
505
505
  }
506
506
 
507
+ /**
508
+ * Build the `<binary> --version` probe command for a resolved binary path.
509
+ *
510
+ * When the resolved binary is a JS entry (`.mjs`/`.cjs`/`.js` — e.g. OpenClaw,
511
+ * whose package `bin` is `openclaw.mjs` and is what `_resolvePackageBin`
512
+ * returns when the `.cmd` shim isn't on PATH), it MUST be run through node.
513
+ * execSync goes through a shell; on Windows `cmd.exe "C:\…\openclaw.mjs"
514
+ * --version` finds no PATHEXT association for `.mjs`, so it ShellExecutes the
515
+ * file and the OS pops the "choose an app to open this .mjs file" dialog. The
516
+ * launcher polls health/version on a timer, so that dialog reappears over and
517
+ * over — even at idle, and stacked (one per poll). Prefixing node makes the
518
+ * probe run headless. Harmless on Unix (node runs a .mjs regardless of any
519
+ * shebang), so it's applied on every platform for consistency.
520
+ */
521
+ _versionProbeCommand(binary) {
522
+ if (/\.(mjs|cjs|js)$/i.test(binary)) {
523
+ return `"${this._nodeBinary()}" "${binary}" --version`;
524
+ }
525
+ return `"${binary}" --version`;
526
+ }
527
+
528
+ /**
529
+ * Resolve a node executable to run JS-entry CLIs with. Prefers the launcher's
530
+ * portable node, then a PATH lookup, then the bare name. Deliberately does NOT
531
+ * use process.execPath: when the core runs inside the Electron main process
532
+ * that path is the Electron binary, and `electron foo.mjs` would launch the
533
+ * app instead of running the script.
534
+ */
535
+ _nodeBinary() {
536
+ const isWin = process.platform === 'win32';
537
+ const nodeName = isWin ? 'node.exe' : 'node';
538
+ const portableDir = path.join(os.homedir(), '.openagents', 'nodejs');
539
+ for (const candidate of [
540
+ path.join(portableDir, nodeName),
541
+ path.join(portableDir, 'bin', nodeName),
542
+ ]) {
543
+ if (fs.existsSync(candidate)) return candidate;
544
+ }
545
+ try {
546
+ const found = execSync(isWin ? 'where node.exe' : 'which node', {
547
+ encoding: 'utf-8',
548
+ timeout: 5000,
549
+ stdio: ['pipe', 'pipe', 'pipe'],
550
+ env: getEnhancedEnv(),
551
+ }).split(/\r?\n/)[0].trim();
552
+ if (found) return found;
553
+ } catch {}
554
+ return 'node';
555
+ }
556
+
507
557
  /**
508
558
  * Detect a binary's version string, cached briefly. Returns null on failure.
509
559
  */