agent-ws 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/SECURITY.md +1 -1
- package/dist/agent.js +51 -37
- package/dist/agent.js.map +2 -2
- package/dist/cli.js +60 -39
- package/dist/cli.js.map +2 -2
- package/dist/index.js +51 -37
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -240,6 +240,7 @@ var CodexRunner = class {
|
|
|
240
240
|
timeout = null;
|
|
241
241
|
disposed = false;
|
|
242
242
|
killed = false;
|
|
243
|
+
threadId = null;
|
|
243
244
|
codexPath;
|
|
244
245
|
timeoutMs;
|
|
245
246
|
log;
|
|
@@ -268,8 +269,9 @@ var CodexRunner = class {
|
|
|
268
269
|
|
|
269
270
|
${prompt}`;
|
|
270
271
|
}
|
|
271
|
-
const
|
|
272
|
-
|
|
272
|
+
const resuming = projectId && this.threadId;
|
|
273
|
+
const args = resuming ? ["exec", "resume", this.threadId, "--json", "--full-auto", "--skip-git-repo-check"] : ["exec", "--json", "--full-auto", "--skip-git-repo-check"];
|
|
274
|
+
if (model && !resuming) {
|
|
273
275
|
args.push("--model", model);
|
|
274
276
|
}
|
|
275
277
|
args.push("-");
|
|
@@ -366,28 +368,41 @@ ${prompt}`;
|
|
|
366
368
|
});
|
|
367
369
|
}
|
|
368
370
|
/**
|
|
369
|
-
* Parse JSONL output from
|
|
370
|
-
*
|
|
371
|
+
* Parse JSONL output from `codex exec --json`.
|
|
372
|
+
*
|
|
373
|
+
* Event format (one JSON object per line):
|
|
374
|
+
* { type: "thread.started", thread_id }
|
|
375
|
+
* { type: "turn.started" }
|
|
376
|
+
* { type: "item.started", item: { id, type, ... } }
|
|
377
|
+
* { type: "item.completed", item: { id, type: "agent_message", text } }
|
|
378
|
+
* { type: "item.completed", item: { id, type: "command_execution", command, exit_code } }
|
|
379
|
+
* { type: "turn.completed", usage: { input_tokens, output_tokens, ... } }
|
|
371
380
|
*/
|
|
372
381
|
parseStreamLine(line, handlers, requestId) {
|
|
373
382
|
if (!line.trim()) return;
|
|
374
383
|
try {
|
|
375
384
|
const event = JSON.parse(line);
|
|
376
|
-
if (event.type === "
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
if (block.type === "output_text" && block.text) {
|
|
380
|
-
handlers.onChunk(block.text, requestId);
|
|
381
|
-
} else if (block.type === "text" && block.text) {
|
|
382
|
-
handlers.onChunk(block.text, requestId);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
} else if (typeof event.content === "string" && event.content) {
|
|
386
|
-
handlers.onChunk(event.content, requestId);
|
|
387
|
-
}
|
|
385
|
+
if (event.type === "thread.started" && event.thread_id) {
|
|
386
|
+
this.threadId = event.thread_id;
|
|
387
|
+
this.log.debug({ threadId: this.threadId, requestId }, "Captured Codex thread ID");
|
|
388
388
|
return;
|
|
389
389
|
}
|
|
390
|
-
if (event.type === "
|
|
390
|
+
if (event.type === "item.completed" && event.item?.type === "agent_message" && event.item.text) {
|
|
391
|
+
handlers.onChunk(event.item.text, requestId);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
if (event.type === "item.completed" && event.item?.type === "reasoning" && event.item.text) {
|
|
395
|
+
handlers.onChunk(event.item.text, requestId, true);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
if (event.type === "turn.failed") {
|
|
399
|
+
const msg = event.error?.message || event.message || "Codex turn failed";
|
|
400
|
+
handlers.onError(msg, requestId);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
if (event.type === "error") {
|
|
404
|
+
const msg = event.message || event.error?.message || "Codex error";
|
|
405
|
+
handlers.onError(msg, requestId);
|
|
391
406
|
return;
|
|
392
407
|
}
|
|
393
408
|
} catch {
|
|
@@ -540,7 +555,8 @@ var AgentWebSocketServer = class {
|
|
|
540
555
|
this.heartbeatInterval = null;
|
|
541
556
|
}
|
|
542
557
|
for (const [ws, state] of this.connections) {
|
|
543
|
-
state.
|
|
558
|
+
state.claudeRunner?.dispose();
|
|
559
|
+
state.codexRunner?.dispose();
|
|
544
560
|
ws.terminate();
|
|
545
561
|
}
|
|
546
562
|
this.connections.clear();
|
|
@@ -561,8 +577,7 @@ var AgentWebSocketServer = class {
|
|
|
561
577
|
}
|
|
562
578
|
const clientIp = req.socket.remoteAddress;
|
|
563
579
|
this.log.info({ clientIp }, "Client connected");
|
|
564
|
-
const
|
|
565
|
-
const state = { runner, isAlive: true, activeRequestId: null };
|
|
580
|
+
const state = { claudeRunner: null, codexRunner: null, activeRunner: null, isAlive: true, activeRequestId: null };
|
|
566
581
|
this.connections.set(ws, state);
|
|
567
582
|
this.sendMessage(ws, {
|
|
568
583
|
type: "connected",
|
|
@@ -578,7 +593,8 @@ var AgentWebSocketServer = class {
|
|
|
578
593
|
});
|
|
579
594
|
ws.on("close", () => {
|
|
580
595
|
this.log.info({ clientIp }, "Client disconnected");
|
|
581
|
-
state.
|
|
596
|
+
state.claudeRunner?.dispose();
|
|
597
|
+
state.codexRunner?.dispose();
|
|
582
598
|
this.connections.delete(ws);
|
|
583
599
|
});
|
|
584
600
|
ws.on("error", (err) => {
|
|
@@ -612,25 +628,20 @@ var AgentWebSocketServer = class {
|
|
|
612
628
|
}
|
|
613
629
|
state.activeRequestId = message.requestId;
|
|
614
630
|
if (message.provider === "codex") {
|
|
615
|
-
if (!
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
} catch {
|
|
619
|
-
}
|
|
620
|
-
state.runner = new CodexRunner({
|
|
631
|
+
if (!state.codexRunner) {
|
|
632
|
+
state.codexRunner = new CodexRunner({
|
|
633
|
+
codexPath: this.options.codexPath,
|
|
621
634
|
timeoutMs: this.options.timeoutMs,
|
|
622
635
|
logger: this.log.child({ component: "codex-runner" }),
|
|
623
636
|
sessionDir: this.options.sessionDir
|
|
624
637
|
});
|
|
625
638
|
}
|
|
639
|
+
state.activeRunner = state.codexRunner;
|
|
626
640
|
} else {
|
|
627
|
-
if (!
|
|
628
|
-
|
|
629
|
-
state.runner.dispose();
|
|
630
|
-
} catch {
|
|
631
|
-
}
|
|
632
|
-
state.runner = this.createRunner();
|
|
641
|
+
if (!state.claudeRunner) {
|
|
642
|
+
state.claudeRunner = this.createRunner();
|
|
633
643
|
}
|
|
644
|
+
state.activeRunner = state.claudeRunner;
|
|
634
645
|
}
|
|
635
646
|
const handlers = {
|
|
636
647
|
onChunk: (content, requestId, thinking) => {
|
|
@@ -657,13 +668,13 @@ var AgentWebSocketServer = class {
|
|
|
657
668
|
}
|
|
658
669
|
}
|
|
659
670
|
};
|
|
660
|
-
state.
|
|
671
|
+
state.activeRunner.run(
|
|
661
672
|
{ prompt: message.prompt, model: message.model, systemPrompt: message.systemPrompt, projectId: message.projectId, requestId: message.requestId, thinkingTokens: message.thinkingTokens },
|
|
662
673
|
handlers
|
|
663
674
|
);
|
|
664
675
|
}
|
|
665
676
|
handleCancel(ws, state) {
|
|
666
|
-
state.
|
|
677
|
+
state.activeRunner?.kill();
|
|
667
678
|
const requestId = state.activeRequestId;
|
|
668
679
|
state.activeRequestId = null;
|
|
669
680
|
this.log.info({ requestId }, "Request cancelled");
|
|
@@ -692,7 +703,8 @@ var AgentWebSocketServer = class {
|
|
|
692
703
|
for (const [ws, state] of this.connections) {
|
|
693
704
|
if (!state.isAlive) {
|
|
694
705
|
this.log.debug("Terminating dead connection");
|
|
695
|
-
state.
|
|
706
|
+
state.claudeRunner?.dispose();
|
|
707
|
+
state.codexRunner?.dispose();
|
|
696
708
|
this.connections.delete(ws);
|
|
697
709
|
ws.terminate();
|
|
698
710
|
continue;
|
|
@@ -702,7 +714,8 @@ var AgentWebSocketServer = class {
|
|
|
702
714
|
ws.ping();
|
|
703
715
|
} catch {
|
|
704
716
|
this.log.debug("Ping failed, terminating connection");
|
|
705
|
-
state.
|
|
717
|
+
state.claudeRunner?.dispose();
|
|
718
|
+
state.codexRunner?.dispose();
|
|
706
719
|
this.connections.delete(ws);
|
|
707
720
|
ws.terminate();
|
|
708
721
|
}
|
|
@@ -745,6 +758,7 @@ var AgentWS = class {
|
|
|
745
758
|
host: options.host ?? "localhost",
|
|
746
759
|
logger: this.log,
|
|
747
760
|
claudePath: options.claudePath,
|
|
761
|
+
codexPath: options.codexPath,
|
|
748
762
|
timeoutMs: options.timeoutMs,
|
|
749
763
|
allowedOrigins: options.allowedOrigins,
|
|
750
764
|
runnerFactory: options.runnerFactory,
|
|
@@ -784,9 +798,9 @@ function checkClaudeCli(claudePath = "claude") {
|
|
|
784
798
|
}
|
|
785
799
|
|
|
786
800
|
// src/cli.ts
|
|
787
|
-
var VERSION = true ? "1.0.
|
|
801
|
+
var VERSION = true ? "1.0.2" : "0.0.0-dev";
|
|
788
802
|
var program = new Command();
|
|
789
|
-
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("-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) => {
|
|
803
|
+
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) => {
|
|
790
804
|
console.log(`
|
|
791
805
|
\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
|
|
792
806
|
\u2551 agent-ws v${VERSION.padEnd(20)}\u2551
|
|
@@ -802,6 +816,12 @@ program.name("agent-ws").description("WebSocket bridge for CLI AI agents (Claude
|
|
|
802
816
|
process.exit(1);
|
|
803
817
|
}
|
|
804
818
|
console.log(`Found Claude CLI: ${check.version}`);
|
|
819
|
+
const codexCheck = checkClaudeCli(opts.codexPath);
|
|
820
|
+
if (codexCheck.available) {
|
|
821
|
+
console.log(`Found Codex CLI: ${codexCheck.version}`);
|
|
822
|
+
} else {
|
|
823
|
+
console.log("Codex CLI not found (codex provider will be unavailable)");
|
|
824
|
+
}
|
|
805
825
|
const port = parseInt(opts.port, 10);
|
|
806
826
|
if (isNaN(port) || port < 1 || port > 65535) {
|
|
807
827
|
console.error(`Invalid port: ${opts.port} (must be 1\u201365535)`);
|
|
@@ -828,6 +848,7 @@ program.name("agent-ws").description("WebSocket bridge for CLI AI agents (Claude
|
|
|
828
848
|
port,
|
|
829
849
|
host: opts.host,
|
|
830
850
|
claudePath: opts.claudePath,
|
|
851
|
+
codexPath: opts.codexPath,
|
|
831
852
|
timeoutMs,
|
|
832
853
|
logLevel: opts.logLevel,
|
|
833
854
|
allowedOrigins
|
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(\"-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 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 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 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 runner: Runner;\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 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.runner.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 runner = this.createRunner();\n const state: ConnectionState = { runner, 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.runner.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 // Switch runner if provider changed\n if (message.provider === \"codex\") {\n if (!(state.runner instanceof CodexRunner)) {\n try { state.runner.dispose(); } catch { /* old runner already dead */ }\n state.runner = new CodexRunner({\n timeoutMs: this.options.timeoutMs,\n logger: this.log.child({ component: \"codex-runner\" }),\n sessionDir: this.options.sessionDir,\n });\n }\n } else {\n if (!(state.runner instanceof ClaudeRunner)) {\n try { state.runner.dispose(); } catch { /* old runner already dead */ }\n state.runner = this.createRunner();\n }\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.runner.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.runner.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.runner.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.runner.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 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 const args = [\"--json\"];\n if (model) {\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 CLI.\n * Looks for text content in response events.\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 // Codex emits message events with content\n if (event.type === \"message\" && event.role === \"assistant\") {\n if (Array.isArray(event.content)) {\n for (const block of event.content) {\n if (block.type === \"output_text\" && block.text) {\n handlers.onChunk(block.text, requestId);\n } else if (block.type === \"text\" && block.text) {\n handlers.onChunk(block.text, requestId);\n }\n }\n } else if (typeof event.content === \"string\" && event.content) {\n handlers.onChunk(event.content, requestId);\n }\n return;\n }\n\n // Response completed event\n if (event.type === \"response.completed\" || event.type === \"item.completed\") {\n // Content already streamed above\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 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 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 { 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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",
|
|
6
6
|
"names": ["spawn", "mkdirSync", "resolve", "tmpdir", "createInterface", "DEFAULT_TIMEOUT_MS", "resolve"]
|
|
7
7
|
}
|