@dolusoft/claude-collab 1.4.1 → 1.4.3

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
@@ -26,8 +26,6 @@ using System.Runtime.InteropServices;
26
26
  public class ConInject {
27
27
  [DllImport("kernel32.dll")] public static extern bool FreeConsole();
28
28
  [DllImport("kernel32.dll")] public static extern bool AttachConsole(uint pid);
29
- [DllImport("kernel32.dll")] public static extern IntPtr GetConsoleWindow();
30
- [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hwnd);
31
29
  [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
32
30
  public static extern IntPtr CreateFile(
33
31
  string lpFileName, uint dwDesiredAccess, uint dwShareMode,
@@ -56,7 +54,7 @@ public class ConInject {
56
54
  return CreateFile("CONIN$", 0xC0000000, 3, IntPtr.Zero, 3, 0, IntPtr.Zero);
57
55
  }
58
56
 
59
- // Inject only text characters into console input buffer (no Ctrl keys, no Enter)
57
+ // Inject plain text characters into console input buffer
60
58
  public static int InjectText(uint pid, string text) {
61
59
  IntPtr hIn = OpenConin(pid);
62
60
  if (hIn == new IntPtr(-1)) return -1;
@@ -74,13 +72,56 @@ public class ConInject {
74
72
  return ok ? (int)written : -2;
75
73
  }
76
74
 
77
- // Focus the console window for WScript.Shell.SendKeys
78
- public static IntPtr FocusConsole(uint pid) {
79
- FreeConsole();
80
- if (!AttachConsole(pid)) return IntPtr.Zero;
81
- IntPtr hwnd = GetConsoleWindow();
82
- if (hwnd != IntPtr.Zero) SetForegroundWindow(hwnd);
83
- return hwnd;
75
+ // Inject Enter (VK_RETURN = 0x0D)
76
+ public static int InjectEnter(uint pid) {
77
+ IntPtr hIn = OpenConin(pid);
78
+ if (hIn == new IntPtr(-1)) return -1;
79
+
80
+ var records = new INPUT_RECORD[] {
81
+ new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x0D, UnicodeChar=0x0D },
82
+ new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x0D, UnicodeChar=0x0D }
83
+ };
84
+
85
+ uint written;
86
+ bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);
87
+ CloseHandle(hIn);
88
+ return ok ? (int)written : -2;
89
+ }
90
+
91
+ // Inject Ctrl+U (VK_U = 0x55, char = 0x15)
92
+ public static int InjectCtrlU(uint pid) {
93
+ IntPtr hIn = OpenConin(pid);
94
+ if (hIn == new IntPtr(-1)) return -1;
95
+
96
+ var records = new INPUT_RECORD[] {
97
+ new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=LEFT_CTRL },
98
+ new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x55, UnicodeChar=0x15, dwControlKeyState=LEFT_CTRL },
99
+ new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x55, UnicodeChar=0x15, dwControlKeyState=LEFT_CTRL },
100
+ new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=0 }
101
+ };
102
+
103
+ uint written;
104
+ bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);
105
+ CloseHandle(hIn);
106
+ return ok ? (int)written : -2;
107
+ }
108
+
109
+ // Inject Ctrl+Y (VK_Y = 0x59, char = 0x19)
110
+ public static int InjectCtrlY(uint pid) {
111
+ IntPtr hIn = OpenConin(pid);
112
+ if (hIn == new IntPtr(-1)) return -1;
113
+
114
+ var records = new INPUT_RECORD[] {
115
+ new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=LEFT_CTRL },
116
+ new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x59, UnicodeChar=0x19, dwControlKeyState=LEFT_CTRL },
117
+ new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x59, UnicodeChar=0x19, dwControlKeyState=LEFT_CTRL },
118
+ new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=0 }
119
+ };
120
+
121
+ uint written;
122
+ bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);
123
+ CloseHandle(hIn);
124
+ return ok ? (int)written : -2;
84
125
  }
85
126
  }
86
127
  `;
@@ -118,33 +159,24 @@ async function windowsInject(text) {
118
159
  const script = buildScript(claudePid, `
119
160
  $textBytes = [System.Convert]::FromBase64String('${textB64}')
120
161
  $text = [System.Text.Encoding]::Unicode.GetString($textBytes)
121
- $wsh = New-Object -ComObject WScript.Shell
122
162
 
123
- # 1. Focus console and send Ctrl+U to save user's current text to kill ring
124
- $hwnd = [ConInject]::FocusConsole([uint32]$claudePid)
125
- Start-Sleep -Milliseconds 150
126
- $wsh.SendKeys('^u')
127
- Start-Sleep -Milliseconds 150
163
+ # 1. Ctrl+U to save user's current text to kill ring
164
+ [ConInject]::InjectCtrlU([uint32]$claudePid) | Out-Null
165
+ Start-Sleep -Milliseconds 100
128
166
 
129
167
  # 2. Write question text into console input buffer
130
168
  [ConInject]::InjectText([uint32]$claudePid, $text) | Out-Null
169
+ Start-Sleep -Milliseconds 50
131
170
 
132
- # 3. Re-focus (InjectText calls FreeConsole internally, focus may be lost)
133
- [ConInject]::FocusConsole([uint32]$claudePid) | Out-Null
134
- Start-Sleep -Milliseconds 150
135
-
136
- # 4. Send Enter
137
- $wsh.SendKeys('~')
171
+ # 3. Send Enter
172
+ [ConInject]::InjectEnter([uint32]$claudePid) | Out-Null
138
173
  `);
139
174
  await run(script);
140
175
  }
141
176
  async function windowsInjectCtrlY() {
142
177
  const claudePid = process.ppid;
143
178
  const script = buildScript(claudePid, `
