agent-ws 1.0.3 → 1.0.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/README.md +4 -1
- package/dist/agent.js +120 -23
- package/dist/agent.js.map +2 -2
- package/dist/cli.js +125 -28
- package/dist/cli.js.map +2 -2
- package/dist/index.js +120 -23
- package/dist/index.js.map +2 -2
- package/package.json +1 -2
package/dist/cli.js
CHANGED
|
@@ -37,7 +37,8 @@ var ClaudeRunner = class {
|
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
39
|
this.kill();
|
|
40
|
-
const { prompt, model, systemPrompt, projectId, requestId, thinkingTokens } = options;
|
|
40
|
+
const { prompt, model, systemPrompt, projectId, requestId, thinkingTokens, images } = options;
|
|
41
|
+
const hasImages = images && images.length > 0;
|
|
41
42
|
const args = [
|
|
42
43
|
"--print",
|
|
43
44
|
"--verbose",
|
|
@@ -50,6 +51,9 @@ var ClaudeRunner = class {
|
|
|
50
51
|
""
|
|
51
52
|
// Disable tool use — we only want generated text
|
|
52
53
|
];
|
|
54
|
+
if (hasImages) {
|
|
55
|
+
args.push("--input-format", "stream-json");
|
|
56
|
+
}
|
|
53
57
|
if (projectId) {
|
|
54
58
|
args.push("--continue");
|
|
55
59
|
}
|
|
@@ -105,7 +109,20 @@ var ClaudeRunner = class {
|
|
|
105
109
|
}
|
|
106
110
|
this.log.debug({ pid: this.process.pid, requestId }, "Claude process spawned");
|
|
107
111
|
if (this.process.stdin) {
|
|
108
|
-
|
|
112
|
+
if (hasImages) {
|
|
113
|
+
const content = [];
|
|
114
|
+
for (const img of images) {
|
|
115
|
+
content.push({
|
|
116
|
+
type: "image",
|
|
117
|
+
source: { type: "base64", media_type: img.media_type, data: img.data }
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
content.push({ type: "text", text: prompt });
|
|
121
|
+
const msg = JSON.stringify({ type: "user", message: { role: "user", content } });
|
|
122
|
+
this.process.stdin.write(msg + "\n");
|
|
123
|
+
} else {
|
|
124
|
+
this.process.stdin.write(prompt);
|
|
125
|
+
}
|
|
109
126
|
this.process.stdin.end();
|
|
110
127
|
}
|
|
111
128
|
let handlersDone = false;
|
|
@@ -230,8 +247,8 @@ var ClaudeRunner = class {
|
|
|
230
247
|
|
|
231
248
|
// src/process/codex-runner.ts
|
|
232
249
|
import { spawn as spawn2 } from "node:child_process";
|
|
233
|
-
import { mkdirSync as mkdirSync2 } from "node:fs";
|
|
234
|
-
import { resolve as resolve2 } from "node:path";
|
|
250
|
+
import { mkdirSync as mkdirSync2, writeFileSync, unlinkSync } from "node:fs";
|
|
251
|
+
import { resolve as resolve2, join } from "node:path";
|
|
235
252
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
236
253
|
import { createInterface as createInterface2 } from "node:readline";
|
|
237
254
|
var DEFAULT_TIMEOUT_MS2 = 5 * 60 * 1e3;
|
|
@@ -260,7 +277,7 @@ var CodexRunner = class {
|
|
|
260
277
|
return;
|
|
261
278
|
}
|
|
262
279
|
this.kill();
|
|
263
|
-
const { prompt, model, systemPrompt, projectId, requestId } = options;
|
|
280
|
+
const { prompt, model, systemPrompt, projectId, requestId, images } = options;
|
|
264
281
|
let fullPrompt = prompt;
|
|
265
282
|
if (systemPrompt) {
|
|
266
283
|
fullPrompt = `${systemPrompt}
|
|
@@ -269,11 +286,28 @@ var CodexRunner = class {
|
|
|
269
286
|
|
|
270
287
|
${prompt}`;
|
|
271
288
|
}
|
|
289
|
+
const imagePaths = [];
|
|
290
|
+
if (images && images.length > 0) {
|
|
291
|
+
const imgDir = resolve2(tmpdir2(), "agent-ws-images");
|
|
292
|
+
mkdirSync2(imgDir, { recursive: true });
|
|
293
|
+
const safeId = requestId.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
|
|
294
|
+
for (let i = 0; i < images.length; i++) {
|
|
295
|
+
const img = images[i];
|
|
296
|
+
const rawExt = img.media_type.split("/")[1] || "png";
|
|
297
|
+
const ext = rawExt.replace(/[^a-zA-Z0-9]/g, "").slice(0, 10) || "png";
|
|
298
|
+
const imgPath = join(imgDir, `${safeId}-${i}.${ext}`);
|
|
299
|
+
writeFileSync(imgPath, Buffer.from(img.data, "base64"));
|
|
300
|
+
imagePaths.push(imgPath);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
272
303
|
const resuming = projectId && this.threadId;
|
|
273
304
|
const args = resuming ? ["exec", "resume", this.threadId, "--json", "--full-auto", "--skip-git-repo-check"] : ["exec", "--json", "--full-auto", "--skip-git-repo-check"];
|
|
274
305
|
if (model && !resuming) {
|
|
275
306
|
args.push("--model", model);
|
|
276
307
|
}
|
|
308
|
+
for (const imgPath of imagePaths) {
|
|
309
|
+
args.push("-i", imgPath);
|
|
310
|
+
}
|
|
277
311
|
args.push("-");
|
|
278
312
|
this.log.info({ requestId, model, promptLength: prompt.length }, "Spawning Codex process");
|
|
279
313
|
this.killed = false;
|
|
@@ -287,6 +321,14 @@ ${prompt}`;
|
|
|
287
321
|
}
|
|
288
322
|
mkdirSync2(cwd, { recursive: true });
|
|
289
323
|
}
|
|
324
|
+
const cleanupImages = () => {
|
|
325
|
+
for (const p of imagePaths) {
|
|
326
|
+
try {
|
|
327
|
+
unlinkSync(p);
|
|
328
|
+
} catch {
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
};
|
|
290
332
|
const ALLOWED_ENV_KEYS = [
|
|
291
333
|
"PATH",
|
|
292
334
|
"HOME",
|
|
@@ -310,6 +352,7 @@ ${prompt}`;
|
|
|
310
352
|
env
|
|
311
353
|
});
|
|
312
354
|
} catch (err) {
|
|
355
|
+
cleanupImages();
|
|
313
356
|
const message = err instanceof Error ? err.message : "Failed to start Codex";
|
|
314
357
|
this.log.error({ err, requestId }, "Failed to spawn Codex process");
|
|
315
358
|
handlers.onError(message, requestId);
|
|
@@ -348,6 +391,7 @@ ${prompt}`;
|
|
|
348
391
|
}
|
|
349
392
|
this.process.on("exit", (exitCode, signal) => {
|
|
350
393
|
this.process = null;
|
|
394
|
+
cleanupImages();
|
|
351
395
|
if (this.killed) {
|
|
352
396
|
this.log.debug({ requestId }, "Codex process was killed");
|
|
353
397
|
return;
|
|
@@ -363,6 +407,7 @@ ${prompt}`;
|
|
|
363
407
|
});
|
|
364
408
|
this.process.on("error", (err) => {
|
|
365
409
|
this.process = null;
|
|
410
|
+
cleanupImages();
|
|
366
411
|
this.log.error({ err, requestId }, "Codex process error");
|
|
367
412
|
finish(() => handlers.onError(err.message, requestId));
|
|
368
413
|
});
|
|
@@ -435,6 +480,14 @@ ${prompt}`;
|
|
|
435
480
|
// src/server/protocol.ts
|
|
436
481
|
var MAX_PROMPT_BYTES = 512 * 1024;
|
|
437
482
|
var MAX_SYSTEM_PROMPT_BYTES = 64 * 1024;
|
|
483
|
+
var MAX_IMAGES = 4;
|
|
484
|
+
var MAX_IMAGE_BASE64_BYTES = 10 * 1024 * 1024;
|
|
485
|
+
var ALLOWED_IMAGE_TYPES = /* @__PURE__ */ new Set([
|
|
486
|
+
"image/png",
|
|
487
|
+
"image/jpeg",
|
|
488
|
+
"image/gif",
|
|
489
|
+
"image/webp"
|
|
490
|
+
]);
|
|
438
491
|
var MAX_PROJECT_ID_LENGTH = 128;
|
|
439
492
|
var PROJECT_ID_PATTERN = /^[a-zA-Z0-9._-]+$/;
|
|
440
493
|
function parseClientMessage(raw) {
|
|
@@ -481,6 +534,30 @@ function parseClientMessage(raw) {
|
|
|
481
534
|
return { ok: false, error: "projectId contains invalid characters (allowed: alphanumeric, hyphens, underscores, dots)" };
|
|
482
535
|
}
|
|
483
536
|
}
|
|
537
|
+
let parsedImages;
|
|
538
|
+
const rawImages = obj["images"];
|
|
539
|
+
if (Array.isArray(rawImages) && rawImages.length > 0) {
|
|
540
|
+
if (rawImages.length > MAX_IMAGES) {
|
|
541
|
+
return { ok: false, error: `Too many images (max ${MAX_IMAGES})` };
|
|
542
|
+
}
|
|
543
|
+
parsedImages = [];
|
|
544
|
+
for (const img of rawImages) {
|
|
545
|
+
if (typeof img !== "object" || img === null) {
|
|
546
|
+
return { ok: false, error: "Each image must be an object with media_type and data" };
|
|
547
|
+
}
|
|
548
|
+
const imgObj = img;
|
|
549
|
+
if (typeof imgObj["media_type"] !== "string" || typeof imgObj["data"] !== "string") {
|
|
550
|
+
return { ok: false, error: "Each image must have string media_type and data fields" };
|
|
551
|
+
}
|
|
552
|
+
if (!ALLOWED_IMAGE_TYPES.has(imgObj["media_type"])) {
|
|
553
|
+
return { ok: false, error: `Unsupported image type: ${String(imgObj["media_type"]).slice(0, 50)} (allowed: png, jpeg, gif, webp)` };
|
|
554
|
+
}
|
|
555
|
+
if (imgObj["data"].length > MAX_IMAGE_BASE64_BYTES) {
|
|
556
|
+
return { ok: false, error: `Image exceeds maximum size of ${MAX_IMAGE_BASE64_BYTES} bytes` };
|
|
557
|
+
}
|
|
558
|
+
parsedImages.push({ media_type: imgObj["media_type"], data: imgObj["data"] });
|
|
559
|
+
}
|
|
560
|
+
}
|
|
484
561
|
return {
|
|
485
562
|
ok: true,
|
|
486
563
|
message: {
|
|
@@ -491,7 +568,8 @@ function parseClientMessage(raw) {
|
|
|
491
568
|
projectId: typeof projectId === "string" ? projectId : void 0,
|
|
492
569
|
requestId,
|
|
493
570
|
provider: provider === "codex" ? "codex" : "claude",
|
|
494
|
-
thinkingTokens: typeof thinkingTokens === "number" && thinkingTokens >= 0 ? thinkingTokens : void 0
|
|
571
|
+
thinkingTokens: typeof thinkingTokens === "number" && thinkingTokens >= 0 ? thinkingTokens : void 0,
|
|
572
|
+
images: parsedImages
|
|
495
573
|
}
|
|
496
574
|
};
|
|
497
575
|
}
|
|
@@ -515,7 +593,7 @@ function serializeMessage(message) {
|
|
|
515
593
|
|
|
516
594
|
// src/server/websocket.ts
|
|
517
595
|
var HEARTBEAT_INTERVAL_MS = 3e4;
|
|
518
|
-
var DEFAULT_MAX_PAYLOAD = 1024 * 1024;
|
|
596
|
+
var DEFAULT_MAX_PAYLOAD = 50 * 1024 * 1024;
|
|
519
597
|
var AgentWebSocketServer = class {
|
|
520
598
|
wss = null;
|
|
521
599
|
heartbeatInterval = null;
|
|
@@ -629,17 +707,12 @@ var AgentWebSocketServer = class {
|
|
|
629
707
|
state.activeRequestId = message.requestId;
|
|
630
708
|
if (message.provider === "codex") {
|
|
631
709
|
if (!state.codexRunner) {
|
|
632
|
-
state.codexRunner =
|
|
633
|
-
codexPath: this.options.codexPath,
|
|
634
|
-
timeoutMs: this.options.timeoutMs,
|
|
635
|
-
logger: this.log.child({ component: "codex-runner" }),
|
|
636
|
-
sessionDir: this.options.sessionDir
|
|
637
|
-
});
|
|
710
|
+
state.codexRunner = this.createCodexRunner();
|
|
638
711
|
}
|
|
639
712
|
state.activeRunner = state.codexRunner;
|
|
640
713
|
} else {
|
|
641
714
|
if (!state.claudeRunner) {
|
|
642
|
-
state.claudeRunner = this.
|
|
715
|
+
state.claudeRunner = this.createClaudeRunner();
|
|
643
716
|
}
|
|
644
717
|
state.activeRunner = state.claudeRunner;
|
|
645
718
|
}
|
|
@@ -669,14 +742,25 @@ var AgentWebSocketServer = class {
|
|
|
669
742
|
}
|
|
670
743
|
};
|
|
671
744
|
state.activeRunner.run(
|
|
672
|
-
{
|
|
745
|
+
{
|
|
746
|
+
prompt: message.prompt,
|
|
747
|
+
model: message.model,
|
|
748
|
+
systemPrompt: message.systemPrompt,
|
|
749
|
+
projectId: message.projectId,
|
|
750
|
+
requestId: message.requestId,
|
|
751
|
+
thinkingTokens: message.thinkingTokens,
|
|
752
|
+
images: message.images
|
|
753
|
+
},
|
|
673
754
|
handlers
|
|
674
755
|
);
|
|
675
756
|
}
|
|
676
757
|
handleCancel(ws, state) {
|
|
677
|
-
state.activeRunner?.kill();
|
|
678
758
|
const requestId = state.activeRequestId;
|
|
759
|
+
state.activeRunner?.kill();
|
|
679
760
|
state.activeRequestId = null;
|
|
761
|
+
if (requestId) {
|
|
762
|
+
this.sendMessage(ws, { type: "error", message: "Request cancelled", requestId });
|
|
763
|
+
}
|
|
680
764
|
this.log.info({ requestId }, "Request cancelled");
|
|
681
765
|
}
|
|
682
766
|
sendMessage(ws, message) {
|
|
@@ -686,17 +770,28 @@ var AgentWebSocketServer = class {
|
|
|
686
770
|
this.log.warn({ messageType: message.type, readyState: ws.readyState }, "Dropping message, WebSocket not OPEN");
|
|
687
771
|
}
|
|
688
772
|
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
773
|
+
createClaudeRunner() {
|
|
774
|
+
const factory = this.options.claudeRunnerFactory ?? this.options.runnerFactory;
|
|
775
|
+
if (factory) {
|
|
776
|
+
return factory(this.log);
|
|
692
777
|
}
|
|
693
|
-
|
|
778
|
+
return new ClaudeRunner({
|
|
694
779
|
claudePath: this.options.claudePath,
|
|
695
780
|
timeoutMs: this.options.timeoutMs,
|
|
696
|
-
logger: this.log.child({ component: "runner" }),
|
|
781
|
+
logger: this.log.child({ component: "claude-runner" }),
|
|
697
782
|
sessionDir: this.options.sessionDir
|
|
698
|
-
};
|
|
699
|
-
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
createCodexRunner() {
|
|
786
|
+
if (this.options.codexRunnerFactory) {
|
|
787
|
+
return this.options.codexRunnerFactory(this.log);
|
|
788
|
+
}
|
|
789
|
+
return new CodexRunner({
|
|
790
|
+
codexPath: this.options.codexPath,
|
|
791
|
+
timeoutMs: this.options.timeoutMs,
|
|
792
|
+
logger: this.log.child({ component: "codex-runner" }),
|
|
793
|
+
sessionDir: this.options.sessionDir
|
|
794
|
+
});
|
|
700
795
|
}
|
|
701
796
|
startHeartbeat() {
|
|
702
797
|
this.heartbeatInterval = setInterval(() => {
|
|
@@ -762,6 +857,8 @@ var AgentWS = class {
|
|
|
762
857
|
timeoutMs: options.timeoutMs,
|
|
763
858
|
allowedOrigins: options.allowedOrigins,
|
|
764
859
|
runnerFactory: options.runnerFactory,
|
|
860
|
+
claudeRunnerFactory: options.claudeRunnerFactory,
|
|
861
|
+
codexRunnerFactory: options.codexRunnerFactory,
|
|
765
862
|
agentName: options.agentName,
|
|
766
863
|
sessionDir: options.sessionDir
|
|
767
864
|
};
|
|
@@ -777,9 +874,9 @@ var AgentWS = class {
|
|
|
777
874
|
|
|
778
875
|
// src/utils/claude-check.ts
|
|
779
876
|
import { execFileSync } from "node:child_process";
|
|
780
|
-
function
|
|
877
|
+
function checkCli(cliPath = "claude") {
|
|
781
878
|
try {
|
|
782
|
-
const output = execFileSync(
|
|
879
|
+
const output = execFileSync(cliPath, ["--version"], {
|
|
783
880
|
timeout: 5e3,
|
|
784
881
|
stdio: "pipe",
|
|
785
882
|
encoding: "utf-8"
|
|
@@ -798,7 +895,7 @@ function checkClaudeCli(claudePath = "claude") {
|
|
|
798
895
|
}
|
|
799
896
|
|
|
800
897
|
// src/cli.ts
|
|
801
|
-
var VERSION = true ? "1.0.
|
|
898
|
+
var VERSION = true ? "1.0.4" : "0.0.0-dev";
|
|
802
899
|
var program = new Command();
|
|
803
900
|
program.name("agent-ws").description("WebSocket bridge for CLI AI agents (Claude, Codex)").version(VERSION).option("-p, --port <port>", "WebSocket server port", "9999").option("-H, --host <host>", "WebSocket server host", "localhost").option("-c, --claude-path <path>", "Path to Claude CLI", "claude").option("--codex-path <path>", "Path to Codex CLI", "codex").option("-t, --timeout <seconds>", "Process timeout in seconds", "300").option("--log-level <level>", "Log level (debug, info, warn, error)", "info").option("--origins <origins>", "Comma-separated allowed origins").action(async (opts) => {
|
|
804
901
|
console.log(`
|
|
@@ -807,7 +904,7 @@ program.name("agent-ws").description("WebSocket bridge for CLI AI agents (Claude
|
|
|
807
904
|
\u2551 CLI AI Agent Bridge \u2551
|
|
808
905
|
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
809
906
|
`);
|
|
810
|
-
const check =
|
|
907
|
+
const check = checkCli(opts.claudePath);
|
|
811
908
|
if (!check.available) {
|
|
812
909
|
console.error(`Claude CLI not found at: ${opts.claudePath}`);
|
|
813
910
|
console.error("Make sure Claude Code is installed and in your PATH.");
|
|
@@ -816,7 +913,7 @@ program.name("agent-ws").description("WebSocket bridge for CLI AI agents (Claude
|
|
|
816
913
|
process.exit(1);
|
|
817
914
|
}
|
|
818
915
|
console.log(`Found Claude CLI: ${check.version}`);
|
|
819
|
-
const codexCheck =
|
|
916
|
+
const codexCheck = checkCli(opts.codexPath);
|
|
820
917
|
if (codexCheck.available) {
|
|
821
918
|
console.log(`Found Codex CLI: ${codexCheck.version}`);
|
|
822
919
|
} else {
|
package/dist/cli.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/cli.ts", "../src/server/websocket.ts", "../src/process/claude-runner.ts", "../src/process/codex-runner.ts", "../src/server/protocol.ts", "../src/utils/logger.ts", "../src/agent.ts", "../src/utils/claude-check.ts"],
|
|
4
|
-
"sourcesContent": ["import { Command } from \"commander\";\nimport { AgentWS } from \"./agent.js\";\nimport { checkClaudeCli } from \"./utils/claude-check.js\";\n\ndeclare const PKG_VERSION: string;\nconst VERSION = typeof PKG_VERSION !== \"undefined\" ? PKG_VERSION : \"0.0.0-dev\";\n\nconst program = new Command();\n\nprogram\n .name(\"agent-ws\")\n .description(\"WebSocket bridge for CLI AI agents (Claude, Codex)\")\n .version(VERSION)\n .option(\"-p, --port <port>\", \"WebSocket server port\", \"9999\")\n .option(\"-H, --host <host>\", \"WebSocket server host\", \"localhost\")\n .option(\"-c, --claude-path <path>\", \"Path to Claude CLI\", \"claude\")\n .option(\"--codex-path <path>\", \"Path to Codex CLI\", \"codex\")\n .option(\"-t, --timeout <seconds>\", \"Process timeout in seconds\", \"300\")\n .option(\"--log-level <level>\", \"Log level (debug, info, warn, error)\", \"info\")\n .option(\"--origins <origins>\", \"Comma-separated allowed origins\")\n .action(async (opts: {\n port: string;\n host: string;\n claudePath: string;\n codexPath: string;\n timeout: string;\n logLevel: string;\n origins?: string;\n }) => {\n // Banner\n console.log(`\n\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n\u2551 agent-ws v${VERSION.padEnd(20)}\u2551\n\u2551 CLI AI Agent Bridge \u2551\n\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\n`);\n\n // Check Claude CLI\n const check = checkClaudeCli(opts.claudePath);\n if (!check.available) {\n console.error(`Claude CLI not found at: ${opts.claudePath}`);\n console.error(\"Make sure Claude Code is installed and in your PATH.\");\n console.error(\"Install: npm install -g @anthropic-ai/claude-code\");\n console.error(`Or specify path: agent-ws --claude-path /path/to/claude`);\n process.exit(1);\n }\n console.log(`Found Claude CLI: ${check.version}`);\n\n // Check Codex CLI (optional \u2014 just warn if missing)\n const codexCheck = checkClaudeCli(opts.codexPath);\n if (codexCheck.available) {\n console.log(`Found Codex CLI: ${codexCheck.version}`);\n } else {\n console.log(\"Codex CLI not found (codex provider will be unavailable)\");\n }\n\n const port = parseInt(opts.port, 10);\n if (isNaN(port) || port < 1 || port > 65535) {\n console.error(`Invalid port: ${opts.port} (must be 1\u201365535)`);\n process.exit(1);\n }\n\n const timeoutSeconds = parseInt(opts.timeout, 10);\n if (isNaN(timeoutSeconds) || timeoutSeconds < 1 || timeoutSeconds > 3600) {\n console.error(`Invalid timeout: ${opts.timeout} (must be 1\u20133600 seconds)`);\n process.exit(1);\n }\n const timeoutMs = timeoutSeconds * 1000;\n\n const allowedOrigins = opts.origins?.split(\",\").map((o) => o.trim()).filter(Boolean);\n if (allowedOrigins) {\n for (const origin of allowedOrigins) {\n try {\n new URL(origin);\n } catch {\n console.error(`Invalid origin: \"${origin}\" (must be a valid URL, e.g. https://example.com)`);\n process.exit(1);\n }\n }\n }\n\n const agent = new AgentWS({\n port,\n host: opts.host,\n claudePath: opts.claudePath,\n codexPath: opts.codexPath,\n timeoutMs,\n logLevel: opts.logLevel,\n allowedOrigins,\n });\n\n try {\n await agent.start();\n } catch (err) {\n if (err instanceof Error && \"code\" in err && (err as NodeJS.ErrnoException).code === \"EADDRINUSE\") {\n console.error(`Port ${port} is already in use.`);\n console.error(\"Another instance of agent-ws might be running.\");\n }\n process.exit(1);\n }\n\n console.log(`agent-ws running on ws://${opts.host}:${port}`);\n console.log(\"Waiting for connections...\\n\");\n console.log(\"Press Ctrl+C to stop\\n\");\n\n // Graceful shutdown\n const shutdown = () => {\n agent.stop();\n console.log(\"\\nagent-ws stopped\");\n process.exit(0);\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n });\n\nprogram.parse();\n", "import { WebSocketServer, WebSocket } from \"ws\";\nimport type { IncomingMessage } from \"node:http\";\nimport { ClaudeRunner, type ClaudeRunnerOptions, type Runner, type RunHandlers } from \"../process/claude-runner.js\";\nimport { CodexRunner } from \"../process/codex-runner.js\";\nimport {\n parseClientMessage,\n serializeMessage,\n type AgentMessage,\n type PromptMessage,\n} from \"./protocol.js\";\nimport type { Logger } from \"../utils/logger.js\";\n\nconst HEARTBEAT_INTERVAL_MS = 30_000;\nconst DEFAULT_MAX_PAYLOAD = 1024 * 1024; // 1MB\n\nexport type RunnerFactory = (log: Logger) => Runner;\n\ninterface ConnectionState {\n claudeRunner: Runner | null;\n codexRunner: Runner | null;\n activeRunner: Runner | null;\n isAlive: boolean;\n activeRequestId: string | null;\n}\n\nexport interface AgentWebSocketServerOptions {\n port: number;\n host: string;\n logger: Logger;\n claudePath?: string;\n codexPath?: string;\n timeoutMs?: number;\n allowedOrigins?: string[];\n maxPayload?: number;\n runnerFactory?: RunnerFactory;\n agentName?: string;\n sessionDir?: string;\n}\n\nexport class AgentWebSocketServer {\n private wss: WebSocketServer | null = null;\n private heartbeatInterval: NodeJS.Timeout | null = null;\n private readonly connections = new Map<WebSocket, ConnectionState>();\n private readonly log: Logger;\n private readonly options: AgentWebSocketServerOptions;\n\n constructor(options: AgentWebSocketServerOptions) {\n this.options = options;\n this.log = options.logger;\n }\n\n start(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.wss = new WebSocketServer({\n port: this.options.port,\n host: this.options.host,\n maxPayload: this.options.maxPayload ?? DEFAULT_MAX_PAYLOAD,\n });\n\n this.wss.on(\"listening\", () => {\n this.log.info({ port: this.options.port, host: this.options.host }, \"WebSocket server started\");\n this.startHeartbeat();\n resolve();\n });\n\n this.wss.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n this.log.fatal({ port: this.options.port }, \"Port already in use\");\n } else {\n this.log.error({ err }, \"WebSocket server error\");\n }\n reject(err);\n });\n\n this.wss.on(\"connection\", (ws, req) => this.handleConnection(ws, req));\n });\n }\n\n stop(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = null;\n }\n\n for (const [ws, state] of this.connections) {\n state.claudeRunner?.dispose();\n state.codexRunner?.dispose();\n ws.terminate();\n }\n this.connections.clear();\n\n if (this.wss) {\n this.wss.close();\n this.wss = null;\n }\n\n this.log.info(\"WebSocket server stopped\");\n }\n\n private handleConnection(ws: WebSocket, req: IncomingMessage): void {\n // Origin check\n if (this.options.allowedOrigins && this.options.allowedOrigins.length > 0) {\n const origin = req.headers.origin;\n if (!origin || !this.options.allowedOrigins.includes(origin)) {\n this.log.warn({ origin: origin ?? \"(none)\" }, \"Rejected connection: origin not in allowlist\");\n ws.close(4003, \"Origin not allowed\");\n return;\n }\n }\n\n const clientIp = req.socket.remoteAddress;\n this.log.info({ clientIp }, \"Client connected\");\n\n const state: ConnectionState = { claudeRunner: null, codexRunner: null, activeRunner: null, isAlive: true, activeRequestId: null };\n this.connections.set(ws, state);\n\n // Send connected message\n this.sendMessage(ws, {\n type: \"connected\",\n version: \"1.0\",\n agent: this.options.agentName ?? \"agent-ws\",\n });\n\n ws.on(\"pong\", () => {\n state.isAlive = true;\n });\n\n ws.on(\"message\", (data) => {\n const raw = data.toString();\n this.handleMessage(ws, state, raw);\n });\n\n ws.on(\"close\", () => {\n this.log.info({ clientIp }, \"Client disconnected\");\n state.claudeRunner?.dispose();\n state.codexRunner?.dispose();\n this.connections.delete(ws);\n });\n\n ws.on(\"error\", (err) => {\n this.log.error({ err, clientIp }, \"WebSocket error\");\n });\n }\n\n private handleMessage(ws: WebSocket, state: ConnectionState, raw: string): void {\n const result = parseClientMessage(raw);\n\n if (!result.ok) {\n this.sendMessage(ws, { type: \"error\", message: result.error });\n return;\n }\n\n const { message } = result;\n\n switch (message.type) {\n case \"prompt\":\n this.handlePrompt(ws, state, message);\n break;\n case \"cancel\":\n this.handleCancel(ws, state);\n break;\n }\n }\n\n private handlePrompt(ws: WebSocket, state: ConnectionState, message: PromptMessage): void {\n if (state.activeRequestId !== null) {\n this.sendMessage(ws, {\n type: \"error\",\n message: \"Request already in progress\",\n requestId: message.requestId,\n });\n return;\n }\n\n state.activeRequestId = message.requestId;\n\n // Select runner for the requested provider (lazy-created, preserved across switches)\n if (message.provider === \"codex\") {\n if (!state.codexRunner) {\n state.codexRunner = new CodexRunner({\n codexPath: this.options.codexPath,\n timeoutMs: this.options.timeoutMs,\n logger: this.log.child({ component: \"codex-runner\" }),\n sessionDir: this.options.sessionDir,\n });\n }\n state.activeRunner = state.codexRunner;\n } else {\n if (!state.claudeRunner) {\n state.claudeRunner = this.createRunner();\n }\n state.activeRunner = state.claudeRunner;\n }\n\n const handlers: RunHandlers = {\n onChunk: (content, requestId, thinking) => {\n try {\n this.sendMessage(ws, { type: \"chunk\", content, requestId, ...(thinking ? { thinking: true } : {}) });\n } catch (err) {\n this.log.warn({ err, requestId }, \"Error in onChunk handler\");\n }\n },\n onComplete: (requestId) => {\n try {\n state.activeRequestId = null;\n this.sendMessage(ws, { type: \"complete\", requestId });\n } catch (err) {\n this.log.warn({ err, requestId }, \"Error in onComplete handler\");\n }\n },\n onError: (errorMessage, requestId) => {\n try {\n state.activeRequestId = null;\n this.sendMessage(ws, { type: \"error\", message: errorMessage, requestId });\n } catch (err) {\n this.log.warn({ err, requestId }, \"Error in onError handler\");\n }\n },\n };\n\n state.activeRunner!.run(\n { prompt: message.prompt, model: message.model, systemPrompt: message.systemPrompt, projectId: message.projectId, requestId: message.requestId, thinkingTokens: message.thinkingTokens },\n handlers,\n );\n }\n\n private handleCancel(ws: WebSocket, state: ConnectionState): void {\n state.activeRunner?.kill();\n const requestId = state.activeRequestId;\n state.activeRequestId = null;\n this.log.info({ requestId }, \"Request cancelled\");\n }\n\n private sendMessage(ws: WebSocket, message: AgentMessage): void {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(serializeMessage(message));\n } else {\n this.log.warn({ messageType: message.type, readyState: ws.readyState }, \"Dropping message, WebSocket not OPEN\");\n }\n }\n\n private createRunner(): Runner {\n if (this.options.runnerFactory) {\n return this.options.runnerFactory(this.log);\n }\n\n const runnerOptions: ClaudeRunnerOptions = {\n claudePath: this.options.claudePath,\n timeoutMs: this.options.timeoutMs,\n logger: this.log.child({ component: \"runner\" }),\n sessionDir: this.options.sessionDir,\n };\n return new ClaudeRunner(runnerOptions);\n }\n\n private startHeartbeat(): void {\n this.heartbeatInterval = setInterval(() => {\n for (const [ws, state] of this.connections) {\n if (!state.isAlive) {\n this.log.debug(\"Terminating dead connection\");\n state.claudeRunner?.dispose();\n state.codexRunner?.dispose();\n this.connections.delete(ws);\n ws.terminate();\n continue;\n }\n\n state.isAlive = false;\n try {\n ws.ping();\n } catch {\n this.log.debug(\"Ping failed, terminating connection\");\n state.claudeRunner?.dispose();\n state.codexRunner?.dispose();\n this.connections.delete(ws);\n ws.terminate();\n }\n }\n }, HEARTBEAT_INTERVAL_MS);\n }\n}\n", "import { spawn, type ChildProcess } from \"node:child_process\";\nimport { mkdirSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport { createInterface } from \"node:readline\";\nimport type { Logger } from \"../utils/logger.js\";\n\nexport interface RunOptions {\n prompt: string;\n model?: string;\n systemPrompt?: string;\n projectId?: string;\n requestId: string;\n thinkingTokens?: number;\n}\n\nexport interface RunHandlers {\n onChunk: (content: string, requestId: string, thinking?: boolean) => void;\n onComplete: (requestId: string) => void;\n onError: (message: string, requestId: string) => void;\n}\n\n/** Interface for runner injection (testing) */\nexport interface Runner {\n run(options: RunOptions, handlers: RunHandlers): void;\n kill(): void;\n dispose(): void;\n}\n\nexport interface ClaudeRunnerOptions {\n claudePath?: string;\n timeoutMs?: number;\n logger: Logger;\n sessionDir?: string;\n}\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\n\nexport class ClaudeRunner implements Runner {\n private process: ChildProcess | null = null;\n private timeout: NodeJS.Timeout | null = null;\n private disposed = false;\n private killed = false;\n private readonly claudePath: string;\n private readonly timeoutMs: number;\n private readonly log: Logger;\n private readonly sessionDir: string;\n\n constructor(options: ClaudeRunnerOptions) {\n this.claudePath = options.claudePath ?? \"claude\";\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.log = options.logger;\n this.sessionDir = options.sessionDir ?? \"agent-ws-sessions\";\n }\n\n get isRunning(): boolean {\n return this.process !== null;\n }\n\n run(options: RunOptions, handlers: RunHandlers): void {\n if (this.disposed) {\n handlers.onError(\"Runner has been disposed\", options.requestId);\n return;\n }\n\n // Kill any existing process first\n this.kill();\n\n const { prompt, model, systemPrompt, projectId, requestId, thinkingTokens } = options;\n\n const args = [\n \"--print\",\n \"--verbose\",\n \"--output-format\", \"stream-json\",\n \"--max-turns\", \"1\", // Single-turn text output, no agentic loops\n \"--tools\", \"\", // Disable tool use \u2014 we only want generated text\n ];\n // Only resume session when a projectId is provided (scoped by CWD)\n if (projectId) {\n args.push(\"--continue\");\n }\n if (model) {\n args.push(\"--model\", model);\n }\n if (systemPrompt) {\n args.push(\"--append-system-prompt\", systemPrompt);\n }\n // Prompt is piped via stdin (no arg length limits, no flag-parsing issues)\n args.push(\"-\");\n\n this.log.info({ requestId, model, promptLength: prompt.length }, \"Spawning Claude process\");\n this.killed = false;\n\n // Use project-scoped CWD so --continue resumes the correct session\n // (Claude CLI scopes sessions by working directory)\n let cwd: string | undefined;\n if (projectId) {\n const base = resolve(tmpdir(), this.sessionDir);\n cwd = resolve(base, projectId);\n if (!cwd.startsWith(base + \"/\") && cwd !== base) {\n handlers.onError(\"Invalid projectId\", requestId);\n return;\n }\n mkdirSync(cwd, { recursive: true });\n }\n\n try {\n const ALLOWED_ENV_KEYS = [\n \"PATH\", \"HOME\", \"USER\", \"SHELL\", \"TERM\", \"LANG\", \"LC_ALL\",\n \"ANTHROPIC_API_KEY\", \"NODE_PATH\", \"XDG_CONFIG_HOME\",\n ];\n const env: Record<string, string> = {};\n if (thinkingTokens !== undefined) {\n env[\"MAX_THINKING_TOKENS\"] = String(thinkingTokens);\n }\n for (const key of ALLOWED_ENV_KEYS) {\n if (process.env[key]) env[key] = process.env[key]!;\n }\n\n this.process = spawn(this.claudePath, args, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n cwd,\n env,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Failed to start Claude\";\n this.log.error({ err, requestId }, \"Failed to spawn Claude process\");\n handlers.onError(message, requestId);\n return;\n }\n\n this.log.debug({ pid: this.process.pid, requestId }, \"Claude process spawned\");\n\n // Write prompt to stdin and close it\n if (this.process.stdin) {\n this.process.stdin.write(prompt);\n this.process.stdin.end();\n }\n\n // Guard against double handler invocation (e.g. error + exit both firing)\n let handlersDone = false;\n const finish = (cb: () => void) => {\n if (handlersDone) return;\n handlersDone = true;\n this.clearTimeout();\n cb();\n };\n\n // Set up timeout\n this.timeout = setTimeout(() => {\n this.log.warn({ requestId }, \"Claude process timed out\");\n this.kill();\n finish(() => handlers.onError(\"Process timed out\", requestId));\n }, this.timeoutMs);\n\n // Parse NDJSON from stdout\n if (this.process.stdout) {\n const rl = createInterface({ input: this.process.stdout });\n rl.on(\"line\", (line) => {\n this.parseStreamLine(line, handlers, requestId);\n });\n }\n\n // Capture stderr \u2014 logs at warn level so errors are visible\n if (this.process.stderr) {\n const stderrRl = createInterface({ input: this.process.stderr });\n stderrRl.on(\"line\", (line) => {\n if (line.trim()) {\n this.log.warn({ requestId, stderr: line }, \"Claude stderr\");\n }\n });\n }\n\n // Handle exit\n this.process.on(\"exit\", (exitCode, signal) => {\n this.process = null;\n\n if (this.killed) {\n this.log.debug({ requestId }, \"Claude process was killed\");\n return;\n }\n\n if (exitCode === 0) {\n this.log.info({ requestId }, \"Claude process completed successfully\");\n finish(() => handlers.onComplete(requestId));\n } else {\n const reason = exitCode !== null\n ? `Claude CLI exited with code ${exitCode}`\n : `Claude CLI killed by signal ${signal ?? \"unknown\"}`;\n this.log.warn({ requestId, exitCode, signal }, reason);\n finish(() => handlers.onError(reason, requestId));\n }\n });\n\n this.process.on(\"error\", (err) => {\n this.process = null;\n this.log.error({ err, requestId }, \"Claude process error\");\n finish(() => handlers.onError(err.message, requestId));\n });\n }\n\n /**\n * Parse a single NDJSON line from Claude CLI's stream-json output.\n *\n * The stream-json format can emit several event types. We look for content\n * in these known patterns (in priority order):\n *\n * 1. Raw Anthropic API event: { type: \"content_block_delta\", delta: { type: \"text_delta\"|\"thinking_delta\", text|thinking } }\n * 2. Wrapped stream event: { type: \"stream_event\", event: { type: \"content_block_delta\", ... } }\n * 3. Complete assistant msg: { type: \"assistant\", message: { content: [{ type: \"text\"|\"thinking\", text|thinking }] } }\n */\n private parseStreamLine(line: string, handlers: RunHandlers, requestId: string): void {\n if (!line.trim()) return;\n\n try {\n const event = JSON.parse(line);\n\n // Pattern 1: Raw content_block_delta\n if (event.type === \"content_block_delta\") {\n if (event.delta?.type === \"text_delta\" && event.delta.text) {\n handlers.onChunk(event.delta.text, requestId);\n } else if (event.delta?.type === \"thinking_delta\" && event.delta.thinking) {\n handlers.onChunk(event.delta.thinking, requestId, true);\n }\n return;\n }\n\n // Pattern 2: Wrapped in stream_event\n if (event.type === \"stream_event\" && event.event) {\n const inner = event.event;\n if (inner.type === \"content_block_delta\") {\n if (inner.delta?.type === \"text_delta\" && inner.delta.text) {\n handlers.onChunk(inner.delta.text, requestId);\n } else if (inner.delta?.type === \"thinking_delta\" && inner.delta.thinking) {\n handlers.onChunk(inner.delta.thinking, requestId, true);\n }\n }\n return;\n }\n\n // Pattern 3: Complete assistant message\n if (event.type === \"assistant\" && Array.isArray(event.message?.content)) {\n for (const block of event.message.content) {\n if (block.type === \"text\" && block.text) {\n handlers.onChunk(block.text, requestId);\n } else if (block.type === \"thinking\" && block.thinking) {\n handlers.onChunk(block.thinking, requestId, true);\n }\n }\n return;\n }\n\n // Result event \u2014 ignore (we already streamed the content)\n if (event.type === \"result\") {\n return;\n }\n } catch {\n // Non-JSON line, skip\n }\n }\n\n kill(): void {\n this.clearTimeout();\n if (this.process) {\n this.log.debug({ pid: this.process.pid }, \"Killing Claude process\");\n this.killed = true;\n try {\n this.process.kill();\n } catch {\n // Process may already be dead\n }\n this.process = null;\n }\n }\n\n dispose(): void {\n this.disposed = true;\n this.kill();\n }\n\n private clearTimeout(): void {\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n }\n}\n", "import { spawn, type ChildProcess } from \"node:child_process\";\nimport { mkdirSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport { createInterface } from \"node:readline\";\nimport type { Logger } from \"../utils/logger.js\";\nimport type { Runner, RunOptions, RunHandlers } from \"./claude-runner.js\";\n\nexport interface CodexRunnerOptions {\n codexPath?: string;\n timeoutMs?: number;\n logger: Logger;\n sessionDir?: string;\n}\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;\n\nexport class CodexRunner implements Runner {\n private process: ChildProcess | null = null;\n private timeout: NodeJS.Timeout | null = null;\n private disposed = false;\n private killed = false;\n private threadId: string | null = null;\n private readonly codexPath: string;\n private readonly timeoutMs: number;\n private readonly log: Logger;\n private readonly sessionDir: string;\n\n constructor(options: CodexRunnerOptions) {\n this.codexPath = options.codexPath ?? \"codex\";\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.log = options.logger;\n this.sessionDir = options.sessionDir ?? \"agent-ws-sessions\";\n }\n\n get isRunning(): boolean {\n return this.process !== null;\n }\n\n run(options: RunOptions, handlers: RunHandlers): void {\n if (this.disposed) {\n handlers.onError(\"Runner has been disposed\", options.requestId);\n return;\n }\n\n this.kill();\n\n const { prompt, model, systemPrompt, projectId, requestId } = options;\n\n // Build the full prompt: prepend system prompt since Codex doesn't have\n // a dedicated --append-system-prompt flag\n let fullPrompt = prompt;\n if (systemPrompt) {\n fullPrompt = `${systemPrompt}\\n\\n---\\n\\n${prompt}`;\n }\n\n // Resume existing thread if we have one and a projectId is set (session scoping)\n const resuming = projectId && this.threadId;\n const args: string[] = resuming\n ? [\"exec\", \"resume\", this.threadId!, \"--json\", \"--full-auto\", \"--skip-git-repo-check\"]\n : [\"exec\", \"--json\", \"--full-auto\", \"--skip-git-repo-check\"];\n if (model && !resuming) {\n args.push(\"--model\", model);\n }\n // Read prompt from stdin\n args.push(\"-\");\n\n this.log.info({ requestId, model, promptLength: prompt.length }, \"Spawning Codex process\");\n this.killed = false;\n\n let cwd: string | undefined;\n if (projectId) {\n const base = resolve(tmpdir(), this.sessionDir);\n cwd = resolve(base, projectId);\n if (!cwd.startsWith(base + \"/\") && cwd !== base) {\n handlers.onError(\"Invalid projectId\", requestId);\n return;\n }\n mkdirSync(cwd, { recursive: true });\n }\n\n const ALLOWED_ENV_KEYS = [\n \"PATH\", \"HOME\", \"USER\", \"SHELL\", \"TERM\", \"LANG\", \"LC_ALL\",\n \"OPENAI_API_KEY\", \"NODE_PATH\", \"XDG_CONFIG_HOME\",\n ];\n const env: Record<string, string> = {};\n for (const key of ALLOWED_ENV_KEYS) {\n if (process.env[key]) env[key] = process.env[key]!;\n }\n\n try {\n this.process = spawn(this.codexPath, args, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n cwd,\n env,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Failed to start Codex\";\n this.log.error({ err, requestId }, \"Failed to spawn Codex process\");\n handlers.onError(message, requestId);\n return;\n }\n\n this.log.debug({ pid: this.process.pid, requestId }, \"Codex process spawned\");\n\n if (this.process.stdin) {\n this.process.stdin.write(fullPrompt);\n this.process.stdin.end();\n }\n\n // Guard against double handler invocation (e.g. error + exit both firing)\n let handlersDone = false;\n const finish = (cb: () => void) => {\n if (handlersDone) return;\n handlersDone = true;\n this.clearTimeout();\n cb();\n };\n\n this.timeout = setTimeout(() => {\n this.log.warn({ requestId }, \"Codex process timed out\");\n this.kill();\n finish(() => handlers.onError(\"Process timed out\", requestId));\n }, this.timeoutMs);\n\n if (this.process.stdout) {\n const rl = createInterface({ input: this.process.stdout });\n rl.on(\"line\", (line) => {\n this.parseStreamLine(line, handlers, requestId);\n });\n }\n\n if (this.process.stderr) {\n const stderrRl = createInterface({ input: this.process.stderr });\n stderrRl.on(\"line\", (line) => {\n if (line.trim()) {\n this.log.warn({ requestId, stderr: line }, \"Codex stderr\");\n }\n });\n }\n\n this.process.on(\"exit\", (exitCode, signal) => {\n this.process = null;\n\n if (this.killed) {\n this.log.debug({ requestId }, \"Codex process was killed\");\n return;\n }\n\n if (exitCode === 0) {\n this.log.info({ requestId }, \"Codex process completed successfully\");\n finish(() => handlers.onComplete(requestId));\n } else {\n const reason = exitCode !== null\n ? `Codex CLI exited with code ${exitCode}`\n : `Codex CLI killed by signal ${signal ?? \"unknown\"}`;\n this.log.warn({ requestId, exitCode, signal }, reason);\n finish(() => handlers.onError(reason, requestId));\n }\n });\n\n this.process.on(\"error\", (err) => {\n this.process = null;\n this.log.error({ err, requestId }, \"Codex process error\");\n finish(() => handlers.onError(err.message, requestId));\n });\n }\n\n /**\n * Parse JSONL output from `codex exec --json`.\n *\n * Event format (one JSON object per line):\n * { type: \"thread.started\", thread_id }\n * { type: \"turn.started\" }\n * { type: \"item.started\", item: { id, type, ... } }\n * { type: \"item.completed\", item: { id, type: \"agent_message\", text } }\n * { type: \"item.completed\", item: { id, type: \"command_execution\", command, exit_code } }\n * { type: \"turn.completed\", usage: { input_tokens, output_tokens, ... } }\n */\n private parseStreamLine(line: string, handlers: RunHandlers, requestId: string): void {\n if (!line.trim()) return;\n\n try {\n const event = JSON.parse(line);\n\n // Capture thread_id for session resumption\n if (event.type === \"thread.started\" && event.thread_id) {\n this.threadId = event.thread_id;\n this.log.debug({ threadId: this.threadId, requestId }, \"Captured Codex thread ID\");\n return;\n }\n\n // Agent message \u2014 the actual text content we want to stream\n if (event.type === \"item.completed\" && event.item?.type === \"agent_message\" && event.item.text) {\n handlers.onChunk(event.item.text, requestId);\n return;\n }\n\n // Reasoning trace \u2014 forward as thinking\n if (event.type === \"item.completed\" && event.item?.type === \"reasoning\" && event.item.text) {\n handlers.onChunk(event.item.text, requestId, true);\n return;\n }\n\n // Turn failed \u2014 surface as error\n if (event.type === \"turn.failed\") {\n const msg = event.error?.message || event.message || \"Codex turn failed\";\n handlers.onError(msg, requestId);\n return;\n }\n\n // error event\n if (event.type === \"error\") {\n const msg = event.message || event.error?.message || \"Codex error\";\n handlers.onError(msg, requestId);\n return;\n }\n } catch {\n // Non-JSON line, skip\n }\n }\n\n kill(): void {\n this.clearTimeout();\n if (this.process) {\n this.log.debug({ pid: this.process.pid }, \"Killing Codex process\");\n this.killed = true;\n try {\n this.process.kill();\n } catch {\n // Process may already be dead\n }\n this.process = null;\n }\n }\n\n dispose(): void {\n this.disposed = true;\n this.kill();\n }\n\n private clearTimeout(): void {\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n }\n}\n", "// Maximum prompt size: 512KB\nconst MAX_PROMPT_BYTES = 512 * 1024;\n// Maximum system prompt size: 64KB\nconst MAX_SYSTEM_PROMPT_BYTES = 64 * 1024;\n// Maximum projectId length\nconst MAX_PROJECT_ID_LENGTH = 128;\n// Allowed projectId characters: alphanumeric, hyphens, underscores, dots\nconst PROJECT_ID_PATTERN = /^[a-zA-Z0-9._-]+$/;\n\n// --- Client \u2192 Agent messages ---\n\nexport interface PromptMessage {\n type: \"prompt\";\n prompt: string;\n model?: string;\n systemPrompt?: string;\n projectId?: string;\n requestId: string;\n provider?: \"claude\" | \"codex\";\n thinkingTokens?: number;\n}\n\nexport interface CancelMessage {\n type: \"cancel\";\n requestId?: string;\n}\n\nexport type ClientMessage = PromptMessage | CancelMessage;\n\n// --- Agent \u2192 Client messages ---\n\nexport interface ConnectedMessage {\n type: \"connected\";\n version: string;\n agent: string;\n}\n\nexport interface ChunkMessage {\n type: \"chunk\";\n content: string;\n requestId: string;\n thinking?: boolean;\n}\n\nexport interface CompleteMessage {\n type: \"complete\";\n requestId: string;\n}\n\nexport interface ErrorMessage {\n type: \"error\";\n message: string;\n requestId?: string;\n}\n\nexport type AgentMessage =\n | ConnectedMessage\n | ChunkMessage\n | CompleteMessage\n | ErrorMessage;\n\n// --- Parsing & validation ---\n\nexport type ParseResult =\n | { ok: true; message: ClientMessage }\n | { ok: false; error: string };\n\nexport function parseClientMessage(raw: string): ParseResult {\n let data: unknown;\n\n try {\n data = JSON.parse(raw);\n } catch {\n return { ok: false, error: \"Invalid JSON\" };\n }\n\n if (typeof data !== \"object\" || data === null || Array.isArray(data)) {\n return { ok: false, error: \"Message must be a JSON object\" };\n }\n\n const obj = data as Record<string, unknown>;\n const type = obj[\"type\"];\n\n if (typeof type !== \"string\") {\n return { ok: false, error: \"Missing or invalid 'type' field\" };\n }\n\n switch (type) {\n case \"prompt\": {\n const prompt = obj[\"prompt\"];\n if (typeof prompt !== \"string\" || prompt.length === 0) {\n return { ok: false, error: \"Missing or empty 'prompt' field\" };\n }\n\n if (new TextEncoder().encode(prompt).byteLength > MAX_PROMPT_BYTES) {\n return { ok: false, error: `Prompt exceeds maximum size of ${MAX_PROMPT_BYTES} bytes` };\n }\n\n const requestId = obj[\"requestId\"];\n if (typeof requestId !== \"string\" || requestId.length === 0) {\n return { ok: false, error: \"Missing or empty 'requestId' field\" };\n }\n\n const model = obj[\"model\"];\n const systemPrompt = obj[\"systemPrompt\"];\n const projectId = obj[\"projectId\"];\n const provider = obj[\"provider\"];\n const thinkingTokens = obj[\"thinkingTokens\"];\n\n if (typeof systemPrompt === \"string\" && new TextEncoder().encode(systemPrompt).byteLength > MAX_SYSTEM_PROMPT_BYTES) {\n return { ok: false, error: `System prompt exceeds maximum size of ${MAX_SYSTEM_PROMPT_BYTES} bytes` };\n }\n\n if (typeof projectId === \"string\") {\n if (projectId.length > MAX_PROJECT_ID_LENGTH) {\n return { ok: false, error: `projectId exceeds maximum length of ${MAX_PROJECT_ID_LENGTH}` };\n }\n if (!PROJECT_ID_PATTERN.test(projectId)) {\n return { ok: false, error: \"projectId contains invalid characters (allowed: alphanumeric, hyphens, underscores, dots)\" };\n }\n }\n\n return {\n ok: true,\n message: {\n type: \"prompt\",\n prompt,\n model: typeof model === \"string\" ? model : undefined,\n systemPrompt: typeof systemPrompt === \"string\" ? systemPrompt : undefined,\n projectId: typeof projectId === \"string\" ? projectId : undefined,\n requestId,\n provider: provider === \"codex\" ? \"codex\" : \"claude\",\n thinkingTokens: typeof thinkingTokens === \"number\" && thinkingTokens >= 0 ? thinkingTokens : undefined,\n },\n };\n }\n\n case \"cancel\": {\n const requestId = obj[\"requestId\"];\n return {\n ok: true,\n message: {\n type: \"cancel\",\n requestId: typeof requestId === \"string\" ? requestId : undefined,\n },\n };\n }\n\n default:\n return { ok: false, error: `Unknown message type: ${String(type).slice(0, 50)}` };\n }\n}\n\n// --- Serialization ---\n\nexport function serializeMessage(message: AgentMessage): string {\n return JSON.stringify(message);\n}\n", "import pino from \"pino\";\n\nexport interface LoggerOptions {\n level?: string;\n pretty?: boolean;\n}\n\nexport function createLogger(options: LoggerOptions = {}): pino.Logger {\n const { level = \"info\", pretty = process.env[\"NODE_ENV\"] !== \"production\" } = options;\n\n if (pretty) {\n try {\n return pino({\n level,\n transport: {\n target: \"pino-pretty\",\n options: {\n colorize: true,\n translateTime: \"HH:MM:ss\",\n ignore: \"pid,hostname\",\n },\n },\n });\n } catch {\n // pino-pretty not available, fall back to plain JSON logging\n }\n }\n\n return pino({ level });\n}\n\nexport type Logger = pino.Logger;\n", "import { AgentWebSocketServer, type AgentWebSocketServerOptions, type RunnerFactory } from \"./server/websocket.js\";\nimport { createLogger, type Logger } from \"./utils/logger.js\";\n\nexport interface AgentWSOptions {\n port?: number;\n host?: string;\n claudePath?: string;\n codexPath?: string;\n timeoutMs?: number;\n logLevel?: string;\n allowedOrigins?: string[];\n runnerFactory?: RunnerFactory;\n agentName?: string;\n sessionDir?: string;\n}\n\nexport class AgentWS {\n private server: AgentWebSocketServer;\n private readonly log: Logger;\n\n constructor(options: AgentWSOptions = {}) {\n this.log = createLogger({ level: options.logLevel ?? \"info\" });\n\n const serverOptions: AgentWebSocketServerOptions = {\n port: options.port ?? 9999,\n host: options.host ?? \"localhost\",\n logger: this.log,\n claudePath: options.claudePath,\n codexPath: options.codexPath,\n timeoutMs: options.timeoutMs,\n allowedOrigins: options.allowedOrigins,\n runnerFactory: options.runnerFactory,\n agentName: options.agentName,\n sessionDir: options.sessionDir,\n };\n\n this.server = new AgentWebSocketServer(serverOptions);\n }\n\n async start(): Promise<void> {\n await this.server.start();\n }\n\n stop(): void {\n this.server.stop();\n }\n}\n", "import { execFileSync } from \"node:child_process\";\n\nexport interface ClaudeCheckResult {\n available: boolean;\n version?: string;\n error?: string;\n}\n\nexport function checkClaudeCli(claudePath: string = \"claude\"): ClaudeCheckResult {\n try {\n const output = execFileSync(claudePath, [\"--version\"], {\n timeout: 5000,\n stdio: \"pipe\",\n encoding: \"utf-8\",\n });\n\n return {\n available: true,\n version: output.trim(),\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Unknown error\";\n return {\n available: false,\n error: message,\n };\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { Command } from \"commander\";\nimport { AgentWS } from \"./agent.js\";\nimport { checkCli } from \"./utils/claude-check.js\";\n\ndeclare const PKG_VERSION: string;\nconst VERSION = typeof PKG_VERSION !== \"undefined\" ? PKG_VERSION : \"0.0.0-dev\";\n\nconst program = new Command();\n\nprogram\n .name(\"agent-ws\")\n .description(\"WebSocket bridge for CLI AI agents (Claude, Codex)\")\n .version(VERSION)\n .option(\"-p, --port <port>\", \"WebSocket server port\", \"9999\")\n .option(\"-H, --host <host>\", \"WebSocket server host\", \"localhost\")\n .option(\"-c, --claude-path <path>\", \"Path to Claude CLI\", \"claude\")\n .option(\"--codex-path <path>\", \"Path to Codex CLI\", \"codex\")\n .option(\"-t, --timeout <seconds>\", \"Process timeout in seconds\", \"300\")\n .option(\"--log-level <level>\", \"Log level (debug, info, warn, error)\", \"info\")\n .option(\"--origins <origins>\", \"Comma-separated allowed origins\")\n .action(async (opts: {\n port: string;\n host: string;\n claudePath: string;\n codexPath: string;\n timeout: string;\n logLevel: string;\n origins?: string;\n }) => {\n // Banner\n console.log(`\n\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n\u2551 agent-ws v${VERSION.padEnd(20)}\u2551\n\u2551 CLI AI Agent Bridge \u2551\n\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\n`);\n\n // Check Claude CLI\n const check = checkCli(opts.claudePath);\n if (!check.available) {\n console.error(`Claude CLI not found at: ${opts.claudePath}`);\n console.error(\"Make sure Claude Code is installed and in your PATH.\");\n console.error(\"Install: npm install -g @anthropic-ai/claude-code\");\n console.error(`Or specify path: agent-ws --claude-path /path/to/claude`);\n process.exit(1);\n }\n console.log(`Found Claude CLI: ${check.version}`);\n\n // Check Codex CLI (optional \u2014 just warn if missing)\n const codexCheck = checkCli(opts.codexPath);\n if (codexCheck.available) {\n console.log(`Found Codex CLI: ${codexCheck.version}`);\n } else {\n console.log(\"Codex CLI not found (codex provider will be unavailable)\");\n }\n\n const port = parseInt(opts.port, 10);\n if (isNaN(port) || port < 1 || port > 65535) {\n console.error(`Invalid port: ${opts.port} (must be 1\u201365535)`);\n process.exit(1);\n }\n\n const timeoutSeconds = parseInt(opts.timeout, 10);\n if (isNaN(timeoutSeconds) || timeoutSeconds < 1 || timeoutSeconds > 3600) {\n console.error(`Invalid timeout: ${opts.timeout} (must be 1\u20133600 seconds)`);\n process.exit(1);\n }\n const timeoutMs = timeoutSeconds * 1000;\n\n const allowedOrigins = opts.origins?.split(\",\").map((o) => o.trim()).filter(Boolean);\n if (allowedOrigins) {\n for (const origin of allowedOrigins) {\n try {\n new URL(origin);\n } catch {\n console.error(`Invalid origin: \"${origin}\" (must be a valid URL, e.g. https://example.com)`);\n process.exit(1);\n }\n }\n }\n\n const agent = new AgentWS({\n port,\n host: opts.host,\n claudePath: opts.claudePath,\n codexPath: opts.codexPath,\n timeoutMs,\n logLevel: opts.logLevel,\n allowedOrigins,\n });\n\n try {\n await agent.start();\n } catch (err) {\n if (err instanceof Error && \"code\" in err && (err as NodeJS.ErrnoException).code === \"EADDRINUSE\") {\n console.error(`Port ${port} is already in use.`);\n console.error(\"Another instance of agent-ws might be running.\");\n }\n process.exit(1);\n }\n\n console.log(`agent-ws running on ws://${opts.host}:${port}`);\n console.log(\"Waiting for connections...\\n\");\n console.log(\"Press Ctrl+C to stop\\n\");\n\n // Graceful shutdown\n const shutdown = () => {\n agent.stop();\n console.log(\"\\nagent-ws stopped\");\n process.exit(0);\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n });\n\nprogram.parse();\n", "import { WebSocketServer, WebSocket } from \"ws\";\nimport type { IncomingMessage } from \"node:http\";\nimport { ClaudeRunner, type ClaudeRunnerOptions, type Runner, type RunHandlers } from \"../process/claude-runner.js\";\nimport { CodexRunner } from \"../process/codex-runner.js\";\nimport {\n parseClientMessage,\n serializeMessage,\n type AgentMessage,\n type PromptMessage,\n} from \"./protocol.js\";\nimport type { Logger } from \"../utils/logger.js\";\n\nconst HEARTBEAT_INTERVAL_MS = 30_000;\nconst DEFAULT_MAX_PAYLOAD = 50 * 1024 * 1024; // 50MB (images can be large)\n\nexport type RunnerFactory = (log: Logger) => Runner;\n\ninterface ConnectionState {\n claudeRunner: Runner | null;\n codexRunner: Runner | null;\n activeRunner: Runner | null;\n isAlive: boolean;\n activeRequestId: string | null;\n}\n\nexport interface AgentWebSocketServerOptions {\n port: number;\n host: string;\n logger: Logger;\n claudePath?: string;\n codexPath?: string;\n timeoutMs?: number;\n allowedOrigins?: string[];\n maxPayload?: number;\n /** @deprecated Use claudeRunnerFactory instead */\n runnerFactory?: RunnerFactory;\n claudeRunnerFactory?: RunnerFactory;\n codexRunnerFactory?: RunnerFactory;\n agentName?: string;\n sessionDir?: string;\n}\n\nexport class AgentWebSocketServer {\n private wss: WebSocketServer | null = null;\n private heartbeatInterval: NodeJS.Timeout | null = null;\n private readonly connections = new Map<WebSocket, ConnectionState>();\n private readonly log: Logger;\n private readonly options: AgentWebSocketServerOptions;\n\n constructor(options: AgentWebSocketServerOptions) {\n this.options = options;\n this.log = options.logger;\n }\n\n start(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.wss = new WebSocketServer({\n port: this.options.port,\n host: this.options.host,\n maxPayload: this.options.maxPayload ?? DEFAULT_MAX_PAYLOAD,\n });\n\n this.wss.on(\"listening\", () => {\n this.log.info({ port: this.options.port, host: this.options.host }, \"WebSocket server started\");\n this.startHeartbeat();\n resolve();\n });\n\n this.wss.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n this.log.fatal({ port: this.options.port }, \"Port already in use\");\n } else {\n this.log.error({ err }, \"WebSocket server error\");\n }\n reject(err);\n });\n\n this.wss.on(\"connection\", (ws, req) => this.handleConnection(ws, req));\n });\n }\n\n stop(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = null;\n }\n\n for (const [ws, state] of this.connections) {\n state.claudeRunner?.dispose();\n state.codexRunner?.dispose();\n ws.terminate();\n }\n this.connections.clear();\n\n if (this.wss) {\n this.wss.close();\n this.wss = null;\n }\n\n this.log.info(\"WebSocket server stopped\");\n }\n\n private handleConnection(ws: WebSocket, req: IncomingMessage): void {\n // Origin check\n if (this.options.allowedOrigins && this.options.allowedOrigins.length > 0) {\n const origin = req.headers.origin;\n if (!origin || !this.options.allowedOrigins.includes(origin)) {\n this.log.warn({ origin: origin ?? \"(none)\" }, \"Rejected connection: origin not in allowlist\");\n ws.close(4003, \"Origin not allowed\");\n return;\n }\n }\n\n const clientIp = req.socket.remoteAddress;\n this.log.info({ clientIp }, \"Client connected\");\n\n const state: ConnectionState = { claudeRunner: null, codexRunner: null, activeRunner: null, isAlive: true, activeRequestId: null };\n this.connections.set(ws, state);\n\n // Send connected message\n this.sendMessage(ws, {\n type: \"connected\",\n version: \"1.0\",\n agent: this.options.agentName ?? \"agent-ws\",\n });\n\n ws.on(\"pong\", () => {\n state.isAlive = true;\n });\n\n ws.on(\"message\", (data) => {\n const raw = data.toString();\n this.handleMessage(ws, state, raw);\n });\n\n ws.on(\"close\", () => {\n this.log.info({ clientIp }, \"Client disconnected\");\n state.claudeRunner?.dispose();\n state.codexRunner?.dispose();\n this.connections.delete(ws);\n });\n\n ws.on(\"error\", (err) => {\n this.log.error({ err, clientIp }, \"WebSocket error\");\n });\n }\n\n private handleMessage(ws: WebSocket, state: ConnectionState, raw: string): void {\n const result = parseClientMessage(raw);\n\n if (!result.ok) {\n this.sendMessage(ws, { type: \"error\", message: result.error });\n return;\n }\n\n const { message } = result;\n\n switch (message.type) {\n case \"prompt\":\n this.handlePrompt(ws, state, message);\n break;\n case \"cancel\":\n this.handleCancel(ws, state);\n break;\n }\n }\n\n private handlePrompt(ws: WebSocket, state: ConnectionState, message: PromptMessage): void {\n if (state.activeRequestId !== null) {\n this.sendMessage(ws, {\n type: \"error\",\n message: \"Request already in progress\",\n requestId: message.requestId,\n });\n return;\n }\n\n state.activeRequestId = message.requestId;\n\n // Select runner for the requested provider (lazy-created, preserved across switches)\n if (message.provider === \"codex\") {\n if (!state.codexRunner) {\n state.codexRunner = this.createCodexRunner();\n }\n state.activeRunner = state.codexRunner;\n } else {\n if (!state.claudeRunner) {\n state.claudeRunner = this.createClaudeRunner();\n }\n state.activeRunner = state.claudeRunner;\n }\n\n const handlers: RunHandlers = {\n onChunk: (content, requestId, thinking) => {\n try {\n this.sendMessage(ws, { type: \"chunk\", content, requestId, ...(thinking ? { thinking: true } : {}) });\n } catch (err) {\n this.log.warn({ err, requestId }, \"Error in onChunk handler\");\n }\n },\n onComplete: (requestId) => {\n try {\n state.activeRequestId = null;\n this.sendMessage(ws, { type: \"complete\", requestId });\n } catch (err) {\n this.log.warn({ err, requestId }, \"Error in onComplete handler\");\n }\n },\n onError: (errorMessage, requestId) => {\n try {\n state.activeRequestId = null;\n this.sendMessage(ws, { type: \"error\", message: errorMessage, requestId });\n } catch (err) {\n this.log.warn({ err, requestId }, \"Error in onError handler\");\n }\n },\n };\n\n state.activeRunner!.run(\n {\n prompt: message.prompt,\n model: message.model,\n systemPrompt: message.systemPrompt,\n projectId: message.projectId,\n requestId: message.requestId,\n thinkingTokens: message.thinkingTokens,\n images: message.images,\n },\n handlers,\n );\n }\n\n private handleCancel(ws: WebSocket, state: ConnectionState): void {\n const requestId = state.activeRequestId;\n state.activeRunner?.kill();\n state.activeRequestId = null;\n\n if (requestId) {\n this.sendMessage(ws, { type: \"error\", message: \"Request cancelled\", requestId });\n }\n this.log.info({ requestId }, \"Request cancelled\");\n }\n\n private sendMessage(ws: WebSocket, message: AgentMessage): void {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(serializeMessage(message));\n } else {\n this.log.warn({ messageType: message.type, readyState: ws.readyState }, \"Dropping message, WebSocket not OPEN\");\n }\n }\n\n private createClaudeRunner(): Runner {\n const factory = this.options.claudeRunnerFactory ?? this.options.runnerFactory;\n if (factory) {\n return factory(this.log);\n }\n\n return new ClaudeRunner({\n claudePath: this.options.claudePath,\n timeoutMs: this.options.timeoutMs,\n logger: this.log.child({ component: \"claude-runner\" }),\n sessionDir: this.options.sessionDir,\n });\n }\n\n private createCodexRunner(): Runner {\n if (this.options.codexRunnerFactory) {\n return this.options.codexRunnerFactory(this.log);\n }\n\n return new CodexRunner({\n codexPath: this.options.codexPath,\n timeoutMs: this.options.timeoutMs,\n logger: this.log.child({ component: \"codex-runner\" }),\n sessionDir: this.options.sessionDir,\n });\n }\n\n private startHeartbeat(): void {\n this.heartbeatInterval = setInterval(() => {\n for (const [ws, state] of this.connections) {\n if (!state.isAlive) {\n this.log.debug(\"Terminating dead connection\");\n state.claudeRunner?.dispose();\n state.codexRunner?.dispose();\n this.connections.delete(ws);\n ws.terminate();\n continue;\n }\n\n state.isAlive = false;\n try {\n ws.ping();\n } catch {\n this.log.debug(\"Ping failed, terminating connection\");\n state.claudeRunner?.dispose();\n state.codexRunner?.dispose();\n this.connections.delete(ws);\n ws.terminate();\n }\n }\n }, HEARTBEAT_INTERVAL_MS);\n }\n}\n", "import { spawn, type ChildProcess } from \"node:child_process\";\nimport { mkdirSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport { createInterface } from \"node:readline\";\nimport type { Logger } from \"../utils/logger.js\";\nimport type { PromptImage } from \"../server/protocol.js\";\n\nexport interface RunOptions {\n prompt: string;\n model?: string;\n systemPrompt?: string;\n projectId?: string;\n requestId: string;\n thinkingTokens?: number;\n images?: PromptImage[];\n}\n\nexport interface RunHandlers {\n onChunk: (content: string, requestId: string, thinking?: boolean) => void;\n onComplete: (requestId: string) => void;\n onError: (message: string, requestId: string) => void;\n}\n\n/** Interface for runner injection (testing) */\nexport interface Runner {\n run(options: RunOptions, handlers: RunHandlers): void;\n kill(): void;\n dispose(): void;\n}\n\nexport interface ClaudeRunnerOptions {\n claudePath?: string;\n timeoutMs?: number;\n logger: Logger;\n sessionDir?: string;\n}\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\n\nexport class ClaudeRunner implements Runner {\n private process: ChildProcess | null = null;\n private timeout: NodeJS.Timeout | null = null;\n private disposed = false;\n private killed = false;\n private readonly claudePath: string;\n private readonly timeoutMs: number;\n private readonly log: Logger;\n private readonly sessionDir: string;\n\n constructor(options: ClaudeRunnerOptions) {\n this.claudePath = options.claudePath ?? \"claude\";\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.log = options.logger;\n this.sessionDir = options.sessionDir ?? \"agent-ws-sessions\";\n }\n\n get isRunning(): boolean {\n return this.process !== null;\n }\n\n run(options: RunOptions, handlers: RunHandlers): void {\n if (this.disposed) {\n handlers.onError(\"Runner has been disposed\", options.requestId);\n return;\n }\n\n // Kill any existing process first\n this.kill();\n\n const { prompt, model, systemPrompt, projectId, requestId, thinkingTokens, images } = options;\n const hasImages = images && images.length > 0;\n\n const args = [\n \"--print\",\n \"--verbose\",\n \"--output-format\", \"stream-json\",\n \"--max-turns\", \"1\", // Single-turn text output, no agentic loops\n \"--tools\", \"\", // Disable tool use \u2014 we only want generated text\n ];\n // Use stream-json input when images are present (supports content blocks)\n if (hasImages) {\n args.push(\"--input-format\", \"stream-json\");\n }\n // Only resume session when a projectId is provided (scoped by CWD)\n if (projectId) {\n args.push(\"--continue\");\n }\n if (model) {\n args.push(\"--model\", model);\n }\n if (systemPrompt) {\n args.push(\"--append-system-prompt\", systemPrompt);\n }\n // Prompt is piped via stdin (no arg length limits, no flag-parsing issues)\n args.push(\"-\");\n\n this.log.info({ requestId, model, promptLength: prompt.length }, \"Spawning Claude process\");\n this.killed = false;\n\n // Use project-scoped CWD so --continue resumes the correct session\n // (Claude CLI scopes sessions by working directory)\n let cwd: string | undefined;\n if (projectId) {\n const base = resolve(tmpdir(), this.sessionDir);\n cwd = resolve(base, projectId);\n if (!cwd.startsWith(base + \"/\") && cwd !== base) {\n handlers.onError(\"Invalid projectId\", requestId);\n return;\n }\n mkdirSync(cwd, { recursive: true });\n }\n\n try {\n const ALLOWED_ENV_KEYS = [\n \"PATH\", \"HOME\", \"USER\", \"SHELL\", \"TERM\", \"LANG\", \"LC_ALL\",\n \"ANTHROPIC_API_KEY\", \"NODE_PATH\", \"XDG_CONFIG_HOME\",\n ];\n const env: Record<string, string> = {};\n if (thinkingTokens !== undefined) {\n env[\"MAX_THINKING_TOKENS\"] = String(thinkingTokens);\n }\n for (const key of ALLOWED_ENV_KEYS) {\n if (process.env[key]) env[key] = process.env[key]!;\n }\n\n this.process = spawn(this.claudePath, args, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n cwd,\n env,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Failed to start Claude\";\n this.log.error({ err, requestId }, \"Failed to spawn Claude process\");\n handlers.onError(message, requestId);\n return;\n }\n\n this.log.debug({ pid: this.process.pid, requestId }, \"Claude process spawned\");\n\n // Write prompt to stdin and close it\n if (this.process.stdin) {\n if (hasImages) {\n // stream-json input: structured message with image content blocks\n const content: Array<Record<string, unknown>> = [];\n for (const img of images!) {\n content.push({\n type: \"image\",\n source: { type: \"base64\", media_type: img.media_type, data: img.data },\n });\n }\n content.push({ type: \"text\", text: prompt });\n const msg = JSON.stringify({ type: \"user\", message: { role: \"user\", content } });\n this.process.stdin.write(msg + \"\\n\");\n } else {\n this.process.stdin.write(prompt);\n }\n this.process.stdin.end();\n }\n\n // Guard against double handler invocation (e.g. error + exit both firing)\n let handlersDone = false;\n const finish = (cb: () => void) => {\n if (handlersDone) return;\n handlersDone = true;\n this.clearTimeout();\n cb();\n };\n\n // Set up timeout\n this.timeout = setTimeout(() => {\n this.log.warn({ requestId }, \"Claude process timed out\");\n this.kill();\n finish(() => handlers.onError(\"Process timed out\", requestId));\n }, this.timeoutMs);\n\n // Parse NDJSON from stdout\n if (this.process.stdout) {\n const rl = createInterface({ input: this.process.stdout });\n rl.on(\"line\", (line) => {\n this.parseStreamLine(line, handlers, requestId);\n });\n }\n\n // Capture stderr \u2014 logs at warn level so errors are visible\n if (this.process.stderr) {\n const stderrRl = createInterface({ input: this.process.stderr });\n stderrRl.on(\"line\", (line) => {\n if (line.trim()) {\n this.log.warn({ requestId, stderr: line }, \"Claude stderr\");\n }\n });\n }\n\n // Handle exit\n this.process.on(\"exit\", (exitCode, signal) => {\n this.process = null;\n\n if (this.killed) {\n this.log.debug({ requestId }, \"Claude process was killed\");\n return;\n }\n\n if (exitCode === 0) {\n this.log.info({ requestId }, \"Claude process completed successfully\");\n finish(() => handlers.onComplete(requestId));\n } else {\n const reason = exitCode !== null\n ? `Claude CLI exited with code ${exitCode}`\n : `Claude CLI killed by signal ${signal ?? \"unknown\"}`;\n this.log.warn({ requestId, exitCode, signal }, reason);\n finish(() => handlers.onError(reason, requestId));\n }\n });\n\n this.process.on(\"error\", (err) => {\n this.process = null;\n this.log.error({ err, requestId }, \"Claude process error\");\n finish(() => handlers.onError(err.message, requestId));\n });\n }\n\n /**\n * Parse a single NDJSON line from Claude CLI's stream-json output.\n *\n * The stream-json format can emit several event types. We look for content\n * in these known patterns (in priority order):\n *\n * 1. Raw Anthropic API event: { type: \"content_block_delta\", delta: { type: \"text_delta\"|\"thinking_delta\", text|thinking } }\n * 2. Wrapped stream event: { type: \"stream_event\", event: { type: \"content_block_delta\", ... } }\n * 3. Complete assistant msg: { type: \"assistant\", message: { content: [{ type: \"text\"|\"thinking\", text|thinking }] } }\n */\n private parseStreamLine(line: string, handlers: RunHandlers, requestId: string): void {\n if (!line.trim()) return;\n\n try {\n const event = JSON.parse(line);\n\n // Pattern 1: Raw content_block_delta\n if (event.type === \"content_block_delta\") {\n if (event.delta?.type === \"text_delta\" && event.delta.text) {\n handlers.onChunk(event.delta.text, requestId);\n } else if (event.delta?.type === \"thinking_delta\" && event.delta.thinking) {\n handlers.onChunk(event.delta.thinking, requestId, true);\n }\n return;\n }\n\n // Pattern 2: Wrapped in stream_event\n if (event.type === \"stream_event\" && event.event) {\n const inner = event.event;\n if (inner.type === \"content_block_delta\") {\n if (inner.delta?.type === \"text_delta\" && inner.delta.text) {\n handlers.onChunk(inner.delta.text, requestId);\n } else if (inner.delta?.type === \"thinking_delta\" && inner.delta.thinking) {\n handlers.onChunk(inner.delta.thinking, requestId, true);\n }\n }\n return;\n }\n\n // Pattern 3: Complete assistant message\n if (event.type === \"assistant\" && Array.isArray(event.message?.content)) {\n for (const block of event.message.content) {\n if (block.type === \"text\" && block.text) {\n handlers.onChunk(block.text, requestId);\n } else if (block.type === \"thinking\" && block.thinking) {\n handlers.onChunk(block.thinking, requestId, true);\n }\n }\n return;\n }\n\n // Result event \u2014 ignore (we already streamed the content)\n if (event.type === \"result\") {\n return;\n }\n } catch {\n // Non-JSON line, skip\n }\n }\n\n kill(): void {\n this.clearTimeout();\n if (this.process) {\n this.log.debug({ pid: this.process.pid }, \"Killing Claude process\");\n this.killed = true;\n try {\n this.process.kill();\n } catch {\n // Process may already be dead\n }\n this.process = null;\n }\n }\n\n dispose(): void {\n this.disposed = true;\n this.kill();\n }\n\n private clearTimeout(): void {\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n }\n}\n", "import { spawn, type ChildProcess } from \"node:child_process\";\nimport { mkdirSync, writeFileSync, unlinkSync } from \"node:fs\";\nimport { resolve, join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport { createInterface } from \"node:readline\";\nimport type { Logger } from \"../utils/logger.js\";\nimport type { Runner, RunOptions, RunHandlers } from \"./claude-runner.js\";\n\nexport interface CodexRunnerOptions {\n codexPath?: string;\n timeoutMs?: number;\n logger: Logger;\n sessionDir?: string;\n}\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;\n\nexport class CodexRunner implements Runner {\n private process: ChildProcess | null = null;\n private timeout: NodeJS.Timeout | null = null;\n private disposed = false;\n private killed = false;\n private threadId: string | null = null;\n private readonly codexPath: string;\n private readonly timeoutMs: number;\n private readonly log: Logger;\n private readonly sessionDir: string;\n\n constructor(options: CodexRunnerOptions) {\n this.codexPath = options.codexPath ?? \"codex\";\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.log = options.logger;\n this.sessionDir = options.sessionDir ?? \"agent-ws-sessions\";\n }\n\n get isRunning(): boolean {\n return this.process !== null;\n }\n\n run(options: RunOptions, handlers: RunHandlers): void {\n if (this.disposed) {\n handlers.onError(\"Runner has been disposed\", options.requestId);\n return;\n }\n\n this.kill();\n\n // Note: thinkingTokens is intentionally not used \u2014 Codex does not support thinking tokens\n const { prompt, model, systemPrompt, projectId, requestId, images } = options;\n\n // Build the full prompt: prepend system prompt since Codex doesn't have\n // a dedicated --append-system-prompt flag\n let fullPrompt = prompt;\n if (systemPrompt) {\n fullPrompt = `${systemPrompt}\\n\\n---\\n\\n${prompt}`;\n }\n\n // Write images to temp files for the -i flag\n const imagePaths: string[] = [];\n if (images && images.length > 0) {\n const imgDir = resolve(tmpdir(), \"agent-ws-images\");\n mkdirSync(imgDir, { recursive: true });\n // Sanitize requestId for safe use in filenames (strip anything that isn't alphanumeric/hyphen/underscore)\n const safeId = requestId.replace(/[^a-zA-Z0-9_-]/g, \"_\").slice(0, 64);\n for (let i = 0; i < images.length; i++) {\n const img = images[i]!;\n const rawExt = img.media_type.split(\"/\")[1] || \"png\";\n const ext = rawExt.replace(/[^a-zA-Z0-9]/g, \"\").slice(0, 10) || \"png\";\n const imgPath = join(imgDir, `${safeId}-${i}.${ext}`);\n writeFileSync(imgPath, Buffer.from(img.data, \"base64\"));\n imagePaths.push(imgPath);\n }\n }\n\n // Resume existing thread if we have one and a projectId is set (session scoping)\n const resuming = projectId && this.threadId;\n const args: string[] = resuming\n ? [\"exec\", \"resume\", this.threadId!, \"--json\", \"--full-auto\", \"--skip-git-repo-check\"]\n : [\"exec\", \"--json\", \"--full-auto\", \"--skip-git-repo-check\"];\n if (model && !resuming) {\n args.push(\"--model\", model);\n }\n // Attach images via -i flags\n for (const imgPath of imagePaths) {\n args.push(\"-i\", imgPath);\n }\n // Read prompt from stdin\n args.push(\"-\");\n\n this.log.info({ requestId, model, promptLength: prompt.length }, \"Spawning Codex process\");\n this.killed = false;\n\n let cwd: string | undefined;\n if (projectId) {\n const base = resolve(tmpdir(), this.sessionDir);\n cwd = resolve(base, projectId);\n if (!cwd.startsWith(base + \"/\") && cwd !== base) {\n handlers.onError(\"Invalid projectId\", requestId);\n return;\n }\n mkdirSync(cwd, { recursive: true });\n }\n\n const cleanupImages = () => {\n for (const p of imagePaths) {\n try { unlinkSync(p); } catch { /* already cleaned */ }\n }\n };\n\n const ALLOWED_ENV_KEYS = [\n \"PATH\", \"HOME\", \"USER\", \"SHELL\", \"TERM\", \"LANG\", \"LC_ALL\",\n \"OPENAI_API_KEY\", \"NODE_PATH\", \"XDG_CONFIG_HOME\",\n ];\n const env: Record<string, string> = {};\n for (const key of ALLOWED_ENV_KEYS) {\n if (process.env[key]) env[key] = process.env[key]!;\n }\n\n try {\n this.process = spawn(this.codexPath, args, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n cwd,\n env,\n });\n } catch (err) {\n cleanupImages();\n const message = err instanceof Error ? err.message : \"Failed to start Codex\";\n this.log.error({ err, requestId }, \"Failed to spawn Codex process\");\n handlers.onError(message, requestId);\n return;\n }\n\n this.log.debug({ pid: this.process.pid, requestId }, \"Codex process spawned\");\n\n if (this.process.stdin) {\n this.process.stdin.write(fullPrompt);\n this.process.stdin.end();\n }\n\n // Guard against double handler invocation (e.g. error + exit both firing)\n let handlersDone = false;\n const finish = (cb: () => void) => {\n if (handlersDone) return;\n handlersDone = true;\n this.clearTimeout();\n cb();\n };\n\n this.timeout = setTimeout(() => {\n this.log.warn({ requestId }, \"Codex process timed out\");\n this.kill();\n finish(() => handlers.onError(\"Process timed out\", requestId));\n }, this.timeoutMs);\n\n if (this.process.stdout) {\n const rl = createInterface({ input: this.process.stdout });\n rl.on(\"line\", (line) => {\n this.parseStreamLine(line, handlers, requestId);\n });\n }\n\n if (this.process.stderr) {\n const stderrRl = createInterface({ input: this.process.stderr });\n stderrRl.on(\"line\", (line) => {\n if (line.trim()) {\n this.log.warn({ requestId, stderr: line }, \"Codex stderr\");\n }\n });\n }\n\n this.process.on(\"exit\", (exitCode, signal) => {\n this.process = null;\n cleanupImages();\n\n if (this.killed) {\n this.log.debug({ requestId }, \"Codex process was killed\");\n return;\n }\n\n if (exitCode === 0) {\n this.log.info({ requestId }, \"Codex process completed successfully\");\n finish(() => handlers.onComplete(requestId));\n } else {\n const reason = exitCode !== null\n ? `Codex CLI exited with code ${exitCode}`\n : `Codex CLI killed by signal ${signal ?? \"unknown\"}`;\n this.log.warn({ requestId, exitCode, signal }, reason);\n finish(() => handlers.onError(reason, requestId));\n }\n });\n\n this.process.on(\"error\", (err) => {\n this.process = null;\n cleanupImages();\n this.log.error({ err, requestId }, \"Codex process error\");\n finish(() => handlers.onError(err.message, requestId));\n });\n }\n\n /**\n * Parse JSONL output from `codex exec --json`.\n *\n * Event format (one JSON object per line):\n * { type: \"thread.started\", thread_id }\n * { type: \"turn.started\" }\n * { type: \"item.started\", item: { id, type, ... } }\n * { type: \"item.completed\", item: { id, type: \"agent_message\", text } }\n * { type: \"item.completed\", item: { id, type: \"command_execution\", command, exit_code } }\n * { type: \"turn.completed\", usage: { input_tokens, output_tokens, ... } }\n */\n private parseStreamLine(line: string, handlers: RunHandlers, requestId: string): void {\n if (!line.trim()) return;\n\n try {\n const event = JSON.parse(line);\n\n // Capture thread_id for session resumption\n if (event.type === \"thread.started\" && event.thread_id) {\n this.threadId = event.thread_id;\n this.log.debug({ threadId: this.threadId, requestId }, \"Captured Codex thread ID\");\n return;\n }\n\n // Agent message \u2014 the actual text content we want to stream\n if (event.type === \"item.completed\" && event.item?.type === \"agent_message\" && event.item.text) {\n handlers.onChunk(event.item.text, requestId);\n return;\n }\n\n // Reasoning trace \u2014 forward as thinking\n if (event.type === \"item.completed\" && event.item?.type === \"reasoning\" && event.item.text) {\n handlers.onChunk(event.item.text, requestId, true);\n return;\n }\n\n // Turn failed \u2014 surface as error\n if (event.type === \"turn.failed\") {\n const msg = event.error?.message || event.message || \"Codex turn failed\";\n handlers.onError(msg, requestId);\n return;\n }\n\n // error event\n if (event.type === \"error\") {\n const msg = event.message || event.error?.message || \"Codex error\";\n handlers.onError(msg, requestId);\n return;\n }\n } catch {\n // Non-JSON line, skip\n }\n }\n\n kill(): void {\n this.clearTimeout();\n if (this.process) {\n this.log.debug({ pid: this.process.pid }, \"Killing Codex process\");\n this.killed = true;\n try {\n this.process.kill();\n } catch {\n // Process may already be dead\n }\n this.process = null;\n }\n }\n\n dispose(): void {\n this.disposed = true;\n this.kill();\n }\n\n private clearTimeout(): void {\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n }\n}\n", "// Maximum prompt size: 512KB\nconst MAX_PROMPT_BYTES = 512 * 1024;\n// Maximum system prompt size: 64KB\nconst MAX_SYSTEM_PROMPT_BYTES = 64 * 1024;\n// Maximum images per message\nconst MAX_IMAGES = 4;\n// Maximum single image size: 10MB base64\nconst MAX_IMAGE_BASE64_BYTES = 10 * 1024 * 1024;\n// Allowed image MIME types\nconst ALLOWED_IMAGE_TYPES = new Set([\n \"image/png\", \"image/jpeg\", \"image/gif\", \"image/webp\",\n]);\n// Maximum projectId length\nconst MAX_PROJECT_ID_LENGTH = 128;\n// Allowed projectId characters: alphanumeric, hyphens, underscores, dots\nconst PROJECT_ID_PATTERN = /^[a-zA-Z0-9._-]+$/;\n\n// --- Client \u2192 Agent messages ---\n\nexport interface PromptImage {\n media_type: string;\n data: string; // base64-encoded\n}\n\nexport interface PromptMessage {\n type: \"prompt\";\n prompt: string;\n model?: string;\n systemPrompt?: string;\n projectId?: string;\n requestId: string;\n provider?: \"claude\" | \"codex\";\n thinkingTokens?: number;\n images?: PromptImage[];\n}\n\nexport interface CancelMessage {\n type: \"cancel\";\n requestId?: string;\n}\n\nexport type ClientMessage = PromptMessage | CancelMessage;\n\n// --- Agent \u2192 Client messages ---\n\nexport interface ConnectedMessage {\n type: \"connected\";\n version: string;\n agent: string;\n}\n\nexport interface ChunkMessage {\n type: \"chunk\";\n content: string;\n requestId: string;\n thinking?: boolean;\n}\n\nexport interface CompleteMessage {\n type: \"complete\";\n requestId: string;\n}\n\nexport interface ErrorMessage {\n type: \"error\";\n message: string;\n requestId?: string;\n}\n\nexport type AgentMessage =\n | ConnectedMessage\n | ChunkMessage\n | CompleteMessage\n | ErrorMessage;\n\n// --- Parsing & validation ---\n\nexport type ParseResult =\n | { ok: true; message: ClientMessage }\n | { ok: false; error: string };\n\nexport function parseClientMessage(raw: string): ParseResult {\n let data: unknown;\n\n try {\n data = JSON.parse(raw);\n } catch {\n return { ok: false, error: \"Invalid JSON\" };\n }\n\n if (typeof data !== \"object\" || data === null || Array.isArray(data)) {\n return { ok: false, error: \"Message must be a JSON object\" };\n }\n\n const obj = data as Record<string, unknown>;\n const type = obj[\"type\"];\n\n if (typeof type !== \"string\") {\n return { ok: false, error: \"Missing or invalid 'type' field\" };\n }\n\n switch (type) {\n case \"prompt\": {\n const prompt = obj[\"prompt\"];\n if (typeof prompt !== \"string\" || prompt.length === 0) {\n return { ok: false, error: \"Missing or empty 'prompt' field\" };\n }\n\n if (new TextEncoder().encode(prompt).byteLength > MAX_PROMPT_BYTES) {\n return { ok: false, error: `Prompt exceeds maximum size of ${MAX_PROMPT_BYTES} bytes` };\n }\n\n const requestId = obj[\"requestId\"];\n if (typeof requestId !== \"string\" || requestId.length === 0) {\n return { ok: false, error: \"Missing or empty 'requestId' field\" };\n }\n\n const model = obj[\"model\"];\n const systemPrompt = obj[\"systemPrompt\"];\n const projectId = obj[\"projectId\"];\n const provider = obj[\"provider\"];\n const thinkingTokens = obj[\"thinkingTokens\"];\n\n if (typeof systemPrompt === \"string\" && new TextEncoder().encode(systemPrompt).byteLength > MAX_SYSTEM_PROMPT_BYTES) {\n return { ok: false, error: `System prompt exceeds maximum size of ${MAX_SYSTEM_PROMPT_BYTES} bytes` };\n }\n\n if (typeof projectId === \"string\") {\n if (projectId.length > MAX_PROJECT_ID_LENGTH) {\n return { ok: false, error: `projectId exceeds maximum length of ${MAX_PROJECT_ID_LENGTH}` };\n }\n if (!PROJECT_ID_PATTERN.test(projectId)) {\n return { ok: false, error: \"projectId contains invalid characters (allowed: alphanumeric, hyphens, underscores, dots)\" };\n }\n }\n\n // Parse images (optional array of { media_type, data })\n let parsedImages: PromptImage[] | undefined;\n const rawImages = obj[\"images\"];\n if (Array.isArray(rawImages) && rawImages.length > 0) {\n if (rawImages.length > MAX_IMAGES) {\n return { ok: false, error: `Too many images (max ${MAX_IMAGES})` };\n }\n parsedImages = [];\n for (const img of rawImages) {\n if (typeof img !== \"object\" || img === null) {\n return { ok: false, error: \"Each image must be an object with media_type and data\" };\n }\n const imgObj = img as Record<string, unknown>;\n if (typeof imgObj[\"media_type\"] !== \"string\" || typeof imgObj[\"data\"] !== \"string\") {\n return { ok: false, error: \"Each image must have string media_type and data fields\" };\n }\n if (!ALLOWED_IMAGE_TYPES.has(imgObj[\"media_type\"])) {\n return { ok: false, error: `Unsupported image type: ${String(imgObj[\"media_type\"]).slice(0, 50)} (allowed: png, jpeg, gif, webp)` };\n }\n if (imgObj[\"data\"].length > MAX_IMAGE_BASE64_BYTES) {\n return { ok: false, error: `Image exceeds maximum size of ${MAX_IMAGE_BASE64_BYTES} bytes` };\n }\n parsedImages.push({ media_type: imgObj[\"media_type\"], data: imgObj[\"data\"] });\n }\n }\n\n return {\n ok: true,\n message: {\n type: \"prompt\",\n prompt,\n model: typeof model === \"string\" ? model : undefined,\n systemPrompt: typeof systemPrompt === \"string\" ? systemPrompt : undefined,\n projectId: typeof projectId === \"string\" ? projectId : undefined,\n requestId,\n provider: provider === \"codex\" ? \"codex\" : \"claude\",\n thinkingTokens: typeof thinkingTokens === \"number\" && thinkingTokens >= 0 ? thinkingTokens : undefined,\n images: parsedImages,\n },\n };\n }\n\n case \"cancel\": {\n const requestId = obj[\"requestId\"];\n return {\n ok: true,\n message: {\n type: \"cancel\",\n requestId: typeof requestId === \"string\" ? requestId : undefined,\n },\n };\n }\n\n default:\n return { ok: false, error: `Unknown message type: ${String(type).slice(0, 50)}` };\n }\n}\n\n// --- Serialization ---\n\nexport function serializeMessage(message: AgentMessage): string {\n return JSON.stringify(message);\n}\n", "import pino from \"pino\";\n\nexport interface LoggerOptions {\n level?: string;\n pretty?: boolean;\n}\n\nexport function createLogger(options: LoggerOptions = {}): pino.Logger {\n const { level = \"info\", pretty = process.env[\"NODE_ENV\"] !== \"production\" } = options;\n\n if (pretty) {\n try {\n return pino({\n level,\n transport: {\n target: \"pino-pretty\",\n options: {\n colorize: true,\n translateTime: \"HH:MM:ss\",\n ignore: \"pid,hostname\",\n },\n },\n });\n } catch {\n // pino-pretty not available, fall back to plain JSON logging\n }\n }\n\n return pino({ level });\n}\n\nexport type Logger = pino.Logger;\n", "import { AgentWebSocketServer, type AgentWebSocketServerOptions, type RunnerFactory } from \"./server/websocket.js\";\nimport { createLogger, type Logger } from \"./utils/logger.js\";\n\nexport interface AgentWSOptions {\n port?: number;\n host?: string;\n claudePath?: string;\n codexPath?: string;\n timeoutMs?: number;\n logLevel?: string;\n allowedOrigins?: string[];\n /** @deprecated Use claudeRunnerFactory instead */\n runnerFactory?: RunnerFactory;\n claudeRunnerFactory?: RunnerFactory;\n codexRunnerFactory?: RunnerFactory;\n agentName?: string;\n sessionDir?: string;\n}\n\nexport class AgentWS {\n private server: AgentWebSocketServer;\n private readonly log: Logger;\n\n constructor(options: AgentWSOptions = {}) {\n this.log = createLogger({ level: options.logLevel ?? \"info\" });\n\n const serverOptions: AgentWebSocketServerOptions = {\n port: options.port ?? 9999,\n host: options.host ?? \"localhost\",\n logger: this.log,\n claudePath: options.claudePath,\n codexPath: options.codexPath,\n timeoutMs: options.timeoutMs,\n allowedOrigins: options.allowedOrigins,\n runnerFactory: options.runnerFactory,\n claudeRunnerFactory: options.claudeRunnerFactory,\n codexRunnerFactory: options.codexRunnerFactory,\n agentName: options.agentName,\n sessionDir: options.sessionDir,\n };\n\n this.server = new AgentWebSocketServer(serverOptions);\n }\n\n async start(): Promise<void> {\n await this.server.start();\n }\n\n stop(): void {\n this.server.stop();\n }\n}\n", "import { execFileSync } from \"node:child_process\";\n\nexport interface CliCheckResult {\n available: boolean;\n version?: string;\n error?: string;\n}\n\nexport function checkCli(cliPath: string = \"claude\"): CliCheckResult {\n try {\n const output = execFileSync(cliPath, [\"--version\"], {\n timeout: 5000,\n stdio: \"pipe\",\n encoding: \"utf-8\",\n });\n\n return {\n available: true,\n version: output.trim(),\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Unknown error\";\n return {\n available: false,\n error: message,\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["spawn", "mkdirSync", "resolve", "tmpdir", "createInterface", "DEFAULT_TIMEOUT_MS", "resolve"]
|
|
7
7
|
}
|