cto-ai-cli 1.3.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/api/server.ts","../../src/engine/analyzer.ts","../../src/types/engine.ts","../../src/types/config.ts","../../src/engine/tokenizer.ts","../../src/engine/graph.ts","../../src/engine/risk.ts","../../src/engine/cache.ts","../../src/engine/selector.ts","../../src/govern/secrets.ts","../../src/engine/pruner.ts","../../src/engine/graph-utils.ts","../../src/engine/coverage.ts","../../src/engine/budget.ts","../../src/engine/score.ts","../../src/engine/benchmark.ts","../../src/engine/quality-benchmark.ts","../../src/interact/router.ts","../../src/interact/prompt.ts","../../src/engine/pr-context.ts","../../src/interact/orchestrator.ts","../../src/interact/estimator.ts","../../src/govern/audit.ts"],"sourcesContent":["import { createServer, IncomingMessage, ServerResponse } from 'node:http';\nimport { resolve } from 'node:path';\nimport { analyzeProject } from '../engine/analyzer.js';\nimport { getCachedAnalysis } from '../engine/cache.js';\nimport { selectContext } from '../engine/selector.js';\nimport { computeContextScore, renderContextScore } from '../engine/score.js';\nimport { runBenchmark } from '../engine/benchmark.js';\nimport { runQualityBenchmark } from '../engine/quality-benchmark.js';\nimport { generatePRContext } from '../engine/pr-context.js';\nimport { planInteraction } from '../interact/orchestrator.js';\n\n// ===== CTO Context-as-a-Service API =====\n//\n// REST API for the CTO engine. Deploy anywhere, integrate with anything.\n//\n// Endpoints:\n// POST /v1/analyze — Full project analysis\n// POST /v1/select — Optimal context selection for a task\n// POST /v1/score — Context Score™ (0-100)\n// POST /v1/benchmark — CTO vs naive vs random\n// POST /v1/quality — Quality benchmark (relevance, completeness, noise)\n// POST /v1/pr-context — PR-focused context from git diff\n// POST /v1/interact — Full pipeline: analyze → select → prompt → cost\n// GET /v1/health — Health check\n// GET /v1/openapi — OpenAPI spec\n\nconst API_VERSION = '1.0.0';\nconst DEFAULT_PORT = 3141; // pi\n\n// ===== AUTH =====\n\nfunction validateApiKey(req: IncomingMessage): boolean {\n const apiKey = process.env.CTO_API_KEY;\n if (!apiKey) return true; // No key configured = open (dev mode)\n\n const authRaw = req.headers['authorization'] ?? req.headers['x-api-key'];\n if (!authRaw) return false;\n const auth = Array.isArray(authRaw) ? authRaw[0] : authRaw;\n\n const token = auth.startsWith('Bearer ') ? auth.slice(7) : auth;\n return token === apiKey;\n}\n\n// ===== RATE LIMITING =====\n\nconst rateLimitWindow = 60_000; // 1 minute\nconst rateLimitMax = parseInt(process.env.CTO_RATE_LIMIT ?? '60', 10);\nconst requestCounts = new Map<string, { count: number; reset: number }>();\n\nfunction checkRateLimit(ip: string): boolean {\n const now = Date.now();\n const entry = requestCounts.get(ip);\n\n if (!entry || now > entry.reset) {\n requestCounts.set(ip, { count: 1, reset: now + rateLimitWindow });\n return true;\n }\n\n if (entry.count >= rateLimitMax) return false;\n entry.count++;\n return true;\n}\n\n// ===== HELPERS =====\n\nfunction getIP(req: IncomingMessage): string {\n return (req.headers['x-forwarded-for'] as string)?.split(',')[0]?.trim()\n ?? req.socket.remoteAddress\n ?? 'unknown';\n}\n\nasync function readBody(req: IncomingMessage): Promise<any> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on('data', (chunk) => chunks.push(chunk));\n req.on('end', () => {\n try {\n const body = Buffer.concat(chunks).toString('utf-8');\n resolve(body ? JSON.parse(body) : {});\n } catch {\n reject(new Error('Invalid JSON body'));\n }\n });\n req.on('error', reject);\n });\n}\n\nfunction json(res: ServerResponse, status: number, data: any): void {\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Api-Key',\n 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',\n 'X-CTO-Version': API_VERSION,\n });\n res.end(JSON.stringify(data));\n}\n\nfunction error(res: ServerResponse, status: number, message: string): void {\n json(res, status, { error: message, status });\n}\n\n// ===== ROUTE HANDLERS =====\n\nasync function handleAnalyze(body: any, res: ServerResponse): Promise<void> {\n const { path: projectPath } = body;\n if (!projectPath) return error(res, 400, 'Missing required field: path');\n\n const absPath = resolve(projectPath);\n const analysis = await getCachedAnalysis(absPath);\n\n json(res, 200, {\n project: analysis.projectName,\n files: analysis.totalFiles,\n tokens: analysis.totalTokens,\n stack: analysis.stack,\n risk: analysis.riskProfile.distribution,\n graph: {\n edges: analysis.graph.edges.length,\n hubs: analysis.graph.hubs.length,\n clusters: analysis.graph.clusters.length,\n orphans: analysis.graph.orphans.length,\n },\n analyzedAt: analysis.analyzedAt,\n });\n}\n\nasync function handleSelect(body: any, res: ServerResponse): Promise<void> {\n const { path: projectPath, task, budget } = body;\n if (!projectPath) return error(res, 400, 'Missing required field: path');\n if (!task) return error(res, 400, 'Missing required field: task');\n\n const absPath = resolve(projectPath);\n const analysis = await getCachedAnalysis(absPath);\n const selection = await selectContext({\n task,\n analysis,\n budget: budget ?? 50_000,\n });\n\n json(res, 200, {\n files: selection.files.map((f) => ({\n path: f.relativePath,\n tokens: f.tokens,\n pruneLevel: f.pruneLevel,\n riskScore: f.riskScore,\n reason: f.reason,\n })),\n totalTokens: selection.totalTokens,\n budget: selection.budget,\n usedPercent: selection.usedPercent,\n coverage: selection.coverage.score,\n riskScore: selection.riskScore,\n hash: selection.hash,\n });\n}\n\nasync function handleScore(body: any, res: ServerResponse): Promise<void> {\n const { path: projectPath, task, budget } = body;\n if (!projectPath) return error(res, 400, 'Missing required field: path');\n\n const absPath = resolve(projectPath);\n const analysis = await getCachedAnalysis(absPath);\n const score = await computeContextScore(\n analysis,\n task ?? 'general code review and refactoring',\n budget ?? 50_000,\n );\n\n json(res, 200, {\n overall: score.overall,\n grade: score.grade,\n dimensions: {\n efficiency: score.dimensions.efficiency.score,\n coverage: score.dimensions.coverage.score,\n riskControl: score.dimensions.riskControl.score,\n structure: score.dimensions.structure.score,\n governance: score.dimensions.governance.score,\n },\n comparison: score.comparison,\n insights: score.insights,\n meta: score.meta,\n });\n}\n\nasync function handleBenchmark(body: any, res: ServerResponse): Promise<void> {\n const { path: projectPath, task, budget } = body;\n if (!projectPath) return error(res, 400, 'Missing required field: path');\n\n const absPath = resolve(projectPath);\n const analysis = await getCachedAnalysis(absPath);\n const result = await runBenchmark(\n analysis,\n task ?? 'general code review and refactoring',\n budget ?? 50_000,\n );\n\n json(res, 200, result);\n}\n\nasync function handleQuality(body: any, res: ServerResponse): Promise<void> {\n const { path: projectPath, task, budget } = body;\n if (!projectPath) return error(res, 400, 'Missing required field: path');\n if (!task) return error(res, 400, 'Missing required field: task');\n\n const absPath = resolve(projectPath);\n const analysis = await getCachedAnalysis(absPath);\n const result = await runQualityBenchmark(analysis, task, budget ?? 50_000);\n\n json(res, 200, {\n strategies: result.strategies,\n comparison: result.comparison,\n verdict: result.verdict,\n promptTokens: {\n cto: result.prompts.cto.tokens,\n naive: result.prompts.naive.tokens,\n },\n });\n}\n\nasync function handlePRContext(body: any, res: ServerResponse): Promise<void> {\n const { path: projectPath, baseBranch, depth, includeTests } = body;\n if (!projectPath) return error(res, 400, 'Missing required field: path');\n\n const absPath = resolve(projectPath);\n const analysis = await getCachedAnalysis(absPath);\n const pr = await generatePRContext(analysis, {\n baseBranch: baseBranch ?? 'main',\n depth: depth ?? 2,\n includeTests: includeTests ?? false,\n });\n\n json(res, 200, {\n isGitRepo: pr.isGitRepo,\n baseBranch: pr.baseBranch,\n currentBranch: pr.currentBranch,\n changedFiles: pr.changedFiles,\n dependencyFiles: pr.dependencyFiles,\n totalChangedTokens: pr.totalChangedTokens,\n totalContextTokens: pr.totalContextTokens,\n riskSummary: pr.riskSummary,\n });\n}\n\nasync function handleInteract(body: any, res: ServerResponse): Promise<void> {\n const { path: projectPath, task, budget, model } = body;\n if (!projectPath) return error(res, 400, 'Missing required field: path');\n if (!task) return error(res, 400, 'Missing required field: task');\n\n const absPath = resolve(projectPath);\n const analysis = await getCachedAnalysis(absPath);\n const plan = await planInteraction({\n task,\n analysis,\n budget: budget ?? 50_000,\n model,\n });\n\n json(res, 200, {\n id: plan.id,\n task: plan.task,\n model: plan.model,\n context: {\n files: plan.context.files.length,\n totalTokens: plan.context.totalTokens,\n coverage: plan.context.coverage.score,\n riskScore: plan.context.riskScore,\n },\n prompt: {\n tokens: plan.prompt.totalTokens,\n sections: plan.prompt.sections.map((s) => s.id),\n rendered: plan.prompt.rendered,\n },\n cost: plan.cost,\n decisions: plan.decisions,\n });\n}\n\nfunction handleHealth(_body: any, res: ServerResponse): void {\n json(res, 200, {\n status: 'ok',\n version: API_VERSION,\n uptime: process.uptime(),\n rateLimit: {\n max: rateLimitMax,\n windowMs: rateLimitWindow,\n },\n });\n}\n\n// ===== OPENAPI SPEC =====\n\nfunction handleOpenAPI(_body: any, res: ServerResponse): void {\n json(res, 200, {\n openapi: '3.1.0',\n info: {\n title: 'CTO Context-as-a-Service API',\n version: API_VERSION,\n description: 'AI context optimization API. Analyzes codebases, scores context quality, selects optimal files.',\n },\n servers: [{ url: `http://localhost:${process.env.PORT ?? DEFAULT_PORT}` }],\n security: [{ apiKey: [] }],\n components: {\n securitySchemes: {\n apiKey: {\n type: 'apiKey',\n in: 'header',\n name: 'Authorization',\n description: 'Bearer token. Set CTO_API_KEY env var on server.',\n },\n },\n },\n paths: {\n '/v1/analyze': {\n post: {\n summary: 'Analyze a project',\n requestBody: { content: { 'application/json': { schema: { type: 'object', required: ['path'], properties: { path: { type: 'string', description: 'Absolute path to project' } } } } } },\n responses: { '200': { description: 'Project analysis summary' } },\n },\n },\n '/v1/select': {\n post: {\n summary: 'Select optimal context for a task',\n requestBody: { content: { 'application/json': { schema: { type: 'object', required: ['path', 'task'], properties: { path: { type: 'string' }, task: { type: 'string' }, budget: { type: 'number', default: 50000 } } } } } },\n responses: { '200': { description: 'Selected files with tokens, risk, coverage' } },\n },\n },\n '/v1/score': {\n post: {\n summary: 'Get Context Score™ (0-100)',\n requestBody: { content: { 'application/json': { schema: { type: 'object', required: ['path'], properties: { path: { type: 'string' }, task: { type: 'string' }, budget: { type: 'number' } } } } } },\n responses: { '200': { description: 'Context Score with dimensions and savings' } },\n },\n },\n '/v1/benchmark': {\n post: {\n summary: 'Run CTO vs naive vs random benchmark',\n requestBody: { content: { 'application/json': { schema: { type: 'object', required: ['path'], properties: { path: { type: 'string' }, task: { type: 'string' }, budget: { type: 'number' } } } } } },\n responses: { '200': { description: 'Three-way benchmark comparison' } },\n },\n },\n '/v1/quality': {\n post: {\n summary: 'Quality benchmark — relevance, completeness, noise',\n requestBody: { content: { 'application/json': { schema: { type: 'object', required: ['path', 'task'], properties: { path: { type: 'string' }, task: { type: 'string' }, budget: { type: 'number' } } } } } },\n responses: { '200': { description: 'Quality metrics for CTO vs naive vs random' } },\n },\n },\n '/v1/pr-context': {\n post: {\n summary: 'PR-focused context from git diff',\n requestBody: { content: { 'application/json': { schema: { type: 'object', required: ['path'], properties: { path: { type: 'string' }, baseBranch: { type: 'string', default: 'main' }, depth: { type: 'number', default: 2 } } } } } },\n responses: { '200': { description: 'Changed files, dependencies, risk summary' } },\n },\n },\n '/v1/interact': {\n post: {\n summary: 'Full pipeline: analyze → select → prompt → cost',\n requestBody: { content: { 'application/json': { schema: { type: 'object', required: ['path', 'task'], properties: { path: { type: 'string' }, task: { type: 'string' }, budget: { type: 'number' }, model: { type: 'string' } } } } } },\n responses: { '200': { description: 'Full interaction plan with prompt and cost' } },\n },\n },\n '/v1/health': {\n get: {\n summary: 'Health check',\n responses: { '200': { description: 'Server status' } },\n },\n },\n },\n });\n}\n\n// ===== ROUTER =====\n\nconst routes: Record<string, (body: any, res: ServerResponse) => void | Promise<void>> = {\n 'POST /v1/analyze': handleAnalyze,\n 'POST /v1/select': handleSelect,\n 'POST /v1/score': handleScore,\n 'POST /v1/benchmark': handleBenchmark,\n 'POST /v1/quality': handleQuality,\n 'POST /v1/pr-context': handlePRContext,\n 'POST /v1/interact': handleInteract,\n 'GET /v1/health': handleHealth,\n 'GET /v1/openapi': handleOpenAPI,\n 'GET /v1/openapi.json': handleOpenAPI,\n};\n\n// ===== SERVER =====\n\nexport function createAPIServer(): ReturnType<typeof createServer> {\n const server = createServer(async (req, res) => {\n // CORS preflight\n if (req.method === 'OPTIONS') {\n res.writeHead(204, {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Api-Key',\n 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',\n });\n return res.end();\n }\n\n const ip = getIP(req);\n const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);\n const routeKey = `${req.method} ${url.pathname}`;\n\n // Rate limiting\n if (!checkRateLimit(ip)) {\n return error(res, 429, 'Rate limit exceeded. Try again later.');\n }\n\n // Auth\n if (!validateApiKey(req)) {\n return error(res, 401, 'Unauthorized. Provide a valid API key via Authorization header.');\n }\n\n // Route\n const handler = routes[routeKey];\n if (!handler) {\n return error(res, 404, `Not found: ${routeKey}. GET /v1/openapi for docs.`);\n }\n\n try {\n const body = req.method === 'GET' ? {} : await readBody(req);\n await handler(body, res);\n } catch (err: any) {\n console.error(`[CTO API] Error on ${routeKey}:`, err.message);\n error(res, 500, err.message ?? 'Internal server error');\n }\n });\n\n return server;\n}\n\n// ===== MAIN (when run directly) =====\n\nconst port = parseInt(process.env.PORT ?? `${DEFAULT_PORT}`, 10);\nconst server = createAPIServer();\n\nserver.listen(port, () => {\n const keyStatus = process.env.CTO_API_KEY ? '🔒 API key required' : '🔓 Open (set CTO_API_KEY to secure)';\n console.log(`\n ╔══════════════════════════════════════════════╗\n ║ ║\n ║ ⚡ CTO Context-as-a-Service API v${API_VERSION} ║\n ║ ║\n ║ http://localhost:${port.toString().padEnd(25)}║\n ║ ${keyStatus.padEnd(42)} ║\n ║ Rate limit: ${rateLimitMax} req/min${''.padEnd(20)} ║\n ║ ║\n ║ GET /v1/health — Status ║\n ║ GET /v1/openapi — API docs ║\n ║ POST /v1/analyze — Analyze project ║\n ║ POST /v1/select — Select context ║\n ║ POST /v1/score — Context Score™ ║\n ║ POST /v1/benchmark — CTO vs naive ║\n ║ POST /v1/quality — Quality benchmark ║\n ║ POST /v1/pr-context — PR context ║\n ║ POST /v1/interact — Full pipeline ║\n ║ ║\n ╚══════════════════════════════════════════════╝\n`);\n});\n","import { readFile, readdir, stat } from 'node:fs/promises';\nimport { join, extname, relative, resolve, basename } from 'node:path';\nimport { createHash } from 'node:crypto';\nimport type {\n AnalyzedFile,\n FileKind,\n ProjectAnalysis,\n WalkEntry,\n WalkOptions,\n} from '../types/engine.js';\nimport { DEFAULT_RISK_WEIGHTS } from '../types/engine.js';\nimport type { CTOConfig } from '../types/config.js';\nimport { DEFAULT_CONFIG } from '../types/config.js';\nimport { estimateTokens, countTokensChars4 } from './tokenizer.js';\nimport { buildProjectGraph } from './graph.js';\nimport { scoreAllFiles } from './risk.js';\n\n// ===== FILE WALKING =====\n\nfunction matchesPattern(filename: string, patterns: string[]): boolean {\n for (const pattern of patterns) {\n if (pattern.startsWith('*.')) {\n const ext = pattern.slice(1);\n if (filename.endsWith(ext)) return true;\n } else if (filename === pattern) {\n return true;\n }\n }\n return false;\n}\n\nexport async function walkProject(\n rootPath: string,\n options: WalkOptions,\n): Promise<WalkEntry[]> {\n const results: WalkEntry[] = [];\n const { ignoreDirs, ignorePatterns, extensions, maxDepth = 20 } = options;\n const ignoreDirSet = new Set(ignoreDirs);\n\n async function walk(dir: string, depth: number): Promise<void> {\n if (depth > maxDepth) return;\n\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n const promises: Promise<void>[] = [];\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n\n if (entry.isDirectory()) {\n if (!ignoreDirSet.has(entry.name) && !entry.name.startsWith('.')) {\n promises.push(walk(fullPath, depth + 1));\n }\n } else if (entry.isFile()) {\n const ext = extname(entry.name).slice(1).toLowerCase();\n if (ext && extensions.includes(ext) && !matchesPattern(entry.name, ignorePatterns)) {\n promises.push(\n (async () => {\n const fileStat = await stat(fullPath).catch(() => null);\n if (!fileStat) return;\n\n let lines = 0;\n try {\n const content = await readFile(fullPath, 'utf-8');\n lines = content.split('\\n').length;\n } catch {\n lines = 0;\n }\n\n results.push({\n path: fullPath,\n relativePath: relative(rootPath, fullPath),\n extension: ext,\n size: fileStat.size,\n lastModified: fileStat.mtime,\n lines,\n });\n })(),\n );\n }\n }\n }\n\n await Promise.all(promises);\n }\n\n await walk(rootPath, 0);\n return results;\n}\n\n// ===== FILE KIND DETECTION =====\n\nconst TYPE_PATTERNS = [/types?\\//i, /\\.d\\.ts$/, /interfaces?\\//i];\nconst TEST_PATTERNS = [/\\.test\\.[jt]sx?$/, /\\.spec\\.[jt]sx?$/, /\\/__tests__\\//, /\\/tests?\\//];\nconst CONFIG_PATTERNS = [/\\.config\\.[jt]s$/, /rc\\.[jt]s$/, /\\.env/, /tsconfig/, /package\\.json$/, /\\.yml$/, /\\.yaml$/, /\\.toml$/];\nconst ENTRY_PATTERNS = [/^index\\.[jt]sx?$/, /^main\\.[jt]sx?$/, /^app\\.[jt]sx?$/, /^server\\.[jt]sx?$/];\n\nexport function classifyFileKind(relativePath: string): FileKind {\n const filename = basename(relativePath);\n\n if (TYPE_PATTERNS.some((p) => p.test(relativePath))) return 'type';\n if (TEST_PATTERNS.some((p) => p.test(relativePath))) return 'test';\n if (CONFIG_PATTERNS.some((p) => p.test(relativePath) || p.test(filename))) return 'config';\n if (ENTRY_PATTERNS.some((p) => p.test(filename))) return 'entry';\n return 'source';\n}\n\n// ===== STACK DETECTION =====\n\nexport function detectStack(files: WalkEntry[]): string[] {\n const stack: string[] = [];\n const extensions = new Set(files.map((f) => f.extension));\n const paths = files.map((f) => f.relativePath.toLowerCase());\n\n if (extensions.has('ts') || extensions.has('tsx')) stack.push('TypeScript');\n else if (extensions.has('js') || extensions.has('jsx')) stack.push('JavaScript');\n if (extensions.has('py')) stack.push('Python');\n if (extensions.has('go')) stack.push('Go');\n if (extensions.has('rs')) stack.push('Rust');\n if (extensions.has('java')) stack.push('Java');\n if (extensions.has('kt')) stack.push('Kotlin');\n if (extensions.has('rb')) stack.push('Ruby');\n if (extensions.has('php')) stack.push('PHP');\n if (extensions.has('cs')) stack.push('C#');\n if (extensions.has('c') || extensions.has('cpp')) stack.push('C/C++');\n\n if (paths.some((p) => p.includes('next.config'))) stack.push('Next.js');\n if (paths.some((p) => p.includes('nuxt.config'))) stack.push('Nuxt');\n if (paths.some((p) => p.includes('angular.json'))) stack.push('Angular');\n\n return stack;\n}\n\n// ===== MAIN ANALYSIS PIPELINE =====\n\nexport async function analyzeProject(\n projectPath: string,\n config?: Partial<CTOConfig>,\n): Promise<ProjectAnalysis> {\n const absPath = resolve(projectPath);\n const projectName = basename(absPath);\n const mergedConfig = mergeConfig(DEFAULT_CONFIG, config);\n\n // 1. Walk project files\n const allExtensions = [\n ...mergedConfig.analysis.extensions.code,\n ...mergedConfig.analysis.extensions.config,\n ...mergedConfig.analysis.extensions.docs,\n ];\n\n const walkEntries = await walkProject(absPath, {\n ignoreDirs: mergedConfig.analysis.ignore.dirs,\n ignorePatterns: mergedConfig.analysis.ignore.patterns,\n extensions: allExtensions,\n maxDepth: mergedConfig.analysis.maxDepth,\n });\n\n // 2. Estimate tokens and build initial AnalyzedFile[]\n const tokenMethod = mergedConfig.tokens.method;\n const files: AnalyzedFile[] = [];\n\n for (const entry of walkEntries) {\n let tokens: number;\n if (tokenMethod === 'tiktoken') {\n try {\n const content = await readFile(entry.path, 'utf-8');\n tokens = estimateTokens(content, entry.size, 'tiktoken');\n } catch {\n tokens = countTokensChars4(entry.size);\n }\n } else {\n tokens = countTokensChars4(entry.size);\n }\n\n files.push({\n path: entry.path,\n relativePath: entry.relativePath,\n extension: entry.extension,\n size: entry.size,\n tokens,\n lines: entry.lines,\n lastModified: entry.lastModified,\n kind: classifyFileKind(entry.relativePath),\n\n // Graph data — populated by graph analysis\n imports: [],\n importedBy: [],\n isHub: false,\n complexity: 0,\n\n // Risk data — populated by risk analysis\n riskScore: 0,\n riskFactors: [],\n exclusionImpact: 'none',\n });\n }\n\n // 3. Build dependency graph (AST-based, best-effort)\n const graph = buildProjectGraph(absPath, files);\n\n // 4. Enrich files with graph data\n for (const file of files) {\n const nodeImports: string[] = [];\n const nodeImportedBy: string[] = [];\n\n for (const edge of graph.edges) {\n if (edge.from === file.relativePath) nodeImports.push(edge.to);\n if (edge.to === file.relativePath) nodeImportedBy.push(edge.from);\n }\n\n file.imports = nodeImports;\n file.importedBy = nodeImportedBy;\n file.isHub = graph.hubs.some((h) => h.relativePath === file.relativePath);\n }\n\n // 5. Score risk for all files\n const riskWeights = mergedConfig.risk.weights;\n scoreAllFiles(files, graph, riskWeights);\n\n // 6. Build risk profile\n const riskProfile = {\n distribution: {\n critical: files.filter((f) => f.riskScore >= 80).length,\n high: files.filter((f) => f.riskScore >= 60 && f.riskScore < 80).length,\n medium: files.filter((f) => f.riskScore >= 30 && f.riskScore < 60).length,\n low: files.filter((f) => f.riskScore < 30).length,\n },\n topRiskFiles: [...files].sort((a, b) => b.riskScore - a.riskScore).slice(0, 10),\n overallComplexity: files.length > 0\n ? files.reduce((s, f) => s + f.complexity, 0) / files.length\n : 0,\n };\n\n // 7. Build analysis hash for determinism\n const totalTokens = files.reduce((s, f) => s + f.tokens, 0);\n const hashInput = files\n .map((f) => `${f.relativePath}:${f.tokens}:${f.riskScore}`)\n .sort()\n .join('|');\n const hash = createHash('sha256').update(hashInput).digest('hex').substring(0, 16);\n\n const stack = detectStack(walkEntries);\n\n return {\n projectPath: absPath,\n projectName,\n analyzedAt: new Date(),\n hash,\n files,\n totalFiles: files.length,\n totalTokens,\n graph,\n riskProfile,\n stack,\n tokenMethod,\n };\n}\n\n// ===== CONFIG MERGE =====\n\nfunction mergeConfig(base: CTOConfig, overrides?: Partial<CTOConfig>): CTOConfig {\n if (!overrides) return base;\n\n return {\n ...base,\n ...overrides,\n analysis: {\n ...base.analysis,\n ...overrides.analysis,\n extensions: {\n ...base.analysis.extensions,\n ...overrides.analysis?.extensions,\n },\n ignore: {\n ...base.analysis.ignore,\n ...overrides.analysis?.ignore,\n },\n },\n risk: {\n ...base.risk,\n ...overrides.risk,\n weights: {\n ...base.risk.weights,\n ...overrides.risk?.weights,\n },\n },\n interaction: {\n ...base.interaction,\n ...overrides.interaction,\n },\n tokens: {\n ...base.tokens,\n ...overrides.tokens,\n },\n governance: {\n ...base.governance,\n ...overrides.governance,\n },\n };\n}\n","// ===== Layer 1: Context Intelligence Engine Types =====\n\n// ===== FILE ANALYSIS =====\n\nexport interface AnalyzedFile {\n path: string;\n relativePath: string;\n extension: string;\n size: number;\n tokens: number;\n lines: number;\n lastModified: Date;\n kind: FileKind;\n\n // Graph data (populated after graph analysis)\n imports: string[];\n importedBy: string[];\n isHub: boolean;\n complexity: number;\n\n // Risk data (populated after risk analysis)\n riskScore: number;\n riskFactors: RiskFactor[];\n exclusionImpact: ExclusionImpact;\n}\n\nexport type FileKind = 'source' | 'type' | 'test' | 'config' | 'entry' | 'asset';\nexport type ExclusionImpact = 'critical' | 'high' | 'medium' | 'low' | 'none';\n\n// ===== PROJECT ANALYSIS =====\n\nexport interface ProjectAnalysis {\n projectPath: string;\n projectName: string;\n analyzedAt: Date;\n hash: string;\n\n files: AnalyzedFile[];\n totalFiles: number;\n totalTokens: number;\n\n graph: ProjectGraph;\n riskProfile: RiskProfile;\n stack: string[];\n tokenMethod: 'chars4' | 'tiktoken';\n}\n\n// ===== DEPENDENCY GRAPH =====\n\nexport interface ProjectGraph {\n nodes: string[];\n edges: GraphEdge[];\n hubs: HubNode[];\n leaves: string[];\n orphans: string[];\n clusters: FileCluster[];\n}\n\nexport interface GraphEdge {\n from: string;\n to: string;\n type: 'import' | 'export' | 're-export';\n}\n\nexport interface HubNode {\n relativePath: string;\n dependents: number;\n dependencies: number;\n score: number;\n}\n\nexport interface FileCluster {\n id: string;\n name: string;\n files: string[];\n totalTokens: number;\n internalEdges: number;\n externalEdges: number;\n cohesion: number;\n}\n\n// ===== RISK MODEL =====\n\nexport interface RiskProfile {\n distribution: {\n critical: number;\n high: number;\n medium: number;\n low: number;\n };\n topRiskFiles: AnalyzedFile[];\n overallComplexity: number;\n}\n\nexport interface RiskFactor {\n type: RiskFactorType;\n score: number;\n weight: number;\n detail: string;\n}\n\nexport type RiskFactorType =\n | 'hub'\n | 'type-provider'\n | 'complexity'\n | 'recency'\n | 'config'\n | 'churn';\n\nexport interface RiskWeights {\n hub: number;\n typeProvider: number;\n complexity: number;\n recency: number;\n config: number;\n churn: number;\n}\n\nexport const DEFAULT_RISK_WEIGHTS: RiskWeights = {\n hub: 30,\n typeProvider: 25,\n complexity: 15,\n recency: 15,\n config: 10,\n churn: 5,\n};\n\n// ===== CONTEXT COVERAGE =====\n\nexport interface CoverageResult {\n score: number;\n relevantFiles: string[];\n includedRelevant: string[];\n missingRelevant: string[];\n missingCritical: string[];\n explanation: string;\n}\n\n// ===== CONTEXT SELECTION =====\n\nexport interface ContextSelection {\n files: SelectedFile[];\n totalTokens: number;\n budget: number;\n usedPercent: number;\n\n coverage: CoverageResult;\n riskScore: number;\n deterministic: boolean;\n hash: string;\n\n decisions: SelectionDecision[];\n}\n\nexport interface SelectedFile {\n relativePath: string;\n tokens: number;\n originalTokens: number;\n pruneLevel: PruneLevel;\n riskScore: number;\n reason: string;\n}\n\nexport type PruneLevel = 'full' | 'signatures' | 'skeleton' | 'excluded';\n\nexport interface SelectionDecision {\n file: string;\n action: 'include-full' | 'include-signatures' | 'include-skeleton' | 'exclude';\n reason: string;\n alternatives?: string;\n}\n\n// ===== BUDGET =====\n\nexport interface BudgetPlan {\n budget: number;\n used: number;\n remaining: number;\n fillPercent: number;\n files: BudgetEntry[];\n}\n\nexport interface BudgetEntry {\n relativePath: string;\n originalTokens: number;\n allocatedTokens: number;\n pruneLevel: PruneLevel;\n included: boolean;\n reason: string;\n}\n\n// ===== PRUNING =====\n\nexport interface PrunedContent {\n relativePath: string;\n originalTokens: number;\n prunedTokens: number;\n pruneLevel: PruneLevel;\n content: string;\n savingsPercent: number;\n}\n\n// ===== WALKER =====\n\nexport interface WalkEntry {\n path: string;\n relativePath: string;\n extension: string;\n size: number;\n lastModified: Date;\n lines: number;\n}\n\nexport interface WalkOptions {\n ignoreDirs: string[];\n ignorePatterns: string[];\n extensions: string[];\n maxDepth?: number;\n}\n","// ===== Configuration Types =====\n\nimport type { RiskWeights } from './engine.js';\n\nexport interface CTOConfig {\n version: string;\n\n analysis: {\n extensions: {\n code: string[];\n config: string[];\n docs: string[];\n };\n ignore: {\n dirs: string[];\n patterns: string[];\n };\n maxDepth: number;\n };\n\n risk: {\n weights: RiskWeights;\n };\n\n interaction: {\n defaultBudget: number;\n defaultModel: string;\n };\n\n tokens: {\n method: 'chars4' | 'tiktoken';\n };\n\n governance: {\n auditEnabled: boolean;\n secretDetection: boolean;\n retentionDays: number;\n };\n}\n\nexport const DEFAULT_CONFIG: CTOConfig = {\n version: '2.0',\n\n analysis: {\n extensions: {\n code: ['ts', 'tsx', 'js', 'jsx', 'py', 'go', 'rs', 'java', 'kt', 'rb', 'php', 'c', 'cpp', 'h', 'hpp', 'cs'],\n config: ['json', 'yml', 'yaml', 'toml'],\n docs: ['md', 'txt', 'rst'],\n },\n ignore: {\n dirs: ['node_modules', 'dist', 'build', '.git', 'coverage', '__pycache__', '.next', 'vendor', '.cto'],\n patterns: ['*.min.js', '*.map', '*.lock', '*.generated.*'],\n },\n maxDepth: 20,\n },\n\n risk: {\n weights: {\n hub: 30,\n typeProvider: 25,\n complexity: 15,\n recency: 15,\n config: 10,\n churn: 5,\n },\n },\n\n interaction: {\n defaultBudget: 50_000,\n defaultModel: 'claude-sonnet-4',\n },\n\n tokens: {\n method: 'chars4',\n },\n\n governance: {\n auditEnabled: true,\n secretDetection: true,\n retentionDays: 90,\n },\n};\n","import { encodingForModel } from 'js-tiktoken';\nimport { readFile, stat } from 'node:fs/promises';\n\nconst CHARS_PER_TOKEN = 4;\n\nlet encoder: ReturnType<typeof encodingForModel> | null = null;\n\nfunction getEncoder() {\n if (!encoder) {\n encoder = encodingForModel('claude-3-5-sonnet-20241022' as Parameters<typeof encodingForModel>[0]);\n }\n return encoder;\n}\n\nexport function countTokensTiktoken(text: string): number {\n try {\n const enc = getEncoder();\n const tokens = enc.encode(text);\n return tokens.length;\n } catch {\n return Math.ceil(text.length / CHARS_PER_TOKEN);\n }\n}\n\nexport function countTokensChars4(sizeInBytes: number): number {\n return Math.ceil(sizeInBytes / CHARS_PER_TOKEN);\n}\n\nexport function estimateTokens(\n content: string,\n sizeInBytes: number,\n method: 'chars4' | 'tiktoken' = 'chars4',\n): number {\n if (method === 'tiktoken') {\n return countTokensTiktoken(content);\n }\n return countTokensChars4(sizeInBytes);\n}\n\nexport async function estimateFileTokens(\n filePath: string,\n method: 'chars4' | 'tiktoken' = 'chars4',\n): Promise<number> {\n if (method === 'chars4') {\n const s = await stat(filePath);\n return countTokensChars4(s.size);\n }\n\n try {\n const content = await readFile(filePath, 'utf-8');\n return countTokensTiktoken(content);\n } catch {\n const s = await stat(filePath);\n return countTokensChars4(s.size);\n }\n}\n\nexport function freeEncoder(): void {\n encoder = null;\n}\n","import { Project, SyntaxKind, type SourceFile, type Node } from 'ts-morph';\nimport { resolve, relative, dirname, join, basename } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport type {\n AnalyzedFile,\n ProjectGraph,\n GraphEdge,\n HubNode,\n FileCluster,\n} from '../types/engine.js';\n\nconst TS_EXTENSIONS = new Set(['ts', 'tsx', 'js', 'jsx', 'mts', 'mjs', 'cts', 'cjs']);\n\n// ===== PROJECT CREATION =====\n\nexport function createProject(projectPath: string, filePaths: string[]): Project {\n const tsConfigPath = join(projectPath, 'tsconfig.json');\n const hasTsConfig = existsSync(tsConfigPath);\n\n const project = new Project({\n tsConfigFilePath: hasTsConfig ? tsConfigPath : undefined,\n skipAddingFilesFromTsConfig: true,\n compilerOptions: hasTsConfig\n ? undefined\n : {\n allowJs: true,\n jsx: 4 as any, // JsxEmit.ReactJSX\n esModuleInterop: true,\n moduleResolution: 100 as any, // Bundler\n },\n });\n\n const tsFiles = filePaths.filter((f) => {\n const ext = f.split('.').pop()?.toLowerCase() ?? '';\n return TS_EXTENSIONS.has(ext);\n });\n\n for (const filePath of tsFiles) {\n try {\n project.addSourceFileAtPath(filePath);\n } catch {\n // skip files that can't be parsed\n }\n }\n\n return project;\n}\n\n// ===== DEPENDENCY GRAPH =====\n\nexport function buildProjectGraph(\n projectPath: string,\n files: AnalyzedFile[],\n): ProjectGraph {\n const absPath = resolve(projectPath);\n\n const tsFiles = files\n .filter((f) => TS_EXTENSIONS.has(f.extension))\n .map((f) => f.path);\n\n if (tsFiles.length === 0) {\n return emptyGraph(files);\n }\n\n let project: Project;\n try {\n project = createProject(projectPath, tsFiles);\n } catch {\n return emptyGraph(files);\n }\n\n const edges: GraphEdge[] = [];\n const nodeSet = new Set<string>();\n\n for (const sourceFile of project.getSourceFiles()) {\n const fromRel = relative(absPath, sourceFile.getFilePath());\n if (fromRel.startsWith('..') || fromRel.includes('node_modules')) continue;\n nodeSet.add(fromRel);\n\n // Imports\n for (const imp of sourceFile.getImportDeclarations()) {\n const moduleSpecifier = imp.getModuleSpecifierValue();\n const resolved = resolveImport(sourceFile, moduleSpecifier, absPath);\n if (resolved) {\n nodeSet.add(resolved);\n edges.push({ from: fromRel, to: resolved, type: 'import' });\n }\n }\n\n // Re-exports\n for (const exp of sourceFile.getExportDeclarations()) {\n const moduleSpecifier = exp.getModuleSpecifierValue();\n if (moduleSpecifier) {\n const resolved = resolveImport(sourceFile, moduleSpecifier, absPath);\n if (resolved) {\n nodeSet.add(resolved);\n edges.push({ from: fromRel, to: resolved, type: 're-export' });\n }\n }\n }\n }\n\n const nodes = Array.from(nodeSet);\n\n // Calculate import counts\n const importedByCount = new Map<string, number>();\n const importCount = new Map<string, number>();\n\n for (const edge of edges) {\n importedByCount.set(edge.to, (importedByCount.get(edge.to) ?? 0) + 1);\n importCount.set(edge.from, (importCount.get(edge.from) ?? 0) + 1);\n }\n\n // Identify hubs using normalized in-degree centrality (Freeman, 1978).\n // centrality = in-degree / (N - 1), then combined with out-degree for a\n // \"betweenness-lite\" score: score = (in-degree × 2 + out-degree) / (N - 1 + 1)\n // This normalizes by graph size so hub detection is consistent across projects.\n const N = Math.max(nodes.length, 1);\n const hubs: HubNode[] = nodes\n .map((node) => {\n const inDeg = importedByCount.get(node) ?? 0;\n const outDeg = importCount.get(node) ?? 0;\n // Normalized centrality score (0-100 scale)\n const centrality = N > 1 ? (inDeg / (N - 1)) * 100 : 0;\n const score = Math.round(centrality + outDeg * (100 / (2 * N)));\n return {\n relativePath: node,\n dependents: inDeg,\n dependencies: outDeg,\n score: Math.min(100, score),\n };\n })\n .filter((h) => h.dependents >= 3 || h.score >= 15)\n .sort((a, b) => b.score - a.score);\n\n // Identify leaves (files that import but are not imported by anyone)\n const leaves = nodes.filter(\n (node) => (importedByCount.get(node) ?? 0) === 0 && (importCount.get(node) ?? 0) > 0,\n );\n\n // Identify orphans (files with no connections at all)\n const connectedNodes = new Set<string>();\n for (const edge of edges) {\n connectedNodes.add(edge.from);\n connectedNodes.add(edge.to);\n }\n const allFileNodes = new Set(files.map((f) => f.relativePath));\n const orphans = Array.from(allFileNodes).filter((n) => !connectedNodes.has(n));\n\n // Detect clusters using Union-Find for true connected components,\n // then refine with directory grouping for naming.\n const clusters = detectClusters(nodes, edges, files);\n\n // Enrich files with complexity (AST-based)\n enrichComplexity(project, absPath, files);\n\n return { nodes, edges, hubs, leaves, orphans, clusters };\n}\n\n// ===== CLUSTER DETECTION (Union-Find + directory naming) =====\n\nclass UnionFind {\n parent: Map<string, string>;\n rank: Map<string, number>;\n\n constructor(nodes: string[]) {\n this.parent = new Map();\n this.rank = new Map();\n for (const n of nodes) {\n this.parent.set(n, n);\n this.rank.set(n, 0);\n }\n }\n\n find(x: string): string {\n const p = this.parent.get(x);\n if (p === undefined) return x;\n if (p !== x) {\n this.parent.set(x, this.find(p)); // path compression\n }\n return this.parent.get(x)!;\n }\n\n union(a: string, b: string): void {\n const ra = this.find(a);\n const rb = this.find(b);\n if (ra === rb) return;\n const rankA = this.rank.get(ra) ?? 0;\n const rankB = this.rank.get(rb) ?? 0;\n if (rankA < rankB) {\n this.parent.set(ra, rb);\n } else if (rankA > rankB) {\n this.parent.set(rb, ra);\n } else {\n this.parent.set(rb, ra);\n this.rank.set(ra, rankA + 1);\n }\n }\n}\n\nfunction detectClusters(\n nodes: string[],\n edges: GraphEdge[],\n files: AnalyzedFile[],\n): FileCluster[] {\n // 1. Build connected components using Union-Find (O(E × α(V)))\n const uf = new UnionFind(nodes);\n for (const edge of edges) {\n uf.union(edge.from, edge.to);\n }\n\n // 2. Group by component root\n const components = new Map<string, string[]>();\n for (const node of nodes) {\n const root = uf.find(node);\n if (!components.has(root)) components.set(root, []);\n components.get(root)!.push(node);\n }\n\n // 3. For each component, derive a human-readable name from common directory prefix\n const tokenMap = new Map(files.map((f) => [f.relativePath, f.tokens]));\n const clusters: FileCluster[] = [];\n\n for (const [, groupFiles] of components) {\n if (groupFiles.length < 2) continue;\n\n // Find common directory prefix for naming\n const name = commonPrefix(groupFiles);\n const fileSet = new Set(groupFiles);\n let internalEdges = 0;\n let externalEdges = 0;\n\n for (const edge of edges) {\n const fromIn = fileSet.has(edge.from);\n const toIn = fileSet.has(edge.to);\n if (fromIn && toIn) internalEdges++;\n else if (fromIn || toIn) externalEdges++;\n }\n\n const totalEdges = internalEdges + externalEdges;\n const cohesion = totalEdges > 0 ? internalEdges / totalEdges : 0;\n const totalTokens = groupFiles.reduce((s, f) => s + (tokenMap.get(f) ?? 0), 0);\n\n clusters.push({\n id: name.replace(/[^a-zA-Z0-9]/g, '-') || `cluster-${clusters.length}`,\n name: name || `cluster-${clusters.length}`,\n files: groupFiles,\n totalTokens,\n internalEdges,\n externalEdges,\n cohesion: Math.round(cohesion * 100) / 100,\n });\n }\n\n return clusters.sort((a, b) => b.files.length - a.files.length);\n}\n\nfunction commonPrefix(paths: string[]): string {\n if (paths.length === 0) return '';\n const parts = paths.map((p) => p.split('/'));\n const prefix: string[] = [];\n for (let i = 0; i < parts[0].length - 1; i++) {\n const segment = parts[0][i];\n if (parts.every((p) => p[i] === segment)) {\n prefix.push(segment);\n } else break;\n }\n return prefix.join('/') || parts[0][0];\n}\n\n// ===== COMPLEXITY ANALYSIS =====\n\nfunction enrichComplexity(\n project: Project,\n absPath: string,\n files: AnalyzedFile[],\n): void {\n const fileMap = new Map(files.map((f) => [f.relativePath, f]));\n\n for (const sourceFile of project.getSourceFiles()) {\n const relPath = relative(absPath, sourceFile.getFilePath());\n if (relPath.startsWith('..') || relPath.includes('node_modules')) continue;\n\n const file = fileMap.get(relPath);\n if (!file) continue;\n\n let totalComplexity = 0;\n\n // Function declarations\n for (const func of sourceFile.getFunctions()) {\n totalComplexity += calculateCyclomaticComplexity(func);\n }\n\n // Class methods\n for (const cls of sourceFile.getClasses()) {\n for (const method of cls.getMethods()) {\n totalComplexity += calculateCyclomaticComplexity(method);\n }\n }\n\n // Arrow functions assigned to variables\n for (const varDecl of sourceFile.getVariableDeclarations()) {\n const init = varDecl.getInitializer();\n if (init && (init.getKind() === SyntaxKind.ArrowFunction || init.getKind() === SyntaxKind.FunctionExpression)) {\n totalComplexity += calculateCyclomaticComplexity(init);\n }\n }\n\n file.complexity = Math.max(1, totalComplexity);\n }\n}\n\nfunction calculateCyclomaticComplexity(node: Node): number {\n let complexity = 1;\n\n node.forEachDescendant((descendant) => {\n switch (descendant.getKind()) {\n case SyntaxKind.IfStatement:\n case SyntaxKind.ConditionalExpression:\n case SyntaxKind.ForStatement:\n case SyntaxKind.ForInStatement:\n case SyntaxKind.ForOfStatement:\n case SyntaxKind.WhileStatement:\n case SyntaxKind.DoStatement:\n case SyntaxKind.CaseClause:\n case SyntaxKind.CatchClause:\n complexity++;\n break;\n case SyntaxKind.BinaryExpression: {\n // FIX: Check the operator token kind directly instead of getText()\n // to avoid double-counting nested logical expressions.\n // getText() on `a && (b || c)` returns the full text including\n // the inner `||`, which would match both operators from the outer node.\n const opToken = (descendant as any).getOperatorToken?.();\n if (opToken) {\n const kind = opToken.getKind();\n if (\n kind === SyntaxKind.AmpersandAmpersandToken ||\n kind === SyntaxKind.BarBarToken ||\n kind === SyntaxKind.QuestionQuestionToken\n ) {\n complexity++;\n }\n }\n break;\n }\n }\n });\n\n return complexity;\n}\n\n// ===== IMPORT RESOLUTION =====\n\nfunction resolveImport(\n sourceFile: SourceFile,\n moduleSpecifier: string,\n projectRoot: string,\n): string | null {\n if (!moduleSpecifier.startsWith('.')) return null;\n\n const sourceDir = dirname(sourceFile.getFilePath());\n const basePath = resolve(sourceDir, moduleSpecifier);\n\n const extensions = ['.ts', '.tsx', '.js', '.jsx', '/index.ts', '/index.tsx', '/index.js', '/index.jsx'];\n\n for (const ext of extensions) {\n const candidate = basePath.endsWith(ext) ? basePath : basePath + ext;\n if (existsSync(candidate)) {\n const rel = relative(projectRoot, candidate);\n if (!rel.startsWith('..')) return rel;\n }\n }\n\n // .js → .ts resolution\n if (moduleSpecifier.endsWith('.js')) {\n const tsPath = basePath.replace(/\\.js$/, '.ts');\n if (existsSync(tsPath)) {\n const rel = relative(projectRoot, tsPath);\n if (!rel.startsWith('..')) return rel;\n }\n }\n\n return null;\n}\n\n// ===== HELPERS =====\n\nfunction emptyGraph(files: AnalyzedFile[]): ProjectGraph {\n return {\n nodes: files.map((f) => f.relativePath),\n edges: [],\n hubs: [],\n leaves: [],\n orphans: files.map((f) => f.relativePath),\n clusters: [],\n };\n}\n","import type {\n AnalyzedFile,\n RiskFactor,\n RiskFactorType,\n RiskWeights,\n ExclusionImpact,\n ProjectGraph,\n} from '../types/engine.js';\nimport { DEFAULT_RISK_WEIGHTS } from '../types/engine.js';\n\n// ===== RISK SCORING ENGINE =====\n//\n// Each file gets a riskScore ∈ [0, 100] representing the risk of EXCLUDING it\n// from AI context. Higher score = more dangerous to exclude.\n//\n// riskScore(file) = Σ(factor.score × factor.weight) / Σ(factor.weight)\n\nexport function scoreAllFiles(\n files: AnalyzedFile[],\n graph: ProjectGraph,\n weights: RiskWeights = DEFAULT_RISK_WEIGHTS,\n): void {\n // Pre-compute type provider map: files that export types used by others\n const typeProviderUsage = computeTypeProviderUsage(files, graph);\n\n for (const file of files) {\n const factors = computeRiskFactors(file, graph, typeProviderUsage, weights);\n file.riskFactors = factors;\n file.riskScore = computeWeightedScore(factors);\n file.exclusionImpact = scoreToImpact(file.riskScore);\n }\n}\n\nexport function scoreFile(\n file: AnalyzedFile,\n graph: ProjectGraph,\n weights: RiskWeights = DEFAULT_RISK_WEIGHTS,\n): number {\n const typeProviderUsage = computeTypeProviderUsage([file], graph);\n const factors = computeRiskFactors(file, graph, typeProviderUsage, weights);\n file.riskFactors = factors;\n file.riskScore = computeWeightedScore(factors);\n file.exclusionImpact = scoreToImpact(file.riskScore);\n return file.riskScore;\n}\n\n// ===== FACTOR COMPUTATION =====\n\nfunction computeRiskFactors(\n file: AnalyzedFile,\n graph: ProjectGraph,\n typeProviderUsage: Map<string, number>,\n weights: RiskWeights,\n): RiskFactor[] {\n const factors: RiskFactor[] = [];\n\n // 1. Hub factor — how many files depend on this file\n factors.push(computeHubFactor(file, weights.hub));\n\n // 2. Type provider factor — exports types used by other files\n factors.push(computeTypeProviderFactor(file, typeProviderUsage, weights.typeProvider));\n\n // 3. Complexity factor — cyclomatic complexity\n factors.push(computeComplexityFactor(file, weights.complexity));\n\n // 4. Recency factor — how recently modified\n factors.push(computeRecencyFactor(file, weights.recency));\n\n // 5. Config factor — is it a config or entry point\n factors.push(computeConfigFactor(file, weights.config));\n\n // 6. Churn factor — based on complexity as proxy (git integration deferred)\n factors.push(computeChurnFactor(file, weights.churn));\n\n return factors;\n}\n\nfunction computeHubFactor(file: AnalyzedFile, weight: number): RiskFactor {\n const dependents = file.importedBy.length;\n\n // Logarithmic scaling: score = min(100, 100 × log₂(1 + dependents) / log₂(1 + K))\n // K=12 means 12 dependents → score 100. Based on information theory:\n // each doubling of dependents adds equal marginal risk.\n const K = 12;\n const score = dependents === 0\n ? 0\n : Math.min(100, Math.round(100 * Math.log2(1 + dependents) / Math.log2(1 + K)));\n\n const detail = dependents === 0\n ? 'No dependents'\n : `Hub: ${dependents} file(s) depend on this (score ${score}/100)`;\n\n return { type: 'hub', score, weight, detail };\n}\n\nfunction computeTypeProviderFactor(\n file: AnalyzedFile,\n usage: Map<string, number>,\n weight: number,\n): RiskFactor {\n const isTypeFile = file.kind === 'type';\n const consumers = usage.get(file.relativePath) ?? 0;\n\n let score: number;\n let detail: string;\n\n if (isTypeFile && consumers >= 4) {\n score = 100;\n detail = `Type provider: used by ${consumers} files (critical type source)`;\n } else if (isTypeFile && consumers >= 1) {\n score = 50;\n detail = `Type provider: used by ${consumers} files`;\n } else if (isTypeFile) {\n score = 30;\n detail = 'Type file (no detected consumers)';\n } else {\n score = 0;\n detail = 'Not a type provider';\n }\n\n return { type: 'type-provider', score, weight, detail };\n}\n\nfunction computeComplexityFactor(file: AnalyzedFile, weight: number): RiskFactor {\n const c = file.complexity;\n\n // Logarithmic scaling: score = min(100, 100 × ln(1 + c) / ln(1 + K))\n // K=30 means complexity 30 → score 100. ln provides diminishing returns\n // for very complex files (consistent with McCabe 1976 thresholds).\n const K = 30;\n const score = Math.min(100, Math.round(100 * Math.log(1 + c) / Math.log(1 + K)));\n\n const detail = c >= 30\n ? `Very high complexity: ${c} (AI needs full context)`\n : c >= 10\n ? `High complexity: ${c}`\n : `Complexity: ${c}`;\n\n return { type: 'complexity', score, weight, detail };\n}\n\nfunction computeRecencyFactor(file: AnalyzedFile, weight: number): RiskFactor {\n const now = Date.now();\n const modified = new Date(file.lastModified).getTime();\n const daysAgo = (now - modified) / (1000 * 60 * 60 * 24);\n\n // Exponential decay with half-life of 7 days.\n // score = 100 × 2^(-daysAgo / halfLife)\n // This is the standard temporal decay model used in information retrieval\n // (Lv & Zhai, 2011 — \"Adaptive Relevance Feedback\").\n const HALF_LIFE = 7;\n const score = Math.round(100 * Math.pow(2, -daysAgo / HALF_LIFE));\n\n const detail = daysAgo <= 1\n ? 'Modified today'\n : `Modified ${Math.round(daysAgo)} days ago (decay score ${score})`;\n\n return { type: 'recency', score, weight, detail };\n}\n\nfunction computeConfigFactor(file: AnalyzedFile, weight: number): RiskFactor {\n let score: number;\n let detail: string;\n\n if (file.kind === 'entry') {\n score = 90;\n detail = 'Entry point — critical for understanding app structure';\n } else if (file.kind === 'config') {\n score = 80;\n detail = 'Configuration file — affects runtime behavior';\n } else {\n score = 0;\n detail = 'Regular source file';\n }\n\n return { type: 'config', score, weight, detail };\n}\n\nfunction computeChurnFactor(file: AnalyzedFile, weight: number): RiskFactor {\n // PROXY: Without git integration, approximate churn as geometric mean of\n // complexity signal and recency signal. This avoids double-weighting\n // (since complexity and recency have their own factors) by using the\n // *interaction* term only — high churn requires BOTH high complexity AND\n // recent modification simultaneously.\n //\n // TODO: Replace with real git churn (commit count in last 30 days) when\n // git integration is added. Proxy weight is intentionally low (5%).\n const complexitySignal = Math.min(file.complexity / 20, 1);\n const now = Date.now();\n const daysAgo = (now - new Date(file.lastModified).getTime()) / (1000 * 60 * 60 * 24);\n const recencySignal = Math.pow(2, -daysAgo / 7); // same half-life as recency factor\n\n // Geometric mean ensures both signals must be high for a high score\n const score = Math.round(Math.sqrt(complexitySignal * recencySignal) * 100);\n const detail = score >= 50\n ? 'Likely under active development (complex + recent)'\n : score >= 20\n ? 'Some recent activity'\n : 'Stable — low churn (proxy estimate)';\n\n return { type: 'churn', score, weight, detail };\n}\n\n// ===== HELPERS =====\n\nfunction computeWeightedScore(factors: RiskFactor[]): number {\n let totalWeightedScore = 0;\n let totalWeight = 0;\n\n for (const factor of factors) {\n totalWeightedScore += factor.score * factor.weight;\n totalWeight += factor.weight;\n }\n\n if (totalWeight === 0) return 0;\n return Math.round(totalWeightedScore / totalWeight);\n}\n\nfunction scoreToImpact(score: number): ExclusionImpact {\n if (score >= 80) return 'critical';\n if (score >= 60) return 'high';\n if (score >= 30) return 'medium';\n if (score > 0) return 'low';\n return 'none';\n}\n\nfunction computeTypeProviderUsage(\n files: AnalyzedFile[],\n graph: ProjectGraph,\n): Map<string, number> {\n const usage = new Map<string, number>();\n\n // Count how many files import each type file\n const typeFiles = new Set(\n files.filter((f) => f.kind === 'type').map((f) => f.relativePath),\n );\n\n for (const edge of graph.edges) {\n if (typeFiles.has(edge.to)) {\n usage.set(edge.to, (usage.get(edge.to) ?? 0) + 1);\n }\n }\n\n return usage;\n}\n","import { createHash } from 'node:crypto';\nimport { readdir, stat } from 'node:fs/promises';\nimport { join, extname, relative, resolve } from 'node:path';\nimport type { ProjectAnalysis } from '../types/engine.js';\nimport type { CTOConfig } from '../types/config.js';\nimport { DEFAULT_CONFIG } from '../types/config.js';\nimport { analyzeProject } from './analyzer.js';\n\n// ===== Analysis Cache =====\n//\n// Problem: analyzeProject() is expensive (file walk + AST parse + token count + graph build).\n// MCP tools and CLI commands call it on every invocation.\n//\n// Solution: Two-level cache with lightweight fingerprint invalidation.\n// 1. Compute a fast fingerprint: hash of (sorted file paths + mtimes)\n// Cost: O(n) readdir + stat, no file reads, no AST, no token counting\n// 2. If fingerprint matches cached entry → return cached analysis (instant)\n// 3. If fingerprint differs → full re-analysis, update cache\n//\n// TTL: Safety net. Even if fingerprint matches, expire after maxAgeMs.\n//\n// Reference: Content-addressable caching (Git object model principle)\n\ninterface CacheEntry {\n analysis: ProjectAnalysis;\n fingerprint: string;\n createdAt: number;\n hits: number;\n}\n\ninterface CacheOptions {\n maxAgeMs: number;\n maxEntries: number;\n enabled: boolean;\n}\n\nconst DEFAULT_CACHE_OPTIONS: CacheOptions = {\n maxAgeMs: 5 * 60 * 1000, // 5 minutes\n maxEntries: 10,\n enabled: true,\n};\n\n// In-memory LRU-ish cache\nconst cache = new Map<string, CacheEntry>();\nlet cacheOptions: CacheOptions = { ...DEFAULT_CACHE_OPTIONS };\n\n// ===== FINGERPRINT =====\n\n// Fast fingerprint: walk directory, collect paths + mtimes, hash them.\n// ~10-100x faster than full analysis (no file reads, no AST, no tokenization).\nasync function computeFingerprint(\n rootPath: string,\n config: CTOConfig = DEFAULT_CONFIG,\n): Promise<string> {\n const entries: string[] = [];\n const allExtensions = new Set([\n ...config.analysis.extensions.code,\n ...config.analysis.extensions.config,\n ...config.analysis.extensions.docs,\n ]);\n const ignoreDirSet = new Set(config.analysis.ignore.dirs);\n\n async function walk(dir: string, depth: number): Promise<void> {\n if (depth > config.analysis.maxDepth) return;\n\n let dirEntries;\n try {\n dirEntries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n const promises: Promise<void>[] = [];\n\n for (const entry of dirEntries) {\n const fullPath = join(dir, entry.name);\n\n if (entry.isDirectory()) {\n if (!ignoreDirSet.has(entry.name) && !entry.name.startsWith('.')) {\n promises.push(walk(fullPath, depth + 1));\n }\n } else if (entry.isFile()) {\n const ext = extname(entry.name).slice(1).toLowerCase();\n if (ext && allExtensions.has(ext)) {\n promises.push(\n (async () => {\n try {\n const s = await stat(fullPath);\n const rel = relative(rootPath, fullPath);\n // Include path + mtime + size for change detection\n entries.push(`${rel}:${s.mtimeMs.toFixed(0)}:${s.size}`);\n } catch {\n // skip inaccessible files\n }\n })(),\n );\n }\n }\n }\n\n await Promise.all(promises);\n }\n\n await walk(rootPath, 0);\n\n // Sort for determinism\n entries.sort();\n return createHash('sha256').update(entries.join('|')).digest('hex').substring(0, 16);\n}\n\n// ===== PUBLIC API =====\n\n/**\n * Get a project analysis, using cache when possible.\n *\n * Cache hit: ~1-5ms (fingerprint check only)\n * Cache miss: full analyzeProject() + cache update\n */\nexport async function getCachedAnalysis(\n projectPath: string,\n config?: Partial<CTOConfig>,\n): Promise<ProjectAnalysis> {\n const absPath = resolve(projectPath);\n\n if (!cacheOptions.enabled) {\n return analyzeProject(absPath, config);\n }\n\n const existing = cache.get(absPath);\n\n // Check TTL first (cheap)\n if (existing) {\n const age = Date.now() - existing.createdAt;\n if (age > cacheOptions.maxAgeMs) {\n cache.delete(absPath);\n }\n }\n\n // Compute fingerprint\n const mergedConfig = config\n ? { ...DEFAULT_CONFIG, ...config } as CTOConfig\n : DEFAULT_CONFIG;\n const fingerprint = await computeFingerprint(absPath, mergedConfig);\n\n // Cache hit: fingerprint matches\n const cached = cache.get(absPath);\n if (cached && cached.fingerprint === fingerprint) {\n cached.hits++;\n return cached.analysis;\n }\n\n // Cache miss: full analysis\n const analysis = await analyzeProject(absPath, config);\n\n // Evict oldest entry if at capacity\n if (cache.size >= cacheOptions.maxEntries) {\n const oldest = [...cache.entries()].sort(\n (a, b) => a[1].createdAt - b[1].createdAt,\n )[0];\n if (oldest) cache.delete(oldest[0]);\n }\n\n cache.set(absPath, {\n analysis,\n fingerprint,\n createdAt: Date.now(),\n hits: 0,\n });\n\n return analysis;\n}\n\n/**\n * Invalidate cache for a specific project (e.g., after a known file change).\n */\nexport function invalidateCache(projectPath?: string): void {\n if (projectPath) {\n cache.delete(resolve(projectPath));\n } else {\n cache.clear();\n }\n}\n\n/**\n * Get cache statistics for debugging/monitoring.\n */\nexport function getCacheStats(): {\n entries: number;\n totalHits: number;\n projects: { path: string; hits: number; ageMs: number }[];\n} {\n const now = Date.now();\n const projects = [...cache.entries()].map(([path, entry]) => ({\n path,\n hits: entry.hits,\n ageMs: now - entry.createdAt,\n }));\n\n return {\n entries: cache.size,\n totalHits: projects.reduce((s, p) => s + p.hits, 0),\n projects,\n };\n}\n\n/**\n * Configure cache behavior.\n */\nexport function configureCache(options: Partial<CacheOptions>): void {\n cacheOptions = { ...cacheOptions, ...options };\n if (!cacheOptions.enabled) {\n cache.clear();\n }\n}\n","import { createHash } from 'node:crypto';\nimport type {\n AnalyzedFile,\n ProjectAnalysis,\n ContextSelection,\n SelectedFile,\n SelectionDecision,\n PruneLevel,\n CoverageResult,\n} from '../types/engine.js';\nimport type { PolicySet, PolicyRule } from '../types/govern.js';\nimport { scanFileForSecrets } from '../govern/secrets.js';\nimport { pruneFile } from './pruner.js';\nimport { calculateCoverage } from './coverage.js';\nimport { getPruneLevelForRisk } from './budget.js';\nimport { buildAdjacencyList, bfsBidirectional, matchGlob } from './graph-utils.js';\n\n// ===== DETERMINISTIC CONTEXT SELECTION =====\n//\n// Given a task, analysis, budget, and policies → always returns the same file set.\n// No randomness, no heuristics that change over time.\n//\n// Algorithm:\n// 1. Identify target files from task description\n// 2. Expand via dependency graph (BFS, depth=2)\n// 3. Apply policies (include-always, exclude-always)\n// 4. Score & rank by riskScore\n// 5. Greedy allocation with cascading prune levels\n// 6. Validate policies\n// 7. Calculate coverage score\n// 8. Hash for reproducibility\n\nexport interface SelectionInput {\n task: string;\n analysis: ProjectAnalysis;\n budget: number;\n policies?: PolicySet;\n depth?: number;\n}\n\nexport async function selectContext(input: SelectionInput): Promise<ContextSelection> {\n const { task, analysis, budget, policies, depth = 2 } = input;\n const decisions: SelectionDecision[] = [];\n\n // 1. Identify target files from task description\n const targetPaths = identifyTargetFiles(task, analysis.files);\n if (targetPaths.length > 0) {\n decisions.push({\n file: targetPaths.join(', '),\n action: 'include-full',\n reason: `Target file(s) identified from task description`,\n });\n }\n\n // 2. Expand via dependency graph (O(V+E) using adjacency list)\n const adj = buildAdjacencyList(analysis.graph.edges);\n const expandedPaths = targetPaths.length > 0\n ? Array.from(bfsBidirectional(targetPaths, adj, depth))\n : [];\n const expansionCount = expandedPaths.length - targetPaths.length;\n if (expansionCount > 0) {\n decisions.push({\n file: `${expansionCount} dependencies`,\n action: 'include-full',\n reason: `Expanded ${targetPaths.length} target(s) to ${expandedPaths.length} files via dependency graph (depth ${depth})`,\n });\n }\n\n // 2b. Add type providers of expanded files as candidates.\n // This aligns with coverage.ts which counts type providers as \"relevant\".\n // Without this, coverage would flag missing critical type files that the\n // selector never considered as candidates — a consistency bug.\n const allFileMap = new Map(analysis.files.map((f) => [f.relativePath, f]));\n if (targetPaths.length > 0) {\n for (const path of expandedPaths) {\n const file = allFileMap.get(path);\n if (!file) continue;\n for (const imp of file.imports) {\n const impFile = allFileMap.get(imp);\n if (impFile && impFile.kind === 'type') {\n expandedPaths.push(imp);\n }\n }\n }\n }\n\n // 3. Apply policies\n const { mustInclude, mustExclude } = applyPolicies(analysis.files, policies);\n\n // Merge: targets + expanded + must-include → candidate set\n const candidateSet = new Set([...expandedPaths, ...mustInclude]);\n\n // If no targets identified, use all files (filtered by exclude)\n if (targetPaths.length === 0) {\n for (const f of analysis.files) {\n candidateSet.add(f.relativePath);\n }\n }\n\n // Remove must-exclude\n for (const ex of mustExclude) {\n candidateSet.delete(ex);\n decisions.push({\n file: ex,\n action: 'exclude',\n reason: 'Excluded by policy',\n });\n }\n\n // 3b. secret-block: scan candidate files for secrets and exclude them\n const hasSecretBlock = policies?.rules.some(\n (r) => r.type === 'secret-block' && r.enabled,\n );\n if (hasSecretBlock) {\n for (const path of Array.from(candidateSet)) {\n const file = allFileMap.get(path);\n if (!file) continue;\n const findings = await scanFileForSecrets(\n file.path,\n analysis.projectPath,\n );\n if (findings.length > 0) {\n candidateSet.delete(path);\n decisions.push({\n file: path,\n action: 'exclude',\n reason: `Blocked: ${findings.length} secret(s) detected (${findings.map((f) => f.type).join(', ')})`,\n });\n }\n }\n }\n\n // 4. Sort candidates by riskScore descending\n const candidates = Array.from(candidateSet)\n .map((p) => allFileMap.get(p))\n .filter((f): f is AnalyzedFile => f !== undefined)\n .sort((a, b) => {\n // Targets always first\n const aIsTarget = targetPaths.includes(a.relativePath) ? 0 : 1;\n const bIsTarget = targetPaths.includes(b.relativePath) ? 0 : 1;\n if (aIsTarget !== bIsTarget) return aIsTarget - bIsTarget;\n\n // Then must-include\n const aIsMust = mustInclude.has(a.relativePath) ? 0 : 1;\n const bIsMust = mustInclude.has(b.relativePath) ? 0 : 1;\n if (aIsMust !== bIsMust) return aIsMust - bIsMust;\n\n // Then by riskScore\n return b.riskScore - a.riskScore;\n });\n\n // 5. Greedy allocation with cascading prune levels\n const selectedFiles: SelectedFile[] = [];\n let usedTokens = 0;\n\n for (const file of candidates) {\n const isTarget = targetPaths.includes(file.relativePath);\n const isMustInclude = mustInclude.has(file.relativePath);\n const defaultLevel = isTarget ? 'full' : getPruneLevelForRisk(file.riskScore);\n const levels = getCascadeLevels(defaultLevel);\n\n let included = false;\n\n for (const level of levels) {\n if (level === 'excluded') break;\n\n let tokens: number;\n if (level === 'full') {\n tokens = file.tokens;\n } else {\n const pruned = await pruneFile(file, level);\n tokens = pruned.prunedTokens;\n }\n\n if (usedTokens + tokens <= budget) {\n usedTokens += tokens;\n selectedFiles.push({\n relativePath: file.relativePath,\n tokens,\n originalTokens: file.tokens,\n pruneLevel: level,\n riskScore: file.riskScore,\n reason: buildReason(file, level, isTarget, isMustInclude),\n });\n\n if (level !== defaultLevel) {\n decisions.push({\n file: file.relativePath,\n action: `include-${level}` as SelectionDecision['action'],\n reason: `Downgraded from ${defaultLevel} to ${level} due to budget constraint`,\n alternatives: `Would need ${file.tokens - tokens} more tokens for ${defaultLevel}`,\n });\n }\n\n included = true;\n break;\n }\n }\n\n if (!included) {\n decisions.push({\n file: file.relativePath,\n action: 'exclude',\n reason: `Budget exhausted (risk: ${file.riskScore}, needs ${file.tokens} tokens)`,\n });\n }\n }\n\n // 6. Calculate coverage\n const includedPaths = selectedFiles.map((f) => f.relativePath);\n const coverage = calculateCoverage(\n targetPaths,\n includedPaths,\n analysis.files,\n analysis.graph,\n depth,\n );\n\n // 7. Calculate overall risk of the selection (lower = better)\n const includedSet = new Set(includedPaths);\n const excludedFiles = analysis.files.filter(\n (f) => !includedSet.has(f.relativePath),\n );\n const excludedRisk = excludedFiles.length > 0\n ? Math.round(excludedFiles.reduce((s, f) => s + f.riskScore, 0) / excludedFiles.length)\n : 0;\n\n // 8. Hash for determinism\n const hashInput = selectedFiles\n .map((f) => `${f.relativePath}:${f.pruneLevel}`)\n .sort()\n .join('|') + `|budget:${budget}`;\n const hash = createHash('sha256').update(hashInput).digest('hex').substring(0, 16);\n\n return {\n files: selectedFiles,\n totalTokens: usedTokens,\n budget,\n usedPercent: budget > 0 ? Math.round((usedTokens / budget) * 100 * 10) / 10 : 0,\n coverage,\n riskScore: excludedRisk,\n deterministic: true,\n hash,\n decisions,\n };\n}\n\n// ===== TARGET IDENTIFICATION =====\n\nfunction identifyTargetFiles(task: string, files: AnalyzedFile[]): string[] {\n const targets: string[] = [];\n\n // Extract file paths mentioned in the task\n // Matches patterns like: src/foo/bar.ts, ./utils.js, components/Header.tsx\n const pathPattern = /(?:^|\\s|[\"'`])([.\\w/-]+\\.[a-zA-Z]{1,4})(?:\\s|$|[\"'`]|,|:)/g;\n let match: RegExpExecArray | null;\n\n while ((match = pathPattern.exec(task)) !== null) {\n const candidate = match[1];\n // Find matching file\n const found = files.find(\n (f) => f.relativePath === candidate || f.relativePath.endsWith(candidate),\n );\n if (found && !targets.includes(found.relativePath)) {\n targets.push(found.relativePath);\n }\n }\n\n return targets;\n}\n\n// ===== POLICY APPLICATION =====\n\nfunction applyPolicies(\n files: AnalyzedFile[],\n policies?: PolicySet,\n): { mustInclude: Set<string>; mustExclude: Set<string> } {\n const mustInclude = new Set<string>();\n const mustExclude = new Set<string>();\n\n if (!policies) return { mustInclude, mustExclude };\n\n for (const rule of policies.rules) {\n if (!rule.enabled) continue;\n\n if (rule.type === 'include-always' && rule.pattern) {\n for (const file of files) {\n if (matchGlob(file.relativePath, rule.pattern)) {\n mustInclude.add(file.relativePath);\n }\n }\n }\n\n if (rule.type === 'exclude-always' && rule.pattern) {\n for (const file of files) {\n if (matchGlob(file.relativePath, rule.pattern)) {\n mustExclude.add(file.relativePath);\n }\n }\n }\n\n // secret-block is handled separately in applyPoliciesAsync\n // because it requires file I/O (scanning file contents)\n }\n\n return { mustInclude, mustExclude };\n}\n\n// ===== HELPERS =====\n\nfunction getCascadeLevels(startLevel: PruneLevel): PruneLevel[] {\n const all: PruneLevel[] = ['full', 'signatures', 'skeleton', 'excluded'];\n const startIdx = all.indexOf(startLevel);\n return all.slice(startIdx);\n}\n\nfunction buildReason(\n file: AnalyzedFile,\n level: PruneLevel,\n isTarget: boolean,\n isMustInclude: boolean,\n): string {\n if (isTarget) return 'Target file';\n if (isMustInclude) return 'Required by policy';\n\n const impact = file.exclusionImpact;\n const levelStr = level === 'full' ? 'full content' : level;\n\n if (impact === 'critical') return `Critical dependency (risk ${file.riskScore}) — ${levelStr}`;\n if (impact === 'high') return `High-risk dependency (risk ${file.riskScore}) — ${levelStr}`;\n if (impact === 'medium') return `Medium relevance (risk ${file.riskScore}) — ${levelStr}`;\n return `Low relevance (risk ${file.riskScore}) — ${levelStr}`;\n}\n","import { readFile } from 'node:fs/promises';\nimport { resolve, relative } from 'node:path';\nimport type { SecretFinding, SecretType } from '../types/govern.js';\n\n// ===== SECRET DETECTION ENGINE =====\n\ninterface SecretPattern {\n type: SecretType;\n pattern: RegExp;\n severity: SecretFinding['severity'];\n description: string;\n}\n\nconst BUILTIN_PATTERNS: { type: SecretType; source: string; flags: string; severity: SecretFinding['severity']; description: string }[] = [\n // API Keys\n { type: 'api-key', source: '(?:api[_-]?key|apikey)\\\\s*[:=]\\\\s*[\\'\"]?([a-zA-Z0-9_\\\\-]{20,})[\\'\"]?', flags: 'gi', severity: 'critical', description: 'API Key' },\n { type: 'api-key', source: 'sk-[a-zA-Z0-9]{20,}', flags: 'g', severity: 'critical', description: 'OpenAI/Anthropic API Key' },\n { type: 'api-key', source: 'sk-ant-[a-zA-Z0-9\\\\-]{20,}', flags: 'g', severity: 'critical', description: 'Anthropic API Key' },\n\n // AWS\n { type: 'aws-key', source: 'AKIA[0-9A-Z]{16}', flags: 'g', severity: 'critical', description: 'AWS Access Key ID' },\n { type: 'aws-key', source: '(?:aws_secret_access_key|aws_secret)\\\\s*[:=]\\\\s*[\\'\"]?([a-zA-Z0-9/+=]{40})[\\'\"]?', flags: 'gi', severity: 'critical', description: 'AWS Secret Key' },\n\n // Private Keys\n { type: 'private-key', source: '-----BEGIN (?:RSA |EC |DSA )?PRIVATE KEY-----', flags: 'g', severity: 'critical', description: 'Private Key' },\n { type: 'private-key', source: '-----BEGIN OPENSSH PRIVATE KEY-----', flags: 'g', severity: 'critical', description: 'SSH Private Key' },\n\n // Passwords\n { type: 'password', source: '(?:password|passwd|pwd)\\\\s*[:=]\\\\s*[\\'\"]([^\\'\"]{8,})[\\'\"](?!\\\\s*\\\\{)', flags: 'gi', severity: 'high', description: 'Hardcoded Password' },\n { type: 'password', source: '(?:DB_PASSWORD|DATABASE_PASSWORD|MYSQL_PASSWORD|POSTGRES_PASSWORD)\\\\s*[:=]\\\\s*[\\'\"]?([^\\'\"{}\\\\s]{4,})[\\'\"]?', flags: 'gi', severity: 'high', description: 'Database Password' },\n\n // Tokens\n { type: 'token', source: '(?:bearer|token|auth_token|access_token|refresh_token)\\\\s*[:=]\\\\s*[\\'\"]([a-zA-Z0-9_\\\\-.]{20,})[\\'\"](?!\\\\s*\\\\{)', flags: 'gi', severity: 'high', description: 'Auth Token' },\n { type: 'token', source: 'ghp_[a-zA-Z0-9]{36}', flags: 'g', severity: 'critical', description: 'GitHub Personal Access Token' },\n { type: 'token', source: 'gho_[a-zA-Z0-9]{36}', flags: 'g', severity: 'critical', description: 'GitHub OAuth Token' },\n { type: 'token', source: 'glpat-[a-zA-Z0-9\\\\-]{20,}', flags: 'g', severity: 'critical', description: 'GitLab Personal Access Token' },\n { type: 'token', source: 'npm_[a-zA-Z0-9]{36}', flags: 'g', severity: 'high', description: 'npm Token' },\n\n // Connection strings\n { type: 'connection-string', source: '(?:mongodb(?:\\\\+srv)?|postgres(?:ql)?|mysql|redis|amqp):\\\\/\\\\/[^\\\\s\\'\"]+:[^\\\\s\\'\"]+@[^\\\\s\\'\"]+', flags: 'gi', severity: 'critical', description: 'Database Connection String' },\n { type: 'connection-string', source: '(?:DATABASE_URL|REDIS_URL|MONGODB_URI)\\\\s*[:=]\\\\s*[\\'\"]?([^\\\\s\\'\"]{10,})[\\'\"]?', flags: 'gi', severity: 'high', description: 'Database URL' },\n\n // Environment variables with secrets\n { type: 'env-variable', source: '(?:SECRET|PRIVATE|ENCRYPTION)[_-]?(?:KEY|TOKEN|PASS)\\\\s*[:=]\\\\s*[\\'\"]?([^\\\\s\\'\"]{8,})[\\'\"]?', flags: 'gi', severity: 'high', description: 'Secret Environment Variable' },\n];\n\nfunction buildPatterns(customPatterns: string[] = []): SecretPattern[] {\n const patterns: SecretPattern[] = BUILTIN_PATTERNS.map((def) => ({\n type: def.type,\n pattern: new RegExp(def.source, def.flags),\n severity: def.severity,\n description: def.description,\n }));\n\n for (const custom of customPatterns) {\n try {\n patterns.push({\n type: 'custom',\n pattern: new RegExp(custom, 'gi'),\n severity: 'medium',\n description: `Custom pattern: ${custom}`,\n });\n } catch { /* skip invalid regex */ }\n }\n\n return patterns;\n}\n\nexport function scanContentForSecrets(\n content: string,\n filePath: string,\n customPatterns: string[] = [],\n): SecretFinding[] {\n const findings: SecretFinding[] = [];\n const lines = content.split('\\n');\n const allPatterns = buildPatterns(customPatterns);\n\n for (const secretPattern of allPatterns) {\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n secretPattern.pattern.lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = secretPattern.pattern.exec(line)) !== null) {\n const matchText = match[0];\n if (isTemplateOrPlaceholder(matchText)) continue;\n\n findings.push({\n type: secretPattern.type,\n file: filePath,\n line: i + 1,\n match: matchText,\n redacted: redactSecret(matchText),\n severity: secretPattern.severity,\n });\n }\n }\n }\n\n return deduplicateFindings(findings);\n}\n\nexport async function scanFileForSecrets(\n filePath: string,\n projectPath: string,\n customPatterns: string[] = [],\n): Promise<SecretFinding[]> {\n try {\n const content = await readFile(filePath, 'utf-8');\n const relPath = relative(resolve(projectPath), resolve(filePath));\n return scanContentForSecrets(content, relPath, customPatterns);\n } catch {\n return [];\n }\n}\n\nexport async function scanProjectForSecrets(\n projectPath: string,\n filePaths: string[],\n customPatterns: string[] = [],\n): Promise<SecretFinding[]> {\n const allFindings: SecretFinding[] = [];\n\n for (const fp of filePaths) {\n const findings = await scanFileForSecrets(fp, projectPath, customPatterns);\n allFindings.push(...findings);\n }\n\n return allFindings.sort((a, b) => {\n const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };\n return severityOrder[a.severity] - severityOrder[b.severity];\n });\n}\n\nexport function sanitizeContent(content: string, customPatterns: string[] = []): string {\n let sanitized = content;\n const allPatterns = buildPatterns(customPatterns);\n\n for (const secretPattern of allPatterns) {\n sanitized = sanitized.replace(secretPattern.pattern, (match) => {\n if (isTemplateOrPlaceholder(match)) return match;\n return redactSecret(match);\n });\n }\n\n return sanitized;\n}\n\nfunction redactSecret(value: string): string {\n if (value.length <= 8) return '***REDACTED***';\n const prefix = value.substring(0, 4);\n const suffix = value.substring(value.length - 2);\n return `${prefix}${'*'.repeat(Math.min(value.length - 6, 20))}${suffix}`;\n}\n\nfunction isTemplateOrPlaceholder(value: string): boolean {\n const placeholders = [\n /\\$\\{.*\\}/, /\\{\\{.*\\}\\}/, /%[sd]/, /<[A-Z_]+>/, /YOUR_.*_HERE/i,\n /\\bCHANGE_ME\\b/i, /\\bPLACEHOLDER\\b/i, /\\bexample\\b/i, /\\bTODO\\b/i, /xxx+/i,\n /\\breplace.?me\\b/i, /\\bdummy\\b/i, /\\btest_?key\\b/i, /\\bsample\\b/i,\n ];\n return placeholders.some((p) => p.test(value));\n}\n\nfunction deduplicateFindings(findings: SecretFinding[]): SecretFinding[] {\n const seen = new Set<string>();\n return findings.filter((f) => {\n const key = `${f.file}:${f.line}:${f.type}:${f.match}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n","import { Project, SyntaxKind, type SourceFile } from 'ts-morph';\nimport { readFile } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { AnalyzedFile, PruneLevel, PrunedContent } from '../types/engine.js';\nimport { countTokensChars4 } from './tokenizer.js';\n\nconst TS_EXTENSIONS = new Set(['ts', 'tsx', 'js', 'jsx', 'mts', 'mjs']);\n\n// ===== PUBLIC API =====\n\nexport async function pruneFile(\n file: AnalyzedFile,\n level: PruneLevel,\n): Promise<PrunedContent> {\n if (level === 'excluded') {\n return emptyResult(file, 'excluded');\n }\n\n if (level === 'full') {\n return fullContent(file);\n }\n\n const ext = file.extension.toLowerCase();\n const isTS = TS_EXTENSIONS.has(ext);\n\n if (isTS) {\n return pruneTypeScript(file, level);\n }\n\n return pruneGeneric(file, level);\n}\n\nexport async function pruneFiles(\n files: AnalyzedFile[],\n levelFn: (file: AnalyzedFile) => PruneLevel,\n): Promise<PrunedContent[]> {\n const results: PrunedContent[] = [];\n\n for (const file of files) {\n const level = levelFn(file);\n const pruned = await pruneFile(file, level);\n results.push(pruned);\n }\n\n return results;\n}\n\n// ===== TYPESCRIPT AST-BASED PRUNING =====\n\nasync function pruneTypeScript(\n file: AnalyzedFile,\n level: PruneLevel,\n): Promise<PrunedContent> {\n let content: string;\n try {\n content = await readFile(file.path, 'utf-8');\n } catch {\n return emptyResult(file, level);\n }\n\n let project: Project;\n try {\n const tsConfigPath = findTsConfig(file.path);\n project = new Project({\n tsConfigFilePath: tsConfigPath,\n skipAddingFilesFromTsConfig: true,\n compilerOptions: tsConfigPath\n ? undefined\n : { allowJs: true, esModuleInterop: true },\n });\n project.createSourceFile(file.path, content, { overwrite: true });\n } catch {\n // Fallback to generic pruning if AST fails\n return pruneGenericFromContent(file, content, level);\n }\n\n const sourceFile = project.getSourceFiles()[0];\n if (!sourceFile) {\n return pruneGenericFromContent(file, content, level);\n }\n\n const prunedContent = level === 'signatures'\n ? extractSignaturesAST(sourceFile)\n : extractSkeletonAST(sourceFile);\n\n const prunedTokens = countTokensChars4(Buffer.byteLength(prunedContent, 'utf-8'));\n const savingsPercent = file.tokens > 0 ? ((file.tokens - prunedTokens) / file.tokens) * 100 : 0;\n\n return {\n relativePath: file.relativePath,\n originalTokens: file.tokens,\n prunedTokens,\n pruneLevel: level,\n content: prunedContent,\n savingsPercent: Math.max(0, savingsPercent),\n };\n}\n\n// ===== SIGNATURES: Keep imports, type defs, function signatures, class outlines =====\n\nfunction extractSignaturesAST(sf: SourceFile): string {\n const parts: string[] = [];\n\n // Imports\n for (const imp of sf.getImportDeclarations()) {\n parts.push(imp.getText());\n }\n\n if (parts.length > 0) parts.push('');\n\n // Type aliases\n for (const ta of sf.getTypeAliases()) {\n addJSDoc(ta, parts);\n parts.push(ta.getText());\n }\n\n // Interfaces\n for (const iface of sf.getInterfaces()) {\n addJSDoc(iface, parts);\n parts.push(iface.getText());\n }\n\n // Enums\n for (const en of sf.getEnums()) {\n addJSDoc(en, parts);\n parts.push(en.getText());\n }\n\n // Function declarations — signature only\n for (const fn of sf.getFunctions()) {\n addJSDoc(fn, parts);\n const isExported = fn.isExported();\n const isAsync = fn.isAsync();\n const name = fn.getName() ?? '<anonymous>';\n const params = fn.getParameters().map((p) => p.getText()).join(', ');\n const returnType = fn.getReturnTypeNode()?.getText();\n const returnStr = returnType ? `: ${returnType}` : '';\n\n const prefix = isExported ? 'export ' : '';\n const asyncStr = isAsync ? 'async ' : '';\n parts.push(`${prefix}${asyncStr}function ${name}(${params})${returnStr} { /* ... */ }`);\n }\n\n // Variable declarations (const/let with arrow functions)\n for (const stmt of sf.getVariableStatements()) {\n for (const decl of stmt.getDeclarations()) {\n const init = decl.getInitializer();\n if (init && (init.getKind() === SyntaxKind.ArrowFunction || init.getKind() === SyntaxKind.FunctionExpression)) {\n addJSDoc(stmt, parts);\n const isExported = stmt.isExported();\n const prefix = isExported ? 'export ' : '';\n const kind = stmt.getDeclarationKind();\n const name = decl.getName();\n const typeNode = decl.getTypeNode()?.getText();\n const typeStr = typeNode ? `: ${typeNode}` : '';\n parts.push(`${prefix}${kind} ${name}${typeStr} = /* ... */;`);\n } else {\n // Non-function variables: keep full declaration\n addJSDoc(stmt, parts);\n parts.push(stmt.getText());\n }\n }\n }\n\n // Classes — outline with method signatures\n for (const cls of sf.getClasses()) {\n addJSDoc(cls, parts);\n const isExported = cls.isExported();\n const prefix = isExported ? 'export ' : '';\n const name = cls.getName() ?? '<anonymous>';\n const ext = cls.getExtends()?.getText();\n const impl = cls.getImplements().map((i) => i.getText()).join(', ');\n let header = `${prefix}class ${name}`;\n if (ext) header += ` extends ${ext}`;\n if (impl) header += ` implements ${impl}`;\n header += ' {';\n parts.push(header);\n\n // Properties\n for (const prop of cls.getProperties()) {\n parts.push(` ${prop.getText()}`);\n }\n\n // Constructor\n const ctor = cls.getConstructors()[0];\n if (ctor) {\n const ctorParams = ctor.getParameters().map((p) => p.getText()).join(', ');\n parts.push(` constructor(${ctorParams}) { /* ... */ }`);\n }\n\n // Methods — signature only\n for (const method of cls.getMethods()) {\n const isStatic = method.isStatic();\n const isAsync = method.isAsync();\n const methodName = method.getName();\n const methodParams = method.getParameters().map((p) => p.getText()).join(', ');\n const returnType = method.getReturnTypeNode()?.getText();\n const returnStr = returnType ? `: ${returnType}` : '';\n const staticStr = isStatic ? 'static ' : '';\n const asyncStr = isAsync ? 'async ' : '';\n parts.push(` ${staticStr}${asyncStr}${methodName}(${methodParams})${returnStr} { /* ... */ }`);\n }\n\n parts.push('}');\n }\n\n // Re-exports\n for (const exp of sf.getExportDeclarations()) {\n parts.push(exp.getText());\n }\n\n // Export assignments\n for (const exp of sf.getExportAssignments()) {\n parts.push(exp.getText());\n }\n\n return parts.join('\\n');\n}\n\n// ===== SKELETON: Keep only declarations, no bodies at all =====\n\nfunction extractSkeletonAST(sf: SourceFile): string {\n const parts: string[] = [];\n\n // Imports\n for (const imp of sf.getImportDeclarations()) {\n parts.push(imp.getText());\n }\n\n if (parts.length > 0) parts.push('');\n\n // Type aliases — full\n for (const ta of sf.getTypeAliases()) {\n if (ta.isExported()) parts.push(ta.getText());\n }\n\n // Interfaces — name + extends only\n for (const iface of sf.getInterfaces()) {\n if (!iface.isExported()) continue;\n const ext = iface.getExtends().map((e) => e.getText());\n const extStr = ext.length > 0 ? ` extends ${ext.join(', ')}` : '';\n parts.push(`export interface ${iface.getName()}${extStr} { /* ${iface.getProperties().length} props */ }`);\n }\n\n // Enums — name only\n for (const en of sf.getEnums()) {\n if (!en.isExported()) continue;\n const members = en.getMembers().map((m) => m.getName());\n parts.push(`export enum ${en.getName()} { ${members.join(', ')} }`);\n }\n\n // Functions — name + params only\n for (const fn of sf.getFunctions()) {\n if (!fn.isExported()) continue;\n const name = fn.getName() ?? '<anonymous>';\n const params = fn.getParameters().map((p) => p.getText()).join(', ');\n parts.push(`export function ${name}(${params});`);\n }\n\n // Classes — name + method names only\n for (const cls of sf.getClasses()) {\n if (!cls.isExported()) continue;\n const methods = cls.getMethods().map((m) => m.getName());\n parts.push(`export class ${cls.getName()} { /* methods: ${methods.join(', ')} */ }`);\n }\n\n // Re-exports\n for (const exp of sf.getExportDeclarations()) {\n parts.push(exp.getText());\n }\n\n return parts.join('\\n');\n}\n\n// ===== GENERIC PRUNING (non-TS files) =====\n\nasync function pruneGeneric(\n file: AnalyzedFile,\n level: PruneLevel,\n): Promise<PrunedContent> {\n let content: string;\n try {\n content = await readFile(file.path, 'utf-8');\n } catch {\n return emptyResult(file, level);\n }\n\n return pruneGenericFromContent(file, content, level);\n}\n\nfunction pruneGenericFromContent(\n file: AnalyzedFile,\n content: string,\n level: PruneLevel,\n): PrunedContent {\n const lines = content.split('\\n');\n let result: string[];\n\n if (level === 'signatures') {\n result = lines.filter((line) => {\n const t = line.trim();\n return (\n t === '' ||\n t.startsWith('#') ||\n t.startsWith('//') ||\n t.startsWith('import ') ||\n t.startsWith('from ') ||\n t.startsWith('export ') ||\n t.startsWith('def ') ||\n t.startsWith('async def ') ||\n t.startsWith('class ') ||\n t.startsWith('function ') ||\n t.startsWith('const ') ||\n t.startsWith('let ') ||\n t.startsWith('var ') ||\n /^(pub |fn |struct |enum |impl |mod |use )/.test(t)\n );\n });\n } else {\n // skeleton: even more aggressive — only declarations\n result = lines.filter((line) => {\n const t = line.trim();\n return (\n t.startsWith('import ') ||\n t.startsWith('from ') ||\n t.startsWith('export ') ||\n t.startsWith('def ') ||\n t.startsWith('class ') ||\n t.startsWith('function ') ||\n /^(pub |fn |struct |enum |mod |use )/.test(t)\n );\n });\n }\n\n const prunedContent = result.join('\\n');\n const prunedTokens = countTokensChars4(Buffer.byteLength(prunedContent, 'utf-8'));\n const savingsPercent = file.tokens > 0 ? ((file.tokens - prunedTokens) / file.tokens) * 100 : 0;\n\n return {\n relativePath: file.relativePath,\n originalTokens: file.tokens,\n prunedTokens,\n pruneLevel: level,\n content: prunedContent,\n savingsPercent: Math.max(0, savingsPercent),\n };\n}\n\n// ===== HELPERS =====\n\nasync function fullContent(file: AnalyzedFile): Promise<PrunedContent> {\n let content = '';\n try {\n content = await readFile(file.path, 'utf-8');\n } catch { /* empty */ }\n\n return {\n relativePath: file.relativePath,\n originalTokens: file.tokens,\n prunedTokens: file.tokens,\n pruneLevel: 'full',\n content,\n savingsPercent: 0,\n };\n}\n\nfunction emptyResult(file: AnalyzedFile, level: PruneLevel): PrunedContent {\n return {\n relativePath: file.relativePath,\n originalTokens: file.tokens,\n prunedTokens: 0,\n pruneLevel: level,\n content: '',\n savingsPercent: 100,\n };\n}\n\nfunction addJSDoc(node: { getJsDocs?: () => { getText(): string }[] }, parts: string[]): void {\n if (!node.getJsDocs) return;\n const docs = node.getJsDocs();\n if (docs.length > 0) {\n parts.push(docs[0].getText());\n }\n}\n\nfunction findTsConfig(filePath: string): string | undefined {\n let dir = filePath;\n for (let i = 0; i < 10; i++) {\n dir = join(dir, '..');\n const candidate = join(dir, 'tsconfig.json');\n if (existsSync(candidate)) return candidate;\n }\n return undefined;\n}\n","import type { GraphEdge } from '../types/engine.js';\n\n// ===== SHARED GRAPH UTILITIES =====\n\nexport interface AdjacencyList {\n forward: Map<string, string[]>; // file → files it imports\n reverse: Map<string, string[]>; // file → files that import it\n}\n\nexport function buildAdjacencyList(edges: GraphEdge[]): AdjacencyList {\n const forward = new Map<string, string[]>();\n const reverse = new Map<string, string[]>();\n\n for (const edge of edges) {\n if (!forward.has(edge.from)) forward.set(edge.from, []);\n forward.get(edge.from)!.push(edge.to);\n\n if (!reverse.has(edge.to)) reverse.set(edge.to, []);\n reverse.get(edge.to)!.push(edge.from);\n }\n\n return { forward, reverse };\n}\n\nexport function bfsBidirectional(\n seeds: string[],\n adj: AdjacencyList,\n depth: number,\n): Set<string> {\n const result = new Set(seeds);\n let frontier = [...seeds];\n const visited = new Set<string>();\n\n for (let d = 0; d < depth; d++) {\n const nextFrontier: string[] = [];\n\n for (const node of frontier) {\n if (visited.has(node)) continue;\n visited.add(node);\n\n // Forward neighbors (imports)\n const fwd = adj.forward.get(node);\n if (fwd) {\n for (const neighbor of fwd) {\n if (!visited.has(neighbor)) {\n result.add(neighbor);\n nextFrontier.push(neighbor);\n }\n }\n }\n\n // Reverse neighbors (imported by)\n const rev = adj.reverse.get(node);\n if (rev) {\n for (const neighbor of rev) {\n if (!visited.has(neighbor)) {\n result.add(neighbor);\n nextFrontier.push(neighbor);\n }\n }\n }\n }\n\n frontier = nextFrontier;\n }\n\n return result;\n}\n\nexport function matchGlob(path: string, pattern: string): boolean {\n const regexStr = pattern\n .replace(/\\./g, '\\\\.')\n .replace(/\\*\\*/g, '§§')\n .replace(/\\*/g, '[^/]*')\n .replace(/§§/g, '.*')\n .replace(/\\?/g, '.');\n\n try {\n return new RegExp(`^${regexStr}$`).test(path);\n } catch {\n return false;\n }\n}\n","import type {\n AnalyzedFile,\n ProjectGraph,\n CoverageResult,\n} from '../types/engine.js';\nimport { buildAdjacencyList, bfsBidirectional } from './graph-utils.js';\n\n// ===== CONTEXT COVERAGE SCORING =====\n//\n// Given a set of included files and a task's target files, calculate\n// how much of the \"relevant universe\" is covered.\n//\n// coverageScore = |includedRelevant| / |relevantFiles| × 100\n//\n// \"Relevant\" = target files + their dependencies (up to `depth` levels)\n// + type providers used by included files.\n\nexport function calculateCoverage(\n targetPaths: string[],\n includedPaths: string[],\n allFiles: AnalyzedFile[],\n graph: ProjectGraph,\n depth: number = 2,\n): CoverageResult {\n // 1. Find all relevant files: targets + their dependency cone\n // Uses adjacency list for O(V+E) BFS instead of scanning all edges per node.\n const adj = buildAdjacencyList(graph.edges);\n const relevantSet = targetPaths.length > 0\n ? bfsBidirectional(targetPaths, adj, depth)\n : new Set<string>();\n const includedSet = new Set(includedPaths);\n\n // Also add type providers used by included files\n const tempFileMap = new Map(allFiles.map((f) => [f.relativePath, f]));\n for (const path of includedPaths) {\n const file = tempFileMap.get(path);\n if (!file) continue;\n\n for (const imp of file.imports) {\n const impFile = tempFileMap.get(imp);\n if (impFile && impFile.kind === 'type') {\n relevantSet.add(imp);\n }\n }\n }\n\n // 2. Calculate coverage\n const relevantFiles = Array.from(relevantSet);\n const includedRelevant = relevantFiles.filter((f) => includedSet.has(f));\n const missingRelevant = relevantFiles.filter((f) => !includedSet.has(f));\n\n // Missing critical = missing files with critical/high exclusion impact\n const missingCritical = missingRelevant.filter((f) => {\n const file = tempFileMap.get(f);\n return file && (file.exclusionImpact === 'critical' || file.exclusionImpact === 'high');\n });\n\n // Risk-weighted coverage: missing a high-risk file hurts more than missing a low-risk one.\n // score = Σ(riskScore of included relevant) / Σ(riskScore of all relevant) × 100\n // Falls back to count-based if no risk data is available.\n const fileMap = new Map(allFiles.map((f) => [f.relativePath, f]));\n let totalRelevantRisk = 0;\n let includedRelevantRisk = 0;\n\n for (const f of relevantFiles) {\n const risk = fileMap.get(f)?.riskScore ?? 1;\n totalRelevantRisk += risk;\n if (includedSet.has(f)) {\n includedRelevantRisk += risk;\n }\n }\n\n const score = totalRelevantRisk > 0\n ? Math.round((includedRelevantRisk / totalRelevantRisk) * 100)\n : relevantFiles.length > 0\n ? Math.round((includedRelevant.length / relevantFiles.length) * 100)\n : 100;\n\n // Build explanation\n let explanation: string;\n if (score >= 90) {\n explanation = `Excellent coverage (${score}%): AI has nearly all relevant context.`;\n } else if (score >= 70) {\n explanation = `Good coverage (${score}%): Most relevant files included.`;\n if (missingCritical.length > 0) {\n explanation += ` Warning: ${missingCritical.length} critical file(s) missing.`;\n }\n } else if (score >= 50) {\n explanation = `Partial coverage (${score}%): Significant context is missing.`;\n if (missingCritical.length > 0) {\n explanation += ` ${missingCritical.length} critical file(s) not included — AI quality will degrade.`;\n }\n } else {\n explanation = `Low coverage (${score}%): Most relevant files are excluded. AI response quality will be poor.`;\n }\n\n return {\n score,\n relevantFiles,\n includedRelevant,\n missingRelevant,\n missingCritical,\n explanation,\n };\n}\n","import type { AnalyzedFile, BudgetPlan, BudgetEntry, PruneLevel } from '../types/engine.js';\nimport { pruneFile } from './pruner.js';\n\n// ===== BUDGET OPTIMIZER =====\n//\n// Greedy knapsack with cascading prune levels.\n// Files are sorted by riskScore (descending) — highest risk first.\n// Each file is tried at progressively smaller prune levels until it fits.\n\nexport function getPruneLevelForRisk(riskScore: number): PruneLevel {\n if (riskScore >= 80) return 'full'; // critical — include everything, no cascading\n if (riskScore >= 60) return 'full'; // high — try full first, can cascade\n if (riskScore >= 30) return 'signatures'; // medium — signatures by default\n return 'skeleton'; // low — skeleton\n}\n\nexport function isCriticalRisk(riskScore: number): boolean {\n return riskScore >= 80;\n}\n\nexport async function optimizeBudget(\n files: AnalyzedFile[],\n budget: number,\n): Promise<BudgetPlan> {\n const entries: BudgetEntry[] = [];\n let used = 0;\n\n // Sort by riskScore descending — most important files first\n const sorted = [...files].sort((a, b) => b.riskScore - a.riskScore);\n\n for (const file of sorted) {\n const defaultLevel = getPruneLevelForRisk(file.riskScore);\n\n // Try cascading prune levels: full → signatures → skeleton → excluded\n const levelsToTry = getCascadeLevels(defaultLevel);\n\n let included = false;\n\n for (const level of levelsToTry) {\n if (level === 'excluded') break;\n\n if (level === 'full') {\n if (used + file.tokens <= budget) {\n used += file.tokens;\n entries.push({\n relativePath: file.relativePath,\n originalTokens: file.tokens,\n allocatedTokens: file.tokens,\n pruneLevel: 'full',\n included: true,\n reason: `Risk ${file.riskScore} — included in full`,\n });\n included = true;\n break;\n }\n } else {\n const pruned = await pruneFile(file, level);\n if (pruned.prunedTokens > 0 && used + pruned.prunedTokens <= budget) {\n used += pruned.prunedTokens;\n entries.push({\n relativePath: file.relativePath,\n originalTokens: file.tokens,\n allocatedTokens: pruned.prunedTokens,\n pruneLevel: level,\n included: true,\n reason: `Risk ${file.riskScore} — pruned to ${level} (budget constraint)`,\n });\n included = true;\n break;\n }\n }\n }\n\n if (!included) {\n entries.push({\n relativePath: file.relativePath,\n originalTokens: file.tokens,\n allocatedTokens: 0,\n pruneLevel: 'excluded',\n included: false,\n reason: `Risk ${file.riskScore} — excluded (budget exhausted, ${file.tokens} tokens)`,\n });\n }\n }\n\n return {\n budget,\n used,\n remaining: budget - used,\n fillPercent: budget > 0 ? Math.round((used / budget) * 100 * 10) / 10 : 0,\n files: entries,\n };\n}\n\n// ===== HELPERS =====\n\nfunction getCascadeLevels(startLevel: PruneLevel): PruneLevel[] {\n const all: PruneLevel[] = ['full', 'signatures', 'skeleton', 'excluded'];\n const startIdx = all.indexOf(startLevel);\n return all.slice(startIdx);\n}\n","import type { ProjectAnalysis, AnalyzedFile } from '../types/engine.js';\nimport type { ContextSelection } from '../types/engine.js';\nimport { selectContext } from './selector.js';\nimport { calculateCoverage } from './coverage.js';\nimport { buildAdjacencyList } from './graph-utils.js';\n\n// ===== Context Score™ =====\n//\n// A single 0-100 metric that quantifies how well a project's context\n// can be optimized for AI consumption.\n//\n// The score answers: \"If I send this project to an AI with CTO,\n// how much value am I getting per token?\"\n//\n// Dimensions:\n// 1. Efficiency (30%) — How much can we compress without losing value?\n// 2. Coverage (25%) — How much of the relevant universe do we capture?\n// 3. Risk Control (20%) — Are high-risk files properly prioritized?\n// 4. Structure (15%) — How well-organized is the codebase for AI consumption?\n// 5. Governance (10%) — Is the project set up for safe, auditable AI use?\n//\n// Grade scale:\n// A+ (95-100) | A (90-94) | A- (85-89)\n// B+ (80-84) | B (75-79) | B- (70-74)\n// C+ (65-69) | C (60-64) | C- (55-59)\n// D (40-54) | F (0-39)\n\nexport type Grade = 'A+' | 'A' | 'A-' | 'B+' | 'B' | 'B-' | 'C+' | 'C' | 'C-' | 'D' | 'F';\n\nexport interface ContextScore {\n overall: number;\n grade: Grade;\n\n dimensions: {\n efficiency: DimensionScore;\n coverage: DimensionScore;\n riskControl: DimensionScore;\n structure: DimensionScore;\n governance: DimensionScore;\n };\n\n insights: ScoreInsight[];\n\n comparison: {\n naiveTokens: number;\n optimizedTokens: number;\n savedTokens: number;\n savedPercent: number;\n monthlySavingsUSD: number;\n };\n\n meta: {\n projectName: string;\n totalFiles: number;\n totalTokens: number;\n analyzedAt: Date;\n };\n}\n\nexport interface DimensionScore {\n score: number;\n weight: number;\n weighted: number;\n detail: string;\n}\n\nexport interface ScoreInsight {\n type: 'strength' | 'weakness' | 'opportunity';\n title: string;\n detail: string;\n impact: 'high' | 'medium' | 'low';\n}\n\n// ===== MAIN API =====\n\n/**\n * Compute the Context Score™ for a project.\n *\n * @param analysis - Project analysis (from analyzeProject or getCachedAnalysis)\n * @param task - Representative task (default: \"general code review\")\n * @param budget - Token budget (default: 50000)\n */\nexport async function computeContextScore(\n analysis: ProjectAnalysis,\n task: string = 'general code review and refactoring',\n budget: number = 50_000,\n): Promise<ContextScore> {\n // Run context selection to get real numbers\n const selection = await selectContext({ task, analysis, budget });\n\n const insights: ScoreInsight[] = [];\n\n // 1. EFFICIENCY (30%) — compression ratio + pruning effectiveness\n const efficiency = scoreEfficiency(analysis, selection, insights);\n\n // 2. COVERAGE (25%) — how much of the relevant universe is captured\n const coverage = scoreCoverage(analysis, selection, insights);\n\n // 3. RISK CONTROL (20%) — high-risk file prioritization\n const riskControl = scoreRiskControl(analysis, selection, insights);\n\n // 4. STRUCTURE (15%) — codebase organization for AI\n const structure = scoreStructure(analysis, insights);\n\n // 5. GOVERNANCE (10%) — project setup for safe AI use\n const governance = scoreGovernance(analysis, insights);\n\n // Overall\n const overall = Math.round(\n efficiency.weighted + coverage.weighted + riskControl.weighted +\n structure.weighted + governance.weighted\n );\n\n const grade = scoreToGrade(overall);\n\n // Comparison: CTO vs naive (send everything)\n const naiveTokens = analysis.totalTokens;\n const optimizedTokens = selection.totalTokens;\n const savedTokens = naiveTokens - optimizedTokens;\n const savedPercent = naiveTokens > 0 ? Math.round((savedTokens / naiveTokens) * 100) : 0;\n\n // Monthly savings estimate: assume 40 interactions/day, 20 working days\n // Claude Sonnet: $3/M input tokens\n const interactionsPerMonth = 40 * 20;\n const costPerMToken = 3; // $/M tokens (Sonnet)\n const naiveMonthlyCost = (naiveTokens / 1_000_000) * costPerMToken * interactionsPerMonth;\n const optimizedMonthlyCost = (optimizedTokens / 1_000_000) * costPerMToken * interactionsPerMonth;\n const monthlySavingsUSD = Math.round((naiveMonthlyCost - optimizedMonthlyCost) * 100) / 100;\n\n return {\n overall,\n grade,\n dimensions: {\n efficiency,\n coverage,\n riskControl,\n structure,\n governance,\n },\n insights: insights.sort((a, b) => {\n const order = { high: 0, medium: 1, low: 2 };\n return order[a.impact] - order[b.impact];\n }),\n comparison: {\n naiveTokens,\n optimizedTokens,\n savedTokens,\n savedPercent,\n monthlySavingsUSD,\n },\n meta: {\n projectName: analysis.projectName,\n totalFiles: analysis.totalFiles,\n totalTokens: analysis.totalTokens,\n analyzedAt: analysis.analyzedAt,\n },\n };\n}\n\n// ===== DIMENSION SCORERS =====\n\nfunction scoreEfficiency(\n analysis: ProjectAnalysis,\n selection: ContextSelection,\n insights: ScoreInsight[],\n): DimensionScore {\n const weight = 30;\n\n // Compression ratio: how much we reduced tokens\n const ratio = analysis.totalTokens > 0\n ? 1 - (selection.totalTokens / analysis.totalTokens)\n : 0;\n\n // File selectivity: what % of files were excluded\n const selectivity = analysis.totalFiles > 0\n ? 1 - (selection.files.length / analysis.totalFiles)\n : 0;\n\n // Pruning effectiveness: how many files got pruned (signatures/skeleton)\n const prunedFiles = selection.files.filter(\n (f) => f.pruneLevel === 'signatures' || f.pruneLevel === 'skeleton'\n ).length;\n const pruneRatio = selection.files.length > 0\n ? prunedFiles / selection.files.length\n : 0;\n\n // Weighted combination\n const raw = (ratio * 0.5 + selectivity * 0.3 + pruneRatio * 0.2) * 100;\n const score = Math.min(100, Math.max(0, Math.round(raw)));\n const weighted = (score / 100) * weight;\n\n if (ratio > 0.7) {\n insights.push({\n type: 'strength',\n title: 'Excellent compression',\n detail: `${Math.round(ratio * 100)}% token reduction while maintaining context quality`,\n impact: 'high',\n });\n }\n\n if (ratio < 0.3 && analysis.totalTokens > 20_000) {\n insights.push({\n type: 'weakness',\n title: 'Low compression opportunity',\n detail: 'Most files are needed. Consider splitting the project into smaller modules.',\n impact: 'medium',\n });\n }\n\n return {\n score,\n weight,\n weighted,\n detail: `${Math.round(ratio * 100)}% compression, ${prunedFiles}/${selection.files.length} files pruned`,\n };\n}\n\nfunction scoreCoverage(\n analysis: ProjectAnalysis,\n selection: ContextSelection,\n insights: ScoreInsight[],\n): DimensionScore {\n const weight = 25;\n\n const coverageScore = selection.coverage.score;\n const missingCritical = selection.coverage.missingCritical.length;\n\n // Penalize missing critical files heavily\n let penalty = 0;\n if (missingCritical > 0) {\n penalty = Math.min(30, missingCritical * 10);\n insights.push({\n type: 'weakness',\n title: `${missingCritical} critical file(s) missing from context`,\n detail: `Missing: ${selection.coverage.missingCritical.slice(0, 3).join(', ')}${missingCritical > 3 ? ` +${missingCritical - 3} more` : ''}`,\n impact: 'high',\n });\n }\n\n const score = Math.min(100, Math.max(0, Math.round(coverageScore - penalty)));\n const weighted = (score / 100) * weight;\n\n if (coverageScore >= 90 && missingCritical === 0) {\n insights.push({\n type: 'strength',\n title: 'Excellent context coverage',\n detail: `${coverageScore}% of the relevant universe captured with zero critical gaps`,\n impact: 'high',\n });\n }\n\n return {\n score,\n weight,\n weighted,\n detail: `${coverageScore}% coverage, ${missingCritical} critical gaps`,\n };\n}\n\nfunction scoreRiskControl(\n analysis: ProjectAnalysis,\n selection: ContextSelection,\n insights: ScoreInsight[],\n): DimensionScore {\n const weight = 20;\n\n const dist = analysis.riskProfile.distribution;\n const totalFiles = analysis.totalFiles;\n\n // What % of critical+high risk files are included in the selection?\n const criticalFiles = analysis.files.filter((f) => f.riskScore >= 80);\n const highFiles = analysis.files.filter((f) => f.riskScore >= 60 && f.riskScore < 80);\n const selectedPaths = new Set(selection.files.map((f) => f.relativePath));\n\n const criticalIncluded = criticalFiles.filter((f) => selectedPaths.has(f.relativePath)).length;\n const highIncluded = highFiles.filter((f) => selectedPaths.has(f.relativePath)).length;\n\n const criticalCoverage = criticalFiles.length > 0\n ? criticalIncluded / criticalFiles.length\n : 1;\n const highCoverage = highFiles.length > 0\n ? highIncluded / highFiles.length\n : 1;\n\n // Risk distribution health: fewer critical files = healthier\n const criticalRatio = totalFiles > 0 ? dist.critical / totalFiles : 0;\n const healthScore = Math.max(0, 1 - criticalRatio * 5); // penalize heavy critical\n\n const raw = (criticalCoverage * 0.5 + highCoverage * 0.3 + healthScore * 0.2) * 100;\n const score = Math.min(100, Math.max(0, Math.round(raw)));\n const weighted = (score / 100) * weight;\n\n if (criticalCoverage === 1 && criticalFiles.length > 0) {\n insights.push({\n type: 'strength',\n title: 'All critical files included',\n detail: `${criticalFiles.length} critical-risk files are captured in context`,\n impact: 'high',\n });\n }\n\n if (criticalRatio > 0.2) {\n insights.push({\n type: 'opportunity',\n title: 'High concentration of critical files',\n detail: `${dist.critical} files (${Math.round(criticalRatio * 100)}%) are critical risk. Consider refactoring complex modules.`,\n impact: 'medium',\n });\n }\n\n return {\n score,\n weight,\n weighted,\n detail: `${criticalIncluded}/${criticalFiles.length} critical + ${highIncluded}/${highFiles.length} high-risk files included`,\n };\n}\n\nfunction scoreStructure(\n analysis: ProjectAnalysis,\n insights: ScoreInsight[],\n): DimensionScore {\n const weight = 15;\n\n const graph = analysis.graph;\n const totalFiles = analysis.totalFiles;\n\n // Cluster cohesion: well-organized projects have clear clusters\n const avgCohesion = graph.clusters.length > 0\n ? graph.clusters.reduce((s, c) => s + c.cohesion, 0) / graph.clusters.length\n : 0;\n\n // Orphan penalty: too many orphans = poor structure\n const orphanRatio = totalFiles > 0 ? graph.orphans.length / totalFiles : 0;\n\n // Hub concentration: too few hubs = flat, too many = coupled\n const hubRatio = totalFiles > 0 ? graph.hubs.length / totalFiles : 0;\n const hubHealth = hubRatio > 0.02 && hubRatio < 0.15 ? 1 : Math.max(0, 1 - Math.abs(hubRatio - 0.08) * 10);\n\n // Type coverage: having type files is good for AI\n const typeFiles = analysis.files.filter((f) => f.kind === 'type').length;\n const typeRatio = totalFiles > 0 ? typeFiles / totalFiles : 0;\n const typeScore = Math.min(1, typeRatio * 10); // reward up to 10% types\n\n const raw = (avgCohesion * 0.3 + (1 - orphanRatio) * 0.3 + hubHealth * 0.2 + typeScore * 0.2) * 100;\n const score = Math.min(100, Math.max(0, Math.round(raw)));\n const weighted = (score / 100) * weight;\n\n if (orphanRatio > 0.5) {\n insights.push({\n type: 'weakness',\n title: 'Many orphan files',\n detail: `${graph.orphans.length} files (${Math.round(orphanRatio * 100)}%) have no imports/exports. AI gets less context from the dependency graph.`,\n impact: 'medium',\n });\n }\n\n if (graph.clusters.length > 0 && avgCohesion > 0.7) {\n insights.push({\n type: 'strength',\n title: 'Well-organized module structure',\n detail: `${graph.clusters.length} cohesive clusters (avg cohesion: ${(avgCohesion * 100).toFixed(0)}%). CTO can efficiently select relevant modules.`,\n impact: 'medium',\n });\n }\n\n return {\n score,\n weight,\n weighted,\n detail: `${graph.clusters.length} clusters, ${graph.orphans.length} orphans, ${graph.hubs.length} hubs`,\n };\n}\n\nfunction scoreGovernance(\n analysis: ProjectAnalysis,\n insights: ScoreInsight[],\n): DimensionScore {\n const weight = 10;\n\n // Check for config/policy/type organization\n const hasTypes = analysis.files.some((f) => f.kind === 'type');\n const hasConfig = analysis.files.some((f) => f.kind === 'config');\n const hasTests = analysis.files.some((f) => f.kind === 'test');\n\n let score = 50; // baseline\n\n if (hasTypes) { score += 15; }\n if (hasConfig) { score += 10; }\n if (hasTests) { score += 15; }\n\n // Stack detection: known stacks get better AI support\n if (analysis.stack.length > 0) { score += 10; }\n\n score = Math.min(100, score);\n const weighted = (score / 100) * weight;\n\n if (!hasTests) {\n insights.push({\n type: 'opportunity',\n title: 'No test files detected',\n detail: 'Adding tests helps CTO understand code intent and provides better context boundaries.',\n impact: 'low',\n });\n }\n\n if (!hasTypes) {\n insights.push({\n type: 'opportunity',\n title: 'No type definition files',\n detail: 'Type files dramatically improve AI code generation accuracy. Consider adding interfaces/types.',\n impact: 'medium',\n });\n }\n\n return {\n score,\n weight,\n weighted,\n detail: `types:${hasTypes ? '✓' : '✗'} tests:${hasTests ? '✓' : '✗'} config:${hasConfig ? '✓' : '✗'} stack:${analysis.stack.join(',') || 'unknown'}`,\n };\n}\n\n// ===== HELPERS =====\n\nfunction scoreToGrade(score: number): Grade {\n if (score >= 95) return 'A+';\n if (score >= 90) return 'A';\n if (score >= 85) return 'A-';\n if (score >= 80) return 'B+';\n if (score >= 75) return 'B';\n if (score >= 70) return 'B-';\n if (score >= 65) return 'C+';\n if (score >= 60) return 'C';\n if (score >= 55) return 'C-';\n if (score >= 40) return 'D';\n return 'F';\n}\n\n// ===== RENDERING =====\n\n/**\n * Render the Context Score as a beautiful terminal-friendly string.\n */\nexport function renderContextScore(score: ContextScore): string {\n const lines: string[] = [];\n\n const gradeColor = score.grade.startsWith('A') ? '🟢'\n : score.grade.startsWith('B') ? '🔵'\n : score.grade.startsWith('C') ? '🟡'\n : '🔴';\n\n lines.push('');\n lines.push(` ╔══════════════════════════════════════════════════╗`);\n lines.push(` ║ ║`);\n lines.push(` ║ ${gradeColor} Context Score™ ${padCenter(score.overall.toString(), 3)} / 100 Grade: ${padCenter(score.grade, 2)} ║`);\n lines.push(` ║ ║`);\n lines.push(` ║ ${score.meta.projectName.padEnd(20).substring(0, 20)} ║`);\n lines.push(` ║ ${score.meta.totalFiles} files · ${Math.round(score.meta.totalTokens / 1000)}K tokens ║`);\n lines.push(` ║ ║`);\n lines.push(` ╠══════════════════════════════════════════════════╣`);\n\n // Dimensions\n const dims = [\n { label: 'Efficiency', dim: score.dimensions.efficiency },\n { label: 'Coverage', dim: score.dimensions.coverage },\n { label: 'Risk Control', dim: score.dimensions.riskControl },\n { label: 'Structure', dim: score.dimensions.structure },\n { label: 'Governance', dim: score.dimensions.governance },\n ];\n\n lines.push(` ║ ║`);\n\n for (const { label, dim } of dims) {\n const bar = renderBar(dim.score, 20);\n const pct = dim.score.toString().padStart(3);\n lines.push(` ║ ${label.padEnd(14)} ${bar} ${pct}% (×${dim.weight}%) ║`);\n }\n\n lines.push(` ║ ║`);\n lines.push(` ╠══════════════════════════════════════════════════╣`);\n\n // Comparison\n lines.push(` ║ ║`);\n lines.push(` ║ 💰 vs. Sending Everything: ║`);\n lines.push(` ║ Tokens saved: ${formatNumber(score.comparison.savedTokens).padEnd(12)} (${score.comparison.savedPercent}%) ║`);\n lines.push(` ║ Monthly savings: $${score.comparison.monthlySavingsUSD.toFixed(2).padEnd(10)} ║`);\n lines.push(` ║ (${score.comparison.optimizedTokens.toLocaleString()} vs ${score.comparison.naiveTokens.toLocaleString()} tokens) ║`);\n lines.push(` ║ ║`);\n\n // Insights\n if (score.insights.length > 0) {\n lines.push(` ╠══════════════════════════════════════════════════╣`);\n lines.push(` ║ ║`);\n\n const top = score.insights.slice(0, 5);\n for (const insight of top) {\n const icon = insight.type === 'strength' ? '✅'\n : insight.type === 'weakness' ? '⚠️'\n : '💡';\n const title = insight.title.substring(0, 44).padEnd(44);\n lines.push(` ║ ${icon} ${title} ║`);\n }\n\n lines.push(` ║ ║`);\n }\n\n lines.push(` ╚══════════════════════════════════════════════════╝`);\n lines.push('');\n\n return lines.join('\\n');\n}\n\nfunction renderBar(pct: number, width: number): string {\n const filled = Math.round((pct / 100) * width);\n const empty = width - filled;\n return '█'.repeat(filled) + '░'.repeat(empty);\n}\n\nfunction padCenter(str: string, width: number): string {\n const pad = Math.max(0, width - str.length);\n const left = Math.floor(pad / 2);\n return ' '.repeat(left) + str + ' '.repeat(pad - left);\n}\n\nfunction formatNumber(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n return n.toString();\n}\n","import type { ProjectAnalysis } from '../types/engine.js';\nimport { selectContext } from './selector.js';\n\n// ===== Benchmark Engine =====\n//\n// Proves CTO works with real numbers. Compares three strategies:\n// 1. CTO (risk-aware, deterministic selection)\n// 2. Naive (send everything — what most people do)\n// 3. Random (randomly pick files up to budget — baseline)\n//\n// Measures: tokens, coverage, cost, time\n\nexport interface BenchmarkResult {\n project: string;\n totalFiles: number;\n totalTokens: number;\n budget: number;\n task: string;\n\n strategies: {\n cto: StrategyResult;\n naive: StrategyResult;\n random: StrategyResult;\n };\n\n winner: 'cto' | 'naive' | 'random';\n ctoAdvantage: {\n vsNaiveTokensSaved: number;\n vsNaiveTokensSavedPercent: number;\n vsRandomCoverageGain: number;\n vsNaiveCostSavedMonthlyUSD: number;\n };\n}\n\nexport interface StrategyResult {\n filesSelected: number;\n tokensUsed: number;\n coverageScore: number;\n criticalFilesCovered: number;\n criticalFilesTotal: number;\n highRiskCovered: number;\n highRiskTotal: number;\n costPerInteractionUSD: number;\n timeMs: number;\n}\n\n/**\n * Run a full benchmark comparing CTO vs naive vs random selection.\n */\nexport async function runBenchmark(\n analysis: ProjectAnalysis,\n task: string = 'general code review and refactoring',\n budget: number = 50_000,\n): Promise<BenchmarkResult> {\n const criticalFiles = analysis.files.filter((f) => f.riskScore >= 80);\n const highRiskFiles = analysis.files.filter((f) => f.riskScore >= 60 && f.riskScore < 80);\n\n // ===== STRATEGY 1: CTO (risk-aware selection) =====\n const ctoStart = performance.now();\n const ctoSelection = await selectContext({ task, analysis, budget });\n const ctoTime = performance.now() - ctoStart;\n\n const ctoSelectedPaths = new Set(ctoSelection.files.map((f) => f.relativePath));\n const ctoCritical = criticalFiles.filter((f) => ctoSelectedPaths.has(f.relativePath)).length;\n const ctoHigh = highRiskFiles.filter((f) => ctoSelectedPaths.has(f.relativePath)).length;\n\n const cto: StrategyResult = {\n filesSelected: ctoSelection.files.length,\n tokensUsed: ctoSelection.totalTokens,\n coverageScore: ctoSelection.coverage.score,\n criticalFilesCovered: ctoCritical,\n criticalFilesTotal: criticalFiles.length,\n highRiskCovered: ctoHigh,\n highRiskTotal: highRiskFiles.length,\n costPerInteractionUSD: (ctoSelection.totalTokens / 1_000_000) * 3, // Sonnet pricing\n timeMs: Math.round(ctoTime),\n };\n\n // ===== STRATEGY 2: NAIVE (send everything up to budget) =====\n const naiveStart = performance.now();\n const naiveFiles = [...analysis.files].sort((a, b) => a.relativePath.localeCompare(b.relativePath));\n let naiveTokens = 0;\n let naiveCount = 0;\n const naiveSelectedPaths = new Set<string>();\n\n for (const f of naiveFiles) {\n if (naiveTokens + f.tokens <= budget) {\n naiveTokens += f.tokens;\n naiveCount++;\n naiveSelectedPaths.add(f.relativePath);\n }\n }\n // If budget exceeds total, include everything\n if (naiveTokens === 0 && analysis.totalTokens <= budget) {\n naiveTokens = analysis.totalTokens;\n naiveCount = analysis.totalFiles;\n for (const f of analysis.files) naiveSelectedPaths.add(f.relativePath);\n }\n const naiveTime = performance.now() - naiveStart;\n\n const naiveCritical = criticalFiles.filter((f) => naiveSelectedPaths.has(f.relativePath)).length;\n const naiveHigh = highRiskFiles.filter((f) => naiveSelectedPaths.has(f.relativePath)).length;\n\n // Naive coverage: just count how many of the relevant files are included\n const naiveCoverage = analysis.totalFiles > 0\n ? Math.round((naiveCount / analysis.totalFiles) * 100)\n : 0;\n\n const naive: StrategyResult = {\n filesSelected: naiveCount,\n tokensUsed: naiveTokens > 0 ? naiveTokens : analysis.totalTokens,\n coverageScore: naiveTokens > 0 ? naiveCoverage : 100,\n criticalFilesCovered: naiveCritical,\n criticalFilesTotal: criticalFiles.length,\n highRiskCovered: naiveHigh,\n highRiskTotal: highRiskFiles.length,\n costPerInteractionUSD: ((naiveTokens > 0 ? naiveTokens : analysis.totalTokens) / 1_000_000) * 3,\n timeMs: Math.round(naiveTime),\n };\n\n // ===== STRATEGY 3: RANDOM (randomly pick files up to budget) =====\n const randomStart = performance.now();\n const shuffled = [...analysis.files].sort(() => Math.random() - 0.5);\n let randomTokens = 0;\n let randomCount = 0;\n const randomSelectedPaths = new Set<string>();\n\n for (const f of shuffled) {\n if (randomTokens + f.tokens <= budget) {\n randomTokens += f.tokens;\n randomCount++;\n randomSelectedPaths.add(f.relativePath);\n }\n }\n const randomTime = performance.now() - randomStart;\n\n const randomCritical = criticalFiles.filter((f) => randomSelectedPaths.has(f.relativePath)).length;\n const randomHigh = highRiskFiles.filter((f) => randomSelectedPaths.has(f.relativePath)).length;\n const randomCoverage = analysis.totalFiles > 0\n ? Math.round((randomCount / analysis.totalFiles) * 100)\n : 0;\n\n const random: StrategyResult = {\n filesSelected: randomCount,\n tokensUsed: randomTokens,\n coverageScore: randomCoverage,\n criticalFilesCovered: randomCritical,\n criticalFilesTotal: criticalFiles.length,\n highRiskCovered: randomHigh,\n highRiskTotal: highRiskFiles.length,\n costPerInteractionUSD: (randomTokens / 1_000_000) * 3,\n timeMs: Math.round(randomTime),\n };\n\n // ===== DETERMINE WINNER =====\n // Score: coverage * 0.5 + criticalCoverage * 0.3 + tokenEfficiency * 0.2\n const ctoScore = computeStrategyScore(cto, budget);\n const naiveScore = computeStrategyScore(naive, budget);\n const randomScore = computeStrategyScore(random, budget);\n\n const winner = ctoScore >= naiveScore && ctoScore >= randomScore ? 'cto'\n : naiveScore >= randomScore ? 'naive' : 'random';\n\n // Monthly savings: 40 interactions/day × 20 days\n const interactionsPerMonth = 800;\n const vsNaiveCostSaved = (naive.costPerInteractionUSD - cto.costPerInteractionUSD) * interactionsPerMonth;\n\n return {\n project: analysis.projectName,\n totalFiles: analysis.totalFiles,\n totalTokens: analysis.totalTokens,\n budget,\n task,\n strategies: { cto, naive, random },\n winner,\n ctoAdvantage: {\n vsNaiveTokensSaved: naive.tokensUsed - cto.tokensUsed,\n vsNaiveTokensSavedPercent: naive.tokensUsed > 0\n ? Math.round(((naive.tokensUsed - cto.tokensUsed) / naive.tokensUsed) * 100)\n : 0,\n vsRandomCoverageGain: cto.coverageScore - random.coverageScore,\n vsNaiveCostSavedMonthlyUSD: Math.round(vsNaiveCostSaved * 100) / 100,\n },\n };\n}\n\nfunction computeStrategyScore(strategy: StrategyResult, budget: number): number {\n const coverageWeight = strategy.coverageScore / 100;\n const criticalWeight = strategy.criticalFilesTotal > 0\n ? strategy.criticalFilesCovered / strategy.criticalFilesTotal\n : 1;\n const efficiency = budget > 0 ? 1 - (strategy.tokensUsed / budget) : 0;\n\n return coverageWeight * 0.5 + criticalWeight * 0.3 + Math.max(0, efficiency) * 0.2;\n}\n\n/**\n * Render benchmark results as a formatted comparison table.\n */\nexport function renderBenchmark(result: BenchmarkResult): string {\n const lines: string[] = [];\n const { cto, naive, random } = result.strategies;\n\n lines.push('');\n lines.push(` ╔══════════════════════════════════════════════════════════════╗`);\n lines.push(` ║ ⚡ CTO Benchmark — ${result.project.substring(0, 20).padEnd(20)} ║`);\n lines.push(` ╠══════════════════════════════════════════════════════════════╣`);\n lines.push(` ║ ║`);\n lines.push(` ║ ${pad('Metric', 20)} ${pad('CTO', 12)} ${pad('Naive', 12)} ${pad('Random', 12)} ║`);\n lines.push(` ║ ${'─'.repeat(56)} ║`);\n lines.push(` ║ ${pad('Files selected', 20)} ${pad(cto.filesSelected.toString(), 12)} ${pad(naive.filesSelected.toString(), 12)} ${pad(random.filesSelected.toString(), 12)} ║`);\n lines.push(` ║ ${pad('Tokens used', 20)} ${pad(fmt(cto.tokensUsed), 12)} ${pad(fmt(naive.tokensUsed), 12)} ${pad(fmt(random.tokensUsed), 12)} ║`);\n lines.push(` ║ ${pad('Coverage', 20)} ${pad(cto.coverageScore + '%', 12)} ${pad(naive.coverageScore + '%', 12)} ${pad(random.coverageScore + '%', 12)} ║`);\n lines.push(` ║ ${pad('Critical files', 20)} ${pad(`${cto.criticalFilesCovered}/${cto.criticalFilesTotal}`, 12)} ${pad(`${naive.criticalFilesCovered}/${naive.criticalFilesTotal}`, 12)} ${pad(`${random.criticalFilesCovered}/${random.criticalFilesTotal}`, 12)} ║`);\n lines.push(` ║ ${pad('High-risk files', 20)} ${pad(`${cto.highRiskCovered}/${cto.highRiskTotal}`, 12)} ${pad(`${naive.highRiskCovered}/${naive.highRiskTotal}`, 12)} ${pad(`${random.highRiskCovered}/${random.highRiskTotal}`, 12)} ║`);\n lines.push(` ║ ${pad('Cost/interaction', 20)} ${pad('$' + cto.costPerInteractionUSD.toFixed(4), 12)} ${pad('$' + naive.costPerInteractionUSD.toFixed(4), 12)} ${pad('$' + random.costPerInteractionUSD.toFixed(4), 12)} ║`);\n lines.push(` ║ ${pad('Time', 20)} ${pad(cto.timeMs + 'ms', 12)} ${pad(naive.timeMs + 'ms', 12)} ${pad(random.timeMs + 'ms', 12)} ║`);\n lines.push(` ║ ║`);\n lines.push(` ╠══════════════════════════════════════════════════════════════╣`);\n lines.push(` ║ ║`);\n lines.push(` ║ 🏆 Winner: ${result.winner.toUpperCase().padEnd(48)} ║`);\n\n if (result.ctoAdvantage.vsNaiveTokensSavedPercent > 0) {\n lines.push(` ║ 📉 ${result.ctoAdvantage.vsNaiveTokensSavedPercent}% fewer tokens than naive ║`);\n }\n if (result.ctoAdvantage.vsRandomCoverageGain > 0) {\n lines.push(` ║ 📈 +${result.ctoAdvantage.vsRandomCoverageGain}% better coverage than random ║`);\n }\n if (result.ctoAdvantage.vsNaiveCostSavedMonthlyUSD > 0) {\n lines.push(` ║ 💰 $${result.ctoAdvantage.vsNaiveCostSavedMonthlyUSD.toFixed(2)}/mo saved vs naive (800 interactions) ║`);\n }\n\n lines.push(` ║ ║`);\n lines.push(` ╚══════════════════════════════════════════════════════════════╝`);\n lines.push('');\n\n return lines.join('\\n');\n}\n\nfunction pad(s: string, w: number): string { return s.padEnd(w).substring(0, w); }\nfunction fmt(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n return n.toString();\n}\n","import { resolve } from 'node:path';\nimport { readFile } from 'node:fs/promises';\nimport type { ProjectAnalysis, AnalyzedFile, ContextSelection } from '../types/engine.js';\nimport type { TaskType } from '../types/interact.js';\nimport { selectContext } from './selector.js';\nimport { buildAdjacencyList, bfsBidirectional } from './graph-utils.js';\nimport { classifyTask } from '../interact/router.js';\nimport { buildPrompt } from '../interact/prompt.js';\nimport { countTokensChars4 } from './tokenizer.js';\n\n// ===== Quality Benchmark =====\n//\n// Proves that CTO context → better AI output by comparing prompt quality\n// across three strategies: CTO (risk-aware), Naive (alphabetical), Random.\n//\n// Metrics:\n// 1. Relevance Score — What % of included files are actually relevant to the task?\n// 2. Completeness Score — What % of task-critical files are included?\n// 3. Noise Ratio — What % of tokens are wasted on irrelevant files?\n// 4. Type Coverage — Are type definitions included for the selected files?\n// 5. Dependency Closure — Are transitive deps of relevant files included?\n//\n// These are PROXY metrics for output quality. The claim:\n// Higher relevance + completeness → fewer hallucinations + more correct code.\n\nexport interface QualityBenchmarkResult {\n project: string;\n task: string;\n taskType: TaskType;\n budget: number;\n\n strategies: {\n cto: QualityMetrics;\n naive: QualityMetrics;\n random: QualityMetrics;\n };\n\n comparison: {\n ctoVsNaiveRelevance: number;\n ctoVsRandomRelevance: number;\n ctoVsNaiveCompleteness: number;\n ctoVsRandomCompleteness: number;\n ctoNoiseReduction: number;\n };\n\n prompts: {\n cto: { rendered: string; tokens: number };\n naive: { rendered: string; tokens: number };\n };\n\n verdict: string;\n}\n\nexport interface QualityMetrics {\n filesSelected: number;\n tokensUsed: number;\n\n relevanceScore: number;\n completenessScore: number;\n noiseRatio: number;\n typeCoverage: number;\n dependencyClosure: number;\n\n relevantFilesIncluded: number;\n relevantFilesTotal: number;\n typeFilesIncluded: number;\n typeFilesNeeded: number;\n depsIncluded: number;\n depsNeeded: number;\n}\n\n// ===== MAIN API =====\n\n/**\n * Run a quality benchmark comparing CTO vs naive vs random context selection.\n * Measures relevance, completeness, noise, and dependency closure.\n */\nexport async function runQualityBenchmark(\n analysis: ProjectAnalysis,\n task: string,\n budget: number = 50_000,\n): Promise<QualityBenchmarkResult> {\n const taskType = classifyTask(task);\n\n // 1. Identify task-relevant files using keyword matching + graph expansion\n const relevantFiles = identifyRelevantFiles(analysis, task, taskType);\n const relevantPaths = new Set(relevantFiles.map((f) => f.relativePath));\n\n // 2. Identify type files needed by relevant files\n const typeFilesNeeded = findTypeFiles(analysis, relevantFiles);\n const typePaths = new Set(typeFilesNeeded.map((f) => f.relativePath));\n\n // 3. Identify transitive deps of relevant files\n const adj = buildAdjacencyList(analysis.graph.edges);\n const depsNeeded = bfsBidirectional(\n relevantFiles.map((f) => f.relativePath),\n adj,\n 2,\n );\n\n // 4. Run CTO selection\n const ctoSelection = await selectContext({ task, analysis, budget });\n const ctoMetrics = computeMetrics(\n ctoSelection.files.map((f) => f.relativePath),\n ctoSelection.totalTokens,\n analysis,\n relevantPaths,\n typePaths,\n depsNeeded,\n );\n\n // 5. Run Naive selection (alphabetical, up to budget)\n const naiveFiles = [...analysis.files]\n .sort((a, b) => a.relativePath.localeCompare(b.relativePath));\n const naiveSelected: string[] = [];\n let naiveTokens = 0;\n for (const f of naiveFiles) {\n if (naiveTokens + f.tokens <= budget) {\n naiveSelected.push(f.relativePath);\n naiveTokens += f.tokens;\n }\n }\n if (naiveSelected.length === 0 && analysis.totalTokens <= budget) {\n for (const f of analysis.files) naiveSelected.push(f.relativePath);\n naiveTokens = analysis.totalTokens;\n }\n const naiveMetrics = computeMetrics(\n naiveSelected, naiveTokens, analysis, relevantPaths, typePaths, depsNeeded,\n );\n\n // 6. Run Random selection\n const shuffled = [...analysis.files].sort(() => Math.random() - 0.5);\n const randomSelected: string[] = [];\n let randomTokens = 0;\n for (const f of shuffled) {\n if (randomTokens + f.tokens <= budget) {\n randomSelected.push(f.relativePath);\n randomTokens += f.tokens;\n }\n }\n const randomMetrics = computeMetrics(\n randomSelected, randomTokens, analysis, relevantPaths, typePaths, depsNeeded,\n );\n\n // 7. Generate actual prompts for CTO vs Naive\n const ctoPrompt = buildPrompt({\n task,\n taskType,\n analysis,\n selection: ctoSelection,\n enableCoT: true,\n });\n\n // Build a fake selection for naive to generate its prompt\n const naiveSelectionFiles = naiveSelected.map((p) => {\n const f = analysis.files.find((af) => af.relativePath === p);\n return {\n relativePath: p,\n tokens: f?.tokens ?? 0,\n originalTokens: f?.tokens ?? 0,\n pruneLevel: 'full' as const,\n riskScore: f?.riskScore ?? 0,\n reason: 'alphabetical inclusion',\n };\n });\n const naiveFakeSelection: ContextSelection = {\n files: naiveSelectionFiles,\n totalTokens: naiveTokens,\n budget,\n usedPercent: budget > 0 ? (naiveTokens / budget) * 100 : 0,\n coverage: { score: naiveMetrics.completenessScore, missingCritical: [], missingRelevant: [], relevantFiles: [], includedRelevant: [], explanation: 'naive selection' },\n riskScore: 0,\n deterministic: false,\n hash: '',\n decisions: [],\n };\n const naivePrompt = buildPrompt({\n task,\n taskType,\n analysis,\n selection: naiveFakeSelection,\n enableCoT: true,\n });\n\n // 8. Comparison\n const comparison = {\n ctoVsNaiveRelevance: ctoMetrics.relevanceScore - naiveMetrics.relevanceScore,\n ctoVsRandomRelevance: ctoMetrics.relevanceScore - randomMetrics.relevanceScore,\n ctoVsNaiveCompleteness: ctoMetrics.completenessScore - naiveMetrics.completenessScore,\n ctoVsRandomCompleteness: ctoMetrics.completenessScore - randomMetrics.completenessScore,\n ctoNoiseReduction: naiveMetrics.noiseRatio - ctoMetrics.noiseRatio,\n };\n\n // 9. Verdict\n const verdict = generateVerdict(ctoMetrics, naiveMetrics, randomMetrics, comparison);\n\n return {\n project: analysis.projectName,\n task,\n taskType,\n budget,\n strategies: {\n cto: ctoMetrics,\n naive: naiveMetrics,\n random: randomMetrics,\n },\n comparison,\n prompts: {\n cto: { rendered: ctoPrompt.rendered, tokens: ctoPrompt.totalTokens },\n naive: { rendered: naivePrompt.rendered, tokens: naivePrompt.totalTokens },\n },\n verdict,\n };\n}\n\n// ===== RELEVANCE IDENTIFICATION =====\n\nfunction identifyRelevantFiles(\n analysis: ProjectAnalysis,\n task: string,\n taskType: TaskType,\n): AnalyzedFile[] {\n const keywords = extractKeywords(task);\n const scored = new Map<string, number>();\n\n for (const file of analysis.files) {\n let relevance = 0;\n\n // Keyword match in path\n for (const kw of keywords) {\n if (file.relativePath.toLowerCase().includes(kw)) {\n relevance += 10;\n }\n }\n\n // High risk = likely important\n if (file.riskScore >= 60) relevance += 5;\n\n // Hub files are often relevant\n if (file.isHub) relevance += 3;\n\n // Entry points\n if (file.kind === 'entry') relevance += 3;\n\n // Type files that define interfaces used across the project\n if (file.kind === 'type') relevance += 2;\n\n // Task-type specific boosts\n if (taskType === 'test' && file.kind === 'test') relevance += 8;\n if (taskType === 'refactor' && file.complexity > 10) relevance += 4;\n if (taskType === 'debug' && file.riskScore >= 40) relevance += 4;\n\n if (relevance > 0) {\n scored.set(file.relativePath, relevance);\n }\n }\n\n // Expand via dependencies\n const adj = buildAdjacencyList(analysis.graph.edges);\n const seeds = [...scored.keys()];\n const expanded = bfsBidirectional(seeds, adj, 1);\n\n // Add expanded files with lower score\n for (const path of expanded) {\n if (!scored.has(path)) {\n scored.set(path, 1);\n }\n }\n\n // Return files sorted by relevance\n return analysis.files\n .filter((f) => scored.has(f.relativePath))\n .sort((a, b) => (scored.get(b.relativePath) ?? 0) - (scored.get(a.relativePath) ?? 0));\n}\n\nfunction extractKeywords(task: string): string[] {\n const stopWords = new Set([\n 'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being',\n 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could',\n 'should', 'may', 'might', 'can', 'shall', 'to', 'of', 'in', 'for',\n 'on', 'with', 'at', 'by', 'from', 'as', 'into', 'through', 'and',\n 'but', 'or', 'nor', 'not', 'so', 'yet', 'both', 'either', 'neither',\n 'this', 'that', 'these', 'those', 'it', 'its', 'my', 'your', 'our',\n 'their', 'his', 'her', 'fix', 'add', 'remove', 'update', 'change',\n 'refactor', 'implement', 'create', 'build', 'make', 'code', 'file',\n ]);\n\n return task\n .toLowerCase()\n .replace(/[^a-z0-9\\s]/g, '')\n .split(/\\s+/)\n .filter((w) => w.length > 2 && !stopWords.has(w));\n}\n\nfunction findTypeFiles(\n analysis: ProjectAnalysis,\n relevantFiles: AnalyzedFile[],\n): AnalyzedFile[] {\n const adj = buildAdjacencyList(analysis.graph.edges);\n const typeFiles = new Set<string>();\n\n for (const file of relevantFiles) {\n // Find forward deps that are type files\n const deps = adj.forward.get(file.relativePath) ?? [];\n for (const dep of deps) {\n const depFile = analysis.files.find((f) => f.relativePath === dep);\n if (depFile && depFile.kind === 'type') {\n typeFiles.add(dep);\n }\n }\n }\n\n return analysis.files.filter((f) => typeFiles.has(f.relativePath));\n}\n\n// ===== METRICS COMPUTATION =====\n\nfunction computeMetrics(\n selectedPaths: string[],\n tokensUsed: number,\n analysis: ProjectAnalysis,\n relevantPaths: Set<string>,\n typePaths: Set<string>,\n depsNeeded: Set<string>,\n): QualityMetrics {\n const selected = new Set(selectedPaths);\n\n // Relevance: what % of selected files are actually relevant?\n const relevantIncluded = selectedPaths.filter((p) => relevantPaths.has(p)).length;\n const relevanceScore = selectedPaths.length > 0\n ? Math.round((relevantIncluded / selectedPaths.length) * 100)\n : 0;\n\n // Completeness: what % of relevant files are included?\n const completenessHits = [...relevantPaths].filter((p) => selected.has(p)).length;\n const completenessScore = relevantPaths.size > 0\n ? Math.round((completenessHits / relevantPaths.size) * 100)\n : 100;\n\n // Noise: what % of tokens are spent on irrelevant files?\n let irrelevantTokens = 0;\n for (const path of selectedPaths) {\n if (!relevantPaths.has(path)) {\n const f = analysis.files.find((af) => af.relativePath === path);\n irrelevantTokens += f?.tokens ?? 0;\n }\n }\n const noiseRatio = tokensUsed > 0\n ? Math.min(100, Math.round((irrelevantTokens / tokensUsed) * 100))\n : 0;\n\n // Type coverage: are needed type files included?\n const typeIncluded = [...typePaths].filter((p) => selected.has(p)).length;\n const typeCoverage = typePaths.size > 0\n ? Math.round((typeIncluded / typePaths.size) * 100)\n : 100;\n\n // Dependency closure: are transitive deps included?\n const depsIncluded = [...depsNeeded].filter((p) => selected.has(p)).length;\n const dependencyClosure = depsNeeded.size > 0\n ? Math.round((depsIncluded / depsNeeded.size) * 100)\n : 100;\n\n return {\n filesSelected: selectedPaths.length,\n tokensUsed,\n relevanceScore,\n completenessScore,\n noiseRatio,\n typeCoverage,\n dependencyClosure,\n relevantFilesIncluded: relevantIncluded,\n relevantFilesTotal: relevantPaths.size,\n typeFilesIncluded: typeIncluded,\n typeFilesNeeded: typePaths.size,\n depsIncluded,\n depsNeeded: depsNeeded.size,\n };\n}\n\n// ===== VERDICT =====\n\nfunction generateVerdict(\n cto: QualityMetrics,\n naive: QualityMetrics,\n random: QualityMetrics,\n comp: QualityBenchmarkResult['comparison'],\n): string {\n const lines: string[] = [];\n\n lines.push('## Quality Verdict');\n lines.push('');\n\n // Headline\n if (comp.ctoVsNaiveRelevance > 0 && comp.ctoVsNaiveCompleteness > 0) {\n lines.push(`**CTO produces higher-quality context than both naive and random selection.**`);\n } else if (comp.ctoVsRandomRelevance > 0) {\n lines.push(`**CTO produces higher-quality context than random selection.**`);\n } else {\n lines.push(`**All strategies perform similarly for this task.**`);\n }\n lines.push('');\n\n // Relevance\n lines.push(`### Relevance (higher = less hallucination risk)`);\n lines.push(`- CTO: ${cto.relevanceScore}% of included files are relevant`);\n lines.push(`- Naive: ${naive.relevanceScore}% relevant`);\n lines.push(`- Random: ${random.relevanceScore}% relevant`);\n if (comp.ctoVsNaiveRelevance > 0) {\n lines.push(`- **CTO includes ${comp.ctoVsNaiveRelevance}% more relevant files than naive**`);\n }\n lines.push('');\n\n // Completeness\n lines.push(`### Completeness (higher = more correct code generation)`);\n lines.push(`- CTO: ${cto.completenessScore}% of required files included`);\n lines.push(`- Naive: ${naive.completenessScore}% complete`);\n lines.push(`- Random: ${random.completenessScore}% complete`);\n if (comp.ctoVsNaiveCompleteness > 0) {\n lines.push(`- **CTO captures ${comp.ctoVsNaiveCompleteness}% more required files**`);\n }\n lines.push('');\n\n // Noise\n lines.push(`### Noise (lower = less distraction for the AI)`);\n lines.push(`- CTO: ${cto.noiseRatio}% noise`);\n lines.push(`- Naive: ${naive.noiseRatio}% noise`);\n lines.push(`- Random: ${random.noiseRatio}% noise`);\n if (comp.ctoNoiseReduction > 0) {\n lines.push(`- **CTO reduces noise by ${comp.ctoNoiseReduction} percentage points**`);\n }\n lines.push('');\n\n // Type coverage\n lines.push(`### Type Coverage (higher = fewer type errors in generated code)`);\n lines.push(`- CTO: ${cto.typeCoverage}% | Naive: ${naive.typeCoverage}% | Random: ${random.typeCoverage}%`);\n lines.push('');\n\n // Dependency closure\n lines.push(`### Dependency Closure (higher = AI understands import chain)`);\n lines.push(`- CTO: ${cto.dependencyClosure}% | Naive: ${naive.dependencyClosure}% | Random: ${random.dependencyClosure}%`);\n\n return lines.join('\\n');\n}\n\n// ===== RENDERING =====\n\nexport function renderQualityBenchmark(result: QualityBenchmarkResult): string {\n const { cto, naive, random } = result.strategies;\n const lines: string[] = [];\n\n lines.push('');\n lines.push(` ╔══════════════════════════════════════════════════════════════════╗`);\n lines.push(` ║ 🔬 Quality Benchmark — ${pad(result.project, 20)} ║`);\n lines.push(` ║ Task: ${pad(result.task.substring(0, 45), 45)} ║`);\n lines.push(` ╠══════════════════════════════════════════════════════════════════╣`);\n lines.push(` ║ ║`);\n lines.push(` ║ ${pad('Metric', 22)} ${pad('CTO', 12)} ${pad('Naive', 12)} ${pad('Random', 12)} ║`);\n lines.push(` ║ ${'─'.repeat(58)} ║`);\n lines.push(` ║ ${pad('Relevance', 22)} ${pad(cto.relevanceScore + '%', 12)} ${pad(naive.relevanceScore + '%', 12)} ${pad(random.relevanceScore + '%', 12)} ║`);\n lines.push(` ║ ${pad('Completeness', 22)} ${pad(cto.completenessScore + '%', 12)} ${pad(naive.completenessScore + '%', 12)} ${pad(random.completenessScore + '%', 12)} ║`);\n lines.push(` ║ ${pad('Noise ratio', 22)} ${pad(cto.noiseRatio + '%', 12)} ${pad(naive.noiseRatio + '%', 12)} ${pad(random.noiseRatio + '%', 12)} ║`);\n lines.push(` ║ ${pad('Type coverage', 22)} ${pad(cto.typeCoverage + '%', 12)} ${pad(naive.typeCoverage + '%', 12)} ${pad(random.typeCoverage + '%', 12)} ║`);\n lines.push(` ║ ${pad('Dependency closure', 22)} ${pad(cto.dependencyClosure + '%', 12)} ${pad(naive.dependencyClosure + '%', 12)} ${pad(random.dependencyClosure + '%', 12)} ║`);\n lines.push(` ║ ${'─'.repeat(58)} ║`);\n lines.push(` ║ ${pad('Relevant files', 22)} ${pad(`${cto.relevantFilesIncluded}/${cto.relevantFilesTotal}`, 12)} ${pad(`${naive.relevantFilesIncluded}/${naive.relevantFilesTotal}`, 12)} ${pad(`${random.relevantFilesIncluded}/${random.relevantFilesTotal}`, 12)} ║`);\n lines.push(` ║ ${pad('Type files', 22)} ${pad(`${cto.typeFilesIncluded}/${cto.typeFilesNeeded}`, 12)} ${pad(`${naive.typeFilesIncluded}/${naive.typeFilesNeeded}`, 12)} ${pad(`${random.typeFilesIncluded}/${random.typeFilesNeeded}`, 12)} ║`);\n lines.push(` ║ ${pad('Tokens used', 22)} ${pad(fmt(cto.tokensUsed), 12)} ${pad(fmt(naive.tokensUsed), 12)} ${pad(fmt(random.tokensUsed), 12)} ║`);\n lines.push(` ║ ║`);\n\n // Comparison highlights\n const c = result.comparison;\n if (c.ctoVsNaiveRelevance > 0) {\n lines.push(` ║ 📈 +${c.ctoVsNaiveRelevance}% more relevant files than naive ║`);\n }\n if (c.ctoVsNaiveCompleteness > 0) {\n lines.push(` ║ ✅ +${c.ctoVsNaiveCompleteness}% more complete context than naive ║`);\n }\n if (c.ctoNoiseReduction > 0) {\n lines.push(` ║ 🔇 ${c.ctoNoiseReduction}% less noise than naive ║`);\n }\n\n lines.push(` ║ ║`);\n lines.push(` ╚══════════════════════════════════════════════════════════════════╝`);\n lines.push('');\n\n return lines.join('\\n');\n}\n\nfunction pad(s: string, w: number): string { return s.padEnd(w).substring(0, w); }\nfunction fmt(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n return n.toString();\n}\n","import type { TaskType, ModelChoice, ModelSpec, ModelId } from '../types/interact.js';\nimport type { ProjectAnalysis } from '../types/engine.js';\n\n// ===== MODEL REGISTRY =====\n\nexport const MODEL_REGISTRY: ModelSpec[] = [\n {\n id: 'claude-haiku-3.5',\n name: 'Claude 3.5 Haiku',\n tier: 'fast',\n pricing: { inputPerMillion: 0.80, outputPerMillion: 4.00, cacheReadPerMillion: 0.08 },\n contextWindow: 200_000,\n strengths: ['speed', 'simple-tasks', 'low-cost'],\n },\n {\n id: 'claude-sonnet-4',\n name: 'Claude Sonnet 4',\n tier: 'balanced',\n pricing: { inputPerMillion: 3.00, outputPerMillion: 15.00, cacheReadPerMillion: 0.30 },\n contextWindow: 200_000,\n strengths: ['code-generation', 'refactoring', 'balanced-reasoning'],\n },\n {\n id: 'claude-opus-4',\n name: 'Claude Opus 4',\n tier: 'reasoning',\n pricing: { inputPerMillion: 15.00, outputPerMillion: 75.00, cacheReadPerMillion: 1.50 },\n contextWindow: 200_000,\n strengths: ['deep-reasoning', 'architecture', 'complex-debugging'],\n },\n];\n\n// ===== ROUTING RULES =====\n\ninterface RoutingRule {\n task: TaskType;\n defaultModel: ModelId;\n upgradeIf: (analysis: ProjectAnalysis) => boolean;\n upgradeTo: ModelId;\n reason: string;\n upgradeReason: string;\n}\n\nconst ROUTING_RULES: RoutingRule[] = [\n {\n task: 'simple-edit',\n defaultModel: 'claude-haiku-3.5',\n upgradeIf: () => false,\n upgradeTo: 'claude-haiku-3.5',\n reason: 'Simple edits are best handled by fast models',\n upgradeReason: '',\n },\n {\n task: 'docs',\n defaultModel: 'claude-haiku-3.5',\n upgradeIf: (a) => a.totalTokens > 100_000,\n upgradeTo: 'claude-sonnet-4',\n reason: 'Documentation tasks are straightforward',\n upgradeReason: 'Large codebase — Sonnet provides better understanding',\n },\n {\n task: 'test',\n defaultModel: 'claude-sonnet-4',\n upgradeIf: (a) => a.riskProfile.overallComplexity > 15,\n upgradeTo: 'claude-opus-4',\n reason: 'Test generation requires good code understanding',\n upgradeReason: 'High complexity codebase — Opus for better test coverage',\n },\n {\n task: 'debug',\n defaultModel: 'claude-sonnet-4',\n upgradeIf: (a) => a.riskProfile.distribution.critical > 5,\n upgradeTo: 'claude-opus-4',\n reason: 'Debugging requires solid reasoning about code flow',\n upgradeReason: 'Many critical files involved — Opus for deeper analysis',\n },\n {\n task: 'refactor',\n defaultModel: 'claude-sonnet-4',\n upgradeIf: (a) => a.totalFiles > 50 && a.riskProfile.overallComplexity > 10,\n upgradeTo: 'claude-opus-4',\n reason: 'Refactoring needs good structural understanding',\n upgradeReason: 'Large + complex project — Opus for safer refactoring',\n },\n {\n task: 'review',\n defaultModel: 'claude-sonnet-4',\n upgradeIf: (a) => a.riskProfile.distribution.critical > 3,\n upgradeTo: 'claude-opus-4',\n reason: 'Code review benefits from balanced reasoning',\n upgradeReason: 'Critical code under review — Opus for thorough analysis',\n },\n {\n task: 'feature',\n defaultModel: 'claude-sonnet-4',\n upgradeIf: (a) => a.totalFiles > 100,\n upgradeTo: 'claude-opus-4',\n reason: 'Feature development needs code generation + understanding',\n upgradeReason: 'Large codebase — Opus for better integration',\n },\n {\n task: 'architecture',\n defaultModel: 'claude-opus-4',\n upgradeIf: () => false,\n upgradeTo: 'claude-opus-4',\n reason: 'Architecture decisions require deep reasoning',\n upgradeReason: '',\n },\n];\n\n// ===== TASK CLASSIFICATION =====\n\nconst TASK_KEYWORDS: Record<TaskType, string[]> = {\n debug: ['debug', 'fix', 'bug', 'error', 'issue', 'broken', 'crash', 'failing', 'wrong'],\n review: ['review', 'check', 'assess', 'evaluate', 'audit', 'inspect', 'critique'],\n refactor: ['refactor', 'restructure', 'reorganize', 'clean up', 'simplify', 'extract', 'move'],\n test: ['test', 'spec', 'coverage', 'unit test', 'integration test', 'e2e'],\n docs: ['document', 'docs', 'readme', 'jsdoc', 'comment', 'explain'],\n feature: ['add', 'implement', 'create', 'build', 'new', 'feature', 'endpoint'],\n architecture: ['architecture', 'design', 'system', 'structure', 'migrate', 'pattern'],\n 'simple-edit': ['rename', 'typo', 'update', 'change', 'modify', 'tweak', 'adjust'],\n};\n\nexport function classifyTask(taskDescription: string): TaskType {\n const lower = taskDescription.toLowerCase();\n\n // Score each task type by keyword matches\n let bestType: TaskType = 'simple-edit';\n let bestScore = 0;\n\n for (const [type, keywords] of Object.entries(TASK_KEYWORDS) as [TaskType, string[]][]) {\n let score = 0;\n for (const kw of keywords) {\n if (lower.includes(kw)) score++;\n }\n if (score > bestScore) {\n bestScore = score;\n bestType = type;\n }\n }\n\n return bestType;\n}\n\n// ===== MODEL ROUTING =====\n\nexport function routeModel(\n taskType: TaskType,\n analysis: ProjectAnalysis,\n preferredModel?: ModelId,\n): ModelChoice {\n // If user explicitly chose a model, respect it\n if (preferredModel) {\n const spec = MODEL_REGISTRY.find((m) => m.id === preferredModel);\n if (spec) {\n return {\n model: preferredModel,\n reason: 'User-specified model',\n confidence: 1.0,\n alternatives: buildAlternatives(preferredModel, taskType),\n };\n }\n }\n\n // Find routing rule for this task\n const rule = ROUTING_RULES.find((r) => r.task === taskType);\n if (!rule) {\n return {\n model: 'claude-sonnet-4',\n reason: 'Default model for unrecognized task type',\n confidence: 0.5,\n alternatives: buildAlternatives('claude-sonnet-4', taskType),\n };\n }\n\n // Check if upgrade is warranted\n const shouldUpgrade = rule.upgradeIf(analysis);\n const model = shouldUpgrade ? rule.upgradeTo : rule.defaultModel;\n const reason = shouldUpgrade ? rule.upgradeReason : rule.reason;\n\n return {\n model,\n reason,\n confidence: shouldUpgrade ? 0.8 : 0.9,\n alternatives: buildAlternatives(model, taskType),\n };\n}\n\n// ===== HELPERS =====\n\nfunction buildAlternatives(chosenModel: ModelId, taskType: TaskType) {\n return MODEL_REGISTRY\n .filter((m) => m.id !== chosenModel)\n .map((m) => {\n const chosen = MODEL_REGISTRY.find((r) => r.id === chosenModel)!;\n const costDelta = m.pricing.inputPerMillion - chosen.pricing.inputPerMillion;\n const tradeoff = costDelta > 0\n ? `More capable but ${(costDelta / chosen.pricing.inputPerMillion * 100).toFixed(0)}% more expensive`\n : `${Math.abs(costDelta / chosen.pricing.inputPerMillion * 100).toFixed(0)}% cheaper but less capable`;\n\n return { model: m.id, costDelta, tradeoff };\n });\n}\n\nexport function getModelSpec(modelId: ModelId): ModelSpec | undefined {\n return MODEL_REGISTRY.find((m) => m.id === modelId);\n}\n","import type { StructuredPrompt, PromptSection, TaskType } from '../types/interact.js';\nimport type { ContextSelection, ProjectAnalysis } from '../types/engine.js';\nimport { countTokensChars4 } from '../engine/tokenizer.js';\n\n// ===== STRUCTURED PROMPT BUILDER =====\n//\n// Not templates. Not libraries.\n// Task-aware prompt construction with sections that can be measured and optimized.\n\nexport interface PromptOptions {\n task: string;\n taskType: TaskType;\n analysis: ProjectAnalysis;\n selection: ContextSelection;\n enableCoT?: boolean;\n enableConstraints?: boolean;\n enableAntiHallucination?: boolean;\n}\n\nexport function buildPrompt(options: PromptOptions): StructuredPrompt {\n const {\n task,\n taskType,\n analysis,\n selection,\n enableCoT = true,\n enableConstraints = true,\n enableAntiHallucination = true,\n } = options;\n\n const sections: PromptSection[] = [];\n\n // 1. System section — role priming\n sections.push(buildSystemSection(analysis.stack, taskType));\n\n // 2. Context section — project info + selected files\n sections.push(buildContextSection(analysis, selection));\n\n // 3. Task section — what the user wants\n sections.push(buildTaskSection(task, taskType));\n\n // 4. Constraints section — safety rails\n if (enableConstraints) {\n sections.push(buildConstraintsSection(analysis.stack, taskType));\n }\n\n // 5. Chain-of-thought section\n if (enableCoT) {\n sections.push(buildCoTSection(taskType));\n }\n\n // 6. Anti-hallucination section\n if (enableAntiHallucination) {\n sections.push(buildAntiHallucinationSection());\n }\n\n // 7. Output format section\n sections.push(buildFormatSection(taskType));\n\n const rendered = sections.map((s) => s.content).join('\\n\\n---\\n\\n');\n const totalTokens = sections.reduce((s, sec) => s + sec.tokens, 0);\n\n return { sections, totalTokens, rendered };\n}\n\n// ===== SECTION BUILDERS =====\n\nfunction buildSystemSection(stack: string[], taskType: TaskType): PromptSection {\n const stackStr = stack.length > 0 ? stack.join(', ') : 'software';\n const taskRole = TASK_ROLES[taskType] ?? 'engineer';\n\n const content = [\n `You are a senior ${stackStr} ${taskRole} with deep expertise in clean architecture, testing, and production-quality code.`,\n 'You prioritize correctness, readability, and maintainability.',\n 'You never make assumptions without evidence from the code.',\n ].join(' ');\n\n return makeSection('system', 'system', content);\n}\n\nfunction buildContextSection(\n analysis: ProjectAnalysis,\n selection: ContextSelection,\n): PromptSection {\n const lines: string[] = [];\n\n lines.push(`## Project: ${analysis.projectName}`);\n lines.push(`Stack: ${analysis.stack.join(', ') || 'Unknown'}`);\n lines.push(`Files analyzed: ${analysis.totalFiles} | Tokens: ~${Math.round(analysis.totalTokens / 1000)}K`);\n lines.push(`Context coverage: ${selection.coverage.score}% | Risk score: ${selection.riskScore}/100`);\n lines.push('');\n\n // List included files with their prune levels\n lines.push('### Included Files');\n lines.push('');\n\n const fullFiles = selection.files.filter((f) => f.pruneLevel === 'full');\n const sigFiles = selection.files.filter((f) => f.pruneLevel === 'signatures');\n const skelFiles = selection.files.filter((f) => f.pruneLevel === 'skeleton');\n\n if (fullFiles.length > 0) {\n lines.push('**Full content (read these first):**');\n for (const f of fullFiles) {\n lines.push(`- \\`${f.relativePath}\\` (~${Math.round(f.tokens / 1000)}K tokens) — ${f.reason}`);\n }\n lines.push('');\n }\n\n if (sigFiles.length > 0) {\n lines.push('**Signatures only (reference as needed):**');\n for (const f of sigFiles) {\n lines.push(`- \\`${f.relativePath}\\` (~${Math.round(f.tokens / 1000)}K tokens)`);\n }\n lines.push('');\n }\n\n if (skelFiles.length > 0) {\n lines.push('**Skeleton (structure overview):**');\n for (const f of skelFiles) {\n lines.push(`- \\`${f.relativePath}\\``);\n }\n lines.push('');\n }\n\n if (selection.coverage.missingCritical.length > 0) {\n lines.push('⚠️ **Missing critical files** (not included due to budget):');\n for (const f of selection.coverage.missingCritical) {\n lines.push(`- \\`${f}\\``);\n }\n lines.push('');\n }\n\n const content = lines.join('\\n');\n return makeSection('context', 'context', content);\n}\n\nfunction buildTaskSection(task: string, taskType: TaskType): PromptSection {\n const content = [\n '## Task',\n '',\n task,\n '',\n `Task type: **${taskType}**`,\n ].join('\\n');\n\n return makeSection('task', 'task', content);\n}\n\nfunction buildConstraintsSection(stack: string[], taskType: TaskType): PromptSection {\n const lines: string[] = ['## Constraints', ''];\n\n lines.push('- **Do NOT** delete or modify existing tests unless explicitly asked');\n lines.push('- **Do NOT** change function signatures that are part of the public API');\n lines.push('- **Do NOT** introduce new dependencies without mentioning it');\n lines.push('- **Always** handle errors explicitly (no silent catches)');\n lines.push('- **Always** preserve existing code style and conventions');\n lines.push('- **Prefer** minimal changes — smallest diff that solves the problem');\n\n if (stack.includes('TypeScript')) {\n lines.push('- **Always** use strict TypeScript types (no `any` unless unavoidable)');\n lines.push('- **Always** add explicit return types to exported functions');\n }\n\n if (taskType === 'refactor') {\n lines.push('- **Do NOT** change behavior — refactoring must be behavior-preserving');\n lines.push('- **Verify** all existing tests still pass after changes');\n }\n\n if (taskType === 'test') {\n lines.push('- Use AAA pattern: Arrange, Act, Assert');\n lines.push('- Test boundaries, null/undefined, async errors, type edges');\n lines.push('- Use descriptive test names: \"should [expected] when [condition]\"');\n }\n\n return makeSection('constraints', 'constraints', lines.join('\\n'));\n}\n\nfunction buildCoTSection(taskType: TaskType): PromptSection {\n const steps = COT_STEPS[taskType] ?? COT_STEPS['simple-edit'];\n\n const lines: string[] = ['## Thinking Process', '', 'Before writing any code:'];\n steps.forEach((step, i) => {\n lines.push(`${i + 1}. ${step}`);\n });\n\n return makeSection('cot', 'constraints', lines.join('\\n'));\n}\n\nfunction buildAntiHallucinationSection(): PromptSection {\n const content = [\n '## Important',\n '',\n '- Only reference files, functions, and APIs that exist in the provided context',\n '- If you are unsure about something, say so explicitly',\n '- Do NOT invent function signatures, types, or module paths',\n '- If the context is insufficient to complete the task, explain what is missing',\n ].join('\\n');\n\n return makeSection('anti-hallucination', 'constraints', content);\n}\n\nfunction buildFormatSection(taskType: TaskType): PromptSection {\n const lines: string[] = ['## Output Format', ''];\n\n if (taskType === 'review') {\n lines.push('Provide findings in priority order: Critical > Major > Minor > Nitpick');\n lines.push('For each finding: file, line, issue, and concrete suggestion with code');\n } else if (taskType === 'architecture') {\n lines.push('Present 2-3 options with trade-offs, then recommend one with justification');\n } else if (taskType === 'debug') {\n lines.push('1. Root cause analysis');\n lines.push('2. Minimal fix');\n lines.push('3. Explanation of why the fix works');\n lines.push('4. Edge cases to consider');\n } else {\n lines.push('Provide clean, production-ready code with brief explanations of key decisions');\n }\n\n return makeSection('format', 'format', lines.join('\\n'));\n}\n\n// ===== CONSTANTS =====\n\nconst TASK_ROLES: Record<TaskType, string> = {\n debug: 'debugger',\n review: 'code reviewer',\n refactor: 'architect',\n test: 'test engineer',\n docs: 'technical writer',\n feature: 'engineer',\n architecture: 'systems architect',\n 'simple-edit': 'engineer',\n};\n\nconst COT_STEPS: Record<TaskType, string[]> = {\n debug: [\n '**Reproduce** — Understand the exact symptom and when it occurs',\n '**Hypothesize** — List the most likely root causes (max 3)',\n '**Verify** — Check each hypothesis against the code',\n '**Fix** — Apply the minimal fix that addresses the root cause',\n '**Validate** — Explain why the fix works and what edge cases it covers',\n ],\n review: [\n '**Understand** — Read the code and understand its purpose',\n '**Assess** — Evaluate correctness, readability, performance, security',\n '**Prioritize** — Rank issues by severity (critical > major > minor)',\n '**Suggest** — Provide concrete, actionable improvements with code',\n ],\n refactor: [\n '**Analyze** — Identify code smells and structural issues',\n '**Plan** — Define the target structure before changing anything',\n '**Preserve** — Ensure behavior doesn\\'t change',\n '**Refactor** — Apply changes incrementally',\n '**Verify** — Confirm all existing tests still pass',\n ],\n test: [\n '**Identify** — What needs testing? (happy path, edge cases, errors)',\n '**Structure** — Use AAA pattern: Arrange, Act, Assert',\n '**Cover** — Test boundaries, null/undefined, async errors',\n '**Isolate** — Mock external dependencies, test units independently',\n ],\n docs: [\n '**Read** — Understand the code before documenting',\n '**Structure** — Organize by audience (API users, contributors, operators)',\n '**Write** — Clear, concise, with examples',\n ],\n feature: [\n '**Clarify** — Restate the requirement in your own words',\n '**Design** — Plan the approach (types, interfaces, flow)',\n '**Implement** — Build incrementally, starting with types',\n '**Test** — Write tests alongside implementation',\n '**Integrate** — Ensure no regressions',\n ],\n architecture: [\n '**Context** — Understand current architecture and constraints',\n '**Options** — Present 2-3 viable approaches with trade-offs',\n '**Recommend** — Choose the best and explain why',\n '**Plan** — Define migration steps',\n '**Risks** — Identify risks and mitigation strategies',\n ],\n 'simple-edit': [\n '**Understand** — Read the relevant code',\n '**Plan** — Think before writing',\n '**Implement** — Write clean, well-typed code',\n '**Verify** — Check for edge cases',\n ],\n};\n\n// ===== HELPERS =====\n\nfunction makeSection(\n id: string,\n role: PromptSection['role'],\n content: string,\n): PromptSection {\n const tokens = countTokensChars4(Buffer.byteLength(content, 'utf-8'));\n return { id, role, content, tokens };\n}\n","import { resolve } from 'node:path';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport type { ProjectAnalysis, AnalyzedFile } from '../types/engine.js';\nimport { buildAdjacencyList, bfsBidirectional } from './graph-utils.js';\n\n// ===== PR Context — Git-diff Aware Context Selection =====\n//\n// When the task is \"review this PR\", sending the entire project is wasteful.\n// This module:\n// 1. Extracts changed files from git diff (branch comparison or working dir)\n// 2. Expands to transitive dependencies using BFS on the adjacency list\n// 3. Prioritizes by risk score (high-risk changed files first)\n// 4. Returns a structured PR context with change categorization\n//\n// Complexity: O(|changed| × depth) for BFS expansion\n\nconst exec = promisify(execFile);\n\nasync function git(args: string[], cwd: string): Promise<string> {\n try {\n const { stdout } = await exec('git', args, { cwd, maxBuffer: 10 * 1024 * 1024 });\n return stdout.trim();\n } catch {\n return '';\n }\n}\n\n// ===== TYPES =====\n\nexport type ChangeType = 'added' | 'modified' | 'deleted' | 'renamed';\n\nexport interface ChangedFile {\n relativePath: string;\n changeType: ChangeType;\n linesAdded: number;\n linesRemoved: number;\n}\n\nexport interface PRContextResult {\n baseBranch: string;\n currentBranch: string;\n isGitRepo: boolean;\n\n changedFiles: ChangedFile[];\n dependencyFiles: string[];\n allRelevantFiles: AnalyzedFile[];\n\n totalChangedTokens: number;\n totalContextTokens: number;\n\n riskSummary: {\n critical: number;\n high: number;\n medium: number;\n low: number;\n maxRiskFile: string;\n maxRiskScore: number;\n };\n\n renderedSummary: string;\n}\n\nexport interface PRContextOptions {\n baseBranch?: string;\n depth?: number;\n includeTests?: boolean;\n}\n\n// ===== GIT OPERATIONS =====\n\nasync function isGitRepo(projectPath: string): Promise<boolean> {\n const result = await git(['rev-parse', '--is-inside-work-tree'], projectPath);\n return result === 'true';\n}\n\nasync function getCurrentBranch(projectPath: string): Promise<string> {\n return git(['rev-parse', '--abbrev-ref', 'HEAD'], projectPath);\n}\n\nasync function getChangedFilesFromDiff(\n projectPath: string,\n baseBranch?: string,\n): Promise<ChangedFile[]> {\n const results = new Map<string, ChangedFile>();\n\n // Working directory changes (unstaged)\n const workingDiff = await git(['diff', '--numstat', 'HEAD'], projectPath);\n parseDiffNumstat(workingDiff, results, 'modified');\n\n // Staged changes\n const stagedDiff = await git(['diff', '--numstat', '--cached'], projectPath);\n parseDiffNumstat(stagedDiff, results, 'modified');\n\n // Untracked files\n const untracked = await git(['ls-files', '--others', '--exclude-standard'], projectPath);\n for (const line of untracked.split('\\n')) {\n const f = line.trim();\n if (f && !results.has(f)) {\n results.set(f, { relativePath: f, changeType: 'added', linesAdded: 0, linesRemoved: 0 });\n }\n }\n\n // Branch comparison (if baseBranch provided)\n if (baseBranch) {\n // Check if base branch exists\n const branchExists = await git(['rev-parse', '--verify', baseBranch], projectPath);\n if (branchExists) {\n const branchDiff = await git(['diff', '--numstat', `${baseBranch}...HEAD`], projectPath);\n parseDiffNumstat(branchDiff, results, 'modified');\n\n // Detect newly added files (in HEAD but not in base)\n const nameStatus = await git(['diff', '--name-status', `${baseBranch}...HEAD`], projectPath);\n for (const line of nameStatus.split('\\n')) {\n const parts = line.trim().split('\\t');\n if (parts.length >= 2) {\n const status = parts[0];\n const filePath = parts[parts.length - 1];\n if (results.has(filePath)) {\n const existing = results.get(filePath)!;\n if (status === 'A') existing.changeType = 'added';\n else if (status === 'D') existing.changeType = 'deleted';\n else if (status.startsWith('R')) existing.changeType = 'renamed';\n }\n }\n }\n }\n }\n\n return [...results.values()];\n}\n\nfunction parseDiffNumstat(\n output: string,\n results: Map<string, ChangedFile>,\n defaultType: ChangeType,\n): void {\n for (const line of output.split('\\n')) {\n const parts = line.trim().split('\\t');\n if (parts.length < 3) continue;\n\n const added = parts[0] === '-' ? 0 : parseInt(parts[0], 10) || 0;\n const removed = parts[1] === '-' ? 0 : parseInt(parts[1], 10) || 0;\n const filePath = parts[2];\n\n if (!filePath) continue;\n\n const existing = results.get(filePath);\n if (existing) {\n existing.linesAdded = Math.max(existing.linesAdded, added);\n existing.linesRemoved = Math.max(existing.linesRemoved, removed);\n } else {\n results.set(filePath, {\n relativePath: filePath,\n changeType: defaultType,\n linesAdded: added,\n linesRemoved: removed,\n });\n }\n }\n}\n\n// ===== MAIN API =====\n\n/**\n * Generate PR-focused context by analyzing git changes and expanding dependencies.\n *\n * @param analysis - Project analysis (from analyzeProject or getCachedAnalysis)\n * @param options - PR context options (baseBranch, depth, includeTests)\n * @returns Structured PR context with changed files, dependencies, risk summary\n */\nexport async function generatePRContext(\n analysis: ProjectAnalysis,\n options: PRContextOptions = {},\n): Promise<PRContextResult> {\n const projectPath = resolve(analysis.projectPath);\n const baseBranch = options.baseBranch ?? 'main';\n const depth = options.depth ?? 2;\n const includeTests = options.includeTests ?? false;\n\n // Check git repo\n const gitRepo = await isGitRepo(projectPath);\n if (!gitRepo) {\n return emptyResult(baseBranch);\n }\n\n const currentBranch = await getCurrentBranch(projectPath);\n\n // 1. Get changed files from git\n const changedFiles = await getChangedFilesFromDiff(projectPath, baseBranch);\n\n if (changedFiles.length === 0) {\n return {\n ...emptyResult(baseBranch),\n currentBranch,\n isGitRepo: true,\n renderedSummary: '# PR Context\\n\\nNo changed files detected.',\n };\n }\n\n // 2. Filter to files that exist in our analysis\n const analysisFileSet = new Set(analysis.files.map((f) => f.relativePath));\n const validChangedPaths = changedFiles\n .filter((c) => c.changeType !== 'deleted' && analysisFileSet.has(c.relativePath))\n .map((c) => c.relativePath);\n\n // 3. Expand dependencies using BFS on adjacency list\n const adj = buildAdjacencyList(analysis.graph.edges);\n const expanded = bfsBidirectional(validChangedPaths, adj, depth);\n\n // Separate changed files from dependency-only files\n const changedSet = new Set(validChangedPaths);\n const dependencyFiles = [...expanded].filter((f) => !changedSet.has(f));\n\n // 4. Filter tests if not included\n const allRelevantPaths = new Set(expanded);\n if (!includeTests) {\n for (const path of allRelevantPaths) {\n const file = analysis.files.find((f) => f.relativePath === path);\n if (file && file.kind === 'test') {\n // Keep if it was directly changed, remove if it's a dependency\n if (!changedSet.has(path)) {\n allRelevantPaths.delete(path);\n }\n }\n }\n }\n\n // 5. Collect AnalyzedFile objects, sorted by risk score (descending)\n const allRelevantFiles = analysis.files\n .filter((f) => allRelevantPaths.has(f.relativePath))\n .sort((a, b) => b.riskScore - a.riskScore);\n\n // 6. Compute token totals\n const changedAnalyzed = allRelevantFiles.filter((f) => changedSet.has(f.relativePath));\n const totalChangedTokens = changedAnalyzed.reduce((s, f) => s + f.tokens, 0);\n const totalContextTokens = allRelevantFiles.reduce((s, f) => s + f.tokens, 0);\n\n // 7. Risk summary\n const riskSummary = {\n critical: allRelevantFiles.filter((f) => f.riskScore >= 80).length,\n high: allRelevantFiles.filter((f) => f.riskScore >= 60 && f.riskScore < 80).length,\n medium: allRelevantFiles.filter((f) => f.riskScore >= 30 && f.riskScore < 60).length,\n low: allRelevantFiles.filter((f) => f.riskScore < 30).length,\n maxRiskFile: allRelevantFiles[0]?.relativePath ?? '',\n maxRiskScore: allRelevantFiles[0]?.riskScore ?? 0,\n };\n\n // 8. Render summary\n const renderedSummary = renderSummary(\n analysis,\n currentBranch,\n baseBranch,\n changedFiles,\n dependencyFiles,\n allRelevantFiles,\n changedSet,\n riskSummary,\n totalChangedTokens,\n totalContextTokens,\n );\n\n return {\n baseBranch,\n currentBranch,\n isGitRepo: true,\n changedFiles,\n dependencyFiles: dependencyFiles.filter((f) => allRelevantPaths.has(f)),\n allRelevantFiles,\n totalChangedTokens,\n totalContextTokens,\n riskSummary,\n renderedSummary,\n };\n}\n\n// ===== RENDERING =====\n\nfunction renderSummary(\n analysis: ProjectAnalysis,\n currentBranch: string,\n baseBranch: string,\n changedFiles: ChangedFile[],\n dependencyFiles: string[],\n allRelevant: AnalyzedFile[],\n changedSet: Set<string>,\n risk: PRContextResult['riskSummary'],\n changedTokens: number,\n totalTokens: number,\n): string {\n const lines: string[] = [];\n\n lines.push(`## PR Context — ${analysis.projectName}`);\n lines.push('');\n lines.push(`**Branch:** ${currentBranch} ← ${baseBranch}`);\n lines.push(`**Changed:** ${changedFiles.length} files | **Dependencies:** ${dependencyFiles.length} files`);\n lines.push(`**Tokens:** ~${Math.round(changedTokens / 1000)}K changed + ~${Math.round((totalTokens - changedTokens) / 1000)}K context = ~${Math.round(totalTokens / 1000)}K total`);\n lines.push('');\n\n // Risk banner\n if (risk.critical > 0 || risk.high > 0) {\n lines.push(`⚠️ **Risk:** ${risk.critical} critical + ${risk.high} high-risk files affected`);\n lines.push(`**Highest risk:** ${risk.maxRiskFile} (score: ${risk.maxRiskScore})`);\n lines.push('');\n }\n\n // Changed files\n lines.push('### Changed Files');\n lines.push('');\n\n const sortedChanged = changedFiles\n .filter((c) => c.changeType !== 'deleted')\n .sort((a, b) => {\n const fa = allRelevant.find((f) => f.relativePath === a.relativePath);\n const fb = allRelevant.find((f) => f.relativePath === b.relativePath);\n return (fb?.riskScore ?? 0) - (fa?.riskScore ?? 0);\n });\n\n for (const c of sortedChanged) {\n const file = allRelevant.find((f) => f.relativePath === c.relativePath);\n const risk = file ? ` risk:${file.riskScore}` : '';\n const delta = c.linesAdded || c.linesRemoved\n ? ` (+${c.linesAdded}/-${c.linesRemoved})`\n : '';\n const badge = c.changeType === 'added' ? ' 🆕' : c.changeType === 'renamed' ? ' 📝' : '';\n lines.push(`- \\`${c.relativePath}\\`${delta}${risk}${badge}`);\n }\n\n // Deleted files\n const deleted = changedFiles.filter((c) => c.changeType === 'deleted');\n if (deleted.length > 0) {\n lines.push('');\n lines.push(`**Deleted:** ${deleted.map((d) => `\\`${d.relativePath}\\``).join(', ')}`);\n }\n\n // Dependencies\n if (dependencyFiles.length > 0) {\n lines.push('');\n lines.push('### Dependencies (included for context)');\n lines.push('');\n\n const depWithInfo = dependencyFiles\n .map((d) => {\n const file = allRelevant.find((f) => f.relativePath === d);\n return { path: d, riskScore: file?.riskScore ?? 0, tokens: file?.tokens ?? 0 };\n })\n .sort((a, b) => b.riskScore - a.riskScore);\n\n for (const d of depWithInfo) {\n lines.push(`- \\`${d.path}\\` risk:${d.riskScore} ~${Math.round(d.tokens / 1000)}K tokens`);\n }\n }\n\n lines.push('');\n lines.push('### Review Focus');\n lines.push('');\n lines.push('- Review changed files for correctness, especially high-risk files');\n lines.push('- Dependencies are included for type/interface context — not for review');\n lines.push(`- ${analysis.totalFiles - allRelevant.length} files excluded (not affected by this change)`);\n\n return lines.join('\\n');\n}\n\n// ===== HELPERS =====\n\nfunction emptyResult(baseBranch: string): PRContextResult {\n return {\n baseBranch,\n currentBranch: '',\n isGitRepo: false,\n changedFiles: [],\n dependencyFiles: [],\n allRelevantFiles: [],\n totalChangedTokens: 0,\n totalContextTokens: 0,\n riskSummary: { critical: 0, high: 0, medium: 0, low: 0, maxRiskFile: '', maxRiskScore: 0 },\n renderedSummary: '# PR Context\\n\\nNot a git repository.',\n };\n}\n","import { randomUUID } from 'node:crypto';\nimport type { InteractionPlan, PlanDecision, TaskType } from '../types/interact.js';\nimport type { ProjectAnalysis } from '../types/engine.js';\nimport type { PolicySet } from '../types/govern.js';\nimport { selectContext } from '../engine/selector.js';\nimport { classifyTask, routeModel } from './router.js';\nimport { estimateCost } from './estimator.js';\nimport { buildPrompt } from './prompt.js';\nimport { logAudit } from '../govern/audit.js';\n\n// ===== INTERACTION ORCHESTRATOR =====\n//\n// The brain of CTO v2. Given a task description:\n// 1. Classify task type\n// 2. Select optimal context (deterministic)\n// 3. Choose best model\n// 4. Build structured prompt\n// 5. Estimate cost\n// 6. Explain all decisions\n\nexport interface OrchestratorInput {\n task: string;\n analysis: ProjectAnalysis;\n budget?: number;\n model?: string;\n policies?: PolicySet;\n depth?: number;\n enableCoT?: boolean;\n enableConstraints?: boolean;\n enableAntiHallucination?: boolean;\n}\n\nexport async function planInteraction(input: OrchestratorInput): Promise<InteractionPlan> {\n const {\n task,\n analysis,\n budget = 50_000,\n model: preferredModel,\n policies,\n depth = 2,\n enableCoT = true,\n enableConstraints = true,\n enableAntiHallucination = true,\n } = input;\n\n const decisions: PlanDecision[] = [];\n\n // 1. CLASSIFY task\n const taskType: TaskType = classifyTask(task);\n decisions.push({\n step: 'classify',\n decision: taskType,\n reason: `Task classified as \"${taskType}\" based on keyword analysis`,\n data: { task, taskType },\n });\n\n // 2. SELECT context (deterministic)\n const context = await selectContext({\n task,\n analysis,\n budget,\n policies,\n depth,\n });\n\n decisions.push({\n step: 'select-context',\n decision: `${context.files.length} files selected (${context.totalTokens} tokens)`,\n reason: `Coverage: ${context.coverage.score}%, Risk: ${context.riskScore}/100`,\n data: {\n filesIncluded: context.files.length,\n tokensUsed: context.totalTokens,\n budget,\n coverage: context.coverage.score,\n risk: context.riskScore,\n },\n });\n\n // 3. CHOOSE model\n const modelChoice = routeModel(taskType, analysis, preferredModel);\n decisions.push({\n step: 'choose-model',\n decision: modelChoice.model,\n reason: modelChoice.reason,\n data: {\n confidence: modelChoice.confidence,\n alternatives: modelChoice.alternatives.length,\n },\n });\n\n // 4. BUILD prompt\n const prompt = buildPrompt({\n task,\n taskType,\n analysis,\n selection: context,\n enableCoT,\n enableConstraints,\n enableAntiHallucination,\n });\n\n decisions.push({\n step: 'build-prompt',\n decision: `${prompt.sections.length} sections, ${prompt.totalTokens} tokens`,\n reason: `Sections: ${prompt.sections.map((s) => s.id).join(', ')}`,\n });\n\n // 5. ESTIMATE cost\n const cost = estimateCost(\n modelChoice.model,\n context.totalTokens + prompt.totalTokens,\n analysis.totalTokens,\n );\n\n decisions.push({\n step: 'estimate-cost',\n decision: cost.formatted,\n reason: cost.savings.formatted,\n data: {\n inputTokens: cost.inputTokens,\n totalCost: cost.totalCost,\n savings: cost.savings.percent,\n },\n });\n\n const plan: InteractionPlan = {\n id: randomUUID().substring(0, 8),\n task,\n taskType,\n timestamp: new Date(),\n context,\n model: modelChoice,\n prompt,\n cost,\n decisions,\n };\n\n // 6. AUDIT LOG — record this interaction for governance\n try {\n await logAudit('interact', analysis.projectPath, {\n interactionId: plan.id,\n task,\n taskType,\n contextHash: context.hash,\n filesIncluded: context.files.length,\n filesExcluded: analysis.totalFiles - context.files.length,\n tokensUsed: context.totalTokens,\n coverageScore: context.coverage.score,\n riskScore: context.riskScore,\n model: modelChoice.model,\n estimatedCost: cost.totalCost,\n });\n } catch {\n // Audit failure should never block the interaction pipeline\n }\n\n return plan;\n}\n","import type { CostEstimate, ModelId } from '../types/interact.js';\nimport { getModelSpec, MODEL_REGISTRY } from './router.js';\n\n// ===== COST ESTIMATION =====\n\nexport function estimateCost(\n modelId: ModelId,\n inputTokens: number,\n totalProjectTokens: number,\n estimatedOutputRatio: number = 0.3,\n): CostEstimate {\n const spec = getModelSpec(modelId) ?? MODEL_REGISTRY[1]; // fallback to Sonnet\n const estimatedOutputTokens = Math.round(inputTokens * estimatedOutputRatio);\n\n const inputCost = (inputTokens / 1_000_000) * spec.pricing.inputPerMillion;\n const outputCost = (estimatedOutputTokens / 1_000_000) * spec.pricing.outputPerMillion;\n const totalCost = inputCost + outputCost;\n\n // Without optimization = sending all project tokens\n const woInputCost = (totalProjectTokens / 1_000_000) * spec.pricing.inputPerMillion;\n const woOutputCost = (Math.round(totalProjectTokens * estimatedOutputRatio) / 1_000_000) * spec.pricing.outputPerMillion;\n const woTotalCost = woInputCost + woOutputCost;\n\n const tokensSaved = totalProjectTokens - inputTokens;\n const costSaved = woTotalCost - totalCost;\n const savingsPercent = woTotalCost > 0 ? (costSaved / woTotalCost) * 100 : 0;\n\n return {\n model: modelId,\n inputTokens,\n estimatedOutputTokens,\n inputCost: round(inputCost),\n outputCost: round(outputCost),\n totalCost: round(totalCost),\n formatted: formatCost(totalCost),\n\n withoutOptimization: {\n inputTokens: totalProjectTokens,\n totalCost: round(woTotalCost),\n formatted: formatCost(woTotalCost),\n },\n\n savings: {\n tokensSaved: Math.max(0, tokensSaved),\n costSaved: round(Math.max(0, costSaved)),\n percent: Math.max(0, Math.round(savingsPercent)),\n formatted: costSaved > 0\n ? `saved ${formatCost(costSaved)} (${Math.round(savingsPercent)}%)`\n : 'no savings',\n },\n };\n}\n\n// ===== HELPERS =====\n\nfunction round(n: number): number {\n return Math.round(n * 1_000_000) / 1_000_000;\n}\n\nfunction formatCost(cost: number): string {\n if (cost < 0.001) return '<$0.001';\n if (cost < 0.01) return `$${cost.toFixed(4)}`;\n if (cost < 1) return `$${cost.toFixed(3)}`;\n return `$${cost.toFixed(2)}`;\n}\n","import { randomUUID, createHash } from 'node:crypto';\nimport { readdir, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { userInfo } from 'node:os';\nimport { homedir } from 'node:os';\nimport type { AuditEntry, AuditAction } from '../types/govern.js';\n\n// ===== AUDIT TRAIL =====\n//\n// Immutable, tamper-evident audit log for all CTO interactions.\n// Each entry is SHA-256 hashed for integrity verification.\n\nconst CTO_DIR = '.cto-ai';\nconst AUDIT_DIR = 'audit';\nconst MAX_ENTRIES_PER_FILE = 500;\n\nfunction getAuditDir(): string {\n return join(homedir(), CTO_DIR, AUDIT_DIR);\n}\n\nfunction getCurrentAuditFile(): string {\n const date = new Date().toISOString().split('T')[0].replace(/-/g, '');\n return join(getAuditDir(), `audit_${date}.json`);\n}\n\nfunction computeIntegrityHash(entry: Omit<AuditEntry, 'integrityHash'>): string {\n const payload = JSON.stringify({\n id: entry.id,\n timestamp: entry.timestamp,\n action: entry.action,\n user: entry.user,\n projectPath: entry.projectPath,\n details: entry.details,\n });\n return createHash('sha256').update(payload).digest('hex');\n}\n\n// ===== HELPERS (inline to avoid cross-layer deps) =====\n\nasync function ensureDir(dirPath: string): Promise<void> {\n const { mkdir } = await import('node:fs/promises');\n await mkdir(dirPath, { recursive: true });\n}\n\nasync function readJSON<T>(filePath: string): Promise<T | null> {\n const { readFile } = await import('node:fs/promises');\n try {\n const content = await readFile(filePath, 'utf-8');\n return JSON.parse(content) as T;\n } catch {\n return null;\n }\n}\n\nasync function writeJSON(filePath: string, data: unknown): Promise<void> {\n const { writeFile } = await import('node:fs/promises');\n await ensureDir(join(filePath, '..'));\n await writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8');\n}\n\n// ===== PUBLIC API =====\n\nexport async function logAudit(\n action: AuditAction,\n projectPath: string,\n details: Record<string, unknown> = {},\n): Promise<AuditEntry> {\n const auditDir = getAuditDir();\n await ensureDir(auditDir);\n\n let currentUser: string;\n try {\n currentUser = userInfo().username;\n } catch {\n currentUser = process.env.USER ?? process.env.USERNAME ?? 'unknown';\n }\n\n const partialEntry = {\n id: randomUUID().substring(0, 12),\n timestamp: new Date(),\n action,\n user: currentUser,\n projectPath,\n details,\n };\n\n const entry: AuditEntry = {\n ...partialEntry,\n integrityHash: computeIntegrityHash(partialEntry),\n };\n\n const auditFile = getCurrentAuditFile();\n let entries = await readJSON<AuditEntry[]>(auditFile) ?? [];\n entries.push(entry);\n\n if (entries.length > MAX_ENTRIES_PER_FILE) {\n entries = entries.slice(-MAX_ENTRIES_PER_FILE);\n }\n\n await writeJSON(auditFile, entries);\n try { await chmod(auditFile, 0o600); } catch { /* ignore on Windows */ }\n\n return entry;\n}\n\nexport async function getAuditEntries(\n options: {\n projectPath?: string;\n action?: AuditAction;\n since?: Date;\n limit?: number;\n } = {},\n): Promise<AuditEntry[]> {\n const auditDir = getAuditDir();\n let files: string[];\n try {\n files = await readdir(auditDir);\n } catch {\n return [];\n }\n\n const auditFiles = files\n .filter((f) => f.startsWith('audit_') && f.endsWith('.json'))\n .sort()\n .reverse();\n\n const allEntries: AuditEntry[] = [];\n const limit = options.limit ?? 100;\n\n for (const file of auditFiles) {\n if (allEntries.length >= limit) break;\n\n const entries = await readJSON<AuditEntry[]>(join(auditDir, file));\n if (!entries) continue;\n\n for (const entry of entries.reverse()) {\n if (allEntries.length >= limit) break;\n if (options.projectPath && entry.projectPath !== options.projectPath) continue;\n if (options.action && entry.action !== options.action) continue;\n if (options.since && new Date(entry.timestamp) < options.since) continue;\n allEntries.push(entry);\n }\n }\n\n return allEntries;\n}\n\nexport function verifyAuditEntry(entry: AuditEntry): boolean {\n const { integrityHash, ...rest } = entry;\n const expected = computeIntegrityHash(rest as Omit<AuditEntry, 'integrityHash'>);\n return expected === integrityHash;\n}\n\nexport async function verifyAuditIntegrity(): Promise<{\n totalEntries: number;\n validEntries: number;\n invalidEntries: AuditEntry[];\n}> {\n const entries = await getAuditEntries({ limit: 10000 });\n const invalidEntries: AuditEntry[] = [];\n\n for (const entry of entries) {\n if (!verifyAuditEntry(entry)) {\n invalidEntries.push(entry);\n }\n }\n\n return {\n totalEntries: entries.length,\n validEntries: entries.length - invalidEntries.length,\n invalidEntries,\n };\n}\n\nexport async function purgeOldAuditEntries(retentionDays: number): Promise<number> {\n const auditDir = getAuditDir();\n let files: string[];\n try {\n files = await readdir(auditDir);\n } catch {\n return 0;\n }\n\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - retentionDays);\n const cutoffStr = cutoff.toISOString().split('T')[0].replace(/-/g, '');\n\n let purged = 0;\n const { unlink } = await import('node:fs/promises');\n\n for (const file of files) {\n if (!file.startsWith('audit_') || !file.endsWith('.json')) continue;\n const dateStr = file.replace('audit_', '').replace('.json', '');\n if (dateStr < cutoffStr) {\n try {\n await unlink(join(auditDir, file));\n purged++;\n } catch { /* ignore */ }\n }\n }\n\n return purged;\n}\n"],"mappings":"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","names":["resolve","readFile","stat","join","relative","resolve","basename","join","stat","readFile","relative","basename","resolve","createHash","readdir","stat","join","extname","relative","resolve","readdir","join","extname","stat","relative","createHash","resolve","createHash","readFile","resolve","relative","Project","SyntaxKind","readFile","existsSync","join","TS_EXTENSIONS","readFile","Project","SyntaxKind","join","existsSync","createHash","resolve","resolve","emptyResult","risk","randomUUID","createHash","readdir","join","readFile","randomUUID","resolve","server"]}