144
- $wsh = New-Object -ComObject WScript.Shell
145
- $hwnd = [ConInject]::FocusConsole([uint32]$claudePid)
146
- Start-Sleep -Milliseconds 150
147
- $wsh.SendKeys('^y')
179
+ [ConInject]::InjectCtrlY([uint32]$claudePid) | Out-Null
148
180
  `);
149
181
  await run(script);
150
182
  }
@@ -211,9 +243,10 @@ var config = {
211
243
  */
212
244
  p2p: {
213
245
  /**
214
- * 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.
215
247
  */
216
- 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)
217
250
  }};
218
251
 
219
252
  // src/infrastructure/p2p/p2p-node.ts
@@ -241,23 +274,47 @@ var P2PNode = class {
241
274
  return this.localMember?.teamName;
242
275
  }
243
276
  /**
244
- * Starts the WS server on the configured fixed port.
277
+ * Starts the WS server on a random available port within the configured range.
245
278
  * Called automatically from join() if not yet started.
246
279
  */
247
280
  async start() {
248
- this.port = config.p2p.port;
249
- 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
+ }
250
297
  this.setupWssHandlers();
251
298
  this._isStarted = true;
252
299
  console.error(`P2P node started on port ${this.port}`);
253
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
+ }
254
311
  async join(teamName, displayName) {
255
312
  if (!this._isStarted) {
256
313
  await this.start();
257
314
  }
258
315
  const memberId = v4();
259
316
  this.localMember = { memberId, teamName, displayName };
260
- return { memberId, teamId: teamName, teamName, displayName, status: "ONLINE" };
317
+ return { memberId, teamId: teamName, teamName, displayName, status: "ONLINE", port: this.port };
261
318
  }
262
319
  /**
263
320
  * Connects to a peer at the given IP and port.
@@ -267,8 +324,7 @@ var P2PNode = class {
267
324
  if (!this.localMember) {
268
325
  throw new Error("Must call join() before connectPeer()");
269
326
  }
270
- const targetPort = port ?? config.p2p.port;
271
- const ws = new WebSocket(`ws://${ip}:${targetPort}`);
327
+ const ws = new WebSocket(`ws://${ip}:${port}`);
272
328
  ws.on("message", (data) => {
273
329
  try {
274
330
  const msg = parseP2PMsg(data.toString());
@@ -288,7 +344,7 @@ var P2PNode = class {
288
344
  });
289
345
  await new Promise((resolve, reject) => {
290
346
  const timeout = setTimeout(
291
- () => reject(new Error(`Connection timeout to ${ip}:${targetPort}`)),
347
+ () => reject(new Error(`Connection timeout to ${ip}:${port}`)),
292
348
  5e3
293
349
  );
294
350
  ws.on("open", () => {
@@ -595,8 +651,10 @@ function registerJoinTool(server, client) {
595
651
  text: `Successfully joined team "${member.teamName}" as "${member.displayName}".
596
652
 
597
653
  Your member ID: ${member.memberId}
598
- Team ID: ${member.teamId}
599
- Status: ${member.status}`
654
+ Status: ${member.status}
655
+ Listening on port: ${member.port}
656
+
657
+ Share this port with the other terminal so they can run: connect_peer("<your-ip>", ${member.port})`
600
658
  }
601
659
  ]
602
660
  };
@@ -616,18 +674,17 @@ Status: ${member.status}`
616
674
  }
617
675
  var connectPeerSchema = {
618
676
  ip: z.string().describe('IP address of the peer to connect to (e.g., "172.16.40.137")'),
619
- port: z.number().optional().describe(`Port the peer is listening on (default: ${config.p2p.port})`)
677
+ port: z.number().describe("Port the peer is listening on (shown in their join response)")
620
678
  };
621
679
  function registerConnectPeerTool(server, client) {
622
680
  server.tool("connect_peer", connectPeerSchema, async (args) => {
623
- const targetPort = args.port ?? config.p2p.port;
624
681
  try {
625
682
  const peerTeam = await client.connectPeer(args.ip, args.port);
626
683
  return {
627
684
  content: [
628
685
  {
629
686
  type: "text",
630
- text: `Connected to peer "${peerTeam}" at ${args.ip}:${targetPort}.`
687
+ text: `Connected to peer "${peerTeam}" at ${args.ip}:${args.port}.`
631
688
  }
632
689
  ]
633
690
  };
@@ -637,7 +694,7 @@ function registerConnectPeerTool(server, client) {
637
694
  content: [
638
695
  {
639
696
  type: "text",
640
- text: `Failed to connect to ${args.ip}:${targetPort}: ${errorMessage}`
697
+ text: `Failed to connect to ${args.ip}:${args.port}: ${errorMessage}`
641
698
  }
642
699
  ],
643
700
  isError: true
@@ -931,13 +988,6 @@ var program = new Command();
931
988
  program.name("claude-collab").description("Real-time P2P team collaboration between Claude Code terminals").version("0.1.0");
932
989
  program.command("client").description("Start MCP client (P2P mode, connects to Claude Code)").action(async () => {
933
990
  const p2pNode = new P2PNode();
934
- try {
935
- await p2pNode.start();
936
- } catch (error) {
937
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
938
- console.error(`Failed to start P2P node: ${errorMessage}`);
939
- process.exit(1);
940
- }
941
991
  await startMcpServer({ client: p2pNode });
942
992
  });
943
993
  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 * CONIN$ gives the real console input handle (not the MCP pipe stdin).\r\n * ppid = Claude Code process — the one actively reading from the console.\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\")] public static extern IntPtr GetConsoleWindow();\r\n [DllImport(\"user32.dll\")] public static extern bool SetForegroundWindow(IntPtr hwnd);\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 only text characters into console input buffer (no Ctrl keys, no Enter)\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 // Focus the console window for WScript.Shell.SendKeys\r\n public static IntPtr FocusConsole(uint pid) {\r\n FreeConsole();\r\n if (!AttachConsole(pid)) return IntPtr.Zero;\r\n IntPtr hwnd = GetConsoleWindow();\r\n if (hwnd != IntPtr.Zero) SetForegroundWindow(hwnd);\r\n return hwnd;\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$wsh = New-Object -ComObject WScript.Shell\r\n\r\n# 1. Focus console and send Ctrl+U to save user's current text to kill ring\r\n$hwnd = [ConInject]::FocusConsole([uint32]$claudePid)\r\nStart-Sleep -Milliseconds 150\r\n$wsh.SendKeys('^u')\r\nStart-Sleep -Milliseconds 150\r\n\r\n# 2. Write question text into console input buffer\r\n[ConInject]::InjectText([uint32]$claudePid, $text) | Out-Null\r\n\r\n# 3. Re-focus (InjectText calls FreeConsole internally, focus may be lost)\r\n[ConInject]::FocusConsole([uint32]$claudePid) | Out-Null\r\nStart-Sleep -Milliseconds 150\r\n\r\n# 4. Send Enter\r\n$wsh.SendKeys('~')\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$wsh = New-Object -ComObject WScript.Shell\r\n$hwnd = [ConInject]::FocusConsole([uint32]$claudePid)\r\nStart-Sleep -Milliseconds 150\r\n$wsh.SendKeys('^y')\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/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":";;;;;;;;;;;;;;AAqFO,SAAS,gBAAgB,GAAA,EAAqB;AACnD,EAAA,OAAO,IAAA,CAAK,UAAU,GAAG,CAAA;AAC3B;AAEO,SAAS,YAAY,IAAA,EAAsB;AAChD,EAAA,OAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AACxB;AC9EA,IAAM,YAAA,GAAe;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AA4GrB,SAAS,WAAA,CAAY,WAAmB,IAAA,EAAsB;AAC5D,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,MAAA,EAAO,EAAG,CAAA,UAAA,EAAa,IAAA,CAAK,GAAA,EAAK,CAAA,IAAA,CAAM,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA;AAChF,EAAA,OAAO;AAAA,QAAA,EACC,OAAO,CAAA;AAAA;AAAA,aAAA,EAEF,SAAS;AAAA,iBAAA,EACL,YAAY,CAAA;AAAA,EAC7B,IAAI;AAAA,CAAA;AAEN;AAEA,SAAS,IAAI,MAAA,EAA+B;AAC1C,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,IAAA,MAAM,UAAU,MAAA,CAAO,IAAA,CAAK,QAAQ,SAAS,CAAA,CAAE,SAAS,QAAQ,CAAA;AAChE,IAAA,QAAA;AAAA,MACE,YAAA;AAAA,MACA,CAAC,YAAA,EAAc,cAAA,EAAgB,QAAA,EAAU,mBAAmB,OAAO,CAAA;AAAA,MACnE,EAAE,aAAa,IAAA,EAAK;AAAA,MACpB,MAAM;AACJ,QAAA,MAAM,OAAA,GAAU,MAAA,CAAO,KAAA,CAAM,mBAAmB,IAAI,CAAC,CAAA;AACrD,QAAA,IAAI,SAAS,IAAI;AAAE,UAAA,UAAA,CAAW,OAAO,CAAA;AAAA,QAAG,CAAA,CAAA,MAAQ;AAAA,QAAW;AAC3D,QAAA,OAAA,EAAQ;AAAA,MACV;AAAA,KACF;AAAA,EACF,CAAC,CAAA;AACH;AAEA,eAAsB,cAAc,IAAA,EAA6B;AAC/D,EAAA,MAAM,YAAY,OAAA,CAAQ,IAAA;AAC1B,EAAA,MAAM,UAAU,MAAA,CAAO,IAAA,CAAK,MAAM,SAAS,CAAA,CAAE,SAAS,QAAQ,CAAA;AAE9D,EAAA,MAAM,MAAA,GAAS,YAAY,SAAA,EAAW;AAAA,iDAAA,EACW,OAAO,CAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,CAazD,CAAA;AAEC,EAAA,MAAM,IAAI,MAAM,CAAA;AAClB;AAEA,eAAsB,kBAAA,GAAoC;AACxD,EAAA,MAAM,YAAY,OAAA,CAAQ,IAAA;AAE1B,EAAA,MAAM,MAAA,GAAS,YAAY,SAAA,EAAW;AAAA;AAAA,CAEvC,CAAA;AAEC,EAAA,MAAM,IAAI,MAAM,CAAA;AAClB;;;ACtKA,SAAS,2BAA2B,QAAA,EAAsC;AAExE,EAAA,MAAM,UAAU,QAAA,CAAS,OAAA,CAAQ,QAAQ,MAAA,EAAQ,GAAG,EAAE,IAAA,EAAK;AAC3D,EAAA,OAAO,CAAA,gBAAA,EAAmB,QAAA,CAAS,UAAU,CAAA,GAAA,EAAM,SAAS,IAAA,CAAK,WAAW,CAAA,EAAA,EAAK,QAAA,CAAS,KAAK,QAAQ,CAAA,GAAA,EAAM,OAAO,CAAA,8BAAA,EAAiC,SAAS,UAAU,CAAA,kCAAA,CAAA;AAC1K;AAMA,eAAsB,yBAAyB,QAAA,EAA6C;AAC1F,EAAA,IAAI,OAAA,CAAQ,aAAa,OAAA,EAAS;AAElC,EAAA,MAAM,IAAA,GAAO,2BAA2B,QAAQ,CAAA;AAChD,EAAA,MAAM,cAAc,IAAI,CAAA;AAC1B;AAMA,eAAsB,iBAAA,GAAmC;AACvD,EAAA,IAAI,OAAA,CAAQ,aAAa,OAAA,EAAS;AAClC,EAAA,MAAM,kBAAA,EAAmB;AAC3B;;;AC1BA,IAAM,gBAAA,GAAmB,IAAI,EAAA,GAAK,GAAA;AAElC,IAAM,cAAA,GAAN,cAA6B,YAAA,CAAa;AAAA,EAChC,QAA8B,EAAC;AAAA,EAC/B,UAAA,GAAa,KAAA;AAAA;AAAA;AAAA;AAAA,EAKrB,QAAQ,QAAA,EAAoC;AAC1C,IAAA,IAAA,CAAK,KAAA,CAAM,KAAK,QAAQ,CAAA;AACxB,IAAA,IAAI,CAAC,IAAA,CAAK,UAAA,EAAY,KAAK,KAAK,WAAA,EAAY;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAA,GAAsB;AACpB,IAAA,IAAA,CAAK,KAAK,SAAS,CAAA;AAAA,EACrB;AAAA,EAEA,MAAc,WAAA,GAA6B;AACzC,IAAA,IAAI,IAAA,CAAK,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG;AAC3B,MAAA,IAAA,CAAK,UAAA,GAAa,KAAA;AAClB,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,KAAA,CAAM,KAAA,EAAM;AAGlC,IAAA,MAAM,yBAAyB,QAAQ,CAAA;AAGvC,IAAA,MAAM,IAAI,OAAA,CAAc,CAAC,OAAA,KAAY;AACnC,MAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,OAAA,EAAS,gBAAgB,CAAA;AAClD,MAAA,IAAA,CAAK,IAAA,CAAK,WAAW,MAAM;AACzB,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,OAAA,EAAQ;AAAA,MACV,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAGD,IAAA,MAAM,iBAAA,EAAkB;AAGxB,IAAA,KAAK,KAAK,WAAA,EAAY;AAAA,EACxB;AACF,CAAA;AAEO,IAAM,cAAA,GAAiB,IAAI,cAAA,EAAe;;;ACtD1C,IAAM,MAAA,GAAS;AAAA;AAAA;AAAA;AAAA,EAIpB,GAAA,EAAK;AAAA;AAAA;AAAA;AAAA,IAIH,cAAc,MAAA,CAAO,OAAA,CAAQ,GAAA,CAAI,wBAAwB,KAAK,KAAK,CAAA;AAAA,IACnE,cAAc,MAAA,CAAO,OAAA,CAAQ,GAAA,CAAI,wBAAwB,KAAK,KAAK;AAAA,GAiBvE,CAAA;;;ACwBO,IAAM,UAAN,MAAuC;AAAA,EACpC,GAAA,GAA8B,IAAA;AAAA,EAC9B,IAAA,GAAO,CAAA;AAAA;AAAA,EAGE,SAAA,uBAAgB,GAAA,EAAuB;AAAA;AAAA,EAEvC,QAAA,uBAAe,GAAA,EAAuB;AAAA;AAAA,EAGtC,iBAAA,uBAAwB,GAAA,EAA8B;AAAA;AAAA,EAGtD,eAAA,uBAAsB,GAAA,EAA4B;AAAA;AAAA,EAGlD,cAAA,uBAAqB,GAAA,EAAoB;AAAA;AAAA,EAGzC,eAAA,uBAAsB,GAAA,EAA2B;AAAA,EAE1D,WAAA,GAAkC,IAAA;AAAA,EAClC,UAAA,GAAa,KAAA;AAAA,EAErB,IAAI,WAAA,GAAuB;AACzB,IAAA,OAAO,IAAA,CAAK,UAAA;AAAA,EACd;AAAA,EAEA,IAAI,aAAA,GAAoC;AACtC,IAAA,OAAO,KAAK,WAAA,EAAa,QAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,KAAA,GAAuB;AAC3B,IAAA,MAAM,EAAE,YAAA,EAAc,YAAA,EAAa,GAAI,MAAA,CAAO,GAAA;AAC9C,IAAA,MAAM,KAAA,GAAQ,eAAe,YAAA,GAAe,CAAA;AAC5C,IAAA,MAAM,cAAc,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,MAAA,KAAW,KAAK,CAAA;AAEpD,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,MAAA,MAAM,IAAA,GAAO,YAAA,GAAA,CAAiB,WAAA,GAAc,CAAA,IAAK,KAAA;AACjD,MAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAA;AACrC,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,QAAA;AAAA,MACF;AAAA,IACF;AAEA,IAAA,IAAI,CAAC,KAAK,GAAA,EAAK;AACb,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,2BAAA,EAA8B,YAAY,CAAA,CAAA,EAAI,YAAY,CAAA,gEAAA;AAAA,OAE5D;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,gBAAA,EAAiB;AACtB,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,IAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,yBAAA,EAA4B,IAAA,CAAK,IAAI,CAAA,CAAE,CAAA;AAAA,EACvD;AAAA,EAEQ,QAAQ,IAAA,EAAgC;AAC9C,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,MAAM,GAAA,GAAM,IAAI,eAAA,CAAgB,EAAE,MAAM,CAAA;AACxC,MAAA,GAAA,CAAI,IAAA,CAAK,aAAa,MAAM;AAC1B,QAAA,IAAA,CAAK,GAAA,GAAM,GAAA;AACX,QAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,MACd,CAAC,CAAA;AACD,MAAA,GAAA,CAAI,IAAA,CAAK,OAAA,EAAS,MAAM,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,IACxC,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,IAAA,CAAK,QAAA,EAAkB,WAAA,EAA0C;AACrE,IAAA,IAAI,CAAC,KAAK,UAAA,EAAY;AACpB,MAAA,MAAM,KAAK,KAAA,EAAM;AAAA,IACnB;AAEA,IAAA,MAAM,WAAWA,EAAA,EAAO;AACxB,IAAA,IAAA,CAAK,WAAA,GAAc,EAAE,QAAA,EAAU,QAAA,EAAU,WAAA,EAAY;AAErD,IAAA,OAAO,EAAE,QAAA,EAAU,MAAA,EAAQ,QAAA,EAAU,QAAA,EAAU,aAAa,MAAA,EAAQ,QAAA,EAAU,IAAA,EAAM,IAAA,CAAK,IAAA,EAAK;AAAA,EAChG;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAA,CAAY,EAAA,EAAY,IAAA,EAA+B;AAC3D,IAAA,IAAI,CAAC,KAAK,WAAA,EAAa;AACrB,MAAA,MAAM,IAAI,MAAM,uCAAuC,CAAA;AAAA,IACzD;AAEA,IAAA,MAAM,KAAK,IAAI,SAAA,CAAU,QAAQ,EAAE,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,CAAA;AAG7C,IAAA,EAAA,CAAG,EAAA,CAAG,SAAA,EAAW,CAAC,IAAA,KAAS;AACzB,MAAA,IAAI;AACF,QAAA,MAAM,GAAA,GAAM,WAAA,CAAY,IAAA,CAAK,QAAA,EAAU,CAAA;AACvC,QAAA,IAAA,CAAK,aAAA,CAAc,IAAI,GAAG,CAAA;AAAA,MAC5B,SAAS,GAAA,EAAK;AACZ,QAAA,OAAA,CAAQ,KAAA,CAAM,gCAAgC,GAAG,CAAA;AAAA,MACnD;AAAA,IACF,CAAC,CAAA;AAED,IAAA,EAAA,CAAG,EAAA,CAAG,SAAS,MAAM;AACnB,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,EAAE,CAAA;AACjC,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,IAAI,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,IAAI,MAAM,EAAA,EAAI;AACnC,UAAA,IAAA,CAAK,SAAA,CAAU,OAAO,IAAI,CAAA;AAAA,QAC5B;AACA,QAAA,IAAA,CAAK,QAAA,CAAS,OAAO,EAAE,CAAA;AAAA,MACzB;AAAA,IACF,CAAC,CAAA;AAGD,IAAA,MAAM,IAAI,OAAA,CAAc,CAAC,OAAA,EAAS,MAAA,KAAW;AAC3C,MAAA,MAAM,OAAA,GAAU,UAAA;AAAA,QACd,MAAM,OAAO,IAAI,KAAA,CAAM,yBAAyB,EAAE,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,CAAC,CAAA;AAAA,QAC7D;AAAA,OACF;AAEA,MAAA,EAAA,CAAG,EAAA,CAAG,QAAQ,MAAM;AAClB,QAAA,YAAA,CAAa,OAAO,CAAA;AACpB,QAAA,MAAM,KAAA,GAAqB;AAAA,UACzB,IAAA,EAAM,WAAA;AAAA,UACN,QAAA,EAAU,KAAK,WAAA,CAAa,QAAA;AAAA,UAC5B,YAAA,EAAc,KAAK,WAAA,CAAa;AAAA,SAClC;AACA,QAAA,EAAA,CAAG,IAAA,CAAK,eAAA,CAAgB,KAAK,CAAC,CAAA;AAC9B,QAAA,OAAA,EAAQ;AAAA,MACV,CAAC,CAAA;AAED,MAAA,EAAA,CAAG,EAAA,CAAG,OAAA,EAAS,CAAC,GAAA,KAAQ;AACtB,QAAA,YAAA,CAAa,OAAO,CAAA;AACpB,QAAA,MAAA,CAAO,GAAG,CAAA;AAAA,MACZ,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAGD,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,eAAA;AAAA,MAC1B,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,WAAA;AAAA,MAClB;AAAA,KACF;AAEA,IAAA,OAAO,QAAA,CAAS,QAAA;AAAA,EAClB;AAAA,EAEA,MAAM,GAAA,CAAI,MAAA,EAAgB,OAAA,EAAiB,MAAA,EAAwC;AACjF,IAAA,MAAM,EAAA,GAAK,MAAM,IAAA,CAAK,iBAAA,CAAkB,MAAM,CAAA;AAC9C,IAAA,MAAM,aAAaA,EAAA,EAAO;AAC1B,IAAA,MAAM,YAAYA,EAAA,EAAO;AAEzB,IAAA,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,UAAA,EAAY,MAAM,CAAA;AAG1C,IAAA,MAAM,aAAa,IAAA,CAAK,eAAA;AAAA,MACtB,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,aAAA,IAAiB,EAAE,SAAA,KAAc,SAAA;AAAA,MACnD;AAAA,KACF;AAEA,IAAA,MAAM,GAAA,GAAiB;AAAA,MACrB,IAAA,EAAM,SAAA;AAAA,MACN,UAAA;AAAA,MACA,YAAA,EAAc,KAAK,WAAA,CAAa,QAAA;AAAA,MAChC,QAAA,EAAU,KAAK,WAAA,CAAa,QAAA;AAAA,MAC5B,MAAA;AAAA,MACA,OAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,EAAA,CAAG,IAAA,CAAK,eAAA,CAAgB,GAAG,CAAC,CAAA;AAE5B,IAAA,MAAM,UAAA;AACN,IAAA,OAAO,UAAA;AAAA,EACT;AAAA,EAEA,MAAM,YAAY,UAAA,EAAuD;AAEvE,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,UAAU,CAAA;AAClD,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,OAAO;AAAA,QACL,UAAA;AAAA,QACA,IAAA,EAAM,EAAE,WAAA,EAAa,CAAA,EAAG,OAAO,QAAQ,CAAA,OAAA,CAAA,EAAW,QAAA,EAAU,MAAA,CAAO,QAAA,EAAS;AAAA,QAC5E,SAAS,MAAA,CAAO,OAAA;AAAA,QAChB,QAAQ,MAAA,CAAO,MAAA;AAAA,QACf,YAAY,MAAA,CAAO;AAAA,OACrB;AAAA,IACF;AAGA,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,UAAU,CAAA;AACjD,IAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AAEpB,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,MAAM,CAAA;AACpC,IAAA,IAAI,CAAC,EAAA,IAAM,EAAA,CAAG,UAAA,KAAe,SAAA,CAAU,MAAM,OAAO,IAAA;AAEpD,IAAA,MAAM,YAAYA,EAAA,EAAO;AAEzB,IAAA,MAAM,kBAAkB,IAAA,CAAK,eAAA;AAAA,MAC3B,CAAC,CAAA,KACE,CAAA,CAAE,IAAA,KAAS,YAAA,IAAgB,CAAA,CAAE,UAAA,KAAe,UAAA,IAC5C,CAAA,CAAE,IAAA,KAAS,oBAAA,IAAwB,CAAA,CAAE,SAAA,KAAc,SAAA;AAAA,MACtD;AAAA,KACF;AAEA,IAAA,MAAM,MAAA,GAA0B;AAAA,MAC9B,IAAA,EAAM,gBAAA;AAAA,MACN,UAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,EAAA,CAAG,IAAA,CAAK,eAAA,CAAgB,MAAM,CAAC,CAAA;AAE/B,IAAA,MAAM,WAAW,MAAM,eAAA;AACvB,IAAA,IAAI,QAAA,CAAS,IAAA,KAAS,oBAAA,EAAsB,OAAO,IAAA;AAEnD,IAAA,MAAM,MAAA,GAAS,QAAA;AACf,IAAA,IAAA,CAAK,eAAA,CAAgB,IAAI,UAAA,EAAY;AAAA,MACnC,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,YAAY,MAAA,CAAO,UAAA;AAAA,MACnB,UAAU,MAAA,CAAO,QAAA;AAAA,MACjB,cAAc,MAAA,CAAO;AAAA,KACtB,CAAA;AAED,IAAA,OAAO;AAAA,MACL,UAAA;AAAA,MACA,IAAA,EAAM,EAAE,WAAA,EAAa,CAAA,EAAG,OAAO,QAAQ,CAAA,OAAA,CAAA,EAAW,QAAA,EAAU,MAAA,CAAO,QAAA,EAAS;AAAA,MAC5E,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,YAAY,MAAA,CAAO;AAAA,KACrB;AAAA,EACF;AAAA,EAEA,MAAM,KAAA,CAAM,UAAA,EAAoB,OAAA,EAAiB,MAAA,EAAsC;AACrF,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,iBAAA,CAAkB,GAAA,CAAI,UAAU,CAAA;AACtD,IAAA,IAAI,CAAC,QAAA,EAAU,MAAM,IAAI,KAAA,CAAM,CAAA,SAAA,EAAY,UAAU,CAAA,mBAAA,CAAqB,CAAA;AAE1E,IAAA,QAAA,CAAS,QAAA,GAAW,IAAA;AACpB,IAAA,QAAA,CAAS,aAAA,GAAgB,OAAA;AACzB,IAAA,QAAA,CAAS,YAAA,GAAe,MAAA;AAExB,IAAA,MAAM,SAAA,GAA0B;AAAA,MAC9B,IAAA,EAAM,YAAA;AAAA,MACN,UAAA;AAAA,MACA,OAAA;AAAA,MACA,MAAA;AAAA,MACA,UAAA,EAAA,iBAAY,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MACnC,QAAA,EAAU,KAAK,WAAA,CAAa,QAAA;AAAA,MAC5B,YAAA,EAAc,KAAK,WAAA,CAAa;AAAA,KAClC;AAEA,IAAA,IAAI,QAAA,CAAS,EAAA,CAAG,UAAA,KAAe,SAAA,CAAU,IAAA,EAAM;AAC7C,MAAA,QAAA,CAAS,EAAA,CAAG,IAAA,CAAK,eAAA,CAAgB,SAAS,CAAC,CAAA;AAAA,IAC7C;AAAA,EACF;AAAA,EAEA,MAAM,QAAA,GAAiC;AACrC,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,MAAM,YAAY,CAAC,GAAG,IAAA,CAAK,iBAAA,CAAkB,QAAQ,CAAA,CAClD,MAAA,CAAO,CAAC,MAAM,CAAC,CAAA,CAAE,QAAQ,CAAA,CACzB,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,MACX,YAAY,CAAA,CAAE,UAAA;AAAA,MACd,IAAA,EAAM,EAAE,WAAA,EAAa,CAAA,EAAG,EAAE,QAAQ,CAAA,OAAA,CAAA,EAAW,QAAA,EAAU,CAAA,CAAE,QAAA,EAAS;AAAA,MAClE,SAAS,CAAA,CAAE,OAAA;AAAA,MACX,QAAQ,CAAA,CAAE,MAAA;AAAA,MACV,MAAA,EAAQ,SAAA;AAAA,MACR,SAAA,EAAW,CAAA,CAAE,SAAA,CAAU,WAAA,EAAY;AAAA,MACnC,KAAA,EAAO,GAAA,GAAM,CAAA,CAAE,SAAA,CAAU,OAAA;AAAQ,KACnC,CAAE,CAAA;AAEJ,IAAA,OAAO;AAAA,MACL,SAAA;AAAA,MACA,YAAY,SAAA,CAAU,MAAA;AAAA,MACtB,cAAc,SAAA,CAAU;AAAA,KAC1B;AAAA,EACF;AAAA,EAEA,MAAM,UAAA,GAA4B;AAChC,IAAA,KAAA,MAAW,EAAA,IAAM,IAAA,CAAK,SAAA,CAAU,MAAA,EAAO,EAAG;AACxC,MAAA,EAAA,CAAG,KAAA,EAAM;AAAA,IACX;AACA,IAAA,IAAA,CAAK,UAAU,KAAA,EAAM;AAErB,IAAA,MAAM,IAAI,OAAA,CAAc,CAAC,OAAA,KAAY;AACnC,MAAA,IAAI,KAAK,GAAA,EAAK;AACZ,QAAA,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,MAAM,OAAA,EAAS,CAAA;AAAA,MAChC,CAAA,MAAO;AACL,QAAA,OAAA,EAAQ;AAAA,MACV;AAAA,IACF,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,UAAA,GAAa,KAAA;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAMQ,gBAAA,GAAyB;AAC/B,IAAA,IAAA,CAAK,GAAA,CAAK,EAAA,CAAG,YAAA,EAAc,CAAC,EAAA,KAAO;AACjC,MAAA,EAAA,CAAG,EAAA,CAAG,SAAA,EAAW,CAAC,IAAA,KAAS;AACzB,QAAA,IAAI;AACF,UAAA,MAAM,GAAA,GAAM,WAAA,CAAY,IAAA,CAAK,QAAA,EAAU,CAAA;AAGvC,UAAA,IAAI,GAAA,CAAI,IAAA,KAAS,WAAA,IAAe,IAAA,CAAK,WAAA,EAAa;AAChD,YAAA,MAAM,KAAA,GAAqB;AAAA,cACzB,IAAA,EAAM,WAAA;AAAA,cACN,QAAA,EAAU,KAAK,WAAA,CAAY,QAAA;AAAA,cAC3B,YAAA,EAAc,KAAK,WAAA,CAAY;AAAA,aACjC;AACA,YAAA,EAAA,CAAG,IAAA,CAAK,eAAA,CAAgB,KAAK,CAAC,CAAA;AAAA,UAChC;AAEA,UAAA,IAAA,CAAK,aAAA,CAAc,IAAI,GAAG,CAAA;AAAA,QAC5B,SAAS,GAAA,EAAK;AACZ,UAAA,OAAA,CAAQ,KAAA,CAAM,yCAAyC,GAAG,CAAA;AAAA,QAC5D;AAAA,MACF,CAAC,CAAA;AAED,MAAA,EAAA,CAAG,EAAA,CAAG,SAAS,MAAM;AACnB,QAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,EAAE,CAAA;AACjC,QAAA,IAAI,IAAA,EAAM;AACR,UAAA,IAAI,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,IAAI,MAAM,EAAA,EAAI;AACnC,YAAA,IAAA,CAAK,SAAA,CAAU,OAAO,IAAI,CAAA;AAAA,UAC5B;AACA,UAAA,IAAA,CAAK,QAAA,CAAS,OAAO,EAAE,CAAA;AAAA,QACzB;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAMQ,aAAA,CAAc,IAAe,GAAA,EAAmB;AAEtD,IAAA,KAAA,MAAW,OAAA,IAAW,KAAK,eAAA,EAAiB;AAC1C,MAAA,OAAA,CAAQ,GAAG,CAAA;AAAA,IACb;AAEA,IAAA,QAAQ,IAAI,IAAA;AAAM,MAChB,KAAK,WAAA;AACH,QAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,EAAA,EAAI,GAAA,CAAI,QAAQ,CAAA;AAClC,QAAA,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,GAAA,CAAI,QAAA,EAAU,EAAE,CAAA;AACnC,QAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,iBAAA,EAAoB,GAAA,CAAI,QAAQ,CAAA,CAAE,CAAA;AAChD,QAAA;AAAA,MAEF,KAAK,SAAA;AACH,QAAA,IAAA,CAAK,iBAAA,CAAkB,IAAI,GAAG,CAAA;AAC9B,QAAA;AAAA,MAEF,KAAK,gBAAA;AACH,QAAA,IAAA,CAAK,eAAA,CAAgB,IAAI,GAAG,CAAA;AAC5B,QAAA;AAAA,MAEF,KAAK,YAAA;AAEH,QAAA,IAAI,CAAC,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,GAAA,CAAI,UAAU,CAAA,EAAG;AAC7C,UAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,GAAA,CAAI,UAAA,EAAY;AAAA,YACvC,SAAS,GAAA,CAAI,OAAA;AAAA,YACb,QAAQ,GAAA,CAAI,MAAA;AAAA,YACZ,YAAY,GAAA,CAAI,UAAA;AAAA,YAChB,UAAU,GAAA,CAAI,QAAA;AAAA,YACd,cAAc,GAAA,CAAI;AAAA,WACnB,CAAA;AAAA,QACH;AACA,QAAA;AAAA,MAEF,KAAK,UAAA;AACH,QAAA,EAAA,CAAG,KAAK,eAAA,CAAgB,EAAE,IAAA,EAAM,UAAA,EAAY,CAAC,CAAA;AAC7C,QAAA;AAAA;AAIJ,EACF;AAAA,EAEQ,iBAAA,CAAkB,IAAe,GAAA,EAAsB;AAC7D,IAAA,IAAA,CAAK,iBAAA,CAAkB,GAAA,CAAI,GAAA,CAAI,UAAA,EAAY;AAAA,MACzC,YAAY,GAAA,CAAI,UAAA;AAAA,MAChB,UAAU,GAAA,CAAI,QAAA;AAAA,MACd,cAAc,GAAA,CAAI,YAAA;AAAA,MAClB,SAAS,GAAA,CAAI,OAAA;AAAA,MACb,QAAQ,GAAA,CAAI,MAAA;AAAA,MACZ,SAAA,sBAAe,IAAA,EAAK;AAAA,MACpB,EAAA;AAAA,MACA,QAAA,EAAU;AAAA,KACX,CAAA;AAGD,IAAA,cAAA,CAAe,OAAA,CAAQ;AAAA,MACrB,YAAY,GAAA,CAAI,UAAA;AAAA,MAChB,IAAA,EAAM;AAAA,QACJ,WAAA,EAAa,CAAA,EAAG,GAAA,CAAI,QAAQ,CAAA,OAAA,CAAA;AAAA,QAC5B,UAAU,GAAA,CAAI;AAAA,OAChB;AAAA,MACA,SAAS,GAAA,CAAI,OAAA;AAAA,MACb,QAAQ,GAAA,CAAI,MAAA;AAAA,MACZ,MAAA,EAAQ,SAAA;AAAA,MACR,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MAClC,KAAA,EAAO;AAAA,KACR,CAAA;AAGD,IAAA,MAAM,GAAA,GAAoB;AAAA,MACxB,IAAA,EAAM,aAAA;AAAA,MACN,YAAY,GAAA,CAAI,UAAA;AAAA,MAChB,WAAW,GAAA,CAAI;AAAA,KACjB;AACA,IAAA,EAAA,CAAG,IAAA,CAAK,eAAA,CAAgB,GAAG,CAAC,CAAA;AAAA,EAC9B;AAAA,EAEQ,eAAA,CAAgB,IAAe,GAAA,EAA4B;AACjE,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,iBAAA,CAAkB,GAAA,CAAI,IAAI,UAAU,CAAA;AAE1D,IAAA,IAAI,CAAC,UAAU,QAAA,EAAU;AACvB,MAAA,MAAM,OAAA,GAA+B;AAAA,QACnC,IAAA,EAAM,oBAAA;AAAA,QACN,YAAY,GAAA,CAAI,UAAA;AAAA,QAChB,WAAW,GAAA,CAAI;AAAA,OACjB;AACA,MAAA,EAAA,CAAG,IAAA,CAAK,eAAA,CAAgB,OAAO,CAAC,CAAA;AAChC,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,MAAA,GAAuB;AAAA,MAC3B,IAAA,EAAM,YAAA;AAAA,MACN,YAAY,GAAA,CAAI,UAAA;AAAA,MAChB,SAAS,QAAA,CAAS,aAAA;AAAA,MAClB,QAAQ,QAAA,CAAS,YAAA;AAAA,MACjB,UAAA,EAAA,iBAAY,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MACnC,QAAA,EAAU,KAAK,WAAA,CAAa,QAAA;AAAA,MAC5B,YAAA,EAAc,KAAK,WAAA,CAAa,QAAA;AAAA,MAChC,WAAW,GAAA,CAAI;AAAA,KACjB;AACA,IAAA,EAAA,CAAG,IAAA,CAAK,eAAA,CAAgB,MAAM,CAAC,CAAA;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,kBAAkB,QAAA,EAAsC;AACpE,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,QAAQ,CAAA;AAC5C,IAAA,IAAI,QAAA,IAAY,QAAA,CAAS,UAAA,KAAe,SAAA,CAAU,IAAA,EAAM;AACtD,MAAA,OAAO,QAAA;AAAA,IACT;AAEA,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,0BAA0B,QAAQ,CAAA,8CAAA;AAAA,KACpC;AAAA,EACF;AAAA,EAEQ,eAAA,CACN,QACA,SAAA,EACY;AACZ,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,OAAA,GAAU,WAAW,MAAM;AAC/B,QAAA,IAAA,CAAK,eAAA,CAAgB,OAAO,OAAO,CAAA;AACnC,QAAA,MAAA,CAAO,IAAI,KAAA,CAAM,uBAAuB,CAAC,CAAA;AAAA,MAC3C,GAAG,SAAS,CAAA;AAEZ,MAAA,MAAM,OAAA,GAAU,CAAC,GAAA,KAAsB;AACrC,QAAA,IAAI,MAAA,CAAO,GAAG,CAAA,EAAG;AACf,UAAA,YAAA,CAAa,OAAO,CAAA;AACpB,UAAA,IAAA,CAAK,eAAA,CAAgB,OAAO,OAAO,CAAA;AACnC,UAAA,OAAA,CAAQ,GAAQ,CAAA;AAAA,QAClB;AAAA,MACF,CAAA;AAEA,MAAA,IAAA,CAAK,eAAA,CAAgB,IAAI,OAAO,CAAA;AAAA,IAClC,CAAC,CAAA;AAAA,EACH;AACF,CAAA;AC1gBA,IAAM,UAAA,GAAa;AAAA,EACjB,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO,CAAE,SAAS,2DAA2D,CAAA;AAAA,EACrF,aAAa,CAAA,CACV,MAAA,GACA,QAAA,EAAS,CACT,SAAS,4DAA4D;AAC1E,CAAA;AAKO,SAAS,gBAAA,CAAiB,QAAmB,MAAA,EAA6B;AAC/E,EAAA,MAAA,CAAO,IAAA,CAAK,MAAA,EAAQ,UAAA,EAAY,OAAO,IAAA,KAAS;AAC9C,IAAA,MAAM,WAAW,IAAA,CAAK,IAAA;AACtB,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,WAAA,IAAe,CAAA,EAAG,QAAQ,CAAA,OAAA,CAAA;AAEnD,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,IAAA,CAAK,UAAU,WAAW,CAAA;AAEtD,MAAA,OAAO;AAAA,QACL,OAAA,EAAS;AAAA,UACP;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,MAAM,CAAA,0BAAA,EAA6B,MAAA,CAAO,QAAQ,CAAA,MAAA,EAAS,OAAO,WAAW,CAAA;;AAAA,gBAAA,EAAyB,OAAO,QAAQ;AAAA,QAAA,EAAa,OAAO,MAAM;AAAA,mBAAA,EAAwB,OAAO,IAAI;;AAAA,mFAAA,EAA0F,OAAO,IAAI,CAAA,CAAA;AAAA;AACzR;AACF,OACF;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,YAAA,GAAe,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,eAAA;AAC9D,MAAA,OAAO;AAAA,QACL,OAAA,EAAS;AAAA,UACP;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,wBAAwB,YAAY,CAAA;AAAA;AAC5C,SACF;AAAA,QACA,OAAA,EAAS;AAAA,OACX;AAAA,IACF;AAAA,EACF,CAAC,CAAA;AACH;AC3CA,IAAM,iBAAA,GAAoB;AAAA,EACxB,EAAA,EAAIC,CAAAA,CAAE,MAAA,EAAO,CAAE,SAAS,8DAA8D,CAAA;AAAA,EACtF,IAAA,EAAMA,CAAAA,CAAE,MAAA,EAAO,CAAE,SAAS,8DAA8D;AAC1F,CAAA;AAEO,SAAS,uBAAA,CAAwB,QAAmB,MAAA,EAA6B;AACtF,EAAA,MAAA,CAAO,IAAA,CAAK,cAAA,EAAgB,iBAAA,EAAmB,OAAO,IAAA,KAAS;AAC7D,IAAA,IAAI;AACF,MAAA,MAAM,WAAW,MAAM,MAAA,CAAO,YAAY,IAAA,CAAK,EAAA,EAAI,KAAK,IAAI,CAAA;AAE5D,MAAA,OAAO;AAAA,QACL,OAAA,EAAS;AAAA,UACP;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,sBAAsB,QAAQ,CAAA,KAAA,EAAQ,KAAK,EAAE,CAAA,CAAA,EAAI,KAAK,IAAI,CAAA,CAAA;AAAA;AAClE;AACF,OACF;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,YAAA,GAAe,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,eAAA;AAC9D,MAAA,OAAO;AAAA,QACL,OAAA,EAAS;AAAA,UACP;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,wBAAwB,IAAA,CAAK,EAAE,IAAI,IAAA,CAAK,IAAI,KAAK,YAAY,CAAA;AAAA;AACrE,SACF;AAAA,QACA,OAAA,EAAS;AAAA,OACX;AAAA,IACF;AAAA,EACF,CAAC,CAAA;AACH;AC3BA,IAAM,SAAA,GAAY;AAAA,EAChB,IAAA,EAAMA,CAAAA,CAAE,MAAA,EAAO,CAAE,SAAS,uDAAuD,CAAA;AAAA,EACjF,QAAA,EAAUA,CAAAA,CAAE,MAAA,EAAO,CAAE,SAAS,yCAAyC;AACzE,CAAA;AAKO,SAAS,eAAA,CAAgB,QAAmB,MAAA,EAA6B;AAC9E,EAAA,MAAA,CAAO,IAAA,CAAK,KAAA,EAAO,SAAA,EAAW,OAAO,IAAA,KAAS;AAC5C,IAAA,MAAM,aAAa,IAAA,CAAK,IAAA;AACxB,IAAA,MAAM,WAAW,IAAA,CAAK,QAAA;AAEtB,IAAA,IAAI;AACF,MAAA,IAAI,CAAC,OAAO,aAAA,EAAe;AACzB,QAAA,OAAO;AAAA,UACL,OAAA,EAAS;AAAA,YACP;AAAA,cACE,IAAA,EAAM,MAAA;AAAA,cACN,IAAA,EAAM;AAAA;AACR,WACF;AAAA,UACA,OAAA,EAAS;AAAA,SACX;AAAA,MACF;AAEA,MAAA,MAAM,aAAa,MAAM,MAAA,CAAO,GAAA,CAAI,UAAA,EAAY,UAAU,UAAU,CAAA;AAGpE,MAAA,MAAM,gBAAA,GAAmB,GAAA;AACzB,MAAA,MAAM,WAAA,GAAc,IAAI,EAAA,GAAK,GAAA;AAC7B,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI,GAAI,WAAA;AAE9B,MAAA,OAAO,IAAA,CAAK,GAAA,EAAI,GAAI,QAAA,EAAU;AAC5B,QAAA,MAAM,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,gBAAgB,CAAC,CAAA;AACpE,QAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,WAAA,CAAY,UAAU,CAAA;AAClD,QAAA,IAAI,WAAW,IAAA,EAAM;AACnB,UAAA,OAAO;AAAA,YACL,OAAA,EAAS;AAAA,cACP;AAAA,gBACE,IAAA,EAAM,MAAA;AAAA,gBACN,IAAA,EAAM,KAAK,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,EAAA,EAAK,MAAA,CAAO,KAAK,QAAQ,CAAA;;AAAA,EAAqB,OAAO,OAAO,CAAA;AAAA;AAChG;AACF,WACF;AAAA,QACF;AAAA,MACF;AAGA,MAAA,OAAO;AAAA,QACL,OAAA,EAAS;AAAA,UACP;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,CAAA;AAAA,eAAA,EAAwE,UAAU,CAAA;;AAAA,+DAAA;AAAA;AAC1F;AACF,OACF;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,YAAA,GAAe,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,eAAA;AAC9D,MAAA,OAAO;AAAA,QACL,OAAA,EAAS;AAAA,UACP;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,4BAA4B,YAAY,CAAA;AAAA;AAChD,SACF;AAAA,QACA,OAAA,EAAS;AAAA,OACX;AAAA,IACF;AAAA,EACF,CAAC,CAAA;AACH;ACtEA,IAAM,iBAAA,GAAoB;AAAA,EACxB,WAAA,EAAaA,CAAAA,CAAE,MAAA,EAAO,CAAE,SAAS,4CAA4C;AAC/E,CAAA;AAKO,SAAS,uBAAA,CAAwB,QAAmB,MAAA,EAA6B;AACtF,EAAA,MAAA,CAAO,IAAA,CAAK,cAAA,EAAgB,iBAAA,EAAmB,OAAO,IAAA,KAAS;AAC7D,IAAA,MAAM,aAAa,IAAA,CAAK,WAAA;AAExB,IAAA,IAAI;AACF,MAAA,IAAI,CAAC,OAAO,aAAA,EAAe;AACzB,QAAA,OAAO;AAAA,UACL,OAAA,EAAS;AAAA,YACP;AAAA,cACE,IAAA,EAAM,MAAA;AAAA,cACN,IAAA,EAAM;AAAA;AACR,WACF;AAAA,UACA,OAAA,EAAS;AAAA,SACX;AAAA,MACF;AAEA,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,WAAA,CAAY,UAAU,CAAA;AAElD,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,OAAO;AAAA,UACL,OAAA,EAAS;AAAA,YACP;AAAA,cACE,IAAA,EAAM,MAAA;AAAA,cACN,IAAA,EAAM,gCAAgC,UAAU,CAAA,sFAAA;AAAA;AAClD;AACF,SACF;AAAA,MACF;AAEA,MAAA,OAAO;AAAA,QACL,OAAA,EAAS;AAAA,UACP;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,iBAAiB,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,EAAA,EAAK,MAAA,CAAO,KAAK,QAAQ,CAAA;;AAAA,EAAW,OAAO,OAAO,CAAA;AAAA;AAClG;AACF,OACF;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,YAAA,GAAe,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,eAAA;AAC9D,MAAA,OAAO;AAAA,QACL,OAAA,EAAS;AAAA,UACP;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,2BAA2B,YAAY,CAAA;AAAA;AAC/C,SACF;AAAA,QACA,OAAA,EAAS;AAAA,OACX;AAAA,IACF;AAAA,EACF,CAAC,CAAA;AACH;;;AC5DA,IAAM,cAAc,EAAC;AAKd,SAAS,iBAAA,CAAkB,QAAmB,MAAA,EAA6B;AAChF,EAAA,MAAA,CAAO,IAAA,CAAK,OAAA,EAAS,WAAA,EAAa,YAAY;AAC5C,IAAA,IAAI;AACF,MAAA,IAAI,CAAC,OAAO,aAAA,EAAe;AACzB,QAAA,OAAO;AAAA,UACL,OAAA,EAAS;AAAA,YACP;AAAA,cACE,IAAA,EAAM,MAAA;AAAA,cACN,IAAA,EAAM;AAAA;AACR,WACF;AAAA,UACA,OAAA,EAAS;AAAA,SACX;AAAA,MACF;AAEA,MAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO,QAAA,EAAS;AAEpC,MAAA,IAAI,KAAA,CAAM,SAAA,CAAU,MAAA,KAAW,CAAA,EAAG;AAChC,QAAA,OAAO;AAAA,UACL,OAAA,EAAS;AAAA,YACP;AAAA,cACE,IAAA,EAAM,MAAA;AAAA,cACN,IAAA,EAAM;AAAA;AACR;AACF,SACF;AAAA,MACF;AAEA,MAAA,MAAM,gBAAgB,KAAA,CAAM,SAAA,CACzB,GAAA,CAAI,CAAC,GAAG,CAAA,KAAM;AACb,QAAA,MAAM,UAAA,GAAa,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,QAAQ,GAAI,CAAA;AAC5C,QAAA,MAAM,MAAA,GAAS,UAAA,GAAa,EAAA,GAAK,CAAA,EAAG,UAAU,CAAA,KAAA,CAAA,GAAU,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,EAAE,CAAC,CAAA,KAAA,CAAA;AAEtF,QAAA,OAAO,CAAA,IAAA,EAAO,CAAA,GAAI,CAAC,CAAA,gBAAA,EAAmB,CAAA,CAAE,IAAA,CAAK,WAAW,CAAA,EAAA,EAAK,CAAA,CAAE,IAAA,CAAK,QAAQ,CAAA,IAAA,EAAO,MAAM;AAAA,UAAA,EACvF,EAAE,UAAU,CAAA;AAAA,YAAA,EACV,EAAE,MAAM;;AAAA,EAEpB,EAAE,OAAO;;AAAA,GAAA,CAAA;AAAA,MAGH,CAAC,CAAA,CACA,IAAA,CAAK,MAAM,CAAA;AAEd,MAAA,OAAO;AAAA,QACL,OAAA,EAAS;AAAA,UACP;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,MAAM,CAAA,SAAA,EAAY,KAAA,CAAM,YAAY,CAAA,UAAA,EAAa,MAAM,UAAU,CAAA;;AAAA,EAAc,aAAa;;AAAA,+DAAA;AAAA;AAC9F;AACF,OACF;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,YAAA,GAAe,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,eAAA;AAC9D,MAAA,OAAO;AAAA,QACL,OAAA,EAAS;AAAA,UACP;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,wBAAwB,YAAY,CAAA;AAAA;AAC5C,SACF;AAAA,QACA,OAAA,EAAS;AAAA,OACX;AAAA,IACF;AAAA,EACF,CAAC,CAAA;AACH;ACnEA,IAAM,WAAA,GAAc;AAAA,EAClB,UAAA,EAAYA,CAAAA,CAAE,MAAA,EAAO,CAAE,SAAS,iDAAiD,CAAA;AAAA,EACjF,MAAA,EAAQA,CAAAA,CAAE,MAAA,EAAO,CAAE,SAAS,iDAAiD;AAC/E,CAAA;AAKO,SAAS,iBAAA,CAAkB,QAAmB,MAAA,EAA6B;AAChF,EAAA,MAAA,CAAO,IAAA,CAAK,OAAA,EAAS,WAAA,EAAa,OAAO,IAAA,KAAS;AAChD,IAAA,MAAM,aAAa,IAAA,CAAK,UAAA;AACxB,IAAA,MAAM,SAAS,IAAA,CAAK,MAAA;AAEpB,IAAA,IAAI;AACF,MAAA,IAAI,CAAC,OAAO,aAAA,EAAe;AACzB,QAAA,OAAO;AAAA,UACL,OAAA,EAAS;AAAA,YACP;AAAA,cACE,IAAA,EAAM,MAAA;AAAA,cACN,IAAA,EAAM;AAAA;AACR,WACF;AAAA,UACA,OAAA,EAAS;AAAA,SACX;AAAA,MACF;AAEA,MAAA,MAAM,MAAA,CAAO,KAAA,CAAM,UAAA,EAAY,MAAA,EAAQ,UAAU,CAAA;AAGjD,MAAA,cAAA,CAAe,aAAA,EAAc;AAE7B,MAAA,OAAO;AAAA,QACL,OAAA,EAAS;AAAA,UACP;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,yCAAyC,UAAU,CAAA,GAAA;AAAA;AAC3D;AACF,OACF;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,YAAA,GAAe,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,eAAA;AAC9D,MAAA,OAAO;AAAA,QACL,OAAA,EAAS;AAAA,UACP;AAAA,YACE,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,yBAAyB,YAAY,CAAA;AAAA;AAC7C,SACF;AAAA,QACA,OAAA,EAAS;AAAA,OACX;AAAA,IACF;AAAA,EACF,CAAC,CAAA;AACH;;;ACxCO,SAAS,gBAAgB,OAAA,EAAsC;AACpE,EAAA,MAAM,EAAE,QAAO,GAAI,OAAA;AAEnB,EAAA,MAAM,SAAS,IAAI,SAAA;AAAA,IACjB;AAAA,MACE,IAAA,EAAM,eAAA;AAAA,MACN,OAAA,EAAS;AAAA,KACX;AAAA,IACA;AAAA,MACE,YAAA,EAAc;AAAA,QACZ,SAAA,EAAW;AAAA,UACT,SAAA,EAAW,IAAA;AAAA,UACX,WAAA,EAAa;AAAA;AACf;AACF;AACF,GACF;AAGA,EAAA,gBAAA,CAAiB,QAAQ,MAAM,CAAA;AAC/B,EAAA,uBAAA,CAAwB,QAAQ,MAAM,CAAA;AACtC,EAAA,eAAA,CAAgB,QAAQ,MAAM,CAAA;AAC9B,EAAA,uBAAA,CAAwB,QAAQ,MAAM,CAAA;AACtC,EAAA,iBAAA,CAAkB,QAAQ,MAAM,CAAA;AAChC,EAAA,iBAAA,CAAkB,QAAQ,MAAM,CAAA;AAGhC,EAAA,MAAA,CAAO,QAAA;AAAA,IACL,iBAAA;AAAA,IACA,mBAAA;AAAA,IACA,EAAE,WAAA,EAAa,kDAAA,EAAoD,QAAA,EAAU,kBAAA,EAAmB;AAAA,IAChG,YAAY;AACV,MAAA,IAAI;AACF,QAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO,QAAA,EAAS;AACpC,QAAA,OAAO;AAAA,UACL,QAAA,EAAU;AAAA,YACR;AAAA,cACE,GAAA,EAAK,mBAAA;AAAA,cACL,QAAA,EAAU,kBAAA;AAAA,cACV,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,KAAA,EAAO,MAAM,CAAC;AAAA;AACrC;AACF,SACF;AAAA,MACF,SAAS,KAAA,EAAO;AACd,QAAA,MAAM,YAAA,GAAe,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,eAAA;AAC9D,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,YAAY,CAAA,CAAE,CAAA;AAAA,MACzD;AAAA,IACF;AAAA,GACF;AAEA,EAAA,OAAO,MAAA;AACT;AAKA,eAAsB,eAAe,OAAA,EAA0C;AAC7E,EAAA,MAAM,MAAA,GAAS,gBAAgB,OAAO,CAAA;AACtC,EAAA,MAAM,SAAA,GAAY,IAAI,oBAAA,EAAqB;AAC3C,EAAA,MAAM,MAAA,CAAO,QAAQ,SAAS,CAAA;AAChC;;;AC1EA,IAAM,OAAA,GAAU,IAAI,OAAA,EAAQ;AAE5B,OAAA,CACG,KAAK,eAAe,CAAA,CACpB,YAAY,gEAAgE,CAAA,CAC5E,QAAQ,OAAO,CAAA;AAGlB,OAAA,CACG,QAAQ,QAAQ,CAAA,CAChB,YAAY,sDAAsD,CAAA,CAClE,OAAO,YAAY;AAClB,EAAA,MAAM,OAAA,GAAU,IAAI,OAAA,EAAQ;AAC5B,EAAA,MAAM,cAAA,CAAe,EAAE,MAAA,EAAQ,OAAA,EAAS,CAAA;AAC1C,CAAC,CAAA;AAEH,OAAA,CAAQ,KAAA,EAAM","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} 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 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 * 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 await startMcpServer({ client: p2pNode });\r\n });\r\n\r\nprogram.parse();\r\n"]}