@dolusoft/claude-collab 1.4.2 → 1.4.4

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
@@ -5,7 +5,7 @@ import { v4 } from 'uuid';
5
5
  import { EventEmitter } from 'events';
6
6
  import { execFile } from 'child_process';
7
7
  import { unlinkSync } from 'fs';
8
- import { tmpdir } from 'os';
8
+ import { tmpdir, networkInterfaces } from 'os';
9
9
  import { join } from 'path';
10
10
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
11
11
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
@@ -243,9 +243,10 @@ var config = {
243
243
  */
244
244
  p2p: {
245
245
  /**
246
- * Fixed port for the WS server. Override with CLAUDE_COLLAB_PORT env var.
246
+ * Port range for the WS server. Override with CLAUDE_COLLAB_PORT_MIN / MAX env vars.
247
247
  */
248
- port: Number(process.env["CLAUDE_COLLAB_PORT"] ?? 11777)
248
+ portRangeMin: Number(process.env["CLAUDE_COLLAB_PORT_MIN"] ?? 11700),
249
+ portRangeMax: Number(process.env["CLAUDE_COLLAB_PORT_MAX"] ?? 11750)
249
250
  }};
250
251
 
251
252
  // src/infrastructure/p2p/p2p-node.ts
@@ -273,23 +274,47 @@ var P2PNode = class {
273
274
  return this.localMember?.teamName;
274
275
  }
275
276
  /**
276
- * Starts the WS server on the configured fixed port.
277
+ * Starts the WS server on a random available port within the configured range.
277
278
  * Called automatically from join() if not yet started.
278
279
  */
279
280
  async start() {
280
- this.port = config.p2p.port;
281
- this.wss = new WebSocketServer({ port: this.port });
281
+ const { portRangeMin, portRangeMax } = config.p2p;
282
+ const range = portRangeMax - portRangeMin + 1;
283
+ const startOffset = Math.floor(Math.random() * range);
284
+ for (let i = 0; i < range; i++) {
285
+ const port = portRangeMin + (startOffset + i) % range;
286
+ const bound = await this.tryBind(port);
287
+ if (bound) {
288
+ this.port = port;
289
+ break;
290
+ }
291
+ }
292
+ if (!this.wss) {
293
+ throw new Error(
294
+ `No available port in range ${portRangeMin}-${portRangeMax}. Override with CLAUDE_COLLAB_PORT_MIN / CLAUDE_COLLAB_PORT_MAX.`
295
+ );
296
+ }
282
297
  this.setupWssHandlers();
283
298
  this._isStarted = true;
284
299
  console.error(`P2P node started on port ${this.port}`);
285
300
  }
301
+ tryBind(port) {
302
+ return new Promise((resolve) => {
303
+ const wss = new WebSocketServer({ port });
304
+ wss.once("listening", () => {
305
+ this.wss = wss;
306
+ resolve(true);
307
+ });
308
+ wss.once("error", () => resolve(false));
309
+ });
310
+ }
286
311
  async join(teamName, displayName) {
287
312
  if (!this._isStarted) {
288
313
  await this.start();
289
314
  }
290
315
  const memberId = v4();
291
316
  this.localMember = { memberId, teamName, displayName };
292
- return { memberId, teamId: teamName, teamName, displayName, status: "ONLINE" };
317
+ return { memberId, teamId: teamName, teamName, displayName, status: "ONLINE", port: this.port };
293
318
  }
