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/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 args = ["--json"];
272
- if (model) {
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 Codex CLI.
370
- * Looks for text content in response events.
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 === "message" && event.role === "assistant") {
377
- if (Array.isArray(event.content)) {
378
- for (const block of event.content) {
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 === "response.completed" || event.type === "item.completed") {
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.runner.dispose();
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 runner = this.createRunner();
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.runner.dispose();
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 (!(state.runner instanceof CodexRunner)) {
616
- try {
617
- state.runner.dispose();
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 (!(state.runner instanceof ClaudeRunner)) {
628
- try {
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.runner.run(
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.runner.kill();
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.runner.dispose();
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.runner.dispose();
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.1" : "0.0.0-dev";
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
  }