agent-ws 1.0.0 → 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 CHANGED
@@ -35,7 +35,9 @@ agent-ws
35
35
  # Connect via WebSocket on ws://localhost:9999
36
36
  ```
37
37
 
38
- ## Library Usage
38
+ ## Library Usage (Node.js only)
39
+
40
+ If you want to embed the WebSocket server into your own Node.js backend (e.g. Express, Fastify, or a Next.js API route) instead of running the CLI:
39
41
 
40
42
  ```typescript
41
43
  import { AgentWS } from "agent-ws";
@@ -50,6 +52,8 @@ const agent = new AgentWS({
50
52
  await agent.start();
51
53
  ```
52
54
 
55
+ > **Note:** This is server-side only. Browser/React clients should connect to the running agent-ws server as a WebSocket client (see [Protocol](#protocol)).
56
+
53
57
  ## CLI Options
54
58
 
55
59
  ```
@@ -68,7 +72,7 @@ await agent.start();
68
72
  ```
69
73
  ┌───────────────┐ WebSocket ┌─────────────┐ stdio ┌─────────────┐
70
74
  │ Your App │ <=================> │ agent-ws │ <===============> │ Claude Code │
71
- │ (any client) │ localhost:9999 │ (Node.js) │ --print --json │ / Codex │
75
+ │ (any client) │ localhost:9999 │ (Node.js) │ stdio │ / Codex │
72
76
  └───────────────┘ └─────────────┘ └─────────────┘
73
77
  ```
74
78
 
@@ -83,7 +87,7 @@ Any WebSocket client can connect — browser frontends, backend services, script
83
87
 
84
88
  | Agent | Provider field | CLI |
85
89
  |-------|---------------|-----|
86
- | Claude Code | `"claude"` (default) | `claude --print` (+ `--continue` when `projectId` is set) |
90
+ | Claude Code | `"claude"` (default) | `claude --print --verbose --output-format stream-json` |
87
91
  | Codex | `"codex"` | `codex --json` |
88
92
 
89
93
  ## Protocol
package/SECURITY.md CHANGED
@@ -22,4 +22,4 @@ agent-ws runs locally on your machine and bridges WebSocket connections to CLI A
22
22
 
23
23
  | Version | Supported |
24
24
  |---------|-----------|
25
- | 0.x | Latest release only |
25
+ | 1.x | Latest release only |
package/dist/agent.js CHANGED
@@ -35,6 +35,7 @@ var ClaudeRunner = class {
35
35
  const { prompt, model, systemPrompt, projectId, requestId, thinkingTokens } = options;
36
36
  const args = [
37
37
  "--print",
38
+ "--verbose",
38
39
  "--output-format",
39
40
  "stream-json",
40
41
  "--max-turns",
@@ -234,6 +235,7 @@ var CodexRunner = class {
234
235
  timeout = null;
235
236
  disposed = false;
236
237
  killed = false;
238
+ threadId = null;
237
239
  codexPath;
238
240
  timeoutMs;
239
241
  log;
@@ -262,8 +264,9 @@ var CodexRunner = class {
262
264
 
263
265
  ${prompt}`;
264
266
  }
265
- const args = ["--json"];
266
- if (model) {
267
+ const resuming = projectId && this.threadId;
268
+ const args = resuming ? ["exec", "resume", this.threadId, "--json", "--full-auto", "--skip-git-repo-check"] : ["exec", "--json", "--full-auto", "--skip-git-repo-check"];
269
+ if (model && !resuming) {
267
270
  args.push("--model", model);
268
271
  }
269
272
  args.push("-");
@@ -360,28 +363,41 @@ ${prompt}`;
360
363
  });
361
364
  }
362
365
  /**
363
- * Parse JSONL output from Codex CLI.
364
- * Looks for text content in response events.
366
+ * Parse JSONL output from `codex exec --json`.
367
+ *
368
+ * Event format (one JSON object per line):
369
+ * { type: "thread.started", thread_id }
370
+ * { type: "turn.started" }
371
+ * { type: "item.started", item: { id, type, ... } }
372
+ * { type: "item.completed", item: { id, type: "agent_message", text } }
373
+ * { type: "item.completed", item: { id, type: "command_execution", command, exit_code } }
374
+ * { type: "turn.completed", usage: { input_tokens, output_tokens, ... } }
365
375
  */
366
376
  parseStreamLine(line, handlers, requestId) {
367
377
  if (!line.trim()) return;
368
378
  try {
369
379
  const event = JSON.parse(line);
370
- if (event.type === "message" && event.role === "assistant") {
371
- if (Array.isArray(event.content)) {
372
- for (const block of event.content) {
373
- if (block.type === "output_text" && block.text) {
374
- handlers.onChunk(block.text, requestId);
375
- } else if (block.type === "text" && block.text) {
376
- handlers.onChunk(block.text, requestId);
377
- }
378
- }
379
- } else if (typeof event.content === "string" && event.content) {
380
- handlers.onChunk(event.content, requestId);
381
- }
380
+ if (event.type === "thread.started" && event.thread_id) {
381
+ this.threadId = event.thread_id;
382
+ this.log.debug({ threadId: this.threadId, requestId }, "Captured Codex thread ID");
383
+ return;
384
+ }
385
+ if (event.type === "item.completed" && event.item?.type === "agent_message" && event.item.text) {
386
+ handlers.onChunk(event.item.text, requestId);
387
+ return;
388
+ }
389
+ if (event.type === "item.completed" && event.item?.type === "reasoning" && event.item.text) {
390
+ handlers.onChunk(event.item.text, requestId, true);
382
391
  return;
383
392
  }
384
- if (event.type === "response.completed" || event.type === "item.completed") {
393
+ if (event.type === "turn.failed") {
394
+ const msg = event.error?.message || event.message || "Codex turn failed";
395
+ handlers.onError(msg, requestId);
396
+ return;
397
+ }
398
+ if (event.type === "error") {
399
+ const msg = event.message || event.error?.message || "Codex error";
400
+ handlers.onError(msg, requestId);
385
401
  return;
386
402
  }
387
403
  } catch {
@@ -534,7 +550,8 @@ var AgentWebSocketServer = class {
534
550
  this.heartbeatInterval = null;
535
551
  }
536
552
  for (const [ws, state] of this.connections) {
537
- state.runner.dispose();
553
+ state.claudeRunner?.dispose();
554
+ state.codexRunner?.dispose();
538
555
  ws.terminate();
539
556
  }
540
557
  this.connections.clear();
@@ -555,8 +572,7 @@ var AgentWebSocketServer = class {
555
572
  }
556
573
  const clientIp = req.socket.remoteAddress;
557
574
  this.log.info({ clientIp }, "Client connected");
558
- const runner = this.createRunner();
559
- const state = { runner, isAlive: true, activeRequestId: null };
575
+ const state = { claudeRunner: null, codexRunner: null, activeRunner: null, isAlive: true, activeRequestId: null };
560
576
  this.connections.set(ws, state);
561
577
  this.sendMessage(ws, {
562
578
  type: "connected",
@@ -572,7 +588,8 @@ var AgentWebSocketServer = class {
572
588
  });
573
589
  ws.on("close", () => {
574
590
  this.log.info({ clientIp }, "Client disconnected");
575
- state.runner.dispose();
591
+ state.claudeRunner?.dispose();
592
+ state.codexRunner?.dispose();
576
593
  this.connections.delete(ws);
577
594
  });
578
595
  ws.on("error", (err) => {
@@ -606,25 +623,20 @@ var AgentWebSocketServer = class {
606
623
  }
607
624
  state.activeRequestId = message.requestId;
608
625
  if (message.provider === "codex") {
609
- if (!(state.runner instanceof CodexRunner)) {
610
- try {
611
- state.runner.dispose();
612
- } catch {
613
- }
614
- state.runner = new CodexRunner({
626
+ if (!state.codexRunner) {
627
+ state.codexRunner = new CodexRunner({
628
+ codexPath: this.options.codexPath,
615
629
  timeoutMs: this.options.timeoutMs,
616
630
  logger: this.log.child({ component: "codex-runner" }),
617
631
  sessionDir: this.options.sessionDir
618
632
  });
619
633
  }
634
+ state.activeRunner = state.codexRunner;
620
635
  } else {
621
- if (!(state.runner instanceof ClaudeRunner)) {
622
- try {
623
- state.runner.dispose();
624
- } catch {
625
- }
626
- state.runner = this.createRunner();
636
+ if (!state.claudeRunner) {
637
+ state.claudeRunner = this.createRunner();
627
638
  }
639
+ state.activeRunner = state.claudeRunner;
628
640
  }
629
641
  const handlers = {
630
642
  onChunk: (content, requestId, thinking) => {
@@ -651,13 +663,13 @@ var AgentWebSocketServer = class {
651
663
  }
652
664
  }
653
665
  };
654
- state.runner.run(
666
+ state.activeRunner.run(
655
667
  { prompt: message.prompt, model: message.model, systemPrompt: message.systemPrompt, projectId: message.projectId, requestId: message.requestId, thinkingTokens: message.thinkingTokens },
656
668
  handlers
657
669
  );
658
670
  }
659
671
  handleCancel(ws, state) {
660
- state.runner.kill();
672
+ state.activeRunner?.kill();
661
673
  const requestId = state.activeRequestId;
662
674
  state.activeRequestId = null;
663
675
  this.log.info({ requestId }, "Request cancelled");
@@ -686,7 +698,8 @@ var AgentWebSocketServer = class {
686
698
  for (const [ws, state] of this.connections) {
687
699
  if (!state.isAlive) {
688
700
  this.log.debug("Terminating dead connection");
689
- state.runner.dispose();
701
+ state.claudeRunner?.dispose();
702
+ state.codexRunner?.dispose();
690
703
  this.connections.delete(ws);
691
704
  ws.terminate();
692
705
  continue;
@@ -696,7 +709,8 @@ var AgentWebSocketServer = class {
696
709
  ws.ping();
697
710
  } catch {
698
711
  this.log.debug("Ping failed, terminating connection");
699
- state.runner.dispose();
712
+ state.claudeRunner?.dispose();
713
+ state.codexRunner?.dispose();
700
714
  this.connections.delete(ws);
701
715
  ws.terminate();
702
716
  }
@@ -739,6 +753,7 @@ var AgentWS = class {
739
753
  host: options.host ?? "localhost",
740
754
  logger: this.log,
741
755
  claudePath: options.claudePath,
756
+ codexPath: options.codexPath,
742
757
  timeoutMs: options.timeoutMs,
743
758
  allowedOrigins: options.allowedOrigins,
744
759
  runnerFactory: options.runnerFactory,
package/dist/agent.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../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"],
4
- "sourcesContent": ["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 \"--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"],
5
- "mappings": "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",
4
+ "sourcesContent": ["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"],
5
+ "mappings": "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",
6
6
  "names": ["spawn", "mkdirSync", "resolve", "tmpdir", "createInterface", "DEFAULT_TIMEOUT_MS", "resolve"]
7
7
  }