@nexus-cortex/cli 4.35.1 → 4.36.2
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/bin/cortex.js +33 -17
- package/package.json +1 -1
package/bin/cortex.js
CHANGED
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
import { spawn, spawnSync } from 'child_process';
|
|
26
26
|
import { fileURLToPath } from 'url';
|
|
27
27
|
import { dirname, join, resolve } from 'path';
|
|
28
|
-
import { existsSync, readFileSync, realpathSync } from 'fs';
|
|
28
|
+
import { existsSync, readFileSync, realpathSync, mkdirSync, openSync } from 'fs';
|
|
29
|
+
import { homedir } from 'os';
|
|
29
30
|
import { createRequire } from 'module';
|
|
30
31
|
|
|
31
32
|
const __cortex_require = createRequire(import.meta.url);
|
|
@@ -299,8 +300,30 @@ async function startServer() {
|
|
|
299
300
|
if (idleTimeoutFlag) {
|
|
300
301
|
serverArgs.push('--idle-timeout', idleTimeoutFlag);
|
|
301
302
|
}
|
|
303
|
+
// Send the detached server's stdout+stderr to a LOG FILE, not a pipe.
|
|
304
|
+
//
|
|
305
|
+
// Previously stdio was ['ignore','pipe','pipe']. The client read-ends of those
|
|
306
|
+
// pipes close when this short-lived one-shot client EXITS after its command —
|
|
307
|
+
// so the NEXT command makes the still-running detached server write to a broken
|
|
308
|
+
// pipe (EPIPE), which disrupts it and the client's fetch dies with a bare
|
|
309
|
+
// "fetch failed". `browse` writes the most server output (its sub-agent), so it
|
|
310
|
+
// was the reliable trigger; a quiet command like 2+2 often slipped through,
|
|
311
|
+
// which made the failure look intermittent.
|
|
312
|
+
//
|
|
313
|
+
// A file sink has no reader to disappear, so the server never hits EPIPE — and
|
|
314
|
+
// it gives users/containers a real server log to inspect. Readiness is detected
|
|
315
|
+
// via /health polling below, so we never needed to parse the server's stdout.
|
|
316
|
+
// 'w' truncates per fresh server spawn, bounding growth to one server lifetime.
|
|
317
|
+
const logPath = getServerLogPath();
|
|
318
|
+
let logFd;
|
|
319
|
+
try {
|
|
320
|
+
mkdirSync(dirname(logPath), { recursive: true });
|
|
321
|
+
logFd = openSync(logPath, 'w');
|
|
322
|
+
} catch {
|
|
323
|
+
logFd = 'ignore'; // last resort: never fall back to an undrained pipe
|
|
324
|
+
}
|
|
302
325
|
serverProcess = spawn('node', serverArgs, {
|
|
303
|
-
stdio: ['ignore',
|
|
326
|
+
stdio: ['ignore', logFd, logFd],
|
|
304
327
|
// Run the server in — and treat as project root — the directory cortex was invoked
|
|
305
328
|
// from, so `cd foo && cortex "..."` operates on `foo` (not the home dir or a stale
|
|
306
329
|
// PROJECT_PATH from the global ~/.cortex/.env). An explicitly-exported PROJECT_PATH /
|
|
@@ -316,32 +339,25 @@ async function startServer() {
|
|
|
316
339
|
});
|
|
317
340
|
serverProcess.unref();
|
|
318
341
|
|
|
319
|
-
serverProcess.stderr.on('data', (chunk) => {
|
|
320
|
-
const line = chunk.toString();
|
|
321
|
-
if (line.includes('[ERROR]') || line.includes('Failed to start')) {
|
|
322
|
-
process.stderr.write(line);
|
|
323
|
-
}
|
|
324
|
-
});
|
|
325
|
-
|
|
326
342
|
// Wait for healthy (up to 15s)
|
|
327
343
|
for (let i = 0; i < 30; i++) {
|
|
328
344
|
await new Promise(r => setTimeout(r, 500));
|
|
329
345
|
if (await isServerUp()) {
|
|
330
346
|
process.stderr.write(`[cortex] Server ready on ${BASE_URL}\n`);
|
|
331
|
-
// The server is detached + unref'd so it persists on its own. Its piped
|
|
332
|
-
// stdio handles, however, keep THIS short-lived client's event loop alive
|
|
333
|
-
// — so after a one-shot the client would hang until killed. Unref the
|
|
334
|
-
// pipes so the client can exit cleanly once its request completes while
|
|
335
|
-
// the background server keeps running.
|
|
336
|
-
serverProcess.stdout?.unref?.();
|
|
337
|
-
serverProcess.stderr?.unref?.();
|
|
338
347
|
return;
|
|
339
348
|
}
|
|
340
349
|
}
|
|
341
|
-
console.error(
|
|
350
|
+
console.error(`[cortex] Server failed to start within 15s (see ${logPath})`);
|
|
342
351
|
process.exit(1);
|
|
343
352
|
}
|
|
344
353
|
|
|
354
|
+
// Where the auto-started background server logs to. Honors CORTEX_HOME/HOME so
|
|
355
|
+
// it lands beside the rest of the global config (~/.cortex/server.log).
|
|
356
|
+
function getServerLogPath() {
|
|
357
|
+
const base = process.env.CORTEX_HOME || homedir() || process.cwd();
|
|
358
|
+
return join(base, '.cortex', 'server.log');
|
|
359
|
+
}
|
|
360
|
+
|
|
345
361
|
async function ensureServer() {
|
|
346
362
|
if (!(await isServerUp())) {
|
|
347
363
|
await startServer();
|