294
319
  /**
295
320
  * Connects to a peer at the given IP and port.
@@ -299,8 +324,7 @@ var P2PNode = class {
299
324
  if (!this.localMember) {
300
325
  throw new Error("Must call join() before connectPeer()");
301
326
  }
302
- const targetPort = port ?? config.p2p.port;
303
- const ws = new WebSocket(`ws://${ip}:${targetPort}`);
327
+ const ws = new WebSocket(`ws://${ip}:${port}`);
304
328
  ws.on("message", (data) => {
305
329
  try {
306
330
  const msg = parseP2PMsg(data.toString());
@@ -320,7 +344,7 @@ var P2PNode = class {
320
344
  });
321
345
  await new Promise((resolve, reject) => {
322
346
  const timeout = setTimeout(
323
- () => reject(new Error(`Connection timeout to ${ip}:${targetPort}`)),
347
+ () => reject(new Error(`Connection timeout to ${ip}:${port}`)),
324
348
  5e3
325
349
  );
326
350
  ws.on("open", () => {
@@ -447,6 +471,13 @@ var P2PNode = class {
447
471
  pendingCount: questions.length
448
472
  };
449
473
  }
474
+ getInfo() {
475
+ return {
476
+ teamName: this.localMember?.teamName,
477
+ port: this._isStarted ? this.port : void 0,
478
+ connectedPeers: [...this.peerConns.keys()]
479
+ };
480
+ }
450
481
  async disconnect() {
451
482
  for (const ws of this.peerConns.values()) {
452
483
  ws.close();
@@ -627,8 +658,10 @@ function registerJoinTool(server, client) {
627
658
  text: `Successfully joined team "${member.teamName}" as "${member.displayName}".
628
659
 
629
660
  Your member ID: ${member.memberId}
630
- Team ID: ${member.teamId}
631
- Status: ${member.status}`
661
+ Status: ${member.status}
662
+ Listening on port: ${member.port}
663
+
664
+ Share this port with the other terminal so they can run: connect_peer("<your-ip>", ${member.port})`
632
665
  }
633
666
  ]
634
667
  };
@@ -648,18 +681,17 @@ Status: ${member.status}`
648
681
  }
649
682
  var connectPeerSchema = {
650
683
  ip: z.string().describe('IP address of the peer to connect to (e.g., "172.16.40.137")'),
651
- port: z.number().optional().describe(`Port the peer is listening on (default: ${config.p2p.port})`)
684
+ port: z.number().describe("Port the peer is listening on (shown in their join response)")
652
685
  };
653
686
  function registerConnectPeerTool(server, client) {
654
687
  server.tool("connect_peer", connectPeerSchema, async (args) => {
655
- const targetPort = args.port ?? config.p2p.port;
656
688
  try {
657
689
  const peerTeam = await client.connectPeer(args.ip, args.port);
658
690
  return {
659
691
  content: [
660
692
  {
661
693
  type: "text",
662
- text: `Connected to peer "${peerTeam}" at ${args.ip}:${targetPort}.`
694
+ text: `Connected to peer "${peerTeam}" at ${args.ip}:${args.port}.`
663
695
  }
664
696
  ]
665
697
  };
@@ -669,7 +701,7 @@ function registerConnectPeerTool(server, client) {
669
701
  content: [
670
702
  {
671
703
  type: "text",
672
- text: `Failed to connect to ${args.ip}:${targetPort}: ${errorMessage}`
704
+ text: `Failed to connect to ${args.ip}:${args.port}: ${errorMessage}`
673
705
  }
674
706
  ],
675
707
  isError: true
@@ -677,6 +709,40 @@ function registerConnectPeerTool(server, client) {
677
709
  }
678
710
  });
679
711
  }
712
+ function getLocalIPs() {
713
+ const ips = [];
714
+ for (const iface of Object.values(networkInterfaces())) {
715
+ for (const net of iface ?? []) {
716
+ if (net.family === "IPv4" && !net.internal) {
717
+ ips.push(net.address);
718
+ }
719
+ }
720
+ }
721
+ return ips;
722
+ }
723
+ function registerGetInfoTool(server, client) {
724
+ server.tool("get_info", {}, async () => {
725
+ const info = client.getInfo();
726
+ const ips = getLocalIPs();
727
+ const lines = [];
728
+ lines.push(`Team: ${info.teamName ?? "(not joined yet)"}`);
729
+ lines.push(`Port: ${info.port ?? "(not started yet)"}`);
730
+ lines.push(`Local IPs: ${ips.length > 0 ? ips.join(", ") : "(none found)"}`);
731
+ if (info.connectedPeers.length > 0) {
732
+ lines.push(`Connected peers: ${info.connectedPeers.join(", ")}`);
733
+ } else {
734
+ lines.push(`Connected peers: (none)`);
735
+ }
736
+ if (info.port && ips.length > 0) {
737
+ lines.push(`
738
+ Other terminal can connect with:
739
+ connect_peer("${ips[0]}", ${info.port})`);
740
+ }
741
+ return {
742
+ content: [{ type: "text", text: lines.join("\n") }]
743
+ };
744
+ });
745
+ }
680
746
  var askSchema = {
681
747
  team: z.string().describe('Target team name to ask (e.g., "backend", "frontend")'),
682
748
  question: z.string().describe("The question to ask (supports markdown)")
@@ -924,6 +990,7 @@ function createMcpServer(options) {
924
990
  );
925
991
  registerJoinTool(server, client);
926
992
  registerConnectPeerTool(server, client);
993
+ registerGetInfoTool(server, client);
927
994
  registerAskTool(server, client);
928
995
  registerCheckAnswerTool(server, client);
929
996
  registerInboxTool(server, client);
@@ -963,13 +1030,6 @@ var program = new Command();
963
1030
  program.name("claude-collab").description("Real-time P2P team collaboration between Claude Code terminals").version("0.1.0");
964
1031
  program.command("client").description("Start MCP client (P2P mode, connects to Claude Code)").action(async () => {
965
1032
  const p2pNode = new P2PNode();
966
- try {
967
- await p2pNode.start();
968
- } catch (error) {
969
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
970
- console.error(`Failed to start P2P node: ${errorMessage}`);
971
- process.exit(1);
972
- }
973
1033
  await startMcpServer({ client: p2pNode });
974
1034
  });
975
1035
  program.parse();
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/infrastructure/p2p/p2p-message-protocol.ts","../src/infrastructure/terminal-injector/windows-injector.ts","../src/infrastructure/terminal-injector/index.ts","../src/infrastructure/terminal-injector/injection-queue.ts","../src/config/index.ts","../src/infrastructure/p2p/p2p-node.ts","../src/presentation/mcp/tools/join.tool.ts","../src/presentation/mcp/tools/connect-peer.tool.ts","../src/presentation/mcp/tools/ask.tool.ts","../src/presentation/mcp/tools/check.tool.ts","../src/presentation/mcp/tools/inbox.tool.ts","../src/presentation/mcp/tools/reply.tool.ts","../src/presentation/mcp/server.ts","../src/cli.ts"],"names":["uuidv4","z"],"mappings":"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","file":"cli.js","sourcesContent":["/**\r\n * P2P Wire Message Protocol\r\n * Defines messages exchanged directly between P2P nodes.\r\n * @module infrastructure/p2p/p2p-message-protocol\r\n */\r\n\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\n\r\n// First message sent by the connecting peer to identify itself\r\nexport interface P2PHelloMsg {\r\n type: 'P2P_HELLO';\r\n fromTeam: string;\r\n fromMemberId: string;\r\n}\r\n\r\n// Questioner → Answerer: send a question\r\nexport interface P2PAskMsg {\r\n type: 'P2P_ASK';\r\n questionId: string;\r\n fromMemberId: string;\r\n fromTeam: string;\r\n toTeam: string;\r\n content: string;\r\n format: MessageFormat;\r\n requestId: string;\r\n}\r\n\r\n// Answerer → Questioner: acknowledge the question\r\nexport interface P2PAskAckMsg {\r\n type: 'P2P_ASK_ACK';\r\n questionId: string;\r\n requestId: string;\r\n}\r\n\r\n// Questioner → Answerer: poll for answer\r\nexport interface P2PGetAnswerMsg {\r\n type: 'P2P_GET_ANSWER';\r\n questionId: string;\r\n requestId: string;\r\n}\r\n\r\n// Answerer → Questioner: deliver the answer (push or in response to GET_ANSWER)\r\nexport interface P2PAnswerMsg {\r\n type: 'P2P_ANSWER';\r\n questionId: string;\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n fromTeam: string;\r\n fromMemberId: string;\r\n requestId?: string;\r\n}\r\n\r\n// Answerer → Questioner: answer not ready yet\r\nexport interface P2PAnswerPendingMsg {\r\n type: 'P2P_ANSWER_PENDING';\r\n questionId: string;\r\n requestId: string;\r\n}\r\n\r\nexport interface P2PPingMsg {\r\n type: 'P2P_PING';\r\n}\r\n\r\nexport interface P2PPongMsg {\r\n type: 'P2P_PONG';\r\n}\r\n\r\nexport interface P2PErrorMsg {\r\n type: 'P2P_ERROR';\r\n code: string;\r\n message: string;\r\n}\r\n\r\nexport type P2PMsg =\r\n | P2PHelloMsg\r\n | P2PAskMsg\r\n | P2PAskAckMsg\r\n | P2PGetAnswerMsg\r\n | P2PAnswerMsg\r\n | P2PAnswerPendingMsg\r\n | P2PPingMsg\r\n | P2PPongMsg\r\n | P2PErrorMsg;\r\n\r\nexport function serializeP2PMsg(msg: P2PMsg): string {\r\n return JSON.stringify(msg);\r\n}\r\n\r\nexport function parseP2PMsg(data: string): P2PMsg {\r\n return JSON.parse(data) as P2PMsg;\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 * Configuration module\r\n * @module config\r\n */\r\n\r\n/**\r\n * Application configuration\r\n */\r\nexport const config = {\r\n /**\r\n * P2P node configuration\r\n */\r\n p2p: {\r\n /**\r\n * Fixed port for the WS server. Override with CLAUDE_COLLAB_PORT env var.\r\n */\r\n port: Number(process.env['CLAUDE_COLLAB_PORT'] ?? 11777),\r\n },\r\n\r\n /**\r\n * Communication configuration\r\n */\r\n communication: {\r\n /**\r\n * Default timeout for waiting for an answer (in milliseconds)\r\n */\r\n defaultTimeout: 30000,\r\n\r\n /**\r\n * Maximum message content length\r\n */\r\n maxMessageLength: 50000,\r\n },\r\n} as const;\r\n\r\nexport type Config = typeof config;\r\n","/**\r\n * P2PNode\r\n * Implements ICollabClient using a peer-to-peer WebSocket architecture.\r\n * Each node runs its own WS server on a fixed port; peers are connected\r\n * manually via connectPeer().\r\n * @module infrastructure/p2p/p2p-node\r\n */\r\n\r\nimport { WebSocketServer, WebSocket } 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} 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 P2PAskMsg,\r\n type P2PAskAckMsg,\r\n type P2PGetAnswerMsg,\r\n type P2PAnswerMsg,\r\n type P2PAnswerPendingMsg,\r\n type P2PHelloMsg,\r\n serializeP2PMsg,\r\n parseP2PMsg,\r\n} from './p2p-message-protocol.js';\r\nimport { injectionQueue } from '../terminal-injector/injection-queue.js';\r\nimport { config } from '../../config/index.js';\r\n\r\ninterface IncomingQuestion {\r\n questionId: string;\r\n fromTeam: string;\r\n fromMemberId: string;\r\n content: string;\r\n format: MessageFormat;\r\n createdAt: Date;\r\n ws: WebSocket;\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 fromTeam: string;\r\n fromMemberId: string;\r\n}\r\n\r\ninterface LocalMember {\r\n memberId: string;\r\n teamName: string;\r\n displayName: string;\r\n}\r\n\r\nexport class P2PNode implements ICollabClient {\r\n private wss: WebSocketServer | null = null;\r\n private port = 0;\r\n\r\n // Connections indexed by remote team name\r\n private readonly peerConns = new Map<string, WebSocket>();\r\n // Reverse lookup: ws → teamName (for cleanup)\r\n private readonly wsToTeam = new Map<WebSocket, string>();\r\n\r\n // Questions we received from remote peers (our inbox)\r\n private readonly incomingQuestions = new Map<string, IncomingQuestion>();\r\n\r\n // Answers we received for questions we asked\r\n private readonly receivedAnswers = new Map<string, ReceivedAnswer>();\r\n\r\n // Maps questionId → remote teamName (so we know who to poll)\r\n private readonly questionToTeam = new Map<string, string>();\r\n\r\n // Pending response handlers (request-response correlation by filter)\r\n private readonly pendingHandlers = new Set<(msg: P2PMsg) => void>();\r\n\r\n private localMember: LocalMember | null = null;\r\n private _isStarted = false;\r\n\r\n get isConnected(): boolean {\r\n return this._isStarted;\r\n }\r\n\r\n get currentTeamId(): string | undefined {\r\n return this.localMember?.teamName;\r\n }\r\n\r\n /**\r\n * Starts the WS server on the configured fixed port.\r\n * Called automatically from join() if not yet started.\r\n */\r\n async start(): Promise<void> {\r\n this.port = config.p2p.port;\r\n this.wss = new WebSocketServer({ port: this.port });\r\n this.setupWssHandlers();\r\n this._isStarted = true;\r\n console.error(`P2P node started on port ${this.port}`);\r\n }\r\n\r\n async join(teamName: string, displayName: string): Promise<JoinResult> {\r\n if (!this._isStarted) {\r\n await this.start();\r\n }\r\n\r\n const memberId = uuidv4();\r\n this.localMember = { memberId, teamName, displayName };\r\n\r\n return { memberId, teamId: teamName, teamName, displayName, status: 'ONLINE' };\r\n }\r\n\r\n /**\r\n * Connects to a peer at the given IP and port.\r\n * Performs a bidirectional HELLO handshake and returns the peer's team name.\r\n */\r\n async connectPeer(ip: string, port?: number): Promise<string> {\r\n if (!this.localMember) {\r\n throw new Error('Must call join() before connectPeer()');\r\n }\r\n\r\n const targetPort = port ?? config.p2p.port;\r\n const ws = new WebSocket(`ws://${ip}:${targetPort}`);\r\n\r\n // Set up persistent message handler\r\n ws.on('message', (data) => {\r\n try {\r\n const msg = parseP2PMsg(data.toString());\r\n this.handleMessage(ws, msg);\r\n } catch (err) {\r\n console.error('Failed to parse P2P message:', err);\r\n }\r\n });\r\n\r\n ws.on('close', () => {\r\n const team = this.wsToTeam.get(ws);\r\n if (team) {\r\n if (this.peerConns.get(team) === ws) {\r\n this.peerConns.delete(team);\r\n }\r\n this.wsToTeam.delete(ws);\r\n }\r\n });\r\n\r\n // Connect and send our HELLO\r\n await new Promise<void>((resolve, reject) => {\r\n const timeout = setTimeout(\r\n () => reject(new Error(`Connection timeout to ${ip}:${targetPort}`)),\r\n 5000\r\n );\r\n\r\n ws.on('open', () => {\r\n clearTimeout(timeout);\r\n const hello: P2PHelloMsg = {\r\n type: 'P2P_HELLO',\r\n fromTeam: this.localMember!.teamName,\r\n fromMemberId: this.localMember!.memberId,\r\n };\r\n ws.send(serializeP2PMsg(hello));\r\n resolve();\r\n });\r\n\r\n ws.on('error', (err) => {\r\n clearTimeout(timeout);\r\n reject(err);\r\n });\r\n });\r\n\r\n // Wait for their HELLO back to identify their team name\r\n const helloMsg = await this.waitForResponse<P2PHelloMsg>(\r\n (m) => m.type === 'P2P_HELLO',\r\n 10000\r\n );\r\n\r\n return helloMsg.fromTeam;\r\n }\r\n\r\n async ask(toTeam: string, content: string, format: MessageFormat): Promise<string> {\r\n const ws = await this.getPeerConnection(toTeam);\r\n const questionId = uuidv4();\r\n const requestId = uuidv4();\r\n\r\n this.questionToTeam.set(questionId, toTeam);\r\n\r\n // Register handler before sending (avoids race where ACK arrives first)\r\n const ackPromise = this.waitForResponse<P2PAskAckMsg>(\r\n (m) => m.type === 'P2P_ASK_ACK' && m.requestId === requestId,\r\n 5000\r\n );\r\n\r\n const msg: P2PAskMsg = {\r\n type: 'P2P_ASK',\r\n questionId,\r\n fromMemberId: this.localMember!.memberId,\r\n fromTeam: this.localMember!.teamName,\r\n toTeam,\r\n content,\r\n format,\r\n requestId,\r\n };\r\n ws.send(serializeP2PMsg(msg));\r\n\r\n await ackPromise;\r\n return questionId;\r\n }\r\n\r\n async checkAnswer(questionId: string): Promise<CheckAnswerResult | null> {\r\n // Check local cache first (populated by push from remote)\r\n const cached = this.receivedAnswers.get(questionId);\r\n if (cached) {\r\n return {\r\n questionId,\r\n from: { displayName: `${cached.fromTeam} Claude`, teamName: cached.fromTeam },\r\n content: cached.content,\r\n format: cached.format,\r\n answeredAt: cached.answeredAt,\r\n };\r\n }\r\n\r\n // Poll the remote peer\r\n const toTeam = this.questionToTeam.get(questionId);\r\n if (!toTeam) return null;\r\n\r\n const ws = this.peerConns.get(toTeam);\r\n if (!ws || ws.readyState !== WebSocket.OPEN) return null;\r\n\r\n const requestId = uuidv4();\r\n\r\n const responsePromise = this.waitForResponse<P2PAnswerMsg | P2PAnswerPendingMsg>(\r\n (m) =>\r\n (m.type === 'P2P_ANSWER' && m.questionId === questionId) ||\r\n (m.type === 'P2P_ANSWER_PENDING' && m.requestId === requestId),\r\n 5000\r\n );\r\n\r\n const getMsg: P2PGetAnswerMsg = {\r\n type: 'P2P_GET_ANSWER',\r\n questionId,\r\n requestId,\r\n };\r\n ws.send(serializeP2PMsg(getMsg));\r\n\r\n const response = await responsePromise;\r\n if (response.type === 'P2P_ANSWER_PENDING') return null;\r\n\r\n const answer = response as P2PAnswerMsg;\r\n this.receivedAnswers.set(questionId, {\r\n content: answer.content,\r\n format: answer.format,\r\n answeredAt: answer.answeredAt,\r\n fromTeam: answer.fromTeam,\r\n fromMemberId: answer.fromMemberId,\r\n });\r\n\r\n return {\r\n questionId,\r\n from: { displayName: `${answer.fromTeam} Claude`, teamName: answer.fromTeam },\r\n content: answer.content,\r\n format: answer.format,\r\n answeredAt: answer.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 in inbox`);\r\n\r\n question.answered = true;\r\n question.answerContent = content;\r\n question.answerFormat = format;\r\n\r\n const answerMsg: P2PAnswerMsg = {\r\n type: 'P2P_ANSWER',\r\n questionId,\r\n content,\r\n format,\r\n answeredAt: new Date().toISOString(),\r\n fromTeam: this.localMember!.teamName,\r\n fromMemberId: this.localMember!.memberId,\r\n };\r\n\r\n if (question.ws.readyState === WebSocket.OPEN) {\r\n question.ws.send(serializeP2PMsg(answerMsg));\r\n }\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.fromTeam} Claude`, teamName: q.fromTeam },\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\r\n return {\r\n questions,\r\n totalCount: questions.length,\r\n pendingCount: questions.length,\r\n };\r\n }\r\n\r\n async disconnect(): Promise<void> {\r\n for (const ws of this.peerConns.values()) {\r\n ws.close();\r\n }\r\n this.peerConns.clear();\r\n\r\n await new Promise<void>((resolve) => {\r\n if (this.wss) {\r\n this.wss.close(() => resolve());\r\n } else {\r\n resolve();\r\n }\r\n });\r\n\r\n this._isStarted = false;\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: WebSocket server setup\r\n // ---------------------------------------------------------------------------\r\n\r\n private setupWssHandlers(): void {\r\n this.wss!.on('connection', (ws) => {\r\n ws.on('message', (data) => {\r\n try {\r\n const msg = parseP2PMsg(data.toString());\r\n\r\n // Send our HELLO back on incoming HELLO (bidirectional identification)\r\n if (msg.type === 'P2P_HELLO' && this.localMember) {\r\n const hello: P2PHelloMsg = {\r\n type: 'P2P_HELLO',\r\n fromTeam: this.localMember.teamName,\r\n fromMemberId: this.localMember.memberId,\r\n };\r\n ws.send(serializeP2PMsg(hello));\r\n }\r\n\r\n this.handleMessage(ws, msg);\r\n } catch (err) {\r\n console.error('Failed to parse incoming P2P message:', err);\r\n }\r\n });\r\n\r\n ws.on('close', () => {\r\n const team = this.wsToTeam.get(ws);\r\n if (team) {\r\n if (this.peerConns.get(team) === ws) {\r\n this.peerConns.delete(team);\r\n }\r\n this.wsToTeam.delete(ws);\r\n }\r\n });\r\n });\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: unified message handler\r\n // ---------------------------------------------------------------------------\r\n\r\n private handleMessage(ws: WebSocket, msg: P2PMsg): void {\r\n // Dispatch to all pending response handlers first\r\n for (const handler of this.pendingHandlers) {\r\n handler(msg);\r\n }\r\n\r\n switch (msg.type) {\r\n case 'P2P_HELLO':\r\n this.wsToTeam.set(ws, msg.fromTeam);\r\n this.peerConns.set(msg.fromTeam, ws);\r\n console.error(`Peer identified: ${msg.fromTeam}`);\r\n break;\r\n\r\n case 'P2P_ASK':\r\n this.handleIncomingAsk(ws, msg);\r\n break;\r\n\r\n case 'P2P_GET_ANSWER':\r\n this.handleGetAnswer(ws, msg);\r\n break;\r\n\r\n case 'P2P_ANSWER':\r\n // Push answer received for a question WE asked\r\n if (!this.receivedAnswers.has(msg.questionId)) {\r\n this.receivedAnswers.set(msg.questionId, {\r\n content: msg.content,\r\n format: msg.format,\r\n answeredAt: msg.answeredAt,\r\n fromTeam: msg.fromTeam,\r\n fromMemberId: msg.fromMemberId,\r\n });\r\n }\r\n break;\r\n\r\n case 'P2P_PING':\r\n ws.send(serializeP2PMsg({ type: 'P2P_PONG' }));\r\n break;\r\n\r\n // P2P_ASK_ACK, P2P_ANSWER_PENDING, P2P_PONG, P2P_ERROR\r\n // are handled by pendingHandlers above; no extra action needed here.\r\n }\r\n }\r\n\r\n private handleIncomingAsk(ws: WebSocket, msg: P2PAskMsg): void {\r\n this.incomingQuestions.set(msg.questionId, {\r\n questionId: msg.questionId,\r\n fromTeam: msg.fromTeam,\r\n fromMemberId: msg.fromMemberId,\r\n content: msg.content,\r\n format: msg.format,\r\n createdAt: new Date(),\r\n ws,\r\n answered: false,\r\n });\r\n\r\n // Inject into the terminal so Claude Code can auto-reply\r\n injectionQueue.enqueue({\r\n questionId: msg.questionId,\r\n from: {\r\n displayName: `${msg.fromTeam} Claude`,\r\n teamName: msg.fromTeam,\r\n },\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 // ACK\r\n const ack: P2PAskAckMsg = {\r\n type: 'P2P_ASK_ACK',\r\n questionId: msg.questionId,\r\n requestId: msg.requestId,\r\n };\r\n ws.send(serializeP2PMsg(ack));\r\n }\r\n\r\n private handleGetAnswer(ws: WebSocket, msg: P2PGetAnswerMsg): void {\r\n const question = this.incomingQuestions.get(msg.questionId);\r\n\r\n if (!question?.answered) {\r\n const pending: P2PAnswerPendingMsg = {\r\n type: 'P2P_ANSWER_PENDING',\r\n questionId: msg.questionId,\r\n requestId: msg.requestId,\r\n };\r\n ws.send(serializeP2PMsg(pending));\r\n return;\r\n }\r\n\r\n const answer: P2PAnswerMsg = {\r\n type: 'P2P_ANSWER',\r\n questionId: msg.questionId,\r\n content: question.answerContent!,\r\n format: question.answerFormat!,\r\n answeredAt: new Date().toISOString(),\r\n fromTeam: this.localMember!.teamName,\r\n fromMemberId: this.localMember!.memberId,\r\n requestId: msg.requestId,\r\n };\r\n ws.send(serializeP2PMsg(answer));\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: peer connection management\r\n // ---------------------------------------------------------------------------\r\n\r\n private async getPeerConnection(teamName: string): Promise<WebSocket> {\r\n const existing = this.peerConns.get(teamName);\r\n if (existing && existing.readyState === WebSocket.OPEN) {\r\n return existing;\r\n }\r\n\r\n throw new Error(\r\n `No connection to team '${teamName}'. Use the connect_peer tool to connect first.`\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('P2P 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 * Join Tool\r\n * Joins a team channel for collaboration\r\n * @module presentation/mcp/tools/join\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\n/**\r\n * Join tool input schema\r\n */\r\nconst joinSchema = {\r\n team: z.string().describe('Team name to join (e.g., \"frontend\", \"backend\", \"devops\")'),\r\n displayName: z\r\n .string()\r\n .optional()\r\n .describe('Display name for this terminal (default: team + \" Claude\")'),\r\n};\r\n\r\n/**\r\n * Registers the join tool with the MCP server\r\n */\r\nexport function registerJoinTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('join', joinSchema, async (args) => {\r\n const teamName = args.team;\r\n const displayName = args.displayName ?? `${teamName} Claude`;\r\n\r\n try {\r\n const member = await client.join(teamName, displayName);\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Successfully joined team \"${member.teamName}\" as \"${member.displayName}\".\\n\\nYour member ID: ${member.memberId}\\nTeam ID: ${member.teamId}\\nStatus: ${member.status}`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to join team: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Connect Peer Tool\r\n * Manually connects to a peer node by IP address\r\n * @module presentation/mcp/tools/connect-peer\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 { config } from '../../../config/index.js';\r\n\r\nconst connectPeerSchema = {\r\n ip: z.string().describe('IP address of the peer to connect to (e.g., \"172.16.40.137\")'),\r\n port: z\r\n .number()\r\n .optional()\r\n .describe(`Port the peer is listening on (default: ${config.p2p.port})`),\r\n};\r\n\r\nexport function registerConnectPeerTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('connect_peer', connectPeerSchema, async (args) => {\r\n const targetPort = args.port ?? config.p2p.port;\r\n\r\n try {\r\n const peerTeam = await client.connectPeer(args.ip, args.port);\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Connected to peer \"${peerTeam}\" at ${args.ip}:${targetPort}.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to connect to ${args.ip}:${targetPort}: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Ask Tool\r\n * Sends a question to another team and returns a question ID immediately.\r\n * Use the \"check_answer\" tool with the question ID to retrieve the answer later.\r\n * @module presentation/mcp/tools/ask\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\n/**\r\n * Ask tool input schema\r\n */\r\nconst askSchema = {\r\n team: z.string().describe('Target team name to ask (e.g., \"backend\", \"frontend\")'),\r\n question: z.string().describe('The question to ask (supports markdown)'),\r\n};\r\n\r\n/**\r\n * Registers the ask tool with the MCP server\r\n */\r\nexport function registerAskTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('ask', askSchema, async (args) => {\r\n const targetTeam = args.team;\r\n const question = args.question;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n const questionId = await client.ask(targetTeam, question, 'markdown');\r\n\r\n // Poll until answer arrives (max 5 minutes, every 5 seconds)\r\n const POLL_INTERVAL_MS = 5_000;\r\n const MAX_WAIT_MS = 5 * 60 * 1000;\r\n const deadline = Date.now() + MAX_WAIT_MS;\r\n\r\n while (Date.now() < deadline) {\r\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\r\n const answer = await client.checkAnswer(questionId);\r\n if (answer !== null) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `**${answer.from.displayName} (${answer.from.teamName}) cevapladı:**\\n\\n${answer.content}`,\r\n },\r\n ],\r\n };\r\n }\r\n }\r\n\r\n // Timed out — return question ID for manual follow-up\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Soru gönderildi ancak 5 dakika içinde cevap gelmedi.\\nQuestion ID: \\`${questionId}\\`\\n\\nManuel kontrol için \"check_answer\" tool'unu kullanabilirsin.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to send question: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Check Answer Tool\r\n * Checks if an answer has arrived for a previously sent question.\r\n * Returns the answer if available, or a \"still pending\" message.\r\n * @module presentation/mcp/tools/check\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\n/**\r\n * Check answer tool input schema\r\n */\r\nconst checkAnswerSchema = {\r\n question_id: z.string().describe('The question ID returned by the \"ask\" tool'),\r\n};\r\n\r\n/**\r\n * Registers the check_answer tool with the MCP server\r\n */\r\nexport function registerCheckAnswerTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('check_answer', checkAnswerSchema, async (args) => {\r\n const questionId = args.question_id;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n const answer = await client.checkAnswer(questionId);\r\n\r\n if (!answer) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `No answer yet for question \\`${questionId}\\`. The other team hasn't replied yet. You can continue working and check again later.`,\r\n },\r\n ],\r\n };\r\n }\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `**Answer from ${answer.from.displayName} (${answer.from.teamName}):**\\n\\n${answer.content}`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to check answer: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Inbox Tool\r\n * Lists pending questions directed to the current team\r\n * @module presentation/mcp/tools/inbox\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\n/**\r\n * Inbox tool input schema (no required parameters)\r\n */\r\nconst inboxSchema = {};\r\n\r\n/**\r\n * Registers the inbox tool with the MCP server\r\n */\r\nexport function registerInboxTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('inbox', inboxSchema, async () => {\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n const inbox = await client.getInbox();\r\n\r\n if (inbox.questions.length === 0) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'No pending questions in your inbox.',\r\n },\r\n ],\r\n };\r\n }\r\n\r\n const questionsList = inbox.questions\r\n .map((q, i) => {\r\n const ageSeconds = Math.floor(q.ageMs / 1000);\r\n const ageStr = ageSeconds < 60 ? `${ageSeconds}s ago` : `${Math.floor(ageSeconds / 60)}m ago`;\r\n\r\n return `### ${i + 1}. Question from ${q.from.displayName} (${q.from.teamName}) - ${ageStr}\r\n**ID:** \\`${q.questionId}\\`\r\n**Status:** ${q.status}\r\n\r\n${q.content}\r\n\r\n---`;\r\n })\r\n .join('\\n\\n');\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `# Inbox (${inbox.pendingCount} pending, ${inbox.totalCount} total)\\n\\n${questionsList}\\n\\nUse the \"reply\" tool with the question ID to answer a question.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to get inbox: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Reply Tool\r\n * Replies to a pending question\r\n * @module presentation/mcp/tools/reply\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { injectionQueue } from '../../../infrastructure/terminal-injector/injection-queue.js';\r\n\r\n/**\r\n * Reply tool input schema\r\n */\r\nconst replySchema = {\r\n questionId: z.string().describe('The ID of the question to reply to (from inbox)'),\r\n answer: z.string().describe('Your answer to the question (supports markdown)'),\r\n};\r\n\r\n/**\r\n * Registers the reply tool with the MCP server\r\n */\r\nexport function registerReplyTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('reply', replySchema, async (args) => {\r\n const questionId = args.questionId;\r\n const answer = args.answer;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n await client.reply(questionId, answer, 'markdown');\r\n\r\n // Signal queue: this question is done, process next\r\n injectionQueue.notifyReplied();\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Reply sent successfully to question \\`${questionId}\\`.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to send reply: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * MCP Server\r\n * Provides MCP tools for Claude Code integration\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 { registerJoinTool } from './tools/join.tool.js';\r\nimport { registerConnectPeerTool } from './tools/connect-peer.tool.js';\r\nimport { registerAskTool } from './tools/ask.tool.js';\r\nimport { registerCheckAnswerTool } from './tools/check.tool.js';\r\nimport { registerInboxTool } from './tools/inbox.tool.js';\r\nimport { registerReplyTool } from './tools/reply.tool.js';\r\n\r\n/**\r\n * MCP Server options\r\n */\r\nexport interface McpServerOptions {\r\n client: ICollabClient;\r\n}\r\n\r\n/**\r\n * Creates and configures the MCP server with all tools\r\n */\r\nexport function createMcpServer(options: McpServerOptions): McpServer {\r\n const { client } = options;\r\n\r\n const server = new McpServer(\r\n {\r\n name: 'claude-collab',\r\n version: '0.1.2',\r\n },\r\n {\r\n capabilities: {\r\n resources: {\r\n subscribe: true,\r\n listChanged: true,\r\n },\r\n },\r\n }\r\n );\r\n\r\n // Register all tools\r\n registerJoinTool(server, client);\r\n registerConnectPeerTool(server, client);\r\n registerAskTool(server, client);\r\n registerCheckAnswerTool(server, client);\r\n registerInboxTool(server, client);\r\n registerReplyTool(server, client);\r\n\r\n // Register resource handlers\r\n server.resource(\r\n 'inbox-questions',\r\n 'inbox://questions',\r\n { description: 'Your inbox of pending questions from other teams', mimeType: 'application/json' },\r\n async () => {\r\n try {\r\n const inbox = await client.getInbox();\r\n return {\r\n contents: [\r\n {\r\n uri: 'inbox://questions',\r\n mimeType: 'application/json',\r\n text: JSON.stringify(inbox, null, 2),\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n throw new Error(`Failed to read inbox: ${errorMessage}`);\r\n }\r\n }\r\n );\r\n\r\n return server;\r\n}\r\n\r\n/**\r\n * Starts the MCP server with stdio transport\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\r\n * Provides command-line interface for claude-collab (P2P mode)\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('Real-time P2P team collaboration between Claude Code terminals')\r\n .version('0.1.0');\r\n\r\n// Client command\r\nprogram\r\n .command('client')\r\n .description('Start MCP client (P2P mode, connects to Claude Code)')\r\n .action(async () => {\r\n const p2pNode = new P2PNode();\r\n\r\n try {\r\n await p2pNode.start();\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n console.error(`Failed to start P2P node: ${errorMessage}`);\r\n process.exit(1);\r\n }\r\n\r\n await startMcpServer({ client: p2pNode });\r\n });\r\n\r\nprogram.parse();\r\n"]}
1
+ {"version":3,"sources":["../src/infrastructure/p2p/p2p-message-protocol.ts","../src/infrastructure/terminal-injector/windows-injector.ts","../src/infrastructure/terminal-injector/index.ts","../src/infrastructure/terminal-injector/injection-queue.ts","../src/config/index.ts","../src/infrastructure/p2p/p2p-node.ts","../src/presentation/mcp/tools/join.tool.ts","../src/presentation/mcp/tools/connect-peer.tool.ts","../src/presentation/mcp/tools/get-info.tool.ts","../src/presentation/mcp/tools/ask.tool.ts","../src/presentation/mcp/tools/check.tool.ts","../src/presentation/mcp/tools/inbox.tool.ts","../src/presentation/mcp/tools/reply.tool.ts","../src/presentation/mcp/server.ts","../src/cli.ts"],"names":["uuidv4","z"],"mappings":"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","file":"cli.js","sourcesContent":["/**\r\n * P2P Wire Message Protocol\r\n * Defines messages exchanged directly between P2P nodes.\r\n * @module infrastructure/p2p/p2p-message-protocol\r\n */\r\n\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\n\r\n// First message sent by the connecting peer to identify itself\r\nexport interface P2PHelloMsg {\r\n type: 'P2P_HELLO';\r\n fromTeam: string;\r\n fromMemberId: string;\r\n}\r\n\r\n// Questioner → Answerer: send a question\r\nexport interface P2PAskMsg {\r\n type: 'P2P_ASK';\r\n questionId: string;\r\n fromMemberId: string;\r\n fromTeam: string;\r\n toTeam: string;\r\n content: string;\r\n format: MessageFormat;\r\n requestId: string;\r\n}\r\n\r\n// Answerer → Questioner: acknowledge the question\r\nexport interface P2PAskAckMsg {\r\n type: 'P2P_ASK_ACK';\r\n questionId: string;\r\n requestId: string;\r\n}\r\n\r\n// Questioner → Answerer: poll for answer\r\nexport interface P2PGetAnswerMsg {\r\n type: 'P2P_GET_ANSWER';\r\n questionId: string;\r\n requestId: string;\r\n}\r\n\r\n// Answerer → Questioner: deliver the answer (push or in response to GET_ANSWER)\r\nexport interface P2PAnswerMsg {\r\n type: 'P2P_ANSWER';\r\n questionId: string;\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n fromTeam: string;\r\n fromMemberId: string;\r\n requestId?: string;\r\n}\r\n\r\n// Answerer → Questioner: answer not ready yet\r\nexport interface P2PAnswerPendingMsg {\r\n type: 'P2P_ANSWER_PENDING';\r\n questionId: string;\r\n requestId: string;\r\n}\r\n\r\nexport interface P2PPingMsg {\r\n type: 'P2P_PING';\r\n}\r\n\r\nexport interface P2PPongMsg {\r\n type: 'P2P_PONG';\r\n}\r\n\r\nexport interface P2PErrorMsg {\r\n type: 'P2P_ERROR';\r\n code: string;\r\n message: string;\r\n}\r\n\r\nexport type P2PMsg =\r\n | P2PHelloMsg\r\n | P2PAskMsg\r\n | P2PAskAckMsg\r\n | P2PGetAnswerMsg\r\n | P2PAnswerMsg\r\n | P2PAnswerPendingMsg\r\n | P2PPingMsg\r\n | P2PPongMsg\r\n | P2PErrorMsg;\r\n\r\nexport function serializeP2PMsg(msg: P2PMsg): string {\r\n return JSON.stringify(msg);\r\n}\r\n\r\nexport function parseP2PMsg(data: string): P2PMsg {\r\n return JSON.parse(data) as P2PMsg;\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 * Configuration module\r\n * @module config\r\n */\r\n\r\n/**\r\n * Application configuration\r\n */\r\nexport const config = {\r\n /**\r\n * P2P node configuration\r\n */\r\n p2p: {\r\n /**\r\n * Port range for the WS server. Override with CLAUDE_COLLAB_PORT_MIN / MAX env vars.\r\n */\r\n portRangeMin: Number(process.env['CLAUDE_COLLAB_PORT_MIN'] ?? 11700),\r\n portRangeMax: Number(process.env['CLAUDE_COLLAB_PORT_MAX'] ?? 11750),\r\n },\r\n\r\n /**\r\n * Communication configuration\r\n */\r\n communication: {\r\n /**\r\n * Default timeout for waiting for an answer (in milliseconds)\r\n */\r\n defaultTimeout: 30000,\r\n\r\n /**\r\n * Maximum message content length\r\n */\r\n maxMessageLength: 50000,\r\n },\r\n} as const;\r\n\r\nexport type Config = typeof config;\r\n","/**\r\n * P2PNode\r\n * Implements ICollabClient using a peer-to-peer WebSocket architecture.\r\n * Each node runs its own WS server on a fixed port; peers are connected\r\n * manually via connectPeer().\r\n * @module infrastructure/p2p/p2p-node\r\n */\r\n\r\nimport { WebSocketServer, WebSocket } 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} 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 P2PAskMsg,\r\n type P2PAskAckMsg,\r\n type P2PGetAnswerMsg,\r\n type P2PAnswerMsg,\r\n type P2PAnswerPendingMsg,\r\n type P2PHelloMsg,\r\n serializeP2PMsg,\r\n parseP2PMsg,\r\n} from './p2p-message-protocol.js';\r\nimport { injectionQueue } from '../terminal-injector/injection-queue.js';\r\nimport { config } from '../../config/index.js';\r\n\r\ninterface IncomingQuestion {\r\n questionId: string;\r\n fromTeam: string;\r\n fromMemberId: string;\r\n content: string;\r\n format: MessageFormat;\r\n createdAt: Date;\r\n ws: WebSocket;\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 fromTeam: string;\r\n fromMemberId: string;\r\n}\r\n\r\ninterface LocalMember {\r\n memberId: string;\r\n teamName: string;\r\n displayName: string;\r\n}\r\n\r\nexport class P2PNode implements ICollabClient {\r\n private wss: WebSocketServer | null = null;\r\n private port = 0;\r\n\r\n // Connections indexed by remote team name\r\n private readonly peerConns = new Map<string, WebSocket>();\r\n // Reverse lookup: ws → teamName (for cleanup)\r\n private readonly wsToTeam = new Map<WebSocket, string>();\r\n\r\n // Questions we received from remote peers (our inbox)\r\n private readonly incomingQuestions = new Map<string, IncomingQuestion>();\r\n\r\n // Answers we received for questions we asked\r\n private readonly receivedAnswers = new Map<string, ReceivedAnswer>();\r\n\r\n // Maps questionId → remote teamName (so we know who to poll)\r\n private readonly questionToTeam = new Map<string, string>();\r\n\r\n // Pending response handlers (request-response correlation by filter)\r\n private readonly pendingHandlers = new Set<(msg: P2PMsg) => void>();\r\n\r\n private localMember: LocalMember | null = null;\r\n private _isStarted = false;\r\n\r\n get isConnected(): boolean {\r\n return this._isStarted;\r\n }\r\n\r\n get currentTeamId(): string | undefined {\r\n return this.localMember?.teamName;\r\n }\r\n\r\n /**\r\n * Starts the WS server on a random available port within the configured range.\r\n * Called automatically from join() if not yet started.\r\n */\r\n async start(): Promise<void> {\r\n const { portRangeMin, portRangeMax } = config.p2p;\r\n const range = portRangeMax - portRangeMin + 1;\r\n const startOffset = Math.floor(Math.random() * range);\r\n\r\n for (let i = 0; i < range; i++) {\r\n const port = portRangeMin + ((startOffset + i) % range);\r\n const bound = await this.tryBind(port);\r\n if (bound) {\r\n this.port = port;\r\n break;\r\n }\r\n }\r\n\r\n if (!this.wss) {\r\n throw new Error(\r\n `No available port in range ${portRangeMin}-${portRangeMax}. ` +\r\n `Override with CLAUDE_COLLAB_PORT_MIN / CLAUDE_COLLAB_PORT_MAX.`\r\n );\r\n }\r\n\r\n this.setupWssHandlers();\r\n this._isStarted = true;\r\n console.error(`P2P node started on port ${this.port}`);\r\n }\r\n\r\n private tryBind(port: number): Promise<boolean> {\r\n return new Promise((resolve) => {\r\n const wss = new WebSocketServer({ port });\r\n wss.once('listening', () => {\r\n this.wss = wss;\r\n resolve(true);\r\n });\r\n wss.once('error', () => resolve(false));\r\n });\r\n }\r\n\r\n async join(teamName: string, displayName: string): Promise<JoinResult> {\r\n if (!this._isStarted) {\r\n await this.start();\r\n }\r\n\r\n const memberId = uuidv4();\r\n this.localMember = { memberId, teamName, displayName };\r\n\r\n return { memberId, teamId: teamName, teamName, displayName, status: 'ONLINE', port: this.port };\r\n }\r\n\r\n /**\r\n * Connects to a peer at the given IP and port.\r\n * Performs a bidirectional HELLO handshake and returns the peer's team name.\r\n */\r\n async connectPeer(ip: string, port: number): Promise<string> {\r\n if (!this.localMember) {\r\n throw new Error('Must call join() before connectPeer()');\r\n }\r\n\r\n const ws = new WebSocket(`ws://${ip}:${port}`);\r\n\r\n // Set up persistent message handler\r\n ws.on('message', (data) => {\r\n try {\r\n const msg = parseP2PMsg(data.toString());\r\n this.handleMessage(ws, msg);\r\n } catch (err) {\r\n console.error('Failed to parse P2P message:', err);\r\n }\r\n });\r\n\r\n ws.on('close', () => {\r\n const team = this.wsToTeam.get(ws);\r\n if (team) {\r\n if (this.peerConns.get(team) === ws) {\r\n this.peerConns.delete(team);\r\n }\r\n this.wsToTeam.delete(ws);\r\n }\r\n });\r\n\r\n // Connect and send our HELLO\r\n await new Promise<void>((resolve, reject) => {\r\n const timeout = setTimeout(\r\n () => reject(new Error(`Connection timeout to ${ip}:${port}`)),\r\n 5000\r\n );\r\n\r\n ws.on('open', () => {\r\n clearTimeout(timeout);\r\n const hello: P2PHelloMsg = {\r\n type: 'P2P_HELLO',\r\n fromTeam: this.localMember!.teamName,\r\n fromMemberId: this.localMember!.memberId,\r\n };\r\n ws.send(serializeP2PMsg(hello));\r\n resolve();\r\n });\r\n\r\n ws.on('error', (err) => {\r\n clearTimeout(timeout);\r\n reject(err);\r\n });\r\n });\r\n\r\n // Wait for their HELLO back to identify their team name\r\n const helloMsg = await this.waitForResponse<P2PHelloMsg>(\r\n (m) => m.type === 'P2P_HELLO',\r\n 10000\r\n );\r\n\r\n return helloMsg.fromTeam;\r\n }\r\n\r\n async ask(toTeam: string, content: string, format: MessageFormat): Promise<string> {\r\n const ws = await this.getPeerConnection(toTeam);\r\n const questionId = uuidv4();\r\n const requestId = uuidv4();\r\n\r\n this.questionToTeam.set(questionId, toTeam);\r\n\r\n // Register handler before sending (avoids race where ACK arrives first)\r\n const ackPromise = this.waitForResponse<P2PAskAckMsg>(\r\n (m) => m.type === 'P2P_ASK_ACK' && m.requestId === requestId,\r\n 5000\r\n );\r\n\r\n const msg: P2PAskMsg = {\r\n type: 'P2P_ASK',\r\n questionId,\r\n fromMemberId: this.localMember!.memberId,\r\n fromTeam: this.localMember!.teamName,\r\n toTeam,\r\n content,\r\n format,\r\n requestId,\r\n };\r\n ws.send(serializeP2PMsg(msg));\r\n\r\n await ackPromise;\r\n return questionId;\r\n }\r\n\r\n async checkAnswer(questionId: string): Promise<CheckAnswerResult | null> {\r\n // Check local cache first (populated by push from remote)\r\n const cached = this.receivedAnswers.get(questionId);\r\n if (cached) {\r\n return {\r\n questionId,\r\n from: { displayName: `${cached.fromTeam} Claude`, teamName: cached.fromTeam },\r\n content: cached.content,\r\n format: cached.format,\r\n answeredAt: cached.answeredAt,\r\n };\r\n }\r\n\r\n // Poll the remote peer\r\n const toTeam = this.questionToTeam.get(questionId);\r\n if (!toTeam) return null;\r\n\r\n const ws = this.peerConns.get(toTeam);\r\n if (!ws || ws.readyState !== WebSocket.OPEN) return null;\r\n\r\n const requestId = uuidv4();\r\n\r\n const responsePromise = this.waitForResponse<P2PAnswerMsg | P2PAnswerPendingMsg>(\r\n (m) =>\r\n (m.type === 'P2P_ANSWER' && m.questionId === questionId) ||\r\n (m.type === 'P2P_ANSWER_PENDING' && m.requestId === requestId),\r\n 5000\r\n );\r\n\r\n const getMsg: P2PGetAnswerMsg = {\r\n type: 'P2P_GET_ANSWER',\r\n questionId,\r\n requestId,\r\n };\r\n ws.send(serializeP2PMsg(getMsg));\r\n\r\n const response = await responsePromise;\r\n if (response.type === 'P2P_ANSWER_PENDING') return null;\r\n\r\n const answer = response as P2PAnswerMsg;\r\n this.receivedAnswers.set(questionId, {\r\n content: answer.content,\r\n format: answer.format,\r\n answeredAt: answer.answeredAt,\r\n fromTeam: answer.fromTeam,\r\n fromMemberId: answer.fromMemberId,\r\n });\r\n\r\n return {\r\n questionId,\r\n from: { displayName: `${answer.fromTeam} Claude`, teamName: answer.fromTeam },\r\n content: answer.content,\r\n format: answer.format,\r\n answeredAt: answer.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 in inbox`);\r\n\r\n question.answered = true;\r\n question.answerContent = content;\r\n question.answerFormat = format;\r\n\r\n const answerMsg: P2PAnswerMsg = {\r\n type: 'P2P_ANSWER',\r\n questionId,\r\n content,\r\n format,\r\n answeredAt: new Date().toISOString(),\r\n fromTeam: this.localMember!.teamName,\r\n fromMemberId: this.localMember!.memberId,\r\n };\r\n\r\n if (question.ws.readyState === WebSocket.OPEN) {\r\n question.ws.send(serializeP2PMsg(answerMsg));\r\n }\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.fromTeam} Claude`, teamName: q.fromTeam },\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\r\n return {\r\n questions,\r\n totalCount: questions.length,\r\n pendingCount: questions.length,\r\n };\r\n }\r\n\r\n getInfo(): NodeInfo {\r\n return {\r\n teamName: this.localMember?.teamName,\r\n port: this._isStarted ? this.port : undefined,\r\n connectedPeers: [...this.peerConns.keys()],\r\n };\r\n }\r\n\r\n async disconnect(): Promise<void> {\r\n for (const ws of this.peerConns.values()) {\r\n ws.close();\r\n }\r\n this.peerConns.clear();\r\n\r\n await new Promise<void>((resolve) => {\r\n if (this.wss) {\r\n this.wss.close(() => resolve());\r\n } else {\r\n resolve();\r\n }\r\n });\r\n\r\n this._isStarted = false;\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: WebSocket server setup\r\n // ---------------------------------------------------------------------------\r\n\r\n private setupWssHandlers(): void {\r\n this.wss!.on('connection', (ws) => {\r\n ws.on('message', (data) => {\r\n try {\r\n const msg = parseP2PMsg(data.toString());\r\n\r\n // Send our HELLO back on incoming HELLO (bidirectional identification)\r\n if (msg.type === 'P2P_HELLO' && this.localMember) {\r\n const hello: P2PHelloMsg = {\r\n type: 'P2P_HELLO',\r\n fromTeam: this.localMember.teamName,\r\n fromMemberId: this.localMember.memberId,\r\n };\r\n ws.send(serializeP2PMsg(hello));\r\n }\r\n\r\n this.handleMessage(ws, msg);\r\n } catch (err) {\r\n console.error('Failed to parse incoming P2P message:', err);\r\n }\r\n });\r\n\r\n ws.on('close', () => {\r\n const team = this.wsToTeam.get(ws);\r\n if (team) {\r\n if (this.peerConns.get(team) === ws) {\r\n this.peerConns.delete(team);\r\n }\r\n this.wsToTeam.delete(ws);\r\n }\r\n });\r\n });\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: unified message handler\r\n // ---------------------------------------------------------------------------\r\n\r\n private handleMessage(ws: WebSocket, msg: P2PMsg): void {\r\n // Dispatch to all pending response handlers first\r\n for (const handler of this.pendingHandlers) {\r\n handler(msg);\r\n }\r\n\r\n switch (msg.type) {\r\n case 'P2P_HELLO':\r\n this.wsToTeam.set(ws, msg.fromTeam);\r\n this.peerConns.set(msg.fromTeam, ws);\r\n console.error(`Peer identified: ${msg.fromTeam}`);\r\n break;\r\n\r\n case 'P2P_ASK':\r\n this.handleIncomingAsk(ws, msg);\r\n break;\r\n\r\n case 'P2P_GET_ANSWER':\r\n this.handleGetAnswer(ws, msg);\r\n break;\r\n\r\n case 'P2P_ANSWER':\r\n // Push answer received for a question WE asked\r\n if (!this.receivedAnswers.has(msg.questionId)) {\r\n this.receivedAnswers.set(msg.questionId, {\r\n content: msg.content,\r\n format: msg.format,\r\n answeredAt: msg.answeredAt,\r\n fromTeam: msg.fromTeam,\r\n fromMemberId: msg.fromMemberId,\r\n });\r\n }\r\n break;\r\n\r\n case 'P2P_PING':\r\n ws.send(serializeP2PMsg({ type: 'P2P_PONG' }));\r\n break;\r\n\r\n // P2P_ASK_ACK, P2P_ANSWER_PENDING, P2P_PONG, P2P_ERROR\r\n // are handled by pendingHandlers above; no extra action needed here.\r\n }\r\n }\r\n\r\n private handleIncomingAsk(ws: WebSocket, msg: P2PAskMsg): void {\r\n this.incomingQuestions.set(msg.questionId, {\r\n questionId: msg.questionId,\r\n fromTeam: msg.fromTeam,\r\n fromMemberId: msg.fromMemberId,\r\n content: msg.content,\r\n format: msg.format,\r\n createdAt: new Date(),\r\n ws,\r\n answered: false,\r\n });\r\n\r\n // Inject into the terminal so Claude Code can auto-reply\r\n injectionQueue.enqueue({\r\n questionId: msg.questionId,\r\n from: {\r\n displayName: `${msg.fromTeam} Claude`,\r\n teamName: msg.fromTeam,\r\n },\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 // ACK\r\n const ack: P2PAskAckMsg = {\r\n type: 'P2P_ASK_ACK',\r\n questionId: msg.questionId,\r\n requestId: msg.requestId,\r\n };\r\n ws.send(serializeP2PMsg(ack));\r\n }\r\n\r\n private handleGetAnswer(ws: WebSocket, msg: P2PGetAnswerMsg): void {\r\n const question = this.incomingQuestions.get(msg.questionId);\r\n\r\n if (!question?.answered) {\r\n const pending: P2PAnswerPendingMsg = {\r\n type: 'P2P_ANSWER_PENDING',\r\n questionId: msg.questionId,\r\n requestId: msg.requestId,\r\n };\r\n ws.send(serializeP2PMsg(pending));\r\n return;\r\n }\r\n\r\n const answer: P2PAnswerMsg = {\r\n type: 'P2P_ANSWER',\r\n questionId: msg.questionId,\r\n content: question.answerContent!,\r\n format: question.answerFormat!,\r\n answeredAt: new Date().toISOString(),\r\n fromTeam: this.localMember!.teamName,\r\n fromMemberId: this.localMember!.memberId,\r\n requestId: msg.requestId,\r\n };\r\n ws.send(serializeP2PMsg(answer));\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: peer connection management\r\n // ---------------------------------------------------------------------------\r\n\r\n private async getPeerConnection(teamName: string): Promise<WebSocket> {\r\n const existing = this.peerConns.get(teamName);\r\n if (existing && existing.readyState === WebSocket.OPEN) {\r\n return existing;\r\n }\r\n\r\n throw new Error(\r\n `No connection to team '${teamName}'. Use the connect_peer tool to connect first.`\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('P2P 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 * Join Tool\r\n * Joins a team channel for collaboration\r\n * @module presentation/mcp/tools/join\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\n/**\r\n * Join tool input schema\r\n */\r\nconst joinSchema = {\r\n team: z.string().describe('Team name to join (e.g., \"frontend\", \"backend\", \"devops\")'),\r\n displayName: z\r\n .string()\r\n .optional()\r\n .describe('Display name for this terminal (default: team + \" Claude\")'),\r\n};\r\n\r\n/**\r\n * Registers the join tool with the MCP server\r\n */\r\nexport function registerJoinTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('join', joinSchema, async (args) => {\r\n const teamName = args.team;\r\n const displayName = args.displayName ?? `${teamName} Claude`;\r\n\r\n try {\r\n const member = await client.join(teamName, displayName);\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Successfully joined team \"${member.teamName}\" as \"${member.displayName}\".\\n\\nYour member ID: ${member.memberId}\\nStatus: ${member.status}\\nListening on port: ${member.port}\\n\\nShare this port with the other terminal so they can run: connect_peer(\"<your-ip>\", ${member.port})`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to join team: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Connect Peer Tool\r\n * Manually connects to a peer node by IP address and port\r\n * @module presentation/mcp/tools/connect-peer\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 connectPeerSchema = {\r\n ip: z.string().describe('IP address of the peer to connect to (e.g., \"172.16.40.137\")'),\r\n port: z.number().describe('Port the peer is listening on (shown in their join response)'),\r\n};\r\n\r\nexport function registerConnectPeerTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('connect_peer', connectPeerSchema, async (args) => {\r\n try {\r\n const peerTeam = await client.connectPeer(args.ip, args.port);\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Connected to peer \"${peerTeam}\" at ${args.ip}:${args.port}.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to connect to ${args.ip}:${args.port}: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Get Info Tool\r\n * Returns local node info: team, port, IPs, connected peers\r\n * @module presentation/mcp/tools/get-info\r\n */\r\n\r\nimport { networkInterfaces } from 'os';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\nfunction getLocalIPs(): string[] {\r\n const ips: string[] = [];\r\n for (const iface of Object.values(networkInterfaces())) {\r\n for (const net of iface ?? []) {\r\n if (net.family === 'IPv4' && !net.internal) {\r\n ips.push(net.address);\r\n }\r\n }\r\n }\r\n return ips;\r\n}\r\n\r\nexport function registerGetInfoTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('get_info', {}, async () => {\r\n const info = client.getInfo();\r\n const ips = getLocalIPs();\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`Team: ${info.teamName ?? '(not joined yet)'}`);\r\n lines.push(`Port: ${info.port ?? '(not started yet)'}`);\r\n lines.push(`Local IPs: ${ips.length > 0 ? ips.join(', ') : '(none found)'}`);\r\n\r\n if (info.connectedPeers.length > 0) {\r\n lines.push(`Connected peers: ${info.connectedPeers.join(', ')}`);\r\n } else {\r\n lines.push(`Connected peers: (none)`);\r\n }\r\n\r\n if (info.port && ips.length > 0) {\r\n lines.push(`\\nOther terminal can connect with:\\n connect_peer(\"${ips[0]}\", ${info.port})`);\r\n }\r\n\r\n return {\r\n content: [{ type: 'text', text: lines.join('\\n') }],\r\n };\r\n });\r\n}\r\n","/**\r\n * Ask Tool\r\n * Sends a question to another team and returns a question ID immediately.\r\n * Use the \"check_answer\" tool with the question ID to retrieve the answer later.\r\n * @module presentation/mcp/tools/ask\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\n/**\r\n * Ask tool input schema\r\n */\r\nconst askSchema = {\r\n team: z.string().describe('Target team name to ask (e.g., \"backend\", \"frontend\")'),\r\n question: z.string().describe('The question to ask (supports markdown)'),\r\n};\r\n\r\n/**\r\n * Registers the ask tool with the MCP server\r\n */\r\nexport function registerAskTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('ask', askSchema, async (args) => {\r\n const targetTeam = args.team;\r\n const question = args.question;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n const questionId = await client.ask(targetTeam, question, 'markdown');\r\n\r\n // Poll until answer arrives (max 5 minutes, every 5 seconds)\r\n const POLL_INTERVAL_MS = 5_000;\r\n const MAX_WAIT_MS = 5 * 60 * 1000;\r\n const deadline = Date.now() + MAX_WAIT_MS;\r\n\r\n while (Date.now() < deadline) {\r\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\r\n const answer = await client.checkAnswer(questionId);\r\n if (answer !== null) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `**${answer.from.displayName} (${answer.from.teamName}) cevapladı:**\\n\\n${answer.content}`,\r\n },\r\n ],\r\n };\r\n }\r\n }\r\n\r\n // Timed out — return question ID for manual follow-up\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Soru gönderildi ancak 5 dakika içinde cevap gelmedi.\\nQuestion ID: \\`${questionId}\\`\\n\\nManuel kontrol için \"check_answer\" tool'unu kullanabilirsin.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to send question: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Check Answer Tool\r\n * Checks if an answer has arrived for a previously sent question.\r\n * Returns the answer if available, or a \"still pending\" message.\r\n * @module presentation/mcp/tools/check\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\n/**\r\n * Check answer tool input schema\r\n */\r\nconst checkAnswerSchema = {\r\n question_id: z.string().describe('The question ID returned by the \"ask\" tool'),\r\n};\r\n\r\n/**\r\n * Registers the check_answer tool with the MCP server\r\n */\r\nexport function registerCheckAnswerTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('check_answer', checkAnswerSchema, async (args) => {\r\n const questionId = args.question_id;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n const answer = await client.checkAnswer(questionId);\r\n\r\n if (!answer) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `No answer yet for question \\`${questionId}\\`. The other team hasn't replied yet. You can continue working and check again later.`,\r\n },\r\n ],\r\n };\r\n }\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `**Answer from ${answer.from.displayName} (${answer.from.teamName}):**\\n\\n${answer.content}`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to check answer: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Inbox Tool\r\n * Lists pending questions directed to the current team\r\n * @module presentation/mcp/tools/inbox\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\n/**\r\n * Inbox tool input schema (no required parameters)\r\n */\r\nconst inboxSchema = {};\r\n\r\n/**\r\n * Registers the inbox tool with the MCP server\r\n */\r\nexport function registerInboxTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('inbox', inboxSchema, async () => {\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n const inbox = await client.getInbox();\r\n\r\n if (inbox.questions.length === 0) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'No pending questions in your inbox.',\r\n },\r\n ],\r\n };\r\n }\r\n\r\n const questionsList = inbox.questions\r\n .map((q, i) => {\r\n const ageSeconds = Math.floor(q.ageMs / 1000);\r\n const ageStr = ageSeconds < 60 ? `${ageSeconds}s ago` : `${Math.floor(ageSeconds / 60)}m ago`;\r\n\r\n return `### ${i + 1}. Question from ${q.from.displayName} (${q.from.teamName}) - ${ageStr}\r\n**ID:** \\`${q.questionId}\\`\r\n**Status:** ${q.status}\r\n\r\n${q.content}\r\n\r\n---`;\r\n })\r\n .join('\\n\\n');\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `# Inbox (${inbox.pendingCount} pending, ${inbox.totalCount} total)\\n\\n${questionsList}\\n\\nUse the \"reply\" tool with the question ID to answer a question.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to get inbox: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Reply Tool\r\n * Replies to a pending question\r\n * @module presentation/mcp/tools/reply\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { injectionQueue } from '../../../infrastructure/terminal-injector/injection-queue.js';\r\n\r\n/**\r\n * Reply tool input schema\r\n */\r\nconst replySchema = {\r\n questionId: z.string().describe('The ID of the question to reply to (from inbox)'),\r\n answer: z.string().describe('Your answer to the question (supports markdown)'),\r\n};\r\n\r\n/**\r\n * Registers the reply tool with the MCP server\r\n */\r\nexport function registerReplyTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('reply', replySchema, async (args) => {\r\n const questionId = args.questionId;\r\n const answer = args.answer;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n await client.reply(questionId, answer, 'markdown');\r\n\r\n // Signal queue: this question is done, process next\r\n injectionQueue.notifyReplied();\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Reply sent successfully to question \\`${questionId}\\`.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to send reply: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * MCP Server\r\n * Provides MCP tools for Claude Code integration\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 { registerJoinTool } from './tools/join.tool.js';\r\nimport { registerConnectPeerTool } from './tools/connect-peer.tool.js';\r\nimport { registerGetInfoTool } from './tools/get-info.tool.js';\r\nimport { registerAskTool } from './tools/ask.tool.js';\r\nimport { registerCheckAnswerTool } from './tools/check.tool.js';\r\nimport { registerInboxTool } from './tools/inbox.tool.js';\r\nimport { registerReplyTool } from './tools/reply.tool.js';\r\n\r\n/**\r\n * MCP Server options\r\n */\r\nexport interface McpServerOptions {\r\n client: ICollabClient;\r\n}\r\n\r\n/**\r\n * Creates and configures the MCP server with all tools\r\n */\r\nexport function createMcpServer(options: McpServerOptions): McpServer {\r\n const { client } = options;\r\n\r\n const server = new McpServer(\r\n {\r\n name: 'claude-collab',\r\n version: '0.1.2',\r\n },\r\n {\r\n capabilities: {\r\n resources: {\r\n subscribe: true,\r\n listChanged: true,\r\n },\r\n },\r\n }\r\n );\r\n\r\n // Register all tools\r\n registerJoinTool(server, client);\r\n registerConnectPeerTool(server, client);\r\n registerGetInfoTool(server, client);\r\n registerAskTool(server, client);\r\n registerCheckAnswerTool(server, client);\r\n registerInboxTool(server, client);\r\n registerReplyTool(server, client);\r\n\r\n // Register resource handlers\r\n server.resource(\r\n 'inbox-questions',\r\n 'inbox://questions',\r\n { description: 'Your inbox of pending questions from other teams', mimeType: 'application/json' },\r\n async () => {\r\n try {\r\n const inbox = await client.getInbox();\r\n return {\r\n contents: [\r\n {\r\n uri: 'inbox://questions',\r\n mimeType: 'application/json',\r\n text: JSON.stringify(inbox, null, 2),\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n throw new Error(`Failed to read inbox: ${errorMessage}`);\r\n }\r\n }\r\n );\r\n\r\n return server;\r\n}\r\n\r\n/**\r\n * Starts the MCP server with stdio transport\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\r\n * Provides command-line interface for claude-collab (P2P mode)\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('Real-time P2P team collaboration between Claude Code terminals')\r\n .version('0.1.0');\r\n\r\n// Client command\r\nprogram\r\n .command('client')\r\n .description('Start MCP client (P2P mode, connects to Claude Code)')\r\n .action(async () => {\r\n const p2pNode = new P2PNode();\r\n await startMcpServer({ client: p2pNode });\r\n });\r\n\r\nprogram.parse();\r\n"]}
package/dist/mcp-main.js CHANGED
@@ -4,7 +4,7 @@ import { v4 } from 'uuid';
4
4
  import { EventEmitter } from 'events';
