@dolusoft/claude-collab 1.9.5 → 1.9.6

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
@@ -935,17 +935,7 @@ ${answerLine}`;
935
935
  };
936
936
  });
937
937
  }
938
- function runDirect(argArray) {
939
- return new Promise((resolve, reject) => {
940
- const proc = spawn("netsh", argArray, { stdio: "ignore" });
941
- proc.on("close", (code) => {
942
- if (code === 0) resolve();
943
- else reject(new Error(`netsh exited with code ${code}`));
944
- });
945
- proc.on("error", (err) => reject(new Error(`netsh not found: ${err.message}`)));
946
- });
947
- }
948
- function runElevated(argArray) {
938
+ function runNetshElevated(argArray) {
949
939
  const argList = argArray.map((a) => `"${a}"`).join(",");
950
940
  const psCommand = `Start-Process -FilePath "netsh" -ArgumentList @(${argList}) -Verb RunAs -Wait`;
951
941
  return new Promise((resolve, reject) => {
@@ -960,16 +950,10 @@ function runElevated(argArray) {
960
950
  });
961
951
  }
962
952
  async function runNetsh(argArray) {
963
- try {
964
- await runDirect(argArray);
965
- return { method: "direct" };
966
- } catch {
967
- await runElevated(argArray);
968
- return { method: "elevated" };
969
- }
953
+ await runNetshElevated(argArray);
970
954
  }
971
955
  async function addFirewallRule(port) {
972
- const result = await runNetsh([
956
+ await runNetsh([
973
957
  "advfirewall",
974
958
  "firewall",
975
959
  "add",
@@ -994,10 +978,9 @@ async function addFirewallRule(port) {
994
978
  ]);
995
979
  } catch {
996
980
  }
997
- return result;
998
981
  }
999
982
  async function removeFirewallRule(port) {
1000
- const result = await runNetsh([
983
+ await runNetsh([
1001
984
  "advfirewall",
1002
985
  "firewall",
1003
986
  "delete",
@@ -1008,7 +991,6 @@ async function removeFirewallRule(port) {
1008
991
  await runNetsh(["advfirewall", "firewall", "delete", "rule", "name=claude-collab-discovery"]);
1009
992
  } catch {
1010
993
  }
1011
- return result;
1012
994
  }
1013
995
 
1014
996
  // src/presentation/mcp/tools/firewall-open.tool.ts
@@ -1048,13 +1030,12 @@ function registerFirewallOpenTool(server, client) {
1048
1030
  };
1049
1031
  }
1050
1032
  try {
1051
- const { method } = await addFirewallRule(targetPort);
1052
- const how = method === "direct" ? "applied directly (already elevated)" : "applied via UAC popup";
1033
+ await addFirewallRule(targetPort);
1053
1034
  return {
1054
1035
  content: [{
1055
1036
  type: "text",
1056
1037
  text: [
1057
- `Firewall rule opened for port ${targetPort} (claude-collab-${targetPort}). ${how}.`,
1038
+ `Firewall rule opened for port ${targetPort} (claude-collab-${targetPort}).`,
1058
1039
  `Peers on the LAN can now connect to you inbound.`,
1059
1040
  `Call firewall_close() when you are done with this session.`
1060
1041
  ].join("\n")
@@ -1110,12 +1091,11 @@ function registerFirewallCloseTool(server, client) {
1110
1091
  };
1111
1092
  }
1112
1093
  try {
1113
- const { method } = await removeFirewallRule(targetPort);
1114
- const how = method === "direct" ? "applied directly (already elevated)" : "applied via UAC popup";
1094
+ await removeFirewallRule(targetPort);
1115
1095
  return {
1116
1096
  content: [{
1117
1097
  type: "text",
1118
- text: `Firewall rule removed for port ${targetPort} (claude-collab-${targetPort}). ${how}.`
1098
+ text: `Firewall rule removed for port ${targetPort} (claude-collab-${targetPort}).`
1119
1099
  }]
1120
1100
  };
1121
1101
  } catch (err) {
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\nimport { networkInterfaces } from 'os';\r\n\r\nexport const PEER_DISCOVERY_PORT = 9998;\r\nconst BROADCAST_INTERVAL_MS = 3000;\r\n\r\n/** Returns 255.255.255.255 plus each subnet's directed broadcast address. */\r\nfunction getBroadcastAddresses(): string[] {\r\n const addrs = new Set(['255.255.255.255']);\r\n for (const ifaces of Object.values(networkInterfaces())) {\r\n for (const iface of ifaces ?? []) {\r\n if (iface.family !== 'IPv4' || iface.internal) continue;\r\n const ip = iface.address.split('.').map(Number);\r\n const mask = iface.netmask.split('.').map(Number);\r\n const broadcast = ip.map((b, i) => b | (~mask[i] & 0xff)).join('.');\r\n addrs.add(broadcast);\r\n }\r\n }\r\n return [...addrs];\r\n}\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({ type: 'udp4', reuseAddr: true });\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 for (const addr of getBroadcastAddresses()) {\r\n socket.send(msg, 0, msg.length, PEER_DISCOVERY_PORT, addr, (err) => {\r\n if (err) console.error(`[peer-broadcaster] send to ${addr} error:`, err.message);\r\n });\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 // reuseAddr: true allows multiple processes (e.g. after MCP restart) to share port 9998\r\n const socket = createSocket({ type: 'udp4', reuseAddr: true });\r\n\r\n socket.on('error', (err) => {\r\n console.error('[peer-listener] bind failed on port', PEER_DISCOVERY_PORT, '—', 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 // Push-based answer resolution: questionId → resolve callback\r\n private readonly answerWaiters = new Map<string, (result: CheckAnswerResult) => void>();\r\n // Answers queued for offline peers: peerName → AnswerMsg (delivered on reconnect)\r\n private readonly pendingOutboundAnswers = new Map<string, import('./p2p-protocol.js').AnswerMsg>();\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 waitForAnswer(questionId: string, timeoutMs: number): Promise<CheckAnswerResult | null> {\r\n // Already in cache — resolve immediately\r\n const cached = this.receivedAnswers.get(questionId);\r\n if (cached) {\r\n return Promise.resolve(this.formatAnswer(questionId, cached));\r\n }\r\n\r\n return new Promise((resolve) => {\r\n const timeout = setTimeout(() => {\r\n this.answerWaiters.delete(questionId);\r\n resolve(null);\r\n }, timeoutMs);\r\n\r\n this.answerWaiters.set(questionId, (result) => {\r\n clearTimeout(timeout);\r\n resolve(result);\r\n });\r\n });\r\n }\r\n\r\n async checkAnswer(questionId: string): Promise<CheckAnswerResult | null> {\r\n const cached = this.receivedAnswers.get(questionId);\r\n return cached ? this.formatAnswer(questionId, cached) : null;\r\n }\r\n\r\n private formatAnswer(questionId: string, cached: ReceivedAnswer): CheckAnswerResult {\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 answerMsg: import('./p2p-protocol.js').AnswerMsg = {\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 const ws = this.peerConnections.get(senderName);\r\n if (ws && ws.readyState === WebSocket.OPEN) {\r\n this.sendToWs(ws, answerMsg);\r\n } else {\r\n // Peer is offline — queue the answer and deliver when they reconnect\r\n this.pendingOutboundAnswers.set(senderName, answerMsg);\r\n console.error(`[p2p] \"${senderName}\" is offline, answer queued for delivery on reconnect`);\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 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 this.deliverPendingAnswer(msg.name, ws);\r\n break;\r\n }\r\n\r\n case 'HELLO_ACK': {\r\n if (this.peerConnections.has(msg.name)) {\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 this.deliverPendingAnswer(msg.name, ws);\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 const record: ReceivedAnswer = {\r\n content: msg.content,\r\n format: msg.format,\r\n answeredAt: msg.answeredAt,\r\n fromName: msg.from,\r\n };\r\n this.receivedAnswers.set(msg.questionId, record);\r\n\r\n // Fire push waiter immediately — no more polling needed\r\n const waiter = this.answerWaiters.get(msg.questionId);\r\n if (waiter) {\r\n this.answerWaiters.delete(msg.questionId);\r\n waiter(this.formatAnswer(msg.questionId, record));\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 deliverPendingAnswer(peerName: string, ws: WebSocket): void {\r\n const pending = this.pendingOutboundAnswers.get(peerName);\r\n if (pending) {\r\n this.pendingOutboundAnswers.delete(peerName);\r\n this.sendToWs(ws, pending);\r\n console.error(`[p2p] delivered queued answer to \"${peerName}\" after reconnect`);\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 * @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\nconst ASK_DESCRIPTION = `\\\r\nSend a question to another Claude instance on the LAN and wait for their answer.\r\n\r\nWHEN TO USE:\r\n- You need input, a decision, or work output from a specific peer Claude\r\n- You want to delegate a subtask to another Claude and use their result\r\n- You need to coordinate or synchronize work across multiple Claudes\r\n\r\nWORKFLOW:\r\n1. Call peers() first to confirm the target is online and get their exact name\r\n2. Call ask(peer, question) — this blocks until they reply (up to 5 minutes)\r\n3. Use their answer directly in your ongoing task\r\n\r\nWRITING GOOD QUESTIONS:\r\n- Include all context the other Claude needs — they cannot see your conversation\r\n- Be specific about what format or level of detail you expect in the answer\r\n- If you need code, specify language and constraints\r\n- One focused question per call works better than multiple combined\r\n\r\nDO NOT use this tool if:\r\n- The peer is not listed in peers() — the call will fail immediately\r\n- You just want to share information without needing a response (there is no broadcast tool yet)`;\r\n\r\nconst askSchema = {\r\n peer: z\r\n .string()\r\n .describe('Exact name of the peer to ask. Use peers() first to see who is online and get the correct name.'),\r\n question: z\r\n .string()\r\n .describe(\r\n 'Your question in markdown. Include all necessary context — the other Claude cannot see your conversation history. Be specific about what kind of answer you need.'\r\n ),\r\n};\r\n\r\nexport function registerAskTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('ask', ASK_DESCRIPTION, 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 type: 'text',\r\n text: 'P2P node is not ready yet. Wait a moment and try again.',\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 // Wait for the answer via push — resolves the moment ANSWER arrives\r\n const answer = await client.waitForAnswer(questionId, 5 * 60 * 1000);\r\n\r\n if (answer !== null) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `**${answer.from.displayName} answered:**\\n\\n${answer.content}`,\r\n }],\r\n };\r\n }\r\n\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Question sent to \"${targetPeer}\" but no answer arrived within 5 minutes.`,\r\n `Question ID: \\`${questionId}\\``,\r\n ``,\r\n `The peer may be busy or offline. You can:`,\r\n `- Call peers() to check if they are still connected`,\r\n `- Continue with your task and follow up later`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n const isPeerOffline = errorMessage.includes('not connected');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: isPeerOffline\r\n ? `Peer \"${targetPeer}\" is not connected. Call peers() to see who is currently online.`\r\n : `Failed to send question: ${errorMessage}`,\r\n }],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Reply Tool\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\nconst REPLY_DESCRIPTION = `\\\r\nSend your answer back to a Claude instance that asked you a question.\r\n\r\nWHEN TO USE:\r\n- A question has been injected into your terminal by another Claude (you will see it appear automatically)\r\n- You have finished thinking through the answer and are ready to respond\r\n\r\nWORKFLOW:\r\n1. Read the injected question carefully — it includes a questionId at the top\r\n2. Think through a complete answer\r\n3. Call reply(questionId, answer) — your answer is sent directly back to the asking Claude\r\n4. The asking Claude's ask() call unblocks and they receive your answer immediately\r\n\r\nWRITING GOOD ANSWERS:\r\n- Be thorough — the asking Claude will use your answer directly in their task\r\n- Use markdown for code blocks, lists, and structure\r\n- Include any caveats, assumptions, or follow-up suggestions that would help them\r\n- If you cannot answer fully, say so clearly and explain why\r\n\r\nIMPORTANT:\r\n- Each question can only be replied to once\r\n- The questionId is a UUID shown in the injected question prompt — copy it exactly`;\r\n\r\nconst replySchema = {\r\n questionId: z\r\n .string()\r\n .describe(\r\n 'The UUID of the question to reply to. Shown at the top of the injected question prompt in your terminal.'\r\n ),\r\n answer: z\r\n .string()\r\n .describe(\r\n 'Your complete answer in markdown. Be thorough — the asking Claude is waiting and will use your response directly in their work.'\r\n ),\r\n};\r\n\r\nexport function registerReplyTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('reply', REPLY_DESCRIPTION, 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 type: 'text',\r\n text: 'P2P node is not ready yet. Wait a moment and try again.',\r\n }],\r\n isError: true,\r\n };\r\n }\r\n\r\n await client.reply(questionId, answer, 'markdown');\r\n\r\n injectionQueue.notifyReplied();\r\n\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `Answer sent. The peer's ask() call has been unblocked and they received your response.`,\r\n }],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n const isNotFound = errorMessage.includes('not found');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: isNotFound\r\n ? `Question \\`${questionId}\\` not found. Check that you copied the questionId exactly from the injected prompt.`\r\n : `Failed to send reply: ${errorMessage}`,\r\n }],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Peers Tool\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\nconst PEERS_DESCRIPTION = `\\\r\nShow your identity on the P2P network and list all currently connected peers.\r\n\r\nWHEN TO USE:\r\n- Before calling ask() — to confirm the target peer is online and get their exact name\r\n- After startup — to verify you joined the network successfully\r\n- When a peer seems unreachable — to check if they are still connected\r\n\r\nWHAT IT SHOWS:\r\n- Your own name and the port you are listening on\r\n- All peers who have established a direct connection to you\r\n\r\nIF NO PEERS ARE LISTED:\r\n- Peers discover each other automatically via LAN broadcast every 3 seconds\r\n- If a peer just started, wait a few seconds and call peers() again\r\n- Call firewall_open() so peers on other machines can connect inbound to you\r\n- If still no peers, verify all machines are on the same LAN/subnet`;\r\n\r\nexport function registerPeersTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('peers', PEERS_DESCRIPTION, {}, 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: [\r\n `P2P server is not running yet (port ${myPort} may be in use).`,\r\n `Check the MCP process logs for the error details.`,\r\n ].join('\\n'),\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: [\r\n `You are \"${myName}\" (listening on port ${myPort}).`,\r\n `No peers connected yet.`,\r\n ``,\r\n `Peers auto-discover via LAN broadcast — wait a few seconds if they just started.`,\r\n `Call firewall_open() if peers on other machines cannot reach you.`,\r\n ].join('\\n'),\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 * @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\nconst HISTORY_DESCRIPTION = `\\\r\nShow all questions and answers exchanged this session — both sent and received.\r\n\r\nWHEN TO USE:\r\n- To review what was already discussed before asking a follow-up question\r\n- To check if a previously sent question has been answered yet\r\n- To find a questionId you need to reference\r\n- To catch up on received questions you may have missed\r\n\r\nOUTPUT FORMAT:\r\n- → peer: question you sent, with their answer below\r\n- ← peer: question they sent you, with your reply below\r\n- (no answer yet) means the question is still waiting for a response`;\r\n\r\nexport function registerHistoryTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('history', HISTORY_DESCRIPTION, {}, 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 exchanged yet this session.' }],\r\n };\r\n }\r\n\r\n const unanswered = entries.filter((e) => !e.answer);\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 — use reply() if you haven't answered)`;\r\n return `[${time}] ← ${e.peer}: ${e.question}\\n${answerLine}`;\r\n }\r\n });\r\n\r\n const summary = unanswered.length > 0\r\n ? `\\n\\n⚠ ${unanswered.length} question(s) still waiting for a response.`\r\n : '';\r\n\r\n return {\r\n content: [{ type: 'text', text: lines.join('\\n\\n') + summary }],\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 // TCP rule for the WebSocket port\r\n const result = await 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 // UDP rule for peer discovery (port 9998) — run best-effort, don't fail if already exists\r\n try {\r\n await runNetsh([\r\n 'advfirewall', 'firewall', 'add', 'rule',\r\n 'name=claude-collab-discovery',\r\n 'protocol=UDP',\r\n 'dir=in',\r\n 'localport=9998',\r\n 'action=allow',\r\n ]);\r\n } catch { /* already exists or denied — TCP rule still applied */ }\r\n\r\n return result;\r\n}\r\n\r\nexport async function removeFirewallRule(port: number): Promise<{ method: 'direct' | 'elevated' }> {\r\n const result = await runNetsh([\r\n 'advfirewall', 'firewall', 'delete', 'rule',\r\n `name=claude-collab-${port}`,\r\n ]);\r\n\r\n // Also remove discovery rule best-effort\r\n try {\r\n await runNetsh(['advfirewall', 'firewall', 'delete', 'rule', 'name=claude-collab-discovery']);\r\n } catch { /* may not exist */ }\r\n\r\n return result;\r\n}\r\n","/**\r\n * FirewallOpen Tool\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\nconst FIREWALL_OPEN_DESCRIPTION = `\\\r\nOpen a Windows Firewall inbound rule so peers on the LAN can connect directly to you.\r\n\r\nWHEN YOU NEED THIS:\r\n- Other peers cannot see you in their peers() list even though you are on the same LAN\r\n- You just started and want to make sure all peers can reach you\r\n- A peer explicitly says they cannot connect to you\r\n\r\nWHEN YOU DO NOT NEED THIS:\r\n- You can already see peers in peers() — the connection is working\r\n- You are connecting outbound to others (outbound connections do not require firewall rules)\r\n\r\nWHAT HAPPENS:\r\n- On most systems: the rule is applied immediately (terminal is already elevated)\r\n- On standard Windows: a UAC popup appears — the user must click Yes\r\n- On VMs or headless setups: applied directly if running as Administrator\r\n\r\nThe rule is named \"claude-collab-{port}\" and allows inbound TCP on your current listen port.\r\nCall firewall_close() when you are done to clean up the rule.`;\r\n\r\nexport function registerFirewallOpenTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_open',\r\n FIREWALL_OPEN_DESCRIPTION,\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe(\r\n 'Port to open. Defaults to your current listen port — omit this unless you have a specific reason to override.'\r\n ),\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: 'P2P node is not running yet — port unknown. Try again in a moment.' }],\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 (already elevated)'\r\n : 'applied via UAC popup';\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Firewall rule opened for port ${targetPort} (claude-collab-${targetPort}). ${how}.`,\r\n `Peers on the LAN can now connect to you inbound.`,\r\n `Call firewall_close() when you are done with this session.`,\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: [{\r\n type: 'text',\r\n text: [\r\n `Failed to open firewall: ${msg}`,\r\n ``,\r\n `Try running your terminal as Administrator and call firewall_open() again.`,\r\n ].join('\\n'),\r\n }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n}\r\n","/**\r\n * FirewallClose Tool\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\nconst FIREWALL_CLOSE_DESCRIPTION = `\\\r\nRemove the Windows Firewall inbound rule that was opened by firewall_open().\r\n\r\nWHEN TO USE:\r\n- At the end of a collaboration session to clean up\r\n- When you no longer want to accept inbound peer connections\r\n- As general hygiene — open firewall rules should not be left indefinitely\r\n\r\nWHAT HAPPENS:\r\n- The inbound TCP rule \"claude-collab-{port}\" is deleted from Windows Firewall\r\n- Existing active connections are not dropped — only new inbound connections are blocked\r\n- On standard Windows: a UAC popup appears — the user must click Yes\r\n- On VMs or admin terminals: applied directly without a popup\r\n\r\nNOTE: Because ports are random each session, each startup creates a new rule name.\r\nOld rules from previous sessions can be removed by passing the port explicitly.`;\r\n\r\nexport function registerFirewallCloseTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_close',\r\n FIREWALL_CLOSE_DESCRIPTION,\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe(\r\n 'Port whose rule to remove. Defaults to your current listen port. Pass a specific port to clean up a rule from a previous session.'\r\n ),\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: 'P2P node is not running yet — port unknown. Try again in a moment.' }],\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 (already elevated)'\r\n : 'applied via UAC popup';\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `Firewall rule removed for port ${targetPort} (claude-collab-${targetPort}). ${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: [{\r\n type: 'text',\r\n text: [\r\n `Failed to remove firewall rule: ${msg}`,\r\n ``,\r\n `The rule may not exist (if firewall_open was never called this session), or try running as Administrator.`,\r\n ].join('\\n'),\r\n }],\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"]}
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\nimport { networkInterfaces } from 'os';\r\n\r\nexport const PEER_DISCOVERY_PORT = 9998;\r\nconst BROADCAST_INTERVAL_MS = 3000;\r\n\r\n/** Returns 255.255.255.255 plus each subnet's directed broadcast address. */\r\nfunction getBroadcastAddresses(): string[] {\r\n const addrs = new Set(['255.255.255.255']);\r\n for (const ifaces of Object.values(networkInterfaces())) {\r\n for (const iface of ifaces ?? []) {\r\n if (iface.family !== 'IPv4' || iface.internal) continue;\r\n const ip = iface.address.split('.').map(Number);\r\n const mask = iface.netmask.split('.').map(Number);\r\n const broadcast = ip.map((b, i) => b | (~mask[i] & 0xff)).join('.');\r\n addrs.add(broadcast);\r\n }\r\n }\r\n return [...addrs];\r\n}\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({ type: 'udp4', reuseAddr: true });\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 for (const addr of getBroadcastAddresses()) {\r\n socket.send(msg, 0, msg.length, PEER_DISCOVERY_PORT, addr, (err) => {\r\n if (err) console.error(`[peer-broadcaster] send to ${addr} error:`, err.message);\r\n });\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 // reuseAddr: true allows multiple processes (e.g. after MCP restart) to share port 9998\r\n const socket = createSocket({ type: 'udp4', reuseAddr: true });\r\n\r\n socket.on('error', (err) => {\r\n console.error('[peer-listener] bind failed on port', PEER_DISCOVERY_PORT, '—', 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 // Push-based answer resolution: questionId → resolve callback\r\n private readonly answerWaiters = new Map<string, (result: CheckAnswerResult) => void>();\r\n // Answers queued for offline peers: peerName → AnswerMsg (delivered on reconnect)\r\n private readonly pendingOutboundAnswers = new Map<string, import('./p2p-protocol.js').AnswerMsg>();\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 waitForAnswer(questionId: string, timeoutMs: number): Promise<CheckAnswerResult | null> {\r\n // Already in cache — resolve immediately\r\n const cached = this.receivedAnswers.get(questionId);\r\n if (cached) {\r\n return Promise.resolve(this.formatAnswer(questionId, cached));\r\n }\r\n\r\n return new Promise((resolve) => {\r\n const timeout = setTimeout(() => {\r\n this.answerWaiters.delete(questionId);\r\n resolve(null);\r\n }, timeoutMs);\r\n\r\n this.answerWaiters.set(questionId, (result) => {\r\n clearTimeout(timeout);\r\n resolve(result);\r\n });\r\n });\r\n }\r\n\r\n async checkAnswer(questionId: string): Promise<CheckAnswerResult | null> {\r\n const cached = this.receivedAnswers.get(questionId);\r\n return cached ? this.formatAnswer(questionId, cached) : null;\r\n }\r\n\r\n private formatAnswer(questionId: string, cached: ReceivedAnswer): CheckAnswerResult {\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 answerMsg: import('./p2p-protocol.js').AnswerMsg = {\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 const ws = this.peerConnections.get(senderName);\r\n if (ws && ws.readyState === WebSocket.OPEN) {\r\n this.sendToWs(ws, answerMsg);\r\n } else {\r\n // Peer is offline — queue the answer and deliver when they reconnect\r\n this.pendingOutboundAnswers.set(senderName, answerMsg);\r\n console.error(`[p2p] \"${senderName}\" is offline, answer queued for delivery on reconnect`);\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 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 this.deliverPendingAnswer(msg.name, ws);\r\n break;\r\n }\r\n\r\n case 'HELLO_ACK': {\r\n if (this.peerConnections.has(msg.name)) {\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 this.deliverPendingAnswer(msg.name, ws);\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 const record: ReceivedAnswer = {\r\n content: msg.content,\r\n format: msg.format,\r\n answeredAt: msg.answeredAt,\r\n fromName: msg.from,\r\n };\r\n this.receivedAnswers.set(msg.questionId, record);\r\n\r\n // Fire push waiter immediately — no more polling needed\r\n const waiter = this.answerWaiters.get(msg.questionId);\r\n if (waiter) {\r\n this.answerWaiters.delete(msg.questionId);\r\n waiter(this.formatAnswer(msg.questionId, record));\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 deliverPendingAnswer(peerName: string, ws: WebSocket): void {\r\n const pending = this.pendingOutboundAnswers.get(peerName);\r\n if (pending) {\r\n this.pendingOutboundAnswers.delete(peerName);\r\n this.sendToWs(ws, pending);\r\n console.error(`[p2p] delivered queued answer to \"${peerName}\" after reconnect`);\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 * @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\nconst ASK_DESCRIPTION = `\\\r\nSend a question to another Claude instance on the LAN and wait for their answer.\r\n\r\nWHEN TO USE:\r\n- You need input, a decision, or work output from a specific peer Claude\r\n- You want to delegate a subtask to another Claude and use their result\r\n- You need to coordinate or synchronize work across multiple Claudes\r\n\r\nWORKFLOW:\r\n1. Call peers() first to confirm the target is online and get their exact name\r\n2. Call ask(peer, question) — this blocks until they reply (up to 5 minutes)\r\n3. Use their answer directly in your ongoing task\r\n\r\nWRITING GOOD QUESTIONS:\r\n- Include all context the other Claude needs — they cannot see your conversation\r\n- Be specific about what format or level of detail you expect in the answer\r\n- If you need code, specify language and constraints\r\n- One focused question per call works better than multiple combined\r\n\r\nDO NOT use this tool if:\r\n- The peer is not listed in peers() — the call will fail immediately\r\n- You just want to share information without needing a response (there is no broadcast tool yet)`;\r\n\r\nconst askSchema = {\r\n peer: z\r\n .string()\r\n .describe('Exact name of the peer to ask. Use peers() first to see who is online and get the correct name.'),\r\n question: z\r\n .string()\r\n .describe(\r\n 'Your question in markdown. Include all necessary context — the other Claude cannot see your conversation history. Be specific about what kind of answer you need.'\r\n ),\r\n};\r\n\r\nexport function registerAskTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('ask', ASK_DESCRIPTION, 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 type: 'text',\r\n text: 'P2P node is not ready yet. Wait a moment and try again.',\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 // Wait for the answer via push — resolves the moment ANSWER arrives\r\n const answer = await client.waitForAnswer(questionId, 5 * 60 * 1000);\r\n\r\n if (answer !== null) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `**${answer.from.displayName} answered:**\\n\\n${answer.content}`,\r\n }],\r\n };\r\n }\r\n\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Question sent to \"${targetPeer}\" but no answer arrived within 5 minutes.`,\r\n `Question ID: \\`${questionId}\\``,\r\n ``,\r\n `The peer may be busy or offline. You can:`,\r\n `- Call peers() to check if they are still connected`,\r\n `- Continue with your task and follow up later`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n const isPeerOffline = errorMessage.includes('not connected');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: isPeerOffline\r\n ? `Peer \"${targetPeer}\" is not connected. Call peers() to see who is currently online.`\r\n : `Failed to send question: ${errorMessage}`,\r\n }],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Reply Tool\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\nconst REPLY_DESCRIPTION = `\\\r\nSend your answer back to a Claude instance that asked you a question.\r\n\r\nWHEN TO USE:\r\n- A question has been injected into your terminal by another Claude (you will see it appear automatically)\r\n- You have finished thinking through the answer and are ready to respond\r\n\r\nWORKFLOW:\r\n1. Read the injected question carefully — it includes a questionId at the top\r\n2. Think through a complete answer\r\n3. Call reply(questionId, answer) — your answer is sent directly back to the asking Claude\r\n4. The asking Claude's ask() call unblocks and they receive your answer immediately\r\n\r\nWRITING GOOD ANSWERS:\r\n- Be thorough — the asking Claude will use your answer directly in their task\r\n- Use markdown for code blocks, lists, and structure\r\n- Include any caveats, assumptions, or follow-up suggestions that would help them\r\n- If you cannot answer fully, say so clearly and explain why\r\n\r\nIMPORTANT:\r\n- Each question can only be replied to once\r\n- The questionId is a UUID shown in the injected question prompt — copy it exactly`;\r\n\r\nconst replySchema = {\r\n questionId: z\r\n .string()\r\n .describe(\r\n 'The UUID of the question to reply to. Shown at the top of the injected question prompt in your terminal.'\r\n ),\r\n answer: z\r\n .string()\r\n .describe(\r\n 'Your complete answer in markdown. Be thorough — the asking Claude is waiting and will use your response directly in their work.'\r\n ),\r\n};\r\n\r\nexport function registerReplyTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('reply', REPLY_DESCRIPTION, 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 type: 'text',\r\n text: 'P2P node is not ready yet. Wait a moment and try again.',\r\n }],\r\n isError: true,\r\n };\r\n }\r\n\r\n await client.reply(questionId, answer, 'markdown');\r\n\r\n injectionQueue.notifyReplied();\r\n\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `Answer sent. The peer's ask() call has been unblocked and they received your response.`,\r\n }],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n const isNotFound = errorMessage.includes('not found');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: isNotFound\r\n ? `Question \\`${questionId}\\` not found. Check that you copied the questionId exactly from the injected prompt.`\r\n : `Failed to send reply: ${errorMessage}`,\r\n }],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Peers Tool\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\nconst PEERS_DESCRIPTION = `\\\r\nShow your identity on the P2P network and list all currently connected peers.\r\n\r\nWHEN TO USE:\r\n- Before calling ask() — to confirm the target peer is online and get their exact name\r\n- After startup — to verify you joined the network successfully\r\n- When a peer seems unreachable — to check if they are still connected\r\n\r\nWHAT IT SHOWS:\r\n- Your own name and the port you are listening on\r\n- All peers who have established a direct connection to you\r\n\r\nIF NO PEERS ARE LISTED:\r\n- Peers discover each other automatically via LAN broadcast every 3 seconds\r\n- If a peer just started, wait a few seconds and call peers() again\r\n- Call firewall_open() so peers on other machines can connect inbound to you\r\n- If still no peers, verify all machines are on the same LAN/subnet`;\r\n\r\nexport function registerPeersTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('peers', PEERS_DESCRIPTION, {}, 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: [\r\n `P2P server is not running yet (port ${myPort} may be in use).`,\r\n `Check the MCP process logs for the error details.`,\r\n ].join('\\n'),\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: [\r\n `You are \"${myName}\" (listening on port ${myPort}).`,\r\n `No peers connected yet.`,\r\n ``,\r\n `Peers auto-discover via LAN broadcast — wait a few seconds if they just started.`,\r\n `Call firewall_open() if peers on other machines cannot reach you.`,\r\n ].join('\\n'),\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 * @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\nconst HISTORY_DESCRIPTION = `\\\r\nShow all questions and answers exchanged this session — both sent and received.\r\n\r\nWHEN TO USE:\r\n- To review what was already discussed before asking a follow-up question\r\n- To check if a previously sent question has been answered yet\r\n- To find a questionId you need to reference\r\n- To catch up on received questions you may have missed\r\n\r\nOUTPUT FORMAT:\r\n- → peer: question you sent, with their answer below\r\n- ← peer: question they sent you, with your reply below\r\n- (no answer yet) means the question is still waiting for a response`;\r\n\r\nexport function registerHistoryTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('history', HISTORY_DESCRIPTION, {}, 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 exchanged yet this session.' }],\r\n };\r\n }\r\n\r\n const unanswered = entries.filter((e) => !e.answer);\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 — use reply() if you haven't answered)`;\r\n return `[${time}] ← ${e.peer}: ${e.question}\\n${answerLine}`;\r\n }\r\n });\r\n\r\n const summary = unanswered.length > 0\r\n ? `\\n\\n⚠ ${unanswered.length} question(s) still waiting for a response.`\r\n : '';\r\n\r\n return {\r\n content: [{ type: 'text', text: lines.join('\\n\\n') + summary }],\r\n };\r\n });\r\n}\r\n","/**\r\n * Firewall helpers\r\n * Always elevated via UAC (PowerShell Start-Process -Verb RunAs) so the rule\r\n * is guaranteed to be applied. If the process is already elevated, Windows\r\n * skips the UAC prompt automatically.\r\n * @module infrastructure/firewall/firewall\r\n */\r\n\r\nimport { spawn } from 'child_process';\r\n\r\n/**\r\n * Run netsh via UAC elevation (PowerShell Start-Process -Verb RunAs).\r\n * If the calling process is already elevated, no prompt is shown.\r\n * Always use this path — running netsh directly without elevation can silently\r\n * exit 0 on some Windows versions without actually applying the rule.\r\n */\r\nfunction runNetshElevated(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\nasync function runNetsh(argArray: string[]): Promise<void> {\r\n await runNetshElevated(argArray);\r\n}\r\n\r\nexport async function addFirewallRule(port: number): Promise<void> {\r\n // TCP rule for the WebSocket port\r\n await 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 // UDP rule for peer discovery (port 9998) — run best-effort, don't fail if already exists\r\n try {\r\n await runNetsh([\r\n 'advfirewall', 'firewall', 'add', 'rule',\r\n 'name=claude-collab-discovery',\r\n 'protocol=UDP',\r\n 'dir=in',\r\n 'localport=9998',\r\n 'action=allow',\r\n ]);\r\n } catch { /* already exists or denied — TCP rule still applied */ }\r\n}\r\n\r\nexport async function removeFirewallRule(port: number): Promise<void> {\r\n await runNetsh([\r\n 'advfirewall', 'firewall', 'delete', 'rule',\r\n `name=claude-collab-${port}`,\r\n ]);\r\n\r\n // Also remove discovery rule best-effort\r\n try {\r\n await runNetsh(['advfirewall', 'firewall', 'delete', 'rule', 'name=claude-collab-discovery']);\r\n } catch { /* may not exist */ }\r\n}\r\n","/**\r\n * FirewallOpen Tool\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\nconst FIREWALL_OPEN_DESCRIPTION = `\\\r\nOpen a Windows Firewall inbound rule so peers on the LAN can connect directly to you.\r\n\r\nWHEN YOU NEED THIS:\r\n- Other peers cannot see you in their peers() list even though you are on the same LAN\r\n- You just started and want to make sure all peers can reach you\r\n- A peer explicitly says they cannot connect to you\r\n\r\nWHEN YOU DO NOT NEED THIS:\r\n- You can already see peers in peers() — the connection is working\r\n- You are connecting outbound to others (outbound connections do not require firewall rules)\r\n\r\nWHAT HAPPENS:\r\n- On most systems: the rule is applied immediately (terminal is already elevated)\r\n- On standard Windows: a UAC popup appears — the user must click Yes\r\n- On VMs or headless setups: applied directly if running as Administrator\r\n\r\nThe rule is named \"claude-collab-{port}\" and allows inbound TCP on your current listen port.\r\nCall firewall_close() when you are done to clean up the rule.`;\r\n\r\nexport function registerFirewallOpenTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_open',\r\n FIREWALL_OPEN_DESCRIPTION,\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe(\r\n 'Port to open. Defaults to your current listen port — omit this unless you have a specific reason to override.'\r\n ),\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: 'P2P node is not running yet — port unknown. Try again in a moment.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n try {\r\n await addFirewallRule(targetPort);\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Firewall rule opened for port ${targetPort} (claude-collab-${targetPort}).`,\r\n `Peers on the LAN can now connect to you inbound.`,\r\n `Call firewall_close() when you are done with this session.`,\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: [{\r\n type: 'text',\r\n text: [\r\n `Failed to open firewall: ${msg}`,\r\n ``,\r\n `Try running your terminal as Administrator and call firewall_open() again.`,\r\n ].join('\\n'),\r\n }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n}\r\n","/**\r\n * FirewallClose Tool\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\nconst FIREWALL_CLOSE_DESCRIPTION = `\\\r\nRemove the Windows Firewall inbound rule that was opened by firewall_open().\r\n\r\nWHEN TO USE:\r\n- At the end of a collaboration session to clean up\r\n- When you no longer want to accept inbound peer connections\r\n- As general hygiene — open firewall rules should not be left indefinitely\r\n\r\nWHAT HAPPENS:\r\n- The inbound TCP rule \"claude-collab-{port}\" is deleted from Windows Firewall\r\n- Existing active connections are not dropped — only new inbound connections are blocked\r\n- On standard Windows: a UAC popup appears — the user must click Yes\r\n- On VMs or admin terminals: applied directly without a popup\r\n\r\nNOTE: Because ports are random each session, each startup creates a new rule name.\r\nOld rules from previous sessions can be removed by passing the port explicitly.`;\r\n\r\nexport function registerFirewallCloseTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_close',\r\n FIREWALL_CLOSE_DESCRIPTION,\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe(\r\n 'Port whose rule to remove. Defaults to your current listen port. Pass a specific port to clean up a rule from a previous session.'\r\n ),\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: 'P2P node is not running yet — port unknown. Try again in a moment.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n try {\r\n await removeFirewallRule(targetPort);\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `Firewall rule removed for port ${targetPort} (claude-collab-${targetPort}).`,\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: [{\r\n type: 'text',\r\n text: [\r\n `Failed to remove firewall rule: ${msg}`,\r\n ``,\r\n `The rule may not exist (if firewall_open was never called this session), or try running as Administrator.`,\r\n ].join('\\n'),\r\n }],\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
@@ -934,17 +934,7 @@ ${answerLine}`;
934
934
  };
935
935
  });
936
936
  }
937
- function runDirect(argArray) {
938
- return new Promise((resolve, reject) => {
939
- const proc = spawn("netsh", argArray, { stdio: "ignore" });
940
- proc.on("close", (code) => {
941
- if (code === 0) resolve();
942
- else reject(new Error(`netsh exited with code ${code}`));
943
- });
944
- proc.on("error", (err) => reject(new Error(`netsh not found: ${err.message}`)));
945
- });
946
- }
947
- function runElevated(argArray) {
937
+ function runNetshElevated(argArray) {
948
938
  const argList = argArray.map((a) => `"${a}"`).join(",");
949
939
  const psCommand = `Start-Process -FilePath "netsh" -ArgumentList @(${argList}) -Verb RunAs -Wait`;
950
940
  return new Promise((resolve, reject) => {
@@ -959,16 +949,10 @@ function runElevated(argArray) {
959
949
  });
960
950
  }
961
951
  async function runNetsh(argArray) {
962
- try {
963
- await runDirect(argArray);
964
- return { method: "direct" };
965
- } catch {
966
- await runElevated(argArray);
967
- return { method: "elevated" };
968
- }
952
+ await runNetshElevated(argArray);
969
953
  }
970
954
  async function addFirewallRule(port) {
971
- const result = await runNetsh([
955
+ await runNetsh([
972
956
  "advfirewall",
973
957
  "firewall",
974
958
  "add",
@@ -993,10 +977,9 @@ async function addFirewallRule(port) {
993
977
  ]);
994
978
  } catch {
995
979
  }
996
- return result;
997
980
  }
998
981
  async function removeFirewallRule(port) {
999
- const result = await runNetsh([
982
+ await runNetsh([
1000
983
  "advfirewall",
1001
984
  "firewall",
1002
985
  "delete",
@@ -1007,7 +990,6 @@ async function removeFirewallRule(port) {
1007
990
  await runNetsh(["advfirewall", "firewall", "delete", "rule", "name=claude-collab-discovery"]);
1008
991
  } catch {
1009
992
  }
1010
- return result;
1011
993
  }
1012
994
 
1013
995
  // src/presentation/mcp/tools/firewall-open.tool.ts
@@ -1047,13 +1029,12 @@ function registerFirewallOpenTool(server, client) {
1047
1029
  };
1048
1030
  }
1049
1031
  try {
1050
- const { method } = await addFirewallRule(targetPort);
1051
- const how = method === "direct" ? "applied directly (already elevated)" : "applied via UAC popup";
1032
+ await addFirewallRule(targetPort);
1052
1033
  return {
1053
1034
  content: [{
1054
1035
  type: "text",
1055
1036
  text: [
1056
- `Firewall rule opened for port ${targetPort} (claude-collab-${targetPort}). ${how}.`,
1037
+ `Firewall rule opened for port ${targetPort} (claude-collab-${targetPort}).`,
1057
1038
  `Peers on the LAN can now connect to you inbound.`,
1058
1039
  `Call firewall_close() when you are done with this session.`
1059
1040
  ].join("\n")
@@ -1109,12 +1090,11 @@ function registerFirewallCloseTool(server, client) {
1109
1090
  };
1110
1091
  }
1111
1092
  try {
1112
- const { method } = await removeFirewallRule(targetPort);
1113
- const how = method === "direct" ? "applied directly (already elevated)" : "applied via UAC popup";
1093
+ await removeFirewallRule(targetPort);
1114
1094
  return {
1115
1095
  content: [{
1116
1096
  type: "text",
1117
- text: `Firewall rule removed for port ${targetPort} (claude-collab-${targetPort}). ${how}.`
1097
+ text: `Firewall rule removed for port ${targetPort} (claude-collab-${targetPort}).`
1118
1098
  }]
1119
1099
  };
1120
1100
  } catch (err) {
@@ -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\nimport { networkInterfaces } from 'os';\r\n\r\nexport const PEER_DISCOVERY_PORT = 9998;\r\nconst BROADCAST_INTERVAL_MS = 3000;\r\n\r\n/** Returns 255.255.255.255 plus each subnet's directed broadcast address. */\r\nfunction getBroadcastAddresses(): string[] {\r\n const addrs = new Set(['255.255.255.255']);\r\n for (const ifaces of Object.values(networkInterfaces())) {\r\n for (const iface of ifaces ?? []) {\r\n if (iface.family !== 'IPv4' || iface.internal) continue;\r\n const ip = iface.address.split('.').map(Number);\r\n const mask = iface.netmask.split('.').map(Number);\r\n const broadcast = ip.map((b, i) => b | (~mask[i] & 0xff)).join('.');\r\n addrs.add(broadcast);\r\n }\r\n }\r\n return [...addrs];\r\n}\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({ type: 'udp4', reuseAddr: true });\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 for (const addr of getBroadcastAddresses()) {\r\n socket.send(msg, 0, msg.length, PEER_DISCOVERY_PORT, addr, (err) => {\r\n if (err) console.error(`[peer-broadcaster] send to ${addr} error:`, err.message);\r\n });\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 // reuseAddr: true allows multiple processes (e.g. after MCP restart) to share port 9998\r\n const socket = createSocket({ type: 'udp4', reuseAddr: true });\r\n\r\n socket.on('error', (err) => {\r\n console.error('[peer-listener] bind failed on port', PEER_DISCOVERY_PORT, '—', 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 // Push-based answer resolution: questionId → resolve callback\r\n private readonly answerWaiters = new Map<string, (result: CheckAnswerResult) => void>();\r\n // Answers queued for offline peers: peerName → AnswerMsg (delivered on reconnect)\r\n private readonly pendingOutboundAnswers = new Map<string, import('./p2p-protocol.js').AnswerMsg>();\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 waitForAnswer(questionId: string, timeoutMs: number): Promise<CheckAnswerResult | null> {\r\n // Already in cache — resolve immediately\r\n const cached = this.receivedAnswers.get(questionId);\r\n if (cached) {\r\n return Promise.resolve(this.formatAnswer(questionId, cached));\r\n }\r\n\r\n return new Promise((resolve) => {\r\n const timeout = setTimeout(() => {\r\n this.answerWaiters.delete(questionId);\r\n resolve(null);\r\n }, timeoutMs);\r\n\r\n this.answerWaiters.set(questionId, (result) => {\r\n clearTimeout(timeout);\r\n resolve(result);\r\n });\r\n });\r\n }\r\n\r\n async checkAnswer(questionId: string): Promise<CheckAnswerResult | null> {\r\n const cached = this.receivedAnswers.get(questionId);\r\n return cached ? this.formatAnswer(questionId, cached) : null;\r\n }\r\n\r\n private formatAnswer(questionId: string, cached: ReceivedAnswer): CheckAnswerResult {\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 answerMsg: import('./p2p-protocol.js').AnswerMsg = {\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 const ws = this.peerConnections.get(senderName);\r\n if (ws && ws.readyState === WebSocket.OPEN) {\r\n this.sendToWs(ws, answerMsg);\r\n } else {\r\n // Peer is offline — queue the answer and deliver when they reconnect\r\n this.pendingOutboundAnswers.set(senderName, answerMsg);\r\n console.error(`[p2p] \"${senderName}\" is offline, answer queued for delivery on reconnect`);\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 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 this.deliverPendingAnswer(msg.name, ws);\r\n break;\r\n }\r\n\r\n case 'HELLO_ACK': {\r\n if (this.peerConnections.has(msg.name)) {\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 this.deliverPendingAnswer(msg.name, ws);\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 const record: ReceivedAnswer = {\r\n content: msg.content,\r\n format: msg.format,\r\n answeredAt: msg.answeredAt,\r\n fromName: msg.from,\r\n };\r\n this.receivedAnswers.set(msg.questionId, record);\r\n\r\n // Fire push waiter immediately — no more polling needed\r\n const waiter = this.answerWaiters.get(msg.questionId);\r\n if (waiter) {\r\n this.answerWaiters.delete(msg.questionId);\r\n waiter(this.formatAnswer(msg.questionId, record));\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 deliverPendingAnswer(peerName: string, ws: WebSocket): void {\r\n const pending = this.pendingOutboundAnswers.get(peerName);\r\n if (pending) {\r\n this.pendingOutboundAnswers.delete(peerName);\r\n this.sendToWs(ws, pending);\r\n console.error(`[p2p] delivered queued answer to \"${peerName}\" after reconnect`);\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 * @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\nconst ASK_DESCRIPTION = `\\\r\nSend a question to another Claude instance on the LAN and wait for their answer.\r\n\r\nWHEN TO USE:\r\n- You need input, a decision, or work output from a specific peer Claude\r\n- You want to delegate a subtask to another Claude and use their result\r\n- You need to coordinate or synchronize work across multiple Claudes\r\n\r\nWORKFLOW:\r\n1. Call peers() first to confirm the target is online and get their exact name\r\n2. Call ask(peer, question) — this blocks until they reply (up to 5 minutes)\r\n3. Use their answer directly in your ongoing task\r\n\r\nWRITING GOOD QUESTIONS:\r\n- Include all context the other Claude needs — they cannot see your conversation\r\n- Be specific about what format or level of detail you expect in the answer\r\n- If you need code, specify language and constraints\r\n- One focused question per call works better than multiple combined\r\n\r\nDO NOT use this tool if:\r\n- The peer is not listed in peers() — the call will fail immediately\r\n- You just want to share information without needing a response (there is no broadcast tool yet)`;\r\n\r\nconst askSchema = {\r\n peer: z\r\n .string()\r\n .describe('Exact name of the peer to ask. Use peers() first to see who is online and get the correct name.'),\r\n question: z\r\n .string()\r\n .describe(\r\n 'Your question in markdown. Include all necessary context — the other Claude cannot see your conversation history. Be specific about what kind of answer you need.'\r\n ),\r\n};\r\n\r\nexport function registerAskTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('ask', ASK_DESCRIPTION, 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 type: 'text',\r\n text: 'P2P node is not ready yet. Wait a moment and try again.',\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 // Wait for the answer via push — resolves the moment ANSWER arrives\r\n const answer = await client.waitForAnswer(questionId, 5 * 60 * 1000);\r\n\r\n if (answer !== null) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `**${answer.from.displayName} answered:**\\n\\n${answer.content}`,\r\n }],\r\n };\r\n }\r\n\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Question sent to \"${targetPeer}\" but no answer arrived within 5 minutes.`,\r\n `Question ID: \\`${questionId}\\``,\r\n ``,\r\n `The peer may be busy or offline. You can:`,\r\n `- Call peers() to check if they are still connected`,\r\n `- Continue with your task and follow up later`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n const isPeerOffline = errorMessage.includes('not connected');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: isPeerOffline\r\n ? `Peer \"${targetPeer}\" is not connected. Call peers() to see who is currently online.`\r\n : `Failed to send question: ${errorMessage}`,\r\n }],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Reply Tool\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\nconst REPLY_DESCRIPTION = `\\\r\nSend your answer back to a Claude instance that asked you a question.\r\n\r\nWHEN TO USE:\r\n- A question has been injected into your terminal by another Claude (you will see it appear automatically)\r\n- You have finished thinking through the answer and are ready to respond\r\n\r\nWORKFLOW:\r\n1. Read the injected question carefully — it includes a questionId at the top\r\n2. Think through a complete answer\r\n3. Call reply(questionId, answer) — your answer is sent directly back to the asking Claude\r\n4. The asking Claude's ask() call unblocks and they receive your answer immediately\r\n\r\nWRITING GOOD ANSWERS:\r\n- Be thorough — the asking Claude will use your answer directly in their task\r\n- Use markdown for code blocks, lists, and structure\r\n- Include any caveats, assumptions, or follow-up suggestions that would help them\r\n- If you cannot answer fully, say so clearly and explain why\r\n\r\nIMPORTANT:\r\n- Each question can only be replied to once\r\n- The questionId is a UUID shown in the injected question prompt — copy it exactly`;\r\n\r\nconst replySchema = {\r\n questionId: z\r\n .string()\r\n .describe(\r\n 'The UUID of the question to reply to. Shown at the top of the injected question prompt in your terminal.'\r\n ),\r\n answer: z\r\n .string()\r\n .describe(\r\n 'Your complete answer in markdown. Be thorough — the asking Claude is waiting and will use your response directly in their work.'\r\n ),\r\n};\r\n\r\nexport function registerReplyTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('reply', REPLY_DESCRIPTION, 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 type: 'text',\r\n text: 'P2P node is not ready yet. Wait a moment and try again.',\r\n }],\r\n isError: true,\r\n };\r\n }\r\n\r\n await client.reply(questionId, answer, 'markdown');\r\n\r\n injectionQueue.notifyReplied();\r\n\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `Answer sent. The peer's ask() call has been unblocked and they received your response.`,\r\n }],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n const isNotFound = errorMessage.includes('not found');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: isNotFound\r\n ? `Question \\`${questionId}\\` not found. Check that you copied the questionId exactly from the injected prompt.`\r\n : `Failed to send reply: ${errorMessage}`,\r\n }],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Peers Tool\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\nconst PEERS_DESCRIPTION = `\\\r\nShow your identity on the P2P network and list all currently connected peers.\r\n\r\nWHEN TO USE:\r\n- Before calling ask() — to confirm the target peer is online and get their exact name\r\n- After startup — to verify you joined the network successfully\r\n- When a peer seems unreachable — to check if they are still connected\r\n\r\nWHAT IT SHOWS:\r\n- Your own name and the port you are listening on\r\n- All peers who have established a direct connection to you\r\n\r\nIF NO PEERS ARE LISTED:\r\n- Peers discover each other automatically via LAN broadcast every 3 seconds\r\n- If a peer just started, wait a few seconds and call peers() again\r\n- Call firewall_open() so peers on other machines can connect inbound to you\r\n- If still no peers, verify all machines are on the same LAN/subnet`;\r\n\r\nexport function registerPeersTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('peers', PEERS_DESCRIPTION, {}, 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: [\r\n `P2P server is not running yet (port ${myPort} may be in use).`,\r\n `Check the MCP process logs for the error details.`,\r\n ].join('\\n'),\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: [\r\n `You are \"${myName}\" (listening on port ${myPort}).`,\r\n `No peers connected yet.`,\r\n ``,\r\n `Peers auto-discover via LAN broadcast — wait a few seconds if they just started.`,\r\n `Call firewall_open() if peers on other machines cannot reach you.`,\r\n ].join('\\n'),\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 * @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\nconst HISTORY_DESCRIPTION = `\\\r\nShow all questions and answers exchanged this session — both sent and received.\r\n\r\nWHEN TO USE:\r\n- To review what was already discussed before asking a follow-up question\r\n- To check if a previously sent question has been answered yet\r\n- To find a questionId you need to reference\r\n- To catch up on received questions you may have missed\r\n\r\nOUTPUT FORMAT:\r\n- → peer: question you sent, with their answer below\r\n- ← peer: question they sent you, with your reply below\r\n- (no answer yet) means the question is still waiting for a response`;\r\n\r\nexport function registerHistoryTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('history', HISTORY_DESCRIPTION, {}, 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 exchanged yet this session.' }],\r\n };\r\n }\r\n\r\n const unanswered = entries.filter((e) => !e.answer);\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 — use reply() if you haven't answered)`;\r\n return `[${time}] ← ${e.peer}: ${e.question}\\n${answerLine}`;\r\n }\r\n });\r\n\r\n const summary = unanswered.length > 0\r\n ? `\\n\\n⚠ ${unanswered.length} question(s) still waiting for a response.`\r\n : '';\r\n\r\n return {\r\n content: [{ type: 'text', text: lines.join('\\n\\n') + summary }],\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 // TCP rule for the WebSocket port\r\n const result = await 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 // UDP rule for peer discovery (port 9998) — run best-effort, don't fail if already exists\r\n try {\r\n await runNetsh([\r\n 'advfirewall', 'firewall', 'add', 'rule',\r\n 'name=claude-collab-discovery',\r\n 'protocol=UDP',\r\n 'dir=in',\r\n 'localport=9998',\r\n 'action=allow',\r\n ]);\r\n } catch { /* already exists or denied — TCP rule still applied */ }\r\n\r\n return result;\r\n}\r\n\r\nexport async function removeFirewallRule(port: number): Promise<{ method: 'direct' | 'elevated' }> {\r\n const result = await runNetsh([\r\n 'advfirewall', 'firewall', 'delete', 'rule',\r\n `name=claude-collab-${port}`,\r\n ]);\r\n\r\n // Also remove discovery rule best-effort\r\n try {\r\n await runNetsh(['advfirewall', 'firewall', 'delete', 'rule', 'name=claude-collab-discovery']);\r\n } catch { /* may not exist */ }\r\n\r\n return result;\r\n}\r\n","/**\r\n * FirewallOpen Tool\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\nconst FIREWALL_OPEN_DESCRIPTION = `\\\r\nOpen a Windows Firewall inbound rule so peers on the LAN can connect directly to you.\r\n\r\nWHEN YOU NEED THIS:\r\n- Other peers cannot see you in their peers() list even though you are on the same LAN\r\n- You just started and want to make sure all peers can reach you\r\n- A peer explicitly says they cannot connect to you\r\n\r\nWHEN YOU DO NOT NEED THIS:\r\n- You can already see peers in peers() — the connection is working\r\n- You are connecting outbound to others (outbound connections do not require firewall rules)\r\n\r\nWHAT HAPPENS:\r\n- On most systems: the rule is applied immediately (terminal is already elevated)\r\n- On standard Windows: a UAC popup appears — the user must click Yes\r\n- On VMs or headless setups: applied directly if running as Administrator\r\n\r\nThe rule is named \"claude-collab-{port}\" and allows inbound TCP on your current listen port.\r\nCall firewall_close() when you are done to clean up the rule.`;\r\n\r\nexport function registerFirewallOpenTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_open',\r\n FIREWALL_OPEN_DESCRIPTION,\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe(\r\n 'Port to open. Defaults to your current listen port — omit this unless you have a specific reason to override.'\r\n ),\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: 'P2P node is not running yet — port unknown. Try again in a moment.' }],\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 (already elevated)'\r\n : 'applied via UAC popup';\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Firewall rule opened for port ${targetPort} (claude-collab-${targetPort}). ${how}.`,\r\n `Peers on the LAN can now connect to you inbound.`,\r\n `Call firewall_close() when you are done with this session.`,\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: [{\r\n type: 'text',\r\n text: [\r\n `Failed to open firewall: ${msg}`,\r\n ``,\r\n `Try running your terminal as Administrator and call firewall_open() again.`,\r\n ].join('\\n'),\r\n }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n}\r\n","/**\r\n * FirewallClose Tool\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\nconst FIREWALL_CLOSE_DESCRIPTION = `\\\r\nRemove the Windows Firewall inbound rule that was opened by firewall_open().\r\n\r\nWHEN TO USE:\r\n- At the end of a collaboration session to clean up\r\n- When you no longer want to accept inbound peer connections\r\n- As general hygiene — open firewall rules should not be left indefinitely\r\n\r\nWHAT HAPPENS:\r\n- The inbound TCP rule \"claude-collab-{port}\" is deleted from Windows Firewall\r\n- Existing active connections are not dropped — only new inbound connections are blocked\r\n- On standard Windows: a UAC popup appears — the user must click Yes\r\n- On VMs or admin terminals: applied directly without a popup\r\n\r\nNOTE: Because ports are random each session, each startup creates a new rule name.\r\nOld rules from previous sessions can be removed by passing the port explicitly.`;\r\n\r\nexport function registerFirewallCloseTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_close',\r\n FIREWALL_CLOSE_DESCRIPTION,\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe(\r\n 'Port whose rule to remove. Defaults to your current listen port. Pass a specific port to clean up a rule from a previous session.'\r\n ),\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: 'P2P node is not running yet — port unknown. Try again in a moment.' }],\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 (already elevated)'\r\n : 'applied via UAC popup';\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `Firewall rule removed for port ${targetPort} (claude-collab-${targetPort}). ${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: [{\r\n type: 'text',\r\n text: [\r\n `Failed to remove firewall rule: ${msg}`,\r\n ``,\r\n `The rule may not exist (if firewall_open was never called this session), or try running as Administrator.`,\r\n ].join('\\n'),\r\n }],\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"]}
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\nimport { networkInterfaces } from 'os';\r\n\r\nexport const PEER_DISCOVERY_PORT = 9998;\r\nconst BROADCAST_INTERVAL_MS = 3000;\r\n\r\n/** Returns 255.255.255.255 plus each subnet's directed broadcast address. */\r\nfunction getBroadcastAddresses(): string[] {\r\n const addrs = new Set(['255.255.255.255']);\r\n for (const ifaces of Object.values(networkInterfaces())) {\r\n for (const iface of ifaces ?? []) {\r\n if (iface.family !== 'IPv4' || iface.internal) continue;\r\n const ip = iface.address.split('.').map(Number);\r\n const mask = iface.netmask.split('.').map(Number);\r\n const broadcast = ip.map((b, i) => b | (~mask[i] & 0xff)).join('.');\r\n addrs.add(broadcast);\r\n }\r\n }\r\n return [...addrs];\r\n}\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({ type: 'udp4', reuseAddr: true });\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 for (const addr of getBroadcastAddresses()) {\r\n socket.send(msg, 0, msg.length, PEER_DISCOVERY_PORT, addr, (err) => {\r\n if (err) console.error(`[peer-broadcaster] send to ${addr} error:`, err.message);\r\n });\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 // reuseAddr: true allows multiple processes (e.g. after MCP restart) to share port 9998\r\n const socket = createSocket({ type: 'udp4', reuseAddr: true });\r\n\r\n socket.on('error', (err) => {\r\n console.error('[peer-listener] bind failed on port', PEER_DISCOVERY_PORT, '—', 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 // Push-based answer resolution: questionId → resolve callback\r\n private readonly answerWaiters = new Map<string, (result: CheckAnswerResult) => void>();\r\n // Answers queued for offline peers: peerName → AnswerMsg (delivered on reconnect)\r\n private readonly pendingOutboundAnswers = new Map<string, import('./p2p-protocol.js').AnswerMsg>();\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 waitForAnswer(questionId: string, timeoutMs: number): Promise<CheckAnswerResult | null> {\r\n // Already in cache — resolve immediately\r\n const cached = this.receivedAnswers.get(questionId);\r\n if (cached) {\r\n return Promise.resolve(this.formatAnswer(questionId, cached));\r\n }\r\n\r\n return new Promise((resolve) => {\r\n const timeout = setTimeout(() => {\r\n this.answerWaiters.delete(questionId);\r\n resolve(null);\r\n }, timeoutMs);\r\n\r\n this.answerWaiters.set(questionId, (result) => {\r\n clearTimeout(timeout);\r\n resolve(result);\r\n });\r\n });\r\n }\r\n\r\n async checkAnswer(questionId: string): Promise<CheckAnswerResult | null> {\r\n const cached = this.receivedAnswers.get(questionId);\r\n return cached ? this.formatAnswer(questionId, cached) : null;\r\n }\r\n\r\n private formatAnswer(questionId: string, cached: ReceivedAnswer): CheckAnswerResult {\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 answerMsg: import('./p2p-protocol.js').AnswerMsg = {\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 const ws = this.peerConnections.get(senderName);\r\n if (ws && ws.readyState === WebSocket.OPEN) {\r\n this.sendToWs(ws, answerMsg);\r\n } else {\r\n // Peer is offline — queue the answer and deliver when they reconnect\r\n this.pendingOutboundAnswers.set(senderName, answerMsg);\r\n console.error(`[p2p] \"${senderName}\" is offline, answer queued for delivery on reconnect`);\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 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 this.deliverPendingAnswer(msg.name, ws);\r\n break;\r\n }\r\n\r\n case 'HELLO_ACK': {\r\n if (this.peerConnections.has(msg.name)) {\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 this.deliverPendingAnswer(msg.name, ws);\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 const record: ReceivedAnswer = {\r\n content: msg.content,\r\n format: msg.format,\r\n answeredAt: msg.answeredAt,\r\n fromName: msg.from,\r\n };\r\n this.receivedAnswers.set(msg.questionId, record);\r\n\r\n // Fire push waiter immediately — no more polling needed\r\n const waiter = this.answerWaiters.get(msg.questionId);\r\n if (waiter) {\r\n this.answerWaiters.delete(msg.questionId);\r\n waiter(this.formatAnswer(msg.questionId, record));\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 deliverPendingAnswer(peerName: string, ws: WebSocket): void {\r\n const pending = this.pendingOutboundAnswers.get(peerName);\r\n if (pending) {\r\n this.pendingOutboundAnswers.delete(peerName);\r\n this.sendToWs(ws, pending);\r\n console.error(`[p2p] delivered queued answer to \"${peerName}\" after reconnect`);\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 * @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\nconst ASK_DESCRIPTION = `\\\r\nSend a question to another Claude instance on the LAN and wait for their answer.\r\n\r\nWHEN TO USE:\r\n- You need input, a decision, or work output from a specific peer Claude\r\n- You want to delegate a subtask to another Claude and use their result\r\n- You need to coordinate or synchronize work across multiple Claudes\r\n\r\nWORKFLOW:\r\n1. Call peers() first to confirm the target is online and get their exact name\r\n2. Call ask(peer, question) — this blocks until they reply (up to 5 minutes)\r\n3. Use their answer directly in your ongoing task\r\n\r\nWRITING GOOD QUESTIONS:\r\n- Include all context the other Claude needs — they cannot see your conversation\r\n- Be specific about what format or level of detail you expect in the answer\r\n- If you need code, specify language and constraints\r\n- One focused question per call works better than multiple combined\r\n\r\nDO NOT use this tool if:\r\n- The peer is not listed in peers() — the call will fail immediately\r\n- You just want to share information without needing a response (there is no broadcast tool yet)`;\r\n\r\nconst askSchema = {\r\n peer: z\r\n .string()\r\n .describe('Exact name of the peer to ask. Use peers() first to see who is online and get the correct name.'),\r\n question: z\r\n .string()\r\n .describe(\r\n 'Your question in markdown. Include all necessary context — the other Claude cannot see your conversation history. Be specific about what kind of answer you need.'\r\n ),\r\n};\r\n\r\nexport function registerAskTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('ask', ASK_DESCRIPTION, 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 type: 'text',\r\n text: 'P2P node is not ready yet. Wait a moment and try again.',\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 // Wait for the answer via push — resolves the moment ANSWER arrives\r\n const answer = await client.waitForAnswer(questionId, 5 * 60 * 1000);\r\n\r\n if (answer !== null) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `**${answer.from.displayName} answered:**\\n\\n${answer.content}`,\r\n }],\r\n };\r\n }\r\n\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Question sent to \"${targetPeer}\" but no answer arrived within 5 minutes.`,\r\n `Question ID: \\`${questionId}\\``,\r\n ``,\r\n `The peer may be busy or offline. You can:`,\r\n `- Call peers() to check if they are still connected`,\r\n `- Continue with your task and follow up later`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n const isPeerOffline = errorMessage.includes('not connected');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: isPeerOffline\r\n ? `Peer \"${targetPeer}\" is not connected. Call peers() to see who is currently online.`\r\n : `Failed to send question: ${errorMessage}`,\r\n }],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Reply Tool\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\nconst REPLY_DESCRIPTION = `\\\r\nSend your answer back to a Claude instance that asked you a question.\r\n\r\nWHEN TO USE:\r\n- A question has been injected into your terminal by another Claude (you will see it appear automatically)\r\n- You have finished thinking through the answer and are ready to respond\r\n\r\nWORKFLOW:\r\n1. Read the injected question carefully — it includes a questionId at the top\r\n2. Think through a complete answer\r\n3. Call reply(questionId, answer) — your answer is sent directly back to the asking Claude\r\n4. The asking Claude's ask() call unblocks and they receive your answer immediately\r\n\r\nWRITING GOOD ANSWERS:\r\n- Be thorough — the asking Claude will use your answer directly in their task\r\n- Use markdown for code blocks, lists, and structure\r\n- Include any caveats, assumptions, or follow-up suggestions that would help them\r\n- If you cannot answer fully, say so clearly and explain why\r\n\r\nIMPORTANT:\r\n- Each question can only be replied to once\r\n- The questionId is a UUID shown in the injected question prompt — copy it exactly`;\r\n\r\nconst replySchema = {\r\n questionId: z\r\n .string()\r\n .describe(\r\n 'The UUID of the question to reply to. Shown at the top of the injected question prompt in your terminal.'\r\n ),\r\n answer: z\r\n .string()\r\n .describe(\r\n 'Your complete answer in markdown. Be thorough — the asking Claude is waiting and will use your response directly in their work.'\r\n ),\r\n};\r\n\r\nexport function registerReplyTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('reply', REPLY_DESCRIPTION, 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 type: 'text',\r\n text: 'P2P node is not ready yet. Wait a moment and try again.',\r\n }],\r\n isError: true,\r\n };\r\n }\r\n\r\n await client.reply(questionId, answer, 'markdown');\r\n\r\n injectionQueue.notifyReplied();\r\n\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `Answer sent. The peer's ask() call has been unblocked and they received your response.`,\r\n }],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n const isNotFound = errorMessage.includes('not found');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: isNotFound\r\n ? `Question \\`${questionId}\\` not found. Check that you copied the questionId exactly from the injected prompt.`\r\n : `Failed to send reply: ${errorMessage}`,\r\n }],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Peers Tool\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\nconst PEERS_DESCRIPTION = `\\\r\nShow your identity on the P2P network and list all currently connected peers.\r\n\r\nWHEN TO USE:\r\n- Before calling ask() — to confirm the target peer is online and get their exact name\r\n- After startup — to verify you joined the network successfully\r\n- When a peer seems unreachable — to check if they are still connected\r\n\r\nWHAT IT SHOWS:\r\n- Your own name and the port you are listening on\r\n- All peers who have established a direct connection to you\r\n\r\nIF NO PEERS ARE LISTED:\r\n- Peers discover each other automatically via LAN broadcast every 3 seconds\r\n- If a peer just started, wait a few seconds and call peers() again\r\n- Call firewall_open() so peers on other machines can connect inbound to you\r\n- If still no peers, verify all machines are on the same LAN/subnet`;\r\n\r\nexport function registerPeersTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('peers', PEERS_DESCRIPTION, {}, 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: [\r\n `P2P server is not running yet (port ${myPort} may be in use).`,\r\n `Check the MCP process logs for the error details.`,\r\n ].join('\\n'),\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: [\r\n `You are \"${myName}\" (listening on port ${myPort}).`,\r\n `No peers connected yet.`,\r\n ``,\r\n `Peers auto-discover via LAN broadcast — wait a few seconds if they just started.`,\r\n `Call firewall_open() if peers on other machines cannot reach you.`,\r\n ].join('\\n'),\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 * @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\nconst HISTORY_DESCRIPTION = `\\\r\nShow all questions and answers exchanged this session — both sent and received.\r\n\r\nWHEN TO USE:\r\n- To review what was already discussed before asking a follow-up question\r\n- To check if a previously sent question has been answered yet\r\n- To find a questionId you need to reference\r\n- To catch up on received questions you may have missed\r\n\r\nOUTPUT FORMAT:\r\n- → peer: question you sent, with their answer below\r\n- ← peer: question they sent you, with your reply below\r\n- (no answer yet) means the question is still waiting for a response`;\r\n\r\nexport function registerHistoryTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('history', HISTORY_DESCRIPTION, {}, 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 exchanged yet this session.' }],\r\n };\r\n }\r\n\r\n const unanswered = entries.filter((e) => !e.answer);\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 — use reply() if you haven't answered)`;\r\n return `[${time}] ← ${e.peer}: ${e.question}\\n${answerLine}`;\r\n }\r\n });\r\n\r\n const summary = unanswered.length > 0\r\n ? `\\n\\n⚠ ${unanswered.length} question(s) still waiting for a response.`\r\n : '';\r\n\r\n return {\r\n content: [{ type: 'text', text: lines.join('\\n\\n') + summary }],\r\n };\r\n });\r\n}\r\n","/**\r\n * Firewall helpers\r\n * Always elevated via UAC (PowerShell Start-Process -Verb RunAs) so the rule\r\n * is guaranteed to be applied. If the process is already elevated, Windows\r\n * skips the UAC prompt automatically.\r\n * @module infrastructure/firewall/firewall\r\n */\r\n\r\nimport { spawn } from 'child_process';\r\n\r\n/**\r\n * Run netsh via UAC elevation (PowerShell Start-Process -Verb RunAs).\r\n * If the calling process is already elevated, no prompt is shown.\r\n * Always use this path — running netsh directly without elevation can silently\r\n * exit 0 on some Windows versions without actually applying the rule.\r\n */\r\nfunction runNetshElevated(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\nasync function runNetsh(argArray: string[]): Promise<void> {\r\n await runNetshElevated(argArray);\r\n}\r\n\r\nexport async function addFirewallRule(port: number): Promise<void> {\r\n // TCP rule for the WebSocket port\r\n await 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 // UDP rule for peer discovery (port 9998) — run best-effort, don't fail if already exists\r\n try {\r\n await runNetsh([\r\n 'advfirewall', 'firewall', 'add', 'rule',\r\n 'name=claude-collab-discovery',\r\n 'protocol=UDP',\r\n 'dir=in',\r\n 'localport=9998',\r\n 'action=allow',\r\n ]);\r\n } catch { /* already exists or denied — TCP rule still applied */ }\r\n}\r\n\r\nexport async function removeFirewallRule(port: number): Promise<void> {\r\n await runNetsh([\r\n 'advfirewall', 'firewall', 'delete', 'rule',\r\n `name=claude-collab-${port}`,\r\n ]);\r\n\r\n // Also remove discovery rule best-effort\r\n try {\r\n await runNetsh(['advfirewall', 'firewall', 'delete', 'rule', 'name=claude-collab-discovery']);\r\n } catch { /* may not exist */ }\r\n}\r\n","/**\r\n * FirewallOpen Tool\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\nconst FIREWALL_OPEN_DESCRIPTION = `\\\r\nOpen a Windows Firewall inbound rule so peers on the LAN can connect directly to you.\r\n\r\nWHEN YOU NEED THIS:\r\n- Other peers cannot see you in their peers() list even though you are on the same LAN\r\n- You just started and want to make sure all peers can reach you\r\n- A peer explicitly says they cannot connect to you\r\n\r\nWHEN YOU DO NOT NEED THIS:\r\n- You can already see peers in peers() — the connection is working\r\n- You are connecting outbound to others (outbound connections do not require firewall rules)\r\n\r\nWHAT HAPPENS:\r\n- On most systems: the rule is applied immediately (terminal is already elevated)\r\n- On standard Windows: a UAC popup appears — the user must click Yes\r\n- On VMs or headless setups: applied directly if running as Administrator\r\n\r\nThe rule is named \"claude-collab-{port}\" and allows inbound TCP on your current listen port.\r\nCall firewall_close() when you are done to clean up the rule.`;\r\n\r\nexport function registerFirewallOpenTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_open',\r\n FIREWALL_OPEN_DESCRIPTION,\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe(\r\n 'Port to open. Defaults to your current listen port — omit this unless you have a specific reason to override.'\r\n ),\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: 'P2P node is not running yet — port unknown. Try again in a moment.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n try {\r\n await addFirewallRule(targetPort);\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Firewall rule opened for port ${targetPort} (claude-collab-${targetPort}).`,\r\n `Peers on the LAN can now connect to you inbound.`,\r\n `Call firewall_close() when you are done with this session.`,\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: [{\r\n type: 'text',\r\n text: [\r\n `Failed to open firewall: ${msg}`,\r\n ``,\r\n `Try running your terminal as Administrator and call firewall_open() again.`,\r\n ].join('\\n'),\r\n }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n}\r\n","/**\r\n * FirewallClose Tool\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\nconst FIREWALL_CLOSE_DESCRIPTION = `\\\r\nRemove the Windows Firewall inbound rule that was opened by firewall_open().\r\n\r\nWHEN TO USE:\r\n- At the end of a collaboration session to clean up\r\n- When you no longer want to accept inbound peer connections\r\n- As general hygiene — open firewall rules should not be left indefinitely\r\n\r\nWHAT HAPPENS:\r\n- The inbound TCP rule \"claude-collab-{port}\" is deleted from Windows Firewall\r\n- Existing active connections are not dropped — only new inbound connections are blocked\r\n- On standard Windows: a UAC popup appears — the user must click Yes\r\n- On VMs or admin terminals: applied directly without a popup\r\n\r\nNOTE: Because ports are random each session, each startup creates a new rule name.\r\nOld rules from previous sessions can be removed by passing the port explicitly.`;\r\n\r\nexport function registerFirewallCloseTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_close',\r\n FIREWALL_CLOSE_DESCRIPTION,\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe(\r\n 'Port whose rule to remove. Defaults to your current listen port. Pass a specific port to clean up a rule from a previous session.'\r\n ),\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: 'P2P node is not running yet — port unknown. Try again in a moment.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n try {\r\n await removeFirewallRule(targetPort);\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `Firewall rule removed for port ${targetPort} (claude-collab-${targetPort}).`,\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: [{\r\n type: 'text',\r\n text: [\r\n `Failed to remove firewall rule: ${msg}`,\r\n ``,\r\n `The rule may not exist (if firewall_open was never called this session), or try running as Administrator.`,\r\n ].join('\\n'),\r\n }],\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.5",
3
+ "version": "1.9.6",
4
4
  "description": "Real-time team collaboration between Claude Code terminals via MCP",
5
5
  "type": "module",
6
6
  "main": "./dist/mcp-main.js",