feat: 重构为 Monorepo 架构并实现 HTTP Server

架构变更:
- 采用 pnpm workspaces 实现 Monorepo 结构
- 将现有代码迁移到 packages/core
- 新增 packages/server HTTP 服务层

Server 功能:
- REST API: 会话管理、工具管理、配置管理
- WebSocket: 实时双向通信支持
- SSE: 服务端事件推送
- Hono + Bun 作为运行时

API 端点:
- GET/POST /api/sessions - 会话 CRUD
- GET/POST /api/sessions/:id/messages - 消息管理
- GET /api/sessions/:id/events - SSE 事件流
- WS /api/ws/:sessionId - WebSocket 连接
- GET/POST /api/tools - 工具管理
- GET/PUT /api/config - 配置管理
This commit is contained in:
2025-12-12 10:42:20 +08:00
parent 59dbed926e
commit 5e32375f0e
301 changed files with 3281 additions and 43 deletions
+430
View File
@@ -0,0 +1,430 @@
#!/usr/bin/env node
import { Command } from 'commander';
import { Agent } from './core/agent.js';
import { TerminalUI } from './ui/terminal.js';
import { loadConfig, initConfig } from './utils/config.js';
import { toolRegistry, todoManager, initTaskContext, updateTaskDescription, updateSkillDescription } from './tools/index.js';
import { getPermissionManager, promptPermission } from './permission/index.js';
import { SessionManager } from './session/index.js';
import { agentRegistry } from './agent/index.js';
import { initLSP, shutdownLSP } from './lsp/index.js';
import { getCommandRegistry } from './commands/index.js';
import { getSkillRegistry } from './skills/index.js';
import {
printServerList,
installServer,
installAllServers,
showServerInfo,
} from './lsp/cli.js';
import {
getMCPManager,
loadMCPConfig,
createMCPToolAdapter,
} from './mcp/index.js';
const program = new Command();
// MCP 管理器实例
let mcpInitialized = false;
/**
* 初始化 MCP 系统
* 加载配置、连接服务器、注册工具
*/
async function initMCP(workdir: string): Promise<void> {
if (mcpInitialized) {
return;
}
const mcpConfig = loadMCPConfig(workdir);
// 如果没有 MCP 配置,跳过初始化
if (!mcpConfig.mcp || Object.keys(mcpConfig.mcp).length === 0) {
return;
}
const mcpManager = getMCPManager();
// 监听工具变化事件
mcpManager.on('tools:changed', () => {
registerMCPTools(mcpManager);
});
// 监听服务器事件(用于日志)
mcpManager.on('server:connected', (name) => {
console.log(`🔌 MCP 服务器已连接: ${name}`);
});
mcpManager.on('server:disconnected', (name) => {
console.log(`🔌 MCP 服务器已断开: ${name}`);
});
mcpManager.on('server:error', (name, error) => {
console.error(`❌ MCP 服务器 ${name} 错误:`, error);
});
try {
await mcpManager.initialize(mcpConfig);
registerMCPTools(mcpManager);
mcpInitialized = true;
// 显示 MCP 状态
const statuses = mcpManager.getServerStatuses();
const connected = statuses.filter((s) => s.status === 'connected');
if (connected.length > 0) {
const totalTools = connected.reduce((sum, s) => sum + s.toolCount, 0);
console.log(
`🔌 MCP: ${connected.length} 个服务器已连接,${totalTools} 个工具可用`
);
}
} catch (error) {
console.error(
'❌ MCP 初始化失败:',
error instanceof Error ? error.message : String(error)
);
}
}
/**
* 将 MCP 工具注册到工具注册表
*/
function registerMCPTools(
mcpManager: ReturnType<typeof getMCPManager>
): void {
const adapter = createMCPToolAdapter(mcpManager);
const mcpTools = mcpManager.getTools();
const adaptedTools = adapter.adaptTools(mcpTools);
// 注册到工具注册表
toolRegistry.registerAll(adaptedTools);
}
/**
* 关闭 MCP 系统
*/
async function shutdownMCP(): Promise<void> {
if (mcpInitialized) {
const mcpManager = getMCPManager();
await mcpManager.shutdown();
mcpInitialized = false;
}
}
program
.name('ai-assist')
.description('AI Terminal Assistant - 终端中的 AI 编程助手')
.version('1.0.0');
// 初始化命令
program
.command('init')
.description('初始化配置(设置 API Key 等)')
.action(async () => {
await initConfig();
});
// LSP 命令组
const lspCommand = program
.command('lsp')
.description('语言服务器管理');
lspCommand
.command('list')
.description('列出所有语言服务器及其安装状态')
.action(() => {
printServerList();
});
lspCommand
.command('install [servers...]')
.description('安装指定的语言服务器')
.option('-a, --all', '安装所有语言服务器')
.action(async (servers: string[], options: { all?: boolean }) => {
if (options.all) {
await installAllServers();
} else if (servers.length === 0) {
console.log('用法: ai-assist lsp install <server> [server2] ...');
console.log(' ai-assist lsp install --all');
console.log('\n运行 "ai-assist lsp list" 查看可用的服务器');
} else {
for (const server of servers) {
await installServer(server);
}
}
});
lspCommand
.command('info <server>')
.description('显示语言服务器详细信息')
.action((server: string) => {
showServerInfo(server);
});
// MCP 命令组
const mcpCommand = program.command('mcp').description('MCP 服务器管理');
mcpCommand
.command('list')
.description('列出所有 MCP 服务器及其状态')
.action(async () => {
const mcpConfig = loadMCPConfig(process.cwd());
if (!mcpConfig.mcp || Object.keys(mcpConfig.mcp).length === 0) {
console.log('没有配置 MCP 服务器');
console.log('\n配置方法:');
console.log(' 在 ~/.ai-assist/config.json 或 .ai-assist/config.json 中添加 mcp 配置');
console.log('\n示例:');
console.log(' {');
console.log(' "mcp": {');
console.log(' "filesystem": {');
console.log(' "type": "local",');
console.log(' "command": ["npx", "-y", "@anthropic-ai/mcp-server-filesystem", "/path/to/dir"]');
console.log(' }');
console.log(' }');
console.log(' }');
return;
}
const mcpManager = getMCPManager();
// 尝试连接以获取工具数量
try {
if (!mcpManager.isInitialized()) {
await mcpManager.initialize(mcpConfig);
}
} catch {
// 忽略连接错误,仍然显示配置的服务器
}
const statuses = mcpManager.getServerStatuses();
console.log('\nMCP 服务器列表:\n');
const statusIcons: Record<string, string> = {
connected: '✅',
connecting: '🔄',
disconnected: '⭕',
disabled: '🚫',
error: '❌',
};
for (const status of statuses) {
const icon = statusIcons[status.status] || '❓';
const toolInfo = status.toolCount > 0 ? ` (${status.toolCount} 个工具)` : '';
const errorInfo = status.error ? ` - ${status.error}` : '';
console.log(
` ${icon} ${status.name} [${status.type}] - ${status.status}${toolInfo}${errorInfo}`
);
}
console.log('');
// 关闭连接
await mcpManager.shutdown();
});
mcpCommand
.command('tools [server]')
.description('列出 MCP 服务器提供的工具')
.action(async (server?: string) => {
const mcpConfig = loadMCPConfig(process.cwd());
if (!mcpConfig.mcp || Object.keys(mcpConfig.mcp).length === 0) {
console.log('没有配置 MCP 服务器');
return;
}
const mcpManager = getMCPManager();
try {
if (!mcpManager.isInitialized()) {
await mcpManager.initialize(mcpConfig);
}
const tools = mcpManager.getTools();
if (tools.length === 0) {
console.log('没有可用的 MCP 工具');
return;
}
// 按服务器分组
const toolsByServer = new Map<string, typeof tools>();
for (const tool of tools) {
if (server && tool.server !== server) {
continue;
}
const serverTools = toolsByServer.get(tool.server) || [];
serverTools.push(tool);
toolsByServer.set(tool.server, serverTools);
}
if (toolsByServer.size === 0) {
console.log(server ? `服务器 "${server}" 没有提供工具` : '没有可用的工具');
return;
}
console.log('\nMCP 工具列表:\n');
for (const [serverName, serverTools] of toolsByServer) {
console.log(`📦 ${serverName}:`);
for (const tool of serverTools) {
console.log(` ${tool.name}`);
if (tool.description) {
console.log(` ${tool.description.substring(0, 80)}${tool.description.length > 80 ? '...' : ''}`);
}
}
console.log('');
}
} catch (error) {
console.error(
'获取工具列表失败:',
error instanceof Error ? error.message : String(error)
);
} finally {
await mcpManager.shutdown();
}
});
mcpCommand
.command('test <server>')
.description('测试 MCP 服务器连接')
.action(async (server: string) => {
const mcpConfig = loadMCPConfig(process.cwd());
if (!mcpConfig.mcp?.[server]) {
console.log(`❌ 未找到服务器配置: ${server}`);
return;
}
console.log(`🔄 正在连接 ${server}...`);
const mcpManager = getMCPManager();
try {
await mcpManager.initialize({
mcp: { [server]: mcpConfig.mcp[server] },
tools: mcpConfig.tools,
});
const status = mcpManager.getServerStatus(server);
if (status?.status === 'connected') {
console.log(`✅ 连接成功!`);
console.log(` 工具数量: ${status.toolCount}`);
const tools = mcpManager.getTools();
if (tools.length > 0) {
console.log(' 可用工具:');
for (const tool of tools) {
console.log(` - ${tool.originalName}`);
}
}
} else {
console.log(`❌ 连接失败: ${status?.error || '未知错误'}`);
}
} catch (error) {
console.error(
`❌ 连接失败:`,
error instanceof Error ? error.message : String(error)
);
} finally {
await mcpManager.shutdown();
}
});
// 初始化权限系统
function setupPermissions(): void {
const permissionManager = getPermissionManager();
permissionManager.setAskCallback(promptPermission);
}
// 单次查询命令
program
.command('ask <question>')
.description('单次提问(不进入交互模式)')
.action(async (question: string) => {
setupPermissions();
const config = loadConfig();
const agent = new Agent(config);
// 设置工具注册表(支持动态工具发现)
agent.setRegistry(toolRegistry);
try {
await agent.chat(question, (text) => {
process.stdout.write(text);
});
console.log('');
} catch (error) {
console.error(
'错误:',
error instanceof Error ? error.message : String(error)
);
process.exit(1);
}
});
// 默认:交互模式
program.action(async () => {
setupPermissions();
const config = loadConfig();
const agent = new Agent(config);
// 初始化 LSP 系统
initLSP(process.cwd());
// 初始化 MCP 系统(加载外部工具服务器)
await initMCP(process.cwd());
// 设置工具注册表(支持动态工具发现)
agent.setRegistry(toolRegistry);
// 初始化会话管理器(支持会话持久化)
const sessionManager = new SessionManager();
await sessionManager.init(process.cwd());
agent.setSessionManager(sessionManager);
// 初始化 todoManager(让 todo 工具可以访问会话)
todoManager.setSessionManager(sessionManager);
// 初始化 Agent 注册表(加载预设和用户配置)
await agentRegistry.init(process.cwd());
// 初始化 Task 工具上下文
initTaskContext(config, sessionManager);
updateTaskDescription();
// 初始化 Skill 注册表
const skillRegistry = getSkillRegistry();
await skillRegistry.initialize(process.cwd());
updateSkillDescription();
// 初始化 Command 注册表
const commandRegistry = getCommandRegistry();
await commandRegistry.initialize(process.cwd());
// 显示会话恢复信息
const session = sessionManager.getSession();
if (session && session.messages.length > 0) {
console.log(`\n📂 已恢复会话 (${session.messages.length} 条消息)`);
}
// 启动终端 UI
const ui = new TerminalUI(agent);
// 优雅退出
process.on('SIGINT', async () => {
console.log('\n\n👋 再见!');
await shutdownMCP();
await shutdownLSP();
await sessionManager.close();
ui.close();
process.exit(0);
});
await ui.start();
});
program.parse();