tycono 0.1.96-beta.50 → 0.1.96-beta.51
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/tycono.ts +48 -24
- package/package.json +1 -1
package/bin/tycono.ts
CHANGED
|
@@ -219,43 +219,67 @@ async function startServerForTui(): Promise<void> {
|
|
|
219
219
|
const logFd = fs.openSync(logFile, 'a');
|
|
220
220
|
const logStream = fs.createWriteStream(logFile, { fd: logFd });
|
|
221
221
|
const origStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
222
|
-
// Redirect ALL non-Ink output to log file.
|
|
223
|
-
// Ink uses stdout.write with ANSI sequences. Server uses console.log (which calls stdout.write).
|
|
224
|
-
// We must intercept stdout.write but ALWAYS pass through to real stdout,
|
|
225
|
-
// just also copy non-Ink output to log file.
|
|
226
|
-
// The key insight: DON'T BLOCK anything — just copy server output to log file.
|
|
227
|
-
// Ink can handle interleaved output by re-rendering.
|
|
228
|
-
console.log = (...args: unknown[]) => { logStream.write(args.join(' ') + '\n'); };
|
|
229
|
-
console.error = (...args: unknown[]) => { logStream.write(args.join(' ') + '\n'); };
|
|
230
|
-
console.warn = (...args: unknown[]) => { logStream.write(args.join(' ') + '\n'); };
|
|
231
|
-
// Also intercept direct stderr.write (used by our debug logging)
|
|
232
|
-
process.stderr.write = ((chunk: any, ...args: any[]) => {
|
|
233
|
-
logStream.write(typeof chunk === 'string' ? chunk : chunk.toString());
|
|
234
|
-
return true;
|
|
235
|
-
}) as any;
|
|
236
222
|
const origLog = (...args: unknown[]) => origStdoutWrite(args.join(' ') + '\n');
|
|
237
223
|
|
|
238
|
-
|
|
239
|
-
|
|
224
|
+
// Start API server as a CHILD PROCESS to isolate stdout completely
|
|
225
|
+
// This prevents server console.log from corrupting Ink's frame buffer
|
|
226
|
+
const { fork } = await import('node:child_process');
|
|
227
|
+
const serverScript = path.resolve(__dirname, '..', 'src', 'api', 'src', 'server.ts');
|
|
228
|
+
|
|
229
|
+
const child = fork(serverScript, [], {
|
|
230
|
+
execArgv: ['--import', 'tsx'],
|
|
231
|
+
env: {
|
|
232
|
+
...process.env,
|
|
233
|
+
PORT: String(port),
|
|
234
|
+
COMPANY_ROOT: process.env.COMPANY_ROOT,
|
|
235
|
+
},
|
|
236
|
+
stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
|
|
237
|
+
});
|
|
240
238
|
|
|
241
|
-
|
|
239
|
+
// Redirect child stdout/stderr to log file
|
|
240
|
+
child.stdout?.on('data', (data: Buffer) => { logStream.write(data); });
|
|
241
|
+
child.stderr?.on('data', (data: Buffer) => { logStream.write(data); });
|
|
242
|
+
|
|
243
|
+
// Wait for server to be ready (poll health endpoint)
|
|
244
|
+
const waitForServer = async () => {
|
|
245
|
+
const http = await import('node:http');
|
|
246
|
+
for (let i = 0; i < 30; i++) {
|
|
247
|
+
try {
|
|
248
|
+
await new Promise<void>((resolve, reject) => {
|
|
249
|
+
const req = http.get(`http://localhost:${port}/api/health`, (res) => {
|
|
250
|
+
res.resume();
|
|
251
|
+
resolve();
|
|
252
|
+
});
|
|
253
|
+
req.on('error', reject);
|
|
254
|
+
req.setTimeout(1000, () => { req.destroy(); reject(new Error('timeout')); });
|
|
255
|
+
});
|
|
256
|
+
return true;
|
|
257
|
+
} catch {
|
|
258
|
+
await new Promise(r => setTimeout(r, 500));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return false;
|
|
262
|
+
};
|
|
242
263
|
|
|
243
|
-
await
|
|
244
|
-
|
|
245
|
-
|
|
264
|
+
const serverReady = await waitForServer();
|
|
265
|
+
if (!serverReady) {
|
|
266
|
+
origLog(' Failed to start API server. Check logs:', logFile);
|
|
267
|
+
process.exit(1);
|
|
268
|
+
}
|
|
246
269
|
|
|
247
270
|
origLog(` API server started on port ${port}`);
|
|
248
271
|
origLog(` Logs: ${logFile}`);
|
|
249
272
|
|
|
250
|
-
// Graceful shutdown
|
|
273
|
+
// Graceful shutdown — kill child server
|
|
251
274
|
const shutdown = () => {
|
|
252
|
-
|
|
253
|
-
|
|
275
|
+
child.kill();
|
|
276
|
+
process.exit(0);
|
|
254
277
|
};
|
|
255
278
|
process.on('SIGINT', shutdown);
|
|
256
279
|
process.on('SIGTERM', shutdown);
|
|
280
|
+
child.on('exit', () => { process.exit(0); });
|
|
257
281
|
|
|
258
|
-
// Start TUI
|
|
282
|
+
// Start TUI — clean stdout, no server interference
|
|
259
283
|
const { startTui } = await import('../src/tui/index.tsx');
|
|
260
284
|
await startTui({ port });
|
|
261
285
|
}
|