@openagents-org/agent-launcher 0.2.28 → 0.2.29

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.28",
3
+ "version": "0.2.29",
4
4
  "description": "OpenAgents Launcher — install, configure, and run AI coding agents from your terminal",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -180,6 +180,7 @@ class OpenClawAdapter extends BaseAdapter {
180
180
  const sessionKey = `openagents-${this.workspaceId.slice(0, 8)}-${channel.slice(-8)}`;
181
181
 
182
182
  const args = [
183
+ '--log-level', 'trace',
183
184
  'agent', '--local',
184
185
  '--agent', this.openclawAgentId,
185
186
  '--session-id', sessionKey,
@@ -230,73 +231,77 @@ class OpenClawAdapter extends BaseAdapter {
230
231
  }
231
232
  };
232
233
 
233
- // Try node-pty for line-buffered output (real-time tool streaming)
234
- let pty;
235
- try { pty = require('node-pty'); } catch {}
236
-
237
- if (pty) {
238
- // On Windows, .cmd files can't be spawned directly by pty — use cmd.exe
239
- const ptyBin = IS_WINDOWS ? (process.env.COMSPEC || 'cmd.exe') : binary;
240
- const ptyArgs = IS_WINDOWS ? ['/C', binary, ...args] : args;
241
- this._log('Spawn: node-pty (line-buffered)');
242
- const proc = pty.spawn(ptyBin, ptyArgs, {
243
- name: 'xterm',
244
- cols: 200,
245
- rows: 50,
246
- cwd: process.cwd(),
247
- env: spawnEnv,
248
- });
249
-
250
- proc.onData((data) => {
251
- output += data;
252
- lineBuffer += data;
253
- const lines = lineBuffer.split('\n');
254
- lineBuffer = lines.pop() || '';
255
- for (const line of lines) processLine(line);
256
- });
257
-
258
- const timeout = setTimeout(() => {
259
- proc.kill();
260
- reject(new Error('CLI timed out after 600 seconds'));
261
- }, 600000);
262
-
263
- proc.onExit(({ exitCode }) => {
264
- clearTimeout(timeout);
265
- // Process remaining buffer
266
- if (lineBuffer) processLine(lineBuffer);
267
-
268
- if (exitCode !== 0) {
269
- reject(new Error(`CLI exited ${exitCode}: ${output.slice(-300)}`));
270
- return;
234
+ // Redirect stderr to temp file for real-time tool status polling.
235
+ // --log-level trace makes OpenClaw write diagnostic events to stderr
236
+ // even in non-TTY mode. We poll the temp file for new lines every 500ms.
237
+ const stderrFile = path.join(os.tmpdir(), `openclaw-stderr-${Date.now()}.log`);
238
+ const stderrFd = fs.openSync(stderrFile, 'w');
239
+ this._log('Spawn: stderr ' + stderrFile);
240
+
241
+ let spawnBin = binary;
242
+ let spawnArgs = args;
243
+ if (IS_WINDOWS) {
244
+ spawnBin = process.env.COMSPEC || 'cmd.exe';
245
+ spawnArgs = ['/C', binary, ...args.map(a => a.includes(' ') ? `"${a}"` : a)];
246
+ }
247
+ const proc = spawn(spawnBin, spawnArgs, {
248
+ stdio: ['ignore', 'pipe', stderrFd],
249
+ env: spawnEnv,
250
+ timeout: 600000,
251
+ windowsHide: true,
252
+ });
253
+ if (proc.stdout) proc.stdout.on('data', (d) => { output += d; });
254
+
255
+ // Poll stderr file every 500ms for tool events
256
+ let stderrOffset = 0;
257
+ const pollInterval = setInterval(() => {
258
+ try {
259
+ const stat = fs.statSync(stderrFile);
260
+ if (stat.size > stderrOffset) {
261
+ const fd = fs.openSync(stderrFile, 'r');
262
+ const buf = Buffer.alloc(stat.size - stderrOffset);
263
+ fs.readSync(fd, buf, 0, buf.length, stderrOffset);
264
+ fs.closeSync(fd);
265
+ stderrOffset = stat.size;
266
+ const chunk = buf.toString('utf-8');
267
+ const lines = chunk.split('\n');
268
+ for (const line of lines) processLine(line);
271
269
  }
272
- this._parseCliOutput(output, resolve);
273
- });
274
- } else {
275
- // Fallback: regular spawn (buffered on Windows)
276
- this._log('Spawn: fallback (no node-pty)');
277
- let spawnBin = binary;
278
- let spawnArgs = args;
279
- if (IS_WINDOWS) {
280
- spawnBin = process.env.COMSPEC || 'cmd.exe';
281
- spawnArgs = ['/C', binary, ...args.map(a => a.includes(' ') ? `"${a}"` : a)];
282
- }
283
- const proc = spawn(spawnBin, spawnArgs, {
284
- stdio: ['ignore', 'pipe', 'pipe'],
285
- env: spawnEnv,
286
- timeout: 600000,
287
- windowsHide: true,
288
- });
289
- if (proc.stdout) proc.stdout.on('data', (d) => { output += d; });
290
- if (proc.stderr) proc.stderr.on('data', (d) => { output += d; });
291
- proc.on('error', (err) => reject(err));
292
- proc.on('exit', (code) => {
293
- if (code !== 0) {
294
- reject(new Error(`CLI exited ${code}: ${output.slice(-300)}`));
295
- return;
270
+ } catch {}
271
+ }, 500);
272
+
273
+ const killTimeout = setTimeout(() => {
274
+ proc.kill();
275
+ reject(new Error('CLI timed out after 600 seconds'));
276
+ }, 600000);
277
+
278
+ proc.on('error', (err) => {
279
+ clearInterval(pollInterval);
280
+ clearTimeout(killTimeout);
281
+ fs.closeSync(stderrFd);
282
+ try { fs.unlinkSync(stderrFile); } catch {}
283
+ reject(err);
284
+ });
285
+ proc.on('exit', (code) => {
286
+ clearInterval(pollInterval);
287
+ clearTimeout(killTimeout);
288
+ fs.closeSync(stderrFd);
289
+ // Read any remaining stderr
290
+ try {
291
+ const remaining = fs.readFileSync(stderrFile, 'utf-8').slice(stderrOffset);
292
+ if (remaining) {
293
+ output += remaining;
294
+ for (const line of remaining.split('\n')) processLine(line);
296
295
  }
297
- this._parseCliOutput(output, resolve);
298
- });
299
- }
296
+ } catch {}
297
+ try { fs.unlinkSync(stderrFile); } catch {}
298
+
299
+ if (code !== 0) {
300
+ reject(new Error(`CLI exited ${code}: ${output.slice(-300)}`));
301
+ return;
302
+ }
303
+ this._parseCliOutput(output, resolve);
304
+ });
300
305
  });
301
306
  }
302
307