UNPKG

autosnippet

Version:

Extract code patterns into a knowledge base for AI coding assistants

142 lines (141 loc) 5.32 kB
/** * Guard Report API 路由 * * 端点: * GET /api/v1/guard/report — 项目合规性报告(ComplianceReporter + Uncertainty) * GET /api/v1/guard/report/reverse — ReverseGuard 反向验证 * GET /api/v1/guard/report/coverage — CoverageAnalyzer 覆盖率矩阵 */ import express from 'express'; import { getServiceContainer } from '../../injection/ServiceContainer.js'; import { resolveProjectRoot } from '../../shared/resolveProjectRoot.js'; const router = express.Router(); /** * GET /api/v1/guard/report * 生成完整的合规性报告,含 uncertain/coverage/confidence * * Query params: * minScore — 最低通过分数 (默认 60) * maxErrors — 最大错误数 (默认 0) * maxFiles — 扫描文件上限 */ router.get('/', async (req, res) => { try { const container = getServiceContainer(); const complianceReporter = container.get('complianceReporter'); if (!complianceReporter) { res.status(503).json({ success: false, error: { code: 'SERVICE_UNAVAILABLE', message: 'ComplianceReporter not available' }, }); return; } const projectRoot = resolveProjectRoot(container); const qualityGate = { minScore: req.query.minScore ? Number(req.query.minScore) : undefined, maxErrors: req.query.maxErrors ? Number(req.query.maxErrors) : undefined, }; const maxFiles = req.query.maxFiles ? Number(req.query.maxFiles) : undefined; const report = await complianceReporter.generate(projectRoot, { qualityGate, maxFiles, }); res.json({ success: true, data: report }); } catch (err) { res.status(500).json({ success: false, error: { code: 'GUARD_REPORT_ERROR', message: err.message }, }); } }); /** * GET /api/v1/guard/report/reverse * ReverseGuard — Recipe→Code 反向验证 * * Query params: * maxFiles — 扫描文件上限 (默认 200) */ router.get('/reverse', async (req, res) => { try { const container = getServiceContainer(); const projectRoot = resolveProjectRoot(container); const { ReverseGuard } = await import('../../service/guard/ReverseGuard.js'); const { collectSourceFilesWithContent } = await import('../../service/guard/SourceFileCollector.js'); let reverseGuard; try { reverseGuard = container.get('reverseGuard'); } catch { reverseGuard = new ReverseGuard(container.get('knowledgeRepository'), container.get('codeEntityRepository'), container.get('recipeSourceRefRepository')); } const maxFiles = req.query.maxFiles ? Number(req.query.maxFiles) : 200; const projectFiles = await collectSourceFilesWithContent(projectRoot, { maxFiles }); const results = reverseGuard.auditAllRules(projectFiles); const drifts = reverseGuard.getDriftResults(results); res.json({ success: true, data: { totalRecipes: results.length, healthy: results.filter((r) => r.recommendation === 'healthy').length, investigate: results.filter((r) => r.recommendation === 'investigate').length, decay: results.filter((r) => r.recommendation === 'decay').length, drifts, allResults: results.map((r) => ({ recipeId: r.recipeId, title: r.title, recommendation: r.recommendation, signalCount: r.signals.length, })), }, }); } catch (err) { res.status(500).json({ success: false, error: { code: 'REVERSE_GUARD_ERROR', message: err.message }, }); } }); /** * GET /api/v1/guard/report/coverage * CoverageAnalyzer — 模块覆盖率矩阵 */ router.get('/coverage', async (_req, res) => { try { const container = getServiceContainer(); const { CoverageAnalyzer } = await import('../../service/guard/CoverageAnalyzer.js'); let analyzer; try { analyzer = container.get('coverageAnalyzer'); } catch { analyzer = new CoverageAnalyzer(container.get('knowledgeRepository'), container.get('guardViolationRepository')); } // 从 Panorama 或目录结构获取模块文件 const moduleFiles = new Map(); try { const panorama = container.get('panoramaService'); const overview = await panorama.getOverview(); if (overview?.modules) { for (const mod of overview.modules) { if (mod.files?.length > 0) { moduleFiles.set(mod.name, mod.files); } } } } catch { /* PanoramaService not available */ } const matrix = analyzer.analyze(moduleFiles); res.json({ success: true, data: matrix }); } catch (err) { res.status(500).json({ success: false, error: { code: 'COVERAGE_ANALYZER_ERROR', message: err.message }, }); } }); export default router;