Skip to main content
Glama
server.ts65.2 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { existsSync } from 'fs'; import { resolve } from 'path'; import { ModernizationAnalyzer } from './analyzers/modernization.js'; import { CompatibilityAnalyzer, formatCompatibilityReport } from './analyzers/compatibility.js'; import { CodeParser } from './parsers/index.js'; import { ReportFormatter, ReportFormat } from './utils/report-formatter.js'; import { ModernizationRules } from './data/modernization-rules.js'; import { MDNService } from './services/mdn-service.js'; import { CanIUseService } from './services/caniuse-service.js'; import { BaselineService } from './services/baseline-service.js'; import { ApiRecommendationKnowledge, RecommendedApi } from './data/api-recommendations.js'; /** * 現代化分析參數介面 */ interface ModernizationAnalysisArgs { projectPath: string; includePatterns?: string[]; excludePatterns?: string[]; reportFormat?: ReportFormat; } /** * API 組合推薦參數介面 */ interface ApiRecommendationArgs { requirement: string; targetBrowsers?: string[]; performanceRequirements?: 'low' | 'medium' | 'high'; } /** * 相容性分析參數介面 */ interface CompatibilityAnalysisArgs { projectPath: string; browserslistConfig?: string; reportFormat?: ReportFormat; } /** * 驗證錯誤類別 */ class ValidationError extends Error { constructor(message: string) { super(message); this.name = 'ValidationError'; } } /** * 開發決策顧問 MCP Server * 提供程式碼現代化、API組合推薦、相容性分析功能 */ class DevAdvisorServer { private server: Server; private modernizationAnalyzer: ModernizationAnalyzer; private compatibilityAnalyzer: CompatibilityAnalyzer; private codeParser: CodeParser; private reportFormatter: ReportFormatter; private rules: ModernizationRules; private mdnService: MDNService; private canIUseService: CanIUseService; private baselineService: BaselineService; private apiKnowledge: ApiRecommendationKnowledge; constructor() { this.server = new Server( { name: 'dev-advisor', version: '1.0.0', }, { capabilities: { tools: {}, resources: {}, prompts: {}, }, } ); this.codeParser = new CodeParser(); this.canIUseService = new CanIUseService(); this.baselineService = new BaselineService(); this.modernizationAnalyzer = new ModernizationAnalyzer(this.codeParser); this.compatibilityAnalyzer = new CompatibilityAnalyzer(this.codeParser, this.canIUseService); this.reportFormatter = new ReportFormatter(); this.rules = new ModernizationRules(); this.mdnService = new MDNService(); this.apiKnowledge = new ApiRecommendationKnowledge(); this.setupHandlers(); this.setupResourceHandlers(); this.setupPromptHandlers(); } private setupHandlers() { this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'analyze_modernization', description: '分析 JavaScript/TypeScript 程式碼現代化機會,找出可被瀏覽器原生 Web API 替代的第三方函式庫,減少 npm bundle 大小,包括 jQuery、Moment.js、Lodash、XMLHttpRequest 等過時模式的現代化建議', inputSchema: { type: 'object', properties: { projectPath: { type: 'string', description: '專案目錄路徑', }, includePatterns: { type: 'array', items: { type: 'string' }, description: '要掃描的檔案模式,支援 glob 語法,如 ["src/**/*.js", "src/**/*.ts"] 掃描 src 目錄下的 JavaScript/TypeScript 檔案', default: ['**/*.js', '**/*.ts', '**/*.jsx', '**/*.tsx'] }, excludePatterns: { type: 'array', items: { type: 'string' }, description: '要排除的檔案模式 (預設: ["node_modules/**", "dist/**", "build/**"])', default: ['node_modules/**', 'dist/**', 'build/**'] }, reportFormat: { type: 'string', description: '報告格式', enum: ['markdown', 'json', 'html', 'text'], default: 'markdown' } }, required: ['projectPath'], }, }, { name: 'recommend_api_combination', description: '根據自然語言描述的需求,推薦最佳的 API 技術組合', inputSchema: { type: 'object', properties: { requirement: { type: 'string', description: '功能需求描述 (例如:背景擷取影片畫面並分析)', }, targetBrowsers: { type: 'array', items: { type: 'string' }, description: '目標瀏覽器支援 (預設: 現代瀏覽器)', default: ['chrome>=90', 'firefox>=88', 'safari>=14', 'edge>=90'] }, performanceRequirements: { type: 'string', description: '效能需求 (low/medium/high)', enum: ['low', 'medium', 'high'], default: 'medium' } }, required: ['requirement'], }, }, { name: 'analyze_compatibility', description: '分析專案的 API 相容性風險,推薦 polyfill 方案', inputSchema: { type: 'object', properties: { projectPath: { type: 'string', description: '專案目錄路徑', }, browserslistConfig: { type: 'string', description: 'browserslist 配置字串或檔案路徑', }, reportFormat: { type: 'string', description: '報告格式', enum: ['json', 'markdown', 'html'], default: 'markdown' } }, required: ['projectPath'], }, }, { name: 'search_mdn', description: '搜尋 MDN Web Docs 文件,取得最新的 API 資訊、用法說明、棄用狀態和瀏覽器相容性', inputSchema: { type: 'object', properties: { query: { type: 'string', description: '搜尋關鍵字,如 "fetch", "Promise", "Array.prototype.includes"', }, limit: { type: 'number', description: '返回結果數量 (預設: 5)', default: 5 }, locale: { type: 'string', description: '語言 (預設: en-US,可用: zh-TW, zh-CN)', default: 'en-US' } }, required: ['query'], }, }, { name: 'check_browser_support', description: '使用 Can I Use 資料庫檢查 Web API 的瀏覽器相容性,取得支援版本和 polyfill 建議', inputSchema: { type: 'object', properties: { feature: { type: 'string', description: 'Web API 功能名稱,如 "fetch", "flexbox", "css-grid", "webgl"', }, targetBrowsers: { type: 'object', description: '目標瀏覽器版本 (預設: { chrome: "90", firefox: "88", safari: "14", edge: "90" })', default: { chrome: '90', firefox: '88', safari: '14', edge: '90' } } }, required: ['feature'], }, }, { name: 'list_api_categories', description: '列出所有可用的 Web API 類別,從 Can I Use 資料庫中取得完整的類別列表', inputSchema: { type: 'object', properties: {}, required: [], }, }, ], }; }); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { switch (request.params.name) { case 'analyze_modernization': return await this.handleModernizationAnalysis(request.params.arguments); case 'recommend_api_combination': return await this.handleApiRecommendation(request.params.arguments); case 'analyze_compatibility': return await this.handleCompatibilityAnalysis(request.params.arguments); case 'search_mdn': return await this.handleMDNSearch(request.params.arguments); case 'check_compatibility': return await this.handleCompatibilityCheck(request.params.arguments); case 'list_api_categories': return await this.handleListApiCategories(request.params.arguments); default: throw new Error(`Unknown tool: ${request.params.name}`); } }); } /** * 驗證現代化分析參數 */ private validateModernizationArgs(args: unknown): ModernizationAnalysisArgs { if (!args || typeof args !== 'object') { throw new ValidationError('參數格式錯誤,請提供有效的物件參數'); } const { projectPath, includePatterns, excludePatterns, reportFormat } = args as Record<string, unknown>; // 驗證必填參數 projectPath if (typeof projectPath !== 'string' || !projectPath.trim()) { throw new ValidationError('projectPath 為必填欄位,請提供專案目錄路徑'); } // 解析並驗證路徑 const resolvedPath = resolve(projectPath); if (!existsSync(resolvedPath)) { throw new ValidationError(`專案目錄不存在: ${resolvedPath}`); } // 驗證 includePatterns if (includePatterns !== undefined) { if (!Array.isArray(includePatterns) || !includePatterns.every(p => typeof p === 'string')) { throw new ValidationError('includePatterns 必須是字串陣列'); } } // 驗證 excludePatterns if (excludePatterns !== undefined) { if (!Array.isArray(excludePatterns) || !excludePatterns.every(p => typeof p === 'string')) { throw new ValidationError('excludePatterns 必須是字串陣列'); } } // 驗證 reportFormat const validFormats: ReportFormat[] = ['markdown', 'json', 'html', 'text']; if (reportFormat !== undefined && !validFormats.includes(reportFormat as ReportFormat)) { throw new ValidationError(`reportFormat 必須是以下其中之一: ${validFormats.join(', ')}`); } return { projectPath: resolvedPath, includePatterns: includePatterns as string[] | undefined, excludePatterns: excludePatterns as string[] | undefined, reportFormat: reportFormat as ReportFormat | undefined }; } private async handleModernizationAnalysis(args: unknown) { try { // 驗證輸入參數 const validatedArgs = this.validateModernizationArgs(args); const { projectPath, includePatterns = ['**/*.js', '**/*.ts', '**/*.jsx', '**/*.tsx'], excludePatterns = ['node_modules/**', 'dist/**', 'build/**'], reportFormat = 'markdown' } = validatedArgs; // 步驟 1: 先取得所有可用的 API 類別 let allCategories: Array<{ name: string; count: number; description?: string }> = []; let apiCategoryMap = new Map<string, string[]>(); // API 名稱 -> 類別列表 try { allCategories = await this.canIUseService.getAllCategories(); // 步驟 2: 分析專案中的現代化 API,找出它們的類別 const analysis = await this.modernizationAnalyzer.analyze( projectPath, includePatterns, excludePatterns ); // 收集所有提到的現代 API const modernApis = new Set<string>(); for (const file of analysis.fileAnalysis) { for (const api of file.modernizableApis) { modernApis.add(api.modernApi); } } // 為每個現代 API 找出對應的類別 for (const apiName of modernApis) { const categories: string[] = []; // 從知識庫中查找 API const api = this.apiKnowledge.getApi(apiName); if (api) { categories.push(api.category); } else { // 如果知識庫中沒有,嘗試從 Can I Use 資料庫查找 try { // 嘗試搜尋 feature ID const featureIds = await this.canIUseService.searchFeature(apiName); if (featureIds.length > 0) { const featureSupport = await this.canIUseService.getFeatureSupport(featureIds[0]); if (featureSupport && featureSupport.categories) { categories.push(...featureSupport.categories); } } } catch (error) { // 忽略錯誤,繼續處理下一個 API } } if (categories.length > 0) { apiCategoryMap.set(apiName, categories); } } // 將類別資訊添加到分析結果中 const enhancedAnalysis = { ...analysis, categoryInfo: { totalCategories: allCategories.length, apiCategories: Object.fromEntries(apiCategoryMap), allCategories: allCategories.map(cat => ({ name: cat.name, count: cat.count, description: cat.description })) } }; return { content: [ { type: 'text', text: this.formatModernizationReport(enhancedAnalysis, reportFormat), }, ], }; } catch (categoryError) { // 如果取得類別失敗,仍然返回分析結果(不包含類別資訊) console.warn('無法取得類別資訊,將返回不含類別的分析結果:', categoryError); const analysis = await this.modernizationAnalyzer.analyze( projectPath, includePatterns, excludePatterns ); return { content: [ { type: 'text', text: this.formatModernizationReport(analysis, reportFormat), }, ], }; } } catch (error) { const errorMessage = error instanceof ValidationError ? `參數驗證失敗: ${error.message}` : `分析失敗: ${error instanceof Error ? error.message : String(error)}`; return { content: [ { type: 'text', text: errorMessage, }, ], isError: true, }; } } /** * 驗證 API 推薦參數 */ private validateApiRecommendationArgs(args: unknown): ApiRecommendationArgs { if (!args || typeof args !== 'object') { throw new ValidationError('參數格式錯誤,請提供有效的物件參數'); } const { requirement, targetBrowsers, performanceRequirements } = args as Record<string, unknown>; // 驗證必填參數 requirement if (typeof requirement !== 'string' || !requirement.trim()) { throw new ValidationError('requirement 為必填欄位,請描述您的功能需求'); } // 驗證 targetBrowsers if (targetBrowsers !== undefined) { if (!Array.isArray(targetBrowsers) || !targetBrowsers.every(b => typeof b === 'string')) { throw new ValidationError('targetBrowsers 必須是字串陣列'); } } // 驗證 performanceRequirements const validPerf = ['low', 'medium', 'high']; if (performanceRequirements !== undefined && !validPerf.includes(performanceRequirements as string)) { throw new ValidationError(`performanceRequirements 必須是以下其中之一: ${validPerf.join(', ')}`); } return { requirement: requirement.trim(), targetBrowsers: targetBrowsers as string[] | undefined, performanceRequirements: performanceRequirements as 'low' | 'medium' | 'high' | undefined }; } /** * 驗證相容性分析參數 */ private validateCompatibilityArgs(args: unknown): CompatibilityAnalysisArgs { if (!args || typeof args !== 'object') { throw new ValidationError('參數格式錯誤,請提供有效的物件參數'); } const { projectPath, browserslistConfig, reportFormat } = args as Record<string, unknown>; // 驗證必填參數 projectPath if (typeof projectPath !== 'string' || !projectPath.trim()) { throw new ValidationError('projectPath 為必填欄位,請提供專案目錄路徑'); } // 解析並驗證路徑 const resolvedPath = resolve(projectPath); if (!existsSync(resolvedPath)) { throw new ValidationError(`專案目錄不存在: ${resolvedPath}`); } // 驗證 browserslistConfig if (browserslistConfig !== undefined && typeof browserslistConfig !== 'string') { throw new ValidationError('browserslistConfig 必須是字串'); } // 驗證 reportFormat const validFormats: ReportFormat[] = ['markdown', 'json', 'html', 'text']; if (reportFormat !== undefined && !validFormats.includes(reportFormat as ReportFormat)) { throw new ValidationError(`reportFormat 必須是以下其中之一: ${validFormats.join(', ')}`); } return { projectPath: resolvedPath, browserslistConfig: browserslistConfig as string | undefined, reportFormat: reportFormat as ReportFormat | undefined }; } private async handleApiRecommendation(args: unknown) { try { const validatedArgs = this.validateApiRecommendationArgs(args); const { requirement, targetBrowsers, performanceRequirements } = validatedArgs; // 步驟 1: 先取得所有可用的 API 類別 let allCategories: Array<{ name: string; count: number; description?: string }> = []; let matchedCategories: string[] = []; try { allCategories = await this.canIUseService.getAllCategories(); // 根據需求描述匹配相關的類別 const lowerReq = requirement.toLowerCase(); matchedCategories = allCategories .filter(cat => { const catName = cat.name.toLowerCase(); const catDesc = (cat.description || '').toLowerCase(); return lowerReq.includes(catName) || catName.includes(lowerReq) || catDesc.includes(lowerReq) || this.matchCategoryKeywords(lowerReq, cat.name); }) .map(cat => cat.name); } catch (error) { console.warn('無法取得類別列表,將使用預定義知識庫:', error); } // 步驟 2: 從匹配的類別中找出相關的 API const apisFromCategories = new Set<string>(); for (const category of matchedCategories) { try { const featureIds = await this.canIUseService.getFeaturesByCategory(category); // 將 feature ID 轉換為 API 名稱(如果知識庫中有對應的) for (const featureId of featureIds.slice(0, 10)) { // 限制每個類別最多 10 個 const api = this.apiKnowledge.getApiByCaniuseId(featureId); if (api) { apisFromCategories.add(api.name); } } } catch (error) { console.warn(`無法取得類別 ${category} 的 API:`, error); } } // 步驟 3: 從知識庫中推薦 API(原有邏輯) const recommendedApis = this.apiKnowledge.recommendApis( requirement, performanceRequirements ); // 步驟 4: 合併結果,優先使用知識庫的推薦,補充類別匹配的結果 const apiMap = new Map<string, RecommendedApi>(); // 先加入知識庫推薦的 API for (const api of recommendedApis) { apiMap.set(api.name, api); } // 補充從類別匹配找到的 API(如果不在知識庫推薦中) for (const apiName of apisFromCategories) { const api = this.apiKnowledge.getApi(apiName); if (api && !apiMap.has(apiName)) { // 檢查是否符合需求描述 const lowerReq = requirement.toLowerCase(); if (api.description.toLowerCase().includes(lowerReq) || api.useCases.some(uc => lowerReq.includes(uc.toLowerCase()))) { apiMap.set(apiName, api); } } } const finalRecommendedApis = Array.from(apiMap.values()); if (finalRecommendedApis.length === 0) { let suggestionText = `# 🔍 API 推薦結果\n\n找不到與「${requirement}」相關的 API 推薦。\n\n`; if (matchedCategories.length > 0) { suggestionText += `**相關類別**: ${matchedCategories.join(', ')}\n\n`; } suggestionText += `**建議:**\n`; suggestionText += `- 嘗試使用更具體的描述\n`; suggestionText += `- 使用英文關鍵字(如 fetch, animation, storage)\n`; suggestionText += `- 描述具體的使用場景\n`; suggestionText += `- 使用 \`list_api_categories\` 工具查看所有可用的 API 類別\n`; return { content: [{ type: 'text', text: suggestionText }] }; } // 解析目標瀏覽器版本 const browserVersions = this.parseBrowserVersions(targetBrowsers); // 為每個推薦的 API 查詢相容性 const apiWithCompatibility = await this.fetchApiCompatibility( finalRecommendedApis, browserVersions ); // 生成報告(包含類別資訊) const report = this.generateApiRecommendationReport( requirement, apiWithCompatibility, browserVersions, performanceRequirements, matchedCategories, allCategories.length ); return { content: [{ type: 'text', text: report }] }; } catch (error) { const errorMessage = error instanceof ValidationError ? `參數驗證失敗: ${error.message}` : `推薦失敗: ${error instanceof Error ? error.message : String(error)}`; return { content: [{ type: 'text', text: errorMessage }], isError: true, }; } } /** * 匹配類別關鍵字 */ private matchCategoryKeywords(requirement: string, categoryName: string): boolean { const categoryKeywords: Record<string, string[]> = { 'CSS': ['css', '樣式', 'style', 'layout', '佈局', 'grid', 'flex'], 'JavaScript': ['javascript', 'js', 'api', 'function', '函式'], 'HTML': ['html', 'element', '元素', 'tag', '標籤'], 'Media': ['media', 'video', 'audio', '影片', '音訊', 'stream', 'streaming'], 'Storage': ['storage', 'store', '儲存', 'cache', '快取', 'database', '資料庫'], 'Network': ['network', 'http', 'fetch', 'request', '請求', 'ajax'], 'Security': ['security', 'crypto', '加密', 'secure', '安全'], 'Performance': ['performance', '效能', 'speed', 'optimize', '優化'], 'Graphics': ['graphics', 'canvas', 'webgl', 'draw', '繪圖', '圖形'], 'DOM': ['dom', 'element', '元素', 'query', 'selector', '選擇器'], 'Events': ['event', '事件', 'listener', '監聽'], 'Forms': ['form', '表單', 'input', 'validate', '驗證'] }; const keywords = categoryKeywords[categoryName] || []; return keywords.some(keyword => requirement.includes(keyword)); } /** * 解析目標瀏覽器版本 */ private parseBrowserVersions(targetBrowsers?: string[]): Record<string, string> { const defaultVersions: Record<string, string> = { chrome: '90', firefox: '88', safari: '14', edge: '90' }; if (!targetBrowsers || targetBrowsers.length === 0) { return defaultVersions; } const versions: Record<string, string> = {}; for (const browser of targetBrowsers) { // 解析格式如 "chrome>=90" 或 "firefox>=88" const match = browser.match(/^(\w+)(?:>=?|>)(\d+)$/); if (match) { versions[match[1].toLowerCase()] = match[2]; } } return Object.keys(versions).length > 0 ? versions : defaultVersions; } /** * 為推薦的 API 查詢相容性 */ private async fetchApiCompatibility( apis: RecommendedApi[], targetBrowsers: Record<string, string> ): Promise<Array<{ api: RecommendedApi; compatibility: { globalSupport: number; supported: string[]; notSupported: string[]; partialSupport: string[]; recommendation: string; polyfillAvailable: boolean; polyfillUrl?: string; } | null; baseline: { status: string; label: string; description: string; icon: string; safeToUse: boolean; recommendation: string; } | null; }>> { const results = []; for (const api of apis) { let compatibility = null; let baseline = null; try { // 使用 Can I Use 查詢相容性 const report = await this.canIUseService.checkCompatibility( api.caniuseId, targetBrowsers ); compatibility = report; } catch (error) { console.warn(`無法取得 ${api.name} 的相容性資料:`, error); } // 查詢 Baseline 狀態 try { const baselineMatches = await this.baselineService.searchFeature(api.name); if (baselineMatches.length > 0) { const baselineFeature = await this.baselineService.getFeature(baselineMatches[0].id) || baselineMatches[0]; if (baselineFeature.baseline) { baseline = { status: baselineFeature.baseline.status, label: this.baselineService.getBaselineLabel(baselineFeature.baseline.status), description: this.baselineService.getBaselineDescription(baselineFeature.baseline.status), icon: this.baselineService.getBaselineIcon(baselineFeature.baseline.status), safeToUse: this.baselineService.isSafeToUse(baselineFeature), recommendation: this.baselineService.getRecommendation(baselineFeature) }; } } } catch (error) { console.warn(`無法取得 ${api.name} 的 Baseline 狀態:`, error); } results.push({ api, compatibility, baseline }); } return results; } /** * 生成 API 推薦報告 */ private generateApiRecommendationReport( requirement: string, apiWithCompatibility: Array<{ api: RecommendedApi; compatibility: { globalSupport: number; supported: string[]; notSupported: string[]; partialSupport: string[]; recommendation: string; polyfillAvailable: boolean; polyfillUrl?: string; } | null; baseline: { status: string; label: string; description: string; icon: string; safeToUse: boolean; recommendation: string; } | null; }>, targetBrowsers: Record<string, string>, performanceLevel?: string, matchedCategories?: string[], totalCategoriesCount?: number ): string { let report = `# 🎯 API 組合推薦\n\n`; report += `**需求**: ${requirement}\n`; report += `**目標瀏覽器**: ${Object.entries(targetBrowsers).map(([b, v]) => `${b} >= ${v}`).join(', ')}\n`; if (performanceLevel) { report += `**效能需求**: ${performanceLevel}\n`; } // 顯示類別分析資訊 if (matchedCategories && matchedCategories.length > 0) { report += `**相關類別**: ${matchedCategories.join(', ')}\n`; } if (totalCategoriesCount) { report += `**可用類別總數**: ${totalCategoriesCount} 個(從 Can I Use 資料庫分析)\n`; } report += `\n---\n\n`; // 按類別分組 const byCategory = new Map<string, typeof apiWithCompatibility>(); for (const item of apiWithCompatibility) { const category = item.api.category; if (!byCategory.has(category)) { byCategory.set(category, []); } byCategory.get(category)!.push(item); } report += `## 📋 推薦 API 列表\n\n`; report += `共找到 **${apiWithCompatibility.length}** 個相關 API:\n\n`; for (const [category, items] of byCategory) { report += `### 📁 ${category}\n\n`; for (const { api, compatibility, baseline } of items) { // API 標題和支援狀態 const supportIcon = compatibility ? (compatibility.notSupported.length === 0 ? '✅' : compatibility.supported.length > 0 ? '⚠️' : '❌') : '❓'; // 如果有 Baseline 狀態,優先使用 Baseline 圖示 const displayIcon = baseline ? baseline.icon : supportIcon; report += `#### ${displayIcon} ${api.name}\n\n`; report += `${api.description}\n\n`; // Baseline 狀態 if (baseline) { report += `**📊 Baseline 狀態**: ${baseline.icon} **${baseline.label}**\n\n`; report += `${baseline.description}\n\n`; if (baseline.safeToUse) { report += `✅ **可安全使用** - 此 API 在所有核心瀏覽器中都支援\n\n`; } else { report += `⚠️ **需謹慎使用** - 建議檢查目標瀏覽器支援情況\n\n`; } } // 用途 report += `**適用場景**: ${api.useCases.join('、')}\n\n`; // 程式碼範例 report += `**程式碼範例**:\n\`\`\`javascript\n${api.codeExample}\n\`\`\`\n\n`; // 可取代的函式庫 if (api.replacesLibraries && api.replacesLibraries.length > 0) { report += `**可取代函式庫**: ${api.replacesLibraries.map(l => `\`${l}\``).join(', ')}\n\n`; } // 相容性資訊 if (compatibility) { report += `**🌐 瀏覽器相容性**:\n\n`; report += `- 全球支援率: **${compatibility.globalSupport.toFixed(1)}%**\n`; if (compatibility.supported.length > 0) { report += `- ✅ 支援: ${compatibility.supported.join(', ')}\n`; } if (compatibility.partialSupport.length > 0) { report += `- ⚠️ 部分支援: ${compatibility.partialSupport.join(', ')}\n`; } if (compatibility.notSupported.length > 0) { report += `- ❌ 不支援: ${compatibility.notSupported.join(', ')}\n`; } report += `\n${compatibility.recommendation}\n\n`; // Polyfill 資訊 if (compatibility.polyfillAvailable) { report += `**🔧 Polyfill 可用**`; if (compatibility.polyfillUrl) { report += `:\n\`\`\`html\n<script src="${compatibility.polyfillUrl}"></script>\n\`\`\``; } report += '\n\n'; } } else { report += `**🌐 瀏覽器相容性**: 無法取得相容性資料,請參考 [Can I Use](https://caniuse.com/?search=${encodeURIComponent(api.caniuseId)})\n\n`; } // 相關 API if (api.relatedApis && api.relatedApis.length > 0) { report += `**相關 API**: ${api.relatedApis.join(', ')}\n\n`; } report += `---\n\n`; } } // 總結建議 report += `## 💡 實作建議\n\n`; // 添加類別分析說明 if (matchedCategories && matchedCategories.length > 0) { report += `### 📊 類別分析\n\n`; report += `本推薦基於以下分析流程:\n\n`; report += `1. ✅ 從 Can I Use 資料庫取得所有 ${totalCategoriesCount || '可用'} 個 API 類別\n`; report += `2. ✅ 根據需求描述匹配相關類別:**${matchedCategories.join('**, **')}**\n`; report += `3. ✅ 從匹配類別中找出相關 API\n`; report += `4. ✅ 結合預定義知識庫的推薦結果\n`; report += `5. ✅ 查詢瀏覽器相容性並生成最終推薦\n\n`; report += `---\n\n`; } const fullySupported = apiWithCompatibility.filter( item => item.compatibility && item.compatibility.notSupported.length === 0 ); const needsPolyfill = apiWithCompatibility.filter( item => item.compatibility && item.compatibility.notSupported.length > 0 && item.compatibility.polyfillAvailable ); const notSupported = apiWithCompatibility.filter( item => item.compatibility && item.compatibility.notSupported.length > 0 && !item.compatibility.polyfillAvailable ); if (fullySupported.length > 0) { report += `### ✅ 可直接使用 (${fullySupported.length})\n`; report += `以下 API 在所有目標瀏覽器中都完全支援:\n`; for (const { api } of fullySupported) { report += `- ${api.name}\n`; } report += '\n'; } if (needsPolyfill.length > 0) { report += `### ⚠️ 需要 Polyfill (${needsPolyfill.length})\n`; report += `以下 API 在部分目標瀏覽器中需要 polyfill:\n`; for (const { api, compatibility } of needsPolyfill) { report += `- ${api.name}`; if (compatibility?.polyfillUrl) { report += ` - [Polyfill](${compatibility.polyfillUrl})`; } report += '\n'; } report += '\n'; } if (notSupported.length > 0) { report += `### ❌ 需要替代方案 (${notSupported.length})\n`; report += `以下 API 在部分目標瀏覽器中不支援且無 polyfill:\n`; for (const { api } of notSupported) { report += `- ${api.name} - 建議尋找替代方案或調整目標瀏覽器\n`; } report += '\n'; } return report; } private async handleCompatibilityAnalysis(args: unknown) { try { const validatedArgs = this.validateCompatibilityArgs(args); const { projectPath, browserslistConfig, reportFormat = 'markdown' } = validatedArgs; // 預設的檔案模式 const includePatterns = ['**/*.js', '**/*.ts', '**/*.jsx', '**/*.tsx']; const excludePatterns = ['node_modules/**', 'dist/**', 'build/**']; // 執行相容性分析 const analysis = await this.compatibilityAnalyzer.analyze( projectPath, includePatterns, excludePatterns, browserslistConfig ); // 格式化報告 const report = formatCompatibilityReport(analysis, reportFormat); return { content: [ { type: 'text', text: report, }, ], }; } catch (error) { const errorMessage = error instanceof ValidationError ? `參數驗證失敗: ${error.message}` : `分析失敗: ${error instanceof Error ? error.message : String(error)}`; return { content: [{ type: 'text', text: errorMessage }], isError: true, }; } } /** * 處理 MDN 搜尋請求 */ private async handleMDNSearch(args: unknown) { try { if (!args || typeof args !== 'object') { throw new ValidationError('參數格式錯誤'); } const { query, limit = 5, locale = 'en-US' } = args as Record<string, unknown>; if (typeof query !== 'string' || !query.trim()) { throw new ValidationError('query 為必填欄位,請提供搜尋關鍵字'); } // 建立服務實例(支援不同語言) const mdnService = new MDNService(locale as string); // 搜尋 MDN const searchResults = await mdnService.search(query, limit as number); if (searchResults.length === 0) { return { content: [{ type: 'text', text: `🔍 MDN 搜尋結果\n\n找不到與 "${query}" 相關的文件。\n\n建議:\n- 嘗試使用英文關鍵字\n- 使用更具體的 API 名稱(如 "Array.prototype.map")` }] }; } // 格式化結果 let report = `# 🔍 MDN 搜尋結果: "${query}"\n\n`; report += `找到 ${searchResults.length} 個相關文件:\n\n`; for (const result of searchResults) { report += `## ${result.title}\n`; report += `📖 ${result.summary}\n`; report += `🔗 ${result.url}\n\n`; } // 嘗試取得第一個結果的詳細資訊 if (searchResults.length > 0) { const detailed = await mdnService.getAPIInfo(searchResults[0].slug); if (detailed) { report += `---\n\n## 📋 詳細資訊: ${detailed.title}\n\n`; if (detailed.deprecated) { report += `⚠️ **此 API 已被棄用**\n\n`; } if (detailed.experimental) { report += `🧪 **此 API 為實驗性功能**\n\n`; } if (detailed.summary) { report += `### 說明\n${detailed.summary}\n\n`; } if (detailed.syntax) { report += `### 語法\n\`\`\`javascript\n${detailed.syntax}\n\`\`\`\n\n`; } if (detailed.browserCompat) { report += `### 瀏覽器相容性\n`; const compat = detailed.browserCompat; if (compat.chrome) report += `- Chrome: ${compat.chrome}\n`; if (compat.firefox) report += `- Firefox: ${compat.firefox}\n`; if (compat.safari) report += `- Safari: ${compat.safari}\n`; if (compat.edge) report += `- Edge: ${compat.edge}\n`; if (compat.nodejs) report += `- Node.js: ${compat.nodejs}\n`; report += '\n'; } report += `🔗 完整文件: ${detailed.url}\n`; } } return { content: [{ type: 'text', text: report }] }; } catch (error) { const errorMessage = error instanceof ValidationError ? `參數驗證失敗: ${error.message}` : `MDN 搜尋失敗: ${error instanceof Error ? error.message : String(error)}`; return { content: [{ type: 'text', text: errorMessage }], isError: true, }; } } /** * 處理相容性檢查請求(整合 Can I Use 和 Baseline) */ private async handleCompatibilityCheck(args: unknown) { try { if (!args || typeof args !== 'object') { throw new ValidationError('參數格式錯誤'); } const { feature, targetBrowsers = { chrome: '90', firefox: '88', safari: '14', edge: '90' } } = args as Record<string, unknown>; if (typeof feature !== 'string' || !feature.trim()) { throw new ValidationError('feature 為必填欄位,請提供要檢查的 Web API 功能名稱'); } // 同時查詢 Can I Use 和 Baseline const [caniuseMatches, baselineMatches] = await Promise.all([ this.canIUseService.searchFeature(feature), this.baselineService.searchFeature(feature) ]); // 如果兩個來源都找不到 if (caniuseMatches.length === 0 && baselineMatches.length === 0) { return { content: [{ type: 'text', text: `🔍 相容性查詢結果\n\n找不到與 "${feature}" 相關的功能。\n\n建議:\n- 嘗試使用不同的關鍵字\n- 常見功能名稱:fetch, flexbox, css-grid, webgl, es6-module, async-functions` }] }; } let report = `# 🌐 Web API 相容性報告: ${feature}\n\n`; // ========== Can I Use 資料 ========== if (caniuseMatches.length > 0) { const featureSupport = await this.canIUseService.getFeatureSupport(caniuseMatches[0]); if (featureSupport) { const compatReport = await this.canIUseService.checkCompatibility( caniuseMatches[0], targetBrowsers as Record<string, string> ); report += `## 📊 概覽\n\n`; report += `- **功能**: ${featureSupport.title}\n`; report += `- **全球支援率**: ${compatReport.globalSupport.toFixed(1)}%\n`; report += `- **標準狀態**: ${this.getStatusText(featureSupport.status)}\n`; if (featureSupport.description) { report += `\n### 說明\n${featureSupport.description}\n`; } report += `\n## 🎯 目標瀏覽器相容性\n\n`; report += `${compatReport.recommendation}\n\n`; if (compatReport.supported.length > 0) { report += `### ✅ 支援的瀏覽器\n`; for (const browser of compatReport.supported) { report += `- ${browser}\n`; } report += '\n'; } if (compatReport.partialSupport.length > 0) { report += `### ⚠️ 部分支援\n`; for (const browser of compatReport.partialSupport) { report += `- ${browser}\n`; } report += '\n'; } if (compatReport.notSupported.length > 0) { report += `### ❌ 不支援\n`; for (const browser of compatReport.notSupported) { report += `- ${browser}\n`; } report += '\n'; } // Polyfill 資訊 if (compatReport.polyfillAvailable) { report += `## 🔧 Polyfill\n\n`; report += `此功能有 polyfill 可用。\n`; if (compatReport.polyfillUrl) { report += `\n\`\`\`html\n<script src="${compatReport.polyfillUrl}"></script>\n\`\`\`\n`; } report += '\n'; } // 各瀏覽器詳細支援版本 report += `## 📱 各瀏覽器支援版本\n\n`; const browsers = featureSupport.browsers; const browserNames: Record<string, string> = { chrome: 'Chrome', firefox: 'Firefox', safari: 'Safari', edge: 'Edge', ie: 'Internet Explorer', opera: 'Opera', ios_saf: 'iOS Safari', android: 'Android Browser', samsung: 'Samsung Internet' }; for (const [key, name] of Object.entries(browserNames)) { const support = (browsers as any)[key]; if (support) { const icon = support.supported ? '✅' : (support.partialSupport ? '⚠️' : '❌'); const version = support.sinceVersion ? `v${support.sinceVersion}+` : (support.supported ? '支援' : '不支援'); report += `| ${icon} ${name} | ${version} |\n`; } } report += '\n'; } } // ========== Baseline 狀態 ========== report += `## 📊 Baseline 狀態\n\n`; if (baselineMatches.length > 0) { const baselineInfo = await this.baselineService.getFeature(baselineMatches[0].id) || baselineMatches[0]; if (baselineInfo.baseline) { report += this.baselineService.formatBaselineInfo(baselineInfo); report += `\n${this.baselineService.getRecommendation(baselineInfo)}\n\n`; // Baseline 的瀏覽器支援資訊 if (baselineInfo.compat) { report += `### Baseline 瀏覽器支援\n\n`; const compat = baselineInfo.compat; if (compat.chrome) { const since = compat.chrome.since || '未知'; const flags = compat.chrome.flags ? ' (需要啟用實驗性功能)' : ''; report += `- **Chrome**: ${since}${flags}\n`; } if (compat.firefox) { const since = compat.firefox.since || '未知'; const flags = compat.firefox.flags ? ' (需要啟用實驗性功能)' : ''; report += `- **Firefox**: ${since}${flags}\n`; } if (compat.safari) { const since = compat.safari.since || '未知'; const flags = compat.safari.flags ? ' (需要啟用實驗性功能)' : ''; report += `- **Safari**: ${since}${flags}\n`; } if (compat.edge) { const since = compat.edge.since || '未知'; const flags = compat.edge.flags ? ' (需要啟用實驗性功能)' : ''; report += `- **Edge**: ${since}${flags}\n`; } report += '\n'; } } else { report += `❓ 此功能尚未有 Baseline 狀態資訊\n\n`; } } else { report += `❓ 在 Baseline 資料庫中找不到此功能\n\n`; report += `建議查閱 [web.dev/baseline](https://web.dev/baseline) 確認。\n\n`; } // ========== 相關連結 ========== report += `## 🔗 相關連結\n\n`; if (caniuseMatches.length > 0) { report += `- [Can I Use](https://caniuse.com/${caniuseMatches[0]})\n`; } if (baselineMatches.length > 0 && baselineMatches[0].mdn?.url) { report += `- [MDN 文件](${baselineMatches[0].mdn.url})\n`; } report += `- [Baseline 狀態](https://web.dev/baseline)\n`; // 其他相關功能 const allMatches = [...new Set([...caniuseMatches.slice(1, 4), ...baselineMatches.slice(1, 4).map(m => m.name)])]; if (allMatches.length > 0) { report += `\n## 🔍 其他相關功能\n\n`; report += `您可能也在尋找:\n`; for (const match of allMatches.slice(0, 5)) { report += `- \`${typeof match === 'string' ? match : match}\`\n`; } } return { content: [{ type: 'text', text: report }] }; } catch (error) { const errorMessage = error instanceof ValidationError ? `參數驗證失敗: ${error.message}` : `相容性檢查失敗: ${error instanceof Error ? error.message : String(error)}`; return { content: [{ type: 'text', text: errorMessage }], isError: true, }; } } /** * 處理列出所有 API 類別的請求 */ private async handleListApiCategories(args: unknown) { try { const categories = await this.canIUseService.getAllCategories(); if (categories.length === 0) { return { content: [{ type: 'text', text: '# 📋 API 類別列表\n\n無法載入類別資料,請稍後再試。' }] }; } // 生成報告 let report = '# 📋 Web API 類別列表\n\n'; report += `本列表包含從 Can I Use 資料庫中提取的所有 Web API 類別。\n\n`; report += `**總共 ${categories.length} 個類別**\n\n`; report += `---\n\n`; // 按類別分組顯示 for (const category of categories) { report += `## ${category.name}\n\n`; report += `- **功能數量**: ${category.count}\n`; if (category.description) { report += `- **說明**: ${category.description}\n`; } report += '\n'; } // 添加使用建議 report += `---\n\n`; report += `## 💡 使用建議\n\n`; report += `您可以使用以下方式查詢特定類別的 API:\n\n`; report += `1. 使用 \`recommend_api_combination\` 工具,描述您的需求\n`; report += `2. 使用 \`search_mdn\` 工具搜尋特定的 API\n`; report += `3. 使用 \`check_browser_support\` 工具檢查特定 API 的瀏覽器支援\n\n`; report += `**注意**: \`recommend_api_combination\` 工具目前使用預定義的 API 知識庫,`; report += `類別可能與此列表不完全一致。此列表反映 Can I Use 資料庫中的實際類別分類。\n`; return { content: [{ type: 'text', text: report }] }; } catch (error) { const errorMessage = `取得 API 類別列表失敗: ${error instanceof Error ? error.message : String(error)}`; return { content: [{ type: 'text', text: errorMessage }], isError: true, }; } } /** * 取得狀態文字 */ private getStatusText(status: string): string { const statusMap: Record<string, string> = { 'rec': '✅ W3C 推薦標準', 'pr': '📋 提議推薦標準', 'cr': '🔍 候選推薦標準', 'wd': '📝 工作草案', 'ls': '📚 Living Standard', 'other': '📌 其他' }; return statusMap[status] || status; } private formatModernizationReport(analysis: any, format: string = 'markdown'): string { return this.reportFormatter.formatModernizationReport(analysis, format as any); } /** * 設定 Resources 處理器 */ private setupResourceHandlers() { // 列出可用的 Resources this.server.setRequestHandler(ListResourcesRequestSchema, async () => { return { resources: [ { uri: 'devadvisor://rules/libraries', name: '函式庫現代化規則', description: '所有可替換的函式庫清單和對應的現代化建議', mimeType: 'application/json' }, { uri: 'devadvisor://rules/apis', name: 'API 現代化規則', description: '所有可現代化的 API 清單和對應的建議', mimeType: 'application/json' }, { uri: 'devadvisor://rules/all', name: '所有現代化規則', description: '完整的現代化規則資料庫', mimeType: 'application/json' }, { uri: 'devadvisor://stats', name: '規則統計資訊', description: '規則資料庫的統計資訊', mimeType: 'application/json' } ] }; }); // 讀取特定 Resource this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const uri = request.params.uri; switch (uri) { case 'devadvisor://rules/libraries': { const libraryRules = this.rules.getAllLibraryRules(); const rulesArray = Array.from(libraryRules.entries()).map(([key, rule]) => ({ id: key, ...rule })); return { contents: [{ uri, mimeType: 'application/json', text: JSON.stringify(rulesArray, null, 2) }] }; } case 'devadvisor://rules/apis': { const apiRules = this.rules.getAllApiRules(); const rulesArray = Array.from(apiRules.entries()).map(([key, rule]) => ({ id: key, ...rule })); return { contents: [{ uri, mimeType: 'application/json', text: JSON.stringify(rulesArray, null, 2) }] }; } case 'devadvisor://rules/all': { const libraryRules = this.rules.getAllLibraryRules(); const apiRules = this.rules.getAllApiRules(); const allRules = { libraries: Array.from(libraryRules.entries()).map(([key, rule]) => ({ id: key, ...rule })), apis: Array.from(apiRules.entries()).map(([key, rule]) => ({ id: key, ...rule })) }; return { contents: [{ uri, mimeType: 'application/json', text: JSON.stringify(allRules, null, 2) }] }; } case 'devadvisor://stats': { const stats = this.rules.getStatistics(); return { contents: [{ uri, mimeType: 'application/json', text: JSON.stringify(stats, null, 2) }] }; } default: throw new Error(`Unknown resource: ${uri}`); } }); } /** * 設定 Prompts 處理器 */ private setupPromptHandlers() { // 列出可用的 Prompts this.server.setRequestHandler(ListPromptsRequestSchema, async () => { return { prompts: [ { name: 'analyze-project', description: '分析專案的程式碼現代化機會', arguments: [ { name: 'projectPath', description: '專案目錄路徑', required: true }, { name: 'focus', description: '分析重點: bundle-size, performance, security, all', required: false } ] }, { name: 'migrate-library', description: '取得特定函式庫的遷移指南', arguments: [ { name: 'library', description: '要遷移的函式庫名稱 (如: jquery, moment, lodash)', required: true } ] }, { name: 'modernize-pattern', description: '取得特定程式碼模式的現代化建議', arguments: [ { name: 'pattern', description: '程式碼模式 (如: callback, var, for-loop, iife)', required: true } ] }, { name: 'quick-wins', description: '取得低風險、高效益的快速改善建議', arguments: [ { name: 'projectPath', description: '專案目錄路徑', required: true } ] }, { name: 'analyze-pr', description: '分析 Git PR 的程式碼變更,整合規則式分析和 AI 分析,提供現代化建議', arguments: [ { name: 'projectPath', description: '專案目錄路徑', required: true }, { name: 'prDiff', description: 'PR 的 diff 內容(可選,如果提供則會用於 AI 分析)', required: false }, { name: 'changedFiles', description: 'PR 變更的檔案列表(JSON 陣列,如 ["src/file1.js", "src/file2.ts"])', required: false } ] } ] }; }); // 取得特定 Prompt this.server.setRequestHandler(GetPromptRequestSchema, async (request) => { const { name, arguments: args } = request.params; switch (name) { case 'analyze-project': { const projectPath = args?.projectPath || '.'; const focus = args?.focus || 'all'; let focusText = ''; switch (focus) { case 'bundle-size': focusText = ',特別關注可以減少 bundle 大小的函式庫替換'; break; case 'performance': focusText = ',特別關注效能優化機會'; break; case 'security': focusText = ',特別關注安全性相關的過時 API (如 eval, innerHTML)'; break; default: focusText = ''; } return { messages: [ { role: 'user', content: { type: 'text', text: `請使用 analyze_modernization 工具分析 "${projectPath}" 專案的程式碼現代化機會${focusText}。 分析後請提供: 1. 執行摘要:發現了多少現代化機會 2. 優先處理清單:按照「低風險高效益」排序的建議 3. 具體的程式碼範例:展示如何將舊程式碼改為現代寫法 4. 風險評估:哪些變更需要特別注意 5. 實作建議:建議的實施順序和時程估算` } } ] }; } case 'migrate-library': { const library = args?.library || 'jquery'; const rule = this.rules.getLibraryRule(library.toLowerCase()); if (rule) { return { messages: [ { role: 'user', content: { type: 'text', text: `請提供 ${rule.name} 的完整遷移指南。 根據規則資料庫,${rule.name} 可以用 ${rule.modernAlternative} 替代。 原因:${rule.reason} 遷移範例: ${rule.migrationExample} 請提供: 1. 詳細的遷移步驟 2. 常見的使用案例和對應的現代寫法 3. 可能遇到的問題和解決方案 4. 測試建議確保遷移成功` } } ] }; } else { return { messages: [ { role: 'user', content: { type: 'text', text: `請提供 ${library} 函式庫的現代化遷移建議。 我想了解: 1. ${library} 是否有原生替代方案或更現代的替代函式庫 2. 遷移的步驟和注意事項 3. 具體的程式碼範例` } } ] }; } } case 'modernize-pattern': { const pattern = args?.pattern || 'callback'; const patternGuides: Record<string, string> = { 'callback': `請說明如何將回調函式模式 (callback pattern) 現代化為 Promise/async-await。 包含: 1. 為什麼要從回調轉換為 Promise 2. 使用 util.promisify 包裝現有回調 API 3. 手動建立 Promise 包裝器 4. 使用 async/await 重構程式碼 5. 錯誤處理的最佳實踐`, 'var': `請說明如何將 var 宣告現代化為 let/const。 包含: 1. var 的問題:變數提升和作用域洩漏 2. let vs const 的選擇原則 3. 迴圈中的 var 陷阱 4. 自動化工具輔助轉換`, 'for-loop': `請說明如何將傳統 for 迴圈現代化為陣列方法。 包含: 1. forEach, map, filter, reduce 的使用時機 2. for...of 與傳統 for 的比較 3. 效能考量 4. 何時仍應使用傳統 for 迴圈`, 'iife': `請說明如何將 IIFE (立即執行函式表達式) 現代化為 ES6 模組。 包含: 1. IIFE 的原始用途:作用域隔離和模組模式 2. ES6 模組如何解決相同問題 3. 逐步遷移策略 4. 相容性考量` }; const guide = patternGuides[pattern.toLowerCase()] || `請說明如何現代化 "${pattern}" 這種程式碼模式,包含範例和最佳實踐。`; return { messages: [ { role: 'user', content: { type: 'text', text: guide } } ] }; } case 'quick-wins': { const projectPath = args?.projectPath || '.'; return { messages: [ { role: 'user', content: { type: 'text', text: `請分析 "${projectPath}" 專案,找出「低風險、高效益」的快速改善機會。 優先尋找: 1. 可直接用原生 API 替換的小型工具函式庫(如 is-number, left-pad, object-assign) 2. var 宣告改為 let/const(無破壞性) 3. 已棄用但有簡單替代方案的 API 4. 已有原生支援的 polyfill 排除: - 需要大規模重構的建議 - 可能造成破壞性變更的建議 請使用 analyze_modernization 工具,然後篩選出符合「快速勝利」條件的建議。` } } ] }; } case 'analyze-pr': { const projectPath = args?.projectPath || '.'; const prDiff = args?.prDiff; const changedFiles = args?.changedFiles; // 構建檔案模式(如果提供了變更檔案列表) let includePatternsText = ''; if (changedFiles) { try { const files = typeof changedFiles === 'string' ? JSON.parse(changedFiles) : changedFiles; if (Array.isArray(files) && files.length > 0) { includePatternsText = `\n\n**注意**:請使用 analyze_modernization 工具時,將 includePatterns 參數設為:\n\`\`\`json\n${JSON.stringify(files, null, 2)}\n\`\`\`\n\n這樣可以只分析 PR 變更的檔案,而不是整個專案。`; } } catch (e) { // 忽略解析錯誤 } } let prDiffSection = ''; if (prDiff) { prDiffSection = `\n\n## PR Diff 內容\n\n以下是 PR 的程式碼變更:\n\n\`\`\`diff\n${prDiff}\n\`\`\`\n\n請仔細分析這些變更,找出可以優化的地方。`; } return { messages: [ { role: 'user', content: { type: 'text', text: `請分析 Git PR 的程式碼變更,整合規則式分析和 AI 分析,提供完整的現代化建議。 ## 分析步驟 ### 步驟 1:取得完整的 Web API 列表 首先,請使用 \`list_api_categories\` 工具取得所有可用的 Web API 類別列表。這將幫助你了解有哪些現代 Web API 可以使用。 ### 步驟 2:規則式分析(針對 PR 變更的檔案) 使用 \`analyze_modernization\` 工具分析 PR 變更的檔案${includePatternsText ? includePatternsText : '。如果提供了 changedFiles 參數,請只分析這些檔案;否則分析整個專案。'}${prDiffSection} ### 步驟 3:整合分析結果 結合以下資訊進行評估: 1. **規則式分析結果**:從 analyze_modernization 工具獲得的現代化建議 2. **Web API 列表**:從 list_api_categories 工具獲得的完整 API 類別 3. **PR Diff 內容**:實際的程式碼變更(如果提供) ### 步驟 4:提供綜合評估報告 請提供一份整合的分析報告,包含: #### 1. PR 變更摘要 - 這個 PR 做了什麼變更 - 變更的檔案和範圍 #### 2. 現代化建議(整合規則式分析) - **函式庫替換機會**:是否使用了可被原生 API 替代的函式庫(jQuery、Moment.js、Lodash 等) - **API 現代化機會**:是否使用了過時的 API(XMLHttpRequest、var、callback 等) - **語法現代化**:var → let/const、傳統 for 迴圈 → 陣列方法等 #### 3. Web API 優化建議(基於完整 API 列表) - 針對 PR 中的功能需求,推薦更適合的現代 Web API - 例如:如果 PR 涉及圖片懶加載,推薦使用 IntersectionObserver - 如果涉及尺寸監聽,推薦使用 ResizeObserver - 參考 list_api_categories 的結果,找出相關的 API 類別 #### 4. 瀏覽器相容性檢查 - 檢查建議的現代 API 是否需要 polyfill - 使用 \`check_browser_support\` 工具檢查關鍵 API 的相容性 - 提供 polyfill 建議和 CDN 連結 #### 5. 風險評估 - 評估變更的風險等級(low/medium/high) - 預估實施工時 - 是否為破壞性變更 #### 6. 優先順序建議 - 按照「低風險、高效益」排序建議 - 標記「快速勝利」項目(< 3 小時、低風險) - 標記需要進一步規劃的項目 ## 重要提示 - **只分析 PR 變更的檔案**:不要分析整個專案,專注於 PR 中的變更 - **整合兩種分析方式**:結合規則式分析(analyze_modernization)和 AI 分析(基於 PR diff) - **參考完整的 Web API 列表**:使用 list_api_categories 的結果來推薦最適合的現代 API - **提供具體的程式碼範例**:每個建議都應該包含「之前」和「之後」的程式碼對比 - **引用 MDN 文件**:使用 \`search_mdn\` 工具查詢相關 API 的文件,並在建議中附上連結 ## 專案路徑 專案路徑:\`${projectPath}\` 現在請開始執行分析步驟。` } } ] }; } default: throw new Error(`Unknown prompt: ${name}`); } }); } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('開發決策顧問 MCP Server 已啟動'); } } // 啟動伺服器 if (import.meta.url === `file://${process.argv[1]}`) { const server = new DevAdvisorServer(); server.run().catch((error) => { console.error('伺服器啟動失敗:', error); process.exit(1); }); } export { DevAdvisorServer };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mukiwu/dev-advisor-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server