cto-ai-cli 3.2.0 → 4.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.
- package/DOCS.md +201 -0
- package/README.md +70 -2
- package/dist/action/index.js +607 -83
- package/dist/api/dashboard.js +85 -23
- package/dist/api/dashboard.js.map +1 -1
- package/dist/api/server.js +86 -24
- package/dist/api/server.js.map +1 -1
- package/dist/cli/gateway.js +2925 -0
- package/dist/cli/score.js +2656 -217
- package/dist/cli/v2/index.js +111 -49
- package/dist/cli/v2/index.js.map +1 -1
- package/dist/engine/index.d.ts +85 -1
- package/dist/engine/index.js +643 -42
- package/dist/engine/index.js.map +1 -1
- package/dist/gateway/index.d.ts +281 -0
- package/dist/gateway/index.js +2803 -0
- package/dist/gateway/index.js.map +1 -0
- package/dist/govern/index.d.ts +45 -4
- package/dist/govern/index.js +318 -33
- package/dist/govern/index.js.map +1 -1
- package/dist/interact/index.js +86 -24
- package/dist/interact/index.js.map +1 -1
- package/dist/mcp/v2.js +108 -46
- package/dist/mcp/v2.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/gateway/server.ts","../../src/gateway/types.ts","../../src/gateway/providers.ts","../../src/govern/secrets.ts","../../src/engine/selector.ts","../../src/engine/pruner.ts","../../src/engine/tokenizer.ts","../../src/engine/graph-utils.ts","../../src/engine/coverage.ts","../../src/engine/budget.ts","../../src/gateway/interceptor.ts","../../src/gateway/tracker.ts","../../src/engine/analyzer.ts","../../src/types/engine.ts","../../src/types/config.ts","../../src/engine/graph.ts","../../src/engine/risk.ts"],"sourcesContent":["// ===== Context Gateway — HTTP Proxy Server =====\n//\n// A transparent proxy that sits between your app and any LLM provider.\n// Point your OPENAI_BASE_URL to this proxy and it will:\n// 1. Intercept requests → scan for secrets → redact or block\n// 2. Optimize context → inject CTO-selected files\n// 3. Track costs → per-model, per-day, per-month\n// 4. Stream responses → full SSE passthrough with zero-copy when possible\n//\n// Architecture:\n// Client → Gateway (localhost:8787) → Provider (api.openai.com, etc.)\n//\n// Zero external dependencies. Node.js http + https only.\n\nimport { createServer, IncomingMessage, ServerResponse, Agent as HttpAgent } from 'node:http';\nimport { request as httpsRequest, Agent as HttpsAgent } from 'node:https';\nimport { request as httpRequest } from 'node:http';\nimport { URL } from 'node:url';\nimport { lookup } from 'node:dns/promises';\nimport type { GatewayConfig, GatewayEventHandler, GatewayEvent, ProviderName } from './types.js';\nimport { DEFAULT_GATEWAY_CONFIG, isAllowedTarget, isPrivateIP } from './types.js';\nimport { detectProvider, estimateCost, getModelConfig } from './providers.js';\nimport { interceptRequest } from './interceptor.js';\nimport { UsageTracker } from './tracker.js';\nimport { analyzeProject } from '../engine/analyzer.js';\nimport type { ProjectAnalysis } from '../types/engine.js';\n\n// ===== GATEWAY CLASS =====\n\nexport class ContextGateway {\n private config: GatewayConfig;\n private tracker: UsageTracker;\n private analysis: ProjectAnalysis | null = null;\n private analysisPromise: Promise<ProjectAnalysis> | null = null;\n private eventHandlers: GatewayEventHandler[] = [];\n private server: ReturnType<typeof createServer> | null = null;\n private httpAgent: HttpAgent;\n private httpsAgent: HttpsAgent;\n private budgetLock = false; // Simple lock for budget reservation\n\n constructor(config: Partial<GatewayConfig> = {}) {\n this.config = { ...DEFAULT_GATEWAY_CONFIG, ...config };\n this.tracker = new UsageTracker(this.config);\n // Connection pooling — reuse TCP/TLS connections\n this.httpAgent = new HttpAgent({ keepAlive: true, maxSockets: 50 });\n this.httpsAgent = new HttpsAgent({ keepAlive: true, maxSockets: 50 });\n\n // Forward tracker events\n this.tracker.onEvent((event) => this.emit(event));\n }\n\n // ===== EVENTS =====\n\n onEvent(handler: GatewayEventHandler): void {\n this.eventHandlers.push(handler);\n }\n\n private emit(event: GatewayEvent): void {\n for (const handler of this.eventHandlers) {\n try { handler(event); } catch { /* safe */ }\n }\n }\n\n // ===== LIFECYCLE =====\n\n async start(): Promise<void> {\n // Start project analysis in background\n if (this.config.optimize) {\n this.analysisPromise = this.refreshAnalysis();\n }\n\n this.server = createServer((req, res) => this.handleRequest(req, res));\n\n return new Promise((resolve) => {\n this.server!.listen(this.config.port, this.config.host, () => {\n resolve();\n });\n });\n }\n\n async stop(): Promise<void> {\n return new Promise((resolve) => {\n if (this.server) {\n this.server.close(() => resolve());\n } else {\n resolve();\n }\n });\n }\n\n getTracker(): UsageTracker {\n return this.tracker;\n }\n\n // ===== ANALYSIS =====\n\n private async refreshAnalysis(): Promise<ProjectAnalysis> {\n try {\n const analysis = await analyzeProject(this.config.projectPath);\n this.analysis = analysis;\n return analysis;\n } catch (err: any) {\n this.emit({ type: 'error', message: `Analysis failed: ${err.message}`, error: err });\n throw err;\n }\n }\n\n // ===== REQUEST HANDLER =====\n\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const startTime = Date.now();\n\n // Dashboard route\n if (this.config.dashboard && req.url?.startsWith(this.config.dashboardPath)) {\n return this.serveDashboard(req, res);\n }\n\n // Health check\n if (req.url === '/health' || req.url === '/__cto/health') {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({\n status: 'ok',\n version: '4.0.0',\n uptime: process.uptime(),\n analysis: this.analysis ? 'ready' : 'loading',\n }));\n return;\n }\n\n // ===== AUTH CHECK =====\n if (this.config.apiKey) {\n const authHeader = req.headers['x-cto-key'] as string\n || req.headers['authorization']?.replace(/^Bearer\\s+/i, '')\n || '';\n if (authHeader !== this.config.apiKey) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized. Set x-cto-key header or Authorization: Bearer <key>' }));\n return;\n }\n }\n\n // Only proxy POST requests (LLM API calls)\n if (req.method !== 'POST') {\n res.writeHead(405, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Method not allowed. Gateway only proxies POST requests.' }));\n return;\n }\n\n // ===== BODY SIZE LIMIT =====\n let body: string;\n try {\n body = await readBody(req, this.config.maxBodyBytes);\n } catch (err: any) {\n const status = err.message === 'body-too-large' ? 413 : 400;\n res.writeHead(status, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: status === 413\n ? `Request body too large. Max: ${Math.round(this.config.maxBodyBytes / 1024 / 1024)}MB`\n : 'Failed to read request body' }));\n return;\n }\n\n let parsedBody: any;\n try {\n parsedBody = JSON.parse(body);\n } catch {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Invalid JSON in request body' }));\n return;\n }\n\n // Detect provider from target URL header\n const targetUrl = req.headers['x-cto-target'] as string\n || req.headers['x-target-url'] as string\n || '';\n\n // ===== SSRF PROTECTION =====\n if (!targetUrl) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({\n error: 'Missing target URL. Set x-cto-target header to the provider API URL.',\n example: 'x-cto-target: https://api.openai.com/v1/chat/completions',\n }));\n return;\n }\n\n let targetUrlParsed: URL;\n try {\n targetUrlParsed = new URL(targetUrl);\n } catch {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Invalid target URL' }));\n return;\n }\n\n // Block non-HTTPS (except localhost for dev)\n if (targetUrlParsed.protocol !== 'https:' && targetUrlParsed.hostname !== 'localhost') {\n res.writeHead(403, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Only HTTPS targets allowed (SSRF protection)' }));\n return;\n }\n\n // Domain allowlist check\n if (!isAllowedTarget(targetUrlParsed.hostname, this.config)) {\n res.writeHead(403, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({\n error: `Target domain not allowed: ${targetUrlParsed.hostname}`,\n allowed: this.config.allowedTargetDomains.length > 0\n ? this.config.allowedTargetDomains\n : ['api.openai.com', 'api.anthropic.com', '*.googleapis.com', '*.openai.azure.com'],\n }));\n return;\n }\n\n // DNS resolution check — block private IPs\n try {\n const resolved = await lookup(targetUrlParsed.hostname);\n if (isPrivateIP(resolved.address)) {\n res.writeHead(403, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Target resolves to private IP (SSRF protection)' }));\n return;\n }\n } catch {\n // DNS resolution failed — let the proxy attempt handle the error\n }\n\n const headers = flattenHeaders(req.headers);\n const provider = detectProvider(targetUrl || req.url || '', headers);\n const parsed = provider.parseRequest(parsedBody);\n\n // ===== BUDGET CHECK WITH RESERVATION =====\n const now = new Date();\n if (this.tracker.isDailyBudgetExceeded(now)) {\n res.writeHead(429, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({\n error: 'Daily budget exceeded',\n budget: this.config.budgetDaily,\n current: this.tracker.getDailyCost(now),\n }));\n return;\n }\n\n if (this.tracker.isMonthlyBudgetExceeded(now)) {\n res.writeHead(429, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({\n error: 'Monthly budget exceeded',\n budget: this.config.budgetMonthly,\n current: this.tracker.getMonthlyCost(now),\n }));\n return;\n }\n\n // Wait for analysis if it's loading\n if (this.analysisPromise && !this.analysis) {\n try {\n await this.analysisPromise;\n } catch {\n // Continue without analysis\n }\n }\n\n // Intercept and optimize\n const interceptResult = await interceptRequest(parsed.messages, this.config, this.analysis);\n\n if (interceptResult.secretsBlocked) {\n res.writeHead(403, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({\n error: 'Request blocked: secrets detected in message content',\n decisions: interceptResult.decisions,\n secretsRedacted: interceptResult.secretsRedacted,\n }));\n\n this.tracker.record({\n provider: provider.name,\n model: parsed.model,\n inputTokens: 0,\n outputTokens: 0,\n costUSD: 0,\n originalTokens: interceptResult.originalTokens,\n optimizedTokens: 0,\n savedTokens: 0,\n savedUSD: 0,\n secretsRedacted: interceptResult.secretsRedacted,\n secretsBlocked: true,\n projectPath: this.config.projectPath,\n latencyMs: Date.now() - startTime,\n stream: parsed.stream,\n error: 'blocked:secrets',\n });\n return;\n }\n\n // Rebuild request body with intercepted messages\n const modifiedBody = rebuildRequestBody(parsedBody, interceptResult.messages, provider.name);\n\n try {\n await this.proxyRequest(targetUrl, req, res, modifiedBody, provider, parsed, interceptResult, startTime);\n } catch (err: any) {\n if (!res.headersSent) {\n const status = err.message === 'upstream-timeout' ? 504 : 502;\n res.writeHead(status, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: status === 504 ? 'Upstream provider timeout' : `Proxy error: ${err.message}` }));\n }\n this.emit({ type: 'error', message: `Proxy error: ${err.message}`, error: err });\n }\n }\n\n // ===== PROXY =====\n\n private async proxyRequest(\n targetUrl: string,\n clientReq: IncomingMessage,\n clientRes: ServerResponse,\n body: string,\n provider: ReturnType<typeof detectProvider>,\n parsed: ReturnType<typeof provider.parseRequest>,\n interceptResult: Awaited<ReturnType<typeof interceptRequest>>,\n startTime: number,\n ): Promise<void> {\n const url = new URL(targetUrl);\n const isHttps = url.protocol === 'https:';\n const requester = isHttps ? httpsRequest : httpRequest;\n\n // Forward headers (strip gateway-specific ones + auth key)\n const forwardHeaders: Record<string, string> = {};\n const stripHeaders = new Set(['host', 'content-length', 'x-cto-target', 'x-target-url', 'x-cto-key']);\n for (const [key, value] of Object.entries(clientReq.headers)) {\n if (stripHeaders.has(key)) continue;\n if (value) forwardHeaders[key] = Array.isArray(value) ? value[0] : value;\n }\n forwardHeaders['content-length'] = Buffer.byteLength(body).toString();\n\n return new Promise((resolve, reject) => {\n const proxyReq = requester(\n {\n hostname: url.hostname,\n port: url.port || (isHttps ? 443 : 80),\n path: url.pathname + url.search,\n method: 'POST',\n headers: forwardHeaders,\n agent: isHttps ? this.httpsAgent : this.httpAgent, // Connection pooling\n timeout: this.config.upstreamTimeoutMs,\n },\n (proxyRes) => {\n if (parsed.stream && proxyRes.headers['content-type']?.includes('text/event-stream')) {\n this.handleStreamResponse(\n proxyRes, clientRes, provider, parsed, interceptResult, startTime\n ).then(resolve).catch(reject);\n } else {\n this.handleBufferedResponse(\n proxyRes, clientRes, provider, parsed, interceptResult, startTime\n ).then(resolve).catch(reject);\n }\n },\n );\n\n proxyReq.on('timeout', () => {\n proxyReq.destroy();\n reject(new Error('upstream-timeout'));\n });\n proxyReq.on('error', reject);\n proxyReq.write(body);\n proxyReq.end();\n });\n }\n\n // ===== STREAM HANDLER =====\n\n private async handleStreamResponse(\n proxyRes: IncomingMessage,\n clientRes: ServerResponse,\n provider: ReturnType<typeof detectProvider>,\n parsed: ReturnType<typeof provider.parseRequest>,\n interceptResult: Awaited<ReturnType<typeof interceptRequest>>,\n startTime: number,\n ): Promise<void> {\n // Forward headers\n clientRes.writeHead(proxyRes.statusCode || 200, proxyRes.headers);\n\n let fullContent = '';\n let inputTokens = 0;\n let outputTokens = 0;\n let sseBuffer = ''; // Buffer for handling chunk boundaries\n\n return new Promise((resolve) => {\n proxyRes.on('data', (chunk: Buffer) => {\n // Pass through to client immediately (zero-copy streaming)\n clientRes.write(chunk);\n\n // Append to SSE buffer and parse complete events\n sseBuffer += chunk.toString();\n const events = sseBuffer.split('\\n\\n');\n // Keep the last (potentially incomplete) event in the buffer\n sseBuffer = events.pop() || '';\n\n for (const event of events) {\n for (const line of event.split('\\n')) {\n if (!line.startsWith('data: ')) continue;\n const data = line.slice(6).trim();\n if (data === '[DONE]') continue;\n\n try {\n const obj = JSON.parse(data);\n // OpenAI/Anthropic streaming format\n const delta = obj.choices?.[0]?.delta?.content\n || obj.delta?.text // Anthropic streaming\n || '';\n if (delta) fullContent += delta;\n\n // Usage (sent in final chunk by some providers)\n if (obj.usage) {\n inputTokens = obj.usage.prompt_tokens || obj.usage.input_tokens || 0;\n outputTokens = obj.usage.completion_tokens || obj.usage.output_tokens || 0;\n }\n } catch { /* partial JSON or non-JSON data line */ }\n }\n }\n });\n\n proxyRes.on('end', () => {\n // Process any remaining buffer\n if (sseBuffer.trim()) {\n for (const line of sseBuffer.split('\\n')) {\n if (!line.startsWith('data: ')) continue;\n const data = line.slice(6).trim();\n if (data === '[DONE]') continue;\n try {\n const obj = JSON.parse(data);\n if (obj.usage) {\n inputTokens = obj.usage.prompt_tokens || obj.usage.input_tokens || 0;\n outputTokens = obj.usage.completion_tokens || obj.usage.output_tokens || 0;\n }\n } catch { /* ignore */ }\n }\n }\n\n clientRes.end();\n\n // Estimate tokens if not provided\n if (inputTokens === 0) inputTokens = interceptResult.optimizedTokens;\n if (outputTokens === 0) outputTokens = Math.ceil(fullContent.length / 4);\n\n const costUSD = estimateCost(provider, parsed.model, inputTokens, outputTokens);\n const originalCost = estimateCost(provider, parsed.model, interceptResult.originalTokens, outputTokens);\n\n this.tracker.record({\n provider: provider.name,\n model: parsed.model,\n inputTokens,\n outputTokens,\n costUSD,\n originalTokens: interceptResult.originalTokens,\n optimizedTokens: interceptResult.optimizedTokens,\n savedTokens: interceptResult.originalTokens - interceptResult.optimizedTokens,\n savedUSD: Math.max(0, originalCost - costUSD),\n secretsRedacted: interceptResult.secretsRedacted,\n secretsBlocked: false,\n projectPath: this.config.projectPath,\n latencyMs: Date.now() - startTime,\n stream: true,\n });\n\n resolve();\n });\n\n proxyRes.on('error', () => {\n clientRes.end();\n resolve();\n });\n });\n }\n\n // ===== BUFFERED HANDLER =====\n\n private async handleBufferedResponse(\n proxyRes: IncomingMessage,\n clientRes: ServerResponse,\n provider: ReturnType<typeof detectProvider>,\n parsed: ReturnType<typeof provider.parseRequest>,\n interceptResult: Awaited<ReturnType<typeof interceptRequest>>,\n startTime: number,\n ): Promise<void> {\n return new Promise((resolve) => {\n const chunks: Buffer[] = [];\n\n proxyRes.on('data', (chunk: Buffer) => chunks.push(chunk));\n\n proxyRes.on('end', () => {\n const responseBody = Buffer.concat(chunks).toString();\n\n // Forward response to client\n clientRes.writeHead(proxyRes.statusCode || 200, proxyRes.headers);\n clientRes.end(responseBody);\n\n // Parse and track\n try {\n const responseJson = JSON.parse(responseBody);\n const parsedResponse = provider.parseResponse(responseJson, false);\n\n const costUSD = estimateCost(\n provider, parsedResponse.model || parsed.model,\n parsedResponse.inputTokens, parsedResponse.outputTokens\n );\n const originalCost = estimateCost(\n provider, parsed.model,\n interceptResult.originalTokens, parsedResponse.outputTokens\n );\n\n this.tracker.record({\n provider: provider.name,\n model: parsedResponse.model || parsed.model,\n inputTokens: parsedResponse.inputTokens,\n outputTokens: parsedResponse.outputTokens,\n costUSD,\n originalTokens: interceptResult.originalTokens,\n optimizedTokens: interceptResult.optimizedTokens,\n savedTokens: interceptResult.originalTokens - interceptResult.optimizedTokens,\n savedUSD: Math.max(0, originalCost - costUSD),\n secretsRedacted: interceptResult.secretsRedacted,\n secretsBlocked: false,\n projectPath: this.config.projectPath,\n latencyMs: Date.now() - startTime,\n stream: false,\n });\n } catch {\n // Track even if response parsing fails\n this.tracker.record({\n provider: provider.name,\n model: parsed.model,\n inputTokens: interceptResult.optimizedTokens,\n outputTokens: 0,\n costUSD: 0,\n originalTokens: interceptResult.originalTokens,\n optimizedTokens: interceptResult.optimizedTokens,\n savedTokens: interceptResult.originalTokens - interceptResult.optimizedTokens,\n savedUSD: 0,\n secretsRedacted: interceptResult.secretsRedacted,\n secretsBlocked: false,\n projectPath: this.config.projectPath,\n latencyMs: Date.now() - startTime,\n stream: false,\n error: 'response-parse-failed',\n });\n }\n\n resolve();\n });\n\n proxyRes.on('error', () => {\n clientRes.end();\n resolve();\n });\n });\n }\n\n // ===== DASHBOARD =====\n\n private serveDashboard(_req: IncomingMessage, res: ServerResponse): void {\n const summary = this.tracker.getSummary('month');\n const dailySummary = this.tracker.getSummary('day');\n\n const html = generateDashboardHTML(summary, dailySummary, this.config, this.analysis);\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(html);\n }\n}\n\n// ===== HELPERS =====\n\nfunction readBody(req: IncomingMessage, maxBytes: number = 0): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let totalBytes = 0;\n req.on('data', (chunk: Buffer) => {\n totalBytes += chunk.length;\n if (maxBytes > 0 && totalBytes > maxBytes) {\n req.destroy();\n reject(new Error('body-too-large'));\n return;\n }\n chunks.push(chunk);\n });\n req.on('end', () => resolve(Buffer.concat(chunks).toString()));\n req.on('error', reject);\n });\n}\n\nfunction flattenHeaders(headers: IncomingMessage['headers']): Record<string, string> {\n const flat: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (value) flat[key] = Array.isArray(value) ? value[0] : value;\n }\n return flat;\n}\n\nfunction rebuildRequestBody(original: any, messages: { role: string; content: string }[], provider: ProviderName): string {\n const body = { ...original };\n\n if (provider === 'anthropic') {\n // Anthropic: separate system from messages\n const systemMsg = messages.find((m) => m.role === 'system');\n const otherMsgs = messages.filter((m) => m.role !== 'system');\n if (systemMsg) body.system = systemMsg.content;\n body.messages = otherMsgs;\n } else if (provider === 'google') {\n // Google: convert to contents format\n const systemMsg = messages.find((m) => m.role === 'system');\n const otherMsgs = messages.filter((m) => m.role !== 'system');\n if (systemMsg) {\n body.systemInstruction = { parts: [{ text: systemMsg.content }] };\n }\n body.contents = otherMsgs.map((m) => ({\n role: m.role === 'assistant' ? 'model' : 'user',\n parts: [{ text: m.content }],\n }));\n } else {\n // OpenAI and compatibles\n body.messages = messages;\n }\n\n return JSON.stringify(body);\n}\n\n// ===== DASHBOARD HTML =====\n\nfunction generateDashboardHTML(\n monthly: ReturnType<UsageTracker['getSummary']>,\n daily: ReturnType<UsageTracker['getSummary']>,\n config: GatewayConfig,\n analysis: ProjectAnalysis | null,\n): string {\n const modelRows = Object.entries(monthly.byModel)\n .sort(([, a], [, b]) => b.costUSD - a.costUSD)\n .map(([model, data]) =>\n `<tr><td>${model}</td><td>${data.requests}</td><td>${(data.tokens / 1000).toFixed(1)}K</td><td>$${data.costUSD.toFixed(4)}</td></tr>`\n ).join('');\n\n const providerRows = Object.entries(monthly.byProvider)\n .sort(([, a], [, b]) => b.costUSD - a.costUSD)\n .map(([provider, data]) =>\n `<tr><td>${provider}</td><td>${data.requests}</td><td>$${data.costUSD.toFixed(4)}</td></tr>`\n ).join('');\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>CTO Gateway Dashboard</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #0a0a0f; color: #e0e0e0; padding: 2rem; }\n h1 { font-size: 1.8rem; margin-bottom: 0.5rem; color: #fff; }\n h2 { font-size: 1.2rem; margin: 2rem 0 1rem; color: #8b8bff; }\n .subtitle { color: #666; margin-bottom: 2rem; }\n .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 2rem; }\n .card { background: #14141f; border: 1px solid #2a2a3a; border-radius: 12px; padding: 1.5rem; }\n .card .label { font-size: 0.75rem; text-transform: uppercase; color: #666; letter-spacing: 0.05em; }\n .card .value { font-size: 2rem; font-weight: 700; color: #fff; margin-top: 0.25rem; }\n .card .detail { font-size: 0.85rem; color: #888; margin-top: 0.25rem; }\n .card.green .value { color: #4ade80; }\n .card.red .value { color: #f87171; }\n .card.blue .value { color: #60a5fa; }\n .card.purple .value { color: #a78bfa; }\n table { width: 100%; border-collapse: collapse; margin-top: 0.5rem; }\n th { text-align: left; padding: 0.5rem; color: #666; font-size: 0.75rem; text-transform: uppercase; border-bottom: 1px solid #2a2a3a; }\n td { padding: 0.5rem; border-bottom: 1px solid #1a1a2a; font-size: 0.9rem; }\n .status { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 8px; }\n .status.on { background: #4ade80; }\n .status.off { background: #666; }\n .footer { margin-top: 3rem; color: #444; font-size: 0.75rem; }\n .badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 0.7rem; font-weight: 600; }\n .badge.critical { background: #7f1d1d; color: #fca5a5; }\n .badge.ok { background: #14532d; color: #86efac; }\n </style>\n</head>\n<body>\n <h1>⚡ CTO Context Gateway</h1>\n <p class=\"subtitle\">Real-time AI proxy with context optimization, secret redaction, and cost tracking</p>\n\n <h2>Today</h2>\n <div class=\"grid\">\n <div class=\"card blue\">\n <div class=\"label\">Requests</div>\n <div class=\"value\">${daily.totalRequests}</div>\n </div>\n <div class=\"card\">\n <div class=\"label\">Cost</div>\n <div class=\"value\">$${daily.totalCostUSD.toFixed(2)}</div>\n ${config.budgetDaily > 0 ? `<div class=\"detail\">Budget: $${config.budgetDaily}/day</div>` : ''}\n </div>\n <div class=\"card green\">\n <div class=\"label\">Tokens Saved</div>\n <div class=\"value\">${(daily.totalSavedTokens / 1000).toFixed(1)}K</div>\n <div class=\"detail\">$${daily.totalSavedUSD.toFixed(2)} saved</div>\n </div>\n <div class=\"card ${daily.totalSecretsRedacted > 0 ? 'red' : ''}\">\n <div class=\"label\">Secrets Redacted</div>\n <div class=\"value\">${daily.totalSecretsRedacted}</div>\n </div>\n </div>\n\n <h2>This Month</h2>\n <div class=\"grid\">\n <div class=\"card blue\">\n <div class=\"label\">Total Requests</div>\n <div class=\"value\">${monthly.totalRequests}</div>\n </div>\n <div class=\"card\">\n <div class=\"label\">Total Cost</div>\n <div class=\"value\">$${monthly.totalCostUSD.toFixed(2)}</div>\n ${config.budgetMonthly > 0 ? `<div class=\"detail\">Budget: $${config.budgetMonthly}/month</div>` : ''}\n </div>\n <div class=\"card green\">\n <div class=\"label\">Total Saved</div>\n <div class=\"value\">$${monthly.totalSavedUSD.toFixed(2)}</div>\n <div class=\"detail\">${(monthly.totalSavedTokens / 1000).toFixed(0)}K tokens</div>\n </div>\n <div class=\"card purple\">\n <div class=\"label\">Tokens Processed</div>\n <div class=\"value\">${((monthly.totalInputTokens + monthly.totalOutputTokens) / 1000).toFixed(0)}K</div>\n <div class=\"detail\">${(monthly.totalInputTokens / 1000).toFixed(0)}K in / ${(monthly.totalOutputTokens / 1000).toFixed(0)}K out</div>\n </div>\n </div>\n\n <h2>Features</h2>\n <div class=\"grid\">\n <div class=\"card\">\n <div class=\"label\">Context Optimization</div>\n <div class=\"value\"><span class=\"status ${config.optimize ? 'on' : 'off'}\"></span>${config.optimize ? 'ON' : 'OFF'}</div>\n ${analysis ? `<div class=\"detail\">${analysis.totalFiles} files, ${(analysis.totalTokens / 1000).toFixed(0)}K tokens</div>` : '<div class=\"detail\">Loading analysis...</div>'}\n </div>\n <div class=\"card\">\n <div class=\"label\">Secret Redaction</div>\n <div class=\"value\"><span class=\"status ${config.redactSecrets ? 'on' : 'off'}\"></span>${config.redactSecrets ? 'ON' : 'OFF'}</div>\n ${config.blockOnSecrets ? '<span class=\"badge critical\">BLOCKING</span>' : ''}\n </div>\n <div class=\"card\">\n <div class=\"label\">Cost Tracking</div>\n <div class=\"value\"><span class=\"status ${config.costTracking ? 'on' : 'off'}\"></span>${config.costTracking ? 'ON' : 'OFF'}</div>\n </div>\n <div class=\"card\">\n <div class=\"label\">Audit Log</div>\n <div class=\"value\"><span class=\"status ${config.auditLog ? 'on' : 'off'}\"></span>${config.auditLog ? 'ON' : 'OFF'}</div>\n <div class=\"detail\">${config.logDir}</div>\n </div>\n </div>\n\n ${modelRows ? `\n <h2>By Model</h2>\n <div class=\"card\">\n <table>\n <thead><tr><th>Model</th><th>Requests</th><th>Tokens</th><th>Cost</th></tr></thead>\n <tbody>${modelRows}</tbody>\n </table>\n </div>` : ''}\n\n ${providerRows ? `\n <h2>By Provider</h2>\n <div class=\"card\">\n <table>\n <thead><tr><th>Provider</th><th>Requests</th><th>Cost</th></tr></thead>\n <tbody>${providerRows}</tbody>\n </table>\n </div>` : ''}\n\n <div class=\"footer\">\n CTO Context Gateway v4.0.0 · Listening on ${config.host}:${config.port} · <a href=\"/health\" style=\"color:#666\">Health</a>\n </div>\n\n <script>setTimeout(() => location.reload(), 30000);</script>\n</body>\n</html>`;\n}\n","// ===== Context Gateway — Type Definitions =====\n\n// ===== PROVIDERS =====\n\nexport type ProviderName = 'openai' | 'anthropic' | 'google' | 'azure-openai' | 'custom';\n\nexport interface ProviderConfig {\n name: ProviderName;\n displayName: string;\n baseUrl: string;\n authHeader: string;\n chatPath: string;\n models: ModelConfig[];\n parseRequest: (body: any) => ParsedRequest;\n parseResponse: (body: any, streaming: boolean) => ParsedResponse;\n detectProvider: (url: string, headers: Record<string, string>) => boolean;\n}\n\nexport interface ModelConfig {\n id: string;\n contextWindow: number;\n costPerMInput: number; // $/million tokens\n costPerMOutput: number;\n maxOutput: number;\n}\n\n// ===== REQUEST / RESPONSE =====\n\nexport interface ParsedRequest {\n model: string;\n messages: Message[];\n stream: boolean;\n maxTokens?: number;\n temperature?: number;\n}\n\nexport interface ParsedResponse {\n model: string;\n inputTokens: number;\n outputTokens: number;\n content: string;\n finishReason: string;\n}\n\nexport interface Message {\n role: 'system' | 'user' | 'assistant' | 'tool';\n content: string;\n}\n\n// ===== GATEWAY CONFIG =====\n\nexport interface GatewayConfig {\n port: number;\n host: string;\n\n // Context optimization\n optimize: boolean;\n projectPath: string;\n budget: number;\n\n // Security\n redactSecrets: boolean;\n blockOnSecrets: boolean;\n apiKey: string; // Gateway auth key (empty = no auth)\n allowedTargetDomains: string[]; // SSRF protection: only proxy to these domains (empty = LLM providers only)\n maxBodyBytes: number; // Max request body size in bytes (0 = unlimited)\n upstreamTimeoutMs: number; // Timeout for upstream provider requests\n\n // Cost control\n costTracking: boolean;\n budgetDaily: number; // Max $/day (0 = unlimited)\n budgetMonthly: number; // Max $/month (0 = unlimited)\n alertThreshold: number; // Alert at % of budget (0.8 = 80%)\n\n // Logging\n auditLog: boolean;\n logDir: string;\n\n // Dashboard\n dashboard: boolean;\n dashboardPath: string;\n}\n\nexport const DEFAULT_GATEWAY_CONFIG: GatewayConfig = {\n port: 8787,\n host: '127.0.0.1',\n optimize: true,\n projectPath: '.',\n budget: 50_000,\n redactSecrets: true,\n blockOnSecrets: false,\n apiKey: '',\n allowedTargetDomains: [], // Empty = default LLM provider allowlist\n maxBodyBytes: 10 * 1024 * 1024, // 10MB\n upstreamTimeoutMs: 120_000, // 2 minutes (streaming can be slow)\n costTracking: true,\n budgetDaily: 0,\n budgetMonthly: 0,\n alertThreshold: 0.8,\n auditLog: true,\n logDir: '.cto/gateway',\n dashboard: true,\n dashboardPath: '/__cto',\n};\n\n// ===== SSRF PROTECTION =====\n// Default safe domains for LLM API providers\nexport const DEFAULT_ALLOWED_DOMAINS = new Set([\n 'api.openai.com',\n 'api.anthropic.com',\n 'generativelanguage.googleapis.com',\n 'aiplatform.googleapis.com',\n // Azure uses custom subdomains: *.openai.azure.com\n]);\n\n// Blocked IP ranges (SSRF protection)\nconst PRIVATE_IP_PATTERNS = [\n /^127\\./, // Loopback\n /^10\\./, // Class A private\n /^172\\.(1[6-9]|2\\d|3[01])\\./,// Class B private\n /^192\\.168\\./, // Class C private\n /^169\\.254\\./, // Link-local (AWS metadata!)\n /^0\\./, // Current network\n /^::1$/, // IPv6 loopback\n /^f[cd]/i, // IPv6 private\n /^fe80:/i, // IPv6 link-local\n];\n\nexport function isPrivateIP(ip: string): boolean {\n return PRIVATE_IP_PATTERNS.some((p) => p.test(ip));\n}\n\nexport function isAllowedTarget(hostname: string, config: GatewayConfig): boolean {\n // User-configured allowlist takes priority\n if (config.allowedTargetDomains.length > 0) {\n return config.allowedTargetDomains.some((d) =>\n hostname === d || hostname.endsWith('.' + d)\n );\n }\n // Default: allow known LLM provider domains + Azure pattern\n if (DEFAULT_ALLOWED_DOMAINS.has(hostname)) return true;\n if (hostname.endsWith('.openai.azure.com')) return true;\n // Block everything else by default\n return false;\n}\n\n// ===== USAGE TRACKING =====\n\nexport interface UsageRecord {\n id: string;\n timestamp: Date;\n provider: ProviderName;\n model: string;\n inputTokens: number;\n outputTokens: number;\n costUSD: number;\n\n // Context optimization\n originalTokens: number; // Before CTO optimization\n optimizedTokens: number; // After CTO optimization\n savedTokens: number;\n savedUSD: number;\n\n // Security\n secretsRedacted: number;\n secretsBlocked: boolean;\n\n // Metadata\n projectPath: string;\n latencyMs: number;\n stream: boolean;\n error?: string;\n}\n\nexport interface UsageSummary {\n period: 'day' | 'week' | 'month' | 'all';\n totalRequests: number;\n totalInputTokens: number;\n totalOutputTokens: number;\n totalCostUSD: number;\n totalSavedTokens: number;\n totalSavedUSD: number;\n totalSecretsRedacted: number;\n byModel: Record<string, { requests: number; costUSD: number; tokens: number }>;\n byProvider: Record<string, { requests: number; costUSD: number }>;\n}\n\n// ===== INTERCEPTOR =====\n\nexport interface InterceptResult {\n modified: boolean;\n messages: Message[];\n originalTokens: number;\n optimizedTokens: number;\n secretsRedacted: number;\n secretsBlocked: boolean;\n contextInjected: boolean;\n decisions: string[];\n}\n\n// ===== EVENTS =====\n\nexport type GatewayEvent =\n | { type: 'request'; record: UsageRecord }\n | { type: 'budget-alert'; current: number; limit: number; period: string }\n | { type: 'budget-exceeded'; current: number; limit: number; period: string }\n | { type: 'secret-blocked'; file: string; count: number }\n | { type: 'error'; message: string; error?: Error };\n\nexport type GatewayEventHandler = (event: GatewayEvent) => void;\n","// ===== Context Gateway — Provider Registry =====\n//\n// Detects and normalizes requests across OpenAI, Anthropic, Google, and Azure.\n// Each provider has different API shapes — this layer abstracts them.\n\nimport type { ProviderConfig, ProviderName, ParsedRequest, ParsedResponse, Message, ModelConfig } from './types.js';\n\n// ===== MODEL PRICING (as of 2026-02) =====\n\nconst OPENAI_MODELS: ModelConfig[] = [\n { id: 'gpt-4o', contextWindow: 128_000, costPerMInput: 2.50, costPerMOutput: 10.00, maxOutput: 16_384 },\n { id: 'gpt-4o-mini', contextWindow: 128_000, costPerMInput: 0.15, costPerMOutput: 0.60, maxOutput: 16_384 },\n { id: 'gpt-4-turbo', contextWindow: 128_000, costPerMInput: 10.00, costPerMOutput: 30.00, maxOutput: 4_096 },\n { id: 'gpt-3.5-turbo', contextWindow: 16_385, costPerMInput: 0.50, costPerMOutput: 1.50, maxOutput: 4_096 },\n { id: 'o1', contextWindow: 200_000, costPerMInput: 15.00, costPerMOutput: 60.00, maxOutput: 100_000 },\n { id: 'o1-mini', contextWindow: 128_000, costPerMInput: 3.00, costPerMOutput: 12.00, maxOutput: 65_536 },\n { id: 'o3-mini', contextWindow: 200_000, costPerMInput: 1.10, costPerMOutput: 4.40, maxOutput: 100_000 },\n];\n\nconst ANTHROPIC_MODELS: ModelConfig[] = [\n { id: 'claude-sonnet-4-20250514', contextWindow: 200_000, costPerMInput: 3.00, costPerMOutput: 15.00, maxOutput: 64_000 },\n { id: 'claude-3-5-haiku-20241022', contextWindow: 200_000, costPerMInput: 0.80, costPerMOutput: 4.00, maxOutput: 8_192 },\n { id: 'claude-3-opus-20240229', contextWindow: 200_000, costPerMInput: 15.00, costPerMOutput: 75.00, maxOutput: 4_096 },\n];\n\nconst GOOGLE_MODELS: ModelConfig[] = [\n { id: 'gemini-2.5-pro', contextWindow: 1_000_000, costPerMInput: 1.25, costPerMOutput: 10.00, maxOutput: 65_536 },\n { id: 'gemini-2.0-flash', contextWindow: 1_000_000, costPerMInput: 0.10, costPerMOutput: 0.40, maxOutput: 8_192 },\n { id: 'gemini-1.5-pro', contextWindow: 2_000_000, costPerMInput: 1.25, costPerMOutput: 5.00, maxOutput: 8_192 },\n];\n\n// ===== PROVIDER DEFINITIONS =====\n\nfunction parseOpenAIRequest(body: any): ParsedRequest {\n const messages: Message[] = (body.messages || []).map((m: any) => ({\n role: m.role || 'user',\n content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),\n }));\n\n return {\n model: body.model || 'unknown',\n messages,\n stream: body.stream === true,\n maxTokens: body.max_tokens ?? body.max_completion_tokens,\n temperature: body.temperature,\n };\n}\n\nfunction parseOpenAIResponse(body: any, streaming: boolean): ParsedResponse {\n if (streaming) {\n // For streaming, body is the accumulated final state\n return {\n model: body.model || 'unknown',\n inputTokens: body.usage?.prompt_tokens || 0,\n outputTokens: body.usage?.completion_tokens || 0,\n content: body.choices?.[0]?.message?.content || '',\n finishReason: body.choices?.[0]?.finish_reason || 'stop',\n };\n }\n\n return {\n model: body.model || 'unknown',\n inputTokens: body.usage?.prompt_tokens || 0,\n outputTokens: body.usage?.completion_tokens || 0,\n content: body.choices?.[0]?.message?.content || '',\n finishReason: body.choices?.[0]?.finish_reason || 'stop',\n };\n}\n\nfunction parseAnthropicRequest(body: any): ParsedRequest {\n const messages: Message[] = [];\n\n // Anthropic uses a separate \"system\" field\n if (body.system) {\n messages.push({ role: 'system', content: body.system });\n }\n\n for (const m of body.messages || []) {\n messages.push({\n role: m.role || 'user',\n content: typeof m.content === 'string' ? m.content : m.content?.map((b: any) => b.text || '').join('\\n') || '',\n });\n }\n\n return {\n model: body.model || 'unknown',\n messages,\n stream: body.stream === true,\n maxTokens: body.max_tokens,\n temperature: body.temperature,\n };\n}\n\nfunction parseAnthropicResponse(body: any, _streaming: boolean): ParsedResponse {\n return {\n model: body.model || 'unknown',\n inputTokens: body.usage?.input_tokens || 0,\n outputTokens: body.usage?.output_tokens || 0,\n content: body.content?.map((b: any) => b.text || '').join('\\n') || '',\n finishReason: body.stop_reason || 'end_turn',\n };\n}\n\nfunction parseGoogleRequest(body: any): ParsedRequest {\n const messages: Message[] = [];\n\n if (body.systemInstruction?.parts) {\n messages.push({\n role: 'system',\n content: body.systemInstruction.parts.map((p: any) => p.text || '').join('\\n'),\n });\n }\n\n for (const item of body.contents || []) {\n const role = item.role === 'model' ? 'assistant' : 'user';\n const content = item.parts?.map((p: any) => p.text || '').join('\\n') || '';\n messages.push({ role, content });\n }\n\n // Extract model from body.model or infer from context\n const model = body.model || body.modelId || 'gemini-2.0-flash';\n\n return {\n model,\n messages,\n stream: body.stream === true,\n maxTokens: body.generationConfig?.maxOutputTokens,\n temperature: body.generationConfig?.temperature,\n };\n}\n\nfunction parseGoogleResponse(body: any, _streaming: boolean): ParsedResponse {\n const candidate = body.candidates?.[0];\n return {\n model: body.modelVersion || body.model || 'gemini-2.0-flash',\n inputTokens: body.usageMetadata?.promptTokenCount || 0,\n outputTokens: body.usageMetadata?.candidatesTokenCount || 0,\n content: candidate?.content?.parts?.map((p: any) => p.text || '').join('\\n') || '',\n finishReason: candidate?.finishReason || 'STOP',\n };\n}\n\n// ===== REGISTRY =====\n\nexport const PROVIDERS: Record<ProviderName, ProviderConfig> = {\n openai: {\n name: 'openai',\n displayName: 'OpenAI',\n baseUrl: 'https://api.openai.com',\n authHeader: 'Authorization',\n chatPath: '/v1/chat/completions',\n models: OPENAI_MODELS,\n parseRequest: parseOpenAIRequest,\n parseResponse: parseOpenAIResponse,\n detectProvider: (url, _headers) =>\n url.includes('api.openai.com') || url.includes('/v1/chat/completions'),\n },\n\n anthropic: {\n name: 'anthropic',\n displayName: 'Anthropic',\n baseUrl: 'https://api.anthropic.com',\n authHeader: 'x-api-key',\n chatPath: '/v1/messages',\n models: ANTHROPIC_MODELS,\n parseRequest: parseAnthropicRequest,\n parseResponse: parseAnthropicResponse,\n detectProvider: (url, headers) =>\n url.includes('api.anthropic.com') ||\n url.includes('/v1/messages') ||\n !!headers['x-api-key'] ||\n !!headers['anthropic-version'],\n },\n\n google: {\n name: 'google',\n displayName: 'Google AI',\n baseUrl: 'https://generativelanguage.googleapis.com',\n authHeader: 'x-goog-api-key',\n chatPath: '/v1beta/models',\n models: GOOGLE_MODELS,\n parseRequest: parseGoogleRequest,\n parseResponse: parseGoogleResponse,\n detectProvider: (url, _headers) =>\n url.includes('generativelanguage.googleapis.com') ||\n url.includes('aiplatform.googleapis.com'),\n },\n\n 'azure-openai': {\n name: 'azure-openai',\n displayName: 'Azure OpenAI',\n baseUrl: '',\n authHeader: 'api-key',\n chatPath: '/openai/deployments',\n models: OPENAI_MODELS, // Same models, different hosting\n parseRequest: parseOpenAIRequest,\n parseResponse: parseOpenAIResponse,\n detectProvider: (url, headers) =>\n url.includes('.openai.azure.com') || !!headers['api-key'],\n },\n\n custom: {\n name: 'custom',\n displayName: 'Custom (OpenAI-compatible)',\n baseUrl: '',\n authHeader: 'Authorization',\n chatPath: '/v1/chat/completions',\n models: [],\n parseRequest: parseOpenAIRequest,\n parseResponse: parseOpenAIResponse,\n detectProvider: () => false, // Fallback only\n },\n};\n\n// ===== DETECTION =====\n\nexport function detectProvider(url: string, headers: Record<string, string>): ProviderConfig {\n for (const provider of Object.values(PROVIDERS)) {\n if (provider.name === 'custom') continue;\n if (provider.detectProvider(url, headers)) return provider;\n }\n // Default to OpenAI-compatible\n return PROVIDERS.custom;\n}\n\nexport function getModelConfig(provider: ProviderConfig, modelId: string): ModelConfig | undefined {\n // Exact match\n const exact = provider.models.find((m) => m.id === modelId);\n if (exact) return exact;\n\n // Prefix match (for versioned models like claude-sonnet-4-*)\n return provider.models.find((m) => modelId.startsWith(m.id) || m.id.startsWith(modelId));\n}\n\nexport function estimateCost(\n provider: ProviderConfig,\n modelId: string,\n inputTokens: number,\n outputTokens: number,\n): number {\n const model = getModelConfig(provider, modelId);\n if (!model) return 0;\n\n const inputCost = (inputTokens / 1_000_000) * model.costPerMInput;\n const outputCost = (outputTokens / 1_000_000) * model.costPerMOutput;\n return Math.round((inputCost + outputCost) * 1_000_000) / 1_000_000; // 6 decimal places\n}\n","import { readFile, writeFile } from 'node:fs/promises';\nimport { readFileSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { resolve, relative, join, dirname } from 'node:path';\nimport { createHash } from 'node:crypto';\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 // Stripe\n { type: 'api-key', source: 'sk_live_[a-zA-Z0-9]{24,}', flags: 'g', severity: 'critical', description: 'Stripe Live Secret Key' },\n { type: 'api-key', source: 'pk_live_[a-zA-Z0-9]{24,}', flags: 'g', severity: 'high', description: 'Stripe Live Publishable Key' },\n { type: 'api-key', source: 'rk_live_[a-zA-Z0-9]{24,}', flags: 'g', severity: 'critical', description: 'Stripe Restricted Key' },\n\n // Slack\n { type: 'token', source: 'xoxb-[0-9]{10,}-[0-9]{10,}-[a-zA-Z0-9]{24,}', flags: 'g', severity: 'critical', description: 'Slack Bot Token' },\n { type: 'token', source: 'xoxp-[0-9]{10,}-[0-9]{10,}-[a-zA-Z0-9]{24,}', flags: 'g', severity: 'critical', description: 'Slack User Token' },\n { type: 'api-key', source: 'https://hooks\\\\.slack\\\\.com/services/T[a-zA-Z0-9_]+/B[a-zA-Z0-9_]+/[a-zA-Z0-9_]+', flags: 'g', severity: 'high', description: 'Slack Webhook URL' },\n\n // Google\n { type: 'api-key', source: 'AIza[0-9A-Za-z_-]{35}', flags: 'g', severity: 'high', description: 'Google API Key' },\n { type: 'token', source: 'ya29\\\\.[0-9A-Za-z_-]+', flags: 'g', severity: 'high', description: 'Google OAuth Token' },\n\n // Azure\n { type: 'api-key', source: '(?:AccountKey|SharedAccessKey)\\\\s*=\\\\s*[a-zA-Z0-9+/=]{40,}', flags: 'g', severity: 'critical', description: 'Azure Storage Key' },\n\n // Twilio\n { type: 'api-key', source: 'AC[a-f0-9]{32}', flags: 'g', severity: 'high', description: 'Twilio Account SID' },\n\n // SendGrid\n { type: 'api-key', source: 'SG\\\\.[a-zA-Z0-9_-]{22}\\\\.[a-zA-Z0-9_-]{43}', flags: 'g', severity: 'critical', description: 'SendGrid API Key' },\n\n // JWT\n { type: 'token', source: 'eyJ[a-zA-Z0-9_-]{10,}\\\\.eyJ[a-zA-Z0-9_-]{10,}\\\\.[a-zA-Z0-9_-]{10,}', flags: 'g', severity: 'high', description: 'JSON Web Token' },\n\n // Datadog\n { type: 'api-key', source: '(?:DD_API_KEY|DATADOG_API_KEY)\\\\s*[:=]\\\\s*[\\'\"]?([a-f0-9]{32})[\\'\"]?', flags: 'gi', severity: 'critical', description: 'Datadog API Key' },\n { type: 'api-key', source: '(?:DD_APP_KEY|DATADOG_APP_KEY)\\\\s*[:=]\\\\s*[\\'\"]?([a-f0-9]{40})[\\'\"]?', flags: 'gi', severity: 'critical', description: 'Datadog App Key' },\n\n // Sentry\n { type: 'connection-string', source: 'https://[a-f0-9]{32}@[a-z0-9]+\\\\.ingest\\\\.sentry\\\\.io/[0-9]+', flags: 'g', severity: 'high', description: 'Sentry DSN' },\n\n // Firebase\n { type: 'api-key', source: '(?:FIREBASE_API_KEY|FIREBASE_KEY)\\\\s*[:=]\\\\s*[\\'\"]?([a-zA-Z0-9_\\\\-]{30,})[\\'\"]?', flags: 'gi', severity: 'high', description: 'Firebase API Key' },\n { type: 'connection-string', source: 'firebase[a-z]*:\\\\/\\\\/[^\\\\s\\'\"]+', flags: 'gi', severity: 'high', description: 'Firebase URL' },\n\n // Supabase\n { type: 'api-key', source: 'sbp_[a-f0-9]{40}', flags: 'g', severity: 'critical', description: 'Supabase Service Key' },\n { type: 'token', source: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\\\\.[a-zA-Z0-9_-]{20,}\\\\.[a-zA-Z0-9_-]{20,}', flags: 'g', severity: 'high', description: 'Supabase Anon/Service JWT' },\n\n // Vercel\n { type: 'token', source: '(?:VERCEL_TOKEN|VERCEL_API_TOKEN)\\\\s*[:=]\\\\s*[\\'\"]?([a-zA-Z0-9]{24,})[\\'\"]?', flags: 'gi', severity: 'critical', description: 'Vercel Token' },\n\n // Heroku\n { type: 'api-key', source: '(?:HEROKU_API_KEY|HEROKU_TOKEN)\\\\s*[:=]\\\\s*[\\'\"]?([a-f0-9\\\\-]{36,})[\\'\"]?', flags: 'gi', severity: 'critical', description: 'Heroku API Key' },\n\n // DigitalOcean\n { type: 'token', source: 'dop_v1_[a-f0-9]{64}', flags: 'g', severity: 'critical', description: 'DigitalOcean Personal Access Token' },\n { type: 'token', source: 'doo_v1_[a-f0-9]{64}', flags: 'g', severity: 'critical', description: 'DigitalOcean OAuth Token' },\n\n // Mailgun\n { type: 'api-key', source: 'key-[a-zA-Z0-9]{32}', flags: 'g', severity: 'high', description: 'Mailgun API Key' },\n\n // PII\n { type: 'pii', source: '\\\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\\\.[A-Z|a-z]{2,}\\\\b', flags: 'g', severity: 'medium', description: 'Email Address (PII)' },\n { type: 'pii', source: '\\\\b(?!000|666|9\\\\d{2})(\\\\d{3})[-.]?(?!00)(\\\\d{2})[-.]?(?!0000)(\\\\d{4})\\\\b', flags: 'g', severity: 'high', description: 'Possible SSN (PII)' },\n];\n\n// Pre-compiled builtin patterns (compiled once, reused across all calls)\nlet _cachedBuiltinPatterns: SecretPattern[] | null = null;\n\nfunction getBuiltinPatterns(): SecretPattern[] {\n if (!_cachedBuiltinPatterns) {\n _cachedBuiltinPatterns = 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 return _cachedBuiltinPatterns;\n}\n\nfunction buildPatterns(customPatterns: string[] = []): SecretPattern[] {\n const builtins = getBuiltinPatterns();\n if (customPatterns.length === 0) return builtins;\n\n // Only create new array when custom patterns exist\n const patterns = [...builtins];\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 extraPiiSafeDomains?: Set<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 if (secretPattern.type === 'pii' && isSafeEmail(matchText, extraPiiSafeDomains)) 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\n// ===== PII SAFE DOMAIN LIST =====\n// Emails at these domains are not flagged as PII (too many false positives)\n\nconst PII_SAFE_EMAIL_DOMAINS = new Set([\n 'example.com', 'example.org', 'example.net',\n 'test.com', 'test.org', 'test.net',\n 'localhost', 'localhost.localdomain',\n 'email.com', 'mail.com',\n 'foo.com', 'bar.com', 'baz.com',\n 'acme.com', 'company.com', 'corp.com',\n 'noreply.com', 'no-reply.com',\n 'users.noreply.github.com',\n 'placeholder.com',\n]);\n\nfunction isSafeEmail(value: string, extraDomains?: Set<string>): boolean {\n const match = value.match(/@([a-zA-Z0-9.-]+)$/);\n if (!match) return false;\n const domain = match[1].toLowerCase();\n if (PII_SAFE_EMAIL_DOMAINS.has(domain)) return true;\n if (extraDomains && extraDomains.has(domain)) return true;\n return false;\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\n// ===== ALLOWLIST — Mark findings as reviewed/safe =====\n\nexport interface AllowlistEntry {\n fingerprint: string; // sha256 of file:type:match\n file: string;\n type: string;\n redacted: string;\n reason: string;\n reviewedBy: string;\n reviewedAt: string;\n}\n\nfunction fingerprintFinding(f: SecretFinding): string {\n return createHash('sha256').update(`${f.file}:${f.type}:${f.match}`).digest('hex').slice(0, 32);\n}\n\nfunction getAllowlistPath(projectPath: string): string {\n return join(projectPath, '.cto', 'audit', 'allowlist.json');\n}\n\nexport function loadAllowlist(projectPath: string): AllowlistEntry[] {\n const filePath = getAllowlistPath(projectPath);\n if (!existsSync(filePath)) return [];\n try {\n return JSON.parse(readFileSync(filePath, 'utf-8'));\n } catch {\n return [];\n }\n}\n\nexport function saveAllowlist(projectPath: string, entries: AllowlistEntry[]): void {\n const filePath = getAllowlistPath(projectPath);\n mkdirSync(dirname(filePath), { recursive: true });\n writeFileSync(filePath, JSON.stringify(entries, null, 2) + '\\n');\n}\n\nexport function addToAllowlist(\n projectPath: string,\n finding: SecretFinding,\n reason: string,\n reviewedBy: string = 'manual',\n): AllowlistEntry {\n const entries = loadAllowlist(projectPath);\n const entry: AllowlistEntry = {\n fingerprint: fingerprintFinding(finding),\n file: finding.file,\n type: finding.type,\n redacted: finding.redacted,\n reason,\n reviewedBy,\n reviewedAt: new Date().toISOString(),\n };\n\n // Deduplicate by fingerprint\n const existing = entries.findIndex((e) => e.fingerprint === entry.fingerprint);\n if (existing >= 0) {\n entries[existing] = entry;\n } else {\n entries.push(entry);\n }\n\n saveAllowlist(projectPath, entries);\n return entry;\n}\n\nexport function filterByAllowlist(findings: SecretFinding[], projectPath: string): {\n filtered: SecretFinding[];\n allowed: SecretFinding[];\n} {\n const allowlist = loadAllowlist(projectPath);\n if (allowlist.length === 0) return { filtered: findings, allowed: [] };\n\n const allowedFingerprints = new Set(allowlist.map((e) => e.fingerprint));\n const filtered: SecretFinding[] = [];\n const allowed: SecretFinding[] = [];\n\n for (const f of findings) {\n if (allowedFingerprints.has(fingerprintFinding(f))) {\n allowed.push(f);\n } else {\n filtered.push(f);\n }\n }\n\n return { filtered, allowed };\n}\n\n// ===== INCREMENTAL SCANNING — Only scan changed files =====\n\ninterface FileHashMap {\n [relativePath: string]: string; // sha256 of file content\n}\n\nfunction getHashCachePath(projectPath: string): string {\n return join(projectPath, '.cto', 'audit', '.hashcache.json');\n}\n\nfunction loadHashCache(projectPath: string): FileHashMap {\n const filePath = getHashCachePath(projectPath);\n if (!existsSync(filePath)) return {};\n try {\n return JSON.parse(readFileSync(filePath, 'utf-8'));\n } catch {\n return {};\n }\n}\n\nfunction saveHashCache(projectPath: string, cache: FileHashMap): void {\n const filePath = getHashCachePath(projectPath);\n mkdirSync(dirname(filePath), { recursive: true });\n writeFileSync(filePath, JSON.stringify(cache));\n}\n\nfunction hashContent(content: string): string {\n return createHash('sha256').update(content).digest('hex').slice(0, 16);\n}\n\nexport function getChangedFiles(\n projectPath: string,\n filePaths: string[],\n): { changed: string[]; unchanged: string[]; cache: FileHashMap } {\n const oldCache = loadHashCache(projectPath);\n const newCache: FileHashMap = {};\n const changed: string[] = [];\n const unchanged: string[] = [];\n\n for (const fp of filePaths) {\n try {\n const content = readFileSync(fp, 'utf-8');\n const relPath = relative(resolve(projectPath), resolve(fp));\n const hash = hashContent(content);\n newCache[relPath] = hash;\n\n if (oldCache[relPath] === hash) {\n unchanged.push(fp);\n } else {\n changed.push(fp);\n }\n } catch {\n changed.push(fp); // Can't read → scan it\n }\n }\n\n return { changed, unchanged, cache: newCache };\n}\n\n// ===== SEVERITY CONFIGURATION =====\n\nexport interface AuditConfig {\n severityOverrides: Partial<Record<SecretType, SecretFinding['severity']>>;\n piiSafeDomains: string[];\n customPatterns: string[];\n entropyThreshold: number;\n includePII: boolean;\n incrementalScan: boolean;\n}\n\nexport const DEFAULT_AUDIT_CONFIG: AuditConfig = {\n severityOverrides: {},\n piiSafeDomains: [],\n customPatterns: [],\n entropyThreshold: 5.0,\n includePII: true,\n incrementalScan: true,\n};\n\nfunction getAuditConfigPath(projectPath: string): string {\n return join(projectPath, '.cto', 'audit', 'config.json');\n}\n\nexport function loadAuditConfig(projectPath: string): AuditConfig {\n const filePath = getAuditConfigPath(projectPath);\n if (!existsSync(filePath)) return { ...DEFAULT_AUDIT_CONFIG };\n try {\n const loaded = JSON.parse(readFileSync(filePath, 'utf-8'));\n return { ...DEFAULT_AUDIT_CONFIG, ...loaded };\n } catch {\n return { ...DEFAULT_AUDIT_CONFIG };\n }\n}\n\nexport function saveAuditConfig(projectPath: string, config: AuditConfig): void {\n const filePath = getAuditConfigPath(projectPath);\n mkdirSync(dirname(filePath), { recursive: true });\n writeFileSync(filePath, JSON.stringify(config, null, 2) + '\\n');\n}\n\nfunction applySeverityOverrides(\n findings: SecretFinding[],\n overrides: Partial<Record<SecretType, SecretFinding['severity']>>,\n): SecretFinding[] {\n if (Object.keys(overrides).length === 0) return findings;\n return findings.map((f) => {\n const override = overrides[f.type];\n if (override) return { ...f, severity: override };\n return f;\n });\n}\n\n// ===== PRE-COMMIT HOOK GENERATOR =====\n\nexport function generatePreCommitHook(projectPath: string, hookType: 'husky' | 'githooks' = 'husky'): string {\n const hookContent = `#!/bin/sh\n# CTO Secret Detection — Pre-commit hook\n# Auto-generated by: npx cto-ai-cli --audit --init-hook\n# Scans ONLY staged files for secrets before allowing commit.\n\nSTAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)\n\nif [ -z \"$STAGED_FILES\" ]; then\n exit 0\nfi\n\necho \"🔍 CTO: Scanning $(echo \"$STAGED_FILES\" | wc -l | tr -d ' ') staged files for secrets...\"\n\n# Write staged files to temp list\nTMPFILE=$(mktemp)\necho \"$STAGED_FILES\" > \"$TMPFILE\"\n\n# Run audit in CI mode on staged files only\nCI=true npx cto-ai-cli --audit --files \"$TMPFILE\"\nRESULT=$?\n\nrm -f \"$TMPFILE\"\n\nif [ $RESULT -ne 0 ]; then\n echo \"\"\n echo \"❌ Commit blocked: secrets detected in staged files.\"\n echo \" Run 'npx cto-ai-cli --audit' to see details.\"\n echo \" Use allowlist to mark reviewed findings as safe.\"\n echo \"\"\n exit 1\nfi\n\necho \"✅ No secrets detected. Proceeding with commit.\"\n`;\n\n let hookPath: string;\n if (hookType === 'husky') {\n hookPath = join(projectPath, '.husky', 'pre-commit');\n } else {\n hookPath = join(projectPath, '.git', 'hooks', 'pre-commit');\n }\n\n mkdirSync(dirname(hookPath), { recursive: true });\n writeFileSync(hookPath, hookContent, { mode: 0o755 });\n\n return hookPath;\n}\n\n// ===== ENTROPY ANALYSIS =====\n\nfunction shannonEntropy(str: string): number {\n const freq = new Map<string, number>();\n for (const ch of str) {\n freq.set(ch, (freq.get(ch) || 0) + 1);\n }\n let entropy = 0;\n for (const count of freq.values()) {\n const p = count / str.length;\n if (p > 0) entropy -= p * Math.log2(p);\n }\n return entropy;\n}\n\nconst HIGH_ENTROPY_RE = /['\"]([a-zA-Z0-9+/=_\\-]{30,})['\"]|=\\s*['\"]?([a-zA-Z0-9+/=_\\-]{30,})['\"]?/g;\n\nconst ENTROPY_SKIP = [\n /^[a-f0-9]{32,}$/i, // hex hashes\n /^[A-Z_]{30,}$/, // all-caps constants\n /^[a-z_]{30,}$/, // all-lowercase identifiers\n /^[a-zA-Z0-9+/]+=+$/, // base64 padding\n /^[a-z]+[A-Z][a-zA-Z]+$/, // camelCase identifiers\n /sha\\d+-/i, // integrity hashes (sha256-, sha512-)\n];\n\nexport function scanContentForHighEntropy(\n content: string,\n filePath: string,\n threshold: number = 5.0,\n): SecretFinding[] {\n const findings: SecretFinding[] = [];\n const lines = content.split('\\n');\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line.trim().startsWith('//') || line.trim().startsWith('#') || line.trim().startsWith('*')) continue;\n\n HIGH_ENTROPY_RE.lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = HIGH_ENTROPY_RE.exec(line)) !== null) {\n const value = match[1] || match[2];\n if (!value || value.length < 40) continue;\n if (isTemplateOrPlaceholder(value)) continue;\n if (ENTROPY_SKIP.some((p) => p.test(value))) continue;\n\n const entropy = shannonEntropy(value);\n if (entropy >= threshold) {\n findings.push({\n type: 'high-entropy',\n file: filePath,\n line: i + 1,\n match: value,\n redacted: redactSecret(value),\n severity: entropy >= 5.0 ? 'high' : 'medium',\n });\n }\n }\n }\n\n return deduplicateFindings(findings);\n}\n\n// ===== FULL PROJECT AUDIT =====\n\nexport interface AuditResult {\n findings: SecretFinding[];\n summary: {\n totalFiles: number;\n filesScanned: number;\n filesWithSecrets: number;\n totalFindings: number;\n bySeverity: { critical: number; high: number; medium: number; low: number };\n byType: Record<string, number>;\n };\n recommendations: string[];\n}\n\nexport interface AuditOptions {\n customPatterns?: string[];\n entropyThreshold?: number;\n includePII?: boolean;\n useAllowlist?: boolean;\n incrementalScan?: boolean;\n severityOverrides?: Partial<Record<SecretType, SecretFinding['severity']>>;\n piiSafeDomains?: string[];\n}\n\nexport async function auditProject(\n projectPath: string,\n filePaths: string[],\n options: AuditOptions = {},\n): Promise<AuditResult> {\n // Load config from .cto/audit/config.json (user overrides take precedence)\n const savedConfig = loadAuditConfig(projectPath);\n const customPatterns = options.customPatterns ?? savedConfig.customPatterns;\n const entropyThreshold = options.entropyThreshold ?? savedConfig.entropyThreshold;\n const includePII = options.includePII ?? savedConfig.includePII;\n const useAllowlist = options.useAllowlist ?? true;\n const incrementalScan = options.incrementalScan ?? savedConfig.incrementalScan;\n const severityOverrides = options.severityOverrides ?? savedConfig.severityOverrides;\n\n // Build per-call PII safe domains set (no global mutation)\n let extraPiiDomains: Set<string> | undefined;\n const allExtraDomains = [...(options.piiSafeDomains || []), ...savedConfig.piiSafeDomains];\n if (allExtraDomains.length > 0) {\n extraPiiDomains = new Set(allExtraDomains.map((d) => d.toLowerCase()));\n }\n\n // Incremental scanning: only scan changed files\n let filesToScan = filePaths;\n let unchangedCount = 0;\n let newCache: Record<string, string> | null = null;\n\n if (incrementalScan) {\n const { changed, unchanged, cache } = getChangedFiles(projectPath, filePaths);\n newCache = cache; // Always save cache for next run\n if (changed.length < filePaths.length) {\n filesToScan = changed;\n unchangedCount = unchanged.length;\n }\n }\n\n const allFindings: SecretFinding[] = [];\n const filesWithSecrets = new Set<string>();\n\n for (const fp of filesToScan) {\n try {\n const content = await readFile(fp, 'utf-8');\n const relPath = relative(resolve(projectPath), resolve(fp));\n\n // Skip test files and declaration files for entropy (too many false positives)\n const isTestFile = /\\.(test|spec|mock)\\.[jt]sx?$/.test(relPath) || relPath.includes('__tests__');\n const isDtsFile = relPath.endsWith('.d.ts');\n\n // Pattern-based detection (pass extra PII domains per-call, no global leak)\n let findings = scanContentForSecrets(content, relPath, customPatterns, extraPiiDomains);\n\n // Filter PII if not wanted\n if (!includePII) {\n findings = findings.filter((f) => f.type !== 'pii');\n }\n\n // Entropy-based detection (skip test/declaration files — too noisy)\n const entropyFindings = (isTestFile || isDtsFile)\n ? []\n : scanContentForHighEntropy(content, relPath, entropyThreshold);\n\n const combined = [...findings, ...entropyFindings];\n if (combined.length > 0) {\n filesWithSecrets.add(relPath);\n allFindings.push(...combined);\n }\n } catch {\n // skip unreadable files\n }\n }\n\n // Apply severity overrides from config\n let finalFindings = applySeverityOverrides(allFindings, severityOverrides);\n\n // Apply allowlist — filter out reviewed findings\n let allowedCount = 0;\n if (useAllowlist) {\n const { filtered, allowed } = filterByAllowlist(finalFindings, projectPath);\n finalFindings = filtered;\n allowedCount = allowed.length;\n }\n\n // Sort by severity\n finalFindings.sort((a, b) => {\n const order = { critical: 0, high: 1, medium: 2, low: 3 };\n return order[a.severity] - order[b.severity];\n });\n\n // Save hash cache for incremental scanning\n if (newCache) {\n saveHashCache(projectPath, newCache);\n }\n\n // Build summary\n const bySeverity = { critical: 0, high: 0, medium: 0, low: 0 };\n const byType: Record<string, number> = {};\n for (const f of finalFindings) {\n bySeverity[f.severity]++;\n byType[f.type] = (byType[f.type] || 0) + 1;\n }\n\n // Generate recommendations\n const recommendations: string[] = [];\n if (bySeverity.critical > 0) {\n recommendations.push('CRITICAL: Rotate all detected credentials immediately. They may already be compromised.');\n }\n if (byType['password'] > 0) {\n recommendations.push('Move passwords to environment variables or a secrets manager (AWS Secrets Manager, Vault, etc.).');\n }\n if (byType['api-key'] > 0 || byType['aws-key'] > 0) {\n recommendations.push('Use environment variables for API keys. Never commit them to source control.');\n }\n if (byType['connection-string'] > 0) {\n recommendations.push('Database connection strings should use environment variables, not hardcoded values.');\n }\n if (byType['private-key'] > 0) {\n recommendations.push('Private keys should NEVER be in source code. Use a key management service.');\n }\n if (byType['pii'] > 0) {\n recommendations.push('PII detected. Review for GDPR/CCPA compliance. Consider data anonymization.');\n }\n if (byType['high-entropy'] > 0) {\n recommendations.push('High-entropy strings detected that may be secrets. Review manually.');\n }\n if (finalFindings.length > 0) {\n recommendations.push('Add a .gitignore entry for .env files if not already present.');\n recommendations.push('Run `npx cto-ai-cli --audit` regularly or add to CI pipeline.');\n }\n if (finalFindings.length === 0) {\n recommendations.push('No secrets detected. Great job keeping your codebase clean!');\n }\n if (allowedCount > 0) {\n recommendations.push(`${allowedCount} finding(s) skipped via allowlist (.cto/audit/allowlist.json).`);\n }\n if (unchangedCount > 0) {\n recommendations.push(`${unchangedCount} unchanged file(s) skipped (incremental scan).`);\n }\n\n return {\n findings: finalFindings,\n summary: {\n totalFiles: filePaths.length,\n filesScanned: filesToScan.length,\n filesWithSecrets: filesWithSecrets.size,\n totalFindings: finalFindings.length,\n bySeverity,\n byType,\n },\n recommendations,\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 { 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 { 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 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","// ===== Context Gateway — Request Interceptor =====\n//\n// Intercepts LLM API requests and:\n// 1. Scans for secrets in message content → redacts or blocks\n// 2. Analyzes context quality → injects CTO-optimized context\n// 3. Tracks token usage before/after optimization\n//\n// Design: Pure functions. No side effects. Easy to test.\n\nimport type { Message, InterceptResult, GatewayConfig } from './types.js';\nimport { scanContentForSecrets, sanitizeContent } from '../govern/secrets.js';\nimport type { ProjectAnalysis } from '../types/engine.js';\nimport { selectContext } from '../engine/selector.js';\nimport { readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nfunction estimateTokensFromString(s: string): number {\n return Math.ceil(Buffer.byteLength(s, 'utf-8') / 4);\n}\n\n// ===== MAIN INTERCEPTOR =====\n\nexport async function interceptRequest(\n messages: Message[],\n config: GatewayConfig,\n analysis: ProjectAnalysis | null,\n): Promise<InterceptResult> {\n const decisions: string[] = [];\n let secretsRedacted = 0;\n let secretsBlocked = false;\n let contextInjected = false;\n\n // Calculate original tokens\n const originalTokens = messages.reduce((sum, m) => sum + estimateTokensFromString(m.content), 0);\n\n // 1. SECRET SCANNING + REDACTION\n let processedMessages = messages;\n\n if (config.redactSecrets || config.blockOnSecrets) {\n const { messages: scannedMessages, redactedCount, blocked, scanDecisions } =\n scanMessages(messages, config);\n processedMessages = scannedMessages;\n secretsRedacted = redactedCount;\n secretsBlocked = blocked;\n decisions.push(...scanDecisions);\n\n if (blocked) {\n return {\n modified: true,\n messages: processedMessages,\n originalTokens,\n optimizedTokens: 0,\n secretsRedacted,\n secretsBlocked: true,\n contextInjected: false,\n decisions,\n };\n }\n }\n\n // 2. CONTEXT OPTIMIZATION\n if (config.optimize && analysis) {\n const { messages: optimizedMessages, injected, optimizeDecisions } =\n await optimizeContext(processedMessages, analysis, config);\n processedMessages = optimizedMessages;\n contextInjected = injected;\n decisions.push(...optimizeDecisions);\n }\n\n // Calculate optimized tokens\n const optimizedTokens = processedMessages.reduce((sum, m) => sum + estimateTokensFromString(m.content), 0);\n\n return {\n modified: secretsRedacted > 0 || contextInjected,\n messages: processedMessages,\n originalTokens,\n optimizedTokens,\n secretsRedacted,\n secretsBlocked,\n contextInjected,\n decisions,\n };\n}\n\n// ===== SECRET SCANNING =====\n\nfunction scanMessages(\n messages: Message[],\n config: GatewayConfig,\n): { messages: Message[]; redactedCount: number; blocked: boolean; scanDecisions: string[] } {\n const scanDecisions: string[] = [];\n let redactedCount = 0;\n let blocked = false;\n\n const scannedMessages = messages.map((msg) => {\n const findings = scanContentForSecrets(msg.content, `message:${msg.role}`);\n\n if (findings.length === 0) return msg;\n\n const criticalCount = findings.filter((f) => f.severity === 'critical').length;\n\n if (config.blockOnSecrets && criticalCount > 0) {\n blocked = true;\n scanDecisions.push(\n `BLOCKED: ${criticalCount} critical secret(s) in ${msg.role} message. ` +\n `Types: ${[...new Set(findings.map((f) => f.type))].join(', ')}`\n );\n return msg;\n }\n\n // Redact secrets\n const sanitized = sanitizeContent(msg.content);\n redactedCount += findings.length;\n\n scanDecisions.push(\n `Redacted ${findings.length} secret(s) in ${msg.role} message: ` +\n `${[...new Set(findings.map((f) => f.type))].join(', ')}`\n );\n\n return { ...msg, content: sanitized };\n });\n\n return { messages: scannedMessages, redactedCount, blocked, scanDecisions };\n}\n\n// ===== CONTEXT OPTIMIZATION =====\n\nasync function optimizeContext(\n messages: Message[],\n analysis: ProjectAnalysis,\n config: GatewayConfig,\n): Promise<{ messages: Message[]; injected: boolean; optimizeDecisions: string[] }> {\n const optimizeDecisions: string[] = [];\n\n // Extract the user's task from the last user message\n const lastUserMsg = [...messages].reverse().find((m) => m.role === 'user');\n if (!lastUserMsg) {\n optimizeDecisions.push('No user message found — skipping optimization');\n return { messages, injected: false, optimizeDecisions };\n }\n\n // Check if there's already a system message with CTO context\n const hasCtxContext = messages.some((m) =>\n m.role === 'system' && m.content.includes('[CTO Context]')\n );\n if (hasCtxContext) {\n optimizeDecisions.push('CTO context already present — skipping injection');\n return { messages, injected: false, optimizeDecisions };\n }\n\n // Run CTO context selection for the user's task\n try {\n const selection = await selectContext({\n task: lastUserMsg.content.slice(0, 500),\n analysis,\n budget: config.budget,\n });\n\n if (selection.files.length === 0) {\n optimizeDecisions.push('No relevant files found for task — skipping injection');\n return { messages, injected: false, optimizeDecisions };\n }\n\n // Reserve ~60% of budget for file contents, rest for metadata + existing messages\n const contentBudget = Math.floor(config.budget * 0.6);\n let usedTokens = 0;\n\n // Build context injection with ACTUAL FILE CONTENTS\n const contextLines: string[] = [\n '[CTO Context] Optimized project context (auto-injected by CTO Gateway)',\n '',\n `Project: ${analysis.projectName} (${analysis.totalFiles} files, ${Math.round(analysis.totalTokens / 1000)}K tokens)`,\n `Selected: ${selection.files.length} files, ${selection.totalTokens.toLocaleString()} tokens (${selection.coverage.score}% coverage)`,\n '',\n ];\n\n // Inject actual file contents for the highest-priority files\n const topFiles = selection.files\n .sort((a, b) => b.riskScore - a.riskScore);\n\n const injectedFiles: string[] = [];\n const skippedFiles: string[] = [];\n\n for (const f of topFiles) {\n if (usedTokens >= contentBudget) {\n skippedFiles.push(f.relativePath);\n continue;\n }\n\n try {\n const fullPath = resolve(config.projectPath, f.relativePath);\n const content = readFileSync(fullPath, 'utf-8');\n\n // Truncate if this single file would blow the budget\n const fileTokens = estimateTokensFromString(content);\n const remainingBudget = contentBudget - usedTokens;\n\n let fileContent: string;\n let truncated = false;\n\n if (fileTokens > remainingBudget) {\n // Truncate to fit budget — keep beginning of file (usually imports/types)\n const charLimit = remainingBudget * 4;\n fileContent = content.slice(0, charLimit);\n truncated = true;\n } else {\n fileContent = content;\n }\n\n const ext = f.relativePath.split('.').pop() || '';\n contextLines.push(`### ${f.relativePath}${truncated ? ' [truncated]' : ''}`);\n contextLines.push('```' + ext);\n contextLines.push(fileContent);\n contextLines.push('```');\n contextLines.push('');\n\n usedTokens += estimateTokensFromString(fileContent);\n injectedFiles.push(f.relativePath);\n } catch {\n skippedFiles.push(f.relativePath);\n }\n }\n\n // Add type file locations (critical for code generation)\n const typeFiles = analysis.files\n .filter((f) => f.kind === 'type')\n .map((f) => f.relativePath);\n\n if (typeFiles.length > 0) {\n contextLines.push('Type definitions (always import from these):');\n for (const tf of typeFiles.slice(0, 10)) {\n contextLines.push(` - ${tf}`);\n }\n contextLines.push('');\n }\n\n // Add hub files (central modules)\n if (analysis.graph.hubs.length > 0) {\n contextLines.push('Hub files (central modules with many dependents):');\n for (const hub of analysis.graph.hubs.slice(0, 5)) {\n contextLines.push(` - ${hub.relativePath} (${hub.dependents} dependents)`);\n }\n contextLines.push('');\n }\n\n // List skipped files so the LLM knows they exist\n if (skippedFiles.length > 0) {\n contextLines.push(`Additional relevant files (not included due to token budget):`);\n for (const sf of skippedFiles.slice(0, 15)) {\n contextLines.push(` - ${sf}`);\n }\n if (skippedFiles.length > 15) {\n contextLines.push(` ... and ${skippedFiles.length - 15} more`);\n }\n }\n\n const contextBlock = contextLines.join('\\n');\n\n // Inject as system message at the beginning\n const systemMsg: Message = {\n role: 'system',\n content: contextBlock,\n };\n\n // Find existing system message and append, or prepend new one\n const existingSystemIdx = messages.findIndex((m) => m.role === 'system');\n let optimizedMessages: Message[];\n\n if (existingSystemIdx >= 0) {\n optimizedMessages = [...messages];\n optimizedMessages[existingSystemIdx] = {\n ...optimizedMessages[existingSystemIdx],\n content: optimizedMessages[existingSystemIdx].content + '\\n\\n' + contextBlock,\n };\n } else {\n optimizedMessages = [systemMsg, ...messages];\n }\n\n optimizeDecisions.push(\n `Injected CTO context: ${injectedFiles.length} files with contents ` +\n `(${usedTokens.toLocaleString()} tokens), ` +\n `${skippedFiles.length} listed without contents, ` +\n `${selection.coverage.score}% coverage`\n );\n\n return { messages: optimizedMessages, injected: true, optimizeDecisions };\n } catch (err: any) {\n optimizeDecisions.push(`Context optimization failed: ${err.message}`);\n return { messages, injected: false, optimizeDecisions };\n }\n}\n","// ===== Context Gateway — Cost & Usage Tracker =====\n//\n// Persistent usage tracking with append-only JSONL storage.\n// Supports daily/monthly aggregation, budget alerts, and export.\n//\n// Design: No external dependencies. Pure Node.js fs.\n// Storage: .cto/gateway/usage/YYYY-MM.jsonl (one file per month)\n\nimport { mkdirSync, appendFileSync, readFileSync, readdirSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport type { UsageRecord, UsageSummary, GatewayConfig, GatewayEvent, GatewayEventHandler, ProviderName } from './types.js';\n\n// ===== TRACKER =====\n\nexport class UsageTracker {\n private logDir: string;\n private config: GatewayConfig;\n private eventHandlers: GatewayEventHandler[] = [];\n private cache: UsageRecord[] | null = null;\n private cacheMonth: string | null = null;\n // In-memory cost accumulators — survive async disk writes\n private memRecords: UsageRecord[] = [];\n\n constructor(config: GatewayConfig) {\n this.config = config;\n this.logDir = join(config.logDir, 'usage');\n mkdirSync(this.logDir, { recursive: true });\n }\n\n // ===== EVENT SYSTEM =====\n\n onEvent(handler: GatewayEventHandler): void {\n this.eventHandlers.push(handler);\n }\n\n private emit(event: GatewayEvent): void {\n for (const handler of this.eventHandlers) {\n try { handler(event); } catch { /* don't let handlers crash the tracker */ }\n }\n }\n\n // ===== RECORD =====\n\n record(params: {\n provider: ProviderName;\n model: string;\n inputTokens: number;\n outputTokens: number;\n costUSD: number;\n originalTokens: number;\n optimizedTokens: number;\n savedTokens: number;\n savedUSD: number;\n secretsRedacted: number;\n secretsBlocked: boolean;\n projectPath: string;\n latencyMs: number;\n stream: boolean;\n error?: string;\n }): UsageRecord {\n const record: UsageRecord = {\n id: randomUUID().slice(0, 8),\n timestamp: new Date(),\n ...params,\n };\n\n // Append to monthly log\n const monthKey = this.getMonthKey(record.timestamp);\n const logFile = join(this.logDir, `${monthKey}.jsonl`);\n const line = JSON.stringify({\n ...record,\n timestamp: record.timestamp.toISOString(),\n });\n appendFileSync(logFile, line + '\\n');\n\n // Keep in memory for accurate budget checks\n this.memRecords.push(record);\n\n // Invalidate disk cache\n this.cache = null;\n\n // Emit event\n this.emit({ type: 'request', record });\n\n // Check budget\n this.checkBudget(record.timestamp);\n\n return record;\n }\n\n // ===== BUDGET CHECKS =====\n\n private checkBudget(now: Date): void {\n if (this.config.budgetDaily > 0) {\n const dailyCost = this.getDailyCost(now);\n const threshold = this.config.budgetDaily * this.config.alertThreshold;\n\n if (dailyCost >= this.config.budgetDaily) {\n this.emit({\n type: 'budget-exceeded',\n current: dailyCost,\n limit: this.config.budgetDaily,\n period: 'daily',\n });\n } else if (dailyCost >= threshold) {\n this.emit({\n type: 'budget-alert',\n current: dailyCost,\n limit: this.config.budgetDaily,\n period: 'daily',\n });\n }\n }\n\n if (this.config.budgetMonthly > 0) {\n const monthlyCost = this.getMonthlyCost(now);\n const threshold = this.config.budgetMonthly * this.config.alertThreshold;\n\n if (monthlyCost >= this.config.budgetMonthly) {\n this.emit({\n type: 'budget-exceeded',\n current: monthlyCost,\n limit: this.config.budgetMonthly,\n period: 'monthly',\n });\n } else if (monthlyCost >= threshold) {\n this.emit({\n type: 'budget-alert',\n current: monthlyCost,\n limit: this.config.budgetMonthly,\n period: 'monthly',\n });\n }\n }\n }\n\n isDailyBudgetExceeded(now: Date = new Date()): boolean {\n if (this.config.budgetDaily <= 0) return false;\n return this.getDailyCost(now) >= this.config.budgetDaily;\n }\n\n isMonthlyBudgetExceeded(now: Date = new Date()): boolean {\n if (this.config.budgetMonthly <= 0) return false;\n return this.getMonthlyCost(now) >= this.config.budgetMonthly;\n }\n\n // ===== QUERIES =====\n\n getDailyCost(date: Date = new Date()): number {\n const dayStr = date.toISOString().split('T')[0];\n // Combine disk records + in-memory records (dedup by id)\n const diskRecords = this.getMonthRecords(date);\n const allRecords = this.mergeWithMemRecords(diskRecords);\n return allRecords\n .filter((r) => r.timestamp.toISOString().startsWith(dayStr))\n .reduce((sum, r) => sum + r.costUSD, 0);\n }\n\n getMonthlyCost(date: Date = new Date()): number {\n const diskRecords = this.getMonthRecords(date);\n const allRecords = this.mergeWithMemRecords(diskRecords);\n return allRecords.reduce((sum, r) => sum + r.costUSD, 0);\n }\n\n private mergeWithMemRecords(diskRecords: UsageRecord[]): UsageRecord[] {\n if (this.memRecords.length === 0) return diskRecords;\n const diskIds = new Set(diskRecords.map((r) => r.id));\n const newRecords = this.memRecords.filter((r) => !diskIds.has(r.id));\n return [...diskRecords, ...newRecords];\n }\n\n getSummary(period: 'day' | 'week' | 'month' | 'all' = 'month'): UsageSummary {\n const now = new Date();\n let records: UsageRecord[];\n\n switch (period) {\n case 'day': {\n const dayStr = now.toISOString().split('T')[0];\n records = this.mergeWithMemRecords(this.getMonthRecords(now)).filter((r) =>\n r.timestamp.toISOString().startsWith(dayStr)\n );\n break;\n }\n case 'week': {\n const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);\n // Cross-month boundary: merge previous month if weekAgo is in a different month\n const weekAgoKey = this.getMonthKey(weekAgo);\n const nowKey = this.getMonthKey(now);\n const baseRecs = weekAgoKey !== nowKey\n ? [...this.getMonthRecordsByKey(weekAgoKey), ...this.getMonthRecords(now)]\n : this.getMonthRecords(now);\n records = this.mergeWithMemRecords(baseRecs).filter((r) => r.timestamp >= weekAgo);\n break;\n }\n case 'month':\n records = this.mergeWithMemRecords(this.getMonthRecords(now));\n break;\n case 'all':\n records = this.mergeWithMemRecords(this.getAllRecords());\n break;\n }\n\n const byModel: Record<string, { requests: number; costUSD: number; tokens: number }> = {};\n const byProvider: Record<string, { requests: number; costUSD: number }> = {};\n\n for (const r of records) {\n // By model\n if (!byModel[r.model]) byModel[r.model] = { requests: 0, costUSD: 0, tokens: 0 };\n byModel[r.model].requests++;\n byModel[r.model].costUSD += r.costUSD;\n byModel[r.model].tokens += r.inputTokens + r.outputTokens;\n\n // By provider\n if (!byProvider[r.provider]) byProvider[r.provider] = { requests: 0, costUSD: 0 };\n byProvider[r.provider].requests++;\n byProvider[r.provider].costUSD += r.costUSD;\n }\n\n return {\n period,\n totalRequests: records.length,\n totalInputTokens: records.reduce((s, r) => s + r.inputTokens, 0),\n totalOutputTokens: records.reduce((s, r) => s + r.outputTokens, 0),\n totalCostUSD: records.reduce((s, r) => s + r.costUSD, 0),\n totalSavedTokens: records.reduce((s, r) => s + r.savedTokens, 0),\n totalSavedUSD: records.reduce((s, r) => s + r.savedUSD, 0),\n totalSecretsRedacted: records.reduce((s, r) => s + r.secretsRedacted, 0),\n byModel,\n byProvider,\n };\n }\n\n // ===== STORAGE =====\n\n private getMonthKey(date: Date): string {\n return date.toISOString().slice(0, 7); // YYYY-MM\n }\n\n private getMonthRecordsByKey(monthKey: string): UsageRecord[] {\n const filePath = join(this.logDir, `${monthKey}.jsonl`);\n if (!existsSync(filePath)) return [];\n return readFileSync(filePath, 'utf-8')\n .split('\\n')\n .filter((line) => line.trim())\n .map((line) => {\n try {\n const parsed = JSON.parse(line);\n parsed.timestamp = new Date(parsed.timestamp);\n return parsed as UsageRecord;\n } catch { return null; }\n })\n .filter((r): r is UsageRecord => r !== null);\n }\n\n private getMonthRecords(date: Date): UsageRecord[] {\n const monthKey = this.getMonthKey(date);\n\n // Use cache if same month\n if (this.cache && this.cacheMonth === monthKey) return this.cache;\n\n const filePath = join(this.logDir, `${monthKey}.jsonl`);\n if (!existsSync(filePath)) return [];\n\n const records = readFileSync(filePath, 'utf-8')\n .split('\\n')\n .filter((line) => line.trim())\n .map((line) => {\n try {\n const parsed = JSON.parse(line);\n parsed.timestamp = new Date(parsed.timestamp);\n return parsed as UsageRecord;\n } catch {\n return null;\n }\n })\n .filter((r): r is UsageRecord => r !== null);\n\n this.cache = records;\n this.cacheMonth = monthKey;\n return records;\n }\n\n private getAllRecords(): UsageRecord[] {\n if (!existsSync(this.logDir)) return [];\n\n const files = readdirSync(this.logDir).filter((f) => f.endsWith('.jsonl')).sort();\n const allRecords: UsageRecord[] = [];\n\n for (const file of files) {\n const content = readFileSync(join(this.logDir, file), 'utf-8');\n const records = content\n .split('\\n')\n .filter((line) => line.trim())\n .map((line) => {\n try {\n const parsed = JSON.parse(line);\n parsed.timestamp = new Date(parsed.timestamp);\n return parsed as UsageRecord;\n } catch {\n return null;\n }\n })\n .filter((r): r is UsageRecord => r !== null);\n\n allRecords.push(...records);\n }\n\n return allRecords;\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 { 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"],"mappings":"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","names":["createHash","readFile","existsSync","join","readFile","readFile","join","existsSync","createHash","readFileSync","resolve","mkdirSync","readFileSync","existsSync","join","readFile","stat","join","relative","resolve","basename","createHash","Project","SyntaxKind","resolve","relative","dirname","join","existsSync","TS_EXTENSIONS","join","stat","readFile","relative","basename","resolve","createHash","resolve","fullContent"]}
|