5
5
  import { execFile } from 'child_process';
6
6
  import { unlinkSync } from 'fs';
7
- import { tmpdir } from 'os';
7
+ import { tmpdir, networkInterfaces } from 'os';
8
8
  import { join } from 'path';
9
9
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
10
10
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
@@ -242,9 +242,10 @@ var config = {
242
242
  */
243
243
  p2p: {
244
244
  /**
245
- * Fixed port for the WS server. Override with CLAUDE_COLLAB_PORT env var.
245
+ * Port range for the WS server. Override with CLAUDE_COLLAB_PORT_MIN / MAX env vars.
246
246
  */
247
- port: Number(process.env["CLAUDE_COLLAB_PORT"] ?? 11777)
247
+ portRangeMin: Number(process.env["CLAUDE_COLLAB_PORT_MIN"] ?? 11700),
248
+ portRangeMax: Number(process.env["CLAUDE_COLLAB_PORT_MAX"] ?? 11750)
248
249
  }};
249
250
 
250
251
  // src/infrastructure/p2p/p2p-node.ts
@@ -272,23 +273,47 @@ var P2PNode = class {
272
273
  return this.localMember?.teamName;
273
274
  }
274
275
  /**
275
- * Starts the WS server on the configured fixed port.
276
+ * Starts the WS server on a random available port within the configured range.
276
277
  * Called automatically from join() if not yet started.
277
278
  */
