/** * Configurable API Client */ import type { Session, Message, HealthStatus, FileListResponse, FileReadResponse, FileTreeResponse, ServerConfig, CommandInfo, CommandSearchResult, CommandExecuteResult, CommandListResponse, CreateCommandInput, UpdateCommandInput, CommandContent, MCPServerStatus, MCPToolInfo, MCPConfig, HookConfig, FileHookConfig, ShellCommandConfig, HookTestResult, AgentListItem, AgentDetail, AgentInput, AgentDefaults, } from './types.js'; // Re-export types export type { Session, Message, HealthStatus, FileInfo, FileListResponse, FileReadResponse, FileTreeNode, FileTreeResponse, ServerConfig, CommandInfo, CommandSearchResult, CommandExecuteResult, CommandListResponse, CreateCommandInput, UpdateCommandInput, CommandContent, MCPServerStatus, MCPServerStatusType, MCPToolInfo, MCPConfig, MCPServerConfigInfo, // Hooks types HookConfig, FileHookConfig, ShellCommandConfig, HookTestResult, // Agent types AgentMode, AgentModelConfig, AgentToolConfig, PermissionRule, AgentBashPermission, AgentFilePermission, AgentGitPermission, AgentPermission, AgentListItem, AgentDetail, AgentInput, AgentDefaults, } from './types.js'; // API Configuration interface ApiConfig { baseUrl: string; wsBaseUrl: () => string; healthUrl: () => string; } let apiConfig: ApiConfig = { baseUrl: '/api', wsBaseUrl: () => { const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; return `${protocol}//${window.location.host}/api`; }, healthUrl: () => '/health', }; /** * Configure API client for different environments */ export function configureApiClient(config: { baseUrl: string; wsBaseUrl: string | (() => string); healthUrl?: string | (() => string); }) { apiConfig = { baseUrl: config.baseUrl, wsBaseUrl: typeof config.wsBaseUrl === 'function' ? config.wsBaseUrl : () => config.wsBaseUrl as string, healthUrl: config.healthUrl ? typeof config.healthUrl === 'function' ? config.healthUrl : () => config.healthUrl as string : () => '/health', }; } async function request(method: string, path: string, body?: unknown): Promise { const response = await fetch(`${apiConfig.baseUrl}${path}`, { method, headers: { 'Content-Type': 'application/json', }, body: body ? JSON.stringify(body) : undefined, }); if (!response.ok) { const error = await response.json().catch(() => ({ error: response.statusText })); throw new Error(error.error || `HTTP ${response.status}`); } return response.json(); } // Health export async function getHealth(): Promise { const healthUrl = apiConfig.healthUrl(); const response = await fetch(healthUrl); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return response.json(); } // Sessions export async function listSessions(): Promise<{ success: boolean; data: Session[] }> { return request('GET', '/sessions'); } export async function createSession(name?: string): Promise<{ success: boolean; data: Session }> { return request('POST', '/sessions', { name }); } export async function getSession(id: string): Promise<{ success: boolean; data: Session }> { return request('GET', `/sessions/${id}`); } export async function deleteSession(id: string): Promise<{ success: boolean }> { return request('DELETE', `/sessions/${id}`); } // Messages export async function getMessages( sessionId: string ): Promise<{ success: boolean; data: Message[] }> { return request('GET', `/sessions/${sessionId}/messages`); } export async function sendMessage( sessionId: string, content: string ): Promise<{ success: boolean; data: Message }> { return request('POST', `/sessions/${sessionId}/messages`, { content }); } // WebSocket export function createWebSocket(sessionId: string): WebSocket { const wsBase = apiConfig.wsBaseUrl(); return new WebSocket(`${wsBase}/ws/${sessionId}`); } // Files export async function getWorkingDirectory(): Promise<{ success: boolean; data: { workingDirectory: string; separator: string }; }> { return request('GET', '/files'); } export async function listFiles( path: string = '.', showHidden: boolean = false ): Promise { const params = new URLSearchParams({ path }); if (showHidden) params.set('hidden', 'true'); return request('GET', `/files/list?${params}`); } export async function readFile(path: string): Promise { return request('GET', `/files/read?path=${encodeURIComponent(path)}`); } export async function getFileTree(path: string = '.', depth: number = 3): Promise { const params = new URLSearchParams({ path, depth: String(depth) }); return request('GET', `/files/tree?${params}`); } // Config export async function getConfig(): Promise<{ success: boolean; data: ServerConfig }> { return request('GET', '/config'); } export async function updateConfig( config: Partial ): Promise<{ success: boolean; data: ServerConfig }> { return request('PATCH', '/config', config); } // Commands export async function listCommands(): Promise<{ success: boolean; data: CommandListResponse }> { return request('GET', '/commands'); } export async function getCommand(name: string): Promise<{ success: boolean; data: CommandInfo }> { return request('GET', `/commands/${encodeURIComponent(name)}`); } export async function executeCommand( name: string, args: string = '' ): Promise<{ success: boolean; data?: CommandExecuteResult; error?: string }> { return request('POST', `/commands/${encodeURIComponent(name)}/execute`, { arguments: args, }); } export async function searchCommands( query: string, limit: number = 10 ): Promise<{ success: boolean; data: CommandSearchResult[] }> { return request('POST', '/commands/search', { query, limit }); } export async function reloadCommands(): Promise<{ success: boolean; data: { message: string; stats: { total: number; bySource: Record } }; }> { return request('POST', '/commands/reload'); } // Commands CRUD export async function createCommand( input: CreateCommandInput ): Promise<{ success: boolean; data?: { name: string; path: string }; error?: string }> { return request('POST', '/commands', input); } export async function getCommandContent( name: string ): Promise<{ success: boolean; data?: CommandContent; error?: string }> { return request('GET', `/commands/${encodeURIComponent(name)}/content`); } export async function updateCommand( name: string, input: UpdateCommandInput ): Promise<{ success: boolean; data?: { name: string; path: string }; error?: string }> { return request('PUT', `/commands/${encodeURIComponent(name)}`, input); } export async function deleteCommand( name: string ): Promise<{ success: boolean; data?: { name: string; path: string }; error?: string }> { return request('DELETE', `/commands/${encodeURIComponent(name)}`); } // ============ MCP API ============ /** * 获取所有 MCP 服务器状态 */ export async function listMCPServers(): Promise<{ success: boolean; data: MCPServerStatus[]; error?: string; }> { return request('GET', '/mcp/servers'); } /** * 获取单个 MCP 服务器详情 */ export async function getMCPServer(name: string): Promise<{ success: boolean; data?: MCPServerStatus; error?: string; }> { return request('GET', `/mcp/servers/${encodeURIComponent(name)}`); } /** * 连接 MCP 服务器 */ export async function connectMCPServer(name: string): Promise<{ success: boolean; data?: { message: string; status: MCPServerStatus }; error?: string; }> { return request('POST', `/mcp/servers/${encodeURIComponent(name)}/connect`); } /** * 断开 MCP 服务器 */ export async function disconnectMCPServer(name: string): Promise<{ success: boolean; data?: { message: string; status: MCPServerStatus }; error?: string; }> { return request('POST', `/mcp/servers/${encodeURIComponent(name)}/disconnect`); } /** * 启用 MCP 服务器 */ export async function enableMCPServer(name: string): Promise<{ success: boolean; data?: { message: string; status: MCPServerStatus }; error?: string; }> { return request('POST', `/mcp/servers/${encodeURIComponent(name)}/enable`); } /** * 禁用 MCP 服务器 */ export async function disableMCPServer(name: string): Promise<{ success: boolean; data?: { message: string; status: MCPServerStatus }; error?: string; }> { return request('POST', `/mcp/servers/${encodeURIComponent(name)}/disable`); } /** * 获取所有 MCP 工具 */ export async function listMCPTools(): Promise<{ success: boolean; data: MCPToolInfo[]; error?: string; }> { return request('GET', '/mcp/tools'); } /** * 获取单个 MCP 工具详情 */ export async function getMCPTool(name: string): Promise<{ success: boolean; data?: MCPToolInfo; error?: string; }> { return request('GET', `/mcp/tools/${encodeURIComponent(name)}`); } /** * 获取 MCP 配置 */ export async function getMCPConfig(): Promise<{ success: boolean; data?: MCPConfig; error?: string; }> { return request('GET', '/mcp/config'); } // ============ Hooks API ============ /** * 获取完整钩子配置 */ export async function getHooksConfig(): Promise<{ success: boolean; data: HookConfig; error?: string; }> { return request('GET', '/hooks/config'); } /** * 更新完整钩子配置 */ export async function updateHooksConfig(config: HookConfig): Promise<{ success: boolean; data: HookConfig; error?: string; }> { return request('PUT', '/hooks/config', config); } /** * 获取 file_edited 钩子配置 */ export async function getFileEditedHooks(): Promise<{ success: boolean; data: FileHookConfig; error?: string; }> { return request('GET', '/hooks/file-edited'); } /** * 更新 file_edited 钩子配置 */ export async function updateFileEditedHooks(hooks: FileHookConfig): Promise<{ success: boolean; data: FileHookConfig; error?: string; }> { return request('PUT', '/hooks/file-edited', hooks); } /** * 获取 file_created 钩子配置 */ export async function getFileCreatedHooks(): Promise<{ success: boolean; data: FileHookConfig; error?: string; }> { return request('GET', '/hooks/file-created'); } /** * 更新 file_created 钩子配置 */ export async function updateFileCreatedHooks(hooks: FileHookConfig): Promise<{ success: boolean; data: FileHookConfig; error?: string; }> { return request('PUT', '/hooks/file-created', hooks); } /** * 获取 file_deleted 钩子配置 */ export async function getFileDeletedHooks(): Promise<{ success: boolean; data: FileHookConfig; error?: string; }> { return request('GET', '/hooks/file-deleted'); } /** * 更新 file_deleted 钩子配置 */ export async function updateFileDeletedHooks(hooks: FileHookConfig): Promise<{ success: boolean; data: FileHookConfig; error?: string; }> { return request('PUT', '/hooks/file-deleted', hooks); } /** * 获取 session_completed 钩子配置 */ export async function getSessionCompletedHooks(): Promise<{ success: boolean; data: ShellCommandConfig[]; error?: string; }> { return request('GET', '/hooks/session-completed'); } /** * 更新 session_completed 钩子配置 */ export async function updateSessionCompletedHooks(hooks: ShellCommandConfig[]): Promise<{ success: boolean; data: ShellCommandConfig[]; error?: string; }> { return request('PUT', '/hooks/session-completed', hooks); } /** * 测试执行钩子命令 */ export async function testHookCommand(command: ShellCommandConfig): Promise<{ success: boolean; data?: HookTestResult; error?: string; }> { return request('POST', '/hooks/test', command); } // ============ Agents API ============ /** * 获取所有 Agent 列表 */ export async function listAgents(): Promise<{ success: boolean; data: AgentListItem[]; error?: string; }> { return request('GET', '/agents'); } /** * 获取单个 Agent 详情 */ export async function getAgent(name: string): Promise<{ success: boolean; data?: AgentDetail; error?: string; }> { return request('GET', `/agents/${encodeURIComponent(name)}`); } /** * 创建新 Agent */ export async function createAgent( name: string, config: AgentInput ): Promise<{ success: boolean; data?: AgentDetail; error?: string; }> { return request('POST', '/agents', { name, ...config }); } /** * 更新 Agent */ export async function updateAgent( name: string, config: AgentInput ): Promise<{ success: boolean; data?: AgentDetail; error?: string; }> { return request('PUT', `/agents/${encodeURIComponent(name)}`, config); } /** * 删除 Agent */ export async function deleteAgent(name: string): Promise<{ success: boolean; error?: string; }> { return request('DELETE', `/agents/${encodeURIComponent(name)}`); } /** * 获取预设 Agent 列表 */ export async function listPresetAgents(): Promise<{ success: boolean; data: AgentListItem[]; error?: string; }> { return request('GET', '/agents/presets'); } /** * 获取全局默认配置 */ export async function getAgentDefaults(): Promise<{ success: boolean; data: AgentDefaults; error?: string; }> { return request('GET', '/agents/defaults'); } /** * 更新全局默认配置 */ export async function updateAgentDefaults(defaults: AgentDefaults): Promise<{ success: boolean; data: AgentDefaults; error?: string; }> { return request('PUT', '/agents/defaults', defaults); }