UNPKG

@yeepay/coderocket-mcp

Version:

CodeRocket MCP - Independent AI-powered code review server for Model Context Protocol

263 lines (248 loc) 9.24 kB
import { readFile, access } from 'fs/promises'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; import { homedir } from 'os'; import { logger } from '../logger.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); /** * 提示词管理器 * * 支持层级查找和coderocket-cli兼容的提示词管理: * 1. 项目级提示词 (./prompts/) * 2. 全局级提示词 (~/.coderocket/prompts/) * 3. 默认提示词 (内置) * * 兼容coderocket-cli的文件命名方式,支持两个项目共享提示词文件 */ export class PromptManager { static prompts = new Map(); static initialized = false; // 功能名到文件名的映射(统一使用git-commit-review-prompt.md) // 所有审查功能使用同一个高质量的提示词,区别仅在于被审查的内容 static PROMPT_FILE_MAPPING = { git_commit: 'git-commit-review-prompt.md', review_commit: 'git-commit-review-prompt.md', code_review: 'git-commit-review-prompt.md', review_code: 'git-commit-review-prompt.md', review_changes: 'git-commit-review-prompt.md', git_changes: 'git-commit-review-prompt.md', review_files: 'git-commit-review-prompt.md', file_review: 'git-commit-review-prompt.md', base: 'git-commit-review-prompt.md', // 统一使用专业的代码审查提示词 }; /** * 初始化提示词系统 */ static async initialize() { if (this.initialized) return; logger.info('初始化提示词管理器'); await this.loadPrompts(); this.initialized = true; logger.info('提示词管理器初始化完成', { promptCount: this.prompts.size, }); } /** * 加载所有提示词 */ static async loadPrompts() { // 加载所有映射的提示词 for (const [key, filename] of Object.entries(this.PROMPT_FILE_MAPPING)) { await this.loadPromptWithFallback(key, filename); } } /** * 层级加载提示词文件:项目级 -> 全局级 -> 默认值 */ static async loadPromptWithFallback(key, filename) { // 1. 尝试从项目级prompts目录加载 const projectPromptsDir = join(process.cwd(), 'prompts'); if (await this.tryLoadPromptFile(projectPromptsDir, filename, key)) { return; } // 2. 尝试从全局~/.coderocket/prompts目录加载 const globalPromptsDir = join(homedir(), '.coderocket', 'prompts'); if (await this.tryLoadPromptFile(globalPromptsDir, filename, key)) { return; } // 3. 使用默认提示词 logger.warn(`提示词文件不存在: ${filename},使用默认提示词`); this.setDefaultPrompt(key); } /** * 尝试从指定目录加载提示词文件 */ static async tryLoadPromptFile(dir, filename, key) { try { const filePath = join(dir, filename); // 检查文件是否存在 await access(filePath); // 读取文件内容 const content = await readFile(filePath, 'utf-8'); this.prompts.set(key, content.trim()); logger.debug(`提示词加载成功: ${key}`, { path: filePath }); return true; } catch (error) { // 文件不存在或读取失败,返回false继续尝试下一级 return false; } } /** * 设置默认提示词 */ static setDefaultPrompt(key) { const defaultPrompts = { base: `你是一个专业的代码审查专家,请对提供的代码进行详细分析。`, code_review: `# 专业代码审查 作为专业的代码审查专家,请对提供的代码片段进行深度分析,包括: ## 审查维度 1. **代码正确性** - 逻辑是否正确,是否存在bug 2. **代码质量** - 结构是否清晰,命名是否规范 3. **性能考虑** - 是否存在性能瓶颈 4. **安全性** - 是否存在安全漏洞 5. **可维护性** - 代码可读性和可扩展性 6. **代码规范** - 是否符合编码规范 请提供具体的改进建议和最佳实践建议。`, git_changes: `# Git变更审查 请对Git仓库中的变更进行专业审查,重点关注: ## 审查重点 1. **变更完整性** - 是否所有相关文件都被正确修改 2. **变更一致性** - 变更在不同文件中的一致性 3. **影响范围评估** - 变更对其他模块的影响 4. **代码质量** - 实现质量和安全性检查 5. **测试覆盖** - 是否需要补充测试 6. **文档更新** - 是否需要更新相关文档 请提供全面的变更评估和改进建议。`, git_commit: `# Git提交审查 作为资深的代码审阅专家,请对Git提交进行专业、深入的审查: ## 审查维度 1. **目标达成度** - 是否完整实现了提交目标 2. **功能完整性** - 功能实现是否正确完整 3. **代码质量** - 代码结构和规范性 4. **可维护性** - 代码的可读性和可维护性 5. **扩展性** - 设计的可扩展性 请提供详细的审查报告和改进建议。`, file_review: `# 多文件综合审查 请对多个文件进行综合性的代码质量评估: ## 审查维度 1. **架构一致性** - 文件间的架构设计一致性 2. **依赖关系** - 文件间的依赖关系是否合理 3. **代码复用** - 是否存在重复代码 4. **命名一致性** - 命名规范是否统一 5. **错误处理** - 错误处理策略是否一致 6. **性能协调** - 文件间的性能配合 请提供整体架构评估和改进建议。`, review_code: `作为专业的代码审查专家,请对提供的代码片段进行深度分析。`, review_changes: `请对Git仓库中的变更进行专业审查。`, review_commit: `请对指定的Git提交进行详细分析。`, review_files: `请对多个文件进行综合性代码质量评估。`, }; const defaultPrompt = defaultPrompts[key] || defaultPrompts.base; this.prompts.set(key, defaultPrompt); logger.debug(`使用默认提示词: ${key}`); } /** * 加载单个提示词(公共方法,用于测试) */ static async loadPrompt(key) { if (!this.initialized) { await this.initialize(); } return this.prompts.get(key) || null; } /** * 清除缓存(用于测试) */ static clearCache() { this.prompts.clear(); this.initialized = false; } /** * 获取默认提示词(用于测试) */ static getDefaultPrompt() { return this.prompts.get('base') || '请对代码进行审查'; } /** * 获取提示词文件的查找路径(用于调试) */ static getPromptPaths(filename) { return [ join(process.cwd(), 'prompts', filename), join(homedir(), '.coderocket', 'prompts', filename), ]; } /** * 获取提示词 */ static getPrompt(key, variables) { if (!this.initialized) { throw new Error('PromptManager 未初始化,请先调用 initialize()'); } let prompt = this.prompts.get(key); if (!prompt) { logger.warn(`提示词不存在: ${key},使用默认提示词`); prompt = this.prompts.get('base') || '请分析提供的内容。'; } // 替换变量 if (variables) { for (const [varKey, value] of Object.entries(variables)) { const placeholder = `{${varKey}}`; prompt = prompt.replace(new RegExp(placeholder, 'g'), value); } } return prompt; } /** * 构建完整的提示词 */ static buildPrompt(toolKey, content, customPrompt, language) { // 如果有自定义提示词,直接使用 if (customPrompt) { return customPrompt.replace('{content}', content); } // 获取基础提示词 const basePrompt = this.getPrompt('base'); const toolPrompt = this.getPrompt(toolKey); // 语言设置 const languageInstruction = language ? `请使用${language}回复。` : '请使用中文回复。'; // 组合提示词 return `${basePrompt} ${toolPrompt} ${languageInstruction} 内容: ${content}`; } /** * 获取所有可用的提示词键 */ static getAvailablePrompts() { return Array.from(this.prompts.keys()); } /** * 检查提示词是否存在 */ static hasPrompt(key) { return this.prompts.has(key); } /** * 动态设置提示词(用于测试或运行时修改) */ static setPrompt(key, content) { this.prompts.set(key, content); logger.debug(`动态设置提示词: ${key}`); } /** * 清除所有提示词(用于测试) */ static clear() { this.prompts.clear(); this.initialized = false; } } //# sourceMappingURL=PromptManager.js.map