@inceptionstack/roundhouse 0.5.2 → 0.5.4
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/architecture.md +94 -32
- package/package.json +1 -1
- package/src/agents/kiro/kiro-adapter.ts +8 -1
- package/src/agents/pi/message-format.ts +87 -0
- package/src/agents/pi/pi-adapter.ts +33 -72
- package/src/cli/agent-command.ts +210 -0
- package/src/cli/cli.ts +63 -305
- package/src/cli/cron-commands.ts +258 -0
- package/src/cli/cron.ts +26 -267
- package/src/cli/launchd.ts +1 -1
- package/src/cli/service-manager.ts +192 -0
- package/src/cli/setup/args.ts +109 -0
- package/src/cli/setup/flows.ts +273 -0
- package/src/cli/setup/helpers.ts +66 -0
- package/src/cli/setup/index.ts +7 -0
- package/src/cli/setup/runtime.ts +109 -0
- package/src/cli/setup/steps.ts +617 -0
- package/src/cli/setup/types.ts +52 -0
- package/src/cli/setup.ts +79 -1275
- package/src/cli/shell.ts +49 -0
- package/src/cli/systemd.ts +6 -33
- package/src/config.ts +67 -53
- package/src/gateway/attachments.ts +147 -0
- package/src/gateway/commands.ts +371 -0
- package/src/gateway/helpers.ts +104 -0
- package/src/gateway/index.ts +11 -0
- package/src/gateway/streaming.ts +235 -0
- package/src/gateway.ts +212 -763
- package/src/types.ts +16 -1
package/src/cli/cli.ts
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { resolve, dirname } from "node:path";
|
|
8
|
-
import { homedir } from "node:os";
|
|
9
8
|
import { readFile } from "node:fs/promises";
|
|
10
9
|
import { readdirSync, statSync } from "node:fs";
|
|
11
10
|
import { execSync, execFileSync, spawn } from "node:child_process";
|
|
@@ -15,7 +14,6 @@ import { performUpdate } from "../commands/update";
|
|
|
15
14
|
import {
|
|
16
15
|
CONFIG_PATH,
|
|
17
16
|
SESSIONS_DIR,
|
|
18
|
-
SERVICE_NAME,
|
|
19
17
|
fileExists,
|
|
20
18
|
loadConfig,
|
|
21
19
|
resolveEnvFilePath,
|
|
@@ -23,14 +21,7 @@ import {
|
|
|
23
21
|
import { getAgentSdkPackage } from "../agents/registry";
|
|
24
22
|
import { threadIdToDir } from "../util";
|
|
25
23
|
import { parseEnvFile, unquoteEnvValue } from "./env-file";
|
|
26
|
-
import {
|
|
27
|
-
SERVICE_PATH,
|
|
28
|
-
systemctl,
|
|
29
|
-
runSudo,
|
|
30
|
-
isServiceInstalled,
|
|
31
|
-
isServiceActive,
|
|
32
|
-
systemctlShow,
|
|
33
|
-
} from "./systemd";
|
|
24
|
+
import { getServiceManager } from "./service-manager";
|
|
34
25
|
|
|
35
26
|
const __filename = fileURLToPath(import.meta.url);
|
|
36
27
|
const __dirname = dirname(__filename);
|
|
@@ -42,7 +33,7 @@ const __dirname = dirname(__filename);
|
|
|
42
33
|
* Only call with trusted/hardcoded strings. Any dynamic segments must be
|
|
43
34
|
* validated (e.g. `/^\d+$/.test(pid)`) before interpolation.
|
|
44
35
|
*/
|
|
45
|
-
function
|
|
36
|
+
function shellExec(cmd: string, opts?: { silent?: boolean }): string {
|
|
46
37
|
try {
|
|
47
38
|
const out = execSync(cmd, { encoding: "utf8", stdio: opts?.silent ? "pipe" : "inherit" });
|
|
48
39
|
return (out ?? "").trim();
|
|
@@ -55,53 +46,32 @@ function run(cmd: string, opts?: { silent?: boolean }): string {
|
|
|
55
46
|
// ── Commands ────────────────────────────────────────
|
|
56
47
|
|
|
57
48
|
async function cmdStart() {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const { isLaunchAgentInstalled, isLaunchAgentRunning, PLIST_PATH } = await import("./launchd.ts");
|
|
61
|
-
if (isLaunchAgentInstalled()) {
|
|
62
|
-
if (isLaunchAgentRunning()) {
|
|
63
|
-
console.log("Roundhouse is already running (LaunchAgent).");
|
|
64
|
-
console.log(" Logs: ~/.roundhouse/logs/roundhouse.log");
|
|
65
|
-
console.log(" Stop: roundhouse stop");
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
// Load it
|
|
69
|
-
try {
|
|
70
|
-
execFileSync("launchctl", ["load", PLIST_PATH], { stdio: "pipe" });
|
|
71
|
-
console.log("LaunchAgent started.");
|
|
72
|
-
console.log(" Logs: ~/.roundhouse/logs/roundhouse.log");
|
|
73
|
-
return;
|
|
74
|
-
} catch {
|
|
75
|
-
// Fall through to foreground
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
49
|
+
const svc = getServiceManager();
|
|
50
|
+
const result = await svc.start();
|
|
79
51
|
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
console.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
52
|
+
if (result.message === "no-service") {
|
|
53
|
+
// No service installed — fall back to foreground
|
|
54
|
+
if (!(await fileExists(CONFIG_PATH))) {
|
|
55
|
+
console.error("No config found. Run 'roundhouse setup --telegram' first.");
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
console.log("No service found. Running in foreground (use Ctrl+C to stop)...");
|
|
59
|
+
if (process.platform !== "darwin") {
|
|
60
|
+
console.log(" Tip: run 'roundhouse setup --telegram' to install as systemd daemon.\n");
|
|
61
|
+
} else {
|
|
62
|
+
console.log("");
|
|
87
63
|
}
|
|
88
|
-
|
|
64
|
+
await cmdRun();
|
|
89
65
|
return;
|
|
90
66
|
}
|
|
91
67
|
|
|
92
|
-
|
|
93
|
-
if (
|
|
94
|
-
console.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
console.log("No systemd service found. Running in foreground (use Ctrl+C to stop)...");
|
|
99
|
-
if (process.platform !== "darwin") {
|
|
100
|
-
console.log(" Tip: run 'roundhouse setup --telegram' to install as systemd daemon.\n");
|
|
101
|
-
} else {
|
|
102
|
-
console.log("");
|
|
68
|
+
console.log(result.message);
|
|
69
|
+
if (result.started && process.platform === "darwin") {
|
|
70
|
+
console.log(" Logs: ~/.roundhouse/logs/roundhouse.log");
|
|
71
|
+
} else if (!result.started) {
|
|
72
|
+
console.log(" Logs: roundhouse logs");
|
|
73
|
+
console.log(" Stop: roundhouse stop");
|
|
103
74
|
}
|
|
104
|
-
await cmdRun();
|
|
105
75
|
}
|
|
106
76
|
|
|
107
77
|
async function cmdRun() {
|
|
@@ -128,7 +98,7 @@ async function cmdRun() {
|
|
|
128
98
|
env: {
|
|
129
99
|
...process.env,
|
|
130
100
|
ROUNDHOUSE_CONFIG: CONFIG_PATH,
|
|
131
|
-
NODE_NO_WARNINGS: "1",
|
|
101
|
+
NODE_NO_WARNINGS: "1",
|
|
132
102
|
},
|
|
133
103
|
});
|
|
134
104
|
}
|
|
@@ -169,24 +139,11 @@ async function cmdInstall() {
|
|
|
169
139
|
console.log(" This sets up config, installs packages, pairs Telegram,");
|
|
170
140
|
console.log(" and installs the systemd service — all in one command.\n");
|
|
171
141
|
}
|
|
172
|
-
async function cmdUninstall() {
|
|
173
|
-
if (process.platform === "darwin") {
|
|
174
|
-
const { uninstallLaunchAgent, isLaunchAgentInstalled } = await import("./launchd.ts");
|
|
175
|
-
if (isLaunchAgentInstalled()) {
|
|
176
|
-
await uninstallLaunchAgent();
|
|
177
|
-
console.log(" ✅ LaunchAgent removed. Config preserved at:", CONFIG_PATH);
|
|
178
|
-
} else {
|
|
179
|
-
console.log(" No LaunchAgent installed.");
|
|
180
|
-
}
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
142
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
runSudo("systemctl", "daemon-reload");
|
|
189
|
-
console.log(" ✅ Daemon removed. Config preserved at:", CONFIG_PATH);
|
|
143
|
+
async function cmdUninstall() {
|
|
144
|
+
const svc = getServiceManager();
|
|
145
|
+
const result = await svc.uninstall();
|
|
146
|
+
console.log(` ✅ ${result.message} Config preserved at:`, CONFIG_PATH);
|
|
190
147
|
}
|
|
191
148
|
|
|
192
149
|
async function cmdUpdate() {
|
|
@@ -200,26 +157,16 @@ async function cmdUpdate() {
|
|
|
200
157
|
|
|
201
158
|
console.log(`[roundhouse] Updated to v${result.latestVersion}`);
|
|
202
159
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
try {
|
|
208
|
-
execFileSync("launchctl", ["unload", PLIST_PATH], { stdio: "pipe" });
|
|
209
|
-
execFileSync("launchctl", ["load", PLIST_PATH], { stdio: "pipe" });
|
|
210
|
-
console.log("\n ✅ Updated and restarted (LaunchAgent).");
|
|
211
|
-
} catch {
|
|
212
|
-
console.log("\n ✅ Update complete. Restart with: roundhouse start");
|
|
213
|
-
}
|
|
214
|
-
} else {
|
|
215
|
-
console.log("\n ✅ Update complete. Restart with: roundhouse start");
|
|
216
|
-
}
|
|
217
|
-
} else if (!isServiceInstalled()) {
|
|
160
|
+
const svc = getServiceManager();
|
|
161
|
+
const status = await svc.status();
|
|
162
|
+
|
|
163
|
+
if (!status.installed) {
|
|
218
164
|
console.log("\n ✅ Update complete. Restart with: roundhouse start");
|
|
219
165
|
} else {
|
|
220
|
-
console.log("\n[roundhouse] Restarting
|
|
166
|
+
console.log("\n[roundhouse] Restarting service...");
|
|
221
167
|
try {
|
|
222
|
-
|
|
168
|
+
const restartResult = await svc.restart();
|
|
169
|
+
console.log(` ✅ ${restartResult.message}`);
|
|
223
170
|
} catch {
|
|
224
171
|
console.log(" ⚠️ Could not restart. Run: roundhouse start");
|
|
225
172
|
}
|
|
@@ -227,41 +174,34 @@ async function cmdUpdate() {
|
|
|
227
174
|
}
|
|
228
175
|
|
|
229
176
|
async function cmdStatus() {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
} else if (isLaunchAgentInstalled()) {
|
|
238
|
-
console.log("\n ⚠️ LaunchAgent installed but not running.\n");
|
|
239
|
-
console.log(" Start with: roundhouse start\n");
|
|
240
|
-
} else {
|
|
241
|
-
console.log("\n ❌ Roundhouse is not running.\n");
|
|
242
|
-
console.log(" Start with: roundhouse start\n");
|
|
243
|
-
}
|
|
177
|
+
const svc = getServiceManager();
|
|
178
|
+
const svcStatus = await svc.status();
|
|
179
|
+
|
|
180
|
+
if (!svcStatus.running) {
|
|
181
|
+
const icon = svcStatus.installed ? "⚠️" : "❌";
|
|
182
|
+
console.log(`\n ${icon} ${svcStatus.message}\n`);
|
|
183
|
+
console.log(" Start with: roundhouse start\n");
|
|
244
184
|
return;
|
|
245
185
|
}
|
|
246
186
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
console.log("
|
|
187
|
+
// macOS: simple status
|
|
188
|
+
if (process.platform === "darwin") {
|
|
189
|
+
console.log("\n ✅ Roundhouse is running (LaunchAgent).\n");
|
|
190
|
+
console.log(" Logs: ~/.roundhouse/logs/roundhouse.log");
|
|
191
|
+
console.log(" Stop: roundhouse stop\n");
|
|
250
192
|
return;
|
|
251
193
|
}
|
|
252
194
|
|
|
253
|
-
//
|
|
195
|
+
// Linux: detailed systemd status
|
|
196
|
+
const { systemctlShow } = await import("./systemd");
|
|
197
|
+
|
|
254
198
|
let config: Awaited<ReturnType<typeof loadConfig>> | null = null;
|
|
255
|
-
try {
|
|
256
|
-
config = await loadConfig();
|
|
257
|
-
} catch {}
|
|
199
|
+
try { config = await loadConfig(); } catch {}
|
|
258
200
|
|
|
259
|
-
// Gather systemd info
|
|
260
201
|
const pid = systemctlShow("MainPID");
|
|
261
202
|
const activeState = systemctlShow("ActiveState");
|
|
262
203
|
const startedAt = systemctlShow("ActiveEnterTimestamp");
|
|
263
204
|
|
|
264
|
-
// Compute uptime
|
|
265
205
|
let uptimeStr = "unknown";
|
|
266
206
|
if (startedAt) {
|
|
267
207
|
const startMs = new Date(startedAt).getTime();
|
|
@@ -272,17 +212,15 @@ async function cmdStatus() {
|
|
|
272
212
|
}
|
|
273
213
|
}
|
|
274
214
|
|
|
275
|
-
// Memory from PID
|
|
276
215
|
let memStr = "unknown";
|
|
277
216
|
if (pid && pid !== "0" && /^\d+$/.test(pid)) {
|
|
278
|
-
const rssKb =
|
|
217
|
+
const rssKb = shellExec(`ps -o rss= -p ${pid}`, { silent: true }).trim();
|
|
279
218
|
if (rssKb) {
|
|
280
219
|
const parsed = parseInt(rssKb, 10);
|
|
281
220
|
if (!isNaN(parsed)) memStr = `${(parsed / 1024).toFixed(1)} MB`;
|
|
282
221
|
}
|
|
283
222
|
}
|
|
284
223
|
|
|
285
|
-
// Read env file for debug flags
|
|
286
224
|
let debugStream = false;
|
|
287
225
|
const statusEnvPath = await resolveEnvFilePath();
|
|
288
226
|
try {
|
|
@@ -290,7 +228,6 @@ async function cmdStatus() {
|
|
|
290
228
|
debugStream = envContent.includes("ROUNDHOUSE_DEBUG_STREAM=1") || envContent.includes('ROUNDHOUSE_DEBUG_STREAM="1"');
|
|
291
229
|
} catch {}
|
|
292
230
|
|
|
293
|
-
// Read versions
|
|
294
231
|
let roundhouseVersion = "unknown";
|
|
295
232
|
let agentVersion = "unknown";
|
|
296
233
|
try {
|
|
@@ -299,7 +236,6 @@ async function cmdStatus() {
|
|
|
299
236
|
roundhouseVersion = pkg.version;
|
|
300
237
|
} catch {}
|
|
301
238
|
|
|
302
|
-
// Resolve agent SDK version from registry
|
|
303
239
|
const agentPkg = config ? getAgentSdkPackage(config.agent.type) : undefined;
|
|
304
240
|
if (agentPkg) {
|
|
305
241
|
try {
|
|
@@ -332,46 +268,21 @@ async function cmdStatus() {
|
|
|
332
268
|
console.log();
|
|
333
269
|
}
|
|
334
270
|
|
|
335
|
-
async function cmdLogs() {
|
|
336
|
-
if (process.platform === "darwin") {
|
|
337
|
-
const logPath = resolve(homedir(), ".roundhouse", "logs", "roundhouse.log");
|
|
338
|
-
const child = spawn("tail", ["-f", "-n", "100", logPath], { stdio: "inherit" });
|
|
339
|
-
child.on("error", () => console.log("Could not read logs. Check ~/.roundhouse/logs/"));
|
|
340
|
-
return;
|
|
341
|
-
}
|
|
342
|
-
const child = spawn("journalctl", ["-u", SERVICE_NAME, "-f", "--no-pager", "-n", "100"], {
|
|
343
|
-
stdio: "inherit",
|
|
344
|
-
});
|
|
345
|
-
child.on("error", () => console.log("Could not read logs. Is the daemon installed?"));
|
|
346
|
-
}
|
|
347
|
-
|
|
348
271
|
async function cmdStop() {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
try { execFileSync("launchctl", ["unload", PLIST_PATH], { stdio: "pipe" }); } catch (e: any) { if (!e.message?.includes("Could not find")) console.warn(" (unload warning:", e.message?.split("\n")[0], ")"); }
|
|
353
|
-
console.log("LaunchAgent stopped.");
|
|
354
|
-
} else {
|
|
355
|
-
console.log("No LaunchAgent installed. Nothing to stop.");
|
|
356
|
-
}
|
|
357
|
-
return;
|
|
358
|
-
}
|
|
359
|
-
systemctl("stop", "Daemon stopped.");
|
|
272
|
+
const svc = getServiceManager();
|
|
273
|
+
const result = await svc.stop();
|
|
274
|
+
console.log(result.message);
|
|
360
275
|
}
|
|
361
276
|
|
|
362
277
|
async function cmdRestart() {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
374
|
-
systemctl("restart", "Daemon restarted.");
|
|
278
|
+
const svc = getServiceManager();
|
|
279
|
+
const result = await svc.restart();
|
|
280
|
+
console.log(result.message);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async function cmdLogs() {
|
|
284
|
+
const svc = getServiceManager();
|
|
285
|
+
svc.logs();
|
|
375
286
|
}
|
|
376
287
|
|
|
377
288
|
async function cmdConfig() {
|
|
@@ -467,162 +378,9 @@ Environment:
|
|
|
467
378
|
|
|
468
379
|
// ── Main ────────────────────────────────────────────
|
|
469
380
|
|
|
470
|
-
async function cmdAgent() {
|
|
471
|
-
// Usage: roundhouse agent <message>
|
|
472
|
-
// roundhouse agent --thread <id> <message>
|
|
473
|
-
// roundhouse agent --ephemeral <message>
|
|
474
|
-
// echo "message" | roundhouse agent --stdin
|
|
475
|
-
const args = process.argv.slice(3);
|
|
476
|
-
let threadId = "";
|
|
477
|
-
let messageText = "";
|
|
478
|
-
let useStdin = false;
|
|
479
|
-
let timeoutMs = 120_000;
|
|
480
|
-
let verbose = false;
|
|
481
|
-
let ephemeral = false;
|
|
482
|
-
|
|
483
|
-
for (let i = 0; i < args.length; i++) {
|
|
484
|
-
if (args[i] === "--thread" && args[i + 1]) {
|
|
485
|
-
threadId = args[++i];
|
|
486
|
-
} else if (args[i] === "--stdin") {
|
|
487
|
-
useStdin = true;
|
|
488
|
-
} else if (args[i] === "--timeout" && args[i + 1]) {
|
|
489
|
-
const val = parseInt(args[++i], 10);
|
|
490
|
-
if (isNaN(val) || val <= 0) { console.error("--timeout must be a positive number (seconds)"); process.exit(1); }
|
|
491
|
-
timeoutMs = val * 1000;
|
|
492
|
-
} else if (args[i] === "--no-timeout") {
|
|
493
|
-
timeoutMs = 0;
|
|
494
|
-
} else if (args[i] === "--verbose") {
|
|
495
|
-
verbose = true;
|
|
496
|
-
} else if (args[i] === "--ephemeral") {
|
|
497
|
-
ephemeral = true;
|
|
498
|
-
} else if (args[i].startsWith("-")) {
|
|
499
|
-
console.error(`Unknown flag: ${args[i]}`);
|
|
500
|
-
process.exit(1);
|
|
501
|
-
} else {
|
|
502
|
-
messageText = args.slice(i).join(" ");
|
|
503
|
-
break;
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
if (useStdin) {
|
|
508
|
-
const chunks: Buffer[] = [];
|
|
509
|
-
let totalBytes = 0;
|
|
510
|
-
const MAX_INPUT = 1024 * 1024; // 1 MB
|
|
511
|
-
for await (const chunk of process.stdin) {
|
|
512
|
-
totalBytes += chunk.length;
|
|
513
|
-
if (totalBytes > MAX_INPUT) {
|
|
514
|
-
console.error(`Input exceeds ${MAX_INPUT / 1024}KB limit. Use a file instead.`);
|
|
515
|
-
process.exit(1);
|
|
516
|
-
}
|
|
517
|
-
chunks.push(chunk);
|
|
518
|
-
}
|
|
519
|
-
// Strip single trailing newline (shell echo adds one)
|
|
520
|
-
let raw = Buffer.concat(chunks).toString("utf8");
|
|
521
|
-
if (raw.endsWith("\n")) raw = raw.slice(0, -1);
|
|
522
|
-
messageText = raw;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
if (!messageText) {
|
|
526
|
-
console.error("Usage: roundhouse agent <message>");
|
|
527
|
-
console.error(" roundhouse agent --thread <id> <message>");
|
|
528
|
-
console.error(" echo \"message\" | roundhouse agent --stdin");
|
|
529
|
-
console.error(" roundhouse agent --timeout 60 <message>");
|
|
530
|
-
console.error(" roundhouse agent --verbose <message>");
|
|
531
|
-
console.error(" roundhouse agent --ephemeral <message>");
|
|
532
|
-
process.exit(1);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
if (threadId && ephemeral) {
|
|
536
|
-
console.error("--thread and --ephemeral cannot be used together");
|
|
537
|
-
process.exit(1);
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
// Default: shared main session. --ephemeral restores one-off CLI behavior.
|
|
541
|
-
if (!threadId) {
|
|
542
|
-
threadId = ephemeral
|
|
543
|
-
? `cli-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
|
544
|
-
: "main";
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
// Suppress debug/info logs unless --verbose
|
|
548
|
-
const origLog = console.log;
|
|
549
|
-
const origWarn = console.warn;
|
|
550
|
-
const origError = console.error;
|
|
551
|
-
if (!verbose) {
|
|
552
|
-
console.log = () => {};
|
|
553
|
-
console.warn = () => {};
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
let agent: import("../types").AgentAdapter | undefined;
|
|
557
|
-
let aborted = false;
|
|
558
|
-
|
|
559
|
-
// Clean abort on SIGINT/SIGTERM
|
|
560
|
-
const handleSignal = async () => {
|
|
561
|
-
if (aborted) return;
|
|
562
|
-
aborted = true;
|
|
563
|
-
console.log = origLog;
|
|
564
|
-
console.warn = origWarn;
|
|
565
|
-
console.error = origError;
|
|
566
|
-
try { await agent?.abort?.(threadId); } catch {}
|
|
567
|
-
try { await agent?.dispose(); } catch {}
|
|
568
|
-
process.exit(130);
|
|
569
|
-
};
|
|
570
|
-
process.on("SIGINT", handleSignal);
|
|
571
|
-
process.on("SIGTERM", handleSignal);
|
|
572
|
-
|
|
573
|
-
// Timeout race
|
|
574
|
-
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
575
|
-
const timeoutPromise = timeoutMs > 0
|
|
576
|
-
? new Promise<never>((_, reject) => {
|
|
577
|
-
timer = setTimeout(async () => {
|
|
578
|
-
aborted = true;
|
|
579
|
-
try { await agent?.abort?.(threadId); } catch {}
|
|
580
|
-
reject(new Error(`Timeout after ${timeoutMs / 1000}s`));
|
|
581
|
-
}, timeoutMs);
|
|
582
|
-
})
|
|
583
|
-
: null;
|
|
584
|
-
|
|
585
|
-
try {
|
|
586
|
-
const config = await loadConfig();
|
|
587
|
-
const { getAgentFactory } = await import("../agents/registry");
|
|
588
|
-
const factory = getAgentFactory(config.agent.type);
|
|
589
|
-
agent = factory(config.agent);
|
|
590
|
-
|
|
591
|
-
const runAgent = async () => {
|
|
592
|
-
if (agent!.promptStream) {
|
|
593
|
-
for await (const event of agent!.promptStream(threadId, { text: messageText })) {
|
|
594
|
-
if (event.type === "text_delta") {
|
|
595
|
-
process.stdout.write(event.text);
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
process.stdout.write("\n");
|
|
599
|
-
} else {
|
|
600
|
-
const response = await agent!.prompt(threadId, { text: messageText });
|
|
601
|
-
origLog(response.text);
|
|
602
|
-
}
|
|
603
|
-
};
|
|
604
|
-
|
|
605
|
-
if (timeoutPromise) {
|
|
606
|
-
await Promise.race([runAgent(), timeoutPromise]);
|
|
607
|
-
} else {
|
|
608
|
-
await runAgent();
|
|
609
|
-
}
|
|
610
|
-
} catch (err: any) {
|
|
611
|
-
console.error = origError;
|
|
612
|
-
console.error(`Error: ${err.message}`);
|
|
613
|
-
process.exit(aborted ? 124 : 1); // 124 = timeout (like coreutils)
|
|
614
|
-
} finally {
|
|
615
|
-
if (timer) clearTimeout(timer);
|
|
616
|
-
process.off("SIGINT", handleSignal);
|
|
617
|
-
process.off("SIGTERM", handleSignal);
|
|
618
|
-
console.log = origLog;
|
|
619
|
-
console.warn = origWarn;
|
|
620
|
-
console.error = origError;
|
|
621
|
-
if (!aborted) await agent?.dispose();
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
381
|
|
|
625
382
|
import { cmdDoctor } from "./doctor";
|
|
383
|
+
import { cmdAgent } from "./agent-command";
|
|
626
384
|
import { cmdCron } from "./cron";
|
|
627
385
|
import { cmdSetup, cmdPair } from "./setup";
|
|
628
386
|
|