@dolusoft/claude-collab 1.9.1 → 1.9.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
@@ -298,8 +298,8 @@ var injectionQueue = new InjectionQueue();
298
298
 
299
299
  // src/infrastructure/p2p/p2p-node.ts
300
300
  var P2PNode = class {
301
- constructor(port) {
302
- this.port = port;
301
+ constructor(portRange = [1e4, 19999]) {
302
+ this.portRange = portRange;
303
303
  }
304
304
  server = null;
305
305
  myName = "";
@@ -317,12 +317,16 @@ var P2PNode = class {
317
317
  pendingHandlers = /* @__PURE__ */ new Set();
318
318
  broadcaster = null;
319
319
  stopPeerWatcher = null;
320
+ boundPort = 0;
320
321
  // ---------------------------------------------------------------------------
321
322
  // ICollabClient implementation
322
323
  // ---------------------------------------------------------------------------
323
324
  get isConnected() {
324
325
  return this.running;
325
326
  }
327
+ get port() {
328
+ return this.boundPort;
329
+ }
326
330
  get currentTeamId() {
327
331
  return this.myName || void 0;
328
332
  }
@@ -336,7 +340,7 @@ var P2PNode = class {
336
340
  teamName: name,
337
341
  displayName,
338
342
  status: "ONLINE",
339
- port: this.port
343
+ port: this.boundPort
340
344
  };
341
345
  }
342
346
  async ask(toPeer, content, format) {
@@ -403,7 +407,7 @@ var P2PNode = class {
403
407
  getInfo() {
404
408
  return {
405
409
  teamName: this.myName,
406
- port: this.port,
410
+ port: this.boundPort,
407
411
  connectedPeers: [...this.peerConnections.keys()]
408
412
  };
409
413
  }
@@ -446,39 +450,59 @@ var P2PNode = class {
446
450
  // Private: server startup
447
451
  // ---------------------------------------------------------------------------
448
452
  startServer() {
449
- return new Promise((resolve, reject) => {
450
- const wss = new WebSocketServer({ port: this.port });
451
- this.server = wss;
452
- wss.on("listening", () => {
453
- this.running = true;
454
- console.error(`[p2p] listening on port ${this.port} as "${this.myName}"`);
455
- resolve();
456
- });
457
- wss.on("error", (err) => {
458
- if (!this.running) reject(err);
459
- else console.error("[p2p] server error:", err.message);
460
- });
461
- wss.on("connection", (ws) => {
462
- ws.on("message", (data) => {
463
- try {
464
- this.handleMessage(ws, parse(data.toString()));
465
- } catch {
466
- }
453
+ const [min, max] = this.portRange;
454
+ const pick = () => Math.floor(Math.random() * (max - min + 1)) + min;
455
+ const tryBind = (attemptsLeft) => {
456
+ if (attemptsLeft === 0) {
457
+ return Promise.reject(new Error(`No free port found in range ${min}-${max}`));
458
+ }
459
+ const port = pick();
460
+ return new Promise((resolve, reject) => {
461
+ const wss = new WebSocketServer({ port });
462
+ wss.once("listening", () => {
463
+ this.server = wss;
464
+ this.boundPort = port;
465
+ this.running = true;
466
+ console.error(`[p2p] listening on port ${port} as "${this.myName}"`);
467
+ this.attachServerHandlers(wss);
468
+ resolve();
467
469
  });
468
- ws.on("close", () => {
469
- const name = this.wsToName.get(ws);
470
- if (name) {
471
- this.wsToName.delete(ws);
472
- if (this.peerConnections.get(name) === ws) {
473
- this.peerConnections.delete(name);
474
- console.error(`[p2p] peer disconnected (inbound): ${name}`);
475
- }
470
+ wss.once("error", (err) => {
471
+ wss.close();
472
+ if (err.code === "EADDRINUSE") {
473
+ tryBind(attemptsLeft - 1).then(resolve, reject);
474
+ } else {
475
+ reject(err);
476
476
  }
477
477
  });
478
- ws.on("error", (err) => {
479
- console.error("[p2p] inbound ws error:", err.message);
480
- });
481
478
  });
479
+ };
480
+ return tryBind(20);
481
+ }
482
+ attachServerHandlers(wss) {
483
+ wss.on("connection", (ws) => {
484
+ ws.on("message", (data) => {
485
+ try {
486
+ this.handleMessage(ws, parse(data.toString()));
487
+ } catch {
488
+ }
489
+ });
490
+ ws.on("close", () => {
491
+ const name = this.wsToName.get(ws);
492
+ if (name) {
493
+ this.wsToName.delete(ws);
494
+ if (this.peerConnections.get(name) === ws) {
495
+ this.peerConnections.delete(name);
496
+ console.error(`[p2p] peer disconnected (inbound): ${name}`);
497
+ }
498
+ }
499
+ });
500
+ ws.on("error", (err) => {
501
+ console.error("[p2p] inbound ws error:", err.message);
502
+ });
503
+ });
504
+ wss.on("error", (err) => {
505
+ console.error("[p2p] server error:", err.message);
482
506
  });
483
507
  }
484
508
  // ---------------------------------------------------------------------------
@@ -486,7 +510,7 @@ var P2PNode = class {
486
510
  // ---------------------------------------------------------------------------
487
511
  startDiscovery() {
488
512
  this.broadcaster = new PeerBroadcaster();
489
- this.broadcaster.start(this.myName, this.port);
513
+ this.broadcaster.start(this.myName, this.boundPort);
490
514
  this.stopPeerWatcher = watchForPeer((peer) => {
491
515
  if (peer.name === this.myName) return;
492
516
  if (this.peerConnections.has(peer.name)) return;
@@ -726,6 +750,15 @@ function registerPeersTool(server, client) {
726
750
  const myName = info.teamName ?? "(starting...)";
727
751
  const myPort = info.port ?? "?";
728
752
  const connected = info.connectedPeers;
753
+ if (!client.isConnected) {
754
+ return {
755
+ content: [{
756
+ type: "text",
757
+ text: `P2P server is not running yet. Port ${myPort} may be in use. Check the MCP logs for details.`
758
+ }],
759
+ isError: true
760
+ };
761
+ }
729
762
  if (connected.length === 0) {
730
763
  return {
731
764
  content: [{
@@ -924,12 +957,14 @@ async function startMcpServer(options) {
924
957
  }
925
958
 
926
959
  // src/cli.ts
927
- var P2P_PORT = 9999;
928
960
  var program = new Command();
929
961
  program.name("claude-collab").description("P2P collaboration between Claude Code terminals via MCP").version("0.1.0").requiredOption("--name <name>", 'Your name on the network (e.g. "alice")').action(async (options) => {
930
- const node = new P2PNode(P2P_PORT);
931
- await node.join(options.name, options.name);
932
- await startMcpServer({ client: node });
962
+ const node = new P2PNode();
963
+ const mcpReady = startMcpServer({ client: node });
964
+ node.join(options.name, options.name).catch((err) => {
965
+ console.error(`[cli] P2P server failed to start: ${err.message}`);
966
+ });
967
+ await mcpReady;
933
968
  });
934
969
  program.parse();
935
970
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/infrastructure/p2p/p2p-protocol.ts","../src/infrastructure/discovery/peer-broadcaster.ts","../src/infrastructure/discovery/peer-listener.ts","../src/infrastructure/terminal-injector/windows-injector.ts","../src/infrastructure/terminal-injector/index.ts","../src/infrastructure/terminal-injector/injection-queue.ts","../src/infrastructure/p2p/p2p-node.ts","../src/presentation/mcp/tools/ask.tool.ts","../src/presentation/mcp/tools/reply.tool.ts","../src/presentation/mcp/tools/peers.tool.ts","../src/presentation/mcp/tools/history.tool.ts","../src/infrastructure/firewall/firewall.ts","../src/presentation/mcp/tools/firewall-open.tool.ts","../src/presentation/mcp/tools/firewall-close.tool.ts","../src/presentation/mcp/server.ts","../src/cli.ts"],"names":["createSocket","uuidv4","z"],"mappings":"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","file":"cli.js","sourcesContent":["/**\r\n * P2P Wire Protocol\r\n * Messages exchanged directly between peers (no hub).\r\n * @module infrastructure/p2p/p2p-protocol\r\n */\r\n\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\n\r\n// Sent when a peer connects (client → server, or outbound → inbound)\r\nexport interface HelloMsg {\r\n type: 'HELLO';\r\n name: string;\r\n}\r\n\r\n// Acknowledge the HELLO\r\nexport interface HelloAckMsg {\r\n type: 'HELLO_ACK';\r\n name: string;\r\n}\r\n\r\n// Ask a question directly to the connected peer\r\nexport interface AskMsg {\r\n type: 'ASK';\r\n from: string;\r\n questionId: string;\r\n content: string;\r\n format: MessageFormat;\r\n}\r\n\r\n// Confirm question was received\r\nexport interface AskAckMsg {\r\n type: 'ASK_ACK';\r\n questionId: string;\r\n}\r\n\r\n// Push answer back to the asker\r\nexport interface AnswerMsg {\r\n type: 'ANSWER';\r\n from: string;\r\n questionId: string;\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n}\r\n\r\nexport type P2PMsg = HelloMsg | HelloAckMsg | AskMsg | AskAckMsg | AnswerMsg;\r\n\r\nexport function serialize(msg: P2PMsg): string {\r\n return JSON.stringify(msg);\r\n}\r\n\r\nexport function parse(data: string): P2PMsg {\r\n return JSON.parse(data) as P2PMsg;\r\n}\r\n","/**\r\n * PeerBroadcaster\r\n * Periodically sends a UDP broadcast so other peers can discover this node.\r\n * Payload: { type: 'claude-collab-peer', name, port }\r\n * @module infrastructure/discovery/peer-broadcaster\r\n */\r\n\r\nimport { createSocket } from 'dgram';\r\n\r\nexport const PEER_DISCOVERY_PORT = 9998;\r\nconst BROADCAST_INTERVAL_MS = 3000;\r\nconst BROADCAST_ADDRESS = '255.255.255.255';\r\n\r\nexport class PeerBroadcaster {\r\n private socket: ReturnType<typeof createSocket> | null = null;\r\n private timer: NodeJS.Timeout | null = null;\r\n\r\n start(name: string, port: number): void {\r\n if (this.socket) return;\r\n\r\n const socket = createSocket('udp4');\r\n this.socket = socket;\r\n\r\n socket.on('error', (err) => {\r\n console.error('[peer-broadcaster] error:', err.message);\r\n });\r\n\r\n socket.bind(0, () => {\r\n socket.setBroadcast(true);\r\n const send = () => {\r\n if (!this.socket) return;\r\n const msg = Buffer.from(JSON.stringify({ type: 'claude-collab-peer', name, port }));\r\n socket.send(msg, 0, msg.length, PEER_DISCOVERY_PORT, BROADCAST_ADDRESS, (err) => {\r\n if (err) console.error('[peer-broadcaster] send error:', err.message);\r\n });\r\n };\r\n send();\r\n this.timer = setInterval(send, BROADCAST_INTERVAL_MS);\r\n });\r\n }\r\n\r\n stop(): void {\r\n if (this.timer) { clearInterval(this.timer); this.timer = null; }\r\n if (this.socket) { this.socket.close(); this.socket = null; }\r\n }\r\n}\r\n","/**\r\n * PeerListener\r\n * Listens for UDP broadcasts from other peers on the LAN.\r\n * @module infrastructure/discovery/peer-listener\r\n */\r\n\r\nimport { createSocket } from 'dgram';\r\nimport { PEER_DISCOVERY_PORT } from './peer-broadcaster.js';\r\n\r\nexport interface DiscoveredPeer {\r\n name: string;\r\n host: string;\r\n port: number;\r\n}\r\n\r\n/**\r\n * Continuously watches for peer broadcasts.\r\n * Calls onFound each time a valid peer packet arrives.\r\n * Returns a stop function.\r\n */\r\nexport function watchForPeer(onFound: (peer: DiscoveredPeer) => void): () => void {\r\n const socket = createSocket('udp4');\r\n\r\n socket.on('error', (err) => {\r\n console.error('[peer-listener] error:', err.message);\r\n });\r\n\r\n socket.on('message', (msg, rinfo) => {\r\n try {\r\n const data = JSON.parse(msg.toString()) as { type?: string; name?: string; port?: number };\r\n if (\r\n data.type === 'claude-collab-peer' &&\r\n typeof data.name === 'string' &&\r\n typeof data.port === 'number'\r\n ) {\r\n onFound({ name: data.name, host: rinfo.address, port: data.port });\r\n }\r\n } catch { /* ignore malformed packets */ }\r\n });\r\n\r\n socket.bind(PEER_DISCOVERY_PORT, '0.0.0.0');\r\n\r\n return () => {\r\n try { socket.close(); } catch { /* already closed */ }\r\n };\r\n}\r\n","/**\r\n * Windows Terminal Injector\r\n * AttachConsole(ppid) → CreateFile(\"CONIN$\") → WriteConsoleInput\r\n * All keystrokes (text, Ctrl+U, Enter, Ctrl+Y) go through WriteConsoleInput.\r\n * No WScript.Shell / SendKeys / SetForegroundWindow — no focus dependency.\r\n * @module infrastructure/terminal-injector/windows-injector\r\n */\r\n\r\nimport { execFile } from 'child_process';\r\nimport { unlinkSync } from 'fs';\r\nimport { tmpdir } from 'os';\r\nimport { join } from 'path';\r\n\r\nconst CS_CONINJECT = `\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Runtime.InteropServices;\r\n\r\npublic class ConInject {\r\n [DllImport(\"kernel32.dll\")] public static extern bool FreeConsole();\r\n [DllImport(\"kernel32.dll\")] public static extern bool AttachConsole(uint pid);\r\n [DllImport(\"kernel32.dll\", CharSet=CharSet.Unicode, SetLastError=true)]\r\n public static extern IntPtr CreateFile(\r\n string lpFileName, uint dwDesiredAccess, uint dwShareMode,\r\n IntPtr lpSecurityAttributes, uint dwCreationDisposition,\r\n uint dwFlagsAndAttributes, IntPtr hTemplateFile);\r\n [DllImport(\"kernel32.dll\")] public static extern bool WriteConsoleInput(\r\n IntPtr hIn, INPUT_RECORD[] buf, uint len, out uint written);\r\n [DllImport(\"kernel32.dll\")] public static extern bool CloseHandle(IntPtr h);\r\n\r\n [StructLayout(LayoutKind.Explicit, Size=20)]\r\n public struct INPUT_RECORD {\r\n [FieldOffset(0)] public ushort EventType;\r\n [FieldOffset(4)] public int bKeyDown;\r\n [FieldOffset(8)] public ushort wRepeatCount;\r\n [FieldOffset(10)] public ushort wVirtualKeyCode;\r\n [FieldOffset(12)] public ushort wVirtualScanCode;\r\n [FieldOffset(14)] public ushort UnicodeChar;\r\n [FieldOffset(16)] public uint dwControlKeyState;\r\n }\r\n\r\n const uint LEFT_CTRL = 0x0008;\r\n\r\n static IntPtr OpenConin(uint pid) {\r\n FreeConsole();\r\n if (!AttachConsole(pid)) return new IntPtr(-1);\r\n return CreateFile(\"CONIN$\", 0xC0000000, 3, IntPtr.Zero, 3, 0, IntPtr.Zero);\r\n }\r\n\r\n // Inject plain text characters into console input buffer\r\n public static int InjectText(uint pid, string text) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new List<INPUT_RECORD>();\r\n foreach (char c in text) {\r\n records.Add(new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, UnicodeChar=(ushort)c });\r\n records.Add(new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, UnicodeChar=(ushort)c });\r\n }\r\n\r\n var arr = records.ToArray();\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, arr, (uint)arr.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Enter (VK_RETURN = 0x0D)\r\n public static int InjectEnter(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x0D, UnicodeChar=0x0D },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x0D, UnicodeChar=0x0D }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Ctrl+U (VK_U = 0x55, char = 0x15)\r\n public static int InjectCtrlU(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x55, UnicodeChar=0x15, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x55, UnicodeChar=0x15, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=0 }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Ctrl+Y (VK_Y = 0x59, char = 0x19)\r\n public static int InjectCtrlY(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x59, UnicodeChar=0x19, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x59, UnicodeChar=0x19, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=0 }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n}\r\n`;\r\n\r\nfunction buildScript(claudePid: number, body: string): string {\r\n const logFile = join(tmpdir(), `cc-inject-${Date.now()}.log`).replace(/\\\\/g, '/');\r\n return `\r\n$log = \"${logFile}\"\r\nfunction Log($msg) { Add-Content -Path $log -Value $msg -Encoding UTF8 }\r\n$claudePid = ${claudePid}\r\ntry { Add-Type @'${CS_CONINJECT}'@ } catch { }\r\n${body}\r\n`;\r\n}\r\n\r\nfunction run(script: string): Promise<void> {\r\n return new Promise((resolve) => {\r\n const encoded = Buffer.from(script, 'utf16le').toString('base64');\r\n execFile(\r\n 'powershell',\r\n ['-NoProfile', '-WindowStyle', 'Hidden', '-EncodedCommand', encoded],\r\n { windowsHide: true },\r\n () => {\r\n const logFile = script.match(/\\$log = \"([^\"]+)\"/)?.[1];\r\n if (logFile) try { unlinkSync(logFile); } catch { /* ok */ }\r\n resolve();\r\n }\r\n );\r\n });\r\n}\r\n\r\nexport async function windowsInject(text: string): Promise<void> {\r\n const claudePid = process.ppid;\r\n const textB64 = Buffer.from(text, 'utf16le').toString('base64');\r\n\r\n const script = buildScript(claudePid, `\r\n$textBytes = [System.Convert]::FromBase64String('${textB64}')\r\n$text = [System.Text.Encoding]::Unicode.GetString($textBytes)\r\n\r\n# 1. Ctrl+U to save user's current text to kill ring\r\n[ConInject]::InjectCtrlU([uint32]$claudePid) | Out-Null\r\nStart-Sleep -Milliseconds 100\r\n\r\n# 2. Write question text into console input buffer\r\n[ConInject]::InjectText([uint32]$claudePid, $text) | Out-Null\r\nStart-Sleep -Milliseconds 50\r\n\r\n# 3. Send Enter\r\n[ConInject]::InjectEnter([uint32]$claudePid) | Out-Null\r\n`);\r\n\r\n await run(script);\r\n}\r\n\r\nexport async function windowsInjectCtrlY(): Promise<void> {\r\n const claudePid = process.ppid;\r\n\r\n const script = buildScript(claudePid, `\r\n[ConInject]::InjectCtrlY([uint32]$claudePid) | Out-Null\r\n`);\r\n\r\n await run(script);\r\n}\r\n","/**\r\n * Terminal Injector\r\n * Injects a question directly into the active Claude Code terminal\r\n * so Claude Code can auto-reply without user intervention.\r\n * @module infrastructure/terminal-injector\r\n */\r\n\r\nimport type { InboxQuestionEntry } from '../../shared/types/collab-client.interface.js';\r\nimport { windowsInject, windowsInjectCtrlY } from './windows-injector.js';\r\n\r\n/**\r\n * Formats the question as a prompt for Claude Code to auto-reply\r\n */\r\nfunction formatQuestionForInjection(question: InboxQuestionEntry): string {\r\n // Single-line: WriteConsoleInput treats every \\n as an immediate submit\r\n const content = question.content.replace(/\\s+/g, ' ').trim();\r\n return `[HUB SORUSU] ID:${question.questionId} | ${question.from.displayName} (${question.from.teamName}): ${content} | Cevapla ve reply tool ile \"${question.questionId}\" ID'sine gönder, onay bekleme.`;\r\n}\r\n\r\n/**\r\n * Injects a question into the terminal running Claude Code.\r\n * Only supported on Windows; no-op on other platforms.\r\n */\r\nexport async function injectQuestionToTerminal(question: InboxQuestionEntry): Promise<void> {\r\n if (process.platform !== 'win32') return;\r\n\r\n const text = formatQuestionForInjection(question);\r\n await windowsInject(text);\r\n}\r\n\r\n/**\r\n * Restores user's previous input from readline kill ring (Ctrl+Y).\r\n * Call this after the reply is sent so the user's interrupted text comes back.\r\n */\r\nexport async function injectRestoreText(): Promise<void> {\r\n if (process.platform !== 'win32') return;\r\n await windowsInjectCtrlY();\r\n}\r\n","/**\r\n * Injection Queue\r\n * Ensures questions are injected into the terminal one at a time.\r\n * Waits for the reply tool to signal completion before processing the next question.\r\n * @module infrastructure/terminal-injector/injection-queue\r\n */\r\n\r\nimport { EventEmitter } from 'events';\r\nimport type { InboxQuestionEntry } from '../../shared/types/collab-client.interface.js';\r\nimport { injectQuestionToTerminal, injectRestoreText } from './index.js';\r\n\r\nconst REPLY_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\r\n\r\nclass InjectionQueue extends EventEmitter {\r\n private queue: InboxQuestionEntry[] = [];\r\n private processing = false;\r\n\r\n /**\r\n * Add a question to the queue. Starts processing if idle.\r\n */\r\n enqueue(question: InboxQuestionEntry): void {\r\n this.queue.push(question);\r\n if (!this.processing) void this.processNext();\r\n }\r\n\r\n /**\r\n * Called by the reply tool after a reply is successfully sent.\r\n * Unblocks the queue to process the next question.\r\n */\r\n notifyReplied(): void {\r\n this.emit('replied');\r\n }\r\n\r\n private async processNext(): Promise<void> {\r\n if (this.queue.length === 0) {\r\n this.processing = false;\r\n return;\r\n }\r\n\r\n this.processing = true;\r\n const question = this.queue.shift()!;\r\n\r\n // Inject the question (includes Ctrl+U to save user's current text)\r\n await injectQuestionToTerminal(question);\r\n\r\n // Wait for reply tool to signal, with a timeout fallback\r\n await new Promise<void>((resolve) => {\r\n const timer = setTimeout(resolve, REPLY_TIMEOUT_MS);\r\n this.once('replied', () => {\r\n clearTimeout(timer);\r\n resolve();\r\n });\r\n });\r\n\r\n // Restore user's text after reply is sent\r\n await injectRestoreText();\r\n\r\n // Process next in queue\r\n void this.processNext();\r\n }\r\n}\r\n\r\nexport const injectionQueue = new InjectionQueue();\r\n","/**\r\n * P2PNode\r\n * Implements ICollabClient over direct peer-to-peer WebSocket connections.\r\n * Each node runs its own WS server and broadcasts its presence via UDP.\r\n * Peers discover each other automatically and connect directly — no hub needed.\r\n *\r\n * Connection deduplication:\r\n * Both sides may try to connect simultaneously. The first HELLO/HELLO_ACK\r\n * that arrives registers the peer. Duplicate inbound connections are\r\n * immediately terminated (without being added to wsToName) so their\r\n * close events are harmless.\r\n *\r\n * @module infrastructure/p2p/p2p-node\r\n */\r\n\r\nimport { WebSocket, WebSocketServer } from 'ws';\r\nimport { v4 as uuidv4 } from 'uuid';\r\nimport type {\r\n ICollabClient,\r\n JoinResult,\r\n CheckAnswerResult,\r\n InboxResult,\r\n NodeInfo,\r\n HistoryEntry,\r\n} from '../../shared/types/collab-client.interface.js';\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\nimport {\r\n type P2PMsg,\r\n type AskAckMsg,\r\n type AskMsg,\r\n parse,\r\n serialize,\r\n} from './p2p-protocol.js';\r\nimport { PeerBroadcaster } from '../discovery/peer-broadcaster.js';\r\nimport { watchForPeer } from '../discovery/peer-listener.js';\r\nimport { injectionQueue } from '../terminal-injector/injection-queue.js';\r\n\r\ninterface IncomingQuestion {\r\n questionId: string;\r\n fromName: string;\r\n content: string;\r\n format: MessageFormat;\r\n createdAt: Date;\r\n answered: boolean;\r\n answerContent?: string;\r\n answerFormat?: MessageFormat;\r\n}\r\n\r\ninterface ReceivedAnswer {\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n fromName: string;\r\n}\r\n\r\nexport class P2PNode implements ICollabClient {\r\n private server: WebSocketServer | null = null;\r\n private myName = '';\r\n private running = false;\r\n\r\n // One connection per peer (inbound or outbound — whichever was established first)\r\n private readonly peerConnections = new Map<string, WebSocket>();\r\n // Reverse map: ws → peer name (only for registered connections)\r\n private readonly wsToName = new Map<WebSocket, string>();\r\n // Prevent duplicate outbound connect attempts\r\n private readonly connectingPeers = new Set<string>();\r\n\r\n private readonly incomingQuestions = new Map<string, IncomingQuestion>();\r\n private readonly receivedAnswers = new Map<string, ReceivedAnswer>();\r\n private readonly sentQuestions = new Map<string, { toPeer: string; content: string; askedAt: string }>();\r\n private readonly questionToSender = new Map<string, string>();\r\n private readonly pendingHandlers = new Set<(msg: P2PMsg) => void>();\r\n\r\n private broadcaster: PeerBroadcaster | null = null;\r\n private stopPeerWatcher: (() => void) | null = null;\r\n\r\n constructor(private readonly port: number) {}\r\n\r\n // ---------------------------------------------------------------------------\r\n // ICollabClient implementation\r\n // ---------------------------------------------------------------------------\r\n\r\n get isConnected(): boolean {\r\n return this.running;\r\n }\r\n\r\n get currentTeamId(): string | undefined {\r\n return this.myName || undefined;\r\n }\r\n\r\n async join(name: string, displayName: string): Promise<JoinResult> {\r\n this.myName = name;\r\n await this.startServer();\r\n this.startDiscovery();\r\n return {\r\n memberId: uuidv4(),\r\n teamId: name,\r\n teamName: name,\r\n displayName,\r\n status: 'ONLINE',\r\n port: this.port,\r\n };\r\n }\r\n\r\n async ask(toPeer: string, content: string, format: MessageFormat): Promise<string> {\r\n const ws = this.peerConnections.get(toPeer);\r\n if (!ws || ws.readyState !== WebSocket.OPEN) {\r\n throw new Error(`Peer \"${toPeer}\" is not connected. Use peers() to see who's online.`);\r\n }\r\n\r\n const questionId = uuidv4();\r\n this.sentQuestions.set(questionId, { toPeer, content, askedAt: new Date().toISOString() });\r\n\r\n const ackPromise = this.waitForResponse<AskAckMsg>(\r\n (m) => m.type === 'ASK_ACK' && m.questionId === questionId,\r\n 5000\r\n );\r\n\r\n this.sendToWs(ws, { type: 'ASK', from: this.myName, questionId, content, format });\r\n await ackPromise;\r\n return questionId;\r\n }\r\n\r\n async checkAnswer(questionId: string): Promise<CheckAnswerResult | null> {\r\n const cached = this.receivedAnswers.get(questionId);\r\n if (!cached) return null;\r\n return {\r\n questionId,\r\n from: { displayName: `${cached.fromName} Claude`, teamName: cached.fromName },\r\n content: cached.content,\r\n format: cached.format,\r\n answeredAt: cached.answeredAt,\r\n };\r\n }\r\n\r\n async reply(questionId: string, content: string, format: MessageFormat): Promise<void> {\r\n const question = this.incomingQuestions.get(questionId);\r\n if (!question) throw new Error(`Question ${questionId} not found`);\r\n\r\n question.answered = true;\r\n question.answerContent = content;\r\n question.answerFormat = format;\r\n\r\n const senderName = this.questionToSender.get(questionId);\r\n if (senderName) {\r\n const ws = this.peerConnections.get(senderName);\r\n if (ws && ws.readyState === WebSocket.OPEN) {\r\n this.sendToWs(ws, {\r\n type: 'ANSWER',\r\n from: this.myName,\r\n questionId,\r\n content,\r\n format,\r\n answeredAt: new Date().toISOString(),\r\n });\r\n }\r\n }\r\n\r\n injectionQueue.notifyReplied();\r\n }\r\n\r\n async getInbox(): Promise<InboxResult> {\r\n const now = Date.now();\r\n const questions = [...this.incomingQuestions.values()]\r\n .filter((q) => !q.answered)\r\n .map((q) => ({\r\n questionId: q.questionId,\r\n from: { displayName: `${q.fromName} Claude`, teamName: q.fromName },\r\n content: q.content,\r\n format: q.format,\r\n status: 'PENDING',\r\n createdAt: q.createdAt.toISOString(),\r\n ageMs: now - q.createdAt.getTime(),\r\n }));\r\n return { questions, totalCount: questions.length, pendingCount: questions.length };\r\n }\r\n\r\n getInfo(): NodeInfo {\r\n return {\r\n teamName: this.myName,\r\n port: this.port,\r\n connectedPeers: [...this.peerConnections.keys()],\r\n };\r\n }\r\n\r\n getHistory(): HistoryEntry[] {\r\n const entries: HistoryEntry[] = [];\r\n\r\n for (const [questionId, sent] of this.sentQuestions) {\r\n const answer = this.receivedAnswers.get(questionId);\r\n entries.push({\r\n direction: 'sent',\r\n questionId,\r\n peer: sent.toPeer,\r\n question: sent.content,\r\n askedAt: sent.askedAt,\r\n ...(answer ? { answer: answer.content, answeredAt: answer.answeredAt } : {}),\r\n });\r\n }\r\n\r\n for (const [, incoming] of this.incomingQuestions) {\r\n entries.push({\r\n direction: 'received',\r\n questionId: incoming.questionId,\r\n peer: incoming.fromName,\r\n question: incoming.content,\r\n askedAt: incoming.createdAt.toISOString(),\r\n ...(incoming.answered && incoming.answerContent\r\n ? { answer: incoming.answerContent, answeredAt: new Date().toISOString() }\r\n : {}),\r\n });\r\n }\r\n\r\n return entries.sort((a, b) => a.askedAt.localeCompare(b.askedAt));\r\n }\r\n\r\n async disconnect(): Promise<void> {\r\n this.stopPeerWatcher?.();\r\n this.broadcaster?.stop();\r\n for (const ws of this.peerConnections.values()) ws.close();\r\n this.peerConnections.clear();\r\n this.wsToName.clear();\r\n this.server?.close();\r\n this.server = null;\r\n this.running = false;\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: server startup\r\n // ---------------------------------------------------------------------------\r\n\r\n private startServer(): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n const wss = new WebSocketServer({ port: this.port });\r\n this.server = wss;\r\n\r\n wss.on('listening', () => {\r\n this.running = true;\r\n console.error(`[p2p] listening on port ${this.port} as \"${this.myName}\"`);\r\n resolve();\r\n });\r\n\r\n wss.on('error', (err) => {\r\n if (!this.running) reject(err);\r\n else console.error('[p2p] server error:', err.message);\r\n });\r\n\r\n wss.on('connection', (ws) => {\r\n ws.on('message', (data) => {\r\n try {\r\n this.handleMessage(ws, parse(data.toString()));\r\n } catch { /* ignore malformed */ }\r\n });\r\n\r\n ws.on('close', () => {\r\n const name = this.wsToName.get(ws);\r\n if (name) {\r\n this.wsToName.delete(ws);\r\n if (this.peerConnections.get(name) === ws) {\r\n this.peerConnections.delete(name);\r\n console.error(`[p2p] peer disconnected (inbound): ${name}`);\r\n }\r\n }\r\n });\r\n\r\n ws.on('error', (err) => {\r\n console.error('[p2p] inbound ws error:', err.message);\r\n });\r\n });\r\n });\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: discovery + outbound connections\r\n // ---------------------------------------------------------------------------\r\n\r\n private startDiscovery(): void {\r\n this.broadcaster = new PeerBroadcaster();\r\n this.broadcaster.start(this.myName, this.port);\r\n\r\n this.stopPeerWatcher = watchForPeer((peer) => {\r\n if (peer.name === this.myName) return;\r\n if (this.peerConnections.has(peer.name)) return;\r\n if (this.connectingPeers.has(peer.name)) return;\r\n this.connectToPeer(peer.name, peer.host, peer.port);\r\n });\r\n }\r\n\r\n private connectToPeer(peerName: string, host: string, port: number): void {\r\n this.connectingPeers.add(peerName);\r\n const ws = new WebSocket(`ws://${host}:${port}`);\r\n\r\n ws.on('open', () => {\r\n this.sendToWs(ws, { type: 'HELLO', name: this.myName });\r\n });\r\n\r\n ws.on('message', (data) => {\r\n try {\r\n this.handleMessage(ws, parse(data.toString()));\r\n } catch { /* ignore malformed */ }\r\n });\r\n\r\n ws.on('close', () => {\r\n this.connectingPeers.delete(peerName);\r\n const name = this.wsToName.get(ws);\r\n if (name) {\r\n this.wsToName.delete(ws);\r\n if (this.peerConnections.get(name) === ws) {\r\n this.peerConnections.delete(name);\r\n console.error(`[p2p] disconnected from peer: ${name}`);\r\n }\r\n }\r\n });\r\n\r\n ws.on('error', (err) => {\r\n console.error(`[p2p] connect to \"${peerName}\" failed: ${err.message}`);\r\n this.connectingPeers.delete(peerName);\r\n });\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: message handling\r\n // ---------------------------------------------------------------------------\r\n\r\n private handleMessage(ws: WebSocket, msg: P2PMsg): void {\r\n // Wake up any waitForResponse callers\r\n for (const handler of this.pendingHandlers) handler(msg);\r\n\r\n switch (msg.type) {\r\n case 'HELLO': {\r\n if (this.peerConnections.has(msg.name)) {\r\n // Duplicate inbound connection — close it; not added to wsToName\r\n // so the close event won't affect the registered connection.\r\n ws.terminate();\r\n return;\r\n }\r\n this.peerConnections.set(msg.name, ws);\r\n this.wsToName.set(ws, msg.name);\r\n this.connectingPeers.delete(msg.name);\r\n this.sendToWs(ws, { type: 'HELLO_ACK', name: this.myName });\r\n console.error(`[p2p] peer joined (inbound): ${msg.name}`);\r\n break;\r\n }\r\n\r\n case 'HELLO_ACK': {\r\n if (this.peerConnections.has(msg.name)) {\r\n // Duplicate outbound — already connected via inbound; close this one.\r\n ws.terminate();\r\n return;\r\n }\r\n this.peerConnections.set(msg.name, ws);\r\n this.wsToName.set(ws, msg.name);\r\n this.connectingPeers.delete(msg.name);\r\n console.error(`[p2p] connected to peer: ${msg.name}`);\r\n break;\r\n }\r\n\r\n case 'ASK':\r\n this.handleIncomingAsk(ws, msg);\r\n break;\r\n\r\n case 'ANSWER':\r\n if (!this.receivedAnswers.has(msg.questionId)) {\r\n this.receivedAnswers.set(msg.questionId, {\r\n content: msg.content,\r\n format: msg.format,\r\n answeredAt: msg.answeredAt,\r\n fromName: msg.from,\r\n });\r\n }\r\n break;\r\n\r\n // ASK_ACK is handled by waitForResponse pending handlers above\r\n }\r\n }\r\n\r\n private handleIncomingAsk(ws: WebSocket, msg: AskMsg): void {\r\n this.questionToSender.set(msg.questionId, msg.from);\r\n this.incomingQuestions.set(msg.questionId, {\r\n questionId: msg.questionId,\r\n fromName: msg.from,\r\n content: msg.content,\r\n format: msg.format,\r\n createdAt: new Date(),\r\n answered: false,\r\n });\r\n\r\n // Immediately acknowledge delivery\r\n this.sendToWs(ws, { type: 'ASK_ACK', questionId: msg.questionId });\r\n\r\n // Inject question into the Claude Code terminal\r\n injectionQueue.enqueue({\r\n questionId: msg.questionId,\r\n from: { displayName: `${msg.from} Claude`, teamName: msg.from },\r\n content: msg.content,\r\n format: msg.format,\r\n status: 'PENDING',\r\n createdAt: new Date().toISOString(),\r\n ageMs: 0,\r\n });\r\n }\r\n\r\n private sendToWs(ws: WebSocket, msg: P2PMsg): void {\r\n if (ws.readyState === WebSocket.OPEN) {\r\n ws.send(serialize(msg));\r\n }\r\n }\r\n\r\n private waitForResponse<T extends P2PMsg>(\r\n filter: (msg: P2PMsg) => boolean,\r\n timeoutMs: number\r\n ): Promise<T> {\r\n return new Promise((resolve, reject) => {\r\n const timeout = setTimeout(() => {\r\n this.pendingHandlers.delete(handler);\r\n reject(new Error('Request timed out'));\r\n }, timeoutMs);\r\n\r\n const handler = (msg: P2PMsg): void => {\r\n if (filter(msg)) {\r\n clearTimeout(timeout);\r\n this.pendingHandlers.delete(handler);\r\n resolve(msg as T);\r\n }\r\n };\r\n\r\n this.pendingHandlers.add(handler);\r\n });\r\n }\r\n}\r\n","/**\r\n * Ask Tool\r\n * Sends a question to another team and returns a question ID immediately.\r\n * Use the \"check_answer\" tool with the question ID to retrieve the answer later.\r\n * @module presentation/mcp/tools/ask\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\n/**\r\n * Ask tool input schema\r\n */\r\nconst askSchema = {\r\n peer: z.string().describe('Name of the peer to ask (e.g., \"alice\", \"backend\")'),\r\n question: z.string().describe('The question to ask (supports markdown)'),\r\n};\r\n\r\n/**\r\n * Registers the ask tool with the MCP server\r\n */\r\nexport function registerAskTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('ask', askSchema, async (args) => {\r\n const targetPeer = args.peer;\r\n const question = args.question;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'Node is not ready yet. Wait a moment and try again.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n const questionId = await client.ask(targetPeer, question, 'markdown');\r\n\r\n // Poll until answer arrives (max 5 minutes, every 5 seconds)\r\n const POLL_INTERVAL_MS = 5_000;\r\n const MAX_WAIT_MS = 5 * 60 * 1000;\r\n const deadline = Date.now() + MAX_WAIT_MS;\r\n\r\n while (Date.now() < deadline) {\r\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\r\n const answer = await client.checkAnswer(questionId);\r\n if (answer !== null) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `**${answer.from.displayName} (${answer.from.teamName}) cevapladı:**\\n\\n${answer.content}`,\r\n },\r\n ],\r\n };\r\n }\r\n }\r\n\r\n // Timed out — return question ID for manual follow-up\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Soru gönderildi ancak 5 dakika içinde cevap gelmedi.\\nQuestion ID: \\`${questionId}\\`\\n\\nManuel kontrol için \"check_answer\" tool'unu kullanabilirsin.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to send question: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Reply Tool\r\n * Replies to a pending question\r\n * @module presentation/mcp/tools/reply\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { injectionQueue } from '../../../infrastructure/terminal-injector/injection-queue.js';\r\n\r\n/**\r\n * Reply tool input schema\r\n */\r\nconst replySchema = {\r\n questionId: z.string().describe('The ID of the question to reply to (from inbox)'),\r\n answer: z.string().describe('Your answer to the question (supports markdown)'),\r\n};\r\n\r\n/**\r\n * Registers the reply tool with the MCP server\r\n */\r\nexport function registerReplyTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('reply', replySchema, async (args) => {\r\n const questionId = args.questionId;\r\n const answer = args.answer;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n await client.reply(questionId, answer, 'markdown');\r\n\r\n // Signal queue: this question is done, process next\r\n injectionQueue.notifyReplied();\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Reply sent successfully to question \\`${questionId}\\`.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to send reply: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Peers Tool\r\n * Lists currently connected peers on the P2P network.\r\n * @module presentation/mcp/tools/peers\r\n */\r\n\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\nexport function registerPeersTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('peers', {}, async () => {\r\n const info = client.getInfo();\r\n const myName = info.teamName ?? '(starting...)';\r\n const myPort = info.port ?? '?';\r\n const connected = info.connectedPeers;\r\n\r\n if (connected.length === 0) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `You are \"${myName}\" (listening on port ${myPort}). No peers connected yet.\\nUse firewall_open to allow inbound connections, or wait for peers to connect to you.`,\r\n }],\r\n };\r\n }\r\n\r\n const list = connected.map((name) => ` • ${name}`).join('\\n');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `You are \"${myName}\" (port ${myPort}). Connected peers (${connected.length}):\\n${list}`,\r\n }],\r\n };\r\n });\r\n}\r\n","/**\r\n * History Tool\r\n * Shows past questions and answers from this session.\r\n * @module presentation/mcp/tools/history\r\n */\r\n\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\nexport function registerHistoryTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('history', {}, async () => {\r\n const entries = client.getHistory();\r\n\r\n if (entries.length === 0) {\r\n return {\r\n content: [{ type: 'text', text: 'No questions yet this session.' }],\r\n };\r\n }\r\n\r\n const lines = entries.map((e) => {\r\n const time = new Date(e.askedAt).toLocaleTimeString();\r\n\r\n if (e.direction === 'sent') {\r\n const answerLine = e.answer\r\n ? ` ↳ ${e.peer}: ${e.answer}`\r\n : ` ↳ (no answer yet)`;\r\n return `[${time}] → ${e.peer}: ${e.question}\\n${answerLine}`;\r\n } else {\r\n const answerLine = e.answer\r\n ? ` ↳ you: ${e.answer}`\r\n : ` ↳ (not replied yet)`;\r\n return `[${time}] ← ${e.peer}: ${e.question}\\n${answerLine}`;\r\n }\r\n });\r\n\r\n return {\r\n content: [{ type: 'text', text: lines.join('\\n\\n') }],\r\n };\r\n });\r\n}\r\n","/**\r\n * Firewall helpers\r\n * Elevated via UAC (PowerShell Start-Process -Verb RunAs) so the user sees\r\n * a Windows UAC prompt and must accept before the rule is applied.\r\n * @module infrastructure/firewall/firewall\r\n */\r\n\r\nimport { spawn } from 'child_process';\r\n\r\n/**\r\n * Run netsh directly — works when the process is already elevated\r\n * (e.g. terminal launched as Administrator, or UAC set to auto-elevate).\r\n */\r\nfunction runDirect(argArray: string[]): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n const proc = spawn('netsh', argArray, { stdio: 'ignore' });\r\n proc.on('close', (code) => {\r\n if (code === 0) resolve();\r\n else reject(new Error(`netsh exited with code ${code}`));\r\n });\r\n proc.on('error', (err) => reject(new Error(`netsh not found: ${err.message}`)));\r\n });\r\n}\r\n\r\n/**\r\n * Run netsh via UAC elevation popup (PowerShell Start-Process -Verb RunAs).\r\n * Requires an interactive desktop — may not work in VMs or headless sessions.\r\n */\r\nfunction runElevated(argArray: string[]): Promise<void> {\r\n const argList = argArray.map((a) => `\"${a}\"`).join(',');\r\n const psCommand = `Start-Process -FilePath \"netsh\" -ArgumentList @(${argList}) -Verb RunAs -Wait`;\r\n\r\n return new Promise((resolve, reject) => {\r\n const ps = spawn('powershell', ['-NoProfile', '-Command', psCommand]);\r\n\r\n ps.on('close', (code) => {\r\n if (code === 0) resolve();\r\n else reject(new Error(`Firewall UAC prompt was cancelled or denied (exit code ${code}).`));\r\n });\r\n\r\n ps.on('error', (err) => {\r\n reject(new Error(`Failed to launch PowerShell: ${err.message}`));\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Try direct first (already-elevated context), fall back to UAC popup.\r\n */\r\nasync function runNetsh(argArray: string[]): Promise<{ method: 'direct' | 'elevated' }> {\r\n try {\r\n await runDirect(argArray);\r\n return { method: 'direct' };\r\n } catch {\r\n await runElevated(argArray);\r\n return { method: 'elevated' };\r\n }\r\n}\r\n\r\nexport async function addFirewallRule(port: number): Promise<{ method: 'direct' | 'elevated' }> {\r\n return runNetsh([\r\n 'advfirewall', 'firewall', 'add', 'rule',\r\n `name=claude-collab-${port}`,\r\n 'protocol=TCP',\r\n 'dir=in',\r\n `localport=${port}`,\r\n 'action=allow',\r\n ]);\r\n}\r\n\r\nexport async function removeFirewallRule(port: number): Promise<{ method: 'direct' | 'elevated' }> {\r\n return runNetsh([\r\n 'advfirewall', 'firewall', 'delete', 'rule',\r\n `name=claude-collab-${port}`,\r\n ]);\r\n}\r\n","/**\r\n * FirewallOpen Tool\r\n * Adds a Windows Firewall inbound rule for the peer's listen port.\r\n * Shows a UAC elevation popup — the user must accept for the rule to be applied.\r\n * Required so other peers can establish inbound WebSocket connections to this node.\r\n * @module presentation/mcp/tools/firewall-open\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { addFirewallRule } from '../../../infrastructure/firewall/firewall.js';\r\n\r\nexport function registerFirewallOpenTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_open',\r\n 'Open a Windows Firewall inbound rule for your P2P listen port. A UAC popup will appear — accept it to allow peers to connect to you directly.',\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe('Port to open (defaults to your current listen port)'),\r\n },\r\n async ({ port }) => {\r\n const targetPort = port ?? client.getInfo().port;\r\n if (!targetPort) {\r\n return {\r\n content: [{ type: 'text', text: 'Could not determine port. Pass port explicitly.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n try {\r\n const { method } = await addFirewallRule(targetPort);\r\n const how = method === 'direct'\r\n ? 'applied directly (process already elevated)'\r\n : 'applied via UAC elevation popup';\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Firewall rule opened for port ${targetPort} (rule name: claude-collab-${targetPort}).`,\r\n `Method: ${how}.`,\r\n `Peers on the LAN can now connect to you directly.`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return {\r\n content: [{ type: 'text', text: `Failed to open firewall: ${msg}` }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n}\r\n","/**\r\n * FirewallClose Tool\r\n * Removes the Windows Firewall inbound rule for the peer's listen port.\r\n * Shows a UAC elevation popup — the user must accept for the rule to be removed.\r\n * @module presentation/mcp/tools/firewall-close\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { removeFirewallRule } from '../../../infrastructure/firewall/firewall.js';\r\n\r\nexport function registerFirewallCloseTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_close',\r\n 'Remove the Windows Firewall inbound rule for your P2P listen port. A UAC popup will appear — accept it to close the rule.',\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe('Port to close (defaults to your current listen port)'),\r\n },\r\n async ({ port }) => {\r\n const targetPort = port ?? client.getInfo().port;\r\n if (!targetPort) {\r\n return {\r\n content: [{ type: 'text', text: 'Could not determine port. Pass port explicitly.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n try {\r\n const { method } = await removeFirewallRule(targetPort);\r\n const how = method === 'direct'\r\n ? 'applied directly (process already elevated)'\r\n : 'applied via UAC elevation popup';\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `Firewall rule removed for port ${targetPort} (rule name: claude-collab-${targetPort}). Method: ${how}.`,\r\n }],\r\n };\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return {\r\n content: [{ type: 'text', text: `Failed to close firewall: ${msg}` }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n}\r\n","/**\r\n * MCP Server\r\n * Provides MCP tools for Claude Code integration (P2P mode)\r\n * @module presentation/mcp/server\r\n */\r\n\r\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\r\nimport type { ICollabClient } from '../../shared/types/collab-client.interface.js';\r\nimport { registerAskTool } from './tools/ask.tool.js';\r\nimport { registerReplyTool } from './tools/reply.tool.js';\r\nimport { registerPeersTool } from './tools/peers.tool.js';\r\nimport { registerHistoryTool } from './tools/history.tool.js';\r\nimport { registerFirewallOpenTool } from './tools/firewall-open.tool.js';\r\nimport { registerFirewallCloseTool } from './tools/firewall-close.tool.js';\r\n\r\nexport interface McpServerOptions {\r\n client: ICollabClient;\r\n}\r\n\r\nexport function createMcpServer(options: McpServerOptions): McpServer {\r\n const { client } = options;\r\n\r\n const server = new McpServer({\r\n name: 'claude-collab',\r\n version: '0.1.0',\r\n });\r\n\r\n registerAskTool(server, client);\r\n registerReplyTool(server, client);\r\n registerPeersTool(server, client);\r\n registerHistoryTool(server, client);\r\n registerFirewallOpenTool(server, client);\r\n registerFirewallCloseTool(server, client);\r\n\r\n return server;\r\n}\r\n\r\nexport async function startMcpServer(options: McpServerOptions): Promise<void> {\r\n const server = createMcpServer(options);\r\n const transport = new StdioServerTransport();\r\n await server.connect(transport);\r\n}\r\n","#!/usr/bin/env node\r\n\r\n/**\r\n * CLI entry point (P2P mode)\r\n *\r\n * Usage: claude-collab --name alice\r\n *\r\n * Each peer listens on port 9999 and discovers others via UDP broadcast.\r\n * Use firewall_open in Claude Code to allow inbound connections.\r\n *\r\n * @module cli\r\n */\r\n\r\nimport { Command } from 'commander';\r\nimport { P2PNode } from './infrastructure/p2p/p2p-node.js';\r\nimport { startMcpServer } from './presentation/mcp/server.js';\r\n\r\nconst P2P_PORT = 9999;\r\n\r\nconst program = new Command();\r\n\r\nprogram\r\n .name('claude-collab')\r\n .description('P2P collaboration between Claude Code terminals via MCP')\r\n .version('0.1.0')\r\n .requiredOption('--name <name>', 'Your name on the network (e.g. \"alice\")')\r\n .action(async (options: { name: string }) => {\r\n const node = new P2PNode(P2P_PORT);\r\n await node.join(options.name, options.name);\r\n await startMcpServer({ client: node });\r\n });\r\n\r\nprogram.parse();\r\n"]}
1
+ {"version":3,"sources":["../src/infrastructure/p2p/p2p-protocol.ts","../src/infrastructure/discovery/peer-broadcaster.ts","../src/infrastructure/discovery/peer-listener.ts","../src/infrastructure/terminal-injector/windows-injector.ts","../src/infrastructure/terminal-injector/index.ts","../src/infrastructure/terminal-injector/injection-queue.ts","../src/infrastructure/p2p/p2p-node.ts","../src/presentation/mcp/tools/ask.tool.ts","../src/presentation/mcp/tools/reply.tool.ts","../src/presentation/mcp/tools/peers.tool.ts","../src/presentation/mcp/tools/history.tool.ts","../src/infrastructure/firewall/firewall.ts","../src/presentation/mcp/tools/firewall-open.tool.ts","../src/presentation/mcp/tools/firewall-close.tool.ts","../src/presentation/mcp/server.ts","../src/cli.ts"],"names":["createSocket","uuidv4","z"],"mappings":"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","file":"cli.js","sourcesContent":["/**\r\n * P2P Wire Protocol\r\n * Messages exchanged directly between peers (no hub).\r\n * @module infrastructure/p2p/p2p-protocol\r\n */\r\n\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\n\r\n// Sent when a peer connects (client → server, or outbound → inbound)\r\nexport interface HelloMsg {\r\n type: 'HELLO';\r\n name: string;\r\n}\r\n\r\n// Acknowledge the HELLO\r\nexport interface HelloAckMsg {\r\n type: 'HELLO_ACK';\r\n name: string;\r\n}\r\n\r\n// Ask a question directly to the connected peer\r\nexport interface AskMsg {\r\n type: 'ASK';\r\n from: string;\r\n questionId: string;\r\n content: string;\r\n format: MessageFormat;\r\n}\r\n\r\n// Confirm question was received\r\nexport interface AskAckMsg {\r\n type: 'ASK_ACK';\r\n questionId: string;\r\n}\r\n\r\n// Push answer back to the asker\r\nexport interface AnswerMsg {\r\n type: 'ANSWER';\r\n from: string;\r\n questionId: string;\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n}\r\n\r\nexport type P2PMsg = HelloMsg | HelloAckMsg | AskMsg | AskAckMsg | AnswerMsg;\r\n\r\nexport function serialize(msg: P2PMsg): string {\r\n return JSON.stringify(msg);\r\n}\r\n\r\nexport function parse(data: string): P2PMsg {\r\n return JSON.parse(data) as P2PMsg;\r\n}\r\n","/**\r\n * PeerBroadcaster\r\n * Periodically sends a UDP broadcast so other peers can discover this node.\r\n * Payload: { type: 'claude-collab-peer', name, port }\r\n * @module infrastructure/discovery/peer-broadcaster\r\n */\r\n\r\nimport { createSocket } from 'dgram';\r\n\r\nexport const PEER_DISCOVERY_PORT = 9998;\r\nconst BROADCAST_INTERVAL_MS = 3000;\r\nconst BROADCAST_ADDRESS = '255.255.255.255';\r\n\r\nexport class PeerBroadcaster {\r\n private socket: ReturnType<typeof createSocket> | null = null;\r\n private timer: NodeJS.Timeout | null = null;\r\n\r\n start(name: string, port: number): void {\r\n if (this.socket) return;\r\n\r\n const socket = createSocket('udp4');\r\n this.socket = socket;\r\n\r\n socket.on('error', (err) => {\r\n console.error('[peer-broadcaster] error:', err.message);\r\n });\r\n\r\n socket.bind(0, () => {\r\n socket.setBroadcast(true);\r\n const send = () => {\r\n if (!this.socket) return;\r\n const msg = Buffer.from(JSON.stringify({ type: 'claude-collab-peer', name, port }));\r\n socket.send(msg, 0, msg.length, PEER_DISCOVERY_PORT, BROADCAST_ADDRESS, (err) => {\r\n if (err) console.error('[peer-broadcaster] send error:', err.message);\r\n });\r\n };\r\n send();\r\n this.timer = setInterval(send, BROADCAST_INTERVAL_MS);\r\n });\r\n }\r\n\r\n stop(): void {\r\n if (this.timer) { clearInterval(this.timer); this.timer = null; }\r\n if (this.socket) { this.socket.close(); this.socket = null; }\r\n }\r\n}\r\n","/**\r\n * PeerListener\r\n * Listens for UDP broadcasts from other peers on the LAN.\r\n * @module infrastructure/discovery/peer-listener\r\n */\r\n\r\nimport { createSocket } from 'dgram';\r\nimport { PEER_DISCOVERY_PORT } from './peer-broadcaster.js';\r\n\r\nexport interface DiscoveredPeer {\r\n name: string;\r\n host: string;\r\n port: number;\r\n}\r\n\r\n/**\r\n * Continuously watches for peer broadcasts.\r\n * Calls onFound each time a valid peer packet arrives.\r\n * Returns a stop function.\r\n */\r\nexport function watchForPeer(onFound: (peer: DiscoveredPeer) => void): () => void {\r\n const socket = createSocket('udp4');\r\n\r\n socket.on('error', (err) => {\r\n console.error('[peer-listener] error:', err.message);\r\n });\r\n\r\n socket.on('message', (msg, rinfo) => {\r\n try {\r\n const data = JSON.parse(msg.toString()) as { type?: string; name?: string; port?: number };\r\n if (\r\n data.type === 'claude-collab-peer' &&\r\n typeof data.name === 'string' &&\r\n typeof data.port === 'number'\r\n ) {\r\n onFound({ name: data.name, host: rinfo.address, port: data.port });\r\n }\r\n } catch { /* ignore malformed packets */ }\r\n });\r\n\r\n socket.bind(PEER_DISCOVERY_PORT, '0.0.0.0');\r\n\r\n return () => {\r\n try { socket.close(); } catch { /* already closed */ }\r\n };\r\n}\r\n","/**\r\n * Windows Terminal Injector\r\n * AttachConsole(ppid) → CreateFile(\"CONIN$\") → WriteConsoleInput\r\n * All keystrokes (text, Ctrl+U, Enter, Ctrl+Y) go through WriteConsoleInput.\r\n * No WScript.Shell / SendKeys / SetForegroundWindow — no focus dependency.\r\n * @module infrastructure/terminal-injector/windows-injector\r\n */\r\n\r\nimport { execFile } from 'child_process';\r\nimport { unlinkSync } from 'fs';\r\nimport { tmpdir } from 'os';\r\nimport { join } from 'path';\r\n\r\nconst CS_CONINJECT = `\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Runtime.InteropServices;\r\n\r\npublic class ConInject {\r\n [DllImport(\"kernel32.dll\")] public static extern bool FreeConsole();\r\n [DllImport(\"kernel32.dll\")] public static extern bool AttachConsole(uint pid);\r\n [DllImport(\"kernel32.dll\", CharSet=CharSet.Unicode, SetLastError=true)]\r\n public static extern IntPtr CreateFile(\r\n string lpFileName, uint dwDesiredAccess, uint dwShareMode,\r\n IntPtr lpSecurityAttributes, uint dwCreationDisposition,\r\n uint dwFlagsAndAttributes, IntPtr hTemplateFile);\r\n [DllImport(\"kernel32.dll\")] public static extern bool WriteConsoleInput(\r\n IntPtr hIn, INPUT_RECORD[] buf, uint len, out uint written);\r\n [DllImport(\"kernel32.dll\")] public static extern bool CloseHandle(IntPtr h);\r\n\r\n [StructLayout(LayoutKind.Explicit, Size=20)]\r\n public struct INPUT_RECORD {\r\n [FieldOffset(0)] public ushort EventType;\r\n [FieldOffset(4)] public int bKeyDown;\r\n [FieldOffset(8)] public ushort wRepeatCount;\r\n [FieldOffset(10)] public ushort wVirtualKeyCode;\r\n [FieldOffset(12)] public ushort wVirtualScanCode;\r\n [FieldOffset(14)] public ushort UnicodeChar;\r\n [FieldOffset(16)] public uint dwControlKeyState;\r\n }\r\n\r\n const uint LEFT_CTRL = 0x0008;\r\n\r\n static IntPtr OpenConin(uint pid) {\r\n FreeConsole();\r\n if (!AttachConsole(pid)) return new IntPtr(-1);\r\n return CreateFile(\"CONIN$\", 0xC0000000, 3, IntPtr.Zero, 3, 0, IntPtr.Zero);\r\n }\r\n\r\n // Inject plain text characters into console input buffer\r\n public static int InjectText(uint pid, string text) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new List<INPUT_RECORD>();\r\n foreach (char c in text) {\r\n records.Add(new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, UnicodeChar=(ushort)c });\r\n records.Add(new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, UnicodeChar=(ushort)c });\r\n }\r\n\r\n var arr = records.ToArray();\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, arr, (uint)arr.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Enter (VK_RETURN = 0x0D)\r\n public static int InjectEnter(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x0D, UnicodeChar=0x0D },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x0D, UnicodeChar=0x0D }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Ctrl+U (VK_U = 0x55, char = 0x15)\r\n public static int InjectCtrlU(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x55, UnicodeChar=0x15, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x55, UnicodeChar=0x15, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=0 }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Ctrl+Y (VK_Y = 0x59, char = 0x19)\r\n public static int InjectCtrlY(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x59, UnicodeChar=0x19, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x59, UnicodeChar=0x19, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=0 }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n}\r\n`;\r\n\r\nfunction buildScript(claudePid: number, body: string): string {\r\n const logFile = join(tmpdir(), `cc-inject-${Date.now()}.log`).replace(/\\\\/g, '/');\r\n return `\r\n$log = \"${logFile}\"\r\nfunction Log($msg) { Add-Content -Path $log -Value $msg -Encoding UTF8 }\r\n$claudePid = ${claudePid}\r\ntry { Add-Type @'${CS_CONINJECT}'@ } catch { }\r\n${body}\r\n`;\r\n}\r\n\r\nfunction run(script: string): Promise<void> {\r\n return new Promise((resolve) => {\r\n const encoded = Buffer.from(script, 'utf16le').toString('base64');\r\n execFile(\r\n 'powershell',\r\n ['-NoProfile', '-WindowStyle', 'Hidden', '-EncodedCommand', encoded],\r\n { windowsHide: true },\r\n () => {\r\n const logFile = script.match(/\\$log = \"([^\"]+)\"/)?.[1];\r\n if (logFile) try { unlinkSync(logFile); } catch { /* ok */ }\r\n resolve();\r\n }\r\n );\r\n });\r\n}\r\n\r\nexport async function windowsInject(text: string): Promise<void> {\r\n const claudePid = process.ppid;\r\n const textB64 = Buffer.from(text, 'utf16le').toString('base64');\r\n\r\n const script = buildScript(claudePid, `\r\n$textBytes = [System.Convert]::FromBase64String('${textB64}')\r\n$text = [System.Text.Encoding]::Unicode.GetString($textBytes)\r\n\r\n# 1. Ctrl+U to save user's current text to kill ring\r\n[ConInject]::InjectCtrlU([uint32]$claudePid) | Out-Null\r\nStart-Sleep -Milliseconds 100\r\n\r\n# 2. Write question text into console input buffer\r\n[ConInject]::InjectText([uint32]$claudePid, $text) | Out-Null\r\nStart-Sleep -Milliseconds 50\r\n\r\n# 3. Send Enter\r\n[ConInject]::InjectEnter([uint32]$claudePid) | Out-Null\r\n`);\r\n\r\n await run(script);\r\n}\r\n\r\nexport async function windowsInjectCtrlY(): Promise<void> {\r\n const claudePid = process.ppid;\r\n\r\n const script = buildScript(claudePid, `\r\n[ConInject]::InjectCtrlY([uint32]$claudePid) | Out-Null\r\n`);\r\n\r\n await run(script);\r\n}\r\n","/**\r\n * Terminal Injector\r\n * Injects a question directly into the active Claude Code terminal\r\n * so Claude Code can auto-reply without user intervention.\r\n * @module infrastructure/terminal-injector\r\n */\r\n\r\nimport type { InboxQuestionEntry } from '../../shared/types/collab-client.interface.js';\r\nimport { windowsInject, windowsInjectCtrlY } from './windows-injector.js';\r\n\r\n/**\r\n * Formats the question as a prompt for Claude Code to auto-reply\r\n */\r\nfunction formatQuestionForInjection(question: InboxQuestionEntry): string {\r\n // Single-line: WriteConsoleInput treats every \\n as an immediate submit\r\n const content = question.content.replace(/\\s+/g, ' ').trim();\r\n return `[HUB SORUSU] ID:${question.questionId} | ${question.from.displayName} (${question.from.teamName}): ${content} | Cevapla ve reply tool ile \"${question.questionId}\" ID'sine gönder, onay bekleme.`;\r\n}\r\n\r\n/**\r\n * Injects a question into the terminal running Claude Code.\r\n * Only supported on Windows; no-op on other platforms.\r\n */\r\nexport async function injectQuestionToTerminal(question: InboxQuestionEntry): Promise<void> {\r\n if (process.platform !== 'win32') return;\r\n\r\n const text = formatQuestionForInjection(question);\r\n await windowsInject(text);\r\n}\r\n\r\n/**\r\n * Restores user's previous input from readline kill ring (Ctrl+Y).\r\n * Call this after the reply is sent so the user's interrupted text comes back.\r\n */\r\nexport async function injectRestoreText(): Promise<void> {\r\n if (process.platform !== 'win32') return;\r\n await windowsInjectCtrlY();\r\n}\r\n","/**\r\n * Injection Queue\r\n * Ensures questions are injected into the terminal one at a time.\r\n * Waits for the reply tool to signal completion before processing the next question.\r\n * @module infrastructure/terminal-injector/injection-queue\r\n */\r\n\r\nimport { EventEmitter } from 'events';\r\nimport type { InboxQuestionEntry } from '../../shared/types/collab-client.interface.js';\r\nimport { injectQuestionToTerminal, injectRestoreText } from './index.js';\r\n\r\nconst REPLY_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\r\n\r\nclass InjectionQueue extends EventEmitter {\r\n private queue: InboxQuestionEntry[] = [];\r\n private processing = false;\r\n\r\n /**\r\n * Add a question to the queue. Starts processing if idle.\r\n */\r\n enqueue(question: InboxQuestionEntry): void {\r\n this.queue.push(question);\r\n if (!this.processing) void this.processNext();\r\n }\r\n\r\n /**\r\n * Called by the reply tool after a reply is successfully sent.\r\n * Unblocks the queue to process the next question.\r\n */\r\n notifyReplied(): void {\r\n this.emit('replied');\r\n }\r\n\r\n private async processNext(): Promise<void> {\r\n if (this.queue.length === 0) {\r\n this.processing = false;\r\n return;\r\n }\r\n\r\n this.processing = true;\r\n const question = this.queue.shift()!;\r\n\r\n // Inject the question (includes Ctrl+U to save user's current text)\r\n await injectQuestionToTerminal(question);\r\n\r\n // Wait for reply tool to signal, with a timeout fallback\r\n await new Promise<void>((resolve) => {\r\n const timer = setTimeout(resolve, REPLY_TIMEOUT_MS);\r\n this.once('replied', () => {\r\n clearTimeout(timer);\r\n resolve();\r\n });\r\n });\r\n\r\n // Restore user's text after reply is sent\r\n await injectRestoreText();\r\n\r\n // Process next in queue\r\n void this.processNext();\r\n }\r\n}\r\n\r\nexport const injectionQueue = new InjectionQueue();\r\n","/**\r\n * P2PNode\r\n * Implements ICollabClient over direct peer-to-peer WebSocket connections.\r\n * Each node runs its own WS server and broadcasts its presence via UDP.\r\n * Peers discover each other automatically and connect directly — no hub needed.\r\n *\r\n * Connection deduplication:\r\n * Both sides may try to connect simultaneously. The first HELLO/HELLO_ACK\r\n * that arrives registers the peer. Duplicate inbound connections are\r\n * immediately terminated (without being added to wsToName) so their\r\n * close events are harmless.\r\n *\r\n * @module infrastructure/p2p/p2p-node\r\n */\r\n\r\nimport { WebSocket, WebSocketServer } from 'ws';\r\nimport { v4 as uuidv4 } from 'uuid';\r\nimport type {\r\n ICollabClient,\r\n JoinResult,\r\n CheckAnswerResult,\r\n InboxResult,\r\n NodeInfo,\r\n HistoryEntry,\r\n} from '../../shared/types/collab-client.interface.js';\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\nimport {\r\n type P2PMsg,\r\n type AskAckMsg,\r\n type AskMsg,\r\n parse,\r\n serialize,\r\n} from './p2p-protocol.js';\r\nimport { PeerBroadcaster } from '../discovery/peer-broadcaster.js';\r\nimport { watchForPeer } from '../discovery/peer-listener.js';\r\nimport { injectionQueue } from '../terminal-injector/injection-queue.js';\r\n\r\ninterface IncomingQuestion {\r\n questionId: string;\r\n fromName: string;\r\n content: string;\r\n format: MessageFormat;\r\n createdAt: Date;\r\n answered: boolean;\r\n answerContent?: string;\r\n answerFormat?: MessageFormat;\r\n}\r\n\r\ninterface ReceivedAnswer {\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n fromName: string;\r\n}\r\n\r\nexport class P2PNode implements ICollabClient {\r\n private server: WebSocketServer | null = null;\r\n private myName = '';\r\n private running = false;\r\n\r\n // One connection per peer (inbound or outbound — whichever was established first)\r\n private readonly peerConnections = new Map<string, WebSocket>();\r\n // Reverse map: ws → peer name (only for registered connections)\r\n private readonly wsToName = new Map<WebSocket, string>();\r\n // Prevent duplicate outbound connect attempts\r\n private readonly connectingPeers = new Set<string>();\r\n\r\n private readonly incomingQuestions = new Map<string, IncomingQuestion>();\r\n private readonly receivedAnswers = new Map<string, ReceivedAnswer>();\r\n private readonly sentQuestions = new Map<string, { toPeer: string; content: string; askedAt: string }>();\r\n private readonly questionToSender = new Map<string, string>();\r\n private readonly pendingHandlers = new Set<(msg: P2PMsg) => void>();\r\n\r\n private broadcaster: PeerBroadcaster | null = null;\r\n private stopPeerWatcher: (() => void) | null = null;\r\n\r\n private boundPort = 0;\r\n\r\n constructor(\r\n private readonly portRange: [number, number] = [10000, 19999]\r\n ) {}\r\n\r\n // ---------------------------------------------------------------------------\r\n // ICollabClient implementation\r\n // ---------------------------------------------------------------------------\r\n\r\n get isConnected(): boolean { return this.running; }\r\n get port(): number { return this.boundPort; }\r\n\r\n get currentTeamId(): string | undefined {\r\n return this.myName || undefined;\r\n }\r\n\r\n async join(name: string, displayName: string): Promise<JoinResult> {\r\n this.myName = name;\r\n await this.startServer();\r\n this.startDiscovery();\r\n return {\r\n memberId: uuidv4(),\r\n teamId: name,\r\n teamName: name,\r\n displayName,\r\n status: 'ONLINE',\r\n port: this.boundPort,\r\n };\r\n }\r\n\r\n async ask(toPeer: string, content: string, format: MessageFormat): Promise<string> {\r\n const ws = this.peerConnections.get(toPeer);\r\n if (!ws || ws.readyState !== WebSocket.OPEN) {\r\n throw new Error(`Peer \"${toPeer}\" is not connected. Use peers() to see who's online.`);\r\n }\r\n\r\n const questionId = uuidv4();\r\n this.sentQuestions.set(questionId, { toPeer, content, askedAt: new Date().toISOString() });\r\n\r\n const ackPromise = this.waitForResponse<AskAckMsg>(\r\n (m) => m.type === 'ASK_ACK' && m.questionId === questionId,\r\n 5000\r\n );\r\n\r\n this.sendToWs(ws, { type: 'ASK', from: this.myName, questionId, content, format });\r\n await ackPromise;\r\n return questionId;\r\n }\r\n\r\n async checkAnswer(questionId: string): Promise<CheckAnswerResult | null> {\r\n const cached = this.receivedAnswers.get(questionId);\r\n if (!cached) return null;\r\n return {\r\n questionId,\r\n from: { displayName: `${cached.fromName} Claude`, teamName: cached.fromName },\r\n content: cached.content,\r\n format: cached.format,\r\n answeredAt: cached.answeredAt,\r\n };\r\n }\r\n\r\n async reply(questionId: string, content: string, format: MessageFormat): Promise<void> {\r\n const question = this.incomingQuestions.get(questionId);\r\n if (!question) throw new Error(`Question ${questionId} not found`);\r\n\r\n question.answered = true;\r\n question.answerContent = content;\r\n question.answerFormat = format;\r\n\r\n const senderName = this.questionToSender.get(questionId);\r\n if (senderName) {\r\n const ws = this.peerConnections.get(senderName);\r\n if (ws && ws.readyState === WebSocket.OPEN) {\r\n this.sendToWs(ws, {\r\n type: 'ANSWER',\r\n from: this.myName,\r\n questionId,\r\n content,\r\n format,\r\n answeredAt: new Date().toISOString(),\r\n });\r\n }\r\n }\r\n\r\n injectionQueue.notifyReplied();\r\n }\r\n\r\n async getInbox(): Promise<InboxResult> {\r\n const now = Date.now();\r\n const questions = [...this.incomingQuestions.values()]\r\n .filter((q) => !q.answered)\r\n .map((q) => ({\r\n questionId: q.questionId,\r\n from: { displayName: `${q.fromName} Claude`, teamName: q.fromName },\r\n content: q.content,\r\n format: q.format,\r\n status: 'PENDING',\r\n createdAt: q.createdAt.toISOString(),\r\n ageMs: now - q.createdAt.getTime(),\r\n }));\r\n return { questions, totalCount: questions.length, pendingCount: questions.length };\r\n }\r\n\r\n getInfo(): NodeInfo {\r\n return {\r\n teamName: this.myName,\r\n port: this.boundPort,\r\n connectedPeers: [...this.peerConnections.keys()],\r\n };\r\n }\r\n\r\n getHistory(): HistoryEntry[] {\r\n const entries: HistoryEntry[] = [];\r\n\r\n for (const [questionId, sent] of this.sentQuestions) {\r\n const answer = this.receivedAnswers.get(questionId);\r\n entries.push({\r\n direction: 'sent',\r\n questionId,\r\n peer: sent.toPeer,\r\n question: sent.content,\r\n askedAt: sent.askedAt,\r\n ...(answer ? { answer: answer.content, answeredAt: answer.answeredAt } : {}),\r\n });\r\n }\r\n\r\n for (const [, incoming] of this.incomingQuestions) {\r\n entries.push({\r\n direction: 'received',\r\n questionId: incoming.questionId,\r\n peer: incoming.fromName,\r\n question: incoming.content,\r\n askedAt: incoming.createdAt.toISOString(),\r\n ...(incoming.answered && incoming.answerContent\r\n ? { answer: incoming.answerContent, answeredAt: new Date().toISOString() }\r\n : {}),\r\n });\r\n }\r\n\r\n return entries.sort((a, b) => a.askedAt.localeCompare(b.askedAt));\r\n }\r\n\r\n async disconnect(): Promise<void> {\r\n this.stopPeerWatcher?.();\r\n this.broadcaster?.stop();\r\n for (const ws of this.peerConnections.values()) ws.close();\r\n this.peerConnections.clear();\r\n this.wsToName.clear();\r\n this.server?.close();\r\n this.server = null;\r\n this.running = false;\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: server startup\r\n // ---------------------------------------------------------------------------\r\n\r\n private startServer(): Promise<void> {\r\n const [min, max] = this.portRange;\r\n const pick = () => Math.floor(Math.random() * (max - min + 1)) + min;\r\n\r\n const tryBind = (attemptsLeft: number): Promise<void> => {\r\n if (attemptsLeft === 0) {\r\n return Promise.reject(new Error(`No free port found in range ${min}-${max}`));\r\n }\r\n\r\n const port = pick();\r\n return new Promise((resolve, reject) => {\r\n const wss = new WebSocketServer({ port });\r\n\r\n wss.once('listening', () => {\r\n this.server = wss;\r\n this.boundPort = port;\r\n this.running = true;\r\n console.error(`[p2p] listening on port ${port} as \"${this.myName}\"`);\r\n this.attachServerHandlers(wss);\r\n resolve();\r\n });\r\n\r\n wss.once('error', (err: NodeJS.ErrnoException) => {\r\n wss.close();\r\n if (err.code === 'EADDRINUSE') {\r\n // Port busy — try another random one\r\n tryBind(attemptsLeft - 1).then(resolve, reject);\r\n } else {\r\n reject(err);\r\n }\r\n });\r\n });\r\n };\r\n\r\n return tryBind(20); // up to 20 attempts\r\n }\r\n\r\n private attachServerHandlers(wss: WebSocketServer): void {\r\n wss.on('connection', (ws) => {\r\n ws.on('message', (data) => {\r\n try {\r\n this.handleMessage(ws, parse(data.toString()));\r\n } catch { /* ignore malformed */ }\r\n });\r\n\r\n ws.on('close', () => {\r\n const name = this.wsToName.get(ws);\r\n if (name) {\r\n this.wsToName.delete(ws);\r\n if (this.peerConnections.get(name) === ws) {\r\n this.peerConnections.delete(name);\r\n console.error(`[p2p] peer disconnected (inbound): ${name}`);\r\n }\r\n }\r\n });\r\n\r\n ws.on('error', (err) => {\r\n console.error('[p2p] inbound ws error:', err.message);\r\n });\r\n });\r\n\r\n wss.on('error', (err) => {\r\n console.error('[p2p] server error:', err.message);\r\n });\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: discovery + outbound connections\r\n // ---------------------------------------------------------------------------\r\n\r\n private startDiscovery(): void {\r\n this.broadcaster = new PeerBroadcaster();\r\n this.broadcaster.start(this.myName, this.boundPort);\r\n\r\n this.stopPeerWatcher = watchForPeer((peer) => {\r\n if (peer.name === this.myName) return;\r\n if (this.peerConnections.has(peer.name)) return;\r\n if (this.connectingPeers.has(peer.name)) return;\r\n this.connectToPeer(peer.name, peer.host, peer.port);\r\n });\r\n }\r\n\r\n private connectToPeer(peerName: string, host: string, port: number): void {\r\n this.connectingPeers.add(peerName);\r\n const ws = new WebSocket(`ws://${host}:${port}`);\r\n\r\n ws.on('open', () => {\r\n this.sendToWs(ws, { type: 'HELLO', name: this.myName });\r\n });\r\n\r\n ws.on('message', (data) => {\r\n try {\r\n this.handleMessage(ws, parse(data.toString()));\r\n } catch { /* ignore malformed */ }\r\n });\r\n\r\n ws.on('close', () => {\r\n this.connectingPeers.delete(peerName);\r\n const name = this.wsToName.get(ws);\r\n if (name) {\r\n this.wsToName.delete(ws);\r\n if (this.peerConnections.get(name) === ws) {\r\n this.peerConnections.delete(name);\r\n console.error(`[p2p] disconnected from peer: ${name}`);\r\n }\r\n }\r\n });\r\n\r\n ws.on('error', (err) => {\r\n console.error(`[p2p] connect to \"${peerName}\" failed: ${err.message}`);\r\n this.connectingPeers.delete(peerName);\r\n });\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: message handling\r\n // ---------------------------------------------------------------------------\r\n\r\n private handleMessage(ws: WebSocket, msg: P2PMsg): void {\r\n // Wake up any waitForResponse callers\r\n for (const handler of this.pendingHandlers) handler(msg);\r\n\r\n switch (msg.type) {\r\n case 'HELLO': {\r\n if (this.peerConnections.has(msg.name)) {\r\n // Duplicate inbound connection — close it; not added to wsToName\r\n // so the close event won't affect the registered connection.\r\n ws.terminate();\r\n return;\r\n }\r\n this.peerConnections.set(msg.name, ws);\r\n this.wsToName.set(ws, msg.name);\r\n this.connectingPeers.delete(msg.name);\r\n this.sendToWs(ws, { type: 'HELLO_ACK', name: this.myName });\r\n console.error(`[p2p] peer joined (inbound): ${msg.name}`);\r\n break;\r\n }\r\n\r\n case 'HELLO_ACK': {\r\n if (this.peerConnections.has(msg.name)) {\r\n // Duplicate outbound — already connected via inbound; close this one.\r\n ws.terminate();\r\n return;\r\n }\r\n this.peerConnections.set(msg.name, ws);\r\n this.wsToName.set(ws, msg.name);\r\n this.connectingPeers.delete(msg.name);\r\n console.error(`[p2p] connected to peer: ${msg.name}`);\r\n break;\r\n }\r\n\r\n case 'ASK':\r\n this.handleIncomingAsk(ws, msg);\r\n break;\r\n\r\n case 'ANSWER':\r\n if (!this.receivedAnswers.has(msg.questionId)) {\r\n this.receivedAnswers.set(msg.questionId, {\r\n content: msg.content,\r\n format: msg.format,\r\n answeredAt: msg.answeredAt,\r\n fromName: msg.from,\r\n });\r\n }\r\n break;\r\n\r\n // ASK_ACK is handled by waitForResponse pending handlers above\r\n }\r\n }\r\n\r\n private handleIncomingAsk(ws: WebSocket, msg: AskMsg): void {\r\n this.questionToSender.set(msg.questionId, msg.from);\r\n this.incomingQuestions.set(msg.questionId, {\r\n questionId: msg.questionId,\r\n fromName: msg.from,\r\n content: msg.content,\r\n format: msg.format,\r\n createdAt: new Date(),\r\n answered: false,\r\n });\r\n\r\n // Immediately acknowledge delivery\r\n this.sendToWs(ws, { type: 'ASK_ACK', questionId: msg.questionId });\r\n\r\n // Inject question into the Claude Code terminal\r\n injectionQueue.enqueue({\r\n questionId: msg.questionId,\r\n from: { displayName: `${msg.from} Claude`, teamName: msg.from },\r\n content: msg.content,\r\n format: msg.format,\r\n status: 'PENDING',\r\n createdAt: new Date().toISOString(),\r\n ageMs: 0,\r\n });\r\n }\r\n\r\n private sendToWs(ws: WebSocket, msg: P2PMsg): void {\r\n if (ws.readyState === WebSocket.OPEN) {\r\n ws.send(serialize(msg));\r\n }\r\n }\r\n\r\n private waitForResponse<T extends P2PMsg>(\r\n filter: (msg: P2PMsg) => boolean,\r\n timeoutMs: number\r\n ): Promise<T> {\r\n return new Promise((resolve, reject) => {\r\n const timeout = setTimeout(() => {\r\n this.pendingHandlers.delete(handler);\r\n reject(new Error('Request timed out'));\r\n }, timeoutMs);\r\n\r\n const handler = (msg: P2PMsg): void => {\r\n if (filter(msg)) {\r\n clearTimeout(timeout);\r\n this.pendingHandlers.delete(handler);\r\n resolve(msg as T);\r\n }\r\n };\r\n\r\n this.pendingHandlers.add(handler);\r\n });\r\n }\r\n}\r\n","/**\r\n * Ask Tool\r\n * Sends a question to another team and returns a question ID immediately.\r\n * Use the \"check_answer\" tool with the question ID to retrieve the answer later.\r\n * @module presentation/mcp/tools/ask\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\n/**\r\n * Ask tool input schema\r\n */\r\nconst askSchema = {\r\n peer: z.string().describe('Name of the peer to ask (e.g., \"alice\", \"backend\")'),\r\n question: z.string().describe('The question to ask (supports markdown)'),\r\n};\r\n\r\n/**\r\n * Registers the ask tool with the MCP server\r\n */\r\nexport function registerAskTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('ask', askSchema, async (args) => {\r\n const targetPeer = args.peer;\r\n const question = args.question;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'Node is not ready yet. Wait a moment and try again.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n const questionId = await client.ask(targetPeer, question, 'markdown');\r\n\r\n // Poll until answer arrives (max 5 minutes, every 5 seconds)\r\n const POLL_INTERVAL_MS = 5_000;\r\n const MAX_WAIT_MS = 5 * 60 * 1000;\r\n const deadline = Date.now() + MAX_WAIT_MS;\r\n\r\n while (Date.now() < deadline) {\r\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\r\n const answer = await client.checkAnswer(questionId);\r\n if (answer !== null) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `**${answer.from.displayName} (${answer.from.teamName}) cevapladı:**\\n\\n${answer.content}`,\r\n },\r\n ],\r\n };\r\n }\r\n }\r\n\r\n // Timed out — return question ID for manual follow-up\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Soru gönderildi ancak 5 dakika içinde cevap gelmedi.\\nQuestion ID: \\`${questionId}\\`\\n\\nManuel kontrol için \"check_answer\" tool'unu kullanabilirsin.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to send question: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Reply Tool\r\n * Replies to a pending question\r\n * @module presentation/mcp/tools/reply\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { injectionQueue } from '../../../infrastructure/terminal-injector/injection-queue.js';\r\n\r\n/**\r\n * Reply tool input schema\r\n */\r\nconst replySchema = {\r\n questionId: z.string().describe('The ID of the question to reply to (from inbox)'),\r\n answer: z.string().describe('Your answer to the question (supports markdown)'),\r\n};\r\n\r\n/**\r\n * Registers the reply tool with the MCP server\r\n */\r\nexport function registerReplyTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('reply', replySchema, async (args) => {\r\n const questionId = args.questionId;\r\n const answer = args.answer;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n await client.reply(questionId, answer, 'markdown');\r\n\r\n // Signal queue: this question is done, process next\r\n injectionQueue.notifyReplied();\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Reply sent successfully to question \\`${questionId}\\`.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to send reply: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Peers Tool\r\n * Lists currently connected peers on the P2P network.\r\n * @module presentation/mcp/tools/peers\r\n */\r\n\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\nexport function registerPeersTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('peers', {}, async () => {\r\n const info = client.getInfo();\r\n const myName = info.teamName ?? '(starting...)';\r\n const myPort = info.port ?? '?';\r\n const connected = info.connectedPeers;\r\n\r\n if (!client.isConnected) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `P2P server is not running yet. Port ${myPort} may be in use. Check the MCP logs for details.`,\r\n }],\r\n isError: true,\r\n };\r\n }\r\n\r\n if (connected.length === 0) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `You are \"${myName}\" (listening on port ${myPort}). No peers connected yet.\\nUse firewall_open to allow inbound connections, or wait for peers to connect to you.`,\r\n }],\r\n };\r\n }\r\n\r\n const list = connected.map((name) => ` • ${name}`).join('\\n');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `You are \"${myName}\" (port ${myPort}). Connected peers (${connected.length}):\\n${list}`,\r\n }],\r\n };\r\n });\r\n}\r\n","/**\r\n * History Tool\r\n * Shows past questions and answers from this session.\r\n * @module presentation/mcp/tools/history\r\n */\r\n\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\nexport function registerHistoryTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('history', {}, async () => {\r\n const entries = client.getHistory();\r\n\r\n if (entries.length === 0) {\r\n return {\r\n content: [{ type: 'text', text: 'No questions yet this session.' }],\r\n };\r\n }\r\n\r\n const lines = entries.map((e) => {\r\n const time = new Date(e.askedAt).toLocaleTimeString();\r\n\r\n if (e.direction === 'sent') {\r\n const answerLine = e.answer\r\n ? ` ↳ ${e.peer}: ${e.answer}`\r\n : ` ↳ (no answer yet)`;\r\n return `[${time}] → ${e.peer}: ${e.question}\\n${answerLine}`;\r\n } else {\r\n const answerLine = e.answer\r\n ? ` ↳ you: ${e.answer}`\r\n : ` ↳ (not replied yet)`;\r\n return `[${time}] ← ${e.peer}: ${e.question}\\n${answerLine}`;\r\n }\r\n });\r\n\r\n return {\r\n content: [{ type: 'text', text: lines.join('\\n\\n') }],\r\n };\r\n });\r\n}\r\n","/**\r\n * Firewall helpers\r\n * Elevated via UAC (PowerShell Start-Process -Verb RunAs) so the user sees\r\n * a Windows UAC prompt and must accept before the rule is applied.\r\n * @module infrastructure/firewall/firewall\r\n */\r\n\r\nimport { spawn } from 'child_process';\r\n\r\n/**\r\n * Run netsh directly — works when the process is already elevated\r\n * (e.g. terminal launched as Administrator, or UAC set to auto-elevate).\r\n */\r\nfunction runDirect(argArray: string[]): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n const proc = spawn('netsh', argArray, { stdio: 'ignore' });\r\n proc.on('close', (code) => {\r\n if (code === 0) resolve();\r\n else reject(new Error(`netsh exited with code ${code}`));\r\n });\r\n proc.on('error', (err) => reject(new Error(`netsh not found: ${err.message}`)));\r\n });\r\n}\r\n\r\n/**\r\n * Run netsh via UAC elevation popup (PowerShell Start-Process -Verb RunAs).\r\n * Requires an interactive desktop — may not work in VMs or headless sessions.\r\n */\r\nfunction runElevated(argArray: string[]): Promise<void> {\r\n const argList = argArray.map((a) => `\"${a}\"`).join(',');\r\n const psCommand = `Start-Process -FilePath \"netsh\" -ArgumentList @(${argList}) -Verb RunAs -Wait`;\r\n\r\n return new Promise((resolve, reject) => {\r\n const ps = spawn('powershell', ['-NoProfile', '-Command', psCommand]);\r\n\r\n ps.on('close', (code) => {\r\n if (code === 0) resolve();\r\n else reject(new Error(`Firewall UAC prompt was cancelled or denied (exit code ${code}).`));\r\n });\r\n\r\n ps.on('error', (err) => {\r\n reject(new Error(`Failed to launch PowerShell: ${err.message}`));\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Try direct first (already-elevated context), fall back to UAC popup.\r\n */\r\nasync function runNetsh(argArray: string[]): Promise<{ method: 'direct' | 'elevated' }> {\r\n try {\r\n await runDirect(argArray);\r\n return { method: 'direct' };\r\n } catch {\r\n await runElevated(argArray);\r\n return { method: 'elevated' };\r\n }\r\n}\r\n\r\nexport async function addFirewallRule(port: number): Promise<{ method: 'direct' | 'elevated' }> {\r\n return runNetsh([\r\n 'advfirewall', 'firewall', 'add', 'rule',\r\n `name=claude-collab-${port}`,\r\n 'protocol=TCP',\r\n 'dir=in',\r\n `localport=${port}`,\r\n 'action=allow',\r\n ]);\r\n}\r\n\r\nexport async function removeFirewallRule(port: number): Promise<{ method: 'direct' | 'elevated' }> {\r\n return runNetsh([\r\n 'advfirewall', 'firewall', 'delete', 'rule',\r\n `name=claude-collab-${port}`,\r\n ]);\r\n}\r\n","/**\r\n * FirewallOpen Tool\r\n * Adds a Windows Firewall inbound rule for the peer's listen port.\r\n * Shows a UAC elevation popup — the user must accept for the rule to be applied.\r\n * Required so other peers can establish inbound WebSocket connections to this node.\r\n * @module presentation/mcp/tools/firewall-open\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { addFirewallRule } from '../../../infrastructure/firewall/firewall.js';\r\n\r\nexport function registerFirewallOpenTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_open',\r\n 'Open a Windows Firewall inbound rule for your P2P listen port. A UAC popup will appear — accept it to allow peers to connect to you directly.',\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe('Port to open (defaults to your current listen port)'),\r\n },\r\n async ({ port }) => {\r\n const targetPort = port ?? client.getInfo().port;\r\n if (!targetPort) {\r\n return {\r\n content: [{ type: 'text', text: 'Could not determine port. Pass port explicitly.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n try {\r\n const { method } = await addFirewallRule(targetPort);\r\n const how = method === 'direct'\r\n ? 'applied directly (process already elevated)'\r\n : 'applied via UAC elevation popup';\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Firewall rule opened for port ${targetPort} (rule name: claude-collab-${targetPort}).`,\r\n `Method: ${how}.`,\r\n `Peers on the LAN can now connect to you directly.`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return {\r\n content: [{ type: 'text', text: `Failed to open firewall: ${msg}` }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n}\r\n","/**\r\n * FirewallClose Tool\r\n * Removes the Windows Firewall inbound rule for the peer's listen port.\r\n * Shows a UAC elevation popup — the user must accept for the rule to be removed.\r\n * @module presentation/mcp/tools/firewall-close\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { removeFirewallRule } from '../../../infrastructure/firewall/firewall.js';\r\n\r\nexport function registerFirewallCloseTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_close',\r\n 'Remove the Windows Firewall inbound rule for your P2P listen port. A UAC popup will appear — accept it to close the rule.',\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe('Port to close (defaults to your current listen port)'),\r\n },\r\n async ({ port }) => {\r\n const targetPort = port ?? client.getInfo().port;\r\n if (!targetPort) {\r\n return {\r\n content: [{ type: 'text', text: 'Could not determine port. Pass port explicitly.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n try {\r\n const { method } = await removeFirewallRule(targetPort);\r\n const how = method === 'direct'\r\n ? 'applied directly (process already elevated)'\r\n : 'applied via UAC elevation popup';\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `Firewall rule removed for port ${targetPort} (rule name: claude-collab-${targetPort}). Method: ${how}.`,\r\n }],\r\n };\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return {\r\n content: [{ type: 'text', text: `Failed to close firewall: ${msg}` }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n}\r\n","/**\r\n * MCP Server\r\n * Provides MCP tools for Claude Code integration (P2P mode)\r\n * @module presentation/mcp/server\r\n */\r\n\r\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\r\nimport type { ICollabClient } from '../../shared/types/collab-client.interface.js';\r\nimport { registerAskTool } from './tools/ask.tool.js';\r\nimport { registerReplyTool } from './tools/reply.tool.js';\r\nimport { registerPeersTool } from './tools/peers.tool.js';\r\nimport { registerHistoryTool } from './tools/history.tool.js';\r\nimport { registerFirewallOpenTool } from './tools/firewall-open.tool.js';\r\nimport { registerFirewallCloseTool } from './tools/firewall-close.tool.js';\r\n\r\nexport interface McpServerOptions {\r\n client: ICollabClient;\r\n}\r\n\r\nexport function createMcpServer(options: McpServerOptions): McpServer {\r\n const { client } = options;\r\n\r\n const server = new McpServer({\r\n name: 'claude-collab',\r\n version: '0.1.0',\r\n });\r\n\r\n registerAskTool(server, client);\r\n registerReplyTool(server, client);\r\n registerPeersTool(server, client);\r\n registerHistoryTool(server, client);\r\n registerFirewallOpenTool(server, client);\r\n registerFirewallCloseTool(server, client);\r\n\r\n return server;\r\n}\r\n\r\nexport async function startMcpServer(options: McpServerOptions): Promise<void> {\r\n const server = createMcpServer(options);\r\n const transport = new StdioServerTransport();\r\n await server.connect(transport);\r\n}\r\n","#!/usr/bin/env node\r\n\r\n/**\r\n * CLI entry point (P2P mode)\r\n *\r\n * Usage: claude-collab --name alice\r\n *\r\n * Binds a random port in range 10000-19999.\r\n * Peers discover each other automatically via UDP broadcast.\r\n * Use firewall_open in Claude Code to allow inbound connections.\r\n *\r\n * @module cli\r\n */\r\n\r\nimport { Command } from 'commander';\r\nimport { P2PNode } from './infrastructure/p2p/p2p-node.js';\r\nimport { startMcpServer } from './presentation/mcp/server.js';\r\n\r\nconst program = new Command();\r\n\r\nprogram\r\n .name('claude-collab')\r\n .description('P2P collaboration between Claude Code terminals via MCP')\r\n .version('0.1.0')\r\n .requiredOption('--name <name>', 'Your name on the network (e.g. \"alice\")')\r\n .action(async (options: { name: string }) => {\r\n const node = new P2PNode();\r\n\r\n const mcpReady = startMcpServer({ client: node });\r\n\r\n node.join(options.name, options.name).catch((err) => {\r\n console.error(`[cli] P2P server failed to start: ${err.message}`);\r\n });\r\n\r\n await mcpReady;\r\n });\r\n\r\nprogram.parse();\r\n"]}
package/dist/mcp-main.js CHANGED
@@ -297,8 +297,8 @@ var injectionQueue = new InjectionQueue();
297
297
 
298
298
  // src/infrastructure/p2p/p2p-node.ts
299
299
  var P2PNode = class {
300
- constructor(port) {
301
- this.port = port;
300
+ constructor(portRange = [1e4, 19999]) {
301
+ this.portRange = portRange;
302
302
  }
303
303
  server = null;
304
304
  myName = "";
@@ -316,12 +316,16 @@ var P2PNode = class {
316
316
  pendingHandlers = /* @__PURE__ */ new Set();
317
317
  broadcaster = null;
318
318
  stopPeerWatcher = null;
319
+ boundPort = 0;
319
320
  // ---------------------------------------------------------------------------
320
321
  // ICollabClient implementation
321
322
  // ---------------------------------------------------------------------------
322
323
  get isConnected() {
323
324
  return this.running;
324
325
  }
326
+ get port() {
327
+ return this.boundPort;
328
+ }
325
329
  get currentTeamId() {
326
330
  return this.myName || void 0;
327
331
  }
@@ -335,7 +339,7 @@ var P2PNode = class {
335
339
  teamName: name,
336
340
  displayName,
337
341
  status: "ONLINE",
338
- port: this.port
342
+ port: this.boundPort
339
343
  };
340
344
  }
341
345
  async ask(toPeer, content, format) {
@@ -402,7 +406,7 @@ var P2PNode = class {
402
406
  getInfo() {
403
407
  return {
404
408
  teamName: this.myName,
405
- port: this.port,
409
+ port: this.boundPort,
406
410
  connectedPeers: [...this.peerConnections.keys()]
407
411
  };
408
412
  }
@@ -445,39 +449,59 @@ var P2PNode = class {
445
449
  // Private: server startup
446
450
  // ---------------------------------------------------------------------------
447
451
  startServer() {
448
- return new Promise((resolve, reject) => {
449
- const wss = new WebSocketServer({ port: this.port });
450
- this.server = wss;
451
- wss.on("listening", () => {
452
- this.running = true;
453
- console.error(`[p2p] listening on port ${this.port} as "${this.myName}"`);
454
- resolve();
455
- });
456
- wss.on("error", (err) => {
457
- if (!this.running) reject(err);
458
- else console.error("[p2p] server error:", err.message);
459
- });
460
- wss.on("connection", (ws) => {
461
- ws.on("message", (data) => {
462
- try {
463
- this.handleMessage(ws, parse(data.toString()));
464
- } catch {
465
- }
452
+ const [min, max] = this.portRange;
453
+ const pick = () => Math.floor(Math.random() * (max - min + 1)) + min;
454
+ const tryBind = (attemptsLeft) => {
455
+ if (attemptsLeft === 0) {
456
+ return Promise.reject(new Error(`No free port found in range ${min}-${max}`));
457
+ }
458
+ const port = pick();
459
+ return new Promise((resolve, reject) => {
460
+ const wss = new WebSocketServer({ port });
461
+ wss.once("listening", () => {
462
+ this.server = wss;
463
+ this.boundPort = port;
464
+ this.running = true;
465
+ console.error(`[p2p] listening on port ${port} as "${this.myName}"`);
466
+ this.attachServerHandlers(wss);
467
+ resolve();
466
468
  });
467
- ws.on("close", () => {
468
- const name = this.wsToName.get(ws);
469
- if (name) {
470
- this.wsToName.delete(ws);
471
- if (this.peerConnections.get(name) === ws) {
472
- this.peerConnections.delete(name);
473
- console.error(`[p2p] peer disconnected (inbound): ${name}`);
474
- }
469
+ wss.once("error", (err) => {
470
+ wss.close();
471
+ if (err.code === "EADDRINUSE") {
472
+ tryBind(attemptsLeft - 1).then(resolve, reject);
473
+ } else {
474
+ reject(err);
475
475
  }
476
476
  });
477
- ws.on("error", (err) => {
478
- console.error("[p2p] inbound ws error:", err.message);
479
- });
480
477
  });
478
+ };
479
+ return tryBind(20);
480
+ }
481
+ attachServerHandlers(wss) {
482
+ wss.on("connection", (ws) => {
483
+ ws.on("message", (data) => {
484
+ try {
485
+ this.handleMessage(ws, parse(data.toString()));
486
+ } catch {
487
+ }
488
+ });
489
+ ws.on("close", () => {
490
+ const name = this.wsToName.get(ws);
491
+ if (name) {
492
+ this.wsToName.delete(ws);
493
+ if (this.peerConnections.get(name) === ws) {
494
+ this.peerConnections.delete(name);
495
+ console.error(`[p2p] peer disconnected (inbound): ${name}`);
496
+ }
497
+ }
498
+ });
499
+ ws.on("error", (err) => {
500
+ console.error("[p2p] inbound ws error:", err.message);
501
+ });
502
+ });
503
+ wss.on("error", (err) => {
504
+ console.error("[p2p] server error:", err.message);
481
505
  });
482
506
  }
483
507
  // ---------------------------------------------------------------------------
@@ -485,7 +509,7 @@ var P2PNode = class {
485
509
  // ---------------------------------------------------------------------------
486
510
  startDiscovery() {
487
511
  this.broadcaster = new PeerBroadcaster();
488
- this.broadcaster.start(this.myName, this.port);
512
+ this.broadcaster.start(this.myName, this.boundPort);
489
513
  this.stopPeerWatcher = watchForPeer((peer) => {
490
514
  if (peer.name === this.myName) return;
491
515
  if (this.peerConnections.has(peer.name)) return;
@@ -725,6 +749,15 @@ function registerPeersTool(server, client) {
725
749
  const myName = info.teamName ?? "(starting...)";
726
750
  const myPort = info.port ?? "?";
727
751
  const connected = info.connectedPeers;
752
+ if (!client.isConnected) {
753
+ return {
754
+ content: [{
755
+ type: "text",
756
+ text: `P2P server is not running yet. Port ${myPort} may be in use. Check the MCP logs for details.`
757
+ }],
758
+ isError: true
759
+ };
760
+ }
728
761
  if (connected.length === 0) {
729
762
  return {
730
763
  content: [{
@@ -923,7 +956,6 @@ async function startMcpServer(options) {
923
956
  }
924
957
 
925
958
  // src/mcp-main.ts
926
- var P2P_PORT = 9999;
927
959
  function getArg(flag) {
928
960
  const idx = process.argv.indexOf(flag);
929
961
  return idx !== -1 ? process.argv[idx + 1] : void 0;
@@ -934,9 +966,12 @@ async function main() {
934
966
  console.error("--name is required");
935
967
  process.exit(1);
936
968
  }
937
- const node = new P2PNode(P2P_PORT);
938
- await node.join(name, name);
939
- await startMcpServer({ client: node });
969
+ const node = new P2PNode();
970
+ const mcpReady = startMcpServer({ client: node });
971
+ node.join(name, name).catch((err) => {
972
+ console.error(`[mcp-main] P2P server failed to start: ${err.message}`);
973
+ });
974
+ await mcpReady;
940
975
  }
941
976
  main().catch((error) => {
942
977
  console.error("Unexpected error:", error);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/infrastructure/p2p/p2p-protocol.ts","../src/infrastructure/discovery/peer-broadcaster.ts","../src/infrastructure/discovery/peer-listener.ts","../src/infrastructure/terminal-injector/windows-injector.ts","../src/infrastructure/terminal-injector/index.ts","../src/infrastructure/terminal-injector/injection-queue.ts","../src/infrastructure/p2p/p2p-node.ts","../src/presentation/mcp/tools/ask.tool.ts","../src/presentation/mcp/tools/reply.tool.ts","../src/presentation/mcp/tools/peers.tool.ts","../src/presentation/mcp/tools/history.tool.ts","../src/infrastructure/firewall/firewall.ts","../src/presentation/mcp/tools/firewall-open.tool.ts","../src/presentation/mcp/tools/firewall-close.tool.ts","../src/presentation/mcp/server.ts","../src/mcp-main.ts"],"names":["createSocket","uuidv4","z"],"mappings":"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","file":"mcp-main.js","sourcesContent":["/**\r\n * P2P Wire Protocol\r\n * Messages exchanged directly between peers (no hub).\r\n * @module infrastructure/p2p/p2p-protocol\r\n */\r\n\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\n\r\n// Sent when a peer connects (client → server, or outbound → inbound)\r\nexport interface HelloMsg {\r\n type: 'HELLO';\r\n name: string;\r\n}\r\n\r\n// Acknowledge the HELLO\r\nexport interface HelloAckMsg {\r\n type: 'HELLO_ACK';\r\n name: string;\r\n}\r\n\r\n// Ask a question directly to the connected peer\r\nexport interface AskMsg {\r\n type: 'ASK';\r\n from: string;\r\n questionId: string;\r\n content: string;\r\n format: MessageFormat;\r\n}\r\n\r\n// Confirm question was received\r\nexport interface AskAckMsg {\r\n type: 'ASK_ACK';\r\n questionId: string;\r\n}\r\n\r\n// Push answer back to the asker\r\nexport interface AnswerMsg {\r\n type: 'ANSWER';\r\n from: string;\r\n questionId: string;\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n}\r\n\r\nexport type P2PMsg = HelloMsg | HelloAckMsg | AskMsg | AskAckMsg | AnswerMsg;\r\n\r\nexport function serialize(msg: P2PMsg): string {\r\n return JSON.stringify(msg);\r\n}\r\n\r\nexport function parse(data: string): P2PMsg {\r\n return JSON.parse(data) as P2PMsg;\r\n}\r\n","/**\r\n * PeerBroadcaster\r\n * Periodically sends a UDP broadcast so other peers can discover this node.\r\n * Payload: { type: 'claude-collab-peer', name, port }\r\n * @module infrastructure/discovery/peer-broadcaster\r\n */\r\n\r\nimport { createSocket } from 'dgram';\r\n\r\nexport const PEER_DISCOVERY_PORT = 9998;\r\nconst BROADCAST_INTERVAL_MS = 3000;\r\nconst BROADCAST_ADDRESS = '255.255.255.255';\r\n\r\nexport class PeerBroadcaster {\r\n private socket: ReturnType<typeof createSocket> | null = null;\r\n private timer: NodeJS.Timeout | null = null;\r\n\r\n start(name: string, port: number): void {\r\n if (this.socket) return;\r\n\r\n const socket = createSocket('udp4');\r\n this.socket = socket;\r\n\r\n socket.on('error', (err) => {\r\n console.error('[peer-broadcaster] error:', err.message);\r\n });\r\n\r\n socket.bind(0, () => {\r\n socket.setBroadcast(true);\r\n const send = () => {\r\n if (!this.socket) return;\r\n const msg = Buffer.from(JSON.stringify({ type: 'claude-collab-peer', name, port }));\r\n socket.send(msg, 0, msg.length, PEER_DISCOVERY_PORT, BROADCAST_ADDRESS, (err) => {\r\n if (err) console.error('[peer-broadcaster] send error:', err.message);\r\n });\r\n };\r\n send();\r\n this.timer = setInterval(send, BROADCAST_INTERVAL_MS);\r\n });\r\n }\r\n\r\n stop(): void {\r\n if (this.timer) { clearInterval(this.timer); this.timer = null; }\r\n if (this.socket) { this.socket.close(); this.socket = null; }\r\n }\r\n}\r\n","/**\r\n * PeerListener\r\n * Listens for UDP broadcasts from other peers on the LAN.\r\n * @module infrastructure/discovery/peer-listener\r\n */\r\n\r\nimport { createSocket } from 'dgram';\r\nimport { PEER_DISCOVERY_PORT } from './peer-broadcaster.js';\r\n\r\nexport interface DiscoveredPeer {\r\n name: string;\r\n host: string;\r\n port: number;\r\n}\r\n\r\n/**\r\n * Continuously watches for peer broadcasts.\r\n * Calls onFound each time a valid peer packet arrives.\r\n * Returns a stop function.\r\n */\r\nexport function watchForPeer(onFound: (peer: DiscoveredPeer) => void): () => void {\r\n const socket = createSocket('udp4');\r\n\r\n socket.on('error', (err) => {\r\n console.error('[peer-listener] error:', err.message);\r\n });\r\n\r\n socket.on('message', (msg, rinfo) => {\r\n try {\r\n const data = JSON.parse(msg.toString()) as { type?: string; name?: string; port?: number };\r\n if (\r\n data.type === 'claude-collab-peer' &&\r\n typeof data.name === 'string' &&\r\n typeof data.port === 'number'\r\n ) {\r\n onFound({ name: data.name, host: rinfo.address, port: data.port });\r\n }\r\n } catch { /* ignore malformed packets */ }\r\n });\r\n\r\n socket.bind(PEER_DISCOVERY_PORT, '0.0.0.0');\r\n\r\n return () => {\r\n try { socket.close(); } catch { /* already closed */ }\r\n };\r\n}\r\n","/**\r\n * Windows Terminal Injector\r\n * AttachConsole(ppid) → CreateFile(\"CONIN$\") → WriteConsoleInput\r\n * All keystrokes (text, Ctrl+U, Enter, Ctrl+Y) go through WriteConsoleInput.\r\n * No WScript.Shell / SendKeys / SetForegroundWindow — no focus dependency.\r\n * @module infrastructure/terminal-injector/windows-injector\r\n */\r\n\r\nimport { execFile } from 'child_process';\r\nimport { unlinkSync } from 'fs';\r\nimport { tmpdir } from 'os';\r\nimport { join } from 'path';\r\n\r\nconst CS_CONINJECT = `\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Runtime.InteropServices;\r\n\r\npublic class ConInject {\r\n [DllImport(\"kernel32.dll\")] public static extern bool FreeConsole();\r\n [DllImport(\"kernel32.dll\")] public static extern bool AttachConsole(uint pid);\r\n [DllImport(\"kernel32.dll\", CharSet=CharSet.Unicode, SetLastError=true)]\r\n public static extern IntPtr CreateFile(\r\n string lpFileName, uint dwDesiredAccess, uint dwShareMode,\r\n IntPtr lpSecurityAttributes, uint dwCreationDisposition,\r\n uint dwFlagsAndAttributes, IntPtr hTemplateFile);\r\n [DllImport(\"kernel32.dll\")] public static extern bool WriteConsoleInput(\r\n IntPtr hIn, INPUT_RECORD[] buf, uint len, out uint written);\r\n [DllImport(\"kernel32.dll\")] public static extern bool CloseHandle(IntPtr h);\r\n\r\n [StructLayout(LayoutKind.Explicit, Size=20)]\r\n public struct INPUT_RECORD {\r\n [FieldOffset(0)] public ushort EventType;\r\n [FieldOffset(4)] public int bKeyDown;\r\n [FieldOffset(8)] public ushort wRepeatCount;\r\n [FieldOffset(10)] public ushort wVirtualKeyCode;\r\n [FieldOffset(12)] public ushort wVirtualScanCode;\r\n [FieldOffset(14)] public ushort UnicodeChar;\r\n [FieldOffset(16)] public uint dwControlKeyState;\r\n }\r\n\r\n const uint LEFT_CTRL = 0x0008;\r\n\r\n static IntPtr OpenConin(uint pid) {\r\n FreeConsole();\r\n if (!AttachConsole(pid)) return new IntPtr(-1);\r\n return CreateFile(\"CONIN$\", 0xC0000000, 3, IntPtr.Zero, 3, 0, IntPtr.Zero);\r\n }\r\n\r\n // Inject plain text characters into console input buffer\r\n public static int InjectText(uint pid, string text) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new List<INPUT_RECORD>();\r\n foreach (char c in text) {\r\n records.Add(new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, UnicodeChar=(ushort)c });\r\n records.Add(new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, UnicodeChar=(ushort)c });\r\n }\r\n\r\n var arr = records.ToArray();\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, arr, (uint)arr.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Enter (VK_RETURN = 0x0D)\r\n public static int InjectEnter(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x0D, UnicodeChar=0x0D },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x0D, UnicodeChar=0x0D }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Ctrl+U (VK_U = 0x55, char = 0x15)\r\n public static int InjectCtrlU(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x55, UnicodeChar=0x15, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x55, UnicodeChar=0x15, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=0 }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Ctrl+Y (VK_Y = 0x59, char = 0x19)\r\n public static int InjectCtrlY(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x59, UnicodeChar=0x19, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x59, UnicodeChar=0x19, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=0 }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n}\r\n`;\r\n\r\nfunction buildScript(claudePid: number, body: string): string {\r\n const logFile = join(tmpdir(), `cc-inject-${Date.now()}.log`).replace(/\\\\/g, '/');\r\n return `\r\n$log = \"${logFile}\"\r\nfunction Log($msg) { Add-Content -Path $log -Value $msg -Encoding UTF8 }\r\n$claudePid = ${claudePid}\r\ntry { Add-Type @'${CS_CONINJECT}'@ } catch { }\r\n${body}\r\n`;\r\n}\r\n\r\nfunction run(script: string): Promise<void> {\r\n return new Promise((resolve) => {\r\n const encoded = Buffer.from(script, 'utf16le').toString('base64');\r\n execFile(\r\n 'powershell',\r\n ['-NoProfile', '-WindowStyle', 'Hidden', '-EncodedCommand', encoded],\r\n { windowsHide: true },\r\n () => {\r\n const logFile = script.match(/\\$log = \"([^\"]+)\"/)?.[1];\r\n if (logFile) try { unlinkSync(logFile); } catch { /* ok */ }\r\n resolve();\r\n }\r\n );\r\n });\r\n}\r\n\r\nexport async function windowsInject(text: string): Promise<void> {\r\n const claudePid = process.ppid;\r\n const textB64 = Buffer.from(text, 'utf16le').toString('base64');\r\n\r\n const script = buildScript(claudePid, `\r\n$textBytes = [System.Convert]::FromBase64String('${textB64}')\r\n$text = [System.Text.Encoding]::Unicode.GetString($textBytes)\r\n\r\n# 1. Ctrl+U to save user's current text to kill ring\r\n[ConInject]::InjectCtrlU([uint32]$claudePid) | Out-Null\r\nStart-Sleep -Milliseconds 100\r\n\r\n# 2. Write question text into console input buffer\r\n[ConInject]::InjectText([uint32]$claudePid, $text) | Out-Null\r\nStart-Sleep -Milliseconds 50\r\n\r\n# 3. Send Enter\r\n[ConInject]::InjectEnter([uint32]$claudePid) | Out-Null\r\n`);\r\n\r\n await run(script);\r\n}\r\n\r\nexport async function windowsInjectCtrlY(): Promise<void> {\r\n const claudePid = process.ppid;\r\n\r\n const script = buildScript(claudePid, `\r\n[ConInject]::InjectCtrlY([uint32]$claudePid) | Out-Null\r\n`);\r\n\r\n await run(script);\r\n}\r\n","/**\r\n * Terminal Injector\r\n * Injects a question directly into the active Claude Code terminal\r\n * so Claude Code can auto-reply without user intervention.\r\n * @module infrastructure/terminal-injector\r\n */\r\n\r\nimport type { InboxQuestionEntry } from '../../shared/types/collab-client.interface.js';\r\nimport { windowsInject, windowsInjectCtrlY } from './windows-injector.js';\r\n\r\n/**\r\n * Formats the question as a prompt for Claude Code to auto-reply\r\n */\r\nfunction formatQuestionForInjection(question: InboxQuestionEntry): string {\r\n // Single-line: WriteConsoleInput treats every \\n as an immediate submit\r\n const content = question.content.replace(/\\s+/g, ' ').trim();\r\n return `[HUB SORUSU] ID:${question.questionId} | ${question.from.displayName} (${question.from.teamName}): ${content} | Cevapla ve reply tool ile \"${question.questionId}\" ID'sine gönder, onay bekleme.`;\r\n}\r\n\r\n/**\r\n * Injects a question into the terminal running Claude Code.\r\n * Only supported on Windows; no-op on other platforms.\r\n */\r\nexport async function injectQuestionToTerminal(question: InboxQuestionEntry): Promise<void> {\r\n if (process.platform !== 'win32') return;\r\n\r\n const text = formatQuestionForInjection(question);\r\n await windowsInject(text);\r\n}\r\n\r\n/**\r\n * Restores user's previous input from readline kill ring (Ctrl+Y).\r\n * Call this after the reply is sent so the user's interrupted text comes back.\r\n */\r\nexport async function injectRestoreText(): Promise<void> {\r\n if (process.platform !== 'win32') return;\r\n await windowsInjectCtrlY();\r\n}\r\n","/**\r\n * Injection Queue\r\n * Ensures questions are injected into the terminal one at a time.\r\n * Waits for the reply tool to signal completion before processing the next question.\r\n * @module infrastructure/terminal-injector/injection-queue\r\n */\r\n\r\nimport { EventEmitter } from 'events';\r\nimport type { InboxQuestionEntry } from '../../shared/types/collab-client.interface.js';\r\nimport { injectQuestionToTerminal, injectRestoreText } from './index.js';\r\n\r\nconst REPLY_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\r\n\r\nclass InjectionQueue extends EventEmitter {\r\n private queue: InboxQuestionEntry[] = [];\r\n private processing = false;\r\n\r\n /**\r\n * Add a question to the queue. Starts processing if idle.\r\n */\r\n enqueue(question: InboxQuestionEntry): void {\r\n this.queue.push(question);\r\n if (!this.processing) void this.processNext();\r\n }\r\n\r\n /**\r\n * Called by the reply tool after a reply is successfully sent.\r\n * Unblocks the queue to process the next question.\r\n */\r\n notifyReplied(): void {\r\n this.emit('replied');\r\n }\r\n\r\n private async processNext(): Promise<void> {\r\n if (this.queue.length === 0) {\r\n this.processing = false;\r\n return;\r\n }\r\n\r\n this.processing = true;\r\n const question = this.queue.shift()!;\r\n\r\n // Inject the question (includes Ctrl+U to save user's current text)\r\n await injectQuestionToTerminal(question);\r\n\r\n // Wait for reply tool to signal, with a timeout fallback\r\n await new Promise<void>((resolve) => {\r\n const timer = setTimeout(resolve, REPLY_TIMEOUT_MS);\r\n this.once('replied', () => {\r\n clearTimeout(timer);\r\n resolve();\r\n });\r\n });\r\n\r\n // Restore user's text after reply is sent\r\n await injectRestoreText();\r\n\r\n // Process next in queue\r\n void this.processNext();\r\n }\r\n}\r\n\r\nexport const injectionQueue = new InjectionQueue();\r\n","/**\r\n * P2PNode\r\n * Implements ICollabClient over direct peer-to-peer WebSocket connections.\r\n * Each node runs its own WS server and broadcasts its presence via UDP.\r\n * Peers discover each other automatically and connect directly — no hub needed.\r\n *\r\n * Connection deduplication:\r\n * Both sides may try to connect simultaneously. The first HELLO/HELLO_ACK\r\n * that arrives registers the peer. Duplicate inbound connections are\r\n * immediately terminated (without being added to wsToName) so their\r\n * close events are harmless.\r\n *\r\n * @module infrastructure/p2p/p2p-node\r\n */\r\n\r\nimport { WebSocket, WebSocketServer } from 'ws';\r\nimport { v4 as uuidv4 } from 'uuid';\r\nimport type {\r\n ICollabClient,\r\n JoinResult,\r\n CheckAnswerResult,\r\n InboxResult,\r\n NodeInfo,\r\n HistoryEntry,\r\n} from '../../shared/types/collab-client.interface.js';\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\nimport {\r\n type P2PMsg,\r\n type AskAckMsg,\r\n type AskMsg,\r\n parse,\r\n serialize,\r\n} from './p2p-protocol.js';\r\nimport { PeerBroadcaster } from '../discovery/peer-broadcaster.js';\r\nimport { watchForPeer } from '../discovery/peer-listener.js';\r\nimport { injectionQueue } from '../terminal-injector/injection-queue.js';\r\n\r\ninterface IncomingQuestion {\r\n questionId: string;\r\n fromName: string;\r\n content: string;\r\n format: MessageFormat;\r\n createdAt: Date;\r\n answered: boolean;\r\n answerContent?: string;\r\n answerFormat?: MessageFormat;\r\n}\r\n\r\ninterface ReceivedAnswer {\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n fromName: string;\r\n}\r\n\r\nexport class P2PNode implements ICollabClient {\r\n private server: WebSocketServer | null = null;\r\n private myName = '';\r\n private running = false;\r\n\r\n // One connection per peer (inbound or outbound — whichever was established first)\r\n private readonly peerConnections = new Map<string, WebSocket>();\r\n // Reverse map: ws → peer name (only for registered connections)\r\n private readonly wsToName = new Map<WebSocket, string>();\r\n // Prevent duplicate outbound connect attempts\r\n private readonly connectingPeers = new Set<string>();\r\n\r\n private readonly incomingQuestions = new Map<string, IncomingQuestion>();\r\n private readonly receivedAnswers = new Map<string, ReceivedAnswer>();\r\n private readonly sentQuestions = new Map<string, { toPeer: string; content: string; askedAt: string }>();\r\n private readonly questionToSender = new Map<string, string>();\r\n private readonly pendingHandlers = new Set<(msg: P2PMsg) => void>();\r\n\r\n private broadcaster: PeerBroadcaster | null = null;\r\n private stopPeerWatcher: (() => void) | null = null;\r\n\r\n constructor(private readonly port: number) {}\r\n\r\n // ---------------------------------------------------------------------------\r\n // ICollabClient implementation\r\n // ---------------------------------------------------------------------------\r\n\r\n get isConnected(): boolean {\r\n return this.running;\r\n }\r\n\r\n get currentTeamId(): string | undefined {\r\n return this.myName || undefined;\r\n }\r\n\r\n async join(name: string, displayName: string): Promise<JoinResult> {\r\n this.myName = name;\r\n await this.startServer();\r\n this.startDiscovery();\r\n return {\r\n memberId: uuidv4(),\r\n teamId: name,\r\n teamName: name,\r\n displayName,\r\n status: 'ONLINE',\r\n port: this.port,\r\n };\r\n }\r\n\r\n async ask(toPeer: string, content: string, format: MessageFormat): Promise<string> {\r\n const ws = this.peerConnections.get(toPeer);\r\n if (!ws || ws.readyState !== WebSocket.OPEN) {\r\n throw new Error(`Peer \"${toPeer}\" is not connected. Use peers() to see who's online.`);\r\n }\r\n\r\n const questionId = uuidv4();\r\n this.sentQuestions.set(questionId, { toPeer, content, askedAt: new Date().toISOString() });\r\n\r\n const ackPromise = this.waitForResponse<AskAckMsg>(\r\n (m) => m.type === 'ASK_ACK' && m.questionId === questionId,\r\n 5000\r\n );\r\n\r\n this.sendToWs(ws, { type: 'ASK', from: this.myName, questionId, content, format });\r\n await ackPromise;\r\n return questionId;\r\n }\r\n\r\n async checkAnswer(questionId: string): Promise<CheckAnswerResult | null> {\r\n const cached = this.receivedAnswers.get(questionId);\r\n if (!cached) return null;\r\n return {\r\n questionId,\r\n from: { displayName: `${cached.fromName} Claude`, teamName: cached.fromName },\r\n content: cached.content,\r\n format: cached.format,\r\n answeredAt: cached.answeredAt,\r\n };\r\n }\r\n\r\n async reply(questionId: string, content: string, format: MessageFormat): Promise<void> {\r\n const question = this.incomingQuestions.get(questionId);\r\n if (!question) throw new Error(`Question ${questionId} not found`);\r\n\r\n question.answered = true;\r\n question.answerContent = content;\r\n question.answerFormat = format;\r\n\r\n const senderName = this.questionToSender.get(questionId);\r\n if (senderName) {\r\n const ws = this.peerConnections.get(senderName);\r\n if (ws && ws.readyState === WebSocket.OPEN) {\r\n this.sendToWs(ws, {\r\n type: 'ANSWER',\r\n from: this.myName,\r\n questionId,\r\n content,\r\n format,\r\n answeredAt: new Date().toISOString(),\r\n });\r\n }\r\n }\r\n\r\n injectionQueue.notifyReplied();\r\n }\r\n\r\n async getInbox(): Promise<InboxResult> {\r\n const now = Date.now();\r\n const questions = [...this.incomingQuestions.values()]\r\n .filter((q) => !q.answered)\r\n .map((q) => ({\r\n questionId: q.questionId,\r\n from: { displayName: `${q.fromName} Claude`, teamName: q.fromName },\r\n content: q.content,\r\n format: q.format,\r\n status: 'PENDING',\r\n createdAt: q.createdAt.toISOString(),\r\n ageMs: now - q.createdAt.getTime(),\r\n }));\r\n return { questions, totalCount: questions.length, pendingCount: questions.length };\r\n }\r\n\r\n getInfo(): NodeInfo {\r\n return {\r\n teamName: this.myName,\r\n port: this.port,\r\n connectedPeers: [...this.peerConnections.keys()],\r\n };\r\n }\r\n\r\n getHistory(): HistoryEntry[] {\r\n const entries: HistoryEntry[] = [];\r\n\r\n for (const [questionId, sent] of this.sentQuestions) {\r\n const answer = this.receivedAnswers.get(questionId);\r\n entries.push({\r\n direction: 'sent',\r\n questionId,\r\n peer: sent.toPeer,\r\n question: sent.content,\r\n askedAt: sent.askedAt,\r\n ...(answer ? { answer: answer.content, answeredAt: answer.answeredAt } : {}),\r\n });\r\n }\r\n\r\n for (const [, incoming] of this.incomingQuestions) {\r\n entries.push({\r\n direction: 'received',\r\n questionId: incoming.questionId,\r\n peer: incoming.fromName,\r\n question: incoming.content,\r\n askedAt: incoming.createdAt.toISOString(),\r\n ...(incoming.answered && incoming.answerContent\r\n ? { answer: incoming.answerContent, answeredAt: new Date().toISOString() }\r\n : {}),\r\n });\r\n }\r\n\r\n return entries.sort((a, b) => a.askedAt.localeCompare(b.askedAt));\r\n }\r\n\r\n async disconnect(): Promise<void> {\r\n this.stopPeerWatcher?.();\r\n this.broadcaster?.stop();\r\n for (const ws of this.peerConnections.values()) ws.close();\r\n this.peerConnections.clear();\r\n this.wsToName.clear();\r\n this.server?.close();\r\n this.server = null;\r\n this.running = false;\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: server startup\r\n // ---------------------------------------------------------------------------\r\n\r\n private startServer(): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n const wss = new WebSocketServer({ port: this.port });\r\n this.server = wss;\r\n\r\n wss.on('listening', () => {\r\n this.running = true;\r\n console.error(`[p2p] listening on port ${this.port} as \"${this.myName}\"`);\r\n resolve();\r\n });\r\n\r\n wss.on('error', (err) => {\r\n if (!this.running) reject(err);\r\n else console.error('[p2p] server error:', err.message);\r\n });\r\n\r\n wss.on('connection', (ws) => {\r\n ws.on('message', (data) => {\r\n try {\r\n this.handleMessage(ws, parse(data.toString()));\r\n } catch { /* ignore malformed */ }\r\n });\r\n\r\n ws.on('close', () => {\r\n const name = this.wsToName.get(ws);\r\n if (name) {\r\n this.wsToName.delete(ws);\r\n if (this.peerConnections.get(name) === ws) {\r\n this.peerConnections.delete(name);\r\n console.error(`[p2p] peer disconnected (inbound): ${name}`);\r\n }\r\n }\r\n });\r\n\r\n ws.on('error', (err) => {\r\n console.error('[p2p] inbound ws error:', err.message);\r\n });\r\n });\r\n });\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: discovery + outbound connections\r\n // ---------------------------------------------------------------------------\r\n\r\n private startDiscovery(): void {\r\n this.broadcaster = new PeerBroadcaster();\r\n this.broadcaster.start(this.myName, this.port);\r\n\r\n this.stopPeerWatcher = watchForPeer((peer) => {\r\n if (peer.name === this.myName) return;\r\n if (this.peerConnections.has(peer.name)) return;\r\n if (this.connectingPeers.has(peer.name)) return;\r\n this.connectToPeer(peer.name, peer.host, peer.port);\r\n });\r\n }\r\n\r\n private connectToPeer(peerName: string, host: string, port: number): void {\r\n this.connectingPeers.add(peerName);\r\n const ws = new WebSocket(`ws://${host}:${port}`);\r\n\r\n ws.on('open', () => {\r\n this.sendToWs(ws, { type: 'HELLO', name: this.myName });\r\n });\r\n\r\n ws.on('message', (data) => {\r\n try {\r\n this.handleMessage(ws, parse(data.toString()));\r\n } catch { /* ignore malformed */ }\r\n });\r\n\r\n ws.on('close', () => {\r\n this.connectingPeers.delete(peerName);\r\n const name = this.wsToName.get(ws);\r\n if (name) {\r\n this.wsToName.delete(ws);\r\n if (this.peerConnections.get(name) === ws) {\r\n this.peerConnections.delete(name);\r\n console.error(`[p2p] disconnected from peer: ${name}`);\r\n }\r\n }\r\n });\r\n\r\n ws.on('error', (err) => {\r\n console.error(`[p2p] connect to \"${peerName}\" failed: ${err.message}`);\r\n this.connectingPeers.delete(peerName);\r\n });\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: message handling\r\n // ---------------------------------------------------------------------------\r\n\r\n private handleMessage(ws: WebSocket, msg: P2PMsg): void {\r\n // Wake up any waitForResponse callers\r\n for (const handler of this.pendingHandlers) handler(msg);\r\n\r\n switch (msg.type) {\r\n case 'HELLO': {\r\n if (this.peerConnections.has(msg.name)) {\r\n // Duplicate inbound connection — close it; not added to wsToName\r\n // so the close event won't affect the registered connection.\r\n ws.terminate();\r\n return;\r\n }\r\n this.peerConnections.set(msg.name, ws);\r\n this.wsToName.set(ws, msg.name);\r\n this.connectingPeers.delete(msg.name);\r\n this.sendToWs(ws, { type: 'HELLO_ACK', name: this.myName });\r\n console.error(`[p2p] peer joined (inbound): ${msg.name}`);\r\n break;\r\n }\r\n\r\n case 'HELLO_ACK': {\r\n if (this.peerConnections.has(msg.name)) {\r\n // Duplicate outbound — already connected via inbound; close this one.\r\n ws.terminate();\r\n return;\r\n }\r\n this.peerConnections.set(msg.name, ws);\r\n this.wsToName.set(ws, msg.name);\r\n this.connectingPeers.delete(msg.name);\r\n console.error(`[p2p] connected to peer: ${msg.name}`);\r\n break;\r\n }\r\n\r\n case 'ASK':\r\n this.handleIncomingAsk(ws, msg);\r\n break;\r\n\r\n case 'ANSWER':\r\n if (!this.receivedAnswers.has(msg.questionId)) {\r\n this.receivedAnswers.set(msg.questionId, {\r\n content: msg.content,\r\n format: msg.format,\r\n answeredAt: msg.answeredAt,\r\n fromName: msg.from,\r\n });\r\n }\r\n break;\r\n\r\n // ASK_ACK is handled by waitForResponse pending handlers above\r\n }\r\n }\r\n\r\n private handleIncomingAsk(ws: WebSocket, msg: AskMsg): void {\r\n this.questionToSender.set(msg.questionId, msg.from);\r\n this.incomingQuestions.set(msg.questionId, {\r\n questionId: msg.questionId,\r\n fromName: msg.from,\r\n content: msg.content,\r\n format: msg.format,\r\n createdAt: new Date(),\r\n answered: false,\r\n });\r\n\r\n // Immediately acknowledge delivery\r\n this.sendToWs(ws, { type: 'ASK_ACK', questionId: msg.questionId });\r\n\r\n // Inject question into the Claude Code terminal\r\n injectionQueue.enqueue({\r\n questionId: msg.questionId,\r\n from: { displayName: `${msg.from} Claude`, teamName: msg.from },\r\n content: msg.content,\r\n format: msg.format,\r\n status: 'PENDING',\r\n createdAt: new Date().toISOString(),\r\n ageMs: 0,\r\n });\r\n }\r\n\r\n private sendToWs(ws: WebSocket, msg: P2PMsg): void {\r\n if (ws.readyState === WebSocket.OPEN) {\r\n ws.send(serialize(msg));\r\n }\r\n }\r\n\r\n private waitForResponse<T extends P2PMsg>(\r\n filter: (msg: P2PMsg) => boolean,\r\n timeoutMs: number\r\n ): Promise<T> {\r\n return new Promise((resolve, reject) => {\r\n const timeout = setTimeout(() => {\r\n this.pendingHandlers.delete(handler);\r\n reject(new Error('Request timed out'));\r\n }, timeoutMs);\r\n\r\n const handler = (msg: P2PMsg): void => {\r\n if (filter(msg)) {\r\n clearTimeout(timeout);\r\n this.pendingHandlers.delete(handler);\r\n resolve(msg as T);\r\n }\r\n };\r\n\r\n this.pendingHandlers.add(handler);\r\n });\r\n }\r\n}\r\n","/**\r\n * Ask Tool\r\n * Sends a question to another team and returns a question ID immediately.\r\n * Use the \"check_answer\" tool with the question ID to retrieve the answer later.\r\n * @module presentation/mcp/tools/ask\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\n/**\r\n * Ask tool input schema\r\n */\r\nconst askSchema = {\r\n peer: z.string().describe('Name of the peer to ask (e.g., \"alice\", \"backend\")'),\r\n question: z.string().describe('The question to ask (supports markdown)'),\r\n};\r\n\r\n/**\r\n * Registers the ask tool with the MCP server\r\n */\r\nexport function registerAskTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('ask', askSchema, async (args) => {\r\n const targetPeer = args.peer;\r\n const question = args.question;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'Node is not ready yet. Wait a moment and try again.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n const questionId = await client.ask(targetPeer, question, 'markdown');\r\n\r\n // Poll until answer arrives (max 5 minutes, every 5 seconds)\r\n const POLL_INTERVAL_MS = 5_000;\r\n const MAX_WAIT_MS = 5 * 60 * 1000;\r\n const deadline = Date.now() + MAX_WAIT_MS;\r\n\r\n while (Date.now() < deadline) {\r\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\r\n const answer = await client.checkAnswer(questionId);\r\n if (answer !== null) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `**${answer.from.displayName} (${answer.from.teamName}) cevapladı:**\\n\\n${answer.content}`,\r\n },\r\n ],\r\n };\r\n }\r\n }\r\n\r\n // Timed out — return question ID for manual follow-up\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Soru gönderildi ancak 5 dakika içinde cevap gelmedi.\\nQuestion ID: \\`${questionId}\\`\\n\\nManuel kontrol için \"check_answer\" tool'unu kullanabilirsin.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to send question: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Reply Tool\r\n * Replies to a pending question\r\n * @module presentation/mcp/tools/reply\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { injectionQueue } from '../../../infrastructure/terminal-injector/injection-queue.js';\r\n\r\n/**\r\n * Reply tool input schema\r\n */\r\nconst replySchema = {\r\n questionId: z.string().describe('The ID of the question to reply to (from inbox)'),\r\n answer: z.string().describe('Your answer to the question (supports markdown)'),\r\n};\r\n\r\n/**\r\n * Registers the reply tool with the MCP server\r\n */\r\nexport function registerReplyTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('reply', replySchema, async (args) => {\r\n const questionId = args.questionId;\r\n const answer = args.answer;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n await client.reply(questionId, answer, 'markdown');\r\n\r\n // Signal queue: this question is done, process next\r\n injectionQueue.notifyReplied();\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Reply sent successfully to question \\`${questionId}\\`.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to send reply: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Peers Tool\r\n * Lists currently connected peers on the P2P network.\r\n * @module presentation/mcp/tools/peers\r\n */\r\n\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\nexport function registerPeersTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('peers', {}, async () => {\r\n const info = client.getInfo();\r\n const myName = info.teamName ?? '(starting...)';\r\n const myPort = info.port ?? '?';\r\n const connected = info.connectedPeers;\r\n\r\n if (connected.length === 0) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `You are \"${myName}\" (listening on port ${myPort}). No peers connected yet.\\nUse firewall_open to allow inbound connections, or wait for peers to connect to you.`,\r\n }],\r\n };\r\n }\r\n\r\n const list = connected.map((name) => ` • ${name}`).join('\\n');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `You are \"${myName}\" (port ${myPort}). Connected peers (${connected.length}):\\n${list}`,\r\n }],\r\n };\r\n });\r\n}\r\n","/**\r\n * History Tool\r\n * Shows past questions and answers from this session.\r\n * @module presentation/mcp/tools/history\r\n */\r\n\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\nexport function registerHistoryTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('history', {}, async () => {\r\n const entries = client.getHistory();\r\n\r\n if (entries.length === 0) {\r\n return {\r\n content: [{ type: 'text', text: 'No questions yet this session.' }],\r\n };\r\n }\r\n\r\n const lines = entries.map((e) => {\r\n const time = new Date(e.askedAt).toLocaleTimeString();\r\n\r\n if (e.direction === 'sent') {\r\n const answerLine = e.answer\r\n ? ` ↳ ${e.peer}: ${e.answer}`\r\n : ` ↳ (no answer yet)`;\r\n return `[${time}] → ${e.peer}: ${e.question}\\n${answerLine}`;\r\n } else {\r\n const answerLine = e.answer\r\n ? ` ↳ you: ${e.answer}`\r\n : ` ↳ (not replied yet)`;\r\n return `[${time}] ← ${e.peer}: ${e.question}\\n${answerLine}`;\r\n }\r\n });\r\n\r\n return {\r\n content: [{ type: 'text', text: lines.join('\\n\\n') }],\r\n };\r\n });\r\n}\r\n","/**\r\n * Firewall helpers\r\n * Elevated via UAC (PowerShell Start-Process -Verb RunAs) so the user sees\r\n * a Windows UAC prompt and must accept before the rule is applied.\r\n * @module infrastructure/firewall/firewall\r\n */\r\n\r\nimport { spawn } from 'child_process';\r\n\r\n/**\r\n * Run netsh directly — works when the process is already elevated\r\n * (e.g. terminal launched as Administrator, or UAC set to auto-elevate).\r\n */\r\nfunction runDirect(argArray: string[]): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n const proc = spawn('netsh', argArray, { stdio: 'ignore' });\r\n proc.on('close', (code) => {\r\n if (code === 0) resolve();\r\n else reject(new Error(`netsh exited with code ${code}`));\r\n });\r\n proc.on('error', (err) => reject(new Error(`netsh not found: ${err.message}`)));\r\n });\r\n}\r\n\r\n/**\r\n * Run netsh via UAC elevation popup (PowerShell Start-Process -Verb RunAs).\r\n * Requires an interactive desktop — may not work in VMs or headless sessions.\r\n */\r\nfunction runElevated(argArray: string[]): Promise<void> {\r\n const argList = argArray.map((a) => `\"${a}\"`).join(',');\r\n const psCommand = `Start-Process -FilePath \"netsh\" -ArgumentList @(${argList}) -Verb RunAs -Wait`;\r\n\r\n return new Promise((resolve, reject) => {\r\n const ps = spawn('powershell', ['-NoProfile', '-Command', psCommand]);\r\n\r\n ps.on('close', (code) => {\r\n if (code === 0) resolve();\r\n else reject(new Error(`Firewall UAC prompt was cancelled or denied (exit code ${code}).`));\r\n });\r\n\r\n ps.on('error', (err) => {\r\n reject(new Error(`Failed to launch PowerShell: ${err.message}`));\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Try direct first (already-elevated context), fall back to UAC popup.\r\n */\r\nasync function runNetsh(argArray: string[]): Promise<{ method: 'direct' | 'elevated' }> {\r\n try {\r\n await runDirect(argArray);\r\n return { method: 'direct' };\r\n } catch {\r\n await runElevated(argArray);\r\n return { method: 'elevated' };\r\n }\r\n}\r\n\r\nexport async function addFirewallRule(port: number): Promise<{ method: 'direct' | 'elevated' }> {\r\n return runNetsh([\r\n 'advfirewall', 'firewall', 'add', 'rule',\r\n `name=claude-collab-${port}`,\r\n 'protocol=TCP',\r\n 'dir=in',\r\n `localport=${port}`,\r\n 'action=allow',\r\n ]);\r\n}\r\n\r\nexport async function removeFirewallRule(port: number): Promise<{ method: 'direct' | 'elevated' }> {\r\n return runNetsh([\r\n 'advfirewall', 'firewall', 'delete', 'rule',\r\n `name=claude-collab-${port}`,\r\n ]);\r\n}\r\n","/**\r\n * FirewallOpen Tool\r\n * Adds a Windows Firewall inbound rule for the peer's listen port.\r\n * Shows a UAC elevation popup — the user must accept for the rule to be applied.\r\n * Required so other peers can establish inbound WebSocket connections to this node.\r\n * @module presentation/mcp/tools/firewall-open\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { addFirewallRule } from '../../../infrastructure/firewall/firewall.js';\r\n\r\nexport function registerFirewallOpenTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_open',\r\n 'Open a Windows Firewall inbound rule for your P2P listen port. A UAC popup will appear — accept it to allow peers to connect to you directly.',\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe('Port to open (defaults to your current listen port)'),\r\n },\r\n async ({ port }) => {\r\n const targetPort = port ?? client.getInfo().port;\r\n if (!targetPort) {\r\n return {\r\n content: [{ type: 'text', text: 'Could not determine port. Pass port explicitly.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n try {\r\n const { method } = await addFirewallRule(targetPort);\r\n const how = method === 'direct'\r\n ? 'applied directly (process already elevated)'\r\n : 'applied via UAC elevation popup';\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Firewall rule opened for port ${targetPort} (rule name: claude-collab-${targetPort}).`,\r\n `Method: ${how}.`,\r\n `Peers on the LAN can now connect to you directly.`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return {\r\n content: [{ type: 'text', text: `Failed to open firewall: ${msg}` }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n}\r\n","/**\r\n * FirewallClose Tool\r\n * Removes the Windows Firewall inbound rule for the peer's listen port.\r\n * Shows a UAC elevation popup — the user must accept for the rule to be removed.\r\n * @module presentation/mcp/tools/firewall-close\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { removeFirewallRule } from '../../../infrastructure/firewall/firewall.js';\r\n\r\nexport function registerFirewallCloseTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_close',\r\n 'Remove the Windows Firewall inbound rule for your P2P listen port. A UAC popup will appear — accept it to close the rule.',\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe('Port to close (defaults to your current listen port)'),\r\n },\r\n async ({ port }) => {\r\n const targetPort = port ?? client.getInfo().port;\r\n if (!targetPort) {\r\n return {\r\n content: [{ type: 'text', text: 'Could not determine port. Pass port explicitly.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n try {\r\n const { method } = await removeFirewallRule(targetPort);\r\n const how = method === 'direct'\r\n ? 'applied directly (process already elevated)'\r\n : 'applied via UAC elevation popup';\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `Firewall rule removed for port ${targetPort} (rule name: claude-collab-${targetPort}). Method: ${how}.`,\r\n }],\r\n };\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return {\r\n content: [{ type: 'text', text: `Failed to close firewall: ${msg}` }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n}\r\n","/**\r\n * MCP Server\r\n * Provides MCP tools for Claude Code integration (P2P mode)\r\n * @module presentation/mcp/server\r\n */\r\n\r\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\r\nimport type { ICollabClient } from '../../shared/types/collab-client.interface.js';\r\nimport { registerAskTool } from './tools/ask.tool.js';\r\nimport { registerReplyTool } from './tools/reply.tool.js';\r\nimport { registerPeersTool } from './tools/peers.tool.js';\r\nimport { registerHistoryTool } from './tools/history.tool.js';\r\nimport { registerFirewallOpenTool } from './tools/firewall-open.tool.js';\r\nimport { registerFirewallCloseTool } from './tools/firewall-close.tool.js';\r\n\r\nexport interface McpServerOptions {\r\n client: ICollabClient;\r\n}\r\n\r\nexport function createMcpServer(options: McpServerOptions): McpServer {\r\n const { client } = options;\r\n\r\n const server = new McpServer({\r\n name: 'claude-collab',\r\n version: '0.1.0',\r\n });\r\n\r\n registerAskTool(server, client);\r\n registerReplyTool(server, client);\r\n registerPeersTool(server, client);\r\n registerHistoryTool(server, client);\r\n registerFirewallOpenTool(server, client);\r\n registerFirewallCloseTool(server, client);\r\n\r\n return server;\r\n}\r\n\r\nexport async function startMcpServer(options: McpServerOptions): Promise<void> {\r\n const server = createMcpServer(options);\r\n const transport = new StdioServerTransport();\r\n await server.connect(transport);\r\n}\r\n","#!/usr/bin/env node\r\n\r\n/**\r\n * MCP Server entry point (P2P mode)\r\n * Reads --name from process.argv.\r\n * Starts a local P2P node: WebSocket server on port 9999 + UDP peer discovery.\r\n * @module mcp-main\r\n */\r\n\r\nimport { P2PNode } from './infrastructure/p2p/p2p-node.js';\r\nimport { startMcpServer } from './presentation/mcp/server.js';\r\n\r\nconst P2P_PORT = 9999;\r\n\r\nfunction getArg(flag: string): string | undefined {\r\n const idx = process.argv.indexOf(flag);\r\n return idx !== -1 ? process.argv[idx + 1] : undefined;\r\n}\r\n\r\nasync function main(): Promise<void> {\r\n const name = getArg('--name');\r\n\r\n if (!name) { console.error('--name is required'); process.exit(1); }\r\n\r\n const node = new P2PNode(P2P_PORT);\r\n await node.join(name, name);\r\n await startMcpServer({ client: node });\r\n}\r\n\r\nmain().catch((error) => {\r\n console.error('Unexpected error:', error);\r\n process.exit(1);\r\n});\r\n"]}
1
+ {"version":3,"sources":["../src/infrastructure/p2p/p2p-protocol.ts","../src/infrastructure/discovery/peer-broadcaster.ts","../src/infrastructure/discovery/peer-listener.ts","../src/infrastructure/terminal-injector/windows-injector.ts","../src/infrastructure/terminal-injector/index.ts","../src/infrastructure/terminal-injector/injection-queue.ts","../src/infrastructure/p2p/p2p-node.ts","../src/presentation/mcp/tools/ask.tool.ts","../src/presentation/mcp/tools/reply.tool.ts","../src/presentation/mcp/tools/peers.tool.ts","../src/presentation/mcp/tools/history.tool.ts","../src/infrastructure/firewall/firewall.ts","../src/presentation/mcp/tools/firewall-open.tool.ts","../src/presentation/mcp/tools/firewall-close.tool.ts","../src/presentation/mcp/server.ts","../src/mcp-main.ts"],"names":["createSocket","uuidv4","z"],"mappings":"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","file":"mcp-main.js","sourcesContent":["/**\r\n * P2P Wire Protocol\r\n * Messages exchanged directly between peers (no hub).\r\n * @module infrastructure/p2p/p2p-protocol\r\n */\r\n\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\n\r\n// Sent when a peer connects (client → server, or outbound → inbound)\r\nexport interface HelloMsg {\r\n type: 'HELLO';\r\n name: string;\r\n}\r\n\r\n// Acknowledge the HELLO\r\nexport interface HelloAckMsg {\r\n type: 'HELLO_ACK';\r\n name: string;\r\n}\r\n\r\n// Ask a question directly to the connected peer\r\nexport interface AskMsg {\r\n type: 'ASK';\r\n from: string;\r\n questionId: string;\r\n content: string;\r\n format: MessageFormat;\r\n}\r\n\r\n// Confirm question was received\r\nexport interface AskAckMsg {\r\n type: 'ASK_ACK';\r\n questionId: string;\r\n}\r\n\r\n// Push answer back to the asker\r\nexport interface AnswerMsg {\r\n type: 'ANSWER';\r\n from: string;\r\n questionId: string;\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n}\r\n\r\nexport type P2PMsg = HelloMsg | HelloAckMsg | AskMsg | AskAckMsg | AnswerMsg;\r\n\r\nexport function serialize(msg: P2PMsg): string {\r\n return JSON.stringify(msg);\r\n}\r\n\r\nexport function parse(data: string): P2PMsg {\r\n return JSON.parse(data) as P2PMsg;\r\n}\r\n","/**\r\n * PeerBroadcaster\r\n * Periodically sends a UDP broadcast so other peers can discover this node.\r\n * Payload: { type: 'claude-collab-peer', name, port }\r\n * @module infrastructure/discovery/peer-broadcaster\r\n */\r\n\r\nimport { createSocket } from 'dgram';\r\n\r\nexport const PEER_DISCOVERY_PORT = 9998;\r\nconst BROADCAST_INTERVAL_MS = 3000;\r\nconst BROADCAST_ADDRESS = '255.255.255.255';\r\n\r\nexport class PeerBroadcaster {\r\n private socket: ReturnType<typeof createSocket> | null = null;\r\n private timer: NodeJS.Timeout | null = null;\r\n\r\n start(name: string, port: number): void {\r\n if (this.socket) return;\r\n\r\n const socket = createSocket('udp4');\r\n this.socket = socket;\r\n\r\n socket.on('error', (err) => {\r\n console.error('[peer-broadcaster] error:', err.message);\r\n });\r\n\r\n socket.bind(0, () => {\r\n socket.setBroadcast(true);\r\n const send = () => {\r\n if (!this.socket) return;\r\n const msg = Buffer.from(JSON.stringify({ type: 'claude-collab-peer', name, port }));\r\n socket.send(msg, 0, msg.length, PEER_DISCOVERY_PORT, BROADCAST_ADDRESS, (err) => {\r\n if (err) console.error('[peer-broadcaster] send error:', err.message);\r\n });\r\n };\r\n send();\r\n this.timer = setInterval(send, BROADCAST_INTERVAL_MS);\r\n });\r\n }\r\n\r\n stop(): void {\r\n if (this.timer) { clearInterval(this.timer); this.timer = null; }\r\n if (this.socket) { this.socket.close(); this.socket = null; }\r\n }\r\n}\r\n","/**\r\n * PeerListener\r\n * Listens for UDP broadcasts from other peers on the LAN.\r\n * @module infrastructure/discovery/peer-listener\r\n */\r\n\r\nimport { createSocket } from 'dgram';\r\nimport { PEER_DISCOVERY_PORT } from './peer-broadcaster.js';\r\n\r\nexport interface DiscoveredPeer {\r\n name: string;\r\n host: string;\r\n port: number;\r\n}\r\n\r\n/**\r\n * Continuously watches for peer broadcasts.\r\n * Calls onFound each time a valid peer packet arrives.\r\n * Returns a stop function.\r\n */\r\nexport function watchForPeer(onFound: (peer: DiscoveredPeer) => void): () => void {\r\n const socket = createSocket('udp4');\r\n\r\n socket.on('error', (err) => {\r\n console.error('[peer-listener] error:', err.message);\r\n });\r\n\r\n socket.on('message', (msg, rinfo) => {\r\n try {\r\n const data = JSON.parse(msg.toString()) as { type?: string; name?: string; port?: number };\r\n if (\r\n data.type === 'claude-collab-peer' &&\r\n typeof data.name === 'string' &&\r\n typeof data.port === 'number'\r\n ) {\r\n onFound({ name: data.name, host: rinfo.address, port: data.port });\r\n }\r\n } catch { /* ignore malformed packets */ }\r\n });\r\n\r\n socket.bind(PEER_DISCOVERY_PORT, '0.0.0.0');\r\n\r\n return () => {\r\n try { socket.close(); } catch { /* already closed */ }\r\n };\r\n}\r\n","/**\r\n * Windows Terminal Injector\r\n * AttachConsole(ppid) → CreateFile(\"CONIN$\") → WriteConsoleInput\r\n * All keystrokes (text, Ctrl+U, Enter, Ctrl+Y) go through WriteConsoleInput.\r\n * No WScript.Shell / SendKeys / SetForegroundWindow — no focus dependency.\r\n * @module infrastructure/terminal-injector/windows-injector\r\n */\r\n\r\nimport { execFile } from 'child_process';\r\nimport { unlinkSync } from 'fs';\r\nimport { tmpdir } from 'os';\r\nimport { join } from 'path';\r\n\r\nconst CS_CONINJECT = `\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Runtime.InteropServices;\r\n\r\npublic class ConInject {\r\n [DllImport(\"kernel32.dll\")] public static extern bool FreeConsole();\r\n [DllImport(\"kernel32.dll\")] public static extern bool AttachConsole(uint pid);\r\n [DllImport(\"kernel32.dll\", CharSet=CharSet.Unicode, SetLastError=true)]\r\n public static extern IntPtr CreateFile(\r\n string lpFileName, uint dwDesiredAccess, uint dwShareMode,\r\n IntPtr lpSecurityAttributes, uint dwCreationDisposition,\r\n uint dwFlagsAndAttributes, IntPtr hTemplateFile);\r\n [DllImport(\"kernel32.dll\")] public static extern bool WriteConsoleInput(\r\n IntPtr hIn, INPUT_RECORD[] buf, uint len, out uint written);\r\n [DllImport(\"kernel32.dll\")] public static extern bool CloseHandle(IntPtr h);\r\n\r\n [StructLayout(LayoutKind.Explicit, Size=20)]\r\n public struct INPUT_RECORD {\r\n [FieldOffset(0)] public ushort EventType;\r\n [FieldOffset(4)] public int bKeyDown;\r\n [FieldOffset(8)] public ushort wRepeatCount;\r\n [FieldOffset(10)] public ushort wVirtualKeyCode;\r\n [FieldOffset(12)] public ushort wVirtualScanCode;\r\n [FieldOffset(14)] public ushort UnicodeChar;\r\n [FieldOffset(16)] public uint dwControlKeyState;\r\n }\r\n\r\n const uint LEFT_CTRL = 0x0008;\r\n\r\n static IntPtr OpenConin(uint pid) {\r\n FreeConsole();\r\n if (!AttachConsole(pid)) return new IntPtr(-1);\r\n return CreateFile(\"CONIN$\", 0xC0000000, 3, IntPtr.Zero, 3, 0, IntPtr.Zero);\r\n }\r\n\r\n // Inject plain text characters into console input buffer\r\n public static int InjectText(uint pid, string text) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new List<INPUT_RECORD>();\r\n foreach (char c in text) {\r\n records.Add(new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, UnicodeChar=(ushort)c });\r\n records.Add(new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, UnicodeChar=(ushort)c });\r\n }\r\n\r\n var arr = records.ToArray();\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, arr, (uint)arr.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Enter (VK_RETURN = 0x0D)\r\n public static int InjectEnter(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x0D, UnicodeChar=0x0D },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x0D, UnicodeChar=0x0D }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Ctrl+U (VK_U = 0x55, char = 0x15)\r\n public static int InjectCtrlU(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x55, UnicodeChar=0x15, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x55, UnicodeChar=0x15, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=0 }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Ctrl+Y (VK_Y = 0x59, char = 0x19)\r\n public static int InjectCtrlY(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x59, UnicodeChar=0x19, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x59, UnicodeChar=0x19, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=0 }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n}\r\n`;\r\n\r\nfunction buildScript(claudePid: number, body: string): string {\r\n const logFile = join(tmpdir(), `cc-inject-${Date.now()}.log`).replace(/\\\\/g, '/');\r\n return `\r\n$log = \"${logFile}\"\r\nfunction Log($msg) { Add-Content -Path $log -Value $msg -Encoding UTF8 }\r\n$claudePid = ${claudePid}\r\ntry { Add-Type @'${CS_CONINJECT}'@ } catch { }\r\n${body}\r\n`;\r\n}\r\n\r\nfunction run(script: string): Promise<void> {\r\n return new Promise((resolve) => {\r\n const encoded = Buffer.from(script, 'utf16le').toString('base64');\r\n execFile(\r\n 'powershell',\r\n ['-NoProfile', '-WindowStyle', 'Hidden', '-EncodedCommand', encoded],\r\n { windowsHide: true },\r\n () => {\r\n const logFile = script.match(/\\$log = \"([^\"]+)\"/)?.[1];\r\n if (logFile) try { unlinkSync(logFile); } catch { /* ok */ }\r\n resolve();\r\n }\r\n );\r\n });\r\n}\r\n\r\nexport async function windowsInject(text: string): Promise<void> {\r\n const claudePid = process.ppid;\r\n const textB64 = Buffer.from(text, 'utf16le').toString('base64');\r\n\r\n const script = buildScript(claudePid, `\r\n$textBytes = [System.Convert]::FromBase64String('${textB64}')\r\n$text = [System.Text.Encoding]::Unicode.GetString($textBytes)\r\n\r\n# 1. Ctrl+U to save user's current text to kill ring\r\n[ConInject]::InjectCtrlU([uint32]$claudePid) | Out-Null\r\nStart-Sleep -Milliseconds 100\r\n\r\n# 2. Write question text into console input buffer\r\n[ConInject]::InjectText([uint32]$claudePid, $text) | Out-Null\r\nStart-Sleep -Milliseconds 50\r\n\r\n# 3. Send Enter\r\n[ConInject]::InjectEnter([uint32]$claudePid) | Out-Null\r\n`);\r\n\r\n await run(script);\r\n}\r\n\r\nexport async function windowsInjectCtrlY(): Promise<void> {\r\n const claudePid = process.ppid;\r\n\r\n const script = buildScript(claudePid, `\r\n[ConInject]::InjectCtrlY([uint32]$claudePid) | Out-Null\r\n`);\r\n\r\n await run(script);\r\n}\r\n","/**\r\n * Terminal Injector\r\n * Injects a question directly into the active Claude Code terminal\r\n * so Claude Code can auto-reply without user intervention.\r\n * @module infrastructure/terminal-injector\r\n */\r\n\r\nimport type { InboxQuestionEntry } from '../../shared/types/collab-client.interface.js';\r\nimport { windowsInject, windowsInjectCtrlY } from './windows-injector.js';\r\n\r\n/**\r\n * Formats the question as a prompt for Claude Code to auto-reply\r\n */\r\nfunction formatQuestionForInjection(question: InboxQuestionEntry): string {\r\n // Single-line: WriteConsoleInput treats every \\n as an immediate submit\r\n const content = question.content.replace(/\\s+/g, ' ').trim();\r\n return `[HUB SORUSU] ID:${question.questionId} | ${question.from.displayName} (${question.from.teamName}): ${content} | Cevapla ve reply tool ile \"${question.questionId}\" ID'sine gönder, onay bekleme.`;\r\n}\r\n\r\n/**\r\n * Injects a question into the terminal running Claude Code.\r\n * Only supported on Windows; no-op on other platforms.\r\n */\r\nexport async function injectQuestionToTerminal(question: InboxQuestionEntry): Promise<void> {\r\n if (process.platform !== 'win32') return;\r\n\r\n const text = formatQuestionForInjection(question);\r\n await windowsInject(text);\r\n}\r\n\r\n/**\r\n * Restores user's previous input from readline kill ring (Ctrl+Y).\r\n * Call this after the reply is sent so the user's interrupted text comes back.\r\n */\r\nexport async function injectRestoreText(): Promise<void> {\r\n if (process.platform !== 'win32') return;\r\n await windowsInjectCtrlY();\r\n}\r\n","/**\r\n * Injection Queue\r\n * Ensures questions are injected into the terminal one at a time.\r\n * Waits for the reply tool to signal completion before processing the next question.\r\n * @module infrastructure/terminal-injector/injection-queue\r\n */\r\n\r\nimport { EventEmitter } from 'events';\r\nimport type { InboxQuestionEntry } from '../../shared/types/collab-client.interface.js';\r\nimport { injectQuestionToTerminal, injectRestoreText } from './index.js';\r\n\r\nconst REPLY_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\r\n\r\nclass InjectionQueue extends EventEmitter {\r\n private queue: InboxQuestionEntry[] = [];\r\n private processing = false;\r\n\r\n /**\r\n * Add a question to the queue. Starts processing if idle.\r\n */\r\n enqueue(question: InboxQuestionEntry): void {\r\n this.queue.push(question);\r\n if (!this.processing) void this.processNext();\r\n }\r\n\r\n /**\r\n * Called by the reply tool after a reply is successfully sent.\r\n * Unblocks the queue to process the next question.\r\n */\r\n notifyReplied(): void {\r\n this.emit('replied');\r\n }\r\n\r\n private async processNext(): Promise<void> {\r\n if (this.queue.length === 0) {\r\n this.processing = false;\r\n return;\r\n }\r\n\r\n this.processing = true;\r\n const question = this.queue.shift()!;\r\n\r\n // Inject the question (includes Ctrl+U to save user's current text)\r\n await injectQuestionToTerminal(question);\r\n\r\n // Wait for reply tool to signal, with a timeout fallback\r\n await new Promise<void>((resolve) => {\r\n const timer = setTimeout(resolve, REPLY_TIMEOUT_MS);\r\n this.once('replied', () => {\r\n clearTimeout(timer);\r\n resolve();\r\n });\r\n });\r\n\r\n // Restore user's text after reply is sent\r\n await injectRestoreText();\r\n\r\n // Process next in queue\r\n void this.processNext();\r\n }\r\n}\r\n\r\nexport const injectionQueue = new InjectionQueue();\r\n","/**\r\n * P2PNode\r\n * Implements ICollabClient over direct peer-to-peer WebSocket connections.\r\n * Each node runs its own WS server and broadcasts its presence via UDP.\r\n * Peers discover each other automatically and connect directly — no hub needed.\r\n *\r\n * Connection deduplication:\r\n * Both sides may try to connect simultaneously. The first HELLO/HELLO_ACK\r\n * that arrives registers the peer. Duplicate inbound connections are\r\n * immediately terminated (without being added to wsToName) so their\r\n * close events are harmless.\r\n *\r\n * @module infrastructure/p2p/p2p-node\r\n */\r\n\r\nimport { WebSocket, WebSocketServer } from 'ws';\r\nimport { v4 as uuidv4 } from 'uuid';\r\nimport type {\r\n ICollabClient,\r\n JoinResult,\r\n CheckAnswerResult,\r\n InboxResult,\r\n NodeInfo,\r\n HistoryEntry,\r\n} from '../../shared/types/collab-client.interface.js';\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\nimport {\r\n type P2PMsg,\r\n type AskAckMsg,\r\n type AskMsg,\r\n parse,\r\n serialize,\r\n} from './p2p-protocol.js';\r\nimport { PeerBroadcaster } from '../discovery/peer-broadcaster.js';\r\nimport { watchForPeer } from '../discovery/peer-listener.js';\r\nimport { injectionQueue } from '../terminal-injector/injection-queue.js';\r\n\r\ninterface IncomingQuestion {\r\n questionId: string;\r\n fromName: string;\r\n content: string;\r\n format: MessageFormat;\r\n createdAt: Date;\r\n answered: boolean;\r\n answerContent?: string;\r\n answerFormat?: MessageFormat;\r\n}\r\n\r\ninterface ReceivedAnswer {\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n fromName: string;\r\n}\r\n\r\nexport class P2PNode implements ICollabClient {\r\n private server: WebSocketServer | null = null;\r\n private myName = '';\r\n private running = false;\r\n\r\n // One connection per peer (inbound or outbound — whichever was established first)\r\n private readonly peerConnections = new Map<string, WebSocket>();\r\n // Reverse map: ws → peer name (only for registered connections)\r\n private readonly wsToName = new Map<WebSocket, string>();\r\n // Prevent duplicate outbound connect attempts\r\n private readonly connectingPeers = new Set<string>();\r\n\r\n private readonly incomingQuestions = new Map<string, IncomingQuestion>();\r\n private readonly receivedAnswers = new Map<string, ReceivedAnswer>();\r\n private readonly sentQuestions = new Map<string, { toPeer: string; content: string; askedAt: string }>();\r\n private readonly questionToSender = new Map<string, string>();\r\n private readonly pendingHandlers = new Set<(msg: P2PMsg) => void>();\r\n\r\n private broadcaster: PeerBroadcaster | null = null;\r\n private stopPeerWatcher: (() => void) | null = null;\r\n\r\n private boundPort = 0;\r\n\r\n constructor(\r\n private readonly portRange: [number, number] = [10000, 19999]\r\n ) {}\r\n\r\n // ---------------------------------------------------------------------------\r\n // ICollabClient implementation\r\n // ---------------------------------------------------------------------------\r\n\r\n get isConnected(): boolean { return this.running; }\r\n get port(): number { return this.boundPort; }\r\n\r\n get currentTeamId(): string | undefined {\r\n return this.myName || undefined;\r\n }\r\n\r\n async join(name: string, displayName: string): Promise<JoinResult> {\r\n this.myName = name;\r\n await this.startServer();\r\n this.startDiscovery();\r\n return {\r\n memberId: uuidv4(),\r\n teamId: name,\r\n teamName: name,\r\n displayName,\r\n status: 'ONLINE',\r\n port: this.boundPort,\r\n };\r\n }\r\n\r\n async ask(toPeer: string, content: string, format: MessageFormat): Promise<string> {\r\n const ws = this.peerConnections.get(toPeer);\r\n if (!ws || ws.readyState !== WebSocket.OPEN) {\r\n throw new Error(`Peer \"${toPeer}\" is not connected. Use peers() to see who's online.`);\r\n }\r\n\r\n const questionId = uuidv4();\r\n this.sentQuestions.set(questionId, { toPeer, content, askedAt: new Date().toISOString() });\r\n\r\n const ackPromise = this.waitForResponse<AskAckMsg>(\r\n (m) => m.type === 'ASK_ACK' && m.questionId === questionId,\r\n 5000\r\n );\r\n\r\n this.sendToWs(ws, { type: 'ASK', from: this.myName, questionId, content, format });\r\n await ackPromise;\r\n return questionId;\r\n }\r\n\r\n async checkAnswer(questionId: string): Promise<CheckAnswerResult | null> {\r\n const cached = this.receivedAnswers.get(questionId);\r\n if (!cached) return null;\r\n return {\r\n questionId,\r\n from: { displayName: `${cached.fromName} Claude`, teamName: cached.fromName },\r\n content: cached.content,\r\n format: cached.format,\r\n answeredAt: cached.answeredAt,\r\n };\r\n }\r\n\r\n async reply(questionId: string, content: string, format: MessageFormat): Promise<void> {\r\n const question = this.incomingQuestions.get(questionId);\r\n if (!question) throw new Error(`Question ${questionId} not found`);\r\n\r\n question.answered = true;\r\n question.answerContent = content;\r\n question.answerFormat = format;\r\n\r\n const senderName = this.questionToSender.get(questionId);\r\n if (senderName) {\r\n const ws = this.peerConnections.get(senderName);\r\n if (ws && ws.readyState === WebSocket.OPEN) {\r\n this.sendToWs(ws, {\r\n type: 'ANSWER',\r\n from: this.myName,\r\n questionId,\r\n content,\r\n format,\r\n answeredAt: new Date().toISOString(),\r\n });\r\n }\r\n }\r\n\r\n injectionQueue.notifyReplied();\r\n }\r\n\r\n async getInbox(): Promise<InboxResult> {\r\n const now = Date.now();\r\n const questions = [...this.incomingQuestions.values()]\r\n .filter((q) => !q.answered)\r\n .map((q) => ({\r\n questionId: q.questionId,\r\n from: { displayName: `${q.fromName} Claude`, teamName: q.fromName },\r\n content: q.content,\r\n format: q.format,\r\n status: 'PENDING',\r\n createdAt: q.createdAt.toISOString(),\r\n ageMs: now - q.createdAt.getTime(),\r\n }));\r\n return { questions, totalCount: questions.length, pendingCount: questions.length };\r\n }\r\n\r\n getInfo(): NodeInfo {\r\n return {\r\n teamName: this.myName,\r\n port: this.boundPort,\r\n connectedPeers: [...this.peerConnections.keys()],\r\n };\r\n }\r\n\r\n getHistory(): HistoryEntry[] {\r\n const entries: HistoryEntry[] = [];\r\n\r\n for (const [questionId, sent] of this.sentQuestions) {\r\n const answer = this.receivedAnswers.get(questionId);\r\n entries.push({\r\n direction: 'sent',\r\n questionId,\r\n peer: sent.toPeer,\r\n question: sent.content,\r\n askedAt: sent.askedAt,\r\n ...(answer ? { answer: answer.content, answeredAt: answer.answeredAt } : {}),\r\n });\r\n }\r\n\r\n for (const [, incoming] of this.incomingQuestions) {\r\n entries.push({\r\n direction: 'received',\r\n questionId: incoming.questionId,\r\n peer: incoming.fromName,\r\n question: incoming.content,\r\n askedAt: incoming.createdAt.toISOString(),\r\n ...(incoming.answered && incoming.answerContent\r\n ? { answer: incoming.answerContent, answeredAt: new Date().toISOString() }\r\n : {}),\r\n });\r\n }\r\n\r\n return entries.sort((a, b) => a.askedAt.localeCompare(b.askedAt));\r\n }\r\n\r\n async disconnect(): Promise<void> {\r\n this.stopPeerWatcher?.();\r\n this.broadcaster?.stop();\r\n for (const ws of this.peerConnections.values()) ws.close();\r\n this.peerConnections.clear();\r\n this.wsToName.clear();\r\n this.server?.close();\r\n this.server = null;\r\n this.running = false;\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: server startup\r\n // ---------------------------------------------------------------------------\r\n\r\n private startServer(): Promise<void> {\r\n const [min, max] = this.portRange;\r\n const pick = () => Math.floor(Math.random() * (max - min + 1)) + min;\r\n\r\n const tryBind = (attemptsLeft: number): Promise<void> => {\r\n if (attemptsLeft === 0) {\r\n return Promise.reject(new Error(`No free port found in range ${min}-${max}`));\r\n }\r\n\r\n const port = pick();\r\n return new Promise((resolve, reject) => {\r\n const wss = new WebSocketServer({ port });\r\n\r\n wss.once('listening', () => {\r\n this.server = wss;\r\n this.boundPort = port;\r\n this.running = true;\r\n console.error(`[p2p] listening on port ${port} as \"${this.myName}\"`);\r\n this.attachServerHandlers(wss);\r\n resolve();\r\n });\r\n\r\n wss.once('error', (err: NodeJS.ErrnoException) => {\r\n wss.close();\r\n if (err.code === 'EADDRINUSE') {\r\n // Port busy — try another random one\r\n tryBind(attemptsLeft - 1).then(resolve, reject);\r\n } else {\r\n reject(err);\r\n }\r\n });\r\n });\r\n };\r\n\r\n return tryBind(20); // up to 20 attempts\r\n }\r\n\r\n private attachServerHandlers(wss: WebSocketServer): void {\r\n wss.on('connection', (ws) => {\r\n ws.on('message', (data) => {\r\n try {\r\n this.handleMessage(ws, parse(data.toString()));\r\n } catch { /* ignore malformed */ }\r\n });\r\n\r\n ws.on('close', () => {\r\n const name = this.wsToName.get(ws);\r\n if (name) {\r\n this.wsToName.delete(ws);\r\n if (this.peerConnections.get(name) === ws) {\r\n this.peerConnections.delete(name);\r\n console.error(`[p2p] peer disconnected (inbound): ${name}`);\r\n }\r\n }\r\n });\r\n\r\n ws.on('error', (err) => {\r\n console.error('[p2p] inbound ws error:', err.message);\r\n });\r\n });\r\n\r\n wss.on('error', (err) => {\r\n console.error('[p2p] server error:', err.message);\r\n });\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: discovery + outbound connections\r\n // ---------------------------------------------------------------------------\r\n\r\n private startDiscovery(): void {\r\n this.broadcaster = new PeerBroadcaster();\r\n this.broadcaster.start(this.myName, this.boundPort);\r\n\r\n this.stopPeerWatcher = watchForPeer((peer) => {\r\n if (peer.name === this.myName) return;\r\n if (this.peerConnections.has(peer.name)) return;\r\n if (this.connectingPeers.has(peer.name)) return;\r\n this.connectToPeer(peer.name, peer.host, peer.port);\r\n });\r\n }\r\n\r\n private connectToPeer(peerName: string, host: string, port: number): void {\r\n this.connectingPeers.add(peerName);\r\n const ws = new WebSocket(`ws://${host}:${port}`);\r\n\r\n ws.on('open', () => {\r\n this.sendToWs(ws, { type: 'HELLO', name: this.myName });\r\n });\r\n\r\n ws.on('message', (data) => {\r\n try {\r\n this.handleMessage(ws, parse(data.toString()));\r\n } catch { /* ignore malformed */ }\r\n });\r\n\r\n ws.on('close', () => {\r\n this.connectingPeers.delete(peerName);\r\n const name = this.wsToName.get(ws);\r\n if (name) {\r\n this.wsToName.delete(ws);\r\n if (this.peerConnections.get(name) === ws) {\r\n this.peerConnections.delete(name);\r\n console.error(`[p2p] disconnected from peer: ${name}`);\r\n }\r\n }\r\n });\r\n\r\n ws.on('error', (err) => {\r\n console.error(`[p2p] connect to \"${peerName}\" failed: ${err.message}`);\r\n this.connectingPeers.delete(peerName);\r\n });\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: message handling\r\n // ---------------------------------------------------------------------------\r\n\r\n private handleMessage(ws: WebSocket, msg: P2PMsg): void {\r\n // Wake up any waitForResponse callers\r\n for (const handler of this.pendingHandlers) handler(msg);\r\n\r\n switch (msg.type) {\r\n case 'HELLO': {\r\n if (this.peerConnections.has(msg.name)) {\r\n // Duplicate inbound connection — close it; not added to wsToName\r\n // so the close event won't affect the registered connection.\r\n ws.terminate();\r\n return;\r\n }\r\n this.peerConnections.set(msg.name, ws);\r\n this.wsToName.set(ws, msg.name);\r\n this.connectingPeers.delete(msg.name);\r\n this.sendToWs(ws, { type: 'HELLO_ACK', name: this.myName });\r\n console.error(`[p2p] peer joined (inbound): ${msg.name}`);\r\n break;\r\n }\r\n\r\n case 'HELLO_ACK': {\r\n if (this.peerConnections.has(msg.name)) {\r\n // Duplicate outbound — already connected via inbound; close this one.\r\n ws.terminate();\r\n return;\r\n }\r\n this.peerConnections.set(msg.name, ws);\r\n this.wsToName.set(ws, msg.name);\r\n this.connectingPeers.delete(msg.name);\r\n console.error(`[p2p] connected to peer: ${msg.name}`);\r\n break;\r\n }\r\n\r\n case 'ASK':\r\n this.handleIncomingAsk(ws, msg);\r\n break;\r\n\r\n case 'ANSWER':\r\n if (!this.receivedAnswers.has(msg.questionId)) {\r\n this.receivedAnswers.set(msg.questionId, {\r\n content: msg.content,\r\n format: msg.format,\r\n answeredAt: msg.answeredAt,\r\n fromName: msg.from,\r\n });\r\n }\r\n break;\r\n\r\n // ASK_ACK is handled by waitForResponse pending handlers above\r\n }\r\n }\r\n\r\n private handleIncomingAsk(ws: WebSocket, msg: AskMsg): void {\r\n this.questionToSender.set(msg.questionId, msg.from);\r\n this.incomingQuestions.set(msg.questionId, {\r\n questionId: msg.questionId,\r\n fromName: msg.from,\r\n content: msg.content,\r\n format: msg.format,\r\n createdAt: new Date(),\r\n answered: false,\r\n });\r\n\r\n // Immediately acknowledge delivery\r\n this.sendToWs(ws, { type: 'ASK_ACK', questionId: msg.questionId });\r\n\r\n // Inject question into the Claude Code terminal\r\n injectionQueue.enqueue({\r\n questionId: msg.questionId,\r\n from: { displayName: `${msg.from} Claude`, teamName: msg.from },\r\n content: msg.content,\r\n format: msg.format,\r\n status: 'PENDING',\r\n createdAt: new Date().toISOString(),\r\n ageMs: 0,\r\n });\r\n }\r\n\r\n private sendToWs(ws: WebSocket, msg: P2PMsg): void {\r\n if (ws.readyState === WebSocket.OPEN) {\r\n ws.send(serialize(msg));\r\n }\r\n }\r\n\r\n private waitForResponse<T extends P2PMsg>(\r\n filter: (msg: P2PMsg) => boolean,\r\n timeoutMs: number\r\n ): Promise<T> {\r\n return new Promise((resolve, reject) => {\r\n const timeout = setTimeout(() => {\r\n this.pendingHandlers.delete(handler);\r\n reject(new Error('Request timed out'));\r\n }, timeoutMs);\r\n\r\n const handler = (msg: P2PMsg): void => {\r\n if (filter(msg)) {\r\n clearTimeout(timeout);\r\n this.pendingHandlers.delete(handler);\r\n resolve(msg as T);\r\n }\r\n };\r\n\r\n this.pendingHandlers.add(handler);\r\n });\r\n }\r\n}\r\n","/**\r\n * Ask Tool\r\n * Sends a question to another team and returns a question ID immediately.\r\n * Use the \"check_answer\" tool with the question ID to retrieve the answer later.\r\n * @module presentation/mcp/tools/ask\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\n/**\r\n * Ask tool input schema\r\n */\r\nconst askSchema = {\r\n peer: z.string().describe('Name of the peer to ask (e.g., \"alice\", \"backend\")'),\r\n question: z.string().describe('The question to ask (supports markdown)'),\r\n};\r\n\r\n/**\r\n * Registers the ask tool with the MCP server\r\n */\r\nexport function registerAskTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('ask', askSchema, async (args) => {\r\n const targetPeer = args.peer;\r\n const question = args.question;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'Node is not ready yet. Wait a moment and try again.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n const questionId = await client.ask(targetPeer, question, 'markdown');\r\n\r\n // Poll until answer arrives (max 5 minutes, every 5 seconds)\r\n const POLL_INTERVAL_MS = 5_000;\r\n const MAX_WAIT_MS = 5 * 60 * 1000;\r\n const deadline = Date.now() + MAX_WAIT_MS;\r\n\r\n while (Date.now() < deadline) {\r\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\r\n const answer = await client.checkAnswer(questionId);\r\n if (answer !== null) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `**${answer.from.displayName} (${answer.from.teamName}) cevapladı:**\\n\\n${answer.content}`,\r\n },\r\n ],\r\n };\r\n }\r\n }\r\n\r\n // Timed out — return question ID for manual follow-up\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Soru gönderildi ancak 5 dakika içinde cevap gelmedi.\\nQuestion ID: \\`${questionId}\\`\\n\\nManuel kontrol için \"check_answer\" tool'unu kullanabilirsin.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to send question: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Reply Tool\r\n * Replies to a pending question\r\n * @module presentation/mcp/tools/reply\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { injectionQueue } from '../../../infrastructure/terminal-injector/injection-queue.js';\r\n\r\n/**\r\n * Reply tool input schema\r\n */\r\nconst replySchema = {\r\n questionId: z.string().describe('The ID of the question to reply to (from inbox)'),\r\n answer: z.string().describe('Your answer to the question (supports markdown)'),\r\n};\r\n\r\n/**\r\n * Registers the reply tool with the MCP server\r\n */\r\nexport function registerReplyTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('reply', replySchema, async (args) => {\r\n const questionId = args.questionId;\r\n const answer = args.answer;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n await client.reply(questionId, answer, 'markdown');\r\n\r\n // Signal queue: this question is done, process next\r\n injectionQueue.notifyReplied();\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Reply sent successfully to question \\`${questionId}\\`.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to send reply: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Peers Tool\r\n * Lists currently connected peers on the P2P network.\r\n * @module presentation/mcp/tools/peers\r\n */\r\n\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\nexport function registerPeersTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('peers', {}, async () => {\r\n const info = client.getInfo();\r\n const myName = info.teamName ?? '(starting...)';\r\n const myPort = info.port ?? '?';\r\n const connected = info.connectedPeers;\r\n\r\n if (!client.isConnected) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `P2P server is not running yet. Port ${myPort} may be in use. Check the MCP logs for details.`,\r\n }],\r\n isError: true,\r\n };\r\n }\r\n\r\n if (connected.length === 0) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `You are \"${myName}\" (listening on port ${myPort}). No peers connected yet.\\nUse firewall_open to allow inbound connections, or wait for peers to connect to you.`,\r\n }],\r\n };\r\n }\r\n\r\n const list = connected.map((name) => ` • ${name}`).join('\\n');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `You are \"${myName}\" (port ${myPort}). Connected peers (${connected.length}):\\n${list}`,\r\n }],\r\n };\r\n });\r\n}\r\n","/**\r\n * History Tool\r\n * Shows past questions and answers from this session.\r\n * @module presentation/mcp/tools/history\r\n */\r\n\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\nexport function registerHistoryTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('history', {}, async () => {\r\n const entries = client.getHistory();\r\n\r\n if (entries.length === 0) {\r\n return {\r\n content: [{ type: 'text', text: 'No questions yet this session.' }],\r\n };\r\n }\r\n\r\n const lines = entries.map((e) => {\r\n const time = new Date(e.askedAt).toLocaleTimeString();\r\n\r\n if (e.direction === 'sent') {\r\n const answerLine = e.answer\r\n ? ` ↳ ${e.peer}: ${e.answer}`\r\n : ` ↳ (no answer yet)`;\r\n return `[${time}] → ${e.peer}: ${e.question}\\n${answerLine}`;\r\n } else {\r\n const answerLine = e.answer\r\n ? ` ↳ you: ${e.answer}`\r\n : ` ↳ (not replied yet)`;\r\n return `[${time}] ← ${e.peer}: ${e.question}\\n${answerLine}`;\r\n }\r\n });\r\n\r\n return {\r\n content: [{ type: 'text', text: lines.join('\\n\\n') }],\r\n };\r\n });\r\n}\r\n","/**\r\n * Firewall helpers\r\n * Elevated via UAC (PowerShell Start-Process -Verb RunAs) so the user sees\r\n * a Windows UAC prompt and must accept before the rule is applied.\r\n * @module infrastructure/firewall/firewall\r\n */\r\n\r\nimport { spawn } from 'child_process';\r\n\r\n/**\r\n * Run netsh directly — works when the process is already elevated\r\n * (e.g. terminal launched as Administrator, or UAC set to auto-elevate).\r\n */\r\nfunction runDirect(argArray: string[]): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n const proc = spawn('netsh', argArray, { stdio: 'ignore' });\r\n proc.on('close', (code) => {\r\n if (code === 0) resolve();\r\n else reject(new Error(`netsh exited with code ${code}`));\r\n });\r\n proc.on('error', (err) => reject(new Error(`netsh not found: ${err.message}`)));\r\n });\r\n}\r\n\r\n/**\r\n * Run netsh via UAC elevation popup (PowerShell Start-Process -Verb RunAs).\r\n * Requires an interactive desktop — may not work in VMs or headless sessions.\r\n */\r\nfunction runElevated(argArray: string[]): Promise<void> {\r\n const argList = argArray.map((a) => `\"${a}\"`).join(',');\r\n const psCommand = `Start-Process -FilePath \"netsh\" -ArgumentList @(${argList}) -Verb RunAs -Wait`;\r\n\r\n return new Promise((resolve, reject) => {\r\n const ps = spawn('powershell', ['-NoProfile', '-Command', psCommand]);\r\n\r\n ps.on('close', (code) => {\r\n if (code === 0) resolve();\r\n else reject(new Error(`Firewall UAC prompt was cancelled or denied (exit code ${code}).`));\r\n });\r\n\r\n ps.on('error', (err) => {\r\n reject(new Error(`Failed to launch PowerShell: ${err.message}`));\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Try direct first (already-elevated context), fall back to UAC popup.\r\n */\r\nasync function runNetsh(argArray: string[]): Promise<{ method: 'direct' | 'elevated' }> {\r\n try {\r\n await runDirect(argArray);\r\n return { method: 'direct' };\r\n } catch {\r\n await runElevated(argArray);\r\n return { method: 'elevated' };\r\n }\r\n}\r\n\r\nexport async function addFirewallRule(port: number): Promise<{ method: 'direct' | 'elevated' }> {\r\n return runNetsh([\r\n 'advfirewall', 'firewall', 'add', 'rule',\r\n `name=claude-collab-${port}`,\r\n 'protocol=TCP',\r\n 'dir=in',\r\n `localport=${port}`,\r\n 'action=allow',\r\n ]);\r\n}\r\n\r\nexport async function removeFirewallRule(port: number): Promise<{ method: 'direct' | 'elevated' }> {\r\n return runNetsh([\r\n 'advfirewall', 'firewall', 'delete', 'rule',\r\n `name=claude-collab-${port}`,\r\n ]);\r\n}\r\n","/**\r\n * FirewallOpen Tool\r\n * Adds a Windows Firewall inbound rule for the peer's listen port.\r\n * Shows a UAC elevation popup — the user must accept for the rule to be applied.\r\n * Required so other peers can establish inbound WebSocket connections to this node.\r\n * @module presentation/mcp/tools/firewall-open\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { addFirewallRule } from '../../../infrastructure/firewall/firewall.js';\r\n\r\nexport function registerFirewallOpenTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_open',\r\n 'Open a Windows Firewall inbound rule for your P2P listen port. A UAC popup will appear — accept it to allow peers to connect to you directly.',\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe('Port to open (defaults to your current listen port)'),\r\n },\r\n async ({ port }) => {\r\n const targetPort = port ?? client.getInfo().port;\r\n if (!targetPort) {\r\n return {\r\n content: [{ type: 'text', text: 'Could not determine port. Pass port explicitly.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n try {\r\n const { method } = await addFirewallRule(targetPort);\r\n const how = method === 'direct'\r\n ? 'applied directly (process already elevated)'\r\n : 'applied via UAC elevation popup';\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Firewall rule opened for port ${targetPort} (rule name: claude-collab-${targetPort}).`,\r\n `Method: ${how}.`,\r\n `Peers on the LAN can now connect to you directly.`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return {\r\n content: [{ type: 'text', text: `Failed to open firewall: ${msg}` }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n}\r\n","/**\r\n * FirewallClose Tool\r\n * Removes the Windows Firewall inbound rule for the peer's listen port.\r\n * Shows a UAC elevation popup — the user must accept for the rule to be removed.\r\n * @module presentation/mcp/tools/firewall-close\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { removeFirewallRule } from '../../../infrastructure/firewall/firewall.js';\r\n\r\nexport function registerFirewallCloseTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_close',\r\n 'Remove the Windows Firewall inbound rule for your P2P listen port. A UAC popup will appear — accept it to close the rule.',\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe('Port to close (defaults to your current listen port)'),\r\n },\r\n async ({ port }) => {\r\n const targetPort = port ?? client.getInfo().port;\r\n if (!targetPort) {\r\n return {\r\n content: [{ type: 'text', text: 'Could not determine port. Pass port explicitly.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n try {\r\n const { method } = await removeFirewallRule(targetPort);\r\n const how = method === 'direct'\r\n ? 'applied directly (process already elevated)'\r\n : 'applied via UAC elevation popup';\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `Firewall rule removed for port ${targetPort} (rule name: claude-collab-${targetPort}). Method: ${how}.`,\r\n }],\r\n };\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return {\r\n content: [{ type: 'text', text: `Failed to close firewall: ${msg}` }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n}\r\n","/**\r\n * MCP Server\r\n * Provides MCP tools for Claude Code integration (P2P mode)\r\n * @module presentation/mcp/server\r\n */\r\n\r\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\r\nimport type { ICollabClient } from '../../shared/types/collab-client.interface.js';\r\nimport { registerAskTool } from './tools/ask.tool.js';\r\nimport { registerReplyTool } from './tools/reply.tool.js';\r\nimport { registerPeersTool } from './tools/peers.tool.js';\r\nimport { registerHistoryTool } from './tools/history.tool.js';\r\nimport { registerFirewallOpenTool } from './tools/firewall-open.tool.js';\r\nimport { registerFirewallCloseTool } from './tools/firewall-close.tool.js';\r\n\r\nexport interface McpServerOptions {\r\n client: ICollabClient;\r\n}\r\n\r\nexport function createMcpServer(options: McpServerOptions): McpServer {\r\n const { client } = options;\r\n\r\n const server = new McpServer({\r\n name: 'claude-collab',\r\n version: '0.1.0',\r\n });\r\n\r\n registerAskTool(server, client);\r\n registerReplyTool(server, client);\r\n registerPeersTool(server, client);\r\n registerHistoryTool(server, client);\r\n registerFirewallOpenTool(server, client);\r\n registerFirewallCloseTool(server, client);\r\n\r\n return server;\r\n}\r\n\r\nexport async function startMcpServer(options: McpServerOptions): Promise<void> {\r\n const server = createMcpServer(options);\r\n const transport = new StdioServerTransport();\r\n await server.connect(transport);\r\n}\r\n","#!/usr/bin/env node\r\n\r\n/**\r\n * MCP Server entry point (P2P mode)\r\n * Reads --name from process.argv.\r\n * Starts a local P2P node on a random port in range 10000-19999.\r\n * @module mcp-main\r\n */\r\n\r\nimport { P2PNode } from './infrastructure/p2p/p2p-node.js';\r\nimport { startMcpServer } from './presentation/mcp/server.js';\r\n\r\nfunction getArg(flag: string): string | undefined {\r\n const idx = process.argv.indexOf(flag);\r\n return idx !== -1 ? process.argv[idx + 1] : undefined;\r\n}\r\n\r\nasync function main(): Promise<void> {\r\n const name = getArg('--name');\r\n\r\n if (!name) { console.error('--name is required'); process.exit(1); }\r\n\r\n const node = new P2PNode();\r\n\r\n // Start MCP stdio transport first — Claude Code can connect immediately.\r\n // P2P server binds a random port in the background.\r\n const mcpReady = startMcpServer({ client: node });\r\n\r\n node.join(name, name).catch((err) => {\r\n console.error(`[mcp-main] P2P server failed to start: ${err.message}`);\r\n });\r\n\r\n await mcpReady;\r\n}\r\n\r\nmain().catch((error) => {\r\n console.error('Unexpected error:', error);\r\n process.exit(1);\r\n});\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dolusoft/claude-collab",
3
- "version": "1.9.1",
3
+ "version": "1.9.2",
4
4
  "description": "Real-time team collaboration between Claude Code terminals via MCP",
5
5
  "type": "module",
6
6
  "main": "./dist/mcp-main.js",