@openlife/cli 1.7.12 → 1.7.13

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.
@@ -288,7 +288,46 @@ class Brain {
288
288
  const commandArgs = process.platform === 'win32'
289
289
  ? args
290
290
  : ['-k', '2s', `${timeoutSeconds}s`, 'codex', ...args];
291
- const { stdout } = await execFile(command, commandArgs, { maxBuffer: 1024 * 1024 * 10, timeout: timeoutMs + 3000, killSignal: 'SIGKILL' });
291
+ // Codex CLI reads stdin when invoked without a TTY. The promisified
292
+ // execFile doesn't expose stdio, so it keeps the child's stdin
293
+ // attached to our (open) pipe — codex then waits forever for input
294
+ // and our outer timeout fires. Use spawn with `stdio: ['ignore', ...]`
295
+ // to close stdin explicitly. Fixes ~30s phantom timeouts when the
296
+ // daemon (non-TTY) calls codex.
297
+ const stdout = await new Promise((resolve, reject) => {
298
+ const child = child_process.spawn(command, commandArgs, {
299
+ stdio: ['ignore', 'pipe', 'pipe'],
300
+ });
301
+ let stdoutBuf = '';
302
+ let stderrBuf = '';
303
+ let killed = false;
304
+ const watchdog = setTimeout(() => {
305
+ killed = true;
306
+ try {
307
+ child.kill('SIGKILL');
308
+ }
309
+ catch { /* ignore */ }
310
+ }, timeoutMs + 3000);
311
+ child.stdout.on('data', (d) => { stdoutBuf += String(d); });
312
+ child.stderr.on('data', (d) => { stderrBuf += String(d); });
313
+ child.on('error', (err) => { clearTimeout(watchdog); reject(err); });
314
+ child.on('close', (code, signal) => {
315
+ clearTimeout(watchdog);
316
+ if (killed || code === 124 || (signal && killed)) {
317
+ const e = new Error('ETIMEDOUT');
318
+ e.code = 'ETIMEDOUT';
319
+ reject(e);
320
+ return;
321
+ }
322
+ if (code !== 0) {
323
+ const e = new Error(`codex exited with code ${code}: ${stderrBuf.slice(-300)}`);
324
+ e.code = String(code);
325
+ reject(e);
326
+ return;
327
+ }
328
+ resolve(stdoutBuf);
329
+ });
330
+ });
292
331
  const lastMessage = fs.existsSync(outputFile) ? fs.readFileSync(outputFile, 'utf-8').trim() : '';
293
332
  try {
294
333
  fs.unlinkSync(outputFile);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openlife/cli",
3
- "version": "1.7.12",
3
+ "version": "1.7.13",
4
4
  "description": "OPEN-LIFE Córtex Orquestrador Dual-Core",
5
5
  "main": "dist/index.js",
6
6
  "files": [