278
279
  async start() {
279
- this.port = config.p2p.port;
280
- this.wss = new WebSocketServer({ port: this.port });
280
+ const { portRangeMin, portRangeMax } = config.p2p;
281
+ const range = portRangeMax - portRangeMin + 1;
282
+ const startOffset = Math.floor(Math.random() * range);
283
+ for (let i = 0; i < range; i++) {
284
+ const port = portRangeMin + (startOffset + i) % range;
285
+ const bound = await this.tryBind(port);
286
+ if (bound) {
287
+ this.port = port;
288
+ break;
289
+ }
290
+ }
291
+ if (!this.wss) {
292
+ throw new Error(
293
+ `No available port in range ${portRangeMin}-${portRangeMax}. Override with CLAUDE_COLLAB_PORT_MIN / CLAUDE_COLLAB_PORT_MAX.`
294
+ );
295
+ }
281
296
  this.setupWssHandlers();
282
297
  this._isStarted = true;
283
298
  console.error(`P2P node started on port ${this.port}`);
284
299
  }
300
+ tryBind(port) {
301
+ return new Promise((resolve) => {
302
+ const wss = new WebSocketServer({ port });
303
+ wss.once("listening", () => {
304
+ this.wss = wss;
305
+ resolve(true);
306
+ });
307
+ wss.once("error", () => resolve(false));
308
+ });
309
+ }
285
310
  async join(teamName, displayName) {
286
311
  if (!this._isStarted) {
287
312
  await this.start();
288
313
  }
289
314
  const memberId = v4();
290
315
  this.localMember = { memberId, teamName, displayName };
291
- return { memberId, teamId: teamName, teamName, displayName, status: "ONLINE" };
316
+ return { memberId, teamId: teamName, teamName, displayName, status: "ONLINE", port: this.port };
292
317
  }
