imtoagent 0.3.5 → 0.3.6
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/imtoagent-real +138 -94
- package/bin/imtoagent.cjs +12 -4
- package/modules/agent/codex-adapter.ts +1 -1
- package/package.json +1 -1
package/bin/imtoagent-real
CHANGED
|
@@ -5,14 +5,16 @@
|
|
|
5
5
|
// Available after npm install -g imtoagent:
|
|
6
6
|
// imtoagent setup — interactive setup wizard
|
|
7
7
|
// imtoagent start — start gateway in background
|
|
8
|
+
// imtoagent run — start gateway in foreground
|
|
8
9
|
// imtoagent stop — stop gateway
|
|
9
10
|
// imtoagent status — check running status
|
|
10
11
|
// imtoagent restore — hot reload
|
|
11
|
-
// imtoagent daemon — foreground daemon (auto-restart
|
|
12
|
+
// imtoagent daemon — foreground daemon (auto-restart, for launchd/systemd)
|
|
12
13
|
// ================================================================
|
|
13
14
|
|
|
14
15
|
import * as fs from 'fs';
|
|
15
16
|
import * as path from 'path';
|
|
17
|
+
import { spawn, execSync } from 'child_process';
|
|
16
18
|
import { getDataDir } from '../modules/utils/paths';
|
|
17
19
|
|
|
18
20
|
const PID_FILE = '/tmp/imtoagent.pid';
|
|
@@ -29,6 +31,9 @@ switch (command) {
|
|
|
29
31
|
case 'start':
|
|
30
32
|
await cmdStart();
|
|
31
33
|
break;
|
|
34
|
+
case 'run':
|
|
35
|
+
await cmdRun();
|
|
36
|
+
break;
|
|
32
37
|
case 'stop':
|
|
33
38
|
await cmdStop();
|
|
34
39
|
break;
|
|
@@ -42,14 +47,12 @@ switch (command) {
|
|
|
42
47
|
await cmdDaemon();
|
|
43
48
|
break;
|
|
44
49
|
case undefined: {
|
|
45
|
-
// No command → auto-enter setup if not configured, show help otherwise
|
|
46
50
|
const dataDir = getDataDir();
|
|
47
51
|
const configPath = path.join(dataDir, 'config.json');
|
|
48
52
|
let needsSetup = !fs.existsSync(configPath);
|
|
49
53
|
if (!needsSetup) {
|
|
50
54
|
try {
|
|
51
55
|
const raw = fs.readFileSync(configPath, 'utf-8');
|
|
52
|
-
// If config still has YOUR_ placeholders, setup is incomplete
|
|
53
56
|
needsSetup = /YOUR_[A-Z_]+/.test(raw);
|
|
54
57
|
} catch { needsSetup = true; }
|
|
55
58
|
}
|
|
@@ -81,11 +84,12 @@ imtoagent — IM ↔ Agent Unified Gateway
|
|
|
81
84
|
|
|
82
85
|
Usage:
|
|
83
86
|
imtoagent setup Interactive setup wizard
|
|
84
|
-
imtoagent start Start gateway in background
|
|
87
|
+
imtoagent start Start gateway in background (returns immediately)
|
|
88
|
+
imtoagent run Start gateway in foreground (Ctrl+C to stop)
|
|
85
89
|
imtoagent stop Stop gateway
|
|
86
90
|
imtoagent status Check running status
|
|
87
91
|
imtoagent restore Hot reload
|
|
88
|
-
imtoagent daemon Foreground daemon
|
|
92
|
+
imtoagent daemon Foreground daemon with auto-restart (for launchd/systemd)
|
|
89
93
|
|
|
90
94
|
Data directory: ${getDataDir()}
|
|
91
95
|
`);
|
|
@@ -100,7 +104,22 @@ async function cmdSetup() {
|
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
// ================================================================
|
|
103
|
-
//
|
|
107
|
+
// Shared: build gateway launch args
|
|
108
|
+
// ================================================================
|
|
109
|
+
function getGatewayArgs() {
|
|
110
|
+
const pkgDir = path.resolve(import.meta.dirname, '..');
|
|
111
|
+
const indexFile = path.join(pkgDir, 'index.ts');
|
|
112
|
+
return { execPath: process.execPath, args: ['run', indexFile] };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function ensureLogDir(dataDir: string) {
|
|
116
|
+
const logsDir = path.join(dataDir, 'logs');
|
|
117
|
+
if (!fs.existsSync(logsDir)) fs.mkdirSync(logsDir, { recursive: true });
|
|
118
|
+
return path.join(logsDir, 'imtoagent.log');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ================================================================
|
|
122
|
+
// start — background mode (spawn detached, log to file, return immediately)
|
|
104
123
|
// ================================================================
|
|
105
124
|
async function cmdStart() {
|
|
106
125
|
// Check if already running
|
|
@@ -112,12 +131,10 @@ async function cmdStart() {
|
|
|
112
131
|
console.error(` Run "imtoagent stop" to stop first`);
|
|
113
132
|
process.exit(1);
|
|
114
133
|
} catch {
|
|
115
|
-
// Stale PID file, clean up
|
|
116
134
|
fs.unlinkSync(PID_FILE);
|
|
117
135
|
}
|
|
118
136
|
}
|
|
119
137
|
|
|
120
|
-
// Check if config exists
|
|
121
138
|
const dataDir = getDataDir();
|
|
122
139
|
const configPath = path.join(dataDir, 'config.json');
|
|
123
140
|
if (!fs.existsSync(configPath)) {
|
|
@@ -125,7 +142,7 @@ async function cmdStart() {
|
|
|
125
142
|
process.exit(1);
|
|
126
143
|
}
|
|
127
144
|
|
|
128
|
-
//
|
|
145
|
+
// Backend check (non-blocking)
|
|
129
146
|
try {
|
|
130
147
|
const { checkBackend } = await import('../modules/utils/backend-check');
|
|
131
148
|
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
@@ -140,25 +157,89 @@ async function cmdStart() {
|
|
|
140
157
|
}
|
|
141
158
|
if (missingBackends.length > 0) {
|
|
142
159
|
console.error(`\n⚠️ The following backends are configured but not installed, messages will fail after gateway starts:`);
|
|
143
|
-
for (const b of missingBackends) {
|
|
144
|
-
console.error(` ❌ ${b}`);
|
|
145
|
-
}
|
|
160
|
+
for (const b of missingBackends) console.error(` ❌ ${b}`);
|
|
146
161
|
console.error(`\nPlease install the missing backends, or run "imtoagent setup" to reconfigure.\n`);
|
|
147
|
-
// Don't force exit, let user start gateway and install backends later
|
|
148
162
|
}
|
|
149
163
|
} catch {
|
|
150
164
|
// Check failure doesn't block startup
|
|
151
165
|
}
|
|
152
166
|
|
|
153
|
-
|
|
167
|
+
const logFile = ensureLogDir(dataDir);
|
|
168
|
+
|
|
169
|
+
console.log('🚀 Starting imtoagent gateway (background)...');
|
|
154
170
|
console.log(` Data directory: ${dataDir}`);
|
|
155
|
-
console.log(`
|
|
171
|
+
console.log(` Log file: ${logFile}`);
|
|
156
172
|
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
|
|
173
|
+
const { execPath, args } = getGatewayArgs();
|
|
174
|
+
const cmdLine = `"${execPath}" run "${path.resolve(import.meta.dirname, '..', 'index.ts')}"`;
|
|
175
|
+
|
|
176
|
+
// Use a shell to launch the gateway in background — avoids event-loop blockers
|
|
177
|
+
const shellCmd = `IMTOAGENT_HOME="${dataDir}" ${cmdLine} >> "${logFile}" 2>&1 &
|
|
178
|
+
PID=$!
|
|
179
|
+
echo $PID`;
|
|
160
180
|
|
|
161
|
-
const
|
|
181
|
+
const { execSync } = await import('child_process');
|
|
182
|
+
const pidStr = execSync(shellCmd, {
|
|
183
|
+
cwd: dataDir,
|
|
184
|
+
env: { ...process.env, IMTOAGENT_HOME: dataDir },
|
|
185
|
+
encoding: 'utf-8',
|
|
186
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
187
|
+
}).trim();
|
|
188
|
+
const gatewayPid = parseInt(pidStr.split('\n').pop()!);
|
|
189
|
+
|
|
190
|
+
fs.writeFileSync(PID_FILE, String(gatewayPid));
|
|
191
|
+
console.log(`✅ Gateway started (PID=${gatewayPid})`);
|
|
192
|
+
|
|
193
|
+
// Wait for startup verification
|
|
194
|
+
await new Promise(r => setTimeout(r, 3000));
|
|
195
|
+
try {
|
|
196
|
+
process.kill(gatewayPid, 0);
|
|
197
|
+
console.log('✅ Gateway is running');
|
|
198
|
+
} catch {
|
|
199
|
+
console.error('❌ Gateway failed to start, check logs:');
|
|
200
|
+
if (fs.existsSync(logFile)) {
|
|
201
|
+
console.log(fs.readFileSync(logFile, 'utf-8').slice(-2000));
|
|
202
|
+
}
|
|
203
|
+
fs.unlinkSync(PID_FILE);
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Explicitly exit — Bun may keep event loop alive due to inherited stdio
|
|
208
|
+
process.exit(0);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// ================================================================
|
|
212
|
+
// run — foreground mode (real-time logs, Ctrl+C to stop)
|
|
213
|
+
// ================================================================
|
|
214
|
+
async function cmdRun() {
|
|
215
|
+
const dataDir = getDataDir();
|
|
216
|
+
const configPath = path.join(dataDir, 'config.json');
|
|
217
|
+
if (!fs.existsSync(configPath)) {
|
|
218
|
+
console.error('❌ No config file found. Please run "imtoagent setup" first');
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const logFile = ensureLogDir(dataDir);
|
|
223
|
+
|
|
224
|
+
// Warn if already running in background
|
|
225
|
+
if (fs.existsSync(PID_FILE)) {
|
|
226
|
+
const pid = parseInt(fs.readFileSync(PID_FILE, 'utf-8').trim());
|
|
227
|
+
try {
|
|
228
|
+
process.kill(pid, 0);
|
|
229
|
+
console.log(`⚠️ Gateway is already running in background (PID=${pid})`);
|
|
230
|
+
console.log(` Run "imtoagent stop" first, or this may conflict.\n`);
|
|
231
|
+
} catch {
|
|
232
|
+
fs.unlinkSync(PID_FILE);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const { execPath, args } = getGatewayArgs();
|
|
237
|
+
|
|
238
|
+
console.log('🚀 Starting imtoagent gateway (foreground mode)...');
|
|
239
|
+
console.log(' Press Ctrl+C to stop');
|
|
240
|
+
console.log('');
|
|
241
|
+
|
|
242
|
+
const child = Bun.spawn([execPath, ...args], {
|
|
162
243
|
cwd: dataDir,
|
|
163
244
|
env: { ...process.env, IMTOAGENT_HOME: dataDir },
|
|
164
245
|
stdout: 'pipe',
|
|
@@ -166,16 +247,10 @@ async function cmdStart() {
|
|
|
166
247
|
});
|
|
167
248
|
|
|
168
249
|
fs.writeFileSync(PID_FILE, String(child.pid));
|
|
169
|
-
console.log(`✅ Gateway started (PID=${child.pid})`);
|
|
170
250
|
|
|
171
|
-
|
|
172
|
-
const logsDir = path.join(dataDir, 'logs');
|
|
173
|
-
if (!fs.existsSync(logsDir)) fs.mkdirSync(logsDir, { recursive: true });
|
|
174
|
-
const logFile = path.join(logsDir, 'imtoagent.log');
|
|
251
|
+
const logStream = fs.createWriteStream(logFile, { flags: 'a' });
|
|
175
252
|
|
|
176
|
-
|
|
177
|
-
(async () => {
|
|
178
|
-
const logStream = fs.createWriteStream(logFile, { flags: 'a' });
|
|
253
|
+
const pumpOut = (async () => {
|
|
179
254
|
for await (const chunk of child.stdout as any) {
|
|
180
255
|
const line = new TextDecoder().decode(chunk);
|
|
181
256
|
process.stdout.write(line);
|
|
@@ -183,8 +258,7 @@ async function cmdStart() {
|
|
|
183
258
|
}
|
|
184
259
|
})().catch(() => {});
|
|
185
260
|
|
|
186
|
-
(async () => {
|
|
187
|
-
const logStream = fs.createWriteStream(logFile, { flags: 'a' });
|
|
261
|
+
const pumpErr = (async () => {
|
|
188
262
|
for await (const chunk of child.stderr as any) {
|
|
189
263
|
const line = new TextDecoder().decode(chunk);
|
|
190
264
|
process.stderr.write(line);
|
|
@@ -192,18 +266,24 @@ async function cmdStart() {
|
|
|
192
266
|
}
|
|
193
267
|
})().catch(() => {});
|
|
194
268
|
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
process.kill(child.pid,
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
269
|
+
// Ctrl+C → SIGTERM to child
|
|
270
|
+
const cleanup = () => {
|
|
271
|
+
console.log('\n🛑 Stopping gateway...');
|
|
272
|
+
try { process.kill(child.pid, 'SIGTERM'); } catch {}
|
|
273
|
+
};
|
|
274
|
+
process.on('SIGINT', cleanup);
|
|
275
|
+
process.on('SIGTERM', cleanup);
|
|
276
|
+
|
|
277
|
+
const exitCode = await child.exited;
|
|
278
|
+
await Promise.allSettled([pumpOut, pumpErr]);
|
|
279
|
+
logStream.end();
|
|
280
|
+
|
|
281
|
+
try { fs.unlinkSync(PID_FILE); } catch {}
|
|
282
|
+
|
|
283
|
+
if (exitCode === 0) {
|
|
284
|
+
console.log('✅ Gateway exited cleanly');
|
|
285
|
+
} else {
|
|
286
|
+
console.log(`⚠️ Gateway exited with code ${exitCode}`);
|
|
207
287
|
}
|
|
208
288
|
}
|
|
209
289
|
|
|
@@ -222,7 +302,6 @@ async function cmdStop() {
|
|
|
222
302
|
console.log(`⏹ Stopping gateway (PID=${pid})...`);
|
|
223
303
|
process.kill(pid, 'SIGTERM');
|
|
224
304
|
|
|
225
|
-
// Wait for process to exit
|
|
226
305
|
for (let i = 0; i < 20; i++) {
|
|
227
306
|
try {
|
|
228
307
|
process.kill(pid, 0);
|
|
@@ -232,7 +311,6 @@ async function cmdStop() {
|
|
|
232
311
|
}
|
|
233
312
|
}
|
|
234
313
|
|
|
235
|
-
// Check if still running
|
|
236
314
|
try {
|
|
237
315
|
process.kill(pid, 0);
|
|
238
316
|
console.log('⚠️ Process not responding, force killing...');
|
|
@@ -256,7 +334,6 @@ async function cmdStatus() {
|
|
|
256
334
|
console.log(`\n📊 imtoagent Status`);
|
|
257
335
|
console.log(` Data directory: ${dataDir}`);
|
|
258
336
|
|
|
259
|
-
// Process status
|
|
260
337
|
if (fs.existsSync(PID_FILE)) {
|
|
261
338
|
const pid = parseInt(fs.readFileSync(PID_FILE, 'utf-8').trim());
|
|
262
339
|
try {
|
|
@@ -269,7 +346,6 @@ async function cmdStatus() {
|
|
|
269
346
|
console.log(` Process: ⏸ Not running`);
|
|
270
347
|
}
|
|
271
348
|
|
|
272
|
-
// Config file
|
|
273
349
|
const configPath = path.join(dataDir, 'config.json');
|
|
274
350
|
if (fs.existsSync(configPath)) {
|
|
275
351
|
try {
|
|
@@ -286,7 +362,6 @@ async function cmdStatus() {
|
|
|
286
362
|
console.log(` Config: ❌ Not found (run "imtoagent setup")`);
|
|
287
363
|
}
|
|
288
364
|
|
|
289
|
-
// Log file
|
|
290
365
|
const logFile = path.join(dataDir, 'logs', 'imtoagent.log');
|
|
291
366
|
if (fs.existsSync(logFile)) {
|
|
292
367
|
const stats = fs.statSync(logFile);
|
|
@@ -320,13 +395,7 @@ async function cmdRestore() {
|
|
|
320
395
|
}
|
|
321
396
|
|
|
322
397
|
// ================================================================
|
|
323
|
-
// daemon — foreground daemon
|
|
324
|
-
// ================================================================
|
|
325
|
-
// Design:
|
|
326
|
-
// - Runs in foreground, managed by launchd / systemd etc.
|
|
327
|
-
// - Auto-restarts on crash (exponential backoff, max 30s)
|
|
328
|
-
// - Graceful shutdown on SIGTERM/SIGINT, no restart
|
|
329
|
-
// - Logs written to ~/.imtoagent/logs/imtoagent.log
|
|
398
|
+
// daemon — foreground daemon with auto-restart (for launchd/systemd)
|
|
330
399
|
// ================================================================
|
|
331
400
|
async function cmdDaemon(): Promise<void> {
|
|
332
401
|
const dataDir = getDataDir();
|
|
@@ -337,21 +406,15 @@ async function cmdDaemon(): Promise<void> {
|
|
|
337
406
|
process.exit(1);
|
|
338
407
|
}
|
|
339
408
|
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
const logFile = path.join(logsDir, 'imtoagent.log');
|
|
343
|
-
|
|
344
|
-
const pkgDir = path.resolve(import.meta.dirname, '..');
|
|
345
|
-
const indexFile = path.join(pkgDir, 'index.ts');
|
|
409
|
+
const logFile = ensureLogDir(dataDir);
|
|
410
|
+
const { execPath, args } = getGatewayArgs();
|
|
346
411
|
|
|
347
412
|
console.log(`🛡 imtoagent Daemon Mode`);
|
|
348
413
|
console.log(` Data directory: ${dataDir}`);
|
|
349
414
|
console.log(` Log file: ${logFile}`);
|
|
350
415
|
console.log(` Press Ctrl+C to stop\n`);
|
|
351
416
|
|
|
352
|
-
// Graceful shutdown flag
|
|
353
417
|
let shuttingDown = false;
|
|
354
|
-
|
|
355
418
|
const shutdown = () => {
|
|
356
419
|
if (shuttingDown) return;
|
|
357
420
|
shuttingDown = true;
|
|
@@ -362,15 +425,13 @@ async function cmdDaemon(): Promise<void> {
|
|
|
362
425
|
process.on('SIGINT', shutdown);
|
|
363
426
|
|
|
364
427
|
let retryDelay = 0;
|
|
365
|
-
const MAX_RETRY_DELAY = 30_000;
|
|
428
|
+
const MAX_RETRY_DELAY = 30_000;
|
|
366
429
|
|
|
367
430
|
while (!shuttingDown) {
|
|
368
|
-
// No delay on first run, exponential backoff after
|
|
369
431
|
if (retryDelay > 0) {
|
|
370
432
|
console.log(` Waiting ${retryDelay / 1000}s before restart...`);
|
|
371
433
|
await new Promise<void>(resolve => {
|
|
372
434
|
const timer = setTimeout(resolve, retryDelay);
|
|
373
|
-
// Exit immediately if shutdown signal received during wait
|
|
374
435
|
const check = setInterval(() => {
|
|
375
436
|
if (shuttingDown) {
|
|
376
437
|
clearTimeout(timer);
|
|
@@ -382,56 +443,39 @@ async function cmdDaemon(): Promise<void> {
|
|
|
382
443
|
if (shuttingDown) break;
|
|
383
444
|
}
|
|
384
445
|
|
|
385
|
-
|
|
446
|
+
// Open log fd for child stdout/stderr
|
|
447
|
+
const logFd = fs.openSync(logFile, 'a');
|
|
386
448
|
|
|
387
|
-
const child =
|
|
449
|
+
const child = spawn(execPath, args, {
|
|
388
450
|
cwd: dataDir,
|
|
389
451
|
env: { ...process.env, IMTOAGENT_HOME: dataDir },
|
|
390
|
-
|
|
391
|
-
|
|
452
|
+
detached: true,
|
|
453
|
+
stdio: ['ignore', logFd, logFd],
|
|
392
454
|
});
|
|
393
455
|
|
|
394
456
|
const childPid = child.pid;
|
|
395
457
|
fs.writeFileSync(PID_FILE, String(childPid));
|
|
396
458
|
console.log(`[${new Date().toISOString()}] 🚀 Starting gateway (PID=${childPid})`);
|
|
397
459
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
logStream.write(line);
|
|
404
|
-
}
|
|
405
|
-
})().catch(() => {});
|
|
406
|
-
|
|
407
|
-
const pumpStderr = (async () => {
|
|
408
|
-
for await (const chunk of child.stderr as any) {
|
|
409
|
-
const line = new TextDecoder().decode(chunk);
|
|
410
|
-
process.stderr.write(line);
|
|
411
|
-
logStream.write(line);
|
|
412
|
-
}
|
|
413
|
-
})().catch(() => {});
|
|
414
|
-
|
|
415
|
-
// Wait for child process to exit
|
|
416
|
-
const exitCode = await child.exited;
|
|
417
|
-
await Promise.allSettled([pumpStdout, pumpStderr]);
|
|
418
|
-
logStream.end();
|
|
460
|
+
let childExitCode: number | null = null;
|
|
461
|
+
await new Promise<void>(resolve => {
|
|
462
|
+
child.on('exit', (code) => { childExitCode = code; resolve(); });
|
|
463
|
+
child.on('error', () => resolve());
|
|
464
|
+
});
|
|
419
465
|
|
|
466
|
+
fs.closeSync(logFd);
|
|
420
467
|
try { fs.unlinkSync(PID_FILE); } catch {}
|
|
421
468
|
|
|
422
469
|
if (shuttingDown) break;
|
|
423
470
|
|
|
424
|
-
|
|
425
|
-
if (exitCode === 0) {
|
|
471
|
+
if (childExitCode === 0) {
|
|
426
472
|
console.log(`[${new Date().toISOString()}] ⏹ Gateway exited cleanly (code=0), not restarting`);
|
|
427
473
|
break;
|
|
428
474
|
}
|
|
429
475
|
|
|
430
|
-
// Crash → exponential backoff restart
|
|
431
476
|
retryDelay = retryDelay === 0 ? 3_000 : Math.min(retryDelay * 2, MAX_RETRY_DELAY);
|
|
432
|
-
console.log(`[${new Date().toISOString()}] ⚠️ Gateway crashed (code=${
|
|
477
|
+
console.log(`[${new Date().toISOString()}] ⚠️ Gateway crashed (code=${childExitCode}), restarting in ${retryDelay / 1000}s`);
|
|
433
478
|
}
|
|
434
479
|
|
|
435
480
|
console.log('👋 Daemon stopped');
|
|
436
481
|
}
|
|
437
|
-
|
package/bin/imtoagent.cjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"use strict";
|
|
4
4
|
var path = require("path");
|
|
5
5
|
var fs = require("fs");
|
|
6
|
-
var
|
|
6
|
+
var spawn = require("child_process").spawn;
|
|
7
7
|
|
|
8
8
|
var candidates = [
|
|
9
9
|
process.env.BUN_BIN,
|
|
@@ -12,7 +12,7 @@ var candidates = [
|
|
|
12
12
|
"/opt/homebrew/bin/bun",
|
|
13
13
|
];
|
|
14
14
|
try {
|
|
15
|
-
var r = spawnSync("which", ["bun"]);
|
|
15
|
+
var r = require("child_process").spawnSync("which", ["bun"]);
|
|
16
16
|
if (r.status === 0) candidates.unshift(r.stdout.toString().trim());
|
|
17
17
|
} catch (e) {}
|
|
18
18
|
|
|
@@ -32,8 +32,16 @@ if (!bunPath) {
|
|
|
32
32
|
|
|
33
33
|
var pkgDir = path.resolve(__dirname, "..");
|
|
34
34
|
var real = path.join(pkgDir, "bin", "imtoagent-real");
|
|
35
|
-
var
|
|
35
|
+
var child = spawn(bunPath, [real].concat(process.argv.slice(2)), {
|
|
36
36
|
stdio: "inherit",
|
|
37
37
|
env: Object.assign({}, process.env),
|
|
38
38
|
});
|
|
39
|
-
|
|
39
|
+
|
|
40
|
+
child.on("exit", function (code) {
|
|
41
|
+
process.exit(code || 0);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
child.on("error", function (err) {
|
|
45
|
+
console.error("❌ Failed to start imtoagent:", err.message);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
});
|
|
@@ -88,7 +88,7 @@ async function spawnCodexResume(cwd: string, threadId: string, prompt: string):
|
|
|
88
88
|
try {
|
|
89
89
|
[stdout, stderr] = await Promise.all([
|
|
90
90
|
new Response(child.stdout).text().catch((e: any) => { throw new Error(`stdout read failed: ${e?.message || e}`); }),
|
|
91
|
-
new Response(child.stderr).text().catch((e: any) => { throw new Error(`stderr read failed: ${e?.message || e}
|
|
91
|
+
new Response(child.stderr).text().catch((e: any) => { throw new Error(`stderr read failed: ${e?.message || e}`); }),
|
|
92
92
|
]);
|
|
93
93
|
} catch (ioErr: any) {
|
|
94
94
|
try { child.kill('SIGKILL'); } catch {}
|