@dolusoft/claude-collab 0.1.2 → 0.1.5
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 +62 -7
- package/dist/cli.js.map +1 -1
- package/dist/mcp-main.js +62 -7
- package/dist/mcp-main.js.map +1 -1
- package/package.json +1 -1
package/dist/mcp-main.js
CHANGED
|
@@ -3,6 +3,7 @@ import WebSocket from 'ws';
|
|
|
3
3
|
import { v4 } from 'uuid';
|
|
4
4
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
5
5
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
6
|
+
import { ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
6
7
|
import { z } from 'zod';
|
|
7
8
|
import { spawn } from 'child_process';
|
|
8
9
|
import { createConnection } from 'net';
|
|
@@ -516,20 +517,74 @@ function registerReplyTool(server, hubClient) {
|
|
|
516
517
|
|
|
517
518
|
// src/presentation/mcp/server.ts
|
|
518
519
|
function createMcpServer(options) {
|
|
519
|
-
const
|
|
520
|
-
|
|
521
|
-
|
|
520
|
+
const { hubClient } = options;
|
|
521
|
+
const server = new McpServer(
|
|
522
|
+
{
|
|
523
|
+
name: "claude-collab",
|
|
524
|
+
version: "0.1.2"
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
capabilities: {
|
|
528
|
+
resources: {
|
|
529
|
+
subscribe: true,
|
|
530
|
+
listChanged: true
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
);
|
|
535
|
+
registerJoinTool(server, hubClient);
|
|
536
|
+
registerAskTool(server, hubClient);
|
|
537
|
+
registerInboxTool(server, hubClient);
|
|
538
|
+
registerReplyTool(server, hubClient);
|
|
539
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
540
|
+
return {
|
|
541
|
+
resources: [
|
|
542
|
+
{
|
|
543
|
+
uri: "inbox://questions",
|
|
544
|
+
name: "Pending Questions",
|
|
545
|
+
description: "Your inbox of pending questions from other teams",
|
|
546
|
+
mimeType: "application/json"
|
|
547
|
+
}
|
|
548
|
+
]
|
|
549
|
+
};
|
|
550
|
+
});
|
|
551
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
552
|
+
if (request.params.uri === "inbox://questions") {
|
|
553
|
+
try {
|
|
554
|
+
const inbox = await hubClient.getInbox();
|
|
555
|
+
return {
|
|
556
|
+
contents: [
|
|
557
|
+
{
|
|
558
|
+
uri: "inbox://questions",
|
|
559
|
+
mimeType: "application/json",
|
|
560
|
+
text: JSON.stringify(inbox, null, 2)
|
|
561
|
+
}
|
|
562
|
+
]
|
|
563
|
+
};
|
|
564
|
+
} catch (error) {
|
|
565
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
566
|
+
throw new Error(`Failed to read inbox: ${errorMessage}`);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
throw new Error(`Unknown resource URI: ${request.params.uri}`);
|
|
522
570
|
});
|
|
523
|
-
registerJoinTool(server, options.hubClient);
|
|
524
|
-
registerAskTool(server, options.hubClient);
|
|
525
|
-
registerInboxTool(server, options.hubClient);
|
|
526
|
-
registerReplyTool(server, options.hubClient);
|
|
527
571
|
return server;
|
|
528
572
|
}
|
|
529
573
|
async function startMcpServer(options) {
|
|
574
|
+
const { hubClient } = options;
|
|
530
575
|
const server = createMcpServer(options);
|
|
531
576
|
const transport = new StdioServerTransport();
|
|
532
577
|
await server.connect(transport);
|
|
578
|
+
hubClient.events.onQuestion = async (question) => {
|
|
579
|
+
await server.notification({
|
|
580
|
+
method: "notifications/resources/updated",
|
|
581
|
+
params: {
|
|
582
|
+
uri: "inbox://questions"
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
console.error(`[\u{1F4EC} New Question] From: ${question.from.displayName}`);
|
|
586
|
+
console.error(`[\u{1F4A1} Tip] Check your inbox with: inbox()`);
|
|
587
|
+
};
|
|
533
588
|
}
|
|
534
589
|
async function isHubRunning(host = config.hub.host, port = config.hub.port) {
|
|
535
590
|
return new Promise((resolve) => {
|
package/dist/mcp-main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config/index.ts","../src/infrastructure/websocket/message-protocol.ts","../src/infrastructure/websocket/hub-client.ts","../src/presentation/mcp/tools/join.tool.ts","../src/presentation/mcp/tools/ask.tool.ts","../src/presentation/mcp/tools/inbox.tool.ts","../src/presentation/mcp/tools/reply.tool.ts","../src/presentation/mcp/server.ts","../src/infrastructure/hub-launcher/auto-start.service.ts","../src/mcp-main.ts"],"names":["uuidv4","args","z"],"mappings":"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","file":"mcp-main.js","sourcesContent":["/**\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 * WebSocket Hub configuration\r\n */\r\n hub: {\r\n /**\r\n * Default port for the Hub server\r\n */\r\n port: parseInt(process.env['CLAUDE_COLLAB_PORT'] ?? '9999', 10),\r\n\r\n /**\r\n * Host to bind the Hub server to\r\n */\r\n host: process.env['CLAUDE_COLLAB_HOST'] ?? 'localhost',\r\n\r\n /**\r\n * Heartbeat interval in milliseconds\r\n */\r\n heartbeatInterval: 30000,\r\n\r\n /**\r\n * Client timeout in milliseconds (no heartbeat received)\r\n */\r\n clientTimeout: 60000,\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\r\n /**\r\n * Auto-start configuration\r\n */\r\n autoStart: {\r\n /**\r\n * Whether to auto-start the hub if not running\r\n */\r\n enabled: true,\r\n\r\n /**\r\n * Maximum retries when connecting to hub\r\n */\r\n maxRetries: 3,\r\n\r\n /**\r\n * Delay between retries in milliseconds\r\n */\r\n retryDelay: 1000,\r\n },\r\n} as const;\r\n\r\nexport type Config = typeof config;\r\n","/**\r\n * WebSocket Message Protocol\r\n * Defines the message format between Hub and Clients\r\n * @module infrastructure/websocket/message-protocol\r\n */\r\n\r\nimport type { MemberId, TeamId, QuestionId } from '../../shared/types/branded-types.js';\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\nimport type { MemberStatus } from '../../domain/entities/member.entity.js';\r\nimport type { QuestionStatus } from '../../domain/entities/question.entity.js';\r\n\r\n// ============================================================================\r\n// Client → Hub Messages\r\n// ============================================================================\r\n\r\nexport type ClientMessageType = 'JOIN' | 'LEAVE' | 'ASK' | 'REPLY' | 'PING' | 'GET_INBOX';\r\n\r\nexport interface JoinMessage {\r\n type: 'JOIN';\r\n teamName: string;\r\n displayName: string;\r\n}\r\n\r\nexport interface LeaveMessage {\r\n type: 'LEAVE';\r\n}\r\n\r\nexport interface AskMessage {\r\n type: 'ASK';\r\n toTeam: string;\r\n content: string;\r\n format: MessageFormat;\r\n requestId: string; // For correlating response\r\n}\r\n\r\nexport interface ReplyMessage {\r\n type: 'REPLY';\r\n questionId: QuestionId;\r\n content: string;\r\n format: MessageFormat;\r\n}\r\n\r\nexport interface PingMessage {\r\n type: 'PING';\r\n}\r\n\r\nexport interface GetInboxMessage {\r\n type: 'GET_INBOX';\r\n requestId: string;\r\n}\r\n\r\nexport type ClientMessage =\r\n | JoinMessage\r\n | LeaveMessage\r\n | AskMessage\r\n | ReplyMessage\r\n | PingMessage\r\n | GetInboxMessage;\r\n\r\n// ============================================================================\r\n// Hub → Client Messages\r\n// ============================================================================\r\n\r\nexport type HubMessageType =\r\n | 'JOINED'\r\n | 'LEFT'\r\n | 'MEMBER_JOINED'\r\n | 'MEMBER_LEFT'\r\n | 'QUESTION'\r\n | 'ANSWER'\r\n | 'QUESTION_SENT'\r\n | 'INBOX'\r\n | 'PONG'\r\n | 'ERROR';\r\n\r\nexport interface MemberInfo {\r\n memberId: MemberId;\r\n teamId: TeamId;\r\n teamName: string;\r\n displayName: string;\r\n status: MemberStatus;\r\n}\r\n\r\nexport interface JoinedMessage {\r\n type: 'JOINED';\r\n member: MemberInfo;\r\n memberCount: number;\r\n}\r\n\r\nexport interface LeftMessage {\r\n type: 'LEFT';\r\n memberId: MemberId;\r\n}\r\n\r\nexport interface MemberJoinedMessage {\r\n type: 'MEMBER_JOINED';\r\n member: MemberInfo;\r\n}\r\n\r\nexport interface MemberLeftMessage {\r\n type: 'MEMBER_LEFT';\r\n memberId: MemberId;\r\n teamId: TeamId;\r\n}\r\n\r\nexport interface QuestionMessage {\r\n type: 'QUESTION';\r\n questionId: QuestionId;\r\n from: MemberInfo;\r\n content: string;\r\n format: MessageFormat;\r\n createdAt: string;\r\n}\r\n\r\nexport interface AnswerMessage {\r\n type: 'ANSWER';\r\n questionId: QuestionId;\r\n from: MemberInfo;\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n requestId?: string; // Correlates with original ASK request\r\n}\r\n\r\nexport interface QuestionSentMessage {\r\n type: 'QUESTION_SENT';\r\n questionId: QuestionId;\r\n toTeamId: TeamId;\r\n status: QuestionStatus;\r\n requestId: string;\r\n}\r\n\r\nexport interface InboxQuestionInfo {\r\n questionId: QuestionId;\r\n from: MemberInfo;\r\n content: string;\r\n format: MessageFormat;\r\n status: QuestionStatus;\r\n createdAt: string;\r\n ageMs: number;\r\n}\r\n\r\nexport interface InboxMessage {\r\n type: 'INBOX';\r\n questions: InboxQuestionInfo[];\r\n totalCount: number;\r\n pendingCount: number;\r\n requestId: string;\r\n}\r\n\r\nexport interface PongMessage {\r\n type: 'PONG';\r\n timestamp: string;\r\n}\r\n\r\nexport interface ErrorMessage {\r\n type: 'ERROR';\r\n code: string;\r\n message: string;\r\n requestId?: string;\r\n}\r\n\r\nexport type HubMessage =\r\n | JoinedMessage\r\n | LeftMessage\r\n | MemberJoinedMessage\r\n | MemberLeftMessage\r\n | QuestionMessage\r\n | AnswerMessage\r\n | QuestionSentMessage\r\n | InboxMessage\r\n | PongMessage\r\n | ErrorMessage;\r\n\r\n// ============================================================================\r\n// Serialization Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Serializes a message to JSON string\r\n */\r\nexport function serializeMessage<T extends ClientMessage | HubMessage>(message: T): string {\r\n return JSON.stringify(message);\r\n}\r\n\r\n/**\r\n * Parses a client message from JSON string\r\n */\r\nexport function parseClientMessage(data: string): ClientMessage {\r\n const parsed = JSON.parse(data) as ClientMessage;\r\n validateClientMessage(parsed);\r\n return parsed;\r\n}\r\n\r\n/**\r\n * Parses a hub message from JSON string\r\n */\r\nexport function parseHubMessage(data: string): HubMessage {\r\n return JSON.parse(data) as HubMessage;\r\n}\r\n\r\n/**\r\n * Validates a client message\r\n */\r\nfunction validateClientMessage(message: ClientMessage): void {\r\n if (!message.type) {\r\n throw new Error('Message must have a type');\r\n }\r\n\r\n const validTypes: ClientMessageType[] = ['JOIN', 'LEAVE', 'ASK', 'REPLY', 'PING', 'GET_INBOX'];\r\n if (!validTypes.includes(message.type)) {\r\n throw new Error(`Invalid message type: ${message.type}`);\r\n }\r\n}\r\n\r\n/**\r\n * Creates an error message\r\n */\r\nexport function createErrorMessage(\r\n code: string,\r\n message: string,\r\n requestId?: string\r\n): ErrorMessage {\r\n return {\r\n type: 'ERROR',\r\n code,\r\n message,\r\n requestId,\r\n };\r\n}\r\n","/**\r\n * WebSocket Hub Client\r\n * Client that connects to the Hub server\r\n * @module infrastructure/websocket/hub-client\r\n */\r\n\r\nimport WebSocket from 'ws';\r\nimport { v4 as uuidv4 } from 'uuid';\r\nimport type { MemberId, TeamId, QuestionId } from '../../shared/types/branded-types.js';\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\nimport { config } from '../../config/index.js';\r\nimport {\r\n type ClientMessage,\r\n type HubMessage,\r\n type QuestionMessage,\r\n type AnswerMessage,\r\n type InboxMessage,\r\n type MemberInfo,\r\n serializeMessage,\r\n parseHubMessage,\r\n} from './message-protocol.js';\r\n\r\n/**\r\n * Pending request with timeout\r\n */\r\ninterface PendingRequest<T> {\r\n resolve: (value: T) => void;\r\n reject: (error: Error) => void;\r\n timeout: ReturnType<typeof setTimeout>;\r\n}\r\n\r\n/**\r\n * Hub client options\r\n */\r\nexport interface HubClientOptions {\r\n host?: string;\r\n port?: number;\r\n reconnect?: boolean;\r\n reconnectDelay?: number;\r\n maxReconnectAttempts?: number;\r\n}\r\n\r\n/**\r\n * Hub client events\r\n */\r\nexport interface HubClientEvents {\r\n onConnected?: () => void;\r\n onDisconnected?: () => void;\r\n onQuestion?: (question: QuestionMessage) => void;\r\n onAnswer?: (answer: AnswerMessage) => void;\r\n onMemberJoined?: (member: MemberInfo) => void;\r\n onMemberLeft?: (memberId: MemberId, teamId: TeamId) => void;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\n/**\r\n * WebSocket Hub Client\r\n */\r\nexport class HubClient {\r\n private ws: WebSocket | null = null;\r\n private readonly pendingRequests = new Map<string, PendingRequest<HubMessage>>();\r\n private reconnectAttempts = 0;\r\n private isClosing = false;\r\n\r\n private memberId?: MemberId;\r\n private teamId?: TeamId;\r\n private teamName?: string;\r\n private displayName?: string;\r\n\r\n constructor(\r\n private readonly options: HubClientOptions = {},\r\n private readonly events: HubClientEvents = {}\r\n ) {}\r\n\r\n /**\r\n * Connects to the Hub server\r\n */\r\n async connect(): Promise<void> {\r\n const host = this.options.host ?? config.hub.host;\r\n const port = this.options.port ?? config.hub.port;\r\n const url = `ws://${host}:${port}`;\r\n\r\n return new Promise((resolve, reject) => {\r\n try {\r\n this.ws = new WebSocket(url);\r\n\r\n this.ws.on('open', () => {\r\n this.reconnectAttempts = 0;\r\n this.startPingInterval();\r\n this.events.onConnected?.();\r\n resolve();\r\n });\r\n\r\n this.ws.on('message', (data) => {\r\n this.handleMessage(data.toString());\r\n });\r\n\r\n this.ws.on('close', () => {\r\n this.handleDisconnect();\r\n });\r\n\r\n this.ws.on('error', (error) => {\r\n this.events.onError?.(error);\r\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\r\n reject(error);\r\n }\r\n });\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Disconnects from the Hub server\r\n */\r\n async disconnect(): Promise<void> {\r\n this.isClosing = true;\r\n\r\n if (this.memberId) {\r\n this.send({ type: 'LEAVE' });\r\n }\r\n\r\n return new Promise((resolve) => {\r\n if (this.ws) {\r\n this.ws.close();\r\n this.ws = null;\r\n }\r\n this.isClosing = false;\r\n resolve();\r\n });\r\n }\r\n\r\n /**\r\n * Joins a team\r\n */\r\n async join(teamName: string, displayName: string): Promise<MemberInfo> {\r\n const requestId = uuidv4();\r\n\r\n this.send({\r\n type: 'JOIN',\r\n teamName,\r\n displayName,\r\n });\r\n\r\n const response = await this.waitForResponse<{ type: 'JOINED'; member: MemberInfo }>(\r\n (msg) => msg.type === 'JOINED',\r\n 30000\r\n );\r\n\r\n this.memberId = response.member.memberId;\r\n this.teamId = response.member.teamId;\r\n this.teamName = teamName;\r\n this.displayName = displayName;\r\n\r\n return response.member;\r\n }\r\n\r\n /**\r\n * Asks a question to another team\r\n */\r\n async ask(\r\n toTeam: string,\r\n content: string,\r\n format: MessageFormat = 'markdown',\r\n timeoutMs: number = config.communication.defaultTimeout\r\n ): Promise<AnswerMessage> {\r\n const requestId = uuidv4();\r\n\r\n this.send({\r\n type: 'ASK',\r\n toTeam,\r\n content,\r\n format,\r\n requestId,\r\n });\r\n\r\n // Wait for QUESTION_SENT confirmation\r\n const questionSent = await this.waitForResponse<{\r\n type: 'QUESTION_SENT';\r\n questionId: QuestionId;\r\n requestId: string;\r\n }>(\r\n (msg) => msg.type === 'QUESTION_SENT' && 'requestId' in msg && msg.requestId === requestId,\r\n 5000\r\n );\r\n\r\n const questionId = questionSent.questionId;\r\n\r\n // Wait for ANSWER with matching questionId\r\n const answer = await this.waitForResponse<AnswerMessage>(\r\n (msg) => msg.type === 'ANSWER' && msg.questionId === questionId,\r\n timeoutMs\r\n );\r\n\r\n return answer;\r\n }\r\n\r\n /**\r\n * Gets the inbox (pending questions)\r\n */\r\n async getInbox(): Promise<InboxMessage> {\r\n const requestId = uuidv4();\r\n\r\n this.send({\r\n type: 'GET_INBOX',\r\n requestId,\r\n });\r\n\r\n return this.waitForResponse<InboxMessage>(\r\n (msg) => msg.type === 'INBOX' && msg.requestId === requestId,\r\n 5000\r\n );\r\n }\r\n\r\n /**\r\n * Replies to a question\r\n */\r\n async reply(questionId: QuestionId, content: string, format: MessageFormat = 'markdown'): Promise<void> {\r\n this.send({\r\n type: 'REPLY',\r\n questionId,\r\n content,\r\n format,\r\n });\r\n }\r\n\r\n /**\r\n * Checks if connected\r\n */\r\n get isConnected(): boolean {\r\n return this.ws !== null && this.ws.readyState === WebSocket.OPEN;\r\n }\r\n\r\n /**\r\n * Gets the current member ID\r\n */\r\n get currentMemberId(): MemberId | undefined {\r\n return this.memberId;\r\n }\r\n\r\n /**\r\n * Gets the current team ID\r\n */\r\n get currentTeamId(): TeamId | undefined {\r\n return this.teamId;\r\n }\r\n\r\n private send(message: ClientMessage): void {\r\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\r\n this.ws.send(serializeMessage(message));\r\n }\r\n }\r\n\r\n private handleMessage(data: string): void {\r\n try {\r\n const message = parseHubMessage(data);\r\n\r\n // Check pending requests\r\n for (const [requestId, pending] of this.pendingRequests) {\r\n // This is handled by the filter function in waitForResponse\r\n }\r\n\r\n // Handle specific message types\r\n switch (message.type) {\r\n case 'QUESTION':\r\n this.events.onQuestion?.(message);\r\n break;\r\n case 'ANSWER':\r\n this.events.onAnswer?.(message);\r\n break;\r\n case 'MEMBER_JOINED':\r\n this.events.onMemberJoined?.(message.member);\r\n break;\r\n case 'MEMBER_LEFT':\r\n this.events.onMemberLeft?.(message.memberId, message.teamId);\r\n break;\r\n case 'ERROR':\r\n this.events.onError?.(new Error(`${message.code}: ${message.message}`));\r\n break;\r\n }\r\n\r\n // Resolve any matching pending requests\r\n this.resolvePendingRequest(message);\r\n } catch (error) {\r\n console.error('Failed to parse message:', error);\r\n }\r\n }\r\n\r\n private resolvePendingRequest(message: HubMessage): void {\r\n for (const [requestId, pending] of this.pendingRequests) {\r\n // The filter is stored separately, we'll match by message type patterns\r\n this.pendingRequests.delete(requestId);\r\n clearTimeout(pending.timeout);\r\n pending.resolve(message);\r\n break; // Only resolve one request per message\r\n }\r\n }\r\n\r\n private waitForResponse<T extends HubMessage>(\r\n filter: (msg: HubMessage) => boolean,\r\n timeoutMs: number\r\n ): Promise<T> {\r\n return new Promise((resolve, reject) => {\r\n const requestId = uuidv4();\r\n\r\n const timeout = setTimeout(() => {\r\n this.pendingRequests.delete(requestId);\r\n reject(new Error('Request timed out'));\r\n }, timeoutMs);\r\n\r\n // Store filter function with the pending request\r\n const pending: PendingRequest<HubMessage> & { filter: (msg: HubMessage) => boolean } = {\r\n resolve: (msg) => {\r\n if (filter(msg)) {\r\n resolve(msg as T);\r\n }\r\n },\r\n reject,\r\n timeout,\r\n filter,\r\n };\r\n\r\n this.pendingRequests.set(requestId, pending);\r\n\r\n // Override handleMessage to check this specific filter\r\n const originalHandler = this.handleMessage.bind(this);\r\n const checkFilter = (data: string): void => {\r\n try {\r\n const message = parseHubMessage(data);\r\n if (filter(message)) {\r\n this.pendingRequests.delete(requestId);\r\n clearTimeout(timeout);\r\n resolve(message as T);\r\n }\r\n } catch {\r\n // Ignore parse errors here\r\n }\r\n originalHandler(data);\r\n };\r\n\r\n // Temporarily override\r\n if (this.ws) {\r\n this.ws.removeAllListeners('message');\r\n this.ws.on('message', (data) => checkFilter(data.toString()));\r\n }\r\n });\r\n }\r\n\r\n private handleDisconnect(): void {\r\n this.events.onDisconnected?.();\r\n\r\n if (this.isClosing) return;\r\n\r\n const shouldReconnect = this.options.reconnect ?? true;\r\n const maxAttempts = this.options.maxReconnectAttempts ?? config.autoStart.maxRetries;\r\n\r\n if (shouldReconnect && this.reconnectAttempts < maxAttempts) {\r\n this.reconnectAttempts++;\r\n const delay = this.options.reconnectDelay ?? config.autoStart.retryDelay;\r\n\r\n setTimeout(() => {\r\n this.connect()\r\n .then(() => {\r\n if (this.teamName && this.displayName) {\r\n return this.join(this.teamName, this.displayName);\r\n }\r\n })\r\n .catch((error) => {\r\n this.events.onError?.(error);\r\n });\r\n }, delay);\r\n }\r\n }\r\n\r\n private pingInterval: ReturnType<typeof setInterval> | null = null;\r\n\r\n private startPingInterval(): void {\r\n this.pingInterval = setInterval(() => {\r\n this.send({ type: 'PING' });\r\n }, config.hub.heartbeatInterval);\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 { HubClient } from '../../../infrastructure/websocket/hub-client.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, hubClient: HubClient): 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 // Ensure connected to hub\r\n if (!hubClient.isConnected) {\r\n await hubClient.connect();\r\n }\r\n\r\n // Join the team\r\n const member = await hubClient.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 * Ask Tool\r\n * Asks a question to another team and waits for response\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 { HubClient } from '../../../infrastructure/websocket/hub-client.js';\r\nimport { config } from '../../../config/index.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 timeout: z\r\n .number()\r\n .optional()\r\n .describe(`Timeout in seconds to wait for answer (default: ${config.communication.defaultTimeout / 1000}s)`),\r\n};\r\n\r\n/**\r\n * Registers the ask tool with the MCP server\r\n */\r\nexport function registerAskTool(server: McpServer, hubClient: HubClient): void {\r\n server.tool('ask', askSchema, async (args) => {\r\n const targetTeam = args.team;\r\n const question = args.question;\r\n const timeoutMs = (args.timeout ?? config.communication.defaultTimeout / 1000) * 1000;\r\n\r\n try {\r\n // Check if joined a team\r\n if (!hubClient.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 // Ask the question and wait for answer\r\n const answer = await hubClient.ask(targetTeam, question, 'markdown', timeoutMs);\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\r\n if (errorMessage.includes('timed out')) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `No response received from team \"${targetTeam}\" within ${timeoutMs / 1000} seconds. The question has been delivered but no one answered yet.`,\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: `Failed to ask question: ${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 { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { HubClient } from '../../../infrastructure/websocket/hub-client.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, hubClient: HubClient): void {\r\n server.tool('inbox', inboxSchema, async () => {\r\n try {\r\n // Check if joined a team\r\n if (!hubClient.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 // Get inbox\r\n const inbox = await hubClient.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 // Format questions list\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 { HubClient } from '../../../infrastructure/websocket/hub-client.js';\r\nimport type { QuestionId } from '../../../shared/types/branded-types.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, hubClient: HubClient): void {\r\n server.tool('reply', replySchema, async (args) => {\r\n const questionId = args.questionId as QuestionId;\r\n const answer = args.answer;\r\n\r\n try {\r\n // Check if joined a team\r\n if (!hubClient.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 // Send the reply\r\n await hubClient.reply(questionId, answer, 'markdown');\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 { HubClient } from '../../infrastructure/websocket/hub-client.js';\r\nimport { registerJoinTool } from './tools/join.tool.js';\r\nimport { registerAskTool } from './tools/ask.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 hubClient: HubClient;\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 server = new McpServer({\r\n name: 'claude-collab',\r\n version: '0.1.0',\r\n });\r\n\r\n // Register all tools\r\n registerJoinTool(server, options.hubClient);\r\n registerAskTool(server, options.hubClient);\r\n registerInboxTool(server, options.hubClient);\r\n registerReplyTool(server, options.hubClient);\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\r\n await server.connect(transport);\r\n}\r\n","/**\r\n * Auto-Start Service\r\n * Automatically starts the Hub server if not running\r\n * @module infrastructure/hub-launcher/auto-start\r\n */\r\n\r\nimport { spawn, type ChildProcess } from 'child_process';\r\nimport { createConnection } from 'net';\r\nimport { config } from '../../config/index.js';\r\n\r\n/**\r\n * Auto-start service options\r\n */\r\nexport interface AutoStartOptions {\r\n host?: string;\r\n port?: number;\r\n maxRetries?: number;\r\n retryDelay?: number;\r\n}\r\n\r\n/**\r\n * Checks if the Hub server is running\r\n */\r\nexport async function isHubRunning(\r\n host: string = config.hub.host,\r\n port: number = config.hub.port\r\n): Promise<boolean> {\r\n return new Promise((resolve) => {\r\n const socket = createConnection({ host, port }, () => {\r\n socket.end();\r\n resolve(true);\r\n });\r\n\r\n socket.on('error', () => {\r\n resolve(false);\r\n });\r\n\r\n socket.setTimeout(1000, () => {\r\n socket.destroy();\r\n resolve(false);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Waits for the Hub server to become available\r\n */\r\nexport async function waitForHub(\r\n host: string = config.hub.host,\r\n port: number = config.hub.port,\r\n maxRetries: number = config.autoStart.maxRetries,\r\n retryDelay: number = config.autoStart.retryDelay\r\n): Promise<boolean> {\r\n for (let i = 0; i < maxRetries; i++) {\r\n if (await isHubRunning(host, port)) {\r\n return true;\r\n }\r\n await new Promise((resolve) => setTimeout(resolve, retryDelay));\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Starts the Hub server as a background process\r\n */\r\nexport function startHubProcess(options: AutoStartOptions = {}): ChildProcess {\r\n const host = options.host ?? config.hub.host;\r\n const port = options.port ?? config.hub.port;\r\n\r\n // Start hub-main.js as a detached process\r\n const hubProcess = spawn(\r\n process.execPath,\r\n [\r\n '--experimental-specifier-resolution=node',\r\n new URL('../../hub-main.js', import.meta.url).pathname,\r\n '--host',\r\n host,\r\n '--port',\r\n port.toString(),\r\n ],\r\n {\r\n detached: true,\r\n stdio: 'ignore',\r\n }\r\n );\r\n\r\n hubProcess.unref();\r\n return hubProcess;\r\n}\r\n\r\n/**\r\n * Ensures the Hub is running, starting it if necessary\r\n */\r\nexport async function ensureHubRunning(options: AutoStartOptions = {}): Promise<boolean> {\r\n const host = options.host ?? config.hub.host;\r\n const port = options.port ?? config.hub.port;\r\n const maxRetries = options.maxRetries ?? config.autoStart.maxRetries;\r\n const retryDelay = options.retryDelay ?? config.autoStart.retryDelay;\r\n\r\n // Check if already running\r\n if (await isHubRunning(host, port)) {\r\n return true;\r\n }\r\n\r\n // Try to start the hub\r\n console.log(`Hub not running. Starting hub on ${host}:${port}...`);\r\n startHubProcess({ host, port });\r\n\r\n // Wait for it to become available\r\n const isRunning = await waitForHub(host, port, maxRetries, retryDelay);\r\n\r\n if (isRunning) {\r\n console.log('Hub started successfully');\r\n } else {\r\n console.error('Failed to start hub');\r\n }\r\n\r\n return isRunning;\r\n}\r\n","#!/usr/bin/env node\r\n\r\n/**\r\n * MCP Server entry point\r\n * This is the main entry point for the MCP client that connects to Claude Code\r\n * @module mcp-main\r\n */\r\n\r\nimport { HubClient } from './infrastructure/websocket/hub-client.js';\r\nimport { startMcpServer } from './presentation/mcp/server.js';\r\nimport { ensureHubRunning } from './infrastructure/hub-launcher/auto-start.service.js';\r\nimport { config } from './config/index.js';\r\n\r\nconst args = process.argv.slice(2);\r\n\r\ninterface ClientOptions {\r\n team?: string;\r\n host: string;\r\n port: number;\r\n autoHub: boolean;\r\n}\r\n\r\nfunction parseArgs(): ClientOptions {\r\n const options: ClientOptions = {\r\n host: config.hub.host,\r\n port: config.hub.port,\r\n autoHub: false,\r\n };\r\n\r\n for (let i = 0; i < args.length; i++) {\r\n const arg = args[i];\r\n const nextArg = args[i + 1];\r\n\r\n if (arg === '--team' && nextArg) {\r\n options.team = nextArg;\r\n i++;\r\n } else if (arg === '--host' && nextArg) {\r\n options.host = nextArg;\r\n i++;\r\n } else if (arg === '--port' && nextArg) {\r\n options.port = parseInt(nextArg, 10);\r\n i++;\r\n } else if (arg === '--auto-hub') {\r\n options.autoHub = true;\r\n } else if (arg === '-h' || arg === '--help') {\r\n console.error(`\r\nClaude Collab MCP Client\r\n\r\nUsage:\r\n mcp-main [options]\r\n\r\nOptions:\r\n --team <team> Team to auto-join (optional)\r\n --host <host> Hub host (default: ${config.hub.host})\r\n --port <port> Hub port (default: ${config.hub.port})\r\n --auto-hub Auto-start hub if not running\r\n -h, --help Show this help message\r\n`);\r\n process.exit(0);\r\n }\r\n }\r\n\r\n return options;\r\n}\r\n\r\nasync function main(): Promise<void> {\r\n const options = parseArgs();\r\n\r\n // Auto-start hub if requested\r\n if (options.autoHub) {\r\n const hubRunning = await ensureHubRunning({\r\n host: options.host,\r\n port: options.port,\r\n });\r\n\r\n if (!hubRunning) {\r\n console.error('Failed to start hub server. Exiting.');\r\n process.exit(1);\r\n }\r\n }\r\n\r\n // Create hub client\r\n const hubClient = new HubClient(\r\n {\r\n host: options.host,\r\n port: options.port,\r\n reconnect: true,\r\n },\r\n {\r\n onError: (error) => {\r\n console.error('Hub client error:', error.message);\r\n },\r\n onQuestion: (question) => {\r\n // Questions will be handled by inbox tool\r\n console.error(`[Question received from ${question.from.displayName}]`);\r\n },\r\n }\r\n );\r\n\r\n // Connect to hub\r\n try {\r\n await hubClient.connect();\r\n\r\n // Auto-join team if specified\r\n if (options.team) {\r\n await hubClient.join(options.team, `${options.team} Claude`);\r\n console.error(`Auto-joined team: ${options.team}`);\r\n }\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n console.error(`Failed to connect to hub: ${errorMessage}`);\r\n console.error('Make sure the hub server is running or use --auto-hub flag.');\r\n process.exit(1);\r\n }\r\n\r\n // Start MCP server\r\n await startMcpServer({ hubClient });\r\n}\r\n\r\nmain().catch((error) => {\r\n console.error('Unexpected error:', error);\r\n process.exit(1);\r\n});\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/config/index.ts","../src/infrastructure/websocket/message-protocol.ts","../src/infrastructure/websocket/hub-client.ts","../src/presentation/mcp/tools/join.tool.ts","../src/presentation/mcp/tools/ask.tool.ts","../src/presentation/mcp/tools/inbox.tool.ts","../src/presentation/mcp/tools/reply.tool.ts","../src/presentation/mcp/server.ts","../src/infrastructure/hub-launcher/auto-start.service.ts","../src/mcp-main.ts"],"names":["uuidv4","args","z"],"mappings":"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","file":"mcp-main.js","sourcesContent":["/**\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 * WebSocket Hub configuration\r\n */\r\n hub: {\r\n /**\r\n * Default port for the Hub server\r\n */\r\n port: parseInt(process.env['CLAUDE_COLLAB_PORT'] ?? '9999', 10),\r\n\r\n /**\r\n * Host to bind the Hub server to\r\n */\r\n host: process.env['CLAUDE_COLLAB_HOST'] ?? 'localhost',\r\n\r\n /**\r\n * Heartbeat interval in milliseconds\r\n */\r\n heartbeatInterval: 30000,\r\n\r\n /**\r\n * Client timeout in milliseconds (no heartbeat received)\r\n */\r\n clientTimeout: 60000,\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\r\n /**\r\n * Auto-start configuration\r\n */\r\n autoStart: {\r\n /**\r\n * Whether to auto-start the hub if not running\r\n */\r\n enabled: true,\r\n\r\n /**\r\n * Maximum retries when connecting to hub\r\n */\r\n maxRetries: 3,\r\n\r\n /**\r\n * Delay between retries in milliseconds\r\n */\r\n retryDelay: 1000,\r\n },\r\n} as const;\r\n\r\nexport type Config = typeof config;\r\n","/**\r\n * WebSocket Message Protocol\r\n * Defines the message format between Hub and Clients\r\n * @module infrastructure/websocket/message-protocol\r\n */\r\n\r\nimport type { MemberId, TeamId, QuestionId } from '../../shared/types/branded-types.js';\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\nimport type { MemberStatus } from '../../domain/entities/member.entity.js';\r\nimport type { QuestionStatus } from '../../domain/entities/question.entity.js';\r\n\r\n// ============================================================================\r\n// Client → Hub Messages\r\n// ============================================================================\r\n\r\nexport type ClientMessageType = 'JOIN' | 'LEAVE' | 'ASK' | 'REPLY' | 'PING' | 'GET_INBOX';\r\n\r\nexport interface JoinMessage {\r\n type: 'JOIN';\r\n teamName: string;\r\n displayName: string;\r\n}\r\n\r\nexport interface LeaveMessage {\r\n type: 'LEAVE';\r\n}\r\n\r\nexport interface AskMessage {\r\n type: 'ASK';\r\n toTeam: string;\r\n content: string;\r\n format: MessageFormat;\r\n requestId: string; // For correlating response\r\n}\r\n\r\nexport interface ReplyMessage {\r\n type: 'REPLY';\r\n questionId: QuestionId;\r\n content: string;\r\n format: MessageFormat;\r\n}\r\n\r\nexport interface PingMessage {\r\n type: 'PING';\r\n}\r\n\r\nexport interface GetInboxMessage {\r\n type: 'GET_INBOX';\r\n requestId: string;\r\n}\r\n\r\nexport type ClientMessage =\r\n | JoinMessage\r\n | LeaveMessage\r\n | AskMessage\r\n | ReplyMessage\r\n | PingMessage\r\n | GetInboxMessage;\r\n\r\n// ============================================================================\r\n// Hub → Client Messages\r\n// ============================================================================\r\n\r\nexport type HubMessageType =\r\n | 'JOINED'\r\n | 'LEFT'\r\n | 'MEMBER_JOINED'\r\n | 'MEMBER_LEFT'\r\n | 'QUESTION'\r\n | 'ANSWER'\r\n | 'QUESTION_SENT'\r\n | 'INBOX'\r\n | 'PONG'\r\n | 'ERROR';\r\n\r\nexport interface MemberInfo {\r\n memberId: MemberId;\r\n teamId: TeamId;\r\n teamName: string;\r\n displayName: string;\r\n status: MemberStatus;\r\n}\r\n\r\nexport interface JoinedMessage {\r\n type: 'JOINED';\r\n member: MemberInfo;\r\n memberCount: number;\r\n}\r\n\r\nexport interface LeftMessage {\r\n type: 'LEFT';\r\n memberId: MemberId;\r\n}\r\n\r\nexport interface MemberJoinedMessage {\r\n type: 'MEMBER_JOINED';\r\n member: MemberInfo;\r\n}\r\n\r\nexport interface MemberLeftMessage {\r\n type: 'MEMBER_LEFT';\r\n memberId: MemberId;\r\n teamId: TeamId;\r\n}\r\n\r\nexport interface QuestionMessage {\r\n type: 'QUESTION';\r\n questionId: QuestionId;\r\n from: MemberInfo;\r\n content: string;\r\n format: MessageFormat;\r\n createdAt: string;\r\n}\r\n\r\nexport interface AnswerMessage {\r\n type: 'ANSWER';\r\n questionId: QuestionId;\r\n from: MemberInfo;\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n requestId?: string; // Correlates with original ASK request\r\n}\r\n\r\nexport interface QuestionSentMessage {\r\n type: 'QUESTION_SENT';\r\n questionId: QuestionId;\r\n toTeamId: TeamId;\r\n status: QuestionStatus;\r\n requestId: string;\r\n}\r\n\r\nexport interface InboxQuestionInfo {\r\n questionId: QuestionId;\r\n from: MemberInfo;\r\n content: string;\r\n format: MessageFormat;\r\n status: QuestionStatus;\r\n createdAt: string;\r\n ageMs: number;\r\n}\r\n\r\nexport interface InboxMessage {\r\n type: 'INBOX';\r\n questions: InboxQuestionInfo[];\r\n totalCount: number;\r\n pendingCount: number;\r\n requestId: string;\r\n}\r\n\r\nexport interface PongMessage {\r\n type: 'PONG';\r\n timestamp: string;\r\n}\r\n\r\nexport interface ErrorMessage {\r\n type: 'ERROR';\r\n code: string;\r\n message: string;\r\n requestId?: string;\r\n}\r\n\r\nexport type HubMessage =\r\n | JoinedMessage\r\n | LeftMessage\r\n | MemberJoinedMessage\r\n | MemberLeftMessage\r\n | QuestionMessage\r\n | AnswerMessage\r\n | QuestionSentMessage\r\n | InboxMessage\r\n | PongMessage\r\n | ErrorMessage;\r\n\r\n// ============================================================================\r\n// Serialization Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Serializes a message to JSON string\r\n */\r\nexport function serializeMessage<T extends ClientMessage | HubMessage>(message: T): string {\r\n return JSON.stringify(message);\r\n}\r\n\r\n/**\r\n * Parses a client message from JSON string\r\n */\r\nexport function parseClientMessage(data: string): ClientMessage {\r\n const parsed = JSON.parse(data) as ClientMessage;\r\n validateClientMessage(parsed);\r\n return parsed;\r\n}\r\n\r\n/**\r\n * Parses a hub message from JSON string\r\n */\r\nexport function parseHubMessage(data: string): HubMessage {\r\n return JSON.parse(data) as HubMessage;\r\n}\r\n\r\n/**\r\n * Validates a client message\r\n */\r\nfunction validateClientMessage(message: ClientMessage): void {\r\n if (!message.type) {\r\n throw new Error('Message must have a type');\r\n }\r\n\r\n const validTypes: ClientMessageType[] = ['JOIN', 'LEAVE', 'ASK', 'REPLY', 'PING', 'GET_INBOX'];\r\n if (!validTypes.includes(message.type)) {\r\n throw new Error(`Invalid message type: ${message.type}`);\r\n }\r\n}\r\n\r\n/**\r\n * Creates an error message\r\n */\r\nexport function createErrorMessage(\r\n code: string,\r\n message: string,\r\n requestId?: string\r\n): ErrorMessage {\r\n return {\r\n type: 'ERROR',\r\n code,\r\n message,\r\n requestId,\r\n };\r\n}\r\n","/**\r\n * WebSocket Hub Client\r\n * Client that connects to the Hub server\r\n * @module infrastructure/websocket/hub-client\r\n */\r\n\r\nimport WebSocket from 'ws';\r\nimport { v4 as uuidv4 } from 'uuid';\r\nimport type { MemberId, TeamId, QuestionId } from '../../shared/types/branded-types.js';\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\nimport { config } from '../../config/index.js';\r\nimport {\r\n type ClientMessage,\r\n type HubMessage,\r\n type QuestionMessage,\r\n type AnswerMessage,\r\n type InboxMessage,\r\n type MemberInfo,\r\n serializeMessage,\r\n parseHubMessage,\r\n} from './message-protocol.js';\r\n\r\n/**\r\n * Pending request with timeout\r\n */\r\ninterface PendingRequest<T> {\r\n resolve: (value: T) => void;\r\n reject: (error: Error) => void;\r\n timeout: ReturnType<typeof setTimeout>;\r\n}\r\n\r\n/**\r\n * Hub client options\r\n */\r\nexport interface HubClientOptions {\r\n host?: string;\r\n port?: number;\r\n reconnect?: boolean;\r\n reconnectDelay?: number;\r\n maxReconnectAttempts?: number;\r\n}\r\n\r\n/**\r\n * Hub client events\r\n */\r\nexport interface HubClientEvents {\r\n onConnected?: () => void;\r\n onDisconnected?: () => void;\r\n onQuestion?: (question: QuestionMessage) => void;\r\n onAnswer?: (answer: AnswerMessage) => void;\r\n onMemberJoined?: (member: MemberInfo) => void;\r\n onMemberLeft?: (memberId: MemberId, teamId: TeamId) => void;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\n/**\r\n * WebSocket Hub Client\r\n */\r\nexport class HubClient {\r\n private ws: WebSocket | null = null;\r\n private readonly pendingRequests = new Map<string, PendingRequest<HubMessage>>();\r\n private reconnectAttempts = 0;\r\n private isClosing = false;\r\n\r\n private memberId?: MemberId;\r\n private teamId?: TeamId;\r\n private teamName?: string;\r\n private displayName?: string;\r\n\r\n constructor(\r\n private readonly options: HubClientOptions = {},\r\n public readonly events: HubClientEvents = {}\r\n ) {}\r\n\r\n /**\r\n * Connects to the Hub server\r\n */\r\n async connect(): Promise<void> {\r\n const host = this.options.host ?? config.hub.host;\r\n const port = this.options.port ?? config.hub.port;\r\n const url = `ws://${host}:${port}`;\r\n\r\n return new Promise((resolve, reject) => {\r\n try {\r\n this.ws = new WebSocket(url);\r\n\r\n this.ws.on('open', () => {\r\n this.reconnectAttempts = 0;\r\n this.startPingInterval();\r\n this.events.onConnected?.();\r\n resolve();\r\n });\r\n\r\n this.ws.on('message', (data) => {\r\n this.handleMessage(data.toString());\r\n });\r\n\r\n this.ws.on('close', () => {\r\n this.handleDisconnect();\r\n });\r\n\r\n this.ws.on('error', (error) => {\r\n this.events.onError?.(error);\r\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\r\n reject(error);\r\n }\r\n });\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Disconnects from the Hub server\r\n */\r\n async disconnect(): Promise<void> {\r\n this.isClosing = true;\r\n\r\n if (this.memberId) {\r\n this.send({ type: 'LEAVE' });\r\n }\r\n\r\n return new Promise((resolve) => {\r\n if (this.ws) {\r\n this.ws.close();\r\n this.ws = null;\r\n }\r\n this.isClosing = false;\r\n resolve();\r\n });\r\n }\r\n\r\n /**\r\n * Joins a team\r\n */\r\n async join(teamName: string, displayName: string): Promise<MemberInfo> {\r\n const requestId = uuidv4();\r\n\r\n this.send({\r\n type: 'JOIN',\r\n teamName,\r\n displayName,\r\n });\r\n\r\n const response = await this.waitForResponse<{ type: 'JOINED'; member: MemberInfo }>(\r\n (msg) => msg.type === 'JOINED',\r\n 30000\r\n );\r\n\r\n this.memberId = response.member.memberId;\r\n this.teamId = response.member.teamId;\r\n this.teamName = teamName;\r\n this.displayName = displayName;\r\n\r\n return response.member;\r\n }\r\n\r\n /**\r\n * Asks a question to another team\r\n */\r\n async ask(\r\n toTeam: string,\r\n content: string,\r\n format: MessageFormat = 'markdown',\r\n timeoutMs: number = config.communication.defaultTimeout\r\n ): Promise<AnswerMessage> {\r\n const requestId = uuidv4();\r\n\r\n this.send({\r\n type: 'ASK',\r\n toTeam,\r\n content,\r\n format,\r\n requestId,\r\n });\r\n\r\n // Wait for QUESTION_SENT confirmation\r\n const questionSent = await this.waitForResponse<{\r\n type: 'QUESTION_SENT';\r\n questionId: QuestionId;\r\n requestId: string;\r\n }>(\r\n (msg) => msg.type === 'QUESTION_SENT' && 'requestId' in msg && msg.requestId === requestId,\r\n 5000\r\n );\r\n\r\n const questionId = questionSent.questionId;\r\n\r\n // Wait for ANSWER with matching questionId\r\n const answer = await this.waitForResponse<AnswerMessage>(\r\n (msg) => msg.type === 'ANSWER' && msg.questionId === questionId,\r\n timeoutMs\r\n );\r\n\r\n return answer;\r\n }\r\n\r\n /**\r\n * Gets the inbox (pending questions)\r\n */\r\n async getInbox(): Promise<InboxMessage> {\r\n const requestId = uuidv4();\r\n\r\n this.send({\r\n type: 'GET_INBOX',\r\n requestId,\r\n });\r\n\r\n return this.waitForResponse<InboxMessage>(\r\n (msg) => msg.type === 'INBOX' && msg.requestId === requestId,\r\n 5000\r\n );\r\n }\r\n\r\n /**\r\n * Replies to a question\r\n */\r\n async reply(questionId: QuestionId, content: string, format: MessageFormat = 'markdown'): Promise<void> {\r\n this.send({\r\n type: 'REPLY',\r\n questionId,\r\n content,\r\n format,\r\n });\r\n }\r\n\r\n /**\r\n * Checks if connected\r\n */\r\n get isConnected(): boolean {\r\n return this.ws !== null && this.ws.readyState === WebSocket.OPEN;\r\n }\r\n\r\n /**\r\n * Gets the current member ID\r\n */\r\n get currentMemberId(): MemberId | undefined {\r\n return this.memberId;\r\n }\r\n\r\n /**\r\n * Gets the current team ID\r\n */\r\n get currentTeamId(): TeamId | undefined {\r\n return this.teamId;\r\n }\r\n\r\n private send(message: ClientMessage): void {\r\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\r\n this.ws.send(serializeMessage(message));\r\n }\r\n }\r\n\r\n private handleMessage(data: string): void {\r\n try {\r\n const message = parseHubMessage(data);\r\n\r\n // Check pending requests\r\n for (const [requestId, pending] of this.pendingRequests) {\r\n // This is handled by the filter function in waitForResponse\r\n }\r\n\r\n // Handle specific message types\r\n switch (message.type) {\r\n case 'QUESTION':\r\n this.events.onQuestion?.(message);\r\n break;\r\n case 'ANSWER':\r\n this.events.onAnswer?.(message);\r\n break;\r\n case 'MEMBER_JOINED':\r\n this.events.onMemberJoined?.(message.member);\r\n break;\r\n case 'MEMBER_LEFT':\r\n this.events.onMemberLeft?.(message.memberId, message.teamId);\r\n break;\r\n case 'ERROR':\r\n this.events.onError?.(new Error(`${message.code}: ${message.message}`));\r\n break;\r\n }\r\n\r\n // Resolve any matching pending requests\r\n this.resolvePendingRequest(message);\r\n } catch (error) {\r\n console.error('Failed to parse message:', error);\r\n }\r\n }\r\n\r\n private resolvePendingRequest(message: HubMessage): void {\r\n for (const [requestId, pending] of this.pendingRequests) {\r\n // The filter is stored separately, we'll match by message type patterns\r\n this.pendingRequests.delete(requestId);\r\n clearTimeout(pending.timeout);\r\n pending.resolve(message);\r\n break; // Only resolve one request per message\r\n }\r\n }\r\n\r\n private waitForResponse<T extends HubMessage>(\r\n filter: (msg: HubMessage) => boolean,\r\n timeoutMs: number\r\n ): Promise<T> {\r\n return new Promise((resolve, reject) => {\r\n const requestId = uuidv4();\r\n\r\n const timeout = setTimeout(() => {\r\n this.pendingRequests.delete(requestId);\r\n reject(new Error('Request timed out'));\r\n }, timeoutMs);\r\n\r\n // Store filter function with the pending request\r\n const pending: PendingRequest<HubMessage> & { filter: (msg: HubMessage) => boolean } = {\r\n resolve: (msg) => {\r\n if (filter(msg)) {\r\n resolve(msg as T);\r\n }\r\n },\r\n reject,\r\n timeout,\r\n filter,\r\n };\r\n\r\n this.pendingRequests.set(requestId, pending);\r\n\r\n // Override handleMessage to check this specific filter\r\n const originalHandler = this.handleMessage.bind(this);\r\n const checkFilter = (data: string): void => {\r\n try {\r\n const message = parseHubMessage(data);\r\n if (filter(message)) {\r\n this.pendingRequests.delete(requestId);\r\n clearTimeout(timeout);\r\n resolve(message as T);\r\n }\r\n } catch {\r\n // Ignore parse errors here\r\n }\r\n originalHandler(data);\r\n };\r\n\r\n // Temporarily override\r\n if (this.ws) {\r\n this.ws.removeAllListeners('message');\r\n this.ws.on('message', (data) => checkFilter(data.toString()));\r\n }\r\n });\r\n }\r\n\r\n private handleDisconnect(): void {\r\n this.events.onDisconnected?.();\r\n\r\n if (this.isClosing) return;\r\n\r\n const shouldReconnect = this.options.reconnect ?? true;\r\n const maxAttempts = this.options.maxReconnectAttempts ?? config.autoStart.maxRetries;\r\n\r\n if (shouldReconnect && this.reconnectAttempts < maxAttempts) {\r\n this.reconnectAttempts++;\r\n const delay = this.options.reconnectDelay ?? config.autoStart.retryDelay;\r\n\r\n setTimeout(() => {\r\n this.connect()\r\n .then(() => {\r\n if (this.teamName && this.displayName) {\r\n return this.join(this.teamName, this.displayName);\r\n }\r\n })\r\n .catch((error) => {\r\n this.events.onError?.(error);\r\n });\r\n }, delay);\r\n }\r\n }\r\n\r\n private pingInterval: ReturnType<typeof setInterval> | null = null;\r\n\r\n private startPingInterval(): void {\r\n this.pingInterval = setInterval(() => {\r\n this.send({ type: 'PING' });\r\n }, config.hub.heartbeatInterval);\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 { HubClient } from '../../../infrastructure/websocket/hub-client.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, hubClient: HubClient): 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 // Ensure connected to hub\r\n if (!hubClient.isConnected) {\r\n await hubClient.connect();\r\n }\r\n\r\n // Join the team\r\n const member = await hubClient.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 * Ask Tool\r\n * Asks a question to another team and waits for response\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 { HubClient } from '../../../infrastructure/websocket/hub-client.js';\r\nimport { config } from '../../../config/index.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 timeout: z\r\n .number()\r\n .optional()\r\n .describe(`Timeout in seconds to wait for answer (default: ${config.communication.defaultTimeout / 1000}s)`),\r\n};\r\n\r\n/**\r\n * Registers the ask tool with the MCP server\r\n */\r\nexport function registerAskTool(server: McpServer, hubClient: HubClient): void {\r\n server.tool('ask', askSchema, async (args) => {\r\n const targetTeam = args.team;\r\n const question = args.question;\r\n const timeoutMs = (args.timeout ?? config.communication.defaultTimeout / 1000) * 1000;\r\n\r\n try {\r\n // Check if joined a team\r\n if (!hubClient.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 // Ask the question and wait for answer\r\n const answer = await hubClient.ask(targetTeam, question, 'markdown', timeoutMs);\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\r\n if (errorMessage.includes('timed out')) {\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `No response received from team \"${targetTeam}\" within ${timeoutMs / 1000} seconds. The question has been delivered but no one answered yet.`,\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: `Failed to ask question: ${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 { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { HubClient } from '../../../infrastructure/websocket/hub-client.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, hubClient: HubClient): void {\r\n server.tool('inbox', inboxSchema, async () => {\r\n try {\r\n // Check if joined a team\r\n if (!hubClient.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 // Get inbox\r\n const inbox = await hubClient.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 // Format questions list\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 { HubClient } from '../../../infrastructure/websocket/hub-client.js';\r\nimport type { QuestionId } from '../../../shared/types/branded-types.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, hubClient: HubClient): void {\r\n server.tool('reply', replySchema, async (args) => {\r\n const questionId = args.questionId as QuestionId;\r\n const answer = args.answer;\r\n\r\n try {\r\n // Check if joined a team\r\n if (!hubClient.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 // Send the reply\r\n await hubClient.reply(questionId, answer, 'markdown');\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 {\r\n ListResourcesRequestSchema,\r\n ReadResourceRequestSchema,\r\n} from '@modelcontextprotocol/sdk/types.js';\r\nimport type { HubClient } from '../../infrastructure/websocket/hub-client.js';\r\nimport { registerJoinTool } from './tools/join.tool.js';\r\nimport { registerAskTool } from './tools/ask.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 hubClient: HubClient;\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 { hubClient } = 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, hubClient);\r\n registerAskTool(server, hubClient);\r\n registerInboxTool(server, hubClient);\r\n registerReplyTool(server, hubClient);\r\n\r\n // Register resource handlers\r\n server.setRequestHandler(ListResourcesRequestSchema, async () => {\r\n return {\r\n resources: [\r\n {\r\n uri: 'inbox://questions',\r\n name: 'Pending Questions',\r\n description: 'Your inbox of pending questions from other teams',\r\n mimeType: 'application/json',\r\n },\r\n ],\r\n };\r\n });\r\n\r\n server.setRequestHandler(ReadResourceRequestSchema, async (request) => {\r\n if (request.params.uri === 'inbox://questions') {\r\n try {\r\n const inbox = await hubClient.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 throw new Error(`Unknown resource URI: ${request.params.uri}`);\r\n });\r\n\r\n return server;\r\n}\r\n\r\n/**\r\n * Starts the MCP server with stdio transport and sets up notifications\r\n */\r\nexport async function startMcpServer(options: McpServerOptions): Promise<void> {\r\n const { hubClient } = options;\r\n const server = createMcpServer(options);\r\n const transport = new StdioServerTransport();\r\n\r\n await server.connect(transport);\r\n\r\n // Setup notification when questions arrive\r\n hubClient.events.onQuestion = async (question) => {\r\n // Send resource updated notification to Claude\r\n await server.notification({\r\n method: 'notifications/resources/updated',\r\n params: {\r\n uri: 'inbox://questions',\r\n },\r\n });\r\n\r\n // Log for debugging\r\n console.error(`[📬 New Question] From: ${question.from.displayName}`);\r\n console.error(`[💡 Tip] Check your inbox with: inbox()`);\r\n };\r\n}\r\n","/**\r\n * Auto-Start Service\r\n * Automatically starts the Hub server if not running\r\n * @module infrastructure/hub-launcher/auto-start\r\n */\r\n\r\nimport { spawn, type ChildProcess } from 'child_process';\r\nimport { createConnection } from 'net';\r\nimport { config } from '../../config/index.js';\r\n\r\n/**\r\n * Auto-start service options\r\n */\r\nexport interface AutoStartOptions {\r\n host?: string;\r\n port?: number;\r\n maxRetries?: number;\r\n retryDelay?: number;\r\n}\r\n\r\n/**\r\n * Checks if the Hub server is running\r\n */\r\nexport async function isHubRunning(\r\n host: string = config.hub.host,\r\n port: number = config.hub.port\r\n): Promise<boolean> {\r\n return new Promise((resolve) => {\r\n const socket = createConnection({ host, port }, () => {\r\n socket.end();\r\n resolve(true);\r\n });\r\n\r\n socket.on('error', () => {\r\n resolve(false);\r\n });\r\n\r\n socket.setTimeout(1000, () => {\r\n socket.destroy();\r\n resolve(false);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Waits for the Hub server to become available\r\n */\r\nexport async function waitForHub(\r\n host: string = config.hub.host,\r\n port: number = config.hub.port,\r\n maxRetries: number = config.autoStart.maxRetries,\r\n retryDelay: number = config.autoStart.retryDelay\r\n): Promise<boolean> {\r\n for (let i = 0; i < maxRetries; i++) {\r\n if (await isHubRunning(host, port)) {\r\n return true;\r\n }\r\n await new Promise((resolve) => setTimeout(resolve, retryDelay));\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Starts the Hub server as a background process\r\n */\r\nexport function startHubProcess(options: AutoStartOptions = {}): ChildProcess {\r\n const host = options.host ?? config.hub.host;\r\n const port = options.port ?? config.hub.port;\r\n\r\n // Start hub-main.js as a detached process\r\n const hubProcess = spawn(\r\n process.execPath,\r\n [\r\n '--experimental-specifier-resolution=node',\r\n new URL('../../hub-main.js', import.meta.url).pathname,\r\n '--host',\r\n host,\r\n '--port',\r\n port.toString(),\r\n ],\r\n {\r\n detached: true,\r\n stdio: 'ignore',\r\n }\r\n );\r\n\r\n hubProcess.unref();\r\n return hubProcess;\r\n}\r\n\r\n/**\r\n * Ensures the Hub is running, starting it if necessary\r\n */\r\nexport async function ensureHubRunning(options: AutoStartOptions = {}): Promise<boolean> {\r\n const host = options.host ?? config.hub.host;\r\n const port = options.port ?? config.hub.port;\r\n const maxRetries = options.maxRetries ?? config.autoStart.maxRetries;\r\n const retryDelay = options.retryDelay ?? config.autoStart.retryDelay;\r\n\r\n // Check if already running\r\n if (await isHubRunning(host, port)) {\r\n return true;\r\n }\r\n\r\n // Try to start the hub\r\n console.log(`Hub not running. Starting hub on ${host}:${port}...`);\r\n startHubProcess({ host, port });\r\n\r\n // Wait for it to become available\r\n const isRunning = await waitForHub(host, port, maxRetries, retryDelay);\r\n\r\n if (isRunning) {\r\n console.log('Hub started successfully');\r\n } else {\r\n console.error('Failed to start hub');\r\n }\r\n\r\n return isRunning;\r\n}\r\n","#!/usr/bin/env node\r\n\r\n/**\r\n * MCP Server entry point\r\n * This is the main entry point for the MCP client that connects to Claude Code\r\n * @module mcp-main\r\n */\r\n\r\nimport { HubClient } from './infrastructure/websocket/hub-client.js';\r\nimport { startMcpServer } from './presentation/mcp/server.js';\r\nimport { ensureHubRunning } from './infrastructure/hub-launcher/auto-start.service.js';\r\nimport { config } from './config/index.js';\r\n\r\nconst args = process.argv.slice(2);\r\n\r\ninterface ClientOptions {\r\n team?: string;\r\n host: string;\r\n port: number;\r\n autoHub: boolean;\r\n}\r\n\r\nfunction parseArgs(): ClientOptions {\r\n const options: ClientOptions = {\r\n host: config.hub.host,\r\n port: config.hub.port,\r\n autoHub: false,\r\n };\r\n\r\n for (let i = 0; i < args.length; i++) {\r\n const arg = args[i];\r\n const nextArg = args[i + 1];\r\n\r\n if (arg === '--team' && nextArg) {\r\n options.team = nextArg;\r\n i++;\r\n } else if (arg === '--host' && nextArg) {\r\n options.host = nextArg;\r\n i++;\r\n } else if (arg === '--port' && nextArg) {\r\n options.port = parseInt(nextArg, 10);\r\n i++;\r\n } else if (arg === '--auto-hub') {\r\n options.autoHub = true;\r\n } else if (arg === '-h' || arg === '--help') {\r\n console.error(`\r\nClaude Collab MCP Client\r\n\r\nUsage:\r\n mcp-main [options]\r\n\r\nOptions:\r\n --team <team> Team to auto-join (optional)\r\n --host <host> Hub host (default: ${config.hub.host})\r\n --port <port> Hub port (default: ${config.hub.port})\r\n --auto-hub Auto-start hub if not running\r\n -h, --help Show this help message\r\n`);\r\n process.exit(0);\r\n }\r\n }\r\n\r\n return options;\r\n}\r\n\r\nasync function main(): Promise<void> {\r\n const options = parseArgs();\r\n\r\n // Auto-start hub if requested\r\n if (options.autoHub) {\r\n const hubRunning = await ensureHubRunning({\r\n host: options.host,\r\n port: options.port,\r\n });\r\n\r\n if (!hubRunning) {\r\n console.error('Failed to start hub server. Exiting.');\r\n process.exit(1);\r\n }\r\n }\r\n\r\n // Create hub client\r\n const hubClient = new HubClient(\r\n {\r\n host: options.host,\r\n port: options.port,\r\n reconnect: true,\r\n },\r\n {\r\n onError: (error) => {\r\n console.error('Hub client error:', error.message);\r\n },\r\n onQuestion: (question) => {\r\n // Questions will be handled by inbox tool\r\n console.error(`[Question received from ${question.from.displayName}]`);\r\n },\r\n }\r\n );\r\n\r\n // Connect to hub\r\n try {\r\n await hubClient.connect();\r\n\r\n // Auto-join team if specified\r\n if (options.team) {\r\n await hubClient.join(options.team, `${options.team} Claude`);\r\n console.error(`Auto-joined team: ${options.team}`);\r\n }\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n console.error(`Failed to connect to hub: ${errorMessage}`);\r\n console.error('Make sure the hub server is running or use --auto-hub flag.');\r\n process.exit(1);\r\n }\r\n\r\n // Start MCP server\r\n await startMcpServer({ hubClient });\r\n}\r\n\r\nmain().catch((error) => {\r\n console.error('Unexpected error:', error);\r\n process.exit(1);\r\n});\r\n"]}
|