293
318
  /**
294
319
  * Connects to a peer at the given IP and port.
@@ -298,8 +323,7 @@ var P2PNode = class {
298
323
  if (!this.localMember) {
299
324
  throw new Error("Must call join() before connectPeer()");
300
325
  }
301
- const targetPort = port ?? config.p2p.port;
302
- const ws = new WebSocket(`ws://${ip}:${targetPort}`);
326
+ const ws = new WebSocket(`ws://${ip}:${port}`);
303
327
  ws.on("message", (data) => {
304
328
  try {
305
329
  const msg = parseP2PMsg(data.toString());
@@ -319,7 +343,7 @@ var P2PNode = class {
319
343
  });
320
344
  await new Promise((resolve, reject) => {
321
345
  const timeout = setTimeout(
322
- () => reject(new Error(`Connection timeout to ${ip}:${targetPort}`)),
346
+ () => reject(new Error(`Connection timeout to ${ip}:${port}`)),
323
347
  5e3
324
348
  );
325
349
  ws.on("open", () => {
@@ -446,6 +470,13 @@ var P2PNode = class {
446
470
  pendingCount: questions.length
447
471
  };
448
472
  }
473
+ getInfo() {
474
+ return {
475
+ teamName: this.localMember?.teamName,
476
+ port: this._isStarted ? this.port : void 0,
477
+ connectedPeers: [...this.peerConns.keys()]
478
+ };
479
+ }
449
480
  async disconnect() {
450
481
  for (const ws of this.peerConns.values()) {
451
482
  ws.close();
@@ -626,8 +657,10 @@ function registerJoinTool(server, client) {
626
657
  text: `Successfully joined team "${member.teamName}" as "${member.displayName}".
627
658
 
628
659
  Your member ID: ${member.memberId}
629
- Team ID: ${member.teamId}
630
- Status: ${member.status}`
660
+ Status: ${member.status}
661
+ Listening on port: ${member.port}
662
+
663
+ Share this port with the other terminal so they can run: connect_peer("<your-ip>", ${member.port})`
631
664
  }
632
665
  ]
633
666
  };
@@ -647,18 +680,17 @@ Status: ${member.status}`
647
680
  }
648
681
  var connectPeerSchema = {
649
682
  ip: z.string().describe('IP address of the peer to connect to (e.g., "172.16.40.137")'),
650
- port: z.number().optional().describe(`Port the peer is listening on (default: ${config.p2p.port})`)
683
+ port: z.number().describe("Port the peer is listening on (shown in their join response)")
651
684
  };
652
685
  function registerConnectPeerTool(server, client) {
653
686
  server.tool("connect_peer", connectPeerSchema, async (args) => {
654
- const targetPort = args.port ?? config.p2p.port;
655
687
  try {
656
688
  const peerTeam = await client.connectPeer(args.ip, args.port);
657
689
  return {
658
690
  content: [
659
691
  {
660
692
  type: "text",
661
- text: `Connected to peer "${peerTeam}" at ${args.ip}:${targetPort}.`
693
+ text: `Connected to peer "${peerTeam}" at ${args.ip}:${args.port}.`
662
694
  }
663
695
  ]
664
696
  };
@@ -668,7 +700,7 @@ function registerConnectPeerTool(server, client) {
668
700
  content: [
669
701
  {
670
702
  type: "text",
671
- text: `Failed to connect to ${args.ip}:${targetPort}: ${errorMessage}`
703
+ text: `Failed to connect to ${args.ip}:${args.port}: ${errorMessage}`
672
704
  }
673
705
  ],
674
706
  isError: true
@@ -676,6 +708,40 @@ function registerConnectPeerTool(server, client) {
676
708
  }
677
709
  });
678
710
  }
711
+ function getLocalIPs() {
712
+ const ips = [];
713
+ for (const iface of Object.values(networkInterfaces())) {
714
+ for (const net of iface ?? []) {
715
+ if (net.family === "IPv4" && !net.internal) {
716
+ ips.push(net.address);
717
+ }
718
+ }
719
+ }
720
+ return ips;
721
+ }
722
+ function registerGetInfoTool(server, client) {
723
+ server.tool("get_info", {}, async () => {
724
+ const info = client.getInfo();
725
+ const ips = getLocalIPs();
726
+ const lines = [];
727
+ lines.push(`Team: ${info.teamName ?? "(not joined yet)"}`);
728
+ lines.push(`Port: ${info.port ?? "(not started yet)"}`);
729
+ lines.push(`Local IPs: ${ips.length > 0 ? ips.join(", ") : "(none found)"}`);
730
+ if (info.connectedPeers.length > 0) {
731
+ lines.push(`Connected peers: ${info.connectedPeers.join(", ")}`);
732
+ } else {
733
+ lines.push(`Connected peers: (none)`);
734
+ }
735
+ if (info.port && ips.length > 0) {
736
+ lines.push(`
737
+ Other terminal can connect with:
738
+ connect_peer("${ips[0]}", ${info.port})`);
739
+ }
740
+ return {
741
+ content: [{ type: "text", text: lines.join("\n") }]
742
+ };
743
+ });
744
+ }
679
745
  var askSchema = {
680
746
  team: z.string().describe('Target team name to ask (e.g., "backend", "frontend")'),
681
747
  question: z.string().describe("The question to ask (supports markdown)")
@@ -923,6 +989,7 @@ function createMcpServer(options) {
923
989
  );
924
990
  registerJoinTool(server, client);
925
991
  registerConnectPeerTool(server, client);
992
+ registerGetInfoTool(server, client);
926
993
  registerAskTool(server, client);
927
994
  registerCheckAnswerTool(server, client);
928
995
  registerInboxTool(server, client);
@@ -960,13 +1027,6 @@ async function startMcpServer(options) {
960
1027
  // src/mcp-main.ts
961
1028
  async function main() {
962
1029
  const p2pNode = new P2PNode();
963
- try {
964
- await p2pNode.start();
965
- } catch (error) {
966
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
967
- console.error(`Failed to start P2P node: ${errorMessage}`);
968
- process.exit(1);
969
- }
970
1030
  await startMcpServer({ client: p2pNode });
971
1031
  }
972
1032
  main().catch((error) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/infrastructure/p2p/p2p-message-protocol.ts","../src/infrastructure/terminal-injector/windows-injector.ts","../src/infrastructure/terminal-injector/index.ts","../src/infrastructure/terminal-injector/injection-queue.ts","../src/config/index.ts","../src/infrastructure/p2p/p2p-node.ts","../src/presentation/mcp/tools/join.tool.ts","../src/presentation/mcp/tools/connect-peer.tool.ts","../src/presentation/mcp/tools/ask.tool.ts","../src/presentation/mcp/tools/check.tool.ts","../src/presentation/mcp/tools/inbox.tool.ts","../src/presentation/mcp/tools/reply.tool.ts","../src/presentation/mcp/server.ts","../src/mcp-main.ts"],"names":["uuidv4","z"],"mappings":"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","file":"mcp-main.js","sourcesContent":["/**\r\n * P2P Wire Message Protocol\r\n * Defines messages exchanged directly between P2P nodes.\r\n * @module infrastructure/p2p/p2p-message-protocol\r\n */\r\n\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\n\r\n// First message sent by the connecting peer to identify itself\r\nexport interface P2PHelloMsg {\r\n type: 'P2P_HELLO';\r\n fromTeam: string;\r\n fromMemberId: string;\r\n}\r\n\r\n// Questioner → Answerer: send a question\r\nexport interface P2PAskMsg {\r\n type: 'P2P_ASK';\r\n questionId: string;\r\n fromMemberId: string;\r\n fromTeam: string;\r\n toTeam: string;\r\n content: string;\r\n format: MessageFormat;\r\n requestId: string;\r\n}\r\n\r\n// Answerer → Questioner: acknowledge the question\r\nexport interface P2PAskAckMsg {\r\n type: 'P2P_ASK_ACK';\r\n questionId: string;\r\n requestId: string;\r\n}\r\n\r\n// Questioner → Answerer: poll for answer\r\nexport interface P2PGetAnswerMsg {\r\n type: 'P2P_GET_ANSWER';\r\n questionId: string;\r\n requestId: string;\r\n}\r\n\r\n// Answerer → Questioner: deliver the answer (push or in response to GET_ANSWER)\r\nexport interface P2PAnswerMsg {\r\n type: 'P2P_ANSWER';\r\n questionId: string;\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n fromTeam: string;\r\n fromMemberId: string;\r\n requestId?: string;\r\n}\r\n\r\n// Answerer → Questioner: answer not ready yet\r\nexport interface P2PAnswerPendingMsg {\r\n type: 'P2P_ANSWER_PENDING';\r\n questionId: string;\r\n requestId: string;\r\n}\r\n\r\nexport interface P2PPingMsg {\r\n type: 'P2P_PING';\r\n}\r\n\r\nexport interface P2PPongMsg {\r\n type: 'P2P_PONG';\r\n}\r\n\r\nexport interface P2PErrorMsg {\r\n type: 'P2P_ERROR';\r\n code: string;\r\n message: string;\r\n}\r\n\r\nexport type P2PMsg =\r\n | P2PHelloMsg\r\n | P2PAskMsg\r\n | P2PAskAckMsg\r\n | P2PGetAnswerMsg\r\n | P2PAnswerMsg\r\n | P2PAnswerPendingMsg\r\n | P2PPingMsg\r\n | P2PPongMsg\r\n | P2PErrorMsg;\r\n\r\nexport function serializeP2PMsg(msg: P2PMsg): string {\r\n return JSON.stringify(msg);\r\n}\r\n\r\nexport function parseP2PMsg(data: string): P2PMsg {\r\n return JSON.parse(data) as P2PMsg;\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 * Configuration module\r\n * @module config\r\n */\r\n\r\n/**\r\n * Application configuration\r\n */\r\nexport const config = {\r\n /**\r\n * P2P node configuration\r\n */\r\n p2p: {\r\n /**\r\n * Fixed port for the WS server. Override with CLAUDE_COLLAB_PORT env var.\r\n */\r\n port: Number(process.env['CLAUDE_COLLAB_PORT'] ?? 11777),\r\n },\r\n\r\n /**\r\n * Communication configuration\r\n */\r\n communication: {\r\n /**\r\n * Default timeout for waiting for an answer (in milliseconds)\r\n */\r\n defaultTimeout: 30000,\r\n\r\n /**\r\n * Maximum message content length\r\n */\r\n maxMessageLength: 50000,\r\n },\r\n} as const;\r\n\r\nexport type Config = typeof config;\r\n","/**\r\n * P2PNode\r\n * Implements ICollabClient using a peer-to-peer WebSocket architecture.\r\n * Each node runs its own WS server on a fixed port; peers are connected\r\n * manually via connectPeer().\r\n * @module infrastructure/p2p/p2p-node\r\n */\r\n\r\nimport { WebSocketServer, WebSocket } 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} 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 P2PAskMsg,\r\n type P2PAskAckMsg,\r\n type P2PGetAnswerMsg,\r\n type P2PAnswerMsg,\r\n type P2PAnswerPendingMsg,\r\n type P2PHelloMsg,\r\n serializeP2PMsg,\r\n parseP2PMsg,\r\n} from './p2p-message-protocol.js';\r\nimport { injectionQueue } from '../terminal-injector/injection-queue.js';\r\nimport { config } from '../../config/index.js';\r\n\r\ninterface IncomingQuestion {\r\n questionId: string;\r\n fromTeam: string;\r\n fromMemberId: string;\r\n content: string;\r\n format: MessageFormat;\r\n createdAt: Date;\r\n ws: WebSocket;\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 fromTeam: string;\r\n fromMemberId: string;\r\n}\r\n\r\ninterface LocalMember {\r\n memberId: string;\r\n teamName: string;\r\n displayName: string;\r\n}\r\n\r\nexport class P2PNode implements ICollabClient {\r\n private wss: WebSocketServer | null = null;\r\n private port = 0;\r\n\r\n // Connections indexed by remote team name\r\n private readonly peerConns = new Map<string, WebSocket>();\r\n // Reverse lookup: ws → teamName (for cleanup)\r\n private readonly wsToTeam = new Map<WebSocket, string>();\r\n\r\n // Questions we received from remote peers (our inbox)\r\n private readonly incomingQuestions = new Map<string, IncomingQuestion>();\r\n\r\n // Answers we received for questions we asked\r\n private readonly receivedAnswers = new Map<string, ReceivedAnswer>();\r\n\r\n // Maps questionId → remote teamName (so we know who to poll)\r\n private readonly questionToTeam = new Map<string, string>();\r\n\r\n // Pending response handlers (request-response correlation by filter)\r\n private readonly pendingHandlers = new Set<(msg: P2PMsg) => void>();\r\n\r\n private localMember: LocalMember | null = null;\r\n private _isStarted = false;\r\n\r\n get isConnected(): boolean {\r\n return this._isStarted;\r\n }\r\n\r\n get currentTeamId(): string | undefined {\r\n return this.localMember?.teamName;\r\n }\r\n\r\n /**\r\n * Starts the WS server on the configured fixed port.\r\n * Called automatically from join() if not yet started.\r\n */\r\n async start(): Promise<void> {\r\n this.port = config.p2p.port;\r\n this.wss = new WebSocketServer({ port: this.port });\r\n this.setupWssHandlers();\r\n this._isStarted = true;\r\n console.error(`P2P node started on port ${this.port}`);\r\n }\r\n\r\n async join(teamName: string, displayName: string): Promise<JoinResult> {\r\n if (!this._isStarted) {\r\n await this.start();\r\n }\r\n\r\n const memberId = uuidv4();\r\n this.localMember = { memberId, teamName, displayName };\r\n\r\n return { memberId, teamId: teamName, teamName, displayName, status: 'ONLINE' };\r\n }\r\n\r\n /**\r\n * Connects to a peer at the given IP and port.\r\n * Performs a bidirectional HELLO handshake and returns the peer's team name.\r\n */\r\n async connectPeer(ip: string, port?: number): Promise<string> {\r\n if (!this.localMember) {\r\n throw new Error('Must call join() before connectPeer()');\r\n }\r\n\r\n const targetPort = port ?? config.p2p.port;\r\n const ws = new WebSocket(`ws://${ip}:${targetPort}`);\r\n\r\n // Set up persistent message handler\r\n ws.on('message', (data) => {\r\n try {\r\n const msg = parseP2PMsg(data.toString());\r\n this.handleMessage(ws, msg);\r\n } catch (err) {\r\n console.error('Failed to parse P2P message:', err);\r\n }\r\n });\r\n\r\n ws.on('close', () => {\r\n const team = this.wsToTeam.get(ws);\r\n if (team) {\r\n if (this.peerConns.get(team) === ws) {\r\n this.peerConns.delete(team);\r\n }\r\n this.wsToTeam.delete(ws);\r\n }\r\n });\r\n\r\n // Connect and send our HELLO\r\n await new Promise<void>((resolve, reject) => {\r\n const timeout = setTimeout(\r\n () => reject(new Error(`Connection timeout to ${ip}:${targetPort}`)),\r\n 5000\r\n );\r\n\r\n ws.on('open', () => {\r\n clearTimeout(timeout);\r\n const hello: P2PHelloMsg = {\r\n type: 'P2P_HELLO',\r\n fromTeam: this.localMember!.teamName,\r\n fromMemberId: this.localMember!.memberId,\r\n };\r\n ws.send(serializeP2PMsg(hello));\r\n resolve();\r\n });\r\n\r\n ws.on('error', (err) => {\r\n clearTimeout(timeout);\r\n reject(err);\r\n });\r\n });\r\n\r\n // Wait for their HELLO back to identify their team name\r\n const helloMsg = await this.waitForResponse<P2PHelloMsg>(\r\n (m) => m.type === 'P2P_HELLO',\r\n 10000\r\n );\r\n\r\n return helloMsg.fromTeam;\r\n }\r\n\r\n async ask(toTeam: string, content: string, format: MessageFormat): Promise<string> {\r\n const ws = await this.getPeerConnection(toTeam);\r\n const questionId = uuidv4();\r\n const requestId = uuidv4();\r\n\r\n this.questionToTeam.set(questionId, toTeam);\r\n\r\n // Register handler before sending (avoids race where ACK arrives first)\r\n const ackPromise = this.waitForResponse<P2PAskAckMsg>(\r\n (m) => m.type === 'P2P_ASK_ACK' && m.requestId === requestId,\r\n 5000\r\n );\r\n\r\n const msg: P2PAskMsg = {\r\n type: 'P2P_ASK',\r\n questionId,\r\n fromMemberId: this.localMember!.memberId,\r\n fromTeam: this.localMember!.teamName,\r\n toTeam,\r\n content,\r\n format,\r\n requestId,\r\n };\r\n ws.send(serializeP2PMsg(msg));\r\n\r\n await ackPromise;\r\n return questionId;\r\n }\r\n\r\n async checkAnswer(questionId: string): Promise<CheckAnswerResult | null> {\r\n // Check local cache first (populated by push from remote)\r\n const cached = this.receivedAnswers.get(questionId);\r\n if (cached) {\r\n return {\r\n questionId,\r\n from: { displayName: `${cached.fromTeam} Claude`, teamName: cached.fromTeam },\r\n content: cached.content,\r\n format: cached.format,\r\n answeredAt: cached.answeredAt,\r\n };\r\n }\r\n\r\n // Poll the remote peer\r\n const toTeam = this.questionToTeam.get(questionId);\r\n if (!toTeam) return null;\r\n\r\n const ws = this.peerConns.get(toTeam);\r\n if (!ws || ws.readyState !== WebSocket.OPEN) return null;\r\n\r\n const requestId = uuidv4();\r\n\r\n const responsePromise = this.waitForResponse<P2PAnswerMsg | P2PAnswerPendingMsg>(\r\n (m) =>\r\n (m.type === 'P2P_ANSWER' && m.questionId === questionId) ||\r\n (m.type === 'P2P_ANSWER_PENDING' && m.requestId === requestId),\r\n 5000\r\n );\r\n\r\n const getMsg: P2PGetAnswerMsg = {\r\n type: 'P2P_GET_ANSWER',\r\n questionId,\r\n requestId,\r\n };\r\n ws.send(serializeP2PMsg(getMsg));\r\n\r\n const response = await responsePromise;\r\n if (response.type === 'P2P_ANSWER_PENDING') return null;\r\n\r\n const answer = response as P2PAnswerMsg;\r\n this.receivedAnswers.set(questionId, {\r\n content: answer.content,\r\n format: answer.format,\r\n answeredAt: answer.answeredAt,\r\n fromTeam: answer.fromTeam,\r\n fromMemberId: answer.fromMemberId,\r\n });\r\n\r\n return {\r\n questionId,\r\n from: { displayName: `${answer.fromTeam} Claude`, teamName: answer.fromTeam },\r\n content: answer.content,\r\n format: answer.format,\r\n answeredAt: answer.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 in inbox`);\r\n\r\n question.answered = true;\r\n question.answerContent = content;\r\n question.answerFormat = format;\r\n\r\n const answerMsg: P2PAnswerMsg = {\r\n type: 'P2P_ANSWER',\r\n questionId,\r\n content,\r\n format,\r\n answeredAt: new Date().toISOString(),\r\n fromTeam: this.localMember!.teamName,\r\n fromMemberId: this.localMember!.memberId,\r\n };\r\n\r\n if (question.ws.readyState === WebSocket.OPEN) {\r\n question.ws.send(serializeP2PMsg(answerMsg));\r\n }\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.fromTeam} Claude`, teamName: q.fromTeam },\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\r\n return {\r\n questions,\r\n totalCount: questions.length,\r\n pendingCount: questions.length,\r\n };\r\n }\r\n\r\n async disconnect(): Promise<void> {\r\n for (const ws of this.peerConns.values()) {\r\n ws.close();\r\n }\r\n this.peerConns.clear();\r\n\r\n await new Promise<void>((resolve) => {\r\n if (this.wss) {\r\n this.wss.close(() => resolve());\r\n } else {\r\n resolve();\r\n }\r\n });\r\n\r\n this._isStarted = false;\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: WebSocket server setup\r\n // ---------------------------------------------------------------------------\r\n\r\n private setupWssHandlers(): void {\r\n this.wss!.on('connection', (ws) => {\r\n ws.on('message', (data) => {\r\n try {\r\n const msg = parseP2PMsg(data.toString());\r\n\r\n // Send our HELLO back on incoming HELLO (bidirectional identification)\r\n if (msg.type === 'P2P_HELLO' && this.localMember) {\r\n const hello: P2PHelloMsg = {\r\n type: 'P2P_HELLO',\r\n fromTeam: this.localMember.teamName,\r\n fromMemberId: this.localMember.memberId,\r\n };\r\n ws.send(serializeP2PMsg(hello));\r\n }\r\n\r\n this.handleMessage(ws, msg);\r\n } catch (err) {\r\n console.error('Failed to parse incoming P2P message:', err);\r\n }\r\n });\r\n\r\n ws.on('close', () => {\r\n const team = this.wsToTeam.get(ws);\r\n if (team) {\r\n if (this.peerConns.get(team) === ws) {\r\n this.peerConns.delete(team);\r\n }\r\n this.wsToTeam.delete(ws);\r\n }\r\n });\r\n });\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: unified message handler\r\n // ---------------------------------------------------------------------------\r\n\r\n private handleMessage(ws: WebSocket, msg: P2PMsg): void {\r\n // Dispatch to all pending response handlers first\r\n for (const handler of this.pendingHandlers) {\r\n handler(msg);\r\n }\r\n\r\n switch (msg.type) {\r\n case 'P2P_HELLO':\r\n this.wsToTeam.set(ws, msg.fromTeam);\r\n this.peerConns.set(msg.fromTeam, ws);\r\n console.error(`Peer identified: ${msg.fromTeam}`);\r\n break;\r\n\r\n case 'P2P_ASK':\r\n this.handleIncomingAsk(ws, msg);\r\n break;\r\n\r\n case 'P2P_GET_ANSWER':\r\n this.handleGetAnswer(ws, msg);\r\n break;\r\n\r\n case 'P2P_ANSWER':\r\n // Push answer received for a question WE asked\r\n if (!this.receivedAnswers.has(msg.questionId)) {\r\n this.receivedAnswers.set(msg.questionId, {\r\n content: msg.content,\r\n format: msg.format,\r\n answeredAt: msg.answeredAt,\r\n fromTeam: msg.fromTeam,\r\n fromMemberId: msg.fromMemberId,\r\n });\r\n }\r\n break;\r\n\r\n case 'P2P_PING':\r\n ws.send(serializeP2PMsg({ type: 'P2P_PONG' }));\r\n break;\r\n\r\n // P2P_ASK_ACK, P2P_ANSWER_PENDING, P2P_PONG, P2P_ERROR\r\n // are handled by pendingHandlers above; no extra action needed here.\r\n }\r\n }\r\n\r\n private handleIncomingAsk(ws: WebSocket, msg: P2PAskMsg): void {\r\n this.incomingQuestions.set(msg.questionId, {\r\n questionId: msg.questionId,\r\n fromTeam: msg.fromTeam,\r\n fromMemberId: msg.fromMemberId,\r\n content: msg.content,\r\n format: msg.format,\r\n createdAt: new Date(),\r\n ws,\r\n answered: false,\r\n });\r\n\r\n // Inject into the terminal so Claude Code can auto-reply\r\n injectionQueue.enqueue({\r\n questionId: msg.questionId,\r\n from: {\r\n displayName: `${msg.fromTeam} Claude`,\r\n teamName: msg.fromTeam,\r\n },\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 // ACK\r\n const ack: P2PAskAckMsg = {\r\n type: 'P2P_ASK_ACK',\r\n questionId: msg.questionId,\r\n requestId: msg.requestId,\r\n };\r\n ws.send(serializeP2PMsg(ack));\r\n }\r\n\r\n private handleGetAnswer(ws: WebSocket, msg: P2PGetAnswerMsg): void {\r\n const question = this.incomingQuestions.get(msg.questionId);\r\n\r\n if (!question?.answered) {\r\n const pending: P2PAnswerPendingMsg = {\r\n type: 'P2P_ANSWER_PENDING',\r\n questionId: msg.questionId,\r\n requestId: msg.requestId,\r\n };\r\n ws.send(serializeP2PMsg(pending));\r\n return;\r\n }\r\n\r\n const answer: P2PAnswerMsg = {\r\n type: 'P2P_ANSWER',\r\n questionId: msg.questionId,\r\n content: question.answerContent!,\r\n format: question.answerFormat!,\r\n answeredAt: new Date().toISOString(),\r\n fromTeam: this.localMember!.teamName,\r\n fromMemberId: this.localMember!.memberId,\r\n requestId: msg.requestId,\r\n };\r\n ws.send(serializeP2PMsg(answer));\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: peer connection management\r\n // ---------------------------------------------------------------------------\r\n\r\n private async getPeerConnection(teamName: string): Promise<WebSocket> {\r\n const existing = this.peerConns.get(teamName);\r\n if (existing && existing.readyState === WebSocket.OPEN) {\r\n return existing;\r\n }\r\n\r\n throw new Error(\r\n `No connection to team '${teamName}'. Use the connect_peer tool to connect first.`\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('P2P 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 * Join Tool\r\n * Joins a team channel for collaboration\r\n * @module presentation/mcp/tools/join\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\n/**\r\n * Join tool input schema\r\n */\r\nconst joinSchema = {\r\n team: z.string().describe('Team name to join (e.g., \"frontend\", \"backend\", \"devops\")'),\r\n displayName: z\r\n .string()\r\n .optional()\r\n .describe('Display name for this terminal (default: team + \" Claude\")'),\r\n};\r\n\r\n/**\r\n * Registers the join tool with the MCP server\r\n */\r\nexport function registerJoinTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('join', joinSchema, async (args) => {\r\n const teamName = args.team;\r\n const displayName = args.displayName ?? `${teamName} Claude`;\r\n\r\n try {\r\n const member = await client.join(teamName, displayName);\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Successfully joined team \"${member.teamName}\" as \"${member.displayName}\".\\n\\nYour member ID: ${member.memberId}\\nTeam ID: ${member.teamId}\\nStatus: ${member.status}`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to join team: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Connect Peer Tool\r\n * Manually connects to a peer node by IP address\r\n * @module presentation/mcp/tools/connect-peer\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 { config } from '../../../config/index.js';\r\n\r\nconst connectPeerSchema = {\r\n ip: z.string().describe('IP address of the peer to connect to (e.g., \"172.16.40.137\")'),\r\n port: z\r\n .number()\r\n .optional()\r\n .describe(`Port the peer is listening on (default: ${config.p2p.port})`),\r\n};\r\n\r\nexport function registerConnectPeerTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('connect_peer', connectPeerSchema, async (args) => {\r\n const targetPort = args.port ?? config.p2p.port;\r\n\r\n try {\r\n const peerTeam = await client.connectPeer(args.ip, args.port);\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Connected to peer \"${peerTeam}\" at ${args.ip}:${targetPort}.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to connect to ${args.ip}:${targetPort}: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Ask Tool\r\n * Sends a question to another team and returns a question ID immediately.\r\n * Use the \"check_answer\" tool with the question ID to retrieve the answer later.\r\n * @module presentation/mcp/tools/ask\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\n/**\r\n * Ask tool input schema\r\n */\r\nconst askSchema = {\r\n team: z.string().describe('Target team name to ask (e.g., \"backend\", \"frontend\")'),\r\n question: z.string().describe('The question to ask (supports markdown)'),\r\n};\r\n\r\n/**\r\n * Registers the ask tool with the MCP server\r\n */\r\nexport function registerAskTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('ask', askSchema, async (args) => {\r\n const targetTeam = args.team;\r\n const question = args.question;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n const questionId = await client.ask(targetTeam, question, 'markdown');\r\n\r\n // Poll until answer arrives (max 5 minutes, every 5 seconds)\r\n const POLL_INTERVAL_MS = 5_000;\r\n const MAX_WAIT_MS = 5 * 60 * 1000;\r\n const deadline = Date.now() + MAX_WAIT_MS;\r\n\r\n while (Date.now() < deadline) {\r\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\r\n const answer = await client.checkAnswer(questionId);\r\n if (answer !== null) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `**${answer.from.displayName} (${answer.from.teamName}) cevapladı:**\\n\\n${answer.content}`,\r\n },\r\n ],\r\n };\r\n }\r\n }\r\n\r\n // Timed out — return question ID for manual follow-up\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Soru gönderildi ancak 5 dakika içinde cevap gelmedi.\\nQuestion ID: \\`${questionId}\\`\\n\\nManuel kontrol için \"check_answer\" tool'unu kullanabilirsin.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to send question: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Check Answer Tool\r\n * Checks if an answer has arrived for a previously sent question.\r\n * Returns the answer if available, or a \"still pending\" message.\r\n * @module presentation/mcp/tools/check\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\n/**\r\n * Check answer tool input schema\r\n */\r\nconst checkAnswerSchema = {\r\n question_id: z.string().describe('The question ID returned by the \"ask\" tool'),\r\n};\r\n\r\n/**\r\n * Registers the check_answer tool with the MCP server\r\n */\r\nexport function registerCheckAnswerTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('check_answer', checkAnswerSchema, async (args) => {\r\n const questionId = args.question_id;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n const answer = await client.checkAnswer(questionId);\r\n\r\n if (!answer) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `No answer yet for question \\`${questionId}\\`. The other team hasn't replied yet. You can continue working and check again later.`,\r\n },\r\n ],\r\n };\r\n }\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `**Answer from ${answer.from.displayName} (${answer.from.teamName}):**\\n\\n${answer.content}`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to check answer: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Inbox Tool\r\n * Lists pending questions directed to the current team\r\n * @module presentation/mcp/tools/inbox\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\n/**\r\n * Inbox tool input schema (no required parameters)\r\n */\r\nconst inboxSchema = {};\r\n\r\n/**\r\n * Registers the inbox tool with the MCP server\r\n */\r\nexport function registerInboxTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('inbox', inboxSchema, async () => {\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n const inbox = await client.getInbox();\r\n\r\n if (inbox.questions.length === 0) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'No pending questions in your inbox.',\r\n },\r\n ],\r\n };\r\n }\r\n\r\n const questionsList = inbox.questions\r\n .map((q, i) => {\r\n const ageSeconds = Math.floor(q.ageMs / 1000);\r\n const ageStr = ageSeconds < 60 ? `${ageSeconds}s ago` : `${Math.floor(ageSeconds / 60)}m ago`;\r\n\r\n return `### ${i + 1}. Question from ${q.from.displayName} (${q.from.teamName}) - ${ageStr}\r\n**ID:** \\`${q.questionId}\\`\r\n**Status:** ${q.status}\r\n\r\n${q.content}\r\n\r\n---`;\r\n })\r\n .join('\\n\\n');\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `# Inbox (${inbox.pendingCount} pending, ${inbox.totalCount} total)\\n\\n${questionsList}\\n\\nUse the \"reply\" tool with the question ID to answer a question.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to get inbox: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Reply Tool\r\n * Replies to a pending question\r\n * @module presentation/mcp/tools/reply\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { injectionQueue } from '../../../infrastructure/terminal-injector/injection-queue.js';\r\n\r\n/**\r\n * Reply tool input schema\r\n */\r\nconst replySchema = {\r\n questionId: z.string().describe('The ID of the question to reply to (from inbox)'),\r\n answer: z.string().describe('Your answer to the question (supports markdown)'),\r\n};\r\n\r\n/**\r\n * Registers the reply tool with the MCP server\r\n */\r\nexport function registerReplyTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('reply', replySchema, async (args) => {\r\n const questionId = args.questionId;\r\n const answer = args.answer;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n await client.reply(questionId, answer, 'markdown');\r\n\r\n // Signal queue: this question is done, process next\r\n injectionQueue.notifyReplied();\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Reply sent successfully to question \\`${questionId}\\`.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to send reply: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * MCP Server\r\n * Provides MCP tools for Claude Code integration\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 { registerJoinTool } from './tools/join.tool.js';\r\nimport { registerConnectPeerTool } from './tools/connect-peer.tool.js';\r\nimport { registerAskTool } from './tools/ask.tool.js';\r\nimport { registerCheckAnswerTool } from './tools/check.tool.js';\r\nimport { registerInboxTool } from './tools/inbox.tool.js';\r\nimport { registerReplyTool } from './tools/reply.tool.js';\r\n\r\n/**\r\n * MCP Server options\r\n */\r\nexport interface McpServerOptions {\r\n client: ICollabClient;\r\n}\r\n\r\n/**\r\n * Creates and configures the MCP server with all tools\r\n */\r\nexport function createMcpServer(options: McpServerOptions): McpServer {\r\n const { client } = options;\r\n\r\n const server = new McpServer(\r\n {\r\n name: 'claude-collab',\r\n version: '0.1.2',\r\n },\r\n {\r\n capabilities: {\r\n resources: {\r\n subscribe: true,\r\n listChanged: true,\r\n },\r\n },\r\n }\r\n );\r\n\r\n // Register all tools\r\n registerJoinTool(server, client);\r\n registerConnectPeerTool(server, client);\r\n registerAskTool(server, client);\r\n registerCheckAnswerTool(server, client);\r\n registerInboxTool(server, client);\r\n registerReplyTool(server, client);\r\n\r\n // Register resource handlers\r\n server.resource(\r\n 'inbox-questions',\r\n 'inbox://questions',\r\n { description: 'Your inbox of pending questions from other teams', mimeType: 'application/json' },\r\n async () => {\r\n try {\r\n const inbox = await client.getInbox();\r\n return {\r\n contents: [\r\n {\r\n uri: 'inbox://questions',\r\n mimeType: 'application/json',\r\n text: JSON.stringify(inbox, null, 2),\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n throw new Error(`Failed to read inbox: ${errorMessage}`);\r\n }\r\n }\r\n );\r\n\r\n return server;\r\n}\r\n\r\n/**\r\n * Starts the MCP server with stdio transport\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 * @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\nasync function main(): Promise<void> {\r\n const p2pNode = new P2PNode();\r\n\r\n try {\r\n await p2pNode.start();\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n console.error(`Failed to start P2P node: ${errorMessage}`);\r\n process.exit(1);\r\n }\r\n\r\n await startMcpServer({ client: p2pNode });\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-message-protocol.ts","../src/infrastructure/terminal-injector/windows-injector.ts","../src/infrastructure/terminal-injector/index.ts","../src/infrastructure/terminal-injector/injection-queue.ts","../src/config/index.ts","../src/infrastructure/p2p/p2p-node.ts","../src/presentation/mcp/tools/join.tool.ts","../src/presentation/mcp/tools/connect-peer.tool.ts","../src/presentation/mcp/tools/get-info.tool.ts","../src/presentation/mcp/tools/ask.tool.ts","../src/presentation/mcp/tools/check.tool.ts","../src/presentation/mcp/tools/inbox.tool.ts","../src/presentation/mcp/tools/reply.tool.ts","../src/presentation/mcp/server.ts","../src/mcp-main.ts"],"names":["uuidv4","z"],"mappings":"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","file":"mcp-main.js","sourcesContent":["/**\r\n * P2P Wire Message Protocol\r\n * Defines messages exchanged directly between P2P nodes.\r\n * @module infrastructure/p2p/p2p-message-protocol\r\n */\r\n\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\n\r\n// First message sent by the connecting peer to identify itself\r\nexport interface P2PHelloMsg {\r\n type: 'P2P_HELLO';\r\n fromTeam: string;\r\n fromMemberId: string;\r\n}\r\n\r\n// Questioner → Answerer: send a question\r\nexport interface P2PAskMsg {\r\n type: 'P2P_ASK';\r\n questionId: string;\r\n fromMemberId: string;\r\n fromTeam: string;\r\n toTeam: string;\r\n content: string;\r\n format: MessageFormat;\r\n requestId: string;\r\n}\r\n\r\n// Answerer → Questioner: acknowledge the question\r\nexport interface P2PAskAckMsg {\r\n type: 'P2P_ASK_ACK';\r\n questionId: string;\r\n requestId: string;\r\n}\r\n\r\n// Questioner → Answerer: poll for answer\r\nexport interface P2PGetAnswerMsg {\r\n type: 'P2P_GET_ANSWER';\r\n questionId: string;\r\n requestId: string;\r\n}\r\n\r\n// Answerer → Questioner: deliver the answer (push or in response to GET_ANSWER)\r\nexport interface P2PAnswerMsg {\r\n type: 'P2P_ANSWER';\r\n questionId: string;\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n fromTeam: string;\r\n fromMemberId: string;\r\n requestId?: string;\r\n}\r\n\r\n// Answerer → Questioner: answer not ready yet\r\nexport interface P2PAnswerPendingMsg {\r\n type: 'P2P_ANSWER_PENDING';\r\n questionId: string;\r\n requestId: string;\r\n}\r\n\r\nexport interface P2PPingMsg {\r\n type: 'P2P_PING';\r\n}\r\n\r\nexport interface P2PPongMsg {\r\n type: 'P2P_PONG';\r\n}\r\n\r\nexport interface P2PErrorMsg {\r\n type: 'P2P_ERROR';\r\n code: string;\r\n message: string;\r\n}\r\n\r\nexport type P2PMsg =\r\n | P2PHelloMsg\r\n | P2PAskMsg\r\n | P2PAskAckMsg\r\n | P2PGetAnswerMsg\r\n | P2PAnswerMsg\r\n | P2PAnswerPendingMsg\r\n | P2PPingMsg\r\n | P2PPongMsg\r\n | P2PErrorMsg;\r\n\r\nexport function serializeP2PMsg(msg: P2PMsg): string {\r\n return JSON.stringify(msg);\r\n}\r\n\r\nexport function parseP2PMsg(data: string): P2PMsg {\r\n return JSON.parse(data) as P2PMsg;\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 * Configuration module\r\n * @module config\r\n */\r\n\r\n/**\r\n * Application configuration\r\n */\r\nexport const config = {\r\n /**\r\n * P2P node configuration\r\n */\r\n p2p: {\r\n /**\r\n * Port range for the WS server. Override with CLAUDE_COLLAB_PORT_MIN / MAX env vars.\r\n */\r\n portRangeMin: Number(process.env['CLAUDE_COLLAB_PORT_MIN'] ?? 11700),\r\n portRangeMax: Number(process.env['CLAUDE_COLLAB_PORT_MAX'] ?? 11750),\r\n },\r\n\r\n /**\r\n * Communication configuration\r\n */\r\n communication: {\r\n /**\r\n * Default timeout for waiting for an answer (in milliseconds)\r\n */\r\n defaultTimeout: 30000,\r\n\r\n /**\r\n * Maximum message content length\r\n */\r\n maxMessageLength: 50000,\r\n },\r\n} as const;\r\n\r\nexport type Config = typeof config;\r\n","/**\r\n * P2PNode\r\n * Implements ICollabClient using a peer-to-peer WebSocket architecture.\r\n * Each node runs its own WS server on a fixed port; peers are connected\r\n * manually via connectPeer().\r\n * @module infrastructure/p2p/p2p-node\r\n */\r\n\r\nimport { WebSocketServer, WebSocket } 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} 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 P2PAskMsg,\r\n type P2PAskAckMsg,\r\n type P2PGetAnswerMsg,\r\n type P2PAnswerMsg,\r\n type P2PAnswerPendingMsg,\r\n type P2PHelloMsg,\r\n serializeP2PMsg,\r\n parseP2PMsg,\r\n} from './p2p-message-protocol.js';\r\nimport { injectionQueue } from '../terminal-injector/injection-queue.js';\r\nimport { config } from '../../config/index.js';\r\n\r\ninterface IncomingQuestion {\r\n questionId: string;\r\n fromTeam: string;\r\n fromMemberId: string;\r\n content: string;\r\n format: MessageFormat;\r\n createdAt: Date;\r\n ws: WebSocket;\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 fromTeam: string;\r\n fromMemberId: string;\r\n}\r\n\r\ninterface LocalMember {\r\n memberId: string;\r\n teamName: string;\r\n displayName: string;\r\n}\r\n\r\nexport class P2PNode implements ICollabClient {\r\n private wss: WebSocketServer | null = null;\r\n private port = 0;\r\n\r\n // Connections indexed by remote team name\r\n private readonly peerConns = new Map<string, WebSocket>();\r\n // Reverse lookup: ws → teamName (for cleanup)\r\n private readonly wsToTeam = new Map<WebSocket, string>();\r\n\r\n // Questions we received from remote peers (our inbox)\r\n private readonly incomingQuestions = new Map<string, IncomingQuestion>();\r\n\r\n // Answers we received for questions we asked\r\n private readonly receivedAnswers = new Map<string, ReceivedAnswer>();\r\n\r\n // Maps questionId → remote teamName (so we know who to poll)\r\n private readonly questionToTeam = new Map<string, string>();\r\n\r\n // Pending response handlers (request-response correlation by filter)\r\n private readonly pendingHandlers = new Set<(msg: P2PMsg) => void>();\r\n\r\n private localMember: LocalMember | null = null;\r\n private _isStarted = false;\r\n\r\n get isConnected(): boolean {\r\n return this._isStarted;\r\n }\r\n\r\n get currentTeamId(): string | undefined {\r\n return this.localMember?.teamName;\r\n }\r\n\r\n /**\r\n * Starts the WS server on a random available port within the configured range.\r\n * Called automatically from join() if not yet started.\r\n */\r\n async start(): Promise<void> {\r\n const { portRangeMin, portRangeMax } = config.p2p;\r\n const range = portRangeMax - portRangeMin + 1;\r\n const startOffset = Math.floor(Math.random() * range);\r\n\r\n for (let i = 0; i < range; i++) {\r\n const port = portRangeMin + ((startOffset + i) % range);\r\n const bound = await this.tryBind(port);\r\n if (bound) {\r\n this.port = port;\r\n break;\r\n }\r\n }\r\n\r\n if (!this.wss) {\r\n throw new Error(\r\n `No available port in range ${portRangeMin}-${portRangeMax}. ` +\r\n `Override with CLAUDE_COLLAB_PORT_MIN / CLAUDE_COLLAB_PORT_MAX.`\r\n );\r\n }\r\n\r\n this.setupWssHandlers();\r\n this._isStarted = true;\r\n console.error(`P2P node started on port ${this.port}`);\r\n }\r\n\r\n private tryBind(port: number): Promise<boolean> {\r\n return new Promise((resolve) => {\r\n const wss = new WebSocketServer({ port });\r\n wss.once('listening', () => {\r\n this.wss = wss;\r\n resolve(true);\r\n });\r\n wss.once('error', () => resolve(false));\r\n });\r\n }\r\n\r\n async join(teamName: string, displayName: string): Promise<JoinResult> {\r\n if (!this._isStarted) {\r\n await this.start();\r\n }\r\n\r\n const memberId = uuidv4();\r\n this.localMember = { memberId, teamName, displayName };\r\n\r\n return { memberId, teamId: teamName, teamName, displayName, status: 'ONLINE', port: this.port };\r\n }\r\n\r\n /**\r\n * Connects to a peer at the given IP and port.\r\n * Performs a bidirectional HELLO handshake and returns the peer's team name.\r\n */\r\n async connectPeer(ip: string, port: number): Promise<string> {\r\n if (!this.localMember) {\r\n throw new Error('Must call join() before connectPeer()');\r\n }\r\n\r\n const ws = new WebSocket(`ws://${ip}:${port}`);\r\n\r\n // Set up persistent message handler\r\n ws.on('message', (data) => {\r\n try {\r\n const msg = parseP2PMsg(data.toString());\r\n this.handleMessage(ws, msg);\r\n } catch (err) {\r\n console.error('Failed to parse P2P message:', err);\r\n }\r\n });\r\n\r\n ws.on('close', () => {\r\n const team = this.wsToTeam.get(ws);\r\n if (team) {\r\n if (this.peerConns.get(team) === ws) {\r\n this.peerConns.delete(team);\r\n }\r\n this.wsToTeam.delete(ws);\r\n }\r\n });\r\n\r\n // Connect and send our HELLO\r\n await new Promise<void>((resolve, reject) => {\r\n const timeout = setTimeout(\r\n () => reject(new Error(`Connection timeout to ${ip}:${port}`)),\r\n 5000\r\n );\r\n\r\n ws.on('open', () => {\r\n clearTimeout(timeout);\r\n const hello: P2PHelloMsg = {\r\n type: 'P2P_HELLO',\r\n fromTeam: this.localMember!.teamName,\r\n fromMemberId: this.localMember!.memberId,\r\n };\r\n ws.send(serializeP2PMsg(hello));\r\n resolve();\r\n });\r\n\r\n ws.on('error', (err) => {\r\n clearTimeout(timeout);\r\n reject(err);\r\n });\r\n });\r\n\r\n // Wait for their HELLO back to identify their team name\r\n const helloMsg = await this.waitForResponse<P2PHelloMsg>(\r\n (m) => m.type === 'P2P_HELLO',\r\n 10000\r\n );\r\n\r\n return helloMsg.fromTeam;\r\n }\r\n\r\n async ask(toTeam: string, content: string, format: MessageFormat): Promise<string> {\r\n const ws = await this.getPeerConnection(toTeam);\r\n const questionId = uuidv4();\r\n const requestId = uuidv4();\r\n\r\n this.questionToTeam.set(questionId, toTeam);\r\n\r\n // Register handler before sending (avoids race where ACK arrives first)\r\n const ackPromise = this.waitForResponse<P2PAskAckMsg>(\r\n (m) => m.type === 'P2P_ASK_ACK' && m.requestId === requestId,\r\n 5000\r\n );\r\n\r\n const msg: P2PAskMsg = {\r\n type: 'P2P_ASK',\r\n questionId,\r\n fromMemberId: this.localMember!.memberId,\r\n fromTeam: this.localMember!.teamName,\r\n toTeam,\r\n content,\r\n format,\r\n requestId,\r\n };\r\n ws.send(serializeP2PMsg(msg));\r\n\r\n await ackPromise;\r\n return questionId;\r\n }\r\n\r\n async checkAnswer(questionId: string): Promise<CheckAnswerResult | null> {\r\n // Check local cache first (populated by push from remote)\r\n const cached = this.receivedAnswers.get(questionId);\r\n if (cached) {\r\n return {\r\n questionId,\r\n from: { displayName: `${cached.fromTeam} Claude`, teamName: cached.fromTeam },\r\n content: cached.content,\r\n format: cached.format,\r\n answeredAt: cached.answeredAt,\r\n };\r\n }\r\n\r\n // Poll the remote peer\r\n const toTeam = this.questionToTeam.get(questionId);\r\n if (!toTeam) return null;\r\n\r\n const ws = this.peerConns.get(toTeam);\r\n if (!ws || ws.readyState !== WebSocket.OPEN) return null;\r\n\r\n const requestId = uuidv4();\r\n\r\n const responsePromise = this.waitForResponse<P2PAnswerMsg | P2PAnswerPendingMsg>(\r\n (m) =>\r\n (m.type === 'P2P_ANSWER' && m.questionId === questionId) ||\r\n (m.type === 'P2P_ANSWER_PENDING' && m.requestId === requestId),\r\n 5000\r\n );\r\n\r\n const getMsg: P2PGetAnswerMsg = {\r\n type: 'P2P_GET_ANSWER',\r\n questionId,\r\n requestId,\r\n };\r\n ws.send(serializeP2PMsg(getMsg));\r\n\r\n const response = await responsePromise;\r\n if (response.type === 'P2P_ANSWER_PENDING') return null;\r\n\r\n const answer = response as P2PAnswerMsg;\r\n this.receivedAnswers.set(questionId, {\r\n content: answer.content,\r\n format: answer.format,\r\n answeredAt: answer.answeredAt,\r\n fromTeam: answer.fromTeam,\r\n fromMemberId: answer.fromMemberId,\r\n });\r\n\r\n return {\r\n questionId,\r\n from: { displayName: `${answer.fromTeam} Claude`, teamName: answer.fromTeam },\r\n content: answer.content,\r\n format: answer.format,\r\n answeredAt: answer.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 in inbox`);\r\n\r\n question.answered = true;\r\n question.answerContent = content;\r\n question.answerFormat = format;\r\n\r\n const answerMsg: P2PAnswerMsg = {\r\n type: 'P2P_ANSWER',\r\n questionId,\r\n content,\r\n format,\r\n answeredAt: new Date().toISOString(),\r\n fromTeam: this.localMember!.teamName,\r\n fromMemberId: this.localMember!.memberId,\r\n };\r\n\r\n if (question.ws.readyState === WebSocket.OPEN) {\r\n question.ws.send(serializeP2PMsg(answerMsg));\r\n }\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.fromTeam} Claude`, teamName: q.fromTeam },\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\r\n return {\r\n questions,\r\n totalCount: questions.length,\r\n pendingCount: questions.length,\r\n };\r\n }\r\n\r\n getInfo(): NodeInfo {\r\n return {\r\n teamName: this.localMember?.teamName,\r\n port: this._isStarted ? this.port : undefined,\r\n connectedPeers: [...this.peerConns.keys()],\r\n };\r\n }\r\n\r\n async disconnect(): Promise<void> {\r\n for (const ws of this.peerConns.values()) {\r\n ws.close();\r\n }\r\n this.peerConns.clear();\r\n\r\n await new Promise<void>((resolve) => {\r\n if (this.wss) {\r\n this.wss.close(() => resolve());\r\n } else {\r\n resolve();\r\n }\r\n });\r\n\r\n this._isStarted = false;\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: WebSocket server setup\r\n // ---------------------------------------------------------------------------\r\n\r\n private setupWssHandlers(): void {\r\n this.wss!.on('connection', (ws) => {\r\n ws.on('message', (data) => {\r\n try {\r\n const msg = parseP2PMsg(data.toString());\r\n\r\n // Send our HELLO back on incoming HELLO (bidirectional identification)\r\n if (msg.type === 'P2P_HELLO' && this.localMember) {\r\n const hello: P2PHelloMsg = {\r\n type: 'P2P_HELLO',\r\n fromTeam: this.localMember.teamName,\r\n fromMemberId: this.localMember.memberId,\r\n };\r\n ws.send(serializeP2PMsg(hello));\r\n }\r\n\r\n this.handleMessage(ws, msg);\r\n } catch (err) {\r\n console.error('Failed to parse incoming P2P message:', err);\r\n }\r\n });\r\n\r\n ws.on('close', () => {\r\n const team = this.wsToTeam.get(ws);\r\n if (team) {\r\n if (this.peerConns.get(team) === ws) {\r\n this.peerConns.delete(team);\r\n }\r\n this.wsToTeam.delete(ws);\r\n }\r\n });\r\n });\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: unified message handler\r\n // ---------------------------------------------------------------------------\r\n\r\n private handleMessage(ws: WebSocket, msg: P2PMsg): void {\r\n // Dispatch to all pending response handlers first\r\n for (const handler of this.pendingHandlers) {\r\n handler(msg);\r\n }\r\n\r\n switch (msg.type) {\r\n case 'P2P_HELLO':\r\n this.wsToTeam.set(ws, msg.fromTeam);\r\n this.peerConns.set(msg.fromTeam, ws);\r\n console.error(`Peer identified: ${msg.fromTeam}`);\r\n break;\r\n\r\n case 'P2P_ASK':\r\n this.handleIncomingAsk(ws, msg);\r\n break;\r\n\r\n case 'P2P_GET_ANSWER':\r\n this.handleGetAnswer(ws, msg);\r\n break;\r\n\r\n case 'P2P_ANSWER':\r\n // Push answer received for a question WE asked\r\n if (!this.receivedAnswers.has(msg.questionId)) {\r\n this.receivedAnswers.set(msg.questionId, {\r\n content: msg.content,\r\n format: msg.format,\r\n answeredAt: msg.answeredAt,\r\n fromTeam: msg.fromTeam,\r\n fromMemberId: msg.fromMemberId,\r\n });\r\n }\r\n break;\r\n\r\n case 'P2P_PING':\r\n ws.send(serializeP2PMsg({ type: 'P2P_PONG' }));\r\n break;\r\n\r\n // P2P_ASK_ACK, P2P_ANSWER_PENDING, P2P_PONG, P2P_ERROR\r\n // are handled by pendingHandlers above; no extra action needed here.\r\n }\r\n }\r\n\r\n private handleIncomingAsk(ws: WebSocket, msg: P2PAskMsg): void {\r\n this.incomingQuestions.set(msg.questionId, {\r\n questionId: msg.questionId,\r\n fromTeam: msg.fromTeam,\r\n fromMemberId: msg.fromMemberId,\r\n content: msg.content,\r\n format: msg.format,\r\n createdAt: new Date(),\r\n ws,\r\n answered: false,\r\n });\r\n\r\n // Inject into the terminal so Claude Code can auto-reply\r\n injectionQueue.enqueue({\r\n questionId: msg.questionId,\r\n from: {\r\n displayName: `${msg.fromTeam} Claude`,\r\n teamName: msg.fromTeam,\r\n },\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 // ACK\r\n const ack: P2PAskAckMsg = {\r\n type: 'P2P_ASK_ACK',\r\n questionId: msg.questionId,\r\n requestId: msg.requestId,\r\n };\r\n ws.send(serializeP2PMsg(ack));\r\n }\r\n\r\n private handleGetAnswer(ws: WebSocket, msg: P2PGetAnswerMsg): void {\r\n const question = this.incomingQuestions.get(msg.questionId);\r\n\r\n if (!question?.answered) {\r\n const pending: P2PAnswerPendingMsg = {\r\n type: 'P2P_ANSWER_PENDING',\r\n questionId: msg.questionId,\r\n requestId: msg.requestId,\r\n };\r\n ws.send(serializeP2PMsg(pending));\r\n return;\r\n }\r\n\r\n const answer: P2PAnswerMsg = {\r\n type: 'P2P_ANSWER',\r\n questionId: msg.questionId,\r\n content: question.answerContent!,\r\n format: question.answerFormat!,\r\n answeredAt: new Date().toISOString(),\r\n fromTeam: this.localMember!.teamName,\r\n fromMemberId: this.localMember!.memberId,\r\n requestId: msg.requestId,\r\n };\r\n ws.send(serializeP2PMsg(answer));\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: peer connection management\r\n // ---------------------------------------------------------------------------\r\n\r\n private async getPeerConnection(teamName: string): Promise<WebSocket> {\r\n const existing = this.peerConns.get(teamName);\r\n if (existing && existing.readyState === WebSocket.OPEN) {\r\n return existing;\r\n }\r\n\r\n throw new Error(\r\n `No connection to team '${teamName}'. Use the connect_peer tool to connect first.`\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('P2P 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 * Join Tool\r\n * Joins a team channel for collaboration\r\n * @module presentation/mcp/tools/join\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\n/**\r\n * Join tool input schema\r\n */\r\nconst joinSchema = {\r\n team: z.string().describe('Team name to join (e.g., \"frontend\", \"backend\", \"devops\")'),\r\n displayName: z\r\n .string()\r\n .optional()\r\n .describe('Display name for this terminal (default: team + \" Claude\")'),\r\n};\r\n\r\n/**\r\n * Registers the join tool with the MCP server\r\n */\r\nexport function registerJoinTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('join', joinSchema, async (args) => {\r\n const teamName = args.team;\r\n const displayName = args.displayName ?? `${teamName} Claude`;\r\n\r\n try {\r\n const member = await client.join(teamName, displayName);\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Successfully joined team \"${member.teamName}\" as \"${member.displayName}\".\\n\\nYour member ID: ${member.memberId}\\nStatus: ${member.status}\\nListening on port: ${member.port}\\n\\nShare this port with the other terminal so they can run: connect_peer(\"<your-ip>\", ${member.port})`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to join team: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Connect Peer Tool\r\n * Manually connects to a peer node by IP address and port\r\n * @module presentation/mcp/tools/connect-peer\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 connectPeerSchema = {\r\n ip: z.string().describe('IP address of the peer to connect to (e.g., \"172.16.40.137\")'),\r\n port: z.number().describe('Port the peer is listening on (shown in their join response)'),\r\n};\r\n\r\nexport function registerConnectPeerTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('connect_peer', connectPeerSchema, async (args) => {\r\n try {\r\n const peerTeam = await client.connectPeer(args.ip, args.port);\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Connected to peer \"${peerTeam}\" at ${args.ip}:${args.port}.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to connect to ${args.ip}:${args.port}: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Get Info Tool\r\n * Returns local node info: team, port, IPs, connected peers\r\n * @module presentation/mcp/tools/get-info\r\n */\r\n\r\nimport { networkInterfaces } from 'os';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\nfunction getLocalIPs(): string[] {\r\n const ips: string[] = [];\r\n for (const iface of Object.values(networkInterfaces())) {\r\n for (const net of iface ?? []) {\r\n if (net.family === 'IPv4' && !net.internal) {\r\n ips.push(net.address);\r\n }\r\n }\r\n }\r\n return ips;\r\n}\r\n\r\nexport function registerGetInfoTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('get_info', {}, async () => {\r\n const info = client.getInfo();\r\n const ips = getLocalIPs();\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`Team: ${info.teamName ?? '(not joined yet)'}`);\r\n lines.push(`Port: ${info.port ?? '(not started yet)'}`);\r\n lines.push(`Local IPs: ${ips.length > 0 ? ips.join(', ') : '(none found)'}`);\r\n\r\n if (info.connectedPeers.length > 0) {\r\n lines.push(`Connected peers: ${info.connectedPeers.join(', ')}`);\r\n } else {\r\n lines.push(`Connected peers: (none)`);\r\n }\r\n\r\n if (info.port && ips.length > 0) {\r\n lines.push(`\\nOther terminal can connect with:\\n connect_peer(\"${ips[0]}\", ${info.port})`);\r\n }\r\n\r\n return {\r\n content: [{ type: 'text', text: lines.join('\\n') }],\r\n };\r\n });\r\n}\r\n","/**\r\n * Ask Tool\r\n * Sends a question to another team and returns a question ID immediately.\r\n * Use the \"check_answer\" tool with the question ID to retrieve the answer later.\r\n * @module presentation/mcp/tools/ask\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\n/**\r\n * Ask tool input schema\r\n */\r\nconst askSchema = {\r\n team: z.string().describe('Target team name to ask (e.g., \"backend\", \"frontend\")'),\r\n question: z.string().describe('The question to ask (supports markdown)'),\r\n};\r\n\r\n/**\r\n * Registers the ask tool with the MCP server\r\n */\r\nexport function registerAskTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('ask', askSchema, async (args) => {\r\n const targetTeam = args.team;\r\n const question = args.question;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n const questionId = await client.ask(targetTeam, question, 'markdown');\r\n\r\n // Poll until answer arrives (max 5 minutes, every 5 seconds)\r\n const POLL_INTERVAL_MS = 5_000;\r\n const MAX_WAIT_MS = 5 * 60 * 1000;\r\n const deadline = Date.now() + MAX_WAIT_MS;\r\n\r\n while (Date.now() < deadline) {\r\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\r\n const answer = await client.checkAnswer(questionId);\r\n if (answer !== null) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `**${answer.from.displayName} (${answer.from.teamName}) cevapladı:**\\n\\n${answer.content}`,\r\n },\r\n ],\r\n };\r\n }\r\n }\r\n\r\n // Timed out — return question ID for manual follow-up\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Soru gönderildi ancak 5 dakika içinde cevap gelmedi.\\nQuestion ID: \\`${questionId}\\`\\n\\nManuel kontrol için \"check_answer\" tool'unu kullanabilirsin.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to send question: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Check Answer Tool\r\n * Checks if an answer has arrived for a previously sent question.\r\n * Returns the answer if available, or a \"still pending\" message.\r\n * @module presentation/mcp/tools/check\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\n/**\r\n * Check answer tool input schema\r\n */\r\nconst checkAnswerSchema = {\r\n question_id: z.string().describe('The question ID returned by the \"ask\" tool'),\r\n};\r\n\r\n/**\r\n * Registers the check_answer tool with the MCP server\r\n */\r\nexport function registerCheckAnswerTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('check_answer', checkAnswerSchema, async (args) => {\r\n const questionId = args.question_id;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n const answer = await client.checkAnswer(questionId);\r\n\r\n if (!answer) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `No answer yet for question \\`${questionId}\\`. The other team hasn't replied yet. You can continue working and check again later.`,\r\n },\r\n ],\r\n };\r\n }\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `**Answer from ${answer.from.displayName} (${answer.from.teamName}):**\\n\\n${answer.content}`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to check answer: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Inbox Tool\r\n * Lists pending questions directed to the current team\r\n * @module presentation/mcp/tools/inbox\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\n/**\r\n * Inbox tool input schema (no required parameters)\r\n */\r\nconst inboxSchema = {};\r\n\r\n/**\r\n * Registers the inbox tool with the MCP server\r\n */\r\nexport function registerInboxTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('inbox', inboxSchema, async () => {\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n const inbox = await client.getInbox();\r\n\r\n if (inbox.questions.length === 0) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'No pending questions in your inbox.',\r\n },\r\n ],\r\n };\r\n }\r\n\r\n const questionsList = inbox.questions\r\n .map((q, i) => {\r\n const ageSeconds = Math.floor(q.ageMs / 1000);\r\n const ageStr = ageSeconds < 60 ? `${ageSeconds}s ago` : `${Math.floor(ageSeconds / 60)}m ago`;\r\n\r\n return `### ${i + 1}. Question from ${q.from.displayName} (${q.from.teamName}) - ${ageStr}\r\n**ID:** \\`${q.questionId}\\`\r\n**Status:** ${q.status}\r\n\r\n${q.content}\r\n\r\n---`;\r\n })\r\n .join('\\n\\n');\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `# Inbox (${inbox.pendingCount} pending, ${inbox.totalCount} total)\\n\\n${questionsList}\\n\\nUse the \"reply\" tool with the question ID to answer a question.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to get inbox: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Reply Tool\r\n * Replies to a pending question\r\n * @module presentation/mcp/tools/reply\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { injectionQueue } from '../../../infrastructure/terminal-injector/injection-queue.js';\r\n\r\n/**\r\n * Reply tool input schema\r\n */\r\nconst replySchema = {\r\n questionId: z.string().describe('The ID of the question to reply to (from inbox)'),\r\n answer: z.string().describe('Your answer to the question (supports markdown)'),\r\n};\r\n\r\n/**\r\n * Registers the reply tool with the MCP server\r\n */\r\nexport function registerReplyTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('reply', replySchema, async (args) => {\r\n const questionId = args.questionId;\r\n const answer = args.answer;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: 'You must join a team first. Use the \"join\" tool to join a team.',\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n\r\n await client.reply(questionId, answer, 'markdown');\r\n\r\n // Signal queue: this question is done, process next\r\n injectionQueue.notifyReplied();\r\n\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Reply sent successfully to question \\`${questionId}\\`.`,\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Failed to send reply: ${errorMessage}`,\r\n },\r\n ],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * MCP Server\r\n * Provides MCP tools for Claude Code integration\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 { registerJoinTool } from './tools/join.tool.js';\r\nimport { registerConnectPeerTool } from './tools/connect-peer.tool.js';\r\nimport { registerGetInfoTool } from './tools/get-info.tool.js';\r\nimport { registerAskTool } from './tools/ask.tool.js';\r\nimport { registerCheckAnswerTool } from './tools/check.tool.js';\r\nimport { registerInboxTool } from './tools/inbox.tool.js';\r\nimport { registerReplyTool } from './tools/reply.tool.js';\r\n\r\n/**\r\n * MCP Server options\r\n */\r\nexport interface McpServerOptions {\r\n client: ICollabClient;\r\n}\r\n\r\n/**\r\n * Creates and configures the MCP server with all tools\r\n */\r\nexport function createMcpServer(options: McpServerOptions): McpServer {\r\n const { client } = options;\r\n\r\n const server = new McpServer(\r\n {\r\n name: 'claude-collab',\r\n version: '0.1.2',\r\n },\r\n {\r\n capabilities: {\r\n resources: {\r\n subscribe: true,\r\n listChanged: true,\r\n },\r\n },\r\n }\r\n );\r\n\r\n // Register all tools\r\n registerJoinTool(server, client);\r\n registerConnectPeerTool(server, client);\r\n registerGetInfoTool(server, client);\r\n registerAskTool(server, client);\r\n registerCheckAnswerTool(server, client);\r\n registerInboxTool(server, client);\r\n registerReplyTool(server, client);\r\n\r\n // Register resource handlers\r\n server.resource(\r\n 'inbox-questions',\r\n 'inbox://questions',\r\n { description: 'Your inbox of pending questions from other teams', mimeType: 'application/json' },\r\n async () => {\r\n try {\r\n const inbox = await client.getInbox();\r\n return {\r\n contents: [\r\n {\r\n uri: 'inbox://questions',\r\n mimeType: 'application/json',\r\n text: JSON.stringify(inbox, null, 2),\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n throw new Error(`Failed to read inbox: ${errorMessage}`);\r\n }\r\n }\r\n );\r\n\r\n return server;\r\n}\r\n\r\n/**\r\n * Starts the MCP server with stdio transport\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 * @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\nasync function main(): Promise<void> {\r\n const p2pNode = new P2PNode();\r\n await startMcpServer({ client: p2pNode });\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.4.2",
3
+ "version": "1.4.4",
4
4
  "description": "Real-time team collaboration between Claude Code terminals via MCP",
5
5
  "type": "module",
6
6
  "main": "./dist/mcp-main.js",