@openagents-org/agent-connector 0.2.9 → 0.3.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/installer.js +61 -11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openagents-org/agent-connector",
3
- "version": "0.2.9",
3
+ "version": "0.3.0",
4
4
  "description": "Agent management CLI and library for OpenAgents — install, configure, and run AI coding agents",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/installer.js CHANGED
@@ -84,11 +84,17 @@ class Installer {
84
84
  throw new Error(`No install definition for agent type: ${agentType}`);
85
85
  }
86
86
 
87
- const cmd = this._getInstallCommand(entry.install);
87
+ let cmd = this._getInstallCommand(entry.install);
88
88
  if (!cmd) {
89
89
  throw new Error(`No install command for ${agentType} on ${Installer.platform()}`);
90
90
  }
91
91
 
92
+ // Use bundled node/npm if system npm not available
93
+ if (cmd.startsWith('npm install')) {
94
+ const args = cmd.replace('npm install', 'install');
95
+ cmd = this._resolveNpmCommand(args);
96
+ }
97
+
92
98
  const output = await this._execShell(cmd);
93
99
  this._markInstalled(agentType);
94
100
  return { success: true, output };
@@ -107,14 +113,18 @@ class Installer {
107
113
  throw new Error(`No install definition for agent type: ${agentType}`);
108
114
  }
109
115
 
110
- let cmd = this._getInstallCommand(entry.install);
111
- if (!cmd) {
116
+ let rawCmd = this._getInstallCommand(entry.install);
117
+ if (!rawCmd) {
112
118
  throw new Error(`No install command for ${agentType} on ${Installer.platform()}`);
113
119
  }
114
120
 
115
- // Add verbose logging for npm so user sees download progress on stderr
116
- if (cmd.includes('npm install') && !cmd.includes('--loglevel')) {
117
- cmd = cmd.replace('npm install', 'npm install --loglevel=verbose');
121
+ // Resolve npm to use bundled node if system npm is not available
122
+ let cmd = rawCmd;
123
+ if (rawCmd.startsWith('npm install')) {
124
+ const args = rawCmd.replace('npm install', 'install --loglevel=verbose');
125
+ cmd = this._resolveNpmCommand(args);
126
+ } else if (rawCmd.startsWith('pip install') || rawCmd.startsWith('pipx install')) {
127
+ cmd = rawCmd; // pip commands stay as-is
118
128
  }
119
129
 
120
130
  if (onData) onData(`$ ${cmd}\n\n`);
@@ -180,14 +190,16 @@ class Installer {
180
190
  }
181
191
 
182
192
  const installCmd = this._getInstallCommand(entry.install);
183
- let cmd = this._deriveUninstallCommand(installCmd);
184
- if (!cmd) {
193
+ let rawCmd = this._deriveUninstallCommand(installCmd);
194
+ if (!rawCmd) {
185
195
  throw new Error(`Cannot derive uninstall command for ${agentType}`);
186
196
  }
187
197
 
188
- // Add verbose logging for npm so user sees progress on stderr
189
- if (cmd.includes('npm uninstall') && !cmd.includes('--loglevel')) {
190
- cmd = cmd.replace('npm uninstall', 'npm uninstall --loglevel=verbose');
198
+ // Resolve npm to use bundled node if system npm is not available
199
+ let cmd = rawCmd;
200
+ if (rawCmd.startsWith('npm uninstall')) {
201
+ const args = rawCmd.replace('npm uninstall', 'uninstall --loglevel=verbose');
202
+ cmd = this._resolveNpmCommand(args);
191
203
  }
192
204
 
193
205
  if (onData) onData(`$ ${cmd}\n\n`);
@@ -353,6 +365,44 @@ class Installer {
353
365
  return env;
354
366
  }
355
367
 
368
+ /**
369
+ * Resolve the npm CLI path. Prefers system npm, falls back to Electron's
370
+ * bundled node + npm-cli.js so installs work on machines without Node.js.
371
+ */
372
+ _resolveNpmCommand(args) {
373
+ // 1. Try system npm
374
+ const { whichBinary } = require('./paths');
375
+ const systemNpm = whichBinary('npm');
376
+ if (systemNpm) return `npm ${args}`;
377
+
378
+ // 2. Use Electron's bundled node to run npm-cli.js
379
+ const nodeExe = process.execPath;
380
+ // Look for npm-cli.js relative to the node binary
381
+ const candidates = [
382
+ // Electron on Windows: resources/app/node_modules/npm/bin/npm-cli.js
383
+ path.join(path.dirname(nodeExe), 'resources', 'app', 'node_modules', 'npm', 'bin', 'npm-cli.js'),
384
+ // npm installed alongside node
385
+ path.join(path.dirname(nodeExe), '..', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'),
386
+ path.join(path.dirname(nodeExe), 'node_modules', 'npm', 'bin', 'npm-cli.js'),
387
+ ];
388
+ // Also check if npm is available as a module from the current process
389
+ try {
390
+ const npmCliPath = require.resolve('npm/bin/npm-cli.js');
391
+ if (npmCliPath) candidates.unshift(npmCliPath);
392
+ } catch {}
393
+
394
+ for (const p of candidates) {
395
+ try {
396
+ if (fs.existsSync(p)) {
397
+ return `"${nodeExe}" "${p}" ${args}`;
398
+ }
399
+ } catch {}
400
+ }
401
+
402
+ // 3. Last resort: just try npm and hope for the best
403
+ return `npm ${args}`;
404
+ }
405
+
356
406
  _execShell(cmd, timeoutMs = 300000) {
357
407
  return new Promise((resolve, reject) => {
358
408
  const env = this._buildShellEnv();