@openagents-org/agent-launcher 0.2.97 → 0.2.99

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openagents-org/agent-launcher",
3
- "version": "0.2.97",
3
+ "version": "0.2.99",
4
4
  "description": "OpenAgents Launcher — install, configure, and run AI coding agents from your terminal",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -33,9 +33,10 @@ class CodexAdapter extends BaseAdapter {
33
33
  this._codexThreadId = null;
34
34
 
35
35
  // Direct LLM API mode
36
- this._directApiKey = process.env.OPENAI_API_KEY || '';
37
- this._directBaseUrl = (process.env.OPENAI_BASE_URL || '').replace(/\/+$/, '');
38
- this._directModel = process.env.CODEX_MODEL || process.env.OPENCLAW_MODEL || '';
36
+ const env = this.agentEnv || process.env;
37
+ this._directApiKey = env.OPENAI_API_KEY || '';
38
+ this._directBaseUrl = (env.OPENAI_BASE_URL || '').replace(/\/+$/, '');
39
+ this._directModel = env.CODEX_MODEL || env.OPENCLAW_MODEL || '';
39
40
  this._directMode = !!(this._directApiKey && this._directBaseUrl);
40
41
 
41
42
  if (this._directMode) {
package/src/daemon.js CHANGED
@@ -25,6 +25,7 @@ class Daemon {
25
25
 
26
26
  // State
27
27
  this._processes = {}; // agentName → { proc, state, restarts, startedAt, lastError }
28
+ this._adapters = {}; // agentName → adapter instance
28
29
  this._stoppedAgents = new Set();
29
30
  this._shuttingDown = false;
30
31
  this._statusInterval = null;
@@ -273,6 +274,12 @@ class Daemon {
273
274
  const name = agentCfg.name;
274
275
  const type = agentCfg.type || 'openclaw';
275
276
 
277
+ // Prevent duplicate launches — if an adapter is already running, skip
278
+ if (this._adapters && this._adapters[name]) {
279
+ this._log(`${name} already running, skipping duplicate launch`);
280
+ return;
281
+ }
282
+
276
283
  this._stoppedAgents.delete(name);
277
284
 
278
285
  const info = {
@@ -418,8 +425,7 @@ class Daemon {
418
425
  return;
419
426
  }
420
427
 
421
- // Store adapter reference for stop
422
- this._adapters = this._adapters || {};
428
+ // Store adapter reference for stop and duplicate detection
423
429
  this._adapters[name] = adapter;
424
430
 
425
431
  info.state = 'running';
package/src/installer.js CHANGED
@@ -266,9 +266,11 @@ class Installer {
266
266
  const shell = process.platform === 'win32'
267
267
  ? (process.env.ComSpec || 'C:\\Windows\\System32\\cmd.exe')
268
268
  : true;
269
+ // Set cwd to runtime prefix dir (avoids running from System32 on Windows)
270
+ const installCwd = rawCmd.startsWith('npm install') ? getRuntimePrefix(agentType) : os.homedir();
269
271
 
270
272
  return new Promise((resolve, reject) => {
271
- const proc = spawn(cmd, [], { shell, env, stdio: ['ignore', 'pipe', 'pipe'] });
273
+ const proc = spawn(cmd, [], { shell, env, cwd: installCwd, stdio: ['ignore', 'pipe', 'pipe'] });
272
274
 
273
275
  if (proc.stdout) proc.stdout.setEncoding('utf-8');
274
276
  if (proc.stderr) proc.stderr.setEncoding('utf-8');
@@ -513,6 +515,10 @@ class Installer {
513
515
  try {
514
516
  const bundledDir = path.join(this.configDir, 'nodejs');
515
517
  if (fs.existsSync(bundledDir)) {
518
+ // Node.js may be directly in nodejs/ (launcher symlink style) or in nodejs/node-v*/
519
+ if (fs.existsSync(path.join(bundledDir, 'node.exe'))) {
520
+ extraDirs.push(bundledDir);
521
+ }
516
522
  const entries = fs.readdirSync(bundledDir).filter(e => e.startsWith('node-'));
517
523
  if (entries.length > 0) {
518
524
  extraDirs.push(path.join(bundledDir, entries[0]));