@hongw/unicoda-mcp 0.1.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/config.ts","../src/server.ts","../src/tools/chat.ts","../src/errors.ts","../src/tools/models.ts","../src/tools/session.ts","../src/tools/workspace.ts","../src/state.ts","../src/providers/copilot.ts","../src/utils/id.ts","../src/utils/path.ts","../src/providers/copilot-event-mapper.ts"],"sourcesContent":["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\r\nimport { parseConfig } from './config.js';\r\nimport { createServer } from './server.js';\r\nimport { StateManager } from './state.js';\r\n\r\nasync function main(): Promise<void> {\r\n const config = parseConfig(process.argv.slice(2));\r\n\r\n const state = new StateManager(config);\r\n const server = createServer(state, config);\r\n\r\n // Graceful shutdown\r\n const shutdown = async () => {\r\n await state.shutdown();\r\n process.exit(0);\r\n };\r\n process.on('SIGINT', shutdown);\r\n process.on('SIGTERM', shutdown);\r\n\r\n // Connect via stdio transport\r\n const transport = new StdioServerTransport();\r\n await server.connect(transport);\r\n}\r\n\r\nmain().catch((err) => {\r\n console.error('Unicoda MCP Server failed to start:', err);\r\n process.exit(1);\r\n});\r\n","import { z } from 'zod';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Request Status\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const RequestStatusSchema = z.enum([\r\n 'queued',\r\n 'running',\r\n 'completed',\r\n 'error',\r\n 'aborted',\r\n 'timeout',\r\n]);\r\nexport type RequestStatus = z.infer<typeof RequestStatusSchema>;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Workspace Status\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const WorkspaceStatusSchema = z.enum(['starting', 'running', 'stopped', 'error']);\r\nexport type WorkspaceStatus = z.infer<typeof WorkspaceStatusSchema>;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Message\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const MessageSchema = z.object({\r\n type: z.enum(['user', 'assistant', 'tool_call', 'tool_result', 'system', 'error']),\r\n content: z.string(),\r\n timestamp: z.string(), // ISO8601\r\n metadata: z\r\n .record(z.string(), z.unknown())\r\n .optional(),\r\n});\r\nexport type Message = z.infer<typeof MessageSchema>;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Attachment\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const AttachmentSchema = z.object({\r\n type: z.enum(['file', 'directory', 'selection']),\r\n path: z.string(),\r\n displayName: z.string().optional(),\r\n});\r\nexport type Attachment = z.infer<typeof AttachmentSchema>;\r\n\r\n// ---------------------------------------------------------------------------\r\n// SendResult — unified return from send / sendAndWait / poll\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface SendResult {\r\n requestId: string;\r\n status: RequestStatus;\r\n messages: Message[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Model\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface Model {\r\n id: string;\r\n provider: string;\r\n name?: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Workspace info (returned to MCP callers)\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface WorkspaceInfo {\r\n workspaceId: string;\r\n directory: string;\r\n provider: string;\r\n status: WorkspaceStatus;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Session info (returned to MCP callers)\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface SessionInfo {\r\n sessionId: string;\r\n workspaceId: string;\r\n createdAt?: string;\r\n modifiedTime?: string;\r\n summary?: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Internal: WorkspaceState\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface WorkspaceState {\r\n workspaceId: string;\r\n directory: string; // canonicalized\r\n originalDirectory: string; // as provided by user\r\n providerName: string;\r\n status: WorkspaceStatus;\r\n createdAt: Date;\r\n lastAccessedAt: Date;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Internal: RequestState\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface RequestState {\r\n requestId: string;\r\n messageId?: string; // SDK-returned messageId\r\n sessionId: string;\r\n workspaceId: string;\r\n status: RequestStatus;\r\n messages: Message[];\r\n createdAt: Date;\r\n completedAt?: Date;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Server Config\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface ServerConfig {\r\n provider: string;\r\n autoStartWorkspace: boolean;\r\n maxWorkspaces: number;\r\n maxSessionsPerWorkspace: number;\r\n workspaceTTL: number; // ms\r\n sessionTTL: number; // ms\r\n requestTTL: number; // ms\r\n portRangeStart: number;\r\n}\r\n\r\nexport const DEFAULT_SERVER_CONFIG: ServerConfig = {\r\n provider: 'copilot',\r\n autoStartWorkspace: true,\r\n maxWorkspaces: 10,\r\n maxSessionsPerWorkspace: 5,\r\n workspaceTTL: 30 * 60 * 1000, // 30 minutes\r\n sessionTTL: 60 * 60 * 1000, // 1 hour\r\n requestTTL: 5 * 60 * 1000, // 5 minutes\r\n portRangeStart: 40000,\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Provider display names\r\n// ---------------------------------------------------------------------------\r\n\r\nconst PROVIDER_DISPLAY_NAMES: Record<string, string> = {\r\n copilot: 'GitHub Copilot',\r\n codex: 'OpenAI Codex',\r\n 'claude-code': 'Claude Code',\r\n};\r\n\r\nexport function getProviderDisplayName(provider: string): string {\r\n return PROVIDER_DISPLAY_NAMES[provider] ?? provider;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Error codes\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const ErrorCodes = {\r\n WORKSPACE_NOT_FOUND: 'WORKSPACE_NOT_FOUND',\r\n SESSION_NOT_FOUND: 'SESSION_NOT_FOUND',\r\n REQUEST_NOT_FOUND: 'REQUEST_NOT_FOUND',\r\n DIRECTORY_NOT_FOUND: 'DIRECTORY_NOT_FOUND',\r\n DIRECTORY_NOT_ABSOLUTE: 'DIRECTORY_NOT_ABSOLUTE',\r\n PROVIDER_NOT_AVAILABLE: 'PROVIDER_NOT_AVAILABLE',\r\n PROVIDER_NOT_SUPPORTED: 'PROVIDER_NOT_SUPPORTED',\r\n CLI_START_FAILED: 'CLI_START_FAILED',\r\n CLI_CONNECTION_LOST: 'CLI_CONNECTION_LOST',\r\n TIMEOUT: 'TIMEOUT',\r\n INVALID_PARAMETER: 'INVALID_PARAMETER',\r\n WORKSPACE_LIMIT_EXCEEDED: 'WORKSPACE_LIMIT_EXCEEDED',\r\n SESSION_LIMIT_EXCEEDED: 'SESSION_LIMIT_EXCEEDED',\r\n REQUEST_ALREADY_COMPLETED: 'REQUEST_ALREADY_COMPLETED',\r\n} as const;\r\n\r\nexport type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];\r\n\r\nconst RETRYABLE_CODES = new Set<ErrorCode>([\r\n ErrorCodes.CLI_START_FAILED,\r\n ErrorCodes.CLI_CONNECTION_LOST,\r\n ErrorCodes.TIMEOUT,\r\n]);\r\n\r\nexport function isRetryable(code: ErrorCode): boolean {\r\n return RETRYABLE_CODES.has(code);\r\n}\r\n","import type { ServerConfig } from './types.js';\r\nimport { DEFAULT_SERVER_CONFIG } from './types.js';\r\n\r\n/**\r\n * Parse server configuration from CLI arguments and environment variables.\r\n * CLI args take precedence over env vars, which take precedence over defaults.\r\n */\r\nexport function parseConfig(argv: string[]): ServerConfig {\r\n const config = { ...DEFAULT_SERVER_CONFIG };\r\n\r\n // Parse CLI args\r\n const args = parseArgs(argv);\r\n\r\n // Provider\r\n config.provider =\r\n args['provider'] ?? env('UNICODA_PROVIDER') ?? config.provider;\r\n\r\n // Auto-start workspace\r\n const autoStart =\r\n args['auto-start-workspace'] ?? env('UNICODA_AUTO_START_WORKSPACE');\r\n if (autoStart !== undefined) {\r\n config.autoStartWorkspace = parseBool(autoStart, config.autoStartWorkspace);\r\n }\r\n\r\n // Max workspaces\r\n const maxWs = args['max-workspaces'] ?? env('UNICODA_MAX_WORKSPACES');\r\n if (maxWs !== undefined) {\r\n config.maxWorkspaces = parseInt(maxWs, 10) || config.maxWorkspaces;\r\n }\r\n\r\n // Workspace TTL\r\n const wsTtl = args['workspace-ttl'] ?? env('UNICODA_WORKSPACE_TTL');\r\n if (wsTtl !== undefined) {\r\n config.workspaceTTL = parseInt(wsTtl, 10) || config.workspaceTTL;\r\n }\r\n\r\n // Port range start\r\n const portStart = args['port-range-start'] ?? env('UNICODA_PORT_RANGE_START');\r\n if (portStart !== undefined) {\r\n config.portRangeStart = parseInt(portStart, 10) || config.portRangeStart;\r\n }\r\n\r\n return config;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction env(name: string): string | undefined {\r\n return process.env[name];\r\n}\r\n\r\nfunction parseBool(value: string, fallback: boolean): boolean {\r\n if (value === 'true' || value === '1' || value === 'yes') return true;\r\n if (value === 'false' || value === '0' || value === 'no') return false;\r\n return fallback;\r\n}\r\n\r\n/**\r\n * Minimal CLI arg parser. Supports `--key value` and `--key=value` forms.\r\n */\r\nfunction parseArgs(argv: string[]): Record<string, string> {\r\n const result: Record<string, string> = {};\r\n for (let i = 0; i < argv.length; i++) {\r\n const arg = argv[i];\r\n if (!arg.startsWith('--')) continue;\r\n\r\n const eqIdx = arg.indexOf('=');\r\n if (eqIdx !== -1) {\r\n const key = arg.slice(2, eqIdx);\r\n result[key] = arg.slice(eqIdx + 1);\r\n } else {\r\n const key = arg.slice(2);\r\n const next = argv[i + 1];\r\n if (next && !next.startsWith('--')) {\r\n result[key] = next;\r\n i++; // skip the value\r\n } else {\r\n result[key] = 'true'; // flag-style\r\n }\r\n }\r\n }\r\n return result;\r\n}\r\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { StateManager } from './state.js';\r\nimport { registerChatTools } from './tools/chat.js';\r\nimport { registerModelTools } from './tools/models.js';\r\nimport { registerSessionTools } from './tools/session.js';\r\nimport { registerWorkspaceTools } from './tools/workspace.js';\r\nimport { getProviderDisplayName } from './types.js';\r\nimport type { ServerConfig } from './types.js';\r\n\r\n/**\r\n * Create and configure the Unicoda MCP Server.\r\n * Registers all tools against the given state manager.\r\n */\r\nexport function createServer(state: StateManager, config: ServerConfig): McpServer {\r\n const providerDisplayName = getProviderDisplayName(config.provider);\r\n\r\n const server = new McpServer({\r\n name: 'unicoda',\r\n version: '1.0.0',\r\n });\r\n\r\n // Register all tool groups\r\n registerWorkspaceTools(server, state, providerDisplayName);\r\n registerSessionTools(server, state, providerDisplayName);\r\n registerChatTools(server, state, providerDisplayName);\r\n registerModelTools(server, state);\r\n\r\n return server;\r\n}\r\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport { z } from 'zod';\r\nimport { toMcpErrorContent } from '../errors.js';\r\nimport type { StateManager } from '../state.js';\r\nimport type { Message, RequestStatus, SendResult } from '../types.js';\r\n\r\nfunction jsonContent(data: unknown) {\r\n return { content: [{ type: 'text' as const, text: JSON.stringify(data, null, 2) }] };\r\n}\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\nfunction isActive(status: RequestStatus): boolean {\r\n return status === 'queued' || status === 'running';\r\n}\r\n\r\ntype DetailLevel = 'status' | 'message' | 'brief' | 'full';\r\n\r\nfunction truncate(str: string, maxLen: number): string {\r\n return str.length <= maxLen ? str : str.slice(0, maxLen) + '…';\r\n}\r\n\r\nfunction applyDetailLevel(\r\n result: SendResult,\r\n detail: DetailLevel,\r\n): { requestId: string; status: RequestStatus; messages?: Message[] } {\r\n switch (detail) {\r\n case 'status':\r\n return { requestId: result.requestId, status: result.status };\r\n\r\n case 'message':\r\n return {\r\n requestId: result.requestId,\r\n status: result.status,\r\n messages: result.messages.filter((m) => m.type === 'assistant'),\r\n };\r\n\r\n case 'brief': {\r\n const messages: Message[] = [];\r\n for (const m of result.messages) {\r\n if (m.type === 'tool_result') continue;\r\n if (m.type === 'tool_call') {\r\n messages.push({\r\n ...m,\r\n content: truncate(m.content, 100),\r\n metadata: m.metadata\r\n ? { ...m.metadata, truncated: m.content.length > 100 }\r\n : undefined,\r\n });\r\n } else {\r\n messages.push(m);\r\n }\r\n }\r\n return { requestId: result.requestId, status: result.status, messages };\r\n }\r\n\r\n case 'full':\r\n default:\r\n return result;\r\n }\r\n}\r\n\r\nexport function registerChatTools(server: McpServer, state: StateManager, providerDisplayName: string): void {\r\n // ----- send --------------------------------------------------------------\r\n server.registerTool(\r\n 'send',\r\n {\r\n title: 'Send Message',\r\n description:\r\n `Send a message to ${providerDisplayName}. Returns immediately with a requestId ` +\r\n 'that can be polled for status and results.',\r\n inputSchema: {\r\n workspace: z.string().describe('Workspace ID or project directory path'),\r\n sessionId: z.string().describe('Session ID'),\r\n prompt: z.string().describe('Message content to send to the agent'),\r\n attachments: z\r\n .array(\r\n z.object({\r\n type: z.enum(['file', 'directory', 'selection']),\r\n path: z.string(),\r\n displayName: z.string().optional(),\r\n }),\r\n )\r\n .optional()\r\n .describe('File attachments'),\r\n },\r\n },\r\n async ({ workspace, sessionId, prompt, attachments }) => {\r\n try {\r\n const ws = state.requireWorkspace(workspace);\r\n const provider = state.getProvider(ws.providerName);\r\n const result = await provider.send(ws.workspaceId, sessionId, {\r\n prompt,\r\n attachments,\r\n });\r\n return jsonContent(result);\r\n } catch (err) {\r\n return toMcpErrorContent(err);\r\n }\r\n },\r\n );\r\n\r\n // ----- send_and_wait -----------------------------------------------------\r\n server.registerTool(\r\n 'send_and_wait',\r\n {\r\n title: 'Send and Wait',\r\n description:\r\n `Send a message to ${providerDisplayName} and wait for the complete response. ` +\r\n 'Blocks until the agent finishes or timeout is reached.',\r\n inputSchema: {\r\n workspace: z.string().describe('Workspace ID or project directory path'),\r\n sessionId: z.string().describe('Session ID'),\r\n prompt: z.string().describe('Message content to send to the agent'),\r\n timeout: z\r\n .number()\r\n .optional()\r\n .describe('Timeout in milliseconds (default: 300000 = 5 minutes)'),\r\n attachments: z\r\n .array(\r\n z.object({\r\n type: z.enum(['file', 'directory', 'selection']),\r\n path: z.string(),\r\n displayName: z.string().optional(),\r\n }),\r\n )\r\n .optional()\r\n .describe('File attachments'),\r\n },\r\n },\r\n async ({ workspace, sessionId, prompt, timeout, attachments }) => {\r\n try {\r\n const ws = state.requireWorkspace(workspace);\r\n const provider = state.getProvider(ws.providerName);\r\n const result = await provider.sendAndWait(ws.workspaceId, sessionId, {\r\n prompt,\r\n attachments,\r\n timeout,\r\n });\r\n return jsonContent(result);\r\n } catch (err) {\r\n return toMcpErrorContent(err);\r\n }\r\n },\r\n );\r\n\r\n // ----- poll --------------------------------------------------------------\r\n server.registerTool(\r\n 'poll',\r\n {\r\n title: 'Poll Request',\r\n description:\r\n 'Check the status of a previously sent request. ' +\r\n 'Returns accumulated messages and current status. ' +\r\n 'Supports long-polling via the timeout parameter and flexible detail levels.',\r\n inputSchema: {\r\n workspace: z.string().describe('Workspace ID or project directory path'),\r\n sessionId: z.string().describe('Session ID'),\r\n requestId: z.string().describe('Request ID returned by send'),\r\n timeout: z\r\n .number()\r\n .optional()\r\n .describe(\r\n 'Long-poll timeout in milliseconds. If provided, waits up to this duration for the request to complete before returning current state.',\r\n ),\r\n detail: z\r\n .enum(['status', 'message', 'brief', 'full'])\r\n .optional()\r\n .describe(\r\n 'Detail level for the response (default: \"full\"). ' +\r\n '\"status\" returns only requestId and status. ' +\r\n '\"message\" returns status + assistant text messages only. ' +\r\n '\"brief\" returns status + assistant messages + tool call summaries (truncated args, no results). ' +\r\n '\"full\" returns everything.',\r\n ),\r\n },\r\n },\r\n async ({ workspace, sessionId, requestId, timeout, detail }) => {\r\n try {\r\n const ws = state.requireWorkspace(workspace);\r\n const provider = state.getProvider(ws.providerName);\r\n\r\n let result = await provider.poll(ws.workspaceId, sessionId, requestId);\r\n\r\n // Long-poll: wait for completion if timeout is specified and request is still active\r\n if (timeout != null && timeout > 0 && isActive(result.status)) {\r\n const deadline = Date.now() + timeout;\r\n const POLL_INTERVAL = 200; // ms\r\n while (Date.now() < deadline && isActive(result.status)) {\r\n await sleep(Math.min(POLL_INTERVAL, deadline - Date.now()));\r\n result = await provider.poll(ws.workspaceId, sessionId, requestId);\r\n }\r\n }\r\n\r\n const effectiveDetail = detail ?? 'full';\r\n\r\n return jsonContent(applyDetailLevel(result, effectiveDetail));\r\n } catch (err) {\r\n return toMcpErrorContent(err);\r\n }\r\n },\r\n );\r\n\r\n // ----- abort -------------------------------------------------------------\r\n server.registerTool(\r\n 'abort',\r\n {\r\n title: 'Abort Request',\r\n description: 'Abort an in-progress request.',\r\n inputSchema: {\r\n workspace: z.string().describe('Workspace ID or project directory path'),\r\n sessionId: z.string().describe('Session ID'),\r\n requestId: z.string().describe('Request ID to abort'),\r\n },\r\n },\r\n async ({ workspace, sessionId, requestId }) => {\r\n try {\r\n const ws = state.requireWorkspace(workspace);\r\n const provider = state.getProvider(ws.providerName);\r\n const result = await provider.abort(ws.workspaceId, sessionId, requestId);\r\n return jsonContent(result);\r\n } catch (err) {\r\n return toMcpErrorContent(err);\r\n }\r\n },\r\n );\r\n}\r\n","import { type ErrorCode, ErrorCodes, isRetryable } from './types.js';\r\n\r\n/**\r\n * Structured error class for all Unicoda errors.\r\n * Carries an error code, retryability flag, and optional context.\r\n */\r\nexport class UnicodaError extends Error {\r\n readonly code: ErrorCode;\r\n readonly retryable: boolean;\r\n readonly details?: Record<string, unknown>;\r\n readonly provider?: string;\r\n readonly requestId?: string;\r\n\r\n constructor(\r\n code: ErrorCode,\r\n message: string,\r\n opts?: {\r\n details?: Record<string, unknown>;\r\n provider?: string;\r\n requestId?: string;\r\n cause?: unknown;\r\n },\r\n ) {\r\n super(message, { cause: opts?.cause });\r\n this.name = 'UnicodaError';\r\n this.code = code;\r\n this.retryable = isRetryable(code);\r\n this.details = opts?.details;\r\n this.provider = opts?.provider;\r\n this.requestId = opts?.requestId;\r\n }\r\n\r\n toJSON() {\r\n return {\r\n error: {\r\n code: this.code,\r\n message: this.message,\r\n details: this.details,\r\n provider: this.provider,\r\n requestId: this.requestId,\r\n retryable: this.retryable,\r\n },\r\n };\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Factory helpers\r\n// ---------------------------------------------------------------------------\r\n\r\nexport function workspaceNotFound(id: string): UnicodaError {\r\n return new UnicodaError(ErrorCodes.WORKSPACE_NOT_FOUND, `Workspace not found: ${id}`);\r\n}\r\n\r\nexport function sessionNotFound(sessionId: string, workspaceId?: string): UnicodaError {\r\n const ctx = workspaceId ? ` in workspace ${workspaceId}` : '';\r\n return new UnicodaError(ErrorCodes.SESSION_NOT_FOUND, `Session not found: ${sessionId}${ctx}`);\r\n}\r\n\r\nexport function requestNotFound(requestId: string): UnicodaError {\r\n return new UnicodaError(ErrorCodes.REQUEST_NOT_FOUND, `Request not found: ${requestId}`, {\r\n requestId,\r\n });\r\n}\r\n\r\nexport function directoryNotFound(dir: string): UnicodaError {\r\n return new UnicodaError(ErrorCodes.DIRECTORY_NOT_FOUND, `Directory not found: ${dir}`, {\r\n details: { directory: dir },\r\n });\r\n}\r\n\r\nexport function directoryNotAbsolute(dir: string): UnicodaError {\r\n return new UnicodaError(\r\n ErrorCodes.DIRECTORY_NOT_ABSOLUTE,\r\n `Directory path must be absolute: ${dir}`,\r\n { details: { directory: dir } },\r\n );\r\n}\r\n\r\nexport function providerNotSupported(name: string): UnicodaError {\r\n return new UnicodaError(ErrorCodes.PROVIDER_NOT_SUPPORTED, `Provider not supported: ${name}`, {\r\n details: { provider: name },\r\n });\r\n}\r\n\r\nexport function providerNotAvailable(name: string, reason?: string): UnicodaError {\r\n const msg = reason ? `Provider not available: ${name} — ${reason}` : `Provider not available: ${name}`;\r\n return new UnicodaError(ErrorCodes.PROVIDER_NOT_AVAILABLE, msg, {\r\n provider: name,\r\n });\r\n}\r\n\r\nexport function cliStartFailed(provider: string, cause?: unknown): UnicodaError {\r\n return new UnicodaError(ErrorCodes.CLI_START_FAILED, `Failed to start ${provider} CLI`, {\r\n provider,\r\n cause,\r\n });\r\n}\r\n\r\nexport function cliConnectionLost(provider: string, cause?: unknown): UnicodaError {\r\n return new UnicodaError(\r\n ErrorCodes.CLI_CONNECTION_LOST,\r\n `Connection to ${provider} CLI lost`,\r\n { provider, cause },\r\n );\r\n}\r\n\r\nexport function timeout(requestId: string, ms: number): UnicodaError {\r\n return new UnicodaError(ErrorCodes.TIMEOUT, `Request ${requestId} timed out after ${ms}ms`, {\r\n requestId,\r\n details: { timeoutMs: ms },\r\n });\r\n}\r\n\r\nexport function invalidParameter(param: string, message: string): UnicodaError {\r\n return new UnicodaError(\r\n ErrorCodes.INVALID_PARAMETER,\r\n `Invalid parameter '${param}': ${message}`,\r\n { details: { parameter: param } },\r\n );\r\n}\r\n\r\nexport function workspaceLimitExceeded(max: number): UnicodaError {\r\n return new UnicodaError(\r\n ErrorCodes.WORKSPACE_LIMIT_EXCEEDED,\r\n `Maximum number of workspaces (${max}) exceeded`,\r\n { details: { maxWorkspaces: max } },\r\n );\r\n}\r\n\r\nexport function sessionLimitExceeded(max: number, workspaceId: string): UnicodaError {\r\n return new UnicodaError(\r\n ErrorCodes.SESSION_LIMIT_EXCEEDED,\r\n `Maximum number of sessions (${max}) exceeded for workspace ${workspaceId}`,\r\n { details: { maxSessions: max, workspaceId } },\r\n );\r\n}\r\n\r\nexport function requestAlreadyCompleted(requestId: string): UnicodaError {\r\n return new UnicodaError(\r\n ErrorCodes.REQUEST_ALREADY_COMPLETED,\r\n `Request ${requestId} has already completed and cannot be aborted`,\r\n { requestId },\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// MCP tool-response formatting\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Format a UnicodaError (or any Error) as MCP tool response content.\r\n */\r\nexport function toMcpErrorContent(err: unknown): { content: Array<{ type: 'text'; text: string }>; isError: true } {\r\n if (err instanceof UnicodaError) {\r\n return {\r\n content: [{ type: 'text', text: JSON.stringify(err.toJSON(), null, 2) }],\r\n isError: true,\r\n };\r\n }\r\n const message = err instanceof Error ? err.message : String(err);\r\n return {\r\n content: [{ type: 'text', text: JSON.stringify({ error: { code: 'INTERNAL_ERROR', message, retryable: false } }, null, 2) }],\r\n isError: true,\r\n };\r\n}\r\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport { z } from 'zod';\r\nimport { toMcpErrorContent } from '../errors.js';\r\nimport type { StateManager } from '../state.js';\r\n\r\nfunction jsonContent(data: unknown) {\r\n return { content: [{ type: 'text' as const, text: JSON.stringify(data, null, 2) }] };\r\n}\r\n\r\nexport function registerModelTools(server: McpServer, state: StateManager): void {\r\n server.registerTool(\r\n 'models_list',\r\n {\r\n title: 'List Models',\r\n description: 'List available AI models.',\r\n inputSchema: {\r\n provider: z\r\n .string()\r\n .optional()\r\n .describe('Filter by provider name. If omitted, returns models from all providers.'),\r\n },\r\n },\r\n async ({ provider: providerName }) => {\r\n try {\r\n const provider = state.getProvider(providerName);\r\n const models = await provider.listModels();\r\n return jsonContent({ models });\r\n } catch (err) {\r\n return toMcpErrorContent(err);\r\n }\r\n },\r\n );\r\n}\r\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport { z } from 'zod';\r\nimport { toMcpErrorContent } from '../errors.js';\r\nimport type { StateManager } from '../state.js';\r\n\r\nfunction jsonContent(data: unknown) {\r\n return { content: [{ type: 'text' as const, text: JSON.stringify(data, null, 2) }] };\r\n}\r\n\r\nexport function registerSessionTools(server: McpServer, state: StateManager, _providerDisplayName: string): void {\r\n // ----- session_create ----------------------------------------------------\r\n server.registerTool(\r\n 'session_create',\r\n {\r\n title: 'Create Session',\r\n description:\r\n 'Create a new conversation session in a workspace. ' +\r\n 'A directory path or workspace ID can be used.',\r\n inputSchema: {\r\n workspace: z\r\n .string()\r\n .describe('Workspace ID or project directory path'),\r\n provider: z\r\n .string()\r\n .optional()\r\n .describe('Backend provider (only used when auto-starting a workspace)'),\r\n model: z\r\n .string()\r\n .optional()\r\n .describe('Model name (e.g. claude-opus-4, gpt-4o)'),\r\n sessionId: z\r\n .string()\r\n .optional()\r\n .describe('Custom session ID (auto-generated if omitted)'),\r\n },\r\n },\r\n async ({ workspace, provider, model, sessionId }) => {\r\n try {\r\n const {\r\n workspace: ws,\r\n provider: prov,\r\n autoStarted,\r\n } = await state.ensureWorkspace(workspace, provider);\r\n\r\n const session = await prov.createSession(ws.workspaceId, {\r\n model,\r\n sessionId,\r\n });\r\n\r\n return jsonContent({\r\n sessionId: session.sessionId,\r\n workspaceId: ws.workspaceId,\r\n workspacePath: ws.directory,\r\n autoStarted,\r\n });\r\n } catch (err) {\r\n return toMcpErrorContent(err);\r\n }\r\n },\r\n );\r\n\r\n // ----- session_list ------------------------------------------------------\r\n server.registerTool(\r\n 'session_list',\r\n {\r\n title: 'List Sessions',\r\n description: 'List all sessions in a workspace.',\r\n inputSchema: {\r\n workspace: z\r\n .string()\r\n .describe('Workspace ID or project directory path'),\r\n },\r\n },\r\n async ({ workspace }) => {\r\n try {\r\n const ws = state.requireWorkspace(workspace);\r\n const provider = state.getProvider(ws.providerName);\r\n const sessions = await provider.listSessions(ws.workspaceId);\r\n\r\n return jsonContent({\r\n sessions: sessions.map((s) => ({\r\n sessionId: s.sessionId,\r\n startTime: s.createdAt?.toISOString(),\r\n modifiedTime: s.modifiedTime?.toISOString(),\r\n summary: s.summary,\r\n })),\r\n });\r\n } catch (err) {\r\n return toMcpErrorContent(err);\r\n }\r\n },\r\n );\r\n\r\n // ----- session_delete ----------------------------------------------------\r\n server.registerTool(\r\n 'session_delete',\r\n {\r\n title: 'Delete Session',\r\n description: 'Delete a session from a workspace.',\r\n inputSchema: {\r\n workspace: z\r\n .string()\r\n .describe('Workspace ID or project directory path'),\r\n sessionId: z.string().describe('Session ID to delete'),\r\n },\r\n },\r\n async ({ workspace, sessionId }) => {\r\n try {\r\n const ws = state.requireWorkspace(workspace);\r\n const provider = state.getProvider(ws.providerName);\r\n await provider.deleteSession(ws.workspaceId, sessionId);\r\n return jsonContent({ success: true });\r\n } catch (err) {\r\n return toMcpErrorContent(err);\r\n }\r\n },\r\n );\r\n\r\n // ----- session_history ---------------------------------------------------\r\n server.registerTool(\r\n 'session_history',\r\n {\r\n title: 'Session History',\r\n description: 'Get the chat history for a session.',\r\n inputSchema: {\r\n workspace: z\r\n .string()\r\n .describe('Workspace ID or project directory path'),\r\n sessionId: z.string().describe('Session ID'),\r\n },\r\n },\r\n async ({ workspace, sessionId }) => {\r\n try {\r\n const ws = state.requireWorkspace(workspace);\r\n const provider = state.getProvider(ws.providerName);\r\n const messages = await provider.getSessionHistory(ws.workspaceId, sessionId);\r\n return jsonContent({ messages });\r\n } catch (err) {\r\n return toMcpErrorContent(err);\r\n }\r\n },\r\n );\r\n}\r\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport { z } from 'zod';\r\nimport { toMcpErrorContent } from '../errors.js';\r\nimport type { StateManager } from '../state.js';\r\n\r\n/** Return MCP text content wrapping a JSON payload. */\r\nfunction jsonContent(data: unknown) {\r\n return { content: [{ type: 'text' as const, text: JSON.stringify(data, null, 2) }] };\r\n}\r\n\r\nexport function registerWorkspaceTools(server: McpServer, state: StateManager, providerDisplayName: string): void {\r\n // ----- workspace_start ---------------------------------------------------\r\n server.registerTool(\r\n 'workspace_start',\r\n {\r\n title: 'Start Workspace',\r\n description:\r\n `Start a ${providerDisplayName} workspace bound to a project directory.`,\r\n inputSchema: {\r\n directory: z.string().describe('Absolute path to the project directory'),\r\n provider: z\r\n .string()\r\n .optional()\r\n .describe('Backend provider (default: copilot). Options: copilot'),\r\n },\r\n },\r\n async ({ directory, provider }) => {\r\n try {\r\n const result = await state.startWorkspace(directory, provider);\r\n return jsonContent({\r\n workspaceId: result.workspace.workspaceId,\r\n directory: result.workspace.originalDirectory,\r\n provider: result.workspace.providerName,\r\n status: result.workspace.status,\r\n });\r\n } catch (err) {\r\n return toMcpErrorContent(err);\r\n }\r\n },\r\n );\r\n\r\n // ----- workspace_stop ----------------------------------------------------\r\n server.registerTool(\r\n 'workspace_stop',\r\n {\r\n title: 'Stop Workspace',\r\n description: 'Stop a running workspace and release its resources.',\r\n inputSchema: {\r\n workspace: z\r\n .string()\r\n .describe('Workspace ID (e.g. ws-a1b2c3d4e5f6) or project directory path'),\r\n },\r\n },\r\n async ({ workspace }) => {\r\n try {\r\n await state.stopWorkspace(workspace);\r\n return jsonContent({ success: true });\r\n } catch (err) {\r\n return toMcpErrorContent(err);\r\n }\r\n },\r\n );\r\n\r\n // ----- workspace_list ----------------------------------------------------\r\n server.registerTool(\r\n 'workspace_list',\r\n {\r\n title: 'List Workspaces',\r\n description: 'List all running workspaces.',\r\n inputSchema: {},\r\n },\r\n async () => {\r\n try {\r\n const workspaces = state.listWorkspaces();\r\n return jsonContent({\r\n workspaces: workspaces.map((ws) => ({\r\n workspaceId: ws.workspaceId,\r\n directory: ws.originalDirectory,\r\n provider: ws.providerName,\r\n status: ws.status,\r\n })),\r\n });\r\n } catch (err) {\r\n return toMcpErrorContent(err);\r\n }\r\n },\r\n );\r\n}\r\n","import fs from 'node:fs';\r\nimport path from 'node:path';\r\nimport {\r\n directoryNotAbsolute,\r\n directoryNotFound,\r\n providerNotSupported,\r\n workspaceLimitExceeded,\r\n workspaceNotFound,\r\n} from './errors.js';\r\nimport type { IProvider } from './providers/base.js';\r\nimport { CopilotProvider } from './providers/copilot.js';\r\nimport type { ServerConfig, WorkspaceState } from './types.js';\r\nimport { generateWorkspaceId } from './utils/id.js';\r\nimport { canonicalizePath, isDirectoryPath } from './utils/path.js';\r\n\r\n/**\r\n * Central state manager for the Unicoda MCP Server.\r\n * Owns workspace lifecycle, provider instantiation, and workspace resolution.\r\n */\r\nexport class StateManager {\r\n private workspaces = new Map<string, WorkspaceState>();\r\n private directoryIndex = new Map<string, string>(); // canonicalPath → workspaceId\r\n private providers = new Map<string, IProvider>();\r\n private ttlInterval: ReturnType<typeof setInterval> | undefined;\r\n\r\n constructor(private config: ServerConfig) {\r\n // Register known providers\r\n this.providers.set('copilot', new CopilotProvider(config.portRangeStart));\r\n\r\n // Start TTL cleanup\r\n this.ttlInterval = setInterval(() => this.cleanupExpired(), 60_000);\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Provider access\r\n // -----------------------------------------------------------------------\r\n\r\n getProvider(name?: string): IProvider {\r\n const providerName = name ?? this.config.provider;\r\n const provider = this.providers.get(providerName);\r\n if (!provider) throw providerNotSupported(providerName);\r\n return provider;\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Workspace resolution: \"workspace\" param → workspaceId\r\n // -----------------------------------------------------------------------\r\n\r\n /**\r\n * Resolve a `workspace` parameter value to a `WorkspaceState`.\r\n * If it's a directory path, look up by canonical path.\r\n * If it's an ID, look up directly.\r\n */\r\n resolveWorkspace(value: string): WorkspaceState | undefined {\r\n if (isDirectoryPath(value)) {\r\n const canonical = canonicalizePath(value);\r\n const wsId = this.directoryIndex.get(canonical);\r\n if (!wsId) return undefined;\r\n return this.workspaces.get(wsId);\r\n }\r\n return this.workspaces.get(value);\r\n }\r\n\r\n /**\r\n * Resolve workspace, throwing if not found.\r\n */\r\n requireWorkspace(value: string): WorkspaceState {\r\n const ws = this.resolveWorkspace(value);\r\n if (!ws) throw workspaceNotFound(value);\r\n ws.lastAccessedAt = new Date();\r\n return ws;\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Workspace lifecycle\r\n // -----------------------------------------------------------------------\r\n\r\n async startWorkspace(\r\n directory: string,\r\n providerName?: string,\r\n ): Promise<{ workspace: WorkspaceState; provider: IProvider; autoStarted: boolean }> {\r\n // Validate directory\r\n if (!path.isAbsolute(directory)) throw directoryNotAbsolute(directory);\r\n if (!fs.existsSync(directory)) throw directoryNotFound(directory);\r\n\r\n const canonical = canonicalizePath(directory);\r\n\r\n // Return existing if already running\r\n const existingId = this.directoryIndex.get(canonical);\r\n if (existingId) {\r\n const existing = this.workspaces.get(existingId);\r\n if (existing && existing.status === 'running') {\r\n existing.lastAccessedAt = new Date();\r\n return {\r\n workspace: existing,\r\n provider: this.getProvider(existing.providerName),\r\n autoStarted: false,\r\n };\r\n }\r\n }\r\n\r\n // Check limit\r\n if (this.workspaces.size >= this.config.maxWorkspaces) {\r\n // Try evicting the least recently accessed\r\n this.evictLRU();\r\n if (this.workspaces.size >= this.config.maxWorkspaces) {\r\n throw workspaceLimitExceeded(this.config.maxWorkspaces);\r\n }\r\n }\r\n\r\n const provider = this.getProvider(providerName);\r\n const workspaceId = generateWorkspaceId(directory);\r\n\r\n const iwk = await provider.startWorkspace(directory, workspaceId);\r\n\r\n const state: WorkspaceState = {\r\n workspaceId: iwk.workspaceId,\r\n directory: canonical,\r\n originalDirectory: directory,\r\n providerName: provider.name,\r\n status: iwk.status,\r\n createdAt: new Date(),\r\n lastAccessedAt: new Date(),\r\n };\r\n\r\n this.workspaces.set(workspaceId, state);\r\n this.directoryIndex.set(canonical, workspaceId);\r\n\r\n return { workspace: state, provider, autoStarted: true };\r\n }\r\n\r\n async stopWorkspace(value: string): Promise<void> {\r\n const ws = this.requireWorkspace(value);\r\n const provider = this.getProvider(ws.providerName);\r\n\r\n await provider.stopWorkspace(ws.workspaceId);\r\n\r\n this.workspaces.delete(ws.workspaceId);\r\n this.directoryIndex.delete(ws.directory);\r\n }\r\n\r\n listWorkspaces(): WorkspaceState[] {\r\n return Array.from(this.workspaces.values());\r\n }\r\n\r\n /**\r\n * Resolve workspace with optional auto-start.\r\n * Used by session/chat tools that accept a `workspace` parameter.\r\n */\r\n async ensureWorkspace(\r\n workspace: string,\r\n providerName?: string,\r\n ): Promise<{ workspace: WorkspaceState; provider: IProvider; autoStarted: boolean }> {\r\n const existing = this.resolveWorkspace(workspace);\r\n if (existing && existing.status === 'running') {\r\n existing.lastAccessedAt = new Date();\r\n return {\r\n workspace: existing,\r\n provider: this.getProvider(existing.providerName),\r\n autoStarted: false,\r\n };\r\n }\r\n\r\n // Auto-start if it's a directory path and config allows\r\n if (isDirectoryPath(workspace) && this.config.autoStartWorkspace) {\r\n return this.startWorkspace(workspace, providerName);\r\n }\r\n\r\n throw workspaceNotFound(workspace);\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Cleanup\r\n // -----------------------------------------------------------------------\r\n\r\n private cleanupExpired(): void {\r\n const now = Date.now();\r\n for (const [id, ws] of this.workspaces) {\r\n if (now - ws.lastAccessedAt.getTime() > this.config.workspaceTTL) {\r\n const provider = this.providers.get(ws.providerName);\r\n if (provider) {\r\n provider.stopWorkspace(id).catch(() => {\r\n // best-effort cleanup\r\n });\r\n }\r\n this.workspaces.delete(id);\r\n this.directoryIndex.delete(ws.directory);\r\n }\r\n }\r\n }\r\n\r\n private evictLRU(): void {\r\n let oldest: { id: string; time: number } | undefined;\r\n for (const [id, ws] of this.workspaces) {\r\n const time = ws.lastAccessedAt.getTime();\r\n if (!oldest || time < oldest.time) {\r\n oldest = { id, time };\r\n }\r\n }\r\n if (oldest) {\r\n const ws = this.workspaces.get(oldest.id);\r\n if (ws) {\r\n const provider = this.providers.get(ws.providerName);\r\n provider?.stopWorkspace(oldest.id).catch(() => {});\r\n this.workspaces.delete(oldest.id);\r\n this.directoryIndex.delete(ws.directory);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Graceful shutdown — stop all workspaces and clear timers.\r\n */\r\n async shutdown(): Promise<void> {\r\n if (this.ttlInterval) {\r\n clearInterval(this.ttlInterval);\r\n this.ttlInterval = undefined;\r\n }\r\n const stops: Promise<void>[] = [];\r\n for (const [id, ws] of this.workspaces) {\r\n const provider = this.providers.get(ws.providerName);\r\n if (provider) {\r\n stops.push(provider.stopWorkspace(id).catch(() => {}));\r\n }\r\n }\r\n await Promise.all(stops);\r\n this.workspaces.clear();\r\n this.directoryIndex.clear();\r\n }\r\n}\r\n","import { CopilotClient, approveAll } from '@github/copilot-sdk';\r\nimport type { MessageOptions, SessionEvent , CopilotSession} from '@github/copilot-sdk';\r\nimport {\r\n cliConnectionLost,\r\n cliStartFailed,\r\n requestAlreadyCompleted,\r\n requestNotFound,\r\n sessionNotFound,\r\n workspaceNotFound,\r\n} from '../errors.js';\r\nimport type { Message, Model, RequestState, SendResult } from '../types.js';\r\nimport { generateRequestId } from '../utils/id.js';\r\nimport type { IProvider, ISession, IWorkspace, SendOptions, SessionOptions } from './base.js';\r\nimport { mapSessionEvent, mapSessionEvents } from './copilot-event-mapper.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Internal state per workspace\r\n// ---------------------------------------------------------------------------\r\n\r\ninterface CopilotWorkspaceState {\r\n workspaceId: string;\r\n directory: string;\r\n client: CopilotClient;\r\n sessions: Map<string, CopilotSession>;\r\n status: 'starting' | 'running' | 'stopped' | 'error';\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// CopilotProvider\r\n// ---------------------------------------------------------------------------\r\n\r\nexport class CopilotProvider implements IProvider {\r\n readonly name = 'copilot';\r\n\r\n private workspaces = new Map<string, CopilotWorkspaceState>();\r\n private requests = new Map<string, RequestState>();\r\n private nextPort: number;\r\n\r\n constructor(portRangeStart = 40000) {\r\n this.nextPort = portRangeStart;\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Workspace management\r\n // -----------------------------------------------------------------------\r\n\r\n async startWorkspace(directory: string, workspaceId: string): Promise<IWorkspace> {\r\n // If already running, return existing\r\n const existing = this.workspaces.get(workspaceId);\r\n if (existing && existing.status === 'running') {\r\n return this.toIWorkspace(existing);\r\n }\r\n\r\n const port = this.nextPort++;\r\n const client = new CopilotClient({\r\n cwd: directory,\r\n port,\r\n autoStart: true,\r\n autoRestart: true,\r\n logLevel: 'warning',\r\n });\r\n\r\n const state: CopilotWorkspaceState = {\r\n workspaceId,\r\n directory,\r\n client,\r\n sessions: new Map(),\r\n status: 'starting',\r\n };\r\n\r\n this.workspaces.set(workspaceId, state);\r\n\r\n try {\r\n await client.start();\r\n state.status = 'running';\r\n } catch (err) {\r\n state.status = 'error';\r\n this.workspaces.delete(workspaceId);\r\n throw cliStartFailed('copilot', err);\r\n }\r\n\r\n // Monitor connection loss\r\n client.on('session.deleted' as const, () => {\r\n // no-op; just keeping the subscription for lifecycle awareness\r\n });\r\n\r\n return this.toIWorkspace(state);\r\n }\r\n\r\n async stopWorkspace(workspaceId: string): Promise<void> {\r\n const state = this.workspaces.get(workspaceId);\r\n if (!state) throw workspaceNotFound(workspaceId);\r\n\r\n // Destroy all sessions first\r\n for (const [, session] of state.sessions) {\r\n try {\r\n await session.destroy();\r\n } catch {\r\n // best-effort\r\n }\r\n }\r\n\r\n try {\r\n await state.client.stop();\r\n } catch {\r\n await state.client.forceStop();\r\n }\r\n\r\n state.status = 'stopped';\r\n this.workspaces.delete(workspaceId);\r\n }\r\n\r\n listWorkspaces(): IWorkspace[] {\r\n return Array.from(this.workspaces.values()).map((s) => this.toIWorkspace(s));\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Session management\r\n // -----------------------------------------------------------------------\r\n\r\n async createSession(workspaceId: string, options?: SessionOptions): Promise<ISession> {\r\n const ws = this.getWorkspaceState(workspaceId);\r\n\r\n const session = await ws.client.createSession({\r\n sessionId: options?.sessionId,\r\n model: options?.model,\r\n onPermissionRequest: approveAll,\r\n });\r\n\r\n ws.sessions.set(session.sessionId, session);\r\n\r\n return {\r\n sessionId: session.sessionId,\r\n workspaceId,\r\n createdAt: new Date(),\r\n modifiedTime: new Date(),\r\n };\r\n }\r\n\r\n async listSessions(workspaceId: string): Promise<ISession[]> {\r\n const ws = this.getWorkspaceState(workspaceId);\r\n\r\n try {\r\n const list = await ws.client.listSessions();\r\n return list.map((meta) => ({\r\n sessionId: meta.sessionId,\r\n workspaceId,\r\n createdAt: meta.startTime ? new Date(meta.startTime) : undefined,\r\n modifiedTime: meta.modifiedTime ? new Date(meta.modifiedTime) : undefined,\r\n summary: meta.summary,\r\n }));\r\n } catch {\r\n // Fallback to locally tracked sessions\r\n return Array.from(ws.sessions.keys()).map((id) => ({\r\n sessionId: id,\r\n workspaceId,\r\n }));\r\n }\r\n }\r\n\r\n async deleteSession(workspaceId: string, sessionId: string): Promise<void> {\r\n const ws = this.getWorkspaceState(workspaceId);\r\n\r\n const session = ws.sessions.get(sessionId);\r\n if (session) {\r\n await session.destroy();\r\n ws.sessions.delete(sessionId);\r\n }\r\n\r\n try {\r\n await ws.client.deleteSession(sessionId);\r\n } catch {\r\n // may already be destroyed — ignore\r\n }\r\n }\r\n\r\n async getSessionHistory(workspaceId: string, sessionId: string): Promise<Message[]> {\r\n const session = this.getSession(workspaceId, sessionId);\r\n const events: SessionEvent[] = await session.getMessages();\r\n return mapSessionEvents(events);\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Chat\r\n // -----------------------------------------------------------------------\r\n\r\n async send(\r\n workspaceId: string,\r\n sessionId: string,\r\n options: SendOptions,\r\n ): Promise<SendResult> {\r\n const session = this.getSession(workspaceId, sessionId);\r\n\r\n const requestId = generateRequestId();\r\n const reqState: RequestState = {\r\n requestId,\r\n sessionId,\r\n workspaceId,\r\n status: 'queued',\r\n messages: [],\r\n createdAt: new Date(),\r\n };\r\n this.requests.set(requestId, reqState);\r\n\r\n // Attach event listeners to buffer incoming events\r\n const unsubscribe = session.on((event: SessionEvent) => {\r\n // Only process events while this request is active\r\n if (reqState.status !== 'queued' && reqState.status !== 'running') {\r\n return;\r\n }\r\n\r\n // Transition to running on first meaningful event\r\n if (reqState.status === 'queued') {\r\n reqState.status = 'running';\r\n }\r\n\r\n const msg = mapSessionEvent(event);\r\n if (msg) {\r\n reqState.messages.push(msg);\r\n }\r\n\r\n // Detect completion\r\n if (event.type === 'session.idle') {\r\n reqState.status = 'completed';\r\n reqState.completedAt = new Date();\r\n unsubscribe();\r\n } else if (event.type === 'session.error') {\r\n reqState.status = 'error';\r\n reqState.completedAt = new Date();\r\n unsubscribe();\r\n }\r\n });\r\n\r\n // Fire the send\r\n try {\r\n const messageId = await session.send({\r\n prompt: options.prompt,\r\n attachments: options.attachments as MessageOptions['attachments'],\r\n });\r\n reqState.messageId = messageId;\r\n if (reqState.status === 'queued') {\r\n reqState.status = 'running';\r\n }\r\n } catch (err) {\r\n reqState.status = 'error';\r\n reqState.completedAt = new Date();\r\n unsubscribe();\r\n reqState.messages.push({\r\n type: 'error',\r\n content: err instanceof Error ? err.message : String(err),\r\n timestamp: new Date().toISOString(),\r\n });\r\n }\r\n\r\n return {\r\n requestId,\r\n status: reqState.status,\r\n messages: reqState.messages,\r\n };\r\n }\r\n\r\n async sendAndWait(\r\n workspaceId: string,\r\n sessionId: string,\r\n options: SendOptions,\r\n ): Promise<SendResult> {\r\n const session = this.getSession(workspaceId, sessionId);\r\n\r\n const requestId = generateRequestId();\r\n const reqState: RequestState = {\r\n requestId,\r\n sessionId,\r\n workspaceId,\r\n status: 'running',\r\n messages: [],\r\n createdAt: new Date(),\r\n };\r\n this.requests.set(requestId, reqState);\r\n\r\n // Collect events while waiting\r\n const unsubscribe = session.on((event: SessionEvent) => {\r\n const msg = mapSessionEvent(event);\r\n if (msg) {\r\n reqState.messages.push(msg);\r\n }\r\n });\r\n\r\n try {\r\n const result = await session.sendAndWait(\r\n {\r\n prompt: options.prompt,\r\n attachments: options.attachments as MessageOptions['attachments'],\r\n },\r\n options.timeout ?? 300_000,\r\n );\r\n\r\n reqState.status = 'completed';\r\n reqState.completedAt = new Date();\r\n\r\n // If the sendAndWait returned an assistant message event and we didn't capture it via the\r\n // event listener (race), append it manually.\r\n if (result) {\r\n const alreadyCaptured = reqState.messages.some(\r\n (m) => m.type === 'assistant' && m.metadata?.messageId === (result.data as { messageId?: string }).messageId,\r\n );\r\n if (!alreadyCaptured) {\r\n const mapped = mapSessionEvent(result);\r\n if (mapped) reqState.messages.push(mapped);\r\n }\r\n }\r\n } catch (err) {\r\n // Determine if it's a timeout or a genuine error\r\n const isTimeout =\r\n err instanceof Error &&\r\n (err.message.toLowerCase().includes('timeout') ||\r\n err.message.toLowerCase().includes('timed out'));\r\n\r\n reqState.status = isTimeout ? 'timeout' : 'error';\r\n reqState.completedAt = new Date();\r\n\r\n reqState.messages.push({\r\n type: 'error',\r\n content: err instanceof Error ? err.message : String(err),\r\n timestamp: new Date().toISOString(),\r\n });\r\n } finally {\r\n unsubscribe();\r\n }\r\n\r\n return {\r\n requestId: reqState.requestId,\r\n status: reqState.status,\r\n messages: reqState.messages,\r\n };\r\n }\r\n\r\n async poll(\r\n workspaceId: string,\r\n _sessionId: string,\r\n requestId: string,\r\n ): Promise<SendResult> {\r\n // Verify workspace exists\r\n this.getWorkspaceState(workspaceId);\r\n\r\n const req = this.requests.get(requestId);\r\n if (!req) throw requestNotFound(requestId);\r\n\r\n return {\r\n requestId: req.requestId,\r\n status: req.status,\r\n messages: [...req.messages],\r\n };\r\n }\r\n\r\n async abort(\r\n workspaceId: string,\r\n sessionId: string,\r\n requestId: string,\r\n ): Promise<SendResult> {\r\n const session = this.getSession(workspaceId, sessionId);\r\n\r\n const req = this.requests.get(requestId);\r\n if (!req) throw requestNotFound(requestId);\r\n\r\n if (req.status === 'completed' || req.status === 'error' || req.status === 'timeout') {\r\n throw requestAlreadyCompleted(requestId);\r\n }\r\n\r\n await session.abort();\r\n\r\n req.status = 'aborted';\r\n req.completedAt = new Date();\r\n\r\n return {\r\n requestId: req.requestId,\r\n status: req.status,\r\n messages: [...req.messages],\r\n };\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Models\r\n // -----------------------------------------------------------------------\r\n\r\n async listModels(): Promise<Model[]> {\r\n // Try to get from the first running workspace\r\n for (const [, ws] of this.workspaces) {\r\n if (ws.status === 'running') {\r\n try {\r\n const models = await ws.client.listModels();\r\n return models.map((m) => ({\r\n id: m.id ?? (m as unknown as { modelId?: string }).modelId ?? 'unknown',\r\n provider: 'copilot',\r\n name: m.name ?? m.id,\r\n }));\r\n } catch {\r\n break; // fall through to hardcoded list\r\n }\r\n }\r\n }\r\n\r\n // Fallback: hardcoded known models\r\n return [\r\n { id: 'gpt-4o', provider: 'copilot', name: 'GPT-4o' },\r\n { id: 'gpt-4.1', provider: 'copilot', name: 'GPT-4.1' },\r\n { id: 'claude-sonnet-4', provider: 'copilot', name: 'Claude Sonnet 4' },\r\n { id: 'claude-opus-4', provider: 'copilot', name: 'Claude Opus 4' },\r\n { id: 'o3', provider: 'copilot', name: 'o3' },\r\n { id: 'o4-mini', provider: 'copilot', name: 'o4-mini' },\r\n { id: 'gemini-2.5-pro', provider: 'copilot', name: 'Gemini 2.5 Pro' },\r\n ];\r\n }\r\n\r\n // -----------------------------------------------------------------------\r\n // Private helpers\r\n // -----------------------------------------------------------------------\r\n\r\n private getWorkspaceState(workspaceId: string): CopilotWorkspaceState {\r\n const ws = this.workspaces.get(workspaceId);\r\n if (!ws) throw workspaceNotFound(workspaceId);\r\n if (ws.status !== 'running') {\r\n throw cliConnectionLost('copilot', new Error(`Workspace ${workspaceId} is ${ws.status}`));\r\n }\r\n return ws;\r\n }\r\n\r\n private getSession(workspaceId: string, sessionId: string): CopilotSession {\r\n const ws = this.getWorkspaceState(workspaceId);\r\n const session = ws.sessions.get(sessionId);\r\n if (!session) throw sessionNotFound(sessionId, workspaceId);\r\n return session;\r\n }\r\n\r\n private toIWorkspace(state: CopilotWorkspaceState): IWorkspace {\r\n return {\r\n workspaceId: state.workspaceId,\r\n directory: state.directory,\r\n provider: 'copilot',\r\n status: state.status,\r\n };\r\n }\r\n}\r\n","import crypto from 'node:crypto';\r\nimport { canonicalizePath } from './path.js';\r\n\r\n/**\r\n * Generate a deterministic workspace ID from a directory path.\r\n * Same canonical path → same ID.\r\n */\r\nexport function generateWorkspaceId(directory: string): string {\r\n const canonical = canonicalizePath(directory);\r\n const hash = crypto.createHash('sha256').update(canonical).digest('hex').slice(0, 12);\r\n return `ws-${hash}`;\r\n}\r\n\r\n/**\r\n * Generate a unique request ID.\r\n */\r\nexport function generateRequestId(): string {\r\n return `req-${crypto.randomUUID().slice(0, 8)}`;\r\n}\r\n\r\n/**\r\n * Generate a unique session ID.\r\n */\r\nexport function generateSessionId(): string {\r\n return `sess-${crypto.randomUUID().slice(0, 8)}`;\r\n}\r\n","import path from 'node:path';\r\nimport fs from 'node:fs';\r\n\r\n/**\r\n * Canonicalize a filesystem path so the same directory always produces the\r\n * same string (and therefore the same workspaceId).\r\n *\r\n * Steps:\r\n * 1. Resolve to an absolute path\r\n * 2. Resolve symlinks (if the path exists on disk)\r\n * 3. Convert to forward slashes (POSIX style)\r\n * 4. Lower-case on Windows (case-insensitive FS)\r\n * 5. Strip trailing slashes\r\n */\r\nexport function canonicalizePath(inputPath: string): string {\r\n // 1. Absolute\r\n let normalized = path.resolve(inputPath);\r\n\r\n // 2. Resolve symlinks\r\n try {\r\n normalized = fs.realpathSync(normalized);\r\n } catch {\r\n // Path may not exist yet — that's OK, just skip realpath.\r\n }\r\n\r\n // 3. Forward slashes\r\n normalized = normalized.replace(/\\\\/g, '/');\r\n\r\n // 4. Lowercase on Windows\r\n if (process.platform === 'win32') {\r\n normalized = normalized.toLowerCase();\r\n }\r\n\r\n // 5. Strip trailing slash(es) — but keep root \"/\"\r\n normalized = normalized.replace(/\\/+$/, '') || '/';\r\n\r\n return normalized;\r\n}\r\n\r\n/**\r\n * Determine whether a `workspace` parameter value looks like a directory path\r\n * (as opposed to a workspaceId).\r\n *\r\n * Heuristic: contains `/` or `\\`, starts with a drive letter (e.g. `C:`),\r\n * or starts with `~`.\r\n */\r\nexport function isDirectoryPath(value: string): boolean {\r\n if (value.includes('/') || value.includes('\\\\')) return true;\r\n if (/^[a-zA-Z]:/.test(value)) return true;\r\n if (value.startsWith('~')) return true;\r\n return false;\r\n}\r\n","import type { SessionEvent } from '@github/copilot-sdk';\r\nimport type { Message } from '../types.js';\r\n\r\n/**\r\n * Map a Copilot SDK `SessionEvent` to our unified `Message` type.\r\n * Returns `null` for event types we don't surface to the caller.\r\n */\r\nexport function mapSessionEvent(event: SessionEvent): Message | null {\r\n const timestamp = event.timestamp ?? new Date().toISOString();\r\n\r\n switch (event.type) {\r\n // ----- User messages -----\r\n case 'user.message':\r\n return {\r\n type: 'user',\r\n content: (event.data as { content?: string }).content ?? '',\r\n timestamp,\r\n metadata: {\r\n messageId: event.id,\r\n },\r\n };\r\n\r\n // ----- Assistant messages -----\r\n case 'assistant.message':\r\n return {\r\n type: 'assistant',\r\n content: (event.data as { content?: string }).content ?? '',\r\n timestamp,\r\n metadata: {\r\n messageId: (event.data as { messageId?: string }).messageId ?? event.id,\r\n },\r\n };\r\n\r\n // ----- Tool calls -----\r\n case 'tool.execution_start': {\r\n const data = event.data as {\r\n toolCallId?: string;\r\n toolName?: string;\r\n arguments?: unknown;\r\n };\r\n return {\r\n type: 'tool_call',\r\n content: `Calling ${data.toolName ?? 'unknown tool'}...`,\r\n timestamp,\r\n metadata: {\r\n toolName: data.toolName,\r\n toolArgs: data.arguments,\r\n toolCallId: data.toolCallId,\r\n },\r\n };\r\n }\r\n\r\n // ----- Tool results -----\r\n case 'tool.execution_complete': {\r\n const data = event.data as {\r\n toolCallId?: string;\r\n toolName?: string;\r\n success?: boolean;\r\n result?: unknown;\r\n error?: string;\r\n };\r\n return {\r\n type: 'tool_result',\r\n content: data.error ?? (typeof data.result === 'string' ? data.result : JSON.stringify(data.result ?? '')),\r\n timestamp,\r\n metadata: {\r\n toolName: data.toolName,\r\n toolResult: data.result,\r\n toolCallId: data.toolCallId,\r\n success: data.success,\r\n },\r\n };\r\n }\r\n\r\n // ----- Session errors -----\r\n case 'session.error': {\r\n const data = event.data as { message?: string; errorType?: string };\r\n return {\r\n type: 'error',\r\n content: data.message ?? 'Unknown error',\r\n timestamp,\r\n metadata: {\r\n errorType: data.errorType,\r\n },\r\n };\r\n }\r\n\r\n // ----- System / info -----\r\n case 'system.message':\r\n return {\r\n type: 'system',\r\n content: (event.data as { content?: string }).content ?? '',\r\n timestamp,\r\n };\r\n\r\n case 'session.info':\r\n case 'session.warning':\r\n return {\r\n type: 'system',\r\n content: (event.data as { message?: string }).message ?? '',\r\n timestamp,\r\n metadata: {\r\n infoType: (event.data as { infoType?: string; warningType?: string }).infoType ??\r\n (event.data as { warningType?: string }).warningType,\r\n },\r\n };\r\n\r\n // ----- Events we silently skip -----\r\n case 'session.start':\r\n case 'session.resume':\r\n case 'session.idle':\r\n case 'session.title_changed':\r\n case 'session.model_change':\r\n case 'session.mode_changed':\r\n case 'session.plan_changed':\r\n case 'session.workspace_file_changed':\r\n case 'session.compaction_start':\r\n case 'session.compaction_complete':\r\n case 'session.task_complete':\r\n case 'session.shutdown':\r\n case 'session.context_changed':\r\n case 'session.usage_info':\r\n case 'session.truncation':\r\n case 'session.snapshot_rewind':\r\n case 'session.handoff':\r\n case 'assistant.turn_start':\r\n case 'assistant.turn_end':\r\n case 'assistant.intent':\r\n case 'assistant.reasoning':\r\n case 'assistant.reasoning_delta':\r\n case 'assistant.streaming_delta':\r\n case 'assistant.message_delta':\r\n case 'assistant.usage':\r\n case 'abort':\r\n case 'tool.user_requested':\r\n case 'tool.execution_partial_result':\r\n case 'tool.execution_progress':\r\n case 'pending_messages.modified':\r\n case 'skill.invoked':\r\n case 'hook.start':\r\n case 'hook.end':\r\n return null;\r\n\r\n default:\r\n // Unknown event type — skip\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Map an array of `SessionEvent[]` to `Message[]`, filtering out null entries.\r\n */\r\nexport function mapSessionEvents(events: SessionEvent[]): Message[] {\r\n const messages: Message[] = [];\r\n for (const event of events) {\r\n const mapped = mapSessionEvent(event);\r\n if (mapped) messages.push(mapped);\r\n }\r\n return messages;\r\n}\r\n"],"mappings":"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","names":["z","z","z","jsonContent","z","z","jsonContent","z","z","jsonContent","z","fs","path","path","fs"]}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@hongw/unicoda-mcp",
3
+ "version": "0.1.0",
4
+ "description": "Unified AI Coding Agent MCP Server — wraps multiple coding agent SDKs (GitHub Copilot, OpenAI Codex, Claude Code) behind a consistent MCP interface",
5
+ "author": "Hong Wang",
6
+ "homepage": "https://github.com/hongw/unicoda-mcp#readme",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/hongw/unicoda-mcp.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/hongw/unicoda-mcp/issues"
13
+ },
14
+ "type": "module",
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "bin": {
18
+ "unicoda-mcp": "./dist/index.js"
19
+ },
20
+ "files": [
21
+ "dist/",
22
+ "README.md",
23
+ "LICENSE"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsup",
27
+ "dev": "tsup --watch",
28
+ "test": "vitest run",
29
+ "test:watch": "vitest",
30
+ "test:coverage": "vitest run --coverage",
31
+ "lint": "eslint src/",
32
+ "lint:fix": "eslint src/ --fix",
33
+ "format": "prettier --write \"src/**/*.ts\"",
34
+ "format:check": "prettier --check \"src/**/*.ts\"",
35
+ "typecheck": "tsc --noEmit",
36
+ "prepack": "pnpm run build"
37
+ },
38
+ "keywords": [
39
+ "mcp",
40
+ "ai",
41
+ "coding-agent",
42
+ "copilot",
43
+ "codex",
44
+ "claude-code",
45
+ "model-context-protocol"
46
+ ],
47
+ "license": "MIT",
48
+ "publishConfig": {
49
+ "access": "public"
50
+ },
51
+ "engines": {
52
+ "node": ">=18"
53
+ },
54
+ "dependencies": {
55
+ "@github/copilot-sdk": "^0.1.30",
56
+ "@modelcontextprotocol/sdk": "^1.27.1",
57
+ "zod": "^4.3.6"
58
+ },
59
+ "devDependencies": {
60
+ "@eslint/js": "^10.0.1",
61
+ "@types/node": "^25.3.5",
62
+ "eslint": "^10.0.3",
63
+ "prettier": "^3.8.1",
64
+ "tsup": "^8.5.1",
65
+ "typescript": "^5.9.3",
66
+ "typescript-eslint": "^8.56.1",
67
+ "vitest": "^4.0.18"
68
+ }
69
+ }